Writing FCode 2.x Programs
この本のみを検索
PDF 文書ファイルをダウンロードする

Serial Devices

10

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( -- )

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( adr len -- actual )

Read len bytes of data from the device into memory starting at adr. 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( -- )

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( adr len -- actual )

Write len bytes of data to the device from memory starting at adr. Return the number of bytes actually written, actual.

Required Properties

The standard properties of a serial driver are:
Table 10-1
Property NameValue
name" SUNW,thingy"
reg{ device-dependent}
device_type" serial"

Device Driver Examples

The three examples that follow 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


  fcode-version1  
     hex  
     " SUNW,zs"           name  
     my-address 10.0000 + my-space 8 reg  
     7 xdrint             " interrupts"  attribute  
     7 0 intr  
  end0  

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   ( adr len -- #read )  
  \  Reads "len" number of characters from the selected port,  
  \    and store them at "adr".  
  \ - write  ( adr len -- #written )  
  \  Writes "len" number of characters from the buffer located  
  \      at "adr" to the selected serial port.  
  
  fcode-version2  
  hex  
  
     my-address 10.0000 + constant phys-addr  
     my-space   constant  my-sbus-space  
     my-address constant  my-sbus-address  
  
     " SUNW,zs"                name  
     phys-addr my-sbus-space 8 reg  
     7 xdrint " interrupts"    attribute  
     7 0                  intr  
  
     : >phys-adr  ( offset -- adr space )  
       my-sbus-address +  my-sbus-space  
     ;  
     : do-map-in  ( offset size -- va )  
       >r >phys-adr r>  " map-in" $call-parent  
     ;  
     : do-map-out ( va size -- )  " map-out" $call-parent  ;  


  \ Extended Serial FCode Program  
     : rc! c! ;  
     : rc@ c@ ;  
     : /string  ( adr len n -- adr+n len-n )  tuck  -  -rot  +  swap  ;  
  
     1 constant RXREADY  \ received character available  
     4 constant TXREADY  \ transmit buffer empty  
  
    : instance  ( -- )   \ verify that "instance" is defined  
      ['] instance ['] ferror < > if  
          instance  
      then  
    ;  
  
     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 + is uart  ;  
     : useb   ( -- )    uartbase is uart  ;  
     : uctl!  ( c -- )  uart  rc!  ;  
     : uctl@  ( -- c )  uart  rc@  ;  
  
     \ The following line assumes that A1 chooses the command vs. data port  
     : udata!  ( c -- )  uart  2 + rc!  ;  
     : udata@  ( -- c )  uart  2 + rc@  ;  
  
     \ 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@  ;  


  \ Extended Serial FCode Program  
  
     : uwrite              ( adr len -- #written )  
        tuck  bounds ?do   ( len )  
        i c@  uemit        ( len )  
        loop               ( len )  
     ;  
     : uread  ( adr len -- #read )              \ -2 for none available right now  
        ukey? 0=  if  2drop -2  exit  then      ( adr len )  
        tuck                                    ( len adr len )  
        begin  dup 0<>   ukey? 0<>  and  while  ( len adr len )  
          over  ukey mask-#data and swap c!     ( len adr len )  
          1 /string                             ( len adr' len' )  
        repeat                                  ( len adr' len' )  
        nip -                                   ( #read )  
     ;  
  
  external  
     : read   ( adr len -- #read )     uread   ;  
     : write  ( adr len -- #written )  uwrite  ;  
  
  end0  

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  
  
     my-address 10.0000 +      constant  phys-adr  
     my-space                  constant  my-sbus-space  
     my-address                constant  my-sbus-address  
     " SUNW,zs"                name  
     phys-addr my-sbus-space 8 reg  
     7 xdrint " interrupts" attribute  
     7 0                  intr  
     " serial"            device-type  
  
     : >phys-adr  ( offset -- adr space )  
          my-sbus-address +  my-sbus-space  
     ;  
     : do-map-in  ( offset size -- va )  
          >r >phys-adr r>  " map-in" $call-parent  
     ;  
     : do-map-out ( va size -- )  " map-out" $call-parent  ;  
     : rc! c! ;  
     : rc@ c@ ;  
     : /string  ( adr len n -- adr+n len-n )  tuck  -  -rot  +  swap  ;  


  \ Complete Serial driver.  
    : instance  ( -- )   \ verify that "instance" is defined  
      ['] instance ['] ferror < > if  
          instance  
      then  
    ;  
     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  
  \----------------------------------------------------------------------------  
  \ ttydriver.fth - Driver for Zilog 8530 SCC (UART) chips.  
  hex  
  0 instance value uartbase  


  \ Complete Serial driver.  
  
  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 + is uart  ;  
     : useb   ( -- )    uartbase is uart  ;  
     : uctl!  ( c -- )  uart  rc!  ;  
     : uctl@  ( -- c )  uart  rc@  ;  
  
     \ The following line assumes that A1 chooses the command vs. data port  
     : udata!  ( c -- )  uart  2 + rc!  ;  
     : udata@  ( -- c )  uart  2 + rc@  ;  
  
     \ 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<>  ;  
  
     \ Clear the break flag  
     : clear-break  ( -- )  
        begin  ubreak? 0=  until  \ Let break finish  
        udata@ drop               \ Eat the null character  
        30 uctl!                  \ Reset errors  


  \ Complete Serial driver.  
     ;  
  
     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  ( adr len -- #written )  
        tuck  bounds ?do   ( len )  
          i c@  uemit      ( len )  
        loop               ( len )  
     ;  
     : uread  ( adr len -- #read )              \ -2 for none available right now  
        ukey? 0=  if  2drop -2  exit  then      ( adr len )  
        tuck                                    ( len adr len )  
        begin  dup 0<>   ukey? 0<>  and  while  ( len adr len )  
          over  ukey mask-#data and swap c!     ( len adr len )  
          1 /string                             ( len adr' len' )  
        repeat                                  ( len adr' len' )  
        nip -                                   ( #read )  
     ;  
  
     : poll-tty  ( -- )  
        ttylock @ if  exit  then  
        ubreak?  if  clear-break  user-abort  then  
     ;  
  
  external  
     : open  ( -- okay? )  
        phys-adr 8 do-map-in is uartbase  
        usea  
        my-args                               ( arg-str )  
        ascii ,  left-parse-string  if        ( rem adr )  
          c@  ascii b  =  if                  ( rem )  
            2drop                             ( )  
            useb                              ( )  
          then                                ( rem )  
          else                                ( rem adr )  
            drop 2drop                        ( )  


  \ Complete Serial driver.  
        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       ( adr )  
          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   ( adr len -- #read )     uread   ;  
     : write  ( adr 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