A project log for Reverse Engineering The Weather STAR 4000

The Weather STAR 4000: A Journey of reverse engineering the hardware to an iconic machine of the 1980s/90s.

techknighttechknight 06/23/2022 at 00:440 Comments

Now up to this point we have the graphics card pretty much figured out. We have the framebuffer control on its fundamental levels where we can set palettes and viewports and their resolutions. 

The next part of this puzzle though is how do we achieve animation? the weather icons used on the WS4000 had an animation to them where you can see the rain falling, such as: 

How do we achieve this effect on the WS4000, and how did they do this originally? 

Well, they use palette swapping trickery. Thing is, you can upload a palette to the RAMDAC as we explained in an earlier post, and you can rotate colors around on the index to do this. 

BUT. the WS4000 actually offers a method to do this on its own, which is identified by this function from ROM that I had documented here: 

code:00000776 CHECK_FOR_ANIMATE:                      ; CODE XREF: code:0000111Cp
code:00000776                                         ; code:0000113Fp ...
code:00000776                 mov     A, RAM_39
code:00000778                 jz      code_782
code:0000077A                 mov     DPTR, #0x601
code:0000077D                 clr     A
code:0000077E                 movx    @DPTR, A
code:0000077F                 lcall   Animate_Palette
code:00000782 code_782:                               ; CODE XREF: CHECK_FOR_ANIMATE+2j
code:00000782                 lcall   code_734
code:00000785                 ret
code:00000785 ; End of function CHECK_FOR_ANIMATE
code:00000786 ; =============== S U B R O U T I N E =======================================
code:00000786 Animate_Palette:                        ; CODE XREF: CHECK_FOR_ANIMATE+9p
code:00000786                                         ; Animate_Palettej ...
code:00000786                 jb      RAM_20.3, Animate_Palette ; Wait for previous operations to clear
code:00000789                 mov     R7, RAM_39      ; How many color blocks to copy
code:0000078B                 mov     R0, #0x35 ; '5' ; Beginning location for RAMDAC Palette Addresses
code:0000078D code_78D:                               ; CODE XREF: Animate_Palette+4Ej
code:0000078D                 mov     DPTR, #0x601    ; Location Pointer to Palette Table
code:00000790                 movx    A, @DPTR
code:00000791                 mov     R1, A           ; Store Value at RAM 0x0601 into R1
code:00000792                 mov     A, @R0
code:00000793                 mov     P2, #0x80 ; 'Ç' ; Set Palette Write Address
code:00000796                 movx    @R0, A          ; Store Value in I-RAM 0x35 as RAMDAC Palette Address
code:00000797                 mov     P2, #0x88 ; 'ê' ; Set RAMDAC to Palette Memory
code:0000079A                 mov     A, #7
code:0000079C                 clr     C
code:0000079D                 subb    A, R1           ; Subtract 7 from the contents in 0x0601
code:0000079E                 mov     R2, A           ; Store Result into R2
code:0000079F                 mov     A, @R0          ; Read Palette Address from I-RAM 0x35
code:000007A0                 add     A, R1           ; Add Current 0x0601 Value to RAMDAC Palette Address
code:000007A1                 mov     B, #3           ; B Register
code:000007A4                 mul     AB              ; Multiply Added Palette Address with 3. A contains Low byte, B contains High Byte Result
code:000007A5                 mov     DPL, A          ; Data Pointer, Low Byte
code:000007A7                 mov     A, B            ; B Register
code:000007A9                 add     A, #0           ; Store 16-bit Multiply Result into Data Pointer.
code:000007AB                 mov     DPH, A          ; Data Pointer, High Byte
code:000007AD code_7AD:                               ; CODE XREF: Animate_Palette+30j
code:000007AD                 movx    A, @DPTR        ; Read Red Value from RAM @DPTR
code:000007AE                 inc     DPTR            ; Advance to Next Value (Green)
code:000007AF                 movx    @R0, A          ; Write Red Value to RAMDAC Palette
code:000007B0                 movx    A, @DPTR        ; Read Green Value from RAM @DPTR
code:000007B1                 inc     DPTR            ; Advance to Next Value (Blue)
code:000007B2                 movx    @R0, A          ; Write Green into RAMDAC Palette
code:000007B3                 movx    A, @DPTR        ; Read Blue Value from RAM @DPTR
code:000007B4                 inc     DPTR            ; Advance to Next Value (Red)
code:000007B5                 movx    @R0, A          ; Write Blue into RAMDAC Palette
code:000007B6                 djnz    R2, code_7AD    ; Decrement R2, Repeat Palette Write until 0
code:000007B8                 mov     A, R1
code:000007B9                 jz      code_7D3
code:000007BB                 mov     A, @R0
code:000007BC                 mov     B, #3           ; B Register
code:000007BF                 mul     AB
code:000007C0                 mov     DPL, A          ; Data Pointer, Low Byte
code:000007C2                 mov     A, B            ; B Register
code:000007C4                 add     A, #0
code:000007C6                 mov     DPH, A          ; Data Pointer, High Byte
code:000007C8 code_7C8:                               ; CODE XREF: Animate_Palette+4Bj
code:000007C8                 movx    A, @DPTR
code:000007C9                 inc     DPTR
code:000007CA                 movx    @R0, A
code:000007CB                 movx    A, @DPTR
code:000007CC                 inc     DPTR
code:000007CD                 movx    @R0, A
code:000007CE                 movx    A, @DPTR
code:000007CF                 inc     DPTR
code:000007D0                 movx    @R0, A
code:000007D1                 djnz    R1, code_7C8
code:000007D3 code_7D3:                               ; CODE XREF: Animate_Palette+33j
code:000007D3                 inc     R0
code:000007D4                 djnz    R7, code_78D
code:000007D6                 mov     DPTR, #0x601
code:000007D9                 movx    A, @DPTR
code:000007DA                 inc     A
code:000007DB                 cjne    A, #7, code_7DF
code:000007DE                 clr     A
code:000007DF code_7DF:                               ; CODE XREF: Animate_Palette+55j
code:000007DF                 movx    @DPTR, A
code:000007E0                 ret
code:000007E0 ; End of function Animate_Palette

As we can see, this function is built into ROM. and within the CMD01, it looks for the number of blocks of 7 colors in the palette to rotate. So you would send the speed at which the palette swapping occurs, and then you send each index number which includes the 7 colors that will swap around. 

Like so:

    //Set up Animating Palette. 
    GPUFIFO = 3;                        //Number of Color Blocks to Animate
    GPUFIFO = 0xC0;                        //Target Slot on Palette (In groups of 7 Colors)
    GPUFIFO = 0xC7;                        //Target Slot on Palette (In groups of 7 Colors)
    GPUFIFO = 0xCE;                        //Target Slot on Palette (In groups of 7 Colors)
    GPUFIFO = 8;                        //Number of NTSC Frames per Step.

This breaks down in detail how this works with the WS4000. you send the number of color blocks to rotate, the index of the beginning of the first of 7 colors in the palette, for each block. And then the speed in NTSC fields.  

So the color palette would look something like this: 

This would be your rain colors! the pointer to this block would be on the left of the group of colors here, and it will rotate one at a time, that entire block of 7 colors, but not touch the 8th color on the right side. 

this one was palette swapping too :-)

Now, we have animation down, we need to take a look at how to run the hardware overall as a whole. The graphics card has been entirely figured out for the critical stuff...

Time to look at the I/O card.