changeset 1726:043d330e2f0e

Recomposed source lines to share more common code between Level 1 and Level 2 clocks
author boisy
date Thu, 11 Nov 2004 22:02:24 +0000
parents 93328dc6e3f4
children 78ce0a5ffc8e
files level1/modules/clock.asm
diffstat 1 files changed, 643 insertions(+), 689 deletions(-) [+]
line wrap: on
line diff
--- a/level1/modules/clock.asm	Sat Sep 04 23:07:01 2004 +0000
+++ b/level1/modules/clock.asm	Thu Nov 11 22:02:24 2004 +0000
@@ -21,601 +21,52 @@
 *
 *   9r6    2003/09/04  Boisy G. Pitre
 * Combined Level One and Level Two sources
-
-         nam   Clock     
-         ttl   OS-9 System Clock
-
-         IFP1            
-         use   defsfile  
-         IFGT  Level-1
-         use   cc3iodefs
-         ENDC
-         ENDC            
-
-Edtn     equ   9
-rev      equ   6 
-
-
+		
+	nam	Clock     
+	ttl	OS-9 System Clock
+		
+	ifp1	
+	use	defsfile
+	ifgt	Level-1
+	use	cc3iodefs
+	endc	
+	endc	
+		
+Edtn	equ	9
+rev	equ	6
+		
+		
 *------------------------------------------------------------
 *
 * Start of module
 *
