Classic Computer Magazine Archive COMPUTE! ISSUE 43 / DECEMBER 1983 / PAGE 344

VIC/64 Clock

Paul F, Schatz

The Commodore 64's CIA chip features a 24-hour time-of-day clock with programmable alarm. Unlike the jiffy clock, it cannot be interrupted by various I/O functions. The program here creates a clock in the corner of the screen which keeps working while you program or run other BASIC programs. For VIC users, see the accompanying article, "VIC Clock."

Since Commodore introduced the 64, much has been written on the 6566/6567 Video Interface Controller (VIC-II) chip and the 6581 Sound Inter­face Device (SID) chip. The 6526 Complex Interface Adapter (CIA) chip, another new integrated circuit, introduced with the 64, has largely been ignored. This chip supersedes the 6522 Versatile Interface Adapter (VIA) used in previous Commodore computers. The CIA has several additional features not in the VIA, one of them a 24-hour time-of-day (TOD) clock with programmable alarm.

How The Time-Of-Day Clock Works

The TOD clock consists of four memory registers organized into hours, minutes, seconds, and tenths of seconds. The CIA continuously updates these registers based on an external frequency source. Like most commercial digital clocks, the CIA chip uses the 60 cycles/second (60 Hz) frequency of the voltage in household electric power lines as a source.

The TOD clock is very different from the jiffy clock, which is referenced by the BASIC variables TI and TI$. The jiffy clock is updated by a carefully timed sequence of instructions in the interrupt service routine of the computer. If the interrupt routine is suspended (as, for example, during cassette loads or saves) or altered, the jiffy clock loses its accuracy. On the other hand, the timing for the TOD clock is independent of the interrupt routine and is as accurate as the external frequency source. (And the 60Hz line frequency of U.S. electric utilities is extremely accurate.)

Program Operation

This program, "64 Clock," creates a window in the upper-left corner of the screen in which the time is continuously displayed. The machine language program hooks into the interrupt routine, so the display is updated every 1/60 second. After the clock display has been set up and started, other BASIC programs can be run while the clock ticks away. The only limitation is that your program must alter the interrupt pointers.

There are two parts to the program. Lines 10 – 180 set up the machine language routine for the display window. Lines 200 – 530 set the time on the clock. When a number is written into the hours register (line 270), the TOD clock stops and does not restart until a number is written into the tenths-of-a-second register (line 370). The numbers in the TOD registers are in binary coded decimal (BCD) format. Lines 500 – 530 are a sub­routine for converting the input data into the proper format for setting the TOD registers.

The default colors for the window display are standard screen color for the characters and white for the background. Thus, if the screen is white, the characters will not be visible. The background color can be changed by entering:

POKE 49263, < color >

where < color > is the number corresponding to one of the 16 colors available on the 64. The position of the window can be changed by entering:

POKE 49207, < column >

where <column> is the number of the column where the window starts. If <column> is 0, the window is in the upper-left corner. If <column> is 28, the window is in the upper-right corner. The display may be turned off and on without affecting the time. To turn on the display, enter SYS 49155. To turn off the display, enter SYS 49152. The display may also be turned off by pressing the RUN/ STOP and RESTORE keys simultaneously.

Since there are two CIA chips built into the 64, it is possible to have two TOD clocks. It is also

possible to set an alarm on the TOD clock which triggers an interrupt. More information on the CIA chip and the TOD clock can be found in Appendix M of the Commodore 64 Programmer's Reference Guide.

VIC Clock

Charles Brannan Program Editor

The Commodore 64's CIA chip is easily programmable for 24-hour time. The timekeeping is independent of any of the computer's other functions. The VIC-20 is equally capable of keeping time, but it has to be done with software.

Every 60th of a second, the VIC's own VIA chip causes an interrupt. An interrupt does what the name implies: The 6502 microprocessor stops whatever it's doing and goes on to execute a special interrupt routine. After the interrupt routine is finished, the interrupted program resumes.

During the interrupt, the VIC performs certain "housekeeping" functions. It reads the keyboard, converts the keyscan code to normal Commodore ASCII, then places this value in the keyboard buffer. The interrupt also flashes the cursor. And each time the interrupt Is called, the interrupt routines increment the realtime clock.

The realtime clock uses three memory locations: 160,161, and 162. The time is stored in sixtieths of a second, since the clock is updated every sixtieth of a second. But a memory location can only hold a value from 0-255, so three locations are used. Every time location 162 wraps around to zero (approximately every four seconds), location 161 is incremented, and when 161 wraps around to zero, location 160 is bumped up by one. Note that the order of the bytes is backward compared to the normal 6502 convention, where the most significant byte (the one that goes up after the least significant byte wraps around to zero) follows the least significant byte.

