dreamcast2: add framebuffer_shaded example

This commit is contained in:
Zack Buhman 2025-08-24 22:16:29 -05:00
parent 8e97614ffe
commit 5f61aaa483
29 changed files with 1553 additions and 1043 deletions

View File

@ -1,30 +1,9 @@
%.csv: %.ods include base.mk
libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $<
OPT = -O2
# HOLLY MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
CFLAGS += -I$(MAKEFILE_PATH)
LIB ?= $(MAKEFILE_PATH)
holly/holly.hpp: regs/holly/holly.csv regs/holly.py include example/example.mk
python regs/holly.py $< > $@
holly/holly_bits.hpp: regs/holly/holly_bits.csv regs/holly_bits.py
python regs/holly_bits.py $< holly > $@
holly/region_array_bits.hpp: regs/holly/region_array_bits.csv regs/holly_bits.py
python regs/holly_bits.py $< holly region_array > $@
# SH7091
sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/sh7091.py
python regs/sh7091.py $< > $@
sh7091/sh7091_bits.hpp: regs/sh7091/sh7091_bits.csv regs/holly_bits.py
python regs/holly_bits.py $< sh7091 > $@
# SYSTEMBUS
systembus/systembus.hpp: regs/systembus/systembus.csv regs/holly.py
python regs/holly.py $< > $@
systembus/systembus_bits.hpp: regs/systembus/systembus_bits.csv regs/holly_bits.py
python regs/holly_bits.py $< system > $@

32
dreamcast2/addresses.lds Normal file
View File

@ -0,0 +1,32 @@
system_boot_rom = 0xa0000000;
system = 0xa05f6800;
maple_if = 0xa05f6c00;
gdrom_if = 0xa05f7000;
g1_if = 0xa05f7400;
g2_if = 0xa05f7800;
pvr_if = 0xa05f7c00;
holly = 0xa05f8000;
modem = 0xa0600000;
aica_sound = 0xa0700000;
aica_rtc = 0xa0710000;
system_boot_rom = 0xa0000000;
aica_wave_memory = 0xa0800000;
texture_memory64 = 0xa4000000;
texture_memory32 = 0xa5000000;
system_memory = 0xac000000;
ta_fifo_polygon_converter = 0x10000000;
ta_fifo_yuv_converter = 0x10800000;
ta_fifo_texture_memory = 0x11000000;
ta_fifo_polygon_converter_mirror = 0x12000000;
ta_fifo_yuv_converter_mirror = 0x12800000;
ta_fifo_texture_memory_mirror = 0x13000000;
store_queue = 0xe0000000;
sh7091_ic_a = 0xf0000000;
sh7091_ic_d = 0xf1000000;
sh7091_oc_a = 0xf4000000;
sh7091_oc_d = 0xf5000000;
sh7091 = 0xff000000;

74
dreamcast2/base.mk Normal file
View File

@ -0,0 +1,74 @@
################################################################################
# architecture flags
################################################################################
AARCH = --isa=sh4 --little
CARCH ?= -m4-single-only -ml
CFLAGS += -mfsca -mfsrra -funsafe-math-optimizations -ffast-math
OBJARCH = -O elf32-shl -B sh4
TARGET = sh4-none-elf-
################################################################################
# architecture-agnostic flags
################################################################################
DEBUG = -g -gdwarf-4
AFLAGS += --fatal-warnings
CSTD ?= -std=gnu23
CXXSTD ?= -std=c++23
CFLAGS += -ffreestanding -nostdlib -fno-builtin
CFLAGS += -falign-functions=4
CFLAGS += -ffunction-sections -fdata-sections -fshort-enums
CFLAGS += -Wall -Werror -Wfatal-errors -Winline
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
CFLAGS += -D__dreamcast__
CXXFLAGS += -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics
LDFLAGS += --gc-sections --no-warn-rwx-segment --print-memory-usage --entry=_start --orphan-handling=error
DEPFLAGS = -MMD -MP
################################################################################
# toolchain
################################################################################
CC = $(TARGET)gcc
CXX = $(TARGET)g++
AS = $(TARGET)as
LD = $(TARGET)ld
OBJCOPY = $(TARGET)objcopy
OBJDUMP = $(TARGET)objdump
################################################################################
# base rules
################################################################################
%.o: %.s
$(AS) $(AARCH) $(AFLAGS) $(DEBUG) $< -o $@
%.o: %.c
$(CC) $(CARCH) $(CFLAGS) $(CSTD) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
%.o: %.cpp
$(CXX) $(CARCH) $(CFLAGS) $(CXXSTD) $(CXXFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
%.elf:
$(LD) $(LDFLAGS) -L $(LIB) -T $(LDSCRIPT) $^ -o $@
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
du -b $@
-include $(shell find -type f -name '*.d')

29
dreamcast2/binary.mk Normal file
View File

@ -0,0 +1,29 @@
define BUILD_BINARY_O
$(OBJCOPY) \
-I binary $(OBJARCH) \
--rename-section .data=.data.$(basename $@) \
$< $@
endef
makefile_path := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
makefile_relative = $(shell realpath --relative-to $(makefile_path) $(1))
as_obj_binary = _binary_$(subst -,_,$(subst .,_,$(subst /,_,$(subst .h,,$(call makefile_relative,$(1))))))
define BUILD_BINARY_H
@echo gen $(call makefile_relative,$@)
@echo '#pragma once' > $@
@echo '' >> $@
@echo '#include <stdint.h>' >> $@
@echo '' >> $@
@echo '#ifdef __cplusplus' >> $@
@echo 'extern "C" {' >> $@
@echo '#endif' >> $@
@echo '' >> $@
@echo 'extern uint32_t $(call as_obj_binary,$@)_start __asm("$(call as_obj_binary,$@)_start");' >> $@
@echo 'extern uint32_t $(call as_obj_binary,$@)_end __asm("$(call as_obj_binary,$@)_end");' >> $@
@echo 'extern uint32_t $(call as_obj_binary,$@)_size __asm("$(call as_obj_binary,$@)_size");' >> $@
@echo '' >> $@
@echo '#ifdef __cplusplus' >> $@
@echo '}' >> $@
@echo '#endif' >> $@
endef

58
dreamcast2/common.lds Normal file
View File

@ -0,0 +1,58 @@
SECTIONS
{
. = ORIGIN(p2ram);
.text.start :
{
KEEP(*(.text.start))
*(.text.startup.*)
} > p2ram AT>p1ram
. = ORIGIN(p1ram) + (. - ORIGIN(p2ram));
.text :
{
*(.text.*)
*(.text)
} > p1ram
.data :
{
*(.data)
*(.data.*)
} > p1ram
.rodata :
{
*(.rodata)
*(.rodata.*)
} > p1ram
.ctors ALIGN(4) :
{
KEEP(*(.ctors))
KEEP(*(.ctors.*))
} > p1ram
.text.vbr :
{
__vbr100 = .;
KEEP(*(.vbr.100))
. = __vbr100 + 0x300;
KEEP(*(.vbr.400))
. = __vbr100 + 0x500;
KEEP(*(.vbr.600))
} > p1ram
.bss ALIGN(32) (NOLOAD) :
{
*(.bss)
*(.bss.*)
*(COMMON)
} > p1ram
INCLUDE "debug.lds"
}
INCLUDE "symbols.lds"
INCLUDE "addresses.lds"

48
dreamcast2/debug.lds Normal file
View File

@ -0,0 +1,48 @@
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3. */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 5. */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.debug_sup 0 : { *(.debug_sup) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.rela.*) }

