Mercurial > hg > Members > kono > nitros9-code
view level1/modules/dw3.asm @ 2308:b5f0c5326e7e
Changes made to move ISR to dw3
author | boisy |
---|---|
date | Sun, 03 Jan 2010 14:35:04 +0000 |
parents | 660cc987e18d |
children | b2bc1ad04163 |
line wrap: on
line source
******************************************************************** * DW3 - DriveWire 3 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. nam DW3 ttl DriveWire 3 Low Level Subroutine Module ifp1 use defsfile use dwdefs.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 dtb name fcs /dw3/ * 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 * * ON ENTRY: * X = ADDRESS OF THE RECEIVE BUFFER * A = TIMEOUT VALUE (182 = APPROX ONE SECOND @ 0.89 MHz) * * ON EXIT: * Y = DATA CHECKSUM * D = ACTUAL NUMBER OF BYTES RECEIVED * X AND U ARE PRESERVED * CC.CARRY IS SET IF A FRAMING ERROR WAS DETECTED * Read use dwread.asm * Write * * Entry: Write use dwwrite.asm * 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 orcc #IntMasks ldx #PIA1Base $FF20 clr 1,x clear CD lda #%11111110 sta ,x lda #%00110100 sta 1,x lda ,x ; 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@ * install ISR InstIRQ 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 ldd #$0003 ;lets try every 6 ticks (0.1 seconds) -- testing 3, gives better response in interactive things 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 #$1F ; mask first 5 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 6,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 3,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 bra CkSuspnd IRQMulti ; 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 bne CkSuspnd bra IRQExit ; **** 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 6,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 3,u ; call DWRead beq IRQSvc2 ; branch if no error leas 2,s ; error, cleanup stack 2 bra IRQExit2 ; don't reset error count on the way out ; process response IRQSvc2 ldd ,s++ ; pull returned status byte into A,data into B (set Z if zero, N if multiread) beq IRQExit ; branch if D = 0 (nothing to do) ; save back D on stack and build our U pshs d anda #$1F ; mask first 5 bits, a is now port #+1 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 bra IRQExit IRQCont clrb tfr d,u ldd ,s++ ; pull returned status byte into A,data into B (set Z if zero, N if multiread) bmi IRQMulti ; branch for multiread ; put byte B in port As buffer - optimization help from Darren Atkinson IRQPutCh 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 ; 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