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
1719static Z80 cpu ;
1820static bool pause = true;
@@ -23,26 +25,7 @@ static us_time_t update_interval = CPU_PAUSE_PERIOD;
2325static float perf_value = 0 ;
2426static 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
4730static 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
5949static 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) {
10986void 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
12198void 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-
179128void cpu_int (bool state ) {
180129 z80_int (& cpu , state );
181130}
182131
183132static 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
188141static 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
194151static 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
199160static 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+
210184void cpu_init (CEDAModule * mod ) {
211185 // init mod struct
212186 memset (mod , 0 , sizeof (* mod ));
0 commit comments