changeset 1689:1f8962dfa31b

This clock2 has Rodney H's changes of 8/1 plus Robert's SmartWatch changes. Submitted to me by Robert Gault on 8/1
author boisy
date Sun, 01 Aug 2004 17:37:56 +0000
parents 2ab141610086
children 9705dee9da1e
files level1/modules/clock2.asm
diffstat 1 files changed, 1131 insertions(+), 939 deletions(-) [+]
line wrap: on
line diff
--- a/level1/modules/clock2.asm	Sun Aug 01 15:19:35 2004 +0000
+++ b/level1/modules/clock2.asm	Sun Aug 01 17:37:56 2004 +0000
@@ -1,939 +1,1131 @@
-********************************************************************
-* 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.
-*
-*          2004/7/13   Robert Gault
-* Added Vavasour/Collyer emulator & MESS (Disto) versions and relocated
-* 'GetTime equ'   statement so it is not within a chip heading.
-
-         nam   Clock2    
-         ttl   Real-Time Clock Subroutines
-
-         ifp1            
-         use   defsfile  
-         endc            
-
-*
-* Setup for specific RTC chip
-*
-         IFNE  RTCJVEmu
-RTC.Base equ   $FFC0
-         ENDC
-
-         IFNE  RTCMESSEmu
-RTC.Base equ   $FF50
-         ENDC
-
-         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+RTCCloud9
-         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,Sbrtn+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.
-*
-
-GetTime  equ   *
-
-*
-* Vavasour / Collyer Emulator (ignores MPI slot)
-*
-         IFNE  RTCJVEmu
-         ldx   #RTC.Base
-         clr   ,-s
-         lda   ,x           get century
-         cmpa  #19
-         bls   cnt
-         lda   #100
-         sta   ,s
-cnt      lda   4,x
-         IFNE  Level-1
-         sta   <D.Daywk
-         ENDC
-         lda   1,x         get decade/year
-         adda  ,s+         add in century
-         ldb   2,x         get month
-         std   <D.Year     tell OS-9
-         IFNE  H6309
-         ldq   3,x         get all time values
-         sta   <D.Day
-         stw   <D.Hour
-         ELSE
-         lda   3,x         get day
-         sta   <D.Day
-         ldd   5,x         get hour/minute
-         std   <D.Hour
-         ENDC
-         lda   7,x
-         sta   <D.Sec
-         rts
-         ENDC
-
-*
-* MESS time update in Disto mode (ignores MPI)
-*   Assumes that PC clock is in AM/PM mode!!!
-*
-         IFNE  RTCMESSEmu
-         ldx   #RTC.Base
-         ldy   #D.Time
-         ldb   #12           counter for data
-         stb   1,x
-         lda   ,x
-         anda  #7
-         IFNE  Level-1
-         sta   <D.Daywk
-         ENDC
-         decb
-         bsr   getval
-         lda   -1,y
-         cmpa  #70          if >xx70 then its 19xx
-         bhi   not20
-         adda  #100
-         sta   -1,y
-not20    bsr   getval       month
-         bsr   getval       day
-         lda   #7           AM/PM mask
-         stb   1,x
-         anda  ,x
-         bitb  #4
-         pshs  cc
-         anda  #3
-         bsr   getval1
-         puls  cc
-         beq   AM
-         lda   #12         convert to 24hr time as it is PM
-         adda  -1,y
-         sta   -1,y
-AM       bsr   getval      minute
-* and now fall through into get second
-getval   lda   #$0f
-         stb   1,x
-         anda  ,x
-getval1  decb
-         pshs  b
-         ldb   #10
-         mul
-         stb   ,y
-         puls  b
-         stb   1,x
-         decb
-         lda   ,x
-         anda  #$0f
-         adda  ,y
-         sta   ,y+
-         rts
-         ENDC
-
-*
-* Eliminator time update  (lacks MPI slot select ability)
-*
-         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+RTCCloud9
-         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             
-
-months   fcb   31,28,31,30,31,30,31,31,30,31,30,31 Days in each month
-         ENDC            
-
-
-
-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+RTCCloud9
-         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             
+********************************************************************
+* 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.
+*
+*          2004/7/13   Robert Gault
+* Added Vavasour/Collyer emulator & MESS (Disto) versions and relocated
+* 'GetTime equ'   statement so it is not within a chip heading.
+*
+*          2004/7/28   Robert Gault
+* Complete rewrite of SmartWatch segment which would never have worked.
+* See previous versions for old code if desired. Routine now will search
+* through all MPI slots to find clock and accept either AM/PM or military
+* time. User notified if clock not found or data memory not available.
+*
+* Initialization routine contains code that bypasses OS-9 system calls to
+* acquire needed low RAM that can?t become ROM. This type of code is not
+* recommended in most cases but nothing else was usable.
+*
+*          2004/7/31   Rodney Hamilton
+* Improved RTCJVEmu code, conditionalized RTC type comments.
+
+         nam   Clock2    
+         ttl   Real-Time Clock Subroutines
+
+         ifp1            
+         use   defsfile  
+         endc            
+
+*
+* Setup for specific RTC chip
+*
+         IFNE  RTCJVEmu
+RTC.Base equ   $FFC0
+         ENDC
+
+         IFNE  RTCMESSEmu
+RTC.Base equ   $FF50
+         ENDC
+
+         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+RTCCloud9
+         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   $C000      clock mapped to $C000-$DFFF; $FFA6 MMU slot
+RTC.Zero equ   0          Send zero bit
+RTC.One  equ   1          Send ones bit
+RTC.Read equ   4
+D.RTCSlt equ   0          on SmartWatch ?data? page
+D.RTCFlg equ   1          on SW page
+D.Temp   equ   2          on SW page, holds "clock" data
+D.Start  equ   3          on SW page, code starts here
+         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,Sbrtn+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.
+*
+
+GetTime  equ   *
+
+         IFNE  RTCJVEmu
+*
+* Vavasour / Collyer Emulator (ignores MPI slot)
+*
+         ldx   #RTC.Base
+         ldd   ,x	get year (CCYY)
+         suba  #20
+         bmi   yr1	19xx, OK as is
+yr0      addb  #100	20xx adjustment
+         deca		also check for
+         bpl   yr0	21xx (optional)
+yr1      stb   <D.Year	set year (~YY)
+         ldd   2,x	get date
+         std   <D.Month	set date (MMDD)
+         IFNE  Level-1
+         ldd   4,x	get time (wwhh)
+         sta   <D.Daywk	set day of week
+         ELSE
+         ldb   5,x	get hour (hh)
+         ENDC
+         stb   <D.Hour	set hour (hh)
+         ldd   6,x	get time (mmss)
+         std   <D.Min	set time (mmss)
+*        rts		fall thru to Setime/Init rts
+         ENDC
+
+         IFNE  RTCMESSEmu
+*
+* MESS time update in Disto mode (ignores MPI)
+*   Assumes that PC clock is in AM/PM mode!!!
+*
+         ldx   #RTC.Base
+         ldy   #D.Time
+         ldb   #12           counter for data
+         stb   1,x
+         lda   ,x
+         anda  #7
+         IFNE  Level-1
+         sta   <D.Daywk
+         ENDC
+         decb
+         bsr   getval
+         lda   -1,y
+         cmpa  #70          if >xx70 then its 19xx
+         bhi   not20
+         adda  #100
+         sta   -1,y
+not20    bsr   getval       month
+         bsr   getval       day
+         lda   #7           AM/PM mask
+         stb   1,x
+         anda  ,x
+         bitb  #4
+         pshs  cc
+         anda  #3
+         bsr   getval1
+         puls  cc
+         beq   AM
+         lda   #12         convert to 24hr time as it is PM
+         adda  -1,y
+         sta   -1,y
+AM       bsr   getval      minute
+* and now fall through into get second
+getval   lda   #$0f
+         stb   1,x
+         anda  ,x
+getval1  decb
+         pshs  b
+         ldb   #10
+         mul
+         stb   ,y
+         puls  b
+         stb   1,x
+         decb
+         lda   ,x
+         anda  #$0f
+         adda  ,y
+         sta   ,y+
+*        rts		fall thru to Setime/Init rts
+         ENDC
+
+         IFNE  RTCElim   
+*
+* Eliminator time update  (lacks MPI slot select ability)
+*
+         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            
+
+         IFNE  RTCDsto2  
+*
+* Disto 2-in-1 RTC time update
+*
+         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            
+
+         IFNE  RTCDsto4  
+*
+* Disto 4-in-1 RTC time update
+*
+         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            
+
+         IFNE  RTCDriveWire
+*
+* Update time from DriveWire
+*
+         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            
+
+         IFNE  RTCBB+RTCCloud9
+*
+* Update time from B&B RTC
+*
+         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            
+
+         IFNE  RTCSmart
+*
+* Update time from Smartwatch RTC
+*
+mes_clk  fcc   /SmartWatch not present!/
+         fcb   $0a
+         fcc   /Reboot or replace clock2 in/
+         fcb   $0a
+         fcc   /os9boot with software version./
+         fcb   $0d
+         
+mem_mes  fcc   /There is no system memory for/
+         fcb   $0a
+         fcc   /the SmartWatch. Please reduce/
+         fcb   $0a
+         fcc   /os9boot size or use soft clock./
+         fcb   $0d
+
+start    equ   *
+         lbra  Init
+         lbra  Read
+         lbra  term
+         
+Read     pshs  cc,d,x,y,u
+         orcc  #$50
+         lda   D.SWPage
+         clrb
+         tfr   d,u         point to working space
+         lda   $FF7F
+         pshs  a
+         lda   D.RTCSlt,u  info for MPI slot
+         sta   $FF7F
+         jsr   D.Start,u   jsr to it
+         lbra  exit
+* This becomes D.Start
+reloc    equ   *
+         IFGT  Level-1
+         lda   D.HINIT
+         anda  #$CC
+         sta   $FF90
+         ENDC
+         ldb   $FFA6       choose to use normal location
+         pshs  b
+         ldb   #$3E
+         stb   $FFA6       reset MMU for clock
+         sta   $FFDE
+         ldd   #RTC.Base
+         tfr   a,dp        DP now points to clock
+findclk  lbsr  wakeup      wakeup the clock
+         IFGT  Level-1
+         ldx   #D.Sec      one incoming byte dropped
+         ELSE
+         ldx   #$58        Level1 D.Sec
+         ENDC
+         lda   #8          bytes to get
+         pshs  a
+L0050    ldb   #8
+L0052    lsr   <RTC.Read   get a bit
+         rora
+         decb  
+         bne   L0052
+         tst   D.RTCFlg,u
+         bne   maybe
+         cmpa  D.Temp,u
+         beq   maybe       clock might look like ROM
+         inc   D.RTCFlg,u  found the clock
+maybe    sta   ,x          transfer it to time
+         lda   ,s          check loop counter
+         cmpa  #8
+         beq   L006F       skip if 0.1 sec
+         cmpa  #4
+         bne   L006B       skip if not day of week
+         IFGT  Level-1
+         lda   ,x          move to correct location
+         anda  #7
+         sta   D.Daywk-D.Day,x
+         ENDC
+         bra   L006F
+L006B    cmpa  #5          hour byte
+         bne   wd
+         lda   ,x
+         bita  #%10000000  12/24hr
+         beq   wd
+         bita  #%00100000  AM/PM
+         pshs  cc
+         anda  #%00011111  keep only time
+         puls  cc
+         bne   pm
+         cmpa  #$12        these are BCD tests
+         bne   am
+         clr   ,x          12AM=0hr military
+         bra   wd
+pm       cmpa  #$12        12PM=12hr military
+         beq   wd
+         adda  #$12        1-11PM add 12 for military
+am       sta   ,x
+wd       leax  -1,x        update time slot
+         bsr   L0087       convert from BCD to binary
+L006F    dec   ,s
+         bne   L0050       get the next byte from clock
+         lda   1,x         get year
+         cmpa  #50         half assed test for century
+         bhs   c19
+         adda  #100        make it 20th
+c19      sta   1,x
+         leas  1,s
+         tst   D.RTCFlg,u
+         bne   found
+         ldb   D.RTCSlt,u
+         bitb  #$30
+         beq   found
+         subb  #$10        not found so move to next slot
+         stb   D.RTCSlt,u
+         stb   $FF7F
+         bra   findclk
+found    clra              system DP is always 0
+         tfr   a,dp
+         IFGT  Level-1
+         lda   D.HINIT     reset system before rts
+         sta   $FF90
+         ENDC
+         sta   $FFDF
+         puls  a
+         sta   $FFA6
+         rts               go back to normal code location
+         
+* Convert BCD to binary
+L0087    lda   1,x
+         clrb  
+L008A    cmpa  #$10        BCD 10
+         bcs   L0094
+         addd  #$F00A      decrease BCD by $10 and add binary 10
+         bra   L008A
+L0094    pshs  a
+         addb  ,s+
+         stb   1,x
+term     rts   
+
+wakeup   lda   <RTC.Read   clear the clock for input
+* When getting time data, bit0 is rotated into a full byte. This
+* means the result is $00 or $FF for ROM. Any other value used for a test
+* will give a false positive for the clock.
+         clrb
+         bita  #1
+         beq   w1
+         comb
+w1       stb   D.Temp,u
+         leax  alert,pcr   point to message
+nxtbyte  ldb   #8          8 bytes to send
+         lda   ,x+
+         beq   term
+nxtbit   lsra              bits sent to clock by toggling
+         bcs   high        Zero and One
+         cmpa  <RTC.Zero   faster than tst
+         bra   nxtbit2
+high     cmpa  <RTC.One
+nxtbit2  decb  
+         bne   nxtbit
+         bra   nxtbyte
+
+* SmartWatch wakeup sequence
+alert    fcb   $c5,$3a,$a3,$5c,$c5,$3a,$a3,$5c,0
+
+exit     equ   *
+         puls  a
+         sta   $FF7F       restore MPI
+         tst   D.RTCFlg,u  was clock found?
+         beq   noclock
+         puls  cc,d,x,y,u,pc
+
+noclock  equ   *
+         lda   #2          error path #
+         leax  mes_clk,pcr
+         ldy   #200         max chars
+         OS9   I$WritLn
+         puls  cc,d,x,y,u,pc
+
+         ENDC
+
+         IFNE  RTCHarrs  
+*
+* Update time from Harris RTC 
+*
+         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            
+
+         IFNE  RTCSoft   
+*
+*
+* Software time update
+*
+*
+         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             
+
+months   fcb   31,28,31,30,31,30,31,31,30,31,30,31 Days in each month
+         ENDC            
+
+
+
+SetTime  equ   *         
+
+         IFNE  RTCElim   
+*
+* Set Eliminator RTC from D.Time
+*
+         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            
+
+         IFNE  RTCDsto2  
+*
+* Set Disto 2-in-1 RTC from Time variables
+*
+         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            
+
+         IFNE  RTCDsto4  
+*
+* Set Disto 4-in-1 RTC from Time variables
+*
+         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            
+
+         IFNE  RTCBB+RTCCloud9
+*
+* Set B&B RTC from Time variables
+*
+         pshs  u,y,cc    
+         leay  SendBCD,pcr Send bytes of clock
+         lbra  TfrTime   
+         ENDC            
+
+         IFNE  RTCHarrs  
+*
+* Set Harris 1770 RTC from Time variables
+*
+         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            
+
+         IFNE  RTCSmart
+         clr   <D.SWPage        safe location for Read
+         pshs  d,x,y,u
+         IFGT  Level-1
+         ldx   <D.SysMem        get memory map
+         ldy   <D.SysDAT        get MMU map
+         ldb   #$20             first 20 pages always in use
+         abx                    point to page
+A1       tst  ,x+
+         beq   A2               found free page so go
+         incb                   update page counter
+         bpl   A1               still in RAM only, then go
+A4       lda   #2               can't find RAM only memory
+         leax  mem_mes,pcr
+         ldy   #40
+         os9   I$WritLn
+         puls  d,x,y,u,pc
+A2       pshs  b                save page #
+         andb  #%11100000       modulo MMU blocks
+         lsrb                   convert to DAT byte value
+         lsrb                   page# * $100 / $2000 = MMU #
+         lsrb                   $2000/$100=$20 at 2 bytes per MMU
+         lsrb                   then page#/$10 gives answer
+         ldd   b,y              get the MMU value
+         cmpd  #$333E           is DAT unused
+         pshs  cc               save answer
+         inc   1,s              update page # for a used page
+         puls  cc,b             get back answer and page #
+         beq   A1               if unused keep going
+         lda   #RAMinUse
+         sta   ,-x              flag the memory in use
+         ELSE
+         ldx   <$20        D.FMBM     free memory bit map
+         ldy   <$22        top of memory bit map
+         ldb   #-1         preset counter
+A1       lda   ,x+         get bits
+         incb              update $800 counter
+         pshs  y           test for end of map
+         cmpx  ,s+
+         bhi   A4          send error message
+         clr   -1,s        preset bit counter
+A2       inc   ,s
+         lsra              read left to right
+         bcs   A2
+         lda   ,s+
+         deca              convert to number of shifts
+         cmpa  #8          overflow value
+         beq   A1          get more map on ov
+         pshs  a           save the number of shifts
+         lda   #8          bytes*8
+         mul
+         addb  ,s          add modulo $800
+         cmpb  #$7E        need RAM not ROM for clock data
+         bhs   A4
+         lda   #%10000000  need to create mask to map the
+A5       lsra              unused bit, so reverse the process
+         dec   ,s          decrease shift counter
+         bne   A5
+         leas  1,s         yank counter
+         ora   -1,x        mark bit used and
+         sta   -1,x        tell the system
+         bra   A3          
+A4       leas  1,s            yank bit info
+         lda   #2             error path #
+         leax  mem_mes,pcr    good memory not found
+         ldy   #200
+         os9   I$WritLn
+         puls  d,x,y,u,pc
+A3       equ   *
+         ENDC
+         stb   <D.SWPage      keep the info for Read
+         tfr   b,a
+         clrb
+         tfr   d,x            regX now points to SW data page
+         ldb   $FF7F          get MPI values
+         andb  #3             keep IRQ info
+         orb   #$30           force slot #4 to start search
+         stb   D.RTCSlt,x     save the info
+         clr   D.RTCFlg,x     set to no clock found
+         leax  D.Start,x      safe location for moved code
+         IFNE  H6309
+         leay  reloc,pcr
+         ldw   #exit-reloc
+         tfm   y+,x+
+         ELSE
+         leau  reloc,pcr       relocation routine to move code
+         ldy   #exit-reloc     to a RAM only location
+B3       lda   ,u+
+         sta   ,x+
+         leay -1,y
+         bne   B3
+         ENDC
+         puls  d,x,y,u,pc
+         ELSE
+         rts             
+         ENDC
+
+         emod            
+len      equ   *         
+         end