The TimeKeeper's registers are incremented and decremented using parameters from a table (TIMETABLE) which contains wrap limits and data masks.
Table driven software is more efficient (spacewise) than inline code
and although it takes longer to write initially, it is easier to add entries
to a table than to write more inline code.
306
XDEF TIMETABLE,TSETINC,TSETDEC,CALSET
307
* Setting the Clock via User Controls
308
TIMETABLE:
309
310
* Parameter to change;
311
* Parameter Bit Mask; Low Wrap; High Wrap
312 0000804A
FFFF 4FF6
DC.L HOUR
313 0000804E
003F 0000 0023 DC.W $3F,$0,$23
314
315 00008054
FFFF 4FF4
DC.L MINUTE
316 00008058
007F 0000 0059 DC.W $7F,$0,$59
317
318 0000805E
FFFF 4FF2
DC.L SECOND
319 00008062
007F 0000 0059 DC.W $7F,$0,$59
320
321 00008068
FFFF 4FF8
DC.L DAY
322 0000806C
0007 0001 0007 DC.W $07,$1,$07
323
324 00008072
FFFF 4FFC
DC.L MONTH
325 00008076
001F 0001 0012 DC.W $1F,$1,$12
326
327 0000807C
FFFF 4FFA
DC.L DATE
328 00008080
003F 0001 0031 DC.W $3F,$1,$31
329
330 00008086
FFFF 4FFE
DC.L YEAR
331 0000808A
00FF 0088 0099 DC.W $0FF,$88,$99
332
333
* D0.W contains the index number
334
TSETINC:
335 00008090
40E7
MOVE.W SR,-(A7) * Save Interrupt Mask
336 00008092
46FC 2F00
MOVE.W #$2F00,SR * Disable Interrupts
337 00008096
4279 0060 4008 CLR.W ZP1WEN
* Enable ZeroPower RAM Writes
338 0000809C
4279 0060 401A CLR.W ZP2WEN
339
340 000080A2
45F9 0000 804A LEA.L TIMETABLE,A2
341 000080A8
C0FC 000A
MULU #10,D0 *
342 000080AC
D4C0
ADDA D0,A2 * A2 points to table entry
343
344
* Increment and wrap if necessary
345 000080AE
023C 00EF
AND.B #$0EF,CCR * Clear Extend Flag
346 000080B2
143C 0001
MOVE.B #1,D2 * ADD Decimal is either R,R or mem,mem
347
348 000080B6
2652
MOVE.L (A2),A3 * Get parameter
349 000080B8
1013
MOVE.B (A3),D0
350 000080BA
C102
ABCD D2,D0
351
352 000080BC
B02A 0009
CMP.B 9(A2),D0 * Compare to High Wrap
353 000080C0
6F00 0006
BLE TSLP1 * Overflow?
354
* Yes
355 000080C4
102A 0007
MOVE.B 7(A2),D0 * Make it wrap
356
357
* Mask the data
358 000080C8
322A 0004 TSLP1 MOVE.W
4(A2),D1 * Get the Bit Mask
359 000080CC
C001
AND.B D1,D0 * Apply the mask to the new data
360 000080CE
4641
NOT.W D1 * Complement the mask
361 000080D0
C213
AND.B (A3),D1 * Get the bits that will not be changed
362 000080D2
8001
OR.B D1,D0 * ready to write
363
364 000080D4
0039 0080 FFFF OR.B #$80,CLKCON
* Set Write
4FF0
365 000080DC
1680
MOVE.B D0,(A3) * Write Data
366 000080DE
0239 007F FFFF AND.B #$7F,CLKCON
* End Write
4FF0
367
368 000080E6
6100 FDB8
BSR RCLKBR * Copy to the Shadow Display Registers
369
370
TSLP4
371 000080EA
4279 0060 4018 CLR.W ZP1WDIS
* Disable ZeroPower RAM Writes
372 000080F0
4279 0060 400A CLR.W ZP2WDIS
373 000080F6
46DF
MOVE.W (A7)+,SR * Restore Interrupt Mask
374
375 000080F8
4E75
RTS * End
376
*----
377
* D0.W contains the index number
378 000080FA
40E7
TSETDEC: MOVE.W SR,-(A7) * Save Interrupt Mask
379 000080FC
46FC 2F00
MOVE.W #$2F00,SR * Disable Interrupts
380 00008100
4279 0060 4008 CLR.W ZP1WEN
* Enable ZeroPower RAM Writes
381 00008106
4279 0060 401A CLR.W ZP2WEN
382
383 0000810C
45F9 0000 804A LEA.L TIMETABLE,A2
384 00008112
C0FC 000A
MULU #10,D0 *
385 00008116
D4C0
ADDA D0,A2 * A2 points to table entry
386
387
* Decrement and wrap if necessary
388 00008118
023C 00EF
AND.B #$0EF,CCR * Clear Extend Flag
389 0000811C
143C 0001
MOVE.B #1,D2 * SUB Decimal is either R,R or mem,mem
390
391 00008120
2652
MOVE.L (A2),A3 * Get parameter
392 00008122
1013
MOVE.B (A3),D0
393 00008124
8102
SBCD D2,D0
394
395 00008126
B02A 0007
CMP.B 7(A2),D0 * Compare to Low Wrap
396 0000812A
6A00 0006
BPL TSLP3 * Under flow?
397
* Yes
398 0000812E
102A 0009
MOVE.B 9(A2),D0 * Make it wrap
399
400 00008132
6094
TSLP3 BRA TSLP1 * Mask it and Write it
401
578
TTL 'Display the Clock'
580
XDEF DISPCLK,CLKPOS
581 00000012
CLKPOS EQU 18 * Clock Position Line #
582
* DISPLAY THE CLOCK
583
DISPCLK:
584 00008304
0C39 0055 FFFF CMP.B #$55,CLKSTAT
4FCE
585 0000830C
6700 0004
BEQ DSPC
586 00008310
4E75
RTS * Clock is Off or missing so don't display it.
587
588 00008312
343C 00FF DSPC MOVE.W #WHITE,D2
* Color
589 00008316
4EB9 0000 0000 E JSR SECOLOR
590
591
* Hours:Minutes:Seconds
592 0000831C
303C 0012
MOVE.W #CLKPOS,D0 * Y line
593 00008320
323C 000A
MOVE.W #10,D1 * X Position
594 00008324
4EB9 0000 0000 E JSR DO_ADR *
Result in D0
595
596 0000832A
1238 8004
MOVE.B DHOUR,D1 * HOUR
597 0000832E
0C01 0013
CMP.B #$13,D1 * If it is .GE. $13 then SUBD $12
598 00008332
6D00 000C
BLT DSPC1
599
600 00008336
023C 00EF
AND.B #$0EF,CCR * Clear Extend Flag
601 0000833A
183C 0012
MOVE.B #$12,D4 * SUB Decimal is either R,R or mem,mem
602 0000833E
8304
SBCD D4,D1
603
604 00008340
4A01
DSPC1 TST.B D1 * If it is '0' make it '12'
605 00008342
6600 0006
BNE DSPC2
606 00008346
123C 0012
MOVE.B #$12,D1
607
608 0000834A
4EB9 0000 0000 E DSPC2 JSR VW2_SEX * View two digits,
blank a leading zero
609
610 00008350
123C 003A
MOVE.B #':',D1 * ':'
611 00008354
4EB9 0000 0000 E JSR HAMMER
612
613 0000835A
1238 8005
MOVE.B DMIN,D1 * MINUTE
614 0000835E
4EB9 0000 0000 E JSR VW2_HEX
615
616 00008364
123C 003A
MOVE.B #':',D1 * ':'
617 00008368
4EB9 0000 0000 E JSR HAMMER
618
619 0000836E
1238 8006
MOVE.B DSEC,D1 * SECOND
620 00008372
4EB9 0000 0000 E JSR VW2_HEX
621
*---------------------
622
* AM/PM
623 00008378
123C 002A
MOVE.B #'*',D1 * space
624 0000837C
4EB9 0000 0000 E JSR HAMMER
625
626 00008382
0C38 0012 8004 CMP.B #$12,DHOUR
*
627 00008388
6C00 000A
BGE DSPC3 * HOUR .GE. $12 = 'PM'
628 0000838C
123C 0041
MOVE.B #'A',D1
629 00008390
6000 0006
BRA DSPC4
630
631 00008394
123C 0050 DSPC3 MOVE.B
#'P',D1
632
633 00008398
4EB9 0000 0000 E DSPC4 JSR HAMMER * 'A' or 'P'
634 0000839E
123C 004D
MOVE.B #'M',D1
635 000083A2
4EB9 0000 0000 E JSR HAMMER *
'M'
636
*---------------------
637
* Day Name
638 000083A8
303C 0013
MOVE.W #(CLKPOS+1),D0 * Y line
639 000083AC
323C 0002
MOVE.W #2,D1 * X Position
640 000083B0
4EB9 0000 0000 E JSR DO_ADR *
Result in D0
641
642 000083B6
4241
CLR.W D1 * Day Name
643 000083B8
1238 8003
MOVE.B DDAY,D1
644 000083BC
0201 0007
AND.B #$07,D1
645 000083C0
41F9 0000 842A LEA.L DOOL,A0
646
647 000083C6
6100 0174
BSR CLKMSG
648
*---------------------
649
* Month,Date,Year
650 000083CA
303C 0013
MOVE.W #(CLKPOS+1),D0 * Y line
651 000083CE
323C 000F
MOVE.W #15,D1 * X Position
652 000083D2
4EB9 0000 0000 E JSR DO_ADR *
Result in D0
653
654 000083D8
4241
CLR.W D1 * Month Name
655 000083DA
1238 8001
MOVE.B DMON,D1
656 000083DE
0201 00FF
AND.B #$0FF,D1
657 000083E2
41F9 0000 848E LEA.L MOOL,A0
658
659 000083E8
6100 0152
BSR CLKMSG
660
*---------------------
661 000083EC
123C 002A
MOVE.B #'*',D1 * Space
662 000083F0
4EB9 0000 0000 E JSR HAMMER
663
*---------------------
664 000083F6
1238 8002
MOVE.B DDATE,D1 * Date
665 000083FA
4EB9 0000 0000 E JSR VW2_HEX
666
*---------------------
667 00008400
123C 002C
MOVE.B #',',D1 * ,
668 00008404
4EB9 0000 0000 E JSR HAMMER
669
*---------------------
670 0000840A
123C 0031
MOVE.B #'1',D1 * 19
671 0000840E
4EB9 0000 0000 E JSR HAMMER
672 00008414
123C 0039
MOVE.B #'9',D1 *
673 00008418
4EB9 0000 0000 E JSR HAMMER
674
*---------------------
675 0000841E
1238 8000
MOVE.B DYR,D1 * Year
676 00008422
4EB9 0000 0000 E JSR VW2_HEX
677
*---------------------
678 00008428
4E75
RTS
679
The reason is very interesting. There is a place in the program with the instruction that does:
MOVE.B $FFFF8000,D1
The PC based assembler produces the code: 1238 8000 which is a MOVE.B instruction using absolute short addressing for the source data. This is proper because the 68010 sign extends absolute short addresses.
It assembles MOVE.B $00008000,D1 as 1239 0000 8000 which is a MOVE.B instruction using absolute long addressing for the source data. This is correct because otherwise $8000 would be sign extended to $FFFF8000.
The PC Based assembler correctly understands that the 68010's absolute word addressing mode will sign extend the value.
However, when the instruction was assembled by the assembler running on the VAX,
MOVE.B $FFFF8000,D1
the code produced was 1239 FFFF 8000 which uses absolute long addressing.
Apparently this assembler, which came from a well known company, which I believe is still around, didn't know about the 68010's absolute short addressing.
Of course, this code was produced back in the 1980s, when the Earth was still smoldering with active volcanos and dinosaurs roamed the land, but I wonder if I should send them a bug report. :-)
In changing the year limits, I found the code:
330 00008086 FFFF 4FFE
DC.L YEAR
331 0000808A 00FF 0088 0099
DC.W $0FF,$88,$99
in the merged file made from 77_5002.bin and 77_5001.bin at:
8080: 00 01 00 31 ff ff 4f fe 00 ff 00 88 00 99 40 e7
What I didn't show was that later on is the ASCII text for the day labels:
008440 84 74 00 00 84 7D 00 00 84 84 09 44 41 59 2A 45
.t...}.....DAY*E
008450 52 52 4F 52 06 53 55 4E 44 41 59 06
4D 4F 4E 44 RROR.SUNDAY.MOND
008460 41 59 07 54 55 45 53 44 41 59 09 57 45 44 4E 45
AY.TUESDAY.WEDNE
008470 53 44 41 59 08 54 48 55 52 53 44 41 59 06 46 52
SDAY.THURSDAY.FR
008480 49 44 41 59 08 53 41 54 55 52 44 41 59 00 00 00
IDAY.SATURDAY...
If we use the address of the 'S' in 'Sunday as a reference ($8455), the code we are looking for, starting at $8089 is $8455 - $8089 = $3CC before the 'S' in 'SUNDAY'.
The code that increments the count in TSETINC:
348 000080B6 2652
MOVE.L (A2),A3 * Get parameter
349 000080B8 1013
MOVE.B (A3),D0
350 000080BA C102
ABCD D2,D0
351
352 000080BC B02A 0009
CMP.B 9(A2),D0 * Compare to High Wrap
353 000080C0 6F00 0006
BLE TSLP1 * Overflow?
354
* Yes
355 000080C4 102A 0007
MOVE.B 7(A2),D0 * Make it wrap
was found at:
80b0: 14 3c 00 01 26 52 10 13 c1 02 b0 2a 00 09 6f 00
80c0: 00 06 10 2a 00 07 32 2a 00 04 c0 01 46 41 c2
13
'6f' is at address $80BE, which is $8455 - $80BE = $397 before the 'S' in 'SUNDAY'.
The code for the century data:
670 0000840A
123C0031
MOVE.B #'1',D1 * 19
671 0000840E
4EB9 0000 0000 E JSR HAMMER
672 00008414
123C0039
MOVE.B #'9',D1
673 00008418
4EB9 0000 0000 E JSR HAMMER
was found at:
8400: 00 2c 4e b9 00 00 31 38 12 3c 00 31 4e b9 00
00
8410: 31 38 12 3c 00 39 4e b9 00 00 31 38 12 39 ff
ff
The '12' is at address $8408, so that this code segment starts at
$8455 - $8408 = $4D before the 'S' in Sunday.
To check this theory, I will use the Roms from a Race Drivin' Compact,
Version 1.7 .
(I believe the final version of Race Drivin' Compact was 1.9 .)
First we find 'SUNDAY'. Note that the strings may be broken up, making them difficult to find with an editor.
0079F0 00 00 7A 2E 09 44 41 59 2A 45 52 52 4F 52 06 53
..z..DAY*ERROR.S
007A00 55 4E 44 41 59 06 4D 4F 4E 44 41 59 07 54 55 45
UNDAY.MONDAY.TUE
007A10 53 44 41 59 09 57 45 44 4E 45 53 44 41 59 08 54
SDAY.WEDNESDAY.T
007A20 48 55 52 53 44 41 59 06 46 52 49 44 41 59 08 53
HURSDAY.FRIDAY.S
007A30 41 54 55 52 44 41 59 00 00 00 7A 84 00 00 7A 90
ATURDAY...z...z.
'SUNDAY' starts at $79FF.
Years Limits:
If we subtract $3CC from $79FF we get $7633. The code there is
007630 4F FE 00 FF 00 88 00 99
40 E7 46 FC 2F 00 42 79
007640 00 60 40 08 42 79 00 60 40 1A 45 F9 00 00 75 F2
which is exactly what we were looking for.
Change BLE to BLS in TSETINC
If we subtract $397 from $79FF we get $7668. The code there is:
007660 10 13 C1 02 B0 2A 00 09 6F 00 00 06 10
2A 00 07
007670 32 2A 00 04 C0 01 46 41 C2 13 80 01 00 39 00 80
Bingo.
Change the Century Data:
If we subtract $4D from $79FF we get $79B2. The code there is:
0079B0 2B 5E 12 3C 00 31 4E B9 00 00 2B 5E 12
3C 00 39
0079C0 4E B9 00 00 2B 5E 12 39 FF FF 80 00 4E B9 00 00
Now all we have to do is transform these addresses back to their orginal
addresses in the Roms (and then burn some Roms) and we will have fixed
the Y2K bug in Race Drivin' Compact Version 1.7 .
Since people might not have the programs to find and make the changes necessary to fix the Y2K bug I am making available the ones I wrote.
The programs are written for Microsoft Visual C++ 6.0 and are Console Applications.
The easiest way to run them is in full screen DOS (or in a DOS box) in a directory containing the data files and the executable program. If you use the Windows Run box you have to specify the complete paths to the input files.
Although they look like DOS applications, they aren't. They require Windows in order to run. (It will tell you that if you run them after booting up in Command Mode.)
If you want to run pure DOS versions, you can compile them under Borland Turbo C if you comment out one line. That line is documented in the source files.
In either case, I recommend that you examine the source file and compile it yourself so you will know that there is nothing nasty hiding in it. I also recommend that you download it only through my Web site (www.jmargolin.com) and only through this page.
Each program has a test subdirectory containing the released executable version of the program along with test data.
Instructions for running each program can be obtained by running the program without any command line arguments.
The programs are copyright 2002 by Jed Margolin (that's me).
I am making the programs available under the following terms:
Individuals who are legal owners of an Atari Games Hard Drivin' or Race Drivin' coin-op game (any version) have permission to make copies of these programs for their own use.
Any commercial or other use is prohibited.
mdump.zip
This program merges and interleaves two binary files and sends an ASCII dump of the results to the screen.
The program is run as follows:
mdump file1.bin file2.bin
The output goes to the screen.
In order to save the dump in a file, redirect the output to a file:
mdump file1.bin file2.bin >saveit.txt
I have included two test files: test1.bin and test2.bin .
Make sure you put the files in the correct order:
mdump test2.bin test1.bin >saveit.txt
Here it is: mdump.zip (320KB)
dump.zip
This program sends an ASCII dump of the input file to the screen.
The program is run as follows:
dump file.bin
The output goes to the screen.
In order to save the dump in a file, redirect the output to a file:
dump file.bin >saveit.txt
I have included a test file: test1.bin .
Here it is: dump.zip (142KB)
checksum.zip
This program calculates the checksum of a file by adding the bytes and reporting the low 16 bits of the sum.
The program is run as follows:
checksum file.bin
The output goes to the screen.
Here it is: checksum.zip (184KB)
change.zip
This program reads an input file, uses a change file containing addresses and data to change, and sends the modified image to an output file. It does not change the input file.
The program is run as follows:
change <infile1.bin> <changes.dat> <outfile.bin>
Input File and
Output File must be different
The file format of the change file is:
address,data
There may be only one address,data entry per line.
The address may be decimal or hex text (example: 0x12334).
The data may be decimal or hex text (example: 0x12).
Addresses must be in ascending order.
Lines beginning with an asterisk ' * ' or spaces are ignored (example: * comment).
I have included the test files: test1.bin and change1.dat as well as a batch file (change1.bat) to make it easier to run.
Here it is: change.zip (227KB)
|