You can read the realtime clock in BASIC without worrying about the memory locations. Two reserved variables, TIME and TIMES, always return the current time. The numeric variable TIME returns the time in sixtieths of a second, and is equivelent to PEEK(160) + PEEK(161 )*256 + PEEK( 162)* 65536. You can divide it by 60 to get the time in seconds. You cannot change TIME directly, as in TIME=0, but you can change TIMES and that will cause TIME to change.

TIMES is a string holding a six-digit number. The format (as in TIMES="041020") is HHMMSS, where HH is the hours, MM is minutes, and SS is seconds. You must "pad out" unused digits with a zero (01 for one hour). You can directly set TIMES, and print out the time with PRINT TIMES. TIMES is a 24-hour clock, as in military time, so any hour after noon has 12 added to it. To set the clock to 10:30 a.m. you would write: TIMES="103000". but you would use TIMES = "172500" for 5:25 p.m. At midnight. TIMES wraps around to "000000". Once you set the time, it keeps counting automatically. Incidentally, you can abbreviate the variables to TI and TI$.

A Few Caveats

There are a few things to look out for when using this software-updated clock. If the interrupt routine is disabled, then it doesn't have the opportunity to update the dock. Cassette input/output uses the VIA chip for its own purposes, preventing its use for the normal system interrupts Therefore, the system clock stops during tape I/O and restarts after the tape access is finished. If you art using the clock to keep the time of day, it will lose as much time as the tape routines take. There is no way around this, so keep it in mind.

It may be convenient to have the time always displayed. Program 2, "VIC Clock," lets you do this. You have the option of starting the clock, stopping it, clearing it, and setting the time. The clock is always displayed in the upper left-hand corner of the screen, and nothing will erase it, not even screen scrolls or clears. The displayed clock is separate from the normal realtime clock variables, TI and TI$, so you can still use them in your program. The clock is added to the interrupt routine discussed above (so it will not update during tape routines either). If you want to turn off the visible clock, just press RUN/STOP-RESTORE.

Look at Program 2 for some details on using the clock and function keys. You can stop the clock with POKE 997, 1 and start it with POKE 997,0. You can also change the color of the clock digits by POKEing 996 with the same color as you would put into color memory, 0-7.

Program 1 :64 Clock

10 A = 0 : FOR I = 49152 TO 49296 : READ J : POKE I, J : A = A + J : NEXT I
20 IF A <>16834 THEN PRINT "ERROR IN DATA {SPACE}STATEMENTS" : END
30 PRINT "{CLR}{DOWN}{RVS}CLOCK FOR C64 {OFF}"
40 PRINT : PRINT "TO SET THE CLOCK - RUN 200"
50 PRINT "TO CHANGE THE COLOR - POKE 49263,COLOR"
60 PRINT "TO BLANK CLOCK DISPLAY - SYS 49152"
70 PRINT "TO ACTIVATE DISPLAY - SYS 49155"
80 SYS 49155
90 END
100 DATA 76, 30, 192, 120, 173, 20, 3, 141, 28, 192, 169, 45, 141, 20, 3, 173, 21
110 DATA 3, 141, 29, 192, 169, 192, 141, 21, 3, 88, 96, 49, 234, 120, 173, 28, 192
120 DATA 141, 20, 3, 173, 29, 192, 141, 21, 3, 88, 96, 173, 24, 208, 41, 240, 74
130 DATA 74, 133, 254, 169, 0, 133, 253, 160, 0, 173, 11, 220, 72, 41, 127, 162, 186
140 DATA 32, 120, 192, 173, 10, 220, 32, 120, 192, 173, 9, 220, 162, 174, 32, 120, 192
150 DATA 173, 8, 220, 32, 137, 192, 104, 16, 3, 169, 144, 44, 169, 129, 32, 141, 192
160 DATA 169, 141, 145, 253, 169, 216, 133, 254, 169, 1, 145, 253, 136, 16, 251, 108, 28
170 DATA 192, 72, 32, 133, 192, 104, 32, 137, 192, 138, 32, 141, 192, 96, 74, 74, 74
180 DATA 74, 41, 15, 9, 176, 145, 253, 200, 96
200 REM CLOCK SETTING ROUTINE
210 PRINT "{CLR}{DOWN}{RVS}SET THE CLOCK {SPACE}" : PRINT
220 POKE 56335, PEEK(56335) AND 127 : REM {SPACE}SET TIME OF DAY CLOCK
230 INPUT "AM OR PM"; A$
240 A = 128 : IF LEFT$(A$, 1) = "A" THEN A = 0
250 INPUT "HOUR"; A$ : IF LEN(A$)>2 THEN PRINT "ERROR" : GOTO 250
260 GOSUB 500 : IF N>18 THEN PRINT "ERROR" : GOTO 250
270 POKE 56331, A + N : REM SET HOURS
280 INPUT "MINUTES"; A$ : IF LEN(A$)>2 THEN PRINT "ERROR" : GOTO 280
290 GOSUB 500 : IF N>89 THEN PRINT "ERROR" : GOTO 280
300 POKE 56330, N : REM SET MINUTES
310 INPUT "SECONDS"; A$ : IF LEN(A$)>2 THEN PRINT "ERROR" : GOTO 310
320 GOSUB 500 : IF N>89 THEN PRINT "ERROR" : GOTO 310
330 POKE 56329, N : REM SET SECONDS
340 PRINT "WHEN YOU ARE READY TO START THE CLOCK,"
350 PRINT "PRESS ANY KEY."
360 GET A$ : IF A$ = ""THEN 360
370 POKE 56328,0 : REM START CLOCK
380 END
500 IF LEN(A$) = 1 THEN T = 0 : GOTO 520
510 T = VAL(LEFT$(A$,1))
520 U = VAL(RIGHT$(A$,1))
530 N = 16 * T + U : RETURN

