Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
mg_notes:apple_iic:iic_bugs [2017/11/06 22:22]
M.G. created
mg_notes:apple_iic:iic_bugs [2017/11/10 03:46] (current)
M.G.
Line 5: Line 5:
 The memory expansion firmware has the following code to test the size of the memory expansion card, if installed: The memory expansion firmware has the following code to test the size of the memory expansion card, if installed:
  
 +<​code>​
  
 +numbanks ​ equ   ​$03bb ​        ; screen hole - $c0
 +sizetemp ​ equ   ​$0478 ​        ; screen hole shared
 +addrl     ​equ ​  ​$bff8 ​        ; slinky address reg for indirect use
 +addrm     ​equ ​  ​$bff9 ​        ; real registers are from $c0c0-$c0c3
 +addrh     ​equ ​  ​$bffa ​        ; ..
 +data      equ   ​$bffb ​        ; slinky data reg
 +
 +; at entry x is expected to have $c8 (slot * $10 + $88)
 +; and y is expected to contain $c4 (slot $Cn)
 +testsize ​ equ   *
 +          lda   #​0 ​           ; zero address reg l/m
 +          sta   ​addrl,​x
 +          sta   ​addrm,​x
 +          lda   #​$10 ​         ; start at 1 meg and go down
 +          sec
 +tsloop ​   sbc   #​1 ​           ; move down a bank
 +          sta   ​addrh,​x
 +          lda   ​data,​x ​       ; save existing data
 +          pha
 +          dec   ​addrl,​x ​      ; fix address (undo auto-increment)
 +          lda   #​$a5 ​         ; common apple check byte
 +          sta   ​data,​x ​       ; store it
 +          dec   ​addrl,​x ​      ; fix...
 +          eor   ​data,​x ​       ; 0 if the data is there
 +          dec   ​addrl,​x ​      ; fix...
 +          cmp   #​1 ​           ; C = 0 if data okay
 +          pla
 +          sta   ​data,​x ​       ; restore data
 +          lda   ​addrh,​x ​      ; <-- SEE COMMENTS BELOW
 +          and   #​$0f ​         ; only lower nibble valid
 +          beq   ​tsnoram ​      ; no RAM somehow! [note: if bank 0, skips checking result of RAM test]
 +          bcs   ​tsloop ​       ; loop until we find a bank [carry set = no RAM in bank]
 +          adc   #​1 ​           ; C = 0 from compare
 +tsnoram ​  ​sta ​  ​numbanks,​y
 +          lsr   a
 +          sta   ​sizetemp ​     ; sizetemp = upper byte of block count
 +          rts
 +</​code>​
 +
 +If you note the code starting at the indicated line, you can see that the code grabs the high byte of the Slinky address register and uses the low nibble directly as a counter value.
 +
 +The problem is that when there is no memory expansion card installed, there is no register, and the value there is floating bus.  The only reason the code gets out of the loop is because the floating bus happens to usually have a bunch of bytes streaming by that have 0 in the low nibble.
 +
 +That being said, MAME before ​ [[https://​github.com/​mamedev/​mame/​commit/​bdcb98307822e79c242782ee67bef966bf4c25de|bdcb983]] did not float the bus for $C0C0-$C0CF. ​ A non-floating bus results in ROM $03 hanging when the card is first accessed, and, due to changes made by Apple, a hang at boot for ROM $04 (and presumably IIc Plus ROM $05).
 +
 +Another minor issue is that the code wouldn'​t find a theoretical Slinky that had only one 64K bank built into it, as the loop terminates when the bank hits 0 (beq tsnoram) even if the carry flag is clear because RAM was found in bank 0.
 +
 +The code could be fixed by using the stack to save the counter and comes out a few bytes shorter:
 +
 +<​code>​
 +testsize ​ equ   *
 +          lda   #​0 ​           ; zero address reg l/m
 +          sta   ​addrl,​x
 +          sta   ​addrm,​x
 +          lda   #​$10 ​         ; start at 1 meg and go down
 +          sec
 +tsloop ​   sbc   #​1 ​           ; move down a bank
 +          sta   ​addrh,​x
 +          pha                 ; save counter, +1 byte code added
 +          lda   ​data,​x ​       ; save existing data
 +          pha
 +          dec   ​addrl,​x ​      ; fix address (undo auto-increment)
 +          lda   #​$a5 ​         ; common apple check byte
 +          sta   ​data,​x ​       ; store it
 +          dec   ​addrl,​x ​      ; fix...
 +          eor   ​data,​x ​       ; 0 if the data is there
 +          dec   ​addrl,​x ​      ; fix...
 +          cmp   #​1 ​           ; C = 0 if data okay
 +          pla
 +          sta   ​data,​x ​       ; restore data
 +          pla                 ; restore counter (net save 4 bytes)
 +          beq   ​tsnoram ​      ; no RAM somehow!
 +          bcs   ​tsloop ​       ; loop until we find a bank
 +          adc   #​1 ​           ; C = 0 from compare
 +tsnoram ​  ​sta ​  ​numbanks,​y
 +          lsr   a
 +          sta   ​sizetemp ​     ; sizetemp = upper byte of block count
 +          rts
 +</​code>​
 +
 +We could use a couple of those bytes to fix the bank 0 issue:
 +
 +<​code>​
 +testsize ​ equ   *
 +          lda   #​0 ​           ; zero address reg l/m
 +          sta   ​addrl,​x
 +          sta   ​addrm,​x
 +          lda   #​$10 ​         ; start at 1 meg and go down
 +          sec
 +tsloop ​   sbc   #​1 ​           ; move down a bank
 +          sta   ​addrh,​x
 +          pha                 ; save counter, +1 byte code added
 +          lda   ​data,​x ​       ; save existing data
 +          pha
 +          dec   ​addrl,​x ​      ; fix address (undo auto-increment)
 +          lda   #​$a5 ​         ; common apple check byte
 +          sta   ​data,​x ​       ; store it
 +          dec   ​addrl,​x ​      ; fix...
 +          eor   ​data,​x ​       ; 0 if the data is there
 +          dec   ​addrl,​x ​      ; fix...
 +          cmp   #​1 ​           ; C = 0 if data okay
 +          pla
 +          sta   ​data,​x ​       ; restore data
 +          pla                 ; restore counter (net save 4 bytes)
 +          bcc   ​tsgotram ​     ; RAM found, extra branch net cost 2 bytes
 +          beq   ​tsnoram ​      ; still won't find lonely bank 0
 +          bne   ​tsloop ​       ; loop until we find a bank
 +tsgotram ​ adc   #​1 ​           ; C = 0 from compare
 +tsnoram ​  ​sta ​  ​numbanks,​y
 +          lsr   a
 +          sta   ​sizetemp ​     ; sizetemp = upper byte of block count
 +          rts
 +</​code>​
 +
 +Since all %%//%%cs and IIc Pluses shipped with a 65C02, the code could be made even smaller (ca65 format):
 +
 +<​code>​
 +testsize: stz   ​addrl,​x ​      ; net save 2 bytes using stz here
 +          stz   ​addrm,​x
 +          lda   #​$10 ​         ; start at 1 meg and go down
 +tsloop: ​  ​dec ​  ​a ​            ; one byte saved using dec a
 +          sta   ​addrh,​x
 +          pha                 ; save counter, net cost 1 byte
 +          lda   ​data,​x ​       ; get exiting data
 +          pha                 ; save it
 +          dec   ​addrl,​x ​      ; fix address (undo auto-increment)
 +          lda   #​$a5 ​         ; common apple check byte
 +          sta   ​data,​x ​       ; store it
 +          dec   ​addrl,​x ​      ; fix...
 +          eor   ​data,​x ​       ; 0 if the data is there
 +          dec   ​addrl,​x ​      ; fix...
 +          cmp   #​1 ​           ; C = 0 if data okay
 +          pla                 ; get data back
 +          sta   ​data,​x ​       ; restore data
 +          pla                 ; get counter back, sets N and Z, net save 4 bytes over existing code
 +          bcc   ​tsgotram ​     ; RAM found, extra branch net cost 2 bytes
 +          beq   ​tsnoram ​      ; still won't find lonely bank 0
 +          bra   ​tsloop ​       ; loop until we find a bank
 +tsgotram: adc   #​1 ​           ; C = 0 from compare, could also use inc a
 +tsnoram: ​ sta   ​numbanks,​y
 +          lsr   a
 +          sta   ​sizetemp ​     ; sizetemp = upper byte of block count
 +          rts
 +</​code>​
 +
 +If it was undesirable to use the stack, we overwrite sizetemp anyway when the routine exits, so we could replace the pha/pla with sta sizetemp/​lda sizetemp at the cost of 4 bytes.