diff --git a/base.mk b/base.mk index fa39ce4..375733d 100644 --- a/base.mk +++ b/base.mk @@ -9,6 +9,7 @@ CFLAGS += -Wno-array-bounds CFLAGS += -Wno-error=maybe-uninitialized CFLAGS += -Wno-error=unused-but-set-variable CFLAGS += -Wno-error=unused-variable +CFLAGS += -Wno-error=unused-function CXXFLAGS += -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics diff --git a/crc32.c b/crc32.c index ef4e8de..58d79a8 100644 --- a/crc32.c +++ b/crc32.c @@ -72,11 +72,11 @@ const uint32_t crc32_table[256] = { }; uint32_t -crc32_update(uint32_t crc, const uint8_t * data, uint32_t len) +crc32_update(uint32_t crc, const uint8_t * buf, uint32_t len) { while (len > 0) { - crc = crc32_table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8); - data++; + crc = crc32_table[*buf ^ ((crc >> 24) & 0xff)] ^ (crc << 8); + buf++; len--; } diff --git a/example/macaw.cpp b/example/macaw.cpp index 24e88e4..0661ecd 100644 --- a/example/macaw.cpp +++ b/example/macaw.cpp @@ -181,8 +181,5 @@ void main() theta += half_degree; frame_ix = (frame_ix + 1) & 1; frame += 1; - - if (frame > 10) - break; } } diff --git a/example/serial_transfer.cpp b/example/serial_transfer.cpp index 0ebdb8a..481ac6e 100644 --- a/example/serial_transfer.cpp +++ b/example/serial_transfer.cpp @@ -173,7 +173,7 @@ void recv_device_status(struct maple_display_poll_state &state) if (bus_data.command_code != maple::device_status::command_code) { state.port[port].ap__lm = 0; } else { - auto& data_fields = bus_data.data_fields; + //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; @@ -298,6 +298,14 @@ void render_write_state(char * dst) render_u32(serial_load::state.write_crc.value, &dst[24]); } +void render_read_state(char * dst) +{ + render_line("read", &dst[0]); + render_u32(sh7091.DMAC.DMATCR1, &dst[8]); + render_u32(sh7091.DMAC.SAR1, &dst[16]); + render_u32(serial_load::state.read_crc.value, &dst[24]); +} + void render_fsm_state(char * dst) { using namespace serial_load; @@ -309,8 +317,7 @@ void render_fsm_state(char * dst) render_write_state(dst); break; case fsm_state::read: - render_line("read", &dst[0]); - render_clear(&dst[8], 24); + render_read_state(dst); break; case fsm_state::jump: render_line("jump", &dst[0]); @@ -355,7 +362,8 @@ void main() __attribute__((section(".text.main"))); void main() { - serial::init(0); + constexpr uint32_t serial_speed = 0; + serial_load::init(serial_speed); struct maple_display_poll_state state = {0}; const uint8_t * font = reinterpret_cast(&_binary_font_portfolio_6x8); @@ -364,17 +372,11 @@ void main() auto renderer1 = maple::display::font_renderer(font); framebuffer[1] = renderer1.fb; - state.want_start = 1; - serial_load::init(); - // reset serial status sh7091.SCIF.SCFSR2 = 0; // reset line status sh7091.SCIF.SCLSR2 = 0; - uint32_t last_scfsr2 = -1; - uint32_t last_sclsr2 = -1; - serial::string("ready\n"); error_counter.brk = 0; @@ -393,7 +395,7 @@ void main() error_counter.brk += 1; error_counter.er += (scfsr2 & scfsr2::er::bit_mask) != 0; sh7091.SCIF.SCFSR2 = scfsr2 & ~(scfsr2::brk::bit_mask | scfsr2::er::bit_mask); - serial_load::init(); + serial_load::init(serial_load::state.speed); serial::reset_txrx(); } else if (scfsr2 & scfsr2::er::bit_mask) { // clear framing error @@ -418,11 +420,7 @@ void main() serial_load::tick(); render(renderer0, renderer1); - //if (sclsr2 != last_sclsr2 || scfsr2 != last_scfsr2) { - state.want_start = 1; - //} - last_scfsr2 = scfsr2; - last_sclsr2 = sclsr2; + state.want_start = 1; handle_maple(state); } } diff --git a/loader.lds b/loader.lds index 8fb732f..bef7081 100644 --- a/loader.lds +++ b/loader.lds @@ -3,7 +3,7 @@ MEMORY { p1ram : ORIGIN = 0xac005000, LENGTH = 0x0000 p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000 - ldram : ORIGIN = 0xacffe000, LENGTH = 0x2000 + ldram : ORIGIN = 0xacffd000, LENGTH = 0x3000 } SECTIONS { diff --git a/main.lds b/main.lds index 4077b02..9b33867 100644 --- a/main.lds +++ b/main.lds @@ -7,4 +7,4 @@ MEMORY INCLUDE "common.lds" -__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x2000; +__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x3000; diff --git a/serial_load.cpp b/serial_load.cpp index 0091dc4..e463055 100644 --- a/serial_load.cpp +++ b/serial_load.cpp @@ -23,11 +23,13 @@ static void move(void *dst, const void *src, uint32_t n) } } -void init() +void init(uint32_t speed) { state.len = 0; state.fsm_state = fsm_state::idle; + state.speed = speed & 0xff; sh7091.DMAC.CHCR1 = 0; + serial::init(state.speed); } void jump_to_func(const uint32_t addr) @@ -35,15 +37,16 @@ void jump_to_func(const uint32_t addr) serial::string("jump to: "); serial::integer(addr); // save our stack - asm volatile ("ldc r15, gbr; " - "mov #0, r15; " + asm volatile ("mov.l r14,@-r15; " + "ldc r15, gbr; " "jsr @%0; " - "nop; " + "mov #0, r15; " "stc gbr, r15; " + "mov.l @r15+,r14; " : : "r"(addr) /* input */ /* clobbered register */ - : "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","macl","mach","gbr","pr" + : "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","r13","macl","mach","gbr","pr" ); // restore our stack } @@ -57,6 +60,15 @@ static inline void prestart_write() state.write_crc.offset = dest; } +static inline void prestart_read() +{ + uint32_t src = state.buf.arg[0]; + uint32_t size = state.buf.arg[1]; + serial::send_dma(src, size); + state.read_crc.value = 0xffffffff; + state.read_crc.offset = src; +} + struct state_arglen_reply command_list[] = { {command::write, reply::write, fsm_state::write}, {command::read , reply::read , fsm_state::read }, @@ -82,6 +94,8 @@ void recv(uint8_t c) state.len = 0; union command_reply reply = command_reply(sar.reply, state.buf.arg[0], state.buf.arg[1]); serial::string(reply.u8, 16); + + if (state.buf.cmd == command::read) prestart_read(); return; } else { /* @@ -115,8 +129,8 @@ void tick() uint32_t dar1 = sh7091.DMAC.DAR1; if (dar1 > state.write_crc.offset) { uint32_t len = dar1 - state.write_crc.offset; - const uint8_t * dest = reinterpret_cast(state.write_crc.offset); - state.write_crc.value = crc32_update(state.write_crc.value, dest, len); + const uint8_t * buf = reinterpret_cast(state.write_crc.offset); + state.write_crc.value = crc32_update(state.write_crc.value, buf, len); state.write_crc.offset += len; } if (chcr1 & dmac::chcr::te::transfers_completed) { @@ -132,6 +146,27 @@ void tick() } break; case fsm_state::read: + { + uint32_t chcr1 = sh7091.DMAC.CHCR1; + uint32_t sar1 = sh7091.DMAC.SAR1; + if (sar1 > state.read_crc.offset) { + uint32_t len = sar1 - state.read_crc.offset; + const uint8_t * buf = reinterpret_cast(state.read_crc.offset); + state.read_crc.value = crc32_update(state.read_crc.value, buf, len); + state.read_crc.offset += len; + } + + if (chcr1 & dmac::chcr::te::transfers_completed) { + state.read_crc.value ^= 0xffffffff; + union command_reply reply = read_crc_reply(state.read_crc.value); + serial::string(reply.u8, 16); + + sh7091.DMAC.CHCR1 = 0; + + // transition to next state + //state.fsm_state = fsm_state::idle; + } + } break; case fsm_state::jump: { @@ -144,6 +179,11 @@ void tick() const uint32_t dest = state.buf.arg[0]; jump_to_func(dest); + // cautiously re-initialize serial; it is possible the called + // function modified serial state + serial::init(state.speed); + sh7091.DMAC.CHCR1 = 0; + // transition to next state state.fsm_state = fsm_state::idle; } @@ -151,7 +191,8 @@ void tick() case fsm_state::speed: { const uint32_t speed = state.buf.arg[0]; - serial::init(speed & 0xff); + state.speed = speed & 0xff; + serial::init(state.speed); // transition to next state state.fsm_state = fsm_state::idle; diff --git a/serial_load.hpp b/serial_load.hpp index f18d3fd..dd7bd85 100644 --- a/serial_load.hpp +++ b/serial_load.hpp @@ -6,7 +6,7 @@ namespace serial_load { -void init(); +void init(uint32_t speed); void recv(uint8_t c); void tick(); @@ -35,6 +35,7 @@ struct state { enum fsm_state fsm_state; struct incremental_crc write_crc; struct incremental_crc read_crc; + uint32_t speed; }; extern struct state state; diff --git a/serial_protocol.hpp b/serial_protocol.hpp index ba39cf6..8751967 100644 --- a/serial_protocol.hpp +++ b/serial_protocol.hpp @@ -39,12 +39,14 @@ namespace reply { constexpr uint32_t jump = gen_cmd("jump"); constexpr uint32_t speed = gen_cmd("sped"); constexpr uint32_t write_crc = gen_cmd("crcW"); + constexpr uint32_t read_crc = gen_cmd("crcR"); static_assert(write == 0x8c661aaa); static_assert(read == 0x512f23b5); static_assert(jump == 0x06cb1b4a); static_assert(speed == 0x8705dd86); static_assert(write_crc == 0x1cced074); + static_assert(read_crc == 0xb9ce82f4); } union command_reply { @@ -121,4 +123,9 @@ constexpr union command_reply write_crc_reply(uint32_t crc) return command_reply(reply::write_crc, crc, 0); } +constexpr union command_reply read_crc_reply(uint32_t crc) +{ + return command_reply(reply::read_crc, crc, 0); +} + } diff --git a/sh7091/serial.cpp b/sh7091/serial.cpp index 618eed7..0d6089c 100644 --- a/sh7091/serial.cpp +++ b/sh7091/serial.cpp @@ -19,7 +19,7 @@ static inline void init_wait() sh7091.TMU.TSTR |= tmu::tstr::str1::counter_start; uint32_t start = sh7091.TMU.TCNT1; - while ((start - sh7091.TMU.TCNT1) < 1); + while ((start - sh7091.TMU.TCNT1) < 20); sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1 } @@ -48,11 +48,6 @@ void init(uint8_t bit_rate) sh7091.SCIF.SCFCR2 = scfcr2::tfrst::reset_operation_enabled | scfcr2::rfrst::reset_operation_enabled; - sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte - | scfcr2::ttrg::trigger_on_8_bytes - //| scfcr2::mce::modem_signals_enabled - ; - sh7091.SCIF.SCSMR2 = scsmr2::chr::_8_bit_data | scsmr2::pe::parity_disabled | scsmr2::stop::_1_stop_bit @@ -72,6 +67,11 @@ void init(uint8_t bit_rate) // wait 1 bit interval init_wait(); + sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte + | scfcr2::ttrg::trigger_on_8_bytes + //| scfcr2::mce::modem_signals_enabled + ; + sh7091.SCIF.SCSCR2 = scscr2::te::transmission_enabled | scscr2::re::reception_enabled; @@ -84,7 +84,7 @@ void character(const char c) // wait for transmit fifo to become partially empty while ((sh7091.SCIF.SCFSR2 & scfsr2::tdfe::bit_mask) == 0); - sh7091.SCIF.SCFSR2 = static_cast(~scfsr2::tdfe::bit_mask); + sh7091.SCIF.SCFSR2 &= ~scfsr2::tdfe::bit_mask; sh7091.SCIF.SCFTDR2 = static_cast(c); } diff --git a/sh7091/serial_dma.hpp b/sh7091/serial_dma.hpp index 1a2ba3f..0e1033f 100644 --- a/sh7091/serial_dma.hpp +++ b/sh7091/serial_dma.hpp @@ -78,7 +78,7 @@ static void recv_dma(uint32_t destination_address, uint32_t length) // DE channel enable sh7091.DMAC.CHCR1 = chcr::dm::destination_address_incremented | chcr::sm::source_address_fixed - | chcr::rs::resource_select(0b1011) /* SCIF */ + | chcr::rs::resource_select(0b1011) /* SCFRDR2 → external address space */ | chcr::tm::cycle_steal_mode /* transmit mode */ | chcr::ts::_8_bit /* transfer size */ //| chcr::ie::interrupt_request_generated @@ -89,4 +89,23 @@ static void recv_dma(uint32_t destination_address, uint32_t length) | dmaor::dme::operation_enabled_on_all_channels; /* DMAC master enable */ } +static void send_dma(uint32_t source_address, uint32_t length) +{ + using namespace dmac; + + sh7091.DMAC.CHCR1 = 0; + + sh7091.DMAC.SAR1 = source_address; + sh7091.DMAC.DAR1 = reinterpret_cast(&sh7091.SCIF.SCFTDR2); + sh7091.DMAC.DMATCR1 = length & 0x00ff'ffff; + + sh7091.DMAC.CHCR1 = chcr::dm::destination_address_fixed + | chcr::sm::source_address_incremented + | chcr::rs::resource_select(0b1010) /* external address space → SCFTDR2 */ + | chcr::tm::cycle_steal_mode /* transmit mode */ + | chcr::ts::_8_bit /* transfer size */ + //| chcr::ie::interrupt_request_generated + | chcr::de::channel_operation_enabled; +} + } diff --git a/tools/command_gen.py b/tools/command_gen.py index b2c9d02..44544b4 100644 --- a/tools/command_gen.py +++ b/tools/command_gen.py @@ -25,6 +25,7 @@ replies = [ "jump", "sped", "crcW", + "crcR", ] for c in commands: diff --git a/tools/ftdi_transfer.cpp b/tools/ftdi_transfer.cpp index e7c9489..4d089dd 100644 --- a/tools/ftdi_transfer.cpp +++ b/tools/ftdi_transfer.cpp @@ -176,7 +176,7 @@ double timespec_difference(struct timespec const * const a, struct timespec cons void dump_command_reply(union serial_load::command_reply& cr) { for (uint32_t i = 0; i < (sizeof (union serial_load::command_reply)) / (sizeof (uint32_t)); i++) { - fprintf(stderr, " %08x\n", cr.u32[i]); + fprintf(stderr, " %08x\n", serial_load::le_bswap(cr.u32[i])); } } @@ -192,15 +192,23 @@ int read_reply(struct ftdi_context * ftdi, uint32_t expected_cmd, union serial_l return -1; } - for (uint32_t i = 0; i < (sizeof (reply)) / (sizeof (uint32_t)); i++) { - reply.u32[i] = le_bswap(reply.u32[i]); - } - uint32_t crc = crc32(&reply.u8[0], 12); if (crc != reply.crc) { - fprintf(stderr, "crc mismatch; remote crc: %08x; local crc: %08x\n", reply.crc, crc); + fprintf(stderr, "reply crc mismatch; remote crc: %08x; local crc: %08x\n", reply.crc, crc); dump_command_reply(reply); - return -1; + + /* + uint8_t buf[16] = {0}; + long length = read_with_timeout(ftdi, reply.u8, 16); + if (length > 0) { + fprintf(stderr, "trailing data:\n"); + for (int i = 0; i < length; i++) { + fprintf(stderr, "%02x ", buf[i]); + } + fprintf(stderr, "\n"); + } + */ + return -2; } if (reply.cmd != expected_cmd) { @@ -208,12 +216,14 @@ int read_reply(struct ftdi_context * ftdi, uint32_t expected_cmd, union serial_l dump_command_reply(reply); return -1; } + dump_command_reply(reply); return 0; } int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t size) { + fprintf(stderr, "do_write\n"); int res; const uint32_t dest = 0xac010000; @@ -223,7 +233,7 @@ int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t siz union serial_load::command_reply reply; res = read_reply(ftdi, serial_load::reply::write, reply); if (res != 0) { - return -1; + return -2; } fprintf(stderr, "remote: dest: %08x size: %08x\n", reply.arg[0], reply.arg[1]); if (reply.arg[0] != dest || reply.arg[1] != size) { @@ -255,6 +265,7 @@ int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t siz int do_jump(struct ftdi_context * ftdi) { + fprintf(stderr, "do_jump\n"); int res; const uint32_t dest = 0xac010000; @@ -266,7 +277,7 @@ int do_jump(struct ftdi_context * ftdi) union serial_load::command_reply reply; res = read_reply(ftdi, serial_load::reply::jump, reply); if (res != 0) { - return -1; + return -2; } fprintf(stderr, "remote: jump: %08x\n", reply.arg[0]); if (reply.arg[0] != dest || reply.arg[1] != 0) { @@ -276,47 +287,91 @@ int do_jump(struct ftdi_context * ftdi) return 0; } -int main(int argc, char * argv[]) +int read_file(const char * filename, uint8_t ** buf, uint32_t * size) { - if (argc < 2) { - fprintf(stderr, "argc\n"); - return EXIT_FAILURE; - } - - FILE * file = fopen(argv[1], "r"); + FILE * file = fopen(filename, "r"); if (file == NULL) { fprintf(stderr, "fopen\n"); - return EXIT_FAILURE; + return -1; } int ret; ret = fseek(file, 0L, SEEK_END); if (ret < 0) { - fprintf(stderr, "seek(SEEK_END)"); - return EXIT_FAILURE; + fprintf(stderr, "fseek(SEEK_END)"); + return -1; } long off = ftell(file); ret = fseek(file, 0L, SEEK_SET); if (ret < 0) { - fprintf(stderr, "seek(SEEK_SET)"); - return EXIT_FAILURE; + fprintf(stderr, "fseek(SEEK_SET)"); + return -1; } - fprintf(stderr, "%s off %ld\n", argv[1], off); - //uint8_t buf[off]; - uint8_t * buf = (uint8_t *)malloc(off); - ssize_t size = fread(buf, 1, off, file); - if (size < 0) { - fprintf(stderr, "read"); - return EXIT_FAILURE; + fprintf(stderr, "%s size %ld\n", filename, off); + *buf = (uint8_t *)malloc(off); + ssize_t fread_size = fread(*buf, 1, off, file); + if (fread_size < 0) { + fprintf(stderr, "fread"); + return -1; } - printf("%02x\n", buf[0]); ret = fclose(file); if (ret < 0) { - fprintf(stderr, "close"); + fprintf(stderr, "fclose"); + return -1; + } + + *size = off; + + return 0; +} + +int do_read(struct ftdi_context * ftdi) +{ + fprintf(stderr, "do_read\n"); + + int res; + + const uint32_t src = 0xac010000; + const uint32_t size = 51584; + union serial_load::command_reply command = serial_load::read_command(src, size); + res = ftdi_write_data(ftdi, command.u8, (sizeof (command))); + assert(res == (sizeof (command))); + union serial_load::command_reply reply; + res = read_reply(ftdi, serial_load::reply::read, reply); + if (res != 0) { + return -2; + } + fprintf(stderr, "remote: src: %08x size: %08x\n", reply.arg[0], reply.arg[1]); + if (reply.arg[0] != src || reply.arg[1] != size) { + return -1; + } + + uint32_t * buf = (uint32_t *)malloc(size); + res = ftdi_read_data(ftdi, (uint8_t *)buf, size); + assert(res >= 0); + assert((uint32_t)res == size); + + uint32_t buf_crc = crc32((uint8_t*)buf, size); + + union serial_load::command_reply crc_reply; + res = read_reply(ftdi, serial_load::reply::read_crc, crc_reply); + if (res != 0) { + return -1; + } + fprintf(stderr, "remote crc: %08x; local crc %08x\n", crc_reply.arg[0], buf_crc); + + + return 0; +} + +int main(int argc, char * argv[]) +{ + if (argc < 2) { + fprintf(stderr, "argc\n"); return EXIT_FAILURE; } @@ -336,15 +391,23 @@ int main(int argc, char * argv[]) int return_code = EXIT_SUCCESS; + uint8_t * buf; + uint32_t size; + res = read_file(argv[1], &buf, &size); + if (res < 0) { + return EXIT_FAILURE; + } + struct timespec start; struct timespec end; res = clock_gettime(CLOCK_MONOTONIC, &start); assert(res >= 0); - int do_write_ret = do_write(ftdi, buf, off); + int do_write_ret = do_write(ftdi, buf, size); res = clock_gettime(CLOCK_MONOTONIC, &end); assert(res >= 0); fprintf(stderr, "do_write time: %.03f\n", timespec_difference(&end, &start)); if (do_write_ret == 0) { + //do_read(ftdi); do_jump(ftdi); } else { return_code = EXIT_FAILURE;