view level1/modules/dwio.asm @ 2898:28ed72477814 lwtools-port

Dummy merge of default branch into lwtools hg -y merge --tool=internal:fail default hg revert --all --no-backup --rev . hg resolve -a -m This dummy merge discards any changes from the default branch so that the result is the same as what lwtools already had. When merging back to default branch later, the discarded changes will be discarded there also, so the result will be that the default branch will contain what the lwtools branch had before these merges. Only scripts/burst was "rescued" from default branch.
author Tormod Volden <debian.tormod@gmail.com>
date Sat, 11 Jan 2014 18:40:44 +0100 (2014-01-11)
parents ed9a4cb85fb3 3231faca9642
children e68c1db27cbe
line wrap: on
line source
********************************************************************
* dwio - DriveWire Low Level Subroutine Module
*
* $Id$
*
* Edt/Rev  YYYY/MM/DD  Modified by
* Comment
* ------------------------------------------------------------------
*   1      2008/01/26  Boisy G. Pitre
* Started as a segregated subroutine module.
*
*   2      2010/01/20  Boisy G. Pitre
* Added support for DWNet
*
*   3      2010/01/23  Aaron A. Wolfe
* Added dynamic polling frequency
*
               nam       dwio
               ttl       DriveWire 3 Low Level Subroutine Module

               ifp1      
               use       defsfile
               use       drivewire.d
               endc      

tylg           set       Sbrtn+Objct
atrv           set       ReEnt+rev
rev            set       $01

               mod       eom,name,tylg,atrv,start,0

* irq
IRQPckt        fcb       $00,$01,$0A         ;IRQ packet Flip(1),Mask(1),Priority(1) bytes
* Default time packet
DefTime        fcb       109,12,31,23,59,59

* for dynamic poll frequency, number of ticks between firing poller - should we move to dwdefs?
* speed 1 = interactive (typing)
PollSpd1       fcb       3
* speed 2 = bulk transfer (depending on how much processing needs to be done to incoming stream, 5-8 seems good)
PollSpd2       fcb       6
* speed 3 = idle 
PollSpd3       fcb       40
* X pollidle -> drop to next slower rate
PollIdle       fcb       60


name           fcs       /dwio/

* DriveWire subroutine entry table
start          lbra      Init
               bra       Read
               nop       
               lbra      Write

* Term
*
* Entry:
*    U  = address of device memory area
*
* Exit:
*    CC = carry set on error
*    B  = error code
*
Term                     
               clrb                          clear Carry
               rts       

Read                   
               IFNE      atari
               jmp       [$FFE0]
               ELSE
               use       dwread.asm
               ENDC

Write                    
               IFNE      atari
               jmp       [$FFE2]
               ELSE
               use       dwwrite.asm
               ENDC


               IFNE      atari
DWInit         rts
               ELSE
			use		dwinit.asm
               ENDC
			
* Init
*
* Entry:
*    Y  = address of device descriptor
*    U  = address of device memory area
*
* Exit:
*    CC = carry set on error
*    B  = error code
*
* Initialize the serial device
Init                     
               clrb                          clear Carry
               pshs      y,x,cc              then push CC on stack
               bsr		DWInit

; allocate DW statics page
               pshs      u
               ldd       #$0100
               os9       F$SRqMem
               tfr       u,x
               puls      u
               lbcs      InitEx
               ifgt      Level-1
               stx       <D.DWStat
               else      
               stx       >D.DWStat
               endc      
; clear out 256 byte page at X
               clrb      
loop@          clr       ,x+
               decb      
               bne       loop@

* send OP_DWINIT
         ; setup DWsub command
               pshs      u
               ldb		 #1					 ; DRIVER VERSION
               lda       #OP_DWINIT          ; load command
               pshs      d                   ; command store on stack
               leax      ,s                  ; point X to stack 
               ldy       #2                  ; 1 byte to send
               ifgt      Level-1
               ldu       <D.DWSubAddr
               else      
               ldu       >D.DWSubAddr
               endc      
               jsr       DW$Write,u                 ; call DWrite
               leas      1,s                 ; leave one byte on stack for response 
               
               ; read protocol version response, 1 byte
               leax      ,s                  ; point X to stack head
               ldy       #1                  ; 1 byte to retrieve
               jsr       DW$Read,u                 ; call DWRead
               beq       InstIRQ             ; branch if no error
               leas      3,s                 ; error, cleanup stack (u and 1 byte from read) 
               lbra      InitEx            	 ; don't install IRQ handler

