- Enorme reestructuració del codi per a que el fluxe comence a ser mes racional

- [NEW] mòdul zx_system per a gestionar la vida i canvi de systemes (48K, 128K...)
This commit is contained in:
2025-07-30 13:01:01 +02:00
parent 2775da3d53
commit 1db0c52e1a
15 changed files with 257 additions and 101 deletions

View File

@@ -19,8 +19,7 @@
namespace audio
{
#define SAMPLING_FREQ 44100
#define AUDIO_BUFFER_SIZE 2048
bool enabled = false;
float cycles_per_sample;
uint8_t volume_table[16] {0,2,3,4,6,8,11,16,23,32,45,64,90,128,180,255};
@@ -122,12 +121,14 @@ namespace audio
void reset()
{
enabled = true;
selected_register = 0;
for (int i=0; i<16;++i) registers[i]=0;
}
void update(uint32_t dt)
{
if (!enabled) return;
//dt = dt >> 1;
// Oscillate (0-1) channel A tone level given its frequency

110
main.cpp
View File

@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stdio.h>
#include "zx_system.h"
#include "z80.h"
#include "z80dis.h"
#include "z80debug.h"
@@ -14,8 +15,6 @@
#include "z80analyze.h"
#include "ui_window.h"
#include "zx_mem.h"
//#include "zx_48mem.h"
//#include "zx_128mem.h"
#include "z80viewer.h"
//#include "zx_128bankviewer.h"
//#include "zx_128pageviewer.h"
@@ -23,7 +22,6 @@
#include "ay_viewer.h"
#include "file.h"
//uint8_t memory[65536];
uint32_t time = 0;
uint32_t t_states = 0;
@@ -77,43 +75,34 @@ namespace actions
z80analyze::show();
return 0;
}
int mode48K(int value)
{
zx_system::reset(ZX_48K);
return 0;
}
int main(int argc, char *argv[])
int mode128K(int value)
{
//const uint32_t clock = 3500000;
const uint32_t clock = 3546900;
const uint32_t update_freq = clock / 10;
zx_system::reset(ZX_128K);
return 0;
}
file::setConfigFolder("z80");
//new zx_48mem();
//new zx_128mem();
mem::init(ZX_128K);
z80dis::loadSymbols();
z80::setClock(clock);
int reset(int value)
{
z80::reset();
z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
audio::init();
return 0;
}
SDL_Init(SDL_INIT_EVERYTHING);
z80debug::init();
//zxscreen::init(SCREEN_MODE_48K);
zxscreen::init(SCREEN_MODE_128K);
//ay_viewer *v = new ay_viewer();
//v->show();
//z80viewer::registerViewer("AY", v);
//z80viewer *v = new zx_128bankviewer();
//v->show();
//z80viewer::registerViewer("128BANK", v);
//v = new zx_128pageviewer();
//v->show();
//z80viewer::registerViewer("128PAGE", v);
int exit(int value)
{
zx_system::shutdown();
return 0;
}
}
void init_menu()
{
ui::menu::init();
ui::menu::setexitcallback(actions::exitMenu);
@@ -123,6 +112,14 @@ int main(int argc, char *argv[])
ui::menu::addseparator(menu);
ui::menu::addoption(menu, "LOAD STATE", nullptr);
ui::menu::addoption(menu, "SAVE STATE", nullptr);
ui::menu::addseparator(menu);
ui::menu::addoption(menu, "EXIT", actions::exit);
menu = ui::menu::addsubmenu("SYSTEM");
ui::menu::addoption(menu, "ZX 48K", actions::mode48K);
ui::menu::addoption(menu, "ZX 128K/+2", actions::mode128K);
ui::menu::addseparator(menu);
ui::menu::addoption(menu, "RESET", actions::reset);
menu = ui::menu::addsubmenu("TAPE");
ui::menu::addbooloption(menu, "FAST LOAD", zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD), actions::fastload);
@@ -138,30 +135,36 @@ int main(int argc, char *argv[])
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);
}
speaker::init();
speaker::register_source(zx_ula::get_sample);
speaker::register_source(audio::get_sample);
int main(int argc, char *argv[])
{
file::setConfigFolder("z80");
SDL_Init(SDL_INIT_EVERYTHING);
init_menu();
z80debug::init();
//uint32_t update_freq =
zx_system::init(ZX_48K);
zx_tape::load("ROBOCOP1.TAP");
if (argc==3) { z80debug::loadngo(argv[1], argv[2]); }
//if (argc==3) { z80debug::loadngo(argv[1], argv[2]); }
z80debug::stop();
//z80debug::stop();
bool should_exit = false;
SDL_Event e;
time = SDL_GetTicks();
t_states = 0;
while (!should_exit)
while (!zx_system::shuttingDown())
{
while (SDL_PollEvent(&e))
{
bool result = true;
if (e.type == SDL_QUIT) { should_exit=true; break; }
if (e.type == SDL_QUIT) { zx_system::shutdown(); break; }
if (e.type == SDL_MOUSEBUTTONDOWN) result = ui::window::sendEvent(e.button.windowID, &e);
if (e.type == SDL_MOUSEBUTTONUP) result = ui::window::sendEvent(e.button.windowID, &e);
if (e.type == SDL_MOUSEMOTION) result = ui::window::sendEvent(e.motion.windowID, &e);
@@ -224,10 +227,11 @@ int main(int argc, char *argv[])
if (e.type == SDL_MOUSEBUTTONUP && e.button.button==1) ui::setClicked(true);
if (!result)
should_exit = true; break;
zx_system::shutdown(); break;
}
if (!z80debug::debugging() && !z80debug::paused()) {
/*
//if (z80::getPC()==0x05C8) zx_tape::go_berserk();
bool fastload=false;
if (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) { fastload=true; time = SDL_GetTicks(); }
@@ -245,7 +249,9 @@ int main(int argc, char *argv[])
//zxscreen::refresh(dt);
}
if (fastload) { printf("%i\n", SDL_GetTicks()-time); t_states=0; }
// En cada bucle fem 10 pasos de la CPU, sino s'ofega
*/
// En cada bucle fem 10 pasos de la CPU, sino s'ofega (jo en veig 5)
for (int i=0;i<5;++i) {
if (z80debug::isbreak(z80::getPC(), 9)) {
z80debug::stop();
@@ -254,23 +260,21 @@ int main(int argc, char *argv[])
} else {
uint8_t dt = z80::step();
t_states += dt;
zx_tape::update(dt);
audio::update(dt);
speaker::update(dt);
zx_system::update(dt);
//zx_tape::update(dt);
//audio::update(dt);
//speaker::update(dt);
zxscreen::refresh(dt);
if (z80debug::debugging()) break;
}
}
uint32_t update_freq = z80::getClock()/10;
if (t_states>=update_freq)
{
//if (SDL_GetTicks()>=time+1000)
//printf("%i\n", SDL_GetTicks()-(time+1000));
//else
// printf("%i\n", SDL_GetTicks()-(time+1000));
//t_states = 0;
//printf("%i: %i\n", SDL_GetTicks()-(time+1000), t_states);
// Esperem a que es compleixca el temps corresponent als t states executats
while (SDL_GetTicks()<time+100) {}
t_states -= update_freq;
time = SDL_GetTicks();
z80analyze::refresh();
@@ -279,7 +283,7 @@ int main(int argc, char *argv[])
z80analyze::refresh(true);
} else if (!z80debug::debugging() && z80debug::paused()) {
} else if (/*!z80debug::debugging() &&*/ z80debug::paused()) {
zxscreen::redraw(false);
ui::menu::show();
zxscreen::present();

19
z80.cpp
View File

@@ -1150,22 +1150,27 @@ namespace z80
if (options[Z80_OPTION_STOP_ON_INVALID]) z80debug::stop();
}
void reset()
void init(uint32_t freq)
{
for (int i=0; i<256; ++i)
{
ports.clear();
//in_ports[i] = nullptr;
//out_ports[i] = nullptr;
setClock(freq);
reset();
clearPorts();
}
mem::reset();
void reset()
{
//mem::reset();
rPC = iff1 = iff2 = im = 0;
rAF = rAF2 = rBC = rBC2 = rDE = rDE2 = rHL = rHL2 = rIX = rIY = rSP = 0xffff;
t = 0;
}
void clearPorts()
{
ports.clear();
}
void setClock(uint32_t freq)
{
clock = freq;

2
z80.h
View File

@@ -9,7 +9,9 @@ namespace z80
#define Z80_OPTION_BREAK_ON_RET 2
#define Z80_NUM_OPTIONS 3
void init(uint32_t freq);
void reset();
void clearPorts();
void setClock(uint32_t freq);
uint32_t getClock();

View File

@@ -816,10 +816,13 @@ namespace z80debug
if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) {
uint8_t dt = z80::step();
zx_tape::update(dt);
audio::update(dt);
speaker::update(dt);
zx_system::update(dt);
//zx_tape::update(dt);
//audio::update(dt);
//speaker::update(dt);
zxscreen::fullrefresh();
z80analyze::refresh();
} else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) {
z80::step();
@@ -827,7 +830,7 @@ namespace z80debug
z80analyze::refresh();
} else if (strcmp(cmd, "r")==0 || strcmp(cmd, "reset")==0) {
z80::reset();
z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
//z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
history::reset();
z80debug::refresh();
z80analyze::refresh();

View File

@@ -25,14 +25,14 @@ namespace mem
void init(uint8_t mode)
{
mem::mode = mode;
if (ram) free(ram);
if (rom) free(rom);
reset();
}
void reset()
{
if (ram) free(ram);
if (rom) free(rom);
FILE* f;
switch(mode)
{

View File

@@ -2,6 +2,7 @@
#include <stdint.h>
#include <stdio.h>
#include "zx_system.h"
#define MEMTAG_NONE 0x00
#define MEMTAG_DATA 0x01
@@ -16,11 +17,6 @@
#define MEMTAG_KNOWN 0x07
#define MEMTAG_TOUCHED 0x70
#define ZX_48K 0x00
#define ZX_128K 0x01
#define ZX_2A_3 0x02
#define ZX_NEXT 0x03
namespace mem
{
void init(uint8_t mode);

View File

@@ -26,6 +26,7 @@ namespace zxscreen
uint32_t t_states_total = 69888;
uint32_t t_states_per_scanline = 224;
uint32_t vsync_lines = 16;
bool interrupt_enabled = true;
uint8_t zoom = 2;
bool fullscreen = false;
@@ -39,8 +40,6 @@ namespace zxscreen
uint8_t t_flash = 0;
bool flash = false;
int pixels_draw = 0;
uint32_t pixel_base_addr = 0x4000;
uint32_t color_base_addr = 0x5800;
@@ -235,6 +234,9 @@ namespace zxscreen
}
create_tables();
ptr_pixel = zx_pixels;
t_screen = t_flash = 0;
flash = false;
reinit();
}
@@ -247,7 +249,7 @@ namespace zxscreen
}
}
void refresh(const uint32_t dt, const bool full)
void refresh(const uint32_t dt)
{
const uint8_t* pixel_mem = mem::rawPtr(pixel_base_addr);
const uint8_t* color_mem = mem::rawPtr(color_base_addr);
@@ -272,17 +274,15 @@ namespace zxscreen
mask>>=1;
*(ptr_pixel++)=(block&mask) ? c1 : c2;
}
pixels_draw+=2;
}
t_screen++;
if (t_screen>=t_states_total) {
pixels_draw=0;
t_flash++;
if (t_flash==16) { t_flash=0; flash = !flash; }
t_screen=0;
ptr_pixel = zx_pixels;
redraw();
if (!full) z80::interrupt();
if (interrupt_enabled) z80::interrupt();
}
}
}
@@ -293,7 +293,9 @@ namespace zxscreen
t_screen = 0;
uint8_t * tmp_ptr = ptr_pixel;
ptr_pixel = zx_pixels;
refresh(t_states_total, true);
interrupt_enabled = false;
refresh(t_states_total);
interrupt_enabled = true;
ptr_pixel = tmp_ptr;
t_screen = tmp;
}

