Mercurial > hg > Members > kono > nitros9-code
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 |