Menu

#2113 Reads/write/compare to non-existent drive memory returns wrong result

v3.9
closed-fixed
gpz
None
GTK3
Drives
2025-04-03
2024-12-27
Lord Crass
No

Vice version: 3.9 GTK3, compiled from source with options "--enable-gtk3ui"
OS: Linux Mint 22 (kernal 6.12.6, GCC 13.3.0)

A routine I've used to detect presence of extra drive RAM in 1541/1571 no longer works properly (didn't work in 3.8 either, not sure when it broke). In the code below, when no drive RAM is present at $6000, the emulator takes the branch $20f when it shouldn't. Looking at $6800 with Vice monitor shows that the byte contains $00 both at the LDA instruction and after the INC.

On a 1571, it works, but only because the memory configuration has an $ff at $6800 instead. If I change it to use $6802, which defaults to a $00 byte, this fails as well.

Also, if I change the CMP $6800 to CMP $0000 (where this address also contains a $00 value), the expected result is returned. The zero flag is set as the value is the same, and the branch is not taken. It seems the problem is comparing to a zero value only in address space that doesn't contain RAM.

Also, the Vice monitor returns a different value from this memory space than a software-based drive monitor does (such as the Warp Speed cartridge's). Using "m $6800" with cartridge monitor returns a value of $68 at $6800 instead of the $00 that Vice monitor shows with sidefx off or $ff with sidefx on. This is somewhat confusing. Is there a way to have the vicemon show what software reads would actually be seeing?

.8:0205  78          SEI
.8:0206  AD 00 68    LDA $6800  ; A=$00
.8:0209  EE 00 68    INC $6800  ; $6800 still contains $00 after this
.8:020c  CD 00 68    CMP $6800  ; Z=0 after this, but should be Z=1
.8:020f  D0 0E       BNE $021F  ; jump is taken, RAM at $6000 detected
.8:0211  AD 00 88    LDA $8800
.8:0214  EE 00 88    INC $8800
.8:0217  CD 00 88    CMP $8800
.8:021a  F0 06       BEQ $0222
.8:021c  A9 08       LDA #$08
.8:021e  2C A9 06    BIT $06A9
.8:0221  2C A9 00    BIT $00A9
.8:0224  85 C7       STA $C7
.8:0226  60          RTS

Discussion

1 2 > >> (Page 1 of 2)
  • gpz

    gpz - 2025-03-30

    https://sourceforge.net/p/vice-emu/code/43662/ might be releated (apparently this is what broke it)

    That said, we DO have a test program to back up this change: https://sourceforge.net/p/vice-emu/code/HEAD/tree/testprogs/drive/openbus/

    In any case, this code actually looks broken to me - there is a 1 in 256 chance it will fail, depending on what is contained in the RAM address being tested before the test - and even regardless of what our "what is read from open bus" theory looks like

    "On a 1571, it works, but only because the memory configuration has an $ff at $6800 instead. If I change it to use $6802, which defaults to a $00 byte, this fails as well."
    This btw sounds very wrong. Bytes in RAM don't default to anything - there is just a certain chance for a certain value to manifest at a certain address at powerup. So anything relying on the powerup state is broken by design.

    Whatever, we need a test case to check a) uninitialized RAM content and b) verify the open bus reads some more. I am not convinced this is an actual bug in VICE for that matter - it seems to be one of those cases were software that only works by chance stopped working, because the chance flipped.

     
  • gpz

    gpz - 2025-03-30

    Forgot:

    Also, the Vice monitor returns a different value from this memory space than a software-based drive monitor does (such as the Warp Speed cartridge's). Using "m $6800" with cartridge monitor returns a value of $68 at $6800 instead of the $00 that Vice monitor shows with sidefx off or $ff with sidefx on. This is somewhat confusing. Is there a way to have the vicemon show what software reads would actually be seeing?

    No, this is not possible. Because "what software reads would actually be seeing" depends on the actual software that is running (and there is no such thing when using VICE monitor). Like in this case, the value is the last value that was on the bus - but there is no such value in the vice monitor :)

     
  • Lord Crass

    Lord Crass - 2025-03-30

    I use this on real hardware (1541-II mostly) and I have not seen it fail there yet. The value read by the drive with no memory mapped at the address always indeed comes back as the high byte that was part of the read (at least this seems to be true with LDA and CMP instructions). Therefore, an INC to this address and then reading it back again should result in the same value instead of the incremented value.

     
  • gpz

    gpz - 2025-03-30

    you are right (brainfart on my end).

    So first thing i did: i ran this openbus.prg on my c64+1541 ... and it works (green border). Same in VICE.

    A quick test in the monitor seems to indicate it is always reading 0 though. Now i am confused - why does that testprogram work?

     
  • gpz

    gpz - 2025-03-30

    OK some more checking. Unfortunately the mentioned fix is indeed the problem. It fixes the case when open io is read by an indexed instruction - which is also what the test program checks.

    it does however break the simple case, without indexing... args

    waiting for @ikorb to comment (he made that test). can't think of a simple fix right now. Its tricky, because right now the "floating value" is set by the dummy reads (which makes lda abs,x work) - but with a regular "lda abs" there is no such thing. we must somehow differentiate between the two things - outside of the cpu core

     

    Last edit: gpz 2025-03-30
  • gpz

    gpz - 2025-03-30

    PS: once we fixed this, we need to check the same thing on vic20 and pet as well

     
  • Olaf Seibert

    Olaf Seibert - 2025-03-31

    yes the PET also reads the high byte of the address from empty space. I never researched deep enough to know why. And I never heard that it would behave differently for indexed addressing modes...

    I even found a test program from Commodore that depends on reading $E8 from $E800:


    r45467 | rhialto | 2025-01-28 21:14:43 +0100 (Tue, 28 Jan 2025) | 15 lines

    Also return empty space on E80x.

    I found a test program that cares about this:
    8032.mem.prg from https://www.zimmers.net/anonftp/pub/cbm/pet/utilities/
    It tests the 64K memory expansion and wants to see empty space at E800 if the
    "I/O peek through" is enabled:

    .C:096d A9 CC LDA #$CC ; enabled; i/o peek though; bank 3 and 1; no w/p
    .C:096f 8D F0 FF STA $FFF0
    .C:0972 85 00 STA $00
    .C:0974 AD 00 E8 LDA $E800 ; I/O area but no chip selected
    .C:0977 C9 E8 CMP #$E8
    .C:0979 F0 07 BEQ $0982


     

    Last edit: Olaf Seibert 2025-03-31
  • Lord Crass

    Lord Crass - 2025-03-31

    A few tests performed on a real 1541-II result in reading the high byte every time. Tried with load and compare instructions in all valid addressing modes.

    However, crossing the page boundary with an index mode results in different behaviour.

    LDX #$01
    LDA $67FF,X (A = contents of $6700,X, which is $700,X when no RAM connected)
    LDA $68FF,X (A = contents of $6800,X or $68 when no RAM connected)

     

    Last edit: Lord Crass 2025-03-31
    • gpz

      gpz - 2025-03-31

      Have you tried the test program linked above? it shows the case where it is NOT the high byte of the address. (You'll have to craft some specific cases with page boundary crossing to make this happen)

       
    • gpz

      gpz - 2025-03-31

      With abs,x the value "read" should be the one resulting from the dummy read, ie from the address before the high byte was corrected after adding the indeed.

      I'm making some tables atm to check if this is really the whole truth. I'd expect at least one more weird case :)

       
  • gpz

    gpz - 2025-03-31

    why it happens is clear now - when trying to read unconnected bus space, the cpu will "see" the last value whatever else left on the bus.

    now why it is different between instructions is a direct consequence out of this, eg for "lda abs" this will be the high byte of the address. For something like "lda abs,x" it will be the value resulting from the dummy read that happens before the actual read.

    Now the problem with fixing this in the emulation is that in the first case, the value is not actually read or written (so the fix in #43662 does not work for it)

    Now what puzzles me - we have a test program for vic20:
    https://sourceforge.net/p/vice-emu/code/HEAD/tree/testprogs/VIC20/unconnected/ (although it is a bit hard to read, it seems it does actually check "lda abs" and "lda abs,x")

    However, i can not find the place in xvic where it handles the case when it should return address highbyte. Somehow it just works. shrug

     
  • Lord Crass

    Lord Crass - 2025-03-31

    I edited my last comment as I forgot to test the case of crossing page boundary.

     
  • Lord Crass

    Lord Crass - 2025-03-31

    Indirect indexed also behaves like absolute indexed. Returns what's in the prior page.

    Ran the openbus.prg with stock ROMs in NTSC C64C and 1541-II drive and it failed the majority of the time, highlighting a seemingly random byte as being wrong on each failure. Rough estimate is that it returned a green border maybe 20% of the time.

     
    • gpz

      gpz - 2025-03-31

      Thats because the transfer routines are PAL only - i didn't manage to fix them :/ Any help with that appreciated, of course :)

       
  • gpz

    gpz - 2025-03-31

    So, i found something interesting - i did not expect this. (This behaviour may be the reason for other strange effects as well - anything that relies on being triggered by reads in codespace)

    in memiec.c put a printf

    static uint8_t drive_read_1541ram(diskunit_context_t *drv, uint16_t address)
    {
        printf("%04x %02x   drive_read_1541ram\n", address, drv->drive_ram[address & 0x7ff]);
        return drv->cpu->cpu_last_data = drv->drive_ram[address & 0x7ff];
    }
    

    and same in drivemem.c

    static uint8_t drive_read_free(diskunit_context_t *drv, uint16_t address)
    {
        printf("%04x %02x   drive_read_free\n", address, drv->cpu->cpu_last_data);
        return drv->cpu->cpu_last_data;
    }
    

    now in vice mon:

    (C:$e5cf) dev 8:
    Setting default device to `Disk8'
    (8:$ec14) a 0205 sei
    .0206  lda $6800
    .0209  
    (8:$0209) break $0205
    BREAK: 1  8:$0205  (Stop on exec)
    (8:$0209) g 0205
    #1 (Stop on  exec 0205) 
    .8:0205  78          SEI            - A:FF X:06 Y:FF SP:45 ..-....C    2629396
    (8:$0205) z
    .8:0206  AD 00 68    LDA $6800      - A:FF X:06 Y:FF SP:45 ..-..I.C    2629398
    (8:$0206) z
    .8:0209  00          BRK            - A:00 X:06 Y:FF SP:45 ..-..IZC    2629402
    (8:$0209) 
    

    you get this output (blank lines after Z in monitor inserted by me)

    0205 78   drive_read_1541ram
    0206 ad   drive_read_1541ram
    0207 00   drive_read_1541ram
    0208 68   drive_read_1541ram
    0209 00   drive_read_1541ram
    
    0206 ad   drive_read_1541ram
    0207 00   drive_read_1541ram
    0208 68   drive_read_1541ram
    0209 00   drive_read_1541ram
    020a 00   drive_read_1541ram
    
    6800 00   drive_read_free
    0209 00   drive_read_1541ram
    020a 00   drive_read_1541ram
    020b 00   drive_read_1541ram
    020c 00   drive_read_1541ram
    020d 00   drive_read_1541ram
    

    so apparently the cpu core always fetches 5 bytes in advance for each instruction - and thats why the current fix does not work for lda abs (and only works by chance for lda abs,x)

    So the question is why it does this - and if it is even possible to fix in the current architecture

     
  • gpz

    gpz - 2025-04-01

    so apparently the cpu core always fetches 5 bytes in advance for each instruction - and thats why the current fix does not work for lda abs (and only works by chance for lda abs,x)

    Theory is wrong - this is the disassembler that is calling it 5 times, AND then triggers another bug.

    I have a temorary fix:

    (C:$e5cd) dev 8:
    Setting default device to `Disk8'
    (8:$ec34) a 205 sei
    .0206  lda $6800
    .0209  lda $5000
    .020c  nop
    .020d  
    (8:$020d) g 205
    #1 (Stop on  exec 0205) 
    .8:0205  78          SEI            - A:00 X:00 Y:01 SP:45 ..-...ZC   27391657
    (8:$0205) z
    .8:0206  AD 00 68    LDA $6800      - A:00 X:00 Y:01 SP:45 ..-..IZC   27391659
    (8:$0206) 
    .8:0209  AD 00 50    LDA $5000      - A:68 X:00 Y:01 SP:45 ..-..I.C   27391663
    (8:$0209) 
    .8:020c  EA          NOP            - A:50 X:00 Y:01 SP:45 ..-..I.C   27391667
    (8:$020c) 
    .8:020d  00          BRK            - A:50 X:00 Y:01 SP:45 ..-..I.C   27391669
    (8:$020d) m 6800 6810
    >8:6800  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00   ................
    >8:6810  00                                                   .
    (8:$6811) g 0205
    #1 (Stop on  exec 0205) 
    .8:0205  78          SEI            - A:50 X:00 Y:01 SP:45 ..-..I.C   27391669
    (8:$0205) z
    .8:0206  AD 00 68    LDA $6800      - A:50 X:00 Y:01 SP:45 ..-..I.C   27391671
    (8:$0206) z
    .8:0209  AD 00 50    LDA $5000      - A:68 X:00 Y:01 SP:45 ..-..I.C   27391675
    (8:$0209) m 6800 6810
    >8:6800  68 68 68 68  68 68 68 68  68 68 68 68  68 68 68 68   HHHHHHHHHHHHHHHH
    >8:6810  68                                                   H
    (8:$6811) 
    

    I comitted in r45617. Please test - also please try a bunch of random "problem cases" :)

    Performance might have suffered, please tell if its a noticable difference.

    If there are still weird problems: you can get debug info when starting with -debug, please attach the relevant part

     
  • gpz

    gpz - 2025-04-01

    Just for the records, so i don't forget:
    1) the (drive) test program needs to be updated to check the lda abs case too
    2) Star_Rank_Boxing_Green_Label_GameStar_s0.g64 works now :)

     
  • Lord Crass

    Lord Crass - 2025-04-01

    Confirmed this fixes the problem with check I used in WS V3 cart. It also works as expected with Star Rank Boxing. Crashes if drive RAM enabled, works if disabled. I think one of the 21 Second backup copiers or the VG Datashack file copier also had some roundabout check for drive RAM, I'll see if I can dig that up and test as well.

     
  • Lord Crass

    Lord Crass - 2025-04-01

    Confirmed working with 21 Second Backup v4.1, which does this:

    .8:0403  6C 01 64    JMP ($6401)    - A:01 X:65 Y:00 SP:3d ..-B.IZ.   11213637
    .8:a5c9  C4 52       CPY $52        - A:EC X:65 Y:00 SP:3d N.-B.I..   11213642
    .8:a5cb  49 56       EOR #$56       - A:EC X:65 Y:00 SP:3d N.-B.I..   11213645
    .8:a5cd  45 06       EOR $06        - A:BA X:65 Y:00 SP:3d N.-B.I..   11213647
    .8:a5cf  20 52 45    JSR $4552      - A:B4 X:65 Y:00 SP:3d N.-B.I..   11213650
    .8:4552  4C EC 66    JMP $66EC      - A:B4 X:65 Y:00 SP:3b N.-B.I..   11213656
    .8:66ec  FB 00 24    ISB $2400,Y    - A:B4 X:65 Y:00 SP:3b N.-B.I..   11213659
    .8:66ef  C0 EC       CPY #$EC       - A:76 X:65 Y:00 SP:3b .V-B.I.C   11213666
    .8:66f1  B0 03       BCS $66F6      - A:76 X:65 Y:00 SP:3b .V-B.I..   11213668
    .8:66f3  FB 00 66    ISB $6600,Y    - A:76 X:65 Y:00 SP:3b .V-B.I..   11213670
    .8:66f6  FB 00 45    ISB $4500,Y    - A:2A X:65 Y:00 SP:3b ..-B.I.C   11213677
    .8:66f3  FB 00 66    ISB $6600,Y    - A:2A X:65 Y:00 SP:3b ..-B.I.C   11213677
    .8:66f9  C8          INY            - A:01 X:65 Y:00 SP:3b ..-B.I.C   11213684
    .8:66fa  44 76       NOOP $76       - A:01 X:65 Y:01 SP:3b ..-B.I.C   11213686
    .8:66fc  D0 EE       BNE $66EC      - A:01 X:65 Y:01 SP:3b ..-B.I.C   11213689
    
     
  • gpz

    gpz - 2025-04-01

    Confirmed working with 21 Second Backup v4.1

    The .g64? Doesn't work for me... do i NEED drive RAM for this? :)

     
  • Lord Crass

    Lord Crass - 2025-04-01

    No, it's a parallel-only copier. The mirrored access it does at $6000 will cause it to crash if you have memory mapped there though. Memory at $8000 is no problem.

    Other parts the protection code are very specific to the drive ROM. Be sure you're using a 1541 and not a 1541-II. You also have to write-protect the disk or it won't load.

     
  • gpz

    gpz - 2025-04-01

    AAAH old drive

    x64sc -default -ntsc -drive8type "1541" -userportdevice "21" -parallel8 "4" -attach8ro "20-sec-backup/VG Datashack 21 Second Backup v4.1.g64"

    working indeed, cool!

     
  • Olaf Seibert

    Olaf Seibert - 2025-04-01

    I think I finally understand where that high address byte is coming from!

    This is because with a LOAD instruction, the last successful read on the bus was the high byte of the address.
    Example: LDA $9000 reads AD 00 90 as instruction bytes and then from $9000.
    Even LDA ($12),Y reads B1 12 as instruction bytes, but then 00 90 from the zero page, then from $9000.
    The only exception is when there is indexing with a page crossing. Then there is a dummy read from $90xx before the real read of $91xx. In that case you get $90, not $91.

    Of course that assumes that the value remains on the unloaded bus for not only one but for 2 cycles.

    Another exceptional case would be if you had empty space in the zero page. Then you would get different results when you use LDA $0012 or LDA $12.

     
    • Ingo Korb

      Ingo Korb - 2025-04-01

      You're not limited to the high byte of the (in-incremented or current) address, if the dummy read hits a non-open memory address its content will stay on the bus.

       

      Last edit: Ingo Korb 2025-04-01
  • Olaf Seibert

    Olaf Seibert - 2025-04-01

    And the last time I made any changes for unmapped addresses in the PET, I must have been tricked by the Vice monitor which doesn't show it like the CPU sees...

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.

MongoDB Logo MongoDB