From 68e21103e09c7a59292485ab805683760b86e6ba Mon Sep 17 00:00:00 2001 From: Xavi Del Campo Date: Sun, 8 Mar 2020 17:23:03 +0100 Subject: Implemented message protocol, not tested yet --- src/Serial.c | 42 ++++++------- src/System.c | 9 +-- src/main.c | 118 ----------------------------------- src/reception.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 204 insertions(+), 151 deletions(-) (limited to 'src') diff --git a/src/Serial.c b/src/Serial.c index f91f168..10bb90f 100644 --- a/src/Serial.c +++ b/src/Serial.c @@ -6,38 +6,29 @@ #include #include #include +#include "reception.h" -enum -{ - FIFO_SZ = 128 -}; - -typedef volatile struct -{ - unsigned char buf[FIFO_SZ]; - size_t pending, processed; - bool full; -} fifo; - -static fifo rx; +fifo rx; -void sio_handler_callback(void) +static void sio_handler_callback(void) { while (SIOCheckInBuffer()) { const unsigned char in = SIOReadByte(); size_t aux = rx.pending; - if (++aux >= (sizeof rx.buf / sizeof *rx.buf)) + if (++aux >= sizeof rx.buf / sizeof *rx.buf) aux = 0; if (aux != rx.processed) { rx.buf[aux] = in; - rx.pending = rx.processed; + rx.pending = aux; + reception_ev(); } else { + printf("fifo full\n"); rx.full = true; } } @@ -78,22 +69,27 @@ void SerialInit(void) }; const int not_crit = EnterCriticalSection(); - void sio_handler(void); + + EnterCriticalSection(); SIOReset(); SIOStart(BAUD_RATE); - const int sio_handle = OpenEvent(SIO_CLASS, SPEC_GENERAL_INTERRUPT, TRIGGER_CALLBACK, sio_handler); + IMASK |= 1 << INT_SIO; - if (sio_handle != 0xFFFFFFFF) - EnableEvent(sio_handle); + void sio_handler(void); + const int sio_handle = OpenEvent(SIO_CLASS, SPEC_GENERAL_INTERRUPT, TRIGGER_CALLBACK, sio_handler_callback); - IMASK |= 1 << INT_SIO; + if (sio_handle != -1) + EnableEvent(sio_handle); SIOEnableRXInterrupt(); if (not_crit) - { ExitCriticalSection(); - } +} + +void SerialWrite(const unsigned char byte) +{ + SIOSendByte(byte); } diff --git a/src/System.c b/src/System.c index 05a9b9b..9250682 100644 --- a/src/System.c +++ b/src/System.c @@ -7,11 +7,12 @@ void SystemInit(void) { redirect_stdio_to_sio(); -#if 0 - PSX_InitEx(PSX_INIT_SAVESTATE | PSX_INIT_CD); -#else PSX_InitEx(0); -#endif SerialInit(); GfxInit(); } + +void SystemDeinit(void) +{ + PSX_DeInit(); +} diff --git a/src/main.c b/src/main.c index 8c958b5..b14ffb5 100644 --- a/src/main.c +++ b/src/main.c @@ -7,124 +7,6 @@ int main(void) { SystemInit(); - reception_loop(); - - for (;;) - ; - -#if 0 - { - uint32_t initPC_Address; - uint32_t RAMDest_Address; - uint32_t ExeSize = 0; - uint32_t i; - void (*exeAddress)(void); - - GfxSetGlobalLuminance(0); - - SerialInit(); - - /* Read PSX-EXE header (32 bytes will be enough). */ - - SerialSetState(SERIAL_STATE_READING_HEADER); - - SerialRead(inBuffer, 32); - - /* Get initial program counter address from PSX-EXE header. */ - - initPC_Address = (inBuffer[0x10] | (inBuffer[0x11] << 8) | (inBuffer[0x12] << 16) | (inBuffer[0x13] << 24) ); - - SerialSetPCAddress(initPC_Address); - - /* dprintf("initPC_Address = 0x%08X\n", initPC_Address); */ - - /* Get destination address in RAM from PSX-EXE header. */ - - RAMDest_Address = (inBuffer[0x18] | (inBuffer[0x19] << 8) | (inBuffer[0x1A] << 16) | (inBuffer[0x1B] << 24) ); - - SerialSetRAMDestAddress(RAMDest_Address); - - /* dprintf("RAMDest_Address = 0x%08X\n", RAMDest_Address); */ - - /* We have received all data correctly. Send ACK. */ - - memset(inBuffer, 0, SystemGetBufferSize()); - - SerialSetState(SERIAL_STATE_WRITING_ACK); - - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); /* Write ACK */ - - /* Get PSX-EXE size, without header, in hexadecimal, little-endian format; */ - - SerialSetState(SERIAL_STATE_READING_EXE_SIZE); - - SerialRead(inBuffer, sizeof(uint32_t) ); - - for (i = 0; i < sizeof(uint32_t); i++) - { - ExeSize |= inBuffer[i] << (i << 3); /* (i << 3) == (i * 8) */ - } - - SerialSetExeSize(ExeSize); - - /* DEBUG_PRINT_VAR(ExeSize); */ - - SerialSetState(SERIAL_STATE_CLEANING_MEMORY); - - exeAddress = (void*)initPC_Address; - - /* Clean memory where EXE data will be loaded, just in case... */ - - memset((void*)RAMDest_Address, 0, (uint32_t)((uint32_t)(&_start) - (uint32_t)(RAMDest_Address) ) ); - - SerialSetState(SERIAL_STATE_WRITING_ACK); - - /* We have received PSX-EXE size (without header) correctly. Send ACK. */ - - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); /* Write ACK */ - - SerialSetState(SERIAL_STATE_READING_EXE_DATA); - - while (GfxIsGPUBusy() == true); - - for (i = 0; i < ExeSize; i += EXE_DATA_PACKET_SIZE) - { - uint32_t bytes_to_read; - - /* Read actual EXE data into proper RAM address. */ - - if ( (i + EXE_DATA_PACKET_SIZE) >= ExeSize) - { - bytes_to_read = ExeSize - i; - } - else - { - bytes_to_read = EXE_DATA_PACKET_SIZE; - } - - SerialRead((uint8_t*)RAMDest_Address + i, bytes_to_read); - - SerialSetExeBytesReceived(bytes_to_read); - - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); /* Write ACK */ - } - - SetVBlankHandler(&ISR_SystemDefaultVBlank); - - /* Make a pretty animation before exeting OpenSend application. */ - - EndAnimation(); - - PSX_DeInit(); - - /* PSX-EXE has been successfully loaded into RAM. Run executable! */ - - /* dprintf("Entering exe...\n"); */ - - exeAddress(); - } -#endif - return 0; } diff --git a/src/reception.c b/src/reception.c index 12c1866..6e07ed7 100644 --- a/src/reception.c +++ b/src/reception.c @@ -1,26 +1,200 @@ #include "reception.h" +#include "System.h" #include "Serial.h" #include +#include +#include +#include -static volatile bool rx; +static volatile bool input_available; + +#define STATES \ + X(magic_byte) \ + X(psx_exe_header) \ + X(dump) \ + X(done) static enum { - +#define X(s) state_##s, + STATES +#undef X } state; -void reception_ev(void) +int (*init_pc)(void); +unsigned char *init_addr; +size_t sz; + +static void ack(void) +{ + enum + { + ACK = 'b' + }; + + SerialWrite(ACK); +} + +static size_t done(void) +{ + return 0; +} + +static size_t dump(void) +{ + size_t aux = rx.processed; + bool done = false; + + while (aux != rx.pending) + { + enum + { + PACKET_SZ = 128 + }; + + static size_t total, packet; + + if (++aux >= sizeof rx.buf / sizeof *rx.buf) + aux = 0; + + init_addr[total] = rx.buf[aux]; + + if (++packet >= PACKET_SZ) + { + ack(); + packet = 0; + } + + if (++total >= sz) + { + done = true; + break; + } + } + + if (done) + { + state = state_done; + } + + return aux; +} + +static size_t psx_exe_header(void) +{ + typedef const struct + { + unsigned char id[8]; + unsigned char unused[8]; + void *init_addr; + void *init_gp; + void *init_pc; + size_t sz; + } __attribute__((packed)) decoded_header; + + size_t aux = rx.processed; + unsigned char header[sizeof (decoded_header)]; + bool full = false; + + while (aux != rx.pending) + { + static size_t i; + + if (++aux >= sizeof rx.buf / sizeof *rx.buf) + aux = 0; + + header[i] = rx.buf[aux]; + + _Static_assert (sizeof (decoded_header) == 32, "unexpected struct size"); + + if (++i >= sizeof (decoded_header)) + { + full = true; + break; + } + } + + if (full) + { + decoded_header *const decoded = (const void *)header; + + if (!strcmp((const char *)decoded->id, "PS-X EXE")) + { + if (decoded->init_pc == (const void *)0x80010000) + { + init_pc = decoded->init_pc + 0x14800; + init_addr = decoded->init_addr + 0x14800; + } + else + { + init_pc = decoded->init_pc; + init_addr = decoded->init_addr; + } + + printf("init_pc=%p,init_addr=%p,sz=%d\n", init_pc, init_addr, sz); + + sz = decoded->sz; + + ack(); + state = state_dump; + } + } + + return aux; +} + +static size_t magic_byte(void) { - rx = true; + size_t aux = rx.processed; + + if (++aux >= sizeof rx.buf / sizeof *rx.buf) + aux = 0; + + { + enum + { + MAGIC_BYTE = 99 + }; + + const unsigned char in = rx.buf[aux]; + + if (in == MAGIC_BYTE) + { + state = state_psx_exe_header; + ack(); + } + } + + return aux; } void reception_loop(void) { - for (;;) + while (state != state_done) { - if (rx) + if (input_available && rx.pending != rx.processed) { + static size_t (*const h[])(void) = + { +#define X(s) [state_##s] = s, + STATES +#undef X + }; + + rx.processed = h[state](); + input_available = false; } } + + if (init_pc) + { + SystemDeinit(); + init_pc(); + } +} + +void reception_ev(void) +{ + input_available = true; } -- cgit v1.2.3