home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1988 / 02 / lindley / lindley.ls3 < prev    next >
Text File  |  1979-12-31  |  10KB  |  485 lines

  1.  
  2. {************************************************}
  3. {***                                          ***}
  4. {***          RS-232 support procedures       ***}
  5. {***      for the serial protocol analyzer    ***}
  6. {***                 written by               ***}
  7. {***              Craig A. Lindley            ***}
  8. {***                                          ***}
  9. {***    Ver: 2.0     Last update: 08/15/87    ***}
  10. {***                                          ***}
  11. {************************************************}
  12.  
  13. CONST
  14.  
  15.  COM1 = $3f8;              {com one port addr}
  16.  COM2 = $2f8;              {com two port addr}
  17.  
  18.  {table of values for the various baud rates}
  19.  {supported by the 8250. Rates from 50..9600}
  20.  
  21.  BaudRate: ARRAY[1..15] OF Integer =
  22.    ($900,$600,$417,$359,$300,$180,$0C0,$060,
  23.     $040,$03A,$030,$020,$018,$010,$00C);
  24.  
  25.  {8259 registers}
  26.  
  27.  Int_Mask_Reg = $21; {interrupt enable register}
  28.  Int_Cmd_Reg  = $20; {command register}
  29.  End_Int_Cmd  = $20; {end of interrupt cmd}
  30.  
  31.  {offsets from PortAddr for the various}
  32.  {8250 registers}
  33.  
  34.  DLL            = 0;
  35.  DLM            = 1;
  36.  Int_Enable_Reg = 1;
  37.  Int_Id_Reg     = 2;
  38.  LineControl    = 3;
  39.  ModemControl   = 4;
  40.  LineStatus     = 5;
  41.  ModemStatus    = 6;
  42.  
  43.  {Status bit definitions}
  44.  
  45.  DataRdyBit     = $01;
  46.  DTRBit         = $01;
  47.  Out2Bit        = $08;
  48.  ORBit          = $01;
  49.  RTSBit         = $02;
  50.  PEBit          = $02;
  51.  FEBit          = $04;
  52.  BrkBit         = $08;
  53.  CTSBit         = $10;
  54.  DSRBit         = $20;
  55.  TxRdyBit       = $20;
  56.  RIBit          = $40;
  57.  CDBit          = $80;
  58.  
  59. TYPE
  60.  
  61.  ParityType = (odd,even,none);
  62.  
  63. VAR
  64.  
  65.  {Global storage of COM parameters}
  66.  {Used by the SetNewCOMParameter}
  67.  {procedure}
  68.  
  69.  COM_Rate,
  70.  COM_StopBits,
  71.  COM_DataBits:  Integer;
  72.  COM_Parity:    ParityType;
  73.  
  74.  
  75. {************** Serial Procedures ***************}
  76.  
  77. PROCEDURE Enable_Serial_Device (PortAddr:Integer);
  78.  
  79. VAR
  80.  
  81.  Temp:   Byte;
  82.  
  83. BEGIN
  84.  
  85.    {clear the 8250 serial device of any garbage}
  86.    {by reading data port, int id reg. line}
  87.    {status reg and modem status reg}
  88.  
  89.     Temp := port[PortAddr];
  90.     Temp := port[PortAddr+Int_Id_Reg];
  91.     Temp := port[PortAddr+LineStatus];
  92.     Temp := port[PortAddr+ModemStatus];
  93.  
  94.     {read 8259 int mask reg and set IRQ3 or IRQ4}
  95.     {low to enable requested interrupts.}
  96.     {write result back to 8259 when finished}
  97.  
  98.     Temp := port[Int_Mask_Reg];
  99.     IF PortAddr = COM1 THEN
  100.        Temp := Temp AND $EF
  101.     ELSE
  102.        Temp := Temp AND $F7;
  103.     port[Int_Mask_Reg] := Temp;
  104.  
  105.     {Out2, DTR and RTS high for 8250}
  106.     port[PortAddr+ModemControl] :=
  107.          Out2Bit + DTRBit + RTSBit;
  108.  
  109.     {all ints active except Tx}
  110.     port[PortAddr+Int_Enable_Reg] := $0D;
  111.     delay(100);
  112.  
  113. END;
  114.  
  115.  
  116. PROCEDURE Disable_Serial_Devices;
  117.  
  118. VAR
  119.  
  120.  Temp:   Byte;
  121.  
  122. BEGIN
  123.  
  124.    {Read int mask in 8259, set both IRQ3}
  125.    {and IRQ4 bits high to disable. Set Out2}
  126.    {low for both COM1 and COM2 to prevent ints}
  127.    {from leaving the async card and finally}
  128.    {disable all interrupt sources in the UART}
  129.  
  130.    Temp := port[Int_Mask_Reg];
  131.    Temp := Temp OR $18;
  132.    port[Int_Mask_Reg] := Temp;
  133.    port[COM1+ModemControl] := 0;
  134.    port[COM2+ModemControl] := 0;
  135.    port[COM1+Int_Enable_Reg] := 0;
  136.    port[COM2+Int_Enable_Reg] := 0;
  137.  
  138. END;
  139.  
  140.  
  141. PROCEDURE COM1_ISR;
  142.  
  143. {COM1 interrupt service routine}
  144.  
  145. VAR
  146.  
  147.  SerialInfo:  DataRec;
  148.  
  149.  Temp:        Integer;
  150.  
  151.  LineState,
  152.  ModemState:  Byte;
  153.  
  154. BEGIN
  155.  
  156.    {read linestatus and modem status and}
  157.    {combine into COM1_Status. See text for}
  158.    {bit encoding.}
  159.  
  160.    LineState := port[COM1+LineStatus];
  161.    ModemState:= port[COM1+ModemStatus];
  162.    Temp := (LineState SHR 1) AND $0F;
  163.  
  164.    {COM1_Status has the UART state in 8 bits}
  165.    {this is comprised of status info only, no data}
  166.  
  167.    COM1_Status := (ModemState AND $F0) OR lo(Temp);
  168.  
  169.    {if there is data to receive and we are}
  170.    {acquiring data}
  171.  
  172.    IF (((LineState AND DataRdyBit) <> 0) AND
  173.          COM1_Data_Acquire) THEN
  174.    BEGIN
  175.       {if there is room in the COM1 input fifo}
  176.       IF COM1_Input_Fifo.Ovd.Count <
  177.                     SerialDataFifoSize THEN
  178.       BEGIN
  179.          {Put received data and status into fifo}
  180.          SerialInfo.Data   := port[COM1];
  181.          SerialInfo.Status := COM1_Status;
  182.          PutSerialData(SerialInfo,COM1_Input_Fifo);
  183.       END
  184.       ELSE
  185.       BEGIN
  186.          writeln('COM1 Input fifo overflowed');
  187.          halt;
  188.      END;
  189.    END;
  190.  
  191.    {signal end of int to 8259}
  192.    port[Int_Cmd_Reg] := End_Int_Cmd;
  193.  
  194. END;
  195.  
  196.  
  197. PROCEDURE COM2_ISR;
  198.  
  199. {COM2 interrupt service routine}
  200.  
  201. VAR
  202.  
  203.  SerialInfo:  DataRec;
  204.  
  205.  Temp:        Integer;
  206.  
  207.  LineState,
  208.  ModemState:  Byte;
  209.  
  210. BEGIN
  211.  
  212.    {read linestatus and modem status and}
  213.    {combine into COM2_Status. See text for}
  214.    {bit encoding.}
  215.  
  216.    LineState := port[COM2+LineStatus];
  217.    ModemState:= port[COM2+ModemStatus];
  218.    Temp := (LineState SHR 1) AND $0F;
  219.  
  220.    {COM2_Status has the UART state in 8 bits}
  221.    {this is comprised of status info only, no data}
  222.  
  223.    COM2_Status := (ModemState AND $F0) OR lo(Temp);
  224.  
  225.    {if there is data to receive and we are}
  226.    {acquiring data}
  227.  
  228.    IF (((LineState AND DataRdyBit) <> 0) AND
  229.          COM2_Data_Acquire) THEN
  230.    BEGIN
  231.       {if there is room in the COM2 input fifo}
  232.       IF COM2_Input_Fifo.Ovd.Count <
  233.                     SerialDataFifoSize THEN
  234.       BEGIN
  235.         {Put received data and status into fifo}
  236.         SerialInfo.Data   := port[COM2];
  237.         SerialInfo.Status := COM2_Status;
  238.         PutSerialData(SerialInfo,COM2_Input_Fifo);
  239.       END
  240.       ELSE
  241.       BEGIN
  242.          writeln('COM2 Input fifo overflowed');
  243.          halt;
  244.       END;
  245.    END;
  246.  
  247.    {signal end of int to 8259}
  248.    port[Int_Cmd_Reg] := End_Int_Cmd;
  249.  
  250. END;
  251.  
  252.  
  253. PROCEDURE COM1_Int_Service_Routine;
  254.  
  255. BEGIN
  256.  
  257.  INLINE($50/$53/$51/$52/$57/   {Push ax,bx,cx,dx,}
  258.         $56/$06/$1e/           {di,si,es,ds}
  259.         $2e/$a1/turbodseg/     {mov ax,cs:turbodseg}
  260.         $8e/$d8/               {mov ds,ax}
  261.         $fb);                  {sti}
  262.  
  263.  COM1_ISR;
  264.  
  265.  {standard interrupt service routine postamble}
  266.  
  267.  INLINE($fa/$1f/$07/$5e/$5f/   {interrupts off}
  268.         $5a/$59/$5b/$58/       {Pop ds,es,si,di,}
  269.                                {dx,cx,bx,ax}
  270.         $5d/$5d/$cf);          {trash sp, restore}
  271.                                {Bp and iret}
  272.  
  273. END;
  274.  
  275.  
  276. PROCEDURE COM2_Int_Service_Routine;
  277.  
  278. BEGIN
  279.  
  280.  INLINE($50/$53/$51/$52/$57/   {Push ax,bx,cx,dx,}
  281.         $56/$06/$1e/           {di,si,es,ds}
  282.         $2e/$a1/turbodseg/     {mov ax,cs:turbodseg}
  283.         $8e/$d8/               {mov ds,ax}
  284.         $fb);                  {sti}
  285.  
  286.  COM2_ISR;
  287.  
  288.  {standard interrupt service routine postamble}
  289.  
  290.  INLINE($fa/$1f/$07/$5e/$5f/   {interrupts off}
  291.         $5a/$59/$5b/$58/       {Pop ds,es,si,di,}
  292.                                {dx,cx,bx,ax}
  293.         $5d/$5d/$cf);          {trash sp, restore}
  294.                                {Bp and iret}
  295.  
  296. END;
  297.  
  298.  
  299.  
  300. PROCEDURE Install_Serial_Handlers;
  301.  
  302. BEGIN
  303.  
  304.  WITH regs DO      {install into IRQ3 & 4}
  305.  BEGIN
  306.     ah := $35;       {get vector func. code}
  307.     al := $0B;       {for IRQ3}
  308.     msdos(regs);     {call dos to get vector}
  309.     OldIRQ3_CS := es;{save code seg}
  310.     OldIRQ3_IP := bx;{and instruction ptr}
  311.  
  312.     ah := $35;       {get vector func. code}
  313.     al := $0C;       {for IRQ4}
  314.     msdos(regs);     {call dos to get vector}
  315.     OldIRQ4_CS := es;{save code seg}
  316.     OldIRQ4_IP := bx;{and instruction ptr}
  317.  
  318.     ah := $25;       {set vector func. code}
  319.     al := $0C;       {for IRQ4}
  320.     ds := cseg;      {code in our segment}
  321.                      {at this offset}
  322.     dx := ofs(COM1_Int_Service_Routine);
  323.     msdos(regs);     {call dos to set vector}
  324.  
  325.     ah := $25;       {set vector func. code}
  326.     al := $0B;       {for IRQ3}
  327.     ds := cseg;      {code in our segment}
  328.                      {at this offset}
  329.     dx := ofs(COM2_Int_Service_Routine);
  330.     msdos(regs);     {call dos to set vector}
  331.  
  332.  END;
  333. END;
  334.  
  335.  
  336. PROCEDURE Remove_Serial_Handlers;
  337.  
  338. BEGIN
  339.    {Put saved vectors for IRQ3 and IRQ4 back}
  340.    WITH regs DO
  341.    BEGIN
  342.       ah := $25;
  343.       al := $0C;
  344.       ds := OldIRQ4_CS;
  345.       dx := OldIRQ4_IP;
  346.       msdos(regs);
  347.  
  348.       ah := $25;
  349.       al := $0B;
  350.       ds := OldIRQ3_CS;
  351.       dx := OldIRQ3_IP;
  352.       msdos(regs);
  353.    END;
  354.  
  355. END;
  356.  
  357.  
  358. PROCEDURE Set_Serial_Parameters
  359.      (PortAddr,Baud,StopBits,DataBits:Integer;
  360.       Parity: ParityType);
  361. VAR
  362.  
  363.  Temp,
  364.  Rate:   Integer;
  365.  
  366. BEGIN
  367.  
  368.    {set DLAB high for divisor regs}
  369.    port[PortAddr+LineControl] := $80;
  370.  
  371.    {look up rate word in table}
  372.    Rate := BaudRate[Baud];
  373.  
  374.    {MSB into most sign divisor reg}
  375.    port[PortAddr+DLM] := hi(Rate);
  376.  
  377.    {LSB into less sign divisor reg}
  378.    port[PortAddr+DLL] := lo(Rate);
  379.  
  380.    {move databits into 2 least sign bits}
  381.    {add in stop bit into bit pos 2}
  382.    {set parity enable and parity even}
  383.    {bits if appropriate}
  384.  
  385.    Temp := (DataBits - 5) AND $03;
  386.    Temp := Temp OR ((StopBits - 1) SHL 2);
  387.    CASE Parity OF
  388.      odd:  Temp := Temp + $08;
  389.     even: Temp := Temp + $18;
  390.     none: ;
  391.    END;
  392.  
  393.    {remove DLAB and setup parameters}
  394.    port[PortAddr+LineControl] := lo(Temp);
  395.    delay(100);
  396.  
  397. END;
  398.  
  399.  
  400. FUNCTION Get_Serial_Status (PortAddr:Integer)
  401.               :Integer;
  402.  
  403. VAR
  404.  
  405.  Temp:  Integer;
  406.  
  407. BEGIN
  408.  
  409.    {Get full 16 bits of COM port status}
  410.    {grouped as ModemStatus:LineStatus}
  411.  
  412.    Temp := port[PortAddr+ModemStatus];
  413.    Temp := Temp SHL 8;
  414.    Temp := Temp OR port[PortAddr+LineStatus];
  415.    Get_Serial_Status := Temp;
  416.  
  417. END;
  418.  
  419.  
  420. PROCEDURE SetNewCOMParameter;
  421.  
  422. BEGIN
  423.  
  424.    {take the COM ports down}
  425.    Disable_Serial_Devices;
  426.  
  427.    {Set the COM ports to the global parameters}
  428.  
  429.    Set_Serial_Parameters(COM1,COM_Rate,
  430.           COM_StopBits,COM_DataBits,COM_Parity);
  431.    Set_Serial_Parameters(COM2,COM_Rate,
  432.           COM_StopBits,COM_DataBits,COM_Parity);
  433.  
  434.    {bring COM ports back up}
  435.    Enable_Serial_Device(COM1);
  436.    Enable_Serial_Device(COM2);
  437.  
  438. END;
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.                                        
  484.  
  485.