View File

@ -0,0 +1,9 @@
START_OBJ = \
start.o \
runtime.o
FRAMEBUFFER_SHADED_OBJ = \
example/framebuffer_shaded.o
example/framebuffer_shaded.elf: LDSCRIPT = $(LIB)/main.lds
example/framebuffer_shaded.elf: $(START_OBJ) $(FRAMEBUFFER_SHADED_OBJ)

View File

@ -0,0 +1,36 @@
#include "memorymap.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
void main()
{
volatile uint32_t * framebuffer = (volatile uint32_t * )texture_memory32;
for (int y = 0; y < 480; y++) {
for (int x = 0; x < 640; x++) {
int red = (y % 255);
int blue = (x % 255);
framebuffer[y * 640 + x] = (red << 16) | (blue << 0);
}
}
using holly::holly;
using namespace holly;
holly.FB_R_CTRL
= fb_r_ctrl::vclk_div::pclk_vclk_1
| fb_r_ctrl::fb_depth::xrgb0888
| fb_r_ctrl::fb_enable;
int fb_y_size = 480 - 1;
int bytes_per_pixel = 4;
int fb_x_size = ((640 * bytes_per_pixel) / 4) - 1;
holly.FB_R_SIZE
= fb_r_size::fb_modulus(1)
| fb_r_size::fb_y_size(fb_y_size)
| fb_r_size::fb_x_size(fb_x_size);
// the framebuffer is at the start of texture memory (texture memory address 0)
holly.FB_R_SOF1 = 0;
}

View File

@ -2,6 +2,7 @@
#include "reg.hpp" #include "reg.hpp"
namespace holly {
struct holly_reg { struct holly_reg {
reg32 ID; /* Device ID */ reg32 ID; /* Device ID */
reg32 REVISION; /* Revision Number */ reg32 REVISION; /* Revision Number */
@ -29,11 +30,11 @@ struct holly_reg {
reg32 FB_Y_CLIP; /* Pixel clip Y coordinate */ reg32 FB_Y_CLIP; /* Pixel clip Y coordinate */
reg8 _pad5[4]; reg8 _pad5[4];
reg32 FPU_SHAD_SCALE; /* Intensity Volume mode */ reg32 FPU_SHAD_SCALE; /* Intensity Volume mode */
reg32 FPU_CULL_VAL; /* Comparison value for culling */ reg32f FPU_CULL_VAL; /* Comparison value for culling */
reg32 FPU_PARAM_CFG; /* Parameter read control */ reg32 FPU_PARAM_CFG; /* Parameter read control */
reg32 HALF_OFFSET; /* Pixel sampling control */ reg32 HALF_OFFSET; /* Pixel sampling control */
reg32 FPU_PERP_VAL; /* Comparison value for perpendicular polygons */ reg32f FPU_PERP_VAL; /* Comparison value for perpendicular polygons */
reg32 ISP_BACKGND_D; /* Background surface depth */ reg32f ISP_BACKGND_D; /* Background surface depth */
reg32 ISP_BACKGND_T; /* Background surface tag */ reg32 ISP_BACKGND_T; /* Background surface tag */
reg8 _pad6[8]; reg8 _pad6[8];
reg32 ISP_FEED_CFG; /* Translucent polygon sort mode */ reg32 ISP_FEED_CFG; /* Translucent polygon sort mode */
@ -90,7 +91,6 @@ struct holly_reg {
reg8 _pad14[160]; reg8 _pad14[160];
reg32 PALETTE_RAM[1024]; /* Palette RAM */ reg32 PALETTE_RAM[1024]; /* Palette RAM */
}; };
static_assert((offsetof (struct holly_reg, ID)) == 0x0); static_assert((offsetof (struct holly_reg, ID)) == 0x0);
static_assert((offsetof (struct holly_reg, REVISION)) == 0x4); static_assert((offsetof (struct holly_reg, REVISION)) == 0x4);
static_assert((offsetof (struct holly_reg, SOFTRESET)) == 0x8); static_assert((offsetof (struct holly_reg, SOFTRESET)) == 0x8);
@ -164,3 +164,4 @@ static_assert((offsetof (struct holly_reg, TA_OL_POINTERS)) == 0x600);
static_assert((offsetof (struct holly_reg, PALETTE_RAM)) == 0x1000); static_assert((offsetof (struct holly_reg, PALETTE_RAM)) == 0x1000);
extern struct holly_reg holly __asm("holly"); extern struct holly_reg holly __asm("holly");
}

View File

@ -140,7 +140,7 @@ namespace holly {
} }
namespace fpu_cull_val { namespace fpu_cull_val {
inline uint32_t culling_comparison_value(float num) { return _i(__builtin_fabsf(num));; } inline float culling_comparison_value(float num) { return num; }
} }
namespace fpu_param_cfg { namespace fpu_param_cfg {
@ -181,11 +181,11 @@ namespace holly {
} }
namespace fpu_perp_val { namespace fpu_perp_val {
inline uint32_t perpendicular_triangle_compare(float num) { return _i(__builtin_fabsf(num));; } inline float perpendicular_triangle_compare(float num) { return num; }
} }
namespace isp_backgnd_d { namespace isp_backgnd_d {
inline uint32_t background_plane_depth(float num) { return _i(num) & 0xfffffff0; } inline float background_plane_depth(float num) { return num; }
} }
namespace isp_backgnd_t { namespace isp_backgnd_t {

10
dreamcast2/main.lds Normal file
View File

@ -0,0 +1,10 @@
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
MEMORY
{
p1ram : ORIGIN = 0x8c010000, LENGTH = 0xff0000
p2ram : ORIGIN = 0xac010000, LENGTH = 0xff0000
}
INCLUDE "common.lds"
__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x4000;

View File

@ -6,7 +6,9 @@
typedef volatile uint8_t reg8; typedef volatile uint8_t reg8;
typedef volatile uint16_t reg16; typedef volatile uint16_t reg16;
typedef volatile uint32_t reg32; typedef volatile uint32_t reg32;
typedef volatile float reg32f;
static_assert((sizeof (reg8)) == 1); static_assert((sizeof (reg8)) == 1);
static_assert((sizeof (reg16)) == 2); static_assert((sizeof (reg16)) == 2);
static_assert((sizeof (reg32)) == 4); static_assert((sizeof (reg32)) == 4);
static_assert((sizeof (reg32f)) == 4);

30
dreamcast2/regs.mk Normal file
View File

@ -0,0 +1,30 @@
%.csv: %.ods
libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $<
# HOLLY
holly/holly.hpp: regs/holly/holly.csv regs/render_block_regs.py
python regs/render_block_regs.py $< holly > $@
holly/holly_bits.hpp: regs/holly/holly_bits.csv regs/render_bits.py
python regs/render_bits.py $< holly > $@
holly/region_array_bits.hpp: regs/holly/region_array_bits.csv regs/render_bits.py
python regs/render_bits.py $< holly region_array > $@
# SH7091
sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/sh7091.py
python regs/sh7091.py $< sh7091 > $@
sh7091/sh7091_bits.hpp: regs/sh7091/sh7091_bits.csv regs/render_bits.py
python regs/render_bits.py $< sh7091 > $@
# SYSTEMBUS
systembus/systembus.hpp: regs/systembus/systembus.csv regs/render_block_regs.py
python regs/render_block_regs.py $< systembus > $@
systembus/systembus_bits.hpp: regs/systembus/systembus_bits.csv regs/render_bits.py
python regs/render_bits.py $< systembus > $@

View File

@ -1,21 +1,41 @@
import sys import sys
import string
from generate import renderer from generate import renderer
from csv_input import read_input from csv_input import read_input
def size_p(size): def size_p(size):
return size in {1, 2, 4} return size in {1, 2, 4}
def size_to_type(size): def size_to_type(size, type=None):
if size == 1: if size == 1:
assert type is None
return "reg8 " return "reg8 "
elif size == 2: elif size == 2:
assert type is None
return "reg16" return "reg16"
elif size == 4: elif size == 4:
if type == "f":
return "reg32f"
else:
assert type is None
return "reg32" return "reg32"
else: else:
raise NotImplemented(size) raise NotImplemented(size)
def split_integer(s):
acc = []
for i, c in enumerate(s):
if c in string.digits:
acc.append(c)
else:
return int("".join(acc), 10), s[i:]
return int("".join(acc), 10), None
def parse_size_type(s):
size, type = split_integer(s)
return size, type
def new_writer(): def new_writer():
first_address = 0 first_address = 0
next_address = 0 next_address = 0
@ -50,7 +70,7 @@ def new_writer():
assert _address <= 0xffff assert _address <= 0xffff
offset_address = (_offset << 16) offset_address = (_offset << 16)
address = offset_address | (_address << 0) address = offset_address | (_address << 0)
size = int(row["size"], 10) size, size_type = parse_size_type(row["size"])
name = row["name"] name = row["name"]
description = row["description"] description = row["description"]
@ -73,7 +93,7 @@ def new_writer():
def field(): def field():
if size_p(size): if size_p(size):
assert address % size == 0 assert address % size == 0
type = size_to_type(size) type = size_to_type(size, size_type)
return f"{type} {name};" return f"{type} {name};"
else: else:
type = size_to_type(4) type = size_to_type(4)

View File

@ -1,18 +0,0 @@
import sys
from csv_input import read_input
from generate import renderer
from block_regs import new_writer
from block_regs import headers
def block():
yield 'extern struct holly_reg holly __asm("holly");'
input_file = sys.argv[1]
rows = read_input(input_file)
process = new_writer()
render, out = renderer()
render(headers())
render(process(rows))
render(block())
sys.stdout.write(out.getvalue())

View File

@ -25,11 +25,11 @@
"holly","006c","4","FB_Y_CLIP","RW","Pixel clip Y coordinate" "holly","006c","4","FB_Y_CLIP","RW","Pixel clip Y coordinate"
,,,,, ,,,,,
"holly","0074","4","FPU_SHAD_SCALE","RW","Intensity Volume mode" "holly","0074","4","FPU_SHAD_SCALE","RW","Intensity Volume mode"
"holly","0078","4","FPU_CULL_VAL","RW","Comparison value for culling" "holly","0078","4f","FPU_CULL_VAL","RW","Comparison value for culling"
"holly","007c","4","FPU_PARAM_CFG","RW","Parameter read control" "holly","007c","4","FPU_PARAM_CFG","RW","Parameter read control"
"holly","0080","4","HALF_OFFSET","RW","Pixel sampling control" "holly","0080","4","HALF_OFFSET","RW","Pixel sampling control"
"holly","0084","4","FPU_PERP_VAL","RW","Comparison value for perpendicular polygons" "holly","0084","4f","FPU_PERP_VAL","RW","Comparison value for perpendicular polygons"
"holly","0088","4","ISP_BACKGND_D","RW","Background surface depth" "holly","0088","4f","ISP_BACKGND_D","RW","Background surface depth"
"holly","008c","4","ISP_BACKGND_T","RW","Background surface tag" "holly","008c","4","ISP_BACKGND_T","RW","Background surface tag"
,,,,, ,,,,,
"holly","0098","4","ISP_FEED_CFG","RW","Translucent polygon sort mode" "holly","0098","4","ISP_FEED_CFG","RW","Translucent polygon sort mode"

1 block address size name r/w description
25 holly 006c 4 FB_Y_CLIP RW Pixel clip Y coordinate
26
27 holly 0074 4 FPU_SHAD_SCALE RW Intensity Volume mode
28 holly 0078 4 4f FPU_CULL_VAL RW Comparison value for culling
29 holly 007c 4 FPU_PARAM_CFG RW Parameter read control
30 holly 0080 4 HALF_OFFSET RW Pixel sampling control
31 holly 0084 4 4f FPU_PERP_VAL RW Comparison value for perpendicular polygons
32 holly 0088 4 4f ISP_BACKGND_D RW Background surface depth
33 holly 008c 4 ISP_BACKGND_T RW Background surface tag
34
35 holly 0098 4 ISP_FEED_CFG RW Translucent polygon sort mode

Binary file not shown.

View File

@ -154,29 +154,14 @@ def render_read_only(bit_def):
" }" " }"
) )
def render_float_mask(mask):
if mask == "float_0_8_23":
return "_i(__builtin_fabsf(num));"
elif mask == "float_1_8_23":
return "_i(num)"
else:
assert mask.startswith("float_")
mask = mask.removeprefix("float_")
sign, exponent, fraction = map(int, mask.split('_'))
assert exponent == 8, exponent
assert sign == 1
bit_length = (sign + exponent + fraction)
mask = (2 ** bit_length - 1) << (32 - bit_length)
return f"_i(num) & {hex(mask)}"
def render_mask(bit_def): def render_mask(bit_def):
assert bit_def["value"] == "" assert bit_def["value"] == ""
mask = bit_def["mask"] mask = bit_def["mask"]
bits = parse_bit_range(bit_def["bits"]) bits = parse_bit_range(bit_def["bits"])
if mask.startswith("float_"): if mask.startswith("float_"):
yield ( yield (
f"inline uint32_t {escape(bit_def['bit_name'])}(float num) {{ " f"inline float {escape(bit_def['bit_name'])}(float num) {{ "
f"return {render_float_mask(mask)};" f"return num;"
" }" " }"
) )
else: else:

View File

@ -0,0 +1,32 @@
import sys
from csv_input import read_input
from generate import renderer
from block_regs import new_writer
from block_regs import headers
def blocks(rows):
blocks = []
for row in rows:
block = row["block"]
if block not in blocks:
blocks.append(block)
for block in blocks:
yield f'extern struct {block.lower()}_reg {block.lower()} __asm("{block.lower()}");'
def namespace(namespace_name, rows):
yield f"namespace {namespace_name} {{"
yield from process(rows)
yield from blocks(rows)
yield "}"
if __name__ == "__main__":
input_file = sys.argv[1]
namespace_name = sys.argv[2]
rows = read_input(input_file)
process = new_writer()
render, out = renderer()
render(headers())
render(namespace(namespace_name, rows))
sys.stdout.write(out.getvalue())

View File

@ -0,0 +1,55 @@
import sys
from generate import renderer
from csv_input import read_input
from block_regs import new_writer
from block_regs import headers
from block_regs import size_to_type
def blocks(rows):
stack = []
last_block = None
for row in rows:
block = row["block"]
if last_block != block:
offset = int(row["offset"], 16)
stack.append((block, offset))
last_block = block
yield "struct sh7091_reg {"
last_offset = 0
last_block = None
reserved_num = 0
for block, offset in stack:
if offset != last_offset:
assert last_block is not None
type = size_to_type(1)
raw_pad = (offset - last_offset) << 16
yield f"{type} _pad{reserved_num}[{hex(raw_pad)} - (sizeof (struct {last_block.lower()}_reg))];"
reserved_num += 1
yield f"struct {block.lower()}_reg {block};"
last_offset = offset
last_block = block
yield "};"
for block, offset in stack:
yield f"static_assert((offsetof (struct sh7091_reg, {block})) == {hex(offset << 16)});"
yield ""
yield 'extern struct sh7091_reg sh7091 __asm("sh7091");'
def namespace(namespace_name, rows):
yield f"namespace {namespace_name} {{"
yield from process(rows)
yield from blocks(rows)
yield "}"
if __name__ == "__main__":
input_file = sys.argv[1]
namespace_name = sys.argv[2]
rows = read_input(input_file)
process = new_writer()
render, out = renderer()
render(headers())
render(namespace(namespace_name, rows))
sys.stdout.write(out.getvalue())

View File

@ -1,145 +0,0 @@
import sys
from generate import renderer
from csv_input import read_input
def size_p(size):
return size in {1, 2, 4}
def size_to_type(size):
if size == 1:
return "reg8 "
elif size == 2:
return "reg16"
elif size == 4:
return "reg32"
else:
raise NotImplemented(size)
def new_writer():
first_address = 0
next_address = 0
last_block = None
size_total = 0
reserved_num = 0
stack = []
def terminate():
nonlocal last_block
nonlocal stack
if last_block is not None:
yield "};"
for address, name in stack:
yield f"static_assert((offsetof (struct {last_block.lower()}_reg, {name})) == {hex(address - first_address)});"
yield ""
stack = []
def process_row(row):
nonlocal first_address
nonlocal next_address
nonlocal last_block
nonlocal reserved_num
nonlocal size_total
nonlocal stack
block = row["block"]
_offset = int(row["offset"], 16) if "offset" in row else 0
_address = int(row["address"], 16)
assert _offset <= 0xff
assert _address <= 0xffff
offset_address = (_offset << 16)
address = offset_address | (_address << 0)
size = int(row["size"], 10)
name = row["name"]
description = row["description"]
if block != last_block:
yield from terminate()
first_address = offset_address
next_address = offset_address
size_total = 0
reserved_num = 0
yield f"struct {block.lower()}_reg {{"
assert address >= next_address, row
if address > next_address:
padding = address - next_address
type = size_to_type(1)
yield f"{type} _pad{reserved_num}[{padding}];"
reserved_num += 1
size_total += padding
def field():
if size_p(size):
assert address % size == 0
type = size_to_type(size)
return f"{type} {name};"
else:
type = size_to_type(4)
return f"{type} {name}[{size // 4}];"
yield field().ljust(27) + f"/* {description} */"
stack.append((address, name))
next_address = address + size
last_block = block
size_total += size
def process(rows):
for row in rows:
yield from process_row(row)
yield from terminate()
return process
def blocks(rows):
stack = []
last_block = None
for row in rows:
block = row["block"]
if last_block != block:
offset = int(row["offset"], 16)
stack.append((block, offset))
last_block = block
yield "struct sh7091_reg {"
last_offset = 0
last_block = None
reserved_num = 0
for block, offset in stack:
if offset != last_offset:
assert last_block is not None
type = size_to_type(1)
raw_pad = (offset - last_offset) << 16
yield f"{type} _pad{reserved_num}[{hex(raw_pad)} - (sizeof (struct {last_block.lower()}_reg))];"
reserved_num += 1
yield f"struct {block.lower()}_reg {block};"
last_offset = offset
last_block = block
yield "};"
for block, offset in stack:
yield f"static_assert((offsetof (struct sh7091_reg, {block})) == {hex(offset << 16)});"
yield ""
yield 'extern struct sh7091_reg sh7091 __asm("sh7091");'
def headers():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield "#include <cstddef>"
yield ""
yield '#include "type.hpp"'
yield ""
if __name__ == "__main__":
input_file = sys.argv[1]
rows = read_input(input_file)
process = new_writer()
render, out = renderer()
render(headers())
render(process(rows))
render(blocks(rows))
sys.stdout.write(out.getvalue())

View File

@ -0,0 +1,67 @@
"register_name","enum_name","bits","bit_name","value","mask","description"
"C2DSTAT",,"31-0","texture_memory_start_address",,"0x13ffffe0",
"C2DLEN",,"23-0","transfer_length",,"0xffffe0",
"C2DST",,"0","start","1",,
,,,,,,
"ISTNRM",,"21","end_of_transferring_punch_through_list","1",,
"ISTNRM",,"20","end_of_dma_sort_dma","1",,
"ISTNRM",,"19","end_of_dma_ch2_dma","1",,
"ISTNRM",,"18","end_of_dma_dev_dma","1",,
"ISTNRM",,"17","end_of_dma_ext_dma2","1",,
"ISTNRM",,"16","end_of_dma_ext_dma1","1",,
"ISTNRM",,"15","end_of_dma_aica_dma","1",,
"ISTNRM",,"14","end_of_dma_gd_dma","1",,
"ISTNRM",,"13","maple_v_blank_over","1",,
"ISTNRM",,"12","end_of_dma_maple_dma","1",,
"ISTNRM",,"11","end_of_dma_pvr_dma","1",,
"ISTNRM",,"10","end_of_transferring_translucent_modifier_volume_list","1",,
"ISTNRM",,"9","end_of_transferring_translucent_list","1",,
"ISTNRM",,"8","end_of_transferring_opaque_modifier_volume_list","1",,
"ISTNRM",,"7","end_of_transferring_opaque_list","1",,
"ISTNRM",,"6","end_of_transferring_yuv","1",,
"ISTNRM",,"5","h_blank_in","1",,
"ISTNRM",,"4","v_blank_out","1",,
"ISTNRM",,"3","v_blank_in","1",,
"ISTNRM",,"2","end_of_render_tsp","1",,
"ISTNRM",,"1","end_of_render_isp","1",,
"ISTNRM",,"0","end_of_render_video","1",,
,,,,,,
"ISTERR",,"31","sh4__if_access_inhibited_area","1",,
"ISTERR",,"28","ddt__if_sort_dma_command_error","1",,
"ISTERR",,"27","g2__time_out_in_cpu_access","1",,
"ISTERR",,"26","g2__dev_dma_time_out","1",,
"ISTERR",,"25","g2__ext_dma2_time_out","1",,
"ISTERR",,"24","g2__ext_dma1_time_out","1",,
"ISTERR",,"23","g2__aica_dma_time_out","1",,
"ISTERR",,"22","g2__dev_dma_over_run","1",,
"ISTERR",,"21","g2__ext_dma2_over_run","1",,
"ISTERR",,"20","g2__ext_dma1_over_run","1",,
"ISTERR",,"19","g2__aica_dma_over_run","1",,
"ISTERR",,"18","g2__dev_dma_illegal_address_set","1",,
"ISTERR",,"17","g2__ext_dma2_illegal_address_set","1",,
"ISTERR",,"16","g2__ext_dma1_illegal_address_set","1",,
"ISTERR",,"15","g2__aica_dma_illegal_address_set","1",,
"ISTERR",,"14","g1__rom_flash_access_at_gd_dma","1",,
"ISTERR",,"13","g1__gd_dma_over_run","1",,
"ISTERR",,"12","g1__illegal_address_set","1",,
"ISTERR",,"11","maple__illegal_command","1",,
"ISTERR",,"10","maple__write_fifo_over_flow","1",,
"ISTERR",,"9","maple__dma_over_run","1",,
"ISTERR",,"8","maple__illegal_address_set","1",,
"ISTERR",,"7","pvrif__dma_over_run","1",,
"ISTERR",,"6","pvrif__illegal_address_set","1",,
"ISTERR",,"5","ta__fifo_overflow","1",,
"ISTERR",,"4","ta__illegal_parameter","1",,
"ISTERR",,"3","ta__object_list_pointer_overflow","1",,
"ISTERR",,"2","ta__isp_tsp_parameter_overflow","1",,
"ISTERR",,"1","render__hazard_processing_of_strip_buffer","1",,
"ISTERR",,"0","render__isp_out_of_cache","1",,
,,,,,,
"FFST",,"5","holly_cpu_if_block_internal_write_buffer",,,
"FFST",,"4","holly_g2_if_block_internal_write_buffer",,,
"FFST",,"0","aica_internal_write_buffer",,,
,,,,,,
"ISTEXT",,3,"external_device",1,,
"ISTEXT",,2,"modem",1,,
"ISTEXT",,1,"aica",1,,
"ISTEXT",,0,"gdrom",1,,
1 register_name enum_name bits bit_name value mask description
2 C2DSTAT 31-0 texture_memory_start_address 0x13ffffe0
3 C2DLEN 23-0 transfer_length 0xffffe0
4 C2DST 0 start 1
5
6 ISTNRM 21 end_of_transferring_punch_through_list 1
7 ISTNRM 20 end_of_dma_sort_dma 1
8 ISTNRM 19 end_of_dma_ch2_dma 1
9 ISTNRM 18 end_of_dma_dev_dma 1
10 ISTNRM 17 end_of_dma_ext_dma2 1
11 ISTNRM 16 end_of_dma_ext_dma1 1
12 ISTNRM 15 end_of_dma_aica_dma 1
13 ISTNRM 14 end_of_dma_gd_dma 1
14 ISTNRM 13 maple_v_blank_over 1
15 ISTNRM 12 end_of_dma_maple_dma 1
16 ISTNRM 11 end_of_dma_pvr_dma 1
17 ISTNRM 10 end_of_transferring_translucent_modifier_volume_list 1
18 ISTNRM 9 end_of_transferring_translucent_list 1
19 ISTNRM 8 end_of_transferring_opaque_modifier_volume_list 1
20 ISTNRM 7 end_of_transferring_opaque_list 1
21 ISTNRM 6 end_of_transferring_yuv 1
22 ISTNRM 5 h_blank_in 1
23 ISTNRM 4 v_blank_out 1
24 ISTNRM 3 v_blank_in 1
25 ISTNRM 2 end_of_render_tsp 1
26 ISTNRM 1 end_of_render_isp 1
27 ISTNRM 0 end_of_render_video 1
28
29 ISTERR 31 sh4__if_access_inhibited_area 1
30 ISTERR 28 ddt__if_sort_dma_command_error 1
31 ISTERR 27 g2__time_out_in_cpu_access 1
32 ISTERR 26 g2__dev_dma_time_out 1
33 ISTERR 25 g2__ext_dma2_time_out 1
34 ISTERR 24 g2__ext_dma1_time_out 1
35 ISTERR 23 g2__aica_dma_time_out 1
36 ISTERR 22 g2__dev_dma_over_run 1
37 ISTERR 21 g2__ext_dma2_over_run 1
38 ISTERR 20 g2__ext_dma1_over_run 1
39 ISTERR 19 g2__aica_dma_over_run 1
40 ISTERR 18 g2__dev_dma_illegal_address_set 1
41 ISTERR 17 g2__ext_dma2_illegal_address_set 1
42 ISTERR 16 g2__ext_dma1_illegal_address_set 1
43 ISTERR 15 g2__aica_dma_illegal_address_set 1
44 ISTERR 14 g1__rom_flash_access_at_gd_dma 1
45 ISTERR 13 g1__gd_dma_over_run 1
46 ISTERR 12 g1__illegal_address_set 1
47 ISTERR 11 maple__illegal_command 1
48 ISTERR 10 maple__write_fifo_over_flow 1
49 ISTERR 9 maple__dma_over_run 1
50 ISTERR 8 maple__illegal_address_set 1
51 ISTERR 7 pvrif__dma_over_run 1
52 ISTERR 6 pvrif__illegal_address_set 1
53 ISTERR 5 ta__fifo_overflow 1
54 ISTERR 4 ta__illegal_parameter 1
55 ISTERR 3 ta__object_list_pointer_overflow 1
56 ISTERR 2 ta__isp_tsp_parameter_overflow 1
57 ISTERR 1 render__hazard_processing_of_strip_buffer 1
58 ISTERR 0 render__isp_out_of_cache 1
59
60 FFST 5 holly_cpu_if_block_internal_write_buffer
61 FFST 4 holly_g2_if_block_internal_write_buffer
62 FFST 0 aica_internal_write_buffer
63
64 ISTEXT 3 external_device 1
65 ISTEXT 2 modem 1
66 ISTEXT 1 aica 1
67 ISTEXT 0 gdrom 1

59
dreamcast2/runtime.cpp Normal file
View File

@ -0,0 +1,59 @@
#include <cstdint>
#include "sh7091/store_queue_transfer.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);
void runtime_init()
__attribute__((section(".text.start.runtime_init")));
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);
// clear BSS
uint32_t * bss_start = &__bss_link_start;
uint32_t * bss_end = &__bss_link_end;
int bss_length = bss_end - bss_start;
sh7091::store_queue_transfer::zeroize(bss_start, bss_length, 0);
// call ctors
uint32_t * ctors_start = &__ctors_link_start;
uint32_t * ctors_end = &__ctors_link_end;
while (ctors_start < ctors_end) {
((init_t *)(*ctors_start++))();
}
}
extern "C"
void foo()
{
runtime_init();
}

