diff --git a/client.py b/client.py index 59d58e6..db19a3d 100644 --- a/client.py +++ b/client.py @@ -2,10 +2,12 @@ import serial import struct import sys import time +import fcntl +import os #dest = 0xac21_0000 -dest = 0xac02_0000 -#dest = 0xac01_0000 +#dest = 0xac02_0000 +dest = 0xac01_0000 ret = [] @@ -71,7 +73,7 @@ def start_data(ser, b): size = len(b) args = struct.pack("> 2; // 0b1111 - break; - case 2: - dst[y_ix - i * 6 + 4] |= (src[(c - ' ') * 8 + i] & 0b1111) << 4; - dst[y_ix - i * 6 + 3] = src[(c - ' ') * 8 + i] >> 4; // 0b11 - break; - case 3: - dst[y_ix - i * 6 + 3] |= src[(c - ' ') * 8 + i] << 2; - break; - case 4: - dst[y_ix - i * 6 + 2] = src[(c - ' ') * 8 + i]; - break; - case 5: - dst[y_ix - i * 6 + 2] |= (src[(c - ' ') * 8 + i] & 0b11) << 6; - dst[y_ix - i * 6 + 1] = src[(c - ' ') * 8 + i] >> 2; // 0b1111 - break; - case 6: - dst[y_ix - i * 6 + 1] |= (src[(c - ' ') * 8 + i] & 0b1111) << 4; - dst[y_ix - i * 6 + 0] = src[(c - ' ') * 8 + i] >> 4; // 0b11 - break; - case 7: - dst[y_ix - i * 6 + 0] |= src[(c - ' ') * 8 + i] << 2; - break; - } - } -} - -void make_vmu_framebuffer(uint32_t * buf) -{ - const uint8_t * src = reinterpret_cast(&_binary_font_portfolio_6x8); - uint8_t * dst = reinterpret_cast(buf); - - for (int i = 0; i < vmu_display::framebuffer_size; i++) { - dst[i] = 0; - } const char * s = " very " " funneh " @@ -75,7 +24,7 @@ void make_vmu_framebuffer(uint32_t * buf) for (int i = 0; i < 8 * 4; i++) { int x = i % 8; int y = i / 8; - render_glyph(dst, src, s[i], x, y); + renderer.glyph(s[i], x, y); } } @@ -89,6 +38,8 @@ inline void copy(T * dst, const T * src, const int32_t n) noexcept } } +static uint8_t * framebuffer; + void send_vmu_framebuffer(uint8_t port, uint8_t lm) { uint32_t send_buf[1024] __attribute__((aligned(32))); @@ -106,7 +57,7 @@ void send_vmu_framebuffer(uint8_t port, uint8_t lm) = writer.append_command(host_port_select, destination_ap, true, // end_flag - vmu_display::framebuffer_size, // send_trailing + maple::display::vmu::framebuffer_size, // send_trailing 0 // recv_trailing ); auto& data_fields = host_command->bus_data.data_fields; @@ -115,7 +66,9 @@ void send_vmu_framebuffer(uint8_t port, uint8_t lm) data_fields.phase = 0; data_fields.block_number = std::byteswap(0x0000); - copy(data_fields.written_data, reinterpret_cast(vmu_framebuffer), vmu_display::framebuffer_size); + copy(data_fields.written_data, + reinterpret_cast(framebuffer), + maple::display::vmu::framebuffer_size); maple::dma_start(send_buf, writer.send_offset, recv_buf, writer.recv_offset); @@ -235,7 +188,10 @@ void main() { serial::init(4); - make_vmu_framebuffer(vmu_framebuffer); + const uint8_t * font = reinterpret_cast(&_binary_font_portfolio_6x8); + auto renderer = maple::display::font_renderer(font); + make_vmu_framebuffer(renderer); + framebuffer = renderer.fb; do_device_request(); diff --git a/example/serial_dma.cpp b/example/serial_dma.cpp new file mode 100644 index 0000000..7125f7a --- /dev/null +++ b/example/serial_dma.cpp @@ -0,0 +1,49 @@ +#include "sh7091/sh7091.hpp" +#include "sh7091/serial.hpp" +#include "sh7091/serial_dma.hpp" + +int main() +{ + serial::init(4); + + uint8_t buf[4] __attribute__((aligned(32))) = {0}; + uint8_t * bufi = + reinterpret_cast(0xa000'0000 + | reinterpret_cast(buf)); + + for (int i = 0; i < 10000; i++) { + asm volatile ("nop;"); + } + + serial::integer(sh7091.DMAC.CHCR1); + serial::integer(sh7091.DMAC.DMAOR); + + serial::string("DAR\n"); + + sh7091.DMAC.DAR1 = reinterpret_cast(&bufi[0]); + + serial::integer(sh7091.DMAC.DAR1); + serial::integer(reinterpret_cast(&bufi[0])); + + + serial::string("wait\n"); + + while (true) { + serial::recv_dma(&bufi[0], 4); + + while ((sh7091.DMAC.CHCR1 & dmac::chcr::te::transfers_completed) == 0) { + }; + + for (uint32_t i = 0; i < 4; i++) { + serial::hexlify(bufi[i]); + serial::character(' '); + } + serial::string("end\n"); + serial::integer(sh7091.DMAC.DAR1); + + while ((sh7091.SCIF.SCFSR2 & 0x60) != 0x60) {} + for (int i = 0; i < 1000000; i++) { + asm volatile ("nop;"); + } + } +} diff --git a/example/serial_transfer.cpp b/example/serial_transfer.cpp index f0d2a38..32bfa67 100644 --- a/example/serial_transfer.cpp +++ b/example/serial_transfer.cpp @@ -1,24 +1,300 @@ #include +#include #include "sh7091/sh7091.hpp" #include "sh7091/sh7091_bits.hpp" #include "sh7091/serial.hpp" +#include "maple/maple.hpp" +#include "maple/maple_bus_commands.hpp" +#include "maple/maple_bus_bits.hpp" +#include "maple/maple_host_command_writer.hpp" +#include "maple/maple_port.hpp" +#include "maple/maple_display.hpp" + #include "serial_load.hpp" +extern uint32_t _binary_font_portfolio_6x8 __asm("_binary_font_portfolio_6x8_portfolio_6x8_data_start"); + +template +inline void copy(T * dst, const T * src, const int32_t n) noexcept +{ + int32_t n_t = n / (sizeof (T)); + while (n_t > 0) { + *dst++ = *src++; + n_t--; + } +} + +static uint8_t * framebuffer; + +static uint32_t send_buf[1024 / 4] __attribute__((aligned(32))); +static uint32_t recv_buf[1024 / 4] __attribute__((aligned(32))); + +enum struct step { + IDLE = 0, + DEVICE_STATUS, + EXTENSION_DEVICE_STATUS, + EXTENSION_DEVICE_REPLY, +}; + +struct maple_display_poll_state { + bool want_start; + enum step step; + struct { + uint8_t ap__lm; + } port[4]; +}; + +void send_vmu_framebuffer(maple::host_command_writer& writer, uint8_t port, uint8_t lm) +{ + using command_type = maple::block_write; + using response_type = maple::device_reply; + + uint32_t host_port_select = host_instruction_port_select(port); + uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; + + auto [host_command, host_response] + = writer.append_command(host_port_select, + destination_ap, + false, // end_flag + maple::display::vmu::framebuffer_size, // send_trailing + 0 // recv_trailing + ); + auto& data_fields = host_command->bus_data.data_fields; + data_fields.function_type = std::byteswap(function_type::bw_lcd); + data_fields.pt = 0; + data_fields.phase = 0; + data_fields.block_number = std::byteswap(0x0000); + + copy(data_fields.written_data, + reinterpret_cast(framebuffer), + maple::display::vmu::framebuffer_size); +} + +void recv_extension_device_status(struct maple_display_poll_state &state) +{ + auto writer = maple::host_command_writer(send_buf, recv_buf); + + using response_type = maple::host_response; + auto host_response = reinterpret_cast(recv_buf); + + uint32_t last_send_offset = 0; + + int response_index = 0; + for (int port = 0; port < 4; port++) { + uint32_t bit = ap::lm_bus::_0; + uint8_t lm = state.port[port].ap__lm; + + for (int i = 0; i < 5; i++) { + if (lm == 0) + break; + + if ((lm & bit) == 0) + continue; + lm &= ~bit; + + auto& bus_data = host_response[response_index++].bus_data; + auto& data_fields = bus_data.data_fields; + if ((bus_data.command_code == maple::device_status::command_code) && + (std::byteswap(data_fields.device_id.ft) & function_type::bw_lcd)) { + + last_send_offset = writer.send_offset; + send_vmu_framebuffer(writer, port, bit); + } else { + // this extension device is not a bw_lcd; remove it + state.port[port].ap__lm &= ~bit; + } + bit <<= 1; + } + } + + { + using command_type = maple::host_command::data_fields>; + auto host_command = reinterpret_cast(&send_buf[last_send_offset / 4]); + host_command->host_instruction |= host_instruction::end_flag; + + maple::dma_start(send_buf, writer.send_offset, + recv_buf, writer.recv_offset); + } +} + +void send_extension_device_request(maple::host_command_writer& writer, uint8_t port, uint8_t lm) +{ + uint32_t host_port_select = host_instruction_port_select(port); + uint32_t destination_ap = ap_port_select(port) | ap::de::expansion_device | lm; + + using command_type = maple::device_request; + using response_type = maple::device_status; + + writer.append_command(host_port_select, + destination_ap, + false); // end_flag +} + +typedef void (* func_t)(maple::host_command_writer& writer, uint8_t port, uint8_t lm); +void do_lm_requests(maple::host_command_writer& writer, uint8_t port, uint8_t lm, func_t func) +{ + uint32_t bit = ap::lm_bus::_0; + for (int i = 0; i < 5; i++) { + if (lm & bit) { + lm &= ~bit; + func(writer, port, bit); + } + bit <<= 1; + } +} + +void recv_device_status(struct maple_display_poll_state &state) +{ + auto writer = maple::host_command_writer(send_buf, recv_buf); + + using response_type = maple::host_response; + auto host_response = reinterpret_cast(recv_buf); + + for (int port = 0; port < 4; port++) { + auto& bus_data = host_response[port].bus_data; + if (bus_data.command_code != maple::device_status::command_code) { + state.port[port].ap__lm = 0; + } else { + auto& data_fields = bus_data.data_fields; + + uint8_t lm = bus_data.source_ap & ap::lm_bus::bit_mask; + state.port[port].ap__lm = lm; + do_lm_requests(writer, port, lm, &send_extension_device_request); + } + } + + maple::dma_start(send_buf, writer.send_offset, + recv_buf, writer.recv_offset); +} + +void send_device_request() +{ + auto writer = maple::host_command_writer(send_buf, recv_buf); + + using command_type = maple::device_request; + using response_type = maple::device_status; + + writer.append_command_all_ports(); + + maple::dma_start(send_buf, writer.send_offset, + recv_buf, writer.recv_offset); +} + +void handle_maple(struct maple_display_poll_state& state) +{ + switch (state.step) { + case step::IDLE: + if (state.want_start) { + // always send to all ports + send_device_request(); + state.step = step::DEVICE_STATUS; + state.want_start = 0; + } + break; + case step::DEVICE_STATUS: + if (maple::dma_poll_complete()) { + recv_device_status(state); + state.step = step::EXTENSION_DEVICE_STATUS; + } + break; + case step::EXTENSION_DEVICE_STATUS: + if (maple::dma_poll_complete()) { + recv_extension_device_status(state); + state.step = step::EXTENSION_DEVICE_REPLY; + } + break; + case step::EXTENSION_DEVICE_REPLY: + if (maple::dma_poll_complete()) { + state.step = step::IDLE; + } + break; + } +} + +void render_glyphs(maple::display::font_renderer& renderer, char * s) +{ + for (int i = 0; i < 8 * 4; i++) { + int x = i % 8; + int y = i / 8; + renderer.glyph(s[i], x, y); + } +} + +void render_serial_state(maple::display::font_renderer& renderer, char * s, const char * msg) +{ + bool end = false; + for (int i = 0; i < 8; i++) { + if (end || msg[i] == 0) { + s[0 + i] = ' '; + end = true; + } else { + s[0 + i] = msg[i]; + } + } + char num_buf[8]; + string::hex(num_buf, 8, sh7091.SCIF.SCFSR2); + for (int i = 0; i < 8; i++) s[8 + i] = num_buf[i]; + string::hex(num_buf, 8, sh7091.SCIF.SCFDR2); + for (int i = 0; i < 8; i++) s[16 + i] = num_buf[i]; + render_glyphs(renderer, s); +} + void main() __attribute__((section(".text.main"))); void main() { - serial::init(12); - load_init(); + serial::init(0); + + struct maple_display_poll_state state = {0}; + const uint8_t * font = reinterpret_cast(&_binary_font_portfolio_6x8); + auto renderer = maple::display::font_renderer(font); + framebuffer = renderer.fb; + char s[33] = + "1562500 " // 0 + " " // 8 + " " // 16 + " "; // 24 + render_glyphs(renderer, s); + state.want_start = 1; + + serial_load::init(); + + // reset serial status + sh7091.SCIF.SCFSR2 = 0; + // reset line status + sh7091.SCIF.SCLSR2 = 0; + + serial::string("ready\n"); while (1) { using namespace scif; - while ((scfdr2::receive_data_bytes(sh7091.SCIF.SCFDR2)) > 0) { + const uint16_t scfsr2 = sh7091.SCIF.SCFSR2; + if (scfsr2 & scfsr2::brk::bit_mask) { + render_serial_state(renderer, s, "brk"); + // clear framing error and break + } else if (scfsr2 & scfsr2::er::bit_mask) { + render_serial_state(renderer, s, "er"); + } else if (scfsr2 & scfsr2::dr::bit_mask) { + render_serial_state(renderer, s, "dr"); + } else if (sh7091.SCIF.SCLSR2 & sclsr2::orer::bit_mask) { + render_serial_state(renderer, s, "orer"); + } else if (scfsr2 & scfsr2::rdf::bit_mask) { + render_serial_state(renderer, s, "rdf"); const uint8_t c = sh7091.SCIF.SCFRDR2; - load_recv(c); + serial_load::recv(c); + } else { + render_serial_state(renderer, s, "idle"); + } + state.want_start = 1; + + handle_maple(state); + + uint16_t error_bits = scfsr2::er::bit_mask | scfsr2::brk::bit_mask; + if (sh7091.SCIF.SCFSR2 & error_bits) { + sh7091.SCIF.SCFSR2 = ~error_bits; } } } diff --git a/loader.lds b/loader.lds index 3041900..ce467d1 100644 --- a/loader.lds +++ b/loader.lds @@ -1,9 +1,9 @@ OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") MEMORY { - p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000 + p1ram : ORIGIN = 0xac005000, LENGTH = 0x0000 p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000 - ldram : ORIGIN = 0x8cfff000, LENGTH = 0x1000 + ldram : ORIGIN = 0xacffe000, LENGTH = 0x2000 } SECTIONS { @@ -12,41 +12,42 @@ SECTIONS .text.startup ALIGN(4) : SUBALIGN(4) { KEEP(*(.text.start)) - *(.text.startup.*) + KEEP(*(.text.startup.*)) . = ALIGN(4); - } > p2ram AT> p2ram + } > p2ram .ctors ALIGN(4) : SUBALIGN(4) { KEEP(*(.ctors)) KEEP(*(.ctors.*)) . = ALIGN(4); - } > p2ram AT> p2ram + } > p2ram . = ORIGIN(ldram); .text ALIGN(4) : SUBALIGN(4) { + KEEP(*(.text.main)) *(.text.*) *(.text) . = ALIGN(4); } > ldram AT> p2ram - .data ALIGN(4) : SUBALIGN(4) + .data ALIGN(4) : { *(.data) *(.data.*) . = ALIGN(4); } > ldram AT> p2ram - .rodata ALIGN(4) : SUBALIGN(4) + .rodata ALIGN(4) : { *(.rodata) *(.rodata.*) . = ALIGN(4); } > ldram AT> p2ram - .bss ALIGN(4) (NOLOAD) : SUBALIGN(4) + .bss ALIGN(4) (NOLOAD) : { *(.bss) *(.bss.*) @@ -56,15 +57,17 @@ SECTIONS .text.vbr ALIGN(4) : SUBALIGN(4) { + /* KEEP(*(.vbr.100)) . = ALIGN(0x300); KEEP(*(.vbr.400)) . = ALIGN(0x200); KEEP(*(.vbr.600)) - } > p1ram + */ + } > p2ram INCLUDE "debug.lds" } -__stack_reservation = 0x0000; +__stack_reservation = 0x0; INCLUDE "symbols.lds" INCLUDE "addresses.lds" diff --git a/maple/maple.cpp b/maple/maple.cpp index e0ff3e8..d77a3e4 100644 --- a/maple/maple.cpp +++ b/maple/maple.cpp @@ -145,6 +145,22 @@ static inline void _dma_start(const uint32_t * command_buf) maple_if.MDST = mdst::start_status::start; } +void dma_wait_complete() +{ + // wait for maple DMA completion + while ((system.ISTNRM & istnrm::end_of_dma_maple_dma) == 0); + system.ISTNRM = istnrm::end_of_dma_maple_dma; +} + +bool dma_poll_complete() +{ + bool complete = (system.ISTNRM & istnrm::end_of_dma_maple_dma) != 0; + if (complete) { + system.ISTNRM = istnrm::end_of_dma_maple_dma; + } + return complete; +} + void dma_start(const uint32_t * send_buf, const uint32_t send_size, const uint32_t * recv_buf, @@ -169,10 +185,6 @@ void dma_start(const uint32_t * send_buf, : "r" (reinterpret_cast(&recv_buf[(32 * i) / 4])) // input ); } - - // wait for maple DMA completion - while ((system.ISTNRM & istnrm::end_of_dma_maple_dma) == 0); - system.ISTNRM = istnrm::end_of_dma_maple_dma; } // wait for completion diff --git a/maple/maple.hpp b/maple/maple.hpp index c099170..7b92600 100644 --- a/maple/maple.hpp +++ b/maple/maple.hpp @@ -34,6 +34,10 @@ struct host_response { }; static_assert((sizeof (host_response)) == align_32byte((sizeof (host_response)))); +void dma_wait_complete(); + +bool dma_poll_complete(); + void dma_start(uint32_t const * const command_buf, const uint32_t command_size, uint32_t const * const receive_buf, diff --git a/maple/maple_display.hpp b/maple/maple_display.hpp new file mode 100644 index 0000000..062e5fa --- /dev/null +++ b/maple/maple_display.hpp @@ -0,0 +1,61 @@ +namespace maple { + +namespace display { + +namespace vmu { +constexpr int32_t width = 48; +constexpr int32_t height = 32; +constexpr int32_t pixels_per_byte = 8; +constexpr int32_t framebuffer_size = width * height / pixels_per_byte; +} + +struct font_renderer { + // 6x8 px font assumed + uint8_t const * const font; + uint8_t fb[vmu::framebuffer_size]; + + constexpr font_renderer(uint8_t const * const font) + : font(font) + { } + + constexpr inline void glyph(uint8_t c, int x, int y) + { + int y_ix = 186 - (y * 6 * 8); + for (int i = 0; i < 8; i++) { + switch (x) { + case 0: + fb[y_ix - i * 6 + 5] = font[(c - ' ') * 8 + i]; + break; + case 1: + fb[y_ix - i * 6 + 5] |= (font[(c - ' ') * 8 + i] & 0b11) << 6; + fb[y_ix - i * 6 + 4] = font[(c - ' ') * 8 + i] >> 2; // 0b1111 + break; + case 2: + fb[y_ix - i * 6 + 4] |= (font[(c - ' ') * 8 + i] & 0b1111) << 4; + fb[y_ix - i * 6 + 3] = font[(c - ' ') * 8 + i] >> 4; // 0b11 + break; + case 3: + fb[y_ix - i * 6 + 3] |= font[(c - ' ') * 8 + i] << 2; + break; + case 4: + fb[y_ix - i * 6 + 2] = font[(c - ' ') * 8 + i]; + break; + case 5: + fb[y_ix - i * 6 + 2] |= (font[(c - ' ') * 8 + i] & 0b11) << 6; + fb[y_ix - i * 6 + 1] = font[(c - ' ') * 8 + i] >> 2; // 0b1111 + break; + case 6: + fb[y_ix - i * 6 + 1] |= (font[(c - ' ') * 8 + i] & 0b1111) << 4; + fb[y_ix - i * 6 + 0] = font[(c - ' ') * 8 + i] >> 4; // 0b11 + break; + case 7: + fb[y_ix - i * 6 + 0] |= font[(c - ' ') * 8 + i] << 2; + break; + } + } + } + +}; + +} // namespace display +} // namespace maple diff --git a/regs/sh7091_bits.csv b/regs/sh7091_bits.csv index f165e1c..db82ffd 100644 --- a/regs/sh7091_bits.csv +++ b/regs/sh7091_bits.csv @@ -291,3 +291,5 @@ "SCIF","SCSPTR2","SPB2IO","1","spb2dt_is_output_to_txd2","1",, "SCIF","SCSPTR2","SPB2DT","0","input_output_data_is_low_level","0",, "SCIF","SCSPTR2","SPB2DT","0","input_output_data_is_high_level","1",, +,,,,,,, +"SCIF","SCLSR2","ORER","0","overrun_error_occured","1",, diff --git a/regs/sh7091_bits.ods b/regs/sh7091_bits.ods index 747ad83..e15da92 100644 Binary files a/regs/sh7091_bits.ods and b/regs/sh7091_bits.ods differ diff --git a/serial_load.cpp b/serial_load.cpp index 9cad9cb..9bc6d3f 100644 --- a/serial_load.cpp +++ b/serial_load.cpp @@ -1,33 +1,13 @@ #include -#include "sh7091/sh7091.hpp" -#include "sh7091/sh7091_bits.hpp" #include "sh7091/serial.hpp" -#include "holly/holly.hpp" +#include "serial_load.hpp" -enum load_command { - CMD_NONE, - CMD_DATA, // DATA 0000 0000 {data} - CMD_JUMP, // JUMP 0000 - CMD_RATE, // RATE 0000 -}; +namespace serial_load { -struct load_state { - union { - uint8_t buf[12]; - struct { - uint8_t cmd[4]; - uint32_t addr1; - uint32_t addr2; - }; - }; - uint32_t len; - enum load_command command; -}; +struct state state; -static struct load_state state; - -void move(void *dst, const void *src, size_t n) +static void move(void *dst, const void *src, uint32_t n) { uint8_t * d = reinterpret_cast(dst); const uint8_t * s = reinterpret_cast(src); @@ -40,22 +20,13 @@ void move(void *dst, const void *src, size_t n) } } -void load_init() +void init() { state.len = 0; state.command = CMD_NONE; } -void debug(const char * s) -{ - char c; - while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0); - while ((c = *s++)) { - sh7091.SCIF.SCFTDR2 = (uint8_t)c; - } -} - -void jump_to_func(const uint32_t addr) +static void jump_to_func(const uint32_t addr) { serial::string("jump to: "); serial::integer(addr); @@ -73,7 +44,7 @@ void jump_to_func(const uint32_t addr) // restore our stack } -void load_recv(uint8_t c) +void recv(uint8_t c) { while (1) { switch (state.command) { @@ -87,7 +58,7 @@ void load_recv(uint8_t c) if (state.len < 12) { return; } else { - debug("data\n"); + serial::string("data"); state.command = CMD_DATA; return; } @@ -98,7 +69,7 @@ void load_recv(uint8_t c) if (state.len < 8) { return; } else { - debug("jump\n"); + serial::string("jump"); state.command = CMD_JUMP; } } else if (state.buf[0] == 'R' && @@ -108,7 +79,7 @@ void load_recv(uint8_t c) if (state.len < 8) { return; } else { - debug("rate\n"); + serial::string("rate"); state.command = CMD_RATE; } } else { @@ -124,7 +95,7 @@ void load_recv(uint8_t c) uint32_t * size = &state.addr1; uint8_t * dest = reinterpret_cast(state.addr2); if (*size > 0) { - sh7091.SCIF.SCFTDR2 = c; + serial::character(c); // write c to dest *dest = c; @@ -135,7 +106,7 @@ void load_recv(uint8_t c) if (*size == 0) { state.len = 0; state.command = CMD_NONE; - debug("next\n"); + serial::string("next"); } return; break; @@ -144,21 +115,17 @@ void load_recv(uint8_t c) // jump state.len = 0; state.command = CMD_NONE; - debug("prejump\n"); - holly.VO_BORDER_COL = (31 << 11); jump_to_func(state.addr1); - holly.VO_BORDER_COL = (63 << 5) | (31 << 0); - debug("postjump\n"); return; break; case CMD_RATE: state.len = 0; state.command = CMD_NONE; - debug("prerate\n"); serial::init(state.addr1 & 0xff); - debug("postrate\n"); return; break; } } } + +} diff --git a/serial_load.hpp b/serial_load.hpp index 9ed6ce7..26c7d60 100644 --- a/serial_load.hpp +++ b/serial_load.hpp @@ -1,4 +1,30 @@ #pragma once -void load_init(); -void load_recv(uint8_t c); +namespace serial_load { + +void init(); +void recv(uint8_t c); + +enum command { + CMD_NONE, + CMD_DATA, // DATA 0000 0000 {data} + CMD_JUMP, // JUMP 0000 + CMD_RATE, // RATE 0000 +}; + +struct state { + union { + uint8_t buf[12]; + struct { + uint8_t cmd[4]; + uint32_t addr1; + uint32_t addr2; + }; + }; + uint32_t len; + enum command command; +}; + +extern struct state state; + +} diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index 7e122e8..867031e 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -37,7 +37,8 @@ void init(uint8_t bit_rate) sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte | scfcr2::ttrg::trigger_on_8_bytes - | scfcr2::mce::modem_signals_enabled; + //| scfcr2::mce::modem_signals_enabled + ; sh7091.SCIF.SCSMR2 = scsmr2::chr::_8_bit_data | scsmr2::pe::parity_disabled @@ -67,12 +68,10 @@ void init(uint8_t bit_rate) void character(const char c) { using namespace scif; - // wait for transmit fifo to become empty + // wait for transmit fifo to become partially empty while ((sh7091.SCIF.SCFSR2 & scfsr2::tdfe::bit_mask) == 0); - for (int i = 0; i < 1000; i++) { - asm volatile ("nop;"); - } + sh7091.SCIF.SCFSR2 = static_cast(~scfsr2::tdfe::bit_mask); sh7091.SCIF.SCFTDR2 = static_cast(c); } @@ -105,6 +104,7 @@ void hexlify(const uint8_t * s, uint32_t len) { for (uint32_t i = 0; i < len; i++) { hexlify(s[i]); + character(' '); } character('\n'); } diff --git a/sh7091/serial_dma.hpp b/sh7091/serial_dma.hpp new file mode 100644 index 0000000..b8bf603 --- /dev/null +++ b/sh7091/serial_dma.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include "sh7091/sh7091_bits.hpp" + +/* + + (4) Channels 1 and 3 can be used in the following manner: + + The allowed transfer data length (8/16/32 bits, 32 bytes) depends on the + transfer area. The 64-bit transfer data length specification is permitted only for + system memory. + + Address mode: Only dual address mode is permitted. + Transfer initiation request: SCIF interrupt and auto request are permitted. + Bus mode: Only cycle steal mode is permitted. + DMA end interrupt: Can be used. +*/ + +/* + After the desired transfer conditions have been set in the DMA source address register (SAR), + DMA destination address register (DAR), DMA transfer count register (DMATCR), DMA + channel control register (CHCR), and DMA operation register (DMAOR), the DMAC transfers + data according to the following procedure: + + 1. The DMAC checks to see if transfer is enabled (DE = 1, DME = 1, TE = 0, NMIF = 0, AE = 0). + + 2. When a transfer request is issued and transfer has been enabled, the DMAC transfers one + transfer unit of data (determined by the setting of TS2–TS0). In auto-request mode, the transfer + begins automatically when the DE bit and DME bit are set to 1. The DMATCR value is + decremented by 1 for each transfer. The actual transfer flow depends on the address mode and + bus mode. + + 3. When the specified number of transfers have been completed (when the DMATCR value + reaches 0), the transfer ends normally. If the IE bit in CHCR is set to 1 at this time, a DMTE + interrupt request is sent to the CPU. + + 4. If a DMAC address error or NMI interrupt occurs, the transfer is suspended. Transfer is also + suspended when the DE bit in CHCR or the DME bit in DMAOR is cleared to 0. In the event + of an address error, a DMAE interrupt request is forcibly sent to the CPU. +*/ + + +namespace serial { + +static void recv_dma(void * destination_address, uint32_t length) +{ + using namespace dmac; + /* Initial settings (SAR, DAR, DMATCR, CHCR, DMAOR) */ + + // RS: SCFRDR2 (SCIF receive-data-full transfer request) + // RS: 0b1011 + + // SAR1 = SCFRDR2 + // DAR1 = (address) + // DMATCR1 = (transfer count, 24 bit) + sh7091.DMAC.CHCR3 = 0; + sh7091.DMAC.CHCR2 = 0; + sh7091.DMAC.CHCR1 = 0; + sh7091.DMAC.CHCR0 = 0; + + sh7091.DMAC.SAR1 = reinterpret_cast(&sh7091.SCIF.SCFRDR2); + sh7091.DMAC.DAR1 = reinterpret_cast(destination_address); + sh7091.DMAC.DMATCR1 = length & 0x00ff'ffff; + + // SSA (only used for PCMCIA) + // STC (only used for PCMCIA) + // DSA (only used for PCMCIA) + // DTC (only used for PCMCIA) + // DS (only used for DREQ requests) + // RL (only used for DRAK requests) + // AM (only used for DACK requests) + // AL (only used for DACK requests) + // DM incremented + // SM fixed + // RS SCIF + // TM cycle steal + // TS byte? + // IE interrupt enable + // TE transfer end (status bit) + // DE channel enable + sh7091.DMAC.CHCR1 = chcr::dm::destination_address_incremented + | chcr::sm::source_address_fixed + | chcr::rs::resource_select(0b1011) /* SCIF */ + | chcr::tm::cycle_steal_mode /* transmit mode */ + | chcr::ts::_8_bit /* transfer size */ + //| chcr::ie::interrupt_request_generated + | chcr::de::channel_operation_enabled; + + sh7091.DMAC.DMAOR = dmaor::ddt::on_demand_data_transfer_mode /* on-demand data transfer mode */ + | dmaor::pr::ch2_ch0_ch1_ch3 /* priority mode; CH2 > CH0 > CH1 > CH3 */ + | dmaor::dme::operation_enabled_on_all_channels; /* DMAC master enable */ +} + +} diff --git a/sh7091/sh7091_bits.hpp b/sh7091/sh7091_bits.hpp index cd49338..2a931d9 100644 --- a/sh7091/sh7091_bits.hpp +++ b/sh7091/sh7091_bits.hpp @@ -817,4 +817,12 @@ namespace scif { } } + namespace sclsr2 { + namespace orer { + constexpr uint32_t overrun_error_occured = 1 << 0; + + constexpr uint32_t bit_mask = 0x1 << 0; + } + } + }