View File

@@ -10,7 +10,7 @@ namespace zxscreen
void setBaseAddresses(const uint32_t pixeladdr, const uint32_t coloraddr);
void reinit();
void focus();
void refresh(const uint32_t dt, const bool full=false);
void refresh(const uint32_t dt);
void fullrefresh();
void debugrefresh();
void redraw(const bool present=true);

View File

@@ -5,24 +5,46 @@
namespace speaker
{
#define SAMPLING_FREQ 44100
#define AUDIO_BUFFER_SIZE 2048
SDL_AudioDeviceID sdlAudioDevice;
uint8_t sound_buffer[AUDIO_BUFFER_SIZE];
uint16_t sampling_freq = 44100;
uint16_t audio_buffer_size = 2048;
SDL_AudioDeviceID sdlAudioDevice = 0;
uint8_t *sound_buffer = nullptr;
uint16_t sound_pos=0;
uint16_t t_sound=0;
std::vector<uint8_t(*)()> sources;
float cycles_per_sample;
void init()
void init(const uint16_t freq, const uint16_t buffer_size)
{
SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE>>2, 0, 0, NULL, NULL};
if (sound_buffer || sdlAudioDevice) quit();
sampling_freq = freq;
audio_buffer_size = buffer_size;
SDL_AudioSpec audioSpec{sampling_freq, AUDIO_U8, 1, 0, (uint16_t)(audio_buffer_size>>2), 0, 0, NULL, NULL};
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
cycles_per_sample = z80::getClock() / SAMPLING_FREQ;
cycles_per_sample = z80::getClock() / sampling_freq;
sound_buffer = (uint8_t*)malloc(audio_buffer_size);
enable();
}
void quit()
{
disable();
sources.clear();
if (sound_buffer) {
free(sound_buffer);
sound_buffer = nullptr;
}
if (sdlAudioDevice) {
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0;
}
}
void enable()
{
SDL_PauseAudioDevice(sdlAudioDevice, 0);
@@ -38,7 +60,7 @@ namespace speaker
sources.push_back(callback);
}
void update(const uint8_t dt)
void update(const uint32_t dt)
{
t_sound += dt;
if (t_sound>=cycles_per_sample) {
@@ -48,12 +70,12 @@ namespace speaker
for (auto callback : sources) sample += callback();
sample /= sources.size();
sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = sample;
sound_buffer[(sound_pos++)&(audio_buffer_size-1)] = sample;
}
if (sound_pos>=1000) {
SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos);
sound_pos = 0;
while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) {}
while (SDL_GetQueuedAudioSize(sdlAudioDevice) > (audio_buffer_size<<1) ) {}
}
}

