From bb1aa5958d1b67707dcf0f6b08bfaf0b408bd46e Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Fri, 19 Sep 2025 13:17:14 +1200 Subject: Massive rewrite This commit rewrites the emulator halfway from scratch to make it easier to change and maintain in the future. The emulator core was rewritten to adhere to the released Bedrock specification (earlier versions implemented an older prototype specification, which is no longer relevant). This commit also adds proper support for running multiple concurrent Bedrock instances. This was previously supported in a limited manner for the on-screen keyboard, but now works for any regular program as well, with switching being performed by pressing the L or R bumper buttons. This is disabled by default, as programs will still need to be baked into the emulator and hand-loaded. --- arm9/source/dev.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 arm9/source/dev.c (limited to 'arm9/source/dev.c') diff --git a/arm9/source/dev.c b/arm9/source/dev.c new file mode 100644 index 0000000..1b9a1dc --- /dev/null +++ b/arm9/source/dev.c @@ -0,0 +1,213 @@ +#include "dev.h" + + +// Reset every device on a device bus. +void dev_reset(DeviceBus *d) { + system_reset(&d->system); + memory_reset(&d->memory); + math_reset(&d->math); + clock_reset(&d->clock); + input_reset(&d->input); + screen_reset(&d->screen); + stream_reset(&d->stream); + fs_reset(&d->file); +} + +// Read a byte from a device bus. +u8 dev_read(DeviceBus *d, u8 port) { + switch(port) { + // SYSTEM DEVICE + case 0x02: return d->system.wake; + case 0x08: return readbuf_read(&d->system.name); + case 0x09: return readbuf_read(&d->system.authors); + case 0x0E: return GETH(connected_devices()); + case 0x0F: return GETL(connected_devices()); + // MEMORY DEVICE + case 0x10: return GETH(d->memory.allocated); + case 0x11: return GETL(d->memory.allocated); + case 0x12: return GETH(d->memory.head1.offset); + case 0x13: return GETL(d->memory.head1.offset); + case 0x14: return d->memory.head1.page; + case 0x15: return d->memory.head1.byte; + case 0x16: + case 0x17: return memory_read(&d->memory.head1); + case 0x1A: return GETH(d->memory.head2.offset); + case 0x1B: return GETL(d->memory.head2.offset); + case 0x1C: return d->memory.head2.page; + case 0x1D: return d->memory.head2.byte; + case 0x1E: + case 0x1F: return memory_read(&d->memory.head2); + // MATH DEVICE + case 0x20: return GETH(math_get_x(&d->math)); + case 0x21: return GETL(math_get_x(&d->math)); + case 0x22: return GETH(math_get_y(&d->math)); + case 0x23: return GETL(math_get_y(&d->math)); + case 0x24: return GETH(math_get_r(&d->math)); + case 0x25: return GETL(math_get_r(&d->math)); + case 0x26: return GETH(math_get_t(&d->math)); + case 0x27: return GETL(math_get_t(&d->math)); + case 0x28: return GETHH(math_get_prod(&d->math)); + case 0x29: return GETHL(math_get_prod(&d->math)); + case 0x2A: return GETLH(math_get_prod(&d->math)); + case 0x2B: return GETLL(math_get_prod(&d->math)); + case 0x2C: return GETH(math_get_quot(&d->math)); + case 0x2D: return GETL(math_get_quot(&d->math)); + case 0x2E: return GETH(math_get_rem(&d->math)); + case 0x2F: return GETL(math_get_rem(&d->math)); + // CLOCK DEVICE + case 0x30: return YEAR(get_datetime()); + case 0x31: return MONTH(get_datetime()); + case 0x32: return DAY(get_datetime()); + case 0x33: return HOUR(get_datetime()); + case 0x34: return MINUTE(get_datetime()); + case 0x35: return SECOND(get_datetime()); + case 0x36: clock_uptime_read(&d->clock); + return GETH(d->clock.uptime); + case 0x37: return GETL(d->clock.uptime); + case 0x38: timer_read(&d->clock.t1); + return GETH(d->clock.t1.read); + case 0x39: return GETL(d->clock.t1.read); + case 0x3A: timer_read(&d->clock.t2); + return GETH(d->clock.t2.read); + case 0x3B: return GETL(d->clock.t2.read); + case 0x3C: timer_read(&d->clock.t3); + return GETH(d->clock.t3.read); + case 0x3D: return GETL(d->clock.t3.read); + case 0x3E: timer_read(&d->clock.t4); + return GETH(d->clock.t4.read); + case 0x3F: return GETL(d->clock.t4.read); + // INPUT DEVICE + case 0x40: input_read_x(&d->input); + return GETH(d->input.x_read); + case 0x41: return GETL(d->input.x_read); + case 0x42: input_read_y(&d->input); + return GETH(d->input.y_read); + case 0x43: return GETL(d->input.y_read); + case 0x48: return BOOL(d->input.pointer); + case 0x49: return d->input.pointer << 7; + case 0x4A: return circbuf_read(&d->input.keybuffer); + case 0x4C: return d->input.gamepad; + // SCREEN DEVICE + case 0x50: return GETH(d->screen.x); + case 0x51: return GETL(d->screen.x); + case 0x52: return GETH(d->screen.y); + case 0x53: return GETL(d->screen.y); + case 0x54: return GETH(PIXELS_WIDTH); + case 0x55: return GETL(PIXELS_WIDTH); + case 0x56: return GETH(PIXELS_HEIGHT); + case 0x57: return GETL(PIXELS_HEIGHT); + // FILE DEVICE + case 0x90: return BOOL(fs_get_open(&d->file)); + case 0x91: return BOOL(fs_get_error(&d->file)); + case 0x92: + case 0x93: return fs_read_byte(&d->file); + case 0x94: return pathbuf_read(&d->file.path); + case 0x95: return BOOL(fs_get_type(&d->file)); + case 0x96: return pathbuf_read(&d->file.child_path); + case 0x97: return BOOL(fs_get_child_type(&d->file)); + case 0x98: return GETHH(d->file.address); + case 0x99: return GETHL(d->file.address); + case 0x9A: return GETLH(d->file.address); + case 0x9B: return GETLL(d->file.address); + case 0x9C: fs_calculate_length(&d->file); return GETHH(d->file.length); + case 0x9D: fs_calculate_length(&d->file); return GETHL(d->file.length); + case 0x9E: fs_calculate_length(&d->file); return GETLH(d->file.length); + case 0x9F: fs_calculate_length(&d->file); return GETLL(d->file.length); + // DEFAULT + default: return 0; + } +} + +// Write a byte to a device bus. +Signal dev_write(DeviceBus *d, u8 port, u8 v) { + switch(port) { + // SYSTEM DEVICE + case 0x00: SETH(d->system.sleep, v); break; + case 0x01: SETL(d->system.sleep, v); return SIG_SLEEP; + case 0x03: if (v) { return SIG_FORK; } else { return SIG_RESET; } + case 0x08: readbuf_set_pointer(&d->system.name); break; + case 0x09: readbuf_set_pointer(&d->system.authors); break; + // MEMORY DEVICE + case 0x10: SETH(d->memory.count, v); break; + case 0x11: SETL(d->memory.count, v); memory_allocate(&d->memory); break; + case 0x12: SETH(d->memory.head1.offset, v); + memory_refresh_cache(&d->memory, &d->memory.head1); break; + case 0x13: SETL(d->memory.head1.offset, v); + memory_refresh_cache(&d->memory, &d->memory.head1); break; + case 0x14: d->memory.head1.page = v; + memory_refresh_page(&d->memory.head1); break; + case 0x15: d->memory.head1.byte = v; break; + case 0x16: + case 0x17: memory_write(&d->memory.head1, v); break; + case 0x18: SETH(d->memory.copy, v); break; + case 0x19: SETL(d->memory.copy, v); memory_copy(&d->memory); break; + case 0x1A: SETH(d->memory.head2.offset, v); + memory_refresh_cache(&d->memory, &d->memory.head2); break; + case 0x1B: SETL(d->memory.head2.offset, v); + memory_refresh_cache(&d->memory, &d->memory.head2); break; + case 0x1C: d->memory.head2.page = v; + memory_refresh_page(&d->memory.head2); break; + case 0x1D: d->memory.head2.byte = v; break; + case 0x1E: + case 0x1F: memory_write(&d->memory.head2, v); break; + // MATH DEVICE + case 0x20: math_clear_cartesian(&d->math); SETH(d->math.x, v); break; + case 0x21: math_clear_cartesian(&d->math); SETL(d->math.x, v); break; + case 0x22: math_clear_cartesian(&d->math); SETH(d->math.y, v); break; + case 0x23: math_clear_cartesian(&d->math); SETL(d->math.y, v); break; + case 0x24: math_clear_polar(&d->math); SETH(d->math.r, v); break; + case 0x25: math_clear_polar(&d->math); SETL(d->math.r, v); break; + case 0x26: math_clear_polar(&d->math); SETH(d->math.t, v); break; + case 0x27: math_clear_polar(&d->math); SETL(d->math.t, v); break; + // CLOCK DEVICE + case 0x38: SETH(d->clock.t1.write, v); break; + case 0x39: SETL(d->clock.t1.write, v); timer_write(&d->clock.t1); break; + case 0x3A: SETH(d->clock.t2.write, v); break; + case 0x3B: SETL(d->clock.t2.write, v); timer_write(&d->clock.t2); break; + case 0x3C: SETH(d->clock.t3.write, v); break; + case 0x3D: SETL(d->clock.t3.write, v); timer_write(&d->clock.t3); break; + case 0x3E: SETH(d->clock.t4.write, v); break; + case 0x3F: SETL(d->clock.t4.write, v); timer_write(&d->clock.t4); break; + // INPUT DEVICE + case 0x4A: circbuf_clear(&d->input.keybuffer); + v ? open_keyboard() : close_keyboard(); break; + // SCREEN DEVICE + case 0x50: SETH(d->screen.x, v); break; + case 0x51: SETL(d->screen.x, v); break; + case 0x52: SETH(d->screen.y, v); break; + case 0x53: SETL(d->screen.y, v); break; + case 0x58: SETH(d->screen.colour, v); break; + case 0x59: SETL(d->screen.colour, v); + screen_commit_colour(&d->screen); break; + case 0x5A: SETH(d->screen.selected, v); break; + case 0x5B: SETL(d->screen.selected, v); break; + case 0x5C: + case 0x5D: spritebuf_push(&d->screen.sprite, v); break; + case 0x5E: screen_draw(&d->screen, v); break; + case 0x5F: screen_move_cursor(&d->screen, v); break; + // STREAM DEVICE + case 0x83: stream_end(&d->stream); break; + case 0x86: + case 0x87: stream_write(&d->stream, v); break; + // FILE DEVICE + case 0x90: fs_push_open(&d->file, v); break; + case 0x91: fs_push_action(&d->file, v); break; + case 0x92: + case 0x93: fs_write_byte(&d->file, v); break; + case 0x94: pathbuf_set_pointer(&d->file.path, v); break; + case 0x95: fs_ascend(&d->file); break; + case 0x96: pathbuf_set_pointer(&d->file.child_path, v); break; + case 0x97: fs_descend(&d->file); break; + case 0x98: SETHH(d->file.address_write, v); break; + case 0x99: SETHL(d->file.address_write, v); break; + case 0x9A: SETLH(d->file.address_write, v); break; + case 0x9B: SETLL(d->file.address_write, v); fs_seek(&d->file); break; + case 0x9C: SETHH(d->file.length_write, v); break; + case 0x9D: SETHL(d->file.length_write, v); break; + case 0x9E: SETLH(d->file.length_write, v); break; + case 0x9F: SETLL(d->file.length_write, v); fs_resize(&d->file); break; + // DEFAULT + default: break; + } + return SIG_NONE; +} -- cgit v1.2.3-70-g09d2