We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!
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.