sikthehedgehog / vdpnotes

VDP notes
4 stars 0 forks source link

Figure out why VRAM address bit 0 is inverted #4

Open sikthehedgehog opened 1 month ago

sikthehedgehog commented 1 month ago

According to kabuto's notes, VRAM address bit 0 is inverted in mode 5 64K:

In 64K mode column 0 (i.e. address bit 1) is inverted, the internal byte order of the VDP is the opposite of what the 68K sees. The VDP just emulates the opposite byte order through its interface, which also means that pixels aren't really stored in natural order internally. This explains a number of issues seen, for example why bytes written by copy commands are in opposite order, bit zero seemingly being swapped when using 128K and SMS modes. And all this was done just to provide seemingly correctly ordered bytes when used by the 68K which has a different byte order compared to the Z80.

EDIT: he meant address bit 0, argh

Emulating this properly is also required to prevent glitches in Road Rash during a mid-screen write.

The problem is… VDP doesn't seem to be inverting that bit in the circuit that scrambles the address bits. w1010 takes address bit 0 as-is (when in mode 5), that's passed to w1011 intact, and then that's used in w1012 in 64KB mode. The only stuff after that is latching the result and muxing to determine which set of bits goes on the bus.~~

EDIT: I'm dumb and the doc actually meant address bit 0 all this time… but that one is still used as-is right in w1012, so the point stands.

So the VDP doesn't seem to be inverting it, despite the fact that we seemingly have proof to the contrary. We need to figure out what is it doing that leads to a similar effect. My guess would be that it's done at the CPU interface level? Or we have the wrong idea of what are the "upper" and "lower" bytes for the VDP?

sikthehedgehog commented 1 month ago

Edited first post because I just realized the notes talked about bit 1 when it really meant bit 0. Doesn't really change the situation though, but leaving it here for those getting email notifications.

sikthehedgehog commented 1 month ago

Looks like there's no inversion at all, the VRAM address is just used as-is. What seems to be going on however is byteswapping, giving the impression that the bottom bit is flipped.

It makes sense in hindsight:

This leaves the question about how does this work with the Z80 in SMS mode, or with mode 4 in MD mode. Also, it seems like DMA fill and DMA copy may expose this discrepancy when autoincrement is larger than 1.

sikthehedgehog commented 1 month ago

Well, screw me:

        (w275 ? { l35[16:1], ~l35[0] } : 17'h1ffff) &

…or so I thought.

l35 holds the current VRAM address (!!) and it comes from the FIFO/DMA block, so at a glance it would seem like the VDP is indeed inverting the address LSB all along, just not where expected. But look where l35 actually comes from:

    ym_slatch #(.DATA_WIDTH(17)) sl35(.MCLK(MCLK), .en(w299), .inp(vram_address), .val(l35));
    ym_slatch #(.DATA_WIDTH(17)) sl36(.MCLK(MCLK), .en(w294), .inp(reg_data_l2), .val(l36));
    ym_slatch #(.DATA_WIDTH(17)) sl37(.MCLK(MCLK), .en(w293), .inp(reg_data_l2), .val(l37));
    ym_slatch #(.DATA_WIDTH(17)) sl38(.MCLK(MCLK), .en(w292), .inp(reg_data_l2), .val(l38));
    ym_slatch #(.DATA_WIDTH(17)) sl39(.MCLK(MCLK), .en(w291), .inp(reg_data_l2), .val(l39));

l36 to l39 are the VRAM address in the FIFO entries. This means that l35 is likely the address used by DMA copy (which by-passes the FIFO), which would mean that the LSB inversion is exclusive to DMA. Considering how DMA doesn't let you specify the write size, it would make sense that they apply this kludge there. It also explains why it doesn't bother to check with mode 4, since DMA doesn't work there.

In short: what I've reported before about the FIFO writes being little endian still seems to be true, but now we know how it's dealt with when the FIFO is by-passed.