/** * 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 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) }