2023-02-19

What if VIC-II had vcbase writable

Ciriciao folks!
This one needs some explanation, what is vcbase? According to the VIC-II article vc is an internal 10 bit counter register that is used to scan the 1000 cells of the screen, vcbase is another register that is used to initialize vc after each scanline. At the start of a frame vcbase is set to 0, so in text mode the screen starts with the first byte pointed by the video page in $18, after each column vc is incremented, after each scanline vc is reset to vcbase if the row is not finished, or the other way around vcbase is set to vc after one full row (8 scanlines). So vcbase is 40 at the beginning of the second row (read byte with offset 40 of the video page), 80 for the next row, etc.

What if we could at the begininning of each frame set the value of vcbase to something else than 0?
What for?

One effect thet requires precise timing, also explained in the VIC-II Article, is called DMA Delay.
It is used to increment vc and vcbase before starting to show the screen, thus scrolling it sideways of the desired amount of characters.
Vc and vcbase are 10 bit registers, so somewhere in the last part of the scrolled screen the counter wraps and the first bytes of the video page are displayed.

Contuining with the experiment of using adders where VIC-II used justaxpositions, we'll extend vc and vcbase to 14 bits (no wrap-arounds until the end of the 16KB bank) and add a new write-only register vcbase_latch. To write to vcbase_latch we'll use another pair of read-only registers, $D01E and $D01F, normally used to read the status of sprites collisions.
In the previous post the adder was only 4 bits wide and did not give issues in VIC-II Kawari, now vc is extended from 10 to 14 bits and the 4 additional bits overlap and need another 4 bit adder.
One other advantage of having 14 bits is that the screen can also be scrolled vertically of any amount of characters.

Mind that the color memory is still only 1K, so the counter will wrap at 10 bit boundaries for the colors, as bofore.

Implementation in Vice

No special flag to enable this feature, the Kernal initializes vcbase_latch to 0, so everityhing works as before if you don't change it.
A new internal register is added in file vice/src/viciisc/viciitypes.h:

    /* Internal memory pointer (VCBASE).  */
    int vcbase;
    int vcbase_latch;

In file vice/src/viciisc/vicii-mem.c write accesses to registers $1E and $1F are diverted to vcbase_latch:

inline static void vcbase_store(const uint16_t addr, const uint8_t value)
{
    VICII_DEBUG_REGISTER(("WIV vc base register %s: $%02X", (addr == 0x1e) ? "LOW" : "HIGH", value));

    if (addr == 0x1e) {
        ((uint8_t *)&vicii.vcbase_latch)[0] = value;
    } else {
        ((uint8_t *)&vicii.vcbase_latch)[1] = value & 0x3f;
    }
}

...

        case 0x1e:                /* $D01E: Sprite-sprite collision or VIC-WIV vc base low */
        case 0x1f:                /* $D01F: Sprite-background collision or VIC-WIV vc base high */
            if (IS_WIV) {
                vcbase_store(addr, value);
            } else {
                collision_store(addr, value);
            }

In file vice/src/viciisc/vicii-cycle.c vcbase is initialized at the beggining of each frame to vcbase_latch:

    vicii.vcbase = IS_WIV ? vicii.vcbase_latch : 0;

Implementation in VIC-II Kawari

In file hdl/matrix.v vcbase is initialized:

`ifdef WIV_EXTENSIONS
                vc_base <= wiv_vcbase_latch;
                vc <= wiv_vcbase_latch;
`else
                vc_base <= 10'd0;
                vc <= 10'd0;
`endif

And in file hdl/addressgen.v it's used for the bitmap mode, 11 bits now instead of the 10 bits of before:

                    if (wiv_xmp)
                        vic_addr = {cb + vc[10:7], vc[6:0], rc}; // bitmap data
                    else
                        vic_addr = {cb[3] + vc[10], vc[9:0], rc}; // bitmap data

And for text mode, the whole 14 bits:

`ifdef WIV_EXTENSIONS
            vic_addr = {vm + vc[13:10], vc[9:0]}; // video matrix c-access
`else
            vic_addr = {vm, vc}; // video matrix c-access
`endif

BASIC example

Only one example in text mode, with increments or decrements of 1 you get an horizontal scrolling, with steps of 40 yuou get a vertical scrolling.

10 rem ** vertical scroll
20 for i=24 to 0 step -1
25 a=i*40
30 poke 53278,(a and 255)
35 poke 53279,(a / 256)
40 for p=0 to 200:next
45 next
50 rem ** horizontal scroll
60 for i=39 to 0 step -1
70 poke 53278,i
80 for p=0 to 200:next
85 next

No comments:

Post a Comment