serial_transfer: self-relocate to the end of system memory

The serial_transfer loader, as long as the target program voluntarily
terminates itself at some point, is able to load multiple programs
consecutively without requiring a physical power cycle to reload the
transfer program from CD.

The current example.mk juggles between two different "memory layouts",
one for "burn to a physical CD" and another for "load via serial
cable". Because the serial_transfer program now relocates itself to
the end of system memory, this means the 0x8c010000 area is now usable
by programs that are loaded by serial_transfer.
This commit is contained in:
Zack Buhman 2024-03-13 20:56:37 +08:00
parent 0806ed9ac7
commit d912278afd
14 changed files with 209 additions and 40 deletions

View File

@ -1,7 +1,8 @@
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
MEMORY
{
p1ram : ORIGIN = 0x8c020000, LENGTH = 0xff0000
p2ram : ORIGIN = 0xac020000, LENGTH = 0xff0000
p1ram : ORIGIN = 0x8c020000, LENGTH = 0xfe0000
p2ram : ORIGIN = 0xac020000, LENGTH = 0xfe0000
}
__stack_reservation = 0x1000;
INCLUDE "common.lds"

View File

@ -70,7 +70,11 @@ def do(ser, b):
sync(ser, b'prime', wait=0)
do(ser, b)
print("\nDATA")
start = time.monotonic()
ret = symmetric(ser, b)
end = time.monotonic()
duration = end - start
print("duration", duration)
print(ret[-5:])
if ret[:-5] != b:
print("ret != b; dumped to asdf.bin")
@ -96,8 +100,8 @@ def console(ser):
with open(sys.argv[1], 'rb') as f:
b = f.read()
#with serial.Serial('/dev/ttyUSB0', 120192, timeout=1) as ser:
with serial.Serial('/dev/ttyUSB0', 312500, timeout=1) as ser:
with serial.Serial('/dev/ttyUSB0', 120192, timeout=1) as ser:
#with serial.Serial('/dev/ttyUSB0', 312500, timeout=1) as ser:
#console(ser)
print("waiting: ", end=' ')
sys.stdout.flush()

View File

@ -44,13 +44,5 @@ SECTIONS
INCLUDE "debug.lds"
}
__p1ram_start = ORIGIN(p1ram);
__p1ram_end = ORIGIN(p1ram) + LENGTH(p1ram);
__bss_link_start = ADDR(.bss);
__bss_link_end = ADDR(.bss) + SIZEOF(.bss);
__ctors_link_start = ADDR(.ctors);
__ctors_link_end = ADDR(.ctors) + SIZEOF(.ctors);
INCLUDE "symbols.lds"
INCLUDE "addresses.lds"

View File

@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
DIR := $(dir $(MAKEFILE_PATH))
LIB ?= .
OPT ?= -O3
OPT ?= -Og
GENERATED ?=
AARCH = --isa=sh4 --little
@ -32,6 +32,11 @@ IP_OBJ = \
sg/sg_ini.o \
sg/aip.o
%.o: %.obj
$(OBJCOPY) -g \
--rename-section IP=.text.$* \
$< $@
ip.elf: $(IP_OBJ)
$(LD) --orphan-handling=error --print-memory-usage -T $(LIB)/ip.lds $^ -o $@
@ -42,11 +47,6 @@ START_OBJ = \
include base.mk
%.o: %.obj
$(OBJCOPY) -g \
--rename-section IP=.text.$* \
$< $@
sine.pcm: common.mk
sox \
--rate 44100 \

View File

@ -16,7 +16,9 @@ SPRITE_OBJ = \
holly/core.o \
holly/region_array.o \
holly/background.o \
holly/ta_fifo_polygon_converter.o
holly/ta_fifo_polygon_converter.o \
sh7091/serial.o \
$(LIBGCC)
example/sprite.elf: LDSCRIPT = $(LIB)/alt.lds
example/sprite.elf: $(START_OBJ) $(SPRITE_OBJ)
@ -149,7 +151,7 @@ WIFFLE_ATTENUATION_OBJ = \
holly/background.o \
holly/ta_fifo_polygon_converter.o
example/wiffle_attenuation.elf: LDSCRIPT = $(LIB)/alt.lds
example/wiffle_attenuation.elf: LDSCRIPT = $(LIB)/main.lds
example/wiffle_attenuation.elf: $(START_OBJ) $(WIFFLE_ATTENUATION_OBJ)
MODIFIER_VOLUME_OBJ = \
@ -322,7 +324,7 @@ SERIAL_TRANSFER_OBJ = \
sh7091/serial.o \
serial_load.o
example/serial_transfer.elf: LDSCRIPT = $(LIB)/main.lds
example/serial_transfer.elf: LDSCRIPT = $(LIB)/loader.lds
example/serial_transfer.elf: $(START_OBJ) $(SERIAL_TRANSFER_OBJ)
INTERRUPT_OBJ = \

