From c8e5d2497542526a9f4744d9a23906a8832d2a34 Mon Sep 17 00:00:00 2001 From: Connor Olding Date: Sun, 21 Oct 2018 17:31:03 +0200 Subject: [PATCH] rewrite the way VI is handled warning: only 240p is tested, and i think 480i is broken. --- inc/kernel.inc | 4 ++ inc/n64_vi.inc | 149 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel.asm | 41 +++++++++----- main.asm | 52 +++++++++++------ 4 files changed, 216 insertions(+), 30 deletions(-) diff --git a/inc/kernel.inc b/inc/kernel.inc index ed78c1f..016e8f7 100644 --- a/inc/kernel.inc +++ b/inc/kernel.inc @@ -13,6 +13,10 @@ constant K_ERRORPC(0x0614) constant K_BADVADDR(0x0618) constant K_HISTORY(0x061C) +constant KV_RES(0x0620) +constant KV_MODE(0x0624) +constant KV_ORIGIN(0x0628) + constant K_64DRIVE_MAGIC(0x0700) constant K_CI_BASE(0x0704) constant K_CONSOLE_AVAILABLE(0x0708) diff --git a/inc/n64_vi.inc b/inc/n64_vi.inc index 4f1f614..560145b 100644 --- a/inc/n64_vi.inc +++ b/inc/n64_vi.inc @@ -55,6 +55,155 @@ constant VI_NTSC_CLOCK(48681812) // NTSC: Hz = 48.681812 MHz constant VI_PAL_CLOCK(49656530) // PAL: Hz = 49.656530 MHz constant VI_MPAL_CLOCK(48628316) // MPAL: Hz = 48.628316 MHz +// enum for video resolutions; values are arbitrary. +// interlaced: +constant RES_640_480(480) // no padding. +constant RES_576_432(432) // 640x480 after VI padding. +constant RES_512_448(448) // stretched to 640x448, 640x480 after VI padding. +// not interlaced: +constant RES_320_240(240) // upscaled 2x. +constant RES_288_216(216) // upscaled 2x. 640x480 after VI padding. +constant RES_256_224(224) // upscaled 2x, stretched to 640x448, etc. + +macro MakeSetScreenNTSC() { + // note that you can only call this macro once. + +SetScreenNTSC: + // this version expects to be called every frame. + // a0: resolution to use (enum). + // a1: desired VI settings (status/control). mutable. + // a2: image color buffer origin address. mutable. + // v0: zero on success, non-zero on failure (bad enum or VI settings). + + lui v1, VI_BASE + lw t0, VI_V_CURRENT_LINE(v1) + andi t0, 1 + + andi t1, a1, 3 // extract BPP + subiu t1, 2 // now 16 BPP is 0 and 32 BPP is 1 + bltz t1, SetScreenNTSC_Fail // fail if it's not set to 16 or 32 BPP + + lli t8, RES_640_480 // delay slot + beq a0, t8, SetScreenNTSC_480 + + lli t9, RES_576_432 // delay slot + beq a0, t9, SetScreenNTSC_432 + + lli t8, RES_512_448 // delay slot + beq a0, t8, SetScreenNTSC_448 + + lli t9, RES_320_240 // delay slot + beq a0, t9, SetScreenNTSC_240 + + lli t8, RES_288_216 // delay slot + beq a0, t8, SetScreenNTSC_216 + + lli t9, RES_256_224 // delay slot + beq a0, t9, SetScreenNTSC_224 + +SetScreenNTSC_Fail: + lli v0, 1 // delay slot + jr ra + sw r0, VI_V_CURRENT_LINE(v1) // clear interrupt + +SetScreenNTSC_SetInterlaced: + beqz t0, SetScreenNTSC_Set // nothing more to do on even fields. + ori a1, INTERLACE + + // handle odd fields. + addu a2, t2 // add width to origin + addu a2, t2 // and again for a full row (when 16 BPP) + beqz t1, SetScreenNTSC_Set // branch when 16 BPP + subiu t7, 2 // prevents bottom line from displaying out-of-bounds garbage + addu a2, t2 + addu a2, t2 // full row (when 32 BPP) + +SetScreenNTSC_Set: + lw t1, VI_V_CURRENT_LINE(v1) + + // variable stuff: + sw t1, VI_V_CURRENT_LINE(v1) + sw t2, VI_WIDTH(v1) // VI_H_WIDTH + sw t3, VI_V_SYNC(v1) + sw t4, VI_X_SCALE(v1) + sw t5, VI_Y_SCALE(v1) + sw t6, VI_H_VIDEO(v1) // VI_H_START + sw t7, VI_V_VIDEO(v1) // VI_V_START + + // constant stuff: + lli t1, 2 + li t2, 57 | (34 << 8) | (5 << 16) | (62 << 20) + lli t3, 3093 + li t4, 3093 | (3093 << 16) + li t5, (0x0E << 16) | 0x204 + sw t1, VI_V_INTR(v1) // VI_INTR + sw t2, VI_TIMING(v1) // VI_BURST + sw t3, VI_H_SYNC(v1) + sw t4, VI_H_SYNC_LEAP(v1) // VI_LEAP + sw t5, VI_V_BURST(v1) + + // final variable stuff: + sw a1, VI_STATUS(v1) // VI_CONTROL + sw a2, VI_ORIGIN(v1) // VI_DRAM_ADDR + + jr ra + lli v0, 0 + +SetScreenNTSC_480: + lli t2, 640 + li t4, 0x400 + li t5, 0x800 | (0x200 << 16) + li t6, (0x6C << 16) | (0x6C + 640) + li t7, (0x23 << 16) | (0x23 + 480) + b SetScreenNTSC_SetInterlaced + lli t3, 525 - 1 + +SetScreenNTSC_432: + lli t2, 576 + li t4, 0x400 + li t5, 0x800 | (0x200 << 16) + li t6, (0x8C << 16) | (0x8C + 576) + li t7, (0x3B << 16) | (0x3B + 432) + b SetScreenNTSC_SetInterlaced + lli t3, 525 - 1 + +SetScreenNTSC_448: + lli t2, 512 + li t4, (512 * 256 + 128) / 160 + li t5, 0x800 | (0x200 << 16) + li t6, (0x6C << 16) | (0x6C + 640) + li t7, (0x33 << 16) | (0x33 + 448) + b SetScreenNTSC_SetInterlaced + lli t3, 525 - 1 + +SetScreenNTSC_240: + lli t2, 320 + li t4, 0x200 + li t5, 0x400 + li t6, (0x6C << 16) | (0x6C + 640) + li t7, (0x23 << 16) | (0x23 + 480) + b SetScreenNTSC_Set + lli t3, 525 + +SetScreenNTSC_216: + lli t2, 288 + li t4, 0x200 + li t5, 0x400 + li t6, (0x8C << 16) | (0x8C + 576) + li t7, (0x3B << 16) | (0x3B + 432) + b SetScreenNTSC_Set + lli t3, 525 + +SetScreenNTSC_224: + lli t2, 256 + li t4, (256 * 256 + 128) / 160 + li t5, 0x400 + li t6, (0x6C << 16) | (0x6C + 640) + li t7, (0x33 << 16) | (0x33 + 448) + b SetScreenNTSC_Set + lli t3, 525 +} + macro ScreenNTSC(width,height, status, origin) { lui a0,VI_BASE // A0 = VI Base Register ($A4400000) la t0,{origin} // T0 = Origin (Frame Buffer Origin In Bytes) diff --git a/kernel.asm b/kernel.asm index 4aa530f..8686b35 100644 --- a/kernel.asm +++ b/kernel.asm @@ -24,6 +24,9 @@ include "init.asm" sw r0, K_UNUSED(gp) sw r0, K_CONSOLE_AVAILABLE(gp) sw r0, K_HISTORY(gp) + sw r0, KV_RES(gp) + sw r0, KV_MODE(gp) + sw r0, KV_ORIGIN(gp) Drive64Init: lui t9, CI_BASE @@ -368,12 +371,12 @@ K_MI_Loop: nop K_MI_SP: - KWriteString(KS_MI_SP) - lli t0, SP_INT_CLR lui a1, SP_BASE sw t0, SP_STATUS(a1) + KWriteString(KS_MI_SP) + lw t0, K_HISTORY(k0) ori t0, MI_INTR_SP sw t0, K_HISTORY(k0) @@ -381,11 +384,11 @@ K_MI_SP: andi s0, ~MI_INTR_SP K_MI_SI: - KWriteString(KS_MI_SI) - lui a1, SI_BASE sw r0, SI_STATUS(a1) + KWriteString(KS_MI_SI) + lw t0, K_HISTORY(k0) ori t0, MI_INTR_SI sw t0, K_HISTORY(k0) @@ -393,11 +396,11 @@ K_MI_SI: andi s0, ~MI_INTR_SI K_MI_AI: - KWriteString(KS_MI_AI) - lui a1, AI_BASE sw r0, AI_STATUS(a1) + KWriteString(KS_MI_AI) + lw t0, K_HISTORY(k0) ori t0, MI_INTR_AI sw t0, K_HISTORY(k0) @@ -405,11 +408,13 @@ K_MI_AI: andi s0, ~MI_INTR_AI K_MI_VI: - KWriteString(KS_MI_VI) - lui a1, VI_BASE - lw t0, VI_V_CURRENT_LINE(a1) - sw t0, VI_V_CURRENT_LINE(a1) + lw a0, KV_RES(k0) + lw a1, KV_MODE(k0) + jal SetScreenNTSC + lw a2, KV_ORIGIN(k0) + + KWriteString(KS_MI_VI) lw t0, K_HISTORY(k0) ori t0, MI_INTR_VI @@ -418,12 +423,12 @@ K_MI_VI: andi s0, ~MI_INTR_VI K_MI_PI: - KWriteString(KS_MI_PI) - lli t0, 0x02 lui a1, PI_BASE sw t0, PI_STATUS(a1) + KWriteString(KS_MI_PI) + lw t0, K_HISTORY(k0) ori t0, MI_INTR_PI sw t0, K_HISTORY(k0) @@ -431,12 +436,12 @@ K_MI_PI: andi s0, ~MI_INTR_PI K_MI_DP: - KWriteString(KS_MI_DP) - lli t0, 0x0800 lui a1, MI_BASE sw t0, MI_INIT_MODE(a1) + KWriteString(KS_MI_DP) + lw t0, K_HISTORY(k0) ori t0, MI_INTR_DP sw t0, K_HISTORY(k0) @@ -485,6 +490,14 @@ dw KCode20, KCode21, KCode22, KCode23 dw KCode24, KCode25, KCode26, KCode27 dw KCode28, KCode29, KCode30, KCode31 +K_SetScreenNTSC: + lui a3, K_BASE + sw a0, KV_RES(a3) + sw a1, KV_MODE(a3) + sw a2, KV_ORIGIN(a3) + // fall-thru +MakeSetScreenNTSC() + include "debug.asm" if K_DEBUG { diff --git a/main.asm b/main.asm index dc1247d..57824ac 100644 --- a/main.asm +++ b/main.asm @@ -117,8 +117,23 @@ MainLoop: beqz t0,- nop - WriteString(S_VI_Wait) + // queue buffers to swap + lui a0, K_BASE + beqz s1, SwapToMain + nop +SwapToAlt: + la t0, VIDEO_C_IMAGE_ALT | UNCACHED + sw t0, KV_ORIGIN(a0) + b + + lli s1, 0 +SwapToMain: + la t0, VIDEO_C_IMAGE | UNCACHED + sw t0, KV_ORIGIN(a0) + lli s1, 1 ++ + // wait on VI too + WriteString(S_VI_Wait) lui a0, VI_BASE - lw t0, VI_V_CURRENT_LINE(a0) @@ -129,24 +144,27 @@ MainLoop: WriteString(SNewFrame) - // swap buffers - lui a0, VI_BASE - beqz s1, SwitchToAlt + j Start3D nop -SwitchToMain: - la t0, VIDEO_C_IMAGE_ALT | UNCACHED - sw t0, VI_ORIGIN(a0) - j Start3D - lli s1, 0 -SwitchToAlt: - la t0, VIDEO_C_IMAGE | UNCACHED - sw t0, VI_ORIGIN(a0) - j Start3D - lli s1, 1 SetupScreen: - ScreenNTSC(WIDTH, HEIGHT, VIDEO_MODE, VIDEO_C_IMAGE | UNCACHED) - jr ra +if WIDTH == 640 { + lli a0, RES_640_480 +} else if WIDTH == 576 { + lli a0, RES_576_432 +} else if WIDTH == 512 { + lli a0, RES_512_448 +} else if WIDTH == 320 { + lli a0, RES_320_240 +} else if WIDTH == 288 { + lli a0, RES_288_216 +} else if WIDTH == 256 { + lli a0, RES_256_224 +} + + li a1, VIDEO_MODE + la a2, VIDEO_C_IMAGE | UNCACHED + j K_SetScreenNTSC // tail-call nop MainDumpWrite: @@ -164,6 +182,8 @@ MainDumpWrite: addiu sp, 0x18 Die: + mfc0 t0, CP0_Status + mtc0 t0, CP0_Status j Die nop