- [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:
26
main.cpp
26
main.cpp
@@ -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
39
z80.cpp
@@ -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
2
z80.h
@@ -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();
|
||||
|
||||
53
z80debug.cpp
53
z80debug.cpp
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
65
zxscreen.cpp
Normal 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
7
zxscreen.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace zxscreen
|
||||
{
|
||||
void show();
|
||||
void refresh();
|
||||
}
|
||||
Reference in New Issue
Block a user