diff --git a/fer.sav b/fer.sav new file mode 100644 index 0000000..8e62f56 Binary files /dev/null and b/fer.sav differ diff --git a/main.cpp b/main.cpp index c3b7413..9871456 100644 --- a/main.cpp +++ b/main.cpp @@ -10,6 +10,7 @@ #include #include "ui.h" #include "ui_menu.h" +#include "z80analyze.h" uint8_t memory[65536]; uint32_t time = 0; @@ -24,10 +25,16 @@ namespace actions zxscreen::refresh(dt); } - int berserk(int value) + int fastload(int value) { - zx_tape::setberserk(!zx_tape::getberserk()); - return zx_tape::getberserk(); + zx_tape::toggleOption(ZXTAPE_OPTION_FAST_LOAD); + return zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD); + } + + int stopatend(int value) + { + zx_tape::toggleOption(ZXTAPE_OPTION_STOP_AT_END); + return zx_tape::getOption(ZXTAPE_OPTION_STOP_AT_END); } int decZoom(int value) @@ -47,6 +54,12 @@ namespace actions zxscreen::toggleFullscreen(); return zxscreen::getFullscreen(); } + + int showAnalyzer(int value) + { + z80analyze::show(); + return 0; + } } int main(int argc, char *argv[]) @@ -73,13 +86,18 @@ int main(int argc, char *argv[]) ui::menu::addoption(menu, "SAVE STATE", nullptr); menu = ui::menu::addsubmenu("TAPE"); - ui::menu::addbooloption(menu, "BERSERK MODE", zx_tape::getberserk(), actions::berserk); + ui::menu::addbooloption(menu, "BERSERK MODE", zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD), actions::fastload); + ui::menu::addbooloption(menu, "STOP AT END", zx_tape::getOption(ZXTAPE_OPTION_STOP_AT_END), actions::stopatend); menu = ui::menu::addsubmenu("SCREEN"); ui::menu::addoption(menu, "DEC ZOOM", actions::decZoom); ui::menu::addoption(menu, "INC ZOOM", actions::incZoom); ui::menu::addbooloption(menu, "FULLSCREEN", zxscreen::getFullscreen(), actions::fullscreen); + menu = ui::menu::addsubmenu("EMULATION"); + ui::menu::addbooloption(menu, "STOP ON INVALID OP", z80::getOption(Z80_OPTION_STOP_ON_INVALID), actions::decZoom); + ui::menu::addoption(menu, "SHOW ANALYZER", actions::showAnalyzer); + zx_ula::sound_init(); zx_tape::load("fernandomartin.tap"); @@ -206,9 +224,9 @@ int main(int argc, char *argv[]) zxscreen::redraw(); } else { //if (z80::getPC()==0x05C8) zx_tape::go_berserk(); - bool berserk=false; - if (zx_tape::getplaying() && zx_tape::getberserk()) { berserk=true; time = SDL_GetTicks(); } - while (zx_tape::getplaying() && zx_tape::getberserk()) + bool fastload=false; + if (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) { fastload=true; time = SDL_GetTicks(); } + while (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) { // zx_tape::update(z80::step()); uint8_t dt = z80::step(); @@ -221,7 +239,7 @@ int main(int argc, char *argv[]) //zx_ula::sound_update(dt); //zxscreen::refresh(dt); } - if (berserk) { printf("%i\n", SDL_GetTicks()-time); t_states=0; } + if (fastload) { printf("%i\n", SDL_GetTicks()-time); t_states=0; } // En cada bucle fem 10 pasos de la CPU, sino s'ofega for (int i=0;i<5;++i) { uint8_t dt = z80::step(); diff --git a/z80.cpp b/z80.cpp index 34bb329..e286f1a 100644 --- a/z80.cpp +++ b/z80.cpp @@ -9,6 +9,7 @@ namespace z80 static uint8_t memtag[65536]; static uint32_t t = 0; static uint16_t current_opcode_address = 0; + bool options[Z80_NUM_OPTIONS] = { true }; int (*in_ports[256])(int); void (*out_ports[256])(int, int); @@ -1032,9 +1033,8 @@ namespace z80 void INVALID(uint8_t opcode) { - // [TODO] printf("INVALID OPCODE AT: %04x\n", current_opcode_address); - z80debug::stop(); + if (options[Z80_OPTION_STOP_ON_INVALID]) z80debug::stop(); } void reset(uint8_t* mem) @@ -2738,4 +2738,19 @@ namespace z80 uint8_t getMemTag(const uint16_t addr) { return memtag[addr]; }; + const bool getOption(const int option) + { + return options[option]; + } + + void setOption(const int option, const bool value) + { + options[option] = value; + } + + void toggleOption(const int option) + { + options[option] = !options[option]; + } + } \ No newline at end of file diff --git a/z80.h b/z80.h index 957efa4..7920c39 100644 --- a/z80.h +++ b/z80.h @@ -9,6 +9,9 @@ namespace z80 #define MEMTAG_CODE 2 #define MEMTAG_DATA 3 + #define Z80_OPTION_STOP_ON_INVALID 0 + #define Z80_NUM_OPTIONS 1 + void reset(uint8_t* mem); void connect_port(int num, int (*in_ptr)(int), void (*out_ptr)(int,int)); void interrupt(); @@ -34,4 +37,8 @@ namespace z80 void setPC(const uint16_t addr); uint8_t getMemTag(const uint16_t addr); + + const bool getOption(const int option); + void setOption(const int option, const bool value); + void toggleOption(const int option); } \ No newline at end of file diff --git a/z80analyze.cpp b/z80analyze.cpp new file mode 100644 index 0000000..996531b --- /dev/null +++ b/z80analyze.cpp @@ -0,0 +1,43 @@ +#include "z80analyze.h" +#include "z80.h" +#include + +namespace z80analyze +{ + SDL_Window *win = nullptr; + SDL_Renderer *ren = nullptr; + SDL_Texture *tex = nullptr; + + void show() + { + if (!win) + { + win = SDL_CreateWindow("Z80 Analyzer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 256, 256, SDL_WINDOW_SHOWN); + ren = SDL_CreateRenderer(win, -1, 0); + tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 256, 256); + } + refresh(); + } + + void refresh() + { + Uint32 *pixels; + int pitch; + SDL_LockTexture(tex, NULL, (void**)&pixels, &pitch); + for (int i=0; i<65536; ++i) + { + uint8_t tag = z80::getMemTag(i); + pixels[i] = tag==MEMTAG_NONE ? 0x808080 : tag==MEMTAG_DATA ? 0x0000FF : 0x00FF00; + } + SDL_UnlockTexture(tex); + SDL_RenderCopy(ren, tex, NULL, NULL); + SDL_RenderPresent(ren); + } + + void hide() + { + SDL_DestroyTexture(tex); + SDL_DestroyRenderer(ren); + SDL_DestroyWindow(win); + } +} diff --git a/z80analyze.h b/z80analyze.h new file mode 100644 index 0000000..b5a93b6 --- /dev/null +++ b/z80analyze.h @@ -0,0 +1,8 @@ +#pragma once + +namespace z80analyze +{ + void show(); + void refresh(); + void hide(); +} diff --git a/zx_screen.cpp b/zx_screen.cpp index 4f3f049..2adfa1f 100644 --- a/zx_screen.cpp +++ b/zx_screen.cpp @@ -181,7 +181,7 @@ namespace zxscreen void redraw(const bool present) { - if (zx_tape::getplaying() && zx_tape::getberserk()) return; + if (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) return; Uint32* pixels; int pitch; diff --git a/zx_tape.cpp b/zx_tape.cpp index 895dfdf..2888446 100644 --- a/zx_tape.cpp +++ b/zx_tape.cpp @@ -1,6 +1,7 @@ #include "zx_tape.h" #include "zx_ula.h" #include "zx_screen.h" +#include "z80debug.h" #include #include #include @@ -34,7 +35,7 @@ namespace zx_tape bool playing = false; bool loaded = false; - bool berserk_mode = true; + bool options[ZXTAPE_NUM_OPTIONS] = { true, true }; std::vector blocks; uint8_t current_block = 0; @@ -80,7 +81,7 @@ namespace zx_tape void stop() { playing = false; - berserk_mode = false; + //berserk_mode = false; } void rewind() @@ -220,6 +221,7 @@ namespace zx_tape printf("end\n"); stop(); rewind(); + if (options[ZXTAPE_OPTION_STOP_AT_END]) z80debug::stop(); } else { @@ -232,8 +234,6 @@ namespace zx_tape zx_ula::set_ear(pulse_level); } - void setberserk(const bool value) { berserk_mode = value; } - const bool getberserk() { return berserk_mode; } const bool getplaying() { return playing; } void report() @@ -242,4 +242,19 @@ namespace zx_tape const int percent = (float(block_pos)/float(blocks[current_block].length))*100; printf("tape loading: %i%\n", percent); } + + const bool getOption(const int option) + { + return options[option]; + } + + void setOption(const int option, const bool value) + { + options[option] = value; + } + + void toggleOption(const int option) + { + options[option] = !options[option]; + } } diff --git a/zx_tape.h b/zx_tape.h index 50e39e5..d9a9122 100644 --- a/zx_tape.h +++ b/zx_tape.h @@ -3,13 +3,19 @@ namespace zx_tape { + #define ZXTAPE_OPTION_FAST_LOAD 0 + #define ZXTAPE_OPTION_STOP_AT_END 1 + #define ZXTAPE_NUM_OPTIONS 2 + void load(const char* filename); void play(); void stop(); void rewind(); void update(const uint8_t dt); - void setberserk(const bool value); - const bool getberserk(); const bool getplaying(); void report(); + + const bool getOption(const int option); + void setOption(const int option, const bool value); + void toggleOption(const int option); }