Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
constant base_address = 0x1900
constant output_address = 0x1904
constant rambuf = 0x1b00 // Starts at 0xZZZBD in ROM
constant header_start_mem = rambuf + 0x3 // Offset to 0xZZZC0
// Address into header/ROM
constant gsu_ramz_addr = rambuf // FBC
constant mapping_mode_addr = header_start_mem + 0x15 // FD5
constant rom_type_addr = header_start_mem + 0x16 // FD6
constant rom_size_addr = header_start_mem + 0x17 // FD7
constant sram_size_addr = header_start_mem + 0x18 // FD8
constant region_addr = header_start_mem + 0x19 // FD9
constant dev_id_addr = header_start_mem + 0x1A // FDA
constant version_number_addr = header_start_mem + 0x1B // FDB
constant checksum_complement_addr = header_start_mem + 0x1C // FDC/D
constant checksum_addr = header_start_mem + 0x1E // FDE/F
// Registers:
// r10: PAL (stored 3)
// r11: ramsz (stored 2)
// r12: chip_type (stored 1)
// r13: score (stored 0)
// Function
// Input: r3 - SMC header status
// Clobbers r1, r2, r3, r10, r11, r12, r13
macro check_header(variable base_address_input, variable output_address_input) {
ld r1,#base_address_input
ld r2,#output_address_input
ld.w r3,(header_offset_addr) // Get header offset
add r1,r3 // Add offset to base address
ld.w (base_address),r1 // Store base_address into RAM
ld.w (output_address),r2 // Store output_address into RAM
log_string("Starting header at:")
hex.l r1
hex.l r3
call load_header_values_into_mem
log_string("Loaded header data")
// Score is stored in r13
ld r13,#0
call validate_checksum
validate_mapping_mode(base_address_input)
call validate_simple_values
call choose_ramsz
call choose_chip_type
call choose_region
log_string("Storing header data at:")
ld.w r1,(output_address)
hex.w r1
ld.b (r1),r13 // score
add r1,#1
ld.b (r1),r12 // chip_type
add r1,#1
ld.b (r1),r11 // ramsz
add r1,#1
ld.b (r1),r10 // PAL
log_string("Finished header. Score:")
hex.b r13
}
validate_checksum:
// if (checksum != 0 && checksum_compliment != 0 && checksum + checksum_compliment == 'hFFFF)
log_string("Checking checksum")
ld.w r1,(checksum_addr) // Load checksum
jp z, finish_checksum // If checksum 0, skip
ld.w r2,(checksum_complement_addr) // Load checksum complement
jp z, finish_checksum // If complement 0, skip
add r1,r2 // Add checksum and complement
cmp r1,#0xFFFF // Compare against 0xFFFF
jp nz, finish_checksum // If not equal, skip
// Increment score
add r13,#4
log_string("Score checksum +4")
finish_checksum:
log_string("Finished checksum")
ret
macro validate_mapping_mode(variable address) {
log_string("Checking mapping mode")
ld.w r1,(mapping_mode_addr)
if (address == 0x7FBC) {
cmp r1,#0x20 // Compare against mapper 0x20 (LoROM)
jp nz, noscore{#}
cmp r1,#0x22 // Compare against mapper 0x22 (SDD1)
jp nz, noscore{#}
} else if (address == 0xFFBC) {
cmp r1,#0x21 // Compare against mapper 0x21 (HiROM)
jp nz, noscore{#}
} else if (address == 0x40FFBC) {
cmp r1,#0x25 // Compare against mapper 0x25 (ExHiROM)
jp nz, noscore{#}
}
add r13,#2 // Add 2 to score
log_string("Score mapper +2")
noscore{#}:
log_string("Finished mapping mode")
}
macro check_simple_value_inequality(variable address, variable less_than, define name) {
// Check address < less_than
ld.b r1,(address)
cmp r1,#less_than // r1 - less_than
jp nc, end_inequality{#} // If carry set, address < less_than
add r15,#1
log_string("Score {name} +1")
end_inequality{#}:
}
macro check_value_equality(variable address, variable compare) {
ld.b r1,(address)
cmp r1,#compare
}
validate_simple_values:
log_string("Checking simple values")
// Check dev id is 0x33
ld.b r1,(dev_id_addr)
cmp r1,#0x33 // If dev id is 0x33
jp nz, rom_type
add r13,#2
log_string("Score dev_id +2")
rom_type:
check_simple_value_inequality(rom_type_addr, 8, rom_type)
check_simple_value_inequality(rom_size_addr, 16, rom_size)
check_simple_value_inequality(sram_size_addr, 8, ram_size)
check_simple_value_inequality(region_addr, 14, region)
log_string("Finished simple values")
ret
choose_ramsz:
log_string("Checking RAMSZ")
ld.b r11,(sram_size_addr) // ramsz is stored in r11
ld r1,#8
cmp r11,r1 // r11 - 8
jp nc, zero_sram // If r11 >= 8
jp end_choose_ramsz
zero_sram:
ld r11,#0
end_choose_ramsz:
log_string("Finished RAMSZ")
ret
choose_chip_type:
log_string("Checking chip type")
ld r12,#0 // chip_type is stored in r12
// if (mapping_mode == 'h20 && rom_type == 'h03) begin
log_string("Checking DSP1")
check_value_equality(mapping_mode_addr, 0x20)
jp nz, dsp1b
check_value_equality(rom_type_addr, 0x03)
jp nz, dsp1b
// Mapping 0x20, rom_type 0x3 => DSP1
or r12,#0x84
jp separate_ifs
dsp1b: // if (mapping_mode == 'h21 && rom_type == 'h03) begin
log_string("Checking DSP1B")
check_value_equality(mapping_mode_addr, 0x21)
jp nz, dsp1b_2
check_value_equality(rom_type_addr, 0x03)
jp nz, dsp1b_2
// Mapping 0x21, rom_type 0x3 => DSP1B
or r12,#0x80
jp separate_ifs
dsp1b_2: // if (mapping_mode == 'h30 && rom_type == 'h05 && dev_id != 'hB2) begin
check_value_equality(mapping_mode_addr, 0x30)
jp nz, dsp1b_3
check_value_equality(rom_type_addr, 0x05)
jp nz, dsp1b_3
check_value_equality(dev_id_addr, 0xB2)
jp z, dsp1b_3
// Mapping 0x30, rom_type 0x5, dev_id != 0xB2 => DSP1B
or r12,#0x80
jp separate_ifs
dsp1b_3: // if (mapping_mode == 'h31 && (rom_type == 'h03 || rom_type == 'h05)) begin
check_value_equality(mapping_mode_addr, 0x31)
jp nz, dsp2
check_value_equality(rom_type_addr, 0x03)
jp z, set_dsp1b_3
check_value_equality(rom_type_addr, 0x05)
jp nz, dsp2
set_dsp1b_3:
// Mapping 0x31, rom_type 0x3 || 0x5 => DSP1B
or r12,#0x80
jp separate_ifs
dsp2: // if (mapping_mode == 'h20 && rom_type == 'h05) begin
log_string("Checking DSP2")
check_value_equality(mapping_mode_addr, 0x20)
jp nz, dsp3
check_value_equality(rom_type_addr, 0x05)
jp nz, dsp3
// Mapping 0x20, rom_type 0x5 => DSP2
or r12,#0x90
jp separate_ifs
dsp3: // if (mapping_mode == 'h30 && rom_type == 'h05 && dev_id == 'hB2) begin
log_string("Checking DSP3")
check_value_equality(mapping_mode_addr, 0x30)
jp nz, dsp4
check_value_equality(rom_type_addr, 0x05)
jp nz, dsp4
check_value_equality(dev_id_addr, 0xB2)
jp nz, dsp4
// Mapping 0x30, rom_type 0x5, dev_id 0xB2 => DSP3
or r12,#0xA0
jp separate_ifs
dsp4: // if (mapping_mode == 'h30 && rom_type == 'h03) begin
log_string("Checking DSP4")
check_value_equality(mapping_mode_addr, 0x30)
jp nz, st010
check_value_equality(rom_type_addr, 0x03)
jp nz, st010
// Mapping 0x30, rom_type 0x3 => DSP4
or r12,#0xB0
jp separate_ifs
st010: // if (mapping_mode == 'h30 && rom_type == 'hF6) begin
log_string("Checking ST010")
check_value_equality(mapping_mode_addr, 0x30)
jp nz, obc1
check_value_equality(rom_type_addr, 0xF6)
jp nz, obc1
// Mapping 0x30, rom_type 0xF6 => ST010
or r12,#0x88
ld r11,#1
// if (rom_size < 10)
check_value_equality(rom_size_addr, 10)
jp nc, separate_ifs
// If rom_size < 10 => ST011
or r12,#0x20
jp separate_ifs
obc1: // if (mapping_mode == 'h30 && rom_type == 'h25) begin
log_string("Checking OBC1")
check_value_equality(mapping_mode_addr, 0x30)
jp nz, separate_ifs
check_value_equality(rom_type_addr, 0x25)
jp nz, separate_ifs
// Mapping 0x30, rom_type 0x25 => OBC1
or r12,#0xC0
separate_ifs: // These ifs are standalone (not else if)
// if (mapping_mode == 'h3A && (rom_type == 'hF5 || rom_type == 'hF9)) begin
log_string("Checking SPC7110")
check_value_equality(mapping_mode_addr, 0x3A)
jp nz, srtc
check_value_equality(rom_type_addr, 0xF5)
jp z, set_spc7110
check_value_equality(rom_type_addr, 0xF9)
jp nz, srtc
// Mapping 0x3A, rom_type 0xF5 || 0xF9 => SPC7110
// Is F9
or r12,#0x08 // With RTC
set_spc7110:
or r12,#0xD0 // SPC7110
srtc: // if (mapping_mode == 'h35 && rom_type == 'h55) begin
log_string("Checking S-RTC")
check_value_equality(mapping_mode_addr, 0x35)
jp nz, cx4
check_value_equality(rom_type_addr, 0x55)
jp nz, cx4
// Mapping 0x35, rom_type 0x55 => S-RTC (+ExHigh)
or r12,#0x8
cx4: // if (mapping_mode == 'h20 && rom_type == 'hF3) begin
log_string("Checking CX4")
check_value_equality(mapping_mode_addr, 0x20)
jp nz, sdd1
check_value_equality(rom_type_addr, 0xF3)
jp nz, sdd1
// Mapping 0x20, rom_type 0xF3 => CX4
or r12,#0x40
sdd1: // if (mapping_mode == 'h32 && (rom_type == 'h43 || rom_type == 'h45) && rom_size < 14) begin
log_string("Checking SDD1")
check_value_equality(mapping_mode_addr, 0x32)
jp nz, sa1
check_value_equality(rom_size_addr, 14) // Only mark SDD1 if rom_size < 14
jp nc, sa1
check_value_equality(rom_type_addr, 0x43)
jp z, set_sdd1
check_value_equality(rom_type_addr, 0x45)
jp nz, sa1
// Mapping 0x32, rom_type 0x43 || 0x45, rom_size < 14 => SDD1
set_sdd1:
or r12,#0x50
sa1: // if (mapping_mode == 'h23 && (rom_type == 'h32 || rom_type == 'h34 || rom_type == 'h35)) begin
log_string("Checking SA1")
check_value_equality(mapping_mode_addr, 0x23)
jp nz, gsu
check_value_equality(rom_type_addr, 0x32)
jp z, set_sa1
check_value_equality(rom_type_addr, 0x34)
jp z, set_sa1
check_value_equality(rom_type_addr, 0x35)
jp nz, gsu
// Mapping 0x23, rom_type 0x32 || 0x34 || 0x35 => SA1
set_sa1:
or r12,#0x60
gsu: // if (mapping_mode == 'h20 && (rom_type == 'h13 || rom_type == 'h14 || rom_type == 'h15 || rom_type == 'h1A)) begin
log_string("Checking GSU")
check_value_equality(mapping_mode_addr, 0x20)
jp nz, finished_chip
check_value_equality(rom_type_addr, 0x13)
jp z, set_gsu
check_value_equality(rom_type_addr, 0x14)
jp z, set_gsu
check_value_equality(rom_type_addr, 0x15)
jp z, set_gsu
check_value_equality(rom_type_addr, 0x1A)
jp nz, finished_chip
// Mapping 0x20, rom_type 0x13 || 0x14 || 0x15 || 0x1A => GSU
set_gsu:
or r12,#0x70
ld.b r11,(gsu_ramz_addr) // Load GSU ramsz
cmp r11,#0xFF // If ramsz == 0xFF
jp nz, check_6
ld r11,#5 // Starfox
check_6:
ld r1,#6
cmp r1,r11 // Cmp 6 - r11
jp nc, finished_chip
ld r11,#6 // Max out at 6
finished_chip:
log_string("Finished chip type, ramsz:")
hex.b r12
hex.b r11
ret
choose_region:
log_string("Checking region")
ld r10,#0
// if ((region >= 'h02 && region <= 'h0C) || region == 'h11) begin
check_value_equality(region_addr, 0x2)
jp c, region_11 // If region < 2, jump to region_11
ld r2,#0xC
cmp r2,r1
jp c, region_11 // If region > 0xC, jump to region_11
jp set_pal // It's PAL
region_11:
cmp r1,#0x11 // If region == 0x11
jp nz, end_region
set_pal:
ld r10,#1
end_region:
log_string("Finished region:")
hex.b r10
ret
// Load all header values from file into memory
load_header_values_into_mem:
seek()
ld r1,#0x44 // Load 0x44 bytes
ld r2,#rambuf // Read into read_space memory
read()
ret
// Fetch a header byte value into register
//macro fetch_header_byte(variable address) {
// ld.b r1,(address)
//}
699e414d1This file is pinned to the selected release. Download the original to open it in your design tool.