 sttl IOP Commands & Responses
 pag

*
*  The IOP (Input/Output Processor) communicates with the
*  system CPU via the FIO Mailbox.  All commands take the
*  general shape of:
*     1 - CPU sends basic command in mailbox
*     2 - IOP consumes command, along with any additional
*         data needed by the command.  This additional
*         data is passed in the FIFO and its form is
*         documented elsewhere.
*     3 - IOP performs the desired function.
*     4 - IOP returns a response code to the system CPU,
*         indicating the success/failure of the command.
*
*  The basic command byte is structured as follows:
*
*            +------------+------+------+
*            | n  n  n  n | x  x | t  t |
*            +------------+------+------+
*
*            +--------------------------+
*            | s  s  s  s   s  s   s  s |
*            +--------------------------+
*
*  Where:
*    nnnn - A four bit command number
*      xx - Two don't care bits
*      tt - The port # for the operation
*    ssss - An sixteen bit sequence # for the operation
*
*
*  Response codes are also an 16 bit value as follows:
*
*            +---+---------------------+
*            | E |      code           |
*            +---+---------------------+
*
*            +--------------------------+
*            | s  s  s  s   s  s   s  s |
*            +--------------------------+
*
*  Where:
*       E - Error indicator.  Set if the operation was not
*           completed as desired.
*    code - A function specific value if E is zero, otherwise
*           the reason the operation was in error.
*    ssss - The matching sequence # for this operation.
*

 lib fio_codes

 sttl IO Command Handler
 pag

*
* IO_han - I/O Command Handler
*   This routine comprises the main processing loop
* for each task in the system.  Whenever an I/O command
* is detected (via the message interrupt), a task will
* be scheduled to process it.  This is that task.
*   The command is saved in the "tscmd" field of the
* task control block.
*

 if DEBUG&DBG_CMD
00 fcc $d,'Task $',0
01 fcc ', Command $',0
02 fcc "/",0
 endif
IO_han clri allow interrupts
 ldx utask get task control block address
 lda tscmd,x get I/O command
 if DEBUG&DBG_CMD
 pshs d,x
 ldx #00b
 jsr DB_pdata
 ldd 2,s
 jsr DB_phex2
 ldx #01b
 jsr DB_pdata
 lda 0,s
 jsr DB_phex
 ldx #02b
 jsr DB_pdata
 ldx utask
 ldd tsseq,x
 jsr DB_phex2
 puls d,x
 endif
 lsra isolate command
 lsra
 lsra
 lsra
 ldy #IO_tbl processing table
 lsla -- word index
 ldy a,y get processor address
 ldb tscmd,x restore command
 andb #$03 isolate device #
 clra
 cmpb #3 check for legal device #
 bne 10f jump if OK
 ldb #E_BADDEV return illegal device error
 bra 20f exit
10 ldx #IO_end interrupt handler address
 pshs x
 ldx utask
 sts umark1,x
 jsr 0,y perform operation & return status
 leas 2,s clean up stack
20 jsr fio_response
IO_end seti mask interrupts
 ldx utask restore task control block address
 sta tstval,x remember transaction value sent
 stb tscmd,x and command response
 lda #TFREE mark task "terminated & free"
 sta tsstat,x
 lda #$FF disassociate from any terminal
 sta tsdev,x
 clr tssgnl,x no waiting signals
 jsr rsched run other tasks
 bra IO_han

*
* Illegal command
*
bad_cmd
 ldb #E_BADCMD error code
 rts

*
* open_tty - Perform device open
*
open_tty
 jsr ttopn perform tty open
 if DEBUG&DBG_IO
 lbsr dmp_TTY
 endif
 ldb #R_OPEN
 rts

*
* close_tty - Perform device close
*
close_tty
 jsr ttcls perform tty close
 if DEBUG&DBG_IO
 lbsr dmp_TTY
 endif
 ldb #R_CLOSE
 rts

*
* req_write - Request permission to write data
*
req_write
 jsr ttftab get TTY table
 if DEBUG&DBG_IO
 bsr dmp_TTY dump TTY Table
 endif
 pshs cc mask interrupts while fiddling
10 seti
 ldy tqout,x get output queue pointer
 ldd oq_count,y get queue length
 addd tsold,x include any space already sold
 addd #FIFO_SIZE and assume the CPU will send this many more
 cmpd #OQHI space available?
 ble 20f yes - OK
 lda tdelay,x special flush bit?
 bita #$40
 beq 15f no - go to sleep
 jsr flusho yes - flush output
 bra 10b try again
15 pshs d,x,y,u no - save registers
 ldb #TTYSPR
 jsr sleep
 puls d,x,y,u restore registers
 bra 10b try again
