serial_transfer: rewrite
This commit is contained in:
parent
71fb02e03d
commit
ff7a03a75c
12
client.py
12
client.py
@ -36,9 +36,10 @@ def symmetric(ser, b):
|
||||
l = []
|
||||
mem = memoryview(b)
|
||||
i = 0
|
||||
chunk_size = 128
|
||||
|
||||
while i < len(b):
|
||||
chunk_size = 128
|
||||
|
||||
if i % 1024 == 0:
|
||||
print(i, end=' ')
|
||||
sys.stdout.flush()
|
||||
@ -49,6 +50,7 @@ def symmetric(ser, b):
|
||||
if len(l) + chunk_size >= i:
|
||||
break
|
||||
|
||||
time.sleep(1000 / 1000000)
|
||||
chunk_size = min(chunk_size, len(b) - i)
|
||||
assert chunk_size > 0, chunk_size
|
||||
ser.write(mem[i:i+chunk_size])
|
||||
@ -73,12 +75,12 @@ def start_data(ser, b):
|
||||
size = len(b)
|
||||
args = struct.pack("<II", size, dest)
|
||||
ret = sync(ser, b'DATA' + args)
|
||||
if ret != b'data\n' and ret != b'\ndata\n' and ret != b'\x00data\n':
|
||||
if ret != b'data' and ret != b'data\n' and ret != b'\ndata\n' and ret != b'\x00data\n':
|
||||
print(".", end=' ')
|
||||
print(ret)
|
||||
time.sleep(1)
|
||||
time.sleep(10)
|
||||
sys.stdout.flush()
|
||||
sync(ser, b'prime', wait=0)
|
||||
sync(ser, b'prime')
|
||||
start_data(ser, b)
|
||||
return
|
||||
print("\nDATA")
|
||||
@ -104,7 +106,6 @@ def do(ser, b):
|
||||
args = struct.pack("<I", dest)
|
||||
ret = sync(ser, b'JUMP' + args, wait=0)
|
||||
print("JUMP", ret)
|
||||
print("console:")
|
||||
console(ser)
|
||||
|
||||
seen_length = 16
|
||||
@ -121,6 +122,7 @@ framebuffer_mode = False
|
||||
framebuffer = []
|
||||
|
||||
def console(ser):
|
||||
print("console:")
|
||||
global framebuffer_mode
|
||||
global framebuffer
|
||||
|
||||
|
23
common.mk
23
common.mk
@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
DIR := $(dir $(MAKEFILE_PATH))
|
||||
|
||||
LIB ?= .
|
||||
OPT ?= -Og
|
||||
OPT ?= -O2
|
||||
GENERATED ?=
|
||||
|
||||
AARCH = --isa=sh4 --little
|
||||
@ -17,6 +17,11 @@ OBJARCH = -O elf32-shl -B sh4
|
||||
|
||||
TARGET = sh4-none-elf-
|
||||
|
||||
START_OBJ = \
|
||||
start.o \
|
||||
runtime.o \
|
||||
sh7091/cache.o
|
||||
|
||||
IP_OBJ = \
|
||||
systemid.o \
|
||||
toc.o \
|
||||
@ -29,8 +34,15 @@ IP_OBJ = \
|
||||
sg_are02.o \
|
||||
sg_are03.o \
|
||||
sg_are04.o \
|
||||
sg_ini.o \
|
||||
aip.o
|
||||
$(START_OBJ) \
|
||||
example/serial_transfer.o \
|
||||
sh7091/serial.o \
|
||||
serial_load.o \
|
||||
maple/maple.o \
|
||||
font/portfolio_6x8/portfolio_6x8.data.o \
|
||||
crc32.o
|
||||
#sg_ini.o \
|
||||
#aip.o
|
||||
|
||||
%.o: %.obj
|
||||
$(OBJCOPY) -g \
|
||||
@ -40,11 +52,6 @@ IP_OBJ = \
|
||||
ip.elf: $(IP_OBJ)
|
||||
$(LD) --orphan-handling=error --print-memory-usage -T $(LIB)/ip.lds $^ -o $@
|
||||
|
||||
START_OBJ = \
|
||||
start.o \
|
||||
runtime.o \
|
||||
sh7091/cache.o
|
||||
|
||||
include base.mk
|
||||
|
||||
sine.pcm: common.mk
|
||||
|
90
crc32.c
Normal file
90
crc32.c
Normal file
@ -0,0 +1,90 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
// Automatically generated CRC function
|
||||
// polynomial: 0x104C11DB7
|
||||
const uint32_t crc32_table[256] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
|
||||
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
|
||||
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
|
||||
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
|
||||
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
|
||||
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
|
||||
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
|
||||
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
|
||||
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
|
||||
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
|
||||
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
|
||||
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
|
||||
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
|
||||
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
|
||||
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
|
||||
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
|
||||
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
|
||||
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
|
||||
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
|
||||
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
|
||||
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
|
||||
};
|
||||
|
||||
uint32_t
|
||||
crc32_update(uint32_t crc, const uint8_t * data, uint32_t len)
|
||||
{
|
||||
while (len > 0) {
|
||||
crc = crc32_table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
|
||||
data++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
crc32(const uint8_t * buf, uint32_t len)
|
||||
{
|
||||
return crc32_update(0xffffffff, buf, len) ^ 0xffffffff;
|
||||
}
|
19
crc32.h
Normal file
19
crc32.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint32_t crc32_table[256];
|
||||
|
||||
uint32_t
|
||||
crc32_update(uint32_t crc, const uint8_t *data, uint32_t len);
|
||||
|
||||
uint32_t
|
||||
crc32(const uint8_t *buf, uint32_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -360,7 +360,8 @@ SERIAL_TRANSFER_OBJ = \
|
||||
sh7091/serial.o \
|
||||
serial_load.o \
|
||||
maple/maple.o \
|
||||
font/portfolio_6x8/portfolio_6x8.data.o
|
||||
font/portfolio_6x8/portfolio_6x8.data.o \
|
||||
crc32.o
|
||||
|
||||
example/serial_transfer.elf: LDSCRIPT = $(LIB)/loader.lds
|
||||
example/serial_transfer.elf: $(START_OBJ) $(SERIAL_TRANSFER_OBJ)
|
||||
|
@ -160,6 +160,7 @@ void main()
|
||||
init_texture_memory(opb_size);
|
||||
|
||||
uint32_t frame_ix = 0;
|
||||
uint32_t frame = 0;
|
||||
|
||||
while (true) {
|
||||
ta_polygon_converter_init(opb_size.total(),
|
||||
@ -179,5 +180,9 @@ void main()
|
||||
|
||||
theta += half_degree;
|
||||
frame_ix = (frame_ix + 1) & 1;
|
||||
frame += 1;
|
||||
|
||||
if (frame > 10)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "serial_load.hpp"
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
extern uint32_t _binary_font_portfolio_6x8 __asm("_binary_font_portfolio_6x8_portfolio_6x8_data_start");
|
||||
|
||||
template <typename T>
|
||||
@ -26,11 +28,21 @@ inline void copy(T * dst, const T * src, const int32_t n) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t * framebuffer;
|
||||
static uint8_t * framebuffer[2];
|
||||
static char textbuffer[2][4 * 8];
|
||||
|
||||
static uint32_t send_buf[1024 / 4] __attribute__((aligned(32)));
|
||||
static uint32_t recv_buf[1024 / 4] __attribute__((aligned(32)));
|
||||
|
||||
struct serial_error_counter {
|
||||
uint32_t brk;
|
||||
uint32_t er;
|
||||
uint32_t dr;
|
||||
uint32_t orer;
|
||||
};
|
||||
|
||||
struct serial_error_counter error_counter;
|
||||
|
||||
enum struct step {
|
||||
IDLE = 0,
|
||||
DEVICE_STATUS,
|
||||
@ -67,9 +79,13 @@ void send_vmu_framebuffer(maple::host_command_writer& writer, uint8_t port, uint
|
||||
data_fields.phase = 0;
|
||||
data_fields.block_number = std::byteswap<uint16_t>(0x0000);
|
||||
|
||||
copy<uint8_t>(data_fields.written_data,
|
||||
reinterpret_cast<uint8_t *>(framebuffer),
|
||||
maple::display::vmu::framebuffer_size);
|
||||
uint8_t * fb;
|
||||
if (lm == ap::lm_bus::_0)
|
||||
fb = framebuffer[0 ^ (port & 1)];
|
||||
else
|
||||
fb = framebuffer[1 ^ (port & 1)];
|
||||
|
||||
copy<uint8_t>(data_fields.written_data, fb, maple::display::vmu::framebuffer_size);
|
||||
}
|
||||
|
||||
void recv_extension_device_status(struct maple_display_poll_state &state)
|
||||
@ -213,7 +229,7 @@ void handle_maple(struct maple_display_poll_state& state)
|
||||
}
|
||||
}
|
||||
|
||||
void render_glyphs(maple::display::font_renderer& renderer, char * s)
|
||||
void render_glyphs(maple::display::font_renderer& renderer, const char * s)
|
||||
{
|
||||
for (int i = 0; i < 8 * 4; i++) {
|
||||
int x = i % 8;
|
||||
@ -222,23 +238,117 @@ void render_glyphs(maple::display::font_renderer& renderer, char * s)
|
||||
}
|
||||
}
|
||||
|
||||
void render_serial_state(maple::display::font_renderer& renderer, char * s, const char * msg)
|
||||
void render_str(const char * src, char * dst)
|
||||
{
|
||||
int i = 0;
|
||||
char c;
|
||||
while ((c = src[i]) != 0) {
|
||||
dst[i] = c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void render_line(const char * src, char * dst, int src_len = 8)
|
||||
{
|
||||
bool end = false;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (end || msg[i] == 0) {
|
||||
s[0 + i] = ' ';
|
||||
if (end || src[i] == 0 || i >= src_len) {
|
||||
dst[i] = ' ';
|
||||
end = true;
|
||||
} else {
|
||||
s[0 + i] = msg[i];
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render_clear(char * dst, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
dst[i] = ' ';
|
||||
}
|
||||
|
||||
void render_u32(uint32_t src, char * dst)
|
||||
{
|
||||
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);
|
||||
string::hex(num_buf, 8, src);
|
||||
for (int i = 0; i < 8; i++) dst[i] = num_buf[i];
|
||||
}
|
||||
|
||||
void render_u8(uint32_t src, char * dst)
|
||||
{
|
||||
char num_buf[2];
|
||||
string::hex(num_buf, 2, src);
|
||||
for (int i = 0; i < 2; i++) dst[i] = num_buf[i];
|
||||
}
|
||||
|
||||
void render_idle_state(char * dst)
|
||||
{
|
||||
render_line("idle", &dst[0]);
|
||||
render_u32(serial_load::state.buf.u32[0], &dst[8]);
|
||||
render_u32(serial_load::state.buf.u32[1], &dst[16]);
|
||||
render_u8(serial_load::state.len, &dst[24]);
|
||||
render_clear(&dst[26], 6);
|
||||
}
|
||||
|
||||
void render_write_state(char * dst)
|
||||
{
|
||||
render_line("write", &dst[0]);
|
||||
render_u32(sh7091.DMAC.DMATCR1, &dst[8]);
|
||||
render_u32(sh7091.DMAC.DAR1, &dst[16]);
|
||||
render_u32(serial_load::state.write_crc.value, &dst[24]);
|
||||
}
|
||||
|
||||
void render_fsm_state(char * dst)
|
||||
{
|
||||
using namespace serial_load;
|
||||
switch (state.fsm_state) {
|
||||
case fsm_state::idle:
|
||||
render_idle_state(dst);
|
||||
break;
|
||||
case fsm_state::write:
|
||||
render_write_state(dst);
|
||||
break;
|
||||
case fsm_state::read:
|
||||
render_line("read", &dst[0]);
|
||||
render_clear(&dst[8], 24);
|
||||
break;
|
||||
case fsm_state::jump:
|
||||
render_line("jump", &dst[0]);
|
||||
render_clear(&dst[8], 24);
|
||||
break;
|
||||
case fsm_state::speed:
|
||||
render_line("speed", &dst[0]);
|
||||
render_clear(&dst[8], 24);
|
||||
break;
|
||||
default:
|
||||
render_line("invalid", &dst[0]);
|
||||
render_clear(&dst[8], 24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void render_error_counter_state(char * dst)
|
||||
{
|
||||
render_str("br", &dst[0]);
|
||||
render_u8(error_counter.brk, &dst[2]);
|
||||
render_str("er", &dst[4]);
|
||||
render_u8(error_counter.er, &dst[6]);
|
||||
render_str("dr", &dst[8]);
|
||||
render_u8(error_counter.dr, &dst[10]);
|
||||
render_str("oe", &dst[12]);
|
||||
render_u8(error_counter.orer, &dst[14]);
|
||||
|
||||
render_u32(sh7091.SCIF.SCFSR2, &dst[16]);
|
||||
render_u32(sh7091.SCIF.SCLSR2, &dst[24]);
|
||||
}
|
||||
|
||||
void render(maple::display::font_renderer& renderer0,
|
||||
maple::display::font_renderer& renderer1)
|
||||
{
|
||||
render_fsm_state(textbuffer[0]);
|
||||
render_error_counter_state(textbuffer[1]);
|
||||
render_glyphs(renderer0, textbuffer[0]);
|
||||
render_glyphs(renderer1, textbuffer[1]);
|
||||
}
|
||||
|
||||
void main() __attribute__((section(".text.main")));
|
||||
@ -249,16 +359,12 @@ void main()
|
||||
|
||||
struct maple_display_poll_state state = {0};
|
||||
const uint8_t * font = reinterpret_cast<const uint8_t *>(&_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;
|
||||
auto renderer0 = maple::display::font_renderer(font);
|
||||
framebuffer[0] = renderer0.fb;
|
||||
auto renderer1 = maple::display::font_renderer(font);
|
||||
framebuffer[1] = renderer1.fb;
|
||||
|
||||
state.want_start = 1;
|
||||
serial_load::init();
|
||||
|
||||
// reset serial status
|
||||
@ -266,35 +372,57 @@ void main()
|
||||
// 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;
|
||||
error_counter.er = 0;
|
||||
error_counter.dr = 0;
|
||||
error_counter.orer = 0;
|
||||
|
||||
while (1) {
|
||||
using namespace scif;
|
||||
|
||||
const uint16_t scfsr2 = sh7091.SCIF.SCFSR2;
|
||||
const uint16_t sclsr2 = sh7091.SCIF.SCLSR2;
|
||||
|
||||
if (scfsr2 & scfsr2::brk::bit_mask) {
|
||||
render_serial_state(renderer, s, "brk");
|
||||
// clear framing error and break
|
||||
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::reset_txrx();
|
||||
} else if (scfsr2 & scfsr2::er::bit_mask) {
|
||||
render_serial_state(renderer, s, "er");
|
||||
// clear framing error
|
||||
error_counter.er += 1;
|
||||
sh7091.SCIF.SCFSR2 = scfsr2 & ~scfsr2::er::bit_mask;
|
||||
} 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");
|
||||
error_counter.dr += 1;
|
||||
sh7091.SCIF.SCFSR2 = scfsr2 & ~scfsr2::dr::bit_mask;
|
||||
} else if (sclsr2 & sclsr2::orer::bit_mask) {
|
||||
error_counter.orer += 1;
|
||||
sh7091.SCIF.SCLSR2 = scfsr2 & ~sclsr2::orer::bit_mask;
|
||||
} else if (scfsr2 & scfsr2::rdf::bit_mask) {
|
||||
render_serial_state(renderer, s, "rdf");
|
||||
const uint8_t c = sh7091.SCIF.SCFRDR2;
|
||||
serial_load::recv(c);
|
||||
} else {
|
||||
render_serial_state(renderer, s, "idle");
|
||||
if (serial_load::state.fsm_state == serial_load::fsm_state::idle) {
|
||||
while (sh7091.SCIF.SCFSR2 & scfsr2::rdf::bit_mask) {
|
||||
const uint8_t c = sh7091.SCIF.SCFRDR2;
|
||||
serial_load::recv(c);
|
||||
sh7091.SCIF.SCFSR2 = scfsr2 & ~scfsr2::rdf::bit_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
state.want_start = 1;
|
||||
|
||||
serial_load::tick();
|
||||
render(renderer0, renderer1);
|
||||
|
||||
//if (sclsr2 != last_sclsr2 || scfsr2 != last_scfsr2) {
|
||||
state.want_start = 1;
|
||||
//}
|
||||
last_scfsr2 = scfsr2;
|
||||
last_sclsr2 = sclsr2;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "holly/background.hpp"
|
||||
#include "holly/region_array.hpp"
|
||||
|
||||
#include "sh7091/serial.hpp"
|
||||
|
||||
struct vertex {
|
||||
float x;
|
||||
float y;
|
||||
@ -86,15 +88,15 @@ void init_texture_memory(const struct opb_size& opb_size)
|
||||
background_parameter(0xff220000);
|
||||
}
|
||||
|
||||
uint32_t _ta_parameter_buf[((32 + 64 + 32) + 32) / 4];
|
||||
|
||||
void main()
|
||||
{
|
||||
serial::init(4);
|
||||
serial::string("main\n");
|
||||
video_output::set_mode_vga();
|
||||
|
||||
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
|
||||
// This is mandatory for ch2-dma to the ta fifo polygon converter.
|
||||
uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf);
|
||||
uint32_t ta_parameter_buf[32 + 64 + 32 / 4] __attribute__((aligned(32)));
|
||||
|
||||
constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list
|
||||
| ta_alloc_ctrl::tm_opb::no_list
|
||||
@ -118,6 +120,8 @@ void main()
|
||||
|
||||
uint32_t frame_ix = 0;
|
||||
|
||||
serial::string("while true\n");
|
||||
|
||||
while (true) {
|
||||
ta_polygon_converter_init(opb_size.total(),
|
||||
ta_alloc,
|
||||
|
@ -116,8 +116,8 @@ void core_wait_end_of_render_video()
|
||||
*/
|
||||
while ((system.ISTNRM & istnrm::end_of_render_tsp) == 0) {
|
||||
if (system.ISTERR) {
|
||||
serial::string("core ");
|
||||
serial::integer<uint32_t>(system.ISTERR);
|
||||
//serial::string("core ");
|
||||
//serial::integer<uint32_t>(system.ISTERR);
|
||||
holly.SOFTRESET = softreset::pipeline_soft_reset;
|
||||
holly.SOFTRESET = 0;
|
||||
break;
|
||||
|
@ -142,8 +142,8 @@ void ta_wait_opaque_list()
|
||||
{
|
||||
while ((system.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0) {
|
||||
if (system.ISTERR) {
|
||||
serial::string("ta ISTERR: ");
|
||||
serial::integer<uint32_t>(system.ISTERR);
|
||||
//serial::string("ta ISTERR: ");
|
||||
//serial::integer<uint32_t>(system.ISTERR);
|
||||
}
|
||||
};
|
||||
|
||||
|
48
ip.lds
48
ip.lds
@ -2,12 +2,14 @@ OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
|
||||
|
||||
MEMORY
|
||||
{
|
||||
systemid (arx) : ORIGIN = 0x8c008000, LENGTH = 0x100
|
||||
toc (arx) : ORIGIN = 0x8c008100, LENGTH = 0x200
|
||||
sg_sec (arx) : ORIGIN = 0x8c008300, LENGTH = 0x3400
|
||||
sg_are (arx) : ORIGIN = 0x8c00b700, LENGTH = 0x100
|
||||
sg_ini (arx) : ORIGIN = 0x8c00b800, LENGTH = 0x2800
|
||||
aip (arx) : ORIGIN = 0x8c00e000, LENGTH = 0x2000
|
||||
systemid : ORIGIN = 0x8c008000, LENGTH = 0x100
|
||||
toc : ORIGIN = 0x8c008100, LENGTH = 0x200
|
||||
sg_sec : ORIGIN = 0x8c008300, LENGTH = 0x3400
|
||||
sg_are : ORIGIN = 0x8c00b700, LENGTH = 0x100
|
||||
sg_ini : ORIGIN = 0x8c00b800, LENGTH = 0x4800
|
||||
/* sg_ini : ORIGIN = 0x8c00b800, LENGTH = 0x2800 */
|
||||
/* aip : ORIGIN = 0x8c00e000, LENGTH = 0x2000 */
|
||||
p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@ -42,14 +44,22 @@ SECTIONS
|
||||
.text.sg_ini :
|
||||
{
|
||||
KEEP(*(.text.*sg_ini))
|
||||
KEEP(*(.text.start))
|
||||
*(.text.startup.*)
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
*(.bss*)
|
||||
*(.data*)
|
||||
. = ORIGIN(sg_ini) + LENGTH(sg_ini);
|
||||
} > sg_ini
|
||||
|
||||
/*
|
||||
.text.aip :
|
||||
{
|
||||
KEEP(*(.text.*aip))
|
||||
. = ORIGIN(aip) + LENGTH(aip);
|
||||
} > aip
|
||||
*/
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
@ -61,3 +71,29 @@ SECTIONS
|
||||
|
||||
INCLUDE "debug.lds"
|
||||
}
|
||||
__stack_reservation = 0x1000;
|
||||
__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - __stack_reservation;
|
||||
|
||||
__text_link_start = 0;
|
||||
__text_link_end = 0;
|
||||
__text_load_start = 0;
|
||||
|
||||
__data_link_start = 0;
|
||||
__data_link_end = 0;
|
||||
__data_load_start = 0;
|
||||
|
||||
__rodata_link_start = 0;
|
||||
__rodata_link_end = 0;
|
||||
__rodata_load_start = 0;
|
||||
|
||||
__ctors_link_start = 0;
|
||||
__ctors_link_end = 0;
|
||||
|
||||
__bss_link_start = 0;
|
||||
__bss_link_end = 0;
|
||||
|
||||
__vbr_link_start = 0;
|
||||
__vbr_link_end = 0;
|
||||
__vbr_load_end = 0;
|
||||
|
||||
INCLUDE "addresses.lds"
|
||||
|
@ -68,6 +68,8 @@ SECTIONS
|
||||
|
||||
INCLUDE "debug.lds"
|
||||
}
|
||||
__stack_reservation = 0x0;
|
||||
|
||||
INCLUDE "symbols.lds"
|
||||
INCLUDE "addresses.lds"
|
||||
|
||||
__stack_end = 0x8c008000;
|
||||
|
4
main.lds
4
main.lds
@ -4,5 +4,7 @@ MEMORY
|
||||
p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000
|
||||
p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000
|
||||
}
|
||||
__stack_reservation = 0x1000;
|
||||
|
||||
INCLUDE "common.lds"
|
||||
|
||||
__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x2000;
|
||||
|
180
serial_load.cpp
180
serial_load.cpp
@ -1,7 +1,10 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "sh7091/serial.hpp"
|
||||
#include "sh7091/serial_dma.hpp"
|
||||
|
||||
#include "serial_load.hpp"
|
||||
#include "crc32.h"
|
||||
|
||||
namespace serial_load {
|
||||
|
||||
@ -23,10 +26,11 @@ static void move(void *dst, const void *src, uint32_t n)
|
||||
void init()
|
||||
{
|
||||
state.len = 0;
|
||||
state.command = CMD_NONE;
|
||||
state.fsm_state = fsm_state::idle;
|
||||
sh7091.DMAC.CHCR1 = 0;
|
||||
}
|
||||
|
||||
static void jump_to_func(const uint32_t addr)
|
||||
void jump_to_func(const uint32_t addr)
|
||||
{
|
||||
serial::string("jump to: ");
|
||||
serial::integer<uint32_t>(addr);
|
||||
@ -44,87 +48,117 @@ static void jump_to_func(const uint32_t addr)
|
||||
// restore our stack
|
||||
}
|
||||
|
||||
static inline void prestart_write()
|
||||
{
|
||||
uint32_t dest = state.buf.arg[0];
|
||||
uint32_t size = state.buf.arg[1];
|
||||
serial::recv_dma(dest - 1, size + 1);
|
||||
state.write_crc.value = 0xffffffff;
|
||||
state.write_crc.offset = dest;
|
||||
}
|
||||
|
||||
struct state_arglen_reply command_list[] = {
|
||||
{command::write, reply::write, fsm_state::write},
|
||||
{command::read , reply::read , fsm_state::read },
|
||||
{command::jump , reply::jump , fsm_state::jump },
|
||||
{command::speed, reply::speed, fsm_state::speed},
|
||||
};
|
||||
constexpr uint32_t command_list_length = (sizeof (command_list)) / (sizeof (command_list[0]));
|
||||
|
||||
void recv(uint8_t c)
|
||||
{
|
||||
while (1) {
|
||||
switch (state.command) {
|
||||
case CMD_NONE:
|
||||
state.buf[state.len++] = c;
|
||||
if (state.len >= 4) {
|
||||
if (state.buf[0] == 'D' &&
|
||||
state.buf[1] == 'A' &&
|
||||
state.buf[2] == 'T' &&
|
||||
state.buf[3] == 'A') {
|
||||
if (state.len < 12) {
|
||||
state.buf.u8[state.len++] = c;
|
||||
switch (state.fsm_state) {
|
||||
case fsm_state::idle:
|
||||
if (state.len == 16) {
|
||||
for (uint32_t i = 0; i < command_list_length; i++) {
|
||||
struct state_arglen_reply& sar = command_list[i];
|
||||
if (state.buf.cmd == sar.command) {
|
||||
uint32_t crc = crc32(&state.buf.u8[0], 12);
|
||||
if (crc == state.buf.crc) {
|
||||
// valid command, do the transition
|
||||
if (state.buf.cmd == command::write) prestart_write();
|
||||
state.fsm_state = sar.fsm_state;
|
||||
state.len = 0;
|
||||
union command_reply reply = command_reply(sar.reply, state.buf.arg[0], state.buf.arg[1]);
|
||||
serial::string(reply.u8, 16);
|
||||
return;
|
||||
} else {
|
||||
serial::string("data");
|
||||
state.command = CMD_DATA;
|
||||
/*
|
||||
union command_reply reply = crc_error_reply(crc);
|
||||
serial::string(reply.u8, 16);
|
||||
state.len = 0;
|
||||
return;
|
||||
*/
|
||||
}
|
||||
} else if (state.buf[0] == 'J' &&
|
||||
state.buf[1] == 'U' &&
|
||||
state.buf[2] == 'M' &&
|
||||
state.buf[3] == 'P') {
|
||||
if (state.len < 8) {
|
||||
return;
|
||||
} else {
|
||||
serial::string("jump");
|
||||
state.command = CMD_JUMP;
|
||||
}
|
||||
} else if (state.buf[0] == 'R' &&
|
||||
state.buf[1] == 'A' &&
|
||||
state.buf[2] == 'T' &&
|
||||
state.buf[3] == 'E') {
|
||||
if (state.len < 8) {
|
||||
return;
|
||||
} else {
|
||||
serial::string("rate");
|
||||
state.command = CMD_RATE;
|
||||
}
|
||||
} else {
|
||||
move(&state.buf[0], &state.buf[1], state.len - 1);
|
||||
state.len -= 1;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case CMD_DATA:
|
||||
{
|
||||
uint32_t * size = &state.addr1;
|
||||
uint8_t * dest = reinterpret_cast<uint8_t *>(state.addr2);
|
||||
if (*size > 0) {
|
||||
serial::character(c);
|
||||
|
||||
// write c to dest
|
||||
*dest = c;
|
||||
state.addr2++;
|
||||
|
||||
(*size)--;
|
||||
}
|
||||
if (*size == 0) {
|
||||
state.len = 0;
|
||||
state.command = CMD_NONE;
|
||||
serial::string("next");
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
case CMD_JUMP:
|
||||
// jump
|
||||
state.len = 0;
|
||||
state.command = CMD_NONE;
|
||||
jump_to_func(state.addr1);
|
||||
return;
|
||||
break;
|
||||
case CMD_RATE:
|
||||
state.len = 0;
|
||||
state.command = CMD_NONE;
|
||||
serial::init(state.addr1 & 0xff);
|
||||
return;
|
||||
// invalid command
|
||||
move(&state.buf.u8[0], &state.buf.u8[1], state.len - 1);
|
||||
state.len -= 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tick()
|
||||
{
|
||||
switch (state.fsm_state) {
|
||||
case fsm_state::idle:
|
||||
break;
|
||||
case fsm_state::write:
|
||||
{
|
||||
// read chcr1 before dar1 to avoid race
|
||||
uint32_t chcr1 = sh7091.DMAC.CHCR1;
|
||||
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<const uint8_t *>(state.write_crc.offset);
|
||||
state.write_crc.value = crc32_update(state.write_crc.value, dest, len);
|
||||
state.write_crc.offset += len;
|
||||
}
|
||||
if (chcr1 & dmac::chcr::te::transfers_completed) {
|
||||
state.write_crc.value ^= 0xffffffff;
|
||||
union command_reply reply = write_crc_reply(state.write_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::read:
|
||||
break;
|
||||
case fsm_state::jump:
|
||||
{
|
||||
using namespace scif;
|
||||
// wait for serial transmission to end
|
||||
constexpr uint32_t transmission_end = scfsr2::tend::bit_mask | scfsr2::tdfe::bit_mask;
|
||||
if ((sh7091.SCIF.SCFSR2 & transmission_end) != transmission_end)
|
||||
return;
|
||||
|
||||
const uint32_t dest = state.buf.arg[0];
|
||||
jump_to_func(dest);
|
||||
|
||||
// transition to next state
|
||||
state.fsm_state = fsm_state::idle;
|
||||
}
|
||||
break;
|
||||
case fsm_state::speed:
|
||||
{
|
||||
const uint32_t speed = state.buf.arg[0];
|
||||
serial::init(speed & 0xff);
|
||||
|
||||
// transition to next state
|
||||
state.fsm_state = fsm_state::idle;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "serial_protocol.hpp"
|
||||
|
||||
namespace serial_load {
|
||||
|
||||
void init();
|
||||
void recv(uint8_t c);
|
||||
void tick();
|
||||
|
||||
enum command {
|
||||
CMD_NONE,
|
||||
CMD_DATA, // DATA 0000 0000 {data}
|
||||
CMD_JUMP, // JUMP 0000
|
||||
CMD_RATE, // RATE 0000
|
||||
enum struct fsm_state {
|
||||
idle,
|
||||
write,
|
||||
read,
|
||||
jump,
|
||||
speed,
|
||||
};
|
||||
|
||||
struct state_arglen_reply {
|
||||
uint32_t command;
|
||||
uint32_t reply;
|
||||
enum fsm_state fsm_state;
|
||||
};
|
||||
|
||||
struct incremental_crc {
|
||||
uint32_t value;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
struct state {
|
||||
union {
|
||||
uint8_t buf[12];
|
||||
struct {
|
||||
uint8_t cmd[4];
|
||||
uint32_t addr1;
|
||||
uint32_t addr2;
|
||||
};
|
||||
};
|
||||
union command_reply buf;
|
||||
uint32_t len;
|
||||
enum command command;
|
||||
enum fsm_state fsm_state;
|
||||
struct incremental_crc write_crc;
|
||||
struct incremental_crc read_crc;
|
||||
};
|
||||
|
||||
extern struct state state;
|
||||
|
124
serial_protocol.hpp
Normal file
124
serial_protocol.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
namespace serial_load {
|
||||
|
||||
consteval uint32_t gen_cmd(const char * s)
|
||||
{
|
||||
uint32_t x = 0
|
||||
| s[0] << 0
|
||||
| s[1] << 8
|
||||
| s[2] << 16
|
||||
| s[3] << 24;
|
||||
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
namespace command {
|
||||
constexpr uint32_t write = gen_cmd("WRTE");
|
||||
constexpr uint32_t read = gen_cmd("READ");
|
||||
constexpr uint32_t jump = gen_cmd("JUMP");
|
||||
constexpr uint32_t speed = gen_cmd("SPED");
|
||||
|
||||
static_assert(write == 0x2cc46ed8);
|
||||
static_assert(read == 0xf18d57c7);
|
||||
static_assert(jump == 0xa6696f38);
|
||||
static_assert(speed == 0x27a7a9f4);
|
||||
}
|
||||
|
||||
namespace reply {
|
||||
constexpr uint32_t write = gen_cmd("wrte");
|
||||
constexpr uint32_t read = gen_cmd("read");
|
||||
constexpr uint32_t jump = gen_cmd("jump");
|
||||
constexpr uint32_t speed = gen_cmd("sped");
|
||||
constexpr uint32_t write_crc = gen_cmd("crcW");
|
||||
|
||||
static_assert(write == 0x8c661aaa);
|
||||
static_assert(read == 0x512f23b5);
|
||||
static_assert(jump == 0x06cb1b4a);
|
||||
static_assert(speed == 0x8705dd86);
|
||||
static_assert(write_crc == 0x1cced074);
|
||||
}
|
||||
|
||||
union command_reply {
|
||||
uint8_t u8[16];
|
||||
uint32_t u32[4];
|
||||
struct {
|
||||
uint32_t cmd;
|
||||
uint32_t arg[2];
|
||||
uint32_t crc;
|
||||
};
|
||||
};
|
||||
|
||||
static inline uint32_t le_bswap(const uint32_t n)
|
||||
{
|
||||
if constexpr (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
return n;
|
||||
else
|
||||
return __builtin_bswap32(n);
|
||||
}
|
||||
|
||||
constexpr union command_reply command_reply(uint32_t cmd, uint32_t arg0, uint32_t arg1)
|
||||
{
|
||||
union command_reply command = {
|
||||
.cmd = le_bswap(cmd),
|
||||
.arg = { le_bswap(arg0), le_bswap(arg1) },
|
||||
.crc = 0,
|
||||
};
|
||||
command.crc = le_bswap(crc32(command.u8, 12));
|
||||
return command;
|
||||
}
|
||||
|
||||
constexpr union command_reply write_command(uint32_t dest, uint32_t size)
|
||||
{
|
||||
return command_reply(command::write, dest, size);
|
||||
}
|
||||
|
||||
constexpr union command_reply read_command(uint32_t dest, uint32_t size)
|
||||
{
|
||||
return command_reply(command::read, dest, size);
|
||||
}
|
||||
|
||||
constexpr union command_reply jump_command(uint32_t dest)
|
||||
{
|
||||
return command_reply(command::jump, dest, 0);
|
||||
}
|
||||
|
||||
constexpr union command_reply speed_command(uint32_t speed)
|
||||
{
|
||||
return command_reply(command::speed, speed, 0);
|
||||
}
|
||||
|
||||
constexpr union command_reply write_reply(uint32_t dest, uint32_t size)
|
||||
{
|
||||
return command_reply(reply::write, dest, size);
|
||||
}
|
||||
|
||||
constexpr union command_reply read_reply(uint32_t dest, uint32_t size)
|
||||
{
|
||||
return command_reply(reply::read, dest, size);
|
||||
}
|
||||
|
||||
constexpr union command_reply jump_reply(uint32_t dest)
|
||||
{
|
||||
return command_reply(reply::jump, dest, 0);
|
||||
}
|
||||
|
||||
constexpr union command_reply speed_reply(uint32_t speed)
|
||||
{
|
||||
return command_reply(reply::speed, speed, 0);
|
||||
}
|
||||
|
||||
constexpr union command_reply write_crc_reply(uint32_t crc)
|
||||
{
|
||||
return command_reply(reply::write_crc, crc, 0);
|
||||
}
|
||||
|
||||
}
|
@ -24,6 +24,19 @@ static inline void init_wait()
|
||||
sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1
|
||||
}
|
||||
|
||||
void reset_txrx()
|
||||
{
|
||||
using namespace scif;
|
||||
|
||||
sh7091.SCIF.SCFCR2 |= ( scfcr2::tfrst::reset_operation_enabled
|
||||
| scfcr2::rfrst::reset_operation_enabled
|
||||
);
|
||||
|
||||
sh7091.SCIF.SCFCR2 &= ~( scfcr2::tfrst::reset_operation_enabled
|
||||
| scfcr2::rfrst::reset_operation_enabled
|
||||
);
|
||||
}
|
||||
|
||||
void init(uint8_t bit_rate)
|
||||
{
|
||||
using namespace scif;
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
namespace serial {
|
||||
|
||||
void reset_txrx();
|
||||
|
||||
void init(uint8_t bit_rate);
|
||||
|
||||
void character(const char c);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "sh7091/sh7091.hpp"
|
||||
#include "sh7091/sh7091_bits.hpp"
|
||||
|
||||
/*
|
||||
@ -42,7 +43,7 @@
|
||||
|
||||
namespace serial {
|
||||
|
||||
static void recv_dma(void * destination_address, uint32_t length)
|
||||
static void recv_dma(uint32_t destination_address, uint32_t length)
|
||||
{
|
||||
using namespace dmac;
|
||||
/* Initial settings (SAR, DAR, DMATCR, CHCR, DMAOR) */
|
||||
@ -53,13 +54,10 @@ static void recv_dma(void * destination_address, uint32_t length)
|
||||
// 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<uint32_t>(&sh7091.SCIF.SCFRDR2);
|
||||
sh7091.DMAC.DAR1 = reinterpret_cast<uint32_t>(destination_address);
|
||||
sh7091.DMAC.DAR1 = destination_address;
|
||||
sh7091.DMAC.DMATCR1 = length & 0x00ff'ffff;
|
||||
|
||||
// SSA (only used for PCMCIA)
|
||||
|
@ -1,6 +1,3 @@
|
||||
/* reserve bytes for serial program loader */
|
||||
__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - __stack_reservation;
|
||||
|
||||
__text_link_start = ADDR(.text);
|
||||
__text_link_end = ADDR(.text) + SIZEOF(.text);
|
||||
__text_load_start = LOADADDR(.text);
|
||||
|
@ -4,21 +4,24 @@ CXXFLAGS = -std=c++23
|
||||
FREETYPE_CFLAGS = $(shell pkg-config --cflags freetype2)
|
||||
FREETYPE_LDFLAGS = $(shell pkg-config --libs freetype2)
|
||||
|
||||
FTDI_CFLAGS = $(shell pkg-config --cflags libftdi1)
|
||||
FTDI_CFLAGS = $(shell pkg-config --cflags libftdi1) -I..
|
||||
FTDI_LDFLAGS = $(shell pkg-config --libs libftdi1)
|
||||
|
||||
all: ttf_outline
|
||||
|
||||
crc32.o: ../crc32.c
|
||||
$(CC) -std=gnu2x $(CFLAGS) -I.. -c $< -o $@
|
||||
|
||||
ttf_%.o: ttf_%.cpp
|
||||
$(CXX) $(CFLAGS) $(FREETYPE_CFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||
$(CXX) $(CFLAGS) $(CXXFLAGS) $(FREETYPE_CFLAGS) -c $< -o $@
|
||||
|
||||
ttf_%: ttf_%.o
|
||||
$(CXX) $(LDFLAGS) $(FREETYPE_LDFLAGS) $^ -o $@
|
||||
|
||||
ftdi_%.o: ftdi_%.c
|
||||
$(CC) -std=gnu2x $(CFLAGS) $(FTDI_CFLAGS) -c $< -o $@
|
||||
ftdi_%.o: ftdi_%.cpp
|
||||
$(CXX) $(CFLAGS) $(CXXFLAGS) $(FTDI_CFLAGS) -c $< -o $@
|
||||
|
||||
ftdi_%: ftdi_%.o
|
||||
ftdi_%: ftdi_%.o crc32.o
|
||||
$(CXX) $(LDFLAGS) $(FTDI_LDFLAGS) $^ -o $@
|
||||
|
||||
ttf_outline: ttf_outline.o 2d_pack.o
|
||||
|
37
tools/command_gen.py
Normal file
37
tools/command_gen.py
Normal file
@ -0,0 +1,37 @@
|
||||
def gen_cmd(s):
|
||||
x = (0
|
||||
| s[0] << 0
|
||||
| s[1] << 8
|
||||
| s[2] << 16
|
||||
| s[3] << 24
|
||||
)
|
||||
|
||||
x ^= (x << 13) & 0xffff_ffff
|
||||
x ^= (x >> 17) & 0xffff_ffff
|
||||
x ^= (x << 5) & 0xffff_ffff
|
||||
|
||||
return x
|
||||
|
||||
commands = [
|
||||
"WRTE",
|
||||
"READ",
|
||||
"JUMP",
|
||||
"SPED",
|
||||
]
|
||||
|
||||
replies = [
|
||||
"wrte",
|
||||
"read",
|
||||
"jump",
|
||||
"sped",
|
||||
"crcW",
|
||||
]
|
||||
|
||||
for c in commands:
|
||||
x = gen_cmd(c.encode('ascii'))
|
||||
print(c, f"{x:08x}")
|
||||
|
||||
|
||||
for c in replies:
|
||||
x = gen_cmd(c.encode('ascii'))
|
||||
print(c, f"{x:08x}")
|
@ -9,23 +9,26 @@
|
||||
#include <ftdi.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "crc32.h"
|
||||
#include "serial_protocol.hpp"
|
||||
|
||||
extern int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi,
|
||||
unsigned short *value, unsigned short *index);
|
||||
|
||||
int dreamcast_rates[] = {
|
||||
1562500,
|
||||
781250,
|
||||
520833,
|
||||
390625,
|
||||
312500,
|
||||
260416,
|
||||
223214,
|
||||
195312,
|
||||
173611,
|
||||
156250,
|
||||
142045,
|
||||
130208,
|
||||
120192
|
||||
1562500, // 0
|
||||
781250, // 1
|
||||
520833, // 2
|
||||
390625, // 3
|
||||
312500, // 4
|
||||
260416, // 5
|
||||
223214, // 6
|
||||
195312, // 7
|
||||
173611, // 8
|
||||
156250, // 9
|
||||
142045, // 10
|
||||
130208, // 11
|
||||
120192 // 12
|
||||
};
|
||||
|
||||
int init_ftdi_context(struct ftdi_context * ftdi)
|
||||
@ -63,9 +66,9 @@ int init_ftdi_context(struct ftdi_context * ftdi)
|
||||
}
|
||||
ftdi_list_free(&devlist);
|
||||
|
||||
/*
|
||||
unsigned short value;
|
||||
unsigned short index;
|
||||
|
||||
for (unsigned int i = 0; i < (sizeof (dreamcast_rates)) / (sizeof (dreamcast_rates[0])); i++) {
|
||||
int baud = convert_baudrate_UT_export(dreamcast_rates[i], ftdi, &value, &index);
|
||||
float baudf = baud;
|
||||
@ -73,15 +76,21 @@ int init_ftdi_context(struct ftdi_context * ftdi)
|
||||
float error = (baudf > ratef) ? ratef / baudf : baudf / ratef;
|
||||
fprintf(stdout, "%d: best: %d, error: %f\n", dreamcast_rates[i], baud, (1.f - error) * 100.f);
|
||||
}
|
||||
*/
|
||||
|
||||
res = ftdi_set_baudrate(ftdi, 1562500);
|
||||
//res = ftdi_set_baudrate(ftdi, 312500);
|
||||
res = ftdi_set_baudrate(ftdi, dreamcast_rates[0]);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "ftdi_set_baudrate\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = ftdi_set_line_property(ftdi, 8, STOP_BIT_1, NONE);
|
||||
res = ftdi_set_line_property2(ftdi, BITS_8, STOP_BIT_1, NONE, BREAK_ON);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "ftdi_set_line_property\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = ftdi_set_line_property2(ftdi, BITS_8, STOP_BIT_1, NONE, BREAK_OFF);
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "ftdi_set_line_property\n");
|
||||
return -1;
|
||||
@ -117,15 +126,7 @@ union data_command {
|
||||
};
|
||||
uint8_t data[4 * 3];
|
||||
};
|
||||
static_assert((sizeof (union data_command)) == 4 * 3);
|
||||
|
||||
uint32_t bswap(const uint32_t n)
|
||||
{
|
||||
if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
return n;
|
||||
else
|
||||
return __builtin_bswap32(n);
|
||||
}
|
||||
static_assert((sizeof (union data_command)) == 12);
|
||||
|
||||
long read_with_timeout(struct ftdi_context * ftdi, uint8_t * read_buf, const long expect_length)
|
||||
{
|
||||
@ -167,79 +168,110 @@ long max(long a, long b)
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
void symmetric(struct ftdi_context * ftdi, const uint8_t * tx_buf, const long size)
|
||||
{
|
||||
int res;
|
||||
uint8_t rx_buf[size];
|
||||
long tx_offset = 0;
|
||||
long rx_offset = 0;
|
||||
|
||||
while (tx_offset < size) {
|
||||
long txrx_diff = tx_offset - rx_offset;
|
||||
long tx_length = max(min(min(chunk_size, size - tx_offset), chunk_size - txrx_diff), 0);
|
||||
|
||||
if (tx_length > 0) {
|
||||
res = ftdi_write_data(ftdi, &tx_buf[tx_offset], tx_length);
|
||||
assert(res >= 0);
|
||||
tx_offset += res;
|
||||
}
|
||||
|
||||
res = ftdi_read_data(ftdi, &rx_buf[rx_offset], size - rx_offset);
|
||||
assert(res >= 0);
|
||||
rx_offset += res;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (tx_buf[i] != rx_buf[i]) {
|
||||
fprintf(stderr, "mismatch at %d\n", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "equal\n");
|
||||
}
|
||||
|
||||
double timespec_difference(struct timespec const * const a, struct timespec const * const b)
|
||||
{
|
||||
return (double)(a->tv_sec - b->tv_sec) + (double)(a->tv_nsec - b->tv_nsec) / 1'000'000'000.0;
|
||||
}
|
||||
|
||||
int transfer(struct ftdi_context * ftdi, const uint8_t * buf, const long size)
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
int read_reply(struct ftdi_context * ftdi, uint32_t expected_cmd, union serial_load::command_reply& reply)
|
||||
{
|
||||
using namespace serial_load;
|
||||
|
||||
constexpr long read_length = (sizeof (union serial_load::command_reply));
|
||||
|
||||
long length = read_with_timeout(ftdi, reply.u8, read_length);
|
||||
if (length != read_length) {
|
||||
fprintf(stderr, "short read; want %ld bytes; received: %ld\n", read_length, length);
|
||||
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);
|
||||
dump_command_reply(reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (reply.cmd != expected_cmd) {
|
||||
fprintf(stderr, "invalid reply; remote cmd %08x; expected cmd: %08x\n", reply.cmd, expected_cmd);
|
||||
dump_command_reply(reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_write(struct ftdi_context * ftdi, const uint8_t * buf, const uint32_t size)
|
||||
{
|
||||
int res;
|
||||
|
||||
union data_command command = {
|
||||
.command = {'D', 'A', 'T', 'A'},
|
||||
.size = bswap(size),
|
||||
.dest = bswap(0xac010000),
|
||||
};
|
||||
|
||||
res = ftdi_write_data(ftdi, command.data, (sizeof (union data_command)));
|
||||
assert(res >= 0);
|
||||
|
||||
const char * expect = "data\n";
|
||||
const long expect_length = 5;
|
||||
uint8_t read_buf[expect_length + 1];
|
||||
read_buf[expect_length] = 0;
|
||||
long read_length = read_with_timeout(ftdi, read_buf, expect_length);
|
||||
if (read_length != expect_length) {
|
||||
fprintf(stderr, "want %ld bytes; received: %ld\n", expect_length, read_length);
|
||||
return -1;
|
||||
}
|
||||
res = memcmp(read_buf, expect, expect_length);
|
||||
const uint32_t dest = 0xac010000;
|
||||
union serial_load::command_reply command = serial_load::write_command(dest, 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::write, reply);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "expect `%s`; received: `%s`\n", expect, read_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "OK\n");
|
||||
fprintf(stderr, "remote: dest: %08x size: %08x\n", reply.arg[0], reply.arg[1]);
|
||||
if (reply.arg[0] != dest || reply.arg[1] != size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct timespec start;
|
||||
struct timespec end;
|
||||
res = clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
symmetric(ftdi, buf, size);
|
||||
assert(res == 0);
|
||||
res = ftdi_write_data(ftdi, buf, size);
|
||||
assert(res >= 0);
|
||||
assert((uint32_t)res == size);
|
||||
res = clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
assert(res == 0);
|
||||
fprintf(stderr, "symmetric time: %.03f\n", timespec_difference(&end, &start));
|
||||
|
||||
uint32_t buf_crc = crc32(buf, size);
|
||||
|
||||
union serial_load::command_reply crc_reply;
|
||||
res = read_reply(ftdi, serial_load::reply::write_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 do_jump(struct ftdi_context * ftdi)
|
||||
{
|
||||
int res;
|
||||
|
||||
const uint32_t dest = 0xac010000;
|
||||
|
||||
union serial_load::command_reply command = serial_load::jump_command(dest);
|
||||
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::jump, reply);
|
||||
if (res != 0) {
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "remote: jump: %08x\n", reply.arg[0]);
|
||||
if (reply.arg[0] != dest || reply.arg[1] != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -273,12 +305,14 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s off %ld\n", argv[1], off);
|
||||
uint8_t buf[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;
|
||||
}
|
||||
printf("%02x\n", buf[0]);
|
||||
|
||||
ret = fclose(file);
|
||||
if (ret < 0) {
|
||||
@ -300,13 +334,25 @@ int main(int argc, char * argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int return_code = EXIT_SUCCESS;
|
||||
|
||||
struct timespec start;
|
||||
struct timespec end;
|
||||
res = clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
int transfer_ret = transfer(ftdi, buf, off);
|
||||
assert(res >= 0);
|
||||
int do_write_ret = do_write(ftdi, buf, off);
|
||||
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_jump(ftdi);
|
||||
} else {
|
||||
return_code = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stderr, "time: %.03f\n", timespec_difference(&end, &start));
|
||||
res = clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
assert(res >= 0);
|
||||
fprintf(stderr, "total time: %.03f\n", timespec_difference(&end, &start));
|
||||
|
||||
return transfer_ret;
|
||||
return return_code;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user