Sitenotice: 11/29/2018: The wiki is back. It turns out, some anti-virus product on my web server had an issue with the latest version of PHP. My server techs have resolved this issue, and things should be working again. During the investigation, I did restore to a backup from September. There is a chance that any changes done since then were lost, but I do not recall any edits. --OS-9 Al

8/30/2016: Massive re-work is being done on the InfoBox Templates. Read that page to keep up with the plan for that, and adding better keyword tags (categories) to all the pages. --OS-9 Al (talk) 15:28, 31 August 2016 (CDT)

A Real-Time Talking Clock, Dennis Kitsz, page 5

From CoCopedia - The Tandy/Radio Shack Color Computer Wiki
Jump to: navigation, search

A Real-Time Talking Clock


Part I

A real-time clock with voice synthesis!

What would you like? A real-time clock? A voice synthesizer? Info on using joysticks? Software without added hardware? A couple of hardware projects to dig into? Okay, get ready: I've got a something-for-everyone series beginning this month that includes two ways of producing voice from the Color Computer and two ways of adding a real-time clock. Depending on how you fold them together, you can have BASIC programs that speak or a clock that talks.

This month I'll be describing how to do voice synthesis - actually, voice recording" - in software, using your joystick input and cassette output ports. In the process, you will learn how the joystick input works, what sampling and timing mean, how the sound output works, and how you can force the high-speed POKE to work in RAM.

After you've had a chance to play with the vocal input/output, I'll create a purely software real-time clock. Since real time anything has to be totally independent of the vagaries of software, you'll learn about interrupts and video synchronization.

In the second part of this series I'll discuss interfacing and using the General Instrument vocal tract synthesizer (sold inexpensively by Radio Shack), and feeding it through the cartridge SND input. That will open the door to combining the vocal hardware with the interrupt-based realtime clock to create a talking timekeeper.

Finally, part three will offer an allophone (speech sound) vocal tract synthesizer that will give you an unlimited vocabulary. I'll provide it with inflection, too, and throw in one more twist to the plot - a battery-powered real-time clock. That will inevitably lead to a rewarding combination: a talking clock that keeps time even when the computer is off. It, too, will be interrupt-driven and completely transparent to other computer operations.


The basic principles of digital recording were explained in my article on Color Quaver (TCCM, November and December, 1983). Here's a review.

Sound is transmitted by variations in air pressure. Pressure variations are transformed by microphones into proportional electrical voltages. In analog recording (such as a phonograph record) the voltages are stored as wiggles in a record groove; in tape recording, .the voltages become variations In magnetic intensity. By reversing the process and forcing voltages through a loudspeaker, air pressure variations can be reproduced; sound results. At all of its stages, analog recording "looks" like the original sound in some respect.

Digital recording also transforms the air pressure changes into electrical variations, at least to start. From that point, though, the process differs dramatically. The electrical variations are measured at regular intervals, and the voltage that has been measured is stored in computer memory, or on disk or tape. To play the sound, the stored numbers are converted back to voltages at exactly the same rate that they were originally measured.

The process of measuring the changes in incoming voltage is called sampling, and the frequency of this process is called the sampling rate. The accuracy of the measurement is called its resolution. Sampling rate is expressed in kilohertz (thousands of cycles per second, abbreviated KHz), and resolution is provided by the number of bits used to sample and store the incoming voltage. The sampling rate affects the fidelity of the sound (faster sampling means a wider frequency range), and the resolution affects the level of sound intensity and noise (higher resolution means wider dynamic range and a better signal-tonoise ratio).

In the demonstration I've got for you, the sampling rate is about 3.6 KHz (7.2 KHz on a 64K computer using the high-speed RAM mode), and the resolution is six bits. The resulting frequency range ends at 1.8 KHz (3.6 KHz on a high-speed 64K computer), and the signal-to-noise ratio is a poor but quite intelligible 36 dB. High fidelity it ain't. Again, you'll find details in the articles on Color Quaver.

The Color Computer has all the means to record and play back voice or music. You won't get much of it - 4.5 seconds is as long as it will last in 16K of memory - but it will start you on adding voice to your Basic programs or doing experiments with digital sound recording.


