- [NEW] zxscreen

- [NEW] F8 para execució
- [NEW] F5 continua execució
- [NEW] ULA synch interrupt
- [NEW] Break on read/write
- [FIX] INC8 and DEC8 did wrong flags calculations
- [FIX] INCMEM8 and DECMEM8 did no flags calculation at all
- [NEW] Flags visualization
- [DEL] run command replaced by cont command
- [NEW] reset command
- [NEW] Breakpoint delete command
This commit is contained in:
2024-04-13 15:30:07 +02:00
parent eb4f2be4a4
commit 0d78733d06
7 changed files with 173 additions and 21 deletions

View File

@@ -3,6 +3,7 @@
#include "z80.h"
#include "z80dis.h"
#include "z80debug.h"
#include "zxscreen.h"
#include <SDL2/SDL.h>
#include <string.h>
@@ -30,6 +31,7 @@ int main(int argc, char *argv[])
SDL_Init(SDL_INIT_EVERYTHING);
z80debug::show();
zxscreen::show();
bool should_exit = false;
SDL_Event e;
@@ -45,7 +47,13 @@ int main(int argc, char *argv[])
should_exit=true; break;
} else if (e.key.keysym.scancode==SDL_SCANCODE_F10) {
t += z80::step();
if (t>=69888) { t=0; z80::interrupt(); }
z80debug::refresh();
zxscreen::refresh();
} else if (e.key.keysym.scancode==SDL_SCANCODE_F5) {
z80::step();
z80debug::cont();
zxscreen::refresh();
} else if (e.key.keysym.scancode==SDL_SCANCODE_RETURN) {
z80debug::executeConsole();
} else if (e.key.keysym.scancode==SDL_SCANCODE_BACKSPACE) {
@@ -55,13 +63,27 @@ int main(int argc, char *argv[])
if (e.type == SDL_TEXTINPUT) {
z80debug::sendToConsole(e.text.text);
}
} else {
if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.scancode==SDL_SCANCODE_F8) {
z80debug::stop();
zxscreen::refresh();
}
}
}
}
if (!z80debug::debugging()) {
if (z80debug::isbreak(z80::getPC()))
if (z80debug::isbreak(z80::getPC())) {
z80debug::stop();
else
zxscreen::refresh();
} else {
t += z80::step();
if (t>=69888) {
t=0;
zxscreen::refresh();
z80::interrupt();
}
}
}
}

39
z80.cpp
View File

