Videopac G7000 BIOS
Last changed: 2003-07-22

The clock routines

The BIOS contains routines to manage and display a clock with minutes and seconds. The routines use quad0 and quad1 as display, the time is counted in the external RAM addresses 01h and 02h. This demo program displays a clock which can be controlled with the joystick. Moving left stops the clock, moving right restarts it. The direction can be changed with moving up and down. To demonstrate how to read back the time the program plays a sound every full minute.

How does it work

The VSYNC IRQ counts the frames in bits 0-5 of iram_clock = 03Eh. If the counter reaches 60 it is reset to 0. This is true even for PAL machines, so the clock is too slow on PAL. Bit 6 = clock_forward of iram_clock controls the direction, by setting clock_stop = bit 7 the clock can be stopped. The routine doclock has to be called manually every frame. It tests if the counter is set to 59 and if the clock is active. Then it updates the time in external RAM and the display in quad0/1. Minutes and seconds are stored as BCD numbers. If the time hits 00:00 while counting backwards the clock stops.

Set start time and initialise quad0/1

To set the start time I simply put the values into external RAM. In this example I set the time to 1 minute and 1 second. This means the first visible time is 01:00, because later I set the frame counter to 58 so the first call to doclock will trigger a count and display the correct time in quad0 and quad1. After setting the time I call initclock which sets the position on screen and the color of the clock in the control registers of quad0 and 1. Then I call waitvsync to make sure that I have enough time between setting the frame counter and the first doclock. I then set the frame counter to 58. After that I call gfxon. The main loop starts with waitvsync so in the meantime the counter is set to 59. This also means that for one frame the displayed time is 01:01. The call to doclock then updates the display and decreases the time.


        ; need to initialise quad0/1
        call    gfxoff

        ; set the start time = 01:00
        call    extramenable
        mov     r0,#eram_minutes
        mov     a,#01h          ; BCD
        movx    @r0,a           ; 1 minutes
        mov     r0,#eram_seconds
        mov     a,#01h          ; BCD
        movx    @r0,a           ; 1 second, will roll over
                                ; immediately to 0 seconds

        ; initialise the display
        call    vdcenable
        mov     r3,#020h        ; x position
        mov     r4,#040h        ; y position
        mov     r6,#col_chr_white
        call    initclock

        ; activate the clock
        call    waitvsync       ; make sure there is no roll
                                ; over before we want it
        mov     r0,#iram_clock
        mov     a,#03Ah
        mov     @r0,a           ; start clock backwards
                                ; rolls over at first VSYNC
                                ; and initialises display in
                                ; first doclock
        call    gfxon

The main loop

As usual I use waitvsync to make sure the loop executes once per frame. When calling doclock it is important to set the Y position and the color to the same values as in initclock. If you want to move the clock or change color call initclock again.


loop
        call    waitvsync       ; once per frame

        mov     r4,#040h        ; y position, same as above !!
        mov     r6,#col_chr_white
        call    doclock         ; update clock, if necessary

Reading back the time

After updating the display I test if the seconds are 0. I only want to start the sound playing once although this part is executed every frame, so I have to test the frame counter. Because I don't want to play the sound again and again when the clock stops, I also check if clock_stop is reset. To ignore the direction bit I use 0FFh-clock_forward and not the easier to read ~clock_forward because ASL has problems with the latter, it is expanded to 16 or 32 bits which is too long to fit into a 8 bit register and ASL is too stupid to cut it to 8 bits.


        ; test the time and play sound every minute
        call    extramenable
        mov     r0,#eram_seconds
        movx    a,@r0
        jnz     nosound

        ; only play sound, if count=0 and still counting
        mov     r0,#iram_clock
        mov     a,@r0
        anl     a,#0FFh-clock_forward
        jnz     nosound

        ; now play the sound
        mov     a,#tune_select2
        call    playsound

nosound

Controlling the clock

Then I test the joystick. I only explain the test for left/right, up/down is the same only with R3 and clock_forward. First I test for left by increasing the X offset. If the joystick was turned left A is now 0. In this case I set the clock_stop bit and skip the test for right, because it is impossible to turn the joystick left and right. Now I decrease the X offset twice which means it is now 0 if the joystick is turned right. In this case I clear the clock_stop bit. Then I do the same for up/down. At last I put the new value for iram_clock back and jump to the beginning of the main loop.


        ; test the joystick
        mov     r1,#0
        call    getjoystick

        ; get value to manipulate
        mov     r0,#iram_clock
        mov     a,@r0
        mov     r7,a

        ; test left/right
        mov     a,r2                    ; x offset
        inc     a
        jnz     joy_noleft
        ; left=stop clock
        mov     a,#clock_stop
        orl     a,r7                    ; set clock_stop
        mov     r7,a
        jmp     joy_noright             ; left = not right
joy_noleft
        dec     a
        dec     a
        jnz     joy_noright
        ; right=start clock
        mov     a,#0FFh-clock_stop
        anl     a,r7                    ; clear clock_stop
        mov     r7,a
joy_noright
        ; ...

        ; up/down left out

        ; ...
joy_end
        ; put new value back into iram_clock
        mov     a,r7
        mov     @r0,a

        jmp     loop                    ; next frame