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) {
105 out_file <<
"0x" << std::hex << std::setw(2) << std::setfill(
'0')
106 <<
static_cast<int>(snes.
Read(0x7E0000 + i));
112 out_file <<
"}};\n\n";
115 out_file <<
"// ================================================"
116 "=========================\n";
117 out_file <<
"// Initial Register States\n";
118 out_file <<
"// ================================================"
119 "=========================\n\n";
121 out_file <<
"struct InitialPpuState {\n";
122 out_file <<
" uint8_t inidisp = 0x" << std::hex << ppu.Read(0x2100,
false)
124 out_file <<
" uint8_t objsel = 0x" << std::hex << ppu.Read(0x2101,
false)
126 out_file <<
" uint8_t bgmode = 0x" << std::hex << ppu.Read(0x2105,
false)
128 out_file <<
" uint8_t mosaic = 0x" << std::hex << ppu.Read(0x2106,
false)
130 out_file <<
" uint8_t tm = 0x" << std::hex << ppu.Read(0x212C,
false)
132 out_file <<
" uint8_t ts = 0x" << std::hex << ppu.Read(0x212D,
false)
134 out_file <<
" uint8_t cgwsel = 0x" << std::hex << ppu.Read(0x2130,
false)
136 out_file <<
" uint8_t cgadsub = 0x" << std::hex << ppu.Read(0x2131,
false)
138 out_file <<
" uint8_t setini = 0x" << std::hex << ppu.Read(0x2133,
false)
140 out_file <<
"};\n\n";
142 out_file <<
"} // namespace emu\n";
143 out_file <<
"} // namespace yaze\n";
145 return absl::OkStatus();
155 std::string rom_path = parser.
GetString(
"rom").value_or(
"");
156 std::string format = parser.
GetString(
"format").value_or(
"cpp");
159 if (!rom || rom->
size() == 0) {
165 std::ostringstream output;
167 if (format ==
"json") {
169 output <<
" \"asm_version\": \"0x" << std::hex << std::setw(2)
173 output <<
" \"area_graphics\": [";
174 for (
int i = 0; i < 10; i++) {
175 output <<
"\"0x" << std::hex << std::setw(2) << std::setfill(
'0')
181 output <<
" \"area_palettes\": [";
182 for (
int i = 0; i < 10; i++) {
183 output <<
"\"0x" << std::hex << std::setw(2) << std::setfill(
'0')
189 output <<
" \"screen_sizes\": [";
190 for (
int i = 0; i < 10; i++) {
191 output <<
"\"0x" << std::hex << std::setw(2) << std::setfill(
'0')
200 output <<
"// Vanilla ROM values extracted\n\n";
202 output <<
"constexpr uint8_t kVanillaASMVersion = 0x" << std::hex
203 << std::setw(2) << std::setfill(
'0')
207 output <<
"// Area graphics for first 10 maps\n";
208 for (
int i = 0; i < 10; i++) {
209 output <<
"constexpr uint8_t kVanillaAreaGraphics" << std::dec << i
210 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
215 output <<
"// Area palettes for first 10 maps\n";
216 for (
int i = 0; i < 10; i++) {
217 output <<
"constexpr uint8_t kVanillaAreaPalette" << std::dec << i
218 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
223 output <<
"// Screen sizes for first 10 maps\n";
224 for (
int i = 0; i < 10; i++) {
225 output <<
"constexpr uint8_t kVanillaScreenSize" << std::dec << i
226 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
231 output <<
"// Sprite sets for first 10 maps\n";
232 for (
int i = 0; i < 10; i++) {
233 output <<
"constexpr uint8_t kVanillaSpriteSet" << std::dec << i
234 <<
" = 0x" << std::hex << std::setw(2) << std::setfill(
'0')
239 std::cout << output.str();
240 formatter.
AddField(
"status",
"success");
241 return absl::OkStatus();
251 std::string rom_path = parser.
GetString(
"rom").value_or(
"");
252 std::string output_path = parser.
GetString(
"output").value_or(
"");
262 std::ofstream out_file(output_path);
263 if (!out_file.is_open()) {
264 return absl::InternalError(
"Failed to open output file: " + output_path);
275 formatter.
AddField(
"status",
"success");
276 formatter.
AddField(
"output_file", output_path);
278 "Successfully extracted golden data from " + rom_path);
279 return absl::OkStatus();
283 std::ofstream& out,
const std::string& rom_path) {
284 out <<
"// =============================================="
285 "===========================\n";
286 out <<
"// YAZE Overworld Golden Data - Generated from: " << rom_path <<
"\n";
287 out <<
"// =============================================="
288 "===========================\n\n";
289 out <<
"#pragma once\n\n";
290 out <<
"#include <cstdint>\n";
291 out <<
"#include <array>\n";
292 out <<
"#include <vector>\n";
293 out <<
"#include \"zelda3/overworld/overworld_map.h\"\n\n";
294 out <<
"namespace yaze {\n";
295 out <<
"namespace test {\n\n";
300 out <<
"// =============================================="
301 "===========================\n";
302 out <<
"// Basic ROM Information\n";
303 out <<
"// =============================================="
304 "===========================\n\n";
306 out <<
"constexpr std::string_view kGoldenROMTitle = \"" << rom.
title()
308 out <<
"constexpr size_t kGoldenROMSize = " << std::dec << rom.
size()
314 out <<
"// =============================================="
315 "===========================\n";
316 out <<
"// ASM Version Information\n";
317 out <<
"// =============================================="
318 "===========================\n\n";
320 auto asm_version = rom.
ReadByte(0x140145);
321 if (asm_version.ok()) {
322 out <<
"constexpr uint8_t kGoldenASMVersion = 0x" << std::hex
323 << std::setw(2) << std::setfill(
'0') <<
static_cast<int>(*asm_version)
326 if (*asm_version == 0xFF) {
327 out <<
"constexpr bool kGoldenIsVanillaROM = true;\n";
328 out <<
"constexpr bool kGoldenHasZSCustomOverworld = false;\n";
330 out <<
"constexpr bool kGoldenIsVanillaROM = false;\n";
331 out <<
"constexpr bool kGoldenHasZSCustomOverworld = true;\n";
332 out <<
"constexpr uint8_t kGoldenZSCustomOverworldVersion = " << std::dec
333 <<
static_cast<int>(*asm_version) <<
";\n";
340 std::ofstream& out,
Overworld& overworld) {
341 out <<
"// =============================================="
342 "===========================\n";
343 out <<
"// Overworld Maps Data\n";
344 out <<
"// =============================================="
345 "===========================\n\n";
348 out <<
"constexpr size_t kGoldenNumOverworldMaps = " << std::dec
349 << maps.size() <<
";\n\n";
351 out <<
"// Map properties for first 20 maps\n";
352 out <<
"constexpr std::array<uint8_t, 20> kGoldenMapAreaGraphics = {{\n";
353 for (
int i = 0; i < std::min(20, static_cast<int>(maps.size())); i++) {
354 out <<
" 0x" << std::hex << std::setw(2) << std::setfill(
'0')
355 <<
static_cast<int>(maps[i].area_graphics());
358 out <<
" // Map " << std::dec << i <<
"\n";
365 out <<
"// =============================================="
366 "===========================\n";
367 out <<
"// Tile Data Information\n";
368 out <<
"// =============================================="
369 "===========================\n\n";
371 out <<
"constexpr bool kGoldenExpandedTile16 = "
373 out <<
"constexpr bool kGoldenExpandedTile32 = "
376 const auto& tiles16 = overworld.
tiles16();
379 out <<
"constexpr size_t kGoldenNumTiles16 = " << std::dec << tiles16.size()
381 out <<
"constexpr size_t kGoldenNumTiles32 = " << std::dec << tiles32.size()
387 out <<
"// =============================================="
388 "===========================\n";
389 out <<
"// Entrance Data\n";
390 out <<
"// =============================================="
391 "===========================\n\n";
393 const auto& entrances = overworld.
entrances();
394 out <<
"constexpr size_t kGoldenNumEntrances = " << std::dec
395 << entrances.size() <<
";\n\n";
397 out <<
"// Sample entrance data (first 10 entrances)\n";
398 out <<
"constexpr std::array<uint16_t, 10> kGoldenEntranceMapPos = {{\n";
399 for (
int i = 0; i < std::min(10, static_cast<int>(entrances.size())); i++) {
400 out <<
" 0x" << std::hex << std::setw(4) << std::setfill(
'0')
401 << entrances[i].map_pos_;
404 out <<
" // Entrance " << std::dec << i <<
"\n";
411 out <<
"} // namespace test\n";
412 out <<
"} // namespace yaze\n";
425 return absl::PermissionDeniedError(
426 "ROM patching is disabled by the project's read-only policy");
428 std::string input_path = parser.
GetString(
"rom").value_or(
"");
429 std::string output_path = parser.
GetString(
"output").value_or(
"");
441 formatter.
AddField(
"status",
"success");
442 formatter.
AddField(
"output_file", output_path);
444 "Successfully created v3 patched ROM: " + output_path);
445 return absl::OkStatus();
461 for (
int i = 0; i < 10; i++) {
470 uint16_t bg_color = 0x0000 + (i * 0x1000);
474 (bg_color >> 8) & 0xFF);
477 uint16_t overlay = 0x0090 + i;
481 (overlay >> 8) & 0xFF);
487 for (
int j = 0; j < 8; j++) {
496 uint16_t message_id = 0x1000 + i;
499 (message_id >> 8) & 0xFF);
502 return absl::OkStatus();
512 std::cout <<
"Available Test Helper Tools:\n\n";
514 <<
" tools-harness-state Generate WRAM state for test harnesses\n";
515 std::cout <<
" tools-extract-values Extract vanilla ROM values\n";
516 std::cout <<
" tools-extract-golden Extract comprehensive golden data\n";
518 <<
" tools-patch-v3 Create v3 ZSCustomOverworld patched ROM\n";
519 std::cout <<
"\nUsage: z3ed <tool-name> --help\n";
521 formatter.
AddField(
"status",
"success");
522 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)
absl::StatusOr< uint8_t > ReadByte(int offset) const
const auto & vector() const
absl::Status SaveToFile(const SaveSettings &settings)
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)
project::YazeProject * project_
uint8_t Read(uint32_t adr)
void Reset(bool hard=false)
void Init(const std::vector< uint8_t > &rom_data)
absl::Status Load(Rom *rom)
Load all overworld data from ROM.
auto expanded_tile32() const
const std::vector< gfx::Tile16 > & tiles16() const
auto expanded_tile16() const
const std::vector< OverworldMap > & overworld_maps() const
auto tiles32_unique() const
const std::vector< OverworldEntrance > & entrances() 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.