-- dit is de Serial_Device_Driver package -- let op : we werken met COM2! -- dwz : TX en RX buffer op 2F8H -- divisor latch register op 2F8H en 2F9H -- line control register op 2FBH -- line status register op 2FDH package Serial_Device_Driver is type 2bits is range 0..3; procedure Get_Number(getal : out INTEGER); procedure Send_Number(getal : in INTEGER); private : for 2bits'Size use 2; -- er mogen slechts 2 bits voor gebruikt worden; end Serial_Device_Driver; with Ada.Interrupts.Names, System, System.Storage_Elements; use Ada.Interrupts.Names, System, System.Storage_Elements; package body Serial_Device_Driver is Bits_In_Word : constant := 16; Bits_In_Byte : constant := 8; Word : constant := 2; type Flag in (Down, Set); type Line_Control_Register is record DL_access : Flag; -- divisor latch access bit break_control : Flag; -- set break control stick_parity : Flag; -- stick parity even_parity : Flag; -- even parity select parity_enable : Flag; -- parity enable stop_bits : Flag; -- stop bits word_length : 2bits; -- word length : zet op 11 end record; -- nu specifieren we de layout for Line_Control_Register use record DL_acces at 0*Word range 7..7; break_control at 0*Word range 6..6; stick_parity at 0*Word range 5..5; even_parity at 0*Word range 4..4; parity_enable at 0*Word range 3..3; stop_bits at 0*Word range 2..2; word_length at 0*Word range 0..1; end record; for Line_Control_Register'Size use Bits_In_Byte; -- het register is 8 bits for Line_Control_Register'Alignment use Word; for Line_Control_Register'Bit_order us Low_Order_First; -- LSB = 0; type Line_Status_Register is record TSR_empty : Flag; -- Trans-shift-register empty THR_empty : Flag; -- Trans-hold-register empty Break_Int : Flag; -- Break interrupt indicator Framing_err : Flag; -- Framing error indicator Par_err : Flag; -- Parity error indicator Overrun_err : Flag; -- Overrun error indicator rec_data_ready : Flag; -- Receiver data ready end record; -- nu specifieren we de layout for Line_Status_Register use record TSR_empty at 0*Word range 6..6; THR_empty at 0*Word range 5..5; Break_Int at 0*Word range 4..4; Framing_err at 0*Word range 3..3; Par_err at 0*Word range 2..2; Overrun_err at 0*Word range 1..1; rec_data_ready at 0*Word range 0..0; end record; for Line_Status_Register'Size use Bits_In_Byte; -- het register is 8 bits for Line_Status_Register'Alignment use Word; for Line_Status_Register'Bit_order us Low_Order_First; -- LSB = 0; -- als bit 7 van het line control register 1 is, dan zijn de adressen 3F8H en 3F9H voor -- het divisor latch register -- als bit 7 van het line control register 0 is, dan zijn de adressen 3F8H en 3F9H voor -- het verzenden en ontvangen van data -- we moeten dus eerst op allebei de computers bit 7 van het line control register op -- 1 zetten, zodat we de baudsnelheid kunnen selecteren; -- als dit gedaan is, zetten we bit 7 van het line control register op 0, zodat we -- de adressen 3F8H en 3F9H kunnen gebruiken als dataregister. type Divisor_Latch_Register is record baud_rate : INTEGER; end record; -- specifieren van de layout for Divisor_Latch_Register use record baud_rate at 0*Word range 0..15; end record; for Divisor_Latch_Register'Size use Bits_In_Word; -- het register is 16 bits for Divisor_Latch_Register'Alignment use Word; for Divisor_Latch_Register'Bit_order us Low_Order_First; -- LSB = 0; type Data_Register is INTEGER; -- alle mogelijke getallen kunnen voorkomen in het data register for Data_Register'Size use Bits_In_Word; Contr_Reg_Addr: constant Address := To_Address(16#2FB#); Stat_Reg_Addr : constant Address := To_Address(16#2FD#); Latch_Reg_Addr : constant Address := To_Address(16#2F8#); Data_Reg_Addr : constant Address := To_Address(16#2F8#); Serial_Priority : constant Interrupt_Priority := 63; Control_Reg : aliased Line_Control_Register; for Control_Reg'Address use Contr_Reg_Addr; Status_Reg : aliased Line_Status_Register; for Status_Reg'Address use Stat_Reg_Addr; Latch_Reg : aliased Divisor_Latch_Register; for Latch_Reg'Address use Latch_Reg_Addr; Data_Reg : aliased Data_Register; for Data_Reg'Address use Data_Reg_Addr; -- nu de interrupt interface nog schrijven protected type Interrupt_Interface(Int_Id : Interrupt_Id; Cr : access Line_Control_Register; Sr : access Line_Status_Register; Lr : access Divisor_Latch_Register; Dr : access Data_Register) is entry Read(getal : out INTEGER); -- het uitlezen van een getal entry Write(getal : in INTEGER); -- het schrijven van een getal private : entry Done(getal : out INTEGER); procedure Handler; pragma Attach_Handler(Handler, Int_Id) pragma Interrupt_Priority(Serial_Priority) Interrupt_Occurred : Boolean := False; Next_Request : Boolean := True; end Interrupt_Interface; Serial_Interface : Interrupt_Interface(Names.Serial, Control_Reg'Address, Status_Reg'Address, Latch_Reg'Address, Data_Reg'Address); protected body Interrupt_Interface is entry Read(getal : out INTEGER) when Next_Request is Shadow_Register : Control_Register; begin -- shadow register invullen -- en copieren naar controle register -- data lezen Interrupt_Occurred := False; Next_Request := False; requeue Done; end Read; entry Write(getal : in INTEGER) when not Next_Request is Shadow_Register : ??? begin ??? end Write; procedure Handler is begin Interrupt_Occurred := True; end Handler; entry Done(getal : out INTEGER) when Interrupt_Occurred is begin Next_Request := True; -- uitlezen van de data in het getal; -- checken op errors? end Done; end Interrupt_Interface; procedure Get_Number(getal : out INTEGER) is begin Serial_Interface.Read(getal); end Get_Number; procedure Send_Number(getal : in INTEGER) is begin -- opsplitsen van getal in afzonderlijke groepjes van 2 bytes! -- in het datareg kunnen maar 16 bits tegelijk Serial_Interface.Write(getal); end Send_Number; end Serial_Device_Driver;