aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2022-10-15 16:53:50 +0200
committerBad Diode <bd@badd10de.dev>2022-10-15 16:53:50 +0200
commitd822337f5920c1b639695ebfcf0eb9e49fd5e01a (patch)
treeb9243dc0f239600ac49bc699890d2f11e5feccae
parent8864a4d8ef6a8597f351f05cfc24b596f24d19e9 (diff)
downloaduxn64-d822337f5920c1b639695ebfcf0eb9e49fd5e01a.tar.gz
uxn64-d822337f5920c1b639695ebfcf0eb9e49fd5e01a.zip
Add minimal code for a working video output program
-rw-r--r--.gitignore1
-rw-r--r--Makefile11
-rw-r--r--src/main.c172
-rw-r--r--src/spec15
-rw-r--r--src/types.h30
5 files changed, 222 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore
index 378eac2..d83b253 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
1build 1build
2a.out
diff --git a/Makefile b/Makefile
index 436fe0a..8917cc9 100644
--- a/Makefile
+++ b/Makefile
@@ -12,12 +12,8 @@ LIBULTRA := $(LIBULTRA_DIR)/usr/lib/libgultra.a
12# Source code location and files to watch for changes. 12# Source code location and files to watch for changes.
13SRC_DIR := src 13SRC_DIR := src
14BUILD_DIR := build 14BUILD_DIR := build
15SRC_MAIN := $(SRC_DIR)/onetri.c \ 15SRC_MAIN := $(SRC_DIR)/main.c
16 $(SRC_DIR)/dram_stack.c \ 16SRC_OBJ :=
17 $(SRC_DIR)/rdp_output.c
18SRC_OBJ := $(SRC_DIR)/static.c \
19 $(SRC_DIR)/cfb.c \
20 $(SRC_DIR)/rsp_cfb.c
21OBJECTS := $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRC_OBJ)) 17OBJECTS := $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRC_OBJ))
22 18
23WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") 19WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h")
@@ -74,10 +70,11 @@ $(BIN): $(ELF) $(OBJECTS) $(WATCH_SRC)
74 --cpp_command="$(SDK_BIN)/mips32-elf-gcc" \ 70 --cpp_command="$(SDK_BIN)/mips32-elf-gcc" \
75 --ld_command="$(SDK_BIN)/mips32-elf-ld" \ 71 --ld_command="$(SDK_BIN)/mips32-elf-ld" \
76 --objcopy_command="$(SDK_BIN)/mips32-elf-objcopy" 72 --objcopy_command="$(SDK_BIN)/mips32-elf-objcopy"
73 rm a.out
77 $(MAKEMASK) $(BIN) 74 $(MAKEMASK) $(BIN)
78 75
79# Test the output .n64 in an emulator. 76# Test the output .n64 in an emulator.
80run: $(BIN) 77run: $(BUILD_DIR) $(BIN)
81 # TODO: Test roms with MAME or cen64 instead of mupen64 for better accuracy. 78 # TODO: Test roms with MAME or cen64 instead of mupen64 for better accuracy.
82 mupen64plus $(BIN) 79 mupen64plus $(BIN)
83 80
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..57a0965
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,172 @@
1#include <ultra64.h>
2
3#include "types.h"
4
5// Screen size.
6#define SCREEN_HEIGHT 240
7#define SCREEN_WIDTH 320
8
9// Get a pointer to the start (top) of a stack.
10#define STACK_START(stack) ((stack) + sizeof((stack)))
11
12//
13// Threads and stacks.
14//
15
16#define STACK_SIZE 8 * 1024
17static OSThread idle_thread;
18static OSThread main_thread;
19static u8 idle_thread_stack[STACK_SIZE] __attribute__((aligned(8)));
20static u8 main_thread_stack[STACK_SIZE] __attribute__((aligned(8)));
21static u64 dram_stack[SP_DRAM_STACK_SIZE64] __attribute__((aligned(16)));
22u64 boot_stack[STACK_SIZE / sizeof(u64)] __attribute__((aligned(8)));
23
24//
25// Framebuffers.
26//
27
28u16 framebuffers[2][SCREEN_WIDTH * SCREEN_HEIGHT];
29u16 rsp_framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
30static int current_fb = 0;
31
32//
33// Message buffers and queues.
34//
35
36#define NUM_PI_MSGS 8
37static OSMesg pi_msg[NUM_PI_MSGS];
38static OSMesg rdp_msg_buf, retrace_msg_buf;
39static OSMesgQueue pi_msg_queue;
40static OSMesgQueue rdp_msg_queue;
41static OSMesgQueue retrace_msg_queue;
42
43// Handle for rom memory.
44OSPiHandle *rom_handle;
45
46static void
47main_proc(void *arg) {
48 (void)arg;
49
50 // Setup the message queues
51 osCreateMesgQueue(&rdp_msg_queue, &rdp_msg_buf, 1);
52 osSetEventMesg(OS_EVENT_DP, &rdp_msg_queue, NULL);
53 osCreateMesgQueue(&retrace_msg_queue, &retrace_msg_buf, 1);
54 osViSetEvent(&retrace_msg_queue, NULL, 1);
55
56 // NOTE: Graphics drawing pipeline:
57 // 1. Transfer gfx data from ROM to RDRAM (CPU -- N64 OS)
58 // 2. Create display list in RDRAM from img data (CPU -- Game application)
59 // 3. Transfer display list and graphics microcode to the RSP (CPU -- N64 OS)
60 // 4. Conversion process (RSP -- GFX microcode)
61 // 5. Transfer converted data to RDP (RSP -- GFX microcode)
62 // 6. Manipulation process (RDP)
63 // 7. Transfer manipulated data to framebuffer (RDP)
64 // 8. Transfer manipulated data to the video interface (CPU -- N64 OS)
65 // 9. Trasfer digital data to DAC (Video Interface)
66 // 10. Video signal is produced.
67
68 // Main loop.
69 size_t i = 0;
70 while (true) {
71 i += 2;
72
73 // Task list.
74 OSTask tlist = (OSTask){
75 {
76 M_GFXTASK, // task type
77 OS_TASK_DP_WAIT, // task flags
78 NULL, // boot ucode pointer (fill in later)
79 0, // boot ucode size (fill in later)
80 NULL, // task ucode pointer (fill in later)
81 SP_UCODE_SIZE, // task ucode size
82 NULL, // task ucode data pointer (fill in later)
83 SP_UCODE_DATA_SIZE, // task ucode data size
84 &dram_stack[0], // task dram stack pointer
85 SP_DRAM_STACK_SIZE8, // task dram stack size
86 NULL, // FIFO buffer start.
87 NULL, // FIFO buffer end.
88 NULL, // task data pointer (fill in later)
89 0, // task data size (fill in later)
90 NULL, // task yield buffer ptr (not used here)
91 0 // task yield buffer size (not used here)
92 },
93 };
94
95 // Graphics command list.
96 Gfx glist[2048];
97
98 OSTask *tlistp = &tlist;
99 Gfx *glistp = glist;
100
101 // Tell RCP where each segment is.
102 gSPSegment(glistp++, 0, 0x0); // Physical address segment
103 gSPSegment(glistp++, 2, OS_K0_TO_PHYSICAL(framebuffers[current_fb]));
104
105 // Clear color framebuffer.
106 Gfx clearcfb_dl[] = {
107 gsDPSetCycleType(G_CYC_FILL),
108 gsDPSetColorImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, rsp_framebuffer),
109 gsDPSetFillColor(GPACK_RGBA5551(64, 64, 255, 1) << 16 | GPACK_RGBA5551(i, i, i, 1)),
110 gsDPFillRectangle(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1),
111 gsSPEndDisplayList(),
112 };
113 gSPDisplayList(glistp++, clearcfb_dl);
114 gDPFullSync(glistp++);
115 gSPEndDisplayList(glistp++);
116
117 // Build graphics task:
118 tlistp->t.ucode_boot = (u64 *) rspbootTextStart;
119 tlistp->t.ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart;
120 tlistp->t.ucode = (u64 *) gspF3DEX2_fifoTextStart;
121 tlistp->t.ucode_data = (u64 *) gspF3DEX2_fifoDataStart;
122 tlistp->t.data_ptr = (u64 *) glist;
123 tlistp->t.data_size = (u32)((glistp - glist) * sizeof(Gfx));
124
125 // Start up the RSP task.
126 osSpTaskStart(tlistp);
127
128 // Wait for RDP completion.
129 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK);
130
131 // Swap buffers.
132 osViSwapBuffer(framebuffers[current_fb]);
133
134 // Make sure there isn't an old retrace in queue
135 // (assumes queue has a depth of 1).
136 if (MQ_IS_FULL(&retrace_msg_queue)) {
137 osRecvMesg(&retrace_msg_queue, NULL, OS_MESG_BLOCK);
138 }
139
140 // Wait for Vertical retrace to finish swap buffers.
141 osRecvMesg(&retrace_msg_queue, NULL, OS_MESG_BLOCK);
142 current_fb ^= 1;
143 }
144}
145
146static void
147idle_proc(void *arg) {
148 (void)arg;
149 // Initialize video.
150 osCreateViManager(OS_PRIORITY_VIMGR);
151 osViSetMode(&osViModeTable[OS_VI_NTSC_LAN1]);
152
153 // Start PI Mgr for access to cartridge.
154 osCreatePiManager((OSPri)OS_PRIORITY_PIMGR, &pi_msg_queue, pi_msg, NUM_PI_MSGS);
155
156 // Create main thread.
157 osCreateThread(&main_thread, 3, main_proc, NULL, STACK_START(main_thread_stack), 10);
158 osStartThread(&main_thread);
159
160 // Become the idle thread.
161 osSetThreadPri(0, 0);
162 for (;;);
163}
164
165
166void
167boot(void) {
168 osInitialize();
169 rom_handle = osCartRomInit();
170 osCreateThread(&idle_thread, 1, idle_proc, NULL, STACK_START(idle_thread_stack), 10);
171 osStartThread(&idle_thread);
172}
diff --git a/src/spec b/src/spec
new file mode 100644
index 0000000..4f7ab6b
--- /dev/null
+++ b/src/spec
@@ -0,0 +1,15 @@
1beginseg
2 name "code"
3 flags BOOT OBJECT
4 entry boot
5 stack boot_stack + STACK_SIZE
6 include "build/blank.elf"
7 include "/opt/n64sdk/libultra/usr/lib/PR/rspboot.o"
8 include "/opt/n64sdk/libultra/usr/lib/PR/gspF3DEX2.xbus.o"
9 include "/opt/n64sdk/libultra/usr/lib/PR/gspF3DEX2.fifo.o"
10endseg
11
12beginwave
13 name "build/onetri"
14 include "code"
15endwave
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..ef9a47a
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,30 @@
1#ifndef _COMMON_H
2#define _COMMON_H
3
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7
8typedef uint8_t u8;
9typedef uint16_t u16;
10typedef uint32_t u32;
11typedef uint64_t u64;
12typedef int8_t s8;
13typedef int16_t s16;
14typedef int32_t s32;
15typedef int64_t s64;
16typedef volatile u8 vu8;
17typedef volatile u16 vu16;
18typedef volatile u32 vu32;
19typedef volatile u64 vu64;
20typedef volatile s8 vs8;
21typedef volatile s16 vs16;
22typedef volatile s32 vs32;
23typedef volatile s64 vs64;
24
25#define KB(N) ((u64)(N) * 1024)
26#define MB(N) ((u64)KB(N) * 1024)
27#define GB(N) ((u64)MB(N) * 1024)
28#define TB(N) ((u64)GB(N) * 1024)
29
30#endif // _COMMON_H