* install ISR
InstIRQ                  
			   puls      a,u		; a has proto version from server.. not used yet

			   ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
               leax      DW.VIRQPkt,x
               pshs      u
               tfr       x,u
               leax      Vi.Stat,x           ;fake VIRQ status register
               lda       #$80                ;VIRQ flag clear, repeated VIRQs
               sta       ,x                  ;set it while we're here...
               tfr       x,d                 ;copy fake VIRQ status register address
               leax      IRQPckt,pcr         ;IRQ polling packet
               leay      IRQSvc,pcr          ;IRQ service entry
               os9       F$IRQ               ;install
               puls      u
               bcs       InitEx              ;exit with error
               clra      
               ldb       PollSpd3,pcr        ; start at idle
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
               leax      DW.VIRQPkt,x
               std       Vi.Rst,x            ; reset count
               tfr       x,y                 ; move VIRQ software packet to Y
tryagain                 
               ldx       #$0001              ; code to install new VIRQ
               os9       F$VIRQ              ; install
               bcc       IRQok               ; no error, continue
               cmpb      #E$UnkSvc
               bne       InitEx
; if we get an E$UnkSvc error, then clock has not been initialized, so do it here
               leax      DefTime,pcr
               os9       F$STime
               bra       tryagain            ; note: this has the slim potential of looping forever
IRQok                    
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
; cheat: we know DW.StatTbl is at offset $00 from D.DWStat, do not bother with leax
               leax      DW.StatTbl,x
               tfr       u,d
               ldb       <V.PORT+1,u         ; get our port #
               sta       b,x                 ; store in table

InitEx                   
               puls      cc,x,y,pc


; ***********************************************************************
; Interrupt handler  - Much help from Darren Atkinson

IRQMulti3      anda      #$0F                ; mask first 4 bits, a is now port #+1
               deca                          ; we pass +1 to use 0 for no data
               pshs      a                   ; save port #
               cmpb      RxGrab,u            ; compare room in buffer to server's byte
               bhs       IRQM06              ; room left >= server's bytes, no problem

               stb       RxGrab,u            ; else replace with room left in our buffer

          ; also limit to end of buffer
IRQM06         ldd       RxBufEnd,u          ; end addr of buffer
               subd      RxBufPut,u          ; subtract current write pointer, result is # bytes left going forward in buff.

IRQM05         cmpb      RxGrab,u            ; compare b (room left) to grab bytes  
               bhs       IRQM03              ; branch if we have room for grab bytes

               stb       RxGrab,u            ; else set grab to room left

          ; send multiread req