-         mod   len,name,Systm+Objct,ReEnt+rev,Init,0
-
-name     fcs   "Clock"   
-         fcb   Edtn      
-
-         IFEQ  Level-1
-
-*TkPerTS  equ   2          ticks per time slice
-TkPerTS  equ   TkPerSec/10	ticks per time slice
-
-NewSvc   fcb   F$Time
-         fdb   FTime-*-2
-         fcb   F$VIRQ
-         fdb   FVIRQ-*-2
-         fcb   F$STime
-         fdb   FSTime-*-2
-         fcb   $80
-
-FSTime   ldx   R$X,u
-         ldd   ,x
-         std   <D.Year
-	 ldd   2,x
-	 std   <D.Day
-	 ldd   4,x
-	 std   <D.Min
-         andcc #^Carry
-
-*
-* Call SetTime entry point in Clock2
-*
-         ldx   <D.Clock2  get entry point to Clock2
-         jsr   $06,x      else call GetTime entry point
-
-         rts
-
-*
-* Clock IRQ Entry Point
-*
-ClockIRQ clra
-         tfr   a,dp                    set direct page to zero
-         lda   PIA0Base+3              get hw byte
-         bmi   L0032                   branch if sync flag on
-         jmp   [>D.SvcIRQ]
-L0032    lda   PIA0Base+2              clear interrupt?
-         dec   <D.Tick                 decrement tick counter
-         bne   L007F                   go around if not zero
-         ldb   <D.Sec                  get minutes/seconds
-* Seconds increment
-         incb                          increment seconds
-         cmpb  #60                     full minute?
-         bcs   L0079                   nope...
-
-*
-* Call GetTime entry point in Clock2
-*
-         ldx   <D.Clock2  get entry point to Clock2
-         jsr   $03,x      call GetTime entry point
-         fcb   $8C		skip next 2 bytes
-
-L0079    stb   <D.Sec                  update sec
-L007B    lda   <D.TSec
-         sta   <D.Tick
-L007F    clra
-         pshs  a
-         ldy   <D.CLTb
-         bra   L009E
-L0087    ldd   ,x
-         subd  #$0001
-         bne   L009C
-         lda   #$01
-         sta   ,s
-         lda   $04,x
-         beq   L00B8
-L0096    ora   #$01
-         sta   $04,x
-         ldd   $02,x
-L009C    std   ,x
-L009E    ldx   ,y++
-         bne   L0087
-         lda   ,s+
-         beq   L00B4
-         ldx   <D.Proc
-         beq   L00AE
-         tst   P$State,x
-         bpl   L00BC                   branch if sysstate not set
-L00AE    jsr   [>D.Poll]
-         bcc   L00AE
-L00B4    jmp   [>D.AltIRQ]
-L00B8    bsr   L00DD
-         bra   L0096
-L00BC    leay  >L00C4,pcr
-         jmp   [>D.URtoSs]
-L00C4    jsr   [>D.Poll]
-         bcc   L00C4
-         ldx   <D.Proc
-         ldb   P$State,x
-         andb  #^SysState              turn off sysstate bit
-         stb   P$State,x
-         ldd   <P$SWI2,x
-         std   <D.SWI2
-         ldd   <D.UsrIRQ
-         std   <D.SvcIRQ
-         bra   L00B4
-L00DD    pshs  y,x
-L00DF    ldx   ,y++
-         stx   -$04,y
-         bne   L00DF
-         puls  y,x
-         leay  -2,y
-         rts
-
-FVIRQ    pshs  cc
-         orcc  #FIRQMask+IRQMask
-         ldy   <D.CLTb
-         ldx   <D.Init
-         ldb   PollCnt,x
-         ldx   R$X,u
-         beq   L0118
-         tst   ,y
-         beq   L010C
-         subb  #$02
-         lslb
-         leay  b,y
-         tst   ,y
-         bne   L0128
-L0106    tst   ,--y
-         beq   L0106
-         leay  $02,y
-L010C    ldx   R$Y,u
-         stx   ,y
-         ldy   R$D,u
-         sty   ,x
-         bra   L0124
-L0118    leax  R$Y,u
-L011A    tst   ,y
-         beq   L0124
-         cmpx  ,y++
-         bne   L011A
-         bsr   L00DD
-L0124    puls  cc
-         clrb
-         rts
-L0128    puls  cc
-         comb
-         ldb   #E$Poll
-         rts
-
-Init     pshs  dp,cc
-         clra
-         tfr   a,dp
-
-         leax  <Clock2,pcr
-         lda   #Sbrtn+Objct
-         os9   F$Link    
-         bcc   LinkOk    
-         jmp   >$FFFE		reset
-LinkOk   sty   <D.Clock2	save entry point
-* Call Clock2 init routine
-         jsr   ,y         call init entry point of Clock2
-
-
-         lda   #TkPerSec
-
-         sta   <D.TSec
-         sta   <D.Tick
-
-* 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
-         stb   <D.Slice
-         orcc  #FIRQMask+IRQMask       mask ints
-         leax  >ClockIRQ,pcr
-         stx   <D.IRQ
-* install system calls
-         leay  >NewSvc,pcr
-         os9   F$SSvc
-         ldx   #PIA0Base
-         clra
-         sta   1,x                     change PIA0Base side A to DDR
-         sta   ,x                      clear PIA0Base side A
-         sta   3,x                     change PIA0Base side B to DDR
-         coma                          complement A side A
-         sta   2,x                     write all 1's to PIA0Base side B
-         lda   #$34
-         sta   1,x                     PIA0Base side A to I/O reg
-         lda   #$3F
-         sta   3,x                     PIA0Base side B to I/O reg
-         lda   2,x
-
-         puls  pc,dp,cc
-
-
-* F$Time system call code
-FTime    ldx   R$X,u
-         ldd   <D.Year
-         std   ,x
-         ldd   <D.Day
-         std   2,x
-         ldd   <D.Min
-         std   4,x
-         clrb
-         rts
-
-
-
-
-         ELSE
-
-
-
-
-* OS-9 Level Two Clock
-
-TkPerTS  equ   2          ticks per time slice
-GI.Toggl equ   %00000001  GIME CART* IRQ enable bit, for CC3
-
-* TC9 needs to reset more interrupt sources
-*GI.Toggl equ %00000111 GIME SERINT*, KEYINT*, CART* IRQ enable bits
-
-
-* Table to set up Service Calls:
-*
-NewSvc   fcb   F$Time    
-         fdb   F.Time-*-2
-         fcb   F$VIRQ    
-         fdb   F.VIRQ-*-2
-         fcb   F$Alarm   
-         fdb   F.ALARM-*-2
-         fcb   F$STime   
-         fdb   F.STime-*-2
-         fcb   $80        end of service call installation table
-
-*---------------------------------------------------------
-* IRQ Handling starts here.
-*
-* Caveat: There may not be a stack at this point, so avoid using one.
-*         Stack is set up by the kernel between here and SvcVIRQ.
-*
-SvcIRQ   lda   >IRQEnR    Get GIME IRQ Status and save it.
-         ora   <D.IRQS   
-         sta   <D.IRQS   
-         bita  #$08       Check for clock interrupt
-         beq   NoClock   
-         anda  #^$08      Drop clock interrupt
-         sta   <D.IRQS   
-         ldx   <D.VIRQ    Set VIRQ routine to be executed
-         clr   <D.QIRQ    ---x IS clock IRQ
-         bra   ContIRQ   
-
-NoClock  leax  DoPoll,pcr If not clock IRQ, just poll IRQ source
-         IFNE  H6309     
-         oim   #$FF,<D.QIRQ    ---x set flag to NOT clock IRQ
-         ELSE            
-         lda   #$FF      
-         sta   <D.QIRQ   
-         ENDC            
-ContIRQ  stx   <D.SvcIRQ 
-         jmp   [D.XIRQ]   Chain through Kernel to continue IRQ handling
-
-*------------------------------------------------------------
-*
-* IRQ handling re-enters here on VSYNC IRQ.
-*
-* - Count down VIRQ timers, mark ones that are done
-* - Call DoPoll/DoToggle to service VIRQs and IRQs and reset GIME
-* - Call Keyboard scan
-* - Update time variables
-* - At end of minute, check alarm
+	mod	len,name,Systm+Objct,ReEnt+rev,Init,0
+		
+name	fcs	"Clock"
+	fcb	Edtn
+		
+		
+	ifeq	Level-1
+TkPerTS	equ	TkPerSec/10	ticks per time slice
+        else
+TkPerTS	equ	2	ticks per time slice
+	endc
+		
 *
