comparison level2/modules/mc09clock.asm @ 3131:e1aadba01e81

Add new Level 2 port for Multicomp09 "mc09l2" Add infrastructure (directories, makefiles etc). Target name is mc09l2 to distinguish it from the Level 1 port (target name mc09). In the code, the name mc09 is used for platform-dependent code, whether for Level 1 or Level 2.
author Neal Crook <foofoobedoo@gmail.com>
date Mon, 05 Dec 2016 17:39:03 +0000
parents
children b79920779783
comparison
equal deleted inserted replaced
3130:e0614e08fa5e 3131:e1aadba01e81
1 ********************************************************************
2 * Clock - Clock for OS-9 Level Two/NitrOS-9
3 *
4 * Clock module for CoCo 3 and TC9 OS9 Level 2 and NitrOS-9
5 *
6 * Includes support for several different RTC chips, GIME Toggle
7 * IRQ fix, numerous minor changes.
8 *
9 * Based on Microware/Tandy Clock Module for CC3/L2
10 *
11 * $Id$
12 *
13 * Edt/Rev YYYY/MM/DD Modified by
14 * Comment
15 * ------------------------------------------------------------------
16 * ????/??/??
17 * NitrOS-9 2.00 distribution.
18 *
19 * 9r4 2003/01/01 Boisy G. Pitre
20 * Back-ported to OS-9 Level Two.
21 *
22 * 9r5 2003/08/18 Boisy G. Pitre
23 * Separated clock into Clock and Clock2 for modularity.
24
25 nam Clock
26 ttl Clock for OS-9 Level Two/NitrOS-9
27
28 TkPerTS equ 2 ticks per time slice
29 GI.Toggl equ %00000001 GIME CART* IRQ enable bit, for CC3
30
31 * TC9 needs to reset more interrupt sources
32 *GI.Toggl equ %00000111 GIME SERINT*, KEYINT*, CART* IRQ enable bits
33
34 IFP1
35 use defsfile
36 use cocovtio.d
37 ENDC
38
39 Edtn equ 9
40 Vrsn equ 5
41
42 *------------------------------------------------------------
43 *
44 * Start of module
45 *
46 mod len,name,Systm+Objct,ReEnt+Vrsn,Init,0
47
48 name fcs "Clock"
49 fcb Edtn
50
51 *
52 * Table to set up Service Calls:
53 *
54 NewSvc fcb F$Time
55 fdb F.Time-*-2
56 fcb F$VIRQ
57 fdb F.VIRQ-*-2
58 fcb F$Alarm
59 fdb F.ALARM-*-2
60 fcb F$STime
61 fdb F.STime-*-2
62 fcb $80 end of service call installation table
63
64 *---------------------------------------------------------
65 * IRQ Handling starts here.
66 *
67 * Caveat: There may not be a stack at this point, so avoid using one.
68 * Stack is set up by the kernel between here and SvcVIRQ.
69 *
70 SvcIRQ lda >IRQEnR Get GIME IRQ Status and save it.
71 ora <D.IRQS
72 sta <D.IRQS
73 bita #$08 Check for clock interrupt
74 beq NoClock
75 anda #^$08 Drop clock interrupt
76 sta <D.IRQS
77 ldx <D.VIRQ Set VIRQ routine to be executed
78 clr <D.QIRQ ---x IS clock IRQ
79 bra ContIRQ
80
81 NoClock leax DoPoll,pcr If not clock IRQ, just poll IRQ source
82 IFNE H6309
83 oim #$FF,<D.QIRQ ---x set flag to NOT clock IRQ
84 ELSE
85 lda #$FF
86 sta <D.QIRQ
87 ENDC
88 ContIRQ stx <D.SvcIRQ
89 jmp [D.XIRQ] Chain through Kernel to continue IRQ handling
90
91 *------------------------------------------------------------
92 *
93 * IRQ handling re-enters here on VSYNC IRQ.
94 *
95 * - Count down VIRQ timers, mark ones that are done
96 * - Call DoPoll/DoToggle to service VIRQs and IRQs and reset GIME
97 * - Call Keyboard scan
98 * - Update time variables
99 * - At end of minute, check alarm
100 *
101 SvcVIRQ clra Flag if we find any VIRQs to service
102 pshs a
103 ldy <D.CLTb Get address of VIRQ table
104 bra virqent
105
106 virqloop equ *
107 IFGT Level-2
108 ldd 2,y Get Level 3 extended map type
109 orcc #IntMasks
110 sta >$0643
111 stb >$0645
112 std >DAT.Regs+1
113 andcc #^IntMasks
114 ENDC
115
116 ldd Vi.Cnt,x Decrement tick count
117 IFNE H6309
118 decd --- subd #1
119 ELSE
120 subd #$0001
121 ENDC
122 bne notzero Is this one done?
123 lda Vi.Stat,x Should we reset?
124 bmi doreset
125 lbsr DelVIRQ No, delete this entry
126 doreset ora #$01 Mark this VIRQ as triggered.
127 sta Vi.Stat,x
128 lda #$80 Add VIRQ as interrupt source
129 sta ,s
130 ldd Vi.Rst,x Reset from Reset count.
131 notzero std Vi.Cnt,x
132 virqent ldx ,y++
133 bne virqloop
134
135 IFGT Level-2
136 puls d
137 orcc #Carry
138 stb >$0643
139 stb >DAT.Regs+1
140 incb
141 stb >$0645
142 stb >DAT.Regs+1
143 andcc #^IntMasks
144 ELSE
145 puls a Get VIRQ status flag: high bit set if VIRQ
146 ENDC
147
148 ora <D.IRQS Check to see if other hardware IRQ pending.
149 bita #%10110111 Any V/IRQ interrupts pending?
150 beq toggle
151 IFGT Level-2
152 lbsr DoPoll Yes, go service them.
153 ELSE
154 bsr DoPoll Yes, go service them.
155 ENDC
156 bra KbdCheck
157 toggle equ *
158 IFGT Level-2
159 lbsr DoToggle No, toggle GIME anyway
160 ELSE
161 bsr DoToggle No, toggle GIME anyway
162 ENDC
163
164 KbdCheck equ *
165 IFGT Level-2
166 lda >$0643 grab current map type
167 ldb >$0645
168 pshs d save it
169 orcc #IntMasks IRQs off
170 lda >$0660 SCF local memory ---x
171 sta >$0643 into DAT image ---x
172 sta >DAT.Regs+1 and into RAM ---x
173 inca
174 sta >$0645
175 sta >DAT.Regs+2 map in SCF, CC3IO, WindInt, etc.
176 ENDC
177
178 jsr [>D.AltIRQ] go update mouse, gfx cursor, keyboard, etc.
179
180 IFGT Level-2
181 puls d restore original map type ---x
182 orcc #IntMasks
183 sta >$0643 into system DAT image ---x
184 stb >$0645
185 std >DAT.Regs+1 and into RAM ---x
186 andcc #$AF
187 ENDC
188
189 dec <D.Tick End of second?
190 bne VIRQend No, skip time update and alarm check
191 lda #TkPerSec Reset tick count
192 sta <D.Tick
193
194 * ATD: Modified to call real time clocks on every minute ONLY.
195 inc <D.Sec go up one second
196 lda <D.Sec grab current second
197 cmpa #60 End of minute?
198 blo VIRQend No, skip time update and alarm check
199 clr <D.Sec Reset second count to zero
200
201 *
202 * Call GetTime entry point in Clock2
203 *
204 ldx <D.Clock2 get entry point to Clock2
205 jsr $03,x call GetTime entry point
206
207 NoGet ldd >WGlobal+G.AlPID
208 ble VIRQend Quit if no Alarm set
209 ldd >WGlobal+G.AlPckt+3 Does Hour/Minute agree?
210 cmpd <D.Hour
211 bne VIRQend
212 ldd >WGlobal+G.AlPckt+1 Does Month/Day agree?
213 cmpd <D.Month
214 bne VIRQend
215 ldb >WGlobal+G.AlPckt+0 Does Year agree?
216 cmpb <D.Year
217 bne VIRQend
218 ldd >WGlobal+G.AlPID
219 cmpd #1
220 beq checkbel
221 os9 F$Send
222 bra endalarm
223 checkbel ldb <D.Sec Sound bell for 15 seconds
224 andb #$F0
225 beq dobell
226 endalarm ldd #$FFFF
227 std >WGlobal+G.AlPID
228 bra VIRQend
229 dobell ldx >WGlobal+G.BelVec
230 beq VIRQend
231 jsr ,x
232 VIRQend jmp [>D.Clock] Jump to kernel's timeslice routine
233
234 *------------------------------------------------------------
235 * Interrupt polling and GIME reset code
236 *
237
238 *
239 * Call [D.Poll] until all interrupts have been handled
240 *
241 Dopoll
242 IFGT Level-2
243 lda >$0643 Level 3: get map type
244 ldb >$0645
245 pshs d save for later
246 ENDC
247 Dopoll.i
248 jsr [>D.Poll] Call poll routine
249 bcc DoPoll.i Until error (error -> no interrupt found)
250
251 IFGT Level-2
252 puls d
253 orcc #IntMasks
254 sta >$0643
255 stb >$0645
256 std >DAT.Regs+1
257 andcc #^IntMasks
258 ENDC
259
260 *
261 * Reset GIME to avoid missed IRQs
262 *
263 DoToggle lda #^GI.Toggl Mask off CART* bit
264 anda <D.IRQS
265 sta <D.IRQS
266 lda <D.IRQER Get current enable register status
267 tfr a,b
268 anda #^GI.Toggl Mask off CART* bit
269 orb #GI.Toggl --- ensure that 60Hz IRQ's are always enabled
270 sta >IRQEnR Disable CART
271 stb >IRQEnR Enable CART
272 clrb
273 rts
274
275
276 *------------------------------------------------------------
277 *
278 * Handle F$VIRQ system call
279 *
280 F.VIRQ pshs cc
281 orcc #IntMasks Disable interrupts
282 ldy <D.CLTb Address of VIRQ table
283 ldx <D.Init Address of INIT
284 ldb PollCnt,x Number of polling table entries from INIT
285 ldx R$X,u Zero means delete entry
286 beq RemVIRQ
287 IFGT Level-2
288 bra FindVIRQ ---x
289
290 v.loop leay 4,y ---x
291 ENDC
292 FindVIRQ ldx ,y++ Is VIRQ entry null?
293 beq AddVIRQ If yes, add entry here
294 decb
295 bne FindVIRQ
296 puls cc
297 comb
298 ldb #E$Poll
299 rts
300
301 AddVIRQ
302 IFGT Level-2
303 ldx R$Y,u
304 stx ,y
305 lda >$0643
306 ldb >$0645
307 std 2,y
308 ELSE
309 leay -2,y point to first null VIRQ entry
310 ldx R$Y,u
311 stx ,y
312 ENDC
313 ldy R$D,u
314 sty ,x
315 bra virqexit
316
317 IFGT Level-2
318 v.chk leay 4,y
319 RemVIRQ ldx ,y
320 ELSE
321 RemVIRQ ldx ,y++
322 ENDC
323 beq virqexit
324 cmpx R$Y,u
325 bne RemVIRQ
326 bsr DelVIRQ
327 virqexit puls cc
328 clrb
329 rts
330
331 DelVIRQ pshs x,y
332 DelVLup
333 IFGT Level-2
334 ldq ,y++ move entries up in table
335 leay 2,y
336 stq -8,y
337 bne DelVLup
338 puls x,y,pc
339 ELSE
340 ldx ,y++ move entries up in table
341 stx -4,y
342 bne DelVLup
343 puls x,y
344 leay -2,y
345 rts
346 ENDC
347
348 *------------------------------------------------------------
349 *
350 * Handle F$Alarm call
351 *
352 F.Alarm ldx #WGlobal+G.AlPckt
353 ldd R$D,u
354 bne DoAlarm
355 std G.AlPID-G.AlPckt,x Erase F$Alarm PID, Signal.
356 rts
357
358 DoAlarm tsta If PID != 0, set alarm for this process
359 bne SetAlarm
360 cmpd #1 1 -> Set system-wide alarm
361 bne GetAlarm
362 SetAlarm std G.AlPID-G.AlPckt,x
363 ldy <D.Proc
364 lda P$Task,y Move from process task
365 ldb <D.SysTsk To system task
366 ldx R$X,u From address given in X
367 ldu #WGlobal+G.AlPckt
368 ldy #5 Move 5 bytes
369 bra FMove
370
371 GetAlarm cmpd #2
372 bne AlarmErr
373 ldd G.AlPID-G.AlPckt,x
374 std R$D,u
375 bra RetTime
376 AlarmErr comb
377 ldb #E$IllArg
378 rts
379
380 *------------------------------------------------------------
381 *
382 * Handle F$Time System call
383 *
384 F.Time equ *
385 ldx #D.Time Address of system time packet
386 RetTime ldy <D.Proc Get pointer to current proc descriptor
387 ldb P$Task,y Process Task number
388 lda <D.SysTsk From System Task
389 ldu R$X,u
390 STime.Mv ldy #6 Move 6 bytes
391 FMove os9 F$Move
392 rts
393
394 *------------------------------------------------------------
395 *
396 * Handle F$STime system call
397 *
398 * First, copy time packet from user address space to system time
399 * variables, then fall through to code to update RTC.
400 *
401 F.STime equ *
402 ldx <D.Proc Caller's process descriptor
403 lda P$Task,x Source is in user map
404 ldx R$X,u Address of caller's time packet
405 ldu #D.Time Destination address
406 ldb <D.SysTsk Destination is in system map
407 bsr STime.Mv Get time packet (ignore errors)
408 lda #TkPerSec Reset to start of second
409 sta <D.Tick
410
411 *
412 * Call SetTime entry point in Clock2
413 ldx <D.Clock2 get entry point to Clock2
414 jsr $06,x else call GetTime entry point
415
416 NoSet rts
417
418 Clock2 fcs "Clock2"
419
420 *--------------------------------------------------
421 *
422 * Clock Initialization
423 *
424 * This vector is called by the kernel to service the first F$STime
425 * call. F$STime is usually called by CC3Go (with a dummy argument)
426 * in order to initialize the clock. F$STime is re-vectored to the
427 * service code above to handle future F$STime calls.
428 *
429 *
430 Init ldx <D.Proc save user proc
431 pshs x
432 ldx <D.SysPrc make sys for link
433 stx <D.Proc
434
435 leax <Clock2,pcr
436 lda #Sbrtn+Objct
437 os9 F$Link
438
439 * And here, we restore the original D.Proc value
440 puls x
441 stx <D.Proc restore user proc
442
443 bcc LinkOk
444 lda #E$MNF
445 jmp <D.Crash
446 LinkOk sty <D.Clock2 save entry point
447 InitCont ldx #PIA0Base point to PIA0
448 clra no error for return...
449 pshs cc save IRQ enable status (and Carry clear)
450 orcc #IntMasks stop interrupts
451
452 * Note: this code can go away once we have a rel_50hz
453 IFEQ TkPerSec-50
454 ldb <D.VIDMD get video mode register copy
455 orb #$08 set 50 Hz VSYNC bit
456 stb <D.VIDMD save video mode register copy
457 stb >$FF98 set 50 Hz VSYNC
458 ENDC
459
460 sta 1,x enable DDRA
461 sta ,x set port A all inputs
462 sta 3,x enable DDRB
463 coma
464 sta 2,x set port B all outputs
465 ldd #$343C [A]=PIA0 CRA contents, [B]=PIA0 CRB contents
466 sta 1,x CA2 (MUX0) out low, port A, disable HBORD high-to-low IRQs
467 stb 3,x CB2 (MUX1) out low, port B, disable VBORD low-to-high IRQs
468 sta $23,x disable CART +RG Mar 14, 2012
469 lda ,x clear possible pending PIA0 HBORD IRQ
470 lda 2,x clear possible pending PIA0 VBORD IRQ
471
472 * Don't need to explicitly read RTC during initialization
473 ldd #59*256+TkPerTS last second and time slice in minute
474 std <D.Sec Will prompt RTC read at next time slice
475
476 stb <D.TSlice set ticks per time slice
477 stb <D.Slice set first time slice
478 leax SvcIRQ,pcr set IRQ handler
479 stx <D.IRQ
480 leax SvcVIRQ,pcr set VIRQ handler
481 stx <D.VIRQ
482 leay NewSvc,pcr insert syscalls
483 os9 F$SSvc
484 * H6309 optimization opportunity here using oim
485 lda <D.IRQER get shadow GIME IRQ enable register
486 ora #$08 set VBORD bit
487 sta <D.IRQER save shadow register
488 sta >IRQEnR enable GIME VBORD IRQs
489
490 * Call Clock2 init routine
491 ldy <D.Clock2 get entry point to Clock2
492 jsr ,y call init entry point of Clock2
493 InitRts puls cc,pc recover IRQ enable status and return
494
495 emod
496 len equ *
497 end