changeset 1313:7fdef42e19a0

New clock/clock2 combo
author boisy
date Thu, 04 Sep 2003 18:31:45 +0000
parents d39be8bc97bc
children b6490bc55a3d
files level1/modules/clock.asm level1/modules/clock2.asm level1/modules/makefile
diffstat 3 files changed, 1437 insertions(+), 276 deletions(-) [+]
line wrap: on
line diff
--- a/level1/modules/clock.asm	Thu Sep 04 18:31:20 2003 +0000
+++ b/level1/modules/clock.asm	Thu Sep 04 18:31:45 2003 +0000
@@ -1,96 +1,60 @@
 ********************************************************************
-* Clock - OS-9 Level One V2 Clock module
+* Clock - OS-9 System Clock
+*
+* CoCo 3 notes:
+* Includes support for several different RTC chips, GIME Toggle
+* IRQ fix, numerous minor changes.
 *
 * $Id$
 *
-* NOTE:  This clock is TOTALLY VALID for ALL DATES between 1900-2155
-*
 * Edt/Rev  YYYY/MM/DD  Modified by
 * Comment
 * ------------------------------------------------------------------
-*   5      1985/??/??
-* From Tandy OS-9 Level One VR 02.00.00
+*          ????/??/??
+* NitrOS-9 2.00 distribution.
 *
-*   6      1999/05/03  Boisy G. Pitre
-* Modified to handle leap years properly for 1900 and 2100 A.D.
+*   9r4    2003/01/01  Boisy G. Pitre
+* Back-ported to OS-9 Level Two.
 *
-*          2002/05/14  Boisy G. Pitre
-* Added TC^3 SCSI/B&B RTC Clock Support.
-
-         nam   Clock
-         ttl   OS-9 Level One V2 Clock module
+*   9r5    2003/08/18  Boisy G. Pitre
+* Separated clock into Clock and Clock2 for modularity.
+*
+*   9r6    2003/09/04  Boisy G. Pitre
+* Combined Level One and Level Two sources
 
-         IFP1
-         use   defsfile
-         ENDC
+         nam   Clock     
+         ttl   OS-9 System Clock
 
-tylg     set   Systm+Objct
-atrv     set   ReEnt+rev
-rev      set   $00
-edition  set   6
-
-         mod   eom,name,tylg,atrv,ClkEnt,RTC.Base
-
-size     equ   .
+         IFP1            
+         use   defsfile  
+         ENDC            
 
-name     fcs   /Clock/
-         fcb   edition
+Edtn     equ   9
+rev      equ   6 
+
 
-* If no RTC defines are set, then this is a software clock
-         IFEQ  RTCBB+RTCTC3
-SOFT     set   1
-         ENDC
+*------------------------------------------------------------
+*
+* Start of module
+*
+         mod   len,name,Systm+Objct,ReEnt+rev,Init,0
 
-         IFNE  RTCBB
-MPIFlag  set   1
-SlotSlct set   $22
-RTC.Base equ   $FF5C
-         ENDC
-         IFNE  RTCTC3
-RTC.Base equ   $FF7C
-         ENDC
-         IFNE  SOFT
-RTC.Base equ   size
-         ENDC
+name     fcs   "Clock"   
+         fcb   Edtn      
+
+         IFEQ  Level-1
 
-         IFNE  RTCBB+RTCTC3
-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
+*TkPerTS  equ   2          ticks per time slice
+TkPerTS  equ   TkPerSec/10	ticks per time slice
 
-SysTbl   fcb   F$Time
+NewSvc   fcb   F$Time
          fdb   FTime-*-2
          fcb   F$VIRQ
          fdb   FVIRQ-*-2
-
-         IFEQ  SOFT
-
          fcb   F$STime
          fdb   FSTime-*-2
-
-         ENDC
-
          fcb   $80
 
-         IFNE  SOFT
-* table of days of the month
-MonthChk fcb   00
-         fcb   31                      January
-         fcb   28                      February
-         fcb   31                      March
-         fcb   30                      April
-         fcb   31                      May
-         fcb   30                      June
-         fcb   31                      July
-         fcb   31                      August
-         fcb   30                      September
-         fcb   31                      October
-         fcb   30                      November
-         fcb   31                      December
-
-         ELSE
-
 FSTime   ldx   R$X,u
          ldd   ,x
          std   <D.Year
@@ -100,134 +64,13 @@
 	 std   <D.Min
          andcc #^Carry
 
-         ENDC
-
-         IFNE  RTCBB+RTCTC3
-
-         pshs  u,y,cc
-         leay  SendBCD,pcr   Send bytes of clock
-	 lbra  TfrTime
 *