-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
+* Table to set up Service Calls
 *
-Dopoll                   
-         IFGT  Level-2   
-         lda   >$0643     Level 3: get map type
-         ldb   >$0645    
-         pshs  d          save for later
-         ENDC            
-Dopoll.i                 
-         jsr   [>D.Poll]  Call poll routine
-         bcc   DoPoll.i   Until error (error -> no interrupt found)
-
-         IFGT  Level-2   
-         puls  d         
-         orcc  #IntMasks 
-         sta   >$0643    
-         stb   >$0645    
-         std   >$FFA1    
-         andcc  #^IntMasks
-         ENDC            
-
-*
-* Reset GIME to avoid missed IRQs
-*
-DoToggle lda   #^GI.Toggl Mask off CART* bit
-         anda  <D.IRQS   
-         sta   <D.IRQS   
-         lda   <D.IRQER   Get current enable register status
-         tfr   a,b       
-         anda  #^GI.Toggl Mask off CART* bit
-         orb   #GI.Toggl  --- ensure that 60Hz IRQ's are always enabled
-         sta   >IRQEnR    Disable CART
-         stb   >IRQEnR    Enable CART
-         clrb            
-         rts             
-
-
-*------------------------------------------------------------
-*
-* Handle F$VIRQ system call
-*
-F.VIRQ   pshs  cc        
-         orcc  #IntMasks  Disable interrupts
-         ldy   <D.CLTb    Address of VIRQ table
-         ldx   <D.Init    Address of INIT
-         ldb   PollCnt,x  Number of polling table entries from INIT
-         ldx   R$X,u      Zero means delete entry
-         beq   RemVIRQ   
-         IFGT  Level-2   
-         bra   FindVIRQ   ---x
-
-v.loop   leay  4,y        ---x
-         ENDC            
-FindVIRQ ldx   ,y++       Is VIRQ entry null?
-         beq   AddVIRQ    If yes, add entry here
-         decb            
-         bne   FindVIRQ  
-         puls  cc        
-         comb            
-         ldb   #E$Poll   
-         rts             
-
-AddVIRQ                  
-         IFGT  Level-2   
-         ldx   R$Y,u     
-         stx   ,y        
-         lda   >$0643    
-         ldb   >$0645    
-         std   2,y       
-         ELSE            
-         leay  -2,y       point to first null VIRQ entry
-         ldx   R$Y,u     
-         stx   ,y        
-         ENDC            
-         ldy   R$D,u     
-         sty   ,x        
-         bra   virqexit  
-
-         IFGT  Level-2   
-v.chk    leay  4,y       
-RemVIRQ  ldx   ,y        
-         ELSE            
-RemVIRQ  ldx   ,y++      
-         ENDC            
-         beq   virqexit  
-         cmpx  R$Y,u     
-         bne   RemVIRQ   
-         bsr   DelVIRQ   
-virqexit puls  cc        
-         clrb            
-         rts             
-
-DelVIRQ  pshs  x,y       
-DelVLup                  
-         IFGT  Level-2   
-         ldq              ,y++		move entries up in table
-         leay  2,y       
-         stq              -8,y
-         bne   DelVLup   
-         puls  x,y,pc    
-         ELSE            
-         ldx   ,y++       move entries up in table
-         stx   -4,y      
-         bne   DelVLup   
-         puls  x,y       
-         leay  -2,y      
-         rts             
-         ENDC            
-
-         IFGT  Level-1
-*------------------------------------------------------------
-*
-* Handle F$Alarm call
-*
-F.Alarm  ldx   #WGlobal+G.AlPckt
-         ldd   R$D,u     
-         bne   DoAlarm   
-         std   G.AlPID-G.AlPckt,x Erase F$Alarm PID, Signal.
-         rts             
-
-DoAlarm  tsta             If PID != 0, set alarm for this process
-         bne   SetAlarm  
-         cmpd  #1         1 -> Set system-wide alarm
-         bne   GetAlarm  
-SetAlarm std   G.AlPID-G.AlPckt,x
-         ldy   <D.Proc   
-         lda   P$Task,y   Move from process task
-         ldb   <D.SysTsk  To system task
-         ldx   R$X,u      From address given in X
-         ldu   #WGlobal+G.AlPckt
-         ldy   #5         Move 5 bytes
-         bra   FMove     
-
-GetAlarm cmpd  #2        
-         bne   AlarmErr  
-         ldd   G.AlPID-G.AlPckt,x
-         std   R$D,u     
-         bra   RetTime   
-AlarmErr comb            
-         ldb   #E$IllArg 
-         rts             
-         ENDC
-
-*------------------------------------------------------------
-*
-* Handle F$Time System call
-*
-F.Time   equ   *
-         IFGT  Level-1
-         ldx   #D.Time    Address of system time packet
-RetTime  ldy   <D.Proc    Get pointer to current proc descriptor
-         ldb   P$Task,y   Process Task number
-         lda   <D.SysTsk  From System Task
-         ldu   R$X,u     
-STime.Mv ldy   #6         Move 6 bytes
-FMove    os9   F$Move    
-         ELSE
-         ldx   R$X,u	get pointer to caller's space
-         ldd   <D.Year	get year and month
-         std   ,x
-         ldd   <D.Day	get day and hour
-         std   2,x
-         ldd   <D.Min	get minute and second
-         std   4,x
-         clrb
-         ENDC
-         rts             
+NewSvc	fcb	F$Time
+	fdb	FTime-*-2
+	fcb	F$VIRQ
+	fdb	FVIRQ-*-2
+	ifgt	Level-1
+	fcb	F$Alarm
+	fdb	FALARM-*-2
+	endc
+	fcb	F$STime
+	fdb	FSTime-*-2
+	fcb	$80		end of service call installation table
+		
 
 *------------------------------------------------------------
 *