Program 2 : VIC Clock

by Charles Brannon, Program Editor

100 PRINT"{CLR}{RVS}PLEASE WAIT"
110 FORI = 828TO995 : READA : POKEI, A : CK = CK + A : NEXT
120 IFCK<>20518THENPRINT"{HOME}ERROR IN DATA STATEMENTS" : END
125 SYS828
130 PRINT"{CLR}{4 SPACES}{4 DOWN}CHOOSE : {DOWN}"
140 PRINT"{4 SPACES}{RVS}{YEL}F1{OFF} : {BLU}STOP CLOCK"
150 PRINT"{DOWN}{4 SPACES}{RVS}{RED}F3 {OFF}{BLU} : START CLOCK"
160 PRINT"{DOWN}{4 SPACES}{RVS}{PUR}F5 {OFF}{BLU} : CLEAR CLOCK"
165 PRINT"{DOWN}{4 SPACES}{RVS}{GRN}F7 {OFF} : {BLU}SET TIME"
170 GETA$ : IFA$ <CHR$(133)ORA$>CHR$(136)THEN 170
180 ON ASC(A$) - 132 GOTO 190, 240, 250, 200
190 POKE 997, 1 : GOTO 170
200 POKE 997, 1 : INPUT"{CLR}{2 DOWN}HOURS? 00 {4 LEFT}";H$ : IFLEN(H$)< > 2THEN200
210 INPUT"MINUTES? 00{4 LEFT}";M$ : IFLEN(M$)<>2THEN210
220 INPUT"SECONDS? 00{4 LEFT}";S$ : IFLEN(S$)<>2THEN220
230 T$ = H$ + M$ + S$ + "00" : FORI = 1TO8 : POKE998 + I, ASC(MID$(T$,I)) : NEXT : GOTO130
240 POKE997,0 : GOTO170
250 SYS 851 : POKE997, 1 : GOTO170
828 DATA 173, 020, 003, 141, 226, 003
834 DATA 173, 021, 003, 141, 227, 003
840 DATA 120, 169, 098, 141, 020, 003
846 DATA 169, 003, 141, 021, 003, 169
852 DATA 048, 162, 009, 157, 230, 003
858 DATA 202, 208, 250, 142, 229, 003
864 DATA 088, 096, 173, 229, 003, 208
870 DATA 053, 162, 008, 024, 189, 230
876 DATA 003, 105, 001, 141, 228, 003
882 DATA 201, 058, 208, 005, 169, 048
888 DATA 141, 228, 003, 138, 041, 001
894 DATA 240, 012, 173, 228, 003, 201
900 DATA 054, 208, 005, 169, 048, 141
906 DATA 228, 003, 173, 228, 003, 157
912 DATA 230, 003, 202, 240, 007, 201
918 DATA 048, 208, 249, 076, 105, 003
924 DATA 162, 008, 160, 011, 173, 002
930 DATA 144, 010, 169, 000, 133, 251
936 DATA 042, 010, 133, 252, 133, 254
942 DATA 173, 005, 144, 074, 074, 074
948 DATA 005, 252, 133, 252, 169, 000
954 DATA 133, 253, 165, 254, 009, 148
960 DATA 133, 254, 173, 240, 003, 145
966 DATA 253, 189, 230, 003, 009, 128
972 DATA 145, 251, 138, 041, 001, 240
978 DATA 010, 136, 169, 058, 145, 251
984 DATA 173, 240, 003, 145, 253, 136
990 DATA 202, 208, 225, 076, 049, 234