16#include "absl/status/status.h"
17#include "absl/strings/str_cat.h"
27using namespace zelda3;
36 std::string rom_path = parser.
GetString(
"rom").value_or(
"");
37 std::string output_path = parser.
GetString(
"output").value_or(
"");
44 formatter.
AddField(
"status",
"success");
45 formatter.
AddField(
"output_file", output_path);
47 "Successfully generated harness state from " + rom_path);
48 return absl::OkStatus();
52 const std::string& rom_path,
const std::string& output_path) {
56 auto rom_data = rom.
vector();
63 auto& cpu = snes.
cpu();
64 auto& ppu = snes.
ppu();
67 int max_cycles = 15000000;
69 while (cycles < max_cycles) {
72 if (cpu.PB == 0x00 && cpu.PC == 0x8034) {
77 if (cycles >= max_cycles) {
78 return absl::InternalError(
79 "Emulator timed out; did not reach main game loop.");
82 std::ofstream out_file(output_path);
83 if (!out_file.is_open()) {
84 return absl::InternalError(
"Failed to open output file: " + output_path);
88 out_file <<
"// ================================================"
89 "=========================\n";
90 out_file <<
"// YAZE Dungeon Test Harness State - Generated from: "
92 out_file <<
"// ================================================"
93 "=========================\n\n";
94 out_file <<
"#pragma once\n\n";
95 out_file <<
"#include <cstdint>\n";
96 out_file <<
"#include <array>\n\n";
97 out_file <<
"namespace yaze {\n";
98 out_file <<
"namespace emu {\n\n";
101 out_file <<
"constexpr std::array<uint8_t, 0x20000> kInitialWRAMState = {{\n";
102 for (
int i = 0; i < 0x20000; ++i) {
103 if (i % 16 == 0) out_file <<
" ";
104 out_file <<
"0x" << std::hex << std::setw(2) << std::setfill(
'0')
105 <<
static_cast<int>(snes.
Read(0x7E0000 + i));
106 if (i < 0x1FFFF) out_file <<
", ";
107 if (i % 16 == 15) out_file <<
"\n";
109 out_file <<
"}};\n\n";
112 out_file <<
"// ================================================"
113 "=========================\n";
114 out_file <<
"// Initial Register States\n";
115 out_file <<
"// ================================================"
116 "=========================\n\n";
118 out_file <<
"struct InitialPpuState {\n";
119 out_file <<
" uint8_t inidisp = 0x" << std::hex << ppu.Read(0x2100,
false)
121 out_file <<
" uint8_t objsel = 0x" << std::hex << ppu.Read(0x2101,
false)
123 out_file <<
" uint8_t bgmode = 0x" << std::hex << ppu.Read(0x2105,
false)
125 out_file <<
" uint8_t mosaic = 0x" << std::hex << ppu.Read(0x2106,
false)
127 out_file <<
" uint8_t tm = 0x" << std::hex << ppu.Read(0x212C,
false)
129 out_file <<
" uint8_t ts = 0x" << std::hex << ppu.Read(0x212D,
false)
131 out_file <<
" uint8_t cgwsel = 0x" << std::hex << ppu.Read(0x2130,
false)
133 out_file <<
" uint8_t cgadsub = 0x" << std::hex << ppu.Read(0x2131,
false)
135 out_file <<
" uint8_t setini = 0x" << std::hex << ppu.Read(0x2133,
false)
137 out_file <<
"};\n\n";
139 out_file <<
"} // namespace emu\n";
140 out_file <<
"} // namespace yaze\n";
142 return absl::OkStatus();
152 std::string rom_path = parser.
GetString(
"rom").value_or(
"");
153 std::string format = parser.
GetString(
"format").value_or(
"cpp");
156 if (!rom || rom->
size() == 0) {
162 std::ostringstream output;
164 if (format ==
"json") {
166 output <<
" \"asm_version\": \"0x" << std::hex << std::setw(2)
170 output <<
" \"area_graphics\": [";
171 for (
int i = 0; i < 10; i++) {
172 output <<
"\"0x" << std::hex << std::setw(2) << std::setfill(
'0')
174 if (i < 9) output <<
", ";
177 output <<
" \"area_palettes\": [";
178 for (
int i = 0; i < 10; i++) {
179 output <<
"\"0x" << std::hex << std::setw(2) << std::setfill(
'0')
181 if (i < 9) output <<
", ";
184 output <<
" \"screen_sizes\": [";
185 for (
int i = 0; i < 10; i++) {
186 output <<
"\"0x" << std::hex << std::setw(2) << std::setfill(
'0')
188 if (i < 9) output <<
", ";
194 output <<
"// Vanilla ROM values extracted\n\n";
196 output <<
"constexpr uint8_t kVanillaASMVersion = 0x" << std::hex
197 << std::setw(2) << std::setfill(
'0')
201 output <<
"// Area graphics for first 10 maps\n";
202 for (
int i = 0; i < 10; i++) {
203 output <<
"constexpr uint8_t kVanillaAreaGraphics" << std::dec << i
204 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
209 output <<
"// Area palettes for first 10 maps\n";
210 for (
int i = 0; i < 10; i++) {
211 output <<
"constexpr uint8_t kVanillaAreaPalette" << std::dec << i
212 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
217 output <<
"// Screen sizes for first 10 maps\n";
218 for (
int i = 0; i < 10; i++) {
219 output <<
"constexpr uint8_t kVanillaScreenSize" << std::dec << i
220 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
225 output <<
"// Sprite sets for first 10 maps\n";
226 for (
int i = 0; i < 10; i++) {
227 output <<
"constexpr uint8_t kVanillaSpriteSet" << std::dec << i
228 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
233 std::cout << output.str();
234 formatter.
AddField(
"status",
"success");
235 return absl::OkStatus();
245 std::string rom_path = parser.
GetString(
"rom").value_or(
"");
246 std::string output_path = parser.
GetString(
"output").value_or(
"");
256 std::ofstream out_file(output_path);
257 if (!out_file.is_open()) {
258 return absl::InternalError(
"Failed to open output file: " + output_path);
269 formatter.
AddField(
"status",
"success");
270 formatter.
AddField(
"output_file", output_path);
272 "Successfully extracted golden data from " + rom_path);
273 return absl::OkStatus();
277 const std::string& rom_path) {
278 out <<
"// =============================================="
279 "===========================\n";
280 out <<
"// YAZE Overworld Golden Data - Generated from: " << rom_path <<
"\n";
281 out <<
"// =============================================="
282 "===========================\n\n";
283 out <<
"#pragma once\n\n";
284 out <<
"#include <cstdint>\n";
285 out <<
"#include <array>\n";
286 out <<
"#include <vector>\n";
287 out <<
"#include \"zelda3/overworld/overworld_map.h\"\n\n";
288 out <<
"namespace yaze {\n";
289 out <<
"namespace test {\n\n";
294 out <<
"// =============================================="
295 "===========================\n";
296 out <<
"// Basic ROM Information\n";
297 out <<
"// =============================================="
298 "===========================\n\n";
300 out <<
"constexpr std::string_view kGoldenROMTitle = \"" << rom.
title()
302 out <<
"constexpr size_t kGoldenROMSize = " << std::dec << rom.
size()
308 out <<
"// =============================================="
309 "===========================\n";
310 out <<
"// ASM Version Information\n";
311 out <<
"// =============================================="
312 "===========================\n\n";
314 auto asm_version = rom.
ReadByte(0x140145);
315 if (asm_version.ok()) {
316 out <<
"constexpr uint8_t kGoldenASMVersion = 0x" << std::hex << std::setw(2)
317 << std::setfill(
'0') <<
static_cast<int>(*asm_version) <<
";\n";
319 if (*asm_version == 0xFF) {
320 out <<
"constexpr bool kGoldenIsVanillaROM = true;\n";
321 out <<
"constexpr bool kGoldenHasZSCustomOverworld = false;\n";
323 out <<
"constexpr bool kGoldenIsVanillaROM = false;\n";
324 out <<
"constexpr bool kGoldenHasZSCustomOverworld = true;\n";
325 out <<
"constexpr uint8_t kGoldenZSCustomOverworldVersion = "
326 << std::dec << static_cast<int>(*asm_version) <<
";\n";
333 std::ofstream& out,
Overworld& overworld) {
334 out <<
"// =============================================="
335 "===========================\n";
336 out <<
"// Overworld Maps Data\n";
337 out <<
"// =============================================="
338 "===========================\n\n";
341 out <<
"constexpr size_t kGoldenNumOverworldMaps = " << std::dec
342 << maps.size() <<
";\n\n";
344 out <<
"// Map properties for first 20 maps\n";
345 out <<
"constexpr std::array<uint8_t, 20> kGoldenMapAreaGraphics = {{\n";
346 for (
int i = 0; i < std::min(20, static_cast<int>(maps.size())); i++) {
347 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
348 <<
static_cast<int>(maps[i].area_graphics());
349 if (i < 19) out <<
",";
350 out <<
" // Map " << std::dec << i <<
"\n";
357 out <<
"// =============================================="
358 "===========================\n";
359 out <<
"// Tile Data Information\n";
360 out <<
"// =============================================="
361 "===========================\n\n";
363 out <<
"constexpr bool kGoldenExpandedTile16 = "
365 out <<
"constexpr bool kGoldenExpandedTile32 = "
368 const auto& tiles16 = overworld.
tiles16();
371 out <<
"constexpr size_t kGoldenNumTiles16 = " << std::dec << tiles16.size()
373 out <<
"constexpr size_t kGoldenNumTiles32 = " << std::dec << tiles32.size()
378 std::ofstream& out,
Overworld& overworld) {
379 out <<
"// =============================================="
380 "===========================\n";
381 out <<
"// Entrance Data\n";
382 out <<
"// =============================================="
383 "===========================\n\n";
385 const auto& entrances = overworld.
entrances();
386 out <<
"constexpr size_t kGoldenNumEntrances = " << std::dec
387 << entrances.size() <<
";\n\n";
389 out <<
"// Sample entrance data (first 10 entrances)\n";
390 out <<
"constexpr std::array<uint16_t, 10> kGoldenEntranceMapPos = {{\n";
391 for (
int i = 0; i < std::min(10, static_cast<int>(entrances.size())); i++) {
392 out <<
" 0x" << std::hex << std::setw(4) << std::setfill(
'0')
393 << entrances[i].map_pos_;
394 if (i < 9) out <<
",";
395 out <<
" // Entrance " << std::dec << i <<
"\n";
402 out <<
"} // namespace test\n";
403 out <<
"} // namespace yaze\n";
413 std::string input_path = parser.
GetString(
"rom").value_or(
"");
414 std::string output_path = parser.
GetString(
"output").value_or(
"");
426 formatter.
AddField(
"status",
"success");
427 formatter.
AddField(
"output_file", output_path);
429 "Successfully created v3 patched ROM: " + output_path);
430 return absl::OkStatus();
446 for (
int i = 0; i < 10; i++) {
455 uint16_t bg_color = 0x0000 + (i * 0x1000);
459 (bg_color >> 8) & 0xFF);
462 uint16_t overlay = 0x0090 + i;
466 (overlay >> 8) & 0xFF);
472 for (
int j = 0; j < 8; j++) {
481 uint16_t message_id = 0x1000 + i;
484 (message_id >> 8) & 0xFF);
487 return absl::OkStatus();
497 std::cout <<
"Available Test Helper Tools:\n\n";
498 std::cout <<
" tools-harness-state Generate WRAM state for test harnesses\n";
499 std::cout <<
" tools-extract-values Extract vanilla ROM values\n";
500 std::cout <<
" tools-extract-golden Extract comprehensive golden data\n";
501 std::cout <<
" tools-patch-v3 Create v3 ZSCustomOverworld patched ROM\n";
502 std::cout <<
"\nUsage: z3ed <tool-name> --help\n";
504 formatter.
AddField(
"status",
"success");
505 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
absl::Status WriteByte(int addr, uint8_t value)
const auto & vector() const
absl::Status SaveToFile(const SaveSettings &settings)
absl::StatusOr< uint8_t > ReadByte(int offset)
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
uint8_t Read(uint32_t adr)
void Reset(bool hard=false)
void Init(const std::vector< uint8_t > &rom_data)
Represents the full Overworld data, light and dark world.
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
auto expanded_tile32() const
std::vector< gfx::Tile16 > tiles16() const
auto expanded_tile16() const
auto tiles32_unique() const
const std::vector< OverworldEntrance > & entrances() const
auto overworld_maps() const
constexpr int kAreaGfxIdPtr
constexpr int OverworldCustomTileGFXGroupEnabled
constexpr int OverworldCustomAreaSpecificBGEnabled
constexpr int kOverworldSpriteset
constexpr int kOverworldScreenSize
constexpr int OverworldCustomMosaicArray
constexpr int OverworldCustomAnimatedGFXEnabled
constexpr int OverworldCustomMainPaletteEnabled
constexpr int OverworldCustomMainPaletteArray
AreaSizeEnum
Area size enumeration for v3+ ROMs.
constexpr int OverworldCustomASMHasBeenApplied
constexpr int kOverworldMessagesExpanded
constexpr int OverworldCustomAnimatedGFXArray
constexpr int OverworldCustomMosaicEnabled
constexpr int OverworldCustomTileGFXGroupArray
constexpr int OverworldCustomSubscreenOverlayEnabled
constexpr int OverworldCustomAreaSpecificBGPalette
constexpr int kOverworldMapPaletteIds
constexpr int OverworldCustomSubscreenOverlayArray
#define RETURN_IF_ERROR(expr)
CLI command handlers for test helper tools.