aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2022-10-16 15:44:12 +0200
committerBad Diode <bd@badd10de.dev>2022-10-16 15:44:12 +0200
commit9322f2c413b4ea22c386d3725ffa79bc54d5596c (patch)
treebb8f57bbe638a65a9de4ab4bd041c4bc5a6bffab /src
parent40fe8dfc9f9e6e1d69d442fa9e6b15e555d27650 (diff)
downloaduxn64-9322f2c413b4ea22c386d3725ffa79bc54d5596c.tar.gz
uxn64-9322f2c413b4ea22c386d3725ffa79bc54d5596c.zip
Add uxn core and initial implementation of interpreter
Diffstat (limited to 'src')
-rw-r--r--src/main.c464
-rw-r--r--src/ppu.c349
m---------src/uxn0
-rw-r--r--src/uxn_screen_rom.c41
4 files changed, 586 insertions, 268 deletions
diff --git a/src/main.c b/src/main.c
index 4415e27..69e4ac7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,10 +2,6 @@
2 2
3#include "types.h" 3#include "types.h"
4 4
5// Screen size.
6#define SCREEN_WIDTH 320
7#define SCREEN_HEIGHT 240
8
9// Get a pointer to the start (top) of a stack. 5// Get a pointer to the start (top) of a stack.
10#define STACK_START(stack) ((stack) + sizeof((stack))) 6#define STACK_START(stack) ((stack) + sizeof((stack)))
11 7
@@ -16,308 +12,240 @@
16#define STACK_SIZE 8 * 1024 12#define STACK_SIZE 8 * 1024
17static OSThread idle_thread; 13static OSThread idle_thread;
18static OSThread main_thread; 14static OSThread main_thread;
19static u8 idle_thread_stack[STACK_SIZE] __attribute__((aligned(8))); 15static u8 idle_thread_stack[STACK_SIZE] __attribute__((aligned(8)));
20static u8 main_thread_stack[STACK_SIZE] __attribute__((aligned(8))); 16static u8 main_thread_stack[STACK_SIZE] __attribute__((aligned(8)));
21static u64 dram_stack[SP_DRAM_STACK_SIZE64] __attribute__((aligned(16))); 17u64 boot_stack[STACK_SIZE / sizeof(u64)] __attribute__((aligned(8)));
22u64 boot_stack[STACK_SIZE / sizeof(u64)] __attribute__((aligned(8)));
23 18
24// 19//
25// Framebuffers. 20// Message buffers and queues.
26// 21//
27 22
28u16 framebuffers[2][SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(16))); 23#define NUM_PI_MSGS 8
24static OSMesg pi_msg[NUM_PI_MSGS];
25
26// Handle for rom memory.
27OSPiHandle *rom_handle;
29 28
30// 29//
31// Statics. 30// UXN.
32// 31//
33 32
34static int current_fb = 0; 33#include "ppu.c"
35static u16 pixels[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(16))); 34#include "uxn/src/uxn.c"
36static Gfx glist[2048 * 8];
37 35
38// 36#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X))
39// Message buffers and queues.
40//
41 37
42#define NUM_PI_MSGS 8 38static Uxn u;
43static OSMesg pi_msg[NUM_PI_MSGS]; 39static Device *devscreen;
44static OSMesg rdp_msg_buf, retrace_msg_buf; 40static Device *devctrl;
45static OSMesgQueue pi_msg_queue; 41static Device *devmouse;
46static OSMesgQueue rdp_msg_queue;
47static OSMesgQueue retrace_msg_queue;
48 42
49// Handle for rom memory. 43int
50OSPiHandle *rom_handle; 44uxn_halt(Uxn *u, Uint8 error, Uint16 addr) {
45 (void)u;
46 (void)error;
47 (void)addr;
48 for (;;) {}
49}
51 50
52// DEBUG: animations 51int
53static int t = 0; 52uxn_interrupt(void) {
53 return 1;
54}
54 55
55void 56static u8
56fb_write_test(void) { 57nil_dei(Device *d, u8 port) {
57 for (size_t j = 0; j < SCREEN_HEIGHT; j++) { 58 return d->dat[port];
58 for (size_t i = 0; i < SCREEN_WIDTH; i++) { 59}
59 // u16 shade_x = (float)i / (float)SCREEN_WIDTH * 32; 60
60 // u16 shade_y = (float)j / (float)SCREEN_HEIGHT * 32; 61static void
61 // u16 color = shade_x << 11 | shade_y << 1; 62nil_deo(Device *d, u8 port) {
62 u16 shade_x = (float)i / (float)SCREEN_WIDTH * 255; 63 (void)d;
63 u16 shade_y = (float)j / (float)SCREEN_HEIGHT * 255; 64 (void)port;
64 u16 color = GPACK_RGBA5551(shade_x, t, shade_y, 1); 65}
65 // u16 color = t; 66
66 framebuffers[current_fb][i + j * SCREEN_WIDTH] = color; 67static void
67 } 68screen_palette(Device *d) {
69 for(size_t i = 0; i < 4; ++i) {
70 u8 r = ((d->dat[0x8 + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11;
71 u8 g = ((d->dat[0xa + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11;
72 u8 b = ((d->dat[0xc + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11;
73
74 palette[i] = GPACK_RGBA5551(r, g, b, 1);
75 }
76 for(size_t i = 4; i < 16; ++i) {
77 palette[i] = palette[i / 4];
68 } 78 }
79
80 // Redraw the screen if we change the color palette.
81 reqdraw = 1;
82 redraw_screen();
83}
84
85u8
86system_dei(Device *d, u8 port) {
87 switch(port) {
88 case 0x2: return d->u->wst.ptr;
89 case 0x3: return d->u->rst.ptr;
90 default: return d->dat[port];
91 }
69} 92}
70 93
71void 94void
72fb_copy_test(void) { 95system_deo(Device *d, u8 port) {
73 for (size_t i = 0; i < SCREEN_HEIGHT * SCREEN_WIDTH; i++) { 96 switch(port) {
74 framebuffers[current_fb][i] = pixels[i]; 97 case 0x2: d->u->wst.ptr = d->dat[port]; break;
98 case 0x3: d->u->rst.ptr = d->dat[port]; break;
99 case 0xe: break;
100 default: {
101 if(port > 0x7 && port < 0xe) {
102 screen_palette(d);
103 }
104 } break;
105 }
106}
107
108static void
109console_deo(Device *d, u8 port) {
110 (void)d;
111 (void)port;
112}
113
114u8
115screen_dei(Device *d, u8 port) {
116 switch(port) {
117 case 0x2: return screen_width >> 8;
118 case 0x3: return screen_width;
119 case 0x4: return screen_height >> 8;
120 case 0x5: return screen_height;
121 default: return d->dat[port];
75 } 122 }
76} 123}
77 124
78void 125void
79rdp_init(void) { 126screen_deo(Device *d, u8 port) {
80 Gfx *glistp = glist; 127 switch(port) {
81 128 // case 0x3:
82 static const Vp viewport = {{ 129 // if(!FIXED_SIZE) {
83 .vscale = {SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2, G_MAXZ / 2, 0}, 130 // Uint16 w;
84 .vtrans = {SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2, G_MAXZ / 2, 0}, 131 // DEVPEEK16(w, 0x2);
85 }}; 132 // screen_resize(&uxn_screen, clamp(w, 1, 1024), uxn_screen.height);
86 133 // }
87 // Initialize the RSP. 134 // break;
88 Gfx rspinit_dl[] = { 135 // case 0x5:
89 gsSPViewport(&viewport), 136 // if(!FIXED_SIZE) {
90 gsSPClearGeometryMode(G_SHADE | G_SHADING_SMOOTH | G_CULL_BOTH | 137 // Uint16 h;
91 G_FOG | G_LIGHTING | G_TEXTURE_GEN | 138 // DEVPEEK16(h, 0x4);
92 G_TEXTURE_GEN_LINEAR | G_LOD), 139 // screen_resize(&uxn_screen, uxn_screen.width, clamp(h, 1, 1024));
93 gsSPTexture(0, 0, 0, 0, G_OFF), 140 // }
94 }; 141 // break;
95 142 case 0xe: {
96 // Initialize the RDP. 143 u16 x, y;
97 Gfx rdpinit_dl[] = { 144 u8 layer = d->dat[0xe] & 0x40;
98 gsDPSetCycleType(G_CYC_1CYCLE), 145 DEVPEEK16(x, 0x8);
99 gsDPSetScissor(G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 146 DEVPEEK16(y, 0xa);
100 gsDPSetCombineKey(G_CK_NONE), 147 ppu_pixel(layer ? pixels_fg : pixels_bg, x, y, d->dat[0xe] & 0x3);
101 gsDPSetAlphaCompare(G_AC_NONE), 148 if(d->dat[0x6] & 0x01) DEVPOKE16(0x8, x + 1); /* auto x+1 */
102 gsDPSetRenderMode(G_RM_NOOP, G_RM_NOOP2), 149 if(d->dat[0x6] & 0x02) DEVPOKE16(0xa, y + 1); /* auto y+1 */
103 gsDPSetColorDither(G_CD_DISABLE), 150 } break;
104 gsDPPipeSync(), 151 case 0xf: {
105 }; 152 u16 x, y, dx, dy, addr;
106 153 u8 twobpp = !!(d->dat[0xf] & 0x80);
107 gSPDisplayList(glistp++, rspinit_dl); 154 DEVPEEK16(x, 0x8);
108 gSPDisplayList(glistp++, rdpinit_dl); 155 DEVPEEK16(y, 0xa);
109 gDPFullSync(glistp++); 156 DEVPEEK16(addr, 0xc);
110 gSPEndDisplayList(glistp++); 157 u8 n = d->dat[0x6] >> 4;
111 158 dx = (d->dat[0x6] & 0x01) << 3;
112 // Start up the task list. 159 dy = (d->dat[0x6] & 0x02) << 2;
113 OSTask tlist = (OSTask){ 160 if(addr > 0x10000 - ((n + 1) << (3 + twobpp))) {
114 { 161 return;
115 .type = M_GFXTASK, 162 }
116 .flags = OS_TASK_DP_WAIT, 163 u8 *layer = (d->dat[0xf] & 0x40) ? pixels_fg : pixels_bg;
117 .ucode_boot = (u64*)rspbootTextStart, 164 u8 color = d->dat[0xf] & 0xf;
118 .ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart, 165 u8 flipx = d->dat[0xf] & 0x10;
119 .ucode = (u64*)gspF3DEX2_xbusTextStart, 166 u8 flipy = d->dat[0xf] & 0x20;
120 .ucode_size = SP_UCODE_SIZE, 167 for(size_t i = 0; i <= n; i++) {
121 .ucode_data = (u64*)gspF3DEX2_xbusDataStart, 168 u8 *sprite = &d->u->ram[addr];
122 .ucode_data_size = SP_UCODE_DATA_SIZE, 169 if (twobpp) {
123 .data_ptr = (u64*)glist, 170 ppu_2bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy);
124 .data_size = (u32)((glistp - glist) * sizeof(Gfx)), 171 } else {
125 .dram_stack = dram_stack, 172 ppu_1bpp(layer, x + dy * i, y + dx * i, sprite, color, flipx, flipy);
126 .dram_stack_size = SP_DRAM_STACK_SIZE8, 173 }
127 }, 174 addr += (d->dat[0x6] & 0x04) << (1 + twobpp);
128 }; 175 }
129 osSpTaskStart(&tlist); 176 DEVPOKE16(0xc, addr); /* auto addr+length */
130 177 DEVPOKE16(0x8, x + dx); /* auto x+8 */
131 // Wait for RDP completion. 178 DEVPOKE16(0xa, y + dy); /* auto y+8 */
132 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK); 179 } break;
180 }
181 reqdraw = 1;
133} 182}
134 183
135void 184void
136rdp_clearfb(u8 r, u8 g, u8 b) { 185poll_input() {
137 Gfx *glistp = glist; 186 // STUB...
138 Gfx clearcfb_dl[] = {
139 gsDPSetCycleType(G_CYC_FILL),
140 gsDPSetColorImage(
141 G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, framebuffers[current_fb]),
142 gsDPSetFillColor(
143 GPACK_RGBA5551(r, g, b, 1) << 16 | GPACK_RGBA5551(r, g, b, 1)),
144 gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
145 gsDPPipeSync(),
146 };
147 gSPDisplayList(glistp++, clearcfb_dl);
148 gDPFullSync(glistp++);
149 gSPEndDisplayList(glistp++);
150
151 // Start up the task list.
152 OSTask tlist = (OSTask){
153 {
154 .type = M_GFXTASK,
155 .flags = OS_TASK_DP_WAIT,
156 .ucode_boot = (u64*)rspbootTextStart,
157 .ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart,
158 .ucode = (u64*)gspF3DEX2_xbusTextStart,
159 .ucode_size = SP_UCODE_SIZE,
160 .ucode_data = (u64*)gspF3DEX2_xbusDataStart,
161 .ucode_data_size = SP_UCODE_DATA_SIZE,
162 .data_ptr = (u64*)glist,
163 .data_size = (u32)((glistp - glist) * sizeof(Gfx)),
164 .dram_stack = dram_stack,
165 .dram_stack_size = SP_DRAM_STACK_SIZE8,
166 },
167 };
168 osSpTaskStart(&tlist);
169
170 // Wait for RDP completion.
171 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK);
172} 187}
173 188
174void 189void
175rdp_texture_copy(void) { 190handle_input() {
176 Gfx *glistp = glist; 191 // STUB...
177 Gfx dl[] = { 192}
178 gsDPSetTexturePersp(G_TP_NONE), 193
179 gsDPSetCycleType(G_CYC_COPY), 194static u8 uxn_ram[0x10000];
180 gsDPSetRenderMode(G_RM_NOOP, G_RM_NOOP2), 195
181 gsSPClearGeometryMode(G_SHADE | G_SHADING_SMOOTH), 196#include "uxn_screen_rom.c"
182 gsSPTexture(0x2000, 0x2000, 0, G_TX_RENDERTILE, G_ON), 197
183 gsDPSetCombineMode(G_CC_DECALRGB, G_CC_DECALRGB), 198void
184 gsDPSetTexturePersp(G_TP_NONE), 199init_uxn(Uxn *u) {
185 gsDPSetTextureFilter(G_TF_POINT), 200 // Setup UXN memory.
186 }; 201 for (size_t i = 0; i < sizeof(uxn_ram); i++) {
187 gSPDisplayList(glistp++, dl); 202 uxn_ram[i] = 0;
188 for (size_t i = 0; i < 240; i++) { 203 }
189 gDPLoadTextureBlock( 204 uxn_boot(u, uxn_ram);
190 glistp++, 205
191 &pixels[320 * 1 * i], // Texture data. 206 // Copy rom to VM.
192 G_IM_FMT_RGBA, // Image format. 207 // memcpy(u->ram + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom));
193 G_IM_SIZ_16b, // Pixel component size. 208 u8 *dst = u->ram + PAGE_PROGRAM;
194 320, // Width. 209 u8 *src = (u8*)uxn_rom;
195 1, // Height. 210 for (size_t i = 0; i < sizeof(uxn_rom); i++) {
196 0, // Palette location. 211 dst[i] = src[i];
197 G_TX_CLAMP, // S-axis mirror/wrap/clamp.
198 G_TX_CLAMP, // T-axis mirror/wrap/clamp.
199 0, // S-axis mask.
200 0, // T-axis mask.
201 G_TX_NOLOD, // S-axis shift.
202 G_TX_NOLOD); // T-axis shift.
203 gSPTextureRectangle(
204 glistp++,
205 0, // ulx
206 (1 * i) << 2, // uly
207 (320 * (i + 1)) << 2, // lrx
208 (1 * (i + 1)) << 2, // lry
209 0,
210 0,
211 0,
212 4 << 10,
213 1 << 10);
214 } 212 }
215 gDPFullSync(glistp++); 213
216 gSPEndDisplayList(glistp++); 214 // Prepare devices.
217 215 /* system */ uxn_port(u, 0x0, system_dei, system_deo);
218 // Start up the task list. 216 /* console */ uxn_port(u, 0x1, nil_dei, console_deo);
219 OSTask tlist = (OSTask){ 217 /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo);
220 { 218 /* audio0 */ uxn_port(u, 0x3, nil_dei, nil_deo);
221 .type = M_GFXTASK, 219 /* audio1 */ uxn_port(u, 0x4, nil_dei, nil_deo);
222 .flags = OS_TASK_DP_WAIT, 220 /* audio2 */ uxn_port(u, 0x5, nil_dei, nil_deo);
223 .ucode_boot = (u64*)rspbootTextStart, 221 /* audio3 */ uxn_port(u, 0x6, nil_dei, nil_deo);
224 .ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart, 222 /* unused */ uxn_port(u, 0x7, nil_dei, nil_deo);
225 .ucode = (u64*)gspF3DEX2_xbusTextStart, 223 /* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo);
226 .ucode_size = SP_UCODE_SIZE, 224 /* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo);
227 .ucode_data = (u64*)gspF3DEX2_xbusDataStart, 225 /* file0 */ uxn_port(u, 0xa, nil_dei, nil_deo);
228 .ucode_data_size = SP_UCODE_DATA_SIZE, 226 /* file1 */ uxn_port(u, 0xb, nil_dei, nil_deo);
229 .data_ptr = (u64*)glist, 227 /* datetime */ uxn_port(u, 0xc, nil_dei, nil_deo);
230 .data_size = (u32)((glistp - glist) * sizeof(Gfx)), 228 /* unused */ uxn_port(u, 0xd, nil_dei, nil_deo);
231 .dram_stack = dram_stack, 229 /* unused */ uxn_port(u, 0xe, nil_dei, nil_deo);
232 .dram_stack_size = SP_DRAM_STACK_SIZE8, 230 /* unused */ uxn_port(u, 0xf, nil_dei, nil_deo);
233 }, 231 uxn_eval(u, PAGE_PROGRAM);
234 };
235 osSpTaskStart(&tlist);
236
237 // Wait for RDP completion.
238 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK);
239} 232}
240 233
241static void 234static void
242main_proc(void *arg) { 235main_proc(void *arg) {
243 (void)arg; 236 (void)arg;
244 237
245 // Setup the message queues 238 init_ppu();
246 osCreateMesgQueue(&rdp_msg_queue, &rdp_msg_buf, 1);
247 osSetEventMesg(OS_EVENT_DP, &rdp_msg_queue, NULL);
248 osCreateMesgQueue(&retrace_msg_queue, &retrace_msg_buf, 1);
249 osViSetEvent(&retrace_msg_queue, NULL, 1);
250
251 // NOTE: Graphics drawing pipeline:
252 // 1. Transfer gfx data from ROM to RDRAM (CPU -- N64 OS)
253 // 2. Create display list in RDRAM from img data (CPU -- Game application)
254 // 3. Transfer display list and graphics microcode to the RSP (CPU -- N64 OS)
255 // 4. Conversion process (RSP -- GFX microcode)
256 // 5. Transfer converted data to RDP (RSP -- GFX microcode)
257 // 6. Manipulation process (RDP)
258 // 7. Transfer manipulated data to framebuffer (RDP)
259 // 8. Transfer manipulated data to the video interface (CPU -- N64 OS)
260 // 9. Trasfer digital data to DAC (Video Interface)
261 // 10. Video signal is produced.
262
263 // NOTE: Test image.
264 for (size_t j = 0; j < SCREEN_HEIGHT; j++) {
265 for (size_t i = 0; i < SCREEN_WIDTH; i++) {
266 u16 shade_x = (float)i / (float)SCREEN_WIDTH * 255;
267 u16 shade_y = (float)j / (float)SCREEN_HEIGHT * 255;
268 u16 color = GPACK_RGBA5551(shade_x, 0, shade_y, 1);
269 pixels[i + j * SCREEN_WIDTH] = color;
270 }
271 }
272 239
273 // Clear the framebuffer with rdp. 240 init_uxn(&u);
274 rdp_init();
275 241
276 // Main loop. 242 // Main loop.
277 int increment = 4;
278 int direction = increment;
279 while (true) { 243 while (true) {
280 if (t >= 255 - increment) { 244 poll_input();
281 direction = -increment; 245 handle_input();
282 } if (t <= 0 + increment) { 246 uxn_eval(&u, GETVECTOR(devscreen));
283 direction = +increment; 247 blit_framebuffer();
284 } 248 swap_buffers();
285 t += direction;
286
287 // A
288 // rdp_clearfb(t, t, t);
289 // osWritebackDCacheAll();
290 // B
291 // fb_write_test();
292 // osWritebackDCacheAll();
293 // C
294 for (size_t j = 0; j < SCREEN_HEIGHT; j++) {
295 for (size_t i = 0; i < SCREEN_WIDTH; i++) {
296 u16 shade_x = (float)i / (float)SCREEN_WIDTH * 255;
297 u16 shade_y = (float)j / (float)SCREEN_HEIGHT * 255;
298 u16 color = GPACK_RGBA5551(shade_x, t, shade_y, 1);
299 pixels[i + j * SCREEN_WIDTH] = color;
300 }
301 }
302 // osWritebackDCacheAll();
303 // fb_copy_test();
304 // D
305 rdp_texture_copy();
306 // osWritebackDCacheAll();
307 // osWritebackDCacheAll();
308
309 // Swap buffers.
310 osViSwapBuffer(framebuffers[current_fb]);
311
312 // Make sure there isn't an old retrace in queue
313 // (assumes queue has a depth of 1).
314 if (MQ_IS_FULL(&retrace_msg_queue)) {
315 osRecvMesg(&retrace_msg_queue, NULL, OS_MESG_BLOCK);
316 }
317
318 // Wait for Vertical retrace to finish swap buffers.
319 osRecvMesg(&retrace_msg_queue, NULL, OS_MESG_BLOCK);
320 current_fb ^= 1;
321 } 249 }
322} 250}
323 251
diff --git a/src/ppu.c b/src/ppu.c
new file mode 100644
index 0000000..e614f9b
--- /dev/null
+++ b/src/ppu.c
@@ -0,0 +1,349 @@
1// Screen size.
2#define SCREEN_WIDTH 320
3#define SCREEN_HEIGHT 240
4
5static OSMesg rdp_msg_buf, retrace_msg_buf;
6static OSMesgQueue pi_msg_queue;
7static OSMesgQueue rdp_msg_queue;
8static OSMesgQueue retrace_msg_queue;
9
10//
11// Framebuffers.
12//
13
14u16 framebuffers[2][SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(16)));
15
16//
17// Statics.
18//
19
20static u64 dram_stack[SP_DRAM_STACK_SIZE64] __attribute__((aligned(16)));
21static u16 pixels[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(16)));
22static int current_fb = 0;
23static Gfx glist[2048 * 8];
24
25static size_t screen_width = SCREEN_WIDTH;
26static size_t screen_height = SCREEN_HEIGHT;
27static u16 palette[16];
28
29static u8 pixels_fg[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(16)));
30static u8 pixels_bg[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(16)));
31static u8 dirty_lines[SCREEN_HEIGHT];
32static u8 reqdraw = 0;
33
34static u8 blending[5][16] = {
35 {0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0},
36 {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
37 {1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1},
38 {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
39 {1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}};
40
41u16
42rgb565(u32 rgba) {
43 u16 r = (rgba >> 16 & 0xFF);
44 u16 g = (rgba >> 8 & 0xFF);
45 u16 b = (rgba >> 0 & 0xFF);
46 r = r >> 3;
47 g = g >> 2;
48 b = b >> 3;
49 return (r << 11) | (g << 5) | b;
50}
51
52void
53redraw_screen(void) {
54 for (size_t j = 0; j < screen_height; j++) {
55 dirty_lines[j] = 1;
56 }
57}
58
59void
60ppu_pixel(u8 *layer, u16 x, u16 y, u8 color) {
61 if (x >= screen_width || y >= screen_height) {
62 return;
63 }
64 u32 i = x + y *screen_width;
65 if(color != layer[i]) {
66 layer[i] = color;
67 }
68 dirty_lines[y] |= 1;
69}
70
71void
72ppu_1bpp(u8 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) {
73 u16 v, h;
74 for(v = 0; v < 8; v++)
75 for(h = 0; h < 8; h++) {
76 u8 ch1 = (sprite[v] >> (7 - h)) & 0x1;
77 if(ch1 || blending[4][color])
78 ppu_pixel(layer,
79 x + (flipx ? 7 - h : h),
80 y + (flipy ? 7 - v : v),
81 blending[ch1][color]);
82 }
83}
84
85void
86ppu_2bpp(u8 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) {
87 u16 v, h;
88 for(v = 0; v < 8; v++)
89 for(h = 0; h < 8; h++) {
90 u8 ch1 = ((sprite[v] >> (7 - h)) & 0x1);
91 u8 ch2 = ((sprite[v + 8] >> (7 - h)) & 0x1);
92 u8 ch = ch1 + ch2 * 2;
93 if(ch || blending[4][color])
94 ppu_pixel(layer,
95 x + (flipx ? 7 - h : h),
96 y + (flipy ? 7 - v : v),
97 blending[ch][color]);
98 }
99}
100
101void
102fb_write_test(void) {
103 for (size_t j = 0; j < SCREEN_HEIGHT; j++) {
104 for (size_t i = 0; i < SCREEN_WIDTH; i++) {
105 u16 shade_x = (float)i / (float)SCREEN_WIDTH * 255;
106 u16 shade_y = (float)j / (float)SCREEN_HEIGHT * 255;
107 u16 color = GPACK_RGBA5551(shade_x, 0, shade_y, 1);
108 framebuffers[current_fb][i + j * SCREEN_WIDTH] = color;
109 }
110 }
111}
112
113void
114fb_copy_test(void) {
115 for (size_t i = 0; i < SCREEN_HEIGHT * SCREEN_WIDTH; i++) {
116 framebuffers[current_fb][i] = pixels[i];
117 }
118}
119
120void
121rdp_init(void) {
122 Gfx *glistp = glist;
123
124 static const Vp viewport = {{
125 .vscale = {SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2, G_MAXZ / 2, 0},
126 .vtrans = {SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2, G_MAXZ / 2, 0},
127 }};
128
129 // Initialize the RSP.
130 Gfx rspinit_dl[] = {
131 gsSPViewport(&viewport),
132 gsSPClearGeometryMode(G_SHADE | G_SHADING_SMOOTH | G_CULL_BOTH |
133 G_FOG | G_LIGHTING | G_TEXTURE_GEN |
134 G_TEXTURE_GEN_LINEAR | G_LOD),
135 gsSPTexture(0, 0, 0, 0, G_OFF),
136 };
137
138 // Initialize the RDP.
139 Gfx rdpinit_dl[] = {
140 gsDPSetCycleType(G_CYC_1CYCLE),
141 gsDPSetScissor(G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
142 gsDPSetCombineKey(G_CK_NONE),
143 gsDPSetAlphaCompare(G_AC_NONE),
144 gsDPSetRenderMode(G_RM_NOOP, G_RM_NOOP2),
145 gsDPSetColorDither(G_CD_DISABLE),
146 gsDPPipeSync(),
147 };
148
149 gSPDisplayList(glistp++, rspinit_dl);
150 gSPDisplayList(glistp++, rdpinit_dl);
151 gDPFullSync(glistp++);
152 gSPEndDisplayList(glistp++);
153
154 // Start up the task list.
155 OSTask tlist = (OSTask){
156 {
157 .type = M_GFXTASK,
158 .flags = OS_TASK_DP_WAIT,
159 .ucode_boot = (u64*)rspbootTextStart,
160 .ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart,
161 .ucode = (u64*)gspF3DEX2_xbusTextStart,
162 .ucode_size = SP_UCODE_SIZE,
163 .ucode_data = (u64*)gspF3DEX2_xbusDataStart,
164 .ucode_data_size = SP_UCODE_DATA_SIZE,
165 .data_ptr = (u64*)glist,
166 .data_size = (u32)((glistp - glist) * sizeof(Gfx)),
167 .dram_stack = dram_stack,
168 .dram_stack_size = SP_DRAM_STACK_SIZE8,
169 },
170 };
171 osSpTaskStart(&tlist);
172
173 // Wait for RDP completion.
174 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK);
175}
176
177void
178rdp_clearfb(u8 r, u8 g, u8 b) {
179 Gfx *glistp = glist;
180 Gfx clearcfb_dl[] = {
181 gsDPSetCycleType(G_CYC_FILL),
182 gsDPSetColorImage(
183 G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, framebuffers[current_fb]),
184 gsDPSetFillColor(
185 GPACK_RGBA5551(r, g, b, 1) << 16 | GPACK_RGBA5551(r, g, b, 1)),
186 gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
187 gsDPPipeSync(),
188 };
189 gSPDisplayList(glistp++, clearcfb_dl);
190 gDPFullSync(glistp++);
191 gSPEndDisplayList(glistp++);
192
193 // Start up the task list.
194 OSTask tlist = (OSTask){
195 {
196 .type = M_GFXTASK,
197 .flags = OS_TASK_DP_WAIT,
198 .ucode_boot = (u64*)rspbootTextStart,
199 .ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart,
200 .ucode = (u64*)gspF3DEX2_xbusTextStart,
201 .ucode_size = SP_UCODE_SIZE,
202 .ucode_data = (u64*)gspF3DEX2_xbusDataStart,
203 .ucode_data_size = SP_UCODE_DATA_SIZE,
204 .data_ptr = (u64*)glist,
205 .data_size = (u32)((glistp - glist) * sizeof(Gfx)),
206 .dram_stack = dram_stack,
207 .dram_stack_size = SP_DRAM_STACK_SIZE8,
208 },
209 };
210 osSpTaskStart(&tlist);
211
212 // Wait for RDP completion.
213 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK);
214}
215
216void
217rdp_texture_copy(void) {
218 Gfx *glistp = glist;
219 // gSPSegment(glistp++, 0, 0x0); /* Physical address segment */
220 // gSPSegment(glistp++, 1, OS_K0_TO_PHYSICAL(framebuffers[current_fb]));
221
222 Gfx dl[] = {
223 gsDPSetColorImage(
224 G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WIDTH, framebuffers[current_fb]),
225 gsDPSetFillColor(0),
226 gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
227 gsDPPipeSync(),
228 gsDPSetTexturePersp(G_TP_NONE),
229 gsDPSetCycleType(G_CYC_COPY),
230 gsDPSetRenderMode(G_RM_NOOP, G_RM_NOOP2),
231 gsSPClearGeometryMode(G_SHADE | G_SHADING_SMOOTH),
232 gsSPTexture(0x2000, 0x2000, 0, G_TX_RENDERTILE, G_ON),
233 gsDPSetCombineMode(G_CC_DECALRGB, G_CC_DECALRGB),
234 gsDPSetTexturePersp(G_TP_NONE),
235 gsDPSetTextureFilter(G_TF_POINT),
236 };
237 gSPDisplayList(glistp++, dl);
238 for (size_t i = 0; i < 240; i++) {
239 gDPLoadTextureBlock(
240 glistp++,
241 &pixels[320 * 1 * i], // Texture data.
242 G_IM_FMT_RGBA, // Image format.
243 G_IM_SIZ_16b, // Pixel component size.
244 320, // Width.
245 1, // Height.
246 0, // Palette location.
247 G_TX_CLAMP, // S-axis mirror/wrap/clamp.
248 G_TX_CLAMP, // T-axis mirror/wrap/clamp.
249 0, // S-axis mask.
250 0, // T-axis mask.
251 G_TX_NOLOD, // S-axis shift.
252 G_TX_NOLOD); // T-axis shift.
253 gSPTextureRectangle(
254 glistp++,
255 0, // ulx
256 (1 * i) << 2, // uly
257 (320 * (i + 1)) << 2, // lrx
258 (1 * (i + 1)) << 2, // lry
259 0,
260 0,
261 0,
262 4 << 10,
263 1 << 10);
264 }
265 gDPFullSync(glistp++);
266 gSPEndDisplayList(glistp++);
267 osWritebackDCache(&glist, sizeof(glist));
268
269 // Start up the task list.
270 OSTask tlist = (OSTask){
271 {
272 .type = M_GFXTASK,
273 .flags = OS_TASK_DP_WAIT,
274 .ucode_boot = (u64*)rspbootTextStart,
275 .ucode_boot_size = (u32)rspbootTextEnd - (u32)rspbootTextStart,
276 .ucode = (u64*)gspF3DEX2_xbusTextStart,
277 .ucode_size = SP_UCODE_SIZE,
278 .ucode_data = (u64*)gspF3DEX2_xbusDataStart,
279 .ucode_data_size = SP_UCODE_DATA_SIZE,
280 .data_ptr = (u64*)glist,
281 .data_size = (u32)((glistp - glist) * sizeof(Gfx)),
282 .dram_stack = dram_stack,
283 .dram_stack_size = SP_DRAM_STACK_SIZE8,
284 },
285 };
286 osSpTaskStart(&tlist);
287
288 // Wait for RDP completion.
289 osRecvMesg(&rdp_msg_queue, NULL, OS_MESG_BLOCK);
290}
291
292void
293init_ppu(void) {
294 // NOTE: Test image.
295 for (size_t j = 0; j < SCREEN_HEIGHT; j++) {
296 for (size_t i = 0; i < SCREEN_WIDTH; i++) {
297 u16 shade_x = (float)i / (float)SCREEN_WIDTH * 255;
298 u16 shade_y = (float)j / (float)SCREEN_HEIGHT * 255;
299 u16 color = GPACK_RGBA5551(shade_x, 0, shade_y, 1);
300 pixels[i + j * SCREEN_WIDTH] = color;
301 }
302 }
303 // TODO: clear pixel buffers and dirty lines
304
305 // Setup the message queues
306 osCreateMesgQueue(&rdp_msg_queue, &rdp_msg_buf, 1);
307 osSetEventMesg(OS_EVENT_DP, &rdp_msg_queue, NULL);
308 osCreateMesgQueue(&retrace_msg_queue, &retrace_msg_buf, 1);
309 osViSetEvent(&retrace_msg_queue, NULL, 1);
310}
311
312void
313swap_buffers(void) {
314 osViSwapBuffer(framebuffers[current_fb]);
315
316 // Wait for Vertical retrace to finish swap buffers.
317 if (MQ_IS_FULL(&retrace_msg_queue)) {
318 osRecvMesg(&retrace_msg_queue, NULL, OS_MESG_BLOCK);
319 }
320 osRecvMesg(&retrace_msg_queue, NULL, OS_MESG_BLOCK);
321
322 current_fb ^= 1;
323}
324
325void
326blit_framebuffer(void) {
327 if (reqdraw == 0) {
328 return;
329 }
330
331 for (size_t j = 0; j < screen_height; j++) {
332 if (dirty_lines[j] != 0) {
333 for (size_t i = 0; i < screen_width; i++) {
334 size_t idx = i + j * screen_width;
335 pixels[idx] = palette[pixels_fg[idx] << 2 | pixels_bg[idx]];
336 }
337 }
338 dirty_lines[j] = 0;
339 }
340
341 // TODO: Find out how to properly draw to the framebuffer using either the
342 // RDP or DMA. Maybe just drawing directly with the CPU is fine for our
343 // purposes though.
344 // rdp_clearfb(t, t, t);
345 // fb_write_test();
346 fb_copy_test(); // CPU blit
347 // rdp_texture_copy(); // RDP texture blit
348 reqdraw = 0;
349}
diff --git a/src/uxn b/src/uxn
new file mode 160000
Subproject 5496712ae1b231ea31be68151d2cfd10e933969
diff --git a/src/uxn_screen_rom.c b/src/uxn_screen_rom.c
new file mode 100644
index 0000000..4e00d83
--- /dev/null
+++ b/src/uxn_screen_rom.c
@@ -0,0 +1,41 @@
1// NOTE: MIPS is a MSB system, make sure the bytes are in the right order.
2const u16 uxn_rom[] = {
3 0xa001, 0x4780, 0x2037, 0xa0f0, 0x7f80, 0x0837, 0xa0f0, 0xe080,
4 0x0a37, 0xa0f0, 0xc080, 0x0c37, 0xa000, 0xf080, 0x2237, 0xa000,
5 0xa080, 0x2437, 0x8022, 0x3680, 0x013f, 0x8002, 0x3180, 0x2436,
6 0x8001, 0x3f80, 0x0431, 0xa001, 0x6c2e, 0xa001, 0xf52e, 0xa002,
7 0x2f2e, 0xa000, 0x2617, 0x00a0, 0x0126, 0x1780, 0x0030, 0x2126,
8 0x8000, 0x3180, 0x0230, 0xa000, 0x5038, 0x8028, 0x3780, 0x0430,
9 0xa000, 0x4839, 0x802a, 0x37a0, 0x02a3, 0x2e00, 0x8002, 0x30a0,
10 0x0060, 0x3980, 0x2837, 0x8004, 0x30a0, 0x0048, 0x3980, 0x2a37,
11 0xa002, 0xd380, 0x2c37, 0xa0f6, 0x2617, 0xa001, 0x2f17, 0x8002,
12 0x30a0, 0x0070, 0x3980, 0x2837, 0x8004, 0x30a0, 0x0038, 0x3980,
13 0x2a37, 0xa002, 0xd380, 0x2c37, 0xa0f5, 0x2617, 0xa001, 0x2f17,
14 0xa000, 0x2617, 0xa002, 0xc380, 0x2c37, 0xa000, 0x0006, 0x800f,
15 0x1c80, 0x401f, 0x8001, 0x1f80, 0x0004, 0x8002, 0x30a0, 0x0060,
16 0x3938, 0x8028, 0x3706, 0x80f0, 0x1c80, 0x011f, 0x8000, 0x0480,
17 0x0430, 0xa000, 0x3839, 0x3880, 0x2a37, 0x0680, 0x2f17, 0x0189,
18 0x80ca, 0x0d22, 0x6ca0, 0x1000, 0x8f06, 0x8002, 0x1f80, 0x0004,
19 0x8040, 0x3f80, 0x0430, 0xa000, 0x3839, 0x382f, 0x0680, 0x031c,
20 0x8000, 0x0480, 0x403f, 0xa000, 0x4038, 0x8002, 0x30a0, 0x0010,
21 0x3938, 0x6f4f, 0xa000, 0x410e, 0x018a, 0x80cb, 0x0d22, 0x6ca0,
22 0x1000, 0x8f06, 0x8002, 0x1f80, 0x0004, 0x8040, 0x3f80, 0x0430,
23 0xa000, 0x0838, 0x382f, 0x0680, 0x031c, 0x8000, 0x0480, 0x403f,
24 0xa000, 0x4038, 0x8002, 0x30a0, 0x0010, 0x3938, 0x6f4f, 0xa080,
25 0x070e, 0x018a, 0x80cb, 0x0d22, 0x6c18, 0x0fa0, 0x02c3, 0x802c,
26 0x3780, 0x2a37, 0x8028, 0x37a0, 0x0126, 0x174f, 0x802f, 0x97a0,
27 0x0226, 0x1704, 0x8010, 0x1804, 0x9780, 0x28b6, 0xa000, 0x0839,
28 0x0537, 0xa001, 0x2617, 0x0480, 0x1018, 0x0497, 0x0480, 0x1018,
29 0x0417, 0x6c04, 0x8000, 0x0e06, 0x8004, 0x1f80, 0x030e, 0x800f,
30 0x1c80, 0x0004, 0x8030, 0x3fa0, 0x02d3, 0x3880, 0x2c37, 0xa001,
31 0x2f17, 0x6c0f, 0x3867, 0x5fdf, 0xbfbf, 0xbf00, 0x0718, 0x2023,
32 0x4448, 0x4800, 0x7c82, 0x8282, 0x8282, 0x7c00, 0x3010, 0x1010,
33 0x1010, 0x1000, 0x7c82, 0x027c, 0x8080, 0xfe00, 0x7c82, 0x021c,
34 0x0282, 0x7c00, 0x0c14, 0x2444, 0x84fe, 0x0400, 0xfe80, 0x807c,
35 0x0282, 0x7c00, 0x7c82, 0x80fc, 0x8282, 0x7c00, 0x7c82, 0x021e,
36 0x0202, 0x0200, 0x7c82, 0x827c, 0x8282, 0x7c00, 0x7c82, 0x827e,
37 0x0282, 0x7c00, 0x7c82, 0x027e, 0x8282, 0x7e00, 0xfc82, 0x82fc,
38 0x8282, 0xfc00, 0x7c82, 0x8080, 0x8082, 0x7c00, 0xfc82, 0x8282,
39 0x8282, 0xfc00, 0x7c82, 0x80f0, 0x8082, 0x7c00, 0x7c82, 0x80f0,
40 0x8080, 0x8080,
41};