Skip to content

Commit c8726cd

Browse files
committed
Use new breakpoint management in CPU module.
This commit both removes the support for the old embedded breakpoint support in the CPU, and uses the new module for breakpoint management.
1 parent c26f627 commit c8726cd

File tree

3 files changed

+47
-94
lines changed

3 files changed

+47
-94
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ set(CORE_SRCS
1818
src/int.c
1919
src/keyboard.c
2020
src/main.c
21+
src/monitor.c
2122
src/charmon.c
2223
src/serial.c
2324
src/sio2.c

src/cpu.c

Lines changed: 46 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
#include "3rd/disassembler.h"
44
#include "bus.h"
55
#include "int.h"
6+
#include "monitor.h"
67
#include "time.h"
78

89
#include <string.h>
910

1011
#include "log.h"
1112

12-
#define CPU_CHUNK_CYCLES 4000
13-
#define CPU_FREQ 4000000 // [Hz]
14-
#define CPU_CHUNK_PERIOD (CPU_CHUNK_CYCLES * 1000L * 1000L / CPU_FREQ) // [us]
15-
#define CPU_PAUSE_PERIOD 20000 // [us] 20 ms => 50 Hz
13+
#define CPU_CHUNK_CYCLES 4000
14+
#define CPU_FREQ 4000000 // [Hz]
15+
#define CPU_CHUNK_PERIOD (CPU_CHUNK_CYCLES * 1000L * 1000L / CPU_FREQ) // [us]
16+
#define CPU_PAUSE_PERIOD 20000 // [us] 20 ms => 50 Hz
17+
#define CPU_INSTRUCTION_NOP (0x00)
1618

1719
static Z80 cpu;
1820
static bool pause = true;
@@ -23,26 +25,7 @@ static us_time_t update_interval = CPU_PAUSE_PERIOD;
2325
static float perf_value = 0;
2426
static const char *perf_unit = "ips";
2527

26-
#define CPU_BREAKPOINTS 8
27-
static CpuBreakpoint breakpoints[CPU_BREAKPOINTS] = {0};
28-
static unsigned int valid_breakpoints = 0;
29-
30-
/**
31-
* @brief Check if a breakpoint has been hit.
32-
*
33-
* @return true if a breakpoint has been hit, false otherwise.
34-
*/
35-
static bool cpu_checkBreakpoints(void) {
36-
for (size_t i = 0; i < CPU_BREAKPOINTS; ++i) {
37-
if (!breakpoints[i].valid)
38-
continue;
39-
40-
if (cpu.pc.uint16_value == breakpoints[i].address)
41-
return true;
42-
}
43-
44-
return false;
45-
}
28+
static uint8_t cpu_hook(void *context, zuint16 address);
4629

4730
static zuint8 cpu_fetch_opcode(void *context, zuint16 address) {
4831
(void)context;
@@ -53,7 +36,14 @@ static zuint8 cpu_fetch_opcode(void *context, zuint16 address) {
5336
disassemble(blob, address, mnemonic, 256);
5437
LOG_DEBUG("%s: [%04x]:\t%s\n", __func__, address, mnemonic);
5538
});
56-
return bus_mem_read(address);
39+
zuint8 data = 0x00;
40+
if (monitor_checkBreakpoint(address)) {
41+
cpu.hook = cpu_hook;
42+
data = Z80_HOOK;
43+
} else {
44+
data = bus_mem_read(address);
45+
}
46+
return data;
5747
}
5848