@@ -624,33 +75,28 @@
 * First, copy time packet from user address space to system time
 * variables, then fall through to code to update RTC.
 *
-F.STime  equ  *
-         IFGT  Level-1
-         ldx   <D.Proc    Caller's process descriptor
-         lda   P$Task,x   Source is in user map
-         ldx   R$X,u      Address of caller's time packet
-         ldu   #D.Time    Destination address
-         ldb   <D.SysTsk  Destination is in system map
-         bsr   STime.Mv   Get time packet (ignore errors)
-         ELSE
-         ldx   R$X,u
-         ldd   ,x
-         std   <D.Year
-         ldd   2,x
-         std   <D.Day
-         ldd   4,x
-         std   <D.Min
-         ENDC
-         lda   #TkPerSec  Reset to start of second
-         sta   <D.Tick   
+FSTime	equ	*
+	ifgt	Level-1
+	ldx	<D.Proc		caller's process descriptor
+	lda	P$Task,x	source is in user map
+	ldx	R$X,u		address of caller's time packet
+	ldu	#D.Time		destination address
+	ldb	<D.SysTsk	destination is in system map
+	bsr	STime.Mv	get time packet (ignore errors)
+	else	
+	ldx	R$X,u
+	ldd	,x
+	std	<D.Year
+	ldd	2,x
+	std	<D.Day
+	ldd	4,x
+	std	<D.Min
+	endc	
+	lda	#TkPerSec	reset to start of second
+	sta	<D.Tick
+	ldx	<D.Clock2	get entry point to Clock2
+	jmp	$06,x		and call GetTime entry point
 
-*
-* Call SetTime entry point in Clock2
-*
-         ldx   <D.Clock2  get entry point to Clock2
-         jsr   $06,x      else call GetTime entry point
-
-NoSet    rts             
 
 *--------------------------------------------------
 *
@@ -662,82 +108,590 @@
 * 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
-
-         IFGT  Level-1
+Init
+	ifeq	Level-1
+	pshs	dp,cc		save DP and CC
+	clra	
+	tfr	a,dp		set DP to zero
+	else
+	ldx	<D.Proc		save user proc
+	pshs	x
+	ldx	<D.SysPrc	make sys for link
+	stx	<D.Proc
+	endc
+	leax	<Clock2,pcr
+	lda	#Sbrtn+Objct
+	os9	F$Link
+	puls	x
+	stx	<D.Proc		restore user proc
+	bcc	LinkOk
+	ifeq	Level-1
+	jmp	>$FFFE		level 1: jump to reset vector
+	else
+	lda	#E$MNF
+	jmp	<D.Crash	level 2: jump to CRASH vector
+	endc
+LinkOk	sty	<D.Clock2	save entry point
+InitCont
+	ldx	#PIA0Base	point to PIA0
+	clra			no error for return...
+	pshs	cc		save IRQ enable status (and Carry clear)
+	orcc	#IntMasks	stop interrupts
+		
+	ifgt	Level-1
 * Note: this code can go away once we have a rel_50hz
-         IFEQ  TkPerSec-50
-         ldb   <D.VIDMD   get video mode register copy
-         orb   #$08       set 50 Hz VSYNC bit
-         stb   <D.VIDMD   save video mode register copy
-         stb   >$FF98     set 50 Hz VSYNC
-         ENDC            
-         ENDC
+	ifeq	TkPerSec-50
+	ldb	<D.VIDMD	get video mode register copy
+	orb	#$08		set 50 Hz VSYNC bit
+	stb	<D.VIDMD	save video mode register copy
+	stb	>$FF98		set 50 Hz VSYNC
+	endc	
+	endc	
+		
+	sta	1,x		enable DDRA
+	sta	,x		set port A all inputs
+	sta	3,x		enable DDRB
+	coma	
+	sta	2,x		set port B all outputs
+	ldd	#$343C		[A]=PIA0 CRA contents, [B]=PIA0 CRB contents
+	sta	1,x		CA2 (MUX0) out low, port A, disable HBORD high-to-low IRQs
+	stb	3,x		CB2 (MUX1) out low, port B, disable VBORD low-to-high IRQs
+	ifgt	Level-1
+	lda	,x		clear possible pending PIA0 HBORD IRQ
+	endc
+	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
+	ifgt	Level-1
+	leax	SvcVIRQ,pcr	set VIRQ handler
+	stx	<D.VIRQ
+	endc
+	leay	NewSvc,pcr	insert syscalls
+	os9	F$SSvc
+	ifgt	Level-1
+	ifne	H6309
+	oim	#$08,<D.IRQER
+	else	
+	lda	<D.IRQER	get shadow GIME IRQ enable register
+	ora	#$08		set VBORD bit
+	sta	<D.IRQER	save shadow register
+	endc	
+	sta	>IRQEnR		enable GIME VBORD IRQs
+	endc	
+* Call Clock2 init routine
+	ldy	<D.Clock2	get entry point to Clock2
+	jsr	,y		call init entry point of Clock2
+InitRts	puls	cc,pc		recover IRQ enable status and return
 