View File

@@ -3,9 +3,10 @@
namespace speaker
{
void init();
void init(const uint16_t freq = 44100, const uint16_t buffer_size = 2048);
void quit();
void enable();
void disable();
void register_source(uint8_t(*callback)());
void update(const uint8_t dt);
void update(const uint32_t dt);
}

101
zx_system.cpp Normal file
View File

@@ -0,0 +1,101 @@
#include "zx_system.h"
#include "z80.h"
#include "zx_mem.h"
#include "zx_ula.h"
#include "zx_screen.h"
#include "zx_tape.h"
#include "zx_speaker.h"
#include "ay-3-8912.h"
#include <vector>
namespace zx_system
{
bool resetting = true;
bool shutting_down = false;
uint8_t current_mode = ZX_48K;
uint8_t new_mode = ZX_48K;
std::vector<void(*)(uint32_t)> updatables;
int init(const uint8_t mode)
{
updatables.clear();
z80::clearPorts();
resetting = false;
switch(mode)
{
case ZX_NOCHANGE:
{
z80::reset();
break;
}
case ZX_48K:
{
const uint32_t clock = 3500000;
z80::init(clock);
z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
mem::init(ZX_48K);
zxscreen::init(SCREEN_MODE_48K);
speaker::init();
speaker::register_source(zx_ula::get_sample);
registerUpdatable(zx_tape::update);
registerUpdatable(speaker::update);
//registerUpdatable(zxscreen::refresh);
return clock / 10;
break;
}
case ZX_128K:
{
const uint32_t clock = 3546900;
z80::init(clock);
z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
mem::init(ZX_128K);
zxscreen::init(SCREEN_MODE_128K);
audio::init();
speaker::init();
speaker::register_source(zx_ula::get_sample);
speaker::register_source(audio::get_sample);
registerUpdatable(zx_tape::update);
registerUpdatable(audio::update);
registerUpdatable(speaker::update);
//registerUpdatable(zxscreen::refresh);
return clock / 10;
break;
}
}
return 0;
}
void reset(const uint8_t mode)
{
new_mode = mode;
resetting = true;
}
void shutdown()
{
shutting_down = true;
}
const bool shuttingDown()
{
if (resetting) init(new_mode);
return shutting_down;
}
void registerUpdatable(void(*callback)(uint32_t))
{
updatables.push_back(callback);
}
void update(uint32_t dt)
{
for (auto& call : updatables) call(dt);
}
}

19
zx_system.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <stdint.h>
#define ZX_NOCHANGE 0x00
#define ZX_48K 0x01
#define ZX_128K 0x02
#define ZX_2A_3 0x03
#define ZX_NEXT 0x04
namespace zx_system
{
int init(const uint8_t mode);
void reset(const uint8_t mode);
void shutdown();
const bool shuttingDown();
void registerUpdatable(void(*callback)(uint32_t));
void update(uint32_t dt);
}

View File

@@ -95,7 +95,7 @@ namespace zx_tape
pulse_level = 1;
}
void update(const uint8_t dt)
void update(const uint32_t dt)
{
if (!playing) return;

View File

@@ -11,7 +11,7 @@ namespace zx_tape
void play();
void stop();
void rewind();
void update(const uint8_t dt);
void update(const uint32_t dt);
const bool getplaying();
void report();
uint16_t fastLoad(const uint8_t block_type, const uint16_t address, const uint16_t length);