cartridge: initial
The Makefile duplication was done out of laziness; the main Makefile should be rewritten in a similar fashion to this one to allow per-target selection of linker script.
This commit is contained in:
parent
bdaa199ecb
commit
3bb4740030
95
cartridge/Makefile
Normal file
95
cartridge/Makefile
Normal file
@ -0,0 +1,95 @@
|
||||
LIB = ../saturn
|
||||
|
||||
### architecture-specific flags ###
|
||||
|
||||
AARCH = --isa=sh2 --big
|
||||
|
||||
CARCH = -m2 -mb
|
||||
|
||||
### general flags ###
|
||||
|
||||
OPT ?= -O3
|
||||
|
||||
DEBUG = -g -gdwarf-4
|
||||
|
||||
AFLAGS += --fatal-warnings
|
||||
|
||||
CFLAGS += -falign-functions=4 -ffunction-sections -fdata-sections -fshort-enums -ffreestanding -nostdlib
|
||||
CFLAGS += -Wall -Werror -Wfatal-errors
|
||||
CFLAGS += -Wno-array-bounds
|
||||
CFLAGS += -I$(LIB)
|
||||
|
||||
CXXFLAGS += -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics
|
||||
|
||||
LDFLAGS += --gc-sections --print-gc-sections --no-warn-rwx-segment --print-memory-usage --entry=_start --orphan-handling=error
|
||||
LDFLAGS += -L$(LIB)
|
||||
|
||||
DEPFLAGS = -MMD -MP
|
||||
|
||||
### target ###
|
||||
|
||||
TARGET = sh2-none-elf-
|
||||
CC = $(TARGET)gcc
|
||||
CXX = $(TARGET)g++
|
||||
AS = $(TARGET)as
|
||||
LD = $(TARGET)ld
|
||||
OBJCOPY = $(TARGET)objcopy
|
||||
OBJDUMP = $(TARGET)objdump
|
||||
|
||||
### rules ###
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(AARCH) $(AFLAGS) $(DEBUG) $< -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CARCH) $(CFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CARCH) $(CFLAGS) $(CXXFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
|
||||
|
||||
%.elf:
|
||||
$(LD) $(LDFLAGS) -T $(LDSCRIPT) $^ -o $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
du -b $@
|
||||
|
||||
%.ss: %.bin
|
||||
cp $< $@
|
||||
|
||||
%.pcm.o: %.pcm
|
||||
$(OBJCOPY) \
|
||||
-I binary -O elf32-sh -B sh2 \
|
||||
--rename-section .data=.rom.$(basename $@) \
|
||||
$< $@
|
||||
|
||||
### object files ###
|
||||
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_id.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/segasmp/sys_sec.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_area.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_areb.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_aree.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_arej.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_arek.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_arel.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_aret.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_areu.o
|
||||
SYS_IP_OBJ += $(LIB)/ip/sys_init.o
|
||||
|
||||
COMMON_OBJ = start.o runtime.o
|
||||
|
||||
CARTRIDGE_OBJ = main.o wc3.pcm.o
|
||||
cartridge.elf: LDSCRIPT = $(LIB)/cartridge.lds
|
||||
cartridge.elf: $(SYS_IP_OBJ) $(COMMON_OBJ) $(CARTRIDGE_OBJ)
|
||||
|
||||
.SUFFIXES:
|
||||
.INTERMEDIATE:
|
||||
.SECONDARY:
|
||||
.PHONY: all clean
|
||||
|
||||
%: RCS/%,v
|
||||
%: RCS/%
|
||||
%: %,v
|
||||
%: s.%
|
||||
%: SCCS/s.%
|
BIN
cartridge/cartridge.ss
Executable file
BIN
cartridge/cartridge.ss
Executable file
Binary file not shown.
133
cartridge/main.cpp
Normal file
133
cartridge/main.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "vdp1.h"
|
||||
#include "vdp2.h"
|
||||
#include "scsp.h"
|
||||
#include "smpc.h"
|
||||
|
||||
#include "../common/copy.hpp"
|
||||
|
||||
extern void * _wc3_pcm_start __asm("_binary_wc3_pcm_start");
|
||||
extern void * _wc3_pcm_size __asm("_binary_wc3_pcm_size");
|
||||
|
||||
void snd_init()
|
||||
{
|
||||
while ((smpc.reg.SF & 1) != 0);
|
||||
smpc.reg.SF = 1;
|
||||
smpc.reg.COMREG = COMREG__SNDOFF;
|
||||
while (smpc.reg.OREG[31].val != OREG31__SNDOFF);
|
||||
|
||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB;
|
||||
|
||||
volatile uint32_t * dsp_steps = reinterpret_cast<volatile uint32_t *>(&(scsp.reg.dsp.STEP[0].MPRO[0]));
|
||||
fill<volatile uint32_t>(dsp_steps, 0, (sizeof (scsp.reg.dsp.STEP)));
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
scsp.reg.slot[i].SA = 0;
|
||||
scsp.reg.slot[i].MIXER = 0;
|
||||
}
|
||||
|
||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB | MIXER__MVOL(0xf);
|
||||
}
|
||||
|
||||
void snd_step()
|
||||
{
|
||||
const uint16_t * buf = reinterpret_cast<uint16_t*>(&_wc3_pcm_start);
|
||||
const uint32_t size = reinterpret_cast<uint32_t>(&_wc3_pcm_size);
|
||||
constexpr uint32_t chunk_samples = 16384 / 2;
|
||||
constexpr uint32_t chunk_size = chunk_samples * 2;
|
||||
copy<uint16_t>(&scsp.ram.u16[0], buf, chunk_size);
|
||||
|
||||
scsp_slot& slot = scsp.reg.slot[0];
|
||||
// start address (bytes)
|
||||
slot.SA = SA__KYONB | SA__LPCTL__NORMAL | SA__SA(0); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:0]
|
||||
slot.LSA = 0; // loop start address (samples)
|
||||
slot.LEA = chunk_samples * 2; // loop end address (samples)
|
||||
//slot.EG = EG__EGHOLD; // d2r d1r ho ar krs dl rr
|
||||
slot.EG = EG__AR(0x1F) | EG__D1R(0x00) | EG__D2R(0x00) | EG__RR(0x1F);
|
||||
slot.FM = 0; // stwinh sdir tl mdl mdxsl mdysl
|
||||
slot.PITCH = PITCH__OCT(-1) | PITCH__FNS(0); // oct fns
|
||||
slot.LFO = 0; // lfof plfows
|
||||
slot.MIXER = MIXER__DISDL(0b110); // disdl dipan efsdl efpan
|
||||
|
||||
slot.LOOP |= LOOP__KYONEX;
|
||||
|
||||
uint32_t offset = 1;
|
||||
uint32_t chunk = 1;
|
||||
|
||||
constexpr uint32_t timer_a_interrupt = (1 << 6);
|
||||
scsp.reg.ctrl.TIMA = TIMA__TACTL(7)
|
||||
| TIMA__TIMA(128);
|
||||
scsp.reg.ctrl.SCIRE = timer_a_interrupt;
|
||||
|
||||
while (1) {
|
||||
copy<uint16_t>(&scsp.ram.u16[(chunk_size * chunk) / 2], &buf[(chunk_size * offset) / 2], chunk_size);
|
||||
chunk = !chunk;
|
||||
offset = offset + 1;
|
||||
if ((offset * (chunk_size + 1)) > size) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
uint32_t sample = 0;
|
||||
const uint32_t target = chunk_samples * 2;
|
||||
constexpr uint32_t sample_interval = (1 << 10);
|
||||
while (sample < target) {
|
||||
scsp.reg.ctrl.SCIRE = sample_interval;
|
||||
while (!(scsp.reg.ctrl.SCIPD & sample_interval));
|
||||
sample++;
|
||||
}
|
||||
*/
|
||||
while (!(scsp.reg.ctrl.SCIPD & timer_a_interrupt));
|
||||
scsp.reg.ctrl.TIMA = TIMA__TACTL(7)
|
||||
| TIMA__TIMA(128);
|
||||
scsp.reg.ctrl.SCIRE = timer_a_interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void main() __attribute__((section(".text.main")));
|
||||
void main()
|
||||
{
|
||||
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
||||
vdp2.reg.TVMD = ( TVMD__DISP | TVMD__LSMD__NON_INTERLACE
|
||||
| TVMD__VRESO__240 | TVMD__HRESO__NORMAL_320);
|
||||
|
||||
// VDP2 User's Manual:
|
||||
// "When sprite data is in an RGB format, sprite register 0 is selected"
|
||||
// "When the value of a priority number is 0h, it is read as transparent"
|
||||
//
|
||||
// The power-on value of PRISA is zero. Set the priority for sprite register 0
|
||||
// to some number greater than zero, so that the color data is not interpreted
|
||||
// as "transparent".
|
||||
vdp2.reg.PRISA = PRISA__S0PRIN(1); // Sprite register 0 Priority Number
|
||||
|
||||
/* TVM settings must be performed from the second H-blank IN interrupt after the
|
||||
V-blank IN interrupt to the H-blank IN interrupt immediately after the V-blank
|
||||
OUT interrupt. */
|
||||
// "normal" display resolution, 16 bits per pixel, 512x256 framebuffer
|
||||
vdp1.reg.TVMR = TVMR__TVM__NORMAL;
|
||||
|
||||
// swap framebuffers every 1 cycle; non-interlace
|
||||
vdp1.reg.FBCR = 0;
|
||||
|
||||
// erase upper-left coordinate
|
||||
vdp1.reg.EWLR = EWLR__16BPP_X1(0) | EWLR__Y1(0);
|
||||
|
||||
// erase lower-right coordinate
|
||||
vdp1.reg.EWRR = EWRR__16BPP_X3(319) | EWRR__Y3(239);
|
||||
|
||||
// during a framebuffer erase cycle, write the color "black" to each pixel
|
||||
const uint16_t black = 1 << 15 | 0x00ff;
|
||||
vdp1.reg.EWDR = black;
|
||||
|
||||
vdp1.vram.cmd[0].CTRL = CTRL__END;
|
||||
|
||||
snd_init();
|
||||
snd_step();
|
||||
|
||||
vdp2.reg.BGON = 0;
|
||||
|
||||
// start drawing (execute the command list) on every frame
|
||||
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
||||
|
||||
while (1);
|
||||
}
|
67
cartridge/runtime.c
Normal file
67
cartridge/runtime.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include <stdint.h>
|
||||
|
||||
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");
|
||||
|
||||
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 void main(void);
|
||||
|
||||
typedef void(init_t)(void);
|
||||
|
||||
void runtime_init(void)
|
||||
__attribute__((section(".text.startup.runtime_init")));
|
||||
|
||||
void runtime_init(void)
|
||||
{
|
||||
// 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
|
||||
start = &__bss_link_start;
|
||||
end = &__bss_link_end;
|
||||
while (start < end) {
|
||||
*start++ = 0;
|
||||
}
|
||||
|
||||
// call ctors
|
||||
start = &__ctors_link_start;
|
||||
end = &__ctors_link_end;
|
||||
while (start < end) {
|
||||
((init_t*)(*start++))();
|
||||
}
|
||||
}
|
37
cartridge/start.s
Normal file
37
cartridge/start.s
Normal file
@ -0,0 +1,37 @@
|
||||
.section .text.start
|
||||
.global _start
|
||||
_start:
|
||||
/* set stack pointer */
|
||||
mov.l stack_end_ptr,r15
|
||||
|
||||
/* mask all interrupts */
|
||||
mov.l imask_all,r0
|
||||
stc sr,r1
|
||||
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
|
||||
|
||||
.align 4
|
||||
stack_end_ptr:
|
||||
.long __stack_end
|
||||
imask_all:
|
||||
.long 0xf0
|
||||
runtime_init_ptr:
|
||||
.long _runtime_init
|
||||
main_ptr:
|
||||
.long _main
|
Loading…
x
Reference in New Issue
Block a user