diff --git a/dlist.asm b/dlist.asm new file mode 100644 index 0000000..769046d --- /dev/null +++ b/dlist.asm @@ -0,0 +1,77 @@ +// write some F3DZEX instructions to a0 +// clobbers t0,t1,a0 + +define dpos(0) + +macro WriteDL(evaluate L, evaluate R) { + lui t0, ({L} >> 16) & 0xFFFF + lui t1, ({R} >> 16) & 0xFFFF + ori t0, {L} & 0xFFFF + ori t1, {R} & 0xFFFF + sw t0, {dpos}+0(a0) + sw t1, {dpos}+4(a0) +global evaluate dpos({dpos}+8) +if {dpos} >= 0x8000 { + error "much too much" + // FIXME: just add dpos to a0 and set dpos to 0 when this happens +} +} + + // G_RDPPIPESYNC + WriteDL(0xE7000000, 0) + + // G_TEXTURE (disable tile descriptor; dummy second argument) + WriteDL(0xD7000000, 0xFFFFFFFF) + + // G_SETCOMBINE (too complicated to explain here...) + WriteDL(0xFCFFFFFF, 0xFFFE793C) + + // G_RDPSETOTHERMODE (set higher flags, clear all lower flags) + // 0011 1000 0010 1100 0011 0000 + // G_AD_DISABLE | G_CD_MAGICSQ | G_TC_FILT | G_TF_BILERP | + // G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_MDSFT_TEXTPERSP | + // G_CYC_FILL | G_PM_NPRIMITIVE + WriteDL(0xEF382C30, 0x00000000) + + // G_GEOMETRYMODE + // set some bits (TODO: which?), clear none + WriteDL(0xD9000000, 0x00220405) + + // G_SETSCISSOR coordinate order: (top, left), (right, bottom) + WriteDL(0xED000000 | (0 << 14) | (0 << 2), (320 << 14) | (240 << 2)) + + // G_SETBLENDCOLOR + // sets alpha component to 8, everything else to 0 + WriteDL(0xF9000000, 0x00000008) + + // sets near-far plane clipping? maybe? + // G_MOVEWORD, sets G_MW_CLIP+$0004 + WriteDL(0xDB040004, 2) + // G_MOVEWORD, sets G_MW_CLIP+$000C + WriteDL(0xDB04000C, 2) + // G_MOVEWORD, sets G_MW_CLIP+$0014 + WriteDL(0xDB040014, 0x10000 - 2) + // G_MOVEWORD, sets G_MW_CLIP+$001C + WriteDL(0xDB04001C, 0x10000 - 2) + + // G_SETCIMG, set our color buffer (fmt 0, bit size %10, width) + WriteDL(0xFF100000 | (640 - 1), VIDEO_C_BUFFER) + + // G_SETZIMG, set our z buffer (fmt 0, bit size %00, width) + WriteDL(0xFE000000, VIDEO_Z_BUFFER) + + // G_SETFILLCOLOR + WriteDL(0xF7000000, 0xFFFFFFFF) + + // G_FILLRECT coordinate order: (right, bottom), (top, left) + // note that the coordinates are all inclusive! + WriteDL(0xF6000000 | (199 << 14) | (199 << 2), (100 << 14) | (100 << 2)) + + // G_RDPPIPESYNC + WriteDL(0xE7000000, 0) + + // always finish it off by telling RDP to stop! + // G_RDPFULLSYNC + WriteDL(0xE9000000, 0) + // G_ENDDL + WriteDL(0xDF000000, 0) diff --git a/inc/kernel.inc b/inc/kernel.inc index 30c1896..6bfed11 100644 --- a/inc/kernel.inc +++ b/inc/kernel.inc @@ -40,6 +40,7 @@ if K_DEBUG { macro KMaybeDumpString(str) { if K_DEBUG { + lui k0, K_BASE lw t1, K_CONSOLE_AVAILABLE(k0) beqz t1,+ KDumpString({str}) diff --git a/inc/main.inc b/inc/main.inc index 31398e9..7d09df5 100644 --- a/inc/main.inc +++ b/inc/main.inc @@ -8,9 +8,9 @@ constant ADDR_MASK(0x1FFFFFFF) constant BLAH_BASE(0x803F) constant BLAH_COUNTS(0x0010) constant BLAH_SP_TASK(0x0040) -constant BLAH_DLIST_JUMPER(0x0080) -constant BLAH_XXD(0x0100) +constant BLAH_XXD(0x0080) constant BLAH_DLIST(0x1000) +constant BLAH_DLIST_JUMPER(BLAH_DLIST - 0xA8) constant VIDEO_C_BUFFER(0x80100000) constant VIDEO_C_BUFFER_SIZE(640 * 480 * 4) @@ -24,6 +24,9 @@ constant VIDEO_YIELD(VIDEO_STACK + VIDEO_STACK_SIZE) constant VIDEO_YIELD_SIZE(0xC00) macro nops(new_pc) { + if (pc() > {new_pc}) { + error "PC is already past the point specified" + } while (pc() < {new_pc}) { nop } diff --git a/inc/n64_gfx.inc b/inc/n64_gfx.inc index 8bdee7b..d5d4e2b 100644 --- a/inc/n64_gfx.inc +++ b/inc/n64_gfx.inc @@ -71,13 +71,12 @@ macro ScreenNTSC(width,height, status, origin) { macro ScreenPAL(width,height, status, origin) { lui a0,VI_BASE // A0 = VI Base Register ($A4400000) - li t0,{status} // T0 = Status/Control - sw t0,VI_STATUS(a0) // Store Status/Control To VI Status Register ($A4400000) la t0,{origin} // T0 = Origin (Frame Buffer Origin In Bytes) sw t0,VI_ORIGIN(a0) // Store Origin To VI Origin Register ($A4400004) lli t0,{width} // T0 = Width (Frame Buffer Line Width In Pixels) sw t0,VI_WIDTH(a0) // Store Width To VI Width Register ($A4400008) lli t0,$200 // T0 = Vertical Interrupt (Interrupt When Current Half-Line $200) +//lli t0,2 sw t0,VI_V_INTR(a0) // Store Vertical Interrupt To VI Interrupt Register ($A440000C) lli t0,0 // T0 = Current Vertical Line (Current Half-Line, Sampled Once Per Line = 0) sw t0,VI_V_CURRENT_LINE(a0) // Store Current Vertical Line To VI Current Register ($A4400010) @@ -99,6 +98,8 @@ macro ScreenPAL(width,height, status, origin) { sw t0,VI_X_SCALE(a0) // Store X-Scale To VI X Scale Register ($A4400030) lli t0,($100*({height}/60)) // T0 = Y-Scale (Vertical Subpixel Offset In 2.10 Format = 0, 1/Vertical Scale Up Factor In 2.10 Format) sw t0,VI_Y_SCALE(a0) // Store Y-Scale To VI Y Scale Register ($A4400034) + li t0,{status} // T0 = Status/Control + sw t0,VI_STATUS(a0) // Store Status/Control To VI Status Register ($A4400000) } macro WaitScanline(scanline) { // Wait For RDP To Reach Scanline diff --git a/main.asm b/main.asm index d5941d4..4a10cd1 100644 --- a/main.asm +++ b/main.asm @@ -1,9 +1,12 @@ // built on the N64 ROM template by krom arch n64.cpu endian msb + include "inc/n64.inc" include "inc/n64_gfx.inc" include "inc/64drive.inc" +include "inc/main.inc" +include "inc/kernel.inc" output "test.z64", create fill 1052672 // Set ROM Size @@ -16,18 +19,39 @@ insert "bin/6102.bin" // after inserting the header and bootrom, // origin should be at 0x1000. -include "inc/main.inc" - -include "inc/kernel.inc" include "kernel.asm" - nops(0x80010000) +macro EnableInt() { + lli t0, 0xAAA + lli t1, 0xFF01 + lui a0, MI_BASE + sw t0, MI_INTR_MASK(a0) + mtc0 t1, CP0_Status +} + +macro DisableInt() { + lli t0, 0x555 + lli t1, 0x0001 + lui a0, MI_BASE + sw t0, MI_INTR_MASK(a0) + mtc0 t1, CP0_Status +} + +macro SP_BUSY_WAIT() { + lui a0, SP_BASE +- + lw t0, SP_STATUS(a0) + andi t0, 0x1C + sltu t0, r0, t0 // TODO: rewrite this + bnez t0,- + nop +} Main: lui t0, K_BASE lui s0, BLAH_BASE - mfc0 t1, CP0_Status+0 + mfc0 t1, CP0_Status sw t1, 8(s0) nop; nop; nop; nop @@ -41,133 +65,44 @@ Main: li a2, VIDEO_C_BUFFER jal LzDecomp nop - // TODO: flush cache on color buffer mfc0 t0, CP0_Count nop; nop; nop; nop - lw t1, BLAH_COUNTS+0(s0) - sw t0, BLAH_COUNTS+8(s0) + lw t1, BLAH_COUNTS+0x0(s0) + sw t0, BLAH_COUNTS+0x4(s0) subu t1, t0, t1 sw t1, BLAH_COUNTS+0xC(s0) - // FIXME: this is triggering a PI interrupt somehow, - // which is causing the IH debug output to be repeated instead! + jal PokeDataCache + nop + lui a0, BLAH_BASE lli a1, 0x20 ori a2, a0, BLAH_XXD jal DumpAndWrite lli a3, 0x20 * 4 + KMaybeDumpString(KSNewline) InitVideo: - jal LoadRSPBoot - nop - - lui a0, BLAH_BASE - jal PushVideoTask - ori a0, a0, BLAH_SP_TASK - jal SetupScreen nop - mfc0 t0, CP0_Count - sw t0, BLAH_COUNTS+0xC(s0) - -TestRDP: -if 0 { - // take a peek at the stuff at the Task data we wrote - lui a0, BLAH_BASE - ori a0, a0, BLAH_SP_TASK - lli a1, 0x80 - ori a2, a0, BLAH_XXD - jal DumpAndWrite - lli a3, 0x80 * 4 -} - +Test3D: // write the jump to our actual instructions lui a0, BLAH_BASE lui t0, 0xDE01 // jump (no push) - sw t0, BLAH_DLIST_JUMPER+0(a0) ori t1, a0, BLAH_DLIST + sw t0, BLAH_DLIST_JUMPER+0(a0) sw t1, BLAH_DLIST_JUMPER+4(a0) -define dpos(BLAH_DLIST) -macro WriteDL(evaluate L, evaluate R) { - lui t0, ({L} >> 16) & 0xFFFF - lui t1, ({R} >> 16) & 0xFFFF - ori t0, {L} & 0xFFFF - ori t1, {R} & 0xFFFF - sw t0, {dpos}+0(a0) - sw t1, {dpos}+4(a0) -global evaluate dpos({dpos}+8) -if {dpos} >= 0x8000 { - error "much too much" - // FIXME: just add dpos to a0 and set dpos to 0 when this happens -} -} + lui a0, BLAH_BASE + ori a0, BLAH_DLIST - // write some F3DZEX instructions +include "dlist.asm" // takes a0 -{ - // G_RDPPIPESYNC - WriteDL(0xE7000000, 0) - - // G_TEXTURE (disable tile descriptor; dummy second argument) - WriteDL(0xD7000000, 0xFFFFFFFF) - - // G_SETCOMBINE (too complicated to explain here...) - WriteDL(0xFCFFFFFF, 0xFFFE793C) - - // G_RDPSETOTHERMODE (set higher flags, clear all lower flags) - // 0011 1000 0010 1100 0011 0000 - // G_AD_DISABLE | G_CD_MAGICSQ | G_TC_FILT | G_TF_BILERP | - // G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_MDSFT_TEXTPERSP | - // G_CYC_FILL | G_PM_NPRIMITIVE - WriteDL(0xEF382C30, 0x00000000) - - // G_GEOMETRYMODE - // set some bits (TODO: which?), clear none - WriteDL(0xD9000000, 0x00220405) - - // G_SETSCISSOR coordinate order: (top, left), (right, bottom) - WriteDL(0xED000000 | (0 << 14) | (0 << 2), (320 << 14) | (240 << 2)) - - // G_SETBLENDCOLOR - // sets alpha component to 8, everything else to 0 - WriteDL(0xF9000000, 0x00000008) - - // sets near-far plane clipping? maybe? - // G_MOVEWORD, sets G_MW_CLIP+$0004 - WriteDL(0xDB040004, 2) - // G_MOVEWORD, sets G_MW_CLIP+$000C - WriteDL(0xDB04000C, 2) - // G_MOVEWORD, sets G_MW_CLIP+$0014 - WriteDL(0xDB040014, 0x10000 - 2) - // G_MOVEWORD, sets G_MW_CLIP+$001C - WriteDL(0xDB04001C, 0x10000 - 2) - - // G_ENDDL: absent since we're not jumping to this routine -} - - // G_SETCIMG, set our color buffer (fmt 0, bit size %10, width) - WriteDL(0xFF100000 | (640 - 1), VIDEO_C_BUFFER) - - // G_SETZIMG, set our z buffer (fmt 0, bit size %00, width) - WriteDL(0xFE000000, VIDEO_Z_BUFFER) - - // G_SETFILLCOLOR - WriteDL(0xF7000000, 0xFFFFFFFF) - - // G_FILLRECT coordinate order: (right, bottom), (top, left) - // note that the coordinates are all inclusive! - WriteDL(0xF6000000 | (199 << 14) | (199 << 2), (100 << 14) | (100 << 2)) - - // G_RDPPIPESYNC - WriteDL(0xE7000000, 0) - - // always finish it off by telling RDP to stop! - // G_RDPFULLSYNC, G_ENDDL - WriteDL(0xE9000000, 0); WriteDL(0xDF000000, 0) + jal PokeCaches + nop // take a peek at the display list we wrote lui a0, BLAH_BASE @@ -177,25 +112,55 @@ if {dpos} >= 0x8000 { jal DumpAndWrite lli a3, 0x80 * 4 +Start3D: + DisableInt() + // stuff i'm borrowing from zelda: lui a0, SP_BASE lli t0, CLR_SG2 | CLR_SG1 | CLR_SG0 | SET_IOB sw t0, SP_STATUS(a0) - // NOTE: we should be asserting here that SP_STATUS & 1 != 0 + // wait + lui a0, SP_BASE +- + lw t0, SP_STATUS(a0) + andi t0, 1 + beqz t0,- + nop + // set RSP PC to IMEM+$0 lui a0, SP_PC_BASE + //sw r0, SP_PC(a0) li t0, 0x04001000 sw t0, SP_PC(a0) - // tell RSP to run by clearing flags + lui a0, BLAH_BASE + jal PushVideoTask + ori a0, a0, BLAH_SP_TASK + + // take a peek at the Task data we wrote + lui a0, BLAH_BASE + ori a0, a0, BLAH_SP_TASK + lli a1, 0x40 + ori a2, a0, BLAH_XXD + jal DumpAndWrite + lli a3, 0x40 * 4 + KMaybeDumpString(KSNewline) + + SP_BUSY_WAIT() + + jal LoadRSPBoot + nop + + SP_BUSY_WAIT() + + // clear all flags that would halt RSP (i.e. tell it to run!) lui a0, SP_BASE lli t0, SET_IOB | CLR_STP | CLR_BRK | CLR_HLT sw t0, SP_STATUS(a0) nop - // also one thing i noticed in zelda is they set VI_V_INTR to 2 - // so they get interrupts with scanlines (unlike us who just waits) + EnableInt() MainLoop: // borrowing code from krom for now: @@ -217,24 +182,10 @@ MainLoop: nop // delay slot SetupScreen: - // NTSC: 640x480, 32BPP, Interlace, Resample Only, DRAM Origin VIDEO_C_BUFFER ScreenNTSC(640, 480, BPP32|INTERLACE|AA_MODE_2, VIDEO_C_BUFFER | UNCACHED) jr ra nop -LoadRSPBoot: - li t2, F3DZEX_BOOT - li t3, F3DZEX_BOOT.size - subiu t3, t3, 1 // DMA quirk - SP_DMA_WAIT() // clobbers t0, t5 -// ori t1, t5, 0x1000 - la t1, 0xA4001000 - sw t1, SP_MEM_ADDR(t5) - sw t2, SP_DRAM_ADDR(t5) - sw t3, SP_RD_LEN(t5) // pull data from RDRAM into DMEM/IMEM - jr ra - nop - PushVideoTask: // a0: Task RDRAM Pointer (size: 0x40) (should probably be row-aligned) subiu sp, sp, 0x18 @@ -245,9 +196,9 @@ PushVideoTask: li t2, F3DZEX_BOOT // does not need masking for some reason li t3, F3DZEX_BOOT.size li t4, F3DZEX_IMEM & ADDR_MASK - li t5, F3DZEX_IMEM.size // note: Zelda uses 0x1000 for some reason (0x80 too big). + li t5, F3DZEX_IMEM.size li t6, F3DZEX_DMEM & ADDR_MASK - li t7, F3DZEX_DMEM.size // note: Zelda uses 0x800 for some reason (way too big). + li t7, F3DZEX_DMEM.size sw t0, 0x00(a0) sw t1, 0x04(a0) sw t2, 0x08(a0) @@ -261,7 +212,7 @@ PushVideoTask: li t2, VIDEO_SOMETHING & ADDR_MASK li t3, (VIDEO_SOMETHING & ADDR_MASK) + VIDEO_SOMETHING_SIZE // end pointer (not size!) li t4, ((BLAH_BASE << 16) | BLAH_DLIST_JUMPER) & ADDR_MASK // initial DList - lli t5, 8 // size of one jump command + 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 sw t0, 0x20(a0) @@ -290,7 +241,6 @@ PushVideoTask: PushRSPTask: lli t3, 0x40 - 1 // DMA quirk SP_DMA_WAIT() // clobbers t0, t5 -// ori t1, t5, 0xFC0 la t1, 0xA4000FC0 sw t1, SP_MEM_ADDR(t5) sw a0, SP_DRAM_ADDR(t5) @@ -298,6 +248,18 @@ PushRSPTask: jr ra nop +LoadRSPBoot: + la t2, F3DZEX_BOOT & ADDR_MASK + li t3, F3DZEX_BOOT.size + subiu t3, t3, 1 // DMA quirk + SP_DMA_WAIT() // clobbers t0, t5 + la t1, 0xA4001000 + sw t1, SP_MEM_ADDR(t5) + sw t2, SP_DRAM_ADDR(t5) + sw t3, SP_RD_LEN(t5) // pull data from RDRAM into DMEM/IMEM + jr ra + nop + include "lzss.baku.unsafe.asm" align(16); insert F3DZEX_BOOT, "bin/F3DZEX2.boot.bin"