[Hard+Soft] Memory Base 128

hu, cd, scd, acd, supergrafx discussions.
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

It's now Emerald Dragon turn!
emerald.asm

At first glance, it's the cleanest code so far.
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

The code to check for Memory Base 128 presence is roughly the same.

Code: Select all

;-----------------------------------------------------------------------
; Detect Memory Base 128.
; A = #$00 found.
; A = #$ff not found.
;-----------------------------------------------------------------------
l618c_00: LDA     #$03          ; 3 try
          STA     $e209
l6191_00: INC     $e20b
          LDA     #$a8
          JSR     l61cc_00      ; write byte (#$a8)
          LDA     #$00          ; write bit 0 and read joyport
          JSR     l6200_00
          TAY                   ; save joyport to Y
          LDA     #$01          ; write bit 1 and read joyport
          JSR     l6200_00
          CPY     #$00          ; try again if Y is not zero
          BNE     l61af_00
          CMP     #$04          ; try again if the last read nibble is 4
          BNE     l61af_00
          JMP     l61c3_00
l61af_00: INC     $e20c
          DEC     $e209
          BEQ     l61ba_00
          JMP     l6191_00
l61ba_00: CLA                   ; mb128 not found
          LDX     #$03          ; write 3 bits (000)
          JSR     l61d1_00
          LDA     #$ff
          RTS     
l61c3_00: LDA     #$00          ; mb128 found
          RTS     
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

$606f contains a single bit read.

Code: Select all

l606f_00: STZ     $e20b
          STZ     $e20c
          INC     <$28
          ; Send 3 zero bits.
          JSR     l61c6_00
          ; Detect mb128
          JSR     l618c_00
          ORA     #$00
          ; There's no mb128 if the N flag is set
          BMI     l60a5_00
              ; Send 1 one bit
              JSR     l61e2_00
              ; Send byte #$00
              CLA     
              JSR     l61cc_00
              ; Send 2 zero bits
              CLA     
              LDX     #$02
              JSR     l61d1_00
              ; Send byte #$01
              LDA     #$01
              JSR     l61cc_00
              ; Send byte #$00
              CLA     
              JSR     l61cc_00
              ; Send 4 zero bits
              CLA     
              LDX     #$04
              JSR     l61d1_00
              ; Read data
              JSR     l6279_00
              ; Send 3 zero bits
              JSR     l61c6_00
              ; Set return code
              LDA     #$00
l60a5_00: DEC     <$28
          RTS
So from the other 2 games, a read sequence is initiated by writing the following bit sequence:

Code: Select all

100 00000000 00000001 00000000 0000 
Somewhere along those bits is the read address. A code place too investigate is $60a8.
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

Here is 2 utility routines. The first one left shift a 16bits word by 3, storing the result in 3 bytes. The second sends 20bits to the memory base 128.

Code: Select all

; Left shift a word by 3.
; in:  $e206/$e207       input word
; out: $e204/$e205       input word
;      $e206/$e207/$e208 input word shifted to the left by 3.
l6220_00: LDA     $e206
          STA     $e204
          LDA     $e207
          STA     $e205
          STZ     $e208
          LDX     #$03
l6231_00: ASL     $e206
          ROL     $e207
          ROL     $e208
          DEX     
          BNE     l6231_00
          RTS     

Code: Select all

; Send 20 bits to mb128
; in: $e206/$e207/$e208  20 bits to send.
l623e_00: LDA     $e206
          JSR     l61cc_00      ; Send byte
          LDA     $e207
          JSR     l61cc_00      ; Send byte
          LDA     $e208
          LDX     #$04
          JSR     l61d1_00      ; Send 4 bits
          RTS     
And now, the read routine:

Code: Select all

; Read bytes from mb128.
; in: $10/$11     Output buffer address.
;     $12/$13     Read address
;     $e200/$e201 ?
;     $e204/$e205 Number of bytes to read.
;
l60a8_00: INC     <$28          ; Is $28 some kind of lock?
          JSR     l618c_00      ; Detect mb128
          BMI     l610b_00      ; There's no mb128 if the N flag is set
          STZ     $e202
          STZ     $e203
          LDA     <$12
          STA     $e206
          LDA     <$13
          STA     $e207         ; addr   = ($13 << 8) | $12
          JSR     l6220_00      ; addr <<= 3
          JSR     l61e2_00      ; Send bit #1
          LDA     $e200
          JSR     l61cc_00      ; Send byte
          LDA     $e201
          LDX     #$02
          JSR     l61d1_00      ; Send 2 bits
          JSR     l623e_00      ; Send the 20 bits address
l60d6_00: JSR     l6253_00      ; Read a byte 
          STA     [$10]         ; Store byte
          CLC                   ; Increment the number of byte read
          ADC     $e202
          STA     $e202
          LDA     $e203
          ADC     #$00
          STA     $e203
          INC     <$10          ; Increment storage address
          BNE     l60f0_00
          INC     <$11
l60f0_00: LDA     $e204         ; Decrement number of bytes to read
          BNE     l60f8_00
          DEC     $e205
l60f8_00: DEC     $e204
          LDA     $e204
          ORA     $e205
          BNE     l60d6_00      ; Loop until there is nothing to read
          JSR     l61c6_00      ; Send 3 zero bits
          LDA     #$00          ; ret = ok
          JMP     l610d_00
l610b_00: LDA     #$01          ; ret = err
l610d_00: DEC     <$28          ; Release lock?
          ORA     #$00
          RTS     

; Left shift a word by 3.
; in:  $e206/$e207       input word
; out: $e204/$e205       input word
;      $e206/$e207/$e208 input word shifted to the left by 3.
l6220_00: LDA     $e206
          STA     $e204
          LDA     $e207
          STA     $e205
          STZ     $e208
          LDX     #$03
l6231_00: ASL     $e206
          ROL     $e207
          ROL     $e208
          DEX     
          BNE     l6231_00
          RTS     

; Send 20 bits to mb128
; in: $e206/$e207/$e208  20 bits to send.
l623e_00: LDA     $e206
          JSR     l61cc_00      ; Send byte
          LDA     $e207
          JSR     l61cc_00      ; Send byte
          LDA     $e208
          LDX     #$04
          JSR     l61d1_00      ; Send 4 bits
          RTS     
So the read sequence is initiated by sending

Code: Select all

1_xxxxxxxxxx_yyyyyyyyyyyyyyyyyyyy
with yyyyyyyyyyyyyyyyyyyy the 20 bits long read address.
The 10 bits xxxxxxxxxx are still unknown. So far, the only call to $60a8 found set them to 0.

Just after $60a8 comes the routine to write multiple bytes.

Code: Select all

; Write bytes from mb128.
; in: $10/$11     Input buffer address.
;     $12/$13     Write address
;     $e200/$e201 ?
;     $e204/$e205 Number of bytes to write.
;
l6112_00: INC     <$28
          JSR     l618c_00      ; Detect mb128
          BMI     l6185_00      ; There's no mb128 if the N flag is set
          STZ     $ea11
          STZ     $ea12
          LDA     <$12
          STA     $e206
          LDA     <$13
          STA     $e207         ; addr = ($13 << 8) | $12
          JSR     l6220_00      ; addr <<= 3
          JSR     l61de_00      ; Send bit #0
          LDA     $e200
          JSR     l61cc_00      ; Send byte
          LDA     $e201
          LDX     #$02
          JSR     l61d1_00      ; Send 2 bits
          JSR     l623e_00      ; Send the 20 bits address
l6140_00: LDA     [$10]
          JSR     l61cc_00      ; Write byte
          LDA     $ea11
          CLC     
          ADC     [$10]
          STA     $ea11
          LDA     $ea12
          ADC     #$00
          STA     $ea12
          INC     <$10          ; Increment storage address
          BNE     l615c_00
          INC     <$11
l615c_00: LDA     $e204         ; Decrement the number of bytes to write
          BNE     l6164_00
          DEC     $e205
l6164_00: DEC     $e204
          LDA     $e204
          ORA     $e205
          BNE     l6140_00      ; Loop until there is nothing to write
          JSR     l6279_00      ; Read a single bit
          JSR     l6279_00      ; Read a single bit
          PHA     
          JSR     l61c6_00      ; Send 3 zero bits
          PLA     
          BNE     l6180_00      ; Check if the last read bit is not 0
          LDA     #$00
          BRA     l6182_00
l6180_00: LDA     #$06
l6182_00: JMP     l6187_00
l6185_00: LDA     #$01
l6187_00: DEC     <$28
          ORA     #$00
          RTS     
The write sequence is initiated by sending :

Code: Select all

0_xxxxxxxxxx_yyyyyyyyyyyyyyyyyyyy
We can easily conclde that the first bit tells if we are reading or writing.

Next: Figure out how data is stored (i.e. the "filesystem").
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

The header data for a newly formatted mb128 seems to be

Code: Select all

32 06 02 00 d2 d3 d8 cd de b0 bd 31 32 38 00
The code that will copy the pre-built savegames (see emedora.bin attached below) to mb128:

Code: Select all

789f: lda #$5f
      sta $10
      lda #$67
      sta $11
      lda $775f
      sta $12
      lda $7760
      sta $13
      jsr $651f
      rts
Attachments
emedora.bin
(1 KiB) Downloaded 569 times
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

Here's some progress (using Tadaima Yuusha Boshuuchuu and etripator v0.4).
The following routine writes 1024 bytes at the bank #0 of the memory base 128.
The first 16 bytes are copied from $73b1. Bytes 4 to 15 are the infamous "メモリベース128" string.
Unfortunately I don't know what the first 4 bytes stands for.

Code: Select all

mb128_format:    ; $7387
          PHP     
          SEI     
          PHX     
          PHY     
          TII     $73b1, $8000, $0010
          STZ     $8010
          TII     $8010, $8011, $03ef
          LDA     #$00
          STA     <$f8
          LDA     #$80
          STA     <$f9
          STZ     <$fa
          LDA     #$01
          STA     <$fb
          JSR     mb128_write_sectors
          PLY     
          PLX     
          PLP     
          RTS     
mb128_header:    ; $73b1
          ; ???
          .db $30, $06, $00, $00
          ; メモリベース128
          .db $D2, $D3, $D8, $CD, $DE, $B0, $BD, $31, $32, $38, $00, $00
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

The routine $76cf reads the first sectors and check it contains a valid memory base 128 header.
The header is valid if the following conditions are met:
  • The string stored at $8004-$800e is valid (equals to メモリベース128)
  • The following expression is valid ($f8 and $f9 contains the first 2 bytes of the first sector).

    Code: Select all

    subw $fc, $f8
    subw $fc, $f9
    
    if( ($fd == $f9) && ($fc == $f8) )
        ok
    else
        not ok
    
The question is... What are the values of $fc and $fd?
In fact these bytes are set by mb128_read_sectors. It's the sum of the bytes of the sector. So it can be viewed as a CRC.
The header for an empty mb128 is:

Code: Select all

$30, $06, $00, $00, $D2, $D3, $D8, $CD, $DE, $B0, $BD, $31, $32, $38, $00, $00, .... $00
If we sum all the bytes except the first 2 ones, we have:

Code: Select all

$D2+$D3+$D8+$CD+$DE+$B0+$BD+$31+$32+$38 = $630
And this is what we have in the first two bytes $30 and $06.
So the substraction/comparaison is just a CRC check. It seems complicated.. Why not just compare the values of $fc,$fd and $f8,$f9?

Anyway, one mystery solved. The 3rd and 4th bytes meaning is still unknown.

Code: Select all

l76cf_00:
          PHP     
          SEI     
          PHX     
          PHY     
          CLX     
l76d4_00:
          ; Read first sector to $8000
          LDA     #$00
          STA     <$f8
          LDA     #$80
          STA     <$f9
          STZ     <$fa
          LDA     #$01
          STA     <$fb
          JSR     mb128_read_sectors
          
          ; Read succeded if A is zero
          CMP     #$00
          BNE     l773d_00
          
          ; Store the first 2 bytes to $f8 and $f9
          LDA     $8000
          STA     <$f8
          LDA     $8001
          STA     <$f9
          
          ; Check CRC
          ; $fd $fc -= $f8
          LDA     <$fc
          SEC     
          SBC     <$f8
          STA     <$fc
          BCS     l76fe_00
          DEC     <$fd
l76fe_00:

          ; $fd $fc -= $f9
          LDA     <$fc
          SEC     
          SBC     <$f9
          STA     <$fc
          BCS     l7709_00
          DEC     <$fd
l7709_00:

          STZ     <$fa
          
          LDA     <$fd
          CMP     <$f9
          BNE     l7717_00
          LDA     <$fc
          CMP     <$f8
          BEQ     l771b_00
l7717_00:
          LDA     #$01
          STA     <$fa
          
          ; Check if $8004-$800e contains the memory base 128 string (stored at $774a) 
l771b_00:
          LDA     #$04
          STA     <$f8
          LDA     #$80
          STA     <$f9
          LDA     #$4a
          STA     <$fc
          LDA     #$77
          STA     <$fd
          CLY     
l772c_00:
          LDA     [$f8], Y
          CMP     [$fc], Y
          BEQ     l7736_00          
          LDA     #$01
          STA     <$fa
l7736_00:
          INY     
          CPY     #$0a
          BNE     l772c_00
          
          ; We assume that everything is ok
          LDA     <$fa
l773d_00:
          CMP     #$00
          BEQ     l7746_00
          
          ; It seems that 3 attempts are made if something went wrong.
          INX     
          CPX     #$03
          BCC     l76d4_00
          
          ; The end
l7746_00:
          PLY     
          PLX     
          PLP     
          RTS
mb128_string:    ; $774a
          .db $D2, $D3, $D8, $CD, $DE, $B0, $BD, $31, $32, $38
I attached the 2 config files used with etripator v0.4. The command line is :

Code: Select all

etripator --cd -l labels.cfg mb128_2.cfg Track02.iso
Attachments
mb128_2.cfg
(86 Bytes) Downloaded 555 times
labels.cfg
(1.58 KiB) Downloaded 557 times
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

A quick note about the CRC check. The 2 subtractions are done because the CRC is computed as the sum of the sector bytes starting from the 2nd byte (ie without the CRC bytes). That makes sense.

edit: Woohoo! I can finally read a complete sector.
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

I think I figured out the entry structure. Some bytes are still unknown.
The first 1024 bytes of the memory base 128 contains 64 entries of 16 bytes each.
The first entry is the header of the entry list.
  • byte 0 : CRC (lsb)
  • byte 1 : CRC (msb)
  • byte 2 : Total sector count (lsb)
  • byte 3 : Total sector count (msb)
  • byte 4:F: Header name (メモリベース128)
Then follows 63 "directory" entries.
  • byte 0 : Sector index
  • byte 1 : Sector count
  • byte 2 : Unknown (set to 0 and unused by Tadaima Yuusha Boshuuchuu)
  • byte 3 : Unknown (set to 2 and unused by Tadaima Yuusha Boshuuchuu)
  • byte 4 : Data CRC (lsb)
  • byte 5 : Data CRC (msb)
  • byte 6 : Unknown (set to 0 and unused by Tadaima Yuusha Boshuuchuu)
  • byte 7 : Unknown (set to 0 and unused by Tadaima Yuusha Boshuuchuu)
  • byte 8-f : Entry name (set to ユウシャM128 in Tadaima Yuusha Boshuuchuu)
More on CRC computation, entry management and all later...
I attached etripator configuration files and output.
Attachments
mb128.asm
(95.29 KiB) Downloaded 578 times
mb128_2.cfg
(86 Bytes) Downloaded 567 times
labels.cfg
(3.32 KiB) Downloaded 568 times
User avatar
MooZ
Site Admin
Posts: 407
Joined: Sun Jun 22, 2008 3:19 pm
Location: Lvl 3
Contact:

Re: [Hard+Soft] Memory Base 128

Post by MooZ »

Here's the first draft : mb128.txt

Critics/comments/broken english fix appreciated.
Post Reply