@@ -1,4 +1,5 @@
#include "z80.h"
#include "z80debug.h"
#include <stdio.h>
@@ -131,6 +132,7 @@ namespace z80
uint8_t READ_MEM_8(const uint16_t addr)
{
if (z80debug::isbreak(addr, 2)) z80debug::stop();
t+=3;
return memory[addr];
}
@@ -155,13 +157,14 @@ namespace z80
uint16_t READ_MEM_16(const uint16_t addr)
{
return READ_MEM_8(addr) + READ_MEM_8(addr+1) << 8;
return READ_MEM_8(addr) + (READ_MEM_8(addr+1) << 8);
}
const uint8_t WRITE_MEM_8(const uint16_t addr, const uint8_t value)
{
t+=3;
memory[addr] = value;
if (addr>=0x4000) memory[addr] = value;
if (z80debug::isbreak(addr, 4)) z80debug::stop();
return value;
}
@@ -263,9 +266,9 @@ namespace z80
uint8_t value = *reg + 1;
KEEP_FLAGS(fC);
FLAGS_SZXY(*reg);
if (*reg == 0x80) SET_FLAGS(fV);
if ( (*reg & 0x0f) == 0x00 ) SET_FLAGS(fH);
FLAGS_SZXY(value);
if (value == 0x80) SET_FLAGS(fV);
if ( (value & 0x0f) == 0x00 ) SET_FLAGS(fH);
*reg = value;
}
@@ -275,10 +278,10 @@ namespace z80
uint8_t value = *reg - 1;
KEEP_FLAGS(fC);
FLAGS_SZXY(*reg);
FLAGS_SZXY(value);
SET_FLAGS(fN);
if (*reg == 0x7f) SET_FLAGS(fV);
if ( (*reg & 0x0f) == 0x0f ) SET_FLAGS(fH);
if (value == 0x7f) SET_FLAGS(fV);
if ( (value & 0x0f) == 0x0f ) SET_FLAGS(fH);
*reg = value;
}
@@ -288,6 +291,12 @@ namespace z80
t++;
uint8_t value = READ_MEM_8(addr);
value++;
KEEP_FLAGS(fC);
FLAGS_SZXY(value);
if (value == 0x80) SET_FLAGS(fV);
if ( (value & 0x0f) == 0x00 ) SET_FLAGS(fH);
WRITE_MEM_8(addr, value);
}
@@ -296,6 +305,13 @@ namespace z80
t+=1;
uint8_t value = READ_MEM_8(addr);
value--;
KEEP_FLAGS(fC);
FLAGS_SZXY(value);
SET_FLAGS(fN);
if (value == 0x7f) SET_FLAGS(fV);
if ( (value & 0x0f) == 0x0f ) SET_FLAGS(fH);
WRITE_MEM_8(addr, value);
}
@@ -566,6 +582,13 @@ namespace z80
RETN();
}
void interrupt()
{
if (!iff1) return;
PUSH(rPC);
rPC = 0x38;
}
void RST(uint8_t vec)
{
PUSH(rPC);

2
z80.h
View File

@@ -6,6 +6,8 @@ namespace z80
{
void reset(uint8_t* mem);
void connect_port(int num, int (*in_ptr)(), void (*out_ptr)(int));
void interrupt();
uint32_t step();
uint8_t *getMem();

View File

@@ -72,7 +72,7 @@ namespace z80debug
{
is_debugging = true;
if (win) return;
win = SDL_CreateWindow("Z80 Debugger", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 71*CHR_W, 34*CHR_H, SDL_WINDOW_SHOWN);
win = SDL_CreateWindow("Z80 Debugger", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 71*CHR_W, 34*CHR_H, SDL_WINDOW_RESIZABLE);
ren = SDL_CreateRenderer(win, -1, 0);
tex = SDL_CreateTextureFromSurface(ren, SDL_LoadBMP("font.bmp"));
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
@@ -189,7 +189,7 @@ namespace z80debug
printtxt(0,1, "BC BC' IY ", COLOR_WHITE);
printtxt(0,2, "DE DE' SP ", COLOR_WHITE);
printtxt(0,3, "HL HL' PC ", COLOR_WHITE);
printtxt(0,5, "(BC) (DE) (HL) ", COLOR_WHITE);
printtxt(0,4, "(BC) (DE) (HL) ", COLOR_WHITE);
printtxt(3,0, tohex(z80::getAF(), 4), COLOR_GRAY);
printtxt(11,0, tohex(z80::getAF(true), 4), COLOR_GRAY);
@@ -204,9 +204,19 @@ namespace z80debug
printtxt(11,3, tohex(z80::getHL(true), 4), COLOR_GRAY);
printtxt(19,3, tohex(z80::getPC(), 4), COLOR_GRAY);
printtxt(5,5, tohex(memory[z80::getBC()], 2), COLOR_GRAY);
printtxt(13,5, tohex(memory[z80::getDE()], 2), COLOR_GRAY);
printtxt(21,5, tohex(memory[z80::getHL()], 2), COLOR_GRAY);
printtxt(5,4, tohex(memory[z80::getBC()], 2), COLOR_GRAY);
printtxt(13,4, tohex(memory[z80::getDE()], 2), COLOR_GRAY);
printtxt(21,4, tohex(memory[z80::getHL()], 2), COLOR_GRAY);
const uint8_t flags = (z80::getAF() & 0xFF);
printtxt(0,5,"S", flags&0x80?COLOR_WHITE:COLOR_GRAY);
printtxt(1,5,"Z", flags&0x40?COLOR_WHITE:COLOR_GRAY);
printtxt(2,5,"X", flags&0x20?COLOR_WHITE:COLOR_GRAY);
printtxt(3,5,"H", flags&0x10?COLOR_WHITE:COLOR_GRAY);
printtxt(4,5,"Y", flags&0x08?COLOR_WHITE:COLOR_GRAY);
printtxt(5,5,"P", flags&0x04?COLOR_WHITE:COLOR_GRAY);
printtxt(6,5,"N", flags&0x02?COLOR_WHITE:COLOR_GRAY);
printtxt(7,5,"C", flags&0x01?COLOR_WHITE:COLOR_GRAY);
offset_x = offset_y = 0;
box(46,8,11,12,COLOR_WHITE);
@@ -341,15 +351,19 @@ namespace z80debug
if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) {
z80::step();
} else if (strcmp(cmd, "r")==0 || strcmp(cmd, "run")==0 || strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) {
} else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) {
z80::step();
z80debug::cont();
} else if (strcmp(cmd, "r")==0 || strcmp(cmd, "reset")==0) {
z80::reset(z80::getMem());
for (int i=0; i<65536; ++i) breakpoints[i]=0;
z80debug::refresh();
} else if (strcmp(cmd, "b")==0 || strcmp(cmd, "break")==0) {
getcmd();
int address = getnum(cmd);
if (address<0 || address>65536) { strcpy(console_error, "Illegal break address"); return; }
getcmd();
uint8_t break_type = 0;
uint8_t break_type = 1;
if (cmd[0]!=0) {
if (strcmp(cmd, "x")==0 || strcmp(cmd, "exec")==0) {
break_type = 1;
@@ -361,8 +375,27 @@ namespace z80debug
strcpy(console_error, "Illegal break type");
return;
}
breakpoints[address] |= break_type;
}
breakpoints[address] |= break_type;
} else if (strcmp(cmd, "d")==0 || strcmp(cmd, "delete")==0) {
getcmd();
int address = getnum(cmd);
if (address<0 || address>65536) { strcpy(console_error, "Illegal address"); return; }
getcmd();
uint8_t break_type = 7;
if (cmd[0]!=0) {
if (strcmp(cmd, "x")==0 || strcmp(cmd, "exec")==0) {
break_type = 1;
} else if (strcmp(cmd, "r")==0 || strcmp(cmd, "read")==0) {
break_type = 2;
} else if (strcmp(cmd, "w")==0 || strcmp(cmd, "write")==0) {
break_type = 4;
} else {
strcpy(console_error, "Illegal break type");
return;
}
}
breakpoints[address] &= ~break_type;
} else if (strcmp(cmd, "m")==0 || strcmp(cmd, "mem")==0) {
getcmd();
int address = getnum(cmd);
@@ -371,9 +404,9 @@ namespace z80debug
}
}
const bool isbreak(const uint16_t address)
const bool isbreak(const uint16_t address, const uint8_t type)
{
return (breakpoints[address]&1);
return (breakpoints[address]&type);
}
}

