Compare commits

...

46 Commits

Author SHA1 Message Date
742448e7a7 dreamcast2: deferred_shading: clean up code 2025-09-05 23:03:31 -05:00
5e65f3a811 dreamcast2: add deferred shading 2025-09-05 16:33:32 -05:00
35cd182bab dreamcast2: add suzanne_triangle_strips 2025-09-04 21:28:01 -05:00
403ac12171 dreamcast2: add maple_keyboard_serial_forward 2025-09-03 19:56:31 -05:00
b2c7b9e53c dreamcast2: add maple_get_condition 2025-09-03 15:56:20 -05:00
fa5d7315d6 dreamcast2: add maple_device_request example 2025-09-03 15:00:31 -05:00
8ef2d20749 dreamcast2: add maple headers 2025-09-03 14:12:06 -05:00
1f8010ef89 dreamcast2: add font_serial example 2025-09-03 13:23:36 -05:00
1384df407d ftdi_transfer: console: add stdin forwarding 2025-09-03 13:23:03 -05:00
8ce3f8bdc9 dreamcast2: add font example 2025-09-03 12:48:31 -05:00
74a8e073bc dreamcast2: add sierpinski_tetrahedron_fsaa_yscaler 2025-08-28 18:20:43 -05:00
9b7eae231a dreamcast2: add sierpinski_tetrahedron_fsaa 2025-08-28 13:27:59 -05:00
9108c6a9c1 dreamcast2: add triangle_core_fullscreen and textured_background_fullscreen 2025-08-28 11:19:51 -05:00
e6a35d14d5 dreamcast2: add tetrahedron examples 2025-08-27 20:30:30 -05:00
cf70518bfd dreamcast2: add cuba_ta_fullscreen_textured 2025-08-26 20:40:29 -05:00
77f7869e91 ftdi_transfer: add reset command 2025-08-26 19:57:29 -05:00
b54b635e61 dreamcast2: triangle_ta*: remove while (1) loop 2025-08-26 19:57:13 -05:00
9ecb8c6f5f dreamcast2: add triangle_ta_fullscreen 2025-08-26 17:07:59 -05:00
18c906133c dreamcast2: add triangle_ta 2025-08-26 16:45:42 -05:00
45f8661b93 dreamcast2: add triangle_core 2025-08-25 16:40:45 -05:00
586d493a6e dreamcast2: holly: add object_list_bits 2025-08-25 16:40:40 -05:00
5f61aaa483 dreamcast2: add framebuffer_shaded example 2025-08-24 22:16:29 -05:00
8e97614ffe dreamcast2: initial 2025-08-24 11:10:55 -05:00
284310244c math/mat: add col function 2025-07-24 23:09:04 -05:00
13200501ef vec: correct normalize/magnitude declaration 2025-07-21 20:04:20 -05:00
e691956223 vec: more strongly hint on generating fsrra instructions 2025-07-21 16:35:47 -05:00
9585f66637 mat3x3: undelete operator= 2025-07-21 16:35:28 -05:00
1f5fdcc197 mat3x3: add matrix inverse 2025-07-21 13:52:25 -05:00
c55c0e21a9 framebuffer: missing stdint include 2025-07-16 23:46:17 -05:00
d25b5c1392 holly: add framebuffer
This will eventually replace video_output.
2025-07-16 13:02:33 -05:00
51b42a7a55 ttf_bitmap2: show width and height 2025-07-16 13:01:49 -05:00
cf372b7dc8 vec3: add *= 2025-07-16 13:01:17 -05:00
119592bcbe holly: add core_param_init, ta_fifo_texture_memory_transfer 2025-07-16 13:00:36 -05:00
da7d77dd7e add twiddle_data_4bpp 2025-07-02 20:56:51 -05:00
c562ef7025 example: add software_ta_two_volumes 2025-07-02 20:01:11 -05:00
518465e180 tools: add adpcm 2025-06-29 13:15:58 -05:00
b52852537a math: add clamp 2025-06-29 13:08:36 -05:00
51fb0c97a6 base: add adpcm rules 2025-06-28 15:56:54 -05:00
a37ec7eb2c blender: add tentative triangle support 2025-06-26 22:18:52 -05:00
cb8fd7e345 systembus_bits: add istext 2025-06-25 15:03:27 -05:00
b51487d374 aica_common: correct sgc definition 2025-06-25 15:03:14 -05:00
729ffba90f add texture_memory_alloc9 2025-06-25 12:43:43 -05:00
ab153f2c43 software_ta: separate framebuffer index from animation index 2025-06-24 21:16:20 -05:00
5c488ab974 printf: add print_integer function 2025-06-23 15:38:57 -05:00
ef29e0ac25 aica_xm: document constants 2025-06-23 09:48:35 -05:00
ff3f8f0837 aica_xm: channels remember last played instrument 2025-06-22 19:53:08 -05:00
138 changed files with 24056 additions and 78 deletions

2
.gitignore vendored
View File

@ -19,4 +19,4 @@ tools/ftdi_transfer
k_means_vq
*.blend1
*.scramble
*.FCStd1
*.FCStd1

View File

@ -263,11 +263,11 @@ struct aica_common {
uint32_t SGC() const
{
return (static_cast<uint32_t>((reg_2810 >> 14) & 0x1) << 0);
return (static_cast<uint32_t>((reg_2810 >> 13) & 0x3) << 0);
}
void SGC(const uint32_t v)
{
reg_2810 = (((v >> 0) & 0x1) << 14) | (reg_2810 & 0xbfff);
reg_2810 = (((v >> 0) & 0x3) << 13) | (reg_2810 & 0x9fff);
}
uint32_t EG() const
@ -714,7 +714,7 @@ namespace aica {
}
namespace lp_sgc_eg {
constexpr uint32_t LP(const uint32_t reg) { return (static_cast<uint32_t>((reg >> 15) & 0x1) << 0); }
constexpr uint32_t SGC(const uint32_t reg) { return (static_cast<uint32_t>((reg >> 14) & 0x1) << 0); }
constexpr uint32_t SGC(const uint32_t reg) { return (static_cast<uint32_t>((reg >> 13) & 0x3) << 0); }
constexpr uint32_t EG(const uint32_t reg) { return (static_cast<uint32_t>((reg >> 0) & 0x1fff) << 0); }
}
namespace ca {

View File

@ -1,20 +1,18 @@
#pragma once
#if defined(__dreamcast__)
#include "sh7091/serial.hpp"
#define print__character serial::character
#define print__string serial::string
#define print__integer serial::integer<uint32_t>
#else
#error "unknown platform"
#endif
#include "printf/printf.h"
#define print__character print_char
#define print__string print_cstring
#define print__integer print_integer
#define assert(b) \
do { \
if (!(b)) { \
print__string(__FILE__); \
print__character(':'); \
print__integer(__LINE__, ' '); \
print__integer(__LINE__); \
print__character(' '); \
print__string(__func__); \
print__string(": assertion failed: "); \
print__string(#b); \

View File

@ -78,6 +78,12 @@ endef
%.pcm.h: %.pcm
$(BUILD_BINARY_H)
%.adpcm.o: %.adpcm
$(BUILD_BINARY_O)
%.adpcm.h: %.adpcm
$(BUILD_BINARY_H)
%.data.o: %.data
$(BUILD_BINARY_O)

View File

@ -46,12 +46,14 @@ def render_polygons(f, name, polygons):
uv_ix = 0
for i, polygon in enumerate(polygons):
indices = [*polygon.vertices, polygon.material_index, uv_ix]
if len(polygon.vertices) == 3:
indices = [*polygon.vertices, -1, polygon.material_index, uv_ix]
uv_ix += len(polygon.vertices)
s = ", ".join(map(str, indices))
if len(polygon.vertices) == 4:
if len(polygon.vertices) in {3, 4}:
f.write(f" {{{s}}},\n")
else:
f.write(f" {{0, 0, 0, 0, -1}}, // {{{s}}}\n")
f.write(f" {{-1, -1, -1, -1, -1, -1}}, // {{{s}}}\n")
f.write("};\n\n")
def render_polygon_edge_pairs(f, name, polygons):

1
dreamcast2/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.csv

15
dreamcast2/Makefile Normal file
View File

@ -0,0 +1,15 @@
include base.mk
OPT = -O2
MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
CFLAGS += -I$(MAKEFILE_PATH)
LIB ?= $(MAKEFILE_PATH)
include example/example.mk
clean:
find -P \
-regextype posix-egrep \
-regex '.*\.(iso|o|d|bin|elf|cue|gch)$$' \
-exec rm {} \;

32
dreamcast2/addresses.lds Normal file
View File

@ -0,0 +1,32 @@
system_boot_rom = 0xa0000000;
systembus = 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;

76
dreamcast2/base.mk Normal file
View File

@ -0,0 +1,76 @@
################################################################################
# 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
LD_LIBGCC += -L $(dir $(shell $(CC) -print-file-name=libgcc.a)) -lgcc
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) $^ $(LD_LIBGCC) -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 ALIGN(4) :
{
KEEP(*(.text.start))
*(.text.start.*)
} > p2ram AT>p1ram
. = ORIGIN(p1ram) + (. - ORIGIN(p2ram));
.text ALIGN(4) : SUBALIGN(4)
{
*(.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,503 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix, uint32_t texture_address)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::packed_color
| parameter_control_word::texture;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::filter_mode::point_sampled
| tsp_instruction_word::texture_shading_instruction::decal
| tsp_instruction_word::texture_u_size::_256
| tsp_instruction_word::texture_v_size::_256;
polygon->texture_control_word = texture_control_word::pixel_format::rgb565
| texture_control_word::scan_order::non_twiddled
| texture_control_word::texture_address(texture_address / 8);
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_triangle(uint32_t store_queue_ix,
float ax, float ay, float az, float au, float av, uint32_t ac,
float bx, float by, float bz, float bu, float bv, uint32_t bc,
float cx, float cy, float cz, float cu, float cv, uint32_t cc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_3 * vertex = (volatile vertex_parameter::polygon_type_3 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_3)) * 3;
// bottom left
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[0].x = ax;
vertex[0].y = ay;
vertex[0].z = az;
vertex[0].u = au;
vertex[0].v = av;
vertex[0].base_color = ac;
vertex[0].offset_color = 0;
// start store queue transfer of `vertex[0]` to the TA
pref(&vertex[0]);
// top center
vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[1].x = bx;
vertex[1].y = by;
vertex[1].z = bz;
vertex[1].u = bu;
vertex[1].v = bv;
vertex[1].base_color = bc;
vertex[1].offset_color = 0;
// start store queue transfer of `vertex[1]` to the TA
pref(&vertex[1]);
// bottom right
vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| parameter_control_word::end_of_strip;
vertex[2].x = cx;
vertex[2].y = cy;
vertex[2].z = cz;
vertex[2].u = cu;
vertex[2].v = cv;
vertex[2].base_color = cc;
vertex[2].offset_color = 0;
// start store queue transfer of `params[2]` to the TA
pref(&vertex[2]);
return store_queue_ix;
}
/*
These vertex and face definitions are a trivial transformation of the default
Blender cube, as exported by the .obj exporter (with triangulation enabled).
*/
struct vec3 {
float x;
float y;
float z;
};
struct vec2 {
float u;
float v;
};
static const vec3 cube_vertex_position[] = {
{ 1.0f, 1.0f, -1.0f },
{ 1.0f, -1.0f, -1.0f },
{ 1.0f, 1.0f, 1.0f },
{ 1.0f, -1.0f, 1.0f },
{ -1.0f, 1.0f, -1.0f },
{ -1.0f, -1.0f, -1.0f },
{ -1.0f, 1.0f, 1.0f },
{ -1.0f, -1.0f, 1.0f },
};
static const vec2 cube_vertex_texture[] = {
{ 1.0f, 0.0f },
{ 0.0f, 1.0f },
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
};
struct position_texture {
int position;
int texture;
};
struct face {
position_texture a;
position_texture b;
position_texture c;
};
/*
It is also possible to submit each cube face as a 4-vertex triangle strip, or
submit the entire cube as a single triangle strip.
Separate 3-vertex triangles are chosen to make this example more
straightforward, but this is not the best approach if high performance is
desired.
*/
static const face cube_faces[] = {
{{4, 0}, {2, 1}, {0, 2}},
{{2, 0}, {7, 1}, {3, 2}},
{{6, 0}, {5, 1}, {7, 2}},
{{1, 0}, {7, 1}, {5, 2}},
{{0, 0}, {3, 1}, {1, 2}},
{{4, 0}, {1, 1}, {5, 2}},
{{4, 0}, {6, 3}, {2, 1}},
{{2, 0}, {6, 3}, {7, 1}},
{{6, 0}, {4, 3}, {5, 1}},
{{1, 0}, {3, 3}, {7, 1}},
{{0, 0}, {2, 3}, {3, 1}},
{{4, 0}, {0, 3}, {1, 1}},
};
static const int cube_faces_length = (sizeof (cube_faces)) / (sizeof (cube_faces[0]));
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v)
{
// to make the cube's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cos(theta) - z0 * sin(theta);
float y1 = y0;
float z1 = x0 * sin(theta) + z0 * cos(theta);
float x2 = x1;
float y2 = y1 * cos(theta) - z1 * sin(theta);
float z2 = y1 * sin(theta) + z1 * cos(theta);
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 3.0f);
return (vec3){v.x * w, v.y * w, w};
}
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 240.f + 320.f,
v.y * 240.f + 240.f,
v.z,
};
}
void transfer_ta_cube(uint32_t texture_address)
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
uint32_t store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix, texture_address);
for (int face_ix = 0; face_ix < cube_faces_length; face_ix++) {
int ipa = cube_faces[face_ix].a.position;
int ipb = cube_faces[face_ix].b.position;
int ipc = cube_faces[face_ix].c.position;
vec3 vpa = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(cube_vertex_position[ipa])));
vec3 vpb = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(cube_vertex_position[ipb])));
vec3 vpc = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(cube_vertex_position[ipc])));
int ita = cube_faces[face_ix].a.texture;
int itb = cube_faces[face_ix].b.texture;
int itc = cube_faces[face_ix].c.texture;
vec2 vta = cube_vertex_texture[ita];
vec2 vtb = cube_vertex_texture[itb];
vec2 vtc = cube_vertex_texture[itc];
// vertex color is irrelevant in "decal" mode
uint32_t va_color = 0;
uint32_t vb_color = 0;
uint32_t vc_color = 0;
store_queue_ix = transfer_ta_vertex_triangle(store_queue_ix,
vpa.x, vpa.y, vpa.z, vta.u, vta.v, va_color,
vpb.x, vpb.y, vpb.z, vtb.u, vtb.v, vb_color,
vpc.x, vpc.y, vpc.z, vtc.u, vtc.v, vc_color);
}
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
const uint8_t texture[] __attribute__((aligned(4))) = {
#embed "texture/pavement_256x256.rgb565"
};
void transfer_texture(uint32_t texture_start)
{
// use 4-byte transfers to texture memory, for slightly increased transfer
// speed
//
// It would be even faster to use the SH4 store queue for this operation, or
// SH4 DMA.
sh7091::store_queue_transfer::copy((void *)&texture_memory64[texture_start], texture, (sizeof (texture)));
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
// these addresses are in "64-bit" texture memory address space:
uint32_t texture_start = 0x700000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// transfer the texture image to texture ram
//////////////////////////////////////////////////////////////////////////////
transfer_texture(texture_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
// draw 500 frames of cube rotation
for (int i = 0; i < 500; i++) {
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
transfer_ta_cube(texture_start);
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization (and the TA)
//////////////////////////////////////////////////////////////////////////////
while (!(spg_status::vsync(holly.SPG_STATUS)));
while (spg_status::vsync(holly.SPG_STATUS));
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// increment theta for the cube rotation animation
// (used by the `vertex_rotate` function)
theta += 0.01f;
}
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,762 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
static inline void character(const char c)
{
using sh7091::sh7091;
using namespace sh7091;
// set the transmit trigger to `1 byte`--this changes the behavior of TDFE
sh7091.SCIF.SCFCR2 = scif::scfcr2::ttrg::trigger_on_1_bytes;
// wait for transmit fifo to become partially empty
while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0);
// unset tdfe bit
sh7091.SCIF.SCFSR2 = (uint16_t)(~scif::scfsr2::tdfe::bit_mask);
sh7091.SCIF.SCFTDR2 = c;
}
static void string(const char * s)
{
while (*s != 0) {
character(*s++);
}
}
static void print_base16(uint32_t n, int len)
{
char buf[len];
char * bufi = &buf[len - 1];
while (bufi >= buf) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
*bufi = nib;
bufi -= 1;
}
for (int i = 0; i < len; i++) {
character(buf[i]);
}
}
#include "../../math/float_types.hpp"
#include "model/suzanne2.h"
//#include "model/icosphere.h"
//#include "model/cube.h"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0x000000;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0x000000;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0x000000;
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::floating_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
#define abs(n) __builtin_abs(n)
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v)
{
// to make the models's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cos(theta) - z0 * sin(theta);
float y1 = y0;
float z1 = x0 * sin(theta) + z0 * cos(theta);
float x2 = x1;
float y2 = y1 * cos(theta) - z1 * sin(theta);
float z2 = y1 * sin(theta) + z1 * cos(theta);
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 2.0f);
return (vec3){v.x * w, v.y * w, w};
}
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 240.f + 320.f,
v.y * 240.f + 240.f,
v.z,
};
}
static inline uint32_t transfer_ta_vertex_triangle(uint32_t store_queue_ix,
float x, float y, float z,
float r, float g, float b,
bool end_of_strip)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_1 * vertex = (volatile vertex_parameter::polygon_type_1 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_1)) * 1;
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| (end_of_strip ? parameter_control_word::end_of_strip : 0);
vertex[0].x = x;
vertex[0].y = y;
vertex[0].z = z;
//vertex[0].base_color_alpha = a;
vertex[0].base_color_r = r;
vertex[0].base_color_g = g;
vertex[0].base_color_b = b;
pref(vertex);
return store_queue_ix;
}
static inline float remap(float f)
{
return (f + 1.0f) * 0.5f;
}
static inline float unremap(int i)
{
return -1.0f + (((float)i) * (1.0f / 255.0f)) * 2.0f;
}
static inline vec3 remap_normal(vec3 n)
{
return {
remap(n.x),
remap(n.y),
remap(n.z)
};
}
static inline float pow(float f)
{
return __builtin_powf(f, 32);
}
static inline float lighting(vec3& position, vec3& normal) __attribute__((always_inline));
static inline float lighting(vec3& position, vec3& normal)
{
vec3 light_pos = {0, 0, -2};
vec3 view_pos = {0, 0, -5};
// ambient
float ambient_strength = 0.1f;
// diffuse
float diffuse_strength = 0.8f;
vec3 norm = normalize(normal);
vec3 light_dir = normalize(light_pos - position);
float diffuse = max(dot(norm, light_dir), 0.0f);
// specular
float specular_strength = 0.5f;
vec3 view_dir = normalize(view_pos - position);
vec3 reflect_dir = reflect(-light_dir, norm);
float specular = pow(max(dot(view_dir, reflect_dir), 0.0f));
float intensity = ambient_strength + diffuse * diffuse_strength + specular * specular_strength;
return intensity;
}
static const int strips_length = (sizeof (strips)) / (sizeof (strips[0]));
template <int render_mode>
void transfer_ta_strips()
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
uint32_t store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix);
int color_ix = 0;
for (int strip_ix = 0; strip_ix < strips_length; strip_ix++) {
int vertex_ix = strips[strip_ix];
vec3 p = vertex_rotate(vertices[abs(vertex_ix)]);
vec3 vp = vertex_screen_space(
vertex_perspective_divide(p));
vec3 n = vertex_rotate(normals[abs(vertex_ix)]);
bool end_of_strip = vertex_ix < 0;
float intensity = lighting(p, n);
if constexpr (render_mode == 0) {
store_queue_ix = transfer_ta_vertex_triangle(store_queue_ix,
vp.x, vp.y, vp.z,
remap(p.x), remap(p.y), remap(p.z),
//c.x, c.y, c.z,
//remap(n.x), remap(n.y), remap(n.z),
end_of_strip);
}
if constexpr (render_mode == 1) {
store_queue_ix = transfer_ta_vertex_triangle(store_queue_ix,
vp.x, vp.y, vp.z,
//remap(p.x), remap(p.y), remap(p.z),
//c.x, c.y, c.z,
remap(n.x), remap(n.y), remap(n.z),
end_of_strip);
}
if constexpr (render_mode == 2) {
store_queue_ix = transfer_ta_vertex_triangle(store_queue_ix,
vp.x, vp.y, vp.z,
//remap(p.x), remap(p.y), remap(p.z),
intensity, intensity, intensity,
//remap(n.x), remap(n.y), remap(n.z),
end_of_strip);
}
if (end_of_strip) {
color_ix = (color_ix + 1) % 64;
}
}
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
static inline void assert(bool t)
{
if (!t) {
string("assertion failed\n");
}
}
static void ch1_dma_transfer(uint32_t source, uint32_t destination, uint32_t transfers)
{
using namespace sh7091::dmac;
using sh7091::sh7091;
volatile uint32_t _dummy = sh7091.DMAC.CHCR1;
(void)_dummy;
sh7091.DMAC.CHCR1 = 0;
assert((((uint32_t)source) & 0b11111) == 0);
assert((((uint32_t)destination) & 0b11111) == 0);
sh7091.DMAC.SAR1 = source;
sh7091.DMAC.DAR1 = destination;
sh7091.DMAC.DMATCR1 = dmatcr::transfer_count(transfers);
sh7091.DMAC.CHCR1 = chcr::dm::destination_address_incremented
| chcr::sm::source_address_incremented
| chcr::rs::resource_select(0b0100) /* auto request; external address space → external address space */
| chcr::tm::cycle_burst_mode /* transmit mode */
//| chcr::tm::cycle_steal_mode /* transmit mode */
| chcr::ts::_32_byte /* transfer size */
//| chcr::ie::interrupt_request_generated
| chcr::de::channel_operation_enabled;
}
static void ch3_dma_transfer(uint32_t source, uint32_t destination, uint32_t transfers)
{
using namespace sh7091::dmac;
using sh7091::sh7091;
volatile uint32_t _dummy = sh7091.DMAC.CHCR3;
(void)_dummy;
sh7091.DMAC.CHCR3 = 0;
assert((((uint32_t)source) & 0b11111) == 0);
assert((((uint32_t)destination) & 0b11111) == 0);
sh7091.DMAC.SAR3 = source;
sh7091.DMAC.DAR3 = destination;
sh7091.DMAC.DMATCR3 = dmatcr::transfer_count(transfers);
sh7091.DMAC.CHCR3 = chcr::dm::destination_address_incremented
| chcr::sm::source_address_incremented
| chcr::rs::resource_select(0b0100) /* auto request; external address space → external address space */
| chcr::tm::cycle_burst_mode /* transmit mode */
//| chcr::tm::cycle_steal_mode /* transmit mode */
| chcr::ts::_32_byte /* transfer size */
//| chcr::ie::interrupt_request_generated
| chcr::de::channel_operation_enabled;
}
void ch2_dma_transfer(uint32_t source, uint32_t destination, uint32_t transfers)
{
using namespace sh7091::dmac;
using sh7091::sh7091;
using namespace systembus;
using systembus::systembus;
for (uint32_t i = 0; i < transfers; i++) {
ocbp(source + (32 * i));
}
// this dummy read appears to be required on real hardware.
volatile uint32_t _dummy = sh7091.DMAC.CHCR2;
(void)_dummy;
systembus.ISTNRM = istnrm::end_of_dma_ch2_dma;
/* start a new CH2-DMA transfer from "system memory" to "TA FIFO polygon converter" */
sh7091.DMAC.CHCR2 = 0; /* disable DMA channel */
sh7091.DMAC.SAR2 = reinterpret_cast<uint32_t>(source); /* start address, must be aligned to a CHCHR__TS-sized (32-byte) boundary */
sh7091.DMAC.DMATCR2 = dmatcr::transfer_count(transfers); /* transfer count, in CHCHR__TS-sized (32-byte) units */
sh7091.DMAC.CHCR2 = chcr::dm::destination_address_incremented
| chcr::sm::source_address_incremented
| chcr::rs::resource_select(0b0010) /* external request, single address mode;
external address space external device */
| chcr::tm::cycle_burst_mode /* transmit mode */
| chcr::ts::_32_byte /* transfer size */
| chcr::de::channel_operation_enabled;
systembus.C2DSTAT = c2dstat::texture_memory_start_address(destination); /* CH2-DMA destination address */
systembus.C2DLEN = c2dlen::transfer_length(transfers * 32); /* CH2-DMA length (must be a multiple of 32) */
systembus.C2DST = 1; /* CH2-DMA start (an 'external' request from SH7091's perspective) */
}
static inline void wait_ta()
{
using namespace systembus;
using systembus::systembus;
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0) {
if (systembus.ISTERR) {
string("wait ta ISTERR: ");
print_base16(systembus.ISTERR, 8);
string("\n ");
return;
}
};
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
}
static inline void wait_render()
{
using namespace systembus;
using systembus::systembus;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0) {
if (systembus.ISTERR) {
string("wait render ISTERR: ");
print_base16(systembus.ISTERR, 8);
string("\n ");
return;
}
}
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
}
static uint8_t tmp_buf0[640 * 480 * 4] __attribute__((aligned(32)));
static uint8_t tmp_buf1[640 * 480 * 4] __attribute__((aligned(32)));
static const uint32_t framebuffer_start[3] = {0x000000, 0x12c000, 0x258000};
static const uint32_t region_array_start = 0x384000;
static const uint32_t isp_tsp_parameter_start = 0x500000;
static const uint32_t object_list_start = 0x400000;
static inline void deferred_shading_render(int frame_ix)
{
using holly::holly;
using namespace holly;
using systembus::systembus;
using namespace systembus;
{ // start transfer 0
if (frame_ix != 0)
while ((sh7091::sh7091.DMAC.CHCR1 & sh7091::dmac::chcr::te::transfers_completed) == 0);
uint32_t source = (uint32_t)&texture_memory32[framebuffer_start[0]];
ch1_dma_transfer(source, (uint32_t)tmp_buf0, (640 * 480 * 4) / 32);
}
{ // start transfer 1
if (frame_ix != 0)
while ((sh7091::sh7091.DMAC.CHCR3 & sh7091::dmac::chcr::te::transfers_completed) == 0);
uint32_t source = (uint32_t)&texture_memory32[framebuffer_start[1]];
ch3_dma_transfer(source, (uint32_t)tmp_buf1, (640 * 480 * 4) / 32);
}
{ // position
if (frame_ix != 0) {
wait_render();
}
holly.TA_LIST_INIT = ta_list_init::list_init;
(void)holly.TA_LIST_INIT;
transfer_ta_strips<0>();
wait_ta();
holly.FB_W_SOF1 = framebuffer_start[0];
systembus.ISTERR = 0xffffffff;
holly.STARTRENDER = 1;
}
{ // invalidate buffers
for (int i = 0; i < 640 * 480 * 4 / 32; i++) {
ocbi(&tmp_buf0[i * 32]);
ocbi(&tmp_buf1[i * 32]);
}
}
{ // normals
wait_render();
holly.TA_LIST_INIT = ta_list_init::list_init;
(void)holly.TA_LIST_INIT;
transfer_ta_strips<1>();
wait_ta();
holly.FB_W_SOF1 = framebuffer_start[1];
systembus.ISTERR = 0xffffffff;
holly.STARTRENDER = 1;
}
if constexpr (1) {
for (int i = 0; i < 640 * 480; i++) {
if (i % 8 == 0) {
pref(&tmp_buf0[(i + 1) * 4 / 32]);
pref(&tmp_buf1[(i + 1) * 4 / 32]);
}
uint8_t p_b = tmp_buf0[i * 4 + 0];
uint8_t p_g = tmp_buf0[i * 4 + 1];
uint8_t p_r = tmp_buf0[i * 4 + 2];
if (p_b == 0 && p_g == 0 && p_r == 0)
continue;
vec3 p = {unremap(p_r), unremap(p_g), unremap(p_b)};
uint8_t n_b = tmp_buf1[i * 4 + 0];
uint8_t n_g = tmp_buf1[i * 4 + 1];
uint8_t n_r = tmp_buf1[i * 4 + 2];
vec3 n = {unremap(n_r), unremap(n_g), unremap(n_b)};
float intensity = lighting(p, n);
int color = intensity * 255.0f;
if (color > 255) color = 255;
if (color < 0) color = 0;
tmp_buf0[i * 4 + 0] = color;
tmp_buf0[i * 4 + 1] = color;
tmp_buf0[i * 4 + 2] = color;
//if (i % 8 == 7) {
//ocbp(&tmp_buf0[(i & (~7)) * 4 / 32]);
//}
}
}
//systembus.ISTNRM = istnrm::v_blank_in;
//while ((systembus.ISTNRM & istnrm::v_blank_in) == 0);
if (frame_ix != 0) {
while ((systembus.ISTNRM & istnrm::end_of_dma_ch2_dma) == 0);
systembus.ISTNRM = istnrm::end_of_dma_ch2_dma;
}
systembus.LMMODE0 = 1;
systembus.LMMODE1 = 1;
uint32_t destination = 0x11000000 + framebuffer_start[2];
ch2_dma_transfer((uint32_t)tmp_buf0, destination, (640 * 480 * 4) / 32);
holly.FB_R_SOF1 = framebuffer_start[2];
}
static inline void forward_shading_render(int frame_ix)
{
using holly::holly;
using namespace holly;
using systembus::systembus;
using namespace systembus;
holly.TA_LIST_INIT = ta_list_init::list_init;
(void)holly.TA_LIST_INIT;
transfer_ta_strips<2>();
wait_ta();
holly.FB_W_SOF1 = framebuffer_start[frame_ix % 3];
systembus.ISTERR = 0xffffffff;
holly.STARTRENDER = 1;
wait_render();
systembus.ISTNRM = istnrm::v_blank_in;
while ((systembus.ISTNRM & istnrm::v_blank_in) == 0);
holly.FB_R_SOF1 = framebuffer_start[frame_ix % 3];
}
void main()
{
{
using namespace sh7091::dmac;
using sh7091::sh7091;
sh7091.DMAC.CHCR0 = 0;
sh7091.DMAC.CHCR1 = 0;
sh7091.DMAC.CHCR2 = 0;
sh7091.DMAC.CHCR3 = 0;
sh7091.DMAC.DMAOR = dmaor::ddt::on_demand_data_transfer_mode /* on-demand data transfer mode */
| dmaor::pr::ch2_ch0_ch1_ch3 /* priority mode; CH2 > CH0 > CH1 > CH3 */
| dmaor::dme::operation_enabled_on_all_channels; /* DMAC master enable */
}
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 32 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_32x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 32 * 4 * tile_y_num * tile_x_num);
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
//holly.FB_W_SOF1 = framebuffer_start;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
//holly.FB_R_SOF1 = framebuffer_start[0];
using systembus::systembus;
using namespace systembus;
systembus.ISTNRM = 0xffffffff;
// draw 500 frames of cube rotation
for (int frame_ix = 0; frame_ix < 10000; frame_ix++) {
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
if constexpr (false) {
forward_shading_render(frame_ix);
} else {
deferred_shading_render(frame_ix);
}
// increment theta for the cube rotation animation
// (used by the `vertex_rotate` function)
theta += 0.01f;
}
string("return\n ");
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,127 @@
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)
TRIANGLE_CORE_OBJ = \
example/triangle_core.o
example/triangle_core.elf: LDSCRIPT = $(LIB)/main.lds
example/triangle_core.elf: $(START_OBJ) $(TRIANGLE_CORE_OBJ)
TRIANGLE_CORE_FULLSCREEN_OBJ = \
example/triangle_core_fullscreen.o
example/triangle_core_fullscreen.elf: LDSCRIPT = $(LIB)/main.lds
example/triangle_core_fullscreen.elf: $(START_OBJ) $(TRIANGLE_CORE_FULLSCREEN_OBJ)
TEXTURED_BACKGROUND_FULLSCREEN_OBJ = \
example/textured_background_fullscreen.o
example/textured_background_fullscreen.elf: LDSCRIPT = $(LIB)/main.lds
example/textured_background_fullscreen.elf: $(START_OBJ) $(TEXTURED_BACKGROUND_FULLSCREEN_OBJ)
TRIANGLE_TA_OBJ = \
example/triangle_ta.o
example/triangle_ta.elf: LDSCRIPT = $(LIB)/main.lds
example/triangle_ta.elf: $(START_OBJ) $(TRIANGLE_TA_OBJ)
TRIANGLE_TA_FULLSCREEN_OBJ = \
holly/core/region_array.o \
example/triangle_ta_fullscreen.o
example/triangle_ta_fullscreen.elf: LDSCRIPT = $(LIB)/main.lds
example/triangle_ta_fullscreen.elf: $(START_OBJ) $(TRIANGLE_TA_FULLSCREEN_OBJ)
TRIANGLE_TA_LIST_CONT_OBJ = \
example/triangle_ta_list_cont.o
example/triangle_ta_list_cont.elf: LDSCRIPT = $(LIB)/main.lds
example/triangle_ta_list_cont.elf: $(START_OBJ) $(TRIANGLE_TA_LIST_CONT_OBJ)
CUBE_TA_FULLSCREEN_TEXTURED_OBJ = \
holly/core/region_array.o \
example/cube_ta_fullscreen_textured.o
example/cube_ta_fullscreen_textured.elf: LDSCRIPT = $(LIB)/main.lds
example/cube_ta_fullscreen_textured.elf: $(START_OBJ) $(CUBE_TA_FULLSCREEN_TEXTURED_OBJ)
SUZANNE_TRIANGLE_STRIPS_OBJ = \
holly/core/region_array.o \
example/suzanne_triangle_strips.o
example/suzanne_triangle_strips.elf: LDSCRIPT = $(LIB)/main.lds
example/suzanne_triangle_strips.elf: $(START_OBJ) $(SUZANNE_TRIANGLE_STRIPS_OBJ)
DEFERRED_SHADING_OBJ = \
holly/core/region_array.o \
example/deferred_shading.o
example/deferred_shading.elf: LDSCRIPT = $(LIB)/main.lds
example/deferred_shading.elf: $(START_OBJ) $(DEFERRED_SHADING_OBJ)
TETRAHEDRON_OBJ = \
holly/core/region_array.o \
example/tetrahedron.o
example/tetrahedron.elf: LDSCRIPT = $(LIB)/main.lds
example/tetrahedron.elf: $(START_OBJ) $(TETRAHEDRON_OBJ)
SIERPINSKI_TETRAHEDRON_OBJ = \
holly/core/region_array.o \
example/sierpinski_tetrahedron.o
example/sierpinski_tetrahedron.elf: LDSCRIPT = $(LIB)/main.lds
example/sierpinski_tetrahedron.elf: $(START_OBJ) $(SIERPINSKI_TETRAHEDRON_OBJ)
SIERPINSKI_TETRAHEDRON_FSAA_OBJ = \
holly/core/region_array.o \
example/sierpinski_tetrahedron_fsaa.o
example/sierpinski_tetrahedron_fsaa.elf: LDSCRIPT = $(LIB)/main.lds
example/sierpinski_tetrahedron_fsaa.elf: $(START_OBJ) $(SIERPINSKI_TETRAHEDRON_FSAA_OBJ)
SIERPINSKI_TETRAHEDRON_FSAA_YSCALER_OBJ = \
holly/core/region_array.o \
example/sierpinski_tetrahedron_fsaa_yscaler.o
example/sierpinski_tetrahedron_fsaa_yscaler.elf: LDSCRIPT = $(LIB)/main.lds
example/sierpinski_tetrahedron_fsaa_yscaler.elf: $(START_OBJ) $(SIERPINSKI_TETRAHEDRON_FSAA_YSCALER_OBJ)
FONT_OBJ = \
holly/core/region_array.o \
example/font.o
example/font.elf: LDSCRIPT = $(LIB)/main.lds
example/font.elf: $(START_OBJ) $(FONT_OBJ)
FONT_SERIAL_OBJ = \
holly/core/region_array.o \
example/font_serial.o
example/font_serial.elf: LDSCRIPT = $(LIB)/main.lds
example/font_serial.elf: $(START_OBJ) $(FONT_SERIAL_OBJ)
MAPLE_DEVICE_REQUEST_OBJ = \
example/maple_device_request.o
example/maple_device_request.elf: LDSCRIPT = $(LIB)/main.lds
example/maple_device_request.elf: $(START_OBJ) $(MAPLE_DEVICE_REQUEST_OBJ)
MAPLE_GET_CONDITION_OBJ = \
example/maple_get_condition.o
example/maple_get_condition.elf: LDSCRIPT = $(LIB)/main.lds
example/maple_get_condition.elf: $(START_OBJ) $(MAPLE_GET_CONDITION_OBJ)
MAPLE_KEYBOARD_SERIAL_FORWARD_OBJ = \
example/maple_keyboard_serial_forward.o
example/maple_keyboard_serial_forward.elf: LDSCRIPT = $(LIB)/main.lds
example/maple_keyboard_serial_forward.elf: $(START_OBJ) $(MAPLE_KEYBOARD_SERIAL_FORWARD_OBJ)

439
dreamcast2/example/font.cpp Normal file
View File

@ -0,0 +1,439 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
struct vec2 {
float x;
float y;
};
struct face {
float inverse_texture_width;
float inverse_texture_height;
float glyph_width;
float glyph_height;
int hori_advance;
int row_stride;
};
static const face ter_u12n = {
.inverse_texture_width = 1.0f / 128.0f,
.inverse_texture_height = 1.0f / 64.0f,
.glyph_width = 6.0f,
.glyph_height = 12.0f,
.hori_advance = 6,
.row_stride = 21,
};
static inline vec2 glyph_texture(const face& face, const vec2& v, int char_code)
{
int row = char_code / face.row_stride;
int col = char_code % face.row_stride;
return {
(((float)col) * face.glyph_width + v.x * face.glyph_width) * face.inverse_texture_width,
(((float)row) * face.glyph_height + v.y * face.glyph_height) * face.inverse_texture_height,
};
}
static inline vec2 glyph_position(const face& face, const vec2& v, const vec2& p)
{
return {
v.x * face.glyph_width + p.x,
v.y * face.glyph_height + p.y,
};
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix, uint32_t texture_address)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::packed_color
| parameter_control_word::texture;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::filter_mode::point_sampled
| tsp_instruction_word::texture_shading_instruction::decal
| tsp_instruction_word::texture_u_size::_128
| tsp_instruction_word::texture_v_size::_64;
polygon->texture_control_word = texture_control_word::pixel_format::palette_4bpp
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8);
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_quad(uint32_t store_queue_ix,
float ax, float ay, float az, float au, float av, uint32_t ac,
float bx, float by, float bz, float bu, float bv, uint32_t bc,
float cx, float cy, float cz, float cu, float cv, uint32_t cc,
float dx, float dy, float dz, float du, float dv, uint32_t dc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_3 * vertex = (volatile vertex_parameter::polygon_type_3 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_3)) * 4;
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[0].x = ax;
vertex[0].y = ay;
vertex[0].z = az;
vertex[0].u = au;
vertex[0].v = av;
vertex[0].base_color = ac;
vertex[0].offset_color = 0;
// start store queue transfer of `vertex[0]` to the TA
pref(&vertex[0]);
vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[1].x = bx;
vertex[1].y = by;
vertex[1].z = bz;
vertex[1].u = bu;
vertex[1].v = bv;
vertex[1].base_color = bc;
vertex[1].offset_color = 0;
// start store queue transfer of `vertex[1]` to the TA
pref(&vertex[1]);
vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[2].x = dx;
vertex[2].y = dy;
vertex[2].z = dz;
vertex[2].u = du;
vertex[2].v = dv;
vertex[2].base_color = dc;
vertex[2].offset_color = 0;
// start store queue transfer of `params[2]` to the TA
pref(&vertex[2]);
vertex[3].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| parameter_control_word::end_of_strip;
vertex[3].x = cx;
vertex[3].y = cy;
vertex[3].z = cz;
vertex[3].u = cu;
vertex[3].v = cv;
vertex[3].base_color = cc;
vertex[3].offset_color = 0;
// start store queue transfer of `params[3]` to the TA
pref(&vertex[3]);
return store_queue_ix;
}
uint32_t transfer_glyph(uint32_t store_queue_ix,
const face& face,
const vec2& t,
int char_code)
{
static const vec2 vtx[] = {
{ 0, 0 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
};
if (char_code <= 0x20 || char_code >= 0x7f) {
return store_queue_ix;
}
char_code -= 0x20;
vec2 ap = glyph_position(face, vtx[0], t);
vec2 bp = glyph_position(face, vtx[1], t);
vec2 cp = glyph_position(face, vtx[2], t);
vec2 dp = glyph_position(face, vtx[3], t);
vec2 at = glyph_texture(face, vtx[0], char_code);
vec2 bt = glyph_texture(face, vtx[1], char_code);
vec2 ct = glyph_texture(face, vtx[2], char_code);
vec2 dt = glyph_texture(face, vtx[3], char_code);
store_queue_ix = transfer_ta_vertex_quad(store_queue_ix,
ap.x, ap.y, 0.1f, at.x, at.y, 0,
bp.x, bp.y, 0.1f, bt.x, bt.y, 0,
cp.x, cp.y, 0.1f, ct.x, ct.y, 0,
dp.x, dp.y, 0.1f, dt.x, dt.y, 0);
return store_queue_ix;
}
void transfer_scene(uint32_t texture_address)
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
uint32_t store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix, texture_address);
store_queue_ix = transfer_glyph(store_queue_ix,
ter_u12n,
vec2(10, 10),
'a');
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
const uint8_t texture[] __attribute__((aligned(4))) = {
#embed "font/ter_u12n.128x64.palette_4bpp.twiddled"
};
void transfer_texture(uint32_t texture_start)
{
// use 4-byte transfers to texture memory, for slightly increased transfer
// speed
//
// It would be even faster to use the SH4 store queue for this operation, or
// SH4 DMA.
sh7091::store_queue_transfer::copy((void *)&texture_memory64[texture_start], texture, (sizeof (texture)));
}
void main()
{
using namespace holly;
using namespace holly::core;
using holly::holly;
/* palette */
holly.PAL_RAM_CTRL = holly::pal_ram_ctrl::pixel_format::argb4444;
holly.PALETTE_RAM[0] = 0x0000;
holly.PALETTE_RAM[1] = 0xffff;
holly.PT_ALPHA_REF = 0xff;
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
// these addresses are in "64-bit" texture memory address space:
uint32_t texture_start = 0x700000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// transfer the texture image to texture ram
//////////////////////////////////////////////////////////////////////////////
transfer_texture(texture_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
transfer_scene(texture_start);
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization (and the TA)
//////////////////////////////////////////////////////////////////////////////
while (!(spg_status::vsync(holly.SPG_STATUS)));
while (spg_status::vsync(holly.SPG_STATUS));
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
}

View File

@ -0,0 +1,463 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
struct vec2 {
float x;
float y;
};
struct face {
float inverse_texture_width;
float inverse_texture_height;
float glyph_width;
float glyph_height;
int hori_advance;
int row_stride;
};
static const face ter_u12n = {
.inverse_texture_width = 1.0f / 128.0f,
.inverse_texture_height = 1.0f / 64.0f,
.glyph_width = 6.0f,
.glyph_height = 12.0f,
.hori_advance = 6,
.row_stride = 21,
};
static inline vec2 glyph_texture(const face& face, const vec2& v, int char_code)
{
int row = char_code / face.row_stride;
int col = char_code % face.row_stride;
return {
(((float)col) * face.glyph_width + v.x * face.glyph_width) * face.inverse_texture_width,
(((float)row) * face.glyph_height + v.y * face.glyph_height) * face.inverse_texture_height,
};
}
static inline vec2 glyph_position(const face& face, const vec2& v, const vec2& p)
{
return {
v.x * face.glyph_width + p.x,
v.y * face.glyph_height + p.y,
};
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix, uint32_t texture_address)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::packed_color
| parameter_control_word::texture;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::filter_mode::point_sampled
| tsp_instruction_word::texture_shading_instruction::decal
| tsp_instruction_word::texture_u_size::_128
| tsp_instruction_word::texture_v_size::_64;
polygon->texture_control_word = texture_control_word::pixel_format::palette_4bpp
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8);
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_quad(uint32_t store_queue_ix,
float ax, float ay, float az, float au, float av, uint32_t ac,
float bx, float by, float bz, float bu, float bv, uint32_t bc,
float cx, float cy, float cz, float cu, float cv, uint32_t cc,
float dx, float dy, float dz, float du, float dv, uint32_t dc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_3 * vertex = (volatile vertex_parameter::polygon_type_3 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_3)) * 4;
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[0].x = ax;
vertex[0].y = ay;
vertex[0].z = az;
vertex[0].u = au;
vertex[0].v = av;
vertex[0].base_color = ac;
vertex[0].offset_color = 0;
// start store queue transfer of `vertex[0]` to the TA
pref(&vertex[0]);
vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[1].x = bx;
vertex[1].y = by;
vertex[1].z = bz;
vertex[1].u = bu;
vertex[1].v = bv;
vertex[1].base_color = bc;
vertex[1].offset_color = 0;
// start store queue transfer of `vertex[1]` to the TA
pref(&vertex[1]);
vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[2].x = dx;
vertex[2].y = dy;
vertex[2].z = dz;
vertex[2].u = du;
vertex[2].v = dv;
vertex[2].base_color = dc;
vertex[2].offset_color = 0;
// start store queue transfer of `params[2]` to the TA
pref(&vertex[2]);
vertex[3].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| parameter_control_word::end_of_strip;
vertex[3].x = cx;
vertex[3].y = cy;
vertex[3].z = cz;
vertex[3].u = cu;
vertex[3].v = cv;
vertex[3].base_color = cc;
vertex[3].offset_color = 0;
// start store queue transfer of `params[3]` to the TA
pref(&vertex[3]);
return store_queue_ix;
}
uint32_t transfer_glyph(uint32_t store_queue_ix,
const face& face,
const vec2& t,
int char_code)
{
static const vec2 vtx[] = {
{ 0, 0 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
};
if (char_code <= 0x20 || char_code >= 0x7f) {
return store_queue_ix;
}
char_code -= 0x20;
vec2 ap = glyph_position(face, vtx[0], t);
vec2 bp = glyph_position(face, vtx[1], t);
vec2 cp = glyph_position(face, vtx[2], t);
vec2 dp = glyph_position(face, vtx[3], t);
vec2 at = glyph_texture(face, vtx[0], char_code);
vec2 bt = glyph_texture(face, vtx[1], char_code);
vec2 ct = glyph_texture(face, vtx[2], char_code);
vec2 dt = glyph_texture(face, vtx[3], char_code);
store_queue_ix = transfer_ta_vertex_quad(store_queue_ix,
ap.x, ap.y, 0.1f, at.x, at.y, 0,
bp.x, bp.y, 0.1f, bt.x, bt.y, 0,
cp.x, cp.y, 0.1f, ct.x, ct.y, 0,
dp.x, dp.y, 0.1f, dt.x, dt.y, 0);
return store_queue_ix;
}
void transfer_scene(uint32_t texture_address, const uint8_t * buf, int buf_length)
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
uint32_t store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix, texture_address);
int advance = 10;
for (int i = 0; i < buf_length; i++) {
store_queue_ix = transfer_glyph(store_queue_ix,
ter_u12n,
vec2(advance, 10),
buf[i]);
advance += ter_u12n.hori_advance;
}
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
const uint8_t texture[] __attribute__((aligned(4))) = {
#embed "font/ter_u12n.128x64.palette_4bpp.twiddled"
};
void transfer_texture(uint32_t texture_start)
{
// use 4-byte transfers to texture memory, for slightly increased transfer
// speed
//
// It would be even faster to use the SH4 store queue for this operation, or
// SH4 DMA.
sh7091::store_queue_transfer::copy((void *)&texture_memory64[texture_start], texture, (sizeof (texture)));
}
void main()
{
using namespace holly;
using namespace holly::core;
using holly::holly;
/* palette */
holly.PAL_RAM_CTRL = holly::pal_ram_ctrl::pixel_format::argb4444;
holly.PALETTE_RAM[0] = 0x0000;
holly.PALETTE_RAM[1] = 0xffff;
holly.PT_ALPHA_REF = 0xff;
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
// these addresses are in "64-bit" texture memory address space:
uint32_t texture_start = 0x700000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// transfer the texture image to texture ram
//////////////////////////////////////////////////////////////////////////////
transfer_texture(texture_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 8 * 4 * tile_y_num * tile_x_num);
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
uint8_t buf[64];
for (int i = 0; i < 64; i++)
buf[i] = ' ';
int buf_ix = 0;
while (1) {
using namespace sh7091;
using sh7091::sh7091;
while (sh7091.SCIF.SCFSR2 & scif::scfsr2::rdf::bit_mask) {
const uint8_t c = sh7091.SCIF.SCFRDR2;
buf[buf_ix] = c;
buf_ix = (buf_ix + 1) % (sizeof (buf));
sh7091.SCIF.SCFSR2 = (uint16_t)(~scif::scfsr2::rdf::bit_mask);
}
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
transfer_scene(texture_start, buf, (sizeof (buf)));
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization (and the TA)
//////////////////////////////////////////////////////////////////////////////
while (!(spg_status::vsync(holly.SPG_STATUS)));
while (spg_status::vsync(holly.SPG_STATUS));
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
}
}

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[0x200000];
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

@ -0,0 +1,246 @@
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
#include "maple/maple_bits.hpp"
#include "maple/maple_host.hpp"
#include "maple/maple_bus_commands.hpp"
#include "maple/maple_bus_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
/*
See DCDBSysArc990907E.pdf page 274.
Maple DMA uses SH4 DMA channel 0 in "DDT" mode. This means that Holly's Maple
DMA functional unit is externally controlling the SH4's DMA unit.
The Dreamcast boot rom leaves channel 0 already configured for Maple DMA,
though if you felt rebellious and wished to used channel 0 for something else,
you would need to reconfigure channel 0 for Maple/DDT afterwards.
Note that this `maple_dma_start` function does not configure SH4 DMA channel
0, and presumes it is already in the correct state.
*/
void maple_dma_start(void * command_buf)
{
// write back operand cache blocks for command buffer prior to starting DMA
for (uint32_t i = 0; i < align_32byte(send_size) / 32; i++) {
asm volatile ("ocbwb @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)command_buf) + 32 * i))
);
}
using systembus::maple_if;
using systembus::systembus;
using namespace maple;
using namespace systembus;
// if SH4 cache were enabled, it would be necessary to use the `ocbwb` sh4
// instruction to write back the cache to system memory, prior to continuing.
// if SH4 cache were enabled, it would be necessary to use the `ocbi` sh4
// instruction to invalidate any possibly-cached areas of the receive buffer,
// as these are imminently going to be rewritten by the DMA unit independently
// of cache access.
// disable Maple DMA and abort any possibly-in-progress transfers
maple_if.MDEN = mden::dma_enable::abort;
while ((maple_if.MDST & mdst::start_status::bit_mask) != 0);
// clear Maple DMA end status
systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
// 20nsec maple_if. 0xc350 = 1ms
uint32_t one_msec = 0xc350;
// set the Maple bus controller timeout and transfer rate
maple_if.MSYS = msys::time_out_counter(one_msec)
| msys::sending_rate::_2M;
// MDAPRO controls which (system memory) addresses are considered valid for
// Maple DMA. An attempt to use an address outside of this range will cause an
// error interrupt in from the Maple DMA unit.
//
// 0x40 through 0x7F allows for transfers from 0x0c000000 to 0x0fffffff
// System Memory is 0x0c000000 through 0x0cffffff (16MB)
//
// It is probably possible to do strange things such as use texture memory as
// a Maple DMA receive buffer, but TOP_ADDRESS would need to be lowered
// accordingly.
maple_if.MDAPRO = mdapro::security_code
| mdapro::top_address(0x40)
| mdapro::bottom_address(0x7f);
// SOFTWARE_INITIATION allows a Maple DMA transfer to be initiated by a write
// to the MDST register.
maple_if.MDTSEL = mdtsel::trigger_select::software_initiation;
// the Maple DMA start address must be 32-byte aligned
maple_if.MDSTAR = mdstar::table_address((uint32_t)command_buf);
// re-enable Maple DMA
maple_if.MDEN = mden::dma_enable::enable;
// start Maple DMA (completes asynchronously)
maple_if.MDST = mdst::start_status::start;
// write back operand cache blocks for command buffer prior to starting DMA
for (uint32_t i = 0; i < align_32byte(recv_size) / 32; i++) {
asm volatile ("ocbi @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)response_buf) + 32 * i))
);
}
}
void maple_dma_wait_complete()
{
using systembus::systembus;
using namespace systembus;
// wait for Maple DMA completion
while ((systembus.ISTNRM & istnrm::end_of_dma_maple_dma) == 0);
// clear Maple DMA end status
systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
}
void maple_device_request(uint8_t * send_buf, uint8_t * recv_buf)
{
using namespace maple;
auto host_command = (maple::host_command<device_request::data_fields> *)(send_buf);
host_command->host_instruction = host_instruction::end_flag
| host_instruction::port_select::a
| host_instruction::pattern::normal
| host_instruction::transfer_length(0 / 4);
host_command->receive_data_address = ((uint32_t)recv_buf) & receive_data_address::mask;
host_command->header.command_code = device_request::command_code;
host_command->header.destination_ap = ap::port_select::a
| ap::de::device;
host_command->header.source_ap = ap::port_select::a
| ap::de::port;
host_command->header.data_size = 0 / 4;
}
static inline void character(const char c)
{
using sh7091::sh7091;
using namespace sh7091;
// set the transmit trigger to `1 byte`--this changes the behavior of TDFE
sh7091.SCIF.SCFCR2 = scif::scfcr2::ttrg::trigger_on_1_bytes;
// wait for transmit fifo to become partially empty
while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0);
// unset tdfe bit
sh7091.SCIF.SCFSR2 = (uint16_t)(~scif::scfsr2::tdfe::bit_mask);
sh7091.SCIF.SCFTDR2 = c;
}
static void string(const char * s)
{
while (*s != 0) {
character(*s++);
}
}
static void print_base16(uint32_t n, int len)
{
char buf[len];
char * bufi = &buf[len - 1];
while (bufi >= buf) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
*bufi = nib;
bufi -= 1;
}
for (int i = 0; i < len; i++) {
character(buf[i]);
}
}
void main()
{
// Maple DMA buffers must be 32-byte aligned
uint8_t send_buf[1024] __attribute__((aligned(32)));
uint8_t recv_buf[1024] __attribute__((aligned(32)));
// fill send_buf with a "device request" command
// recv_buf is reply destination address
maple_device_request(send_buf, recv_buf);
maple_dma_start(send_buf);
maple_dma_wait_complete();
// decode the reply in recv_buf
auto host_response = (maple::host_response<maple::device_status::data_fields> *)recv_buf;
if (host_response->header.command_code != maple::device_status::command_code) {
string("maple port A: invalid response or disconnected\n");
return;
}
string("host_response:\n");
string(" protocol_header:\n");
string(" command_code : ");
print_base16(host_response->header.command_code, 2); character('\n');
string(" destination_ap : ");
print_base16(host_response->header.destination_ap, 2); character('\n');
string(" source_ap : ");
print_base16(host_response->header.source_ap, 2); character('\n');
string(" data_size : ");
print_base16(host_response->header.data_size, 2); character('\n');
// the Maple bus protocol is big endian, but the SH4 is running in little endian mode
#define bswap32 __builtin_bswap32
#define bswap16 __builtin_bswap16
auto& device_status = host_response->data;
string(" device_status:\n");
string(" device_id:\n");
string(" ft : ");
print_base16(bswap32(device_status.device_id.ft), 8); character('\n');
string(" fd[0]: ");
print_base16(bswap32(device_status.device_id.fd[0]), 8); character('\n');
string(" fd[1]: ");
print_base16(bswap32(device_status.device_id.fd[1]), 8); character('\n');
string(" fd[2]: ");
print_base16(bswap32(device_status.device_id.fd[2]), 8); character('\n');
string(" destination_code: ");
print_base16(bswap32(device_status.destination_code), 2); character('\n');
string(" connection_direction: ");
print_base16(bswap32(device_status.connection_direction), 2); character('\n');
string(" product_name: \"");
for (int i = 0; i < 30; i++)
character(device_status.product_name[i]);
string("\"\n");
string(" license: \"");
for (int i = 0; i < 60; i++)
character(device_status.license[i]);
string("\"\n");
string(" low_consumption_standby_current: ");
print_base16(bswap16(device_status.low_consumption_standby_current), 4); character('\n');
string(" maximum_current_consumption: ");
print_base16(bswap16(device_status.maximum_current_consumption), 4); character('\n');
string(" ");
}

View File

@ -0,0 +1,340 @@
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
#include "maple/maple_bits.hpp"
#include "maple/maple_host.hpp"
#include "maple/maple_bus_commands.hpp"
#include "maple/maple_bus_bits.hpp"
#include "maple/maple_bus_ft0.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
static inline void character(const char c)
{
using sh7091::sh7091;
using namespace sh7091;
// set the transmit trigger to `1 byte`--this changes the behavior of TDFE
sh7091.SCIF.SCFCR2 = scif::scfcr2::ttrg::trigger_on_1_bytes;
// wait for transmit fifo to become partially empty
while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0);
// unset tdfe bit
sh7091.SCIF.SCFSR2 = (uint16_t)(~scif::scfsr2::tdfe::bit_mask);
sh7091.SCIF.SCFTDR2 = c;
}
static void string(const char * s)
{
while (*s != 0) {
character(*s++);
}
}
static void print_base16(uint32_t n, int len)
{
char buf[len];
char * bufi = &buf[len - 1];
while (bufi >= buf) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
*bufi = nib;
bufi -= 1;
}
for (int i = 0; i < len; i++) {
character(buf[i]);
}
}
constexpr inline uint32_t align_32byte(uint32_t mem)
{
return (mem + 31) & ~31;
}
/*
See DCDBSysArc990907E.pdf page 274.
Maple DMA uses SH4 DMA channel 0 in "DDT" mode. This means that Holly's Maple
DMA functional unit is externally controlling the SH4's DMA unit.
The Dreamcast boot rom leaves channel 0 already configured for Maple DMA,
though if you felt rebellious and wished to used channel 0 for something else,
you would need to reconfigure channel 0 for Maple/DDT afterwards.
Note that this `maple_dma_start` function does not configure SH4 DMA channel
0, and presumes it is already in the correct state.
*/
void maple_dma_start(void * command_buf, uint32_t send_size,
void * response_buf, uint32_t recv_size)
{
// write back operand cache blocks for command buffer prior to starting DMA
for (uint32_t i = 0; i < align_32byte(send_size) / 32; i++) {
asm volatile ("ocbwb @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)command_buf) + 32 * i))
);
}
using systembus::maple_if;
using systembus::systembus;
using namespace maple;
using namespace systembus;
// if SH4 cache were enabled, it would be necessary to use the `ocbwb` sh4
// instruction to write back the cache to system memory, prior to continuing.
// if SH4 cache were enabled, it would be necessary to use the `ocbi` sh4
// instruction to invalidate any possibly-cached areas of the receive buffer,
// as these are imminently going to be rewritten by the DMA unit independently
// of cache access.
// disable Maple DMA and abort any possibly-in-progress transfers
maple_if.MDEN = mden::dma_enable::abort;
while ((maple_if.MDST & mdst::start_status::bit_mask) != 0);
// clear Maple DMA end status
systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
// 20nsec maple_if. 0xc350 = 1ms
uint32_t one_msec = 0xc350;
// set the Maple bus controller timeout and transfer rate
maple_if.MSYS = msys::time_out_counter(one_msec)
| msys::sending_rate::_2M;
// MDAPRO controls which (system memory) addresses are considered valid for
// Maple DMA. An attempt to use an address outside of this range will cause an
// error interrupt in from the Maple DMA unit.
//
// 0x40 through 0x7F allows for transfers from 0x0c000000 to 0x0fffffff
// System Memory is 0x0c000000 through 0x0cffffff (16MB)
//
// It is probably possible to do strange things such as use texture memory as
// a Maple DMA receive buffer, but TOP_ADDRESS would need to be lowered
// accordingly.
maple_if.MDAPRO = mdapro::security_code
| mdapro::top_address(0x40)
| mdapro::bottom_address(0x7f);
// SOFTWARE_INITIATION allows a Maple DMA transfer to be initiated by a write
// to the MDST register.
maple_if.MDTSEL = mdtsel::trigger_select::software_initiation;
// the Maple DMA start address must be 32-byte aligned
maple_if.MDSTAR = mdstar::table_address((uint32_t)command_buf);
// re-enable Maple DMA
maple_if.MDEN = mden::dma_enable::enable;
// start Maple DMA (completes asynchronously)
maple_if.MDST = mdst::start_status::start;
// write back operand cache blocks for command buffer prior to starting DMA
for (uint32_t i = 0; i < align_32byte(recv_size) / 32; i++) {
asm volatile ("ocbi @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)response_buf) + 32 * i))
);
}
}
int maple_dma_wait_complete()
{
using systembus::systembus;
using namespace systembus;
// wait for Maple DMA completion
while ((systembus.ISTNRM & istnrm::end_of_dma_maple_dma) == 0) {
if (systembus.ISTERR) {
string("ISTERR ");
print_base16(systembus.ISTERR, 8);
character('\n');
if ((systembus.ISTERR >> 11) & 1) {
return -1;
}
}
}
// clear Maple DMA end status
systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
return 0;
}
template <typename C, typename R>
void maple_device_request(maple::host_command<typename C::data_fields> * host_command,
maple::host_response<typename R::data_fields> * host_response,
bool end_flag = false)
{
using namespace maple;
constexpr uint32_t data_size = (sizeof (typename C::data_fields));
host_command->host_instruction = (end_flag ? host_instruction::end_flag : 0)
| host_instruction::port_select::a
| host_instruction::pattern::normal
| host_instruction::transfer_length(data_size / 4);
host_command->receive_data_address = ((uint32_t)host_response) & receive_data_address::mask;
host_command->header.command_code = C::command_code;
host_command->header.destination_ap = ap::port_select::a
| ap::de::device;
host_command->header.source_ap = ap::port_select::a
| ap::de::port;
host_command->header.data_size = data_size / 4;
}
// the Maple bus protocol is big endian, but the SH4 is running in little endian mode
#define bswap32 __builtin_bswap32
#define bswap16 __builtin_bswap16
void main()
{
// Maple DMA buffers must be 32-byte aligned
uint8_t send_buf[1024] __attribute__((aligned(32)));
uint8_t recv_buf[1024] __attribute__((aligned(32)));
struct requests {
maple::host_command<maple::device_request::data_fields> device_request;
maple::host_command<maple::get_condition::data_fields> get_condition;
};
static_assert((sizeof (requests)) == (sizeof (maple::host_command<maple::device_request::data_fields>)) + (sizeof (maple::host_command<maple::get_condition::data_fields>)));
using maple__data_transfer = maple::data_transfer<maple::ft0::data_transfer::data_format>;
struct responses {
maple::host_response<maple::device_status::data_fields> device_status;
maple::host_response<maple__data_transfer::data_fields> data_transfer;
};
auto requests = (struct requests *)send_buf;
auto responses = (struct responses *)recv_buf;
// fill send_buf with a "device request" command
// recv_buf is reply destination address
maple_device_request<maple::device_request, maple::device_status>(&requests->device_request, &responses->device_status);
maple_device_request<maple::get_condition, maple__data_transfer>(&requests->get_condition, &responses->data_transfer, true);
requests->get_condition.data.function_type = bswap32(maple::function_type::controller);
systembus::systembus.ISTERR = 0xffffffff;
maple_dma_start(send_buf, (sizeof (struct requests)),
recv_buf, (sizeof (struct responses)));
string("wait\n");
int res = maple_dma_wait_complete();
if (res != 0) {
string(" ");
return;
}
if (responses->device_status.header.command_code != maple::device_status::command_code) {
string("maple port A: invalid response or disconnected\n");
string(" ");
return;
}
//////////////////////////////////////////////////////////////////////////////
// data transfer
//////////////////////////////////////////////////////////////////////////////
string("responses->device_status:\n");
string(" header:\n");
string(" command_code : ");
print_base16(responses->device_status.header.command_code, 2); character('\n');
string(" destination_ap : ");
print_base16(responses->device_status.header.destination_ap, 2); character('\n');
string(" source_ap : ");
print_base16(responses->device_status.header.source_ap, 2); character('\n');
string(" data_size : ");
print_base16(responses->device_status.header.data_size, 2); character('\n');
auto& device_status = responses->device_status.data;
string(" data:\n");
string(" device_id:\n");
string(" ft : ");
print_base16(bswap32(device_status.device_id.ft), 8); character('\n');
string(" fd[0]: ");
print_base16(bswap32(device_status.device_id.fd[0]), 8); character('\n');
string(" fd[1]: ");
print_base16(bswap32(device_status.device_id.fd[1]), 8); character('\n');
string(" fd[2]: ");
print_base16(bswap32(device_status.device_id.fd[2]), 8); character('\n');
string(" destination_code: ");
print_base16(bswap32(device_status.destination_code), 2); character('\n');
string(" connection_direction: ");
print_base16(bswap32(device_status.connection_direction), 2); character('\n');
string(" product_name: \"");
for (int i = 0; i < 30; i++)
character(device_status.product_name[i]);
string("\"\n");
string(" license: \"");
for (int i = 0; i < 60; i++)
character(device_status.license[i]);
string("\"\n");
string(" low_consumption_standby_current: ");
print_base16(bswap16(device_status.low_consumption_standby_current), 4); character('\n');
string(" maximum_current_consumption: ");
print_base16(bswap16(device_status.maximum_current_consumption), 4); character('\n');
//////////////////////////////////////////////////////////////////////////////
// data transfer
//////////////////////////////////////////////////////////////////////////////
if (responses->data_transfer.header.command_code != maple__data_transfer::command_code) {
string("maple port A: invalid response or disconnected\n");
print_base16(responses->data_transfer.header.command_code, 8);
character('\n');
string(" ");
return;
}
string("responses->data_transfer:\n");
string(" header:\n");
string(" command_code : ");
print_base16(responses->data_transfer.header.command_code, 2); character('\n');
string(" destination_ap : ");
print_base16(responses->data_transfer.header.destination_ap, 2); character('\n');
string(" source_ap : ");
print_base16(responses->data_transfer.header.source_ap, 2); character('\n');
string(" data_size : ");
print_base16(responses->data_transfer.header.data_size, 2); character('\n');
auto& data_transfer = responses->data_transfer.data;
string(" data:\n");
string(" function_type: ");
print_base16(bswap32(data_transfer.function_type), 8); character('\n');
string(" data:\n");
string(" digital_button: ");
print_base16(bswap16(data_transfer.data.digital_button), 4); character('\n');
string(" analog_coordinate_axis[0]: ");
print_base16(data_transfer.data.analog_coordinate_axis[0], 2); character('\n');
string(" analog_coordinate_axis[1]: ");
print_base16(data_transfer.data.analog_coordinate_axis[1], 2); character('\n');
string(" analog_coordinate_axis[2]: ");
print_base16(data_transfer.data.analog_coordinate_axis[2], 2); character('\n');
string(" analog_coordinate_axis[3]: ");
print_base16(data_transfer.data.analog_coordinate_axis[3], 2); character('\n');
string(" analog_coordinate_axis[4]: ");
print_base16(data_transfer.data.analog_coordinate_axis[4], 2); character('\n');
string(" analog_coordinate_axis[5]: ");
print_base16(data_transfer.data.analog_coordinate_axis[5], 2); character('\n');
string(" ");
}

View File

@ -0,0 +1,437 @@
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
#include "maple/maple_bits.hpp"
#include "maple/maple_host.hpp"
#include "maple/maple_bus_commands.hpp"
#include "maple/maple_bus_bits.hpp"
#include "maple/maple_bus_ft6.hpp"
#include "maple/maple_bus_ft6_scan_code.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
static inline void character(const char c)
{
using sh7091::sh7091;
using namespace sh7091;
// set the transmit trigger to `1 byte`--this changes the behavior of TDFE
sh7091.SCIF.SCFCR2 = scif::scfcr2::ttrg::trigger_on_1_bytes;
// wait for transmit fifo to become partially empty
while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0);
// unset tdfe bit
sh7091.SCIF.SCFSR2 = (uint16_t)(~scif::scfsr2::tdfe::bit_mask);
sh7091.SCIF.SCFTDR2 = c;
}
static void string(const char * s)
{
while (*s != 0) {
character(*s++);
}
}
static void print_base16(uint32_t n, int len)
{
char buf[len];
char * bufi = &buf[len - 1];
while (bufi >= buf) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
*bufi = nib;
bufi -= 1;
}
for (int i = 0; i < len; i++) {
character(buf[i]);
}
}
constexpr inline uint32_t align_32byte(uint32_t mem)
{
return (mem + 31) & ~31;
}
/*
See DCDBSysArc990907E.pdf page 274.
Maple DMA uses SH4 DMA channel 0 in "DDT" mode. This means that Holly's Maple
DMA functional unit is externally controlling the SH4's DMA unit.
The Dreamcast boot rom leaves channel 0 already configured for Maple DMA,
though if you felt rebellious and wished to used channel 0 for something else,
you would need to reconfigure channel 0 for Maple/DDT afterwards.
Note that this `maple_dma_start` function does not configure SH4 DMA channel
0, and presumes it is already in the correct state.
*/
void maple_dma_start(void * command_buf, uint32_t send_size,
void * response_buf, uint32_t recv_size)
{
// write back operand cache blocks for command buffer prior to starting DMA
for (uint32_t i = 0; i < align_32byte(send_size) / 32; i++) {
asm volatile ("ocbwb @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)command_buf) + 32 * i))
);
}
using systembus::maple_if;
using systembus::systembus;
using namespace maple;
using namespace systembus;
// if SH4 cache were enabled, it would be necessary to use the `ocbwb` sh4
// instruction to write back the cache to system memory, prior to continuing.
// if SH4 cache were enabled, it would be necessary to use the `ocbi` sh4
// instruction to invalidate any possibly-cached areas of the receive buffer,
// as these are imminently going to be rewritten by the DMA unit independently
// of cache access.
// disable Maple DMA and abort any possibly-in-progress transfers
maple_if.MDEN = mden::dma_enable::abort;
while ((maple_if.MDST & mdst::start_status::bit_mask) != 0);
// clear Maple DMA end status
systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
// 20nsec maple_if. 0xc350 = 1ms
uint32_t one_msec = 0xc350;
// set the Maple bus controller timeout and transfer rate
maple_if.MSYS = msys::time_out_counter(one_msec)
| msys::sending_rate::_2M;
// MDAPRO controls which (system memory) addresses are considered valid for
// Maple DMA. An attempt to use an address outside of this range will cause an
// error interrupt in from the Maple DMA unit.
//
// 0x40 through 0x7F allows for transfers from 0x0c000000 to 0x0fffffff
// System Memory is 0x0c000000 through 0x0cffffff (16MB)
//
// It is probably possible to do strange things such as use texture memory as
// a Maple DMA receive buffer, but TOP_ADDRESS would need to be lowered
// accordingly.
maple_if.MDAPRO = mdapro::security_code
| mdapro::top_address(0x40)
| mdapro::bottom_address(0x7f);
// SOFTWARE_INITIATION allows a Maple DMA transfer to be initiated by a write
// to the MDST register.
maple_if.MDTSEL = mdtsel::trigger_select::software_initiation;
// the Maple DMA start address must be 32-byte aligned
maple_if.MDSTAR = mdstar::table_address((uint32_t)command_buf);
// re-enable Maple DMA
maple_if.MDEN = mden::dma_enable::enable;
// start Maple DMA (completes asynchronously)
maple_if.MDST = mdst::start_status::start;
// write back operand cache blocks for command buffer prior to starting DMA
for (uint32_t i = 0; i < align_32byte(recv_size) / 32; i++) {
asm volatile ("ocbi @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)response_buf) + 32 * i))
);
}
}
int maple_dma_wait_complete()
{
using systembus::systembus;
using namespace systembus;
// wait for Maple DMA completion
while ((systembus.ISTNRM & istnrm::end_of_dma_maple_dma) == 0) {
if (systembus.ISTERR) {
string("ISTERR ");
print_base16(systembus.ISTERR, 8);
character('\n');
if ((systembus.ISTERR >> 11) & 1) {
return -1;
}
}
}
// clear Maple DMA end status
systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
return 0;
}
template <typename C, typename R>
void maple_device_request(maple::host_command<typename C::data_fields> * host_command,
maple::host_response<typename R::data_fields> * host_response,
bool end_flag = false)
{
using namespace maple;
constexpr uint32_t data_size = (sizeof (typename C::data_fields));
host_command->host_instruction = (end_flag ? host_instruction::end_flag : 0)
| host_instruction::port_select::a
| host_instruction::pattern::normal
| host_instruction::transfer_length(data_size / 4);
host_command->receive_data_address = ((uint32_t)host_response) & receive_data_address::mask;
host_command->header.command_code = C::command_code;
host_command->header.destination_ap = ap::port_select::a
| ap::de::device;
host_command->header.source_ap = ap::port_select::a
| ap::de::port;
host_command->header.data_size = data_size / 4;
}
// the Maple bus protocol is big endian, but the SH4 is running in little endian mode
#define bswap32 __builtin_bswap32
#define bswap16 __builtin_bswap16
void main()
{
// Maple DMA buffers must be 32-byte aligned
uint8_t send_buf[1024] __attribute__((aligned(32)));
uint8_t recv_buf[1024] __attribute__((aligned(32)));
struct requests {
maple::host_command<maple::device_request::data_fields> device_request;
maple::host_command<maple::get_condition::data_fields> get_condition;
};
static_assert((sizeof (requests)) == (sizeof (maple::host_command<maple::device_request::data_fields>)) + (sizeof (maple::host_command<maple::get_condition::data_fields>)));
using maple__data_transfer = maple::data_transfer<maple::ft6::data_transfer::data_format>;
struct responses {
maple::host_response<maple::device_status::data_fields> device_status;
maple::host_response<maple__data_transfer::data_fields> data_transfer;
};
auto requests = (struct requests *)send_buf;
auto responses = (struct responses *)recv_buf;
// fill send_buf with a "device request" command
// recv_buf is reply destination address
maple_device_request<maple::device_request, maple::device_status>(&requests->device_request, &responses->device_status);
maple_device_request<maple::get_condition, maple__data_transfer>(&requests->get_condition, &responses->data_transfer, true);
requests->get_condition.data.function_type = bswap32(maple::function_type::keyboard);
systembus::systembus.ISTERR = 0xffffffff;
maple_dma_start(send_buf, (sizeof (struct requests)),
recv_buf, (sizeof (struct responses)));
string("wait\n");
int res = maple_dma_wait_complete();
if (res != 0) {
string(" ");
return;
}
if (responses->device_status.header.command_code != maple::device_status::command_code) {
string("maple port A: invalid response or disconnected\n");
string(" ");
return;
}
//////////////////////////////////////////////////////////////////////////////
// data transfer
//////////////////////////////////////////////////////////////////////////////
string("responses->device_status:\n");
string(" header:\n");
string(" command_code : ");
print_base16(responses->device_status.header.command_code, 2); character('\n');
string(" destination_ap : ");
print_base16(responses->device_status.header.destination_ap, 2); character('\n');
string(" source_ap : ");
print_base16(responses->device_status.header.source_ap, 2); character('\n');
string(" data_size : ");
print_base16(responses->device_status.header.data_size, 2); character('\n');
auto& device_status = responses->device_status.data;
string(" data:\n");
string(" device_id:\n");
string(" ft : ");
print_base16(bswap32(device_status.device_id.ft), 8); character('\n');
string(" fd[0]: ");
print_base16(bswap32(device_status.device_id.fd[0]), 8); character('\n');
string(" fd[1]: ");
print_base16(bswap32(device_status.device_id.fd[1]), 8); character('\n');
string(" fd[2]: ");
print_base16(bswap32(device_status.device_id.fd[2]), 8); character('\n');
string(" destination_code: ");
print_base16(bswap32(device_status.destination_code), 2); character('\n');
string(" connection_direction: ");
print_base16(bswap32(device_status.connection_direction), 2); character('\n');
string(" product_name: \"");
for (int i = 0; i < 30; i++)
character(device_status.product_name[i]);
string("\"\n");
string(" license: \"");
for (int i = 0; i < 60; i++)
character(device_status.license[i]);
string("\"\n");
string(" low_consumption_standby_current: ");
print_base16(bswap16(device_status.low_consumption_standby_current), 4); character('\n');
string(" maximum_current_consumption: ");
print_base16(bswap16(device_status.maximum_current_consumption), 4); character('\n');
//////////////////////////////////////////////////////////////////////////////
// data transfer
//////////////////////////////////////////////////////////////////////////////
if (responses->data_transfer.header.command_code != maple__data_transfer::command_code) {
string("maple port A: invalid response or disconnected\n");
print_base16(responses->data_transfer.header.command_code, 8);
character('\n');
string(" ");
return;
}
string("responses->data_transfer:\n");
string(" header:\n");
string(" command_code : ");
print_base16(responses->data_transfer.header.command_code, 2); character('\n');
string(" destination_ap : ");
print_base16(responses->data_transfer.header.destination_ap, 2); character('\n');
string(" source_ap : ");
print_base16(responses->data_transfer.header.source_ap, 2); character('\n');
string(" data_size : ");
print_base16(responses->data_transfer.header.data_size, 2); character('\n');
auto& data_transfer = responses->data_transfer.data;
string(" data:\n");
string(" function_type: ");
print_base16(bswap32(data_transfer.function_type), 8); character('\n');
string(" data:\n");
string(" modifier_key: ");
print_base16(data_transfer.data.modifier_key, 2); character('\n');
string(" led_state: ");
print_base16(data_transfer.data.led_state, 2); character('\n');
string(" scan_code_array[0]: ");
print_base16(data_transfer.data.scan_code_array[0], 2); character('\n');
string(" scan_code_array[1]: ");
print_base16(data_transfer.data.scan_code_array[1], 2); character('\n');
string(" scan_code_array[2]: ");
print_base16(data_transfer.data.scan_code_array[2], 2); character('\n');
string(" scan_code_array[3]: ");
print_base16(data_transfer.data.scan_code_array[3], 2); character('\n');
string(" scan_code_array[4]: ");
print_base16(data_transfer.data.scan_code_array[4], 2); character('\n');
string(" scan_code_array[5]: ");
print_base16(data_transfer.data.scan_code_array[5], 2); character('\n');
uint8_t scan_code_array[6];
for (int i = 0; i < 6; i++) {
scan_code_array[i] = data_transfer.data.scan_code_array[i];
}
{
using namespace systembus;
using namespace maple;
maple_if.MDEN = mden::dma_enable::abort;
while ((maple_if.MDST & mdst::start_status::bit_mask) != 0);
// clear Maple DMA end status
systembus::systembus.ISTNRM = istnrm::end_of_dma_maple_dma;
maple_if.MDTSEL = mdtsel::trigger_select::v_blank_initiation;
maple_if.MDAPRO = mdapro::security_code
| mdapro::top_address(0x40)
| mdapro::bottom_address(0x7f);
maple_if.MDSTAR = mdstar::table_address((uint32_t)(&requests->get_condition));
maple_if.MDEN = mden::dma_enable::enable;
}
while (1) {
for (uint32_t i = 0; i < align_32byte((sizeof (struct responses))) / 32; i++) {
asm volatile ("ocbi @%0"
:
: "r" (reinterpret_cast<uint32_t>(((uint32_t)recv_buf) + 32 * i))
);
}
while ((systembus::systembus.ISTNRM & systembus::istnrm::v_blank_in) == 0);
systembus::systembus.ISTNRM = systembus::istnrm::v_blank_in;
asm volatile ("" ::: "memory");
/*
if (responses->device_status.header.command_code != maple::device_status::command_code) {
//string("device_status: invalid response or disconnected\n");
//print_base16(responses->data_transfer.header.command_code, 2);
//character('\n');
//string(" ");
continue;
}
*/
if (responses->data_transfer.header.command_code != maple__data_transfer::command_code) {
//string("data_transfer: invalid response or disconnected\n");
//print_base16(responses->data_transfer.header.command_code, 2);
//character('\n');
//string(" ");
continue;
}
bool rollover = data_transfer.data.scan_code_array[5] == maple::ft6::scan_code::rollover_error;
if (rollover)
string("rollover error\n");
for (int i = 5; i >= 0; i--) {
if (data_transfer.data.scan_code_array[i] == maple::ft6::scan_code::no_operation)
continue;
bool make = true;
for (int j = 0; j < 6; j++) {
if (scan_code_array[j] == data_transfer.data.scan_code_array[i]) {
make = false;
break;
}
}
if (!make)
continue;
//print_base16(data_transfer.data.scan_code_array[i], 2); character('\n');
//for (int j = 0; j < 6; j++) {
//print_base16(data_transfer.data.scan_code_array[j], 2); character(' ');
//}
//character('\n');
bool lshift = (maple::ft6::data_transfer::modifier_key::left_shift() & data_transfer.data.modifier_key) != 0;
bool rshift = (maple::ft6::data_transfer::modifier_key::right_shift() & data_transfer.data.modifier_key) != 0;
bool shift = lshift || rshift;
character(maple::ft6::scan_code::code_point[data_transfer.data.scan_code_array[i]][shift]);
}
for (int i = 0; i < 6; i++) {
scan_code_array[i] = data_transfer.data.scan_code_array[i];
}
}
string(" ");
}

View File

@ -0,0 +1,550 @@
static const int strips[] = {
// strip_0
136, 1, 110, 127, 129, 130, 132, 133, 123, 126, 125, 118, 115, 117, 114, 116, 113, 4, 3, 6, 5, 8, 58, 70, 61, 71, 64, 72, 80, 79, 77, 76, 74, 73, 175, 163, 173, 191, 210, 208, 211, 209, 212, 197, 198, 195, 196, 193, 205, 143, 155, 158, 157, 160, 159, 150, 147, 149, 146, 148, 136, 30, 27, 32, 11, 12, 14, 15, 17, 18, 10, 26, 9, 23, 8, 20, 70, 67, 68, 65, 66, 102, 105, 103, 106, 104, 107, 90, 91, 88, 98, 97, 95, 94, 92, 82, 56, 163, -73,
// strip_1
136, 110, 146, 129, 147, 132, 159, 120, 156, 119, 137, 109, 190, 164, 200, 183, 201, 186, 213, 174, 210, -173,
// strip_2
136, 27, 1, 11, 13, 14, 16, 17, 7, 10, -9,
// strip_3
163, 82, 191, -208,
// strip_4
8, 6, 9, -7,
// strip_5
6, 4, 7, -16,
// strip_6
4, 116, 16, 128, 13, 127, -1,
// strip_7
70, 68, 71, 69, 72, -79,
// strip_8
68, 66, 69, 78, 79, -76,
// strip_9
66, 105, 78, 93, 75, 92, -56,
// strip_10
56, 73, 75, 76, -78,
// strip_11
82, 94, 208, -209,
// strip_12
92, 93, 95, 96, 98, 99, 91, -107,
// strip_13
93, 105, 96, 106, 99, -107,
// strip_14
94, 97, 209, -197,
// strip_15
132, 123, 120, 122, 119, 121, 109, 181, 164, -183,
// strip_16
123, 125, 122, 124, 121, 182, 181, 184, 183, -186,
// strip_17
125, 115, 124, 112, 170, 167, 168, 165, 166, 59, 62, 60, 63, 61, -64,
// strip_18
61, 60, 58, 57, 5, 0, 3, 108, 113, 111, 114, 112, -115,
// strip_19
60, 59, 57, 54, 0, 162, 108, -111,
// strip_20
59, 165, 54, -162,
// strip_21
64, 80, 63, 77, 62, 74, 178, 175, 176, 173, -174,
// strip_22
112, 111, 167, 162, -165,
// strip_23
127, 128, 130, 131, 133, 134, 126, -118,
// strip_24
128, 116, 131, 117, 134, -118,
// strip_25
159, 156, 157, 154, 155, 202, 205, 203, 206, 204, 207, 214, 215, 212, -198,
// strip_26
156, 137, 154, 190, 202, 200, 203, 201, 204, 213, 214, 211, -212,
// strip_27
211, 213, -210,
// strip_28
62, 178, 166, 169, 168, 171, 170, 185, 182, -184,
// strip_29
170, 182, -124,
// strip_30
205, 206, 196, 199, 198, -215,
// strip_31
206, 207, 199, -215,
// strip_32
26, 18, 25, 15, 24, 12, 35, 32, 33, 30, 31, 148, 151, 149, 152, 150, 153, 160, 161, 158, 144, 143, 141, 140, 138, 135, 28, 81, 38, 86, 39, 89, 51, 101, 48, 100, 29, 83, 55, 65, -67,
// strip_33
26, 25, 23, 22, 20, 19, 67, -55,
// strip_34
25, 24, 22, 21, 19, 2, 55, -29,
// strip_35
65, 83, 102, 100, 103, 101, 104, 89, 90, 87, 88, 85, 97, -197,
// strip_36
89, 86, 87, 84, 85, 194, 197, -195,
// strip_37
86, 81, 84, 189, 194, 192, 195, -193,
// strip_38
81, 135, 189, -192,
// strip_39
135, 140, 192, -193,
// strip_40
140, 143, -193,
// strip_41
29, 2, 46, 21, 47, 24, -35,
// strip_42
29, 46, 48, 49, 51, 52, 42, 45, 44, 37, 34, 36, 33, -35,
// strip_43
33, 31, 34, 43, 44, 41, 42, 39, -51,
// strip_44
31, 151, 43, 139, 40, 138, -28,
// strip_45
28, 38, 40, 41, -43,
// strip_46
39, 41, -38,
// strip_47
46, 47, 49, 50, 52, 53, 45, -37,
// strip_48
47, 35, 50, 36, 53, -37,
// strip_49
138, 139, 141, 142, 144, 145, 161, -153,
// strip_50
139, 151, 142, 152, 145, -153,
// strip_51
169, 178, 179, 176, 177, 174, -186,
// strip_52
186, 184, 187, 185, 188, 171, 172, 169, -179,
// strip_53
186, 187, 177, 180, 179, -172,
// strip_54
187, 188, 180, -172,
};
static const vec3 vertices[] = {
{-0.9000000, -0.9000000, -1.0000000},
{-0.9000000, -1.0000000, -0.9000000},
{-1.0000000, -0.9000000, -0.9000000},
{-0.9000000, -0.9309075, -0.9951038},
{-0.9000000, -0.9587687, -0.9809088},
{-0.9309074, -0.9000000, -0.9951038},
{-0.9317268, -0.9319055, -0.9893054},
{-0.9306927, -0.9574144, -0.9759048},
{-0.9587687, -0.9000000, -0.9809088},
{-0.9574655, -0.9307720, -0.9758340},
{-0.9529119, -0.9529119, -0.9663376},
{-0.9309075, -0.9951038, -0.9000000},
{-0.9587687, -0.9809088, -0.9000000},
{-0.9000000, -0.9951038, -0.9309074},
{-0.9319055, -0.9893054, -0.9317268},
{-0.9574144, -0.9759048, -0.9306927},
{-0.9000000, -0.9809088, -0.9587687},
{-0.9307720, -0.9758340, -0.9574655},
{-0.9529119, -0.9663376, -0.9529119},
{-0.9951038, -0.9000000, -0.9309075},
{-0.9809088, -0.9000000, -0.9587687},
{-0.9951038, -0.9309074, -0.9000000},
{-0.9893054, -0.9317268, -0.9319055},
{-0.9759048, -0.9306927, -0.9574144},
{-0.9809088, -0.9587687, -0.9000000},
{-0.9758340, -0.9574655, -0.9307720},
{-0.9663376, -0.9529119, -0.9529119},
{-0.9000000, -1.0000000, 0.9000000},
{-0.9000000, -0.9000000, 1.0000000},
{-1.0000000, -0.9000000, 0.9000000},
{-0.9000000, -0.9951038, 0.9309075},
{-0.9000000, -0.9809088, 0.9587687},
{-0.9309074, -0.9951038, 0.9000000},
{-0.9317268, -0.9893054, 0.9319055},
{-0.9306927, -0.9759048, 0.9574144},
{-0.9587687, -0.9809088, 0.9000000},
{-0.9574655, -0.9758340, 0.9307720},
{-0.9529119, -0.9663376, 0.9529119},
{-0.9309075, -0.9000000, 0.9951038},
{-0.9587687, -0.9000000, 0.9809088},
{-0.9000000, -0.9309074, 0.9951038},
{-0.9319055, -0.9317268, 0.9893054},
{-0.9574144, -0.9306927, 0.9759048},
{-0.9000000, -0.9587687, 0.9809088},
{-0.9307720, -0.9574655, 0.9758340},
{-0.9529119, -0.9529119, 0.9663376},
{-0.9951038, -0.9309075, 0.9000000},
{-0.9809088, -0.9587687, 0.9000000},
{-0.9951038, -0.9000000, 0.9309074},
{-0.9893054, -0.9319055, 0.9317268},
{-0.9759048, -0.9574144, 0.9306927},
{-0.9809088, -0.9000000, 0.9587687},
{-0.9758340, -0.9307720, 0.9574655},
{-0.9663376, -0.9529119, 0.9529119},
{-0.9000000, 0.9000000, -1.0000000},
{-1.0000000, 0.9000000, -0.9000000},
{-0.9000000, 1.0000000, -0.9000000},
{-0.9309075, 0.9000000, -0.9951038},
{-0.9587687, 0.9000000, -0.9809088},
{-0.9000000, 0.9309074, -0.9951038},
{-0.9319055, 0.9317268, -0.9893054},
{-0.9574144, 0.9306927, -0.9759048},
{-0.9000000, 0.9587687, -0.9809088},
{-0.9307720, 0.9574655, -0.9758340},
{-0.9529119, 0.9529119, -0.9663376},
{-0.9951038, 0.9309075, -0.9000000},
{-0.9809088, 0.9587687, -0.9000000},
{-0.9951038, 0.9000000, -0.9309074},
{-0.9893054, 0.9319055, -0.9317268},
{-0.9759048, 0.9574144, -0.9306927},
{-0.9809088, 0.9000000, -0.9587687},
{-0.9758340, 0.9307720, -0.9574655},
{-0.9663376, 0.9529119, -0.9529119},
{-0.9000000, 0.9951038, -0.9309075},
{-0.9000000, 0.9809088, -0.9587687},
{-0.9309074, 0.9951038, -0.9000000},
{-0.9317268, 0.9893054, -0.9319055},
{-0.9306927, 0.9759048, -0.9574144},
{-0.9587687, 0.9809088, -0.9000000},
{-0.9574655, 0.9758340, -0.9307720},
{-0.9529119, 0.9663376, -0.9529119},
{-0.9000000, 0.9000000, 1.0000000},
{-0.9000000, 1.0000000, 0.9000000},
{-1.0000000, 0.9000000, 0.9000000},
{-0.9000000, 0.9309075, 0.9951038},
{-0.9000000, 0.9587687, 0.9809088},
{-0.9309074, 0.9000000, 0.9951038},
{-0.9317268, 0.9319055, 0.9893054},
{-0.9306927, 0.9574144, 0.9759048},
{-0.9587687, 0.9000000, 0.9809088},
{-0.9574655, 0.9307720, 0.9758340},
{-0.9529119, 0.9529119, 0.9663376},
{-0.9309075, 0.9951038, 0.9000000},
{-0.9587687, 0.9809088, 0.9000000},
{-0.9000000, 0.9951038, 0.9309074},
{-0.9319055, 0.9893054, 0.9317268},
{-0.9574144, 0.9759048, 0.9306927},
{-0.9000000, 0.9809088, 0.9587687},
{-0.9307720, 0.9758340, 0.9574655},
{-0.9529119, 0.9663376, 0.9529119},
{-0.9951038, 0.9000000, 0.9309075},
{-0.9809088, 0.9000000, 0.9587687},
{-0.9951038, 0.9309074, 0.9000000},
{-0.9893054, 0.9317268, 0.9319055},
{-0.9759048, 0.9306927, 0.9574144},
{-0.9809088, 0.9587687, 0.9000000},
{-0.9758340, 0.9574655, 0.9307720},
{-0.9663376, 0.9529119, 0.9529119},
{0.9000000, -0.9000000, -1.0000000},
{1.0000000, -0.9000000, -0.9000000},
{0.9000000, -1.0000000, -0.9000000},
{0.9309075, -0.9000000, -0.9951038},
{0.9587687, -0.9000000, -0.9809088},
{0.9000000, -0.9309074, -0.9951038},
{0.9319055, -0.9317268, -0.9893054},
{0.9574144, -0.9306927, -0.9759048},
{0.9000000, -0.9587687, -0.9809088},
{0.9307720, -0.9574655, -0.9758340},
{0.9529119, -0.9529119, -0.9663376},
{0.9951038, -0.9309075, -0.9000000},
{0.9809088, -0.9587687, -0.9000000},
{0.9951038, -0.9000000, -0.9309074},
{0.9893054, -0.9319055, -0.9317268},
{0.9759048, -0.9574144, -0.9306927},
{0.9809088, -0.9000000, -0.9587687},
{0.9758340, -0.9307720, -0.9574655},
{0.9663376, -0.9529119, -0.9529119},
{0.9000000, -0.9951038, -0.9309075},
{0.9000000, -0.9809088, -0.9587687},
{0.9309074, -0.9951038, -0.9000000},
{0.9317268, -0.9893054, -0.9319055},
{0.9306927, -0.9759048, -0.9574144},
{0.9587687, -0.9809088, -0.9000000},
{0.9574655, -0.9758340, -0.9307720},
{0.9529119, -0.9663376, -0.9529119},
{0.9000000, -0.9000000, 1.0000000},
{0.9000000, -1.0000000, 0.9000000},
{1.0000000, -0.9000000, 0.9000000},
{0.9000000, -0.9309075, 0.9951038},
{0.9000000, -0.9587687, 0.9809088},
{0.9309074, -0.9000000, 0.9951038},
{0.9317268, -0.9319055, 0.9893054},
{0.9306927, -0.9574144, 0.9759048},
{0.9587687, -0.9000000, 0.9809088},
{0.9574655, -0.9307720, 0.9758340},
{0.9529119, -0.9529119, 0.9663376},
{0.9309075, -0.9951038, 0.9000000},
{0.9587687, -0.9809088, 0.9000000},
{0.9000000, -0.9951038, 0.9309074},
{0.9319055, -0.9893054, 0.9317268},
{0.9574144, -0.9759048, 0.9306927},
{0.9000000, -0.9809088, 0.9587687},
{0.9307720, -0.9758340, 0.9574655},
{0.9529119, -0.9663376, 0.9529119},
{0.9951038, -0.9000000, 0.9309075},
{0.9809088, -0.9000000, 0.9587687},
{0.9951038, -0.9309074, 0.9000000},
{0.9893054, -0.9317268, 0.9319055},
{0.9759048, -0.9306927, 0.9574144},
{0.9809088, -0.9587687, 0.9000000},
{0.9758340, -0.9574655, 0.9307720},
{0.9663376, -0.9529119, 0.9529119},
{0.9000000, 0.9000000, -1.0000000},
{0.9000000, 1.0000000, -0.9000000},
{1.0000000, 0.9000000, -0.9000000},
{0.9000000, 0.9309075, -0.9951038},
{0.9000000, 0.9587687, -0.9809088},
{0.9309074, 0.9000000, -0.9951038},
{0.9317268, 0.9319055, -0.9893054},
{0.9306927, 0.9574144, -0.9759048},
{0.9587687, 0.9000000, -0.9809088},
{0.9574655, 0.9307720, -0.9758340},
{0.9529119, 0.9529119, -0.9663376},
{0.9309075, 0.9951038, -0.9000000},
{0.9587687, 0.9809088, -0.9000000},
{0.9000000, 0.9951038, -0.9309074},
{0.9319055, 0.9893054, -0.9317268},
{0.9574144, 0.9759048, -0.9306927},
{0.9000000, 0.9809088, -0.9587687},
{0.9307720, 0.9758340, -0.9574655},
{0.9529119, 0.9663376, -0.9529119},
{0.9951038, 0.9000000, -0.9309075},
{0.9809088, 0.9000000, -0.9587687},
{0.9951038, 0.9309074, -0.9000000},
{0.9893054, 0.9317268, -0.9319055},
{0.9759048, 0.9306927, -0.9574144},
{0.9809088, 0.9587687, -0.9000000},
{0.9758340, 0.9574655, -0.9307720},
{0.9663376, 0.9529119, -0.9529119},
{0.9000000, 0.9000000, 1.0000000},
{1.0000000, 0.9000000, 0.9000000},
{0.9000000, 1.0000000, 0.9000000},
{0.9309075, 0.9000000, 0.9951038},
{0.9587687, 0.9000000, 0.9809088},
{0.9000000, 0.9309074, 0.9951038},
{0.9319055, 0.9317268, 0.9893054},
{0.9574144, 0.9306927, 0.9759048},
{0.9000000, 0.9587687, 0.9809088},
{0.9307720, 0.9574655, 0.9758340},
{0.9529119, 0.9529119, 0.9663376},
{0.9951038, 0.9309075, 0.9000000},
{0.9809088, 0.9587687, 0.9000000},
{0.9951038, 0.9000000, 0.9309074},
{0.9893054, 0.9319055, 0.9317268},
{0.9759048, 0.9574144, 0.9306927},
{0.9809088, 0.9000000, 0.9587687},
{0.9758340, 0.9307720, 0.9574655},
{0.9663376, 0.9529119, 0.9529119},
{0.9000000, 0.9951038, 0.9309075},
{0.9000000, 0.9809088, 0.9587687},
{0.9309074, 0.9951038, 0.9000000},
{0.9317268, 0.9893054, 0.9319055},
{0.9306927, 0.9759048, 0.9574144},
{0.9587687, 0.9809088, 0.9000000},
{0.9574655, 0.9758340, 0.9307720},
{0.9529119, 0.9663376, 0.9529119},
};
static const vec3 normals[] = {
{-0.0779369, -0.0779360, -0.9939074},
{-0.0779360, -0.9939074, -0.0779369},
{-0.9939072, -0.0779380, -0.0779372},
{-0.0783546, -0.3064310, -0.9486625},
{-0.0753902, -0.5855243, -0.8071417},
{-0.3066674, -0.0787251, -0.9485555},
{-0.3093096, -0.3102272, -0.8989365},
{-0.2872533, -0.5712489, -0.7688694},
{-0.5853158, -0.0757397, -0.8072601},
{-0.5713511, -0.2876457, -0.7686467},
{-0.5149081, -0.5150670, -0.6852559},
{-0.3064311, -0.9486625, -0.0783546},
{-0.5855243, -0.8071417, -0.0753902},
{-0.0787251, -0.9485555, -0.3066674},
{-0.3102272, -0.8989365, -0.3093096},
{-0.5712489, -0.7688695, -0.2872533},
{-0.0757397, -0.8072602, -0.5853158},
{-0.2876457, -0.7686467, -0.5713511},
{-0.5150670, -0.6852559, -0.5149082},
{-0.9486625, -0.0783546, -0.3064310},
{-0.8071417, -0.0753902, -0.5855243},
{-0.9485555, -0.3066674, -0.0787251},
{-0.8989365, -0.3093096, -0.3102272},
{-0.7688694, -0.2872533, -0.5712489},
{-0.8072601, -0.5853157, -0.0757397},
{-0.7686467, -0.5713511, -0.2876457},
{-0.6852559, -0.5149081, -0.5150669},
{-0.0779375, -0.9939072, 0.0779376},
{-0.0779376, -0.0779375, 0.9939072},
{-0.9939074, -0.0779365, 0.0779364},
{-0.0783542, -0.9486627, 0.3064306},
{-0.0753906, -0.8071429, 0.5855225},
{-0.3066655, -0.9485560, 0.0787252},
{-0.3093096, -0.8989362, 0.3102278},
{-0.2872531, -0.7688694, 0.5712491},
{-0.5853159, -0.8072601, 0.0757390},
{-0.5713505, -0.7686472, 0.2876458},
{-0.5149055, -0.6852569, 0.5150683},
{-0.3064306, -0.0783542, 0.9486628},
{-0.5855225, -0.0753906, 0.8071429},
{-0.0787252, -0.3066655, 0.9485560},
{-0.3102278, -0.3093096, 0.8989362},
{-0.5712491, -0.2872531, 0.7688694},
{-0.0757390, -0.5853159, 0.8072601},
{-0.2876458, -0.5713505, 0.7686472},
{-0.5150683, -0.5149055, 0.6852570},
{-0.9486626, -0.3064307, 0.0783543},
{-0.8071429, -0.5855225, 0.0753906},
{-0.9485561, -0.0787252, 0.3066655},
{-0.8989362, -0.3102278, 0.3093096},
{-0.7688693, -0.5712490, 0.2872531},
{-0.8072600, -0.0757390, 0.5853159},
{-0.7686472, -0.2876458, 0.5713505},
{-0.6852570, -0.5150683, 0.5149055},
{-0.0779376, 0.0779375, -0.9939072},
{-0.9939074, 0.0779365, -0.0779364},
{-0.0779375, 0.9939072, -0.0779376},
{-0.3064306, 0.0783542, -0.9486628},
{-0.5855225, 0.0753906, -0.8071429},
{-0.0787252, 0.3066655, -0.9485560},
{-0.3102278, 0.3093096, -0.8989362},
{-0.5712491, 0.2872531, -0.7688694},
{-0.0757390, 0.5853159, -0.8072600},
{-0.2876458, 0.5713505, -0.7686472},
{-0.5150683, 0.5149055, -0.6852570},
{-0.9486626, 0.3064307, -0.0783543},
{-0.8071429, 0.5855225, -0.0753906},
{-0.9485561, 0.0787252, -0.3066655},
{-0.8989362, 0.3102278, -0.3093096},
{-0.7688693, 0.5712490, -0.2872531},
{-0.8072600, 0.0757390, -0.5853159},
{-0.7686472, 0.2876458, -0.5713505},
{-0.6852570, 0.5150683, -0.5149055},
{-0.0783542, 0.9486627, -0.3064306},
{-0.0753906, 0.8071429, -0.5855225},
{-0.3066655, 0.9485560, -0.0787252},
{-0.3093096, 0.8989362, -0.3102278},
{-0.2872531, 0.7688694, -0.5712491},
{-0.5853159, 0.8072601, -0.0757390},
{-0.5713505, 0.7686472, -0.2876457},
{-0.5149055, 0.6852569, -0.5150683},
{-0.0779369, 0.0779360, 0.9939074},
{-0.0779360, 0.9939074, 0.0779369},
{-0.9939072, 0.0779380, 0.0779371},
{-0.0783546, 0.3064310, 0.9486625},
{-0.0753902, 0.5855243, 0.8071417},
{-0.3066674, 0.0787251, 0.9485555},
{-0.3093096, 0.3102272, 0.8989365},
{-0.2872533, 0.5712489, 0.7688694},
{-0.5853158, 0.0757397, 0.8072601},
{-0.5713511, 0.2876457, 0.7686467},
{-0.5149081, 0.5150670, 0.6852559},
{-0.3064311, 0.9486625, 0.0783546},
{-0.5855243, 0.8071417, 0.0753902},
{-0.0787251, 0.9485555, 0.3066674},
{-0.3102272, 0.8989365, 0.3093096},
{-0.5712489, 0.7688695, 0.2872533},
{-0.0757397, 0.8072602, 0.5853158},
{-0.2876457, 0.7686467, 0.5713511},
{-0.5150670, 0.6852559, 0.5149082},
{-0.9486625, 0.0783546, 0.3064310},
{-0.8071417, 0.0753902, 0.5855243},
{-0.9485555, 0.3066674, 0.0787251},
{-0.8989365, 0.3093096, 0.3102272},
{-0.7688694, 0.2872533, 0.5712489},
{-0.8072601, 0.5853157, 0.0757397},
{-0.7686467, 0.5713511, 0.2876457},
{-0.6852559, 0.5149081, 0.5150669},
{0.0779376, -0.0779375, -0.9939072},
{0.9939074, -0.0779365, -0.0779364},
{0.0779375, -0.9939072, -0.0779376},
{0.3064306, -0.0783542, -0.9486628},
{0.5855225, -0.0753906, -0.8071429},
{0.0787252, -0.3066655, -0.9485560},
{0.3102278, -0.3093096, -0.8989362},
{0.5712491, -0.2872531, -0.7688694},
{0.0757390, -0.5853159, -0.8072600},
{0.2876458, -0.5713505, -0.7686472},
{0.5150683, -0.5149055, -0.6852570},
{0.9486626, -0.3064307, -0.0783543},
{0.8071429, -0.5855225, -0.0753906},
{0.9485561, -0.0787252, -0.3066655},
{0.8989362, -0.3102278, -0.3093096},
{0.7688693, -0.5712490, -0.2872531},
{0.8072600, -0.0757390, -0.5853159},
{0.7686472, -0.2876458, -0.5713505},
{0.6852570, -0.5150683, -0.5149055},
{0.0783542, -0.9486627, -0.3064306},
{0.0753906, -0.8071429, -0.5855225},
{0.3066655, -0.9485560, -0.0787252},
{0.3093096, -0.8989362, -0.3102278},
{0.2872531, -0.7688694, -0.5712491},
{0.5853159, -0.8072601, -0.0757390},
{0.5713505, -0.7686472, -0.2876457},
{0.5149055, -0.6852569, -0.5150683},
{0.0779369, -0.0779360, 0.9939074},
{0.0779360, -0.9939074, 0.0779369},
{0.9939072, -0.0779380, 0.0779371},
{0.0783546, -0.3064310, 0.9486625},
{0.0753902, -0.5855243, 0.8071417},
{0.3066674, -0.0787251, 0.9485555},
{0.3093096, -0.3102272, 0.8989365},
{0.2872533, -0.5712489, 0.7688694},
{0.5853158, -0.0757397, 0.8072601},
{0.5713511, -0.2876457, 0.7686467},
{0.5149081, -0.5150670, 0.6852559},
{0.3064311, -0.9486625, 0.0783546},
{0.5855243, -0.8071417, 0.0753902},
{0.0787251, -0.9485555, 0.3066674},
{0.3102272, -0.8989365, 0.3093096},
{0.5712489, -0.7688695, 0.2872533},
{0.0757397, -0.8072602, 0.5853158},
{0.2876457, -0.7686467, 0.5713511},
{0.5150670, -0.6852559, 0.5149082},
{0.9486625, -0.0783546, 0.3064310},
{0.8071417, -0.0753902, 0.5855243},
{0.9485555, -0.3066674, 0.0787251},
{0.8989365, -0.3093096, 0.3102272},
{0.7688694, -0.2872533, 0.5712489},
{0.8072601, -0.5853157, 0.0757397},
{0.7686467, -0.5713511, 0.2876457},
{0.6852559, -0.5149081, 0.5150669},
{0.0779369, 0.0779360, -0.9939074},
{0.0779360, 0.9939074, -0.0779369},
{0.9939072, 0.0779380, -0.0779372},
{0.0783546, 0.3064310, -0.9486625},
{0.0753902, 0.5855243, -0.8071417},
{0.3066674, 0.0787251, -0.9485555},
{0.3093096, 0.3102272, -0.8989365},
{0.2872533, 0.5712489, -0.7688694},
{0.5853158, 0.0757397, -0.8072601},
{0.5713511, 0.2876457, -0.7686467},
{0.5149081, 0.5150670, -0.6852559},
{0.3064311, 0.9486625, -0.0783547},
{0.5855243, 0.8071417, -0.0753902},
{0.0787251, 0.9485555, -0.3066674},
{0.3102272, 0.8989365, -0.3093096},
{0.5712489, 0.7688695, -0.2872533},
{0.0757397, 0.8072602, -0.5853158},
{0.2876457, 0.7686467, -0.5713511},
{0.5150670, 0.6852559, -0.5149082},
{0.9486625, 0.0783546, -0.3064310},
{0.8071417, 0.0753902, -0.5855243},
{0.9485555, 0.3066674, -0.0787251},
{0.8989365, 0.3093096, -0.3102272},
{0.7688694, 0.2872533, -0.5712489},
{0.8072600, 0.5853158, -0.0757397},
{0.7686467, 0.5713511, -0.2876457},
{0.6852559, 0.5149081, -0.5150669},
{0.0779376, 0.0779375, 0.9939072},
{0.9939074, 0.0779365, 0.0779364},
{0.0779375, 0.9939072, 0.0779376},
{0.3064306, 0.0783542, 0.9486628},
{0.5855225, 0.0753906, 0.8071429},
{0.0787252, 0.3066655, 0.9485560},
{0.3102278, 0.3093096, 0.8989362},
{0.5712491, 0.2872531, 0.7688694},
{0.0757390, 0.5853159, 0.8072600},
{0.2876458, 0.5713505, 0.7686472},
{0.5150683, 0.5149055, 0.6852570},
{0.9486626, 0.3064306, 0.0783542},
{0.8071429, 0.5855225, 0.0753906},
{0.9485561, 0.0787252, 0.3066655},
{0.8989362, 0.3102278, 0.3093096},
{0.7688693, 0.5712490, 0.2872531},
{0.8072600, 0.0757390, 0.5853159},
{0.7686472, 0.2876458, 0.5713505},
{0.6852570, 0.5150683, 0.5149055},
{0.0783542, 0.9486627, 0.3064306},
{0.0753906, 0.8071429, 0.5855225},
{0.3066655, 0.9485561, 0.0787252},
{0.3093096, 0.8989362, 0.3102278},
{0.2872531, 0.7688694, 0.5712491},
{0.5853160, 0.8072601, 0.0757390},
{0.5713505, 0.7686472, 0.2876457},
{0.5149055, 0.6852569, 0.5150683},
};

View File

@ -0,0 +1,124 @@
static const int strips[] = {
// strip_0
0, 13, 12, 14, 2, 24, 27, 33, 7, 39, 34, 40, 8, 35, 28, 31, 4, 21, 19, 16, 0, -13,
// strip_1
0, 12, 17, 18, 3, 26, 29, 34, -8,
// strip_2
0, 17, 19, 20, 4, -28,
// strip_3
34, 26, 7, -27,
// strip_4
26, 18, 27, -2,
// strip_5
12, 2, -18,
// strip_6
8, 28, 29, 20, 3, -17,
// strip_7
13, 16, 15, 5, 23, 30, 36, 9, 41, 35, -40,
// strip_8
16, 21, 5, -30,
// strip_9
21, 31, 30, -9,
// strip_10
31, 35, -9,
// strip_11
14, 13, 1, 15, 22, 23, 10, 36, 38, 41, 11, 40, -39,
// strip_12
14, 1, 25, 22, 32, 10, -38,
// strip_13
14, 25, 24, 6, 33, 37, 39, -11,
// strip_14
25, 32, 6, -37,
// strip_15
32, 38, 37, -11,
};
static const vec3 vertices[] = {
{0.0000000, 0.0000000, -1.0000000},
{0.7236073, -0.5257253, -0.4472195},
{-0.2763880, -0.8506492, -0.4472198},
{-0.8944262, 0.0000000, -0.4472156},
{-0.2763880, 0.8506492, -0.4472198},
{0.7236073, 0.5257253, -0.4472195},
{0.2763880, -0.8506492, 0.4472198},
{-0.7236073, -0.5257253, 0.4472195},
{-0.7236073, 0.5257253, 0.4472195},
{0.2763880, 0.8506492, 0.4472198},
{0.8944262, 0.0000000, 0.4472156},
{0.0000000, 0.0000000, 1.0000000},
{-0.1624556, -0.4999953, -0.8506544},
{0.4253227, -0.3090114, -0.8506542},
{0.2628688, -0.8090116, -0.5257376},
{0.8506479, 0.0000000, -0.5257359},
{0.4253227, 0.3090114, -0.8506542},
{-0.5257298, 0.0000000, -0.8506517},
{-0.6881894, -0.4999969, -0.5257362},
{-0.1624556, 0.4999953, -0.8506544},
{-0.6881894, 0.4999969, -0.5257362},
{0.2628688, 0.8090116, -0.5257376},
{0.9510579, -0.3090126, 0.0000000},
{0.9510579, 0.3090126, 0.0000000},
{0.0000000, -0.9999999, 0.0000000},
{0.5877856, -0.8090167, 0.0000000},
{-0.9510579, -0.3090126, 0.0000000},
{-0.5877856, -0.8090167, 0.0000000},
{-0.5877856, 0.8090167, 0.0000000},
{-0.9510579, 0.3090126, 0.0000000},
{0.5877856, 0.8090167, 0.0000000},
{0.0000000, 0.9999999, 0.0000000},
{0.6881894, -0.4999969, 0.5257362},
{-0.2628688, -0.8090116, 0.5257376},
{-0.8506479, 0.0000000, 0.5257359},
{-0.2628688, 0.8090116, 0.5257376},
{0.6881894, 0.4999969, 0.5257362},
{0.1624556, -0.4999953, 0.8506544},
{0.5257298, 0.0000000, 0.8506517},
{-0.4253227, -0.3090114, 0.8506542},
{-0.4253227, 0.3090114, 0.8506542},
{0.1624556, 0.4999953, 0.8506544},
};
static const vec3 normals[] = {
{-0.0000014, 0.0000000, -1.0000000},
{0.7236077, -0.5257269, -0.4472172},
{-0.2763892, -0.8506496, -0.4472183},
{-0.8944264, 0.0000000, -0.4472152},
{-0.2763892, 0.8506495, -0.4472184},
{0.7236077, 0.5257269, -0.4472172},
{0.2763892, -0.8506496, 0.4472184},
{-0.7236077, -0.5257268, 0.4472171},
{-0.7236077, 0.5257269, 0.4472172},
{0.2763892, 0.8506496, 0.4472184},
{0.8944264, 0.0000000, 0.4472152},
{0.0000014, 0.0000000, 1.0000000},
{-0.1624570, -0.4999964, -0.8506535},
{0.4253235, -0.3090130, -0.8506532},
{0.2628689, -0.8090131, -0.5257353},
{0.8506489, 0.0000000, -0.5257344},
{0.4253235, 0.3090130, -0.8506532},
{-0.5257297, -0.0000000, -0.8506517},
{-0.6881894, -0.4999988, -0.5257342},
{-0.1624570, 0.4999964, -0.8506535},
{-0.6881894, 0.4999988, -0.5257342},
{0.2628689, 0.8090131, -0.5257353},
{0.9510571, -0.3090152, -0.0000002},
{0.9510571, 0.3090152, -0.0000002},
{0.0000000, -1.0000000, -0.0000000},
{0.5877860, -0.8090164, 0.0000002},
{-0.9510571, -0.3090152, 0.0000002},
{-0.5877860, -0.8090164, -0.0000002},
{-0.5877860, 0.8090164, -0.0000002},
{-0.9510571, 0.3090152, 0.0000002},
{0.5877861, 0.8090164, 0.0000002},
{0.0000000, 1.0000000, -0.0000000},
{0.6881894, -0.4999988, 0.5257343},
{-0.2628689, -0.8090131, 0.5257354},
{-0.8506489, -0.0000000, 0.5257344},
{-0.2628689, 0.8090131, 0.5257353},
{0.6881894, 0.4999987, 0.5257342},
{0.1624570, -0.4999964, 0.8506535},
{0.5257297, 0.0000000, 0.8506517},
{-0.4253235, -0.3090130, 0.8506532},
{-0.4253234, 0.3090130, 0.8506532},
{0.1624570, 0.4999964, 0.8506535},
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,495 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
// A blue
// B black
// C red
// D green
// A blue
// B black
struct vec3 {
union {
float x;
float r;
};
union {
float y;
float g;
};
union {
float z;
float b;
};
};
struct vertex {
vec3 position;
vec3 color;
};
constexpr float s = 2.5;
static const vertex tetrahedron_vertex[] = {
{{ 0.500000 * s, -0.204124 * s, 0.288675 * s}, {0.0000, 0.0000, 1.0000}},
{{ 0.000000 * s, -0.204124 * s, -0.577350 * s}, {0.0000, 0.0000, 0.0000}},
{{-0.500000 * s, -0.204124 * s, 0.288675 * s}, {1.0000, 0.0000, 0.0000}},
{{ 0.000000 * s, 0.612372 * s, 0.000000 * s}, {0.0000, 1.0000, 0.0000}},
};
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::floating_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::cull_if_negative;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->data_size_for_sort_dma = 0;
polygon->next_address_for_sort_dma = 0;
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_tetrahedron(uint32_t store_queue_ix,
const vec3& ap, const vec3& ac,
const vec3& bp, const vec3& bc,
const vec3& cp, const vec3& cc,
const vec3& dp, const vec3& dc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
if (ap.z <= 0 || bp.z <= 0 || cp.z <= 0 || dp.z <= 0)
return store_queue_ix;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_1 * vertex = (volatile vertex_parameter::polygon_type_1 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_1)) * 6;
#define transfer_vertex(n, p, c, pcw) \
vertex[n].parameter_control_word = pcw; \
vertex[n].x = p.x; \
vertex[n].y = p.y; \
vertex[n].z = p.z; \
vertex[n].base_color_r = c.r; \
vertex[n].base_color_g = c.g; \
vertex[n].base_color_b = c.b; \
pref(&vertex[n]);
transfer_vertex(0, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(1, bp, bc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(2, cp, cc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(3, dp, dc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(4, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(5, bp, bc, parameter_control_word::para_type::vertex_parameter | parameter_control_word::end_of_strip);
#undef transfer_vertex
return store_queue_ix;
}
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v, float cost, float sint)
{
// to make the cube's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cost - z0 * sint;
float y1 = y0;
float z1 = x0 * sint + z0 * cost;
float x2 = x1;
float y2 = y1 * cost - z1 * sint;
float z2 = y1 * sint + z1 * cost;
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 1.f);
return (vec3){v.x * w, v.y * w, w};
}
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 240.f + 320.f,
v.y * 240.f + 240.f,
v.z,
};
}
static uint32_t store_queue_ix = 0;
static float cost;
static float sint;
static inline void tetrahedron(vec3 a, vec3 b, vec3 c, vec3 d)
{
vec3 ap = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(a, cost, sint)));
vec3 bp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(b, cost, sint)));
vec3 cp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(c, cost, sint)));
vec3 dp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(d, cost, sint)));
const vec3& ac = tetrahedron_vertex[0].color;
const vec3& bc = tetrahedron_vertex[1].color;
const vec3& cc = tetrahedron_vertex[2].color;
const vec3& dc = tetrahedron_vertex[3].color;
store_queue_ix = transfer_ta_vertex_tetrahedron(store_queue_ix,
ap, ac,
bp, bc,
cp, cc,
dp, dc);
}
static inline vec3 midpoint(const vec3& a, const vec3& b)
{
return {(a.x + b.x) * 0.5f,
(a.y + b.y) * 0.5f,
(a.z + b.z) * 0.5f};
}
static void subdivide(vec3 a, vec3 b, vec3 c, vec3 d,
int depth)
{
if (depth == 0) {
tetrahedron(a, b, c, d);
} else {
/*
B
/ \
A---C
*/
vec3 ab = midpoint(a, b);
vec3 ac = midpoint(a, c);
vec3 ad = midpoint(a, d);
vec3 bc = midpoint(b, c);
vec3 bd = midpoint(b, d);
vec3 cd = midpoint(c, d);
/*
b ----
/ \ \
ab bc \
/ \ \
a---ac---c--cd--d
*/
subdivide( a, ab, ac, ad, depth - 1);
subdivide(ab, b, bc, bd, depth - 1);
subdivide(ac, bc, c, cd, depth - 1);
subdivide(ad, bd, cd, d, depth - 1);
}
}
void transfer_ta_sierpinski_tetrahedron()
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix);
cost = cos(theta);
sint = sin(theta);
subdivide(tetrahedron_vertex[0].position,
tetrahedron_vertex[1].position,
tetrahedron_vertex[2].position,
tetrahedron_vertex[3].position,
6);
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start[2] = {0x000000, 0x12c000};
uint32_t region_array_start = 0x258000;
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t object_list_start = 0x300000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x400000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 8 * 4 * tile_y_num * tile_x_num);
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
theta = 0;
// draw 500 frames of cube rotation
for (int i = 0; i < 1000; i++) {
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
volatile uint32_t init = holly.TA_LIST_INIT;
(void)init;
transfer_ta_sierpinski_tetrahedron();
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
using systembus::systembus;
using namespace systembus;
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0);
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
holly.FB_W_SOF1 = framebuffer_start[i & 1];
holly.SCALER_CTL = scaler_ctl::vertical_scale_factor(0x0400);
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0);
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
// increment theta for the cube rotation animation
// (used by the `vertex_rotate` function)
theta += 0.001f;
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization
//////////////////////////////////////////////////////////////////////////////
while ((spg_status::vsync(holly.SPG_STATUS)));
while (!(spg_status::vsync(holly.SPG_STATUS)));
holly.FB_R_SOF1 = framebuffer_start[i & 1];
}
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,496 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
// A blue
// B black
// C red
// D green
// A blue
// B black
struct vec3 {
union {
float x;
float r;
};
union {
float y;
float g;
};
union {
float z;
float b;
};
};
struct vertex {
vec3 position;
vec3 color;
};
constexpr float s = 2.5;
static const vertex tetrahedron_vertex[] = {
{{ 0.500000 * s, -0.204124 * s, 0.288675 * s}, {0.0000, 0.0000, 1.0000}},
{{ 0.000000 * s, -0.204124 * s, -0.577350 * s}, {0.0000, 0.0000, 0.0000}},
{{-0.500000 * s, -0.204124 * s, 0.288675 * s}, {1.0000, 0.0000, 0.0000}},
{{ 0.000000 * s, 0.612372 * s, 0.000000 * s}, {0.0000, 1.0000, 0.0000}},
};
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::floating_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::cull_if_negative;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->data_size_for_sort_dma = 0;
polygon->next_address_for_sort_dma = 0;
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_tetrahedron(uint32_t store_queue_ix,
const vec3& ap, const vec3& ac,
const vec3& bp, const vec3& bc,
const vec3& cp, const vec3& cc,
const vec3& dp, const vec3& dc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
if (ap.z <= 0 || bp.z <= 0 || cp.z <= 0 || dp.z <= 0)
return store_queue_ix;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_1 * vertex = (volatile vertex_parameter::polygon_type_1 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_1)) * 6;
#define transfer_vertex(n, p, c, pcw) \
vertex[n].parameter_control_word = pcw; \
vertex[n].x = p.x; \
vertex[n].y = p.y; \
vertex[n].z = p.z; \
vertex[n].base_color_r = c.r; \
vertex[n].base_color_g = c.g; \
vertex[n].base_color_b = c.b; \
pref(&vertex[n]);
transfer_vertex(0, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(1, bp, bc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(2, cp, cc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(3, dp, dc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(4, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(5, bp, bc, parameter_control_word::para_type::vertex_parameter | parameter_control_word::end_of_strip);
#undef transfer_vertex
return store_queue_ix;
}
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v, float cost, float sint)
{
// to make the cube's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cost - z0 * sint;
float y1 = y0;
float z1 = x0 * sint + z0 * cost;
float x2 = x1;
float y2 = y1 * cost - z1 * sint;
float z2 = y1 * sint + z1 * cost;
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 1.f);
return (vec3){v.x * w, v.y * w, w};
}
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 480.f + 640.f,
v.y * 240.f + 240.f,
v.z,
};
}
static uint32_t store_queue_ix = 0;
static float cost;
static float sint;
static inline void tetrahedron(vec3 a, vec3 b, vec3 c, vec3 d)
{
vec3 ap = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(a, cost, sint)));
vec3 bp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(b, cost, sint)));
vec3 cp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(c, cost, sint)));
vec3 dp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(d, cost, sint)));
const vec3& ac = tetrahedron_vertex[0].color;
const vec3& bc = tetrahedron_vertex[1].color;
const vec3& cc = tetrahedron_vertex[2].color;
const vec3& dc = tetrahedron_vertex[3].color;
store_queue_ix = transfer_ta_vertex_tetrahedron(store_queue_ix,
ap, ac,
bp, bc,
cp, cc,
dp, dc);
}
static inline vec3 midpoint(const vec3& a, const vec3& b)
{
return {(a.x + b.x) * 0.5f,
(a.y + b.y) * 0.5f,
(a.z + b.z) * 0.5f};
}
static void subdivide(vec3 a, vec3 b, vec3 c, vec3 d,
int depth)
{
if (depth == 0) {
tetrahedron(a, b, c, d);
} else {
/*
B
/ \
A---C
*/
vec3 ab = midpoint(a, b);
vec3 ac = midpoint(a, c);
vec3 ad = midpoint(a, d);
vec3 bc = midpoint(b, c);
vec3 bd = midpoint(b, d);
vec3 cd = midpoint(c, d);
/*
b ----
/ \ \
ab bc \
/ \ \
a---ac---c--cd--d
*/
subdivide( a, ab, ac, ad, depth - 1);
subdivide(ab, b, bc, bd, depth - 1);
subdivide(ac, bc, c, cd, depth - 1);
subdivide(ad, bd, cd, d, depth - 1);
}
}
void transfer_ta_sierpinski_tetrahedron()
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix);
cost = cos(theta);
sint = sin(theta);
subdivide(tetrahedron_vertex[0].position,
tetrahedron_vertex[1].position,
tetrahedron_vertex[2].position,
tetrahedron_vertex[3].position,
6);
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start[2] = {0x000000, 0x12c000};
uint32_t region_array_start = 0x258000;
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t object_list_start = 0x300000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 1280 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x400000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x200000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 8 * 4 * tile_y_num * tile_x_num);
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
theta = 0;
// draw 500 frames of cube rotation
for (int i = 0; i < 1000; i++) {
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
volatile uint32_t init = holly.TA_LIST_INIT;
(void)init;
transfer_ta_sierpinski_tetrahedron();
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
using systembus::systembus;
using namespace systembus;
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0);
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
holly.FB_W_SOF1 = framebuffer_start[i & 1];
holly.SCALER_CTL = scaler_ctl::horizontal_scaling_enable
| scaler_ctl::vertical_scale_factor(0x0400);
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0);
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
// increment theta for the cube rotation animation
// (used by the `vertex_rotate` function)
theta += 0.001f;
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization
//////////////////////////////////////////////////////////////////////////////
while ((spg_status::vsync(holly.SPG_STATUS)));
while (!(spg_status::vsync(holly.SPG_STATUS)));
holly.FB_R_SOF1 = framebuffer_start[i & 1];
}
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,543 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
// A blue
// B black
// C red
// D green
// A blue
// B black
struct vec3 {
union {
float x;
float r;
};
union {
float y;
float g;
};
union {
float z;
float b;
};
};
struct vertex {
vec3 position;
vec3 color;
};
constexpr float s = 2.5;
static const vertex tetrahedron_vertex[] = {
{{ 0.500000 * s, -0.204124 * s, 0.288675 * s}, {0.0000, 0.0000, 1.0000}},
{{ 0.000000 * s, -0.204124 * s, -0.577350 * s}, {0.0000, 0.0000, 0.0000}},
{{-0.500000 * s, -0.204124 * s, 0.288675 * s}, {1.0000, 0.0000, 0.0000}},
{{ 0.000000 * s, 0.612372 * s, 0.000000 * s}, {0.0000, 1.0000, 0.0000}},
};
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
template <typename T>
static inline void store_queue_destination_address(T address) {
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address<T>(address);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address<T>(address);
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::floating_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::cull_if_negative;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->data_size_for_sort_dma = 0;
polygon->next_address_for_sort_dma = 0;
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_tetrahedron(uint32_t store_queue_ix,
const vec3& ap, const vec3& ac,
const vec3& bp, const vec3& bc,
const vec3& cp, const vec3& cc,
const vec3& dp, const vec3& dc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
if (ap.z <= 0 || bp.z <= 0 || cp.z <= 0 || dp.z <= 0)
return store_queue_ix;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_1 * vertex = (volatile vertex_parameter::polygon_type_1 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_1)) * 6;
#define transfer_vertex(n, p, c, pcw) \
vertex[n].parameter_control_word = pcw; \
vertex[n].x = p.x; \
vertex[n].y = p.y; \
vertex[n].z = p.z; \
vertex[n].base_color_r = c.r; \
vertex[n].base_color_g = c.g; \
vertex[n].base_color_b = c.b; \
pref(&vertex[n]);
store_queue_destination_address(ta_fifo_polygon_converter);
transfer_vertex(0, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(1, bp, bc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(2, cp, cc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(3, dp, dc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(4, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(5, bp, bc, parameter_control_word::para_type::vertex_parameter | parameter_control_word::end_of_strip);
#undef transfer_vertex
return store_queue_ix;
}
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v, float cost, float sint)
{
// to make the cube's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cost - z0 * sint;
float y1 = y0;
float z1 = x0 * sint + z0 * cost;
float x2 = x1;
float y2 = y1 * cost - z1 * sint;
float z2 = y1 * sint + z1 * cost;
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 1.f);
return (vec3){v.x * w, v.y * w, w};
}
static int y_offset = 0;
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 480.f + 640.f,
v.y * 480.f + 480.f + y_offset,
v.z,
};
}
static uint32_t store_queue_ix = 0;
static float cost;
static float sint;
static inline void tetrahedron(vec3 a, vec3 b, vec3 c, vec3 d)
{
vec3 ap = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(a, cost, sint)));
vec3 bp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(b, cost, sint)));
vec3 cp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(c, cost, sint)));
vec3 dp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(d, cost, sint)));
const vec3& ac = tetrahedron_vertex[0].color;
const vec3& bc = tetrahedron_vertex[1].color;
const vec3& cc = tetrahedron_vertex[2].color;
const vec3& dc = tetrahedron_vertex[3].color;
store_queue_ix = transfer_ta_vertex_tetrahedron(store_queue_ix,
ap, ac,
bp, bc,
cp, cc,
dp, dc);
}
static inline vec3 midpoint(const vec3& a, const vec3& b)
{
return {(a.x + b.x) * 0.5f,
(a.y + b.y) * 0.5f,
(a.z + b.z) * 0.5f};
}
static void subdivide(vec3 a, vec3 b, vec3 c, vec3 d,
int depth)
{
if (depth == 0) {
tetrahedron(a, b, c, d);
} else {
/*
B
/ \
A---C
*/
vec3 ab = midpoint(a, b);
vec3 ac = midpoint(a, c);
vec3 ad = midpoint(a, d);
vec3 bc = midpoint(b, c);
vec3 bd = midpoint(b, d);
vec3 cd = midpoint(c, d);
/*
b ----
/ \ \
ab bc \
/ \ \
a---ac---c--cd--d
*/
subdivide( a, ab, ac, ad, depth - 1);
subdivide(ab, b, bc, bd, depth - 1);
subdivide(ac, bc, c, cd, depth - 1);
subdivide(ad, bd, cd, d, depth - 1);
}
}
void transfer_ta_sierpinski_tetrahedron()
{
store_queue_destination_address(ta_fifo_polygon_converter);
store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix);
cost = cos(theta);
sint = sin(theta);
subdivide(tetrahedron_vertex[0].position,
tetrahedron_vertex[1].position,
tetrahedron_vertex[2].position,
tetrahedron_vertex[3].position,
6);
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start[2] = {0x000000, 0x12c000};
uint32_t region_array_start = 0x258000;
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t object_list_start = 0x300000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 1280 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start + tile_x_num * tile_y_num * 6 * 4,
object_list_start + tile_x_num * tile_y_num * 8 * 4);
transfer_background_polygon(isp_tsp_parameter_start);
sh7091::store_queue_transfer::zeroize((void *)&texture_memory32[framebuffer_start[0]], 640 * 480 * 4 * 2, 0);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x400000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x200000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 8 * 4 * tile_y_num * tile_x_num * 2);
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
holly.SCALER_CTL = scaler_ctl::horizontal_scaling_enable
| scaler_ctl::vertical_scale_factor(0x0800);
holly.SOFTRESET = softreset::pipeline_soft_reset;
holly.SOFTRESET = 0;
theta = 0;
for (int i = 0; i < 1000 - 1; i++) {
using systembus::systembus;
using namespace systembus;
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
holly.TA_OL_BASE = object_list_start;
holly.TA_LIST_INIT = ta_list_init::list_init;
volatile uint32_t init = holly.TA_LIST_INIT;
(void)init;
y_offset = 0;
transfer_ta_sierpinski_tetrahedron();
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0);
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
holly.FB_W_SOF1 = framebuffer_start[i & 1];
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0);
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
holly.TA_OL_BASE = object_list_start + 8 * 4 * tile_y_num * tile_x_num;
holly.TA_LIST_CONT = ta_list_cont::list_cont;
volatile uint32_t cont = holly.TA_LIST_CONT;
(void)cont;
y_offset = -480;
transfer_ta_sierpinski_tetrahedron();
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0);
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
holly.FB_W_SOF1 = framebuffer_start[i & 1] + 640 * 240 * 4;
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start + tile_x_num * tile_y_num * 6 * 4;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0);
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization
//////////////////////////////////////////////////////////////////////////////
while ((spg_status::vsync(holly.SPG_STATUS)));
while (!(spg_status::vsync(holly.SPG_STATUS)));
holly.FB_R_SOF1 = framebuffer_start[i & 1];
// next frame
theta += 0.001f;
}
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,511 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
static inline void character(const char c)
{
using sh7091::sh7091;
using namespace sh7091;
// set the transmit trigger to `1 byte`--this changes the behavior of TDFE
sh7091.SCIF.SCFCR2 = scif::scfcr2::ttrg::trigger_on_1_bytes;
// wait for transmit fifo to become partially empty
while ((sh7091.SCIF.SCFSR2 & scif::scfsr2::tdfe::bit_mask) == 0);
// unset tdfe bit
sh7091.SCIF.SCFSR2 = (uint16_t)(~scif::scfsr2::tdfe::bit_mask);
sh7091.SCIF.SCFTDR2 = c;
}
static void string(const char * s)
{
while (*s != 0) {
character(*s++);
}
}
static void print_base16(uint32_t n, int len)
{
char buf[len];
char * bufi = &buf[len - 1];
while (bufi >= buf) {
uint32_t nib = n & 0xf;
n = n >> 4;
if (nib > 9) {
nib += (97 - 10);
} else {
nib += (48 - 0);
}
*bufi = nib;
bufi -= 1;
}
for (int i = 0; i < len; i++) {
character(buf[i]);
}
}
struct vec3 {
float x;
float y;
float z;
};
#include "model/suzanne.h"
//#include "model/icosphere.h"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0x000000;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0x000000;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0x000000;
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::floating_color;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
#define abs(n) __builtin_abs(n)
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v)
{
// to make the models's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cos(theta) - z0 * sin(theta);
float y1 = y0;
float z1 = x0 * sin(theta) + z0 * cos(theta);
float x2 = x1;
float y2 = y1 * cos(theta) - z1 * sin(theta);
float z2 = y1 * sin(theta) + z1 * cos(theta);
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 2.0f);
return (vec3){v.x * w, v.y * w, w};
}
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 240.f + 320.f,
v.y * 240.f + 240.f,
v.z,
};
}
static inline uint32_t transfer_ta_vertex_triangle(uint32_t store_queue_ix,
float x, float y, float z,
float r, float g, float b,
bool end_of_strip)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_1 * vertex = (volatile vertex_parameter::polygon_type_1 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_1)) * 1;
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| (end_of_strip ? parameter_control_word::end_of_strip : 0);
vertex[0].x = x;
vertex[0].y = y;
vertex[0].z = z;
vertex[0].base_color_alpha = 1.0;
vertex[0].base_color_r = r;
vertex[0].base_color_g = g;
vertex[0].base_color_b = b;
pref(vertex);
return store_queue_ix;
}
static const vec3 colors[] = {
{ 1.0, 0.0, 0.0 },
{ 1.0, 0.5454545454545454, 0.0 },
{ 0.9090909090909092, 1.0, 0.0 },
{ 0.36363636363636376, 1.0, 0.0 },
{ 0.0, 1.0, 0.18181818181818166 },
{ 0.0, 1.0, 0.7272727272727271 },
{ 0.0, 0.7272727272727275, 1.0 },
{ 0.0, 0.18181818181818166, 1.0 },
{ 0.3636363636363633, 0.0, 1.0 },
{ 0.9090909090909092, 0.0, 1.0 },
{ 1.0, 0.0, 0.5454545454545459 },
{ 1.0, 0.0, 0.0 },
{ 0.8500000000000001, 0.0, 0.0 },
{ 0.8500000000000001, 0.4636363636363636, 0.0 },
{ 0.7727272727272729, 0.8500000000000001, 0.0 },
{ 0.30909090909090925, 0.8500000000000001, 0.0 },
{ 0.0, 0.8500000000000001, 0.15454545454545443 },
{ 0.0, 0.8500000000000001, 0.618181818181818 },
{ 0.0, 0.6181818181818185, 0.8500000000000001 },
{ 0.0, 0.15454545454545443, 0.8500000000000001 },
{ 0.30909090909090886, 0.0, 0.8500000000000001 },
{ 0.7727272727272729, 0.0, 0.8500000000000001 },
{ 0.8500000000000001, 0.0, 0.463636363636364 },
{ 0.8500000000000001, 0.0, 0.0 },
{ 0.7, 0.0, 0.0 },
{ 0.7, 0.3818181818181818, 0.0 },
{ 0.6363636363636364, 0.7, 0.0 },
{ 0.25454545454545463, 0.7, 0.0 },
{ 0.0, 0.7, 0.12727272727272715 },
{ 0.0, 0.7, 0.5090909090909089 },
{ 0.0, 0.5090909090909093, 0.7 },
{ 0.0, 0.12727272727272715, 0.7 },
{ 0.2545454545454543, 0.0, 0.7 },
{ 0.6363636363636364, 0.0, 0.7 },
{ 0.7, 0.0, 0.38181818181818206 },
{ 0.7, 0.0, 0.0 },
{ 0.55, 0.0, 0.0 },
{ 0.55, 0.3, 0.0 },
{ 0.5000000000000001, 0.55, 0.0 },
{ 0.2000000000000001, 0.55, 0.0 },
{ 0.0, 0.55, 0.09999999999999992 },
{ 0.0, 0.55, 0.3999999999999999 },
{ 0.0, 0.4000000000000002, 0.55 },
{ 0.0, 0.09999999999999992, 0.55 },
{ 0.19999999999999984, 0.0, 0.55 },
{ 0.5000000000000001, 0.0, 0.55 },
{ 0.55, 0.0, 0.30000000000000027 },
{ 0.55, 0.0, 0.0 },
{ 0.39999999999999997, 0.0, 0.0 },
{ 0.39999999999999997, 0.21818181818181814, 0.0 },
{ 0.36363636363636365, 0.39999999999999997, 0.0 },
{ 0.1454545454545455, 0.39999999999999997, 0.0 },
{ 0.0, 0.39999999999999997, 0.07272727272727265 },
{ 0.0, 0.39999999999999997, 0.2909090909090908 },
{ 0.0, 0.290909090909091, 0.39999999999999997 },
{ 0.0, 0.07272727272727265, 0.39999999999999997 },
{ 0.1454545454545453, 0.0, 0.39999999999999997 },
{ 0.36363636363636365, 0.0, 0.39999999999999997 },
{ 0.39999999999999997, 0.0, 0.21818181818181834 },
{ 0.39999999999999997, 0.0, 0.0 },
{ 0.25, 0.0, 0.0 },
{ 0.25, 0.13636363636363635, 0.0 },
{ 0.2272727272727273, 0.25, 0.0 },
{ 0.09090909090909094, 0.25, 0.0 },
};
static const int strips_length = (sizeof (strips)) / (sizeof (strips[0]));
void transfer_ta_strips()
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
uint32_t store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix);
int color_ix = 0;
for (int strip_ix = 0; strip_ix < strips_length; strip_ix++) {
int vertex_ix = strips[strip_ix];
vec3 vp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(vertices[abs(vertex_ix)])));
const vec3& c = colors[color_ix];
bool end_of_strip = vertex_ix < 0;
store_queue_ix = transfer_ta_vertex_triangle(store_queue_ix,
vp.x, vp.y, vp.z,
c.x, c.y, c.z,
end_of_strip);
if (end_of_strip) {
color_ix = (color_ix + 1) % 64;
}
}
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 32 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_32x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 32 * 4 * tile_y_num * tile_x_num);
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
// draw 500 frames of cube rotation
for (int i = 0; i < 5000; i++) {
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
transfer_ta_strips();
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization (and the TA)
//////////////////////////////////////////////////////////////////////////////
while (!(spg_status::vsync(holly.SPG_STATUS)));
while (spg_status::vsync(holly.SPG_STATUS));
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
// start the actual render--the rendering process begins by interpreting the
// region array
using systembus::systembus;
using namespace systembus;
systembus.ISTERR = 0xffffffff;
holly.STARTRENDER = 1;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0) {
if (systembus.ISTERR) {
string("ISTERR: ");
print_base16(systembus.ISTERR, 8);
string("\n ");
return;
}
}
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
// increment theta for the cube rotation animation
// (used by the `vertex_rotate` function)
theta += 0.01f;
}
string("return\n ");
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,425 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
#include "sh7091/store_queue_transfer.hpp"
// A blue
// B black
// C red
// D green
// A blue
// B black
struct vec3 {
union {
float x;
float r;
};
union {
float y;
float g;
};
union {
float z;
float b;
};
};
struct vertex {
vec3 position;
vec3 color;
};
static const vertex tetrahedron_vertex[] = {
{{ 0.500000, -0.204124, 0.288675}, {0.0000, 0.0000, 1.0000}},
{{ 0.000000, -0.204124, -0.577350}, {0.0000, 0.0000, 0.0000}},
{{-0.500000, -0.204124, 0.288675}, {1.0000, 0.0000, 0.0000}},
{{ 0.000000, 0.612372, 0.000000}, {0.0000, 1.0000, 0.0000}},
};
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
static inline uint32_t transfer_ta_global_end_of_list(uint32_t store_queue_ix)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
return store_queue_ix;
}
static inline uint32_t transfer_ta_global_polygon(uint32_t store_queue_ix, uint32_t texture_address)
{
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::floating_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling;
// Note that it is not possible to use
// ISP_TSP_INSTRUCTION_WORD::GOURAUD_SHADING in this isp_tsp_instruction_word,
// because `gouraud` is one of the bits overwritten by the value in
// parameter_control_word. See DCDBSysArc990907E.pdf page 200.
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::filter_mode::point_sampled
| tsp_instruction_word::texture_shading_instruction::decal
| tsp_instruction_word::texture_u_size::_256
| tsp_instruction_word::texture_v_size::_256;
polygon->texture_control_word = texture_control_word::pixel_format::rgb565
| texture_control_word::scan_order::non_twiddled
| texture_control_word::texture_address(texture_address / 8);
polygon->data_size_for_sort_dma = 0;
polygon->next_address_for_sort_dma = 0;
// start store queue transfer of `polygon` to the TA
pref(polygon);
return store_queue_ix;
}
static inline uint32_t transfer_ta_vertex_tetrahedron(uint32_t store_queue_ix,
const vec3& ap, const vec3& ac,
const vec3& bp, const vec3& bc,
const vec3& cp, const vec3& cc,
const vec3& dp, const vec3& dc)
{
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_1 * vertex = (volatile vertex_parameter::polygon_type_1 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_1)) * 6;
#define transfer_vertex(n, p, c, pcw) \
vertex[n].parameter_control_word = pcw; \
vertex[n].x = p.x; \
vertex[n].y = p.y; \
vertex[n].z = p.z; \
vertex[n].base_color_r = c.r; \
vertex[n].base_color_g = c.g; \
vertex[n].base_color_b = c.b; \
pref(&vertex[n]);
transfer_vertex(0, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(1, bp, bc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(2, cp, cc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(3, dp, dc, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(4, ap, ac, parameter_control_word::para_type::vertex_parameter);
transfer_vertex(5, bp, bc, parameter_control_word::para_type::vertex_parameter | parameter_control_word::end_of_strip);
#undef transfer_vertex
return store_queue_ix;
}
#define cos(n) __builtin_cosf(n)
#define sin(n) __builtin_sinf(n)
static float theta = 0;
static inline vec3 vertex_rotate(vec3 v, float cost, float sint)
{
// to make the cube's appearance more interesting, rotate the vertex on two
// axes
float x0 = v.x;
float y0 = v.y;
float z0 = v.z;
float x1 = x0 * cost - z0 * sint;
float y1 = y0;
float z1 = x0 * sint + z0 * cost;
float x2 = x1;
float y2 = y1 * cost - z1 * sint;
float z2 = y1 * sint + z1 * cost;
return (vec3){x2, y2, z2};
}
static inline vec3 vertex_perspective_divide(vec3 v)
{
float w = 1.0f / (v.z + 1.f);
return (vec3){v.x * w, v.y * w, w};
}
static inline vec3 vertex_screen_space(vec3 v)
{
return (vec3){
v.x * 240.f + 320.f,
v.y * 240.f + 240.f,
v.z,
};
}
void transfer_ta_tetrahedron(uint32_t texture_address)
{
{
using namespace sh7091;
using sh7091::sh7091;
// set the store queue destination address to the TA Polygon Converter FIFO
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
}
uint32_t store_queue_ix = 0;
store_queue_ix = transfer_ta_global_polygon(store_queue_ix, texture_address);
float cost = cos(theta);
float sint = sin(theta);
vec3 ap = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(tetrahedron_vertex[0].position, cost, sint)));
vec3 bp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(tetrahedron_vertex[1].position, cost, sint)));
vec3 cp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(tetrahedron_vertex[2].position, cost, sint)));
vec3 dp = vertex_screen_space(
vertex_perspective_divide(
vertex_rotate(tetrahedron_vertex[3].position, cost, sint)));
const vec3& ac = tetrahedron_vertex[0].color;
const vec3& bc = tetrahedron_vertex[1].color;
const vec3& cc = tetrahedron_vertex[2].color;
const vec3& dc = tetrahedron_vertex[3].color;
store_queue_ix = transfer_ta_vertex_tetrahedron(store_queue_ix,
ap, ac,
bp, bc,
cp, cc,
dp, dc);
store_queue_ix = transfer_ta_global_end_of_list(store_queue_ix);
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
// these addresses are in "64-bit" texture memory address space:
uint32_t texture_start = 0x700000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
// draw 500 frames of cube rotation
for (int i = 0; i < 2000; i++) {
//////////////////////////////////////////////////////////////////////////////
// transfer cube to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
// TA_LIST_INIT needs to be written (every frame) prior to the first FIFO
// write.
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
transfer_ta_tetrahedron(texture_start);
//////////////////////////////////////////////////////////////////////////////
// wait for vertical synchronization (and the TA)
//////////////////////////////////////////////////////////////////////////////
while (!(spg_status::vsync(holly.SPG_STATUS)));
while (spg_status::vsync(holly.SPG_STATUS));
//////////////////////////////////////////////////////////////////////////////
// start the actual rasterization
//////////////////////////////////////////////////////////////////////////////
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// increment theta for the cube rotation animation
// (used by the `vertex_rotate` function)
theta += 0.01f;
}
// return from main; this will effectively jump back to the serial loader
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,197 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/store_queue_transfer.hpp"
void transfer_object_list(uint32_t object_list_start, uint32_t triangle_array_offset)
{
using namespace holly::core;
volatile uint32_t * object_list = (volatile uint32_t *)&texture_memory32[object_list_start];
object_list[0] = object_list::pointer_type::triangle_array
| object_list::triangle_array::number_of_triangles(0)
| object_list::triangle_array::skip(1)
| object_list::triangle_array::start(triangle_array_offset / 4);
object_list[1] = object_list::pointer_type::object_pointer_block_link
| object_list::object_pointer_block_link::end_of_list;
}
void transfer_background_polygon(uint32_t isp_tsp_parameter_start, uint32_t texture_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3, texture>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling
| isp_tsp_instruction_word::texture;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_shading_instruction::decal
| tsp_instruction_word::texture_u_size::_1024
| tsp_instruction_word::texture_v_size::_512;
polygon->texture_control_word = texture_control_word::pixel_format::rgb565
| texture_control_word::scan_order::non_twiddled
| texture_control_word::stride_select
| texture_control_word::texture_address(texture_start / 8);
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].u = 0.0f;
polygon->vertex[0].v = 0.0f;
polygon->vertex[0].base_color = 0;
polygon->vertex[1].x = 640.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].u = 640.0f / 1024.0f;
polygon->vertex[1].v = 0.0f;
polygon->vertex[1].base_color = 0;
polygon->vertex[2].x = 640.0f;
polygon->vertex[2].y = 480.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].u = 640.0f / 1024.0f;
polygon->vertex[2].v = 480.0f / 512.0f;
polygon->vertex[2].base_color = 0;
}
void transfer_region_array(uint32_t region_array_start,
uint32_t opaque_list_pointer)
{
using namespace holly::core::region_array;
/*
Create a minimal region array with a single entry:
- one tile at tile coordinate (0, 0) with one opaque list pointer
*/
/*
Holly reads the region array from "32-bit" texture memory address space,
so the region array is correspondingly written from "32-bit" address space.
*/
volatile region_array_entry * region_array = (volatile region_array_entry *)&texture_memory32[region_array_start];
const int num_tiles_y = 480 / 32;
const int num_tiles_x = 640 / 32;
const int num_tiles = num_tiles_x * num_tiles_y;
for (int i = 0; i < num_tiles; i++) {
/* define one region array entry per 32×32 px tile over a 640x480 px area */
int y = i / num_tiles_x;
int x = i % num_tiles_x;
bool last_tile = (i == (num_tiles - 1));
region_array[i].tile
= (last_tile ? tile::last_region : 0)
| tile::y_position(y)
| tile::x_position(x);
/*
list pointers are offsets relative to the beginning of "32-bit" texture memory.
each list type uses different rasterization steps, "opaque" being the fastest and most efficient.
*/
region_array[i].list_pointer.opaque = list_pointer::empty;
region_array[i].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[i].list_pointer.translucent = list_pointer::empty;
region_array[i].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[i].list_pointer.punch_through = list_pointer::empty;
}
}
const uint8_t texture[] __attribute__((aligned(4))) = {
#embed "texture/tdk_head_cleaner_640x480.rgb565"
};
void transfer_texture(uint32_t texture_start)
{
// use 4-byte transfers to texture memory, for slightly increased transfer
// speed
//
// It would be even faster to use the SH4 store queue for this operation, or
// SH4 DMA.
sh7091::store_queue_transfer::copy((void *)&texture_memory64[texture_start], texture, (sizeof (texture)));
}
void main()
{
uint32_t framebuffer_start = 0x200000;
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
uint32_t texture_start = 0x700000;
transfer_region_array(region_array_start,
object_list_start);
using polygon = holly::core::parameter::isp_tsp_parameter<3, holly::core::parameter::texture>;
uint32_t background_offset = (sizeof (polygon)) * 0;
uint32_t triangle_offset = (sizeof (polygon)) * 1;
transfer_object_list(object_list_start,
triangle_offset);
transfer_background_polygon(isp_tsp_parameter_start + background_offset,
texture_start);
//////////////////////////////////////////////////////////////////////////////
// transfer the texture image to texture ram
//////////////////////////////////////////////////////////////////////////////
transfer_texture(texture_start);
{
using namespace holly;
using holly::holly;
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(3);
holly.ISP_BACKGND_D = 0.000001f;
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
holly.TEXT_CONTROL = text_control::stride(640 / 32);
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
}
}

View File

@ -0,0 +1,180 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
void transfer_object_list(uint32_t object_list_start, uint32_t triangle_array_offset)
{
using namespace holly::core;
volatile uint32_t * object_list = (volatile uint32_t *)&texture_memory32[object_list_start];
object_list[0] = object_list::pointer_type::triangle_array
| object_list::triangle_array::number_of_triangles(0)
| object_list::triangle_array::skip(1)
| object_list::triangle_array::start(triangle_array_offset / 4);
object_list[1] = object_list::pointer_type::object_pointer_block_link
| object_list::object_pointer_block_link::end_of_list;
}
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
void transfer_triangle_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling
| isp_tsp_instruction_word::gouraud_shading;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 1.0f;
polygon->vertex[0].y = 29.0f;
polygon->vertex[0].z = 0.1f;
polygon->vertex[0].base_color = 0xff0000;
polygon->vertex[1].x = 16.0f;
polygon->vertex[1].y = 3.0f;
polygon->vertex[1].z = 0.1f;
polygon->vertex[1].base_color = 0x00ff00;
polygon->vertex[2].x = 31.0f;
polygon->vertex[2].y = 29.0f;
polygon->vertex[2].z = 0.1f;
polygon->vertex[2].base_color = 0x0000ff;
}
void transfer_region_array(uint32_t region_array_start,
uint32_t opaque_list_pointer)
{
using namespace holly::core::region_array;
/*
Create a minimal region array with a single entry:
- one tile at tile coordinate (0, 0) with one opaque list pointer
*/
/*
Holly reads the region array from "32-bit" texture memory address space,
so the region array is correspondingly written from "32-bit" address space.
*/
volatile region_array_entry * region_array = (volatile region_array_entry *)&texture_memory32[region_array_start];
region_array[0].tile
= tile::last_region
| tile::y_position(0)
| tile::x_position(0);
/*
list pointers are offsets relative to the beginning of "32-bit" texture memory.
each list type uses different rasterization steps, "opaque" being the fastest and most efficient.
*/
region_array[0].list_pointer.opaque = list_pointer::object_list(opaque_list_pointer);
region_array[0].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[0].list_pointer.translucent = list_pointer::empty;
region_array[0].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[0].list_pointer.punch_through = list_pointer::empty;
}
void main()
{
uint32_t framebuffer_start = 0x200000;
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
transfer_region_array(region_array_start,
object_list_start);
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t background_offset = (sizeof (polygon)) * 0;
uint32_t triangle_offset = (sizeof (polygon)) * 1;
transfer_object_list(object_list_start,
triangle_offset);
transfer_triangle_polygon(isp_tsp_parameter_start + triangle_offset);
transfer_background_polygon(isp_tsp_parameter_start + background_offset);
{
using namespace holly;
using holly::holly;
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
holly.ISP_BACKGND_D = 0.000001f;
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
}
}

View File

@ -0,0 +1,193 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
void transfer_object_list(uint32_t object_list_start, uint32_t triangle_array_offset)
{
using namespace holly::core;
volatile uint32_t * object_list = (volatile uint32_t *)&texture_memory32[object_list_start];
object_list[0] = object_list::pointer_type::triangle_array
| object_list::triangle_array::number_of_triangles(0)
| object_list::triangle_array::skip(1)
| object_list::triangle_array::start(triangle_array_offset / 4);
object_list[1] = object_list::pointer_type::object_pointer_block_link
| object_list::object_pointer_block_link::end_of_list;
}
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
void transfer_triangle_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling
| isp_tsp_instruction_word::gouraud_shading;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 77.0f;
polygon->vertex[0].y = 450.0f;
polygon->vertex[0].z = 0.1f;
polygon->vertex[0].base_color = 0xff0000;
polygon->vertex[1].x = 320.0f;
polygon->vertex[1].y = 30.0f;
polygon->vertex[1].z = 0.1f;
polygon->vertex[1].base_color = 0x00ff00;
polygon->vertex[2].x = 562.0f;
polygon->vertex[2].y = 450.0f;
polygon->vertex[2].z = 0.1f;
polygon->vertex[2].base_color = 0x0000ff;
}
void transfer_region_array(uint32_t region_array_start,
uint32_t opaque_list_pointer)
{
using namespace holly::core::region_array;
/*
Create a minimal region array with a single entry:
- one tile at tile coordinate (0, 0) with one opaque list pointer
*/
/*
Holly reads the region array from "32-bit" texture memory address space,
so the region array is correspondingly written from "32-bit" address space.
*/
volatile region_array_entry * region_array = (volatile region_array_entry *)&texture_memory32[region_array_start];
const int num_tiles_y = 480 / 32;
const int num_tiles_x = 640 / 32;
const int num_tiles = num_tiles_x * num_tiles_y;
for (int i = 0; i < num_tiles; i++) {
/* define one region array entry per 32×32 px tile over a 640x480 px area */
int y = i / num_tiles_x;
int x = i % num_tiles_x;
bool last_tile = (i == (num_tiles - 1));
region_array[i].tile
= (last_tile ? tile::last_region : 0)
| tile::y_position(y)
| tile::x_position(x);
/*
list pointers are offsets relative to the beginning of "32-bit" texture memory.
each list type uses different rasterization steps, "opaque" being the fastest and most efficient.
*/
region_array[i].list_pointer.opaque = list_pointer::object_list(opaque_list_pointer);
region_array[i].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[i].list_pointer.translucent = list_pointer::empty;
region_array[i].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[i].list_pointer.punch_through = list_pointer::empty;
}
}
void main()
{
uint32_t framebuffer_start = 0x200000;
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
transfer_region_array(region_array_start,
object_list_start);
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t background_offset = (sizeof (polygon)) * 0;
uint32_t triangle_offset = (sizeof (polygon)) * 1;
transfer_object_list(object_list_start,
triangle_offset);
transfer_triangle_polygon(isp_tsp_parameter_start + triangle_offset);
transfer_background_polygon(isp_tsp_parameter_start + background_offset);
{
using namespace holly;
using holly::holly;
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
holly.ISP_BACKGND_D = 0.000001f;
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
}
}

View File

@ -0,0 +1,285 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
void transfer_ta_triangle()
{
using namespace sh7091;
using sh7091::sh7091;
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
uint32_t store_queue_ix = 0;
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::packed_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
pref(polygon);
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_0 * vertex = (volatile vertex_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_0)) * 3;
// bottom left
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[0].x = 1.0f;
vertex[0].y = 29.0f;
vertex[0].z = 0.1f;
vertex[0].base_color = 0xff0000; // red
// start store queue transfer of `vertex[0]` to the TA
pref(&vertex[0]);
// top center
vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[1].x = 16.0f;
vertex[1].y = 3.0f;
vertex[1].z = 0.1f;
vertex[1].base_color = 0x00ff00; // green
// start store queue transfer of `vertex[1]` to the TA
pref(&vertex[1]);
// bottom right
vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| parameter_control_word::end_of_strip;
vertex[2].x = 31.0f;
vertex[2].y = 29.0f;
vertex[2].z = 0.1f;
vertex[2].base_color = 0x0000ff; // blue
// start store queue transfer of `params[2]` to the TA
pref(&vertex[2]);
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
}
void transfer_region_array(uint32_t region_array_start,
uint32_t opaque_list_pointer)
{
using namespace holly::core::region_array;
/*
Create a minimal region array with a single entry:
- one tile at tile coordinate (0, 0) with one opaque list pointer
*/
/*
Holly reads the region array from "32-bit" texture memory address space,
so the region array is correspondingly written from "32-bit" address space.
*/
volatile region_array_entry * region_array = (volatile region_array_entry *)&texture_memory32[region_array_start];
region_array[0].tile
= tile::last_region
| tile::y_position(0)
| tile::x_position(0);
/*
list pointers are offsets relative to the beginning of "32-bit" texture memory.
each list type uses different rasterization steps, "opaque" being the fastest and most efficient.
*/
region_array[0].list_pointer.opaque = list_pointer::object_list(opaque_list_pointer);
region_array[0].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[0].list_pointer.translucent = list_pointer::empty;
region_array[0].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[0].list_pointer.punch_through = list_pointer::empty;
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
transfer_region_array(region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
const int tile_y_num = 1;
const int tile_x_num = 1;
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
//////////////////////////////////////////////////////////////////////////////
// transfer triangles to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
transfer_ta_triangle();
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,262 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
void transfer_ta_triangle()
{
using namespace sh7091;
using sh7091::sh7091;
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
uint32_t store_queue_ix = 0;
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::packed_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
pref(polygon);
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_0 * vertex = (volatile vertex_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_0)) * 3;
// bottom left
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[0].x = 77.0f;
vertex[0].y = 450.0f;
vertex[0].z = 0.1f;
vertex[0].base_color = 0xff0000; // red
// start store queue transfer of `vertex[0]` to the TA
pref(&vertex[0]);
// top center
vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[1].x = 320.0f;
vertex[1].y = 30.0f;
vertex[1].z = 0.1f;
vertex[1].base_color = 0x00ff00; // green
// start store queue transfer of `vertex[1]` to the TA
pref(&vertex[1]);
// bottom right
vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| parameter_control_word::end_of_strip;
vertex[2].x = 562.0f;
vertex[2].y = 450.0f;
vertex[2].z = 0.1f;
vertex[2].base_color = 0x0000ff; // blue
// start store queue transfer of `params[2]` to the TA
pref(&vertex[2]);
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
const int tile_y_num = 480 / 32;
const int tile_x_num = 640 / 32;
using namespace holly::core;
region_array::list_block_size list_block_size = {
.opaque = 8 * 4,
};
region_array::transfer(tile_x_num,
tile_y_num,
list_block_size,
region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
//////////////////////////////////////////////////////////////////////////////
// transfer triangles to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
transfer_ta_triangle();
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
// without waiting for rendering to actually complete, immediately display the
// framebuffer.
holly.FB_R_SOF1 = framebuffer_start;
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,350 @@
#include "memorymap.hpp"
#include "holly/core/object_list_bits.hpp"
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "holly/core/parameter_bits.hpp"
#include "holly/core/parameter.hpp"
#include "holly/ta/global_parameter.hpp"
#include "holly/ta/vertex_parameter.hpp"
#include "holly/ta/parameter_bits.hpp"
#include "holly/holly.hpp"
#include "holly/holly_bits.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
#include "systembus/systembus.hpp"
#include "systembus/systembus_bits.hpp"
void transfer_background_polygon(uint32_t isp_tsp_parameter_start)
{
using namespace holly::core::parameter;
using parameter = isp_tsp_parameter<3>;
volatile parameter * polygon = (volatile parameter *)&texture_memory32[isp_tsp_parameter_start];
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
polygon->texture_control_word = 0;
polygon->vertex[0].x = 0.0f;
polygon->vertex[0].y = 0.0f;
polygon->vertex[0].z = 0.00001f;
polygon->vertex[0].base_color = 0xff00ff;
polygon->vertex[1].x = 32.0f;
polygon->vertex[1].y = 0.0f;
polygon->vertex[1].z = 0.00001f;
polygon->vertex[1].base_color = 0xff00ff;
polygon->vertex[2].x = 32.0f;
polygon->vertex[2].y = 32.0f;
polygon->vertex[2].z = 0.00001f;
polygon->vertex[2].base_color = 0xff00ff;
}
void transfer_ta_triangle(bool alt)
{
using namespace sh7091;
using sh7091::sh7091;
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(ta_fifo_polygon_converter);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(ta_fifo_polygon_converter);
uint32_t store_queue_ix = 0;
using namespace holly::core::parameter;
using namespace holly::ta;
using namespace holly::ta::parameter;
//
// TA polygon global transfer
//
volatile global_parameter::polygon_type_0 * polygon = (volatile global_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::polygon_type_0));
polygon->parameter_control_word = parameter_control_word::para_type::polygon_or_modifier_volume
| parameter_control_word::list_type::opaque
| parameter_control_word::col_type::packed_color
| parameter_control_word::gouraud;
polygon->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always
| isp_tsp_instruction_word::culling_mode::no_culling;
polygon->tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
pref(polygon);
//
// TA polygon vertex transfer
//
volatile vertex_parameter::polygon_type_0 * vertex = (volatile vertex_parameter::polygon_type_0 *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (vertex_parameter::polygon_type_0)) * 3;
// bottom left
vertex[0].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[0].x = 1.0f;
vertex[0].y = 29.0f;
vertex[0].z = 0.1f;
vertex[0].base_color = alt ? 0xffff00 : 0xff0000; // red
// start store queue transfer of `vertex[0]` to the TA
pref(&vertex[0]);
// top center
vertex[1].parameter_control_word = parameter_control_word::para_type::vertex_parameter;
vertex[1].x = 16.0f;
vertex[1].y = 3.0f;
vertex[1].z = 0.1f;
vertex[1].base_color = alt ? 0x00ffff : 0x00ff00; // green
// start store queue transfer of `vertex[1]` to the TA
pref(&vertex[1]);
// bottom right
vertex[2].parameter_control_word = parameter_control_word::para_type::vertex_parameter
| parameter_control_word::end_of_strip;
vertex[2].x = 31.0f;
vertex[2].y = 29.0f;
vertex[2].z = 0.1f;
vertex[2].base_color = alt ? 0xff80ff : 0x0000ff; // blue
// start store queue transfer of `params[2]` to the TA
pref(&vertex[2]);
//
// TA "end of list" global transfer
//
volatile global_parameter::end_of_list * end_of_list = (volatile global_parameter::end_of_list *)&store_queue[store_queue_ix];
store_queue_ix += (sizeof (global_parameter::end_of_list));
end_of_list->parameter_control_word = parameter_control_word::para_type::end_of_list;
// start store queue transfer of `end_of_list` to the TA
pref(end_of_list);
}
void transfer_region_array(uint32_t region_array_start,
uint32_t opaque_list_pointer)
{
using namespace holly::core::region_array;
/*
Create a minimal region array with a single entry:
- one tile at tile coordinate (0, 0) with one opaque list pointer
*/
/*
Holly reads the region array from "32-bit" texture memory address space,
so the region array is correspondingly written from "32-bit" address space.
*/
volatile region_array_entry * region_array = (volatile region_array_entry *)&texture_memory32[region_array_start];
region_array[0].tile
= tile::y_position(0)
| tile::x_position(0);
region_array[0].list_pointer.opaque = list_pointer::object_list(opaque_list_pointer);
region_array[0].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[0].list_pointer.translucent = list_pointer::empty;
region_array[0].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[0].list_pointer.punch_through = list_pointer::empty;
region_array[1].tile
= tile::last_region
| tile::y_position(0)
| tile::x_position(1);
region_array[1].list_pointer.opaque = list_pointer::empty;
region_array[1].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[1].list_pointer.translucent = list_pointer::empty;
region_array[1].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[1].list_pointer.punch_through = list_pointer::empty;
region_array[2].tile
= tile::y_position(0)
| tile::x_position(0);
region_array[2].list_pointer.opaque = list_pointer::object_list(opaque_list_pointer + 8 * 4);
region_array[2].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[2].list_pointer.translucent = list_pointer::empty;
region_array[2].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[2].list_pointer.punch_through = list_pointer::empty;
region_array[3].tile
= tile::last_region
| tile::y_position(0)
| tile::x_position(1);
region_array[3].list_pointer.opaque = list_pointer::empty;
region_array[3].list_pointer.opaque_modifier_volume = list_pointer::empty;
region_array[3].list_pointer.translucent = list_pointer::empty;
region_array[3].list_pointer.translucent_modifier_volume = list_pointer::empty;
region_array[3].list_pointer.punch_through = list_pointer::empty;
}
void main()
{
/*
a very simple memory map:
the ordering within texture memory is not significant, and could be
anything
*/
uint32_t framebuffer_start = 0x200000; // intentionally the same address that the boot rom used to draw the SEGA logo
uint32_t isp_tsp_parameter_start = 0x400000;
uint32_t region_array_start = 0x500000;
uint32_t object_list_start = 0x100000;
transfer_region_array(region_array_start,
object_list_start);
transfer_background_polygon(isp_tsp_parameter_start);
//////////////////////////////////////////////////////////////////////////////
// configure the TA
//////////////////////////////////////////////////////////////////////////////
const int tile_y_num = 1;
const int tile_x_num = 1;
using namespace holly;
using holly::holly;
// TA_GLOB_TILE_CLIP restricts which "object pointer blocks" are written
// to.
//
// This can also be used to implement "windowing", as long as the desired
// window size happens to be a multiple of 32 pixels. The "User Tile Clip" TA
// control parameter can also ~equivalently be used as many times as desired
// within a single TA initialization to produce an identical effect.
//
// See DCDBSysArc990907E.pdf page 183.
holly.TA_GLOB_TILE_CLIP = ta_glob_tile_clip::tile_y_num(tile_y_num - 1)
| ta_glob_tile_clip::tile_x_num(tile_x_num - 1);
// While CORE supports arbitrary-length object lists, the TA uses "object
// pointer blocks" as a memory allocation strategy. These fixed-length blocks
// can still have infinite length via "object pointer block links". This
// mechanism is illustrated in DCDBSysArc990907E.pdf page 188.
holly.TA_ALLOC_CTRL = ta_alloc_ctrl::opb_mode::increasing_addresses
| ta_alloc_ctrl::o_opb::_8x4byte;
// While building object lists, the TA contains an internal index (exposed as
// the read-only TA_ITP_CURRENT) for the next address that new ISP/TSP will be
// stored at. The initial value of this index is TA_ISP_BASE.
// reserve space in ISP/TSP parameters for the background parameter
using polygon = holly::core::parameter::isp_tsp_parameter<3>;
uint32_t ta_isp_base_offset = (sizeof (polygon)) * 1;
holly.TA_ISP_BASE = isp_tsp_parameter_start + ta_isp_base_offset;
holly.TA_ISP_LIMIT = isp_tsp_parameter_start + 0x100000;
// Similarly, the TA also contains, for up to 600 tiles, an internal index for
// the next address that an object list entry will be stored for each
// tile. These internal indicies are partially exposed via the read-only
// TA_OL_POINTERS.
holly.TA_OL_BASE = object_list_start;
// TA_OL_LIMIT, DCDBSysArc990907E.pdf page 385:
//
// > Because the TA may automatically store data in the address that is
// > specified by this register, it must not be used for other data. For
// > example, the address specified here must not be the same as the address
// > in the TA_ISP_BASE register.
holly.TA_OL_LIMIT = object_list_start + 0x100000 - 32;
holly.TA_NEXT_OPB_INIT = (object_list_start + 8 * 4 * 2 * 1);
holly.TA_LIST_INIT = ta_list_init::list_init;
// dummy TA_LIST_INIT read; DCDBSysArc990907E.pdf in multiple places says this
// step is required.
(void)holly.TA_LIST_INIT;
//////////////////////////////////////////////////////////////////////////////
// transfer triangles to texture memory via the TA polygon converter FIFO
//////////////////////////////////////////////////////////////////////////////
using systembus::systembus;
using namespace systembus;
transfer_ta_triangle(true);
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0);
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
// transfer again
holly.TA_OL_BASE = object_list_start + 8 * 4;
holly.TA_LIST_CONT = ta_list_cont::list_cont;
(void)holly.TA_LIST_CONT;
transfer_ta_triangle(false);
while ((systembus.ISTNRM & istnrm::end_of_transferring_opaque_list) == 0);
systembus.ISTNRM = istnrm::end_of_transferring_opaque_list;
//////////////////////////////////////////////////////////////////////////////
// configure CORE
//////////////////////////////////////////////////////////////////////////////
holly.SCALER_CTL = scaler_ctl::vertical_scale_factor(0x0800);
//holly.SCALER_CTL = scaler_ctl::vertical_scale_factor(0x0400);
holly.SOFTRESET = 0b11;
holly.SOFTRESET = 0;
While ((spg_status::vsync(holly.SPG_STATUS)));
while (!(spg_status::vsync(holly.SPG_STATUS)));
// REGION_BASE is the (texture memory-relative) address of the region array.
holly.REGION_BASE = region_array_start;
// PARAM_BASE is the (texture memory-relative) address of ISP/TSP parameters.
// Anything that references an ISP/TSP parameter does so relative to this
// address (and not relative to the beginning of texture memory).
holly.PARAM_BASE = isp_tsp_parameter_start;
// Set the offset of the background ISP/TSP parameter, relative to PARAM_BASE
// SKIP is related to the size of each vertex
uint32_t background_offset = 0;
holly.ISP_BACKGND_T = isp_backgnd_t::tag_address(background_offset / 4)
| isp_backgnd_t::tag_offset(0)
| isp_backgnd_t::skip(1);
// FB_W_SOF1 is the (texture memory-relative) address of the framebuffer that
// will be written to when a tile is rendered/flushed.
holly.FB_W_SOF1 = framebuffer_start;
// start the actual render--the rendering process begins by interpreting the
// region array
holly.STARTRENDER = 1;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0);
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
holly.REGION_BASE = region_array_start + 6 * 4 * 2;
holly.FB_W_SOF1 = framebuffer_start + 640 * 32 * 4 * 2;
holly.STARTRENDER = 1;
holly.FB_R_SOF1 = framebuffer_start;
while ((systembus.ISTNRM & istnrm::end_of_render_tsp) == 0);
systembus.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
// return from main; this will effectively jump back to the serial loader
}

View File

@ -0,0 +1,51 @@
#pragma once
#include <cstdint>
namespace holly::core::object_list {
namespace pointer_type {
constexpr uint32_t triangle_strip = 0b000 << 29;
constexpr uint32_t triangle_array = 0b100 << 29;
constexpr uint32_t quad_array = 0b101 << 29;
constexpr uint32_t object_pointer_block_link = 0b111 << 29;
constexpr uint32_t bit_mask = 0x7 << 29;
}
namespace triangle_strip {
namespace mask {
constexpr uint32_t t0 = 0b100000 << 25;
constexpr uint32_t t1 = 0b010000 << 25;
constexpr uint32_t t2 = 0b001000 << 25;
constexpr uint32_t t3 = 0b000100 << 25;
constexpr uint32_t t4 = 0b000010 << 25;
constexpr uint32_t t5 = 0b000001 << 25;
constexpr uint32_t bit_mask = 0x3f << 25;
}
constexpr uint32_t shadow = 1 << 24;
constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 21; }
constexpr inline uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; }
}
namespace triangle_array {
constexpr inline uint32_t number_of_triangles(uint32_t num) { return (num & 0xf) << 25; }
constexpr uint32_t shadow = 1 << 24;
constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 21; }
constexpr inline uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; }
}
namespace quad_array {
constexpr inline uint32_t number_of_quads(uint32_t num) { return (num & 0xf) << 25; }
constexpr uint32_t shadow = 1 << 24;
constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 21; }
constexpr inline uint32_t start(uint32_t num) { return (num & 0x1fffff) << 0; }
}
namespace object_pointer_block_link {
constexpr uint32_t end_of_list = 1 << 28;
constexpr inline uint32_t next_pointer_block(uint32_t num) { return (num & 0xfffffc) << 0; }
}
}

View File

@ -0,0 +1,146 @@
#pragma once
#include <cstdint>
namespace holly::core::parameter {
enum struct volume_sel {
one_volume,
two_volumes
};
using volume_sel::one_volume;
using volume_sel::two_volumes;
enum struct offset_sel {
offset,
non_offset
};
using offset_sel::offset;
using offset_sel::non_offset;
enum struct texture_sel {
texture,
non_texture
};
using texture_sel::texture;
using texture_sel::non_texture;
template <texture_sel T, volume_sel V, offset_sel O>
struct vertex;
template <>
struct vertex<non_texture, one_volume, non_offset> {
float x;
float y;
float z;
uint32_t base_color;
};
template <>
struct vertex<non_texture, two_volumes, non_offset> {
float x;
float y;
float z;
struct {
uint32_t base_color;
} volume[2];
};
template <>
struct vertex<non_texture, one_volume, offset> {
float x;
float y;
float z;
uint32_t base_color;
uint32_t offset_color;
};
template <>
struct vertex<non_texture, two_volumes, offset> {
float x;
float y;
float z;
struct {
uint32_t base_color;
uint32_t offset_color;
} volume[2];
};
template <>
struct vertex<texture, one_volume, non_offset> {
float x;
float y;
float z;
float u;
float v;
uint32_t base_color;
};
template <>
struct vertex<texture, two_volumes, non_offset> {
float x;
float y;
float z;
struct {
float u;
float v;
uint32_t base_color;
} volume[2];
};
template <>
struct vertex<texture, one_volume, offset> {
float x;
float y;
float z;
float u;
float v;
uint32_t base_color;
uint32_t offset_color;
};
template <>
struct vertex<texture, two_volumes, offset> {
float x;
float y;
float z;
struct {
float u;
float v;
uint32_t base_color;
uint32_t offset_color;
} volume[2];
};
template <int N, texture_sel T=non_texture, volume_sel V=one_volume, offset_sel O=non_offset>
struct isp_tsp_parameter;
template <int N, texture_sel T, offset_sel O>
struct isp_tsp_parameter<N, T, one_volume, O> {
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
struct vertex<T, one_volume, O> vertex[N];
};
template <int N, texture_sel T, offset_sel O>
struct isp_tsp_parameter<N, T, two_volumes, O> {
uint32_t isp_tsp_instruction_word;
struct {
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
} volume[2];
struct vertex<T, two_volumes, O> vertex[N];
};
static_assert((sizeof (isp_tsp_parameter<1>)) == 28);
static_assert((sizeof (isp_tsp_parameter<1, texture>)) == 36);
static_assert((sizeof (isp_tsp_parameter<1, texture, two_volumes>)) == 56);
static_assert((sizeof (isp_tsp_parameter<1, texture, two_volumes, offset>)) == 64);
static_assert((sizeof (isp_tsp_parameter<1, non_texture, two_volumes>)) == 40);
static_assert((sizeof (isp_tsp_parameter<1, non_texture, two_volumes, offset>)) == 48);
}

View File

@ -0,0 +1,195 @@
#pragma once
#include <cstdint>
namespace holly::core::parameter {
namespace isp_tsp_instruction_word {
namespace depth_compare_mode {
constexpr uint32_t never = 0 << 29;
constexpr uint32_t less = 1 << 29;
constexpr uint32_t equal = 2 << 29;
constexpr uint32_t less_or_equal = 3 << 29;
constexpr uint32_t greater = 4 << 29;
constexpr uint32_t greater_or_equal = 5 << 29;
constexpr uint32_t not_equal = 6 << 29;
constexpr uint32_t always = 7 << 29;
constexpr uint32_t bit_mask = 0x7 << 29;
}
namespace volume_instruction {
constexpr uint32_t normal_polygon = 0 << 29;
constexpr uint32_t inside_last_polygon = 1 << 29;
constexpr uint32_t outside_last_polygon = 2 << 29;
constexpr uint32_t bit_mask = 0x7 << 29;
}
namespace culling_mode {
constexpr uint32_t no_culling = 0 << 27;
constexpr uint32_t cull_if_small = 1 << 27;
constexpr uint32_t cull_if_negative = 2 << 27;
constexpr uint32_t cull_if_positive = 3 << 27;
constexpr uint32_t bit_mask = 0x3 << 27;
}
constexpr uint32_t z_write_disable = 1 << 26;
constexpr uint32_t texture = 1 << 25;
constexpr uint32_t offset = 1 << 24;
constexpr uint32_t gouraud_shading = 1 << 23;
constexpr uint32_t _16bit_uv = 1 << 22;
constexpr uint32_t cache_bypass = 1 << 21;
constexpr uint32_t dcalc_ctrl = 1 << 20;
}
namespace tsp_instruction_word {
namespace src_alpha_instr {
constexpr uint32_t zero = 0 << 29;
constexpr uint32_t one = 1 << 29;
constexpr uint32_t other_color = 2 << 29;
constexpr uint32_t inverse_other_color = 3 << 29;
constexpr uint32_t src_alpha = 4 << 29;
constexpr uint32_t inverse_src_alpha = 5 << 29;
constexpr uint32_t dst_alpha = 6 << 29;
constexpr uint32_t inverse_dst_alpha = 7 << 29;
constexpr uint32_t bit_mask = 0x7 << 29;
}
namespace dst_alpha_instr {
constexpr uint32_t zero = 0 << 26;
constexpr uint32_t one = 1 << 26;
constexpr uint32_t other_color = 2 << 26;
constexpr uint32_t inverse_other_color = 3 << 26;
constexpr uint32_t src_alpha = 4 << 26;
constexpr uint32_t inverse_src_alpha = 5 << 26;
constexpr uint32_t dst_alpha = 6 << 26;
constexpr uint32_t inverse_dst_alpha = 7 << 26;
constexpr uint32_t bit_mask = 0x7 << 26;
}
namespace src_select {
constexpr uint32_t primary_accumulation_buffer = 0 << 25;
constexpr uint32_t secondary_accumulation_buffer = 1 << 25;
constexpr uint32_t bit_mask = 0x1 << 25;
}
namespace dst_select {
constexpr uint32_t primary_accumulation_buffer = 0 << 24;
constexpr uint32_t secondary_accumulation_buffer = 1 << 24;
constexpr uint32_t bit_mask = 0x1 << 24;
}
namespace fog_control {
constexpr uint32_t look_up_table = 0b00 << 22;
constexpr uint32_t per_vertex = 0b01 << 22;
constexpr uint32_t no_fog = 0b10 << 22;
constexpr uint32_t look_up_table_mode_2 = 0b11 << 22;
constexpr uint32_t bit_mask = 0x3 << 22;
}
constexpr uint32_t color_clamp = 1 << 21;
constexpr uint32_t use_alpha = 1 << 20;
constexpr uint32_t ignore_texture_alpha = 1 << 19;
namespace flip_uv {
constexpr uint32_t none = 0 << 17;
constexpr uint32_t v = 1 << 17;
constexpr uint32_t u = 2 << 17;
constexpr uint32_t uv = 3 << 17;
constexpr uint32_t bit_mask = 0x3 << 17;
}
namespace clamp_uv {
constexpr uint32_t none = 0 << 15;
constexpr uint32_t v = 1 << 15;
constexpr uint32_t u = 2 << 15;
constexpr uint32_t uv = 3 << 15;
constexpr uint32_t bit_mask = 0x3 << 15;
}
namespace filter_mode {
constexpr uint32_t point_sampled = 0b00 << 13;
constexpr uint32_t bilinear_filter = 0b01 << 13;
constexpr uint32_t trilinear_pass_a = 0b10 << 13;
constexpr uint32_t trilinear_pass_b = 0b11 << 13;
constexpr uint32_t bit_mask = 0x3 << 13;
}
constexpr uint32_t super_sample_texture = 1 << 12;
constexpr inline uint32_t mip_map_d_adjust(uint32_t num) { return (num & 0xf) << 8; }
namespace texture_shading_instruction {
constexpr uint32_t decal = 0 << 6;
constexpr uint32_t modulate = 1 << 6;
constexpr uint32_t decal_alpha = 2 << 6;
constexpr uint32_t modulate_alpha = 3 << 6;
constexpr uint32_t bit_mask = 0x3 << 6;
}
namespace texture_u_size {
constexpr uint32_t _8 = 0 << 3;
constexpr uint32_t _16 = 1 << 3;
constexpr uint32_t _32 = 2 << 3;
constexpr uint32_t _64 = 3 << 3;
constexpr uint32_t _128 = 4 << 3;
constexpr uint32_t _256 = 5 << 3;
constexpr uint32_t _512 = 6 << 3;
constexpr uint32_t _1024 = 7 << 3;
constexpr uint32_t bit_mask = 0x7 << 3;
}
namespace texture_v_size {
constexpr uint32_t _8 = 0 << 0;
constexpr uint32_t _16 = 1 << 0;
constexpr uint32_t _32 = 2 << 0;
constexpr uint32_t _64 = 3 << 0;
constexpr uint32_t _128 = 4 << 0;
constexpr uint32_t _256 = 5 << 0;
constexpr uint32_t _512 = 6 << 0;
constexpr uint32_t _1024 = 7 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
namespace texture_control_word {
constexpr uint32_t mip_mapped = 1 << 31;
constexpr uint32_t vq_compressed = 1 << 30;
namespace pixel_format {
constexpr uint32_t argb1555 = 0 << 27;
constexpr uint32_t rgb565 = 1 << 27;
constexpr uint32_t argb4444 = 2 << 27;
constexpr uint32_t yuv422 = 3 << 27;
constexpr uint32_t bump_map = 4 << 27;
constexpr uint32_t palette_4bpp = 5 << 27;
constexpr uint32_t palette_8bpp = 6 << 27;
constexpr uint32_t bit_mask = 0x7 << 27;
}
namespace scan_order {
constexpr uint32_t twiddled = 0 << 26;
constexpr uint32_t non_twiddled = 1 << 26;
constexpr uint32_t bit_mask = 0x1 << 26;
}
constexpr uint32_t stride_select = 1 << 25;
constexpr inline uint32_t palette_selector4(uint32_t num) { return (num & 0x3f) << 21; }
constexpr inline uint32_t palette_selector8(uint32_t num) { return (num & 0x3) << 25; }
constexpr inline uint32_t texture_address(uint32_t num) { return (num & 0x1fffff) << 0; }
}
}

View File

@ -0,0 +1,80 @@
#include "holly/core/region_array.hpp"
#include "holly/core/region_array_bits.hpp"
#include "sh7091/store_queue_transfer.hpp"
#include "systembus/systembus.hpp"
namespace holly::core::region_array {
void transfer(const int tile_width,
const int tile_height,
const list_block_size& list_block_size,
const uint32_t region_array_start,
const uint32_t object_list_start)
{
const uint32_t ol_base = object_list_start;
const uint32_t num_tiles = tile_width * tile_height;
//region_array_entry region_array[num_tiles];
volatile region_array_entry * region_array = (volatile region_array_entry * )&texture_memory32[region_array_start];
int ix = 0;
for (int y = 0; y < tile_height; y++) {
for (int x = 0; x < tile_width; x++) {
int rix = x * tile_height + y;
//int rix = y * tile_width + x;
region_array[rix].tile = tile::y_position(y)
| tile::x_position(x);
if (y == (tile_height - 1) && x == (tile_width - 1))
region_array[rix].tile |= tile::last_region;
region_array[rix].list_pointer.opaque = (list_block_size.opaque == 0) ? list_pointer::empty :
(ol_base + (list_block_size.opaque * ix)
);
region_array[rix].list_pointer.opaque_modifier_volume = (list_block_size.opaque_modifier_volume == 0) ? list_pointer::empty :
(ol_base + num_tiles * ( list_block_size.opaque
)
+ (list_block_size.opaque_modifier_volume * ix)
);
region_array[rix].list_pointer.translucent = (list_block_size.translucent == 0) ? list_pointer::empty :
(ol_base + num_tiles * ( list_block_size.opaque
+ list_block_size.opaque_modifier_volume
)
+ (list_block_size.translucent * ix)
);
region_array[rix].list_pointer.translucent_modifier_volume = (list_block_size.translucent_modifier_volume == 0) ? list_pointer::empty :
(ol_base + num_tiles * ( list_block_size.opaque
+ list_block_size.opaque_modifier_volume
+ list_block_size.translucent
)
+ (list_block_size.translucent_modifier_volume * ix)
);
region_array[rix].list_pointer.punch_through = (list_block_size.punch_through == 0) ? list_pointer::empty :
(ol_base + num_tiles * ( list_block_size.opaque
+ list_block_size.opaque_modifier_volume
+ list_block_size.translucent
+ list_block_size.translucent_modifier_volume
)
+ (list_block_size.punch_through * ix)
);
ix += 1;
}
}
/*
using systembus::systembus;
systembus.LMMODE0 = 1; // 32-bit address space
systembus.LMMODE1 = 1; // 32-bit address space
void * dst = (void *)(&ta_fifo_texture_memory[region_array_start]);
void * src = (void *)(region_array);
sh7091::store_queue_transfer::copy(dst, src, (sizeof (region_array_entry)) * num_tiles);
*/
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint>
namespace holly::core::region_array {
struct region_array_entry {
uint32_t tile;
struct {
uint32_t opaque;
uint32_t opaque_modifier_volume;
uint32_t translucent;
uint32_t translucent_modifier_volume;
uint32_t punch_through;
} list_pointer;
};
struct list_block_size {
uint32_t opaque;
uint32_t opaque_modifier_volume;
uint32_t translucent;
uint32_t translucent_modifier_volume;
uint32_t punch_through;
uint32_t total() const
{
return opaque
+ opaque_modifier_volume
+ translucent
+ translucent_modifier_volume
+ punch_through;
}
};
void transfer(const int tile_width,
const int tile_height,
const list_block_size& list_block_size,
const uint32_t region_array_start,
const uint32_t object_list_start);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <cstdint>
namespace holly::core::region_array {
namespace tile {
constexpr uint32_t last_region = 1 << 31;
constexpr uint32_t z_clear = 1 << 30;
constexpr uint32_t pre_sort = 1 << 29;
constexpr uint32_t flush_accumulate = 1 << 28;
constexpr inline uint32_t y_position(uint32_t num) { return (num & 0x3f) << 8; }
constexpr inline uint32_t x_position(uint32_t num) { return (num & 0x3f) << 2; }
}
namespace list_pointer {
constexpr uint32_t empty = 1 << 31;
constexpr inline uint32_t object_list(uint32_t num) { return (num & 0xfffffc) << 0; }
}
}

167
dreamcast2/holly/holly.hpp Normal file
View File

@ -0,0 +1,167 @@
#pragma once
#include "reg.hpp"
namespace holly {
struct holly_reg {
reg32 ID; /* Device ID */
reg32 REVISION; /* Revision Number */
reg32 SOFTRESET; /* CORE & TA software reset */
reg8 _pad0[8];
reg32 STARTRENDER; /* Drawing start */
reg32 TEST_SELECT; /* Test (writing this register is prohibited) */
reg8 _pad1[4];
reg32 PARAM_BASE; /* Base address for ISP parameters */
reg8 _pad2[8];
reg32 REGION_BASE; /* Base address for Region Array */
reg32 SPAN_SORT_CFG; /* Span Sorter control */
reg8 _pad3[12];
reg32 VO_BORDER_COL; /* Border area color */
reg32 FB_R_CTRL; /* Frame buffer read control */
reg32 FB_W_CTRL; /* Frame buffer write control */
reg32 FB_W_LINESTRIDE; /* Frame buffer line stride */
reg32 FB_R_SOF1; /* Read start address for field - 1/strip - 1 */
reg32 FB_R_SOF2; /* Read start address for field - 2/strip - 2 */
reg8 _pad4[4];
reg32 FB_R_SIZE; /* Frame buffer XY size */
reg32 FB_W_SOF1; /* Write start address for field - 1/strip - 1 */
reg32 FB_W_SOF2; /* Write start address for field - 2/strip - 2 */
reg32 FB_X_CLIP; /* Pixel clip X coordinate */
reg32 FB_Y_CLIP; /* Pixel clip Y coordinate */
reg8 _pad5[4];
reg32 FPU_SHAD_SCALE; /* Intensity Volume mode */
reg32f FPU_CULL_VAL; /* Comparison value for culling */
reg32 FPU_PARAM_CFG; /* Parameter read control */
reg32 HALF_OFFSET; /* Pixel sampling control */
reg32f FPU_PERP_VAL; /* Comparison value for perpendicular polygons */
reg32f ISP_BACKGND_D; /* Background surface depth */
reg32 ISP_BACKGND_T; /* Background surface tag */
reg8 _pad6[8];
reg32 ISP_FEED_CFG; /* Translucent polygon sort mode */
reg8 _pad7[4];
reg32 SDRAM_REFRESH; /* Texture memory refresh counter */
reg32 SDRAM_ARB_CFG; /* Texture memory arbiter control */
reg32 SDRAM_CFG; /* Texture memory control */
reg8 _pad8[4];
reg32 FOG_COL_RAM; /* Color for Look Up table Fog */
reg32 FOG_COL_VERT; /* Color for vertex Fog */
reg32 FOG_DENSITY; /* Fog scale value */
reg32 FOG_CLAMP_MAX; /* Color clamping maximum value */
reg32 FOG_CLAMP_MIN; /* Color clamping minimum value */
reg32 SPG_TRIGGER_POS; /* External trigger signal HV counter value */
reg32 SPG_HBLANK_INT; /* H-blank interrupt control */
reg32 SPG_VBLANK_INT; /* V-blank interrupt control */
reg32 SPG_CONTROL; /* Sync pulse generator control */
reg32 SPG_HBLANK; /* H-blank control */
reg32 SPG_LOAD; /* HV counter load value */
reg32 SPG_VBLANK; /* V-blank control */
reg32 SPG_WIDTH; /* Sync width control */
reg32 TEXT_CONTROL; /* Texturing control */
reg32 VO_CONTROL; /* Video output control */
reg32 VO_STARTX; /* Video output start X position */
reg32 VO_STARTY; /* Video output start Y position */
reg32 SCALER_CTL; /* X & Y scaler control */
reg8 _pad9[16];
reg32 PAL_RAM_CTRL; /* Palette RAM control */
reg32 SPG_STATUS; /* Sync pulse generator status */
reg32 FB_BURSTCTRL; /* Frame buffer burst control */
reg32 FB_C_SOF; /* Current frame buffer start address */
reg32 Y_COEFF; /* Y scaling coefficent */
reg32 PT_ALPHA_REF; /* Alpha value for Punch Through polygon comparison */
reg8 _pad10[4];
reg32 TA_OL_BASE; /* Object List write start address */
reg32 TA_ISP_BASE; /* ISP/TSP Parameter write start address */
reg32 TA_OL_LIMIT; /* Object List write limit address */
reg32 TA_ISP_LIMIT; /* ISP/TSP Parameter limit address */
reg32 TA_NEXT_OPB; /* Start address for the Object Pointer Block */
reg32 TA_ITP_CURRENT; /* Starting address where the next ISP/TSP Parameters are stored */
reg32 TA_GLOB_TILE_CLIP; /* Global Tile Clip control */
reg32 TA_ALLOC_CTRL; /* Object list control */
reg32 TA_LIST_INIT; /* TA initialization */
reg32 TA_YUV_TEX_BASE; /* YUV422 texture write start address */
reg32 TA_YUV_TEX_CTRL; /* YUV converter control */
reg32 TA_YUV_TEX_CNT; /* YUV converter macro block counter value */
reg8 _pad11[12];
reg32 TA_LIST_CONT; /* TA continuation processing */
reg32 TA_NEXT_OPB_INIT; /* Additional OPB starting address */
reg8 _pad12[152];
reg32 FOG_TABLE[128]; /* Look-up table fog data */
reg8 _pad13[512];
reg32 TA_OL_POINTERS[600]; /* TA Object List Pointer data */
reg8 _pad14[160];
reg32 PALETTE_RAM[1024]; /* Palette RAM */
};
static_assert((offsetof (struct holly_reg, ID)) == 0x0);
static_assert((offsetof (struct holly_reg, REVISION)) == 0x4);
static_assert((offsetof (struct holly_reg, SOFTRESET)) == 0x8);
static_assert((offsetof (struct holly_reg, STARTRENDER)) == 0x14);
static_assert((offsetof (struct holly_reg, TEST_SELECT)) == 0x18);
static_assert((offsetof (struct holly_reg, PARAM_BASE)) == 0x20);
static_assert((offsetof (struct holly_reg, REGION_BASE)) == 0x2c);
static_assert((offsetof (struct holly_reg, SPAN_SORT_CFG)) == 0x30);
static_assert((offsetof (struct holly_reg, VO_BORDER_COL)) == 0x40);
static_assert((offsetof (struct holly_reg, FB_R_CTRL)) == 0x44);
static_assert((offsetof (struct holly_reg, FB_W_CTRL)) == 0x48);
static_assert((offsetof (struct holly_reg, FB_W_LINESTRIDE)) == 0x4c);
static_assert((offsetof (struct holly_reg, FB_R_SOF1)) == 0x50);
static_assert((offsetof (struct holly_reg, FB_R_SOF2)) == 0x54);
static_assert((offsetof (struct holly_reg, FB_R_SIZE)) == 0x5c);
static_assert((offsetof (struct holly_reg, FB_W_SOF1)) == 0x60);
static_assert((offsetof (struct holly_reg, FB_W_SOF2)) == 0x64);
static_assert((offsetof (struct holly_reg, FB_X_CLIP)) == 0x68);
static_assert((offsetof (struct holly_reg, FB_Y_CLIP)) == 0x6c);
static_assert((offsetof (struct holly_reg, FPU_SHAD_SCALE)) == 0x74);
static_assert((offsetof (struct holly_reg, FPU_CULL_VAL)) == 0x78);
static_assert((offsetof (struct holly_reg, FPU_PARAM_CFG)) == 0x7c);
static_assert((offsetof (struct holly_reg, HALF_OFFSET)) == 0x80);
static_assert((offsetof (struct holly_reg, FPU_PERP_VAL)) == 0x84);
static_assert((offsetof (struct holly_reg, ISP_BACKGND_D)) == 0x88);
static_assert((offsetof (struct holly_reg, ISP_BACKGND_T)) == 0x8c);
static_assert((offsetof (struct holly_reg, ISP_FEED_CFG)) == 0x98);
static_assert((offsetof (struct holly_reg, SDRAM_REFRESH)) == 0xa0);
static_assert((offsetof (struct holly_reg, SDRAM_ARB_CFG)) == 0xa4);
static_assert((offsetof (struct holly_reg, SDRAM_CFG)) == 0xa8);
static_assert((offsetof (struct holly_reg, FOG_COL_RAM)) == 0xb0);
static_assert((offsetof (struct holly_reg, FOG_COL_VERT)) == 0xb4);
static_assert((offsetof (struct holly_reg, FOG_DENSITY)) == 0xb8);
static_assert((offsetof (struct holly_reg, FOG_CLAMP_MAX)) == 0xbc);
static_assert((offsetof (struct holly_reg, FOG_CLAMP_MIN)) == 0xc0);
static_assert((offsetof (struct holly_reg, SPG_TRIGGER_POS)) == 0xc4);
static_assert((offsetof (struct holly_reg, SPG_HBLANK_INT)) == 0xc8);
static_assert((offsetof (struct holly_reg, SPG_VBLANK_INT)) == 0xcc);
static_assert((offsetof (struct holly_reg, SPG_CONTROL)) == 0xd0);
static_assert((offsetof (struct holly_reg, SPG_HBLANK)) == 0xd4);
static_assert((offsetof (struct holly_reg, SPG_LOAD)) == 0xd8);
static_assert((offsetof (struct holly_reg, SPG_VBLANK)) == 0xdc);
static_assert((offsetof (struct holly_reg, SPG_WIDTH)) == 0xe0);
static_assert((offsetof (struct holly_reg, TEXT_CONTROL)) == 0xe4);
static_assert((offsetof (struct holly_reg, VO_CONTROL)) == 0xe8);
static_assert((offsetof (struct holly_reg, VO_STARTX)) == 0xec);
static_assert((offsetof (struct holly_reg, VO_STARTY)) == 0xf0);
static_assert((offsetof (struct holly_reg, SCALER_CTL)) == 0xf4);
static_assert((offsetof (struct holly_reg, PAL_RAM_CTRL)) == 0x108);
static_assert((offsetof (struct holly_reg, SPG_STATUS)) == 0x10c);
static_assert((offsetof (struct holly_reg, FB_BURSTCTRL)) == 0x110);
static_assert((offsetof (struct holly_reg, FB_C_SOF)) == 0x114);
static_assert((offsetof (struct holly_reg, Y_COEFF)) == 0x118);
static_assert((offsetof (struct holly_reg, PT_ALPHA_REF)) == 0x11c);
static_assert((offsetof (struct holly_reg, TA_OL_BASE)) == 0x124);
static_assert((offsetof (struct holly_reg, TA_ISP_BASE)) == 0x128);
static_assert((offsetof (struct holly_reg, TA_OL_LIMIT)) == 0x12c);
static_assert((offsetof (struct holly_reg, TA_ISP_LIMIT)) == 0x130);
static_assert((offsetof (struct holly_reg, TA_NEXT_OPB)) == 0x134);
static_assert((offsetof (struct holly_reg, TA_ITP_CURRENT)) == 0x138);
static_assert((offsetof (struct holly_reg, TA_GLOB_TILE_CLIP)) == 0x13c);
static_assert((offsetof (struct holly_reg, TA_ALLOC_CTRL)) == 0x140);
static_assert((offsetof (struct holly_reg, TA_LIST_INIT)) == 0x144);
static_assert((offsetof (struct holly_reg, TA_YUV_TEX_BASE)) == 0x148);
static_assert((offsetof (struct holly_reg, TA_YUV_TEX_CTRL)) == 0x14c);
static_assert((offsetof (struct holly_reg, TA_YUV_TEX_CNT)) == 0x150);
static_assert((offsetof (struct holly_reg, TA_LIST_CONT)) == 0x160);
static_assert((offsetof (struct holly_reg, TA_NEXT_OPB_INIT)) == 0x164);
static_assert((offsetof (struct holly_reg, FOG_TABLE)) == 0x200);
static_assert((offsetof (struct holly_reg, TA_OL_POINTERS)) == 0x600);
static_assert((offsetof (struct holly_reg, PALETTE_RAM)) == 0x1000);
extern struct holly_reg holly __asm("holly");
}

View File

@ -0,0 +1,635 @@
#pragma once
#include <cstdint>
namespace holly {
namespace id {
constexpr inline uint32_t device_id(uint32_t reg) { return (reg >> 16) & 0xffff; }
constexpr inline uint32_t vendor_id(uint32_t reg) { return (reg >> 0) & 0xffff; }
}
namespace revision {
constexpr inline uint32_t chip_revision(uint32_t reg) { return (reg >> 0) & 0xffff; }
}
namespace softreset {
constexpr uint32_t sdram_if_soft_reset = 1 << 2;
constexpr uint32_t pipeline_soft_reset = 1 << 1;
constexpr uint32_t ta_soft_reset = 1 << 0;
}
namespace startrender {
constexpr uint32_t start_render = 1 << 0;
}
namespace test_select {
constexpr inline uint32_t diagdb_data(uint32_t reg) { return (reg >> 5) & 0x1f; }
constexpr inline uint32_t diagda_data(uint32_t reg) { return (reg >> 0) & 0x1f; }
}
namespace param_base {
constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xf00000) << 0; }
}
namespace region_base {
constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; }
}
namespace span_sort_cfg {
constexpr uint32_t cache_bypass = 1 << 16;
constexpr uint32_t offset_sort_enable = 1 << 8;
constexpr uint32_t span_sort_enable = 1 << 0;
}
namespace vo_border_col {
constexpr inline uint32_t chroma(uint32_t num) { return (num & 0x1) << 24; }
constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; }
constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t blue(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fb_r_ctrl {
namespace vclk_div {
constexpr uint32_t pclk_vclk_2 = 0 << 23;
constexpr uint32_t pclk_vclk_1 = 1 << 23;
constexpr uint32_t bit_mask = 0x1 << 23;
}
constexpr uint32_t fb_strip_buf_en = 1 << 22;
constexpr inline uint32_t fb_stripsize(uint32_t num) { return (num & 0x3e) << 16; }
constexpr inline uint32_t fb_chroma_threshold(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t fb_concat(uint32_t num) { return (num & 0x3) << 4; }
namespace fb_depth {
constexpr uint32_t xrgb0555 = 0 << 2;
constexpr uint32_t rgb565 = 1 << 2;
constexpr uint32_t rgb888 = 2 << 2;
constexpr uint32_t xrgb0888 = 3 << 2;
constexpr uint32_t bit_mask = 0x3 << 2;
}
constexpr uint32_t fb_line_double = 1 << 1;
constexpr uint32_t fb_enable = 1 << 0;
}
namespace fb_w_ctrl {
constexpr inline uint32_t fb_alpha_threshold(uint32_t num) { return (num & 0xff) << 16; }
constexpr inline uint32_t fb_kval(uint32_t num) { return (num & 0xff) << 8; }
constexpr uint32_t fb_dither = 1 << 3;
namespace fb_packmode {
constexpr uint32_t krgb0555 = 0 << 0;
constexpr uint32_t rgb565 = 1 << 0;
constexpr uint32_t argb4444 = 2 << 0;
constexpr uint32_t argb1555 = 3 << 0;
constexpr uint32_t rgb888 = 4 << 0;
constexpr uint32_t krgb0888 = 5 << 0;
constexpr uint32_t argb8888 = 6 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
namespace fb_w_linestride {
constexpr inline uint32_t fb_line_stride(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fb_r_sof1 {
constexpr inline uint32_t frame_buffer_read_address_frame_1(uint32_t num) { return (num & 0xfffffc) << 0; }
}
namespace fb_r_sof2 {
constexpr inline uint32_t frame_buffer_read_address_frame_2(uint32_t num) { return (num & 0xfffffc) << 0; }
}
namespace fb_r_size {
constexpr inline uint32_t fb_modulus(uint32_t num) { return (num & 0x3ff) << 20; }
constexpr inline uint32_t fb_y_size(uint32_t num) { return (num & 0x3ff) << 10; }
constexpr inline uint32_t fb_x_size(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace fb_w_sof1 {
constexpr inline uint32_t frame_buffer_write_address_frame_1(uint32_t num) { return (num & 0x1fffffc) << 0; }
}
namespace fb_w_sof2 {
constexpr inline uint32_t frame_buffer_write_address_frame_2(uint32_t num) { return (num & 0x1fffffc) << 0; }
}
namespace fb_x_clip {
constexpr inline uint32_t fb_x_clip_max(uint32_t num) { return (num & 0x7ff) << 16; }
constexpr inline uint32_t fb_x_clip_min(uint32_t num) { return (num & 0x7ff) << 0; }
}
namespace fb_y_clip {
constexpr inline uint32_t fb_y_clip_max(uint32_t num) { return (num & 0x3ff) << 16; }
constexpr inline uint32_t fb_y_clip_min(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace fpu_shad_scale {
namespace simple_shadow_enable {
constexpr uint32_t parameter_selection_volume_mode = 0 << 8;
constexpr uint32_t intensity_volume_mode = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
constexpr inline uint32_t scale_factor_for_shadows(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fpu_cull_val {
inline float culling_comparison_value(float num) { return num; }
}
namespace fpu_param_cfg {
namespace region_header_type {
constexpr uint32_t type_1 = 0 << 21;
constexpr uint32_t type_2 = 1 << 21;
constexpr uint32_t bit_mask = 0x1 << 21;
}
constexpr inline uint32_t tsp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 14; }
constexpr inline uint32_t isp_parameter_burst_threshold(uint32_t num) { return (num & 0x3f) << 8; }
constexpr inline uint32_t pointer_burst_size(uint32_t num) { return (num & 0xf) << 4; }
constexpr inline uint32_t pointer_first_burst_size(uint32_t num) { return (num & 0xf) << 0; }
}
namespace half_offset {
namespace tsp_texel_sampling_position {
constexpr uint32_t top_left = 1 << 2;
constexpr uint32_t center = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace tsp_pixel_sampling_position {
constexpr uint32_t top_left = 1 << 1;
constexpr uint32_t center = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace fpu_pixel_sampling_position {
constexpr uint32_t top_left = 1 << 0;
constexpr uint32_t center = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace fpu_perp_val {
inline float perpendicular_triangle_compare(float num) { return num; }
}
namespace isp_backgnd_d {
inline float background_plane_depth(float num) { return num; }
}
namespace isp_backgnd_t {
constexpr uint32_t cache_bypass = 1 << 28;
constexpr uint32_t shadow = 1 << 27;
constexpr inline uint32_t skip(uint32_t num) { return (num & 0x7) << 24; }
constexpr inline uint32_t tag_address(uint32_t num) { return (num & 0x1fffff) << 3; }
constexpr inline uint32_t tag_offset(uint32_t num) { return (num & 0x7) << 0; }
}
namespace isp_feed_cfg {
constexpr inline uint32_t cache_size_for_translucency(uint32_t num) { return (num & 0x3ff) << 14; }
constexpr inline uint32_t punch_through_chunk_size(uint32_t num) { return (num & 0x3ff) << 4; }
constexpr uint32_t discard_mode = 1 << 3;
constexpr uint32_t pre_sort_mode = 1 << 0;
}
namespace sdram_refresh {
constexpr inline uint32_t refresh_counter_value(uint32_t num) { return (num & 0xff) << 0; }
}
namespace sdram_arb_cfg {
namespace override_value {
constexpr uint32_t priority_only = 0x0 << 18;
constexpr uint32_t rendered_data = 0x1 << 18;
constexpr uint32_t texture_vq_index = 0x2 << 18;
constexpr uint32_t texture_normal_data_and_vq_codebook = 0x3 << 18;
constexpr uint32_t tile_accelerator_isp_tsp_data = 0x4 << 18;
constexpr uint32_t tile_accelerator_pointers = 0x5 << 18;
constexpr uint32_t sh4 = 0x6 << 18;
constexpr uint32_t tsp_parameters = 0x7 << 18;
constexpr uint32_t tsp_region_data = 0x8 << 18;
constexpr uint32_t isp_pointer_data = 0x9 << 18;
constexpr uint32_t isp_parameters = 0xa << 18;
constexpr uint32_t crt_controller = 0xb << 18;
constexpr uint32_t bit_mask = 0xf << 18;
}
namespace arbiter_priority_control {
constexpr uint32_t priority_arbitration_only = 0x0 << 16;
constexpr uint32_t override_value_field = 0x1 << 16;
constexpr uint32_t round_robin_counter = 0x2 << 16;
constexpr uint32_t bit_mask = 0x3 << 16;
}
constexpr inline uint32_t arbiter_crt_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t arbiter_page_break_latency_count_value(uint32_t num) { return (num & 0xff) << 0; }
}
namespace sdram_cfg {
constexpr inline uint32_t read_command_to_returned_data_delay(uint32_t num) { return (num & 0x7) << 26; }
constexpr inline uint32_t cas_latency_value(uint32_t num) { return (num & 0x7) << 23; }
constexpr inline uint32_t activate_to_activate_period(uint32_t num) { return (num & 0x3) << 21; }
constexpr inline uint32_t read_to_write_period(uint32_t num) { return (num & 0x7) << 18; }
constexpr inline uint32_t refresh_to_activate_period(uint32_t num) { return (num & 0xf) << 14; }
constexpr inline uint32_t pre_charge_to_activate_period(uint32_t num) { return (num & 0x3) << 10; }
constexpr inline uint32_t activate_to_pre_charge_period(uint32_t num) { return (num & 0xf) << 6; }
constexpr inline uint32_t activate_to_read_write_command_period(uint32_t num) { return (num & 0x3) << 4; }
constexpr inline uint32_t write_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 2; }
constexpr inline uint32_t read_to_pre_charge_period(uint32_t num) { return (num & 0x3) << 0; }
}
namespace fog_col_ram {
constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; }
constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t blue(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fog_col_vert {
constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; }
constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t blue(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fog_density {
constexpr inline uint32_t fog_scale_mantissa(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t fog_scale_exponent(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fog_clamp_max {
constexpr inline uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; }
constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; }
constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t blue(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fog_clamp_min {
constexpr inline uint32_t alpha(uint32_t num) { return (num & 0xff) << 24; }
constexpr inline uint32_t red(uint32_t num) { return (num & 0xff) << 16; }
constexpr inline uint32_t green(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t blue(uint32_t num) { return (num & 0xff) << 0; }
}
namespace spg_trigger_pos {
constexpr inline uint32_t trigger_v_count(uint32_t reg) { return (reg >> 16) & 0x3ff; }
constexpr inline uint32_t trigger_h_count(uint32_t reg) { return (reg >> 0) & 0x3ff; }
}
namespace spg_hblank_int {
constexpr inline uint32_t hblank_in_interrupt(uint32_t reg) { return (reg >> 16) & 0x3ff; }
namespace hblank_int_mode {
constexpr uint32_t output_equal_line_comp_val = 0x0 << 12;
constexpr uint32_t output_every_line_comp_val = 0x1 << 12;
constexpr uint32_t output_every_line = 0x2 << 12;
constexpr uint32_t bit_mask = 0x3 << 12;
}
constexpr inline uint32_t line_comp_val(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace spg_vblank_int {
constexpr inline uint32_t vblank_out_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 16; }
constexpr inline uint32_t vblank_in_interrupt_line_number(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace spg_control {
namespace csync_on_h {
constexpr uint32_t hsync = 0 << 9;
constexpr uint32_t csync = 1 << 9;
constexpr uint32_t bit_mask = 0x1 << 9;
}
namespace sync_direction {
constexpr uint32_t input = 0 << 8;
constexpr uint32_t output = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
constexpr uint32_t pal = 1 << 7;
constexpr uint32_t ntsc = 1 << 6;
constexpr uint32_t force_field2 = 1 << 5;
constexpr uint32_t interlace = 1 << 4;
constexpr uint32_t spg_lock = 1 << 3;
namespace mcsync_pol {
constexpr uint32_t active_low = 0 << 2;
constexpr uint32_t active_high = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace mvsync_pol {
constexpr uint32_t active_low = 0 << 1;
constexpr uint32_t active_high = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace mhsync_pol {
constexpr uint32_t active_low = 0 << 0;
constexpr uint32_t active_high = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace spg_hblank {
constexpr inline uint32_t hbend(uint32_t num) { return (num & 0x3ff) << 16; }
constexpr inline uint32_t hbstart(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace spg_load {
constexpr inline uint32_t vcount(uint32_t num) { return (num & 0x3ff) << 16; }
constexpr inline uint32_t hcount(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace spg_vblank {
constexpr inline uint32_t vbend(uint32_t num) { return (num & 0x3ff) << 16; }
constexpr inline uint32_t vbstart(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace spg_width {
constexpr inline uint32_t eqwidth(uint32_t num) { return (num & 0x3ff) << 22; }
constexpr inline uint32_t bpwidth(uint32_t num) { return (num & 0x3ff) << 12; }
constexpr inline uint32_t vswidth(uint32_t num) { return (num & 0xf) << 8; }
constexpr inline uint32_t hswidth(uint32_t num) { return (num & 0x7f) << 0; }
}
namespace text_control {
namespace code_book_endian {
constexpr uint32_t little_endian = 0 << 17;
constexpr uint32_t big_endian = 1 << 17;
constexpr uint32_t bit_mask = 0x1 << 17;
}
namespace index_endian {
constexpr uint32_t little_endian = 0 << 16;
constexpr uint32_t big_endian = 1 << 16;
constexpr uint32_t bit_mask = 0x1 << 16;
}
constexpr inline uint32_t bank_bit(uint32_t num) { return (num & 0x1f) << 8; }
constexpr inline uint32_t stride(uint32_t num) { return (num & 0x1f) << 0; }
}
namespace vo_control {
constexpr uint32_t pclk_delay_reset = 1 << 21;
constexpr inline uint32_t pclk_delay(uint32_t num) { return (num & 0x1f) << 16; }
constexpr uint32_t pixel_double = 1 << 8;
namespace field_mode {
constexpr uint32_t use_field_flag_from_spg = 0x0 << 4;
constexpr uint32_t use_inverse_of_field_flag_from_spg = 0x1 << 4;
constexpr uint32_t field_1_fixed = 0x2 << 4;
constexpr uint32_t field_2_fixed = 0x3 << 4;
constexpr uint32_t field_1_when_the_active_edges_of_hsync_and_vsync_match = 0x4 << 4;
constexpr uint32_t field_2_when_the_active_edges_of_hsync_and_vsync_match = 0x5 << 4;
constexpr uint32_t field_1_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x6 << 4;
constexpr uint32_t field_2_when_hsync_becomes_active_in_the_middle_of_the_vsync_active_edge = 0x7 << 4;
constexpr uint32_t inverted_at_the_active_edge_of_vsync = 0x8 << 4;
constexpr uint32_t bit_mask = 0xf << 4;
}
constexpr uint32_t blank_video = 1 << 3;
namespace blank_pol {
constexpr uint32_t active_low = 0 << 2;
constexpr uint32_t active_high = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace vsync_pol {
constexpr uint32_t active_low = 0 << 1;
constexpr uint32_t active_high = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace hsync_pol {
constexpr uint32_t active_low = 0 << 0;
constexpr uint32_t active_high = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace vo_startx {
constexpr inline uint32_t horizontal_start_position(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace vo_starty {
constexpr inline uint32_t vertical_start_position_on_field_2(uint32_t num) { return (num & 0x3ff) << 16; }
constexpr inline uint32_t vertical_start_position_on_field_1(uint32_t num) { return (num & 0x3ff) << 0; }
}
namespace scaler_ctl {
namespace field_select {
constexpr uint32_t field_1 = 0 << 18;
constexpr uint32_t field_2 = 1 << 18;
constexpr uint32_t bit_mask = 0x1 << 18;
}
constexpr uint32_t interlace = 1 << 17;
constexpr uint32_t horizontal_scaling_enable = 1 << 16;
constexpr inline uint32_t vertical_scale_factor(uint32_t num) { return (num & 0xffff) << 0; }
}
namespace pal_ram_ctrl {
namespace pixel_format {
constexpr uint32_t argb1555 = 0 << 0;
constexpr uint32_t rgb565 = 1 << 0;
constexpr uint32_t argb4444 = 2 << 0;
constexpr uint32_t argb8888 = 3 << 0;
constexpr uint32_t bit_mask = 0x3 << 0;
}
}
namespace spg_status {
constexpr inline uint32_t vsync(uint32_t reg) { return (reg >> 13) & 0x1; }
constexpr inline uint32_t hsync(uint32_t reg) { return (reg >> 12) & 0x1; }
constexpr inline uint32_t blank(uint32_t reg) { return (reg >> 11) & 0x1; }
constexpr inline uint32_t fieldnum(uint32_t reg) { return (reg >> 10) & 0x1; }
constexpr inline uint32_t scanline(uint32_t reg) { return (reg >> 0) & 0x3ff; }
}
namespace fb_burstctrl {
constexpr inline uint32_t wr_burst(uint32_t num) { return (num & 0xf) << 16; }
constexpr inline uint32_t vid_lat(uint32_t num) { return (num & 0x7f) << 8; }
constexpr inline uint32_t vid_burst(uint32_t num) { return (num & 0x3f) << 0; }
}
namespace fb_c_sof {
constexpr inline uint32_t frame_buffer_current_read_address(uint32_t reg) { return (reg >> 0) & 0xffffff; }
}
namespace y_coeff {
constexpr inline uint32_t coefficient_1(uint32_t num) { return (num & 0xff) << 8; }
constexpr inline uint32_t coefficient_0_2(uint32_t num) { return (num & 0xff) << 0; }
}
namespace pt_alpha_ref {
constexpr inline uint32_t alpha_reference_for_punch_through(uint32_t num) { return (num & 0xff) << 0; }
}
namespace fog_table {
constexpr inline uint32_t fog_table_data(uint32_t num) { return (num & 0xffff) << 0; }
}
namespace palette_ram {
constexpr inline uint32_t palette_data(uint32_t num) { return (num & 0xffffffff) << 0; }
}
namespace ta_ol_base {
constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xffffe0) << 0; }
}
namespace ta_isp_base {
constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xfffffc) << 0; }
}
namespace ta_ol_limit {
constexpr inline uint32_t limit_address(uint32_t num) { return (num & 0xffffe0) << 0; }
}
namespace ta_isp_limit {
constexpr inline uint32_t limit_address(uint32_t num) { return (num & 0xfffffc) << 0; }
}
namespace ta_next_opb {
constexpr inline uint32_t address(uint32_t num) { return (num & 0xffffe0) << 0; }
}
namespace ta_itp_current {
constexpr inline uint32_t address(uint32_t reg) { return (reg >> 0) & 0xffffff; }
}
namespace ta_glob_tile_clip {
constexpr inline uint32_t tile_y_num(uint32_t num) { return (num & 0xf) << 16; }
constexpr inline uint32_t tile_x_num(uint32_t num) { return (num & 0x3f) << 0; }
}
namespace ta_alloc_ctrl {
namespace opb_mode {
constexpr uint32_t increasing_addresses = 0 << 20;
constexpr uint32_t decreasing_addresses = 1 << 20;
constexpr uint32_t bit_mask = 0x1 << 20;
}
namespace pt_opb {
constexpr uint32_t no_list = 0 << 16;
constexpr uint32_t _8x4byte = 1 << 16;
constexpr uint32_t _16x4byte = 2 << 16;
constexpr uint32_t _32x4byte = 3 << 16;
constexpr uint32_t bit_mask = 0x3 << 16;
}
namespace tm_opb {
constexpr uint32_t no_list = 0 << 12;
constexpr uint32_t _8x4byte = 1 << 12;
constexpr uint32_t _16x4byte = 2 << 12;
constexpr uint32_t _32x4byte = 3 << 12;
constexpr uint32_t bit_mask = 0x3 << 12;
}
namespace t_opb {
constexpr uint32_t no_list = 0 << 8;
constexpr uint32_t _8x4byte = 1 << 8;
constexpr uint32_t _16x4byte = 2 << 8;
constexpr uint32_t _32x4byte = 3 << 8;
constexpr uint32_t bit_mask = 0x3 << 8;
}
namespace om_opb {
constexpr uint32_t no_list = 0 << 4;
constexpr uint32_t _8x4byte = 1 << 4;
constexpr uint32_t _16x4byte = 2 << 4;
constexpr uint32_t _32x4byte = 3 << 4;
constexpr uint32_t bit_mask = 0x3 << 4;
}
namespace o_opb {
constexpr uint32_t no_list = 0 << 0;
constexpr uint32_t _8x4byte = 1 << 0;
constexpr uint32_t _16x4byte = 2 << 0;
constexpr uint32_t _32x4byte = 3 << 0;
constexpr uint32_t bit_mask = 0x3 << 0;
}
}
namespace ta_list_init {
constexpr uint32_t list_init = 1 << 31;
}
namespace ta_yuv_tex_base {
constexpr inline uint32_t base_address(uint32_t num) { return (num & 0xfffff8) << 0; }
}
namespace ta_yuv_tex_ctrl {
namespace yuv_form {
constexpr uint32_t yuv420 = 0 << 24;
constexpr uint32_t yuv422 = 1 << 24;
constexpr uint32_t bit_mask = 0x1 << 24;
}
namespace yuv_tex {
constexpr uint32_t one_texture = 0 << 16;
constexpr uint32_t multiple_textures = 1 << 16;
constexpr uint32_t bit_mask = 0x1 << 16;
}
constexpr inline uint32_t yuv_v_size(uint32_t num) { return (num & 0x3f) << 8; }
constexpr inline uint32_t yuv_u_size(uint32_t num) { return (num & 0x3f) << 0; }
}
namespace ta_yuv_tex_cnt {
constexpr inline uint32_t yuv_num(uint32_t reg) { return (reg >> 0) & 0x1fff; }
}
namespace ta_list_cont {
constexpr uint32_t list_cont = 1 << 31;
}
namespace ta_next_opb_init {
constexpr inline uint32_t address(uint32_t num) { return (num & 0xffffe0) << 0; }
}
namespace ta_ol_pointers {
constexpr inline uint32_t entry(uint32_t reg) { return (reg >> 31) & 0x1; }
constexpr inline uint32_t sprite(uint32_t reg) { return (reg >> 30) & 0x1; }
constexpr inline uint32_t triangle(uint32_t reg) { return (reg >> 29) & 0x1; }
constexpr inline uint32_t number_of_triangles_quads(uint32_t reg) { return (reg >> 25) & 0xf; }
constexpr inline uint32_t shadow(uint32_t reg) { return (reg >> 24) & 0x1; }
constexpr inline uint32_t pointer_address(uint32_t reg) { return (reg >> 2) & 0x3fffff; }
constexpr inline uint32_t skip(uint32_t reg) { return (reg >> 0) & 0x3; }
}
}

View File

@ -0,0 +1,240 @@
#pragma once
#include <cstdint>
#include <cstddef>
namespace holly::ta::global_parameter {
struct end_of_list {
uint32_t parameter_control_word;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t _res3;
uint32_t _res4;
uint32_t _res5;
uint32_t _res6;
};
static_assert((sizeof (end_of_list)) == 32);
static_assert((offsetof (struct end_of_list, parameter_control_word)) == 0x00);
static_assert((offsetof (struct end_of_list, _res0)) == 0x04);
static_assert((offsetof (struct end_of_list, _res1)) == 0x08);
static_assert((offsetof (struct end_of_list, _res2)) == 0x0c);
static_assert((offsetof (struct end_of_list, _res3)) == 0x10);
static_assert((offsetof (struct end_of_list, _res4)) == 0x14);
static_assert((offsetof (struct end_of_list, _res5)) == 0x18);
static_assert((offsetof (struct end_of_list, _res6)) == 0x1c);
struct user_tile_clip {
uint32_t parameter_control_word;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t user_clip_x_min;
uint32_t user_clip_y_min;
uint32_t user_clip_x_max;
uint32_t user_clip_y_max;
};
static_assert((sizeof (user_tile_clip)) == 32);
static_assert((offsetof (struct user_tile_clip, parameter_control_word)) == 0x00);
static_assert((offsetof (struct user_tile_clip, _res0)) == 0x04);
static_assert((offsetof (struct user_tile_clip, _res1)) == 0x08);
static_assert((offsetof (struct user_tile_clip, _res2)) == 0x0c);
static_assert((offsetof (struct user_tile_clip, user_clip_x_min)) == 0x10);
static_assert((offsetof (struct user_tile_clip, user_clip_y_min)) == 0x14);
static_assert((offsetof (struct user_tile_clip, user_clip_x_max)) == 0x18);
static_assert((offsetof (struct user_tile_clip, user_clip_y_max)) == 0x1c);
struct object_list_set {
uint32_t parameter_control_word;
uint32_t object_pointer;
uint32_t _res0;
uint32_t _res1;
uint32_t bounding_box_x_min;
uint32_t bounding_box_y_min;
uint32_t bounding_box_x_max;
uint32_t bounding_box_y_max;
};
static_assert((sizeof (object_list_set)) == 32);
static_assert((offsetof (struct object_list_set, parameter_control_word)) == 0x00);
static_assert((offsetof (struct object_list_set, object_pointer)) == 0x04);
static_assert((offsetof (struct object_list_set, _res0)) == 0x08);
static_assert((offsetof (struct object_list_set, _res1)) == 0x0c);
static_assert((offsetof (struct object_list_set, bounding_box_x_min)) == 0x10);
static_assert((offsetof (struct object_list_set, bounding_box_y_min)) == 0x14);
static_assert((offsetof (struct object_list_set, bounding_box_x_max)) == 0x18);
static_assert((offsetof (struct object_list_set, bounding_box_y_max)) == 0x1c);
struct polygon_type_0 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
uint32_t _res0;
uint32_t _res1;
uint32_t data_size_for_sort_dma;
uint32_t next_address_for_sort_dma;
};
static_assert((sizeof (polygon_type_0)) == 32);
static_assert((offsetof (struct polygon_type_0, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_0, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct polygon_type_0, tsp_instruction_word)) == 0x08);
static_assert((offsetof (struct polygon_type_0, texture_control_word)) == 0x0c);
static_assert((offsetof (struct polygon_type_0, _res0)) == 0x10);
static_assert((offsetof (struct polygon_type_0, _res1)) == 0x14);
static_assert((offsetof (struct polygon_type_0, data_size_for_sort_dma)) == 0x18);
static_assert((offsetof (struct polygon_type_0, next_address_for_sort_dma)) == 0x1c);
struct polygon_type_1 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
float face_color_alpha;
float face_color_r;
float face_color_g;
float face_color_b;
};
static_assert((sizeof (polygon_type_1)) == 32);
static_assert((offsetof (struct polygon_type_1, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_1, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct polygon_type_1, tsp_instruction_word)) == 0x08);
static_assert((offsetof (struct polygon_type_1, texture_control_word)) == 0x0c);
static_assert((offsetof (struct polygon_type_1, face_color_alpha)) == 0x10);
static_assert((offsetof (struct polygon_type_1, face_color_r)) == 0x14);
static_assert((offsetof (struct polygon_type_1, face_color_g)) == 0x18);
static_assert((offsetof (struct polygon_type_1, face_color_b)) == 0x1c);
struct polygon_type_2 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
uint32_t _res0;
uint32_t _res1;
uint32_t data_size_for_sort_dma;
uint32_t next_address_for_sort_dma;
float face_color_alpha;
float face_color_r;
float face_color_g;
float face_color_b;
float face_offset_color_alpha;
float face_offset_color_r;
float face_offset_color_g;
float face_offset_color_b;
};
static_assert((sizeof (polygon_type_2)) == 64);
static_assert((offsetof (struct polygon_type_2, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_2, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct polygon_type_2, tsp_instruction_word)) == 0x08);
static_assert((offsetof (struct polygon_type_2, texture_control_word)) == 0x0c);
static_assert((offsetof (struct polygon_type_2, _res0)) == 0x10);
static_assert((offsetof (struct polygon_type_2, _res1)) == 0x14);
static_assert((offsetof (struct polygon_type_2, data_size_for_sort_dma)) == 0x18);
static_assert((offsetof (struct polygon_type_2, next_address_for_sort_dma)) == 0x1c);
static_assert((offsetof (struct polygon_type_2, face_color_alpha)) == 0x20);
static_assert((offsetof (struct polygon_type_2, face_color_r)) == 0x24);
static_assert((offsetof (struct polygon_type_2, face_color_g)) == 0x28);
static_assert((offsetof (struct polygon_type_2, face_color_b)) == 0x2c);
static_assert((offsetof (struct polygon_type_2, face_offset_color_alpha)) == 0x30);
static_assert((offsetof (struct polygon_type_2, face_offset_color_r)) == 0x34);
static_assert((offsetof (struct polygon_type_2, face_offset_color_g)) == 0x38);
static_assert((offsetof (struct polygon_type_2, face_offset_color_b)) == 0x3c);
struct polygon_type_3 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word_0;
uint32_t texture_control_word_0;
uint32_t tsp_instruction_word_1;
uint32_t texture_control_word_1;
uint32_t data_size_for_sort_dma;
uint32_t next_address_for_sort_dma;
};
static_assert((sizeof (polygon_type_3)) == 32);
static_assert((offsetof (struct polygon_type_3, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_3, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct polygon_type_3, tsp_instruction_word_0)) == 0x08);
static_assert((offsetof (struct polygon_type_3, texture_control_word_0)) == 0x0c);
static_assert((offsetof (struct polygon_type_3, tsp_instruction_word_1)) == 0x10);
static_assert((offsetof (struct polygon_type_3, texture_control_word_1)) == 0x14);
static_assert((offsetof (struct polygon_type_3, data_size_for_sort_dma)) == 0x18);
static_assert((offsetof (struct polygon_type_3, next_address_for_sort_dma)) == 0x1c);
struct polygon_type_4 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word_0;
uint32_t texture_control_word_0;
uint32_t tsp_instruction_word_1;
uint32_t texture_control_word_1;
uint32_t data_size_for_sort_dma;
uint32_t next_address_for_sort_dma;
float face_color_alpha_0;
float face_color_r_0;
float face_color_g_0;
float face_color_b_0;
float face_color_alpha_1;
float face_color_r_1;
float face_color_g_1;
float face_color_b_1;
};
static_assert((sizeof (polygon_type_4)) == 64);
static_assert((offsetof (struct polygon_type_4, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_4, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct polygon_type_4, tsp_instruction_word_0)) == 0x08);
static_assert((offsetof (struct polygon_type_4, texture_control_word_0)) == 0x0c);
static_assert((offsetof (struct polygon_type_4, tsp_instruction_word_1)) == 0x10);
static_assert((offsetof (struct polygon_type_4, texture_control_word_1)) == 0x14);
static_assert((offsetof (struct polygon_type_4, data_size_for_sort_dma)) == 0x18);
static_assert((offsetof (struct polygon_type_4, next_address_for_sort_dma)) == 0x1c);
static_assert((offsetof (struct polygon_type_4, face_color_alpha_0)) == 0x20);
static_assert((offsetof (struct polygon_type_4, face_color_r_0)) == 0x24);
static_assert((offsetof (struct polygon_type_4, face_color_g_0)) == 0x28);
static_assert((offsetof (struct polygon_type_4, face_color_b_0)) == 0x2c);
static_assert((offsetof (struct polygon_type_4, face_color_alpha_1)) == 0x30);
static_assert((offsetof (struct polygon_type_4, face_color_r_1)) == 0x34);
static_assert((offsetof (struct polygon_type_4, face_color_g_1)) == 0x38);
static_assert((offsetof (struct polygon_type_4, face_color_b_1)) == 0x3c);
struct sprite {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
uint32_t base_color;
uint32_t offset_color;
uint32_t data_size_for_sort_dma;
uint32_t next_address_for_sort_dma;
};
static_assert((sizeof (sprite)) == 32);
static_assert((offsetof (struct sprite, parameter_control_word)) == 0x00);
static_assert((offsetof (struct sprite, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct sprite, tsp_instruction_word)) == 0x08);
static_assert((offsetof (struct sprite, texture_control_word)) == 0x0c);
static_assert((offsetof (struct sprite, base_color)) == 0x10);
static_assert((offsetof (struct sprite, offset_color)) == 0x14);
static_assert((offsetof (struct sprite, data_size_for_sort_dma)) == 0x18);
static_assert((offsetof (struct sprite, next_address_for_sort_dma)) == 0x1c);
struct modifier_volume {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t _res3;
uint32_t _res4;
uint32_t _res5;
};
static_assert((sizeof (modifier_volume)) == 32);
static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00);
static_assert((offsetof (struct modifier_volume, isp_tsp_instruction_word)) == 0x04);
static_assert((offsetof (struct modifier_volume, _res0)) == 0x08);
static_assert((offsetof (struct modifier_volume, _res1)) == 0x0c);
static_assert((offsetof (struct modifier_volume, _res2)) == 0x10);
static_assert((offsetof (struct modifier_volume, _res3)) == 0x14);
static_assert((offsetof (struct modifier_volume, _res4)) == 0x18);
static_assert((offsetof (struct modifier_volume, _res5)) == 0x1c);
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <cstdint>
namespace holly::ta::parameter {
namespace parameter_control_word {
namespace para_type {
constexpr uint32_t end_of_list = 0 << 29;
constexpr uint32_t user_tile_clip = 1 << 29;
constexpr uint32_t object_list_set = 2 << 29;
constexpr uint32_t polygon_or_modifier_volume = 4 << 29;
constexpr uint32_t sprite = 5 << 29;
constexpr uint32_t vertex_parameter = 7 << 29;
constexpr uint32_t bit_mask = 0x7 << 29;
}
constexpr uint32_t end_of_strip = 1 << 28;
namespace list_type {
constexpr uint32_t opaque = 0 << 24;
constexpr uint32_t opaque_modifier_volume = 1 << 24;
constexpr uint32_t translucent = 2 << 24;
constexpr uint32_t translucent_modifier_volume = 3 << 24;
constexpr uint32_t punch_through = 4 << 24;
constexpr uint32_t bit_mask = 0x7 << 24;
}
constexpr uint32_t group_en = 1 << 23;
namespace strip_len {
constexpr uint32_t _1_strip = 0 << 18;
constexpr uint32_t _2_strip = 1 << 18;
constexpr uint32_t _4_strip = 2 << 18;
constexpr uint32_t _6_strip = 3 << 18;
constexpr uint32_t bit_mask = 0x3 << 18;
}
namespace user_clip {
constexpr uint32_t disabled = 0 << 16;
constexpr uint32_t inside_enable = 2 << 16;
constexpr uint32_t outside_enable = 3 << 16;
constexpr uint32_t bit_mask = 0x3 << 16;
}
namespace polygon_volume {
constexpr uint32_t no_volume = 0b00 << 6;
constexpr uint32_t intensity_volume = 0b10 << 6;
constexpr uint32_t two_volumes = 0b11 << 6;
constexpr uint32_t bit_mask = 0x3 << 6;
}
namespace modifier_volume {
constexpr uint32_t last_in_volume = 0b01 << 6;
constexpr uint32_t bit_mask = 0x3 << 6;
}
namespace col_type {
constexpr uint32_t packed_color = 0 << 4;
constexpr uint32_t floating_color = 1 << 4;
constexpr uint32_t intensity_mode_1 = 2 << 4;
constexpr uint32_t intensity_mode_2 = 3 << 4;
constexpr uint32_t bit_mask = 0x3 << 4;
}
constexpr uint32_t texture = 1 << 3;
constexpr uint32_t offset = 1 << 2;
constexpr uint32_t gouraud = 1 << 1;
constexpr uint32_t _16bit_uv = 1 << 0;
}
}

View File

@ -0,0 +1,512 @@
#pragma once
#include <cstdint>
#include <cstddef>
namespace holly::ta::vertex_parameter {
struct polygon_type_0 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t _res0;
uint32_t _res1;
uint32_t base_color;
uint32_t _res2;
};
static_assert((sizeof (polygon_type_0)) == 32);
static_assert((offsetof (struct polygon_type_0, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_0, x)) == 0x04);
static_assert((offsetof (struct polygon_type_0, y)) == 0x08);
static_assert((offsetof (struct polygon_type_0, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_0, _res0)) == 0x10);
static_assert((offsetof (struct polygon_type_0, _res1)) == 0x14);
static_assert((offsetof (struct polygon_type_0, base_color)) == 0x18);
static_assert((offsetof (struct polygon_type_0, _res2)) == 0x1c);
struct polygon_type_1 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float base_color_alpha;
float base_color_r;
float base_color_g;
float base_color_b;
};
static_assert((sizeof (polygon_type_1)) == 32);
static_assert((offsetof (struct polygon_type_1, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_1, x)) == 0x04);
static_assert((offsetof (struct polygon_type_1, y)) == 0x08);
static_assert((offsetof (struct polygon_type_1, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_1, base_color_alpha)) == 0x10);
static_assert((offsetof (struct polygon_type_1, base_color_r)) == 0x14);
static_assert((offsetof (struct polygon_type_1, base_color_g)) == 0x18);
static_assert((offsetof (struct polygon_type_1, base_color_b)) == 0x1c);
struct polygon_type_2 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t _res0;
uint32_t _res1;
float base_intensity;
uint32_t _res2;
};
static_assert((sizeof (polygon_type_2)) == 32);
static_assert((offsetof (struct polygon_type_2, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_2, x)) == 0x04);
static_assert((offsetof (struct polygon_type_2, y)) == 0x08);
static_assert((offsetof (struct polygon_type_2, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_2, _res0)) == 0x10);
static_assert((offsetof (struct polygon_type_2, _res1)) == 0x14);
static_assert((offsetof (struct polygon_type_2, base_intensity)) == 0x18);
static_assert((offsetof (struct polygon_type_2, _res2)) == 0x1c);
struct polygon_type_3 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float u;
float v;
uint32_t base_color;
uint32_t offset_color;
};
static_assert((sizeof (polygon_type_3)) == 32);
static_assert((offsetof (struct polygon_type_3, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_3, x)) == 0x04);
static_assert((offsetof (struct polygon_type_3, y)) == 0x08);
static_assert((offsetof (struct polygon_type_3, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_3, u)) == 0x10);
static_assert((offsetof (struct polygon_type_3, v)) == 0x14);
static_assert((offsetof (struct polygon_type_3, base_color)) == 0x18);
static_assert((offsetof (struct polygon_type_3, offset_color)) == 0x1c);
struct polygon_type_4 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t u_v;
uint32_t _res0;
uint32_t base_color;
uint32_t offset_color;
};
static_assert((sizeof (polygon_type_4)) == 32);
static_assert((offsetof (struct polygon_type_4, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_4, x)) == 0x04);
static_assert((offsetof (struct polygon_type_4, y)) == 0x08);
static_assert((offsetof (struct polygon_type_4, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_4, u_v)) == 0x10);
static_assert((offsetof (struct polygon_type_4, _res0)) == 0x14);
static_assert((offsetof (struct polygon_type_4, base_color)) == 0x18);
static_assert((offsetof (struct polygon_type_4, offset_color)) == 0x1c);
struct polygon_type_5 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float u;
float v;
uint32_t _res0;
uint32_t _res1;
float base_color_alpha;
float base_color_r;
float base_color_g;
float base_color_b;
float offset_color_alpha;
float offset_color_r;
float offset_color_g;
float offset_color_b;
};
static_assert((sizeof (polygon_type_5)) == 64);
static_assert((offsetof (struct polygon_type_5, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_5, x)) == 0x04);
static_assert((offsetof (struct polygon_type_5, y)) == 0x08);
static_assert((offsetof (struct polygon_type_5, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_5, u)) == 0x10);
static_assert((offsetof (struct polygon_type_5, v)) == 0x14);
static_assert((offsetof (struct polygon_type_5, _res0)) == 0x18);
static_assert((offsetof (struct polygon_type_5, _res1)) == 0x1c);
static_assert((offsetof (struct polygon_type_5, base_color_alpha)) == 0x20);
static_assert((offsetof (struct polygon_type_5, base_color_r)) == 0x24);
static_assert((offsetof (struct polygon_type_5, base_color_g)) == 0x28);
static_assert((offsetof (struct polygon_type_5, base_color_b)) == 0x2c);
static_assert((offsetof (struct polygon_type_5, offset_color_alpha)) == 0x30);
static_assert((offsetof (struct polygon_type_5, offset_color_r)) == 0x34);
static_assert((offsetof (struct polygon_type_5, offset_color_g)) == 0x38);
static_assert((offsetof (struct polygon_type_5, offset_color_b)) == 0x3c);
struct polygon_type_6 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t u_v;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
float base_color_alpha;
float base_color_r;
float base_color_g;
float base_color_b;
float offset_color_alpha;
float offset_color_r;
float offset_color_g;
float offset_color_b;
};
static_assert((sizeof (polygon_type_6)) == 64);
static_assert((offsetof (struct polygon_type_6, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_6, x)) == 0x04);
static_assert((offsetof (struct polygon_type_6, y)) == 0x08);
static_assert((offsetof (struct polygon_type_6, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_6, u_v)) == 0x10);
static_assert((offsetof (struct polygon_type_6, _res0)) == 0x14);
static_assert((offsetof (struct polygon_type_6, _res1)) == 0x18);
static_assert((offsetof (struct polygon_type_6, _res2)) == 0x1c);
static_assert((offsetof (struct polygon_type_6, base_color_alpha)) == 0x20);
static_assert((offsetof (struct polygon_type_6, base_color_r)) == 0x24);
static_assert((offsetof (struct polygon_type_6, base_color_g)) == 0x28);
static_assert((offsetof (struct polygon_type_6, base_color_b)) == 0x2c);
static_assert((offsetof (struct polygon_type_6, offset_color_alpha)) == 0x30);
static_assert((offsetof (struct polygon_type_6, offset_color_r)) == 0x34);
static_assert((offsetof (struct polygon_type_6, offset_color_g)) == 0x38);
static_assert((offsetof (struct polygon_type_6, offset_color_b)) == 0x3c);
struct polygon_type_7 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float u;
float v;
float base_intensity;
float offset_intensity;
};
static_assert((sizeof (polygon_type_7)) == 32);
static_assert((offsetof (struct polygon_type_7, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_7, x)) == 0x04);
static_assert((offsetof (struct polygon_type_7, y)) == 0x08);
static_assert((offsetof (struct polygon_type_7, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_7, u)) == 0x10);
static_assert((offsetof (struct polygon_type_7, v)) == 0x14);
static_assert((offsetof (struct polygon_type_7, base_intensity)) == 0x18);
static_assert((offsetof (struct polygon_type_7, offset_intensity)) == 0x1c);
struct polygon_type_8 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t u_v;
uint32_t _res0;
float base_intensity;
float offset_intensity;
};
static_assert((sizeof (polygon_type_8)) == 32);
static_assert((offsetof (struct polygon_type_8, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_8, x)) == 0x04);
static_assert((offsetof (struct polygon_type_8, y)) == 0x08);
static_assert((offsetof (struct polygon_type_8, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_8, u_v)) == 0x10);
static_assert((offsetof (struct polygon_type_8, _res0)) == 0x14);
static_assert((offsetof (struct polygon_type_8, base_intensity)) == 0x18);
static_assert((offsetof (struct polygon_type_8, offset_intensity)) == 0x1c);
struct polygon_type_9 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t base_color_0;
uint32_t base_color_1;
uint32_t _res0;
uint32_t _res1;
};
static_assert((sizeof (polygon_type_9)) == 32);
static_assert((offsetof (struct polygon_type_9, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_9, x)) == 0x04);
static_assert((offsetof (struct polygon_type_9, y)) == 0x08);
static_assert((offsetof (struct polygon_type_9, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_9, base_color_0)) == 0x10);
static_assert((offsetof (struct polygon_type_9, base_color_1)) == 0x14);
static_assert((offsetof (struct polygon_type_9, _res0)) == 0x18);
static_assert((offsetof (struct polygon_type_9, _res1)) == 0x1c);
struct polygon_type_10 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t base_intensity_0;
uint32_t base_intensity_1;
uint32_t _res0;
uint32_t _res1;
};
static_assert((sizeof (polygon_type_10)) == 32);
static_assert((offsetof (struct polygon_type_10, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_10, x)) == 0x04);
static_assert((offsetof (struct polygon_type_10, y)) == 0x08);
static_assert((offsetof (struct polygon_type_10, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_10, base_intensity_0)) == 0x10);
static_assert((offsetof (struct polygon_type_10, base_intensity_1)) == 0x14);
static_assert((offsetof (struct polygon_type_10, _res0)) == 0x18);
static_assert((offsetof (struct polygon_type_10, _res1)) == 0x1c);
struct polygon_type_11 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float u_0;
float v_0;
uint32_t base_color_0;
uint32_t offset_color_0;
float u_1;
float v_1;
uint32_t base_color_1;
uint32_t offset_color_1;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t _res3;
};
static_assert((sizeof (polygon_type_11)) == 64);
static_assert((offsetof (struct polygon_type_11, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_11, x)) == 0x04);
static_assert((offsetof (struct polygon_type_11, y)) == 0x08);
static_assert((offsetof (struct polygon_type_11, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_11, u_0)) == 0x10);
static_assert((offsetof (struct polygon_type_11, v_0)) == 0x14);
static_assert((offsetof (struct polygon_type_11, base_color_0)) == 0x18);
static_assert((offsetof (struct polygon_type_11, offset_color_0)) == 0x1c);
static_assert((offsetof (struct polygon_type_11, u_1)) == 0x20);
static_assert((offsetof (struct polygon_type_11, v_1)) == 0x24);
static_assert((offsetof (struct polygon_type_11, base_color_1)) == 0x28);
static_assert((offsetof (struct polygon_type_11, offset_color_1)) == 0x2c);
static_assert((offsetof (struct polygon_type_11, _res0)) == 0x30);
static_assert((offsetof (struct polygon_type_11, _res1)) == 0x34);
static_assert((offsetof (struct polygon_type_11, _res2)) == 0x38);
static_assert((offsetof (struct polygon_type_11, _res3)) == 0x3c);
struct polygon_type_12 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t u_v_0;
uint32_t _res0;
uint32_t base_color_0;
uint32_t offset_color_0;
uint32_t u_v_1;
uint32_t _res1;
uint32_t base_color_1;
uint32_t offset_color_1;
uint32_t _res2;
uint32_t _res3;
uint32_t _res4;
uint32_t _res5;
};
static_assert((sizeof (polygon_type_12)) == 64);
static_assert((offsetof (struct polygon_type_12, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_12, x)) == 0x04);
static_assert((offsetof (struct polygon_type_12, y)) == 0x08);
static_assert((offsetof (struct polygon_type_12, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_12, u_v_0)) == 0x10);
static_assert((offsetof (struct polygon_type_12, _res0)) == 0x14);
static_assert((offsetof (struct polygon_type_12, base_color_0)) == 0x18);
static_assert((offsetof (struct polygon_type_12, offset_color_0)) == 0x1c);
static_assert((offsetof (struct polygon_type_12, u_v_1)) == 0x20);
static_assert((offsetof (struct polygon_type_12, _res1)) == 0x24);
static_assert((offsetof (struct polygon_type_12, base_color_1)) == 0x28);
static_assert((offsetof (struct polygon_type_12, offset_color_1)) == 0x2c);
static_assert((offsetof (struct polygon_type_12, _res2)) == 0x30);
static_assert((offsetof (struct polygon_type_12, _res3)) == 0x34);
static_assert((offsetof (struct polygon_type_12, _res4)) == 0x38);
static_assert((offsetof (struct polygon_type_12, _res5)) == 0x3c);
struct polygon_type_13 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float u_0;
float v_0;
uint32_t base_intensity_0;
float offset_intensity_0;
float u_1;
float v_1;
uint32_t base_intensity_1;
float offset_intensity_1;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t _res3;
};
static_assert((sizeof (polygon_type_13)) == 64);
static_assert((offsetof (struct polygon_type_13, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_13, x)) == 0x04);
static_assert((offsetof (struct polygon_type_13, y)) == 0x08);
static_assert((offsetof (struct polygon_type_13, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_13, u_0)) == 0x10);
static_assert((offsetof (struct polygon_type_13, v_0)) == 0x14);
static_assert((offsetof (struct polygon_type_13, base_intensity_0)) == 0x18);
static_assert((offsetof (struct polygon_type_13, offset_intensity_0)) == 0x1c);
static_assert((offsetof (struct polygon_type_13, u_1)) == 0x20);
static_assert((offsetof (struct polygon_type_13, v_1)) == 0x24);
static_assert((offsetof (struct polygon_type_13, base_intensity_1)) == 0x28);
static_assert((offsetof (struct polygon_type_13, offset_intensity_1)) == 0x2c);
static_assert((offsetof (struct polygon_type_13, _res0)) == 0x30);
static_assert((offsetof (struct polygon_type_13, _res1)) == 0x34);
static_assert((offsetof (struct polygon_type_13, _res2)) == 0x38);
static_assert((offsetof (struct polygon_type_13, _res3)) == 0x3c);
struct polygon_type_14 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t u_v_0;
uint32_t _res0;
uint32_t base_intensity_0;
float offset_intensity_0;
uint32_t u_v_1;
uint32_t _res1;
uint32_t base_intensity_1;
float offset_intensity_1;
uint32_t _res2;
uint32_t _res3;
uint32_t _res4;
uint32_t _res5;
};
static_assert((sizeof (polygon_type_14)) == 64);
static_assert((offsetof (struct polygon_type_14, parameter_control_word)) == 0x00);
static_assert((offsetof (struct polygon_type_14, x)) == 0x04);
static_assert((offsetof (struct polygon_type_14, y)) == 0x08);
static_assert((offsetof (struct polygon_type_14, z)) == 0x0c);
static_assert((offsetof (struct polygon_type_14, u_v_0)) == 0x10);
static_assert((offsetof (struct polygon_type_14, _res0)) == 0x14);
static_assert((offsetof (struct polygon_type_14, base_intensity_0)) == 0x18);
static_assert((offsetof (struct polygon_type_14, offset_intensity_0)) == 0x1c);
static_assert((offsetof (struct polygon_type_14, u_v_1)) == 0x20);
static_assert((offsetof (struct polygon_type_14, _res1)) == 0x24);
static_assert((offsetof (struct polygon_type_14, base_intensity_1)) == 0x28);
static_assert((offsetof (struct polygon_type_14, offset_intensity_1)) == 0x2c);
static_assert((offsetof (struct polygon_type_14, _res2)) == 0x30);
static_assert((offsetof (struct polygon_type_14, _res3)) == 0x34);
static_assert((offsetof (struct polygon_type_14, _res4)) == 0x38);
static_assert((offsetof (struct polygon_type_14, _res5)) == 0x3c);
struct sprite_type_0 {
uint32_t parameter_control_word;
float a_x;
float a_y;
float a_z;
float b_x;
float b_y;
float b_z;
float c_x;
float c_y;
float c_z;
float d_x;
float d_y;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t _res3;
};
static_assert((sizeof (sprite_type_0)) == 64);
static_assert((offsetof (struct sprite_type_0, parameter_control_word)) == 0x00);
static_assert((offsetof (struct sprite_type_0, a_x)) == 0x04);
static_assert((offsetof (struct sprite_type_0, a_y)) == 0x08);
static_assert((offsetof (struct sprite_type_0, a_z)) == 0x0c);
static_assert((offsetof (struct sprite_type_0, b_x)) == 0x10);
static_assert((offsetof (struct sprite_type_0, b_y)) == 0x14);
static_assert((offsetof (struct sprite_type_0, b_z)) == 0x18);
static_assert((offsetof (struct sprite_type_0, c_x)) == 0x1c);
static_assert((offsetof (struct sprite_type_0, c_y)) == 0x20);
static_assert((offsetof (struct sprite_type_0, c_z)) == 0x24);
static_assert((offsetof (struct sprite_type_0, d_x)) == 0x28);
static_assert((offsetof (struct sprite_type_0, d_y)) == 0x2c);
static_assert((offsetof (struct sprite_type_0, _res0)) == 0x30);
static_assert((offsetof (struct sprite_type_0, _res1)) == 0x34);
static_assert((offsetof (struct sprite_type_0, _res2)) == 0x38);
static_assert((offsetof (struct sprite_type_0, _res3)) == 0x3c);
struct sprite_type_1 {
uint32_t parameter_control_word;
float a_x;
float a_y;
float a_z;
float b_x;
float b_y;
float b_z;
float c_x;
float c_y;
float c_z;
float d_x;
float d_y;
uint32_t _res0;
uint32_t a_u_a_v;
uint32_t b_u_b_v;
uint32_t c_u_c_v;
};
static_assert((sizeof (sprite_type_1)) == 64);
static_assert((offsetof (struct sprite_type_1, parameter_control_word)) == 0x00);
static_assert((offsetof (struct sprite_type_1, a_x)) == 0x04);
static_assert((offsetof (struct sprite_type_1, a_y)) == 0x08);
static_assert((offsetof (struct sprite_type_1, a_z)) == 0x0c);
static_assert((offsetof (struct sprite_type_1, b_x)) == 0x10);
static_assert((offsetof (struct sprite_type_1, b_y)) == 0x14);
static_assert((offsetof (struct sprite_type_1, b_z)) == 0x18);
static_assert((offsetof (struct sprite_type_1, c_x)) == 0x1c);
static_assert((offsetof (struct sprite_type_1, c_y)) == 0x20);
static_assert((offsetof (struct sprite_type_1, c_z)) == 0x24);
static_assert((offsetof (struct sprite_type_1, d_x)) == 0x28);
static_assert((offsetof (struct sprite_type_1, d_y)) == 0x2c);
static_assert((offsetof (struct sprite_type_1, _res0)) == 0x30);
static_assert((offsetof (struct sprite_type_1, a_u_a_v)) == 0x34);
static_assert((offsetof (struct sprite_type_1, b_u_b_v)) == 0x38);
static_assert((offsetof (struct sprite_type_1, c_u_c_v)) == 0x3c);
struct modifier_volume {
uint32_t parameter_control_word;
float a_x;
float a_y;
float a_z;
float b_x;
float b_y;
float b_z;
float c_x;
float c_y;
float c_z;
uint32_t _res0;
uint32_t _res1;
uint32_t _res2;
uint32_t _res3;
uint32_t _res4;
uint32_t _res5;
};
static_assert((sizeof (modifier_volume)) == 64);
static_assert((offsetof (struct modifier_volume, parameter_control_word)) == 0x00);
static_assert((offsetof (struct modifier_volume, a_x)) == 0x04);
static_assert((offsetof (struct modifier_volume, a_y)) == 0x08);
static_assert((offsetof (struct modifier_volume, a_z)) == 0x0c);
static_assert((offsetof (struct modifier_volume, b_x)) == 0x10);
static_assert((offsetof (struct modifier_volume, b_y)) == 0x14);
static_assert((offsetof (struct modifier_volume, b_z)) == 0x18);
static_assert((offsetof (struct modifier_volume, c_x)) == 0x1c);
static_assert((offsetof (struct modifier_volume, c_y)) == 0x20);
static_assert((offsetof (struct modifier_volume, c_z)) == 0x24);
static_assert((offsetof (struct modifier_volume, _res0)) == 0x28);
static_assert((offsetof (struct modifier_volume, _res1)) == 0x2c);
static_assert((offsetof (struct modifier_volume, _res2)) == 0x30);
static_assert((offsetof (struct modifier_volume, _res3)) == 0x34);
static_assert((offsetof (struct modifier_volume, _res4)) == 0x38);
static_assert((offsetof (struct modifier_volume, _res5)) == 0x3c);
}

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

@ -0,0 +1,89 @@
#pragma once
#include <cstdint>
namespace maple {
namespace mdstar {
constexpr inline uint32_t table_address(uint32_t num) { return (num & 0xfffffe0) << 0; }
}
namespace mdtsel {
namespace trigger_select {
constexpr uint32_t software_initiation = 0 << 0;
constexpr uint32_t v_blank_initiation = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace mden {
namespace dma_enable {
constexpr uint32_t abort = 0 << 0;
constexpr uint32_t enable = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace mdst {
namespace start_status {
constexpr inline uint32_t status(uint32_t reg) { return (reg >> 0) & 0x1; }
constexpr uint32_t start = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace msys {
constexpr inline uint32_t time_out_counter(uint32_t num) { return (num & 0xffff) << 16; }
constexpr uint32_t single_hard_trigger = 1 << 12;
namespace sending_rate {
constexpr uint32_t _2M = 0 << 8;
constexpr uint32_t _1M = 1 << 8;
constexpr uint32_t bit_mask = 0x3 << 8;
}
constexpr inline uint32_t delay_time(uint32_t num) { return (num & 0xf) << 0; }
}
namespace mst {
constexpr inline uint32_t move_status(uint32_t reg) { return (reg >> 31) & 0x1; }
constexpr inline uint32_t internal_frame_monitor(uint32_t reg) { return (reg >> 24) & 0x7; }
constexpr inline uint32_t internal_state_monitor(uint32_t reg) { return (reg >> 16) & 0x3f; }
constexpr inline uint32_t line_monitor(uint32_t reg) { return (reg >> 0) & 0xff; }
}
namespace mshtcl {
constexpr uint32_t hard_dma_clear = 1 << 0;
}
namespace mdapro {
constexpr uint32_t security_code = 0x6155 << 16;
constexpr inline uint32_t top_address(uint32_t num) { return (num & 0x7f) << 8; }
constexpr inline uint32_t bottom_address(uint32_t num) { return (num & 0x7f) << 0; }
}
namespace mmsel {
namespace msb_selection {
constexpr uint32_t bit7 = 0 << 0;
constexpr uint32_t bit31 = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace mtxdad {
constexpr inline uint32_t txd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
namespace mrxdad {
constexpr inline uint32_t rxd_address_counter(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
namespace mrxdbd {
constexpr inline uint32_t rxd_base_address(uint32_t reg) { return (reg >> 0) & 0x1fffffff; }
}
}

View File

@ -0,0 +1,79 @@
#pragma once
#include <cstdint>
namespace maple {
namespace host_instruction {
constexpr uint32_t end_flag = 1 << 31;
namespace port_select {
constexpr uint32_t a = 0 << 16;
constexpr uint32_t b = 1 << 16;
constexpr uint32_t c = 2 << 16;
constexpr uint32_t d = 3 << 16;
constexpr uint32_t bit_mask = 0x3 << 16;
}
namespace pattern {
constexpr uint32_t normal = 0b000 << 8;
constexpr uint32_t light_gun_mode = 0b010 << 8;
constexpr uint32_t reset = 0b011 << 8;
constexpr uint32_t return_from_light_gun_mode = 0b100 << 8;
constexpr uint32_t nop = 0b111 << 8;
constexpr uint32_t bit_mask = 0x7 << 8;
}
constexpr inline uint32_t transfer_length(uint32_t num) { return (num & 0xff) << 0; }
}
namespace receive_data_address {
constexpr uint32_t mask = 0x1fffffff << 0;
}
namespace ap {
namespace port_select {
constexpr uint32_t a = 0b00 << 6;
constexpr uint32_t b = 0b01 << 6;
constexpr uint32_t c = 0b10 << 6;
constexpr uint32_t d = 0b11 << 6;
constexpr uint32_t bit_mask = 0x3 << 6;
}
namespace de {
constexpr uint32_t device = 1 << 5;
constexpr uint32_t expansion_device = 0 << 5;
constexpr uint32_t port = 0 << 5;
constexpr uint32_t bit_mask = 0x1 << 5;
}
namespace lm_bus {
constexpr uint32_t _4 = 0b10000 << 0;
constexpr uint32_t _3 = 0b01000 << 0;
constexpr uint32_t _2 = 0b00100 << 0;
constexpr uint32_t _1 = 0b00010 << 0;
constexpr uint32_t _0 = 0b00001 << 0;
constexpr uint32_t bit_mask = 0x1f << 0;
}
}
namespace function_type {
constexpr uint32_t camera = 1 << 11;
constexpr uint32_t exchange_media = 1 << 10;
constexpr uint32_t pointing = 1 << 9;
constexpr uint32_t vibration = 1 << 8;
constexpr uint32_t light_gun = 1 << 7;
constexpr uint32_t keyboard = 1 << 6;
constexpr uint32_t ar_gun = 1 << 5;
constexpr uint32_t audio_input = 1 << 4;
constexpr uint32_t timer = 1 << 3;
constexpr uint32_t bw_lcd = 1 << 2;
constexpr uint32_t storage = 1 << 1;
constexpr uint32_t controller = 1 << 0;
}
}

View File

@ -0,0 +1,260 @@
#pragma once
#include <cstdint>
namespace maple {
struct device_id {
uint32_t ft;
uint32_t fd[3];
};
static_assert((sizeof (struct device_id)) == 16);
struct device_request {
static constexpr uint32_t command_code = 0x1;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct device_request::data_fields)) == 0);
struct all_status_request {
static constexpr uint32_t command_code = 0x2;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct all_status_request::data_fields)) == 0);
struct device_reset {
static constexpr uint32_t command_code = 0x3;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct device_reset::data_fields)) == 0);
struct device_kill {
static constexpr uint32_t command_code = 0x4;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct device_kill::data_fields)) == 0);
struct device_status {
static constexpr uint32_t command_code = 0x5;
struct data_fields {
struct device_id device_id;
uint8_t destination_code;
uint8_t connection_direction;
uint8_t product_name[30];
uint8_t license[60];
uint16_t low_consumption_standby_current;
uint16_t maximum_current_consumption;
};
};
static_assert((sizeof (struct device_status::data_fields)) == 112);
template <typename T>
struct device_all_status {
static constexpr uint32_t command_code = 0x6;
struct data_fields {
struct device_id device_id;
uint8_t destination_code;
uint8_t connection_direction;
uint8_t product_name[30];
uint8_t license[60];
uint16_t low_consumption_standby_current;
uint16_t maximum_current_consumption;
T free_device_status;
};
};
static_assert((sizeof (struct device_all_status<uint8_t[0]>::data_fields)) == 112);
struct device_reply {
static constexpr uint32_t command_code = 0x7;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct device_reply::data_fields)) == 0);
template <typename T>
struct data_transfer {
static constexpr uint32_t command_code = 0x8;
struct data_fields {
uint32_t function_type;
T data;
};
};
static_assert((sizeof (struct data_transfer<uint8_t[0]>::data_fields)) == 4);
struct get_condition {
static constexpr uint32_t command_code = 0x9;
struct data_fields {
uint32_t function_type;
};
};
static_assert((sizeof (struct get_condition::data_fields)) == 4);
struct get_media_info {
static constexpr uint32_t command_code = 0xa;
struct data_fields {
uint32_t function_type;
uint32_t pt;
};
};
static_assert((sizeof (struct get_media_info::data_fields)) == 8);
struct block_read {
static constexpr uint32_t command_code = 0xb;
struct data_fields {
uint32_t function_type;
uint8_t pt;
uint8_t phase;
uint16_t block_number;
};
};
static_assert((sizeof (struct block_read::data_fields)) == 8);
template <typename T>
struct block_write {
static constexpr uint32_t command_code = 0xc;
struct data_fields {
uint32_t function_type;
uint8_t pt;
uint8_t phase;
uint16_t block_number;
T written_data;
};
};
static_assert((sizeof (struct block_write<uint8_t[0]>::data_fields)) == 8);
struct get_last_error {
static constexpr uint32_t command_code = 0xd;
struct data_fields {
uint32_t function_type;
uint8_t pt;
uint8_t phase;
uint16_t block_number;
};
};
static_assert((sizeof (struct get_last_error::data_fields)) == 8);
template <typename T>
struct set_condition {
static constexpr uint32_t command_code = 0xe;
struct data_fields {
uint32_t function_type;
T write_in_data;
};
};
static_assert((sizeof (struct set_condition<uint8_t[0]>::data_fields)) == 4);
template <typename T>
struct ft4_control {
static constexpr uint32_t command_code = 0xf;
struct data_fields {
uint32_t function_type;
T ft4_data;
};
};
static_assert((sizeof (struct ft4_control<uint8_t[0]>::data_fields)) == 4);
template <typename T>
struct ar_control {
static constexpr uint32_t command_code = 0x10;
struct data_fields {
uint32_t function_type;
T data;
};
};
static_assert((sizeof (struct ar_control<uint8_t[0]>::data_fields)) == 4);
struct function_type_unknown {
static constexpr uint32_t command_code = 0xfe;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct function_type_unknown::data_fields)) == 0);
struct command_unknown {
static constexpr uint32_t command_code = 0xfd;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct command_unknown::data_fields)) == 0);
struct transmit_again {
static constexpr uint32_t command_code = 0xfc;
struct data_fields {
uint8_t _empty[0];
};
};
static_assert((sizeof (struct transmit_again::data_fields)) == 0);
struct file_error {
static constexpr uint32_t command_code = 0xfb;
struct data_fields {
uint32_t function_error_code;
};
};
static_assert((sizeof (struct file_error::data_fields)) == 4);
struct lcd_error {
static constexpr uint32_t command_code = 0xfa;
struct data_fields {
uint32_t function_error_code;
};
};
static_assert((sizeof (struct lcd_error::data_fields)) == 4);
struct ar_error {
static constexpr uint32_t command_code = 0xf9;
struct data_fields {
uint32_t function_error_code;
};
};
static_assert((sizeof (struct ar_error::data_fields)) == 4);
}

View File

@ -0,0 +1,67 @@
#pragma once
#include <cstdint>
namespace maple::ft0 {
namespace data_transfer {
namespace digital_button {
constexpr uint32_t ra() { return 0b1 << 7; }
constexpr uint32_t ra(uint32_t reg) { return (reg >> 7) & 0b1; }
constexpr uint32_t la() { return 0b1 << 6; }
constexpr uint32_t la(uint32_t reg) { return (reg >> 6) & 0b1; }
constexpr uint32_t da() { return 0b1 << 5; }
constexpr uint32_t da(uint32_t reg) { return (reg >> 5) & 0b1; }
constexpr uint32_t ua() { return 0b1 << 4; }
constexpr uint32_t ua(uint32_t reg) { return (reg >> 4) & 0b1; }
constexpr uint32_t start() { return 0b1 << 3; }
constexpr uint32_t start(uint32_t reg) { return (reg >> 3) & 0b1; }
constexpr uint32_t a() { return 0b1 << 2; }
constexpr uint32_t a(uint32_t reg) { return (reg >> 2) & 0b1; }
constexpr uint32_t b() { return 0b1 << 1; }
constexpr uint32_t b(uint32_t reg) { return (reg >> 1) & 0b1; }
constexpr uint32_t c() { return 0b1 << 0; }
constexpr uint32_t c(uint32_t reg) { return (reg >> 0) & 0b1; }
constexpr uint32_t rb() { return 0b1 << 15; }
constexpr uint32_t rb(uint32_t reg) { return (reg >> 15) & 0b1; }
constexpr uint32_t lb() { return 0b1 << 14; }
constexpr uint32_t lb(uint32_t reg) { return (reg >> 14) & 0b1; }
constexpr uint32_t db() { return 0b1 << 13; }
constexpr uint32_t db(uint32_t reg) { return (reg >> 13) & 0b1; }
constexpr uint32_t ub() { return 0b1 << 12; }
constexpr uint32_t ub(uint32_t reg) { return (reg >> 12) & 0b1; }
constexpr uint32_t d() { return 0b1 << 11; }
constexpr uint32_t d(uint32_t reg) { return (reg >> 11) & 0b1; }
constexpr uint32_t x() { return 0b1 << 10; }
constexpr uint32_t x(uint32_t reg) { return (reg >> 10) & 0b1; }
constexpr uint32_t y() { return 0b1 << 9; }
constexpr uint32_t y(uint32_t reg) { return (reg >> 9) & 0b1; }
constexpr uint32_t z() { return 0b1 << 8; }
constexpr uint32_t z(uint32_t reg) { return (reg >> 8) & 0b1; }
}
struct data_format {
uint16_t digital_button;
uint8_t analog_coordinate_axis[6];
};
static_assert((sizeof (struct data_format)) % 4 == 0);
static_assert((sizeof (struct data_format)) == 8);
}
}

View File

@ -0,0 +1,82 @@
#pragma once
#include <cstdint>
namespace maple::ft6 {
namespace data_transfer {
namespace modifier_key {
constexpr uint32_t s2() { return 0b1 << 7; }
constexpr uint32_t s2(uint32_t reg) { return (reg >> 7) & 0b1; }
constexpr uint32_t right_alt() { return 0b1 << 6; }
constexpr uint32_t right_alt(uint32_t reg) { return (reg >> 6) & 0b1; }
constexpr uint32_t right_shift() { return 0b1 << 5; }
constexpr uint32_t right_shift(uint32_t reg) { return (reg >> 5) & 0b1; }
constexpr uint32_t right_control() { return 0b1 << 4; }
constexpr uint32_t right_control(uint32_t reg) { return (reg >> 4) & 0b1; }
constexpr uint32_t left_gui() { return 0b1 << 3; }
constexpr uint32_t left_gui(uint32_t reg) { return (reg >> 3) & 0b1; }
constexpr uint32_t left_alt() { return 0b1 << 2; }
constexpr uint32_t left_alt(uint32_t reg) { return (reg >> 2) & 0b1; }
constexpr uint32_t left_shift() { return 0b1 << 1; }
constexpr uint32_t left_shift(uint32_t reg) { return (reg >> 1) & 0b1; }
constexpr uint32_t left_control() { return 0b1 << 0; }
constexpr uint32_t left_control(uint32_t reg) { return (reg >> 0) & 0b1; }
}
namespace led_state {
constexpr uint32_t shift() { return 0b1 << 7; }
constexpr uint32_t shift(uint32_t reg) { return (reg >> 7) & 0b1; }
constexpr uint32_t power() { return 0b1 << 6; }
constexpr uint32_t power(uint32_t reg) { return (reg >> 6) & 0b1; }
constexpr uint32_t kana() { return 0b1 << 5; }
constexpr uint32_t kana(uint32_t reg) { return (reg >> 5) & 0b1; }
constexpr uint32_t reserved0() { return 0b1 << 4; }
constexpr uint32_t reserved0(uint32_t reg) { return (reg >> 4) & 0b1; }
constexpr uint32_t reserved1() { return 0b1 << 3; }
constexpr uint32_t reserved1(uint32_t reg) { return (reg >> 3) & 0b1; }
constexpr uint32_t scroll_lock() { return 0b1 << 2; }
constexpr uint32_t scroll_lock(uint32_t reg) { return (reg >> 2) & 0b1; }
constexpr uint32_t caps_lock() { return 0b1 << 1; }
constexpr uint32_t caps_lock(uint32_t reg) { return (reg >> 1) & 0b1; }
constexpr uint32_t num_lock() { return 0b1 << 0; }
constexpr uint32_t num_lock(uint32_t reg) { return (reg >> 0) & 0b1; }
}
struct data_format {
uint8_t modifier_key;
uint8_t led_state;
uint8_t scan_code_array[6];
};
static_assert((sizeof (struct data_format)) % 4 == 0);
static_assert((sizeof (struct data_format)) == 8);
}
namespace set_condition {
struct data_format {
uint8_t led_setting;
uint8_t w1_reserved;
uint8_t w2_reserved;
uint8_t w3_reserved;
};
static_assert((sizeof (struct data_format)) % 4 == 0);
static_assert((sizeof (struct data_format)) == 4);
}
}

View File

@ -0,0 +1,150 @@
#pragma once
#include <cstdint>
namespace maple::ft6::scan_code {
constexpr uint32_t no_operation = 0x0;
constexpr uint32_t rollover_error = 0x1;
constexpr uint32_t post_fail = 0x2;
constexpr uint32_t undefined_error = 0x3;
constexpr uint32_t a_A = 0x4;
constexpr uint32_t b_B = 0x5;
constexpr uint32_t c_C = 0x6;
constexpr uint32_t d_D = 0x7;
constexpr uint32_t e_E = 0x8;
constexpr uint32_t f_F = 0x9;
constexpr uint32_t g_G = 0xa;
constexpr uint32_t h_H = 0xb;
constexpr uint32_t i_I = 0xc;
constexpr uint32_t j_J = 0xd;
constexpr uint32_t k_K = 0xe;
constexpr uint32_t l_L = 0xf;
constexpr uint32_t m_M = 0x10;
constexpr uint32_t n_N = 0x11;
constexpr uint32_t o_O = 0x12;
constexpr uint32_t p_P = 0x13;
constexpr uint32_t q_Q = 0x14;
constexpr uint32_t r_R = 0x15;
constexpr uint32_t s_S = 0x16;
constexpr uint32_t t_T = 0x17;
constexpr uint32_t u_U = 0x18;
constexpr uint32_t v_V = 0x19;
constexpr uint32_t w_W = 0x1a;
constexpr uint32_t x_X = 0x1b;
constexpr uint32_t y_Y = 0x1c;
constexpr uint32_t z_Z = 0x1d;
constexpr uint32_t _1_exclam = 0x1e;
constexpr uint32_t _2_at = 0x1f;
constexpr uint32_t _3_numbersign = 0x20;
constexpr uint32_t _4_dollar = 0x21;
constexpr uint32_t _5_percent = 0x22;
constexpr uint32_t _6_asciicircum = 0x23;
constexpr uint32_t _7_ampersand = 0x24;
constexpr uint32_t _8_asterisk = 0x25;
constexpr uint32_t _9_parenleft = 0x26;
constexpr uint32_t _0_parenright = 0x27;
constexpr uint32_t _return = 0x28;
constexpr uint32_t esc = 0x29;
constexpr uint32_t backspace = 0x2a;
constexpr uint32_t tab = 0x2b;
constexpr uint32_t spacebar = 0x2c;
constexpr uint32_t minus_underscore = 0x2d;
constexpr uint32_t equal_plus = 0x2e;
constexpr uint32_t bracketleft_braceleft = 0x2f;
constexpr uint32_t bracketright_braceright = 0x30;
constexpr uint32_t backslash_bar = 0x31;
constexpr uint32_t iso_numbersign_tilde = 0x32;
constexpr uint32_t semicolon_colon = 0x33;
constexpr uint32_t apostrophe_quotedbl = 0x34;
constexpr uint32_t grave_asciitilde = 0x35;
constexpr uint32_t comma_less = 0x36;
constexpr uint32_t period_greater = 0x37;
constexpr uint32_t slash_question = 0x38;
constexpr uint32_t caps_lock = 0x39;
constexpr uint32_t F1 = 0x3a;
constexpr uint32_t F2 = 0x3b;
constexpr uint32_t F3 = 0x3c;
constexpr uint32_t F4 = 0x3d;
constexpr uint32_t F5 = 0x3e;
constexpr uint32_t F6 = 0x3f;
constexpr uint32_t F7 = 0x40;
constexpr uint32_t F8 = 0x41;
constexpr uint32_t F9 = 0x42;
constexpr uint32_t F10 = 0x43;
constexpr uint32_t F11 = 0x44;
constexpr uint32_t F12 = 0x45;
constexpr uint32_t print_screen = 0x46;
constexpr uint32_t scroll_lock = 0x47;
constexpr uint32_t pause = 0x48;
constexpr uint32_t insert = 0x49;
constexpr uint32_t home = 0x4a;
constexpr uint32_t page_up = 0x4b;
constexpr uint32_t _delete = 0x4c;
constexpr uint32_t end = 0x4d;
constexpr uint32_t page_down = 0x4e;
constexpr uint32_t right_arrow = 0x4f;
constexpr uint32_t left_arrow = 0x50;
constexpr uint32_t down_arrow = 0x51;
constexpr uint32_t up_arrow = 0x52;
constexpr uint32_t last_printable = 0x38;
static const uint8_t code_point[last_printable + 1][2] = {
[scan_code::no_operation] = { 0, 0 },
[scan_code::rollover_error] = { 0, 0 },
[scan_code::post_fail] = { 0, 0 },
[scan_code::undefined_error] = { 0, 0 },
[scan_code::a_A] = { 'a', 'A' },
[scan_code::b_B] = { 'b', 'B' },
[scan_code::c_C] = { 'c', 'C' },
[scan_code::d_D] = { 'd', 'D' },
[scan_code::e_E] = { 'e', 'E' },
[scan_code::f_F] = { 'f', 'F' },
[scan_code::g_G] = { 'g', 'G' },
[scan_code::h_H] = { 'h', 'H' },
[scan_code::i_I] = { 'i', 'I' },
[scan_code::j_J] = { 'j', 'J' },
[scan_code::k_K] = { 'k', 'K' },
[scan_code::l_L] = { 'l', 'L' },
[scan_code::m_M] = { 'm', 'M' },
[scan_code::n_N] = { 'n', 'N' },
[scan_code::o_O] = { 'o', 'O' },
[scan_code::p_P] = { 'p', 'P' },
[scan_code::q_Q] = { 'q', 'Q' },
[scan_code::r_R] = { 'r', 'R' },
[scan_code::s_S] = { 's', 'S' },
[scan_code::t_T] = { 't', 'T' },
[scan_code::u_U] = { 'u', 'U' },
[scan_code::v_V] = { 'v', 'V' },
[scan_code::w_W] = { 'w', 'W' },
[scan_code::x_X] = { 'x', 'X' },
[scan_code::y_Y] = { 'y', 'Y' },
[scan_code::z_Z] = { 'z', 'Z' },
[scan_code::_1_exclam] = { '1', '!' },
[scan_code::_2_at] = { '2', '@' },
[scan_code::_3_numbersign] = { '3', '#' },
[scan_code::_4_dollar] = { '4', '$' },
[scan_code::_5_percent] = { '5', '%' },
[scan_code::_6_asciicircum] = { '6', '^' },
[scan_code::_7_ampersand] = { '7', '&' },
[scan_code::_8_asterisk] = { '8', '*' },
[scan_code::_9_parenleft] = { '9', '(' },
[scan_code::_0_parenright] = { '0', ')' },
[scan_code::_return] = { 0, 0 },
[scan_code::esc] = { 0, 0 },
[scan_code::backspace] = { 0, 0 },
[scan_code::tab] = { 0, 0 },
[scan_code::spacebar] = { ' ', ' ' },
[scan_code::minus_underscore] = { '-', '_' },
[scan_code::equal_plus] = { '=', '+' },
[scan_code::bracketleft_braceleft] = { '[', '{' },
[scan_code::bracketright_braceright] = { ']', '}' },
[scan_code::backslash_bar] = { '\\', '|' },
[scan_code::iso_numbersign_tilde] = { '#', '~' },
[scan_code::semicolon_colon] = { ';', ':' },
[scan_code::apostrophe_quotedbl] = { '\'', '"' },
[scan_code::grave_asciitilde] = { '\'', '~' },
[scan_code::comma_less] = { ',', '<' },
[scan_code::period_greater] = { '.', '>' },
[scan_code::slash_question] = { '/', '?' },
};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <cstdint>
namespace maple {
struct protocol_header {
uint8_t command_code;
uint8_t destination_ap;
uint8_t source_ap;
uint8_t data_size;
};
template <typename T>
struct host_command {
uint32_t host_instruction; // interpreted by the Maple DMA controller
uint32_t receive_data_address; // interpreted by the Maple DMA controller
protocol_header header;
T data;
};
static_assert((sizeof (host_command<uint8_t[0]>)) == 12);
static_assert((sizeof (host_command<uint8_t[0]>[4])) == 48);
constexpr inline uint32_t align(uint32_t mem)
{
return (mem + 31) & ~31;
}
template <typename T>
struct host_response {
protocol_header header;
T data;
uint8_t _pad[align((sizeof (protocol_header)) + (sizeof (T))) - ((sizeof (protocol_header)) + (sizeof (T)))];
};
static_assert((sizeof (host_response<uint8_t[0]>)) == 32);
}

17
dreamcast2/memorymap.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
extern volatile uint8_t system_boot_rom[0x200000] __asm("system_boot_rom") __attribute__((aligned(32)));
extern volatile uint8_t aica_wave_memory[0x200000] __asm("aica_wave_memory") __attribute__((aligned(32)));
extern volatile uint8_t texture_memory64[0x800000] __asm("texture_memory64") __attribute__((aligned(32)));
extern volatile uint8_t texture_memory32[0x800000] __asm("texture_memory32") __attribute__((aligned(32)));
extern volatile uint8_t system_memory[0x1000000] __asm("system_memory") __attribute__((aligned(32)));
extern volatile uint8_t ta_fifo_polygon_converter[0x800000] __asm("ta_fifo_polygon_converter") __attribute__((aligned(32)));
extern volatile uint8_t ta_fifo_yuv_converter[0x800000] __asm("ta_fifo_yuv_converter") __attribute__((aligned(32)));
extern volatile uint8_t ta_fifo_texture_memory[0x800000] __asm("ta_fifo_texture_memory") __attribute__((aligned(32)));
extern volatile uint8_t ta_fifo_polygon_converter_mirror[0x800000] __asm("ta_fifo_polygon_converter_mirror") __attribute__((aligned(32)));
extern volatile uint8_t ta_fifo_yuv_converter_mirror[0x800000] __asm("ta_fifo_yuv_converter_mirror") __attribute__((aligned(32)));
extern volatile uint8_t ta_fifo_texture_memory_mirror[0x800000] __asm("ta_fifo_texture_memory_mirror") __attribute__((aligned(32)));
extern volatile uint8_t store_queue[0x4000000] __asm("store_queue") __attribute__((aligned(32)));
extern volatile uint8_t sh7091_oc_d[0x1000] __asm("sh7091_oc_d") __attribute__((aligned(32)));

14
dreamcast2/reg.hpp Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <cstddef>
#include <cstdint>
typedef volatile uint8_t reg8;
typedef volatile uint16_t reg16;
typedef volatile uint32_t reg32;
typedef volatile float reg32f;
static_assert((sizeof (reg8)) == 1);
static_assert((sizeof (reg16)) == 2);
static_assert((sizeof (reg32)) == 4);
static_assert((sizeof (reg32f)) == 4);

65
dreamcast2/regs.mk Normal file
View File

@ -0,0 +1,65 @@
%.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/core/region_array_bits.hpp: regs/holly/core/region_array_bits.csv regs/render_bits.py
python regs/render_bits.py $< holly::core::region_array > $@
holly/core/object_list_bits.hpp: regs/holly/core/object_list_bits.csv regs/render_bits.py
python regs/render_bits.py $< holly::core::object_list > $@
holly/core/parameter_bits.hpp: regs/holly/core/parameter_bits.csv regs/render_bits.py
python regs/render_bits.py $< holly::core::parameter > $@
holly/ta/parameter_bits.hpp: regs/holly/ta/parameter_bits.csv regs/render_bits.py
python regs/render_bits.py $< holly::ta::parameter > $@
holly/ta/global_parameter.hpp: regs/holly/ta/global_parameter.csv regs/render_ta_parameter_struct.py
python regs/render_ta_parameter_struct.py $< holly::ta::global_parameter > $@
holly/ta/vertex_parameter.hpp: regs/holly/ta/vertex_parameter.csv regs/render_ta_parameter_struct.py
python regs/render_ta_parameter_struct.py $< holly::ta::vertex_parameter > $@
# SH7091
sh7091/sh7091.hpp: regs/sh7091/sh7091.csv regs/render_sh7091.py
python regs/render_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 > $@
# MAPLE
maple/maple_bits.hpp: regs/maple/maple_bits.csv regs/render_bits.py
python regs/render_bits.py $< maple > $@
maple/maple_bus_bits.hpp: regs/maple/maple_bus_bits.csv regs/render_bits.py
python regs/render_bits.py $< maple > $@
maple/maple_bus_commands.hpp: regs/maple/maple_bus_commands.csv regs/render_maple_bus_commands.py
python regs/render_maple_bus_commands.py $< > $@
maple/maple_bus_ft0.hpp: regs/maple/maple_bus_ft0.csv regs/render_maple_data_format.py
python regs/render_maple_data_format.py $< > $@
maple/maple_bus_ft6.hpp: regs/maple/maple_bus_ft6.csv regs/render_maple_data_format.py
python regs/render_maple_data_format.py $< > $@
maple/maple_bus_ft6_scan_code.hpp: regs/maple/maple_bus_ft6_scan_code.csv regs/render_maple_scan_code.py
python regs/render_maple_scan_code.py $< > $@

View File

@ -0,0 +1,120 @@
import sys
import string
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, type=None):
if size == 1:
assert type is None
return "reg8 "
elif size == 2:
assert type is None
return "reg16"
elif size == 4:
if type == "f":
return "reg32f"
else:
assert type is None
return "reg32"
else:
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():
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, size_type = parse_size_type(row["size"])
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, size_type)
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 headers():
yield "#pragma once"
yield ""
yield '#include "reg.hpp"'
yield ""

View File

@ -0,0 +1,27 @@
import csv
def as_dict(header, row0):
row = [s.strip() for s in row0]
return dict(zip(header, row))
def read_input(filename):
with open(filename) as f:
reader = csv.reader(f, delimiter=",", quotechar='"')
header, *rows = reader
rows = [
as_dict(header, row)
for row in rows
if "".join(map(str, row)).strip()
]
return rows
def read_input_headerless(filename):
with open(filename) as f:
reader = csv.reader(f, delimiter=",", quotechar='"')
rows = [
[s.strip() for s in row]
for row in reader
]
return rows

View File

@ -0,0 +1,43 @@
import io
def should_autonewline(line):
return (
"static_assert" not in line
and "extern" not in line
and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh
)
def _render(out, lines):
indent = " "
level = 0
#namespace = 0
for l in lines:
if l and (l[0] == "}" or l[0] == ")"):
level -= 2
#if level < 0:
#assert namespace >= 0
#namespace -= 1
#level = 0
assert level >= 0
if len(l) == 0:
out.write("\n")
else:
out.write(indent * level + l + "\n")
if l and (l[-1] == "{" or l[-1] == "("):
#if l.startswith("namespace"):
# namespace += 1
#else:
level += 2
if level == 0 and l and l[-1] == ";":
if should_autonewline(l):
out.write("\n")
return out
def renderer():
out = io.StringIO()
def render(lines):
return _render(out, lines)
return render, out

View File

@ -0,0 +1,126 @@
from dataclasses import dataclass
class EndOfInput(Exception):
pass
def next_row(ix, rows, advance):
if ix >= len(rows):
raise EndOfInput
if advance:
while rows[ix][0] == "":
ix += 1
if ix >= len(rows):
raise EndOfInput
row = rows[ix]
ix += 1
return ix, row
@dataclass
class FieldDeclaration:
offset: int
name: str
default: int
array_length: str
@dataclass
class StructDeclaration:
name: str
fields: list[FieldDeclaration]
size: int
def parse_type_declaration(ix, rows, expected_offset, expected_sizes):
ix, row = next_row(ix, rows, advance=True)
assert len(row) in {2, 3}, row
struct_name, *empty = row
assert all(e == "" for e in empty)
fields = []
last_offset = 0 - expected_offset
res_ix = 0
def terminate():
size = last_offset + expected_offset
assert size in expected_sizes, size
return ix, StructDeclaration(
struct_name,
fields,
size
)
seen_names = set()
while True:
try:
ix, row = next_row(ix, rows, advance=False)
except EndOfInput:
return terminate()
if row[0] == "":
return terminate()
else:
default = None
if len(row) == 2:
_offset, name = row
elif len(row) == 3:
_offset, name, _default = row
if _default.strip() != "":
default = int(_default, 16)
else:
assert False, row
offset = int(_offset, 16)
assert offset == last_offset + expected_offset, (hex(offset), hex(last_offset))
last_offset = offset
if name == "":
name = f"_res{res_ix}"
res_ix += 1
if fields and fields[-1].name == name:
assert offset == fields[-1].offset + (fields[-1].array_length * expected_offset)
fields[-1].array_length += 1
else:
assert name not in seen_names, row
seen_names.add(name)
fields.append(FieldDeclaration(offset, name, default, 1))
def parse(rows, expected_offset, expected_sizes):
ix = 0
declarations = []
while True:
try:
ix, declaration = parse_type_declaration(ix, rows, expected_offset, expected_sizes)
except EndOfInput:
break
declarations.append(declaration)
return declarations
def render_static_assertions(declaration):
yield f"static_assert((sizeof ({declaration.name})) == {declaration.size});"
for field in declaration.fields:
yield f"static_assert((offsetof (struct {declaration.name}, {field.name})) == 0x{field.offset:02x});"
def render_declaration(declaration, get_type):
yield f"struct {declaration.name} {{"
for field in declaration.fields:
type = get_type(field.name)
if field.array_length == 1:
yield f"{type} {field.name};"
else:
yield f"{type} {field.name}[{field.array_length}];"
yield "};" # struct {declaration.name}
yield from render_static_assertions(declaration)
def render_declarations(namespace, declarations, get_type):
yield f"namespace {namespace} {{"
for declaration in declarations:
yield from render_declaration(declaration, get_type)
yield ""
yield "}"
def headers():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield "#include <cstddef>"
yield ""

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,274 @@
import sys
from collections import defaultdict
from pprint import pprint
from dataclasses import dataclass
from typing import Union
from csv_input import read_input
from generate import renderer
def aggregate_registers(d):
aggregated = defaultdict(list)
for row in d:
#assert row["register_name"] != ""
aggregated[row["register_name"]].append(row)
return dict(aggregated)
def parse_bit_number(s):
assert '-' not in s, s
assert ',' not in s, s
return int(s, 10)
def parse_bit_set(s, split_char, maxsplit):
#assert len(list(c for c in s if c == split_char)) == 1, s
split = list(map(parse_bit_number, s.split(split_char, maxsplit=maxsplit)))
for i in range(len(split) - 1):
left = split[i]
right = split[i+1]
assert left > right, (left, right)
return split
def parse_bit_range(s):
if '-' in s:
left, right = parse_bit_set(s, '-', 1)
return set(range(right, left+1))
elif ',' in s:
bits = parse_bit_set(s, ',', -1)
return set(bits)
else:
num = parse_bit_number(s)
return set([num])
def aggregate_enums(aggregated_rows):
non_enum = []
enum_aggregated = defaultdict(list)
all_bits = set()
enum_bits = dict()
def assert_unique_ordered(bits, row):
nonlocal all_bits
#assert all(bit not in all_bits for bit in bits), (bits, row)
if not all(bit not in all_bits for bit in bits):
print("bit overlap", row, file=sys.stderr)
else:
assert max(all_bits, default=32) > max(bits), (all_bits, bits)
all_bits |= bits
for row in aggregated_rows:
bits = parse_bit_range(row["bits"])
assert row["bit_name"] != "", row
if row["enum_name"] == "":
assert_unique_ordered(bits, row)
non_enum.append(row)
else:
if row["enum_name"] not in enum_bits:
assert_unique_ordered(bits, row)
non_enum.append(row["enum_name"])
else:
assert enum_bits[row["enum_name"]] == bits, row
enum_bits[row["enum_name"]] = bits
enum_aggregated[row["enum_name"]].append(row)
return non_enum, dict(enum_aggregated)
@dataclass
class enum:
name: str
defs: list[dict]
@dataclass
class register:
block: Union[None, str]
name: str
defs: list[Union[dict, enum]]
def aggregate_all_enums(aggregated):
out = []
for register_name, rows in aggregated.items():
non_enum, enum_aggregated = aggregate_enums(rows)
def resolve(row_or_string):
if type(row_or_string) == str:
return enum(row_or_string,
enum_aggregated[row_or_string])
elif type(row_or_string) == dict:
return row_or_string
else:
assert False, (row_or_string, type(row_or_string))
defs = [resolve(aggregate) for aggregate in non_enum]
if 'block' in rows[0]:
blocks = set(row['block'] for row in rows)
assert len(blocks) == 1, blocks
block_name = next(iter(blocks))
out.append(
register(block_name, register_name, defs))
else:
out.append(
register(None, register_name, defs))
return out
'''
register(name='SCALER_CTL',
defs=[enum(name='field_select',
defs=[{'bit_name': 'field_1',
'bits': '18',
'description': '',
'enum_name': 'field_select',
'mask': '',
'register_name': 'SCALER_CTL',
'value': '0'},
{...}]),
{'bit_name': 'interlace',
'bits': '17',
'description': '',
'enum_name': '',
'mask': '',
'register_name': 'SCALER_CTL',
'value': '1'},
{...},
...]),
'''
def mask_from_bits(bits):
mask = 0
for b in bits:
mask |= 1 << b
mask >>= min(bits)
return mask
def parse_value(value):
return eval(value)
def escape(bit_name):
if bit_name[0] in {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}:
return '_' + bit_name
else:
return bit_name
def render_read_only(bit_def):
assert bit_def["value"] == ""
assert bit_def["mask"] == ""
bits = parse_bit_range(bit_def["bits"])
mask_value = mask_from_bits(bits)
yield (
f"constexpr inline uint32_t {escape(bit_def['bit_name'])}(uint32_t reg) {{ "
f"return (reg >> {min(bits)}) & {hex(mask_value)};"
" }"
)
def render_mask(bit_def):
assert bit_def["value"] == ""
mask = bit_def["mask"]
bits = parse_bit_range(bit_def["bits"])
if mask.startswith("float_"):
yield (
f"inline float {escape(bit_def['bit_name'])}(float num) {{ "
f"return num;"
" }"
)
else:
assert mask.startswith("0x") or mask.startswith("0b") or mask[0] in set(range(0, 9+1)), mask
mask_value = eval(mask)
assert mask_value & mask_from_bits(bits) == mask_value, (mask_value, mask_from_bits(bits))
yield (
f"constexpr inline uint32_t {escape(bit_def['bit_name'])}(uint32_t num) {{ "
f"return (num & {hex(mask_value)}) << {min(bits)};"
" }"
)
def render_value(bit_def):
assert bit_def["mask"] == ""
bits = parse_bit_range(bit_def["bits"])
assert parse_value(bit_def["value"]) <= mask_from_bits(bits), (bit_def["value"], mask_from_bits(bits), bits)
bit_ix = min(bits)
yield f"constexpr uint32_t {escape(bit_def['bit_name'])} = {bit_def['value']} << {bit_ix};"
def render_defs(bit_def):
if bit_def["value"] != "":
yield from render_value(bit_def)
elif bit_def["mask"] != "":
yield from render_mask(bit_def)
else:
yield from render_read_only(bit_def)
def render_enum_mask(enum_def):
all_bits = set(bit_def["bits"] for bit_def in enum_def.defs)
assert len(all_bits) == 1
assert all(bit_def["bit_name"] != "bit_mask" for bit_def in enum_def.defs), bit_def
_bits = next(iter(all_bits))
bits = parse_bit_range(_bits)
mask_value = mask_from_bits(bits)
bit_ix = min(bits)
yield ""
yield f"constexpr uint32_t bit_mask = {hex(mask_value)} << {bit_ix};"
def render_enum(enum_def):
yield f"namespace {enum_def.name.lower()} {{"
for bit_def in enum_def.defs:
yield from render_defs(bit_def)
yield from render_enum_mask(enum_def)
yield "}"
def render_register(register):
if register.name != "":
yield f"namespace {register.name.lower()} {{"
last = None
for ix, bit_def in enumerate(register.defs):
if type(bit_def) is enum:
if ix != 0:
yield ""
yield from render_enum(bit_def)
else:
if ix != 0 and type(last) is enum:
yield ""
yield from render_defs(bit_def)
last = bit_def
if register.name != "":
yield "}"
yield ""
def render_registers_inner(registers):
last_block = None
for register in registers:
if register.block != last_block:
assert register.block is not None
if last_block is not None:
yield '}' # end of previous namespace
yield ""
yield f'namespace {register.block.lower()} {{'
if register.block is None:
assert last_block is None
last_block = register.block
yield from render_register(register)
if last_block is not None:
yield '}' # end of block namespace
def render_registers(registers, file_namespaces):
if file_namespaces:
yield f"namespace {file_namespaces[0]} {{"
yield from render_registers(registers, file_namespaces[1:])
yield '}' # end of file namespace
else:
yield from render_registers_inner(registers)
def header():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield ""
if __name__ == "__main__":
d = read_input(sys.argv[1])
file_namespaces = sys.argv[2:]
aggregated = aggregate_registers(d)
registers = aggregate_all_enums(aggregated)
render, out = renderer()
render(header())
render(render_registers(registers, file_namespaces))
sys.stdout.write(out.getvalue())

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,184 @@
from dataclasses import dataclass
from typing import Union
import sys
from csv_input import read_input
from generate import renderer
@dataclass
class CommandNamespace:
name: str
issuing_right: set[str]
command_code: int
data_size: int
def command_namespace(namespace: CommandNamespace,
data_fields: list[tuple[str, tuple[int, str]]]):
length, variable = namespace.data_size
if variable is not None:
assert variable.lower() == "n"
yield "template <typename T>"
yield f"struct {namespace.name} {{"
yield f"static constexpr uint32_t command_code = {hex(namespace.command_code)};"
yield ""
if namespace.data_size == (0, None):
assert data_fields == []
yield "struct data_fields {"
yield "uint8_t _empty[0];"
yield "};"
else:
yield "struct data_fields {"
for field_name, field_size in data_fields:
const, var = field_size
if var is None:
if const in {1, 2, 4}:
bits = const * 8
yield f"uint{bits}_t {field_name};"
elif field_name == "device_id":
yield f"struct device_id {field_name};"
else:
yield f"uint8_t {field_name}[{const}];"
elif const == 0:
assert var == "n"
yield f"T {field_name};"
else:
yield f"uint8_t {field_name}[{const} + {var.upper()}];"
yield "};"
yield ""
yield "};"
if variable is not None:
assert variable == "n"
yield f"static_assert((sizeof (struct {namespace.name}<uint8_t[0]>::data_fields)) == {length});"
else:
yield f"static_assert((sizeof (struct {namespace.name}::data_fields)) == {length});"
yield ""
def parse_data_size(data_size, base, multiple) -> tuple[int, str]:
def parse_term(s):
try:
return int(s, base) * multiple
except ValueError:
div = s.split("/")
if len(div) == 1:
# this must be a variable
assert multiple == 1, s
a, = div
return a
elif len(div) == 2:
# this must be a variable divided by a number
a, b = div
b = int(b, 10)
assert b == multiple
return a
else:
assert False, div
_terms = data_size.split("+")
terms = tuple(parse_term(term) for term in _terms)
if len(terms) == 1:
term, = terms
if type(term) == str:
return (0, term)
elif type(term) == int:
return (term, None)
else:
assert False, (_terms, terms)
elif len(terms) == 2:
assert type(terms[0]) == int
assert type(terms[1]) == str
return terms
else:
assert False, (_terms, terms)
def new_aggregator():
last_name = None
namespace = None
data_fields = []
all_names = set()
def process_row(row):
nonlocal last_name
nonlocal namespace
nonlocal data_fields
if row["name"] == "":
assert all(v == "" for v in row.values()), row
return
if row["name"] != last_name:
if namespace is not None:
yield namespace, data_fields
else:
assert data_fields == []
assert row["name"] != ""
last_name = row["name"]
issuing_right = set(row["issuing_right"].split(", "))
assert all(s in {"host", "peripheral"} for s in issuing_right), row
assert issuing_right != set(), issuing_right
data_size = parse_data_size(row["data_size"], 16, 4)
namespace = CommandNamespace(
name = row["name"],
issuing_right = issuing_right,
command_code = int(row["command_code"], 16),
data_size = data_size,
)
data_fields = []
# fall through
assert last_name is None or row["name"] == last_name, (row["name"], last_name)
if row["data_field"] != "":
assert row["data_field_size"] != ""
data_fields.append((
row["data_field"],
parse_data_size(row["data_field_size"], 10, 1)
))
def terminate():
nonlocal namespace
nonlocal data_fields
if namespace is not None:
yield namespace, data_fields
def process(rows):
for row in rows:
yield from process_row(row)
yield from terminate()
return process
def headers():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield ""
def namespace():
yield "namespace maple {"
yield ""
yield "struct device_id {"
yield "uint32_t ft;"
yield "uint32_t fd[3];"
yield "};"
yield "static_assert((sizeof (struct device_id)) == 16);"
yield ""
for namespace, data_fields in process(rows):
yield from command_namespace(namespace, data_fields)
yield ""
yield "}"
input_file = sys.argv[1]
rows = read_input(input_file)
process = new_aggregator()
render, out = renderer()
render(headers())
render(namespace())
sys.stdout.write(out.getvalue())

View File

@ -0,0 +1,163 @@
import sys
import re
from dataclasses import dataclass
from collections import defaultdict
from csv_input import read_input_headerless
from generate import renderer
@dataclass
class Bit:
name: str
length: int
position: int
@dataclass
class Field:
name: str
bits: list[str]
@dataclass
class Format:
name: str
fields: list[Field]
field_order: list[str]
size: int
def parse_bits(bits: list[str]):
bit_order = [7, 6, 5, 4, 3, 2, 1, 0]
by_name = defaultdict(list)
for bit_ix, bit in zip(bit_order, bits):
if bit == '':
continue
by_name[bit].append(bit_ix)
for name, indicies in by_name.items():
yield Bit(name=name,
length=len(indicies),
position=min(indicies),
)
def parse_format_name(name):
if '<' in name:
head, middle, tail = re.split('[<>]', name)
assert tail == "", name
return head, middle
else:
return name, None
def parse_data_format(ix, rows):
if ix >= len(rows):
return None
while rows[ix][0] == "":
ix += 1
if ix >= len(rows):
return None
format_name, *header = rows[ix]
ix += 1
assert format_name != ""
assert header == ["7", "6", "5", "4", "3", "2", "1", "0"]
fields = defaultdict(list)
field_order = list()
size = 0
while ix < len(rows) and rows[ix][0] != "":
field_name, *_bits = rows[ix]
ix += 1
excess_bits = [b for b in _bits[8:] if b != ""]
assert excess_bits == []
bits = [b for b in _bits[:8]]
assert len(bits) == 8, bits
fields[field_name].append(Field(field_name,
list(parse_bits(bits))))
_, variable = parse_format_name(field_name)
if not variable:
size += 1
if field_name not in field_order:
field_order.append(field_name)
return ix, Format(format_name, dict(fields), field_order, size)
def parse(rows):
ix = 0
formats = []
while True:
ix_format = parse_data_format(ix, rows)
if ix_format is None:
break
ix, format = ix_format
formats.append(format)
assert len(formats) > 0
return formats
def render_format(format):
yield f"namespace {format.name} {{"
for field_name in format.field_order:
subfields = format.fields[field_name]
if not any(field.bits != [] for field in subfields):
continue
yield f"namespace {field_name} {{"
for ix, field in enumerate(subfields):
bit_offset = 8 * ix
for bit in field.bits:
name = bit.name.lower()
pos = bit_offset + bit.position
mask = bin(2 ** bit.length - 1)
yield f"constexpr uint32_t {name}() {{ return {mask} << {pos}; }}"
yield f"constexpr uint32_t {name}(uint32_t reg) {{ return (reg >> {pos}) & {mask}; }}"
yield ""
yield "}"
yield ""
yield f"struct data_format {{"
for _field_name in format.field_order:
field_name, variable = parse_format_name(_field_name)
subfields = format.fields[_field_name]
if variable is not None:
assert len(subfields) == 1
yield f"uint8_t {field_name}[{variable}];"
elif len(subfields) == 1:
field, = subfields
yield f"uint8_t {field_name};"
elif len(subfields) == 2:
yield f"uint16_t {field_name};"
elif len(subfields) in {3, 6}:
yield f"uint8_t {field_name}[{len(subfields)}];"
elif len(subfields) == 16:
# bleh: hacky
yield f"uint16_t {field_name}[8];"
elif len(subfields) == 4:
yield f"uint32_t {field_name};"
else:
assert False, (len(subfields), field_name)
yield "};"
yield f"static_assert((sizeof (struct data_format)) % 4 == 0);"
yield f"static_assert((sizeof (struct data_format)) == {format.size});"
yield "}"
def render_formats(name, formats):
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield ""
yield f"namespace maple::{name} {{"
for format in formats:
yield from render_format(format)
yield ""
yield "}"
if __name__ == "__main__":
rows = read_input_headerless(sys.argv[1])
name = sys.argv[1].split('.')[0].split('_')[-1]
assert len(name) == 3 or len(name) == 4
formats = parse(rows)
render, out = renderer()
render(render_formats(name, formats))
print(out.getvalue())

View File

@ -0,0 +1,65 @@
import sys
import string
from csv_input import read_input
from generate import renderer
def render_row(row):
usage = row['usage']
code = int(row['code'], 16)
yield f"constexpr uint32_t {usage} = {hex(code)};"
def render_rows(rows):
for row in rows:
yield from render_row(row)
def code_point(s):
if not s.strip():
return '0'
elif len(s) == 1:
assert s in string.printable
if s == '\\':
return "'\\\\'"
elif s.strip() == "'":
return "'\\''"
else:
return f"'{s}'"
else:
assert False, s
last_printable = 0x38
def render_normal_shift(row):
usage = row['usage']
normal = code_point(row['normal'])
shift = code_point(row['shift'])
yield f"[scan_code::{usage}] = {{ {normal}, {shift} }},"
def render_scancode_code_point(rows):
yield f"constexpr uint32_t last_printable = {hex(last_printable)};"
yield ""
yield f"static const uint8_t code_point[last_printable + 1][2] = {{"
for i, row in enumerate(rows):
yield from render_normal_shift(row)
if i == last_printable:
break
yield "};"
def render_all(rows):
yield "namespace maple::ft6::scan_code {"
yield from render_rows(rows)
yield from render_scancode_code_point(rows)
yield "}"
def header():
yield "#pragma once"
yield ""
yield "#include <cstdint>"
yield ""
if __name__ == "__main__":
rows = read_input(sys.argv[1])
render, out = renderer()
render(header())
render(render_all(rows))
print(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

@ -0,0 +1,68 @@
import sys
from generate import renderer
from csv_input import read_input_headerless
from generic_sparse_struct import parse
from generic_sparse_struct import headers
from generic_sparse_struct import render_declarations
_field_types = {
"parameter_control_word": "uint32_t",
"user_clip_": "uint32_t",
"object_pointer": "uint32_t",
"bounding_box_": "uint32_t",
"isp_tsp_instruction_word": "uint32_t",
"tsp_instruction_word": "uint32_t",
"texture_control_word": "uint32_t",
"data_size_for_sort_dma": "uint32_t",
"next_address_for_sort_dma": "uint32_t",
"face_color_": "float",
"face_offset_color_": "float",
"x": "float",
"y": "float",
"z": "float",
"base_color_": "float",
"base_color_0": "uint32_t",
"base_color_1": "uint32_t",
"offset_color_0": "uint32_t",
"offset_color_1": "uint32_t",
"base_intensity_": "uint32_t",
"u": "float",
"v": "float",
"u_v": "uint32_t",
"base_color": "uint32_t",
"offset_color": "uint32_t",
"offset_color_": "float",
"base_intensity": "float",
"offset_intensity": "float",
"a_": "float",
"b_": "float",
"c_": "float",
"d_": "float",
"a_u_a_v": "uint32_t",
"b_u_b_v": "uint32_t",
"c_u_c_v": "uint32_t",
"_res": "uint32_t"
}
def get_type(field_name: str):
match = None
match_len = 0
for name, type in _field_types.items():
if field_name.startswith(name) and len(name) >= match_len:
match = type
assert match_len != len(name), (name, match)
match_len = len(name)
assert match != None, field_name
return match
if __name__ == "__main__":
rows = read_input_headerless(sys.argv[1])
namespace = sys.argv[2]
declarations = parse(rows,
expected_offset=4,
expected_sizes={32, 64})
render, out = renderer()
render(headers())
render(render_declarations(namespace, declarations, get_type))
print(out.getvalue())

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

53
dreamcast2/runtime.cpp Normal file
View File

@ -0,0 +1,53 @@
#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++))();
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#define pref(address) \
{ asm volatile ("pref @%0" : : "r" ((uint32_t)(address)) : "memory"); }
#define pref2(address) \
{ asm volatile ("pref @%0" : : "r" (((uint32_t)(address)) + 32) : "memory"); }
#define ocbi(address) \
{ asm volatile ("ocbi @%0" : : "r" ((uint32_t)(address)) : "memory"); }
#define ocbwb(address) \
{ asm volatile ("ocbwb @%0" : : "r" ((uint32_t)(address)) : "memory"); }
#define ocbp(address) \
{ asm volatile ("ocbp @%0" : : "r" ((uint32_t)(address)) : "memory"); }
namespace sh7091::ccn::qacr0 {
template <typename T>
constexpr inline uint32_t address(T a) { return (((uint32_t)a) >> 24) & 0b11100; }
}
namespace sh7091::ccn::qacr1 {
template <typename T>
constexpr inline uint32_t address(T a) { return (((uint32_t)a) >> 24) & 0b11100; }
}

View File

@ -0,0 +1,366 @@
#pragma once
#include "reg.hpp"
namespace sh7091 {
struct ccn_reg {
reg32 PTEH; /* Page table entry high register */
reg32 PTEL; /* Page table entry low register */
reg32 TTB; /* Translation table base register */
reg32 TEA; /* TLB exception address register */
reg32 MMUCR; /* MMU control register */
reg8 BASRA; /* Break ASID register A */
reg8 _pad0[3];
reg8 BASRB; /* Break ASID register B */
reg8 _pad1[3];
reg32 CCR; /* Cache control register */
reg32 TRA; /* TRAPA exception register */
reg32 EXPEVT; /* Exception event register */
reg32 INTEVT; /* Interrupt event register */
reg8 _pad2[8];
reg32 PTEA; /* Page table entry assistance register */
reg32 QACR0; /* Queue address control register 0 */
reg32 QACR1; /* Queue address control register 1 */
};
static_assert((offsetof (struct ccn_reg, PTEH)) == 0x0);
static_assert((offsetof (struct ccn_reg, PTEL)) == 0x4);
static_assert((offsetof (struct ccn_reg, TTB)) == 0x8);
static_assert((offsetof (struct ccn_reg, TEA)) == 0xc);
static_assert((offsetof (struct ccn_reg, MMUCR)) == 0x10);
static_assert((offsetof (struct ccn_reg, BASRA)) == 0x14);
static_assert((offsetof (struct ccn_reg, BASRB)) == 0x18);
static_assert((offsetof (struct ccn_reg, CCR)) == 0x1c);
static_assert((offsetof (struct ccn_reg, TRA)) == 0x20);
static_assert((offsetof (struct ccn_reg, EXPEVT)) == 0x24);
static_assert((offsetof (struct ccn_reg, INTEVT)) == 0x28);
static_assert((offsetof (struct ccn_reg, PTEA)) == 0x34);
static_assert((offsetof (struct ccn_reg, QACR0)) == 0x38);
static_assert((offsetof (struct ccn_reg, QACR1)) == 0x3c);
struct ubc_reg {
reg32 BARA; /* Break address register A */
reg8 BAMRA; /* Break address mask register A */
reg8 _pad0[3];
reg16 BBRA; /* Break bus cycle register A */
reg8 _pad1[2];
reg32 BARB; /* Break address register B */
reg8 BAMRB; /* Break address mask register B */
reg8 _pad2[3];
reg16 BBRB; /* Break bus cycle register B */
reg8 _pad3[2];
reg32 BDRB; /* Break data register B */
reg32 BDMRB; /* Break data mask register B */
reg16 BRCR; /* Break control register */
};
static_assert((offsetof (struct ubc_reg, BARA)) == 0x0);
static_assert((offsetof (struct ubc_reg, BAMRA)) == 0x4);
static_assert((offsetof (struct ubc_reg, BBRA)) == 0x8);
static_assert((offsetof (struct ubc_reg, BARB)) == 0xc);
static_assert((offsetof (struct ubc_reg, BAMRB)) == 0x10);
static_assert((offsetof (struct ubc_reg, BBRB)) == 0x14);
static_assert((offsetof (struct ubc_reg, BDRB)) == 0x18);
static_assert((offsetof (struct ubc_reg, BDMRB)) == 0x1c);
static_assert((offsetof (struct ubc_reg, BRCR)) == 0x20);
struct bsc_reg {
reg32 BCR1; /* Bus control register 1 */
reg16 BCR2; /* Bus control register 2 */
reg8 _pad0[2];
reg32 WCR1; /* Wait state control register 1 */
reg32 WCR2; /* Wait state control register 2 */
reg32 WCR3; /* Wait state control register 3 */
reg32 MCR; /* Memory control register */
reg16 PCR; /* PCMCIA control register */
reg8 _pad1[2];
reg16 RTCSR; /* Refresh timer control/status register */
reg8 _pad2[2];
reg16 RTCNT; /* Refresh timer counter */
reg8 _pad3[2];
reg16 RTCOR; /* Refresh timer constant counter */
reg8 _pad4[2];
reg16 RFCR; /* Refresh count register */
reg8 _pad5[2];
reg32 PCTRA; /* Port control register A */
reg16 PDTRA; /* Port data register A */
reg8 _pad6[14];
reg32 PCTRB; /* Port control register B */
reg16 PDTRB; /* Port data register B */
reg8 _pad7[2];
reg16 GPIOIC; /* GPIO interrupt control register */
reg8 _pad8[1048502];
reg32 SDMR2[16384]; /* Synchronous DRAM mode registers */
reg8 _pad9[196608];
reg32 SDMR3[16384]; /* Synchronous DRAM mode registers */
};
static_assert((offsetof (struct bsc_reg, BCR1)) == 0x0);
static_assert((offsetof (struct bsc_reg, BCR2)) == 0x4);
static_assert((offsetof (struct bsc_reg, WCR1)) == 0x8);
static_assert((offsetof (struct bsc_reg, WCR2)) == 0xc);
static_assert((offsetof (struct bsc_reg, WCR3)) == 0x10);
static_assert((offsetof (struct bsc_reg, MCR)) == 0x14);
static_assert((offsetof (struct bsc_reg, PCR)) == 0x18);
static_assert((offsetof (struct bsc_reg, RTCSR)) == 0x1c);
static_assert((offsetof (struct bsc_reg, RTCNT)) == 0x20);
static_assert((offsetof (struct bsc_reg, RTCOR)) == 0x24);
static_assert((offsetof (struct bsc_reg, RFCR)) == 0x28);
static_assert((offsetof (struct bsc_reg, PCTRA)) == 0x2c);
static_assert((offsetof (struct bsc_reg, PDTRA)) == 0x30);
static_assert((offsetof (struct bsc_reg, PCTRB)) == 0x40);
static_assert((offsetof (struct bsc_reg, PDTRB)) == 0x44);
static_assert((offsetof (struct bsc_reg, GPIOIC)) == 0x48);
static_assert((offsetof (struct bsc_reg, SDMR2)) == 0x100000);
static_assert((offsetof (struct bsc_reg, SDMR3)) == 0x140000);
struct dmac_reg {
reg32 SAR0; /* DMA source address register 0 */
reg32 DAR0; /* DMA destination address register 0 */
reg32 DMATCR0; /* DMA transfer count register 0 */
reg32 CHCR0; /* DMA control register 0 */
reg32 SAR1; /* DMA source address register 1 */
reg32 DAR1; /* DMA destination address register 1 */
reg32 DMATCR1; /* DMA transfer count register 1 */
reg32 CHCR1; /* DMA control register 1 */
reg32 SAR2; /* DMA source address register 2 */
reg32 DAR2; /* DMA destination address register 2 */
reg32 DMATCR2; /* DMA transfer count register 2 */
reg32 CHCR2; /* DMA control register 2 */
reg32 SAR3; /* DMA source address register 3 */
reg32 DAR3; /* DMA destination address register 3 */
reg32 DMATCR3; /* DMA transfer count register 3 */
reg32 CHCR3; /* DMA control register 3 */
reg32 DMAOR; /* DMA operation register */
};
static_assert((offsetof (struct dmac_reg, SAR0)) == 0x0);
static_assert((offsetof (struct dmac_reg, DAR0)) == 0x4);
static_assert((offsetof (struct dmac_reg, DMATCR0)) == 0x8);
static_assert((offsetof (struct dmac_reg, CHCR0)) == 0xc);
static_assert((offsetof (struct dmac_reg, SAR1)) == 0x10);
static_assert((offsetof (struct dmac_reg, DAR1)) == 0x14);
static_assert((offsetof (struct dmac_reg, DMATCR1)) == 0x18);
static_assert((offsetof (struct dmac_reg, CHCR1)) == 0x1c);
static_assert((offsetof (struct dmac_reg, SAR2)) == 0x20);
static_assert((offsetof (struct dmac_reg, DAR2)) == 0x24);
static_assert((offsetof (struct dmac_reg, DMATCR2)) == 0x28);
static_assert((offsetof (struct dmac_reg, CHCR2)) == 0x2c);
static_assert((offsetof (struct dmac_reg, SAR3)) == 0x30);
static_assert((offsetof (struct dmac_reg, DAR3)) == 0x34);
static_assert((offsetof (struct dmac_reg, DMATCR3)) == 0x38);
static_assert((offsetof (struct dmac_reg, CHCR3)) == 0x3c);
static_assert((offsetof (struct dmac_reg, DMAOR)) == 0x40);
struct cpg_reg {
reg16 FRQCR; /* Frequency control register */
reg8 _pad0[2];
reg8 STBCR; /* Standby control register */
reg8 _pad1[3];
reg16 WTCNT; /* Watchdog timer counter */
reg8 _pad2[2];
reg16 WTCSR; /* Watchdog timer control/status register */
reg8 _pad3[2];
reg8 STBCR2; /* Standby control register 2 */
};
static_assert((offsetof (struct cpg_reg, FRQCR)) == 0x0);
static_assert((offsetof (struct cpg_reg, STBCR)) == 0x4);
static_assert((offsetof (struct cpg_reg, WTCNT)) == 0x8);
static_assert((offsetof (struct cpg_reg, WTCSR)) == 0xc);
static_assert((offsetof (struct cpg_reg, STBCR2)) == 0x10);
struct rtc_reg {
reg8 R64CNT; /* 64 Hz counter */
reg8 _pad0[3];
reg8 RSECCNT; /* Second counter */
reg8 _pad1[3];
reg8 RMINCNT; /* Minute counter */
reg8 _pad2[3];
reg8 RHRCNT; /* Hour counter */
reg8 _pad3[3];
reg8 RWKCNT; /* Day-of-week counter */
reg8 _pad4[3];
reg8 RDAYCNT; /* Day counter */
reg8 _pad5[3];
reg8 RMONCNT; /* Month counter */
reg8 _pad6[3];
reg16 RYRCNT; /* Year counter */
reg8 _pad7[2];
reg8 RSECAR; /* Second alarm register */
reg8 _pad8[3];
reg8 RMINAR; /* Minute alarm register */
reg8 _pad9[3];
reg8 RHRAR; /* Hour alarm register */
reg8 _pad10[3];
reg8 RWKAR; /* Day-of-week alarm register */
reg8 _pad11[3];
reg8 RDAYAR; /* Day alarm register */
reg8 _pad12[3];
reg8 RMONAR; /* Month alarm register */
reg8 _pad13[3];
reg8 RCR1; /* RTC control register 1 */
reg8 _pad14[3];
reg8 RCR2; /* RTC control register 2 */
};
static_assert((offsetof (struct rtc_reg, R64CNT)) == 0x0);
static_assert((offsetof (struct rtc_reg, RSECCNT)) == 0x4);
static_assert((offsetof (struct rtc_reg, RMINCNT)) == 0x8);
static_assert((offsetof (struct rtc_reg, RHRCNT)) == 0xc);
static_assert((offsetof (struct rtc_reg, RWKCNT)) == 0x10);
static_assert((offsetof (struct rtc_reg, RDAYCNT)) == 0x14);
static_assert((offsetof (struct rtc_reg, RMONCNT)) == 0x18);
static_assert((offsetof (struct rtc_reg, RYRCNT)) == 0x1c);
static_assert((offsetof (struct rtc_reg, RSECAR)) == 0x20);
static_assert((offsetof (struct rtc_reg, RMINAR)) == 0x24);
static_assert((offsetof (struct rtc_reg, RHRAR)) == 0x28);
static_assert((offsetof (struct rtc_reg, RWKAR)) == 0x2c);
static_assert((offsetof (struct rtc_reg, RDAYAR)) == 0x30);
static_assert((offsetof (struct rtc_reg, RMONAR)) == 0x34);
static_assert((offsetof (struct rtc_reg, RCR1)) == 0x38);
static_assert((offsetof (struct rtc_reg, RCR2)) == 0x3c);
struct intc_reg {
reg16 ICR; /* Interrupt control register */
reg8 _pad0[2];
reg16 IPRA; /* Interrupt priority register A */
reg8 _pad1[2];
reg16 IPRB; /* Interrupt priority register B */
reg8 _pad2[2];
reg16 IPRC; /* Interrupt priority register C */
};
static_assert((offsetof (struct intc_reg, ICR)) == 0x0);
static_assert((offsetof (struct intc_reg, IPRA)) == 0x4);
static_assert((offsetof (struct intc_reg, IPRB)) == 0x8);
static_assert((offsetof (struct intc_reg, IPRC)) == 0xc);
struct tmu_reg {
reg8 TOCR; /* Timer output control register */
reg8 _pad0[3];
reg8 TSTR; /* Timer start register */
reg8 _pad1[3];
reg32 TCOR0; /* Timer constant register 0 */
reg32 TCNT0; /* Timer counter 0 */
reg16 TCR0; /* Timer control register 0 */
reg8 _pad2[2];
reg32 TCOR1; /* Timer constant register 1 */
reg32 TCNT1; /* Timer counter 1 */
reg16 TCR1; /* Timer control register 1 */
reg8 _pad3[2];
reg32 TCOR2; /* Timer constant register 2 */
reg32 TCNT2; /* Timer counter 2 */
reg16 TCR2; /* Timer control register 2 */
reg8 _pad4[2];
reg32 TCPR2; /* Timer input capture register 2 */
};
static_assert((offsetof (struct tmu_reg, TOCR)) == 0x0);
static_assert((offsetof (struct tmu_reg, TSTR)) == 0x4);
static_assert((offsetof (struct tmu_reg, TCOR0)) == 0x8);
static_assert((offsetof (struct tmu_reg, TCNT0)) == 0xc);
static_assert((offsetof (struct tmu_reg, TCR0)) == 0x10);
static_assert((offsetof (struct tmu_reg, TCOR1)) == 0x14);
static_assert((offsetof (struct tmu_reg, TCNT1)) == 0x18);
static_assert((offsetof (struct tmu_reg, TCR1)) == 0x1c);
static_assert((offsetof (struct tmu_reg, TCOR2)) == 0x20);
static_assert((offsetof (struct tmu_reg, TCNT2)) == 0x24);
static_assert((offsetof (struct tmu_reg, TCR2)) == 0x28);
static_assert((offsetof (struct tmu_reg, TCPR2)) == 0x2c);
struct sci_reg {
reg8 SCSMR1; /* Serial mode register 1 */
reg8 _pad0[3];
reg8 SCBRR1; /* Bit rate register 1 */
reg8 _pad1[3];
reg8 SCSCR1; /* Serial control register 1 */
reg8 _pad2[3];
reg8 SCTDR1; /* Transmit data register 1 */
reg8 _pad3[3];
reg8 SCSSR1; /* Serial status register 1 */
reg8 _pad4[3];
reg8 SCRDR1; /* Receive data register 1 */
reg8 _pad5[3];
reg8 SCSCMR1; /* Smart card mode register 1 */
reg8 _pad6[3];
reg8 SCSPTR1; /* Serial port register */
};
static_assert((offsetof (struct sci_reg, SCSMR1)) == 0x0);
static_assert((offsetof (struct sci_reg, SCBRR1)) == 0x4);
static_assert((offsetof (struct sci_reg, SCSCR1)) == 0x8);
static_assert((offsetof (struct sci_reg, SCTDR1)) == 0xc);
static_assert((offsetof (struct sci_reg, SCSSR1)) == 0x10);
static_assert((offsetof (struct sci_reg, SCRDR1)) == 0x14);
static_assert((offsetof (struct sci_reg, SCSCMR1)) == 0x18);
static_assert((offsetof (struct sci_reg, SCSPTR1)) == 0x1c);
struct scif_reg {
reg16 SCSMR2; /* Serial mode register 2 */
reg8 _pad0[2];
reg8 SCBRR2; /* Bit rate register 2 */
reg8 _pad1[3];
reg16 SCSCR2; /* Serial control register 2 */
reg8 _pad2[2];
reg8 SCFTDR2; /* Transmit FIFO data register 2 */
reg8 _pad3[3];
reg16 SCFSR2; /* Serial status register 2 */
reg8 _pad4[2];
reg8 SCFRDR2; /* Receive FIFO data register 2 */
reg8 _pad5[3];
reg16 SCFCR2; /* FIFO control register */
reg8 _pad6[2];
reg16 SCFDR2; /* FIFO data count register */
reg8 _pad7[2];
reg16 SCSPTR2; /* Serial port register 2 */
reg8 _pad8[2];
reg16 SCLSR2; /* Line status register 2 */
};
static_assert((offsetof (struct scif_reg, SCSMR2)) == 0x0);
static_assert((offsetof (struct scif_reg, SCBRR2)) == 0x4);
static_assert((offsetof (struct scif_reg, SCSCR2)) == 0x8);
static_assert((offsetof (struct scif_reg, SCFTDR2)) == 0xc);
static_assert((offsetof (struct scif_reg, SCFSR2)) == 0x10);
static_assert((offsetof (struct scif_reg, SCFRDR2)) == 0x14);
static_assert((offsetof (struct scif_reg, SCFCR2)) == 0x18);
static_assert((offsetof (struct scif_reg, SCFDR2)) == 0x1c);
static_assert((offsetof (struct scif_reg, SCSPTR2)) == 0x20);
static_assert((offsetof (struct scif_reg, SCLSR2)) == 0x24);
struct udi_reg {
reg16 SDIR; /* Instruction register */
reg8 _pad0[6];
reg32 SDDR; /* Data register */
};
static_assert((offsetof (struct udi_reg, SDIR)) == 0x0);
static_assert((offsetof (struct udi_reg, SDDR)) == 0x8);
struct sh7091_reg {
struct ccn_reg CCN;
reg8 _pad0[0x200000 - (sizeof (struct ccn_reg))];
struct ubc_reg UBC;
reg8 _pad1[0x600000 - (sizeof (struct ubc_reg))];
struct bsc_reg BSC;
reg8 _pad2[0x200000 - (sizeof (struct bsc_reg))];
struct dmac_reg DMAC;
reg8 _pad3[0x200000 - (sizeof (struct dmac_reg))];
struct cpg_reg CPG;
reg8 _pad4[0x80000 - (sizeof (struct cpg_reg))];
struct rtc_reg RTC;
reg8 _pad5[0x80000 - (sizeof (struct rtc_reg))];
struct intc_reg INTC;
reg8 _pad6[0x80000 - (sizeof (struct intc_reg))];
struct tmu_reg TMU;
reg8 _pad7[0x80000 - (sizeof (struct tmu_reg))];
struct sci_reg SCI;
reg8 _pad8[0x80000 - (sizeof (struct sci_reg))];
struct scif_reg SCIF;
reg8 _pad9[0x80000 - (sizeof (struct scif_reg))];
struct udi_reg UDI;
};
static_assert((offsetof (struct sh7091_reg, CCN)) == 0x0);
static_assert((offsetof (struct sh7091_reg, UBC)) == 0x200000);
static_assert((offsetof (struct sh7091_reg, BSC)) == 0x800000);
static_assert((offsetof (struct sh7091_reg, DMAC)) == 0xa00000);
static_assert((offsetof (struct sh7091_reg, CPG)) == 0xc00000);
static_assert((offsetof (struct sh7091_reg, RTC)) == 0xc80000);
static_assert((offsetof (struct sh7091_reg, INTC)) == 0xd00000);
static_assert((offsetof (struct sh7091_reg, TMU)) == 0xd80000);
static_assert((offsetof (struct sh7091_reg, SCI)) == 0xe00000);
static_assert((offsetof (struct sh7091_reg, SCIF)) == 0xe80000);
static_assert((offsetof (struct sh7091_reg, UDI)) == 0xf00000);
extern struct sh7091_reg sh7091 __asm("sh7091");
}

View File

@ -0,0 +1,994 @@
#pragma once
#include <cstdint>
namespace sh7091 {
namespace ccn {
namespace pteh {
constexpr inline uint32_t VPN(uint32_t reg) { return (reg >> 10) & 0x3fffff; }
constexpr inline uint32_t ASID(uint32_t reg) { return (reg >> 0) & 0xff; }
}
namespace ptel {
constexpr inline uint32_t PPN(uint32_t reg) { return (reg >> 10) & 0x7ffff; }
namespace v {
constexpr uint32_t invalid = 0 << 8;
constexpr uint32_t valid = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
namespace sz {
constexpr uint32_t _1_kbyte_page = 0b0000 << 4;
constexpr uint32_t _4_kbyte_page = 0b0001 << 4;
constexpr uint32_t _64_kbyte_page = 0b1000 << 4;
constexpr uint32_t _1_mbyte_page = 0b1001 << 4;
constexpr uint32_t bit_mask = 0x9 << 4;
}
namespace pr {
constexpr uint32_t read_only_in_privileged_mode = 0b00 << 5;
constexpr uint32_t read_write_in_privileged_mode = 0b01 << 5;
constexpr uint32_t read_only_in_privileged_and_user_mode = 0b10 << 5;
constexpr uint32_t read_write_in_privileged_and_user_mode = 0b11 << 5;
constexpr uint32_t bit_mask = 0x3 << 5;
}
namespace c {
constexpr uint32_t not_cacheable = 0 << 3;
constexpr uint32_t cacheable = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace d {
constexpr uint32_t write_has_not_been_performed = 0 << 2;
constexpr uint32_t write_has_been_performed = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace sh {
constexpr uint32_t pages_are_shared_by_processes = 0 << 1;
constexpr uint32_t pages_are_not_shared_by_processes = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace wt {
constexpr uint32_t copy_back_mode = 0 << 0;
constexpr uint32_t write_through_mode = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace mmucr {
constexpr inline uint32_t LRUI(uint32_t reg) { return (reg >> 26) & 0x3f; }
constexpr inline uint32_t URB(uint32_t reg) { return (reg >> 18) & 0x3f; }
constexpr inline uint32_t URC(uint32_t reg) { return (reg >> 10) & 0x3f; }
namespace sqmd {
constexpr uint32_t user_privileged_access_possible = 0 << 9;
constexpr uint32_t privileged_access_possible = 1 << 9;
constexpr uint32_t bit_mask = 0x1 << 9;
}
namespace sv {
constexpr uint32_t multiple_virtual_memory_mode = 0 << 8;
constexpr uint32_t single_virtual_memory_mode = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
namespace ti {
constexpr uint32_t invalidate_all_utlb_itlb_bits = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace at {
constexpr uint32_t mmu_disabled = 0 << 0;
constexpr uint32_t mmu_enabled = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace basra {
constexpr inline uint32_t basa(uint32_t num) { return (num & 0xff) << 0; }
}
namespace basrb {
constexpr inline uint32_t basa(uint32_t num) { return (num & 0xff) << 0; }
}
namespace ccr {
namespace iix {
constexpr uint32_t address_bits_12_5_used_for_ic_entry_selection = 0 << 15;
constexpr uint32_t address_bits_25_and_11_5_used_for_ic_entry_selection = 1 << 15;
constexpr uint32_t bit_mask = 0x1 << 15;
}
namespace ici {
constexpr uint32_t clear_v_bits_of_all_ic_entries = 1 << 11;
constexpr uint32_t bit_mask = 0x1 << 11;
}
namespace ice {
constexpr uint32_t ic_not_used = 0 << 8;
constexpr uint32_t ic_used = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
namespace oix {
constexpr uint32_t address_bits_13_5_used_for_oc_entry_selection = 0 << 7;
constexpr uint32_t address_bits_25_and_12_5_used_for_oc_entry_selection = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
namespace ora {
constexpr uint32_t _16_kbytes_used_as_cache = 0 << 5;
constexpr uint32_t _8_kbytes_used_as_cache_8_kbytes_used_as_ram = 1 << 5;
constexpr uint32_t bit_mask = 0x1 << 5;
}
namespace oci {
constexpr uint32_t clear_v_and_u_bits_of_all_oc_entries = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace cb {
constexpr uint32_t write_through_mode = 0 << 2;
constexpr uint32_t copy_back_mode = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace wt {
constexpr uint32_t copy_back_mode = 0 << 1;
constexpr uint32_t write_through_mode = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace oce {
constexpr uint32_t oc_not_used = 0 << 0;
constexpr uint32_t oc_used = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace tra {
constexpr inline uint32_t imm(uint32_t reg) { return (reg >> 2) & 0xff; }
}
namespace expevt {
constexpr inline uint32_t exception_code(uint32_t reg) { return (reg >> 0) & 0xfff; }
}
namespace intevt {
constexpr inline uint32_t exception_code(uint32_t reg) { return (reg >> 0) & 0xfff; }
}
namespace ptea {
namespace tc {
constexpr uint32_t area_5_is_used = 0 << 3;
constexpr uint32_t area_6_is_used = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace sa {
constexpr uint32_t undefined = 0b000 << 0;
constexpr uint32_t variable_size_io_space = 0b001 << 0;
constexpr uint32_t _8_bit_io_space = 0b010 << 0;
constexpr uint32_t _16_bit_io_space = 0b011 << 0;
constexpr uint32_t _8_bit_common_memory_space = 0b100 << 0;
constexpr uint32_t _16_bit_common_memory_space = 0b101 << 0;
constexpr uint32_t _8_bit_attribute_memory_space = 0b110 << 0;
constexpr uint32_t _16_bit_attribute_memory_space = 0b111 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
namespace qacr0 {
constexpr inline uint32_t area(uint32_t num) { return (num & 0x7) << 2; }
}
namespace qacr1 {
constexpr inline uint32_t area(uint32_t num) { return (num & 0x7) << 2; }
}
}
namespace dmac {
namespace dmatcr {
constexpr inline uint32_t transfer_count(uint32_t num) { return (num & 0xffffff) << 0; }
}
namespace chcr {
namespace ssa {
constexpr uint32_t reserved_in_pcmcia_access = 0b000 << 29;
constexpr uint32_t dynamic_bus_sizing_io_space = 0b001 << 29;
constexpr uint32_t _8_bit_io_space = 0b010 << 29;
constexpr uint32_t _16_bit_io_space = 0b011 << 29;
constexpr uint32_t _8_bit_common_memory_space = 0b100 << 29;
constexpr uint32_t _16_bit_common_memory_space = 0b101 << 29;
constexpr uint32_t _8_bit_attribute_memory_space = 0b110 << 29;
constexpr uint32_t _16_bit_attribute_memory_space = 0b111 << 29;
constexpr uint32_t bit_mask = 0x7 << 29;
}
namespace stc {
constexpr uint32_t c5_space_wait_cycle_selection = 0 << 28;
constexpr uint32_t c6_space_wait_cycle_selection = 1 << 28;
constexpr uint32_t bit_mask = 0x1 << 28;
}
namespace dsa {
constexpr uint32_t reserved_in_pcmcia_access = 0b000 << 25;
constexpr uint32_t dynamic_bus_sizing_io_space = 0b001 << 25;
constexpr uint32_t _8_bit_io_space = 0b010 << 25;
constexpr uint32_t _16_bit_io_space = 0b011 << 25;
constexpr uint32_t _8_bit_common_memory_space = 0b100 << 25;
constexpr uint32_t _16_bit_common_memory_space = 0b101 << 25;
constexpr uint32_t _8_bit_attribute_memory_space = 0b110 << 25;
constexpr uint32_t _16_bit_attribute_memory_space = 0b111 << 25;
constexpr uint32_t bit_mask = 0x7 << 25;
}
namespace dtc {
constexpr uint32_t c5_space_wait_cycle_selection = 0 << 24;
constexpr uint32_t c6_space_wait_cycle_selection = 1 << 24;
constexpr uint32_t bit_mask = 0x1 << 24;
}
namespace ds {
constexpr uint32_t low_level_detection = 0 << 19;
constexpr uint32_t falling_edge_detection = 1 << 19;
constexpr uint32_t bit_mask = 0x1 << 19;
}
namespace rl {
constexpr uint32_t drak_is_an_active_high = 0 << 18;
constexpr uint32_t drak_is_an_active_low = 1 << 18;
constexpr uint32_t bit_mask = 0x1 << 18;
}
namespace am {
constexpr uint32_t dack_is_output_in_read_cycle = 0 << 17;
constexpr uint32_t dack_is_output_in_write_cycle = 1 << 17;
constexpr uint32_t bit_mask = 0x1 << 17;
}
namespace al {
constexpr uint32_t active_high_output = 0 << 16;
constexpr uint32_t active_low_output = 1 << 16;
constexpr uint32_t bit_mask = 0x1 << 16;
}
namespace dm {
constexpr uint32_t destination_address_fixed = 0b00 << 14;
constexpr uint32_t destination_address_incremented = 0b01 << 14;
constexpr uint32_t destination_address_decremented = 0b10 << 14;
constexpr uint32_t bit_mask = 0x3 << 14;
}
namespace sm {
constexpr uint32_t source_address_fixed = 0b00 << 12;
constexpr uint32_t source_address_incremented = 0b01 << 12;
constexpr uint32_t source_address_decremented = 0b10 << 12;
constexpr uint32_t bit_mask = 0x3 << 12;
}
namespace rs {
constexpr inline uint32_t resource_select(uint32_t num) { return (num & 0xf) << 8; }
constexpr uint32_t bit_mask = 0xf << 8;
}
namespace tm {
constexpr uint32_t cycle_steal_mode = 0 << 7;
constexpr uint32_t cycle_burst_mode = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
namespace ts {
constexpr uint32_t _64_bit = 0b000 << 4;
constexpr uint32_t _8_bit = 0b001 << 4;
constexpr uint32_t _16_bit = 0b010 << 4;
constexpr uint32_t _32_bit = 0b011 << 4;
constexpr uint32_t _32_byte = 0b100 << 4;
constexpr uint32_t bit_mask = 0x7 << 4;
}
namespace ie {
constexpr uint32_t interrupt_request_not_generated = 0 << 2;
constexpr uint32_t interrupt_request_generated = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace te {
constexpr uint32_t transfers_not_completed = 0 << 1;
constexpr uint32_t transfers_completed = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace de {
constexpr uint32_t channel_operation_disabled = 0 << 0;
constexpr uint32_t channel_operation_enabled = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace dmaor {
namespace ddt {
constexpr uint32_t normal_dma_mode = 0 << 15;
constexpr uint32_t on_demand_data_transfer_mode = 1 << 15;
constexpr uint32_t bit_mask = 0x1 << 15;
}
namespace pr {
constexpr uint32_t ch0_ch1_ch2_ch3 = 0b00 << 8;
constexpr uint32_t ch0_ch2_ch3_ch1 = 0b01 << 8;
constexpr uint32_t ch2_ch0_ch1_ch3 = 0b10 << 8;
constexpr uint32_t round_robin = 0b11 << 8;
constexpr uint32_t bit_mask = 0x3 << 8;
}
namespace ae {
constexpr uint32_t no_address_error__dma_transfer_enabled = 0 << 2;
constexpr uint32_t address_error__dma_transfer_disabled = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace nmif {
constexpr uint32_t no_nmi__dma_transfer_enabled = 0 << 1;
constexpr uint32_t nmi__dma_transfer_disabled = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace dme {
constexpr uint32_t operation_disabled_on_all_channels = 0 << 0;
constexpr uint32_t operation_enabled_on_all_channels = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
}
namespace intc {
namespace icr {
namespace nmil {
constexpr uint32_t pin_input_level_is_low = 0 << 15;
constexpr uint32_t pin_input_level_is_high = 1 << 15;
constexpr uint32_t bit_mask = 0x1 << 15;
}
namespace mai {
constexpr uint32_t interrupts_enabled_while_nmi_pin_is_low = 0 << 14;
constexpr uint32_t interrupts_disabled_while_nmi_pin_is_low = 1 << 14;
constexpr uint32_t bit_mask = 0x1 << 14;
}
namespace nmib {
constexpr uint32_t interrupt_requests_witheld = 0 << 9;
constexpr uint32_t interrupt_requests_detected = 1 << 9;
constexpr uint32_t bit_mask = 0x1 << 9;
}
namespace nmie {
constexpr uint32_t interrupt_on_falling_edge_of_nmi = 0 << 8;
constexpr uint32_t interrupt_on_rising_edge_of_nmi = 1 << 8;
constexpr uint32_t bit_mask = 0x1 << 8;
}
namespace irlm {
constexpr uint32_t level_encoded_interrupt_requests = 0 << 7;
constexpr uint32_t independent_interrupt_request = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
}
namespace ipra {
constexpr inline uint32_t TMU0(uint32_t num) { return (num & 0xf) << 12; }
constexpr inline uint32_t TMU1(uint32_t num) { return (num & 0xf) << 8; }
constexpr inline uint32_t TMU2(uint32_t num) { return (num & 0xf) << 4; }
constexpr inline uint32_t RTC(uint32_t num) { return (num & 0xf) << 0; }
}
namespace iprb {
constexpr inline uint32_t WDT(uint32_t num) { return (num & 0xf) << 12; }
constexpr inline uint32_t REF(uint32_t num) { return (num & 0xf) << 8; }
constexpr inline uint32_t SCI1(uint32_t num) { return (num & 0xf) << 4; }
}
namespace iprc {
constexpr inline uint32_t GPIO(uint32_t num) { return (num & 0xf) << 12; }
constexpr inline uint32_t DMAC(uint32_t num) { return (num & 0xf) << 8; }
constexpr inline uint32_t SCIF(uint32_t num) { return (num & 0xf) << 4; }
constexpr inline uint32_t UDI(uint32_t num) { return (num & 0xf) << 0; }
}
}
namespace tmu {
namespace tocr {
namespace tcoe {
constexpr uint32_t tclk_is_external_clock_or_input_capture = 0 << 0;
constexpr uint32_t tclk_is_on_chip_rtc = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace tstr {
namespace str2 {
constexpr uint32_t counter_start = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace str1 {
constexpr uint32_t counter_start = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace str0 {
constexpr uint32_t counter_start = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace tcr0 {
constexpr uint32_t UNF = 1 << 8;
constexpr uint32_t UNIE = 1 << 5;
namespace ckeg {
constexpr uint32_t rising = 0b00 << 3;
constexpr uint32_t falling = 0b01 << 3;
constexpr uint32_t rising_falling = 0b10 << 3;
constexpr uint32_t bit_mask = 0x3 << 3;
}
namespace tpsc {
constexpr uint32_t p_phi_4 = 0b000 << 0;
constexpr uint32_t p_phi_16 = 0b001 << 0;
constexpr uint32_t p_phi_64 = 0b010 << 0;
constexpr uint32_t p_phi_256 = 0b011 << 0;
constexpr uint32_t p_phi_1024 = 0b100 << 0;
constexpr uint32_t rtc_output = 0b110 << 0;
constexpr uint32_t external = 0b111 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
namespace tcr1 {
constexpr uint32_t UNF = 1 << 8;
constexpr uint32_t UNIE = 1 << 5;
namespace ckeg {
constexpr uint32_t rising = 0b00 << 3;
constexpr uint32_t falling = 0b01 << 3;
constexpr uint32_t rising_falling = 0b10 << 3;
constexpr uint32_t bit_mask = 0x3 << 3;
}
namespace tpsc {
constexpr uint32_t p_phi_4 = 0b000 << 0;
constexpr uint32_t p_phi_16 = 0b001 << 0;
constexpr uint32_t p_phi_64 = 0b010 << 0;
constexpr uint32_t p_phi_256 = 0b011 << 0;
constexpr uint32_t p_phi_1024 = 0b100 << 0;
constexpr uint32_t rtc_output = 0b110 << 0;
constexpr uint32_t external = 0b111 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
namespace tcr2 {
constexpr uint32_t ICPF = 1 << 9;
constexpr uint32_t UNF = 1 << 8;
namespace icpe {
constexpr uint32_t disabled = 0b00 << 6;
constexpr uint32_t enabled = 0b10 << 6;
constexpr uint32_t enabled_with_interrupts = 0b11 << 6;
constexpr uint32_t bit_mask = 0x3 << 6;
}
constexpr uint32_t UNIE = 1 << 5;
namespace ckeg {
constexpr uint32_t rising = 0b00 << 3;
constexpr uint32_t falling = 0b01 << 3;
constexpr uint32_t rising_falling = 0b10 << 3;
constexpr uint32_t bit_mask = 0x3 << 3;
}
namespace tpsc {
constexpr uint32_t p_phi_4 = 0b000 << 0;
constexpr uint32_t p_phi_16 = 0b001 << 0;
constexpr uint32_t p_phi_64 = 0b010 << 0;
constexpr uint32_t p_phi_256 = 0b011 << 0;
constexpr uint32_t p_phi_1024 = 0b100 << 0;
constexpr uint32_t rtc_output = 0b110 << 0;
constexpr uint32_t external = 0b111 << 0;
constexpr uint32_t bit_mask = 0x7 << 0;
}
}
}
namespace scif {
namespace scsmr2 {
namespace chr {
constexpr uint32_t _8_bit_data = 0 << 6;
constexpr uint32_t _7_bit_data = 1 << 6;
constexpr uint32_t bit_mask = 0x1 << 6;
}
namespace pe {
constexpr uint32_t parity_disabled = 0 << 5;
constexpr uint32_t parity_enabled = 1 << 5;
constexpr uint32_t bit_mask = 0x1 << 5;
}
namespace oe {
constexpr uint32_t even_parity = 0 << 4;
constexpr uint32_t odd_parity = 1 << 4;
constexpr uint32_t bit_mask = 0x1 << 4;
}
namespace stop {
constexpr uint32_t _1_stop_bit = 0 << 3;
constexpr uint32_t _2_stop_bits = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace cks {
constexpr uint32_t p_phi_clock = 0b00 << 0;
constexpr uint32_t p_phi_4_clock = 0b01 << 0;
constexpr uint32_t p_phi_16_clock = 0b10 << 0;
constexpr uint32_t p_phi_64_clock = 0b11 << 0;
constexpr uint32_t bit_mask = 0x3 << 0;
}
}
namespace scscr2 {
namespace tie {
constexpr uint32_t transmit_fifo_data_empty_interrupt_disabled = 0 << 7;
constexpr uint32_t transmit_fifo_data_empty_interrupt_enabled = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
namespace rie {
constexpr uint32_t request_disabled = 0 << 6;
constexpr uint32_t request_enabled = 1 << 6;
constexpr uint32_t bit_mask = 0x1 << 6;
}
namespace te {
constexpr uint32_t transmission_disabled = 0 << 5;
constexpr uint32_t transmission_enabled = 1 << 5;
constexpr uint32_t bit_mask = 0x1 << 5;
}
namespace re {
constexpr uint32_t reception_disabled = 0 << 4;
constexpr uint32_t reception_enabled = 1 << 4;
constexpr uint32_t bit_mask = 0x1 << 4;
}
namespace reie {
constexpr uint32_t requests_disabled = 0 << 3;
constexpr uint32_t requests_enabled = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace cke1 {
constexpr uint32_t sck2_pin_functions_as_input_pin = 0 << 1;
constexpr uint32_t sck2_pin_functions_as_clock_input = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
}
namespace scfsr2 {
namespace per3_0 {
constexpr inline uint32_t number_of_parity_errors(uint32_t reg) { return (reg >> 12) & 0xf; }
constexpr uint32_t bit_mask = 0xf << 12;
}
namespace fer3_0 {
constexpr inline uint32_t number_of_framing_errors(uint32_t reg) { return (reg >> 8) & 0xf; }
constexpr uint32_t bit_mask = 0xf << 8;
}
namespace er {
constexpr uint32_t no_framing_error_or_parity_error = 0 << 7;
constexpr uint32_t framing_error_or_parity_error = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
namespace tend {
constexpr uint32_t transmission_in_progress = 0 << 6;
constexpr uint32_t transmission_has_ended = 1 << 6;
constexpr uint32_t bit_mask = 0x1 << 6;
}
namespace tdfe {
constexpr uint32_t transmit_data_bytes_does_exceed_trigger = 0 << 5;
constexpr uint32_t transmit_data_bytes_does_not_exceed_trigger = 1 << 5;
constexpr uint32_t bit_mask = 0x1 << 5;
}
namespace brk {
constexpr uint32_t break_not_received = 0 << 4;
constexpr uint32_t break_received = 1 << 4;
constexpr uint32_t bit_mask = 0x1 << 4;
}
namespace fer {
constexpr uint32_t no_framing_error = 0 << 3;
constexpr uint32_t framing_error = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace per {
constexpr uint32_t parity_error = 0 << 2;
constexpr uint32_t no_parity_error = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace rdf {
constexpr uint32_t receive_data_bytes_less_than_receive_trigger = 0 << 1;
constexpr uint32_t receive_data_bytes_greater_than_or_equal_receive_trigger = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace dr {
constexpr uint32_t reception_is_in_progress = 0 << 0;
constexpr uint32_t no_further_data_has_arrived = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace scfcr2 {
namespace rtrg {
constexpr uint32_t trigger_on_1_byte = 0b00 << 6;
constexpr uint32_t trigger_on_4_bytes = 0b01 << 6;
constexpr uint32_t trigger_on_8_bytes = 0b10 << 6;
constexpr uint32_t trigger_on_14_byte = 0b11 << 6;
constexpr uint32_t bit_mask = 0x3 << 6;
}
namespace ttrg {
constexpr uint32_t trigger_on_8_bytes = 0b00 << 4;
constexpr uint32_t trigger_on_4_bytes = 0b01 << 4;
constexpr uint32_t trigger_on_2_bytes = 0b10 << 4;
constexpr uint32_t trigger_on_1_bytes = 0b11 << 4;
constexpr uint32_t bit_mask = 0x3 << 4;
}
namespace mce {
constexpr uint32_t modem_signals_disabled = 0 << 3;
constexpr uint32_t modem_signals_enabled = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace tfrst {
constexpr uint32_t reset_operation_disabled = 0 << 2;
constexpr uint32_t reset_operation_enabled = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
namespace rfrst {
constexpr uint32_t reset_operation_disabled = 0 << 1;
constexpr uint32_t reset_operation_enabled = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace loop {
constexpr uint32_t loopback_test_disabled = 0 << 0;
constexpr uint32_t loopback_test_enabled = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace scfdr2 {
constexpr inline uint32_t transmit_data_bytes(uint32_t reg) { return (reg >> 8) & 0x1f; }
constexpr inline uint32_t receive_data_bytes(uint32_t reg) { return (reg >> 0) & 0x1f; }
}
namespace scsptr2 {
namespace rtsio {
constexpr uint32_t rtsdt_not_output_to_rts2 = 0 << 7;
constexpr uint32_t rtsdt_output_to_rts2 = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
namespace rtsdt {
constexpr uint32_t input_output_data_is_low_level = 0 << 6;
constexpr uint32_t input_output_data_is_high_level = 1 << 6;
constexpr uint32_t bit_mask = 0x1 << 6;
}
namespace ctsio {
constexpr uint32_t ctsdt_is_not_output_to_cts2 = 0 << 5;
constexpr uint32_t ctsdt_is_output_to_cts2 = 1 << 5;
constexpr uint32_t bit_mask = 0x1 << 5;
}
namespace ctsdt {
constexpr uint32_t input_output_data_is_low_level = 0 << 4;
constexpr uint32_t input_output_data_is_high_level = 1 << 4;
constexpr uint32_t bit_mask = 0x1 << 4;
}
namespace spb2io {
constexpr uint32_t spb2dt_is_not_output_to_txd2 = 0 << 1;
constexpr uint32_t spb2dt_is_output_to_txd2 = 1 << 1;
constexpr uint32_t bit_mask = 0x1 << 1;
}
namespace spb2dt {
constexpr uint32_t input_output_data_is_low_level = 0 << 0;
constexpr uint32_t input_output_data_is_high_level = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
namespace sclsr2 {
namespace orer {
constexpr uint32_t overrun_error_occured = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
}
namespace sh {
namespace sr {
constexpr uint32_t md = 1 << 30;
constexpr uint32_t rb = 1 << 29;
constexpr uint32_t bl = 1 << 28;
constexpr uint32_t fd = 1 << 15;
constexpr uint32_t m = 1 << 9;
constexpr uint32_t q = 1 << 8;
constexpr inline uint32_t imask(uint32_t num) { return (num & 0xf) << 4; }
constexpr uint32_t s = 1 << 1;
constexpr uint32_t t = 1 << 0;
}
namespace fpscr {
constexpr uint32_t fr = 1 << 21;
constexpr uint32_t sz = 1 << 20;
constexpr uint32_t pr = 1 << 19;
constexpr uint32_t dn = 1 << 18;
namespace cause {
constexpr uint32_t fpu_error = 0b100000 << 12;
constexpr uint32_t invalid_operation = 0b010000 << 12;
constexpr uint32_t division_by_zero = 0b001000 << 12;
constexpr uint32_t overflow = 0b000100 << 12;
constexpr uint32_t underflow = 0b000010 << 12;
constexpr uint32_t inexact = 0b000001 << 12;
constexpr uint32_t bit_mask = 0x3f << 12;
}
namespace enabled {
constexpr uint32_t invalid_operation = 0b10000 << 7;
constexpr uint32_t division_by_zero = 0b01000 << 7;
constexpr uint32_t overflow = 0b00100 << 7;
constexpr uint32_t underflow = 0b00010 << 7;
constexpr uint32_t inexact = 0b00001 << 7;
constexpr uint32_t bit_mask = 0x1f << 7;
}
namespace flag {
constexpr uint32_t invalid_operation = 0b10000 << 2;
constexpr uint32_t division_by_zero = 0b01000 << 2;
constexpr uint32_t overflow = 0b00100 << 2;
constexpr uint32_t underflow = 0b00010 << 2;
constexpr uint32_t inexact = 0b00001 << 2;
constexpr uint32_t bit_mask = 0x1f << 2;
}
namespace rm {
constexpr uint32_t round_to_nearest = 0b00 << 0;
constexpr uint32_t round_to_zero = 0b01 << 0;
constexpr uint32_t bit_mask = 0x3 << 0;
}
}
}
namespace ubc {
namespace bamra {
namespace bama {
constexpr uint32_t all_bara_bits_are_included_in_break_conditions = 0b0000 << 0;
constexpr uint32_t lower_10_bits_of_bara_are_not_included_in_break_conditions = 0b0001 << 0;
constexpr uint32_t lower_12_bits_of_bara_are_not_included_in_break_conditions = 0b0010 << 0;
constexpr uint32_t all_bara_bits_are_not_included_in_break_conditions = 0b0011 << 0;
constexpr uint32_t lower_16_bits_of_bara_are_not_included_in_break_conditions = 0b1000 << 0;
constexpr uint32_t lower_20_bits_of_bara_are_not_included_in_break_conditions = 0b1001 << 0;
constexpr uint32_t bit_mask = 0xb << 0;
}
namespace basma {
constexpr uint32_t all_basra_bits_are_included_in_break_conditions = 0 << 2;
constexpr uint32_t no_basra_bits_are_included_in_break_conditions = 1 << 2;
constexpr uint32_t bit_mask = 0x1 << 2;
}
}
namespace bbra {
namespace sza {
constexpr uint32_t operand_size_is_not_included_in_break_conditions = 0b00 << 0;
constexpr uint32_t byte_access_is_used_as_break_condition = 0b01 << 0;
constexpr uint32_t word_access_is_used_as_break_condition = 0b10 << 0;
constexpr uint32_t longword_access_is_used_as_break_condition = 0b11 << 0;
constexpr uint32_t quadword_access_is_used_as_break_condition = 0b1000000 << 0;
constexpr uint32_t bit_mask = 0x43 << 0;
}
namespace ida {
constexpr uint32_t condition_comparison_is_not_performed = 0b00 << 4;
constexpr uint32_t instruction_access_cycle_is_used_as_break_condition = 0b01 << 4;
constexpr uint32_t operand_access_cycle_is_used_as_break_condition = 0b10 << 4;
constexpr uint32_t instruction_access_cycle_or_operand_access_cycle_is_used_as_break_condition = 0b11 << 4;
constexpr uint32_t bit_mask = 0x3 << 4;
}
namespace rwa {
constexpr uint32_t condition_comparison_is_not_performed = 0b00 << 2;
constexpr uint32_t read_cycle_is_used_as_break_condition = 0b01 << 2;
constexpr uint32_t write_cycle_is_used_as_break_condition = 0b10 << 2;
constexpr uint32_t read_cycle_or_write_cycle_is_used_as_break_condition = 0b11 << 2;
constexpr uint32_t bit_mask = 0x3 << 2;
}
}
namespace brcr {
namespace cmfa {
constexpr uint32_t channel_a_break_condition_is_not_matched = 0 << 15;
constexpr uint32_t channel_a_break_condition_match_has_occured = 1 << 15;
constexpr uint32_t bit_mask = 0x1 << 15;
}
namespace cmfb {
constexpr uint32_t channel_b_break_condition_is_not_matched = 0 << 14;
constexpr uint32_t channel_b_break_condition_match_has_occured = 1 << 14;
constexpr uint32_t bit_mask = 0x1 << 14;
}
namespace pcba {
constexpr uint32_t channel_a_pc_break_is_effected_before_instruction_execution = 0 << 10;
constexpr uint32_t channel_a_pc_break_is_effected_after_instruction_execution = 1 << 10;
constexpr uint32_t bit_mask = 0x1 << 10;
}
namespace dbeb {
constexpr uint32_t data_bus_condition_is_not_included_in_channel_b_conditions = 0 << 7;
constexpr uint32_t data_bus_condition_is_included_in_channel_b_conditions = 1 << 7;
constexpr uint32_t bit_mask = 0x1 << 7;
}
namespace pcbb {
constexpr uint32_t channel_b_pc_break_is_effected_before_instruction_execution = 0 << 6;
constexpr uint32_t channel_b_pc_break_is_effected_after_instruction_execution = 1 << 6;
constexpr uint32_t bit_mask = 0x1 << 6;
}
namespace seq {
constexpr uint32_t channel_a_and_b_comparison_are_performed_as_independent_condition = 0 << 3;
constexpr uint32_t channel_a_and_b_comparison_are_performed_as_sequential_condition = 1 << 3;
constexpr uint32_t bit_mask = 0x1 << 3;
}
namespace ubde {
constexpr uint32_t user_break_debug_function_is_not_used = 0 << 0;
constexpr uint32_t user_break_debug_function_is_used = 1 << 0;
constexpr uint32_t bit_mask = 0x1 << 0;
}
}
}
}

View File

@ -0,0 +1,73 @@
#pragma once
#include "sh7091/sh7091.hpp"
#include "sh7091/pref.hpp"
#include "memorymap.hpp"
namespace sh7091 {
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,
const void * src,
int length)
{
uint32_t out = reinterpret_cast<uint32_t>(out_addr);
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(out);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(out);
volatile uint32_t * base = (volatile uint32_t *)&store_queue[(out & 0x03ffffe0)];
const uint32_t * src32 = reinterpret_cast<const uint32_t *>(src);
length = (length + 31) & ~31; // round up to nearest multiple of 32
while (length > 0) {
base[0] = src32[0];
base[1] = src32[1];
base[2] = src32[2];
base[3] = src32[3];
base[4] = src32[4];
base[5] = src32[5];
base[6] = src32[6];
base[7] = src32[7];
pref(&base[0])
length -= 32;
base += 8;
src32 += 8;
}
}
static inline void zeroize(void * out_addr,
int length,
const uint32_t value) __attribute__((always_inline));
static inline void zeroize(void * out_addr,
int length,
const uint32_t value)
{
uint32_t out = reinterpret_cast<uint32_t>(out_addr);
sh7091.CCN.QACR0 = sh7091::ccn::qacr0::address(out);
sh7091.CCN.QACR1 = sh7091::ccn::qacr1::address(out);
volatile uint32_t * base = (volatile uint32_t *)&store_queue[(out & 0x03ffffe0)];
length = (length + 31) & ~31; // round up to nearest multiple of 32
while (length > 0) {
base[0] = value;
base[1] = value;
base[2] = value;
base[3] = value;
base[4] = value;
base[5] = value;
base[6] = value;
base[7] = value;
pref(&base[0]);
length -= 32;
base += 8;
}
}
}
}

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

@ -0,0 +1,309 @@
#pragma once
#include "reg.hpp"
namespace systembus {
struct systembus_reg {
reg32 C2DSTAT; /* CH2-DMA destination address */
reg32 C2DLEN; /* CH2-DMA length */
reg32 C2DST; /* CH2-DMA start */
reg8 _pad0[4];
reg32 SDSTAW; /* Sort-DMA start link table address */
reg32 SDBAAW; /* Sort-DMA link base address */
reg32 SDWLT; /* Sort-DMA link address bit width */
reg32 SDLAS; /* Sort-DMA link address shift control */
reg32 SDST; /* Sort-DMA start */
reg8 _pad1[28];
reg32 DBREQM; /* DBREQ# signal mask control */
reg32 BAVLWC; /* BAVL# signal wait count */
reg32 C2DPYRC; /* DMA (TA/Root Bus) priority count */
reg32 DMAXL; /* CH2-DMA maximum burst length */
reg8 _pad2[48];
reg32 TFREM; /* TA FIFO remaining amount */
reg32 LMMODE0; /* Via TA texture memory bus select 0 */
reg32 LMMODE1; /* Via TA texture memory bus select 1 */
reg32 FFST; /* FIFO status */
reg32 SFRES; /* System reset */
reg8 _pad3[8];
reg32 SBREV; /* System bus revision number */
reg32 RBSPLT; /* SH4 Root Bus split enable */
reg8 _pad4[92];
reg32 ISTNRM; /* Normal interrupt status */
reg32 ISTEXT; /* External interrupt status */
reg32 ISTERR; /* Error interrupt status */
reg8 _pad5[4];
reg32 IML2NRM; /* Level 2 normal interrupt mask */
reg32 IML2EXT; /* Level 2 external interrupt mask */
reg32 IML2ERR; /* Level 2 error interrupt mask */
reg8 _pad6[4];
reg32 IML4NRM; /* Level 4 normal interrupt mask */
reg32 IML4EXT; /* Level 4 external interrupt mask */
reg32 IML4ERR; /* Level 4 error interrupt mask */
reg8 _pad7[4];
reg32 IML6NRM; /* Level 6 normal interrupt mask */
reg32 IML6EXT; /* Level 6 external interrupt mask */
reg32 IML6ERR; /* Level 6 error interrupt mask */
reg8 _pad8[4];
reg32 PDTNRM; /* Normal interrupt PVR-DMA startup mask */
reg32 PDTEXT; /* External interrupt PVR-DMA startup mask */
reg8 _pad9[8];
reg32 G2DTNRM; /* Normal 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, C2DLEN)) == 0x4);
static_assert((offsetof (struct systembus_reg, C2DST)) == 0x8);
static_assert((offsetof (struct systembus_reg, SDSTAW)) == 0x10);
static_assert((offsetof (struct systembus_reg, SDBAAW)) == 0x14);
static_assert((offsetof (struct systembus_reg, SDWLT)) == 0x18);
static_assert((offsetof (struct systembus_reg, SDLAS)) == 0x1c);
static_assert((offsetof (struct systembus_reg, SDST)) == 0x20);
static_assert((offsetof (struct systembus_reg, DBREQM)) == 0x40);
static_assert((offsetof (struct systembus_reg, BAVLWC)) == 0x44);
static_assert((offsetof (struct systembus_reg, C2DPYRC)) == 0x48);
static_assert((offsetof (struct systembus_reg, DMAXL)) == 0x4c);
static_assert((offsetof (struct systembus_reg, TFREM)) == 0x80);
static_assert((offsetof (struct systembus_reg, LMMODE0)) == 0x84);
static_assert((offsetof (struct systembus_reg, LMMODE1)) == 0x88);
static_assert((offsetof (struct systembus_reg, FFST)) == 0x8c);
static_assert((offsetof (struct systembus_reg, SFRES)) == 0x90);
static_assert((offsetof (struct systembus_reg, SBREV)) == 0x9c);
static_assert((offsetof (struct systembus_reg, RBSPLT)) == 0xa0);
static_assert((offsetof (struct systembus_reg, ISTNRM)) == 0x100);
static_assert((offsetof (struct systembus_reg, ISTEXT)) == 0x104);
static_assert((offsetof (struct systembus_reg, ISTERR)) == 0x108);
static_assert((offsetof (struct systembus_reg, IML2NRM)) == 0x110);
static_assert((offsetof (struct systembus_reg, IML2EXT)) == 0x114);
static_assert((offsetof (struct systembus_reg, IML2ERR)) == 0x118);
static_assert((offsetof (struct systembus_reg, IML4NRM)) == 0x120);
static_assert((offsetof (struct systembus_reg, IML4EXT)) == 0x124);
static_assert((offsetof (struct systembus_reg, IML4ERR)) == 0x128);
static_assert((offsetof (struct systembus_reg, IML6NRM)) == 0x130);
static_assert((offsetof (struct systembus_reg, IML6EXT)) == 0x134);
static_assert((offsetof (struct systembus_reg, IML6ERR)) == 0x138);
static_assert((offsetof (struct systembus_reg, PDTNRM)) == 0x140);
static_assert((offsetof (struct systembus_reg, PDTEXT)) == 0x144);
static_assert((offsetof (struct systembus_reg, G2DTNRM)) == 0x150);
static_assert((offsetof (struct systembus_reg, G2DTEXT)) == 0x154);
struct maple_if_reg {
reg8 _pad0[4];
reg32 MDSTAR; /* Maple-DMA command table address */
reg8 _pad1[8];
reg32 MDTSEL; /* Maple-DMA trigger select */
reg32 MDEN; /* Maple-DMA enable */
reg32 MDST; /* Maple-DMA start */
reg8 _pad2[100];
reg32 MSYS; /* Maple system control */
reg32 MST; /* Maple status */
reg32 MSHTCL; /* Maple-DMA hard trigger clear */
reg32 MDAPRO; /* Maple-DMA address range */
reg8 _pad3[88];
reg32 MMSEL; /* Maple MSP selection */
reg8 _pad4[8];
reg32 MTXDAD; /* Maple TXD address counter */
reg32 MRXDAD; /* Maple RXD address counter */
reg32 MRXDBD; /* Maple RXD address base */
};
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, MDEN)) == 0x14);
static_assert((offsetof (struct maple_if_reg, MDST)) == 0x18);
static_assert((offsetof (struct maple_if_reg, MSYS)) == 0x80);
static_assert((offsetof (struct maple_if_reg, MST)) == 0x84);
static_assert((offsetof (struct maple_if_reg, MSHTCL)) == 0x88);
static_assert((offsetof (struct maple_if_reg, MDAPRO)) == 0x8c);
static_assert((offsetof (struct maple_if_reg, MMSEL)) == 0xe8);
static_assert((offsetof (struct maple_if_reg, MTXDAD)) == 0xf4);
static_assert((offsetof (struct maple_if_reg, MRXDAD)) == 0xf8);
static_assert((offsetof (struct maple_if_reg, MRXDBD)) == 0xfc);
struct g1_if_reg {
reg8 _pad0[4];
reg32 GDSTAR; /* GD-DMA start address */
reg32 GDLEN; /* GD-DMA length */
reg32 GDDIR; /* GD-DMA direction */
reg8 _pad1[4];
reg32 GDEN; /* GD-DMA enable */
reg32 GDST; /* GD-DMA start */
reg8 _pad2[100];
reg32 G1RRC; /* System ROM read access timing */
reg32 G1RWC; /* System ROM write access timing */
reg32 G1FRC; /* Flash ROM read access timing */
reg32 G1FWC; /* Flash ROM write access timing */
reg32 G1CRC; /* GD PIO read access timing */
reg32 G1CWC; /* GD PIO write access timing */
reg8 _pad3[8];
reg32 G1GDRC; /* GD-DMA read access timing */
reg32 G1GDWC; /* GD-DMA write access timing */
reg8 _pad4[8];
reg32 G1SYSM; /* System mode */
reg32 G1CRDYC; /* G1IORDY signal control */
reg32 GDAPRO; /* GD-DMA address range */
reg8 _pad5[40];
reg32 GDUNLOCK; /* (undocumented unlock register) */
reg8 _pad6[12];
reg32 GDSTARD; /* GD-DMA address count (on Root Bus) */
reg32 GDLEND; /* GD-DMA transfer counter */
};
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, GDDIR)) == 0xc);
static_assert((offsetof (struct g1_if_reg, GDEN)) == 0x14);
static_assert((offsetof (struct g1_if_reg, GDST)) == 0x18);
static_assert((offsetof (struct g1_if_reg, G1RRC)) == 0x80);
static_assert((offsetof (struct g1_if_reg, G1RWC)) == 0x84);
static_assert((offsetof (struct g1_if_reg, G1FRC)) == 0x88);
static_assert((offsetof (struct g1_if_reg, G1FWC)) == 0x8c);
static_assert((offsetof (struct g1_if_reg, G1CRC)) == 0x90);
static_assert((offsetof (struct g1_if_reg, G1CWC)) == 0x94);
static_assert((offsetof (struct g1_if_reg, G1GDRC)) == 0xa0);
static_assert((offsetof (struct g1_if_reg, G1GDWC)) == 0xa4);
static_assert((offsetof (struct g1_if_reg, G1SYSM)) == 0xb0);
static_assert((offsetof (struct g1_if_reg, G1CRDYC)) == 0xb4);
static_assert((offsetof (struct g1_if_reg, GDAPRO)) == 0xb8);
static_assert((offsetof (struct g1_if_reg, GDUNLOCK)) == 0xe4);
static_assert((offsetof (struct g1_if_reg, GDSTARD)) == 0xf4);
static_assert((offsetof (struct g1_if_reg, GDLEND)) == 0xf8);
struct g2_if_reg {
reg32 ADSTAG; /* ACIA:G2-DMA G2 start address */
reg32 ADSTAR; /* ACIA:G2-DMA system memory start address */
reg32 ADLEN; /* ACIA:G2-DMA length */
reg32 ADDIR; /* ACIA:G2-DMA direction */
reg32 ADTSEL; /* ACIA:G2-DMA trigger select */
reg32 ADEN; /* ACIA:G2-DMA enable */
reg32 ADST; /* ACIA:G2-DMA start */
reg32 ADSUSP; /* ACIA:G2-DMA suspend */
reg32 E1STAG; /* Ext1:G2-DMA start address */
reg32 E1STAR; /* Ext1:G2-DMA system memory start address */
reg32 E1LEN; /* Ext1:G2-DMA length */
reg32 E1DIR; /* Ext1:G2-DMA direction */
reg32 E1TSEL; /* Ext1:G2-DMA trigger select */
reg32 E1EN; /* Ext1:G2-DMA enable */
reg32 E1ST; /* Ext1:G2-DMA start */
reg32 E1SUSP; /* Ext1:G2-DMA suspend */
reg32 E2STAG; /* Ext2:G2-DMA start address */
reg32 E2STAR; /* Ext2:G2-DMA system memory start address */
reg32 E2LEN; /* Ext2:G2-DMA length */
reg32 E2DIR; /* Ext2:G2-DMA direction */
reg32 E2TSEL; /* Ext2:G2-DMA trigger select */
reg32 E2EN; /* Ext2:G2-DMA enable */
reg32 E2ST; /* Ext2:G2-DMA start */
reg32 E2SUSP; /* Ext2:G2-DMA suspend */
reg32 DDSTAG; /* Dev:G2-DMA start address */
reg32 DDSTAR; /* Dev:G2-DMA system memory start address */
reg32 DDLEN; /* Dev:G2-DMA length */
reg32 DDDIR; /* Dev:G2-DMA direction */
reg32 DDTSEL; /* Dev:G2-DMA trigger select */
reg32 DDEN; /* Dev:G2-DMA enable */
reg32 DDST; /* Dev:G2-DMA start */
reg32 DDSUSP; /* Dev:G2-DMA suspend */
reg32 G2ID; /* G2 bus version */
reg8 _pad0[12];
reg32 G2DSTO; /* G2/DS timeout */
reg32 G2TRTO; /* G2/TR timeout */
reg32 G2MDMTO; /* Modem unit wait timeout */
reg32 G2MDMW; /* Modem unit wait time */
reg8 _pad1[28];
reg32 G2APRO; /* G2-DMA address range */
reg32 ADSTAGD; /* AICA-DMA address counter (on AICA) */
reg32 ADSTARD; /* AICA-DMA address counter (on root bus) */
reg32 ADLEND; /* AICA-DMA transfer counter */
reg8 _pad2[4];
reg32 E1STAGD; /* Ext-DMA1 address counter (on Ext) */
reg32 E1STARD; /* Ext-DMA1 address counter (on root bus) */
reg32 E1LEND; /* Ext-DMA1 transfer counter */
reg8 _pad3[4];
reg32 E2STAGD; /* Ext-DMA2 address counter (on Ext) */
reg32 E2STARD; /* Ext-DMA2 address counter (on root bus) */
reg32 E2LEND; /* Ext-DMA2 transfer counter */
reg8 _pad4[4];
reg32 DDSTAGD; /* Dev-DMA address counter (on Dev) */
reg32 DDSTARD; /* Dev-DMA address counter (on root bus) */
reg32 DDLEND; /* Dev-DMA transfer counter */
};
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, ADLEN)) == 0x8);
static_assert((offsetof (struct g2_if_reg, ADDIR)) == 0xc);
static_assert((offsetof (struct g2_if_reg, ADTSEL)) == 0x10);
static_assert((offsetof (struct g2_if_reg, ADEN)) == 0x14);
static_assert((offsetof (struct g2_if_reg, ADST)) == 0x18);
static_assert((offsetof (struct g2_if_reg, ADSUSP)) == 0x1c);
static_assert((offsetof (struct g2_if_reg, E1STAG)) == 0x20);
static_assert((offsetof (struct g2_if_reg, E1STAR)) == 0x24);
static_assert((offsetof (struct g2_if_reg, E1LEN)) == 0x28);
static_assert((offsetof (struct g2_if_reg, E1DIR)) == 0x2c);
static_assert((offsetof (struct g2_if_reg, E1TSEL)) == 0x30);
static_assert((offsetof (struct g2_if_reg, E1EN)) == 0x34);
static_assert((offsetof (struct g2_if_reg, E1ST)) == 0x38);
static_assert((offsetof (struct g2_if_reg, E1SUSP)) == 0x3c);
static_assert((offsetof (struct g2_if_reg, E2STAG)) == 0x40);
static_assert((offsetof (struct g2_if_reg, E2STAR)) == 0x44);
static_assert((offsetof (struct g2_if_reg, E2LEN)) == 0x48);
static_assert((offsetof (struct g2_if_reg, E2DIR)) == 0x4c);
static_assert((offsetof (struct g2_if_reg, E2TSEL)) == 0x50);
static_assert((offsetof (struct g2_if_reg, E2EN)) == 0x54);
static_assert((offsetof (struct g2_if_reg, E2ST)) == 0x58);
static_assert((offsetof (struct g2_if_reg, E2SUSP)) == 0x5c);
static_assert((offsetof (struct g2_if_reg, DDSTAG)) == 0x60);
static_assert((offsetof (struct g2_if_reg, DDSTAR)) == 0x64);
static_assert((offsetof (struct g2_if_reg, DDLEN)) == 0x68);
static_assert((offsetof (struct g2_if_reg, DDDIR)) == 0x6c);
static_assert((offsetof (struct g2_if_reg, DDTSEL)) == 0x70);
static_assert((offsetof (struct g2_if_reg, DDEN)) == 0x74);
static_assert((offsetof (struct g2_if_reg, DDST)) == 0x78);
static_assert((offsetof (struct g2_if_reg, DDSUSP)) == 0x7c);
static_assert((offsetof (struct g2_if_reg, G2ID)) == 0x80);
static_assert((offsetof (struct g2_if_reg, G2DSTO)) == 0x90);
static_assert((offsetof (struct g2_if_reg, G2TRTO)) == 0x94);
static_assert((offsetof (struct g2_if_reg, G2MDMTO)) == 0x98);
static_assert((offsetof (struct g2_if_reg, G2MDMW)) == 0x9c);
static_assert((offsetof (struct g2_if_reg, G2APRO)) == 0xbc);
static_assert((offsetof (struct g2_if_reg, ADSTAGD)) == 0xc0);
static_assert((offsetof (struct g2_if_reg, ADSTARD)) == 0xc4);
static_assert((offsetof (struct g2_if_reg, ADLEND)) == 0xc8);
static_assert((offsetof (struct g2_if_reg, E1STAGD)) == 0xd0);
static_assert((offsetof (struct g2_if_reg, E1STARD)) == 0xd4);
static_assert((offsetof (struct g2_if_reg, E1LEND)) == 0xd8);
static_assert((offsetof (struct g2_if_reg, E2STAGD)) == 0xe0);
static_assert((offsetof (struct g2_if_reg, E2STARD)) == 0xe4);
static_assert((offsetof (struct g2_if_reg, E2LEND)) == 0xe8);
static_assert((offsetof (struct g2_if_reg, DDSTAGD)) == 0xf0);
static_assert((offsetof (struct g2_if_reg, DDSTARD)) == 0xf4);
static_assert((offsetof (struct g2_if_reg, DDLEND)) == 0xf8);
struct pvr_if_reg {
reg32 PDSTAP; /* PVR-DMA start address */
reg32 PDSTAR; /* PVR-DMA system memory start address */
reg32 PDLEN; /* PVR-DMA length */
reg32 PDDIR; /* PVR-DMA direction */
reg32 PDTSEL; /* PVR-DMA trigger select */
reg32 PDEN; /* PVR-DMA enable */
reg32 PDST; /* PVR-DMA start */
reg8 _pad0[100];
reg32 PDAPRO; /* PVR-DMA address range */
reg8 _pad1[108];
reg32 PDSTAPD; /* PVR-DMA address counter (on Ext) */
reg32 PDSTARD; /* PVR-DMA address counter (on root bus) */
reg32 PDLEND; /* PVR-DMA transfer counter */
};
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, PDLEN)) == 0x8);
static_assert((offsetof (struct pvr_if_reg, PDDIR)) == 0xc);
static_assert((offsetof (struct pvr_if_reg, PDTSEL)) == 0x10);
static_assert((offsetof (struct pvr_if_reg, PDEN)) == 0x14);
static_assert((offsetof (struct pvr_if_reg, PDST)) == 0x18);
static_assert((offsetof (struct pvr_if_reg, PDAPRO)) == 0x80);
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, PDLEND)) == 0xf8);
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 inline uint32_t texture_memory_start_address(uint32_t num) { return (num & 0x13ffffe0) << 0; }
}
namespace c2dlen {
constexpr inline 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 inline uint32_t holly_cpu_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 5) & 0x1; }
constexpr inline uint32_t holly_g2_if_block_internal_write_buffer(uint32_t reg) { return (reg >> 4) & 0x1; }
constexpr inline 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;
}
}

Some files were not shown because too many files have changed in this diff Show More