changeset 2654:4036f8e844a7

Level 2 now has its own clock source again
author Boisy Pitre <boisy.pitre@nuance.com>
date Tue, 10 Apr 2012 21:33:53 -0500
parents 40d55004f686
children ead54d2c06d4
files level1/atari/bootfiles/makefile level2/modules/clock.asm
diffstat 2 files changed, 498 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/level1/atari/bootfiles/makefile	Tue Apr 03 21:13:12 2012 -0500
+++ b/level1/atari/bootfiles/makefile	Tue Apr 10 21:33:53 2012 -0500
@@ -11,7 +11,7 @@
 # IMPORTANT! KRN MUST BE THE LAST MODULE IN BOOTFILE_P1!!
 BOOTFILE_P1 = $(MD)/krnp2 $(MD)/init $(MD)/ioman $(MD)/sysgo \
 		$(MD)/dw3.sb \
-		$(MD)/clock_60hz $(MD)/clock2_soft \
+		$(MD)/clock_60hz $(MD)/clock2_dw3 \
           $(MD)/krn
 
 BOOTFILE_P2 = $(MD)/scf.mn $(MD)/vtio.dr $(MD)/term.dt \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level2/modules/clock.asm	Tue Apr 10 21:33:53 2012 -0500
@@ -0,0 +1,497 @@
+********************************************************************
+* Clock - Clock for OS-9 Level Two/NitrOS-9
+*
+* Clock module for CoCo 3 and TC9 OS9 Level 2 and NitrOS-9
+*
+* Includes support for several different RTC chips, GIME Toggle
+* IRQ fix, numerous minor changes.
+*
+* Based on Microware/Tandy Clock Module for CC3/L2
+*
+* $Id$
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*          ????/??/??
+* NitrOS-9 2.00 distribution.
+*
+*   9r4    2003/01/01  Boisy G. Pitre
+* Back-ported to OS-9 Level Two.
+*
+*   9r5    2003/08/18  Boisy G. Pitre
+* Separated clock into Clock and Clock2 for modularity.
+
+         nam   Clock     
+         ttl   Clock for OS-9 Level Two/NitrOS-9
+
+TkPerTS  equ   2          ticks per time slice
+GI.Toggl equ   %00000001  GIME CART* IRQ enable bit, for CC3
+
+* TC9 needs to reset more interrupt sources
+*GI.Toggl equ %00000111 GIME SERINT*, KEYINT*, CART* IRQ enable bits
+
+         IFP1            
+         use   defsfile  
+         use   cocovtio.d  
+         ENDC            
+
+Edtn     equ   9         
+Vrsn     equ   5         
+
+*------------------------------------------------------------
+*
+* Start of module
+*
+         mod   len,name,Systm+Objct,ReEnt+Vrsn,Init,0
+
+name     fcs   "Clock"   
+         fcb   Edtn      
+
+*
+* Table to set up Service Calls:
+*
+NewSvc   fcb   F$Time    
+         fdb   F.Time-*-2
+         fcb   F$VIRQ    
+         fdb   F.VIRQ-*-2
+         fcb   F$Alarm   
+         fdb   F.ALARM-*-2
+         fcb   F$STime   
+         fdb   F.STime-*-2
+         fcb   $80        end of service call installation table
+
+*---------------------------------------------------------
+* IRQ Handling starts here.
+*
+* Caveat: There may not be a stack at this point, so avoid using one.
+*         Stack is set up by the kernel between here and SvcVIRQ.
+*
+SvcIRQ   lda   >IRQEnR    Get GIME IRQ Status and save it.
+         ora   <D.IRQS   
+         sta   <D.IRQS   
+         bita  #$08       Check for clock interrupt
+         beq   NoClock   
+         anda  #^$08      Drop clock interrupt
+         sta   <D.IRQS   
+         ldx   <D.VIRQ    Set VIRQ routine to be executed
+         clr   <D.QIRQ    ---x IS clock IRQ
+         bra   ContIRQ   
+
+NoClock  leax  DoPoll,pcr If not clock IRQ, just poll IRQ source
+         IFNE  H6309     
+         oim              #$FF,<D.QIRQ    ---x set flag to NOT clock IRQ
+         ELSE            
+         lda   #$FF      
+         sta   <D.QIRQ   
+         ENDC            
+ContIRQ  stx   <D.SvcIRQ 
+         jmp   [D.XIRQ]   Chain through Kernel to continue IRQ handling
+
+*------------------------------------------------------------
+*
+* IRQ handling re-enters here on VSYNC IRQ.
+*
+* - Count down VIRQ timers, mark ones that are done
+* - Call DoPoll/DoToggle to service VIRQs and IRQs and reset GIME
+* - Call Keyboard scan
+* - Update time variables
+* - At end of minute, check alarm
+*
+SvcVIRQ  clra             Flag if we find any VIRQs to service
+         pshs  a         
+         ldy   <D.CLTb    Get address of VIRQ table
+         bra   virqent   
+
+virqloop equ   *         
+         IFGT  Level-2   
+         ldd   2,y        Get Level 3 extended map type
+         orcc  #IntMasks 
+         sta   >$0643    
+         stb   >$0645    
+         std   >$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            
+
+*------------------------------------------------------------
+*
+* Handle F$Alarm call
+*
+F.Alarm  ldx   #WGlobal+G.AlPckt
+         ldd   R$D,u     
+         bne   DoAlarm   
+         std   G.AlPID-G.AlPckt,x Erase F$Alarm PID, Signal.
+         rts             
+
+DoAlarm  tsta             If PID != 0, set alarm for this process
+         bne   SetAlarm  
+         cmpd  #1         1 -> Set system-wide alarm
+         bne   GetAlarm  
+SetAlarm std   G.AlPID-G.AlPckt,x
+         ldy   <D.Proc   
+         lda   P$Task,y   Move from process task
+         ldb   <D.SysTsk  To system task
+         ldx   R$X,u      From address given in X
+         ldu   #WGlobal+G.AlPckt
+         ldy   #5         Move 5 bytes
+         bra   FMove     
+
+GetAlarm cmpd  #2        
+         bne   AlarmErr  
+         ldd   G.AlPID-G.AlPckt,x
+         std   R$D,u     
+         bra   RetTime   
+AlarmErr comb            
+         ldb   #E$IllArg 
+         rts             
+
+*------------------------------------------------------------
+*
+* Handle F$Time System call
+*
+F.Time   equ   *
+         ldx   #D.Time    Address of system time packet
+RetTime  ldy   <D.Proc    Get pointer to current proc descriptor
+         ldb   P$Task,y   Process Task number
+         lda   <D.SysTsk  From System Task
+         ldu   R$X,u     
+STime.Mv ldy   #6         Move 6 bytes
+FMove    os9   F$Move    
+         rts             
+
+*------------------------------------------------------------
+*
+* Handle F$STime system call
+*
+* First, copy time packet from user address space to system time
+* variables, then fall through to code to update RTC.
+*
+F.STime  equ  *
+         ldx   <D.Proc    Caller's process descriptor
+         lda   P$Task,x   Source is in user map
+         ldx   R$X,u      Address of caller's time packet
+         ldu   #D.Time    Destination address
+         ldb   <D.SysTsk  Destination is in system map
+         bsr   STime.Mv   Get time packet (ignore errors)
+         lda   #TkPerSec  Reset to start of second
+         sta   <D.Tick   
+
+*
+* Call SetTime entry point in Clock2
+         ldx   <D.Clock2  get entry point to Clock2
+         jsr   $06,x      else call GetTime entry point
+
+NoSet    rts             
+
+Clock2   fcs   "Clock2"  
+
+*--------------------------------------------------
+*
+* Clock Initialization
+*
+* This vector is called by the kernel to service the first F$STime
+* call.  F$STime is usually called by CC3Go (with a dummy argument)
+* in order to initialize the clock.  F$STime is re-vectored to the
+* service code above to handle future F$STime calls.
+*
+*
+Init     ldx   <D.Proc    save user proc
+         pshs  x         
+         ldx   <D.SysPrc  make sys for link
+         stx   <D.Proc   
+
+         leax  <Clock2,pcr
+         lda   #Sbrtn+Objct
+         os9   F$Link    
+
+* And here, we restore the original D.Proc value
+         puls  x         
+         stx   <D.Proc    restore user proc
+
+         bcc   LinkOk    
+         lda   #E$MNF    
+         jmp   <D.Crash  
+LinkOk   sty   <D.Clock2  save entry point
+InitCont ldx   #PIA0Base  point to PIA0
+         clra             no error for return...
+         pshs  cc         save IRQ enable status (and Carry clear)
+         orcc  #IntMasks  stop interrupts
+
+* Note: this code can go away once we have a rel_50hz
+         IFEQ  TkPerSec-50
+         ldb   <D.VIDMD   get video mode register copy
+         orb   #$08       set 50 Hz VSYNC bit
+         stb   <D.VIDMD   save video mode register copy
+         stb   >$FF98     set 50 Hz VSYNC
+         ENDC
+
+         sta   1,x        enable DDRA
+         sta   ,x         set port A all inputs
+         sta   3,x        enable DDRB
+         coma            
+         sta   2,x        set port B all outputs
+         ldd   #$343C     [A]=PIA0 CRA contents, [B]=PIA0 CRB contents
+         sta   1,x        CA2 (MUX0) out low, port A, disable HBORD high-to-low IRQs
+         stb   3,x        CB2 (MUX1) out low, port B, disable VBORD low-to-high IRQs
+         sta   $23,x      disable CART +RG Mar 14, 2012
+         lda   ,x         clear possible pending PIA0 HBORD IRQ
+         lda   2,x        clear possible pending PIA0 VBORD IRQ
+
+* Don't need to explicitly read RTC during initialization
+         ldd   #59*256+TkPerTS last second and time slice in minute
+         std   <D.Sec     Will prompt RTC read at next time slice
+
+         stb   <D.TSlice  set ticks per time slice
+         stb   <D.Slice   set first time slice
+         leax  SvcIRQ,pcr set IRQ handler
+         stx   <D.IRQ    
+         leax  SvcVIRQ,pcr set VIRQ handler
+         stx   <D.VIRQ   
+         leay  NewSvc,pcr insert syscalls
+         os9   F$SSvc    
+* H6309 optimization opportunity here using oim
+         lda   <D.IRQER   get shadow GIME IRQ enable register
+         ora   #$08       set VBORD bit
+         sta   <D.IRQER   save shadow register
+         sta   >IRQEnR    enable GIME VBORD IRQs
+
+* Call Clock2 init routine
+         ldy   <D.Clock2  get entry point to Clock2
+         jsr   ,y         call init entry point of Clock2
+InitRts  puls  cc,pc      recover IRQ enable status and return
+
+         emod            
+len      equ   *         
+         end