| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
#include "support/fake_devices.h" |
| 21 |
#include "support/harness.h" |
| 22 |
|
| 23 |
#include "memory.h" |
| 24 |
#include "cpu/fake6502.h" |
| 25 |
|
| 26 |
#include <stdio.h> |
| 27 |
|
| 28 |
extern struct regs regs; |
| 29 |
extern uint32_t clockticks6502; |
| 30 |
|
| 31 |
|
| 32 |
#define ADDR_VIA1 0x9F01 |
| 33 |
#define ADDR_VIA2 0x9F11 |
| 34 |
#define ADDR_VERA 0x9F23 |
| 35 |
#define ADDR_MIDI 0x9F61 |
| 36 |
|
| 37 |
static uint8_t |
| 38 |
debug_read(uint16_t addr) |
| 39 |
{ |
| 40 |
return debug_read6502(addr, 0, USE_CURRENT_X16_BANK); |
| 41 |
} |
| 42 |
|
| 43 |
|
| 44 |
|
| 45 |
static void |
| 46 |
test_debug_read_routing(void) |
| 47 |
{ |
| 48 |
const struct { |
| 49 |
uint16_t addr; |
| 50 |
fake_dev_t dev; |
| 51 |
uint8_t reg; |
| 52 |
} cases[] = { |
| 53 |
{ ADDR_VIA1, FAKE_VIA1, 0x1 }, |
| 54 |
{ ADDR_VIA2, FAKE_VIA2, 0x1 }, |
| 55 |
{ ADDR_VERA, FAKE_VERA, 0x3 }, |
| 56 |
}; |
| 57 |
|
| 58 |
for (size_t i = 0; i < sizeof cases / sizeof cases[0]; i++) { |
| 59 |
char label[96]; |
| 60 |
fake_devices_reset(); |
| 61 |
debug_read(cases[i].addr); |
| 62 |
|
| 63 |
const fake_dev_log_t *d = &fake_dev[cases[i].dev]; |
| 64 |
snprintf(label, sizeof label, "$%04X reaches %s", |
| 65 |
cases[i].addr, fake_dev_name(cases[i].dev)); |
| 66 |
check_eq(d->reads, 1, label); |
| 67 |
|
| 68 |
snprintf(label, sizeof label, "$%04X arrives at %s as a debug read", |
| 69 |
cases[i].addr, fake_dev_name(cases[i].dev)); |
| 70 |
check_eq(d->debug_reads, 1, label); |
| 71 |
|
| 72 |
snprintf(label, sizeof label, "$%04X selects register %X", |
| 73 |
cases[i].addr, cases[i].reg); |
| 74 |
check_eq(d->last_reg, cases[i].reg, label); |
| 75 |
} |
| 76 |
} |
| 77 |
|
| 78 |
|
| 79 |
|
| 80 |
static void |
| 81 |
test_real_read_is_not_flagged(void) |
| 82 |
{ |
| 83 |
fake_devices_reset(); |
| 84 |
read6502(ADDR_VERA, 0); |
| 85 |
check_eq(fake_dev[FAKE_VERA].reads, 1, "a real read reaches the device"); |
| 86 |
check_eq(fake_dev[FAKE_VERA].debug_reads, 0, "and is not flagged as a debug read"); |
| 87 |
check_eq(fake_dev[FAKE_VERA].state, 1, "and is allowed to move device state"); |
| 88 |
} |
| 89 |
|
| 90 |
|
| 91 |
|
| 92 |
static void |
| 93 |
test_debug_read_moves_no_state(void) |
| 94 |
{ |
| 95 |
fake_devices_reset(); |
| 96 |
debug_read(ADDR_VERA); |
| 97 |
check_eq(fake_dev[FAKE_VERA].state, 0, "a debug read leaves VERA's state alone"); |
| 98 |
|
| 99 |
fake_devices_reset(); |
| 100 |
debug_read(ADDR_VIA1); |
| 101 |
check_eq(fake_dev[FAKE_VIA1].state, 0, "a debug read leaves VIA1's state alone"); |
| 102 |
|
| 103 |
|
| 104 |
fake_devices_reset(); |
| 105 |
for (int i = 0; i < 16; i++) { |
| 106 |
debug_read(ADDR_VERA); |
| 107 |
} |
| 108 |
check_eq(fake_dev[FAKE_VERA].reads, 16, "sixteen debug reads all arrived"); |
| 109 |
check_eq(fake_dev[FAKE_VERA].state, 0, "and none of them moved anything"); |
| 110 |
} |
| 111 |
|
| 112 |
|
| 113 |
|
| 114 |
|
| 115 |
|
| 116 |
static void |
| 117 |
test_debug_read_costs_nothing(void) |
| 118 |
{ |
| 119 |
|
| 120 |
fake_devices_reset(); |
| 121 |
debug_read(0x9F41); |
| 122 |
check_eq(clockticks6502, 0, "a debug read of $9F41 costs no cycles"); |
| 123 |
|
| 124 |
fake_devices_reset(); |
| 125 |
read6502(0x9F41, 0); |
| 126 |
check_eq(clockticks6502, 3, "and a real read of $9F41 costs three"); |
| 127 |
|
| 128 |
|
| 129 |
fake_devices_reset(); |
| 130 |
debug_read(0x9FA0); |
| 131 |
check_eq(clockticks6502, 0, "a debug read of $9FA0 costs no cycles"); |
| 132 |
|
| 133 |
fake_devices_reset(); |
| 134 |
read6502(0x9FA0, 0); |
| 135 |
check_eq(clockticks6502, 3, "and a real read of $9FA0 costs three"); |
| 136 |
|
| 137 |
|
| 138 |
fake_devices_reset(); |
| 139 |
read6502(0x0200, 0); |
| 140 |
check_eq(clockticks6502, 0, "a real read of RAM costs nothing"); |
| 141 |
} |
| 142 |
|
| 143 |
|
| 144 |
|
| 145 |
|
| 146 |
|
| 147 |
static void |
| 148 |
test_io_page_sweep_is_pure(void) |
| 149 |
{ |
| 150 |
fake_devices_reset(); |
| 151 |
|
| 152 |
for (uint16_t addr = 0x9F00; addr < 0xA000; addr++) { |
| 153 |
debug_read(addr); |
| 154 |
} |
| 155 |
|
| 156 |
check(fake_devices_total_reads() > 0, "the sweep reached at least one device"); |
| 157 |
check_eq(clockticks6502, 0, "sweeping the I/O page costs no cycles"); |
| 158 |
|
| 159 |
|
| 160 |
|
| 161 |
|
| 162 |
uint32_t moved = fake_devices_state_sum() - fake_dev[FAKE_YM].state; |
| 163 |
check_eq(moved, 0, "sweeping the I/O page moves no device state"); |
| 164 |
check(fake_dev[FAKE_YM].state > 0, |
| 165 |
"except the YM, whose read has no debug parameter to honour"); |
| 166 |
} |
| 167 |
|
| 168 |
int |
| 169 |
main(void) |
| 170 |
{ |
| 171 |
test_debug_read_routing(); |
| 172 |
test_real_read_is_not_flagged(); |
| 173 |
test_debug_read_moves_no_state(); |
| 174 |
test_debug_read_costs_nothing(); |
| 175 |
test_io_page_sweep_is_pure(); |
| 176 |
return x16_test_summary("debugon_contract"); |
| 177 |
} |