View File

@ -185,5 +185,8 @@ void main()
theta += half_degree;
frame_ix += 1;
if (frame_ix > 10)
break;
}
}

View File

@ -6,24 +6,19 @@
#include "serial_load.hpp"
extern uint32_t __bss_link_start __asm("__bss_link_start");
extern uint32_t __bss_link_end __asm("__bss_link_end");
void main() __attribute__((section(".text.main")));
void main()
{
serial::init(4);
//serial::init(12);
load_init();
while (1) {
using namespace scif;
while ((sh7091.SCIF.SCFSR2 & scfsr2::tdfe::bit_mask) == 0) {
// wait
}
while ((scfdr2::receive_data_bytes(sh7091.SCIF.SCFDR2)) > 0) {
uint8_t c = sh7091.SCIF.SCFRDR2;
const uint8_t c = sh7091.SCIF.SCFRDR2;
load_recv(c);
}
sh7091.SCIF.SCFSR2 = sh7091.SCIF.SCFSR2 & (~scfsr2::rdf::bit_mask);
}
}

61
loader.lds Normal file
View File

@ -0,0 +1,61 @@
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
MEMORY
{
p1ram : ORIGIN = 0x8c020000, LENGTH = 0xfe0000
p2ram : ORIGIN = 0xac020000, LENGTH = 0xfe0000
ldram : ORIGIN = 0x8cfff000, LENGTH = 0x1000
}
SECTIONS
{
. = ORIGIN(p2ram);
.text.startup ALIGN(4) : SUBALIGN(4)
{
KEEP(*(.text.start))
*(.text.startup.*)
. = ALIGN(4);
} > p2ram AT> p2ram
.ctors ALIGN(4) : SUBALIGN(4)
{
KEEP(*(.ctors))
KEEP(*(.ctors.*))
. = ALIGN(4);
} > p2ram AT> p2ram
. = ORIGIN(ldram);
.text ALIGN(4) : SUBALIGN(4)
{
*(.text.*)
*(.text)
. = ALIGN(4);
} > ldram AT> p2ram
.data ALIGN(4) : SUBALIGN(4)
{
*(.data)
*(.data.*)
. = ALIGN(4);
} > ldram AT> p2ram
.rodata ALIGN(4) : SUBALIGN(4)
{
*(.rodata)
*(.rodata.*)
. = ALIGN(4);
} > ldram AT> p2ram
.bss ALIGN(4) (NOLOAD) : SUBALIGN(4)
{
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
} > ldram
INCLUDE "debug.lds"
}
__stack_reservation = 0x0000;
INCLUDE "symbols.lds"
INCLUDE "addresses.lds"

View File

@ -4,4 +4,5 @@ MEMORY
p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000
p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000
}
__stack_reservation = 0x1000;
INCLUDE "common.lds"

View File

@ -1,27 +1,76 @@
#include <cstdint>
#include <type_traits>
#include "sh7091/cache.hpp"
#include "string.hpp"
extern uint32_t __text_link_start __asm("__text_link_start");
extern uint32_t __text_link_end __asm("__text_link_end");
extern uint32_t __text_load_start __asm("__text_load_start");
extern uint32_t __data_link_start __asm("__data_link_start");
extern uint32_t __data_link_end __asm("__data_link_end");
extern uint32_t __data_load_start __asm("__data_load_start");
extern uint32_t __rodata_link_start __asm("__rodata_link_start");
extern uint32_t __rodata_link_end __asm("__rodata_link_end");
extern uint32_t __rodata_load_start __asm("__rodata_load_start");
extern uint32_t __ctors_link_start __asm("__ctors_link_start");
extern uint32_t __ctors_link_end __asm("__ctors_link_end");
extern uint32_t __bss_link_start __asm("__bss_link_start");
extern uint32_t __bss_link_end __asm("__bss_link_end");
extern void main();
typedef void(init_t)(void);
extern "C"
void runtime_init()
__attribute__((section(".text.startup.runtime_init")));
void copy(uint32_t * start, const uint32_t * end, uint32_t * load)
__attribute__((section(".text.startup.copy")));
void copy(uint32_t * start, const uint32_t * end, uint32_t * load)
{
if (start != load) {
while (start < end) {
*start++ = *load++;
}
}
}
extern "C"
void runtime_init()
{
// relocate text (if necessary)
copy(&__text_link_start, &__text_link_end, &__text_load_start);
// relocate data (if necessary)
copy(&__data_link_start, &__data_link_end, &__data_load_start);
// relocate rodata (if necessary)
copy(&__rodata_link_start, &__rodata_link_end, &__rodata_load_start);
uint32_t * start;
uint32_t * end;
// clear BSS
uint32_t * start = &__bss_link_start;
uint32_t * end = &__bss_link_end;
start = &__bss_link_start;
end = &__bss_link_end;
while (start < end) {
*start++ = 0;
}
cache::init();
main();
// call ctors
start = &__ctors_link_start;
end = &__ctors_link_end;
while (start < end) {
((init_t*)(*start++))();
}
cache::init();
}

