this repo has no description
1/*
2 RTCEMDEV.c
3
4 Copyright (C) 2003 Philip Cummins, Paul C. Pratt
5
6 You can redistribute this file and/or modify it under the terms
7 of version 2 of the GNU General Public License as published by
8 the Free Software Foundation. You should have received a copy
9 of the license along with this file; see the file COPYING.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 license for more details.
15*/
16
17/*
18 Real Time Clock EMulated DEVice
19
20 Emulates the RTC found in the Mac Plus.
21
22 This code adapted from "RTC.c" in vMac by Philip Cummins.
23*/
24
25#include "PICOMMON.h"
26
27#if EmRTC
28
29/* define _RTC_Debug */
30#ifdef _RTC_Debug
31#include <stdio.h>
32#endif
33
34#include "RTCEMDEV.h"
35
36#define HaveXPRAM (CurEmMd >= kEmMd_Plus)
37
38/*
39 ReportAbnormalID unused 0x0805 - 0x08FF
40*/
41
42#if HaveXPRAM
43#define PARAMRAMSize 256
44#else
45#define PARAMRAMSize 20
46#endif
47
48#if HaveXPRAM
49#define Group1Base 0x10
50#define Group2Base 0x08
51#else
52#define Group1Base 0x00
53#define Group2Base 0x10
54#endif
55
56typedef struct
57{
58 /* RTC VIA Flags */
59 ui3b WrProtect;
60 ui3b DataOut;
61 ui3b DataNextOut;
62
63 /* RTC Data */
64 ui3b ShiftData;
65 ui3b Counter;
66 ui3b Mode;
67 ui3b SavedCmd;
68#if HaveXPRAM
69 ui3b Sector;
70#endif
71
72 /* RTC Registers */
73 ui3b Seconds_1[4];
74 ui3b PARAMRAM[PARAMRAMSize];
75} RTC_Ty;
76
77LOCALVAR RTC_Ty RTC;
78
79/* RTC Functions */
80
81LOCALVAR ui5b LastRealDate;
82
83#ifndef RTCinitPRAM
84#define RTCinitPRAM 1
85#endif
86
87#ifndef TrackSpeed /* in 0..4 */
88#define TrackSpeed 0
89#endif
90
91#ifndef AlarmOn /* in 0..1 */
92#define AlarmOn 0
93#endif
94
95#ifndef DiskCacheSz /* in 1,2,3,4,6,8,12 */
96/* actual cache size is DiskCacheSz * 32k */
97#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
98#define DiskCacheSz 1
99#else
100#define DiskCacheSz 4
101#endif
102#endif
103
104#ifndef StartUpDisk /* in 0..1 */
105#define StartUpDisk 0
106#endif
107
108#ifndef DiskCacheOn /* in 0..1 */
109#define DiskCacheOn 0
110#endif
111
112#ifndef MouseScalingOn /* in 0..1 */
113#define MouseScalingOn 0
114#endif
115
116#define prb_fontHi 0
117#define prb_fontLo 2
118#define prb_kbdPrintHi (AutoKeyRate + (AutoKeyThresh << 4))
119#define prb_kbdPrintLo 0
120#define prb_volClickHi (SpeakerVol + (TrackSpeed << 3) + (AlarmOn << 7))
121#define prb_volClickLo (CaretBlinkTime + (DoubleClickTime << 4))
122#define prb_miscHi DiskCacheSz
123#define prb_miscLo \
124 ((MenuBlink << 2) + (StartUpDisk << 4) \
125 + (DiskCacheOn << 5) + (MouseScalingOn << 6))
126
127#if dbglog_HAVE && 0
128EXPORTPROC DumpRTC(void);
129
130GLOBALPROC DumpRTC(void)
131{
132 int Counter;
133
134 dbglog_writeln("RTC Parameter RAM");
135 for (Counter = 0; Counter < PARAMRAMSize; Counter++) {
136 dbglog_writeNum(Counter);
137 dbglog_writeCStr(", ");
138 dbglog_writeHex(RTC.PARAMRAM[Counter]);
139 dbglog_writeReturn();
140 }
141}
142#endif
143
144GLOBALFUNC blnr RTC_Init(void)
145{
146 int Counter;
147 ui5b secs;
148
149 RTC.Mode = RTC.ShiftData = RTC.Counter = 0;
150 RTC.DataOut = RTC.DataNextOut = 0;
151 RTC.WrProtect = falseblnr;
152
153 secs = CurMacDateInSeconds;
154 LastRealDate = secs;
155
156 RTC.Seconds_1[0] = secs & 0xFF;
157 RTC.Seconds_1[1] = (secs & 0xFF00) >> 8;
158 RTC.Seconds_1[2] = (secs & 0xFF0000) >> 16;
159 RTC.Seconds_1[3] = (secs & 0xFF000000) >> 24;
160
161 for (Counter = 0; Counter < PARAMRAMSize; Counter++) {
162 RTC.PARAMRAM[Counter] = 0;
163 }
164
165#if RTCinitPRAM
166 RTC.PARAMRAM[0 + Group1Base] = 168; /* valid */
167
168#if EmLocalTalk
169 RTC.PARAMRAM[2 + Group1Base] = LT_NodeHint;
170 /* set to constant instead for testing collisions */
171#else
172#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
173 RTC.PARAMRAM[2 + Group1Base] = 1;
174 /* node id hint for printer port (AppleTalk) */
175#endif
176#endif
177
178#if EmLocalTalk
179 RTC.PARAMRAM[3 + Group1Base] = 0x21;
180#else
181 RTC.PARAMRAM[3 + Group1Base] = 0x22;
182#endif
183 /*
184 serial ports config bits: 4-7 A, 0-3 B
185 useFree 0 Use undefined
186 useATalk 1 AppleTalk
187 useAsync 2 Async
188 useExtClk 3 externally clocked
189 */
190
191 RTC.PARAMRAM[4 + Group1Base] = 204; /* portA, high */
192 RTC.PARAMRAM[5 + Group1Base] = 10; /* portA, low */
193 RTC.PARAMRAM[6 + Group1Base] = 204; /* portB, high */
194 RTC.PARAMRAM[7 + Group1Base] = 10; /* portB, low */
195 RTC.PARAMRAM[13 + Group1Base] = prb_fontLo;
196 RTC.PARAMRAM[14 + Group1Base] = prb_kbdPrintHi;
197#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) || EmLocalTalk
198 RTC.PARAMRAM[15 + Group1Base] = 1;
199 /*
200 printer, if any, connected to modem port
201 because printer port used for appletalk.
202 */
203#endif
204
205#if prb_volClickHi != 0
206 RTC.PARAMRAM[0 + Group2Base] = prb_volClickHi;
207#endif
208 RTC.PARAMRAM[1 + Group2Base] = prb_volClickLo;
209 RTC.PARAMRAM[2 + Group2Base] = prb_miscHi;
210 RTC.PARAMRAM[3 + Group2Base] = prb_miscLo
211#if 0 != vMacScreenDepth
212 | 0x80
213#endif
214 ;
215
216#if HaveXPRAM /* extended parameter ram initialized */
217#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
218 RTC.PARAMRAM[12] = 0x4e;
219 RTC.PARAMRAM[13] = 0x75;
220 RTC.PARAMRAM[14] = 0x4d;
221 RTC.PARAMRAM[15] = 0x63;
222#else
223 RTC.PARAMRAM[12] = 0x42;
224 RTC.PARAMRAM[13] = 0x75;
225 RTC.PARAMRAM[14] = 0x67;
226 RTC.PARAMRAM[15] = 0x73;
227#endif
228#endif
229
230#if ((CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_Classic)) \
231 || (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
232
233 RTC.PARAMRAM[0x01] = 0x80;
234 RTC.PARAMRAM[0x02] = 0x4F;
235#endif
236#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
237 RTC.PARAMRAM[0x03] = 0x48;
238
239 /* video board id */
240 RTC.PARAMRAM[0x46] = /* 0x42 */ 0x76; /* 'v' */
241 RTC.PARAMRAM[0x47] = /* 0x32 */ 0x4D; /* 'M' */
242 /* mode */
243#if (0 == vMacScreenDepth) || (vMacScreenDepth >= 4)
244 RTC.PARAMRAM[0x48] = 0x80;
245#else
246 RTC.PARAMRAM[0x48] = 0x81;
247 /* 0x81 doesn't quite work right at boot */
248 /* no, it seems to work now (?) */
249 /* but only if depth <= 3 */
250#endif
251#endif
252
253#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
254 RTC.PARAMRAM[0x77] = 0x01;
255#endif
256
257#if ((CurEmMd >= kEmMd_SE) && (CurEmMd <= kEmMd_Classic)) \
258 || (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
259
260 /* start up disk (encoded how?) */
261 RTC.PARAMRAM[0x78] = 0x00;
262 RTC.PARAMRAM[0x79] = 0x01;
263 RTC.PARAMRAM[0x7A] = 0xFF;
264 RTC.PARAMRAM[0x7B] = 0xFE;
265#endif
266
267#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
268 RTC.PARAMRAM[0x80] = 0x09;
269 RTC.PARAMRAM[0x81] = 0x80;
270#endif
271
272#if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)
273
274#define pr_HilColRedHi (pr_HilColRed >> 8)
275#if 0 != pr_HilColRedHi
276 RTC.PARAMRAM[0x82] = pr_HilColRedHi;
277#endif
278#define pr_HilColRedLo (pr_HilColRed & 0xFF)
279#if 0 != pr_HilColRedLo
280 RTC.PARAMRAM[0x83] = pr_HilColRedLo;
281#endif
282
283#define pr_HilColGreenHi (pr_HilColGreen >> 8)
284#if 0 != pr_HilColGreenHi
285 RTC.PARAMRAM[0x84] = pr_HilColGreenHi;
286#endif
287#define pr_HilColGreenLo (pr_HilColGreen & 0xFF)
288#if 0 != pr_HilColGreenLo
289 RTC.PARAMRAM[0x85] = pr_HilColGreenLo;
290#endif
291
292#define pr_HilColBlueHi (pr_HilColBlue >> 8)
293#if 0 != pr_HilColBlueHi
294 RTC.PARAMRAM[0x86] = pr_HilColBlueHi;
295#endif
296#define pr_HilColBlueLo (pr_HilColBlue & 0xFF)
297#if 0 != pr_HilColBlueLo
298 RTC.PARAMRAM[0x87] = pr_HilColBlueLo;
299#endif
300
301#endif /* (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) */
302
303#if HaveXPRAM /* extended parameter ram initialized */
304 do_put_mem_long(&RTC.PARAMRAM[0xE4], CurMacLatitude);
305 do_put_mem_long(&RTC.PARAMRAM[0xE8], CurMacLongitude);
306 do_put_mem_long(&RTC.PARAMRAM[0xEC], CurMacDelta);
307#endif
308
309#endif /* RTCinitPRAM */
310
311 return trueblnr;
312}
313
314#ifdef RTC_OneSecond_PulseNtfy
315IMPORTPROC RTC_OneSecond_PulseNtfy(void);
316#endif
317
318GLOBALPROC RTC_Interrupt(void)
319{
320 ui5b Seconds = 0;
321 ui5b NewRealDate = CurMacDateInSeconds;
322 ui5b DateDelta = NewRealDate - LastRealDate;
323
324 if (DateDelta != 0) {
325 Seconds = (RTC.Seconds_1[3] << 24) + (RTC.Seconds_1[2] << 16)
326 + (RTC.Seconds_1[1] << 8) + RTC.Seconds_1[0];
327 Seconds += DateDelta;
328 RTC.Seconds_1[0] = Seconds & 0xFF;
329 RTC.Seconds_1[1] = (Seconds & 0xFF00) >> 8;
330 RTC.Seconds_1[2] = (Seconds & 0xFF0000) >> 16;
331 RTC.Seconds_1[3] = (Seconds & 0xFF000000) >> 24;
332
333 LastRealDate = NewRealDate;
334
335#ifdef RTC_OneSecond_PulseNtfy
336 RTC_OneSecond_PulseNtfy();
337#endif
338 }
339}
340
341LOCALFUNC ui3b RTC_Access_PRAM_Reg(ui3b Data, blnr WriteReg, ui3b t)
342{
343 if (WriteReg) {
344 if (! RTC.WrProtect) {
345 RTC.PARAMRAM[t] = Data;
346#ifdef _RTC_Debug
347 printf("Writing Address %2x, Data %2x\n", t, Data);
348#endif
349 }
350 } else {
351 Data = RTC.PARAMRAM[t];
352 }
353 return Data;
354}
355
356LOCALFUNC ui3b RTC_Access_Reg(ui3b Data, blnr WriteReg, ui3b TheCmd)
357{
358 ui3b t = (TheCmd & 0x7C) >> 2;
359 if (t < 8) {
360 if (WriteReg) {
361 if (! RTC.WrProtect) {
362 RTC.Seconds_1[t & 0x03] = Data;
363 }
364 } else {
365 Data = RTC.Seconds_1[t & 0x03];
366 }
367 } else if (t < 12) {
368 Data = RTC_Access_PRAM_Reg(Data, WriteReg,
369 (t & 0x03) + Group2Base);
370 } else if (t < 16) {
371 if (WriteReg) {
372 switch (t) {
373 case 12 :
374 break; /* Test Write, do nothing */
375 case 13 :
376 RTC.WrProtect = (Data & 0x80) != 0;
377 break; /* Write_Protect Register */
378 default :
379 ReportAbnormalID(0x0801, "Write RTC Reg unknown");
380 break;
381 }
382 } else {
383 ReportAbnormalID(0x0802, "Read RTC Reg unknown");
384 }
385 } else {
386 Data = RTC_Access_PRAM_Reg(Data, WriteReg,
387 (t & 0x0F) + Group1Base);
388 }
389 return Data;
390}
391
392LOCALPROC RTC_DoCmd(void)
393{
394 switch (RTC.Mode) {
395 case 0: /* This Byte is a RTC Command */
396#if HaveXPRAM
397 if ((RTC.ShiftData & 0x78) == 0x38) { /* Extended Command */
398 RTC.SavedCmd = RTC.ShiftData;
399 RTC.Mode = 2;
400#ifdef _RTC_Debug
401 printf("Extended command %2x\n", RTC.ShiftData);
402#endif
403 } else
404#endif
405 {
406 if ((RTC.ShiftData & 0x80) != 0x00) { /* Read Command */
407 RTC.ShiftData =
408 RTC_Access_Reg(0, falseblnr, RTC.ShiftData);
409 RTC.DataNextOut = 1;
410 } else { /* Write Command */
411 RTC.SavedCmd = RTC.ShiftData;
412 RTC.Mode = 1;
413 }
414 }
415 break;
416 case 1: /* This Byte is data for RTC Write */
417 (void) RTC_Access_Reg(RTC.ShiftData,
418 trueblnr, RTC.SavedCmd);
419 RTC.Mode = 0;
420 break;
421#if HaveXPRAM
422 case 2: /* This Byte is rest of Extended RTC command address */
423#ifdef _RTC_Debug
424 printf("Mode 2 %2x\n", RTC.ShiftData);
425#endif
426 RTC.Sector = ((RTC.SavedCmd & 0x07) << 5)
427 | ((RTC.ShiftData & 0x7C) >> 2);
428 if ((RTC.SavedCmd & 0x80) != 0x00) { /* Read Command */
429 RTC.ShiftData = RTC.PARAMRAM[RTC.Sector];
430 RTC.DataNextOut = 1;
431 RTC.Mode = 0;
432#ifdef _RTC_Debug
433 printf("Reading X Address %2x, Data %2x\n",
434 RTC.Sector, RTC.ShiftData);
435#endif
436 } else {
437 RTC.Mode = 3;
438#ifdef _RTC_Debug
439 printf("Writing X Address %2x\n", RTC.Sector);
440#endif
441 }
442 break;
443 case 3: /* This Byte is data for an Extended RTC Write */
444 (void) RTC_Access_PRAM_Reg(RTC.ShiftData,
445 trueblnr, RTC.Sector);
446 RTC.Mode = 0;
447 break;
448#endif
449 }
450}
451
452GLOBALPROC RTCunEnabled_ChangeNtfy(void)
453{
454 if (RTCunEnabled) {
455 /* abort anything going on */
456 if (RTC.Counter != 0) {
457#ifdef _RTC_Debug
458 printf("aborting, %2x\n", RTC.Counter);
459#endif
460 ReportAbnormalID(0x0803, "RTC aborting");
461 }
462 RTC.Mode = 0;
463 RTC.DataOut = 0;
464 RTC.DataNextOut = 0;
465 RTC.ShiftData = 0;
466 RTC.Counter = 0;
467 }
468}
469
470GLOBALPROC RTCclock_ChangeNtfy(void)
471{
472 if (! RTCunEnabled) {
473 if (RTCclock) {
474 RTC.DataOut = RTC.DataNextOut;
475 RTC.Counter = (RTC.Counter - 1) & 0x07;
476 if (RTC.DataOut) {
477 RTCdataLine = ((RTC.ShiftData >> RTC.Counter) & 0x01);
478 /*
479 should notify VIA if changed, so can check
480 data direction
481 */
482 if (RTC.Counter == 0) {
483 RTC.DataNextOut = 0;
484 }
485 } else {
486 RTC.ShiftData = (RTC.ShiftData << 1) | RTCdataLine;
487 if (RTC.Counter == 0) {
488 RTC_DoCmd();
489 }
490 }
491 }
492 }
493}
494
495GLOBALPROC RTCdataLine_ChangeNtfy(void)
496{
497#if dbglog_HAVE
498 if (RTC.DataOut) {
499 if (! RTC.DataNextOut) {
500 /*
501 ignore. The ROM doesn't read from the RTC the
502 way described in the Hardware Reference.
503 It reads the data after setting the clock to
504 one instead of before, and then immediately
505 changes the VIA direction. So the RTC
506 has no way of knowing to stop driving the
507 data line, which certainly can't really be
508 correct.
509 */
510 } else {
511 ReportAbnormalID(0x0804,
512 "write RTC Data unexpected direction");
513 }
514 }
515#endif
516}
517
518#endif /* EmRTC */