*
* The following check for "dead" is necessary because
* since interrupts are asynchronous.  This means that
* a task [at the UniFLEX end] could be in the process
* of sending a "request space" message at the instant
* that an "interrupt all tasks on a terminal" message
* comes through.  If the first message is received by
* the IOP but not processed [completely] until the
* second message is [The request message is received and
* a task dispatched to handle it while the interrupt
* message is being processed] it may be possible to
* have a pending "signal" -- i.e. death, for the "request"
* task.  Since this is only checked in "sleep", the result
* would be to presell some space in the output Q which
* will never be consumed.  After some number of these
* occurences, the terminal would become locked up...
*
20 ldy utask am I supposed to be dead?
 tst tssgnl,y
 bne 30f yes - abort
 ldd tsold,x update amount pre-sold
 addd #FIFO_SIZE -- assume entire FIFO load
 std tsold,x
 ldb #R_REQOK request granted code
 puls cc,pc return
*
30 puls cc clean up stack
 leas 2,s -- pop normal return
 rts abnormal I/O completion (no response)

*
* write_data - Write data to a terminal
*
write_data
 jsr ttftab get tty table pointer
 jsr ttywrt go consume data
 pshs cc save interrupt state
 seti mask interrupts
 ldd tsold,x
 subd #FIFO_SIZE
 bpl 00f
 ldd #0 don't screw up!
00 std tsold,x update count
 ldy tqout,x wake up anybody waiting for space
 if DEBUG&DBG_IO
 pshs d,x,y,u
 ldx #00f
 jsr DB_pdata
 tfr y,d
 jsr DB_phex2
 puls d,x,y,u
 endif
 jsr wakeup
 ldb #R_WRITE
 puls cc,pc return
 if DEBUG&DBG_IO
00 fcc $d,'FIFO consumed, wakeup at $',0
 endif

*
* Write single character
*  -- Character passed via transaction message
*
wrt_sc pshs cc save interrupt state
 jsr ttftab compute tty table address
00 ldy tqout,x output Q pointer
 ldd oq_count,y check for overrun
 cmpd #OQHI
 bls 10f jump if space
 lda tdelay,x special flush bit?
 bita #$40
 beq 05f no - wait for space
 jsr flusho yes - make space!
 bra 00b
05 ldb #TTYOPR wait a while
 jsr sleep
 bra 00b try again
10 ldy utask fetch character
 ldb tstval,y
 jsr ttyout send to output queue
 seti mask interrupts
 jsr ttyst kick output - make sure it starts
 ldb #R_WRITE
 puls cc,pc return

*
* send_int - Interrupt all tasks associated with a terminal
* -- Called directly from interrupt code
*
send_int pshs d,x,y,u
 jsr ttftab get TTY table address
 jsr flusht flush terminal buffers
 ldx #tsktab+(TSKSIZ*2) find all associated tasks
 lda 1,s get terminal #
 ldb #MAX_TSK-2 # tasks in system
10 cmpa tsdev,x task associated with this terminal?
 bne 20f no - continue
 jsr xmtint yes - interrupt him
20 leax TSKSIZ,x next task
 decb any more tasks?
 bne 10b yes - keep going
 puls d,x,y,u clean up stack
 rts


 if DEBUG&DBG_IO
*
* dmp_TTY - dump TTY table
*    X - TTY Table address
*
dmp_TTY pshs d,x,y,u
 tfr x,y
 ldx #00f
 jsr DB_pdata
 ldd 2,s
 jsr DB_phex2
 ldx #01f
 jsr DB_pdata
 lda [tqin,y]
 jsr DB_phex
 ldx #02f
 jsr DB_pdata
 lda [tqout,y]
 jsr DB_phex
 ldx #03f
 jsr DB_pdata
 ldd tstate,y
 jsr DB_phex2
99 puls d,x,y,u,pc
*
00 fcc $d,'TTY Table $',0
01 fcc ', In Q = ',0
02 fcc ', Out Q = ',0
03 fcc ', State = ',0
 endif

*
* I/O Command processing table
*
IO_tbl rmb 0
 fdb bad_cmd  0 -
 fdb open_tty  1 -
 fdb close_tty  2 -
 fdb ttyset  3 -
 fdb ttyget  4 -
 fdb req_write  5 -
 fdb write_data  6 -
 fdb wrt_sc  7 -
 fdb req_read  8 -
 fdb read_data  9 -
 fdb bad_cmd 10 - "send_int" handled directly by interrupt routine!
 fdb bad_cmd 11 -
 fdb bad_cmd 12 -
 fdb bad_cmd 13 -
 fdb bad_cmd 14 -
 fdb bad_cmd 15 -
