• Help me with a crash theory?

    From Colin Leroy-Mira@21:1/5 to All on Tue Apr 23 09:04:59 2024
    Hi all,

    I have a low-level ACIA serial question for you. Context: I'm working
    on my Wozamp thingy, specificaly the audio+video streaming part. It
    works similar to A2stream for the audio, except it reads from the ACIA
    instead of an Uthernet card to redirect execution to the next duty
    cycle.

    I have started investigating a new, weird bug yesterday evening. I had relocated my duty cycle code, which consists of 32 different duty cycles functions, all aligned on pages so I can jump from one to another by
    updating just the high byte of the jmp pointer.

    My duty cycle functions started at $6000, $6100, etc to $7F00 and
    everything worked fine. Yesterday I relocated that to $6400 to
    $8300. Emulation still works good, but it crashes on real hardware.

    The only theory I have right now is that it's due to my savage way of
    reading the next destination byte from the ACIA DATA register: I don't
    have enough cycles to check the STATUS register, so I just read the
    DATA one. At worst, I thought, I'll re-read the same byte, and that's
    not a problem. (and it was not a problem with my functions from $6000
    to $7F00). But in fact, I'm wondering, can I read a byte from the DATA
    register in the middle of the ACIA writing it? This would explain the
    bug:

    $60 = 01100000
    $7F = 01111111
    But:
    $64 = 01100100
    $83 = 10000011

    If I indeed read a byte right when it's written, the first solution is
    no problem, because the high bit is always 0, and then the ACIA can
    update bits in the order it wants, I have a handler at any 011xxxxx
    location.

    But the second solution would be problematic: what if the ACIA updates
    the data register from $7E (01111110), to $81 (10000001) ? If the high
    bit is the first one updated, I could read 11111110 ($FE), and jump to
    $FE00 which would be bad.

    Or, if I go from $83 (10000011) to $64 (01100100) ? Reading in the
    middle of this write could result in 00000011 ($03, bad) if bits are
    written high to low, or 1000100 ($84, also bad) if they are written low
    to high.

    In both cases, reading the DATA register without a care for the
    STATUS register telling me a byte is ready just happens to work safely
    with numbers from $60 to $7F, but can wreak havoc with numbers from $64
    to $83.

    Does this theory sound plausible to you folks?
    --
    Colin
    https://www.colino.net/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Tue Apr 23 17:54:37 2024
    Hi,

    In both cases, reading the DATA register without a care for the
    STATUS register telling me a byte is ready just happens to work safely
    with numbers from $60 to $7F, but can wreak havoc with numbers from $64
    to $83.

    Replying to myself: that theory is valid.

    I tested it using a sender on the PC, doing
    char buf[10000];

    for (i = 0; i < 10000; i++)
    buf[i] = (buf % 2) ? 0xf0 : 0x0f

    while(1)
    fwrite(buf, 1, 10000, tty);


    On the Apple II, a basic cc65 program doing:
    while (1) {
    char r = read_stuff();
    printf("unexpected %02x\n", r);
    }

    with read_stuff() being:

    _read_stuff:
    : lda $C0A9 ; Wait for first byte
    and #$08
    beq :-

    ; loop, reading data reg directly
    duty_cycle:
    lda $C0A8 ; 4 - get data byte
    cmp #$F0 ; 6
    beq ok_f0 ; 8/9
    cmp #$0F ; 10
    beq ok_0f ; 12/13

    ldx #$00 ; We got something else. Return it.
    rts

    ok_f0: WASTE_63 ; 72 (9+63)
    bra duty_cycle ; 75

    ok_0f: WASTE_59 ; 72 (13+59)
    bra duty_cycle ; 75

    Mystery solved :)
    --
    Colin
    https://www.colino.net/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)