View File

@ -1,10 +1,8 @@
#pragma once #pragma once
#include <cstdint> #include "reg.hpp"
#include <cstddef>
#include "type.hpp"
namespace sh7091 {
struct ccn_reg { struct ccn_reg {
reg32 PTEH; /* Page table entry high register */ reg32 PTEH; /* Page table entry high register */
reg32 PTEL; /* Page table entry low register */ reg32 PTEL; /* Page table entry low register */
@ -24,7 +22,6 @@ struct ccn_reg {
reg32 QACR0; /* Queue address control register 0 */ reg32 QACR0; /* Queue address control register 0 */
reg32 QACR1; /* Queue address control register 1 */ reg32 QACR1; /* Queue address control register 1 */
}; };
static_assert((offsetof (struct ccn_reg, PTEH)) == 0x0); static_assert((offsetof (struct ccn_reg, PTEH)) == 0x0);
static_assert((offsetof (struct ccn_reg, PTEL)) == 0x4); static_assert((offsetof (struct ccn_reg, PTEL)) == 0x4);
static_assert((offsetof (struct ccn_reg, TTB)) == 0x8); static_assert((offsetof (struct ccn_reg, TTB)) == 0x8);
@ -55,7 +52,6 @@ struct ubc_reg {
reg32 BDMRB; /* Break data mask register B */ reg32 BDMRB; /* Break data mask register B */
reg16 BRCR; /* Break control register */ reg16 BRCR; /* Break control register */
}; };
static_assert((offsetof (struct ubc_reg, BARA)) == 0x0); static_assert((offsetof (struct ubc_reg, BARA)) == 0x0);
static_assert((offsetof (struct ubc_reg, BAMRA)) == 0x4); static_assert((offsetof (struct ubc_reg, BAMRA)) == 0x4);
static_assert((offsetof (struct ubc_reg, BBRA)) == 0x8); static_assert((offsetof (struct ubc_reg, BBRA)) == 0x8);
@ -96,7 +92,6 @@ struct bsc_reg {
reg8 _pad9[196608]; reg8 _pad9[196608];
reg32 SDMR3[16384]; /* Synchronous DRAM mode registers */ reg32 SDMR3[16384]; /* Synchronous DRAM mode registers */
}; };
static_assert((offsetof (struct bsc_reg, BCR1)) == 0x0); static_assert((offsetof (struct bsc_reg, BCR1)) == 0x0);
static_assert((offsetof (struct bsc_reg, BCR2)) == 0x4); static_assert((offsetof (struct bsc_reg, BCR2)) == 0x4);
static_assert((offsetof (struct bsc_reg, WCR1)) == 0x8); static_assert((offsetof (struct bsc_reg, WCR1)) == 0x8);
@ -135,7 +130,6 @@ struct dmac_reg {
reg32 CHCR3; /* DMA control register 3 */ reg32 CHCR3; /* DMA control register 3 */
reg32 DMAOR; /* DMA operation register */ reg32 DMAOR; /* DMA operation register */
}; };
static_assert((offsetof (struct dmac_reg, SAR0)) == 0x0); static_assert((offsetof (struct dmac_reg, SAR0)) == 0x0);
static_assert((offsetof (struct dmac_reg, DAR0)) == 0x4); static_assert((offsetof (struct dmac_reg, DAR0)) == 0x4);
static_assert((offsetof (struct dmac_reg, DMATCR0)) == 0x8); static_assert((offsetof (struct dmac_reg, DMATCR0)) == 0x8);
@ -165,7 +159,6 @@ struct cpg_reg {
reg8 _pad3[2]; reg8 _pad3[2];
reg8 STBCR2; /* Standby control register 2 */ reg8 STBCR2; /* Standby control register 2 */
}; };
static_assert((offsetof (struct cpg_reg, FRQCR)) == 0x0); static_assert((offsetof (struct cpg_reg, FRQCR)) == 0x0);
static_assert((offsetof (struct cpg_reg, STBCR)) == 0x4); static_assert((offsetof (struct cpg_reg, STBCR)) == 0x4);
static_assert((offsetof (struct cpg_reg, WTCNT)) == 0x8); static_assert((offsetof (struct cpg_reg, WTCNT)) == 0x8);
@ -205,7 +198,6 @@ struct rtc_reg {
reg8 _pad14[3]; reg8 _pad14[3];
reg8 RCR2; /* RTC control register 2 */ reg8 RCR2; /* RTC control register 2 */
}; };
static_assert((offsetof (struct rtc_reg, R64CNT)) == 0x0); static_assert((offsetof (struct rtc_reg, R64CNT)) == 0x0);
static_assert((offsetof (struct rtc_reg, RSECCNT)) == 0x4); static_assert((offsetof (struct rtc_reg, RSECCNT)) == 0x4);
static_assert((offsetof (struct rtc_reg, RMINCNT)) == 0x8); static_assert((offsetof (struct rtc_reg, RMINCNT)) == 0x8);
@ -232,7 +224,6 @@ struct intc_reg {
reg8 _pad2[2]; reg8 _pad2[2];
reg16 IPRC; /* Interrupt priority register C */ reg16 IPRC; /* Interrupt priority register C */
}; };
static_assert((offsetof (struct intc_reg, ICR)) == 0x0); static_assert((offsetof (struct intc_reg, ICR)) == 0x0);
static_assert((offsetof (struct intc_reg, IPRA)) == 0x4); static_assert((offsetof (struct intc_reg, IPRA)) == 0x4);
static_assert((offsetof (struct intc_reg, IPRB)) == 0x8); static_assert((offsetof (struct intc_reg, IPRB)) == 0x8);
@ -257,7 +248,6 @@ struct tmu_reg {
reg8 _pad4[2]; reg8 _pad4[2];
reg32 TCPR2; /* Timer input capture register 2 */ reg32 TCPR2; /* Timer input capture register 2 */
}; };
static_assert((offsetof (struct tmu_reg, TOCR)) == 0x0); static_assert((offsetof (struct tmu_reg, TOCR)) == 0x0);
static_assert((offsetof (struct tmu_reg, TSTR)) == 0x4); static_assert((offsetof (struct tmu_reg, TSTR)) == 0x4);
static_assert((offsetof (struct tmu_reg, TCOR0)) == 0x8); static_assert((offsetof (struct tmu_reg, TCOR0)) == 0x8);
@ -288,7 +278,6 @@ struct sci_reg {
reg8 _pad6[3]; reg8 _pad6[3];
reg8 SCSPTR1; /* Serial port register */ reg8 SCSPTR1; /* Serial port register */
}; };
static_assert((offsetof (struct sci_reg, SCSMR1)) == 0x0); static_assert((offsetof (struct sci_reg, SCSMR1)) == 0x0);
static_assert((offsetof (struct sci_reg, SCBRR1)) == 0x4); static_assert((offsetof (struct sci_reg, SCBRR1)) == 0x4);
static_assert((offsetof (struct sci_reg, SCSCR1)) == 0x8); static_assert((offsetof (struct sci_reg, SCSCR1)) == 0x8);
@ -319,7 +308,6 @@ struct scif_reg {
reg8 _pad8[2]; reg8 _pad8[2];
reg16 SCLSR2; /* Line status register 2 */ reg16 SCLSR2; /* Line status register 2 */
}; };
static_assert((offsetof (struct scif_reg, SCSMR2)) == 0x0); static_assert((offsetof (struct scif_reg, SCSMR2)) == 0x0);
static_assert((offsetof (struct scif_reg, SCBRR2)) == 0x4); static_assert((offsetof (struct scif_reg, SCBRR2)) == 0x4);
static_assert((offsetof (struct scif_reg, SCSCR2)) == 0x8); static_assert((offsetof (struct scif_reg, SCSCR2)) == 0x8);
@ -336,7 +324,6 @@ struct udi_reg {
reg8 _pad0[6]; reg8 _pad0[6];
reg32 SDDR; /* Data register */ reg32 SDDR; /* Data register */
}; };
static_assert((offsetof (struct udi_reg, SDIR)) == 0x0); static_assert((offsetof (struct udi_reg, SDIR)) == 0x0);
static_assert((offsetof (struct udi_reg, SDDR)) == 0x8); static_assert((offsetof (struct udi_reg, SDDR)) == 0x8);
@ -363,7 +350,6 @@ struct sh7091_reg {
reg8 _pad9[0x80000 - (sizeof (struct scif_reg))]; reg8 _pad9[0x80000 - (sizeof (struct scif_reg))];
struct udi_reg UDI; struct udi_reg UDI;
}; };
static_assert((offsetof (struct sh7091_reg, CCN)) == 0x0); static_assert((offsetof (struct sh7091_reg, CCN)) == 0x0);
static_assert((offsetof (struct sh7091_reg, UBC)) == 0x200000); static_assert((offsetof (struct sh7091_reg, UBC)) == 0x200000);
static_assert((offsetof (struct sh7091_reg, BSC)) == 0x800000); static_assert((offsetof (struct sh7091_reg, BSC)) == 0x800000);
@ -377,3 +363,4 @@ static_assert((offsetof (struct sh7091_reg, SCIF)) == 0xe80000);
static_assert((offsetof (struct sh7091_reg, UDI)) == 0xf00000); static_assert((offsetof (struct sh7091_reg, UDI)) == 0xf00000);
extern struct sh7091_reg sh7091 __asm("sh7091"); extern struct sh7091_reg sh7091 __asm("sh7091");
}

