Skip to content

Instantly share code, notes, and snippets.

@zznop
Created September 11, 2021 03:59
Show Gist options
  • Save zznop/1386f598529d09e795852a6320fd38b8 to your computer and use it in GitHub Desktop.
Save zznop/1386f598529d09e795852a6320fd38b8 to your computer and use it in GitHub Desktop.
Decodes and recover patch info from SEGA Genesis Game Genie codes
/**
* MIT License
*
* Copyright (c) 2021 Brandon Miller (zznop)
*
* This program decodes SEGA Genesis Game Genie alphanumeric codes and displays the encoded patch information
*/
package main
import (
"errors"
"fmt"
"os"
"strings"
)
const gameGenieCharacters = "AaBbCcDdEeFfGgHhJjKkLlMmNnPpRrSsTtVvWwXxYyZz0O1I2233445566778899"
func displayUsage() {
fmt.Printf(`Usage: %v <code>
Required:
code SEGA Genesis Game Genie alphanumeric code
example:
%v RFAA-A6VR
`, os.Args[0], os.Args[0])
os.Exit(1)
}
func computePatchInfo(code []string) (uint32, uint16) {
address := uint32(0)
data := uint16(0)
// Character 0
n := strings.Index(gameGenieCharacters, code[0]) >> 1
data |= uint16(n << 3)
// Character 1
n = strings.Index(gameGenieCharacters, code[1]) >> 1
data |= uint16(n >> 2)
address |= uint32((n & 3) << 14)
// Character 2
n = strings.Index(gameGenieCharacters, code[2]) >> 1
address |= uint32(n << 9)
// Character 3
n = strings.Index(gameGenieCharacters, code[3]) >> 1
address |= uint32(((n & 0x0f) << 20) | ((n >> 4) << 8))
// Character 4: '-'
// Character 5
n = strings.Index(gameGenieCharacters, code[5]) >> 1
address |= uint32((n >> 1) << 16)
data |= uint16((n & 1) << 12)
// Character 6
n = strings.Index(gameGenieCharacters, code[6]) >> 1
data |= uint16(((n & 1) << 15) | ((n >> 1) << 8))
// Character 7
n = strings.Index(gameGenieCharacters, code[7]) >> 1
address |= uint32((n & 7) << 5)
data |= uint16((n >> 3) << 13)
// Character 8
n = strings.Index(gameGenieCharacters, code[8]) >> 1
address |= uint32(n)
return address, data
}
func verifyCode(code []string) error {
if len(code) != 9 || code[4] != "-" {
return errors.New("code must be 9 characters in length and contain a hyphen (RFAA-A6VR)")
}
for i := 0; i < len(code); i++ {
if i == 4 {
continue // skip the hyphen
}
if !strings.Contains(gameGenieCharacters, code[i]) {
return fmt.Errorf("code contains an invalid character: '%v'", code[i])
}
}
return nil
}
func main() {
if len(os.Args) != 2 {
displayUsage()
}
code := strings.Split(os.Args[1], "")
if err := verifyCode(code); err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
address, data := computePatchInfo(code)
fmt.Printf("Address : 0x%08x\n", address)
fmt.Printf("Opcode : %04x\n", data)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment