Advertisement
LarsFosdal

Bit-twiddling in Pascal

Jul 5th, 2015
493
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 10.26 KB | None | 0 0
  1. {
  2. Example of bit twiddling in pre-OOP Turbo Pascal
  3. Note the ALL CAPS keywords - from before syntax highlighting.
  4. Took me a while to unlearn that :P
  5. }
  6.  
  7. {$I CODEDEFS.PAS} {Include code generation definitions}
  8. {$O-} {Overlaying not allowed}
  9.  
  10. UNIT LFcomm; {.4 (c) 19880926 Lars Fosdal }
  11.  
  12. { This TP4 Unit supports Com1 and Com2 with a few simple routines...
  13.   ...the receive routine is interruptdriven and buffers input.
  14.  
  15.   Related info can be found in :
  16.  
  17.     "Product Handbook", Western Digital '81
  18.       Section 1  : "WD8250 Asynchronous Communications Element"
  19.  
  20.     "Intel Microsystems Components Handbook", Intel '86
  21.       Pages 2-95 ..2-132 : "8259A Programmable Interrupt Controller"
  22.       Pages 2-144..2-181 : Application Note "Using the 8259A"
  23.  
  24.     "Advanced Techniques in Turbo Pascal", Charles C.Edwards, SYBEX '87
  25.       Pages 220..233 : "Data Communications".
  26.  
  27.     BYTE magazine Vol.12/#12 : "Inside the IBM PC's"
  28.       Pages 173..180 : "IBM PC Family BIOS Comparison" by Jon Shiell.
  29.  
  30.     "Advanced MSDOS", Ray Duncan, MicroSoft Press '86
  31.       Reading the whole book is recommended !!!
  32.  
  33.     and in your TP4,TP5,TP55,TP60 Owner's handbooks.
  34. }
  35.  
  36. INTERFACE USES Dos,Crt,LFsystem;
  37.  
  38. CONST
  39.   Com1         = 1;
  40.   Com2         = 2;
  41.   Ready        = true;
  42.   NotReady     = false;
  43.   NoError      = 0;
  44.   AlreadyOpen  = 1;
  45.   AlreadyClosed= 2;
  46.   NotOpen      = 3;
  47.  
  48. TYPE
  49.   ComSpeed  = 110..38400;
  50.   ComDbits  = 7..8;
  51.   ComSbits  = 1..2;
  52.   ComPorts  = 1..2;
  53.   ComParity = (pNone,pOdd,pMark,pEven,pSpace);
  54.  
  55. VAR
  56.   LFcommSpeed  : ARRAY[ComPorts] OF ComSpeed;
  57.   LFcommDbits  : ARRAY[ComPorts] OF ComDbits;
  58.   LFcommSbits  : ARRAY[ComPorts] OF ComSbits;
  59.   LFcommParity : ARRAY[ComPorts] OF ComParity;
  60.   InverseRTS,
  61.   InverseDTR   : Boolean;
  62.  
  63. FUNCTION ComError:word;
  64. FUNCTION Received(Com:ComPorts):boolean;
  65. FUNCTION cRead(Com:ComPorts):char;
  66. FUNCTION RBused(Com:ComPorts):Word;
  67. PROCEDURE ResetRB(Com:ComPorts);
  68. PROCEDURE cProtocol(Com : ComPorts;  speed : ComSpeed;
  69.                     databits : ComDbits;  parity : ComParity;
  70.                     stopbits:ComSbits);
  71. PROCEDURE cOpen(Com : ComPorts;  RBsize : Word;
  72.                 speed : ComSpeed;  databits : ComDbits;
  73.                 parity : ComParity;  stopbits : ComSbits);
  74. PROCEDURE DTR(Com:ComPorts; state:boolean);
  75. PROCEDURE RTS(Com:ComPorts; state:boolean);
  76. PROCEDURE cBreak(Com:ComPorts);
  77. PROCEDURE cWrite(Com:ComPorts; msg:String);
  78. PROCEDURE cClose(Com:ComPorts);
  79.  
  80.  
  81. IMPLEMENTATION
  82.  
  83.  
  84. CONST
  85.   LFcommMsg = ' LFcomm.4 19880926 Lars Fosdal ';
  86.  
  87.   {--Interrupt consts-}
  88.   imr8259       = $21;
  89.   eoi8259       = $20;
  90.   EOI           = $20;
  91.   iComNo    : ARRAY[ComPorts] OF byte =($0C,$0B);
  92.   irqCom    : ARRAY[ComPorts] OF byte =($EF,$F7);
  93.  
  94.   {---UART registers-}
  95.   Data      : ARRAY[ComPorts] OF word = ($3F8,$2F8);
  96.   iEnable   : ARRAY[ComPorts] OF word = ($3F9,$2F9);
  97.   iIdentify : ARRAY[ComPorts] OF word = ($3FA,$2FA);
  98.   LineCtrl  : ARRAY[ComPorts] OF word = ($3FB,$2FB);
  99.   LineStat  : ARRAY[ComPorts] OF word = ($3FD,$2FD);
  100.   ModemCtrl : ARRAY[ComPorts] OF word = ($3FC,$2FC);
  101.   ModemStat : ARRAY[ComPorts] OF word = ($3FE,$2FE);
  102.   Reserved  : ARRAY[ComPorts] OF word = ($3FF,$2FF);
  103.  
  104.   {--Interupt Enable-}
  105.   InterruptsOff = $00;
  106.   DataReceived  = $01;
  107.   ReadyToSend   = $02;
  108.   LineStatChng  = $04;
  109.   ModemStatChng = $08;
  110.   {Bits 4..7 not used}
  111.  
  112.   {---Line Status----}
  113.   DataRecvReady = $01;
  114.   OverRunError  = $02;
  115.   ParityError   = $04;
  116.   FramingError  = $08;
  117.   BreakDetected = $10;
  118.   XmitHoldEmpty = $20;
  119.   XmitShftEmpty = $40;
  120.   {bit 7 always zero }
  121.  
  122.   {---Line Control---}
  123.   {Bits 0..1 : #DataBits : 0=5, 1=6, 2=7, 3=8 }
  124.   {Bit 2     : #StopBits : 0=1, 1=2 }
  125.   {Bit 3     : Enable Parity}
  126.   {Bit 4     : 0=Odd/Space, 1=Even/Mark}
  127.   {Bit 5     : Select Mark/Space Parity}
  128.   GenerateBreak = $40;
  129.   DivisorLatch  = $80;
  130.  
  131.   {---Modem Status---}
  132.   deltaCTS      = $01;
  133.   deltaDSR      = $02;
  134.   TrailEdgeRI   = $04;
  135.   deltaCD       = $08;
  136.   _CTS_         = $10;
  137.   _DSR_         = $20;
  138.   _RI_          = $40;
  139.   _CD_          = $80;
  140.  
  141.   {---Modem Control--}
  142.   _DTR_         = $01;
  143.   _RTS_         = $02;
  144.   Out1          = $04;
  145.   Out2          = $08;
  146.   LoopBackTest  = $10;
  147.   {bits 5..7 not used}
  148.  
  149. TYPE
  150.   ComBuffer = ARRAY[1..65535] OF byte;
  151.   ComStat   = (Closed,Open);
  152. VAR
  153.   rcvdBS,
  154.   stRcvd,
  155.   eoRcvd    : Array[ComPorts] OF word;
  156.   Rcvd      : Array[ComPorts] OF ^ComBuffer;
  157.   OldVec    : Array[ComPorts] OF Pointer;
  158.   Status    : ARRAY[ComPorts] OF ComStat;
  159.   cno       : Comports;
  160.   ErrorCom  : Byte;
  161.  
  162. PROCEDURE iHandler1(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : word);
  163.  Interrupt;
  164. BEGIN
  165. { sti;}
  166.   Rcvd[Com1]^[eoRcvd[Com1]] := Port[Data[Com1]];
  167.   IF eoRcvd[Com1]<RcvdBS[Com1]
  168.   THEN inc(eoRcvd[Com1])
  169.   ELSE eoRcvd[Com1] := 1;
  170. { cli;}
  171.   Port[eoi8259] := EOI;
  172. END; {PROC iHandler1}
  173.  
  174. PROCEDURE iHandler2(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : word);
  175.  Interrupt;
  176. BEGIN
  177. { sti;}
  178.   Rcvd[Com2]^[eoRcvd[Com2]] := Port[Data[Com2]];
  179.   IF eoRcvd[Com2]<RcvdBS[Com2]
  180.   THEN inc(eoRcvd[Com2])
  181.   ELSE eoRcvd[Com2] := 1;
  182. { cli;}
  183.   Port[eoi8259] := EOI;
  184. END; {PROC iHandler2}
  185.  
  186. PROCEDURE DTR(Com:ComPorts; State:Boolean);
  187. VAR
  188.   onOff,pval : Byte;
  189. BEGIN
  190.   pval := Port[ModemCtrl[com]];
  191.   CASE InverseDTR xor state OF
  192.     False : pval := pval and not _DTR_;
  193.     True  : pval := pval or _DTR_;
  194.   END;
  195.   Port[ModemCtrl[com]] := pval;
  196. END; {PROC DTR}
  197.  
  198. PROCEDURE RTS(Com:ComPorts; State:Boolean);
  199. VAR
  200.  pval : Byte;
  201. BEGIN
  202.   pval := Port[ModemCtrl[com]];
  203.   CASE InverseRTS xor state OF
  204.     False : pval := pval and not _RTS_;
  205.     True  : pval := pval or _RTS_;
  206.   END;
  207.   Port[ModemCtrl[com]] := pval;
  208. END; {PROC RTS}
  209.  
  210. PROCEDURE cBreak(Com:ComPorts);
  211. VAR
  212.   asBefore : byte;
  213. BEGIN
  214.   IF Status[Com]=Open THEN
  215.   BEGIN
  216.     asbefore := port[LineCtrl[Com]]; delay(10);
  217.     port[LineCtrl[Com]] := asBefore or GenerateBreak;
  218.     delay(200);
  219.     port[LineCtrl[Com]] := asBefore;
  220.     ErrorCom := NoError;
  221.   END
  222.    ELSE ErrorCom := NotOpen;
  223. END; {PROC cBreak}
  224.  
  225.  
  226. PROCEDURE cProtocol(Com : ComPorts;  speed : ComSpeed;
  227.                     databits : ComDbits;  parity : ComParity;
  228.                     stopbits : ComSbits);
  229. VAR
  230.   rate : word;
  231.   pval : byte;
  232. BEGIN
  233.   IF Status[Com]=Open THEN
  234.   BEGIN
  235.     cli;
  236.     rate := 115200 div speed;
  237.     pval := port[LineCtrl[Com]]; delay(10);
  238.     port[LineCtrl[Com]] := pval or DivisorLatch; delay(10);
  239.     port[Data[Com]]     := lo(rate); delay(10);
  240.     port[iEnable[Com]]  := hi(rate); delay(10);
  241.     pval := port[LineCtrl[Com]]; delay(10);
  242.     port[LineCtrl[Com]] := pval xor DivisorLatch; delay(10);
  243.     port[LineCtrl[Com]] := (databits-5)
  244.                               +((stopBits-1) shl 2)
  245.                               +(ord(parity) shl 3);
  246.     sti;
  247.     LFcommSpeed[com] := Speed;
  248.     LFcommDbits[com] := Databits;
  249.     LFcommSbits[com] := StopBits;
  250.     LFcommParity[com] := Parity;
  251.     ErrorCom := NoError;
  252.   END
  253.    ELSE ErrorCom := NotOpen;
  254. END; {PROC cProtocol}
  255.  
  256. PROCEDURE cOpen(Com : ComPorts;  RBsize : Word;
  257.                 speed : ComSpeed;  databits : ComDbits;
  258.                 parity : ComParity;  stopbits : ComSbits);
  259. VAR
  260.   pval : byte;
  261. BEGIN
  262.   IF Status[Com]=Closed THEN
  263.   BEGIN
  264.     CASE Com OF
  265.       Com1 : SetIntVec(iComNo[Com1],@iHandler1);
  266.       Com2 : SetIntVec(iComNo[Com2],@iHandler2);
  267.     END;
  268.     RcvdBS[com] := RBSize; GetMem(rcvd[com],RcvdBS[com]);
  269.     Status[Com] := Open;
  270.     cProtocol(Com,speed,databits,parity,stopbits);
  271.     cli;
  272.     pval := port[imr8259]; delay(10);
  273.     port[imr8259] := pval and IrqCom[Com]; delay(10);
  274.     pval := port[LineCtrl[Com]]; delay(10);
  275.     port[LineCtrl[Com]] := pval and $7F; delay(10);
  276.     port[iEnable[Com]] := DataReceived; delay(10);
  277.     pval := port[ModemCtrl[Com]]; delay(10);
  278.     Port[ModemCtrl[Com]] := pval OR (Out2);
  279.     pval := Port[LineStat[Com]];
  280.     ResetRB(Com);
  281.     sti;
  282.     ErrorCom := NoError;
  283.     DTR(Com,True);
  284.   END
  285.    ELSE
  286.   BEGIN
  287.     cProtocol(Com,speed,databits,parity,stopbits);
  288.     ErrorCom := AlreadyOpen;
  289.   END;
  290. END; {PROC cOpen}
  291.  
  292. PROCEDURE cClose(Com:ComPorts);
  293. BEGIN
  294.   IF Status[Com]=Open THEN
  295.   BEGIN
  296.     cli;
  297.     port[imr8259] := port[imr8259] or $18;
  298.     port[LineCtrl[Com]] := port[LineCtrl[Com]] and $7F;
  299.     port[iEnable[Com]] := InterruptsOff;
  300.     port[ModemCtrl[Com]] := 0;
  301.     sti;
  302.     SetIntVec(iComNo[Com],OldVec[Com]);
  303.     FreeMem(Rcvd[com],RcvdBS[com]); RcvdBS[com] := 1;
  304.     Status[Com] := Closed;
  305.     ErrorCom := NoError;
  306.   END ELSE ErrorCom := AlreadyClosed;
  307. END; {PROC cClose}
  308.  
  309. PROCEDURE ResetRB(Com:ComPorts);
  310. BEGIN
  311.   stRcvd[Com] := 1;
  312.   eoRcvd[Com] := 1;
  313. END; {PROC ResetRB}
  314.  
  315. FUNCTION Received(Com:ComPorts):Boolean;
  316. BEGIN
  317.   IF Status[Com]=Open THEN
  318.   BEGIN
  319.     Received := stRcvd[Com]<>eoRcvd[Com];
  320.     ErrorCom := NoError;
  321.   END
  322.    ELSE
  323.   BEGIN
  324.     Received := False;
  325.     ErrorCom := NotOpen;
  326.   END;
  327. END; {FUNC Received}
  328.  
  329. FUNCTION RBused(Com:ComPorts):Word;
  330. BEGIN
  331.   IF eoRcvd[Com]<stRcvd[Com] THEN
  332.    RBused := RcvdBS[Com]-stRcvd[Com]+eoRcvd[Com]
  333.     ELSE RBused := eoRcvd[Com]-stRcvd[Com];
  334. END; {FUNC RBused}
  335.  
  336. FUNCTION cRead(Com:ComPorts):Char;
  337. BEGIN
  338.   IF Status[Com]=Open THEN
  339.   BEGIN
  340.     CLI;
  341.     cRead := chr(Rcvd[Com]^[stRcvd[Com]]);
  342.     IF stRcvd[Com]<RcvdBS[Com] THEN inc(stRcvd[Com])
  343.      ELSE stRcvd[Com] := 1;
  344.     STI;
  345.     ErrorCom := NoError;
  346.   END
  347.    ELSE
  348.   BEGIN
  349.     cRead := #0;
  350.     ErrorCom := NotOpen;
  351.   END;
  352. END; {FUNC cRead}
  353.  
  354. PROCEDURE cWrite(Com:ComPorts; msg:String);
  355. VAR
  356.   n : byte;
  357.   HoldOK,DsrCtsOK : Boolean;
  358. BEGIN
  359.   IF Status[Com]=Open THEN
  360.   BEGIN
  361.     RTS(Com,True);
  362.     FOR n := 1 to length(msg) DO
  363.     BEGIN
  364.       REPEAT
  365.         HoldOK := Port[LineStat[Com]] and xmitHoldEmpty = xmitHoldEmpty;
  366.         {DsrCtsOK := Port[ModemStat[Com]] and (_DSR_+_CTS_) = _DSR_+_CTS_;}
  367.       UNTIL HoldOK { and DsrCtsOK};
  368.       Port[Data[Com]] := byte(msg[n]);
  369.     END;
  370.     RTS(Com,False);
  371.     ErrorCom := NoError;
  372.   END
  373.    ELSE ErrorCom := NotOpen;
  374. END; {PROC cWrite}
  375.  
  376. FUNCTION ComError;
  377. BEGIN
  378.   ComError := ErrorCom;
  379.   ErrorCom := 0;
  380. END; {FUNC ComError}
  381.  
  382. BEGIN {Initialisation part of Unit LFcomm}
  383.   Units.Enter(LFcommMsg,MemAvail,CSeg);
  384.   InverseRTS := False;
  385.   InverseDTR := False;
  386.   FOR cno := Com1 to Com2 DO
  387.   BEGIN
  388.     GetIntVec(iComNo[cno],OldVec[cno]);
  389.     Status[cno] := Closed;
  390.     RcvdBS[cno] := 1;
  391.   END;
  392.   ErrorCom := 0;
  393. END.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement