view level1/modules/mc09clock.asm @ 3277:33d539c123cf

d64: Add mb.ddisk script for making Dragon boot floppy At least it works in XRoar when running off a 80d floppy and preparing a new 40d boot floppy in the second drive. The "format" must be run manually for now since there is not enough memory to run it from inside the script...
author Tormod Volden <debian.tormod@gmail.com>
date Sat, 07 Mar 2020 23:15:05 +0100
parents 174eb9eda7b1
children
line wrap: on
line source

********************************************************************
* Clock - NitrOS-9 System Clock
*
* $Id$
*
* Edt/Rev  YYYY/MM/DD  Modified by
* Comment
* ------------------------------------------------------------------
*          2015/09/09  Neal Crook
* Created from clock.asm version 9r8. This version for 50Hz timer on
* multicomp09.


* [NAC HACK 2015Sep09] Inherited behaviour: this just stomps into
* D.IRQ so I assume that nothing could have been there before (ie
* because it's the "owner" of this vector). If there is an interrupt
* that is NOT a timer interrupt we jump through D.SvcIRQ, which is
* the list of other devices that might want to claim the interrupt.
* At the end of the timer interrupt service routine (ISR) we don't
* jump through D.SvcIRQ. The assumption is that there is only one
* interruptor. If that assumption tests false, the interrupt will
* still be asserted and we'll come straight back into this ISR.
* The timer ISR checks something and considers dispatching through
* AltIRQ. What's that all about?


         nam   Clock
         ttl   NitrOS-9 System Clock

         use   defsfile

tylg     set   Systm+Objct
atrv     set   ReEnt+rev
rev      set   8
edition  set   9

*------------------------------------------------------------
* For a detailed hardware description of the Multicomp09
* timer, refer to mc09.d
*

*------------------------------------------------------------
*
* Start of module
*
         mod   len,name,tylg,atrv,init,0

name     fcs   "Clock"
         fcb   edition


TkPerTS  equ   TkPerSec/10 ticks per time slice

*
* Table to set up Service Calls
*
NewSvc   fcb   F$Time
         fdb   FTime-*-2
         fcb   F$VIRQ
         fdb   FVIRQ-*-2
         fcb   F$STime
         fdb   FSTime-*-2
         fcb   $80        end of service call installation table


*------------------------------------------------------------
*
* 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.
*
FSTime   equ   *
         ldx   R$X,u
         ldd   ,x
         std   <D.Year
         ldd   2,x
         std   <D.Day
         ldd   4,x
         std   <D.Min
         lda   #TkPerSec  reset to start of second
         sta   <D.Tick
         ldx   <D.Clock2  get entry point to Clock2
         clra             clear carry
         jmp   $06,x      and call SetTime entry point

*--------------------------------------------------
*
* Clock Initialization
*
* This vector is called by the kernel to service the first F$STime
* call.  F$STime is usually called by SysGo (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.
*
*

Clock2   fcs   "Clock2"

init
         pshs  dp,cc      save DP and CC
         clra
         tfr   a,dp       set DP to zero
         leax  <Clock2,pcr
         lda   #Sbrtn+Objct
         os9   F$Link
         bcc   LinkOk
         jmp   >$FFFE     level 1: jump to reset vector

LinkOk
         puls  cc,dp      ; Restore saved dp and cc
         sty   <D.Clock2  save entry point
InitCont
* Do not need to explicitly read RTC during initialization
         ldd   #59*256+$01 last second and last tick
         std   <D.Sec     will prompt RTC read at next time slice
         ldb   #TkPerSec
         stb   <D.TSec    set ticks per second
         ldb   #TkPerTS   get ticks per 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

         leay  NewSvc,pcr insert syscalls
         os9   F$SSvc

* Call Clock2 init routine
         ldy   <D.Clock2  get entry point to Clock2
         jsr   ,y         call init entry point of Clock2

* Initialize clock hardware
         lda   #2         enable timer and its interrupt
         sta   TIMER
         rts


*
* Clock IRQ Entry Point
*
* For Multicomp09, called 50 times/s ie once every 20ms
SvcIRQ
         clra
         tfr   a,dp       set direct page to zero

* The increment sets N depending upon whether the timer interrupted
         inc   TIMER
         bmi   TimInt
         jmp   [>D.SvcIRQ] else service other possible IRQ
TimInt
         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

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

         emod
len      equ   *
         end