-* Update time from B&B/TC3 RTC
+* Call SetTime entry point in Clock2
 *
-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
+         ldx   <D.Clock2  get entry point to Clock2
+         jsr   $06,x      else call GetTime entry point
 
-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
-
-         IFNE  RTCDriveWire
-         rts
-
-         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
-
 
 *
 * Clock IRQ Entry Point
@@ -240,80 +83,25 @@
 L0032    lda   PIA0Base+2              clear interrupt?
          dec   <D.Tick                 decrement tick counter
          bne   L007F                   go around if not zero
-         ldd   <D.Min                  get minutes/seconds
+         ldb   <D.Sec                  get minutes/seconds
 * Seconds increment
          incb                          increment seconds
          cmpb  #60                     full minute?
          bcs   L0079                   nope...
 
-         IFNE  RTCBB+RTCTC3+RTCDriveWire
 *
-* Hardware clock code
-*
-
-         lbsr   UpdTime
-	 bra    L007B
-
-         ELSE 
-*
-* Software clock code
+* Call GetTime entry point in Clock2
 *
-* Minutes increment
-         inca                          else increment minute
-         cmpa  #60                     full hour?
-         bcs   L0078                   nope...
-	 ldd   <D.Day                  else increment day
-* Hour increment
-         incb                          increment hour
-         cmpb  #24                     past 23rd hour?
-         bcs   L0075                   branch if not
-* Day increment
-         inca                          else increment day
-         leax  >MonthChk,pcr
-         ldb   <D.Month
-*         cmpb  #3                      is this February?
-*         bne   L005F
-*         ldb   <D.Year                 check year
-*         beq   L005F                   if century, it's a leap year
-*         andb  #$03                    leap year? (divisible by 4)
-*         beq   L0060                   nope
-*L005F    inca
-*L0060    ldb   <D.Month                get month
-         cmpa  b,x                     compare days to max days
-         bls   L0074                   branch if ok
-         cmpb  #2                      is this February?
-         bne   L006X                   if not, go on to year/month
-* Leap year cases checked here
-         ldb   <D.Year                 else check for leap year cases
-         beq   L006X                   branch if year 1900
-         cmpb  #200                    is it 1900+200 (2100)?
-         beq   L006X                   if so, branch
-         andb  #$03                    see if 2^4 bit set (leap year)
-         cmpd  #$1D00                  29th on leap year?
-         beq   L0074                   it's a leap year...
-L006X    ldd   <D.Year                 else get year and month
-* Month increment
-         incb                          increment month
-         cmpb  #13                     past December?
-         bcs   L0070                   branch if not
-* Year increment
-         inca                          else in year
-         ldb   #1                      and start month in January
-L0070    std   <D.Year                 update year/month
-         lda   #1                      new month, first day
-L0074    clrb                          hour 0
-L0075    std   <D.Day                  update day/hour
-         clra                          0 minutes
-L0078    clrb                          0 seconds
+         ldx   <D.Clock2  get entry point to Clock2
+         jsr   $03,x      call GetTime entry point
+         fcb   $8C		skip next 2 bytes
 
-         ENDC
-
-L0079    std   <D.Min                  update min/sec
+L0079    stb   <D.Sec                  update sec
 L007B    lda   <D.TSec
          sta   <D.Tick
 L007F    clra
          pshs  a
-         ldy   <D.CLTB
+         ldy   <D.CLTb
          bra   L009E
 L0087    ldd   ,x
          subd  #$0001
@@ -362,7 +150,7 @@
 
 FVIRQ    pshs  cc
          orcc  #FIRQMask+IRQMask
-         ldy   <D.CLTB
+         ldy   <D.CLTb
          ldx   <D.Init
          ldb   PollCnt,x
          ldx   R$X,u
@@ -396,25 +184,36 @@
          ldb   #E$Poll
          rts
 
-ClkEnt   equ   *
-         pshs  dp,cc
+Init     pshs  dp,cc
          clra
          tfr   a,dp
 
-         lda   #TPS
+         leax  <Clock2,pcr
+         lda   #Systm+Objct
+         os9   F$Link    
+         bcc   LinkOk    
+         jmp   >$FFFE		reset
+LinkOk   sty   <D.Clock2	save entry point
+* Call Clock2 init routine
+         jsr   ,y         call init entry point of Clock2
+
+
+         lda   #TkPerSec
 
          sta   <D.TSec
          sta   <D.Tick
 
-         lda   #TPS/10
+* 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
 
-         sta   <D.TSlice
-         sta   <D.Slice
+         stb   <D.TSlice
+         stb   <D.Slice
          orcc  #FIRQMask+IRQMask       mask ints
          leax  >ClockIRQ,pcr
          stx   <D.IRQ
 * install system calls
-         leay  >SysTbl,pcr
+         leay  >NewSvc,pcr
          os9   F$SSvc
          ldx   #PIA0Base
          clra
@@ -429,13 +228,8 @@
          sta   3,x                     PIA0Base side B to I/O reg
          lda   2,x
 
-         IFEQ  SOFT
-
-	 lbsr  UpdTime                 Update time from RTC if one
+         puls  pc,dp,cc
 
-         ENDC
-
-         puls  pc,dp,cc
 
 * F$Time system call code
 FTime    ldx   R$X,u
@@ -448,6 +242,496 @@
          clrb
          rts
 
-         emod
-eom      equ   *
-         end
+
+
+
+         ELSE
+
+
+
+
+* OS-9 Level Two Clock
+
+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
+
+
+* 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   >$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    
+         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   >$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
+
+*
+* 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   >$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             
+
+
+*------------------------------------------------------------
+*
+* 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            
+
+         IFGT  Level-1
+*------------------------------------------------------------
+*
+* 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             
+         ENDC
+
+*------------------------------------------------------------
+*
+* Handle F$Time System call
+*
+F.Time   equ   *
+         IFGT  Level-1
+         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    
+         ELSE
+         ldx   R$X,u	get pointer to caller's space
+         ldd   <D.Year	get year and month
+         std   ,x
+         ldd   <D.Day	get day and hour
+         std   2,x
+         ldd   <D.Min	get minute and second
+         std   4,x
+         clrb
+         ENDC
+         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  *
+         IFGT  Level-1
+         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)
+         ELSE
+         ldx   R$X,u
+         ldd   ,x
+         std   <D.Year
+         ldd   2,x
+         std   <D.Day
+         ldd   4,x
+         std   <D.Min
+         ENDC
+         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             
+
+*--------------------------------------------------
+*
+* 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   #Systm+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
+
+         IFGT  Level-1
+* 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            
+         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    
+         IFGT  Level-1
+* 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
+         ENDC
+
+* 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
+
+         ENDC
+
+
+Clock2   fcs   "Clock2"  
+
+         emod            
+len      equ   *         
+         end             
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/clock2.asm	Thu Sep 04 18:31:45 2003 +0000
@@ -0,0 +1,836 @@
+********************************************************************
+* Clock2 - Real-Time Clock Subroutines
+*
+* $Id$
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*   1      2003/08/18  Boisy G. Pitre
+* Stripped from clock.asm in order to modularize clocks.
+
+         nam   Clock2    
+         ttl   Real-Time Clock Subroutines
+
+         ifp1            
+         use   defsfile  
+         endc            
+
+*
+* 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+0,JmpTable,RTC.Base
+
+name     fcs   "Clock2"  
+         fcb   1         
+
+         IFNE  MPIFlag   
+SlotSlct fcb   MPI.Slot-1 Slot constant for MPI select code
+         ENDC            
+
+* Jump table for RTC
+*
+* Entry points:
+*  - Init
+*  - SetTime
+*  - GetTime
+JmpTable                 
+         lbra  Init      
+         bra   GetTime   
+         nop             
+         lbra  SetTime   
+
+*
+* GetTime Subroutine
+*
+* This subroutine is called by the main clock module.
+*
+
+*
+* Eliminator time update  (lacks MPI slot select ability)
+*
+GetTime  equ   *         
+         IFNE  RTCElim   
+         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  
+         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  
+         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
+
+         lbra  DoDW      
+
+         use   bbwrite.asm
+
+DoDW     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
+         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  
+         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  
+         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   
+         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
+
+
+SetTime  equ   *         
+*
+* 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             
+
+         IFGT  Level-1
+* OS-9 Level Two code only (for now)
+NewSvc   fcb   F$NVRAM    Eliminator adds one new service call
+         fdb   F.NVRAM-*-2
+         fcb   $80        end of service call installation table
+
+*------------------------------------------------------------
+* 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
+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
+         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            
+
+*
+* 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            
+
+
+*
+* RTC-specific initializations here
+*
+Init     equ   *         
+         IFNE  RTCDsto4  
+* Disto 4-N-1 RTC specific initialization
+         ldx   M$Mem,pcr 
+         ldd   #$010F     Set mode for RTC chip
+         stb   1,x       
+         sta   ,x        
+         ldd   #$0504    
+         sta   ,x        
+         stb   ,x        
+         ENDC            
+
+         IFNE  RTCElim   
+         IFGT  Level-1
+* Eliminator will install specific system calls
+         leay  NewSvc,pcr insert syscalls
+         os9   F$SSvc    
+         ENDC
+         ENDC            
+
+         rts             
+
+         emod            
+len      equ   *         
+         end             
--- a/level1/modules/makefile	Thu Sep 04 18:31:20 2003 +0000
+++ b/level1/modules/makefile	Thu Sep 04 18:31:45 2003 +0000
@@ -2,6 +2,15 @@
 
 include ../../Makefile.rules
 
+CLOCKELIM       = -aRTCElim=1 -aRTCDsto2=0 -aRTCDsto4=0 -aRTCBB=0 -aRTCSmart=0 -aRTCHarrs=0 -aRTCTc3=0 -aRTCSoft=0 -aMPIFlag=0
+CLOCKDISTO2     = -aRTCElim=0 -aRTCDsto2=1 -aRTCDsto4=0 -aRTCBB=0 -aRTCSmart=0 -aRTCHarrs=0 -aRTCTc3=0 -aRTCSoft=0 -aMPIFlag=0
+CLOCKDISTO4     = -aRTCElim=0 -aRTCDsto2=0 -aRTCDsto4=1 -aRTCBB=0 -aRTCSmart=0 -aRTCHarrs=0 -aRTCTc3=0 -aRTCSoft=0 -aMPIFlag=0
+CLOCKBNB        = -aRTCElim=0 -aRTCDsto2=0 -aRTCDsto4=0 -aRTCBB=1 -aRTCSmart=0 -aRTCHarrs=0 -aRTCTc3=0 -aRTCSoft=0 -aMPIFlag=0
+CLOCKSMART      = -aRTCElim=0 -aRTCDsto2=0 -aRTCDsto4=0 -aRTCBB=0 -aRTCSmart=1 -aRTCHarrs=0 -aRTCTc3=0 -aRTCSoft=0 -aMPIFlag=1
+CLOCKHARRIS     = -aRTCElim=0 -aRTCDsto2=0 -aRTCDsto4=0 -aRTCBB=0 -aRTCSmart=0 -aRTCHarrs=1 -aRTCTc3=0 -aRTCSoft=0 -aMPIFlag=0
+CLOCKTC3        = -aRTCElim=0 -aRTCDsto2=0 -aRTCDsto4=0 -aRTCBB=0 -aRTCSmart=0 -aRTCHarrs=0 -aRTCTc3=1 -aRTCSoft=0 -aMPIFlag=0
+CLOCKSOFT       = -aRTCElim=0 -aRTCDsto2=0 -aRTCDsto4=0 -aRTCBB=0 -aRTCSmart=0 -aRTCHarrs=0 -aRTCTc3=0 -aRTCSoft=1 -aMPIFlag=0
+
 DEPENDS		= ./Makefile
 TPB		= $(3RDPARTY)/booters
 
@@ -10,9 +19,9 @@
 BOOTTRACK	= rel $(BOOTERS)
 KERNEL		= os9 os9p2
 SYSMODS		= ioman init sysgo_dd sysgo_h0
-CLOCKS          = clock_elim clock_disto2 clock_disto4 clock_bnb \
-                clock_smart clock_harris clock_tc3 clock_soft \
-		clock_soft_50hz
+CLOCKS          = clock_60hz clock_50hz \
+		clock2_elim clock2_disto2 clock2_disto4 clock2_bnb \
+                clock2_smart clock2_harris clock2_tc3 clock2_soft
 
 RBF		= rbf.mn \
 		ccdisk.dr cchdisk.dr \
@@ -51,6 +60,38 @@
 boot_1773_30ms:	boot_1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDNum=0 -aSTEP=3
 
+# Clocks
+clock_60hz: clock.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=60
+
+clock_50hz: clock.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=50
+
+clock2_elim: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKELIM)
+
+clock2_disto2: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKDISTO2)
+
+clock2_disto4: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKDISTO4)
+
+clock2_bnb: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKBNB)
+
+clock2_smart: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKSMART)
+
+clock2_harris: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKHARRIS)
+
+clock2_tc3: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKTC3)  
+
+clock2_soft: clock2.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< $(CLOCKSOFT)
+
+
 # Floppy descriptors
 SSDD35		= -aCyls=35 -aSides=1 -aSectTrk=18 -aSectTrk0=18 \
 		-aInterlv=3 -aSAS=8 -aDensity=1