-         sta   1,x        enable DDRA
-         sta   ,x         set port A all inputs
-         sta   3,x        enable DDRB
-         coma            
-         sta   2,x        set port B all outputs
-         ldd   #$343C     [A]=PIA0 CRA contents, [B]=PIA0 CRB contents
-         sta   1,x        CA2 (MUX0) out low, port A, disable HBORD high-to-low IRQs
-         stb   3,x        CB2 (MUX1) out low, port B, disable VBORD low-to-high IRQs
-         lda   ,x         clear possible pending PIA0 HBORD IRQ
-         lda   2,x        clear possible pending PIA0 VBORD IRQ
-
-* Don't need to explicitly read RTC during initialization
-         ldd   #59*256+TkPerTS last second and time slice in minute
-         std   <D.Sec     Will prompt RTC read at next time slice
-
-         stb   <D.TSlice  set ticks per time slice
-         stb   <D.Slice   set first time slice
-         leax  SvcIRQ,pcr set IRQ handler
-         stx   <D.IRQ    
-         leax  SvcVIRQ,pcr set VIRQ handler
-         stx   <D.VIRQ   
-         leay  NewSvc,pcr insert syscalls
-         os9   F$SSvc    
-         IFGT  Level-1
-         IFNE  H6309
-         oim   #$08,<D.IRQER
-         ELSE
-         lda   <D.IRQER   get shadow GIME IRQ enable register
-         ora   #$08       set VBORD bit
-         sta   <D.IRQER   save shadow register
-         ENDC
-         sta   >IRQEnR    enable GIME VBORD IRQs
-         ENDC
-
-* Call Clock2 init routine
-         ldy   <D.Clock2  get entry point to Clock2
-         jsr   ,y         call init entry point of Clock2
-InitRts  puls  cc,pc      recover IRQ enable status and return
-
-         ENDC
 
 
-Clock2   fcs   "Clock2"  
+	ifeq	Level-1
+*
+* Clock IRQ Entry Point
+*
+* Called once every 1.66666ms
+SvcIRQ
+	clra	
+	tfr	a,dp		set direct page to zero
+	lda	PIA0Base+3	get hw byte
+	bmi	L0032		branch if sync flag on
+	jmp	[>D.SvcIRQ]	else service other possible IRQ
+L0032	lda	PIA0Base+2	clear interrupt
+	dec	<D.Tick		decrement tick counter
+	bne	L007F		go around if not zero
+	ldb	<D.Sec		get minutes/seconds
+* Seconds increment
+	incb			increment seconds
+	cmpb	#60		full minute?
+	bcs	L0079		nope...
+*
+* Call GetTime entry point in Clock2
+*
+	ldx	<D.Clock2	get entry point to Clock2
+	jsr	$03,x		call GetTime entry point
+	fcb	$8C		skip next 2 bytes
+L0079	stb	<D.Sec		update sec
+L007B	lda	<D.TSec		get ticks per second value
+	sta	<D.Tick		and repopulate tick decrement counter
+L007F	clra			clear A
+	pshs	a		and save it on the stack
+	ldy	<D.CLTb		get pointer to VIRQ Polling Entries
+	bra	L009E		go to the processing portion of the loop
+L0087	ldd	Vi.Cnt,x	get count down counter
+	subd	#$0001		subtract tick count
+	bne	L009C		branch if not at terminal count ($0000)
+	lda	#$01
+	sta	,s		set flag on stack to 1
+	lda	Vi.Stat,x	get status byte
+	beq	DelEntry	branch if zero (one shot, so delete)
+L0096	ora	#Vi.IFlag	set interrupted flag
+	sta	Vi.Stat,x	save in packet
+	ldd	Vi.Rst,x	get reset count
+L009C	std	Vi.Cnt,x	save tick count back
+L009E	ldx	,y++		get two bytes at Y
+	bne	L0087		if not zero, branch
+	lda	,s+		else get byte off stack
+	beq	GoAltIRQ	branch if zero
+	ldx	<D.Proc		else get pointer to current process descriptor
+	beq	L00AE		branch if none
+	tst	P$State,x	test process' state
+	bpl	UsrPoll		branch if system state not set
+L00AE	jsr	[>D.Poll]	poll ISRs
+	bcc	L00AE		keep polling until carry set
+GoAltIRQ
+	jmp	[>D.AltIRQ]	jump into an alternate IRQ if available
+DelEntry
+	bsr	DelVIRQ		delete the VIRQ entry
+	bra	L0096
+
+UsrPoll	leay	>up@,pcr	point to routine to execute
+	jmp	[>D.URtoSs]	User to System
+up@	jsr	[>D.Poll]	call polling routine
+	bcc	up@		keep polling until carry set
+	ldx	<D.Proc		get current process descriptor
+	ldb	P$State,x	and its state
+	andb	#^SysState	turn off sysstate bit
+	stb	P$State,x	save new state
+	ldd	<P$SWI2,x
+	std	<D.SWI2
+	ldd	<D.UsrIRQ
+	std	<D.SvcIRQ
+	bra	GoAltIRQ
 
