If you appreciate the work done within the wiki, please consider supporting The Cutting Room Floor on Patreon. Thanks for all your support!
Notes:688 Attack Sub (Genesis)
Jump to navigation
Jump to search
This page contains notes for the game 688 Attack Sub (Genesis).
Contents
Compressed Data
For those who are wondering, these are the locations of all compressed blobs in the game. If you look, they'll appear to be PowerPacker-compressed blobs. But they're not quite PowerPacker format... and each blob has a size field stored elsewhere.
Address | Size Field | |
---|---|---|
000146cc | $9C8 + 8 | |
000150bc | $330 + 8 | |
0002020e | $C04 + 8 | |
00020e3a | $364 + 8 | |
000211b4 | $9FC + 8 | |
00021bd8 | $318 + 8 | |
00021f06 | $1D8 + 8 | |
000220f4 | $59C + 8 | |
000226b8 | $20C + 8 | |
000228da | $B4 + 8 | |
00023328 | $CC4 + 8 | |
00024014 | $2BC + 8 | |
000242e6 | $E4C + 8 | |
0002515a | $304 + 8 | |
00025472 | $2C0 | |
00025732 | $274 | |
0002652c | $1A4C + 8 | |
00027fa0 | $4FC + 8 | |
000284b2 | $1210 + 8 | |
000296ca | $304 + 8 | |
000299e4 | $E2C + 8 | |
0002a818 | $2C4 + 8 | |
0002aaf2 | $FE0 + 8 | |
0002bada | $2A8 + 8 | |
0002bd98 | $12C0 + 8 | |
0002d060 | $2B0 + 8 | |
000318d0 | $9DC + 8 | |
000322d4 | $310 + 8 | |
000325fa | $91C + 8 | |
00032f3e | $2F8 + 8 | |
0003324c | $7DC + 8 | |
00033a50 | $2A0 + 8 | |
00033d06 | $910 + 8 | |
0003463e | $2D4 + 8 | |
00034928 | $29C + 8 | |
00034bec | $160 + 8 | |
00034d62 | $45C + 8 | |
000351e6 | $188 + 8 | |
000353d6 | $49C | |
00035872 | $460 | |
00035cd2 | $65C | |
0003632e | $57C | |
000368aa | $614 | |
00036ebe | $57C | |
0003743a | $6C8 | |
00037b02 | $680 | |
00038182 | $704 | |
00038886 | $590 | |
00038e16 | $4E8 | |
000392fe | $5F8 | |
000398f6 | $5D0 | |
00039ec6 | $654 | |
0003a51a | $6BC | |
0003abd6 | $718 | |
0003b2fe | $804 + 8 | |
0003bb2a | $2D0 + 8 | |
0003be10 | $8F8 + 8 | |
0003c730 | $2E0 + 8 | |
0007e0d6 | $844 | |
0007e91a | $6BC | |
0007efd6 | $7BC | |
0007f792 | $8A4 | |
00080036 | $6A4 | |
000806da | $6BC | |
00080d96 | $4F4 | |
0008128a | $5B0 | |
0008183a | $8E4 | |
0008211e | $554 | |
00082672 | $59C | |
00082c0e | $828 | |
00083436 | $79C | |
00083bd2 | $504 | |
000840d6 | $46C | |
00084542 | $4AC | |
00084d32 | $1C34 + 8 | |
000869ae | $564 + 8 | |
00086f28 | $355C + 8 | |
0008a48c | $858 + 8 | |
00095e9a | $8D0 + 8 | |
00096792 | $2D0 + 8 | |
00096a78 | $8C8 + 8 | |
00097368 | $2EC + 8 | |
0009766a | $358 + 8 | |
000979ca | $104 + 8 | |
00097ae4 | $1CC + 8 | |
00097cb8 | $8C + 8 | |
00097d5a | $170 + 8 | |
00097ed2 | $78 + 8 |
Looks like there's no unused text or staff rolls here. :( Have the decompression anyway (input is the above table, columns separated by tabs).
// 26 june 2015 package main import ( "fmt" "os" "io/ioutil" "bufio" "encoding/binary" "strings" "strconv" ) // utilities func readbyte(from []byte, addr uint32) byte { return from[addr] } func readword(from []byte, addr uint32) uint16 { return binary.BigEndian.Uint16(from[addr:]) } func readlong(from []byte, addr uint32) uint32 { return binary.BigEndian.Uint32(from[addr:]) } func writebyte(to []byte, addr uint32, b byte) { to[addr] = b } func writeword(to []byte, addr uint32, w uint16) { binary.BigEndian.PutUint16(to[addr:], w) } func writelong(to []byte, addr uint32, l uint32) { binary.BigEndian.PutUint32(to[addr:], l) } func move_b(dest uint32, src uint32) uint32 { dest &= 0xFFFFFF00 dest |= src & 0xFF return dest } func sub_b(dest uint32, src uint32) uint32 { b := byte(dest) b -= byte(src) return move_b(dest, uint32(b)) } func add_w(dest uint32, src uint32) uint32 { w := uint16(dest) w += uint16(src) return move_w(dest, uint32(w)) } func move_w(dest uint32, src uint32) uint32 { dest &= 0xFFFF0000 dest |= src & 0xFFFF return dest } func dbf(reg *uint32) bool { w := uint16(*reg) w-- *reg = move_w(*reg, uint32(w)) return w != 0xFFFF } // note the parameter order here func carryset(src uint32, dest uint32) bool { return dest < src } func aX_dX_w(aX uint32, dX uint32) uint32 { // sign-extend dX as a 16-bit value to 32-bits ddX := uint32(int32(int16(uint16(dX)))) return aX + ddX } func addq_w(dest uint32, src uint32) uint32 { return add_w(dest, src) } func subq_w(dest uint32, src uint32) uint32 { return sub_w(dest, src) } var extend uint32 = 0 func roxl_l(dest uint32, src uint32) uint32 { for { highbit := src & 0x80000000 dest <<= 1 dest |= extend extend = highbit >> 31 src-- if src == 0 { break } } return dest } func subq_b(dest uint32, src uint32) uint32 { return sub_b(dest, src) } func sub_w(dest uint32, src uint32) uint32 { w := uint16(dest) w -= uint16(src) return move_w(dest, uint32(w)) } // the decompressor itself var ROM []byte var RAM = make([]byte, 0x10000) var d0, d1, d2, d3, d4, d5, d6, d7 uint32 var a0, a1, a2, a3, a4, a5, a6 uint32 var assumedEnd uint32 // (a0:source(ROM) a1:destination(RAM) d0:length -- ) func decomp() { a5 = 0x45F6 // RAM writelong(RAM, a5, readlong(ROM, a0 + 4)) a0 += d0 a2 = a1 // RAM a0 -= 4; d5 = readlong(ROM, a0) d1 = 0 d1 = move_b(d1, d5) d5 >>= 8 a1 += d5 assumedEnd = a1 a0 -= 4; d5 = readlong(ROM, a0) d5 >>= d1 d7 = move_b(d7, 0x20) d7 = sub_b(d7, d1) loc_FAF6: sub_FB62() if (d1 & 0xFF) != 0 { goto loc_FB1C } d2 = 0 loc_FAFE: d0 = 2 sub_FB64() d2 = add_w(d2, d1) if (d1 & 0xFFFF) == 3 { goto loc_FAFE } loc_FB0A: d0 = move_w(d0, 8) sub_FB64() a1--; writebyte(RAM, a1, byte(d1)) if dbf(&d2) { goto loc_FB0A } if carryset(a1, a2) { goto loc_FB1C } return loc_FB1C: d0 = 2 sub_FB64() d0 = 0 d0 = move_b(d0, uint32(readbyte(RAM, aX_dX_w(a5, d1)))) d4 = d0 d2 = move_w(d2, d1) d2 = addq_w(d2, 1) if (d2 & 0xFFF) != 4 { goto loc_FB4E } sub_FB62() d0 = d4 if (d1 & 0xFF) != 0 { goto loc_FB3C } d0 = 7 loc_FB3C: sub_FB64() d3 = move_w(d3, d1) loc_FB40: d0 = 3 sub_FB64() d2 = add_w(d2, d1) if (d1 & 0xFFFF) == 7 { goto loc_FB40 } goto loc_FB52 loc_FB4E: sub_FB64() d3 = move_w(d3, d1) loc_FB52: d0 = move_b(d0, uint32(readbyte(RAM, aX_dX_w(a1, d3)))) a1--; writebyte(RAM, a1, byte(d0)) if dbf(&d2) { goto loc_FB52 } if carryset(a1, a2) { goto loc_FAF6 } return } func sub_FB62() { d0 = 1 sub_FB64() } func sub_FB64() { d1 = 0 d0 = subq_w(d0, 1) loc_FB68: extend = d5 & 1 d5 >>= 1 d1 = roxl_l(d1, 1) d7 = subq_b(d7, 1) if (d7 & 0xFF) != 0 { goto loc_FB76 } d7 = move_b(d7, 0x20) a0 -= 4; d5 = readlong(ROM, a0) loc_FB76: if dbf(&d0) { goto loc_FB68 } return } // the program func main() { var err error if len(os.Args) != 3 { fmt.Fprintf(os.Stderr, "usage: %s ROM locations\n", os.Args[0]) os.Exit(1) } ROM, err = ioutil.ReadFile(os.Args[1]) if err != nil { fmt.Fprintf(os.Stderr, "error reading ROM: %v", err) os.Exit(1) } f, err := os.Open(os.Args[2]) if err != nil { fmt.Fprintf(os.Stderr, "error opening location list: %v", err) os.Exit(1) } defer f.Close() r := bufio.NewScanner(f) for r.Scan() { line := r.Text() parts := strings.Split(line, "\t") add8 := strings.Contains(parts[1], "+ 8") parts[1] = strings.Replace(parts[1], "+ 8", "", -1) parts[1] = strings.Replace(parts[1], "$", "", -1) parts[0] = strings.TrimSpace(parts[0]) parts[1] = strings.TrimSpace(parts[1]) offset, err := strconv.ParseUint(parts[0], 16, 32) if err != nil { panic(err) } size, err := strconv.ParseUint(parts[1], 16, 32) if err != nil { panic(err) } if add8 { size += 8 } a0 = uint32(offset) a1 = 0x8000 d0 = uint32(size) decomp() err = ioutil.WriteFile(parts[0], RAM[0x8000:assumedEnd], 0644) if err != nil { fmt.Fprintf(os.Stderr, "error writing file %s: %v", parts[0], err) os.Exit(1) } } if err := r.Err(); err != nil { fmt.Fprintf(os.Stderr, "error reading location list: %v", err) os.Exit(1) } }
Ed Fletcher
It turns out that the string I was trying so hard to find was encoded differently. It's stored at $146A4, with each byte stored $20 lower than its actual ASCII value, and ending with an $FF byte.