initial
This commit is contained in:
commit
d2853464c3
21
.gitignore
vendored
Executable file
21
.gitignore
vendored
Executable file
@ -0,0 +1,21 @@
|
||||
*.pyc
|
||||
__pycache__
|
||||
.~*
|
||||
*.BIN
|
||||
*.bin
|
||||
*.elf
|
||||
*.d
|
||||
*.iso
|
||||
*.cdi
|
||||
*.o
|
||||
*.out
|
||||
*.gch
|
||||
scramble
|
||||
cdi4dc
|
||||
tools/ttf_outline
|
||||
tools/ttf_bitmap
|
||||
tools/ftdi_transfer
|
||||
k_means_vq
|
||||
*.blend1
|
||||
*.scramble
|
||||
*.FCStd1
|
41
Makefile
Normal file
41
Makefile
Normal file
@ -0,0 +1,41 @@
|
||||
all: main.elf
|
||||
|
||||
OPT = -O2
|
||||
|
||||
CSTD = -std=gnu11
|
||||
|
||||
MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
|
||||
LIB ?= $(MAKEFILE_PATH)/dreamcast
|
||||
CFLAGS += -D__dreamcast__
|
||||
CFLAGS += -I$(MAKEFILE_PATH)/c
|
||||
CFLAGS += -I$(MAKEFILE_PATH)/dreamcast
|
||||
CFLAGS += -I$(MAKEFILE_PATH)/
|
||||
CFLAGS += -Wno-error=strict-aliasing -fno-strict-aliasing
|
||||
CARCH = -m4-single -ml
|
||||
|
||||
include dreamcast/base.mk
|
||||
include dreamcast/common.mk
|
||||
include dreamcast/headers.mk
|
||||
include dreamcast/ip.mk
|
||||
|
||||
include main.mk
|
||||
|
||||
%.class.o: %.class
|
||||
$(BUILD_BINARY_O)
|
||||
|
||||
%.class.h: %.class
|
||||
$(BUILD_BINARY_H)
|
||||
|
||||
libgcc/%.o: $(LIBGCC)
|
||||
@mkdir -p $(dir $@)
|
||||
ar x --output $(dir $@) $(LIBGCC) $(notdir $@)
|
||||
sh4-none-elf-objdump -t $@ \
|
||||
| grep -E '[.]hidden' \
|
||||
| grep -vE 'UND' \
|
||||
| cut -d' ' -f10 \
|
||||
| xargs rebind --visibility=default $@
|
||||
|
||||
LIBGCC_OBJ =
|
||||
|
||||
main.elf: LDSCRIPT = $(LIB)/main.lds
|
||||
main.elf: $(START_OBJ) $(MAIN_OBJ) $(LIBGCC_OBJ)
|
8
main.mk
Normal file
8
main.mk
Normal file
@ -0,0 +1,8 @@
|
||||
MAIN_OBJ = \
|
||||
$(LIB)/holly/core.o \
|
||||
$(LIB)/holly/region_array.o \
|
||||
$(LIB)/holly/background.o \
|
||||
$(LIB)/holly/ta_fifo_polygon_converter.o \
|
||||
$(LIB)/holly/video_output.o \
|
||||
$(LIB)/sh7091/serial.o \
|
||||
src/main.o
|
328
src/main.cpp
Normal file
328
src/main.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "holly/background.hpp"
|
||||
#include "holly/core.hpp"
|
||||
#include "holly/core_bits.hpp"
|
||||
#include "holly/holly.hpp"
|
||||
#include "holly/isp_tsp.hpp"
|
||||
#include "holly/region_array.hpp"
|
||||
#include "holly/ta_bits.hpp"
|
||||
#include "holly/ta_fifo_polygon_converter.hpp"
|
||||
#include "holly/ta_global_parameter.hpp"
|
||||
#include "holly/ta_parameter.hpp"
|
||||
#include "holly/ta_vertex_parameter.hpp"
|
||||
#include "holly/texture_memory_alloc3.hpp"
|
||||
#include "holly/video_output.hpp"
|
||||
|
||||
#include "sh7091/sh7091.hpp"
|
||||
#include "sh7091/sh7091_bits.hpp"
|
||||
#include "sh7091/serial.hpp"
|
||||
#include "sh7091/vbr.hpp"
|
||||
|
||||
#include "systembus.hpp"
|
||||
#include "systembus_bits.hpp"
|
||||
|
||||
#include "memorymap.hpp"
|
||||
|
||||
#include "math/vec2.hpp"
|
||||
#include "math/vec3.hpp"
|
||||
#include "math/vec4.hpp"
|
||||
#include "math/mat4x4.hpp"
|
||||
|
||||
using vec2 = vec<2, float>;
|
||||
using vec3 = vec<3, float>;
|
||||
using vec4 = vec<4, float>;
|
||||
using mat4x4 = mat<4, 4, float>;
|
||||
|
||||
static inline __attribute__((always_inline)) void print_exception()
|
||||
{
|
||||
serial::string("expevt ");
|
||||
serial::integer<uint16_t>(sh7091.CCN.EXPEVT);
|
||||
serial::string("intevt ");
|
||||
serial::integer<uint16_t>(sh7091.CCN.INTEVT);
|
||||
serial::string("tra ");
|
||||
serial::integer<uint16_t>(sh7091.CCN.TRA);
|
||||
|
||||
uint32_t spc;
|
||||
uint32_t ssr;
|
||||
asm volatile ("stc spc,%0" : "=r" (spc));
|
||||
asm volatile ("stc ssr,%0" : "=r" (ssr));
|
||||
serial::string("spc ");
|
||||
serial::integer(spc);
|
||||
serial::string("ssr ");
|
||||
serial::integer(ssr);
|
||||
}
|
||||
|
||||
// "dreamcast/sh7091/vbr.hpp" must be included prior to defining any of
|
||||
// vbr100/vbr400/vbr600
|
||||
void vbr100()
|
||||
{
|
||||
serial::string("vbr100\n");
|
||||
print_exception();
|
||||
while (1);
|
||||
}
|
||||
|
||||
void vbr400()
|
||||
{
|
||||
serial::string("vbr400");
|
||||
print_exception();
|
||||
while (1);
|
||||
}
|
||||
|
||||
static int render_done = 0;
|
||||
|
||||
void vbr600()
|
||||
{
|
||||
if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x320) {
|
||||
// read Holly "normal" interrupt status
|
||||
uint32_t istnrm = system.ISTNRM;
|
||||
// read Holly "error" interrupt status
|
||||
uint32_t isterr = system.ISTERR;
|
||||
|
||||
if (isterr) {
|
||||
serial::string("isterr: ");
|
||||
serial::integer<uint32_t>(system.ISTERR);
|
||||
}
|
||||
|
||||
if (istnrm & istnrm::end_of_render_tsp) {
|
||||
system.ISTNRM = istnrm::end_of_render_tsp
|
||||
| istnrm::end_of_render_isp
|
||||
| istnrm::end_of_render_video;
|
||||
render_done = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
serial::string("vbr600");
|
||||
print_exception();
|
||||
while (1);
|
||||
}
|
||||
|
||||
void interrupt_init()
|
||||
{
|
||||
// disable all Holly interrupts
|
||||
system.IML2NRM = 0;
|
||||
system.IML2ERR = 0;
|
||||
system.IML2EXT = 0;
|
||||
|
||||
system.IML4NRM = 0;
|
||||
system.IML4ERR = 0;
|
||||
system.IML4EXT = 0;
|
||||
|
||||
system.IML6NRM = 0;
|
||||
system.IML6ERR = 0;
|
||||
system.IML6EXT = 0;
|
||||
|
||||
// reset Holly interrupt status
|
||||
system.ISTERR = 0xffffffff;
|
||||
system.ISTNRM = 0xffffffff;
|
||||
|
||||
// vbr100/vbr400/vbr600 will be called during interrupts/exceptions as a
|
||||
// consequence of setting vbr to __vbr_link_start.
|
||||
// See also:
|
||||
// - dreamcast/common.lds
|
||||
// - dreamcast/symbols.lds
|
||||
// - dreamcast/sh7091/vbr.hpp
|
||||
uint32_t vbr = reinterpret_cast<uint32_t>(&__vbr_link_start) - 0x100;
|
||||
asm volatile ("ldc %0,vbr" : : "r" (vbr));
|
||||
|
||||
uint32_t sr;
|
||||
asm volatile ("stc sr,%0" : "=r" (sr));
|
||||
// unBLock interrupts/exceptions
|
||||
// unmask all interrupts
|
||||
sr &= ~sh::sr::bl; // BL
|
||||
sr &= ~sh::sr::imask(15); // imask
|
||||
asm volatile ("ldc %0,sr" : : "r" (sr));
|
||||
}
|
||||
|
||||
void global_polygon_type_0(ta_parameter_writer& writer)
|
||||
{
|
||||
// this is the simplest possible polygon configuration:
|
||||
// - untextured
|
||||
// - packed 32-bit color
|
||||
// - not gouraud shaded
|
||||
// - no TA color calculation
|
||||
|
||||
const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume
|
||||
| para_control::list_type::opaque
|
||||
| obj_control::col_type::packed_color
|
||||
;
|
||||
|
||||
const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
|
||||
| isp_tsp_instruction_word::culling_mode::no_culling;
|
||||
|
||||
const uint32_t tsp_instruction_word = tsp_instruction_word::fog_control::no_fog
|
||||
| tsp_instruction_word::src_alpha_instr::one
|
||||
| tsp_instruction_word::dst_alpha_instr::zero
|
||||
;
|
||||
|
||||
const uint32_t texture_control_word = 0;
|
||||
|
||||
writer.append<ta_global_parameter::polygon_type_0>() =
|
||||
ta_global_parameter::polygon_type_0(parameter_control_word,
|
||||
isp_tsp_instruction_word,
|
||||
tsp_instruction_word,
|
||||
texture_control_word,
|
||||
0, // data_size_for_sort_dma
|
||||
0 // next_address_for_sort_dma
|
||||
);
|
||||
}
|
||||
|
||||
static inline void render_triangle(ta_parameter_writer& writer,
|
||||
uint32_t base_color,
|
||||
vec3 ap,
|
||||
vec3 bp,
|
||||
vec3 cp)
|
||||
{
|
||||
writer.append<ta_vertex_parameter::polygon_type_0>() =
|
||||
ta_vertex_parameter::polygon_type_0(polygon_vertex_parameter_control_word(false),
|
||||
ap.x, ap.y, ap.z,
|
||||
base_color
|
||||
);
|
||||
|
||||
writer.append<ta_vertex_parameter::polygon_type_0>() =
|
||||
ta_vertex_parameter::polygon_type_0(polygon_vertex_parameter_control_word(false),
|
||||
bp.x, bp.y, bp.z,
|
||||
base_color
|
||||
);
|
||||
|
||||
writer.append<ta_vertex_parameter::polygon_type_0>() =
|
||||
ta_vertex_parameter::polygon_type_0(polygon_vertex_parameter_control_word(true), // end of triangle strip
|
||||
cp.x, cp.y, cp.z,
|
||||
base_color
|
||||
);
|
||||
}
|
||||
|
||||
void transfer_scene(ta_parameter_writer& writer)
|
||||
{
|
||||
uint32_t base_color = 0xff55aa00;
|
||||
|
||||
vec3 ap = { 320.000f, 50.000f, 0.1f};
|
||||
vec3 bp = { 539.393f, 430.000f, 0.1f};
|
||||
vec3 cp = { 100.607f, 430.000f, 0.1f};
|
||||
|
||||
// global_polygon_type_N only needs to be sent if the polygon type /
|
||||
// parameters change. E.g: multiple triangles that use the same texture and
|
||||
// shading configuration only need a single global_polygon_type_N
|
||||
global_polygon_type_0(writer);
|
||||
|
||||
// render_triangle may be called multiple times
|
||||
render_triangle(writer,
|
||||
base_color,
|
||||
ap,
|
||||
bp,
|
||||
cp);
|
||||
|
||||
// end of opaque list
|
||||
writer.append<ta_global_parameter::end_of_list>() =
|
||||
ta_global_parameter::end_of_list(para_control::para_type::end_of_list);
|
||||
}
|
||||
|
||||
uint8_t __attribute__((aligned(32))) ta_parameter_buf[1024 * 1024];
|
||||
|
||||
void main()
|
||||
{
|
||||
serial::init(0);
|
||||
|
||||
holly.SOFTRESET = softreset::pipeline_soft_reset
|
||||
| softreset::ta_soft_reset;
|
||||
holly.SOFTRESET = 0;
|
||||
|
||||
core_init();
|
||||
|
||||
interrupt_init();
|
||||
// enable end_of_render_tsp interrupt at Holly level 6
|
||||
//
|
||||
// this corresponds to (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x320)
|
||||
// via vbr600 from the CPU's perspective.
|
||||
system.IML6NRM = istnrm::end_of_render_tsp;
|
||||
|
||||
const int framebuffer_width = 640;
|
||||
const int framebuffer_height = 480;
|
||||
const int tile_width = framebuffer_width / 32;
|
||||
const int tile_height = framebuffer_height / 32;
|
||||
|
||||
const uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list
|
||||
| ta_alloc_ctrl::tm_opb::no_list
|
||||
| ta_alloc_ctrl::t_opb::no_list
|
||||
| ta_alloc_ctrl::om_opb::no_list
|
||||
| ta_alloc_ctrl::o_opb::_16x4byte;
|
||||
|
||||
const int opb_size_length = 1;
|
||||
const struct opb_size opb_size[opb_size_length] = {
|
||||
{
|
||||
.opaque = 16 * 4,
|
||||
.opaque_modifier = 0,
|
||||
.translucent = 0,
|
||||
.translucent_modifier = 0,
|
||||
.punch_through = 0
|
||||
}
|
||||
};
|
||||
|
||||
// Create a "region array"; this creates pointers in texture memory for each
|
||||
// of the 300 32×32px tiles in the 640x480px render output.
|
||||
region_array_multipass(tile_width,
|
||||
tile_height,
|
||||
opb_size,
|
||||
opb_size_length,
|
||||
texture_memory_alloc.region_array[0].start,
|
||||
texture_memory_alloc.object_list[0].start);
|
||||
|
||||
// Create a "background" ISP/TSP parameter at address
|
||||
// texture_memory_alloc.background[0].start in texture memory.
|
||||
// This is the "background color" shown behind all other polygons.
|
||||
const uint32_t background_color = 0xff202040;
|
||||
background_parameter2(texture_memory_alloc.background[0].start,
|
||||
background_color);
|
||||
|
||||
// ta_parameter_writer is used to prepare a buffer of "ta parameters"/"drawing
|
||||
// commands" for submission to the TA via DMA.
|
||||
ta_parameter_writer writer = ta_parameter_writer(ta_parameter_buf);
|
||||
|
||||
// set the Dreamcast video output to "VGA" (with several other defaults
|
||||
// including a 640x480 RGB565 framebuffer).
|
||||
video_output::set_mode_vga();
|
||||
|
||||
while (1) {
|
||||
// ta_polygon_converter_init2 must be called each frame, prior to sending
|
||||
// data to the TA. This re-initializes TA internal registers and
|
||||
// offsets. The TA reads from its input (in this case given via
|
||||
// DMA/ta_polygon_converter_transfer), and writes the result to texture
|
||||
// memory.
|
||||
ta_polygon_converter_init2(texture_memory_alloc.isp_tsp_parameters[0].start,
|
||||
texture_memory_alloc.isp_tsp_parameters[0].end,
|
||||
texture_memory_alloc.object_list[0].start,
|
||||
texture_memory_alloc.object_list[0].end,
|
||||
opb_size[0].total(),
|
||||
ta_alloc,
|
||||
tile_width,
|
||||
tile_height);
|
||||
// reset the ta_parameter_writer
|
||||
writer.offset = 0;
|
||||
// perform all vertex/scene calculations, storing the result in System Memory
|
||||
transfer_scene(writer);
|
||||
// write any areas of writer.buf that only exist in SH4 cache back to System Memory
|
||||
ta_polygon_converter_writeback(writer.buf, writer.offset);
|
||||
// DMA transfer from System Memory to the TA FIFO
|
||||
ta_polygon_converter_transfer(writer.buf, writer.offset);
|
||||
// wait for the TA to finish processing all TA commands
|
||||
ta_wait_opaque_list();
|
||||
|
||||
// render_done flag: see vbr600
|
||||
render_done = 0;
|
||||
core_start_render2(texture_memory_alloc.region_array[0].start,
|
||||
texture_memory_alloc.isp_tsp_parameters[0].start,
|
||||
texture_memory_alloc.background[0].start,
|
||||
texture_memory_alloc.framebuffer[0].start,
|
||||
framebuffer_width);
|
||||
// wait for render completion
|
||||
while (render_done == 0) {
|
||||
asm volatile ("nop");
|
||||
};
|
||||
|
||||
// wait for vsync
|
||||
while (!spg_status::vsync(holly.SPG_STATUS));
|
||||
holly.FB_R_SOF1 = texture_memory_alloc.framebuffer[0].start;
|
||||
while (spg_status::vsync(holly.SPG_STATUS));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user