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: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:00000785 code:00000786 code:00000786 ; =============== S U B R O U T I N E ======================================= code:00000786 code:00000786 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: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: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: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: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: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.
//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.