diff --git a/cachetest.asm b/cachetest.asm index 1b0b45c..cbd14f2 100644 --- a/cachetest.asm +++ b/cachetest.asm @@ -44,8 +44,8 @@ constant MAIN_FROM(0x0000) constant MAIN_TO(0x0080) constant MAIN_FONT(0x4000) -constant WIDTH(640) -constant HEIGHT(480) +constant WIDTH(576) // 640 * 0.9 +constant HEIGHT(432) // 480 * 0.9 constant DEPTH(2) constant VIDEO_BUFFER(0x80400000 - WIDTH * HEIGHT * DEPTH) constant VIDEO_MODE(BPP16 | INTERLACE | AA_MODE_2 | DIVOT_EN | PIXEL_ADV_3 | DITHER_FILTER_EN) @@ -89,7 +89,7 @@ Start: li t1, 0xDEADBEEF li t2, 0xCAFEBABE li t3, 0xABAD1DEA - li t4, 0x12345678 + li t4, 0xADD0BEE5 lui a0, MAIN_BASE // spaced out a bit just to see what happens. @@ -137,8 +137,8 @@ if 0 { ori a0, MAIN_FONT // show our results on-screen. - lli s0, 64 // s0: X - lli s1, 48 // s1: Y + lli s0, 16 // s0: X + lli s1, 12 // s1: Y lli s2, 0x20 / 4 // s2: number of words to draw lui s3, MAIN_BASE ori s3, MAIN_TO // s3: start of data to dump @@ -148,12 +148,12 @@ MainHexDumpLoop: lw s4, 0(s3) // s4: current word being drawn - addiu s0, 8 * 8 + addiu s0, 8 * FONT_WIDTH lli s5, 8 // s5: inner loop iteration count MainHexDumpInnerLoop: andi t0, s4, 0x0F - subiu s0, 8 + subiu s0, FONT_WIDTH lui a0, MAIN_BASE ori a0, MAIN_FONT @@ -169,10 +169,40 @@ MainHexDumpInnerLoop: srl s4, 4 subiu s2, 1 - addiu s1, 12 + addiu s1, FONT_HEIGHT bnez s2, MainHexDumpLoop addiu s3, 4 + la s3, TEXT +DrawTextLoop: + lbu a1, 0(s3) + addiu s3, 1 + + beqz a1, DrawTextDone + + lli t0, 0x0D // delay slot + beq a1, t0, DrawTextLoop + + lli t1, 0x0A // delay slot + bne a1, t1,+ + nop + addiu s1, FONT_HEIGHT // next line + b DrawTextLoop + lli s0, 16 // return to base X offset ++ + + lui a0, MAIN_BASE // delay slot + ori a0, MAIN_FONT + sll a2, s1, 16 + or a2, s0 + la a3, VIDEO_BUFFER + jal DrawChar16 + + addiu s0, FONT_WIDTH // delay slot + b DrawTextLoop + nop + +DrawTextDone: // use our old cache-poking utility for now. jal PokeDataCache nop @@ -180,50 +210,57 @@ MainHexDumpInnerLoop: lui a0, VI_BASE li t1, VIDEO_MODE li t2, VIDEO_BUFFER & ADDR_MASK - li t3, 640 // width in pixels (for the buffer) - li t4, 0 // interrupt on line + li t3, WIDTH // width of the buffer in pixels + li t4, 0 // interrupt on line, 0 to disable (i think?) li t5, 0 // current line; any write clears VI interrupt li t6, 0x03E52239 // timings (split into 4) - li t7, 525 - 1 // lines. subtracting by one enables interlacing. - sw t1, 4 * 0(a0) - sw t2, 4 * 1(a0) - sw t3, 4 * 2(a0) - sw t4, 4 * 3(a0) - sw t5, 4 * 4(a0) - sw t6, 4 * 5(a0) - sw t7, 4 * 6(a0) + li t7, 525 - 1 // lines; subtracting by one enables interlacing + sw t1, VI_STATUS(a0) // offset 0x00 + sw t2, VI_ORIGIN(a0) // offset 0x04 + sw t3, VI_WIDTH(a0) // offset 0x08 + sw t4, VI_V_INTR(a0) // offset 0x0C + sw t5, VI_V_CURRENT_LINE(a0) // offset 0x10 + sw t6, VI_TIMING(a0) // offset 0x14 + sw t7, VI_V_SYNC(a0) // offset 0x18 li t1, 0x00000C15 // divide VI clock to get proper NTSC rate li t2, 0x0C150C15 // likewise (this is only different on PAL) - li t3, 0x006C02EC // 640 pixels per row, starting at 108 units - li t4, 0x00230203 // 480 pixels per column, starting at 35 units + li t3, 0x008C02CC // 576 pixels per row, starting at ... units + li t4, 0x003B01EB // 432 pixels per column, starting at ... units li t5, 0x000E0204 // video burst starts at 14 and lasts for 502 units li t6, 0x00000400 // x offset and x step size (inverse scaling) - li t7, 0x00000800 // y offset and y step size (inverse scaling) - sw t1, 4 * 7(a0) - sw t2, 4 * 8(a0) - sw t3, 4 * 9(a0) - sw t4, 4 * 10(a0) - sw t5, 4 * 11(a0) - sw t6, 4 * 12(a0) - sw t7, 4 * 13(a0) + li t7, 0x02000800 // y offset and y step size (inverse scaling) + // setting y offset to 0.5 (it's Q10 fixed point) + // reduces interlacing jitter at the cost of a little image sharpness. + sw t1, VI_H_SYNC(a0) // offset 0x1C + sw t2, VI_H_SYNC_LEAP(a0) // offset 0x20 + sw t3, VI_H_VIDEO(a0) // offset 0x24 + sw t4, VI_V_VIDEO(a0) // offset 0x28 + sw t5, VI_V_BURST(a0) // offset 0x2C + sw t6, VI_X_SCALE(a0) // offset 0x30 + sw t7, VI_Y_SCALE(a0) // offset 0x34 VideoLoop: lui a0, VI_BASE li t1, VIDEO_BUFFER & ADDR_MASK - + // wait until we're done displaying the frame. lw t0, VI_V_CURRENT_LINE(a0) sltiu at, t0, 2 + 1 beqz at,- nop - andi t0, 1 - bnez t0,+ + andi t0, 1 // check if we're on an odd field. + li t2, 0x003B01EB + bnez t0,+ // if we're not, branch. nop - addiu t1, WIDTH * DEPTH + addiu t1, WIDTH * DEPTH // odd field, so offset the image by one row. + li t2, 0x003B01E9 // slightly shorter image so that + // the y offset doesn't cause sampling out of bounds + sw t1, VI_ORIGIN(a0) + sw t2, VI_V_VIDEO(a0) j VideoLoop nop @@ -250,4 +287,9 @@ PokeDataCache: jr ra nop -include "font.asm" +align(16) +insert TEXT, "text.txt" +db 0 +align(4) + +include "font.8x16.asm" diff --git a/dlist.asm b/dlist.asm index 6baff7c..c27c792 100644 --- a/dlist.asm +++ b/dlist.asm @@ -174,14 +174,25 @@ if HIRES { gMatrix(view_mat1, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION) gPipeSync() - gSetCombine(15,15,31,4,7,7,7,4, 15,15,31,4,7,7,7,4) - gSetOtherMode(G_PM_NPRIMITIVE | G_CYC_1CYCLE | G_TP_NONE | G_TD_CLAMP | G_TL_TILE | G_TT_NONE | G_TF_AVERAGE | G_TC_FILT | G_CK_NONE | G_CD_MAGICSQ | G_AD_PATTERN, G_AC_NONE | G_ZS_PIXEL | Z_CMP | Z_UPD) + gSetCombine(0,0,0,4,0,0,0,4, 0,0,0,4,0,0,0,4) +variable upper(G_PM_NPRIMITIVE | G_CYC_1CYCLE | G_TP_NONE | G_TD_CLAMP | G_TL_TILE | G_TT_NONE | G_TF_AVERAGE | G_TC_FILT | G_CK_NONE | G_CD_MAGICSQ | G_AD_PATTERN) +variable lower(AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | G_BL_CLR_IN << 30 | G_BL_A_IN << 26 | G_BL_CLR_MEM << 22 | G_BL_A_MEM << 18) + gSetOtherMode(upper, lower) gGeometryMode(0, G_ZBUFFER | G_SHADE | G_CULL_FRONT | G_SHADING_SMOOTH) gSetSegment6(model) gMatrix(model_mat, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW) gDisplayList((6 << 24) | MODEL_START) +if 0 { + // debug: display coverage values onscreen. + gPipeSync() + gSetOtherMode(G_CYC_1CYCLE, G_ZS_PRIM | IM_RD | FORCE_BL | G_BL_CLR_IN << 30 | G_BL_0 << 26 | G_BL_CLR_BL << 22 | G_BL_A_MEM << 18) + gSetBlendColor(0xFF,0xFF,0xFF,0xFF) + gSetPrimDepth(0xFFFF, 0xFFFF) + gFillRect(0, 0, WIDTH - 1, HEIGHT - 1) +} + // finish. gFullSync() gEndList() @@ -204,8 +215,8 @@ align(8) viewport: // note that the third parameters here affect the range of Z-buffering. - dh WIDTH/2*4, HEIGHT/2*4, 0x3FF, 0 // scale - dh WIDTH/2*4, HEIGHT/2*4, 0x000, 0 // translation + dh WIDTH/2*4, HEIGHT/2*4, 0x1FF, 0 // scale + dh WIDTH/2*4, HEIGHT/2*4, 0x1FF, 0 // translation view_mat0: if FOV90 { @@ -215,10 +226,10 @@ if FOV90 { Mat.X($0001'4C8D, $0000'0000, $0000'0000, $0000'0000) Mat.Y($0000'0000, $0001'BB67, $0000'0000, $0000'0000) } - Mat.Z($0000'0000, $0000'0000, $FFFE'FF00, $FFFF'0000) - Mat.W($0000'0000, $0000'0000, $FFFD'FF00, $0000'0000) + Mat.Z($0000'0000, $0000'0000, $FFFE'FF9A, $FFFF'0000) + Mat.W($0000'0000, $0000'0000, $FFEB'FC00, $0000'0000) Mat.rix() -constant PERSPECTIVE_NORMALIZATION($00FF) +constant PERSPECTIVE_NORMALIZATION($000A) view_mat1: Mat.X($0001'0000, $0000'0000, $0000'0000, $0000'0000) @@ -265,6 +276,6 @@ constant MODEL_START(pc() - model) gQuadTri(2, 3, 7, 6) gEndList() } else { - constant MODEL_START(0x32B0) + constant MODEL_START(0) insert model, "res/teapot.F3D" } diff --git a/font.8x16.asm b/font.8x16.asm new file mode 100644 index 0000000..5b67e53 --- /dev/null +++ b/font.8x16.asm @@ -0,0 +1,144 @@ +constant FONT_WIDTH(8) +constant FONT_HEIGHT(16) +constant FONT_SIZE16(FONT_WIDTH * FONT_HEIGHT * 2 * 95) // 0x5F00 + +LoadFont16: + // loads a 95-character, 8x16 font + // as an RGB5A1 (16-bpp) image to the specified address. + // a0: address to load font to (size: 0x5F00) + li t9, FONT_SIZE16 + addu a1, a0, t9 // a1: end of output (exclusive) + la a2, FONT // a2: start of input + la a3, FONT + FONT.size // a3: end of input (exclusive) + +LoadFont16Loop: + lhu t9, 0(a2) + addiu a2, 2 + + srl t1, t9, 12 + srl t2, t9, 8 + srl t3, t9, 4 + andi t4, t9, 0x0F + andi t2, 0x0F + andi t3, 0x0F + +if 0 { + sll t1, 2 + sll t2, 2 + sll t3, 2 + sll t4, 2 +} else { + // copy lsb to get the full 5-bit range of values. + sll t5, t1, 1 + sll t6, t2, 1 + sll t7, t3, 1 + sll t8, t4, 1 + andi t1, 1 + andi t2, 1 + andi t3, 1 + andi t4, 1 + or t1, t5 + or t2, t6 + or t3, t7 + or t4, t8 + sll t1, 1 + sll t2, 1 + sll t3, 1 + sll t4, 1 +} + + sll t5, t1, 5 + sll t6, t2, 5 + sll t7, t3, 5 + sll t8, t4, 5 + or t1, t5 + or t2, t6 + or t3, t7 + or t4, t8 + + sll t5, t1, 5 + sll t6, t2, 5 + sll t7, t3, 5 + sll t8, t4, 5 + or t1, t5 + or t2, t6 + or t3, t7 + or t4, t8 + + ori t1, 1 + ori t2, 1 + ori t3, 1 + ori t4, 1 + + sh t1, 0x0(a0) + sh t2, 0x2(a0) + sh t3, 0x4(a0) + sh t4, 0x6(a0) + + bne a2, a3, LoadFont16Loop + addiu a0, 0x8 + + jr ra + nop + +DrawChar16: + // draws a 16-bpp character on-screen at the specified coordinates. + // a0: font data address (same argument as LoadFont16) + // a1: character (range: 32 to 126 inclusive) + // a2: X, Y coordinate in pixels: X | Y << 16 + // a3: output image address + + // exit early if character is outside of valid range. + subiu a1, 0x20 + bltz a1, DrawCharDone + sltiu at, a1, 0x80 - 0x20 + beqz at, DrawCharDone + + lli t9, FONT_WIDTH * FONT_HEIGHT * 2 // delay slot + multu a1, t9 + mflo t9 + addu a0, t9 // a0: character data address + + andi a1, a2, 0xFFFF // a1: X + srl a2, 16 // a2: Y + + sll t0, a1, 1 + lli t9, WIDTH * 2 + multu a2, t9 + mflo t9 + addu a3, t0 // offset output by X + addu a3, t9 // offset output by Y + + lli t9, FONT_HEIGHT // t9: rows remaining + +DrawChar16Loop: + // character width hardcoded for 8. + lhu t1, 0x0(a0) + lhu t2, 0x2(a0) + lhu t3, 0x4(a0) + lhu t4, 0x6(a0) + lhu t5, 0x8(a0) + lhu t6, 0xA(a0) + lhu t7, 0xC(a0) + lhu t8, 0xE(a0) + + sh t1, 0x0(a3) + sh t2, 0x2(a3) + sh t3, 0x4(a3) + sh t4, 0x6(a3) + sh t5, 0x8(a3) + sh t6, 0xA(a3) + sh t7, 0xC(a3) + sh t8, 0xE(a3) + + addiu a0, 0x10 + subiu t9, 1 + + bnez t9, DrawChar16Loop + addiu a3, WIDTH * 2 + +DrawCharDone: + jr ra + nop + +insert FONT, "res/fonts/NotoSansMono-SemiCondensedMedium.16.i4" diff --git a/font.asm b/font.asm deleted file mode 100644 index 05bd3d7..0000000 --- a/font.asm +++ /dev/null @@ -1,103 +0,0 @@ -constant FONT_SIZE16(8 * 12 * 2 * 256) // 0xC000 - -LoadFont16: - // loads a 256-character, 8x12 font - // as an RGB5A1 (16-bpp) image to the specified address. - // a0: address to load font to (size: 0xC000) - li t9, FONT_SIZE16 - addu a1, a0, t9 // a1: end of output (exclusive) - la a2, FONT // a2: start of input - la a3, FONT + FONT.size // a3: end of input (exclusive) - -LoadFont16Loop: - lbu t9, 0(a2) - addiu a2, 1 - - // sign-extend every pixel to get our blacks and whites. - sll t1, t9, 24 - sll t2, t9, 25 - sll t3, t9, 26 - sll t4, t9, 27 - sll t5, t9, 28 - sll t6, t9, 29 - sll t7, t9, 30 - sll t8, t9, 31 - // - sra t1, 31 - sra t2, 31 - sra t3, 31 - sra t4, 31 - sra t5, 31 - sra t6, 31 - sra t7, 31 - sra t8, 31 - - sh t1, 0x0(a0) - sh t2, 0x2(a0) - sh t3, 0x4(a0) - sh t4, 0x6(a0) - sh t5, 0x8(a0) - sh t6, 0xA(a0) - sh t7, 0xC(a0) - sh t8, 0xE(a0) - - bne a2, a3, LoadFont16Loop - addiu a0, 0x10 - - jr ra - nop - -DrawChar16: - // draws a 16-bpp character on-screen at the specified coordinates. - // a0: font data address (same argument as LoadFont16) - // a1: character (range: 0 to 255 inclusive) - // a2: X, Y coordinate in pixels: X | Y << 16 - // a3: output image address - - lli t9, 8 * 12 * 2 - multu a1, t9 - mflo t9 - addu a0, t9 // a0: character data address - - andi a1, a2, 0xFFFF // a1: X - srl a2, 16 // a2: Y - - sll t0, a1, 1 - lli t9, WIDTH * 2 - multu a2, t9 - mflo t9 - addu a3, t0 // offset output by X - addu a3, t9 // offset output by Y - - lli t9, 12 // t9: rows remaining (character height) - -DrawChar16Loop: - // character width hardcoded for 8. - lhu t1, 0x0(a0) - lhu t2, 0x2(a0) - lhu t3, 0x4(a0) - lhu t4, 0x6(a0) - lhu t5, 0x8(a0) - lhu t6, 0xA(a0) - lhu t7, 0xC(a0) - lhu t8, 0xE(a0) - - sh t1, 0x0(a3) - sh t2, 0x2(a3) - sh t3, 0x4(a3) - sh t4, 0x6(a3) - sh t5, 0x8(a3) - sh t6, 0xA(a3) - sh t7, 0xC(a3) - sh t8, 0xE(a3) - - addiu a0, 0x10 - subiu t9, 1 - - bnez t9, DrawChar16Loop - addiu a3, WIDTH * 2 - - jr ra - nop - -align(16); insert FONT, "res/dwarf.1bpp" diff --git a/inc/F3DEX2.inc b/inc/F3DEX2.inc index 6943c4d..fd06814 100644 --- a/inc/F3DEX2.inc +++ b/inc/F3DEX2.inc @@ -159,16 +159,29 @@ constant CVG_DST_WRAP(0x100) constant CVG_DST_FULL(0x200) constant CVG_DST_SAVE(0x300) // more Z stuff -constant ZMODE_OPA(0) -constant ZMODE_INTER(0x400) -constant ZMODE_XLU(0x800) -constant ZMODE_DEC(0xC00) +constant ZMODE_OPA(0) // opaque +constant ZMODE_INTER(0x400) // interpenetrating +constant ZMODE_XLU(0x800) // translucent +constant ZMODE_DEC(0xC00) // decal // more coverage stuff constant CVG_X_ALPHA(0x1000) constant ALPHA_CVG_SEL(0x2000) // blending constant FORCE_BL(0x4000) // no effect? +// blending modes +constant G_BL_CLR_IN(0) +constant G_BL_CLR_MEM(1) +constant G_BL_CLR_BL(2) +constant G_BL_CLR_FOG(3) +constant G_BL_1MA(0) +constant G_BL_A_MEM(1) +constant G_BL_A_IN(0) +constant G_BL_A_FOG(1) +constant G_BL_A_SHADE(2) +constant G_BL_1(2) +constant G_BL_0(3) + macro gNoOp() { // stalls the RDP (and not the RSP?) _g(0x00, 0, 0) @@ -489,7 +502,7 @@ macro gSetPrimDepth(variable z, variable dz) { // fixes the Z value to a constant for the following primitives. // useful for 2.5D effects, maybe? // TODO: what are the ranges? - _g(0xEE, 0, (z << 16) | d) + _g(0xEE, 0, (z << 16) | dz) } macro gRdpSetOtherMode(variable omodeH, variable omodeL) { diff --git a/inc/main.inc b/inc/main.inc index 8f1ffb0..094e6fa 100644 --- a/inc/main.inc +++ b/inc/main.inc @@ -5,7 +5,7 @@ constant HICOLOR(0) constant MAIN_DECOMP_IMAGE(HIRES & HICOLOR) -constant MAIN_BASE(0x800E) +constant MAIN_BASE(0x8004) constant MAIN_COUNTS(0x0010) constant MAIN_SP_TASK(0x0040) constant MAIN_XXD(0x0080) @@ -13,6 +13,8 @@ constant MAIN_DLIST(0x1000) constant MAIN_DLIST_SIZE(0xF000) constant MAIN_DLIST_JUMPER(MAIN_DLIST - 0xA8) +constant FONT_BASE(0x8005) + if HIRES { constant WIDTH(640) constant HEIGHT(480) @@ -21,6 +23,12 @@ if HIRES { constant HEIGHT(240) } +if HICOLOR { + constant DEPTH(4) +} else { + constant DEPTH(2) +} + if HIRES { if HICOLOR { // 640x480, 32-bit @@ -44,7 +52,7 @@ constant TASK_DP_WAIT(0x0002) constant TASK_LOADABLE(0x0004) constant TASK_SP_ONLY(0x0008) -constant VIDEO_C_IMAGE_SIZE(WIDTH * HEIGHT * (HICOLOR * 2 + 2)) +constant VIDEO_C_IMAGE_SIZE(WIDTH * HEIGHT * DEPTH) constant VIDEO_Z_IMAGE_SIZE(WIDTH * HEIGHT * 2) constant VIDEO_OUTPUT_SIZE(0x18000) // technically a buffer? constant VIDEO_STACK_SIZE(0x8000) // used for dlist calls, pushing matrices, etc? diff --git a/inc/n64.inc b/inc/n64.inc index f347fb6..278c266 100644 --- a/inc/n64.inc +++ b/inc/n64.inc @@ -15,6 +15,11 @@ include "n64_si.inc" include "n64_pif.inc" include "n64_util.inc" +// Rates +constant CLOCK_RATE(93750000) +constant COUNT_RATE(CLOCK_RATE / 2) // for use with the CP0 Count register. +constant COP_RATE(CLOCK_RATE * 2 / 3) + // Memory Map constant RDRAM_BASE($A3F0) // $03F00000 RDRAM Base constant RDRAM_DEVICE_TYPE($00) // $03F00000 Device Type diff --git a/kernel.asm b/kernel.asm index 8686b35..211921d 100644 --- a/kernel.asm +++ b/kernel.asm @@ -408,7 +408,6 @@ K_MI_AI: andi s0, ~MI_INTR_AI K_MI_VI: - lw a0, KV_RES(k0) lw a1, KV_MODE(k0) jal SetScreenNTSC diff --git a/main.asm b/main.asm index 57824ac..ef7c62f 100644 --- a/main.asm +++ b/main.asm @@ -23,9 +23,13 @@ include "kernel.asm" Main: + lui s0, MAIN_BASE + + jal LoadFont16 + lui a0, FONT_BASE + if MAIN_DECOMP_IMAGE { DecompImage: - lui s0, MAIN_BASE nop; nop; nop; nop mfc0 t0, CP0_Count @@ -72,8 +76,7 @@ Start3D: mfc0 t0, CP0_Status mtc0 t0, CP0_Status - lui a0, MAIN_BASE - ori a0, MAIN_DLIST + ori a0, s0, MAIN_DLIST jal WriteDList or a1, s1, r0 jal PokeDataCache @@ -91,9 +94,8 @@ Start3D: // only the lowest 12 bits are used, so 00000000 is equivalent to 04001000. sw r0, SP_PC(a0) - lui a0, MAIN_BASE jal PushVideoTask - ori a0, MAIN_SP_TASK + ori a0, s0, MAIN_SP_TASK jal LoadRSPBoot nop @@ -106,6 +108,8 @@ Start3D: EnableInt() MainLoop: + mfc0 s2, CP0_Count + WriteString(S_SP_Wait) - mfc0 t0, CP0_Status @@ -117,6 +121,79 @@ MainLoop: beqz t0,- nop + mfc0 s3, CP0_Count + subu s3, s2 + addiu s3, COUNT_RATE / (60 * 200) // for rounding + li t9, COUNT_RATE / (60 * 100) + divu s3, t9 + mflo s2 // s2: frame budget spent in (integer) percent + + // there are faster ways, but i'll prefer smaller codesize for now. + lli t9, 10 + divu s2, t9 + mfhi s3 // s3: (RTL) first digit + mflo t0 + divu t0, t9 + mfhi s4 // s4: (RTL) second digit + mflo t0 + divu t0, t9 + mfhi s5 // s5: (RTL) third digit + +if !HICOLOR { + +if HIRES { + lli s6, 64 // s6: X position + lli s7, 48 // s7: Y position +} else { + lli s6, 32 // s6: X position + lli s7, 24 // s7: Y position +} + + la s8, VIDEO_C_IMAGE // s8: output image buffer + beqz s1,+ + nop + la s8, VIDEO_C_IMAGE_ALT ++ + + beqz s5,+ + lui a0, FONT_BASE + addiu a1, s5, '0' + sll a2, s7, 16 + or a2, s6 + move a3, s8 + jal DrawChar16 ++ + addiu s6, FONT_WIDTH + + or at, s5, s6 + beqz at,+ + lui a0, FONT_BASE + addiu a1, s4, '0' + sll a2, s7, 16 + or a2, s6 + move a3, s8 + jal DrawChar16 ++ + addiu s6, FONT_WIDTH + + lui a0, FONT_BASE + addiu a1, s3, '0' + sll a2, s7, 16 + or a2, s6 + move a3, s8 + jal DrawChar16 + addiu s6, FONT_WIDTH + + lui a0, FONT_BASE + addiu a1, r0, '%' + sll a2, s7, 16 + or a2, s6 + move a3, s8 + jal DrawChar16 + addiu s6, FONT_WIDTH + +} + // queue buffers to swap lui a0, K_BASE beqz s1, SwapToMain @@ -197,6 +274,7 @@ if MAIN_DECOMP_IMAGE { } include "dlist.asm" include "task.asm" +include "font.8x16.asm" if pc() > (MAIN_BASE << 16) { error "ran out of memory for code and data" diff --git a/res/fonts/NotoSansMono-SemiCondensedMedium.16.i4 b/res/fonts/NotoSansMono-SemiCondensedMedium.16.i4 new file mode 100644 index 0000000..34c77aa Binary files /dev/null and b/res/fonts/NotoSansMono-SemiCondensedMedium.16.i4 differ diff --git a/res/teapot.F3D b/res/teapot.F3D index c52a5e4..4908765 100644 Binary files a/res/teapot.F3D and b/res/teapot.F3D differ diff --git a/task.asm b/task.asm index 26fc43a..edf382c 100644 --- a/task.asm +++ b/task.asm @@ -5,10 +5,15 @@ PushVideoTask: lli t0, 1 // mode: video lli t1, TASK_DP_WAIT // flags - li t2, UCODE_BOOT // does not need masking (not actually used?) + li t2, UCODE_BOOT & ADDR_MASK // not actually used? li t3, UCODE_BOOT.size li t4, F3DZEX_IMEM & ADDR_MASK +constant IMEM_SIZE(F3DZEX_IMEM.size) // weird bass quirk +if IMEM_SIZE > 0xFC0 { + li t5, 0xFC0 +} else { li t5, F3DZEX_IMEM.size +} li t6, F3DZEX_DMEM & ADDR_MASK li t7, F3DZEX_DMEM.size sw t0, 0x00(a0) @@ -25,7 +30,7 @@ PushVideoTask: li t2, (VIDEO_OUTPUT & ADDR_MASK) | UNCACHED // most commercial games re-use the yield pointer, so i assume it's fine: li t3, VIDEO_YIELD & ADDR_MASK // stores output buffer size - li t4, ((MAIN_BASE << 16) | MAIN_DLIST_JUMPER) & ADDR_MASK // initial DList + li t4, ((MAIN_BASE << 16) | MAIN_DLIST_JUMPER) // initial DList lli t5, 8 // size of one jump command. this is ignored and 0xA8 is used instead li t6, VIDEO_YIELD & ADDR_MASK li t7, VIDEO_YIELD_SIZE @@ -38,6 +43,8 @@ PushVideoTask: sw t6, 0x38(a0) sw t7, 0x3C(a0) + nop; nop; nop; nop + // tell data cache to write itself out cache 0x19, 0x00(a0) cache 0x19, 0x10(a0) diff --git a/text.txt b/text.txt new file mode 100644 index 0000000..fa310e3 --- /dev/null +++ b/text.txt @@ -0,0 +1,12 @@ +Done with the battles he once +waged across time, he embarked +on a journey. A secret and +personal journey... + +A journey in search of a +beloved and invaluable friend... + +A friend with whom he parted +ways when he finally fulfilled his +heroic destiny and took his place +among legends...