Mercurial > hg > Members > kono > nitros9-code
view level2/modules/clock.asm @ 3226:9749d0dfc4a2
Changed a puls PC to rts to save cycles
author | David Ladd <drencor-xeen@users.sourceforge.net> |
---|---|
date | Sat, 20 Jan 2018 19:32:22 -0600 |
parents | f77ac3ae8a43 |
children |
line wrap: on
line source
******************************************************************** * Clock - Clock for OS-9 Level Two/NitrOS-9 * * Clock module for CoCo 3 and TC9 OS9 Level 2 and NitrOS-9 * * Includes support for several different RTC chips, GIME Toggle * IRQ fix, numerous minor changes. * * Based on Microware/Tandy Clock Module for CC3/L2 * * $Id$ * * Edt/Rev YYYY/MM/DD Modified by * Comment * ------------------------------------------------------------------ * ????/??/?? * NitrOS-9 2.00 distribution. * * 9r4 2003/01/01 Boisy G. Pitre * Back-ported to OS-9 Level Two. * * 9r5 2003/08/18 Boisy G. Pitre * Separated clock into Clock and Clock2 for modularity. nam Clock ttl Clock for OS-9 Level Two/NitrOS-9 TkPerTS equ 2 ticks per time slice GI.Toggl equ %00000001 GIME CART* IRQ enable bit, for CC3 * TC9 needs to reset more interrupt sources *GI.Toggl equ %00000111 GIME SERINT*, KEYINT*, CART* IRQ enable bits IFP1 use defsfile use cocovtio.d ENDC Edtn equ 9 Vrsn equ 5 *------------------------------------------------------------ * * Start of module * mod len,name,Systm+Objct,ReEnt+Vrsn,Init,0 name fcs "Clock" fcb Edtn * * Table to set up Service Calls: * NewSvc fcb F$Time fdb F.Time-*-2 fcb F$VIRQ fdb F.VIRQ-*-2 fcb F$Alarm fdb F.ALARM-*-2 fcb F$STime fdb F.STime-*-2 fcb $80 end of service call installation table *--------------------------------------------------------- * IRQ Handling starts here. * * Caveat: There may not be a stack at this point, so avoid using one. * Stack is set up by the kernel between here and SvcVIRQ. * SvcIRQ lda >IRQEnR Get GIME IRQ Status and save it. ora <D.IRQS sta <D.IRQS bita #$08 Check for clock interrupt beq NoClock anda #^$08 Drop clock interrupt sta <D.IRQS ldx <D.VIRQ Set VIRQ routine to be executed clr <D.QIRQ ---x IS clock IRQ bra ContIRQ NoClock leax DoPoll,pcr If not clock IRQ, just poll IRQ source IFNE H6309 oim #$FF,<D.QIRQ ---x set flag to NOT clock IRQ ELSE lda #$FF sta <D.QIRQ ENDC ContIRQ stx <D.SvcIRQ jmp [D.XIRQ] Chain through Kernel to continue IRQ handling *------------------------------------------------------------ * * IRQ handling re-enters here on VSYNC IRQ. * * - Count down VIRQ timers, mark ones that are done * - Call DoPoll/DoToggle to service VIRQs and IRQs and reset GIME * - Call Keyboard scan * - Update time variables * - At end of minute, check alarm * SvcVIRQ clra Flag if we find any VIRQs to service pshs a ldy <D.CLTb Get address of VIRQ table bra virqent virqloop equ * IFGT Level-2 ldd 2,y Get Level 3 extended map type orcc #IntMasks sta >$0643 stb >$0645 std >DAT.Regs+1 andcc #^IntMasks ENDC ldd Vi.Cnt,x Decrement tick count IFNE H6309 decd --- subd #1 ELSE subd #$0001 ENDC bne notzero Is this one done? lda Vi.Stat,x Should we reset? bmi doreset lbsr DelVIRQ No, delete this entry doreset ora #$01 Mark this VIRQ as triggered. sta Vi.Stat,x lda #$80 Add VIRQ as interrupt source sta ,s ldd Vi.Rst,x Reset from Reset count. notzero std Vi.Cnt,x virqent ldx ,y++ bne virqloop IFGT Level-2 puls d orcc #Carry stb >$0643 stb >DAT.Regs+1 incb stb >$0645 stb >DAT.Regs+1 andcc #^IntMasks ELSE puls a Get VIRQ status flag: high bit set if VIRQ ENDC ora <D.IRQS Check to see if other hardware IRQ pending. bita #%10110111 Any V/IRQ interrupts pending? beq toggle IFGT Level-2 lbsr DoPoll Yes, go service them. ELSE bsr DoPoll Yes, go service them. ENDC bra KbdCheck toggle equ * IFGT Level-2 lbsr DoToggle No, toggle GIME anyway ELSE bsr DoToggle No, toggle GIME anyway ENDC KbdCheck equ * IFGT Level-2 lda >$0643 grab current map type ldb >$0645 pshs d save it orcc #IntMasks IRQs off lda >$0660 SCF local memory ---x sta >$0643 into DAT image ---x sta >DAT.Regs+1 and into RAM ---x inca sta >$0645 sta >DAT.Regs+2 map in SCF, CC3IO, WindInt, etc. ENDC jsr [>D.AltIRQ] go update mouse, gfx cursor, keyboard, etc. IFGT Level-2 puls d restore original map type ---x orcc #IntMasks sta >$0643 into system DAT image ---x stb >$0645 std >DAT.Regs+1 and into RAM ---x andcc #$AF ENDC dec <D.Tick End of second? bne VIRQend No, skip time update and alarm check lda #TkPerSec Reset tick count sta <D.Tick * ATD: Modified to call real time clocks on every minute ONLY. inc <D.Sec go up one second lda <D.Sec grab current second cmpa #60 End of minute? blo VIRQend No, skip time update and alarm check clr <D.Sec Reset second count to zero * * Call GetTime entry point in Clock2 * ldx <D.Clock2 get entry point to Clock2 jsr $03,x call GetTime entry point NoGet ldd >WGlobal+G.AlPID ble VIRQend Quit if no Alarm set ldd >WGlobal+G.AlPckt+3 Does Hour/Minute agree? cmpd <D.Hour bne VIRQend ldd >WGlobal+G.AlPckt+1 Does Month/Day agree? cmpd <D.Month bne VIRQend ldb >WGlobal+G.AlPckt+0 Does Year agree? cmpb <D.Year bne VIRQend ldd >WGlobal+G.AlPID cmpd #1 beq checkbel os9 F$Send bra endalarm checkbel ldb <D.Sec Sound bell for 15 seconds andb #$F0 beq dobell endalarm ldd #$FFFF std >WGlobal+G.AlPID bra VIRQend dobell ldx >WGlobal+G.BelVec beq VIRQend jsr ,x VIRQend jmp [>D.Clock] Jump to kernel's timeslice routine *------------------------------------------------------------ * Interrupt polling and GIME reset code * * * Call [D.Poll] until all interrupts have been handled * Dopoll IFGT Level-2 lda >$0643 Level 3: get map type ldb >$0645 pshs d save for later ENDC Dopoll.i jsr [>D.Poll] Call poll routine bcc DoPoll.i Until error (error -> no interrupt found) IFGT Level-2 puls d orcc #IntMasks sta >$0643 stb >$0645 std >DAT.Regs+1 andcc #^IntMasks ENDC * * Reset GIME to avoid missed IRQs * DoToggle lda #^GI.Toggl Mask off CART* bit anda <D.IRQS sta <D.IRQS lda <D.IRQER Get current enable register status tfr a,b anda #^GI.Toggl Mask off CART* bit orb #GI.Toggl --- ensure that 60Hz IRQ's are always enabled sta >IRQEnR Disable CART stb >IRQEnR Enable CART clrb rts *------------------------------------------------------------ * * Handle F$VIRQ system call * F.VIRQ pshs cc orcc #IntMasks Disable interrupts ldy <D.CLTb Address of VIRQ table ldx <D.Init Address of INIT ldb PollCnt,x Number of polling table entries from INIT ldx R$X,u Zero means delete entry beq RemVIRQ IFGT Level-2 bra FindVIRQ ---x v.loop leay 4,y ---x ENDC FindVIRQ ldx ,y++ Is VIRQ entry null? beq AddVIRQ If yes, add entry here decb bne FindVIRQ puls cc comb ldb #E$Poll rts AddVIRQ IFGT Level-2 ldx R$Y,u stx ,y lda >$0643 ldb >$0645 std 2,y ELSE leay -2,y point to first null VIRQ entry ldx R$Y,u stx ,y ENDC ldy R$D,u sty ,x bra virqexit IFGT Level-2 v.chk leay 4,y RemVIRQ ldx ,y ELSE RemVIRQ ldx ,y++ ENDC beq virqexit cmpx R$Y,u bne RemVIRQ bsr DelVIRQ virqexit puls cc clrb rts DelVIRQ pshs x,y DelVLup IFGT Level-2 ldq ,y++ move entries up in table leay 2,y stq -8,y bne DelVLup puls x,y,pc ELSE ldx ,y++ move entries up in table stx -4,y bne DelVLup puls x,y leay -2,y rts ENDC *------------------------------------------------------------ * * Handle F$Alarm call * F.Alarm ldx #WGlobal+G.AlPckt ldd R$D,u bne DoAlarm std G.AlPID-G.AlPckt,x Erase F$Alarm PID, Signal. rts DoAlarm tsta If PID != 0, set alarm for this process bne SetAlarm cmpd #1 1 -> Set system-wide alarm bne GetAlarm SetAlarm std G.AlPID-G.AlPckt,x ldy <D.Proc lda P$Task,y Move from process task ldb <D.SysTsk To system task ldx R$X,u From address given in X ldu #WGlobal+G.AlPckt ldy #5 Move 5 bytes bra FMove GetAlarm cmpd #2 bne AlarmErr ldd G.AlPID-G.AlPckt,x std R$D,u bra RetTime AlarmErr comb ldb #E$IllArg rts *------------------------------------------------------------ * * Handle F$Time System call * F.Time equ * ldx #D.Time Address of system time packet RetTime ldy <D.Proc Get pointer to current proc descriptor ldb P$Task,y Process Task number lda <D.SysTsk From System Task ldu R$X,u STime.Mv ldy #6 Move 6 bytes FMove os9 F$Move rts *------------------------------------------------------------ * * Handle F$STime system call * * First, copy time packet from user address space to system time * variables, then fall through to code to update RTC. * F.STime equ * ldx <D.Proc Caller's process descriptor lda P$Task,x Source is in user map ldx R$X,u Address of caller's time packet ldu #D.Time Destination address ldb <D.SysTsk Destination is in system map bsr STime.Mv Get time packet (ignore errors) lda #TkPerSec Reset to start of second sta <D.Tick * * Call SetTime entry point in Clock2 ldx <D.Clock2 get entry point to Clock2 jsr $06,x else call GetTime entry point NoSet rts Clock2 fcs "Clock2" *-------------------------------------------------- * * Clock Initialization * * This vector is called by the kernel to service the first F$STime * call. F$STime is usually called by CC3Go (with a dummy argument) * in order to initialize the clock. F$STime is re-vectored to the * service code above to handle future F$STime calls. * * Init ldx <D.Proc save user proc pshs x ldx <D.SysPrc make sys for link stx <D.Proc leax <Clock2,pcr lda #Sbrtn+Objct os9 F$Link * And here, we restore the original D.Proc value puls x stx <D.Proc restore user proc bcc LinkOk lda #E$MNF jmp <D.Crash LinkOk sty <D.Clock2 save entry point InitCont ldx #PIA0Base point to PIA0 clra no error for return... pshs cc save IRQ enable status (and Carry clear) orcc #IntMasks stop interrupts * Note: this code can go away once we have a rel_50hz IFEQ TkPerSec-50 ldb <D.VIDMD get video mode register copy orb #$08 set 50 Hz VSYNC bit stb <D.VIDMD save video mode register copy stb >$FF98 set 50 Hz VSYNC ENDC sta 1,x enable DDRA sta ,x set port A all inputs sta 3,x enable DDRB coma sta 2,x set port B all outputs ldd #$343C [A]=PIA0 CRA contents, [B]=PIA0 CRB contents sta 1,x CA2 (MUX0) out low, port A, disable HBORD high-to-low IRQs stb 3,x CB2 (MUX1) out low, port B, disable VBORD low-to-high IRQs sta $23,x disable CART +RG Mar 14, 2012 lda ,x clear possible pending PIA0 HBORD IRQ lda 2,x clear possible pending PIA0 VBORD IRQ * Don't need to explicitly read RTC during initialization ldd #59*256+TkPerTS last second and time slice in minute std <D.Sec Will prompt RTC read at next time slice stb <D.TSlice set ticks per time slice stb <D.Slice set first time slice leax SvcIRQ,pcr set IRQ handler stx <D.IRQ leax SvcVIRQ,pcr set VIRQ handler stx <D.VIRQ leay NewSvc,pcr insert syscalls os9 F$SSvc * H6309 optimization opportunity here using oim lda <D.IRQER get shadow GIME IRQ enable register ora #$08 set VBORD bit sta <D.IRQER save shadow register sta >IRQEnR enable GIME VBORD IRQs * Call Clock2 init routine ldy <D.Clock2 get entry point to Clock2 jsr ,y call init entry point of Clock2 InitRts puls cc,pc recover IRQ enable status and return emod len equ * end