5949
static void cpu_performance(float *value, const char **unit) {
@@ -82,20 +72,7 @@ static void cpu_poll(void) {
8272
if (pause)
8373
return;
8474

85-
// check if a breakpoint has been hit
86-
if (valid_breakpoints != 0) {
87-
if (cpu_checkBreakpoints()) {
88-
cpu_pause(true);
89-
// TODO(giomba): signal the user that the breakpoint has been hit
90-
return;
91-
}
92-
}
93-
94-
// if there are breakpoints, step one instruction at a time
95-
const unsigned int requested_cycles =
96-
(valid_breakpoints == 0) ? CPU_CHUNK_CYCLES : 1;
97-
98-
cycles += z80_run(&cpu, requested_cycles);
75+
cycles += z80_run(&cpu, CPU_CHUNK_CYCLES);
9976
cpu_update_performance();
10077
}
10178

@@ -109,13 +86,13 @@ static long cpu_remaining(void) {
10986
void cpu_pause(bool enable) {
11087
pause = enable;
11188

112-
if (pause) {
89+
if (!pause)
90+
cpu.hook = NULL;
91+
92+
if (pause)
11393
update_interval = CPU_PAUSE_PERIOD;
114-
} else if (valid_breakpoints > 0) {
115-
update_interval = 0;
116-
} else {
94+
else
11795
update_interval = CPU_CHUNK_PERIOD;
118-
}
11996
}
12097

12198
void cpu_reg(CpuRegs *regs) {
@@ -148,56 +125,44 @@ void cpu_goto(zuint16 address) {
148125
cpu.pc.uint16_value = address;
149126
}
150127

151-
bool cpu_addBreakpoint(zuint16 address) {
152-
// find free breakpoint slot (if any) and add it
153-
for (size_t i = 0; i < CPU_BREAKPOINTS; ++i) {
154-
if (!breakpoints[i].valid) {
155-
breakpoints[i].address = address;
156-
breakpoints[i].valid = true;
157-
++valid_breakpoints;
158-
return true;
159-
}
160-
}
161-
162-
return false;
163-
}
164-
165-
bool cpu_deleteBreakpoint(unsigned int index) {
166-
if (index >= CPU_BREAKPOINTS)
167-
return false;
168-
169-
breakpoints[index].valid = false;
170-
--valid_breakpoints;
171-
return true;
172-
}
173-
174-
size_t cpu_getBreakpoints(CpuBreakpoint *vector[]) {
175-
*vector = breakpoints;
176-
return CPU_BREAKPOINTS;
177-
}
178-
179128
void cpu_int(bool state) {
180129
z80_int(&cpu, state);
181130
}
182131

183132
static uint8_t cpu_mem_read(void *context, zuint16 address) {
184133
(void)context;
134+
if (monitor_checkReadWatchpoint(address)) {
135+
z80_break(&cpu);
136+
cpu_pause(true);
137+
}
185138
return bus_mem_read(address);
186139
}
187140

188141
static void cpu_mem_write(void *context, ceda_address_t address,
189142
uint8_t value) {
190143
(void)context;
144+
if (monitor_checkWriteWatchpoint(address, value)) {
145+
z80_break(&cpu);
146+
cpu_pause(true);
147+
}
191148
bus_mem_write(address, value);
192149
}
193150

194151
static uint8_t cpu_io_in(void *context, zuint16 address) {
195152
(void)context;
153+
if (monitor_checkInWatchpoint(address)) {
154+
z80_break(&cpu);
155+
cpu_pause(true);
156+
}
196157
return bus_io_in((ceda_ioaddr_t)address);
197158
}
198159

199160
static void cpu_io_out(void *context, zuint16 address, zuint8 value) {
200161
(void)context;
162+
if (monitor_checkOutWatchpoint(address, value)) {
163+
z80_break(&cpu);
164+
cpu_pause(true);
165+
}
201166
return bus_io_out((ceda_ioaddr_t)address, value);
202167
}
203168

@@ -207,6 +172,15 @@ static uint8_t cpu_int_read(void *context, zuint16 address) {
207172
return int_pop();
208173
}
209174

175+
static uint8_t cpu_hook(void *context, zuint16 address) {
176+
(void)context;
177+
(void)address;
178+
179+
z80_break(&cpu);
180+
cpu_pause(true);
181+
return Z80_HOOK;
182+
}
183+
210184
void cpu_init(CEDAModule *mod) {
211185
// init mod struct
212186
memset(mod, 0, sizeof(*mod));

src/cpu.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,6 @@ typedef struct CpuRegs {
2626
zuint16 iy;
2727
} CpuRegs;
2828

29-
typedef struct CpuBreakpoint {
30-
bool valid;
31-
zuint16 address;
32-
} CpuBreakpoint;
33-
3429
void cpu_init(CEDAModule *mod);
3530

3631
void cpu_pause(bool enable);
@@ -44,23 +39,6 @@ void cpu_step(void);
4439
*/
4540
void cpu_goto(zuint16 address);
4641

47-
/**
48-
* @brief Add a cpu breakpoint.
49-
*
50-
* The breakpoint will pause the cpu when the cpu tries to fetch the instruction
51-
* located at the given address.
52-
*
53-
* There is a finite number of breakpoints which can be set.
54-
*
55-
* @param address Address of the instruction which must trigger the breakpoint.
56-
* @return true if the breakpoint has been set, false otherwise.
57-
*/
58-
bool cpu_addBreakpoint(zuint16 address);
59-
60-
bool cpu_deleteBreakpoint(unsigned int index);
61-
62-
size_t cpu_getBreakpoints(CpuBreakpoint *v[]);
63-
6442
/**
6543
* @brief Set the interrupt line of the Z80 CPU.
6644
*

0 commit comments

Comments
 (0)