IRQM03         puls      a                   ; port # is on stack
               ldb       RxGrab,u

               pshs      u

          ; setup DWsub command
               pshs      d                   ; (a port, b bytes)
               lda       #OP_SERREADM        ; load command
               pshs      a                   ; command store on stack
               leax      ,s                  ; point X to stack 
               ldy       #3                  ; 3 bytes to send

               ifgt      Level-1
               ldu       <D.DWSubAddr
               else      
               ldu       >D.DWSubAddr
               endc      
               jsr       DW$Write,u                 ; call DWrite

               leas      3,s                 ; clean 3 DWsub args from stack 

               ldx       ,s                  ; pointer to this port's area (from U prior), leave it on stack
               ldb       RxGrab,x            ; set B to grab bytes
               clra                          ; 0 in high byte		
               tfr       d,y                 ; set # bytes for DW

               ldx       RxBufPut,x          ; point X to insert position in this port's buffer
          ; receive response
               jsr       DW$Read,u                 ; call DWRead
          ; handle errors?


               puls      u
               ldb       RxGrab,u            ; our grab bytes

          ; set new RxBufPut
               ldx       RxBufPut,u          ; current write pointer
               abx                           ; add b (# bytes) to RxBufPut
               cmpx      RxBufEnd,u          ; end of Rx buffer?
               blo       IRQM04              ; no, go keep laydown pointer
               ldx       RxBufPtr,u          ; get Rx buffer start address
IRQM04         stx       RxBufPut,u          ; set new Rx data laydown pointer

          ; set new RxDatLen
               ldb       RxDatLen,u
               addb      RxGrab,u
               stb       RxDatLen,u          ; store new value

               lbra      CkSSig              ; had to lbra

IRQMulti                 
		  ; set IRQ freq for bulk
               pshs      a
               lda       PollSpd2,pcr
               lbsr      IRQsetFRQ
               puls      a

          ; initial grab bytes
               stb       RxGrab,u

          ; limit server bytes to bufsize - datlen
               ldb       RxBufSiz,u          ; size of buffer
               subb      RxDatLen,u          ; current bytes in buffer
               bne       IRQMulti3           ; continue, we have some space in buffer
          ; no room in buffer
               tstb      
               lbne      CkSSig              ;had to lbra
               lbra      IRQExit             ;had to lbra

bad
               leas      2,s                 ; error, cleanup stack 2
               lbra      IRQExit2            ; don't reset error count on the way out

; **** IRQ ENTRY POINT
IRQSvc         equ       *
               pshs      cc,dp               ; save system cc,DP
               orcc      #IntMasks           ; mask interrupts

          ; mark VIRQ handled (note U is pointer to our VIRQ packet in DP)
               lda       Vi.Stat,u           ; VIRQ status register
               anda      #^Vi.IFlag          ; clear flag in VIRQ status register
               sta       Vi.Stat,u           ; save it...

          ; poll server for incoming serial data

          ; send request
               lda       #OP_SERREAD         ; load command
               pshs      a                   ; command store on stack
               leax      ,s                  ; point X to stack 
               ldy       #1                  ; 1 byte to send

               ifgt      Level-1
               ldu       <D.DWSubAddr
               else      
               ldu       >D.DWSubAddr
               endc      
               jsr       DW$Write,u                 ; call DWrite

          ; receive response
               leas      -1,s                ; one more byte to fit response
               leax      ,s                  ; point X to stack head
               ldy       #2                  ; 2 bytes to retrieve
               jsr       DW$Read,u                 ; call DWRead
               bcs       bad
               bne       bad

          ; process response	
IRQSvc2                  
               ldd       ,s++                ; pull returned status byte into A,data into B (set Z if zero, N if multiread)
               bne       IRQGotOp            ; branch if D != 0 (something to do)
* this is a NOP response.. do we need to reschedule
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
               lda       DW.VIRQPkt+Vi.Rst+1,x
               cmpa      PollSpd3,pcr
               lbeq      IRQExit             ;we are already at idle speed

               lda       DW.VIRQNOP,x
               inca      
               cmpa      PollIdle,pcr
               beq       FRQdown

               sta       DW.VIRQNOP,x        ;inc NOP count, exit
               lbra      IRQExit

FRQdown        lda       DW.VIRQPkt+Vi.Rst+1,x
               cmpa      PollSpd1,pcr
               beq       FRQd1
               lda       PollSpd3,pcr
FRQd2                    
               sta       DW.VIRQPkt+Vi.Rst+1,x
               clr       DW.VIRQNOP,x
               lbra      IRQExit
FRQd1          lda       PollSpd2,pcr
               bra       FRQd2

; save back D on stack and build our U
IRQGotOp
               cmpd      #16*256+255
               beq       do_reboot

               pshs      d
* mode switch on bits 7+6 of A: 00 = vserial, 01 = vwindow, 10 = wirebug?, 11 = ?							

               anda      #$C0                ; mask last 6 bits
               beq       mode00              ; virtual serial mode
          					; future - handle other modes
               cmpa      #%01000000          ; vwindow?
               beq       mode01
               lbra      IRQExit             ; for now, bail

* Virtual Window Handler
mode01
               lda       ,s
               anda      #%00110000
               beq       key
               lbra      IRQExit

key
               lda       ,s
               anda      #$0F
               ora       #$10
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
; cheat: we know DW.StatTbl is at offset $00 from D.DWStat, do not bother with leax
;			leax    DW.StatTbl,x
               lda       a,x
               clrb      
               tfr       d,u
               puls      d
               lbra      IRQPutch

do_reboot
               lda       #255
               os9       F$Debug

* Virtual Serial Handler
mode00         
               lda       ,s                  ; restore A		  
               anda      #$0F                ; mask first 4 bits, a is now port #+1
               beq       IRQCont             ; if we're here with 0 in the port, its not really a port # (can we jump straight to status?)
               deca                          ; we pass +1 to use 0 for no data
; here we set U to the static storage area of the device we are working with
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
; cheat: we know DW.StatTbl is at offset $00 from D.DWStat, do not bother with leax
;			leax    DW.StatTbl,x
               lda       a,x
               bne       IRQCont             ; if A is 0, then this device is not active, so exit
               puls      d
               lbra      IRQExit
IRQCont                  
               clrb      
               tfr       d,u

               puls      d

          * multiread/status flag is in bit 4 of A
               bita      #$10
               lbeq       IRQPutch            ; branch for read1 if multiread not set

          * all 0s in port means status, anything else is multiread

               bita      #$0F                ;mask bit 7-4
               beq       dostat              ;port # all 0, this is a status response
               lbra      IRQMulti            ;its not all 0, this is a multiread


		 * in status events, databyte is split, 4bits status, 4bits port #          
dostat         bitb      #$F0                ;mask low bits
               lbne      IRQExit             ;we only implement code 0000, term
			* set u to port #
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
               lda       b,x
               bne       statcont            ; if A is 0, then this device is not active, so exit
               lbra      IRQExit

* IRQ set freq routine
* sets freq and clears NOP counter
* a = desired IRQ freq
IRQsetFRQ      pshs      x                   ; preserve
               ifgt      Level-1
               ldx       <D.DWStat
               else      
               ldx       >D.DWStat
               endc      
               sta       DW.VIRQPkt+Vi.Rst+1,x
* +++ BGP +++ added following line so that the counter (which was copied by
* clock before calling us) gets reset to the same value the reset value. Without
* this line, we get called again with the PRIOR Vi.Rst value.
               sta       DW.VIRQPkt+Vi.Cnt+1,x
               clr       DW.VIRQNOP,x
               puls      x
               rts       


* This routine roots through process descriptors in a queue and
* checks to see if the process has a path that is open to the device
* represented by the static storage pointer in U. If so, set the Condem
* bit of the P$State of that process.
*
* Note: we start with path 0 and continue until we get to either (a) the
* last path for that process or (b) a hit on the static storage that we
* are seeking.
*
* Entry: X = process descriptor to evaluate
*        U = static storage of device we want to check against
RootThrough              
               clrb
               leay      P$Path,x
               pshs      x
loop           cmpb      #NumPaths      
               beq       out
               incb
               lda       ,y+
               beq       loop
               pshs      y
               ifgt      Level-1
               ldx       <D.PthDBT
               else      
               ldx       >D.PthDBT
               endc      
               os9       F$Find64
               ldx       PD.DEV,y
               leax      V$STAT,x
               puls      y
               bcs       loop   +BGP+ Jul 20, 2012: continue even if error in F$Find64

               cmpu      ,x
               bne       loop

               ldx       ,s

               ldb       #S$HUP
               stb       P$Signal,x
               os9       F$AProc

*			lda   	P$State,x		get state of recipient
*			ora   	#Condem			set condemn bit
*			sta   	P$State,x		and set it back

out            puls      x
               ldx       P$Queue,x
               bne       RootThrough
               rts       

statcont       clrb      
               tfr       d,u
* NEW: root through all process descriptors. if any has a path open to this
* device, condem it
               ldx       <D.AProcQ
               beq       dowaitq
               bsr       RootThrough
dowaitq        ldx       <D.WProcQ
               beq       dosleepq
               bsr       RootThrough
dosleepq       ldx       <D.SProcQ
               beq       CkLPRC
               bsr       RootThrough

CkLPRC                   
               lda       <V.LPRC,u
               beq       IRQExit             ; no last process, bail
               ldb       #S$HUP
               os9       F$Send              ; send signal, don't think we can do anything about an error result anyway.. so
               bra       CkSuspnd            ; do we need to go check suspend?

; put byte B in port As buffer - optimization help from Darren Atkinson       
IRQPutCh                 
		  ; set IRQ freq for bulk
               lda       PollSpd1,pcr
               lbsr      IRQsetFRQ
               ldx       RxBufPut,u          ; point X to the data buffer

; process interrupt/quit characters here
; note we will have to do this in the multiread (ugh)
               tfr       b,a                 ; put byte in A
               ldb       #S$Intrpt
               cmpa      V.INTR,u
               beq       send@
               ldb       #S$Abort
               cmpa      V.QUIT,u
               bne       store
send@          lda       V.LPRC,u
               beq       IRQExit
               os9       F$Send
               bra       IRQExit

store                    
          ; store our data byte
               sta       ,x+                 ; store and increment buffer pointer

          ; adjust RxBufPut	
               cmpx      RxBufEnd,u          ; end of Rx buffer?
               blo       IRQSkip1            ; no, go keep laydown pointer
               ldx       RxBufPtr,u          ; get Rx buffer start address
IRQSkip1       stx       RxBufPut,u          ; set new Rx data laydown pointer

          ; increment RxDatLen
               inc       RxDatLen,u

CkSSig                   
               lda       <SSigID,u           ; send signal on data ready?
               beq       CkSuspnd
               ldb       <SSigSg,u           ; else get signal code
               os9       F$Send
               clr       <SSigID,u
               bra       IRQExit

          ; check if we have a process waiting for data	
CkSuspnd                 
               lda       <V.WAKE,u           ; V.WAKE?
               beq       IRQExit             ; no
               clr       <V.WAKE,u           ; clear V.WAKE

          ; wake up waiter for read
               ifeq      Level-1
               ldb       #S$Wake
               os9       F$Send
               else      
               clrb      
               tfr       d,x                 ; copy process descriptor pointer
               lda       P$State,x           ; get state flags
               anda      #^Suspend           ; clear suspend state
               sta       P$State,x           ; save state flags
               endc      

IRQExit                  
IRQExit2       puls      cc,dp,pc            ; restore interrupts cc,dp, return

               emod      
eom            equ       *
               end