| 9120e874 Andy McCall |
1 |
#include "cpu_fixture.h" |
| 2 |
|
| 3 |
#include <string.h> |
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
extern uint32_t clockgoal6502; |
| 9 |
|
| 10 |
uint8_t cpu_mem[CPU_MEM_SIZE]; |
| 11 |
uint32_t cpu_stop_count; |
| 12 |
uint32_t cpu_vector_pulls; |
| 13 |
|
| 14 |
static uint32_t cycles_before_run; |
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
#define DIRTY_PAGE_SHIFT 8 |
| 25 |
#define DIRTY_MAX 256 |
| 26 |
|
| 27 |
static uint32_t dirty_pages[DIRTY_MAX]; |
| 28 |
static int dirty_count; |
| 29 |
static bool dirty_all; |
| 30 |
|
| 31 |
static void |
| 32 |
mark_dirty(uint32_t addr) |
| 33 |
{ |
| 34 |
if (dirty_all || addr < 0x10000) { |
| 35 |
return; |
| 36 |
} |
| 37 |
uint32_t page = addr >> DIRTY_PAGE_SHIFT; |
| 38 |
for (int i = 0; i < dirty_count; i++) { |
| 39 |
if (dirty_pages[i] == page) { |
| 40 |
return; |
| 41 |
} |
| 42 |
} |
| 43 |
if (dirty_count == DIRTY_MAX) { |
| 44 |
dirty_all = true; |
| 45 |
return; |
| 46 |
} |
| 47 |
dirty_pages[dirty_count++] = page; |
| 48 |
} |
| 49 |
|
| 50 |
static void |
| 51 |
clear_memory(void) |
| 52 |
{ |
| 53 |
if (dirty_all) { |
| 54 |
memset(cpu_mem, 0, CPU_MEM_SIZE); |
| 55 |
} else { |
| 56 |
for (int i = 0; i < dirty_count; i++) { |
| 57 |
memset(&cpu_mem[dirty_pages[i] << DIRTY_PAGE_SHIFT], 0, |
| 58 |
1u << DIRTY_PAGE_SHIFT); |
| 59 |
} |
| 60 |
memset(cpu_mem, 0, 0x10000); |
| 61 |
} |
| 62 |
dirty_count = 0; |
| 63 |
dirty_all = false; |
| 64 |
} |
| 65 |
|
| 66 |
void |
| 67 |
cpu_seed(uint32_t addr, uint8_t value) |
| 68 |
{ |
| 69 |
addr &= CPU_MEM_SIZE - 1; |
| 70 |
mark_dirty(addr); |
| 71 |
cpu_mem[addr] = value; |
| 72 |
} |
| 73 |
|
| 74 |
|
| 75 |
|
| 76 |
|
| 77 |
|
| 78 |
|
| 79 |
void (*cpu_bus_read_hook)(uint32_t addr, uint8_t value); |
| 80 |
void (*cpu_bus_write_hook)(uint32_t addr, uint8_t value); |
| 81 |
|
| 82 |
|
| 83 |
|
| 84 |
|
| 85 |
|
| 86 |
static uint32_t |
| 87 |
cpu_bus_address(uint16_t address, uint8_t bank) |
| 88 |
{ |
| 89 |
if (!regs.is65c816) { |
| 90 |
return address; |
| 91 |
} |
| 92 |
return ((uint32_t)bank << 16) | address; |
| 93 |
} |
| 94 |
|
| 95 |
uint8_t |
| 96 |
read6502(uint16_t address, uint8_t bank) |
| 97 |
{ |
| 98 |
uint32_t full = cpu_bus_address(address, bank); |
| 99 |
uint8_t value = cpu_mem[full]; |
| 100 |
if (cpu_bus_read_hook) { |
| 101 |
cpu_bus_read_hook(full, value); |
| 102 |
} |
| 103 |
return value; |
| 104 |
} |
| 105 |
|
| 106 |
void |
| 107 |
write6502(uint16_t address, uint8_t bank, uint8_t value) |
| 108 |
{ |
| 109 |
uint32_t full = cpu_bus_address(address, bank); |
| 110 |
mark_dirty(full); |
| 111 |
cpu_mem[full] = value; |
| 112 |
if (cpu_bus_write_hook) { |
| 113 |
cpu_bus_write_hook(full, value); |
| 114 |
} |
| 115 |
} |
| 116 |
|
| 117 |
|
| 118 |
|
| 119 |
void |
| 120 |
stop6502(uint16_t address, uint8_t bank) |
| 121 |
{ |
| 122 |
(void)address; |
| 123 |
(void)bank; |
| 124 |
cpu_stop_count++; |
| 125 |
} |
| 126 |
|
| 127 |
|
| 128 |
void |
| 129 |
vp6502(void) |
| 130 |
{ |
| 131 |
cpu_vector_pulls++; |
| 132 |
} |
| 133 |
|
| 134 |
uint8_t |
| 135 |
memory_get_ram_bank(void) |
| 136 |
{ |
| 137 |
return 0; |
| 138 |
} |
| 139 |
|
| 140 |
uint8_t |
| 141 |
memory_get_rom_bank(void) |
| 142 |
{ |
| 143 |
return 0; |
| 144 |
} |
| 145 |
|
| 146 |
|
| 147 |
|
| 148 |
const char * |
| 149 |
cpu_mode_name(cpu_mode_t mode) |
| 150 |
{ |
| 151 |
switch (mode) { |
| 152 |
case CPU_65C02: return "65C02"; |
| 153 |
case CPU_816_EMU: return "65C816 emulation"; |
| 154 |
case CPU_816_NATIVE_8: return "65C816 native, 8-bit"; |
| 155 |
case CPU_816_NATIVE_16: return "65C816 native, 16-bit"; |
| 156 |
} |
| 157 |
return "?"; |
| 158 |
} |
| 159 |
|
| 160 |
bool |
| 161 |
cpu_mode_is_16bit(cpu_mode_t mode) |
| 162 |
{ |
| 163 |
return mode == CPU_816_NATIVE_16; |
| 164 |
} |
| 165 |
|
| 166 |
void |
| 167 |
cpu_reset_to(cpu_mode_t mode, uint16_t start) |
| 168 |
{ |
| 169 |
clear_memory(); |
| 170 |
cpu_stop_count = 0; |
| 171 |
cpu_vector_pulls = 0; |
| 172 |
|
| 173 |
|
| 174 |
|
| 175 |
|
| 176 |
|
| 177 |
regs.status = 0; |
| 178 |
|
| 179 |
|
| 180 |
|
| 181 |
cpu_mem[0xFFFC] = (uint8_t)(start & 0xFF); |
| 182 |
cpu_mem[0xFFFD] = (uint8_t)(start >> 8); |
| 183 |
|
| 184 |
reset6502(mode != CPU_65C02); |
| 185 |
|
| 186 |
|
| 187 |
|
| 188 |
switch (mode) { |
| 189 |
case CPU_65C02: |
| 190 |
case CPU_816_EMU: |
| 191 |
break; |
| 192 |
case CPU_816_NATIVE_8: |
| 193 |
regs.e = 0; |
| 194 |
regs.status |= FLAG_MEMORY_WIDTH | FLAG_INDEX_WIDTH; |
| 195 |
break; |
| 196 |
case CPU_816_NATIVE_16: |
| 197 |
regs.e = 0; |
| 198 |
regs.status &= (uint8_t) ~(FLAG_MEMORY_WIDTH | FLAG_INDEX_WIDTH); |
| 199 |
break; |
| 200 |
} |
| 201 |
|
| 202 |
clockticks6502 = 0; |
| 203 |
clockgoal6502 = 0; |
| 204 |
cycles_before_run = 0; |
| 205 |
} |
| 206 |
|
| 207 |
uint16_t |
| 208 |
cpu_load(uint16_t addr, const uint8_t *bytes, uint16_t len) |
| 209 |
{ |
| 210 |
memcpy(&cpu_mem[addr], bytes, len); |
| 211 |
return (uint16_t)(addr + len); |
| 212 |
} |
| 213 |
|
| 214 |
void |
| 215 |
cpu_steps(int count) |
| 216 |
{ |
| 217 |
cycles_before_run = clockticks6502; |
| 218 |
for (int i = 0; i < count; i++) { |
| 219 |
step6502(); |
| 220 |
} |
| 221 |
} |
| 222 |
|
| 223 |
uint32_t |
| 224 |
cpu_step(void) |
| 225 |
{ |
| 226 |
cycles_before_run = clockticks6502; |
| 227 |
step6502(); |
| 228 |
return clockticks6502 - cycles_before_run; |
| 229 |
} |
| 230 |
|
| 231 |
void |
| 232 |
cpu_exec(uint32_t ticks) |
| 233 |
{ |
| 234 |
cycles_before_run = clockticks6502; |
| 235 |
exec6502(ticks); |
| 236 |
} |
| 237 |
|
| 238 |
uint32_t |
| 239 |
cpu_last_cycles(void) |
| 240 |
{ |
| 241 |
return clockticks6502 - cycles_before_run; |
| 242 |
} |
| 243 |
|
| 244 |
|
| 245 |
|
| 246 |
|
| 247 |
|
| 248 |
|
| 249 |
uint16_t |
| 250 |
cpu_a(void) |
| 251 |
{ |
| 252 |
return memory_16bit_width() ? regs.c : regs.a; |
| 253 |
} |
| 254 |
|
| 255 |
uint16_t |
| 256 |
cpu_x(void) |
| 257 |
{ |
| 258 |
return index_16bit_width() ? regs.x : regs.xl; |
| 259 |
} |
| 260 |
|
| 261 |
uint16_t |
| 262 |
cpu_y(void) |
| 263 |
{ |
| 264 |
return index_16bit_width() ? regs.y : regs.yl; |
| 265 |
} |
| 266 |
|
| 267 |
bool |
| 268 |
memory_16bit_width(void) |
| 269 |
{ |
| 270 |
return !regs.e && !(regs.status & FLAG_MEMORY_WIDTH); |
| 271 |
} |
| 272 |
|
| 273 |
bool |
| 274 |
index_16bit_width(void) |
| 275 |
{ |
| 276 |
return !regs.e && !(regs.status & FLAG_INDEX_WIDTH); |
| 277 |
} |