The key to digital sampling is joystick input. Unlike simple Atari-style joysticks, which are made up of just four switches, Color Computer joysticks are variable resistors like stereo volume controls. A voltage (actually + 5 volts) is placeD on one side of the resistor, and ground is hooked to the other side. The variable resistor's "wiper" sweeps from the ground side to the + 5 volt side as you move the joystick, producing a variable voltage at the wiper contact. If the distance from ground to the wiper is labeled A and the distance from + 5 volts to the wiper is called B, then the voltage at the wiper is 5*(A/ A+B).

The Basic command PRINT JOYSTK(O) causes the computer to sample the voltage at the joystick wiper. The number displayed is 0 to 63, representing a range from 1/64ths of five volts (zero volts) to 63/64ths of five volts (4.92 volts). Try it; enter these lines:

 10 CLS : A$="#.## VOLTS"
 30 PRINT @ 269, USING A$; 5*A/64;
 40 GOTO 20

As you move the joystick, the voltage being sampled (within 1/2 bit, or 1/128 volt) will be displayed.

The significant question is how the joysticks work. The voltage values don't just jump into the computer. And if you're looking for a sophisticated analog-to-digital converter chip, you won't find it.

The answer lies in Radio Shack's desire for a low-cost solution, and their cleverness in finding it. Converting a number to a voltage turns out to be an easier task than going the other way 'round. Converting a number to a proportional voltage goes this way: The binary value is fed through a group of resistors; each resistor contributes twice the previous amount of voltage (each bit to the right is twice the value of its neighbor to the left). Binary arithmetic prevails (I'm rushing here), and the resulting voltage ends up proportional to the original binary number. Figure 1 is the schematic of the digital-to-analog output stage of the Color Computer (the Color Computer 2 uses a custom integrated circuit for this).

If you can output a known voltage cheaply and easily, then you can measure any unknown voltage by comparing the two until you get a match. The known voltage feeds into one side of a commonplace electronic device known as a comparator; the unknown voltage feeds into the other side. The comparator flips from 0 to 1 when the unknown input equals or exceeds the known input. By reading the state of the comparator, the precise moment of match can be discovered. Figure 2 is the schematic of the joystick input section of the Color Computer.

Look at Listing 1, a Basic version of what Color Basic does when it checks the joystick. The digital-to-analog converter is found at address $FF20; the comparator bit is found at $FF00. The technique shown here is a binary search, also called successive approximation.

Control information is sent to the computer's ports (Lines 5 and 6) to get things set up and ready to read a joystick input. Variable A starts at the midway point (Line 7) and its value is sent to the binary-to-voltage converter (Line 10). Variable B receives the information from the comparator byte; bit 7 is the actual comparator result, and bits 0 through 6 contain other computer information. By ANDing value B with $80 (binary 10000000, Line 12), all but bit 7 are masked out, leaving the comparator information alone. Figure 3 shows that bit going into a 6821 peripheral interface adaptor, marked JOYIN.

If the comparator shows that the known outgoing value is less than the unknown incoming value, the binary search continues with a higher outgoing test value (Lines 14 - 16). Otherwise, it uses a lesser outgoing test value (Lines 17 - 18). The counter is decremented (Line 19), and the loop repeats until the process homes in on the unknown value. The result is divided by four to put it in the range 0 to 63, and then displayed.

Run the program. You'll see that - without ever using a JOYSTK command - the joystick value is printed correctly on the screen. Granted, the process is slow in Basic, but it demonstrates that analog-to-digital conversion is not mysterious.

If it works in Basic, it zips along in machine code. Look at Listing 2. The same values are sent to locations $FF01 and $FF03 to perform the set-up. The values 6 and $80 are stored in memory locations TEMP1 and TEMP2 as variable information. The value in the A accumulator goes to location DAC ($FF20).

The process varies just slightly, since a rotate command is available in 6809 commands, but not in Basic. Bit 7 of ADC ($FF00) is rotated into the carry flag; a branch-oncarry follows. The variable TEMP2 is divided by two (using a logical shift right, LSR). The rest of the listing is patterned after the Basic program. Here's an interesting comparison.

The Basic listing can do about three samples per second; using the JOYSTK command increases the sample to about 40 per second; the machine code routine can make over three and a half thousand samples each second.


So how does knowing how the joystick input works help you make a digital recording of your voice? Remember that the first stage of digital recording is the transformation of air pressure variations into proportional voltages. If the joystick input can measure joystick voltages, then shouldn't it follow that it can measure voltages from, say, a cassette player or microphone amplifier? Yes, it can. Basic can't do it because it's too slow. But machine code - at 3,600 samples per second-can pull in a reasonable representation of a voice.

Once you've got the voice stored as a series of numbers, reproducing it is easy. You swing through memory, taking each byte and feeding it to the digital-to-analog converter. The reproduced sound appears at the output. The only thing you need to keep in mind is that homing in on the sound sample takes longer than reproducing the sound by outputting a sample you've got to add a little delay to keep the input and output rates matched.

Look at Listing 3, a complete record-reproduce program for the Color Computer. The heart of the joystick input program you've already seen is found in Lines 240520. The output routine is in 620 - 690. You can see that Lines 650 - 670 add the delay needed to keep input and output matched.

There are only a few other items to note. First of all, direct addressing is used to speed the program along (Lines 220 - 230). Next, interrupts are turned off to keep the sampling rate rock solid (Line 200). And finally, the "fast RAM" mode is used during the input and output sections (Line 210).

What is fast RAM? What are the mysterious high-speed POKEs all about? Here's the deal. The innards of your Color Computer are created from off-the-shelf components suited to many purposes. One of these is called the SAM (Synchronous Address Multiplexer). The SAM can support several computer configurations - that is, several combinations of types and sizes of RAM. The Color Computer uses several memory sizes (4K, 16K, 32K, 64K) but supports only one RAM type: dynamic.

Dynamic memory, through creative development and lots of luck, is low in power required and physically compact. Best of all, it is inexpensive. On the other hand, its special construction requires a continual refresh of its contents. This refresh is accomplished by reading 128 sequential memory locations at least every microsecond. The refresh complicates computer design because it has to be squeezed in between sequential instructions carried out by the central processing unit (CPU).

Designers at Motorola solved the problem by developing a combination of three sophisticated parts: the 6809 CPU itself, the SAM, and the 6847 video display generator. These work together to execute computer instructions, refresh the dynamic memory, and provide a video display.

Imagine the master clock of the Color Computer as a sequence of regular on-off pulses. During pulses 1, 3, 5, 7, 9 and so forth, the CPU executes its instructions from memory. During even-numbered pulses 2, 4, 6, 8 and so on, the memory is freed from the CPU to create the video display or to carry out the dynamic memory refresh. Since the video display generator also uses sequential addresses when it draws the screen, any video display has the effect of refreshing the memory.

When you turn your Color Computer on, it creates those alternating pulses - first one forthe CPU, then one for the video or refresh. It provides the pulses to all of memory. When you POKE 65495,0 (the usual so-called "high-speed" mode), you keep the refresh and video to the dynamic memory, but drop the extra pulse out when the computer uses the Basic ROM. Basic ROM is static and needs no refresh.

The "super high speed" mode is POKE 65497,0. If you try it, though, your video display will go into a frenzy, and you might lose your programs. That's because this POKE tells the SAM to bother with neither refresh nor video, but rather to consider the computer a machine with static RAM and no display output. No refresh, no video.

In this mode you might lose your programs because the refresh cycle is missing and the memory gradually "forgets" its contents. The mode conditions are summarized in Table 1.

But why does the super high speed work for program Listing 37 In this case, sequential memory is being filled with voice information, and then the voice information is played back. At this program's speed, the very act of filling and reading back the sequential memory acts as a memory refresh! The contents remain intact, undisturbed... though the video display is useless.

Once you've saved the source program in Listing 3 (w VOICE), you can assemble it to memory (A/IM/AO), quit the editor/assembler (Q), and protect Basic memory (CLEAR 200,&H3FOO). To use it, you'll need a joystick cable adaptor (see Figure 4). Turn the volume up on your television or monitor, pop a voice or music cassette into the recorder, and run the following lines:

10 EXEC &H3FOO 20 EXEC &H3F80 30 GOTO 10

The screen will go haywire, but the computer will record and play back the sound every two seconds. If you want to see the actual sound displayed as a sound wave, tap the Break key and enter and run Listing 4.


Since Basic programs have to run at normal speed to refresh the RAM, the voice you use with Basic won't have the quality you can hear at the higher speed. No matter; for some programs, any voice at all is better than none, so drop Lines 120, 130, 210, 550, 610 and 700 from Listing 3. You'll be able to store four seconds of sound in the 16K of memory above location $3FFF.


Now I'll turn away from digital voice recording to explore the first of two techniques for keeping the time of day. Keeping the" real time" is tricky because computer time is relative to its own master clock. The Color Computer's master clock (running at 894,886 pulses per second) is meaningful in just one way - you know exactly how much time each processor instruction takes. That's it; there's no easy way a program can know, so to speak, when one second has passed. Something has to knock on its door, interrupt its reverie, and punch it in the nose.

That digital punch is known as an interrupt. The Color Computer was built with interrupts in mind. The cursor flashes to the rhythm of interrupts, the Sound command counts them out to learn when it's done, and the timer runs with them. Fancy games depend on their presence.

Using interrupts isn't difficult, though it does call for a slight change of perspective. When you think of a program, you probably think of it as a logical series of commands followed one at a time without distraction. Interrupts seem to defy this concept, forcing the program away from its a ppoi nted tasks to work on someth i ng else.

That scenario is basically correct. The surprise is that the program in progress seems to have amnesia - it never remembers that it has been distracted from its work, can never recall what has happened during those lost microseconds.

The ideal interrupt happens like this: a signal (say, one synchronized with the video display) appears on the CPU's interrupt-request (IRQ) connection. If the machine code program in progress (such as the Basic interpreter) has enabledthe interrupt process, then this signal will be accepted as soon as the CPU is finished with its present instruction. The machine state (all the registers, program counter, and flags) gets stashed, and the program counter is given a new value. The new value in the program counter points to an "interrupt service routine."

The interrupt service routine takes care of whatever the programmer had in mind for that particular occurrence of the interrupt. When the interrupt service routine is finished, the original machine state (group of registers and flags) is restored and the main program continues exactly where it left off. A little time has mysteriously disappeared during the course of the main program.

A real-time clock is a perfect example of interrupt use.


The Color Computer invites interrupt exploitation because both vertical and horizontal video signals can be used to generate interrupts. Television images require electrical pulses to cause each frame to begin at the top of the screen, and other pulses to cause each scanning line to begin at the left side of the screen. The signal to begin each frame is called vertical synchronization, and the signal to begin each line is called horizontal synchronization.

Vertical sync, which occurs 60 times every second, is an ideal candidate for interrupt use. After six pulses have occurred, then, 1/10 second has passed; after 60 pulses, one full second has passed. By keeping strict track of the pulse count, you can have a real-time clock.

Look at Listing 5, beginning at Line 200. At each interrupt pulse, the CPU will be directed there. Register X points to the final character in the clock image stored in memory, in ASCII, which starts at 00:00:00.00. The final digit is the 1/60 of a second counter. This value is incremented (Line 220), and checked to see if it has reached six. If it's less than six, the image is transferred to the screen by the exit routine beginning at Line 490. If the counter has reached six, it is reset to zero and the 1/10 of a second counter is incremented. If it hasn't reached ten, the routine exits; otherwise, the one-second counter is incremented. And so on, up to a total count of 99:59:59.95.

The exit routine transfers ten characters of the image to the screen. The 1/60 of a second dig it is not displayed.

The amazing thing about this 116-byte routine is that, as programs go, it is totally mundane. It's nothing more than increment, test, proceed, move memory, and exit. The only item to note is found at Line 570. The command JMP $894C lets Basic complete its part of the interrupt service routine chain (cursor, timer, sound) before returning to the program in progress.

Save the source code (W CLOCK), assemble this program into memory (A/IM/AO), quit the editor/assembler (Q), protect memory (CLEAR 200,&H3FOO) and execute the machine code program (EXEC &H3FOO). The clock will appear in the top corner of the screen, in reverse-video characters. This software clock will survive resets and CLOADs (not necessarily CLOADMs), and will run under most program conditions. Naturally, if you have a 32/64K machine, you'll wantto move it up in memory.


I passed by that interrupt theory pretty quickly to give you a chance to see it perform. There are some important things to understand before you put interrupts to work for yourself.

First of all, since interrupts come through at a regular pace, you've got to make sure you keep ahead of that pace. If you don't, you will not get back to the main course of your program properly.

Rule Number 1 is: make your interrupt routines short and efficient. When using the relatively laggard 60-persecond pulse of the vertical sync, that isn't much of a problem, because 1/60th of a second is 16,667 microseconds, or 14,915 Color Computer master clock pulses. The clock interrupt routine is lengthiest at the change back to 00 hours. Including the machine state saving at the interrupt itself, this requires 303 master pulses plus some more for Basic's timer, cursor and sound. The shortest execution for just a 1/60 second count is only 35 master clock pulses. Overall, the clock routine's time is minuscule with respect to the 14,915 master pulses available.

But what if you wanted to create a kind of super stopwatch? The Color Computer gives you a chance to do that, too. There isn't room to go into the details, but the horizontal synchronization from the video can also be used as an interrupt. This interrupt occurs 15,750 times each second, or once every 63.5 microseconds. This time, 63.5 microseconds is just over 56 computer clock cycles... hardly time to do much of anything. If you think 56 clock cycles isn't any time at all, though, turn to Steve Bjork's article on interrupts (Display Modes, December, 1983 TCCM); the pro speaks!

Figure 3 shows the schematic for interrupt handling in the Color Computer. Shown is the 6821 Peripheral Interface Adaptor (PIA). At the left the vertical (or field) synchronization is marked FS, and feeds CB1; horizontal synchronization is marked HS, and feeds CA 1. By proper programming (refer to the 6821 data sheet for details), either can be fed through to the CPU's interrupt request pin via IRQA and IRQB (right side of the PIA).

Oh yes. Here's Rule Number 2: if you are using interrupts in an independent program that does not work with the Basic ROMs at all, be sure to reset the interrupt latch by reading the correct PIA location (LDA $FF02). Otherwise, further interrupts won't be passed through the PIA, and you'll lose all the timing.


I won't tie all this together until later in this series, but keep in mind that all these concepts involve timing - the ultra-fast timing of digital recording, the hidden timing of interrupts, and (in the next part) the slow timing of interfacing with external electronics.

Ed's Note: Articles referred to, except Part I of this series, are found in back issues of The Color Computer Magazine, unless otherwise noted.


BASIC emulation of a joystick input routine. 16K Extended Color BASIC.

 1 CLS
 2 X=&HFFOO          '* PORT VALUE
 3 DAC = &HFF20      '* D/A CONVT.
 5 POKE &HFF01,&H34  '* CTRL. INFO
 6 POKE &HFF03,&H37  '* CTRL. INFO
 7 A = &H80          '* B 10000000
 8 T1 = 6            '* ITERATIONS
 9 T2 = &H80         '* B 10000000
 10 POKE DAC,A       '* SEND VALUE
 11 B = PEEK (ADC)   '* BYTE BIT 7
 12 B = B AND &H80   '* TEST BIT 7
 13 IF B = 0 THEN 17 '* IF FLIPPED
 14 T2 = T2/2        '* ELSE LESS
 15 A = A + T2       '* ADD VALUE
 16 GOTO 19          '* GO TO NEXT
 17 T2 = T2/2        '* IT IS MORE
 18 A = A - T2       '* ELSE MORE
 19 T1 = T1 - 1      '*'SUB. VALUE
 20 IF T1>0 THEN 10  '* DONE YET?
 21 PRINT@0,"JOY ="; '* A MESSAGE
 23 GOTO 7           '* & DO AGAIN


Machine code version of a joystick input routine, using a binary search.

00270         LDA        #$34
00280         STA        $FF01
00290         LDA        #$37
00300         STA        $FF03
00310 *
00320 NEXTIN  LDA        #$06
00330         STA        <TEMP1
00340         LDA        #$80
00350         STA        <TEMP2
00360 *
00370 AGAIN   STA        DAC
00380         ROL        ADC
00390         BCC        BIGGER
00400 LESSER  LSR        <TEMP2
00410         ADDA        <TEMP2
00420         BRA        JUMP
00430 BIGGER  LSR        <TEMP2
00440         SUBA        <TEMP2
00450         BRA        JUMP
00460 JUMP    DEC        <TEMP1
00470         BNE        AGAIN
00480         STA        ,X+
00490 *


Continous record/reproduce program.

FF20         00100 DAC        EQU     $FF20
FF00         00110 ADC        EQU     $FF00
FFD9         00120 FAST       EQU     $FFD9
FFD8         00130 SLOW       EQU     $FFD8
4000         00140 MEMBOT     EQU     $4000
8000         00150 MEMTOP     EQU     $8000
             00160 *   
3F00         00170            ORG     $3F00
3F           00180            SETDP   $3F
             00190 *   
3F00 1A 50.  00200 START      ORCC    #$50
3F02 B7 FFD9 00210            STA     FAST
3F05 86 3F   00220            LDA     #$3F
3F07 IF 8B   00230            TFR     A,DP
             00240 *   
3F09 8E 4000 00250            LDX     #MEMBOT
             00260 *   
3F0C 86 34   00270            LDA     #$34
3F0E B7 FF01 00280            STA     $FF01
3F11 86 37   00290            LDA     #$37
3F13 B7 FF03 00300            STA     $FF03
             00310 *   
3F16 86 06   00320 NEXTIN     LDA     #$06
3F18 97 9B   00330            STA     <TEMP1
3F1A 86 80   00340            LDA     #$80
3F1C 97 9C   00350            STA     <TEMP2
             00360 *   
3F1E B7 FF20 00370 AGAIN      STA     DAC
3F21 79 FF00 00380            ROL     ADC
3F24 24 06   00390            BCC     BIGGER
3F26 04 9C   00400 LESSER     LSR     <TEMP2
3F28 9B 9C   00410            ADDA    <TEMP2
3F2A 20 06   00420            BRA     JUMP
3F2C 04 9C   00430 BIGGER     LSR     <TEMP2
3F2E 90 9C   00440            SUBA    <TEMP2
3F30 20 00   00450            BRA     JUMP
3F32 0A 9B   00460 JUMP       DEC     <TEMP1
3F34 26 E8   00470            BNE     AGAIN
3F36 A7 80   00480            STA     ,X+
             00490 *   
3F38 8C 8000 00500            CMPX    #MEMTOP
3F3B 26 D9   00510            BNE     NEXTIN
             00520 *   
3F3D 4F      00530            CLRA 
3F3E IF 8B   00540            TFR     A,DP
3F40 B7 FFD8 00550            STA     SLOW
3F43 39      00560            RTS 
             00570 *   
3F80         00580            ORG     $3F80
             00590 *   
3F80 1A 50   00600 PLAYBK     ORCC    #$50
3F82 B7 FFD9 00610            STA     FAST
3F85 8E 4000 00620            LDX     #MEMBOT
3F88 A6 80   00630 SPEAK      LDA     ,X+
3F8A B7 FF20 00640            STA     DAC
3F8D C6 2C   00650            LDB     #$2C
3F8F 5A      00660 LOOP       DECB 
3F90 26 FD   00670            BNE     LOOP
3F92 8C 8000 00680            CMPX    #MEMTOP
3F95 26 F1   00690            BNE     SPEAK
3F97 B7 FFD8 00700            STA     SLOW
3F9A 39      00710            RTS 
             00720 *   
3F9B         00730 TEMP1      RMB     1
3F9C         00740 TEMP2      RMB     1
             00750 *   
0000         00760
00000 TOTAL ERRORS    
ADC     FF00     MEMTOP 8000  
AGAIN   3F1E     NEXTIN 3F16  
BIGGER  3F2C     PLAYBK 3F80  
DAC     FF20     SLOW   FFD8  
FAST    FFD9     SPEAK  3F88  
JUMP    3F32     START  3F00  
LESSER  3F26     TEMP1  3F9B  
LOOP    3F8F     TEMP2  3F9C  
MEMBOT  4000    


Short BASIC routine to display the sound wave representation of the sound recorded by Listing 3. 32K Extended Color Basic

10 CLS0
20 FOR X = &H4000 TO &H8000
30 SET (Y, PEEK(X)/8, 5)
40 Y=Y+1: IF Y>63 THEN CLS0: Y=0


Real-time clock using Internal interrupts which occur 60 times each second. 32K Extended Color Basic

3FOO           00100 ORG $3FOO
               00110 *
3FOO lA 50     00120 INTOFF   ORCC     #$50           * TURN INTERRUPTS OFF
3F02 8E 3FI0   00130          LDX      #START         * POINT X TO SERVICE ROUTINE
3F05 BF 010D   00140          STX      $010D          * STORE ROUTINE TO IRQ VECTOR
3F08 86 37     00150          LDA      #$37           * VALUE 00110111 FOR MASKING
3FOA B7 FF03   00160          STA      $FF03          * TURN ON VERTICAL SYNC
3FOD lC EF     00170          ANDCC    #$EF           * TURN INTERRUPTS ON
3FOF 39        00180          RTS                     * AND BACK TO BASIC "nK"
               00190 *
3FI0 8E 3F77   00200 START    LDX      #IMAGE+I0      * POINT X TO 1/10 SEC.
3F13 C6 30     00210          LDB      #$30           * B BECOMES ASCII OFFSET
3F15 6C 84     00220          INC      ,x             * INCREMENT 1/10 SECONDS
3F17 A6 84     00230          LDA      ,x             * GET 1/10 SECONDS VALUE
3F19 81 36     00240          CMPA     #$36           * IS 6/10 SECONDS COUNTED?
3FIB 2D 2C     00250          BLT      OUT            * IF NOT 6/10 SECONDS, OUT
3F1D 8D 40     00260          BSR      DECI           * ELSE BAC UP 1 MEM. LOCATION
3FIF 81 3A     00270          CMPA     #$3A           * IS IT 1 SECOND YET?
3F21 2D 26     00280          BLT      OUT            * IF NOT 1 SECOND, OUT
3F23 8D 41     00290          BSR      DEC2           * ELSE BACK UP 2 MEM. LOCNS.
3F25 81 3A     00300          CMPA     #$3A           * IS IT 10 SECONDS YET?
3F27 2D 20     00310          BLT      OUT            * IF NOT 10 SECONDS, OUT
3F29 8D 34     00320          BSR      DECI           * BACK UP 1 MEM. LOCATION
3F2B 81 36     00330          CMPA     #$36           * IS IT 60 SECONDS YET?
3F2D 2D lA     00340          BLT      OUT            * IF NOT 60 SECONDS, OUT
3F2F 8D 35     00350          BSR      DEC2           * ELSE BACK UP 2 MEM. LOCNS.
3F31 81 3A     00360          CMPA     #$3A           * IS IT 10 MINUTES YET?
3F33 2D 14     00370          BLT      OUT            * IF NOT 10 MINUTES, OUT
3F35 8D 28     00380          BSR      DECI           * ELSE BACK UP 1 MEM. LOCATION
3F37 81 36     00390          CMPA     #$36           * IS IT 60 MINUTES YET?
3F39 2D DE     00400          BLT      OUT            * IF NOT 60 MINUTES, OUT
3F3B 8D 29     00410          BSR      DEC2           * ELSE BACK UP 2 MEM. LOCNS.
3F3D 81 3A     00420          CMPA     #$3A           * IS IT 10 HOURS YET?
3F3F 2D 08     00430          BLT      OUT            * IF NOT 10 HOURS, OUT
3F41 8D 1C     00440          BSR      DECI           * ELSE BACK UP 1 MEM. LOCATION
3F43 81 3A     00450          CMPA     #$3A           * IS IT 100 HOURS YET?
3F45 2D 02     00460          BLT      OUT            * IF NOT 100 HOURS, OUT
3F47 E7 84     00470          STB      ,x             * PLACE $30 (ASCII ZERO)
               00480 *
3F49 108E 0416 00490 OUT      LDY      #$0416         * POINT TO RIGHT SCREEN
3F4D 8E 3F6D   00500          LDX      #IMAGE         * POINT X TO CLOCK IMAGE
3F50 C6 OA     00510          LDB      #$OA           * COUNT 10 SCREEN POSITIONS
3F52 A6 80     00520 LOOP     LDA      ,X+            * GET CHARACTER FROM CLOCK
3F54 A7 AD     00530          STA      ,Y+            * AND PLACE IT ON THE SCREEN
3F56 5A        00540          DECB                    * DONE WITH IMAGE YET?
3F57 26 F9     00550          BNE      LOOP           * IF NOT, THEN GET NEXT CHAR.
               00560 *
3F59 B6 FF02   00570          LDA      $FF02          * CLEAR VERT. SYNC LATCH
3F5C 7E 894C   00580          JMP      $894C          * AND TO BASIC TO DO RTI
               00590 *
3F5F E7 84     00600 DECI     STB      ,X             * PLACE $30 (ASCII ZERO)
3F61 6C 82     00610          INC      ,-X            * BACK UP ONE MEM. LOCATION
3F63 A6 84     00620          LDA      ,X             * GET VALUE FROM IMAGE
3F65 39        00630          RTS                     * BACK TO MAIN PROGRAM
               00640 *
3F66 E7 84     00650 DEC2     STB      ,X             * PLACE $30 (ASCII ZERO)
3F68 6C 83     00660          INC      ,--X           * BACK UP TWO MEM. LOCATIONS
3F6A A6 84     00670          LDA      ,X             * GET VALUE FROM IMAGE
3F6C 39        00680          RTS                     * BACK TO MAIN PROGRAM
               00690 *
3F6D 30        00700 IMAGE    FCC /00:00:00.00/
               00710 *
     3FOO      00720 END INTOFF

DEC2   3F66
LOOP   3F52
OUT    3F49