Mercurial > hg > Members > kono > nitros9-code
view level2/modules/clock.asm @ 1099:b77631456f91
Change to makefile
author | roug |
---|---|
date | Wed, 09 Apr 2003 19:02:19 +0000 |
parents | 4fa216983d96 |
children | a3d0ac951684 |
line wrap: on
line source
******************************************************************** * Clock - Clocks 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$ * * Ed. Comments Who YY/MM/DD * ------------------------------------------------------------------ * 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 RTCDriveWire RTC.Base equ $0000 ENDC 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 IFNE RTCSoft RTC.Base equ 0 Have to have one defined. ENDC *------------------------------------------------------------ * * Start of module * mod len,name,Systm+Objct,ReEnt+Vrsn,Init,RTC.Base 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 IFNE RTCElim fcb F$NVRAM Eliminator adds one new service call fdb F.NVRAM-*-2 ENDC 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 >$FFA1 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 >$FFA1 incb stb >$0645 stb >$FFA1 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 bsr DoPoll Yes, go service them. bra KbdCheck toggle bsr DoToggle No, toggle GIME anyway 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 >$FFA1 and into RAM ---x inca sta >$0645 sta >$FFA2 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 >$FFA1 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 lbsr UpdTime 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 >$FFA1 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 *------------------------------------------------------------ * * 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. * * * Eliminator time update (lacks MPI slot select ability) * 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 * * Disto 2-in-1 RTC time update * IFNE RTCDsto2 UpdTime pshs a,cc Save old interrupt status and mask IRQs bsr RTCPre 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 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 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 DriveWire * IFNE RTCDriveWire use bbwrite.asm UpdTime pshs y,x,cc lda #'# Time packet orcc #IntMasks Disable interrupts lbsr SerWrite bsr SerRead Read year byte bcs UpdLeave sta <D.Year bsr SerRead Read month byte bcs UpdLeave sta <D.Month bsr SerRead Read day byte bcs UpdLeave sta <D.Day bsr SerRead Read hour byte bcs UpdLeave sta <D.Hour bsr SerRead Read minute byte bcs UpdLeave sta <D.Min bsr SerRead Read second byte bcs UpdLeave sta <D.Sec bsr SerRead Read day of week (0-6) byte UpdLeave puls cc,x,y,pc use bbread.asm 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 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 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+ 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 *------------------------------------------------------------ * * 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 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+RTCDriveWire 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 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 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 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) 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 *-------------------------------------------------- * * 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 * 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 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 * * 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