summary refs log tree commit diff
path: root/misc/dreamcast
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /misc/dreamcast
initial commit
Diffstat (limited to 'misc/dreamcast')
-rw-r--r--misc/dreamcast/DrawColouredQuads.S65
-rw-r--r--misc/dreamcast/DrawTexturedQuads.S63
-rw-r--r--misc/dreamcast/Makefile66
-rw-r--r--misc/dreamcast/ViewportTransform.S218
-rw-r--r--misc/dreamcast/boot_logo.pngbin0 -> 4021 bytes
-rw-r--r--misc/dreamcast/ip.txt3
-rw-r--r--misc/dreamcast/readme.txt9
7 files changed, 424 insertions, 0 deletions
diff --git a/misc/dreamcast/DrawColouredQuads.S b/misc/dreamcast/DrawColouredQuads.S
new file mode 100644
index 0000000..074605a
--- /dev/null
+++ b/misc/dreamcast/DrawColouredQuads.S
@@ -0,0 +1,65 @@
+#include "ViewportTransform.S"
+.global _DrawColouredQuads
+.align 4
+.type  _DrawColouredQuads,%function
+
+_DrawColouredQuads:
+! Setup
+    fldi0 fr1     ! U = 0
+    fldi0 fr2     ! V = 0
+    mov r4,r3     ! r3  = src
+    add #-32, r5  ! r5 -= sizeof(VERTEX)
+    ViewportTransformSetup _VP_COL_HWIDTH
+
+.TRANSFORM_QUAD:
+    mov.l CMD_COL_VERT, r1 ! r1  = GPU VERT command
+
+    LoadColouredVertex
+    ProcessVertex1
+
+    LoadColouredVertex
+    ProcessVertex2
+
+    LoadColouredVertex
+    ProcessVertex3
+
+    LoadColouredVertex
+    ProcessVertex4 CMD_COL_EOS
+
+! CLIPFLAGS TESTING
+    cmp/eq   #0,r0 ! T = r0 == 0 (all points invisible)
+    bt/s    .NO_POINTS_VISIBLE  ! if T goto NO_POINTS_VISIBLE
+    nop
+    bra .SOME_POINTS_VISIBLE
+    nop
+
+.NO_POINTS_VISIBLE:
+    bra .LOOP_END ! jump to loop end after executing instruction in delay slot
+    add #-128, r5 ! r5 -= 4 * sizeof(VERTEX), move back to 1 vertex before start of quad
+
+.SOME_POINTS_VISIBLE:
+
+.LOOP_END:
+    dt r6 ! r6--; T = r6 == 0
+    bf .TRANSFORM_QUAD ! if !T then goto TRANSFORM_QUAD
+    nop
+    
+    add #32, r5     ! r5 += sizeof(VERTEX)
+    rts             ! return after executing instruction in delay slot
+    mov r5,r0       ! r0 = r5
+
+.align 2
+CMD_COL_VERT: .long 0xe0000000
+CMD_COL_EOS:  .long 0xf0000000
+
+.global _VP_COL_HWIDTH
+_VP_COL_HWIDTH:  .long 0
+
+.global _VP_COL_HHEIGHT
+_VP_COL_HHEIGHT: .long 0
+
+.global _VP_COL_X_PLUS_HWIDTH
+_VP_COL_X_PLUS_HWIDTH:  .long 0
+
+.global _VP_COL_Y_PLUS_HHEIGHT
+_VP_COL_Y_PLUS_HHEIGHT: .long 0
diff --git a/misc/dreamcast/DrawTexturedQuads.S b/misc/dreamcast/DrawTexturedQuads.S
new file mode 100644
index 0000000..5ce16bd
--- /dev/null
+++ b/misc/dreamcast/DrawTexturedQuads.S
@@ -0,0 +1,63 @@
+#include "ViewportTransform.S"
+.global _DrawTexturedQuads
+.align 4
+.type  _DrawTexturedQuads,%function
+
+_DrawTexturedQuads:
+! Setup
+    mov r4,r3     ! r3  = src
+    add #-32, r5  ! r5 -= sizeof(VERTEX)
+    ViewportTransformSetup _VP_TEX_HWIDTH
+
+.TRANSFORM_QUAD:
+    mov.l CMD_TEX_VERT, r1 ! r1  = GPU VERT command
+
+    LoadTexturedVertex
+    ProcessVertex1
+
+    LoadTexturedVertex
+    ProcessVertex2
+
+    LoadTexturedVertex
+    ProcessVertex3
+
+    LoadTexturedVertex
+    ProcessVertex4 CMD_TEX_EOS
+
+! CLIPFLAGS TESTING
+    cmp/eq  #0,r0  ! T = r0 == 0 (all points invisible)
+    bt/s    .NO_POINTS_VISIBLE  ! if T goto NO_POINTS_VISIBLE
+    nop
+    bra .SOME_POINTS_VISIBLE
+    nop
+
+.NO_POINTS_VISIBLE:
+    bra .LOOP_END ! jump to loop end after executing instruction in delay slot
+    add #-128, r5 ! r5 -= 4 * sizeof(VERTEX), move back to prior quad, so that this invisible quad gets overwritten in next iteration
+
+.SOME_POINTS_VISIBLE:
+
+.LOOP_END:
+    dt r6 ! r6--; T = r6 == 0
+    bf .TRANSFORM_QUAD ! if !T then goto TRANSFORM_QUAD
+    nop
+    
+    add #32, r5     ! r5 += sizeof(VERTEX)
+    rts             ! return after executing instruction in delay slot
+    mov r5,r0       ! r0 = r5
+
+.align 2
+CMD_TEX_VERT: .long 0xe0000000
+CMD_TEX_EOS:  .long 0xf0000000
+
+.global _VP_TEX_HWIDTH
+_VP_TEX_HWIDTH:  .long 0
+
+.global _VP_TEX_HHEIGHT
+_VP_TEX_HHEIGHT: .long 0
+
+.global _VP_TEX_X_PLUS_HWIDTH
+_VP_TEX_X_PLUS_HWIDTH:  .long 0
+
+.global _VP_TEX_Y_PLUS_HHEIGHT
+_VP_TEX_Y_PLUS_HHEIGHT: .long 0
diff --git a/misc/dreamcast/Makefile b/misc/dreamcast/Makefile
new file mode 100644
index 0000000..5362a41
--- /dev/null
+++ b/misc/dreamcast/Makefile
@@ -0,0 +1,66 @@
+BUILD_DIR		:= build-dc
+SOURCE_DIRS		:= src third_party/bearssl/src misc/dreamcast
+
+S_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.S))
+C_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
+OBJS 	:= $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.S=%.o)))
+CFLAGS	:=-g -O1 -pipe -fno-math-errno -Ithird_party/bearssl/inc
+
+GLDC_LIB=third_party/gldc/libGLdc.a
+LDFLAGS=-g
+LIBS=-lm $(GLDC_LIB) -lppp -lkosfat
+
+TARGET := ClassiCube-dc
+CC_TEXTURES = misc/dreamcast/classicube.zip
+
+ifeq ($(strip $(KOS_BASE)),)
+$(error "Please set KOS variables in your environment.")
+endif
+
+default: $(CC_TEXTURES) $(GLDC_LIB) $(BUILD_DIR) $(TARGET).cdi
+
+$(BUILD_DIR):
+	mkdir -p $(BUILD_DIR)
+	
+$(GLDC_LIB): FORCE
+	$(MAKE) -C third_party/gldc
+FORCE: ;
+
+# TODO add textures to misc folder ?	
+$(CC_TEXTURES): 
+	curl http://www.classicube.net/static/default.zip -o $@
+	
+$(BUILD_DIR)/%.o: src/%.c
+	kos-cc $(CFLAGS) -c $< -o $@
+
+$(BUILD_DIR)/%.o: misc/dreamcast/%.S
+	kos-cc -c $< -o $@
+
+$(BUILD_DIR)/%.o: third_party/bearssl/src/%.c
+	kos-cc $(CFLAGS) -c $< -o $@
+	
+
+$(TARGET).elf: $(OBJS)
+	kos-cc $(LDFLAGS) $^ -o $@ $(LIBS)
+	
+$(TARGET).bin: $(TARGET).elf
+	sh-elf-objcopy -R .stack -O binary $(TARGET).elf $(TARGET).bin
+	
+# https://dcemulation.org/phpBB/viewtopic.php?t=105269
+$(TARGET)-scr.bin: $(TARGET).bin
+	$(KOS_BASE)/utils/scramble/scramble $(TARGET).bin $(TARGET)-scr.bin
+	
+$(TARGET).iso: $(TARGET)-scr.bin
+	mkdir -p ISO_FILES
+	cp $(TARGET)-scr.bin ISO_FILES/1ST_READ.BIN
+	mkdir -p ISO_FILES/audio
+	mkdir -p ISO_FILES/maps
+	mkdir -p ISO_FILES/texpacks
+	mkdir -p ISO_FILES/texturecache
+	cp $(CC_TEXTURES) ISO_FILES/texpacks/default.zip
+	cp misc/dreamcast/IP.BIN IP.BIN
+	mkisofs -G IP.BIN -C 0,11702 -J -l -r -o $(TARGET).iso ISO_FILES
+	# genisoimage -V ClassiCube -G IP.BIN -joliet -rock -l -o $(TARGET).iso ISO_FILES
+	
+$(TARGET).cdi: $(TARGET).iso
+	cdi4dc $(TARGET).iso $(TARGET).cdi
diff --git a/misc/dreamcast/ViewportTransform.S b/misc/dreamcast/ViewportTransform.S
new file mode 100644
index 0000000..19d3052
--- /dev/null
+++ b/misc/dreamcast/ViewportTransform.S
@@ -0,0 +1,218 @@
+! =========================================================
+! ======================== PROCESSOR INFO =================
+! =========================================================
+! The SH4 can dual issue (i.e. parallel execution) two instructions
+! as long as the groups of the two instructions are different:
+! * LS - most APU and FPU register load/stores
+! * EX - most APU arithmetic instructions
+! * MT - TST, CMP, NOP, MOV Rm,Rn
+! * FE - most FPU arithmetic instructions
+! * CO - other instructions (NOTE: Cannot be exeucted in parallel)
+
+! Thee following general aspects of instructions are important to note per the SH4 manual:
+! * Issue rate: Interval between the issue of an instruction and that of the next instruction
+! * Latency: Interval between the issue of an instruction and the generation of its result (completion)
+! * Latency is also the interval between the execution of two instructions with an interdependent relationship.
+!   (although different cases may either increase or decrease Latency)
+!
+
+
+! =========================================================
+! ======================== REGISTER USAGES ================
+! =========================================================
+! SH4 C ABI:
+! -  R0  to  R3 are return values (can be overwritten)
+! -  R4  to  R7 are input arguments (can be overwritten)
+! -  R8  to R13 are non-volatile (must be restored at end)
+! - R14  is the frame pointer (must be restored at end)
+! - R15  is the stack pointer (must be restored at end)
+! - FR0  to FR3 are return values (can be overwritten)
+! - FR4  to FR11 are input arguments (can be overwritten)
+! - FR12 to FR13 are non-volatile (must be restored at end)
+
+!r0 = clip flags
+!r1 = GPU command
+!r2 = temp
+!r3 = prefetch address
+!r4 = src pointer ARG
+!r5 = dst pointer ARG
+!r6 = quads count ARG
+!r7 = ?
+
+!fr0  = temp
+!fr1  = u
+!fr2  = v
+!fr3  = c
+!fr4  = x
+!fr5  = y
+!fr6  = z
+!fr7  = w
+!fr8  = VIEWPORT_HWIDTH
+!fr9  = VIEWPORT_HHEIGHT
+!fr10 = VIEWPORT_X_PLUS_HWIDTH
+!fr11 = VIEWPORT_Y_PLUS_HHEIGHT
+
+!fv4  = XYZW
+
+
+! =========================================================
+! ========================= VERTEX LOADING ================
+! =========================================================
+.macro LoadColouredVertex
+! LOAD XYZ
+    fmov @r4+, fr4   ! LS, X = src->x
+    fmov @r4+, fr5   ! LS, Y = src->y
+    fmov @r4+, fr6   ! LS, Z = src->z
+    fldi1 fr7        ! LS, W = 1.0
+! PREPARE NEXT VERTEX
+    add #16, r3      ! EX, r3 += VERTEX_STRIDE
+    pref @r3         ! LS, PREFETCH r3 (next vertex)
+    add #64, r5      ! EX, r5 += 2 * sizeof(VERTEX)
+! TRANSFORM VERTEX
+    ftrv xmtrx, fv4  ! FE, TRANSFORM(XYZW)
+! LOAD ATTRIBUTES
+    fmov   @r4+,fr3  ! LS, C = src->color
+.endm
+
+.macro LoadTexturedVertex
+! LOAD XYZ
+    fmov @r4+, fr4   ! LS, X = src->x
+    fmov @r4+, fr5   ! LS, Y = src->y
+    fmov @r4+, fr6   ! LS, Z = src->z
+    fldi1 fr7        ! LS, W = 1.0
+! PREPARE NEXT VERTEX
+    add #24, r3      ! EX, r3 += VERTEX_STRIDE
+    pref @r3         ! LS, PREFETCH r3 (next vertex)
+    add #64, r5      ! EX, r5 += 2 * sizeof(VERTEX)
+! TRANSFORM VERTEX
+    ftrv xmtrx, fv4  ! FE, TRANSFORM(XYZW)
+! LOAD ATTRIBUTES
+    fmov    @r4+,fr3 ! LS, C = src->color
+    fmov    @r4+,fr1 ! LS, U = src->u
+    fmov    @r4+,fr2 ! LS, V = src->v
+.endm
+
+! =========================================================
+! ========================= VERTEX OUTPUT =================
+! =========================================================
+! To take advantage of SH4 dual instruction processing, 
+!  clipflag calculation and vertex output are interleaved
+.macro ProcessVertex1
+    fmov.s  fr7,@-r5 ! LS, dst->w = W
+    fmov.s  fr3,@-r5 ! LS, dst->c = C
+    fneg    fr7      ! LS, W = -W
+    fmov.s  fr2,@-r5 ! LS, dst->v = V
+    fcmp/gt fr7,fr6  ! FE, T = Z > W (i.e. Z > -W)
+    fmov.s  fr1,@-r5 ! LS, dst->u = U
+    movt    r0       ! EX, CLIPFLAGS = T
+    fmov.s  fr6,@-r5 ! LS, dst->z = Z
+    fmov.s  fr5,@-r5 ! LS, dst->y = Y
+    fmov.s  fr4,@-r5 ! LS, dst->x = X
+    mov.l   r1,@-r5  ! LS, dst->flags = CMD_VERT
+.endm
+
+.macro ProcessVertex2
+    fmov.s  fr7,@-r5 ! LS, dst->w = W
+    fmov.s  fr3,@-r5 ! LS, dst->c = C
+    fneg    fr7      ! LS, W = -W
+    fmov.s  fr2,@-r5 ! LS, dst->v = V
+    fcmp/gt fr7,fr6  ! FE, T = Z > W (i.e. Z > -W)
+    fmov.s  fr1,@-r5 ! LS, dst->u = U
+    movt    r2       ! EX, tmp = T
+    fmov.s  fr6,@-r5 ! LS, dst->z = Z
+    add     r2,r2    ! EX, tmp = tmp + tmp
+    fmov.s  fr5,@-r5 ! LS, dst->y = Y
+    or      r2,r0    ! EX, CLIPFLAGS |= tmp (T << 1)
+    fmov.s  fr4,@-r5 ! LS, dst->x = X
+    mov.l   r1,@-r5  ! LS, dst->flags = CMD_VERT
+.endm
+
+.macro ProcessVertex3
+    fmov.s  fr7,@-r5 ! LS, dst->w = W
+    fmov.s  fr3,@-r5 ! LS, dst->c = C
+    fneg    fr7      ! LS, W = -W
+    fmov.s  fr2,@-r5 ! LS, dst->v = V
+    fcmp/gt fr7,fr6  ! FE, T = Z > W (i.e. Z > -W)
+    fmov.s  fr1,@-r5 ! LS, dst->u = U
+    movt    r2       ! EX, tmp = T
+    fmov.s  fr6,@-r5 ! LS, dst->z = Z
+    fmov.s  fr5,@-r5 ! LS, dst->y = Y
+    shll2   r2       ! EX, tmp = tmp << 2
+    fmov.s  fr4,@-r5 ! LS, dst->x = X
+    or      r2,r0    ! EX, CLIPFLAGS |= tmp (T << 2)
+    mov.l   r1,@-r5  ! LS, dst->flags = CMD_VERT
+.endm
+
+.macro ProcessVertex4 eos_addr
+    fmov.s  fr7,@-r5 ! LS, dst->w = W
+    fmov.s  fr3,@-r5 ! LS, dst->c = C
+    fneg    fr7      ! LS, W = -W
+    fmov.s  fr2,@-r5 ! LS, dst->v = V
+    fcmp/gt fr7,fr6  ! FE, T = Z > W (i.e. Z > -W)
+    fmov.s  fr1,@-r5 ! LS, dst->u = U
+    movt    r2       ! EX, tmp = T
+    fmov.s  fr6,@-r5 ! LS, dst->z = Z
+    shll2   r2       ! EX, tmp = tmp << 2
+    fmov.s  fr5,@-r5 ! LS, dst->y = Y
+    add     r2,r2    ! EX, tmp = (tmp << 2) + (tmp << 2)
+    fmov.s  fr4,@-r5 ! LS, dst->x = X
+    mov.l \eos_addr, r1 ! LS, r1  = GPU EOS command
+    or      r2,r0    ! EX, CLIPFLAGS |= tmp (T << 3)
+    or      r0,r1    ! EX, r1 |= CLIPFLAGS
+    mov.l   r1,@-r5  ! LS, dst->flags = GPU EOS | CLIPFLAGS
+.endm
+
+
+! =========================================================
+! ====================== VIEWPORT TRANSFORM ===============
+! =========================================================
+!r2 = return addr
+!r0 = temp
+!r5 = dst pointer
+
+!fr0  = temp
+!fr4  = temp
+!fr5  = temp
+!fr5  = temp
+!fr8  = VIEWPORT_HWIDTH
+!fr9  = VIEWPORT_HHEIGHT
+!fr10 = VIEWPORT_X_PLUS_HWIDTH
+!fr11 = VIEWPORT_Y_PLUS_HHEIGHT
+
+.macro ViewportTransformSetup vp_addr
+    mova \vp_addr, r0 ! EX,  r0  = &VIEWPORT
+    fmov.s	@r0+,fr8  ! LS, fr8  = VIEWPORT_HWIDTH
+    fmov.s	@r0+,fr9  ! LS, fr9  = VIEWPORT_HHEIGHT
+    fmov.s	@r0+,fr10 ! LS, fr10 = VIEWPORT_X_PLUS_HWIDTH
+    fmov.s	@r0+,fr11 ! LS, fr11 = VIEWPORT_Y_PLUS_HHEIGHT
+    nop               ! MT (align to even instructions boundary)
+.endm
+
+.macro ViewportTransformVertex
+! INVERSE W CALCULATION
+    add #28, r5       ! EX, r5  = &vertex->w
+    fmov.s  @r5,fr0   ! LS, fr0 = vertex->w
+    fmul    fr0,fr0   ! FE, fr0 = fr0 * fr0
+    add #-24, r5      ! EX, r5  = &vertex->x
+    fsrra   fr0       ! FE, fr0 = 1 / sqrt(fr0) -> 1 / vertex->w
+
+! TRANSFORM X
+    fmov.s @r5,fr4    ! LS, fr4 = vertex->x
+    fmov  fr10,fr5    ! LS, fr5 = VIEWPORT_X_PLUS_HWIDTH
+    fmul  fr8,fr4     ! FE, fr4 = VIEWPORT_HWIDTH * vertex->x
+    fmac  fr0,fr4,fr5 ! FE, fr5 = fr0 * fr4 + fr5 -- (X * F * hwidth) + x_plus_hwidth
+    fmov.s fr5,@r5    ! LS, vertex->x = fr5
+    add #4, r5        ! EX, r5  = &vertex->y
+
+! TRANSFORM Y
+    fmov.s @r5,fr4    ! LS, fr4 = vertex->y
+    fmov  fr11,fr5    ! LS, fr5  = VIEWPORT_Y_PLUS_HHEIGHT
+    fmul  fr9,fr4     ! FE, fr4  = VIEWPORT_HHEIGHT * vertex->y
+    fmac  fr0,fr4,fr5 ! FE, fr5  = fr0 * fr4 + fr5 -- (Y * F * hheight) + y_plus_hheight
+    fmov.s fr5,@r5    ! LS, vertex->y = fr5
+    add #4, r5        ! EX, r5  = &vertex->z
+
+! ASSIGN Z
+    fmov.s fr0,@r5    ! LS, vertex->z = fr0
+    add #20, r5       ! EX, r5 += 20 (points to start of next vertex)
+.endm
diff --git a/misc/dreamcast/boot_logo.png b/misc/dreamcast/boot_logo.png
new file mode 100644
index 0000000..eb243c8
--- /dev/null
+++ b/misc/dreamcast/boot_logo.png
Binary files differdiff --git a/misc/dreamcast/ip.txt b/misc/dreamcast/ip.txt
new file mode 100644
index 0000000..e69910a
--- /dev/null
+++ b/misc/dreamcast/ip.txt
@@ -0,0 +1,3 @@
+Version       : V1.360
+SW Maker Name : UnknownShadow200
+Game Title    : ClassiCube Dreamcast
\ No newline at end of file
diff --git a/misc/dreamcast/readme.txt b/misc/dreamcast/readme.txt
new file mode 100644
index 0000000..a354b6e
--- /dev/null
+++ b/misc/dreamcast/readme.txt
@@ -0,0 +1,9 @@
+The dreamcast build requires an initial bootstrap program (Initial Program) named IP.bin
+
+To generate a custom IP.bin, compile https://github.com/Dreamcast-Projects/makeip
+
+Then run: makeip ip.txt IP.BIN -l boot_logo.png
+
+---
+
+For more details about IP.bin, see https://mc.pp.se/dc/ip.bin.html
\ No newline at end of file