hth313 / Calypsi-tool-chains

Overview of the Calypsi tool chain and open source support packages
16 stars 0 forks source link

[65816] Reading an 8-bit value from Memory actually reads 16-bits #36

Closed ProxyPlayerHD closed 7 months ago

ProxyPlayerHD commented 7 months ago

bit of backstory, I recently finished building my new Video card for my 65816 SBC, instead of Dual Port RAM it uses a bi-directional hardware FIFO and a status register to check if there is space to send and if there is anything to read. on the other side of the FIFO i had a 65C02 as a co-processor which was just writing a decreasing sequence of values from $FF to $00 to the FIFO. and on the main 65816 side of the FIFO i just had a simple program reading and printing out the values:

#define mread8(addr)        *((uint8_t*)addr)
#define _VID_CTRL       0x000100FE
#define _VID_FIFO       0x000100FF
#define _VID_TXF        0x80
#define _VID_RXE        0x40

int main(){
    while(!(mread8(_VID_CTRL) & _VID_RXE)){};   // Wait for Data in the FIFO
    while(mread8(_VID_CTRL) & _VID_RXE){        // Repeat this until the FIFO is empty
        printf("Value: $%02X\n", mread8(_VID_FIFO));
    }
}

but when i ran the code i noticed something strange, only odd values were being printed:

[...]
Value: $E1
Value: $DF
Value: $DD
Value: $DB
Value: $D9
Value: $D7
Value: $D5
Value: $D3
Value: $D1
[...]

i checked and double checked the hardware and the 65C02 code, having no idea why this is happening, until i looked at the assembly output of my C program.

0121                    while(!(mread8(_VID_CTRL) & _VID_RXE)){};
    \ 000007 affe0001             lda     long:0x100fe
    \ 00000b 894000               bit     ##64
    \ 00000e f0f7                 beq     `?L65`
    \ 000010          `?L68`:

turns out when i tried to tell the compiler to read from the 8-bit status register it did a full 16-bit read, so the CPU first read the status register at 0x000100FE and then did another read at 0x000100FF which was the hardware FIFO. meaning everytime i checked the status register it also read and discarded whatever was in the FIFO at that time...

i've noticed that it doesn't do this for writes so i would assume it's an optimiazion to avoid excessive switching between 8 and 16-bit registers. which is fine for memory but can easily mess things up when it comes to IO, as you can see here.

so is there some way to force the compiler to explicitly do an 8-bit read?

hth313 commented 7 months ago

You are correct, it is an optimization to avoid switching between 8 and 16 bit access all the time.

You can force it to read 8-bit using volatile. So mread should be somthing like *((uint8_t volatile *)addr)

ProxyPlayerHD commented 7 months ago

that seems to do the trick according to the generated assembly, thank you!