Mercurial > hg > Members > kono > nitros9-code
changeset 699:3a6527ccdb74
clock from NitrOS-9 is now integrated... no lonnger do we have split clocks
in OS-9 Level Two
author | boisy |
---|---|
date | Wed, 01 Jan 2003 17:03:37 +0000 |
parents | 63cdee2d64ee |
children | bd1333ef2844 |
files | level2/modules/clock.asm |
diffstat | 1 files changed, 1051 insertions(+), 380 deletions(-) [+] |
line wrap: on
line diff
--- a/level2/modules/clock.asm Wed Jan 01 16:59:49 2003 +0000 +++ b/level2/modules/clock.asm Wed Jan 01 17:03:37 2003 +0000 @@ -1,426 +1,1097 @@ ******************************************************************** -* Clock - OS-9 Level Two V3.00 Clock part 1 +* Clock - Clocks for OS-9 Level Two/NitrOS-9 +* +* Clock module for CoCo 3 and TC9 OS9 Level 2 Version 02.00.01 +* +* Includes support for several different RTC chips, GIME Toggle +* IRQ fix, numerous minor changes. +* +* Based on Microware/Tandy Clock Module for CC3/L2 * * $Id$ * * Ed. Comments Who YY/MM/DD * ------------------------------------------------------------------ -* Original version KKD 87/01/01 -* Fixed labels KDM 87/05/22 -* Break into 2 modules KKD 88/09/29 -* Fixed GIME IRQ toggle BRI 88/10/05 -* Changed to TSlice = 3 BRI 88/11/12 -* Changed to TSlice = 2 BRI 88/11/16 -* Added F$TPS, chopped size BRI 88/12/09 -* 14 Added F$TPS, chopped size BRI 88/12/09 -* 15 Fixed bug where F$Link to Clock2 BRI ??/??/?? -* was being done without switching D.Proc to the -* system state D.SysPrc first. This bug caused -* crashes in certain situations. -* 16 The only change in this edition is that BRI 90/04/15 -* Simmy's F$TimAlm call has been combined into -* the standard F$Alarm call, with a few enhancements. -* The best documentation for this (it would probably -* be a good start on a manual page) is the comments -* from the source code. -* 17 Fixed bug where jmp [D.Crash] should instead BGP 98/10/20 -* jmp D.Crash +* NitrOS-9 2.00 distribution ??/??/?? +* Back-ported to OS-9 Level Two BGP 03/01/01 + + nam Clock + ttl Clocks 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 + ENDC + +Edtn equ 9 +Vrsn equ 4 NitrOS-9 version + +* +* Setup for specific RTC chip +* + IFNE RTCElim +RTC.Sped equ $20 32.768 KHz, rate=0 +RTC.Strt equ $06 binary, 24 Hour, DST disabled +RTC.Stop equ $86 bit 7 set stops clock to allow setting time +RTC.Base equ $FF72 I don't know base for this chip. + ENDC + + IFNE RTCDsto2+RTCDsto4 +RTC.Base equ $FF50 Base address of clock + ENDC + + IFNE RTCBB+RTCTc3 + IFNE RTCBB +RTC.Base equ $FF5C In SCS* Decode + ELSE +RTC.Base equ $FF7C Fully decoded RTC + ENDC +RTC.Zero equ -4 Send zero bit by writing this offset +RTC.One equ -3 Send one bit by writing this offset +RTC.Read equ 0 Read data from this offset + ENDC + + IFNE RTCSmart +RTC.Base equ $4004 We map the clock into this addr +RTC.Zero equ -4 Send zero bit by writing this offset +RTC.One equ -3 Send one bit by writing this offset +RTC.Read equ 0 Read data from this offset + ENDC + IFNE RTCHarrs +RTC.Base equ $FF60 Base address for clock + ENDC - nam Clock - ttl OS-9 Level Two V3.00 Clock part 1 + IFNE RTCSoft +RTC.Base equ 0 Have to have one defined. + ENDC - ifp1 - use defsfile - endc +*------------------------------------------------------------ +* +* Start of module +* + mod len,name,Systm+Objct,ReEnt+Vrsn,Init,RTC.Base -edition equ 17 +name fcs "Clock" + fcb Edtn + + IFNE MPIFlag +SlotSlct fcb MPI.Slot-1 Slot constant for MPI select code + ENDC -******************************************************* +* +* 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 - mod len,name,systm+objct,reent+1,Init,0 + IFNE RTCElim + fcb F$NVRAM Eliminator adds one new service call + fdb F.NVRAM-*-2 + ENDC -******************************************************* + fcb $80 end of service call installation table -name fcs "Clock" - fcb edition - -* Svc Calls: +*--------------------------------------------------------- +* 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 -SvcTbl fcb F$Time - fdb FTime-*-2 - fcb F$STime - fdb FSTime-*-2 - fcb F$VIRQ - fdb FVIRQ-*-2 - fcb F$Alarm - fdb FAlarm-*-2 - fcb F$TPS *** new BRI *** - fdb FTPS-*-2 *** new BRI *** -* fcb $26 -* fdb FUnk-*-2 - fcb $80 +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 -*--------------------------------- -* IRQ Handler: -* Note NO STACK HERE! +virqloop 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 + + puls a Get VIRQ status flag: high bit set if VIRQ + ora <D.IRQS Check to see if other hardware IRQ pending. + bita #%10110111 Any V/IRQ interrupts pending? + beq toggle + bsr DoPoll Yes, go service them. + bra KbdCheck +toggle bsr DoToggle No, toggle GIME anyway +KbdCheck jsr [>D.AltIRQ] go update mouse, gfx cursor, keyboard, etc. -IRQChek lda >IRQEnR get GIME irq status - ora <D.IRQS save it - bita #$08 was it VBORD irq? - bne L0035 ..yes, increment time - sta <D.IRQS - ldd <D.GPoll set D.SvcIRQ to GIME polling - bra L0043 ..and jmp D.XIRQ + 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 + + lbsr UpdTime -* WAS VBORD IRQ so increment Time Vars: -L0035 anda #^$08 drop vbord irq - sta <D.IRQS - dec <D.Tick ticks-1 - bne L0041 ..skip if not yet - lda #TkPerSec reset ticks to start of second - sta <D.Tick (also F$Alarm check flag!!) -L0041 ldd <D.VIRQ set alternate IRQ -L0043 std <D.SvcIrq for system state - jmp [D.XIRQ] and finish irq handling. + 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 -*--------------------------------- -* NEW GIME irq register reset: +*------------------------------------------------------------ +* Interrupt polling and GIME reset code +* -GPoll jsr [>D.Poll] do regular polling - bcc GPoll -GFix lda #$FE get enabled bits +* +* Call [D.Poll] until all interrupts have been handled +* +Dopoll jsr [>D.Poll] Call poll routine + bcc DoPoll Until error (error -> no interrupt found) +* +* Reset GIME to avoid missed IRQs +* +DoToggle lda #^GI.Toggl Mask off CART* bit anda <D.IRQS sta <D.IRQS - lda <D.IRQER - tfr a,b copy it for GIME IRQ re-trigger - anda #^$01 select GIME IRQ input(s) to toggle - sta >IrqEnR disable selected GIME input(s) - stb >IrqEnR trigger GIME again - clrb - rts - -*------------------------------ -* VIRQ Handler: - -VIRQChek clr ,-s clear found flag - lda <D.IRQS check for other irqs - bita #$37 any others? - beq L006D ..no - inc ,s yes, set flag -L006D ldy <D.CLTb point to virqtable - bra L008A ..begin search - -* Main Loop: - -L0072 ldd ,x get virq counter - subd #$0001 decrement - bne L0088 ..skip if not ready - inc ,s - lda $04,x check kill flag - bne L0082 ..nope - lbsr L01D9 ..yep, delete entry -L0082 ora #$01 set software irq bit - sta $04,x - ldd $02,x reset counter -L0088 std ,x -L008A ldx ,y++ last entry? - bne L0072 ..no - lda ,s+ else any found? - beq L0092 ..no - bsr GPoll - bra L0094 -L0092 bsr GFix -L0094 jsr [>D.AltIRQ] poll keyboard - lda #TkPerSec - cmpa <D.Tick new second starting? - bne L011D ..not yet - ldd #3 gettime vector - lbsr L0125 - lda <$002D - cmpa #$10 - bhi L011D - beq L00E5 - ldx #$1016 - ldb ,x - beq L011D - leay -$07,x - bsr L00CE - bne L011D - lda <$002D - cmpa #$0F - bcs L00C5 - tstb - bpl L00C5 - clr ,x -L00C5 ldx >$1017 - beq L011D - jsr ,x - bra L011D -L00CE ldb #$04 - pshs x,b - ldx #$0028 -L00D5 lda b,y - bmi L00DF - dec ,s - cmpa b,x - bne L00E3 -L00DF decb - bpl L00D5 - clrb -L00E3 puls pc,x,b -L00E5 ldx <$0048 - leax <$21,x -L00EA lda ,-x - beq L0119 - ldb #$C3 - tfr d,y - lda $06,y - beq L0119 - bsr L00CE - bne L0119 - pshs b - ldd $06,y - exg d,y - clrb - exg d,y - pshs x - ldx <D.Proc - sty <D.Proc - os9 F$Send - stx <D.Proc - puls x - tst ,s+ - bpl L0119 - clra + 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 - std $06,y -L0119 cmpx <$0048 - bhi L00EA -L011D jmp [D.Clock] continue w/multitasking - -*--------------------------------- new! -* F$STime - -FSTime ldx #D.Time - bsr Copy6 - ldd #06 do setime in clock2: - -*--------------------------------- -* CALL CLOCK2: D=offset -L0125 ldx <D.Clock2 else update time vars - jmp d,x do it and rts + rts -*--------------------------------- -* F$Time -* Note that time is already here -* from once/second clock polling! - -FTime ldx #D.Time point to time packet Moved **** -L012C ldy <D.Proc user process - lda <D.SysTsk from sys map - ldb P$Task,y to user map - ldu R$X,u destination=user(X) - bra L015B +*------------------------------------------------------------ +* +* Update time subroutines +* +* The subroutine UpdTime is called once per minute. On systems +* with an RTC, UpdTime reads the RTC and sets the D.Time variables. +* -Copy6 ldy <D.Proc calling process *** changed BRI *** - lda P$Task,y from user map *** changed BRI *** - ldb <D.SysTsk - ldu R$X,u packet - exg x,u -L015B ldy #6 number bytes - os9 F$Move get them - rts - - - -*-------------------------------------------- -* F$Alarm +* +* Eliminator time update (lacks MPI slot select ability) * -* Note: The time packet is standard F$Time format, except seconds are always -* set to zero and $80 through $FF are wild cards that will match any -* time constant. Use of wild cards to replace one or more time -* constants in a time packet results in a repetitive alarm. The BELL -* alarm sounds once per second up to and including the 15th second in -* the alarm minute. Signal alarms are sent on the 16th second of the -* alarm minute to avoid misses when using a real-time Clock2, which may -* be out of sync with the internal VBORD (60 Hz) tick count. -* EG1: X=>$5A0216000000 sets an alarm at midnight on Feb. 22, 1990. -* EG2: X=>$5AFFFF0D0000 sets an alarm at 1:00 PM every day in 1990. -* EG3: X=>$FFFFFFFFFF00 sets an alarm at every minute. -* -* INPUT: A = alarm type or process ID -* B = action or signal code (depending on A) -* X = pointer to caller's time packet (if alarm set or return) -* -* OUTPUT: Alarm set, cleared, or returned, as follows: -* -* - if A=0: -* - if B=0, clear alarm -* - if B=1, set "BELL" alarm -* - D = alarm info -* - X = pointer to caller's 6 byte time packet -* - if B=2, return alarm info -* - D = alarm info -* - X = pointer to caller's 6 byte time packet -* -* - if A<>0: -* - A = process ID to be signalled -* - B = signal code to be sent -* - X = pointer to caller's 6 byte time packet + IFNE RTCElim +UpdTime ldx M$Mem,pcr get RTC base address from fake memory requirement + ldb #$0A UIP status register address + stb ,x generate address strobe + lda 1,x get UIP status + bpl NoUIP Update In Progress, go shift next RTC read + lda #TkPerSec/2 set up next RTC read attempt in 1/2 second + sta <D.Tick save tick + bra UpdTExit and return + +NoUIP decb year register address + stb ,x generate address strobe + lda 1,x get year + sta <D.Year + decb month register address + stb ,x + lda 1,x + sta <D.Month + decb day of month register address + stb ,x + lda 1,x + sta <D.Day + ldb #4 hour register address + stb ,x + lda 1,x + sta <D.Hour + ldb #2 minute register address + stb ,x + lda 1,x + sta <D.Min + clrb second register address + stb ,x + lda 1,x +SaveSec sta <D.Sec +UpdTExit rts + ENDC + * -* ERROR OUTPUT: CC = Carry set -* B = error code +* Disto 2-in-1 RTC time update +* + IFNE RTCDsto2 +UpdTime pshs a,cc Save old interrupt status and mask IRQs + bsr RTCPre -FAlarm ldx <D.Proc - leax >$00C3,x - ldd $01,u - beq L0167 - tsta - bne L017C - cmpb #$01 - beq L0179 - cmpb #$02 - beq L0170 - comb - ldb #$BB - rts -L0167 tst $06,x - bne L0188 - ldx #$100F - bra L0188 -L0170 ldx #$100F - ldd $06,x - std $01,u - bra L012C -L0179 ldx #$100F -L017C pshs x,b,a - clra - clrb - std $06,x - bsr Copy6 - puls x,b,a - clr $05,x -L0188 std $06,x + bsr GetVal Get Year + bsr GetVal Get Month + bsr GetVal Get Day + decb ldb #5 + stb 2,x + decb + lda ,x + anda #3 + bsr GetVal1 Get Hour + bsr GetVal Get Minute + bsr GetVal Get Second + +RTCPost clr >$FFD9 2 MHz (Really should check $A0 first) + puls cc,b + + IFNE MPIFlag + stb >MPI.Slct Restore saved "currently" selected MPak slot + ENDC + clrb rts -*--------------------------------- *** new *** -* get ticks per second: +RTCPre orcc #IntMasks + + IFNE MPIFlag + ldb >MPI.Slct Save currently selected MPak slot on stack + stb 3,s + andb #$F0 + orb >SlotSlct,pcr Get slot to select + stb >MPI.Slct Select MPak slot for clock + ENDC + + ldy #D.Time + ldx M$Mem,pcr + clr 1,x + ldb #12 + clr >$FFD8 1 MHz + rts + +GetVal stb 2,x + decb + lda ,x read tens digit from clock + anda #$0f +GetVal1 pshs b save b + ldb #10 + mul multiply by 10 to get value + stb ,y save 10s value + puls b set up clock for ones digit + stb 2,x + decb + lda ,x read ones digit from clock + anda #$0f + adda ,y add ones + tens + sta ,y+ store clock value into time packet + rts + + ENDC + +* +* Disto 4-in-1 RTC time update +* + IFNE RTCDsto4 +UpdTime equ * + IFNE MPIFlag + pshs cc Save old interrupt status and mask IRQs + orcc #IntMasks + ldb >MPI.Slct Save currently selected MPak slot on stack + pshs b + andb #$F0 + orb >SlotSlct,pcr Select MPak slot for clock + stb >MPI.Slct + ENDC + + ldx M$Mem,pcr + ldy #D.Time Start with seconds + + ldb #11 + bsr GetVal Get Year + bsr GetVal Get Month + bsr GetVal Get Day + lda #3 Mask tens digit of hour to remove AM/PM bit + bsr GetVal1 Get Hour + bsr GetVal Get Minute + bsr GetVal Get Second + + IFNE MPIFlag + puls b Restore saved "currently" selected MPak slot + stb >MPI.Slct + puls cc,pc Restore previous IRQ status + ELSE + rts No MPI, don't need to mess with slot, CC + ENDC -FTPS ldd #TkPerSec number of ticks per second - std R$D,u save it to caller's reg stack - clrb no error... - rts +GetVal lda #$0f Mask to apply to tens digit +GetVal1 stb 1,x + decb + anda ,x read ones digit from clock + pshs b save b + ldb #10 + mul multiply by 10 to get value + stb ,y Add to ones digit + puls b + stb 1,x + decb + lda ,x read tens digit from clock and mask it + anda #$0f + adda ,y + sta ,y+ + rts + + ENDC + + +* +* Update time from B&B RTC +* + IFNE RTCBB+RTCTc3 +UpdTime pshs u,y,cc + leay ReadBCD,pcr Read bytes of clock + +TfrTime orcc #IntMasks turn off interrupts + ldu M$Mem,pcr Get base address + + IFNE MPIFlag + ldb >MPI.Slct Select slot + pshs b + andb #$F0 + orb SlotSlct,pcr + stb >MPI.Slct + ENDC + + lbsr SendMsg Initialize clock + ldx #D.Sec + ldb #8 Tfr 8 bytes + +tfrloop jsr ,y Tfr 1 byte + + bitb #$03 + beq skipstuf Skip over day-of-week, etc. + leax -1,x +skipstuf decb + bne tfrloop + + IFNE MPIFlag + puls b + stb >MPI.Slct restore MPAK slot + ENDC + + puls u,y,cc,pc + +ClkMsg fcb $C5,$3A,$A3,$5C,$C5,$3A,$A3,$5C +* Enable clock with message $C53AA35CC53AA35C +SendMsg lda RTC.Read,u Send Initialization message to clock + leax <ClkMsg,pcr + ldb #8 +msgloop lda ,x+ + bsr SendByte + decb + bne msgloop + rts + +SendBCD pshs b Send byte to clock, first converting to BCD + bitb #$03 + bne BCDskip Send zero for day-of-week, etc. + lda #0 + bra SndBCDGo +BCDskip lda ,x +SndBCDGo tfr a,b + bra binenter +binloop adda #6 +binenter subb #10 + bhs binloop + puls b +SendByte coma Send one byte to clock + rora + bcc sendone +sendzero tst RTC.Zero,u + lsra + bcc sendone + bne sendzero + rts +sendone tst RTC.One,u + lsra + bcc sendone + bne sendzero + rts + -*--------------------------------- -FVIRQ pshs cc save irq status - orcc #IntMasks stop irq/firqs - ldy <D.CLTb point to virq table - ldx <D.Init and Init module - ldb PollCnt,x get max devices - ldx R$X,u get X parameter - beq L01C3 ..remove entry - tst ,y first entry empty? - beq L01B9 ..yes - subb #$02 else point to last - lslb entry in table - leay b,y - tst ,y empty? - bne L01D3 ..no, error -L01B3 tst ,--y found spot? - beq L01B3 ..no, back up - leay $02,y yes, reset ptr -L01B9 ldx R$Y,u get packet ptr - stx ,y set entry - ldd R$D,u get first count *** changed BRI *** - std ,x set it *** changed BRI *** - bra L01CF return okay. -L01C3 ldx R$Y,u get entry -L01C5 tst ,y return if - beq L01CF no entries - cmpx ,y++ else search for - bne L01C5 this entry - bsr L01D9 then remove it -L01CF puls cc restore intrpt status - clrb ok - rts . -L01D3 puls cc retrieve CC reg - comb set error bit - ldb #E$Poll 'Polling Table Full' - rts . +ReadBCD pshs b + ldb #$80 High bit will rotate out after we read 8 bits +readbit lda RTC.Read,u Read a bit + lsra + rorb Shift it into B + bcc readbit Stop when marker bit appears + tfr b,a + bra BCDEnter Convert BCD number to Binary +BCDLoop subb #6 by subtracting 6 for each $10 +BCDEnter suba #$10 + bhs BCDLoop + stb ,x + puls b,pc + + ENDC + + +* +* Update time from Smartwatch RTC +* + IFNE RTCSmart +UpdTime pshs cc + orcc #IntMasks Disable interrupts + lda >MPI.Slct Get MPI slot + ldb <$90 Get GIME shadow of $FF90 + pshs b,a + anda #$F0 + ora >SlotSlct,pcr Get new slot to select + anda #$03 *** TEST *** + sta >MPI.Slct And select it + andb #$FC + stb >$FF90 ROM mapping = 16k internal, 16k external + ldb >$FFA2 Read GIME for $4000-$5fff + pshs b + lda #$3E + sta >$FFA2 Put block $3E at $4000-$5fff + clr >$FFDE Map RAM/ROM, to map in external ROM + lbsr SendMsg Initialize clock + ldx #D.Sec Start with seconds + lda #$08 + sta ,-s Set up loop counter = 8 +L021E ldb #$08 +L0220 lda >RTC.Read+RTC.Base Read one bit + lsra + ror ,x Put bit into time + decb End of bit loop + bne L0220 + lda ,s Check loop counter + cmpa #$08 + beq L023D Fill "seconds" twice (ignore 1st value) + cmpa #$04 + bne L0239 + ldb ,x Save 4th value read at $34 (day of week?) + stb $0A,x + bra L023D And overwrite "day" with day +L0239 leax -$01,x Go to next time to read + bsr BCD2Dec Convert 1,x from BCD to decimal +L023D dec ,s + bne L021E End of loop for reading time + leas $01,s Done with loop counter + clr >$FFDF Map all RAM + puls b + stb >$FFA2 Put back original memory block + puls b,a + sta >MPI.Slct + stb >$FF90 Restore original ROM mapping + puls cc,pc Re-enable interrupts + +* Convert BCD to a normal number + +BCD2Dec lda $01,x + clrb +B2DLoop cmpa #$10 + bcs B2DDone + suba #$10 + addb #$0A + bra B2DLoop +B2DDone pshs a + addb ,s+ + stb $01,x + rts + +ClkMsg fcb $C5,$3A,$A3,$5C,$C5,$3A,$A3,$5C + +* Send above "string" to smartwatch, one bit at a time -*-------------------------- -* delete virq entry: +SendMsg leax <ClkMsg,pcr + lda >RTC.Read+RTC.Base Tell clock we're going to start??? + lda #$08 + sta ,-s Store counter = 8 +L006B ldb #$08 Start of outer loop, 8 bytes to send + lda ,x+ Get byte to send +L006F lsra Start of inner loop, 8 bits to send + bcs L0077 + tst >RTC.Zero+RTC.Base Send a "zero" bit + bra L007A +L0077 tst >RTC.One+RTC.Base Send a "one" bit +L007A decb + bne L006F End of inner loop + dec ,s End of outer loop + bne L006B + puls pc,a + + ENDC + +* +* Update time from Harris RTC +* + IFNE RTCHarrs +UpdTime pshs cc + orcc #IntMasks Disable interrupts + + ldu M$Mem,pcr Get base address + ldy #D.Time Pointer to time in system map + + lda #%00001100 Init command register (Normal,Int. Disabled, + sta $11,u Run,24-hour mode, 32kHz) + + lda ,u Read base address to set-up clock regs for read + lda 6,u Get year + sta ,y+ + lda 4,u Get month + sta ,y+ + lda 5,u Get day + sta ,y+ + lda 1,u Get hour + sta ,y+ + lda 2,u Get minute + sta ,y+ + lda 3,u Get second + sta ,y+ -L01D9 pshs y,x save regs -L01DB ldx ,y++ move entries - stx -$04,y up in table - bne L01DB until last one (0000) - puls y,x - leay -$02,y reset table ptr - rts + puls cc,pc Re-enable interrupts + ENDC +* +* +* Software time update +* +* + + IFNE RTCSoft +UpdTime lda <D.Min grab current minute + inca minute+1 + cmpa #60 End of hour? + blo UpdMin no, Set start of minute + ldd <D.Day get day, hour + incb hour+1 + cmpb #24 End of Day? + blo UpdHour ..no + inca day+1 + leax months-1,pcr point to months table with offset-1: Jan = +1 + ldb <D.Month this month + cmpa b,x end of month? + bls UpdDay ..no, update the day + cmpb #2 yes, is it Feb? + bne NoLeap ..no, ok + ldb <D.Year else get year + andb #$03 check for leap year: good until 2099 + cmpd #$1D00 29th on leap year? + beq UpdDay ..yes, skip it +NoLeap ldd <D.Year else month+1 + incb month+1 + cmpb #13 end of year? + blo UpdMonth ..no + inca year+1 + ldb #$01 set month to jan +UpdMonth std <D.Year save year, month + lda #$01 day=1st +UpdDay clrb hour=midnite +UpdHour std <D.Day save day,hour + clra minute=00 +UpdMin clrb seconds=00 + std <D.Min save min,secs +UpdTExit rts + ENDC + +months fcb 31,28,31,30,31,30,31,31,30,31,30,31 Days in each month -*--------------------------------- -* Clock Init: +*------------------------------------------------------------ +* +* 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 + +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 leay -2,y point to first null VIRQ entry + ldx R$Y,u + stx ,y + ldy R$D,u + sty ,x + bra virqexit + +RemVIRQ ldx ,y++ + beq virqexit + cmpx R$Y,u + bne RemVIRQ + bsr DelVIRQ +virqexit puls cc + clrb + rts + +DelVIRQ pshs x,y +DelVLup ldx ,y++ move entries up in table + stx -4,y + bne DelVLup + puls x,y + leay -2,y + rts + +*------------------------------------------------------------ +* +* 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 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 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 + +* +* No RTC, just end (Also for SmartWatch, temporarily) +* + IFNE RTCSoft+RTCSmart + rts + ENDC + +* +* Set Eliminator RTC from D.Time +* + IFNE RTCElim + pshs cc save interrupt status + orcc #IntMasks disable IRQs + ldx M$Mem,pcr get RTC base address from fake memory requirement + ldy #D.Time point [Y] to time variables in DP + ldd #$0B*256+RTC.Stop + bsr UpdatCk0 stop clock before setting it + ldb #RTC.Sped + bsr UpdatCk0 set crystal speed, output rate + bsr UpdatClk go set year + bsr UpdatClk go set month + bsr UpdatClk go set day of month + bsr UpdatCk0 go set day of week (value doesn't matter) + bsr UpdatCk0 go set hours alarm (value doesn't matter) + bsr UpdatClk go set hour + bsr UpdatCk0 go set minutes alarm (value doesn't matter) + bsr UpdatClk go set minute + bsr UpdatCk0 go set seconds alarm (value doesn't matter) + bsr UpdatClk go set second + ldd #$0B*256+RTC.Strt + bsr UpdatCk0 go start clock + puls cc Recover IRQ status + clrb + rts + +UpdatClk ldb ,y+ get data from D.Time variables in DP +UpdatCk0 std ,x generate address strobe, save data + deca set [A] to next register down + rts + ENDC + +* +* Set Disto 2-in-1 RTC from Time variables +* + IFNE RTCDsto2 + pshs a,cc + lbsr RTCPre Initialize + + bsr SetVal Set Year + bsr SetVal Set Month + bsr SetVal Set Day + ldd #$0805 $08 in A, $05 in B + bsr SetVal1 Set Hour (OR value in A ($08) with hour) + bsr SetVal Set Minute + bsr SetVal Set Second + + lbra RTCPost Clean up + return + +SetVal clra +SetVal1 stb 2,x Set Clock address + decb + pshs b + ldb ,y+ Get current value +DvLoop subb #10 Get Tens digit in A, ones digit in B + bcs DvDone + inca + bra DvLoop +DvDone addb #10 + sta ,x Store tens digit + tfr b,a + puls b Get back original clock address + stb 2,x + decb + sta ,x Store ones digit + rts + ENDC + +* +* Set Disto 4-in-1 RTC from Time variables +* + IFNE RTCDsto4 + pshs cc + orcc #IntMasks + + IFNE MPIFlag + ldb >MPI.Slct Save currently selected MPak slot + pshs b + andb #$F0 + orb >SlotSlct,pcr Get slot to select + stb >MPI.Slct Select MPak slot for clock + ENDC + + ldy #D.Time+6 + ldx M$Mem,pcr + clrb + bsr SetVal Set Second + bsr SetVal Set Minute + bsr SetVal Set Hour + bsr SetVal Set Day + bsr SetVal Set Month + bsr SetVal Set Year + + IFNE MPIFlag + puls b Restore old MPAK slot + stb >MPI.Slct + ENDC + + puls cc + clrb No error + rts -Init clrb necessary??? - pshs cc save intpt status - ldd #(TkPerSec*256)+02 - sta <D.Tick - stb <D.TSlice two ticks/time slice - stb <D.Slice and first slice - orcc #IntMasks stop interrupts - leax >IRQChek,pcr set IRQ handler - stx <D.IRQ - leax >VIRQChek,pcr set VIRQ handler - stx <D.VIRQ - leax >GPoll,pcr set GIME irq reset - stx <D.GPoll -* install system calls - leay >SvcTbl,pcr insert syscalls - os9 F$SSvc - clra - ldx #PIA0Base point to PIA0 - sta $01,x dir register - sta ,x side A are inputs - sta $03,x dir register - coma - sta $02,x side B outputs - ldd #$343C reset D - sta $01,x control reg - stb $03,x set up irq from VBORD - lda $02,x dummy reset - lda #$08 - ora <D.IRQER get GIME IRQ reg/enable VBord irqs - sta <D.IRQER save shadow reg - sta >IRQEnR set VBorder irqs +SetVal clr ,-s Create variable for tens digit + lda ,-y Get current value +DvLoop suba #10 Get Tens digit on stack, ones digit in A + bcs DvDone + inc ,s + bra DvLoop +DvDone adda #10 + stb 1,x Set Clock address + incb + sta ,x Store ones digit + stb 1,x + incb + puls a + sta ,x Store tens digit + rts + ENDC + +* +* Set B&B RTC from Time variables +* + IFNE RTCBB+RTCTc3 + pshs u,y,cc + leay SendBCD,pcr Send bytes of clock + lbra TfrTime + ENDC + +*------------------------------------------------------------ +* read/write RTC Non Volatile RAM (NVRAM) +* +* INPUT: [U] = pointer to caller's register stack +* R$A = access mode (1 = read, 2 = write, other = error) +* R$B = byte count (1 through 50 here, but in other implementations +* may be 1 through 256 where 0 implies 256) +* R$X = address of buffer in user map +* R$Y = start address in NVRAM +* +* OUTPUT: RTC NVRAM read/written +* +* ERROR OUTPUT: [CC] = Carry set +* [B] = error code + IFNE RTCElim +F.NVRAM tfr u,y copy caller's register stack pointer + ldd #$0100 ask for one page + os9 F$SRqMem + bcs NVR.Exit go report error... + pshs y,u save caller's stack and data buffer pointers + ldx R$Y,y get NVRAM start address + cmpx #50 too high? + bhs Arg.Err yes, go return error... + ldb R$B,y get NVRAM byte count + beq Arg.Err + abx check end address + cmpx #50 too high? + bhi Arg.Err yes, go return error... + lda R$A,y get direction flag + cmpa #WRITE. put caller's data into NVRAM? + bne ChkRead no, go check if read... + clra [D]=byte count + pshs d save it... + ldx <D.Proc get caller's process descriptor address + lda P$Task,x caller is source task + ldb <D.SysTsk system is destination task + ldx R$X,y get caller's source pointer + puls y recover byte count + os9 F$Move go MOVE data + bcs NVR.Err + ldy ,s get caller's register stack pointer from stack + lda R$Y+1,y get NVRAM start address + adda #$0E add offset to first RTC NVRAM address + ldb R$B,y get byte count + ldx M$Mem,pcr get clock base address from fake memory requirement + pshs cc,b save IRQ enable status and byte counter + orcc #IntMasks disable IRQs +WrNVR.Lp ldb ,u+ get caller's data + std ,x generate RTC address strobe and save data to NVRAM + inca next NVRAM address + dec 1,s done yet? + bne WrNVR.Lp no, go save another byte + puls cc,b recover IRQ enable status and clean up stack +NVR.RtM puls y,u recover register stack & data buffer pointers + ldd #$0100 return one page + os9 F$SRtMem +NVR.Exit rts + +Arg.Err ldb #E$IllArg Illegal Argument error + bra NVR.Err - ldx <D.Proc save user proc - pshs x - ldx <D.SysPrc make sys for link - stx <D.Proc +ChkRead cmpa #READ. return NVRAM data to caller? + bne Arg.Err illegal access mode, go return error... + lda R$Y+1,y get NVRAM start address + adda #$0E add offset to first RTC NVRAM address + ldx M$Mem,pcr get clock base address from fake memory requirement + pshs cc,b save IRQ enable status and byte counter + orcc #IntMasks disable IRQs +RdNVR.Lp sta ,x generate RTC address strobe + ldb 1,x get NVRAM data + stb ,u+ save it to buffer + inca next NVRAM address + dec 1,s done yet? + bne RdNVR.Lp no, go get another byte + puls cc,a recover IRQ enable status, clean up stack ([A]=0) + ldb R$B,y [D]=byte count + pshs d save it... + ldx <D.Proc get caller's process descriptor address + ldb P$Task,x caller is source task + lda <D.SysTsk system is destination task + ldu R$X,y get caller's source pointer + puls y recover byte count + ldx 2,s get data buffer (source) pointer + os9 F$Move go MOVE data + bcc NVR.RtM +NVR.Err puls y,u recover caller's stack and data pointers + pshs b save error code + ldd #$0100 return one page + os9 F$SRtMem + comb set Carry for error + puls b,pc recover error code, return... + ENDC +* +* Set Harris 1770 RTC from Time variables +* + IFNE RTCHarrs + pshs cc + orcc #IntMasks Disable interrupts - leax <Clock2,pcr - lda #Systm+Objct - os9 F$Link + ldu M$Mem,pcr Get base address + ldy #D.Time Pointer to time in system map + + lda #%00000100 Init command register (Normal,Int. Disabled, + sta $11,u STOP clock,24-hour mode, 32kHz) -* And here, we restore the original D.Proc value - puls x - stx <D.Proc restore user proc + lda ,y+ Get year + sta 6,u + lda ,y+ Get month + sta 4,u + lda ,y+ Get day + sta 5,u + lda ,y+ Get hour + sta 1,u + lda ,y+ Get minute + sta 2,u + lda ,y Get second + sta 3,u + + lda #%00001100 Init command register (Normal,Int. Disabled, + sta $11,u START clock,24-hour mode, 32kHz) + + puls cc,pc Re-enable interrupts + ENDC - bcs err - sty <D.Clock2 save exec vector - jsr ,y do init of clock (ignore errs) - puls pc,cc +*-------------------------------------------------- +* +* 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 #PIA0Base point to PIA0 + clra no error for return... + pshs cc save IRQ enable status (and Carry clear) + orcc #IntMasks stop interrupts + + 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 + lda ,x clear possible pending PIA0 HBORD IRQ + lda 2,x clear possible pending PIA0 VBORD IRQ -err ldb #5 "no clock2" err - jmp D.Crash tell user the booterr +* 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 -Clock2 fcs "Clock2" + 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 + 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 - emod -len equ * - end +* +* RTC-specific initializations here +* + IFNE RTCDsto4 + ldx M$Mem,pcr + ldd #$010F Set mode for RTC chip + stb 1,x + sta ,x + ldd #$0504 + sta ,x + stb ,x + ENDC + puls cc,pc recover IRQ enable status and return + + emod +len equ * + end