View File

@@ -14,5 +14,5 @@ namespace z80debug
void DeleteCharConsole();
void executeConsole();
const bool isbreak(const uint16_t address);
const bool isbreak(const uint16_t address, const uint8_t type=1);
}

65
zxscreen.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "zxscreen.h"
#include "z80.h"
#include <SDL2/SDL.h>
namespace zxscreen
{
uint32_t palette[16] = {
0x000000, 0x000080, 0x800000, 0x800080, 0x008000, 0x008080, 0x808000, 0x808080,
0x000000, 0x0000FF, 0xFF0000, 0xFF00FF, 0x00FF00, 0x00FFFF, 0xFFFF00, 0xFFFFFF
};
SDL_Window *win = nullptr;
SDL_Renderer *ren = nullptr;
SDL_Texture *tex = nullptr;
void show()
{
if (win) return;
win = SDL_CreateWindow("ZX Spectrum Screen", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 352, 288, SDL_WINDOW_RESIZABLE);
ren = SDL_CreateRenderer(win, -1, 0);
tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 352, 288);
refresh();
}
void refresh()
{
const uint8_t* memory = z80::getMem();
//memory+=0x4000;
Uint32* pixels;
int pitch;
SDL_LockTexture(tex, NULL, (void**)&pixels, &pitch);
// Upper border
for (int i=0; i<352*48;++i) *(pixels++) = palette[7];
// scanlines
for (uint8_t y=0; y<192; ++y)
{
// Left border
for (int j=0;j<48;++j) *(pixels++) = palette[7];
// Actual screen
for (uint8_t x=0;x<32;++x)
{
uint16_t address = 0x4000 | (x&0x1f) | ((y&0x7)<<8) | ((y&0x38)<<2) | ((y&0xc0)<<5);
uint8_t block = memory[address];
for (int i=0;i<8;++i)
{
*(pixels++)=(block&0x80) ? palette[7] : palette[0];
block = block<<1;
}
}
// Right border
for (int j=0;j<48;++j) *(pixels++) = palette[7];
}
// Lower border
for (int i=0; i<352*48;++i) *(pixels++)=palette[7];
SDL_UnlockTexture(tex);
SDL_RenderCopy(ren, tex, NULL, NULL);
SDL_RenderPresent(ren);
}
}

7
zxscreen.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
namespace zxscreen
{
void show();
void refresh();
}