home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / ada / 2161 < prev    next >
Encoding:
Text File  |  1992-07-21  |  12.2 KB  |  400 lines

  1. Newsgroups: comp.lang.ada
  2. Path: sparky!uunet!wupost!darwin.sura.net!haven.umd.edu!decuac!ryhope.del.dec.com!jeff
  3. From: jeff@ryhope.del.dec.com (Jeff Finkelstein)
  4. Subject: Re: Serial interrupt handler in Meridian Ada on PC?
  5. Message-ID: <1992Jul21.185652.21106@decuac.dec.com>
  6. Sender:  jeff@ryhope.del.dec.com
  7. Nntp-Posting-Host: server.dco.dec.com
  8. Organization: Digital Equipment Corporation
  9. References: <1992Jul21.110241.15174@verdix.com>
  10. Date: Tue, 21 Jul 1992 18:56:52 GMT
  11. Lines: 387
  12.  
  13. In article <1992Jul21.110241.15174@verdix.com> svh@verdix.com (Steven Hovater) writes:
  14. >I know this was a thread several months back, but did anyone ever 'fess
  15. >up to having done this?
  16. >
  17. >If so, I'd like to see the source. Else, I'll have to do it myself
  18. >(privately).
  19. >
  20. >Might also mention that this has no connection to my work. Honest!
  21. >
  22.  
  23. I'll also start out by saying that the following code has nothing to do
  24. with my work. The code that follows is an interrupt handler written in
  25. Meridian Ada. It is not bug free by any stretch but it does seem to
  26. work. Good luck and have at it. When I get it better tested I'll repost.
  27. And yes, I know it looks like C code, I'm still trying to get into being
  28. an Ada dude.
  29.  
  30. jeff
  31. ----
  32. jeff finkelstein                | disclaimer:
  33. digital equipment corporation   |   A horse is a horse, of course, of course.
  34. jeff@ryhope.del.dec.com         |   
  35. ----
  36. with system;
  37.  
  38. package async is
  39.  
  40. in_c_ct : integer := 0;    -- count of characters used in buffer
  41.  
  42. -- word size
  43. BIT7 : constant integer := 2;
  44. BIT8 : constant integer := 3;
  45. -- stop bits
  46. STOP1 : constant integer := 0;
  47. STOP2  : constant integer := 4;
  48. -- parity
  49. NONE  : constant integer := 0;
  50. ODD  : constant integer := 8;
  51. EVEN  : constant integer := 24;
  52. -- baud rate
  53. B300  : constant integer := 384;
  54. B1200  : constant integer := 96;
  55. B2400  : constant integer := 48;
  56. B4800  : constant integer := 24;
  57. B9600  : constant integer := 12;
  58. B19200 : constant integer := 6;
  59.  
  60. subtype byte is integer range 0..255;
  61.  
  62. procedure setport(prot : integer; baud : integer);   -- setup the serial port
  63. -- prot is word | stop | parity    ex: setport(BIT8 or STOP1 or NONE,B1200)
  64. function carrier return integer;
  65. function getport return integer;    -- returns modem & line status
  66.                    --   bits same as in ibm tech manual
  67. procedure flush_port;             -- flushes input and output buffers
  68. procedure uninit;                 -- remove interrupt
  69. procedure comout(c : character);  -- que character in buffer
  70. function inp_char return character;  -- get one char from buffer,
  71. procedure init_com;               -- initialize the comm port,
  72.  
  73. end async;
  74.  
  75. with async; use async;
  76. with port;
  77. with bit_ops; use bit_ops;
  78. with machine_code;
  79. with system; use system;
  80. with interrupt; use interrupt;
  81. with text_io; use text_io;
  82. with unchecked_conversion;
  83.  
  84. package body async is
  85.  
  86. CR : constant integer := 13;
  87.  
  88. -- define interrupt handler
  89. task inthdlr is
  90.    entry startint;
  91.    for startint use at 16#0C#;
  92. end inthdlr;
  93.  
  94. type uns8 is new integer range 0..255;
  95.  
  96. function to_integer is new unchecked_conversion(
  97.    source => character,
  98.    target => integer);
  99.  
  100. function to_character is new unchecked_conversion(
  101.    source => integer,
  102.    target => character);
  103.  
  104. function to_uns8 is new unchecked_conversion(
  105.    source => integer,
  106.    target => uns8);
  107.  
  108. --#define COM0 1          -- either com0 or com1
  109.  
  110. --#ifdef COM0
  111. comport : constant integer := 0;      --  Com port #
  112. base : constant integer := 16#03f8#; -- base for serial board
  113. comint : constant integer :=  16#0c#;    --  Int Vector used by port
  114. enblirq  : constant integer := 16#ef#;   -- enable communications
  115. maskirq  : constant integer := 16#10#;   -- bit to disable comm interrupt
  116. pused : constant integer := 0;
  117. --#endif
  118.  
  119. --#ifdef COM1
  120. --#define comport  1      --  Com Port
  121. --#define base     0x02f8 -- base for serial board
  122. --#define comint   0xb    --  Int Vector used by port
  123. --#define enblirq  0xf7   -- enable communications
  124. --#define maskirq  0x8    -- bit to disable comm interrupt
  125. --int pused = 1;
  126. --#endif
  127.  
  128. -- 8250 registers
  129. mdmbd0  : constant integer :=   base;    -- lsb baud rate register
  130. dataport  : constant integer := base;    -- transmit/receive data port
  131. mdmbd1 : constant integer :=   base+1;  -- msb baud rate register
  132. ier  : constant integer :=      base+1;  --  interrup enable register
  133. irr  : constant integer :=      base+2;  -- reason for interrupt
  134. lcr  : constant integer :=      base+3;  --  line control register
  135. mcr  : constant integer :=      base+4;  -- modem control register
  136. mdmsta : constant integer :=    base+5;  -- line status register
  137. mdmmsr : constant integer :=    base+6;  -- modem status register
  138.  
  139. -- 8250 values
  140. mdmcd  : constant integer :=   16#80#;     -- mask for carrier dectect
  141. mdmtbe : constant integer :=   16#20#;     -- 8250 tbe flag
  142. dlab  : constant integer :=    16#80#;     -- enable divisor latch
  143.  
  144. -- 8250 interrupt enable values
  145. enbldrdy  : constant integer := 1;       --  enable 'data-ready' interrupt bit
  146. enbltrdy  : constant integer := 2;       --  enable 'xmit-empty' interrupt bit
  147. enbllrdy  : constant integer := 4;       --  enable 'line-change' interrupt bit
  148. enblmrdy  : constant integer := 8;       --  enable 'modem-change' interrupt bit
  149.  
  150. -- 8250 interrupt causes
  151. intms  : constant integer :=    0;       -- int caused by modem status
  152. inttx  : constant integer :=    2;       -- int caused by td
  153. intrd  : constant integer :=    4;       -- int caused by dr
  154. intls  : constant integer :=    6;       -- int caused by line status
  155.  
  156. -- 8259 ports and values
  157. intctlr : constant integer :=  16#21#;     -- ocw 1 for 8259 controller
  158. rs8259 : constant integer :=   16#20#;     -- ocw 3 for 8259
  159. rstint : constant integer :=   16#20#;     -- specific eoi for comm interrupt
  160.  
  161. --        miscellaneous equates
  162. xoff : constant integer :=     16#13#;
  163. xon  : constant integer :=     16#11#;
  164. bufsiz : constant integer :=   512;     -- max number of chars
  165.  
  166. in_c_buf : array (1..bufsiz) of character;   -- allow 512 buffered characters
  167. ou_c_buf : array (1..bufsiz) of character;
  168. linstat : integer;
  169. xon_sent : boolean := false;
  170.  
  171. ou_c_top : constant integer := bufsiz;
  172. in_c_top : constant integer := bufsiz;
  173.  
  174. in_c_in : integer := 0;   -- in_c_buf pointer to last char. placed in buffer
  175. in_c_cur : integer := 0;  -- in_c_buf pointer to next char. to be retrieved
  176. ou_c_in : integer := 0;   -- ou_c_buf pointer to last char. placed in buffer
  177. ou_c_cur : integer := 0;  -- ou_c_buf pointer to next char. to be transmitted
  178. ou_c_ct : integer := 0;    -- count of characters used in buffer
  179. modstat : integer := 0;    -- modem status
  180.  
  181. oldseg : integer;
  182. oldoff : integer;
  183. regs : registers;
  184. rd,tx : character;  -- last received and transmitted character
  185.  
  186. function carrier return integer is
  187. begin
  188.    return port.in_byte(mdmmsr) and 16#80#;
  189. end carrier;
  190.  
  191. procedure disable is
  192. use machine_code;
  193. begin
  194.    inst1'(b1 => 16#FA#);
  195. end disable;
  196.  
  197. procedure enable is
  198. use machine_code;
  199. begin
  200.    inst1'(b1 => 16#FB#);
  201. end enable;
  202.  
  203. procedure setport(prot : integer; baud : integer) is
  204. begin
  205.     disable;                  -- disable interrupts
  206.     port.out_byte(lcr,dlab);           -- enable buad sender
  207.     port.out_byte(mdmbd0,baud and 16#FF#); -- send lsb
  208.     port.out_byte(mdmbd1,baud / 256);  -- send msb
  209.     port.out_byte(lcr,prot);           -- set protocol
  210.     enable;
  211. end setport;
  212.  
  213. --  int getport();
  214. --15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  215. --   T  T  B  F  P   O  D  D  R  D  C  D  T  D  D
  216. --   S  H  I  E  E   R  R  C  I  S  T  D  E  D  C
  217. --   R  R                  D     R  S  C  R  S  T
  218. --   E  E                              D  I  R  S
  219. --Data Ready = DR, Overrun Error = OR, Parity Error = PE, Framing Error = FE,
  220. --Break Interrupt = BI, Transmitter Holding Register = THRE,
  221. --Transmitter Empty = TSRE, Delta Clear to Send = DCTS, Clear to Send = CTS,
  222. --Delta Data Set Ready = DDSR, Data Set Ready = DSR, Ring Indicator = RI,
  223. --Trailing Edge Ring Indicator = TERI, Delta Carrier Detect = DCD,
  224. --Carrier Detect = CD
  225. function getport return integer is
  226. begin
  227.     return(256 * linstat + modstat);
  228. end getport;
  229.  
  230. -- flush_port --   flush the buffers
  231. procedure flush_port is
  232. begin
  233.     disable;
  234.     in_c_in := 0; 
  235.     in_c_cur := 0; --&in_c_buf[0];
  236.     in_c_ct := 0;
  237.     ou_c_in := 0;
  238.     ou_c_cur := 0; --&ou_c_buf[0];
  239.     ou_c_ct := 0; 
  240.     xon_sent := false;
  241.     enable;
  242. end flush_port;
  243.  
  244. procedure getvect is
  245. begin
  246.    regs.ax := 16#350C#; -- get vector for com 1 interrupt routine
  247.    vector(
  248.       on => 16#21#,
  249.       register_block => regs);
  250.    oldseg := regs.es;
  251.    oldoff := regs.bx;
  252. end getvect;
  253.  
  254. procedure setvect is
  255. begin
  256.    regs.ax := 16#250C#; -- set vector for new com1 interrupt routine
  257.    regs.ds := oldseg;
  258.    regs.dx := oldoff;
  259.    vector(
  260.       on => 16#21#,
  261.       register_block => regs);
  262. end setvect;
  263.  
  264. procedure uninit is     -- remove initialization,
  265. begin
  266.     disable;
  267.     setvect; -- restore old vector
  268.     port.out_byte(intctlr,port.in_byte(intctlr) or maskirq); --  disable irq on 8259
  269.     port.out_byte(ier,0); -- clear all interrupt enables
  270.     port.out_byte(lcr,0); -- clear the protocol
  271.     port.out_byte(mcr,0); -- disable out2 on 8250
  272.     enable;
  273. end uninit;
  274.  
  275. procedure comout(c : character) is -- que character in buffer
  276. begin
  277.     if (port.in_byte(mdmsta) and mdmtbe) > 0 and ou_c_ct /= 0 then
  278.     port.out_byte(dataport,to_integer(c)); -- if status is clear then just send
  279.     tx := c;
  280.     else                     -- load it in the buffer
  281.     disable;
  282.     if ou_c_ct < bufsiz then  -- if buffer is full ignore character
  283.         ou_c_buf(ou_c_in) := c;
  284.         ou_c_ct := ou_c_ct + 1;
  285.         if ou_c_in = ou_c_top then
  286.            ou_c_in := 1;
  287.         else
  288.            ou_c_in := ou_c_in + 1;
  289.         end if;
  290.     end if;
  291.     enable;
  292.     end if;
  293. end comout;
  294.  
  295. -- char inp_char()        return a character from the in_c_buf
  296. --                        buffer. assumes you have called
  297. -- in_c_ct to see if theres any characters to get.
  298.  
  299. function inp_char return character is         -- get one char from buffer,
  300. cin : character;
  301. begin
  302.     disable;
  303.     cin := in_c_buf(in_c_cur);
  304.     if in_c_ct > 0 then
  305.     in_c_ct := in_c_ct - 1;
  306.     if in_c_cur = in_c_top then
  307.         in_c_cur := 0;
  308.     else
  309.         in_c_cur := in_c_cur + 1;
  310.     end if;
  311.     end if;
  312.     enable;
  313.     if xon_sent and in_c_ct < 128 then
  314.     comout(ASCII.DC1);
  315.     xon_sent := FALSE;
  316.     end if;
  317.     return cin;
  318. end inp_char;
  319.  
  320. -- receive interrupt handler (changed to place characters in in_c_buf)
  321. task body inthdlr is
  322. begin
  323.  loop
  324.   select
  325.     accept startint do
  326.     disable;
  327.     case port.in_byte(irr) is
  328.       when intrd => -- receive data
  329.         if in_c_ct < bufsiz then -- if buffer is full ignore character
  330.         in_c_buf(in_c_in) := to_character(port.in_byte(dataport));
  331.         rd := in_c_buf(in_c_in);
  332.         in_c_ct := in_c_ct + 1;
  333.         if in_c_in = in_c_top then
  334.            in_c_in := 0;
  335.         else
  336.            in_c_in := in_c_in + 1;
  337.         end if;
  338.         end if;
  339.       when intms =>
  340.         modstat := port.in_byte(mdmmsr);  -- modem status
  341.       when intls =>
  342.         linstat := port.in_byte(mdmsta);  -- line status
  343.       when inttx => -- transmitter empty
  344.         if ou_c_ct > 0 then -- if there is a character
  345.         port.out_byte(dataport,to_integer(ou_c_buf(ou_c_cur)));
  346.         tx := ou_c_buf(ou_c_cur);
  347.         ou_c_ct := ou_c_ct - 1;         -- decrement in_c_buf count
  348.         if ou_c_cur = ou_c_top then
  349.           ou_c_cur := 0;
  350.         else
  351.           ou_c_cur := ou_c_cur + 1;
  352.         end if;
  353.         end if;
  354.       when others =>
  355.         null;
  356.     end case;
  357.     port.out_byte(rs8259,rstint);
  358.     if in_c_ct > (bufsiz*3/4) then
  359.         comout(ASCII.DC3);
  360.         xon_sent := TRUE;
  361.     end if;
  362.     enable;
  363.        end startint;
  364.      end select;
  365.    end loop;
  366. end inthdlr;
  367.  
  368. --  --------- init -----------------------------------
  369. --  program initialization:
  370. --    --  set up vector for rs232 interrupt
  371. --    --  enbl irq
  372. --    --  enbl rs232 interrupt on dr,tx,ms,ls
  373.  
  374. --  ---------------------------------------------------
  375.  
  376. procedure init_com is        -- initialize the comm port,
  377. begin
  378.     getvect;
  379.     disable;
  380.     flush_port;
  381.     port.out_byte(intctlr,port.in_byte(intctlr) and enblirq);
  382.     port.out_byte(lcr,port.in_byte(lcr) and 16#7f#); -- reset dlab for ier access
  383.     port.out_byte(ier,enbldrdy+enbllrdy+enblmrdy+enbltrdy);
  384.     port.out_byte(mcr,16#0f#); --modem control register enable out2 out1 dtr rts
  385.     linstat := port.in_byte(mdmsta);
  386.     modstat := port.in_byte(mdmmsr);
  387.     enable;
  388. end init_com;
  389.  
  390. procedure comok is
  391. begin
  392.     port.out_byte(mcr,16#0F#); -- enable modem
  393. end comok;
  394.  
  395. end async;
  396. -- 
  397. jeff finkelstein                | disclaimer:
  398. digital equipment corporation   |   A horse is a horse, of course, of course.
  399. jeff@ryhope.del.dec.com         |   
  400.