view level2/modules/clock.asm @ 2811:611715587834 lwtools-port

Updated rules.mak and level1/coco1/bootfiles/makefile Updated the rules.mak file to remove the format entire image related to drivewire server disk images. Updated level1/coco1/bootfiles/makefile to create 3 new bootfile images. These images are stripped down to just the common files needed for vovdg games on os9 level 1. These bootfiles are for becker, dw, and arduino. Also corrected a duplicated dd descriptor when building some bootfiles that had both floppy_40d, floppy_80d, RBDW, RBBECKER, and RBARDUINO. Removed the dd descriptor from each of these sections and made it where the dd descriptor for the specific section was added in the main bootfile list.
author David Ladd <drencor-xeen@users.sf.net>
date Mon, 11 Feb 2013 20:16:24 -0600
parents 4036f8e844a7
children f77ac3ae8a43
line wrap: on
line source

********************************************************************
* 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