View File

@ -6,6 +6,10 @@
namespace sh7091 { namespace sh7091 {
namespace store_queue_transfer { namespace store_queue_transfer {
static inline void copy(void * out_addr,
const void * src,
int length) __attribute__((always_inline));
static inline void copy(void * out_addr, static inline void copy(void * out_addr,
const void * src, const void * src,
int length) int length)
@ -14,7 +18,7 @@ namespace sh7091 {
sh7091.CCN.QACR0 = ((out >> 24) & 0b11100); sh7091.CCN.QACR0 = ((out >> 24) & 0b11100);
sh7091.CCN.QACR1 = ((out >> 24) & 0b11100); sh7091.CCN.QACR1 = ((out >> 24) & 0b11100);
volatile uint32_t * base = &store_queue[(out & 0x03ffffe0)]; volatile uint32_t * base = (volatile uint32_t *)&store_queue[(out & 0x03ffffe0)];
const uint32_t * src32 = reinterpret_cast<const uint32_t *>(src); const uint32_t * src32 = reinterpret_cast<const uint32_t *>(src);
length = (length + 31) & ~31; // round up to nearest multiple of 32 length = (length + 31) & ~31; // round up to nearest multiple of 32
@ -38,6 +42,10 @@ namespace sh7091 {
} }
static inline void zeroize(void * out_addr,
int length,
const uint32_t value) __attribute__((always_inline));
static inline void zeroize(void * out_addr, static inline void zeroize(void * out_addr,
int length, int length,
const uint32_t value) const uint32_t value)
@ -46,7 +54,7 @@ namespace sh7091 {
sh7091.CCN.QACR0 = ((out >> 24) & 0b11100); sh7091.CCN.QACR0 = ((out >> 24) & 0b11100);
sh7091.CCN.QACR1 = ((out >> 24) & 0b11100); sh7091.CCN.QACR1 = ((out >> 24) & 0b11100);
volatile uint32_t * base = &store_queue[(out & 0x03ffffe0)]; volatile uint32_t * base = (volatile uint32_t *)&store_queue[(out & 0x03ffffe0)];
length = (length + 31) & ~31; // round up to nearest multiple of 32 length = (length + 31) & ~31; // round up to nearest multiple of 32
while (length > 0) { while (length > 0) {

41
dreamcast2/start.s Normal file
View File

@ -0,0 +1,41 @@
.section .text.start
.global _start
_start:
/* set stack pointer */
mov.l stack_end_ptr,r15
/* mask all interrupts */
mov.l imask_all,r0
mov.l zero_rb,r2
stc sr,r1
or r1,r0
and r0,r2
ldc r2,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
zero_rb:
.long ~(1 << 29)
runtime_init_ptr:
.long __Z12runtime_initv
main_ptr:
.long _main

21
dreamcast2/symbols.lds Normal file
View File

@ -0,0 +1,21 @@
__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);
__vbr_link_start = ADDR(.text.vbr);
__vbr_link_end = ADDR(.text.vbr) + SIZEOF(.text.vbr);
__vbr_load_end = LOADADDR(.text.vbr);

View File

@ -2,6 +2,7 @@
#include "reg.hpp" #include "reg.hpp"
namespace systembus {
struct systembus_reg { struct systembus_reg {
reg32 C2DSTAT; /* CH2-DMA destination address */ reg32 C2DSTAT; /* CH2-DMA destination address */
reg32 C2DLEN; /* CH2-DMA length */ reg32 C2DLEN; /* CH2-DMA length */
@ -49,7 +50,6 @@ struct systembus_reg {
reg32 G2DTNRM; /* Normal interrupt G2-DMA startup mask */ reg32 G2DTNRM; /* Normal interrupt G2-DMA startup mask */
reg32 G2DTEXT; /* External interrupt G2-DMA startup mask */ reg32 G2DTEXT; /* External interrupt G2-DMA startup mask */
}; };
static_assert((offsetof (struct systembus_reg, C2DSTAT)) == 0x0); static_assert((offsetof (struct systembus_reg, C2DSTAT)) == 0x0);
static_assert((offsetof (struct systembus_reg, C2DLEN)) == 0x4); static_assert((offsetof (struct systembus_reg, C2DLEN)) == 0x4);
static_assert((offsetof (struct systembus_reg, C2DST)) == 0x8); static_assert((offsetof (struct systembus_reg, C2DST)) == 0x8);
@ -105,7 +105,6 @@ struct maple_if_reg {
reg32 MRXDAD; /* Maple RXD address counter */ reg32 MRXDAD; /* Maple RXD address counter */
reg32 MRXDBD; /* Maple RXD address base */ reg32 MRXDBD; /* Maple RXD address base */
}; };
static_assert((offsetof (struct maple_if_reg, MDSTAR)) == 0x4); static_assert((offsetof (struct maple_if_reg, MDSTAR)) == 0x4);
static_assert((offsetof (struct maple_if_reg, MDTSEL)) == 0x10); static_assert((offsetof (struct maple_if_reg, MDTSEL)) == 0x10);
static_assert((offsetof (struct maple_if_reg, MDEN)) == 0x14); static_assert((offsetof (struct maple_if_reg, MDEN)) == 0x14);
@ -147,7 +146,6 @@ struct g1_if_reg {
reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */ reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */
reg32 GDLEND; /* GD-DMA transfer counter */ reg32 GDLEND; /* GD-DMA transfer counter */
}; };
static_assert((offsetof (struct g1_if_reg, GDSTAR)) == 0x4); static_assert((offsetof (struct g1_if_reg, GDSTAR)) == 0x4);
static_assert((offsetof (struct g1_if_reg, GDLEN)) == 0x8); static_assert((offsetof (struct g1_if_reg, GDLEN)) == 0x8);
static_assert((offsetof (struct g1_if_reg, GDDIR)) == 0xc); static_assert((offsetof (struct g1_if_reg, GDDIR)) == 0xc);
@ -225,7 +223,6 @@ struct g2_if_reg {
reg32 DDSTARD; /* Dev-DMA address counter (on root bus) */ reg32 DDSTARD; /* Dev-DMA address counter (on root bus) */
reg32 DDLEND; /* Dev-DMA transfer counter */ reg32 DDLEND; /* Dev-DMA transfer counter */
}; };
static_assert((offsetof (struct g2_if_reg, ADSTAG)) == 0x0); static_assert((offsetof (struct g2_if_reg, ADSTAG)) == 0x0);
static_assert((offsetof (struct g2_if_reg, ADSTAR)) == 0x4); static_assert((offsetof (struct g2_if_reg, ADSTAR)) == 0x4);
static_assert((offsetof (struct g2_if_reg, ADLEN)) == 0x8); static_assert((offsetof (struct g2_if_reg, ADLEN)) == 0x8);
@ -292,7 +289,6 @@ struct pvr_if_reg {
reg32 PDSTARD; /* PVR-DMA address counter (on root bus) */ reg32 PDSTARD; /* PVR-DMA address counter (on root bus) */
reg32 PDLEND; /* PVR-DMA transfer counter */ reg32 PDLEND; /* PVR-DMA transfer counter */
}; };
static_assert((offsetof (struct pvr_if_reg, PDSTAP)) == 0x0); static_assert((offsetof (struct pvr_if_reg, PDSTAP)) == 0x0);
static_assert((offsetof (struct pvr_if_reg, PDSTAR)) == 0x4); static_assert((offsetof (struct pvr_if_reg, PDSTAR)) == 0x4);
static_assert((offsetof (struct pvr_if_reg, PDLEN)) == 0x8); static_assert((offsetof (struct pvr_if_reg, PDLEN)) == 0x8);
@ -305,4 +301,9 @@ static_assert((offsetof (struct pvr_if_reg, PDSTAPD)) == 0xf0);
static_assert((offsetof (struct pvr_if_reg, PDSTARD)) == 0xf4); static_assert((offsetof (struct pvr_if_reg, PDSTARD)) == 0xf4);
static_assert((offsetof (struct pvr_if_reg, PDLEND)) == 0xf8); static_assert((offsetof (struct pvr_if_reg, PDLEND)) == 0xf8);
extern struct holly_reg holly __asm("holly"); extern struct systembus_reg systembus __asm("systembus");
extern struct maple_if_reg maple_if __asm("maple_if");
extern struct g1_if_reg g1_if __asm("g1_if");
extern struct g2_if_reg g2_if __asm("g2_if");
extern struct pvr_if_reg pvr_if __asm("pvr_if");
}

View File

@ -0,0 +1,89 @@
#pragma once
#include <cstdint>
namespace systembus {
namespace c2dstat {
constexpr uint32_t texture_memory_start_address(uint32_t num) { return (num & 0x13ffffe0) << 0; }
}
namespace c2dlen {
constexpr uint32_t transfer_length(uint32_t num) { return (num & 0xffffe0) << 0; }
}
namespace c2dst {
constexpr uint32_t start = 1 << 0;
}
namespace istnrm {
constexpr uint32_t end_of_transferring_punch_through_list = 1 << 21;
constexpr uint32_t end_of_dma_sort_dma = 1 << 20;
constexpr uint32_t end_of_dma_ch2_dma = 1 << 19;
constexpr uint32_t end_of_dma_dev_dma = 1 << 18;
constexpr uint32_t end_of_dma_ext_dma2 = 1 << 17;
constexpr uint32_t end_of_dma_ext_dma1 = 1 << 16;
constexpr uint32_t end_of_dma_aica_dma = 1 << 15;
constexpr uint32_t end_of_dma_gd_dma = 1 << 14;
constexpr uint32_t maple_v_blank_over = 1 << 13;
constexpr uint32_t end_of_dma_maple_dma = 1 << 12;
constexpr uint32_t end_of_dma_pvr_dma = 1 << 11;
constexpr uint32_t end_of_transferring_translucent_modifier_volume_list = 1 << 10;
constexpr uint32_t end_of_transferring_translucent_list = 1 << 9;
constexpr uint32_t end_of_transferring_opaque_modifier_volume_list = 1 << 8;
constexpr uint32_t end_of_transferring_opaque_list = 1 << 7;
constexpr uint32_t end_of_transferring_yuv = 1 << 6;
constexpr uint32_t h_blank_in = 1 << 5;
constexpr uint32_t v_blank_out = 1 << 4;
constexpr uint32_t v_blank_in = 1 << 3;
constexpr uint32_t end_of_render_tsp = 1 << 2;
constexpr uint32_t end_of_render_isp = 1 << 1;
constexpr uint32_t end_of_render_video = 1 << 0;
}
namespace isterr {
constexpr uint32_t sh4__if_access_inhibited_area = 1 << 31;
constexpr uint32_t ddt__if_sort_dma_command_error = 1 << 28;
constexpr uint32_t g2__time_out_in_cpu_access = 1 << 27;
constexpr uint32_t g2__dev_dma_time_out = 1 << 26;
constexpr uint32_t g2__ext_dma2_time_out = 1 << 25;
constexpr uint32_t g2__ext_dma1_time_out = 1 << 24;
constexpr uint32_t g2__aica_dma_time_out = 1 << 23;
constexpr uint32_t g2__dev_dma_over_run = 1 << 22;
constexpr uint32_t g2__ext_dma2_over_run = 1 << 21;
constexpr uint32_t g2__ext_dma1_over_run = 1 << 20;
constexpr uint32_t g2__aica_dma_over_run = 1 << 19;
constexpr uint32_t g2__dev_dma_illegal_address_set = 1 << 18;
constexpr uint32_t g2__ext_dma2_illegal_address_set = 1 << 17;
constexpr uint32_t g2__ext_dma1_illegal_address_set = 1 << 16;
constexpr uint32_t g2__aica_dma_illegal_address_set = 1 << 15;
constexpr uint32_t g1__rom_flash_access_at_gd_dma = 1 << 14;
constexpr uint32_t g1__gd_dma_over_run = 1 << 13;
constexpr uint32_t g1__illegal_address_set = 1 << 12;
constexpr uint32_t maple__illegal_command = 1 << 11;
constexpr uint32_t maple__write_fifo_over_flow = 1 << 10;
constexpr uint32_t maple__dma_over_run = 1 << 9;
constexpr uint32_t maple__illegal_address_set = 1 << 8;
constexpr uint32_t pvrif__dma_over_run = 1 << 7;
constexpr uint32_t pvrif__illegal_address_set = 1 << 6;
constexpr uint32_t ta__fifo_overflow = 1 << 5;
constexpr uint32_t ta__illegal_parameter = 1 << 4;
constexpr uint32_t ta__object_list_pointer_overflow = 1 << 3;
constexpr uint32_t ta__isp_tsp_parameter_overflow = 1 << 2;
constexpr uint32_t render__hazard_processing_of_strip_buffer = 1 << 1;
constexpr uint32_t render__isp_out_of_cache = 1 << 0;
}
namespace ffst {
constexpr uint32_t holly_cpu_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 5) & 0x1; }
constexpr uint32_t holly_g2_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 4) & 0x1; }
constexpr uint32_t aica_internal_write_buffer(uint32_t reg) { return (reg >> 0) & 0x1; }
}
namespace istext {
constexpr uint32_t external_device = 1 << 3;
constexpr uint32_t modem = 1 << 2;
constexpr uint32_t aica = 1 << 1;
constexpr uint32_t gdrom = 1 << 0;
}
}