-         emod            
-len      equ   *         
-         end             
+DelVIRQ	pshs	y,x		save off Y,X
+dl@	ldx	,y++		get next entry
+	stx	-$04,y		move up
+	bne	dl@		continue until all are moved
+	puls	y,x		restore
+	leay	-2,y		move back 2 from Y (points to last entry)
+	rts			return
+		
+* Install or Remove VIRQ Entry
+FVIRQ	pshs	cc
+	orcc	#IntMasks	mask all interrupts
+	ldy	<D.CLTb		get pointer to VIRQ polling table
+	ldx	<D.Init		get pointer to init module
+	ldb	PollCnt,x	get poll count
+	ldx	R$X,u		get pointer to caller's X
+	beq	L0118		branch if removing
+	tst	,y		entry available?
+	beq	L010C
+	subb	#$02
+	lslb	
+	leay	b,y
+	tst	,y
+	bne	PTblFul		polling table full
+L0106	tst	,--y
+	beq	L0106
+	leay	$02,y
+L010C	ldx	R$Y,u
+	stx	,y
+	ldy	R$D,u
+	sty	,x
+	bra	L0124
+L0118	leax	R$Y,u		X = caller's Y
+L011A	tst	,y		end of VIRQ table
+	beq	L0124		branch if so
+	cmpx	,y++		else compare to current VIRQ entry and inc Y
+	bne	L011A		continue searching if not matched
+	bsr	DelVIRQ		else delete entry
+L0124	puls	cc
+	clrb	
+	rts	
+PTblFul	puls	cc
+	comb	
+	ldb	#E$Poll
+	rts	
+		
+		
+		
+* F$Time system call code
+FTime	ldx	R$X,u
+	ldd	<D.Year
+	std	,x
+	ldd	<D.Day
+	std	2,x
+	ldd	<D.Min
+	std	4,x
+	clrb	
+	rts	
+		
+		
+		
+		
+	else	
+		
+		
+		
+		
+* OS-9 Level Two Clock
+		
+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
+		
+		
+*---------------------------------------------------------
+* 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
+	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
+	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	
+d@	jsr	[>D.Poll]	call poll routine
+	bcc	d@		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
+*
+FVIRQ	pshs	cc
+	orcc	#IntMasks	disable interrupts
+	ldy	<D.CLTb		address of VIRQ table
+	ldx	<D.Init		address of INIT
+	ldb	PollCnt,x	number of polling table entries from INIT
+	ldx	R$X,u		zero means delete entry
+	beq	RemVIRQ
+	ifgt	Level-2
+	bra	FindVIRQ	---x
+		
+v.loop	leay	4,y		---x
+	endc	
+FindVIRQ
+	ldx	,y++		is VIRQ entry null?
+	beq	AddVIRQ		if yes, add entry here
+	decb	
+	bne	FindVIRQ
+	puls	cc
+	comb	
+	ldb	#E$Poll
+	rts	
+		
+AddVIRQ		
+	ifgt	Level-2
+	ldx	R$Y,u
+	stx	,y
+	lda	>$0643
+	ldb	>$0645
+	std	2,y
+	else	
+	leay	-2,y		point to first null VIRQ entry
+	ldx	R$Y,u
+	stx	,y
+	endc	
+	ldy	R$D,u
+	sty	,x
+	bra	virqexit
+		
+	ifgt	Level-2
+v.chk	leay	4,y
+RemVIRQ	ldx	,y
+	else	
+RemVIRQ	ldx	,y++
+	endc	
+	beq	virqexit
+	cmpx	R$Y,u
+	bne	RemVIRQ
+	bsr	DelVIRQ
+virqexit	puls	cc
+	clrb	
+	rts	
+		
+DelVIRQ	pshs	x,y
+DelVLup		
+	ifgt	Level-2
+	ldq	,y++		move entries up in table
+	leay	2,y
+	stq	-8,y
+	bne	DelVLup
+	puls	x,y,pc
+	else	
+	ldx	,y++		move entries up in table
+	stx	-4,y
+	bne	DelVLup
+	puls	x,y
+	leay	-2,y
+	rts	
+	endc	
+		
+	ifgt	Level-1
+*------------------------------------------------------------
+*
+* Handle F$Alarm call
+*
+FAlarm	ldx	#WGlobal+G.AlPckt
+	ldd	R$D,u
+	bne	DoAlarm
+	std	G.AlPID-G.AlPckt,x	erase F$Alarm PID, Signal.
+	rts	
+		
+DoAlarm	tsta			if PID != 0, set alarm for this process
+	bne	SetAlarm
+	cmpd	#1		1 -> Set system-wide alarm
+	bne	GetAlarm
+SetAlarm
+	std	G.AlPID-G.AlPckt,x
+	ldy	<D.Proc
+	lda	P$Task,y	move from process task
+	ldb	<D.SysTsk	to system task
+	ldx	R$X,u		from address given in X
+	ldu	#WGlobal+G.AlPckt
+	ldy	#5		move 5 bytes
+	bra	FMove
+		
+GetAlarm
+	cmpd	#2
+	bne	AlarmErr
+	ldd	G.AlPID-G.AlPckt,x
+	std	R$D,u
+	bra	RetTime
+AlarmErr
+	comb	
+	ldb	#E$IllArg
+	rts	
+	endc	
+		
+*------------------------------------------------------------
+*
+* Handle F$Time System call
+*
+FTime	equ	*
+	ifgt	Level-1
+	ldx	#D.Time		address of system time packet
+RetTime	ldy	<D.Proc		get pointer to current proc descriptor
+	ldb	P$Task,y	process Task number
+	lda	<D.SysTsk	from System Task
+	ldu	R$X,u
+STime.Mv
+	ldy	#6		move 6 bytes
+FMove	os9	F$Move
+	else	
+	ldx	R$X,u		get pointer to caller's space
+	ldd	<D.Year		get year and month
+	std	,x
+	ldd	<D.Day		get day and hour
+	std	2,x
+	ldd	<D.Min		get minute and second
+	std	4,x
+	clrb	
+	endc	
+	rts	
+		
+		
+	endc	
+		
+		
+Clock2	fcs	"Clock2"
+		
+	emod	
+len	equ	*
+	end