Writing FCode 3.x Programs
  Cerca solo questo libro
Scarica il manuale in formato PDF

Serial Devices

10

This chapter describes programming requirements for serial devices, and gives examples of serial device drivers. Serial devices are byte-oriented, sequentially-accessed devices such as asynchronous communication lines (often attached to a dumb terminal).

Required Methods

The serial device driver must declare the serial device type, and must implement the methods open and close, as well as the following:

install-abort

stack: ( -- )
Instruct the driver to begin periodic polling for a keyboard abort sequence. install-abort is executed when the device is selected as the console input device.

read

stack: ( addr len -- actual )
Read len bytes of data from the device into memory starting at addr. Return the number of bytes actually read, actual, or -2 if no bytes are currently available from the device. -1 is returned if other errors occur.

remove-abort

stack: ( -- )
Instruct the driver to cease periodic polling for a keyboard abort sequence. remove-abort is executed when the console input device is changed from this device to another.

write

stack: ( addr len -- actual )
Write len bytes of data to the device from memory starting at addr. Return the number of bytes actually written, actual.

Required Properties

These are the standard properties of a serial driver:
Table 10-1
Property Name
Value
name" SUNW,zs"
reglist of registers {device-dependent}
device_type" serial"

Device Driver Examples

The following three examples are serial device drivers for the Zilog 8530 SCC (UART) chip.
  • The first sample is a short driver which simply creates a device node and declare the properties for the device.
  • The second sample is a more sophisticated driver that defines methods to control and access the device.
  • The third sample shows the complete serial device driver.

Simple Serial FCode Program


  \ This driver creates a device node and publishes the minimum required set of  
  \ properties.  
  fcode-version1  
     hex  
     " SUNW,zs" name  
     my-address 10.0000 + my-space 8 reg  
     7 encode-int " interrupts"  property  
  end0  

Extended Serial FCode Program