View File

@ -2,6 +2,7 @@
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/serial.hpp"
#include "holly/holly.hpp"
enum load_command {
@ -54,6 +55,24 @@ void debug(const char * s)
}
}
void jump_to_func(const uint32_t addr)
{
serial::string("jump to: ");
serial::integer<uint32_t>(addr);
// save our stack
asm volatile ("ldc r15, gbr; "
"mov #0, r15; "
"jsr @%0; "
"nop; "
"stc gbr, r15; "
:
: "r"(addr) /* input */
/* clobbered register */
: "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","macl","mach","gbr","pr"
);
// restore our stack
}
void load_recv(uint8_t c)
{
if (state.command == CMD_NONE)
@ -119,8 +138,7 @@ void load_recv(uint8_t c)
state.command = CMD_NONE;
debug("prejump\n");
holly.VO_BORDER_COL = (31 << 11);
void (*fptr)(void) = (void (*)(void))state.addr1;
fptr();
jump_to_func(state.addr1);
holly.VO_BORDER_COL = (63 << 5) | (31 << 0);
debug("postjump\n");
return;

View File

@ -19,11 +19,20 @@ void init(uint8_t bit_rate)
sh7091.SCIF.SCFCR2 = scfcr2::tfrst::reset_operation_enabled
| scfcr2::rfrst::reset_operation_enabled;
// tx/rx trigger on 1 byte
sh7091.SCIF.SCFCR2 = 0;
sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte
| scfcr2::ttrg::trigger_on_8_bytes
| scfcr2::mce::modem_signals_disabled;
sh7091.SCIF.SCSPTR2 = 0;
sh7091.SCIF.SCLSR2 = 0;
sh7091.SCIF.SCFSR2 = (~scfsr2::er::bit_mask)
& (~scfsr2::tend::bit_mask)
& (~scfsr2::tdfe::bit_mask)
& (~scfsr2::brk::bit_mask)
& (~scfsr2::rdf::bit_mask)
& (~scfsr2::dr::bit_mask)
& 0xffff;
sh7091.SCIF.SCLSR2 = 0; // clear ORER
sh7091.SCIF.SCSCR2 = scscr2::te::transmission_enabled
| scscr2::re::reception_enabled;

13
start.s
View File

@ -10,8 +10,19 @@ _start:
or r1,r0
ldc r0,sr
/* save pr */
sts.l pr,@-r15
/* jump to runtime_init */
mov.l runtime_init_ptr,r0
jsr @r0
nop
/* restore pr */
lds.l @r15+,pr
/* jump to main */
mov.l main_ptr,r0
jmp @r0
nop
@ -22,3 +33,5 @@ imask_all:
.long 0xf0
runtime_init_ptr:
.long _runtime_init
main_ptr:
.long _main

21
symbols.lds Normal file
View File

@ -0,0 +1,21 @@
__p1ram_start = ORIGIN(p1ram);
/* reserve bytes for serial program loader */
__p1ram_end = ORIGIN(p1ram) + LENGTH(p1ram) - __stack_reservation;
__text_link_start = ADDR(.text);
__text_link_end = ADDR(.text) + SIZEOF(.text);
__text_load_start = LOADADDR(.text);
__data_link_start = ADDR(.data);
__data_link_end = ADDR(.data) + SIZEOF(.data);
__data_load_start = LOADADDR(.data);
__rodata_link_start = ADDR(.rodata);
__rodata_link_end = ADDR(.rodata) + SIZEOF(.rodata);
__rodata_load_start = LOADADDR(.rodata);
__ctors_link_start = ADDR(.ctors);
__ctors_link_end = ADDR(.ctors) + SIZEOF(.ctors);
__bss_link_start = ADDR(.bss);
__bss_link_end = ADDR(.bss) + SIZEOF(.bss);