Code Example 10 Extended Serial FCode Program

  \ Extended Serial FCode Program  
  \ In addition to publishing the properties, this sample driver  
  \ provides methods to access and control the serial ports.  
  \  
  \ The following main methods are provided:  
  \ - usea   ( -- )  
  \    Selects serial port A. All subsequent operations will  
  \         be directed to port A  
  \ - useb   ( -- )  
  \         Selects serial port B. All subsequent operations will  
  \         be directed to port B  
  \ - uemit  ( char -- )  
  \ Emits a given character to the selected serial port.  
  \ - ukey   ( -- key )  
  \ Retrieves a character from the selected serial port.  
  \ - read   ( addr len -- #read )  
  \  Reads "len" number of characters from the selected port,  
  \    and store them at "addr".  
  \ - write  ( addr len -- #written )  
  \  Writes "len" number of characters from the buffer located  
  \      at "addr" to the selected serial port.  
  
  fcode-version2  
  hex  
  
     " SUNW,zs" name  
     my-address 10.0000 + my-space 8 reg  
     7 encode-int " interrupts"    property  
  
     : >phys-addr  ( offset -- phys.lo phys.mid phys.hi )  
       >r my-address r> 0 d+  my-space  
     ;  
     : do-map-in  ( offset size -- virt )  
       >r >phys-addr r>  " map-in" $call-parent  
     ;  
     : do-map-out ( virt size -- )  " map-out" $call-parent  ;  
  
     : /string  ( addr len n -- addr+n len-n )  tuck  -  -rot  +  swap  ;  
  
     1 constant RXREADY  \ received character available  
     4 constant TXREADY  \ transmit buffer empty  

Code Example 10 Extended Serial FCode Program (Continued)

  \ Extended Serial FCode Program  
     0 instance value  uart              \ define uart as an "per-instance" value.  
     0 instance value  uartbase  
     h# ff instance value  mask-#data    \ mask for #data bits  
     h# 10 instance buffer: mode-buf  
  
     \ The following line assumes that A2 selects the channel within the chip  
     : usea   ( -- )    uartbase 4 + to uart  ;  
     : useb   ( -- )    uartbase to uart  ;  
     : uctl!  ( c -- )  uart  rb!  ;  
     : uctl@  ( -- c )  uart  rb@  ;  
  
     \ The following line assumes that A1 chooses the command vs. data port  
     : udata!  ( c -- )  uart  2 + rb!  ;  
     : udata@  ( -- c )  uart  2 + rb@  ;  
  
     \ Test for "break" character received.  
     : ubreak?  ( -- flag )  10 uctl!  uctl@  h# 80 and  0<>  ;  
  
     \ Clear the break flag  
     : clear-break  ( -- )  
        begin  ubreak? 0=  until    \ Let break finish  
        udata@ drop                 \ Eat the null character  
        30 uctl!                    \ Reset errors  
     ;  
  
     : uemit? ( -- flag )  uctl@ TXREADY and  ;  
     : uemit  ( char -- )  begin  uemit?  until  udata!  ;  
  
     : ukey? ( -- flag )  uctl@ RXREADY and  ;  
     : ukey  ( -- key )   begin  ukey?  until  udata@  ;  
  
     : uwrite              ( addr len -- #written )  
        tuck  bounds ?do   ( len )  
           i c@  uemit     ( len )  
        loop               ( len )  
     ;  
  
     : uread  ( addr len -- #read )             \ -2 for none available right now  
        ukey? 0=  if  2drop -2  exit  then      ( addr len )  
        tuck                                    ( len addr len )  
        begin  dup 0<>   ukey? 0<>  and  while  ( len addr len )  

Code Example 10 Extended Serial FCode Program (Continued)

  \ Extended Serial FCode Program  
           over  ukey mask-#data and swap c!    ( len addr len )  
           1 /string                            ( len addr' len' )  
        repeat                                  ( len addr' len' )  
        nip -                                   ( #read )  
     ;  
  
  external  
     : read   ( addr len -- #read )     uread   ;  
     : write  ( addr len -- #written )  uwrite  ;  
  
  end0  

Complete Serial FCode Program

Code Example 11 Complete Serial FCode Program

  \ Complete Serial driver.  
  \ In addition to the methods defined in the above driver sample,  
  \ this version defines more methods to initialize, test, and access  
  \ the serial ports.  
  \ The new main methods are:  
  \ - inituarts      ( -- )  
  \    Initializes both serial ports A and B.  
  \ - open           ( -- okay? )  
  \    Maps in the uart chip.  Selects port A on default, then check  
  \    my-args, if port B was specified, then selects port B instead.  
  \ - close          ( -- )  
  \    Unmap the uart chip.  
  \ - selftest       ( -- )  
  \    Performs selftest on both Port A and B.  
  \ - install-abort  ( -- )  
  \    Sets up alarm to do poll-tty every 10 miliseconds.  
  \ - remove-abort   ( -- )  
  \    Removes the poll-tty alarm.  
  
  fcode-version2  
  hex  
  
     " SUNW,zs" name  
     my-address 10.0000 + my-space 8 reg  
     7 encode-int " interrupts" property  
     " serial" device-type  

Code Example 11 Complete Serial FCode Program (Continued)

  \ Complete Serial driver.  
     : >phys-addr  ( offset -- phys.lo phys.mid phys.hi )  
       >r my-address r> 0 d+  my-space  
     ;  
     : do-map-in  ( offset size -- virt )  >r >phys-addr r>  " map-in" $call-parent  ;  
     : do-map-out ( virt size -- )  " map-out" $call-parent  ;  
     : /string  ( addr len n -- addr+n len-n )  tuck  -  -rot  +  swap  ;  
     fload inituarts.fth  
     fload ttydriver.fth  
  end0  
  \----------------------------------------------------------------------------  
  \ inituarts.fth  
  hex  
  headerless  
  create uart-init-table  
  \ 9 c, c0 c,    \ Master reset channel a (80), channel b (40)  
   9 c,  2 c,     \ Don't respond to intack cycles (02)  
   4 c, 44 c,     \ No parity (00), 1 stop bit (04), x16 clock (40)  
   3 c, c0 c,     \ receive 8 bit characters (c0)  
   5 c, 60 c,     \ transmit 8 bits (60)  
   e c, 82 c,     \ Processor clock is baud rate source (02)  
   b c, 55 c,     \ TRxC = xmit clk (01), enable TRxC (04), Tx clk is baud (10),  
                  \ Rx clk is baud (40)  
   c c,  e c,     \ Time constant low  
   d c,  0 c,     \ Time constant high  
   3 c, c1 c,     \ receive 8 bit characters (c0), enable (01)  
   5 c, 68 c,     \ transmit 8 bits (60), enable (08)  
   e c, 83 c,     \ Processor clock is baud rate source (02), Tx enable (01)  
   0 c, 10 c,     \ Reset status bit latches  
  ff c, ff c,     \ Mark end of data  
  \----------------------------------------------------------------------------  

Code Example 11 Complete Serial FCode Program (Continued)

  \ Complete Serial driver.  
  \ ttydriver.fth - Driver for Zilog 8530 SCC (UART) chips.  
  
  hex  
  0 instance value uartbase  
  
  create default-mode  
  \   0      1      2      3      4      5      6      7  
     00 c,  00 c,  00 c,  c1 c,  44 c,  68 c,  00 c,  00 c,  
  
  \   8      9      a      b      c      d      e      f  
     00 c,  02 c,  00 c,  55 c,  0e c,  00 c,  83 c,  00 c,  
  
         0 instance value  uart        \ define uart as an "per-instance" value.  
     h# ff instance value  mask-#data  \ mask for #data bits  
     h# 10 instance buffer: mode-buf  
  
     create masks   1f c,  7f c,  3f c,  ff c,  
  
     \ The following line assumes that A2 selects the channel within the chip  
     : usea   ( -- )    uartbase 4 + to uart  ;  
     : useb   ( -- )    uartbase to uart  ;  
     : uctl!  ( c -- )  uart  rb!  ;  
     : uctl@  ( -- c )  uart  rb@  ;  
  
     \ The following line assumes that A1 chooses the command vs. data port  
     : udata!  ( c -- )  uart  2 + rb!  ;  
     : udata@  ( -- c )  uart  2 + rb@  ;  
  
     \ Write all the initialization sequence to both uarts  
     : inituart  ( -- )  
        uart-init-table  
        begin   dup c@ ff <>  while  
           dup c@ uctl!  dup ca1+ c@ uctl!  
           /c 2* +  
        repeat  
        drop  
     ;  
  
     : inituarts  ( -- )   usea inituart   useb inituart  usea  ;  
  
     \ Test for "break" character received.  
     : ubreak?  ( -- break? )  10 uctl!  uctl@  h# 80 and  0<>  ;  

Code Example 11 Complete Serial FCode Program (Continued)

  \ Complete Serial driver.  
     \ Clear the break flag  
     : clear-break  ( -- )  
        begin  ubreak? 0=  until  \ Let break finish  
        udata@ drop               \ Eat the null character  
        30 uctl!                  \ Reset errors  
     ;  
  
     1 constant RXREADY           \ received character available  
     4 constant TXREADY           \ transmit buffer empty  
  
     : uemit? ( -- emit? ) uctl@ TXREADY and  ;  
     : uemit ( char -- )  begin  uemit?  until  udata!  ;  
  
     : ukey? ( -- key? )  uctl@ RXREADY and  ;  
     : ukey  ( -- key )  begin  ukey?  until  udata@  ;  
  
     : uwrite  ( addr len -- #written )  
        tuck  bounds ?do   ( len )  
           i c@  uemit     ( len )  
        loop               ( len )  
     ;  
  
     : uread  ( addr len -- #read )             \ -2 for none available right now  
        ukey? 0=  if  2drop -2  exit  then      ( addr len )  
        tuck                                    ( len addr len )  
        begin  dup 0<>   ukey? 0<>  and  while  ( len addr len )  
           over  ukey mask-#data and swap c!    ( len addr len )  
           1 /string                            ( len addr' len' )  
        repeat                                  ( len addr' len' )  
        nip -                                   ( #read )  
     ;  
     : poll-tty  ( -- )  
        ttylock @ if  exit  then  
        ubreak?  if  clear-break  user-abort  then  
     ;  
  
  external  
     : open  ( -- okay? )  
        phys-addr 8 do-map-in to uartbase  
        usea  
        my-args                               ( arg-str )  
        ascii ,  left-parse-string  if        ( rem addr )  
           c@  ascii b  =  if                 ( rem )  

Code Example 11 Complete Serial FCode Program (Continued)

  \ Complete Serial driver.  
              2drop                           ( )  
              useb                            ( )  
           then                               ( rem )  
        else                                  ( rem addr )  
              drop 2drop                      ( )  
        then                                  ( )  
  
        true  
     ;  
  
     : close  ( -- )  uartbase 8 do-map-out  ;  
  
  headers  
     : utest  ( -- 0 )  h# 7f  bl  ?do  i uemit  loop 0  ;  
  
  external  
     : selftest  ( -- error? )  
        open  0=  if  ." Can't open device" true exit  then  
        my-args  if       ( addr )  
           c@  case  
              ascii a  of usea  endof  
              ascii b  of useb  endof  
              ( default ) ." Bad zs port letter" drop false exit  
           endcase  
        else  \ No port letter so test both ports.  
           drop  
           usea utest  
           useb utest  
           or close exit       ( fail? )  
        then  
        utest                  ( fail? )  
        close  
     ;  
     : read   ( addr len -- #read )     uread   ;  
     : write  ( addr len -- #written )  uwrite  ;  
     : install-abort  ( -- )  ['] poll-tty d# 10 alarm  ;  
     : remove-abort   ( -- )  ['] poll-tty 0 alarm  ;  
  
     \ "seek" might be implemented to select a load file name  
     \ Implement "load" ( optional )  
  headers