aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-09-08 13:28:56 +0200
committerBad Diode <bd@badd10de.dev>2021-09-08 13:28:56 +0200
commit7654bb013814d7cf317f7dfd69238abe6dc30ef1 (patch)
treeab375f92d6fe22b1c9ddc1083c6a166756d33c93
parentd09b8df422d03170d0f44093a27607b8f7c1a2b6 (diff)
downloaduxnrpi-7654bb013814d7cf317f7dfd69238abe6dc30ef1.tar.gz
uxnrpi-7654bb013814d7cf317f7dfd69238abe6dc30ef1.zip
Add initial PPU implementation for UXN
-rw-r--r--src/main.c124
-rw-r--r--src/ppu.c85
-rw-r--r--src/ppu.h25
3 files changed, 156 insertions, 78 deletions
diff --git a/src/main.c b/src/main.c
index f2ffa5b..fc073c9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,6 +4,7 @@
4#include "rom.c" 4#include "rom.c"
5 5
6static Uxn u; 6static Uxn u;
7static Ppu ppu;
7static Device *devscreen; 8static Device *devscreen;
8static Device *devctrl; 9static Device *devctrl;
9static Device *devmouse; 10static Device *devmouse;
@@ -24,6 +25,8 @@ console_talk(Device *d, u8 b0, u8 w) {
24 } 25 }
25 switch(b0) { 26 switch(b0) {
26 case 0x8: stmp[0] = d->dat[0x8]; stmp[1] = 0; uart_puts(stmp); break; 27 case 0x8: stmp[0] = d->dat[0x8]; stmp[1] = 0; uart_puts(stmp); break;
28 // TODO: implement printf for the uart to be able to format
29 // numbers.
27 // case 0x9: txt_printf("0x%02x", d->dat[0x9]); break; 30 // case 0x9: txt_printf("0x%02x", d->dat[0x9]); break;
28 // case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break; 31 // case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break;
29 // case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break; 32 // case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break;
@@ -32,72 +35,55 @@ console_talk(Device *d, u8 b0, u8 w) {
32 35
33static void 36static void
34docolors(Device *d) { 37docolors(Device *d) {
35 for(size_t i = 0; i < 4; ++i) { 38 for(size_t i = 0; i < 4; ++i) {
36 u8 r = ((d->dat[0x8 + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; 39 u8 r = ((d->dat[0x8 + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11;
37 u8 g = ((d->dat[0xa + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; 40 u8 g = ((d->dat[0xa + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11;
38 u8 b = ((d->dat[0xc + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11; 41 u8 b = ((d->dat[0xc + i / 2] >> (!(i % 2) << 2)) & 0x0f) * 0x11;
39 palette[i] = (b << 16) | (g << 8) | r; 42 palette[i] = (b << 16) | (g << 8) | r;
40 } 43 }
44 for(size_t i = 4; i < 16; ++i) {
45 palette[i] = palette[i / 4];
46 }
41} 47}
42 48
43void 49void
44system_talk(Device *d, u8 b0, u8 w) { 50system_talk(Device *d, u8 b0, u8 w) {
45 // uart_puts("system_talk\n"); 51 if(!w) { /* read */
46 // TODO: Implement... 52 switch(b0) {
47 if(!w) { /* read */ 53 case 0x2: d->dat[0x2] = d->u->wst.ptr; break;
48 switch(b0) { 54 case 0x3: d->dat[0x3] = d->u->rst.ptr; break;
49 case 0x2: d->dat[0x2] = d->u->wst.ptr; break; 55 }
50 case 0x3: d->dat[0x3] = d->u->rst.ptr; break; 56 } else { /* write */
51 } 57 switch(b0) {
52 } else { /* write */ 58 case 0x2: d->u->wst.ptr = d->dat[0x2]; break;
53 switch(b0) { 59 case 0x3: d->u->rst.ptr = d->dat[0x3]; break;
54 case 0x2: d->u->wst.ptr = d->dat[0x2]; break; 60 case 0xf: d->u->ram.ptr = 0x0000; break;
55 case 0x3: d->u->rst.ptr = d->dat[0x3]; break;
56 case 0xf: d->u->ram.ptr = 0x0000; break;
57 }
58 if(b0 > 0x7 && b0 < 0xe) {
59 docolors(d);
60 } 61 }
61 } 62 if(b0 > 0x7 && b0 < 0xe) {
63 docolors(d);
64 }
65 }
62 (void)b0; 66 (void)b0;
63} 67}
64 68
65void 69void
66screen_talk(Device *d, u8 b0, u8 w) { 70screen_talk(Device *d, u8 b0, u8 w) {
67 // uart_puts("screen_talk\n"); 71 // uart_puts("screen_talk\n");
68 // TODO: Implement... 72 if(w && b0 == 0xe) {
69 // if(w && b0 == 0xe) { 73 Uint16 x = mempeek16(d->dat, 0x8);
70 // u16 x = mempeek16(d->dat, 0x8); 74 Uint16 y = mempeek16(d->dat, 0xa);
71 // u16 y = mempeek16(d->dat, 0xa); 75 Uint8 layer = d->dat[0xe] >> 4 & 0x1;
72 // u8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; 76 ppu_pixel(&ppu, layer, x, y, d->dat[0xe] & 0x3);
73 // u8 *layer = d->dat[0xe] >> 4 & 0x1 ? ppu.fg : ppu.bg; 77 } else if(w && b0 == 0xf) {
74 // u8 mode = d->dat[0xe] >> 5; 78 Uint16 x = mempeek16(d->dat, 0x8);
75 // u8 color = d->dat[0xf] & 0xf; 79 Uint16 y = mempeek16(d->dat, 0xa);
76 // if(!mode) { 80 Uint8 layer = d->dat[0xf] >> 0x6 & 0x1;
77 // ppu_pixel(layer, x, y, d->dat[0xe] & 0x3); 81 Uint8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
78 // } else if(mode-- & 0x1) { 82 if(d->dat[0xf] >> 0x7 & 0x1)
79 // u8 flipx = mode & 0x2; 83 ppu_2bpp(&ppu, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] >> 0x4 & 0x1, d->dat[0xf] >> 0x5 & 0x1);
80 // u8 flipy = mode & 0x4; 84 else
81 // ppu_1bpp(layer, x, y, addr, color, flipx, flipy); 85 ppu_1bpp(&ppu, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] >> 0x4 & 0x1, d->dat[0xf] >> 0x5 & 0x1);
82 // } else { 86 }
83 // u8 flipx = mode & 0x2;
84 // u8 flipy = mode & 0x4;
85 // ppu_2bpp(layer, x, y, addr, color, flipx, flipy);
86 // }
87 // } else if(w && b0 == 0xf) {
88 // u16 x = mempeek16(d->dat, 0x8);
89 // u16 y = mempeek16(d->dat, 0xa);
90 // u8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
91 // u8 *layer = d->dat[0xf] >> 6 & 0x1 ? ppu.fg : ppu.bg;
92 // u8 color = d->dat[0xf] & 0xf;
93 // u8 flipx = (d->dat[0xf] >> 0x4) & 0x1;
94 // u8 flipy = (d->dat[0xf] >> 0x5) & 0x1;
95 // if(d->dat[0xf] >> 0x7 & 0x1) {
96 // ppu_2bpp(layer, x, y, addr, color, flipx, flipy);
97 // } else {
98 // ppu_1bpp(layer, x, y, addr, color, flipx, flipy);
99 // }
100 // }
101} 87}
102 88
103static void 89static void
@@ -111,8 +97,8 @@ audio_talk(Device *d, u8 b0, u8 w) {
111 97
112void 98void
113datetime_talk(Device *d, u8 b0, u8 w) { 99datetime_talk(Device *d, u8 b0, u8 w) {
114 // uart_puts("datetime_talk\n");
115 // TODO: Implement... 100 // TODO: Implement...
101 // uart_puts("datetime_talk\n");
116 (void)d; 102 (void)d;
117 (void)b0; 103 (void)b0;
118 (void)w; 104 (void)w;
@@ -120,8 +106,8 @@ datetime_talk(Device *d, u8 b0, u8 w) {
120 106
121void 107void
122file_talk(Device *d, u8 b0, u8 w) { 108file_talk(Device *d, u8 b0, u8 w) {
123 // uart_puts("file_talk\n");
124 // TODO: Implement... 109 // TODO: Implement...
110 // uart_puts("file_talk\n");
125 (void)d; 111 (void)d;
126 (void)b0; 112 (void)b0;
127 (void)w; 113 (void)w;
@@ -131,7 +117,7 @@ void
131init_uxn() { 117init_uxn() {
132 uart_puts("Initializing UXN.\n"); 118 uart_puts("Initializing UXN.\n");
133 uart_init(); 119 uart_init();
134 ppu_init(); 120 ppu_init(&ppu, SCREEN_WIDTH / 8, SCREEN_HEIGHT / 8);
135 121
136 // Copy rom to VM. 122 // Copy rom to VM.
137 memcpy(u.ram.dat + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); 123 memcpy(u.ram.dat + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom));
@@ -153,8 +139,8 @@ init_uxn() {
153 uxn_port(&u, 0xd, "---", nil_talk); 139 uxn_port(&u, 0xd, "---", nil_talk);
154 uxn_port(&u, 0xe, "---", nil_talk); 140 uxn_port(&u, 0xe, "---", nil_talk);
155 uxn_port(&u, 0xf, "---", nil_talk); 141 uxn_port(&u, 0xf, "---", nil_talk);
156 // mempoke16(devscreen->dat, 2, ppu.hor * 8); 142 mempoke16(devscreen->dat, 2, ppu.width);
157 // mempoke16(devscreen->dat, 4, ppu.ver * 8); 143 mempoke16(devscreen->dat, 4, ppu.height);
158} 144}
159 145
160void main(void) { 146void main(void) {
@@ -166,19 +152,11 @@ void main(void) {
166 // Echo input to standard output. 152 // Echo input to standard output.
167 uxn_eval(&u, mempeek16(devscreen->dat, 0)); 153 uxn_eval(&u, mempeek16(devscreen->dat, 0));
168 154
169 // DEBUG: testing fb drawing. 155 // Blit ppu.pixels to the framebuffer.
170 u32 lines = SCREEN_WIDTH * SCREEN_HEIGHT / 4; 156 // NOTE: This is very inefficient, we likely want to keep track of the
171 for (size_t i = 0; i < lines; i++) { 157 // lines/tiles that have changed and only copy those.
172 framebuffer[i] = palette[0]; 158 for (size_t i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) {
173 } 159 framebuffer[i] = palette[ppu.pixels[i]];
174 for (size_t i = lines; i < lines * 2; i++) {
175 framebuffer[i] = palette[1];
176 }
177 for (size_t i = lines * 2; i < lines * 3; i++) {
178 framebuffer[i] = palette[2];
179 }
180 for (size_t i = lines * 3; i < lines * 4; i++) {
181 framebuffer[i] = palette[3];
182 } 160 }
183 } 161 }
184} 162}
diff --git a/src/ppu.c b/src/ppu.c
index 2e0404f..aeb3699 100644
--- a/src/ppu.c
+++ b/src/ppu.c
@@ -1,14 +1,85 @@
1#include "common.h" 1#include "common.h"
2#include "ppu.h"
3
4
5/*
6Copyright (c) 2021 Devine Lu Linvega
7Copyright (c) 2021 Andrew Alderwick
8Copyright (c) 2021 Bad Diode
9
10Permission to use, copy, modify, and distribute this software for any
11purpose with or without fee is hereby granted, provided that the above
12copyright notice and this permission notice appear in all copies.
13
14THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15WITH REGARD TO THIS SOFTWARE.
16*/
17
18#define SCREEN_WIDTH 64 * 8 / 2
19#define SCREEN_HEIGHT 40 * 8 / 2
2 20
3static u32 *framebuffer = 0; 21static u32 *framebuffer = 0;
4 22
5#define SCREEN_WIDTH 800 23static u32 palette[16];
6#define SCREEN_HEIGHT 600 24static u8 pixels_buf[SCREEN_WIDTH * SCREEN_HEIGHT];
7 25
8static u32 palette[4]; 26static Uint8 blending[5][16] = {
27 {0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0},
28 {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
29 {1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1},
30 {2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
31 {1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}};
9 32
10void 33void
11ppu_init(void) { 34ppu_pixel(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 color)
35{
36 size_t idx = y * p->width + x;
37 Uint8 *pixel = &p->pixels[idx], shift = layer * 2;
38 if(x < p->width && y < p->height) {
39 *pixel = (*pixel & ~(0x3 << shift)) | (color << shift);
40 // framebuffer[idx] = palette[*pixel];
41 }
42}
43
44void
45ppu_1bpp(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy)
46{
47 Uint16 v, h;
48 for(v = 0; v < 8; v++)
49 for(h = 0; h < 8; h++) {
50 Uint8 ch1 = (sprite[v] >> (7 - h)) & 0x1;
51 if(ch1 || blending[4][color])
52 ppu_pixel(p,
53 layer,
54 x + (flipx ? 7 - h : h),
55 y + (flipy ? 7 - v : v),
56 blending[ch1][color]);
57 }
58}
59
60void
61ppu_2bpp(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy)
62{
63 Uint16 v, h;
64 for(v = 0; v < 8; v++)
65 for(h = 0; h < 8; h++) {
66 Uint8 ch1 = ((sprite[v] >> (7 - h)) & 0x1);
67 Uint8 ch2 = ((sprite[v + 8] >> (7 - h)) & 0x1);
68 Uint8 ch = ch1 + ch2 * 2;
69 if(ch || blending[4][color])
70 ppu_pixel(p,
71 layer,
72 x + (flipx ? 7 - h : h),
73 y + (flipy ? 7 - v : v),
74 blending[ch][color]);
75 }
76}
77
78int
79ppu_init(Ppu *p, Uint8 hor, Uint8 ver) {
80 p->width = 8 * hor;
81 p->height = 8 * ver;
82
12 // Initialize the framebuffer. 83 // Initialize the framebuffer.
13 static MboxFramebufferRequest fb_request = { 84 static MboxFramebufferRequest fb_request = {
14 .buf_size = 96, 85 .buf_size = 96,
@@ -53,12 +124,16 @@ ppu_init(void) {
53 framebuffer = (u32*)((uintptr_t)fb_request.framebuffer_tag.fb_addr); 124 framebuffer = (u32*)((uintptr_t)fb_request.framebuffer_tag.fb_addr);
54 } else { 125 } else {
55 uart_puts("Unable initialize framebuffer\n"); 126 uart_puts("Unable initialize framebuffer\n");
56 return; 127 return 0;
57 } 128 }
58 129
130 p->pixels = pixels_buf;
131
59 // Initialize default palette. 132 // Initialize default palette.
60 palette[0] = 0x00444444; 133 palette[0] = 0x00444444;
61 palette[1] = 0x00ffffff; 134 palette[1] = 0x00ffffff;
62 palette[2] = 0x007777ff; 135 palette[2] = 0x007777ff;
63 palette[3] = 0x00ff7777; 136 palette[3] = 0x00ff7777;
137
138 return 1;
64} 139}
diff --git a/src/ppu.h b/src/ppu.h
new file mode 100644
index 0000000..45af70b
--- /dev/null
+++ b/src/ppu.h
@@ -0,0 +1,25 @@
1/*
2Copyright (c) 2021 Devine Lu Linvega
3Copyright (c) 2021 Andrew Alderwick
4
5Permission to use, copy, modify, and distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10WITH REGARD TO THIS SOFTWARE.
11*/
12
13typedef unsigned char Uint8;
14typedef unsigned short Uint16;
15typedef unsigned int Uint32;
16
17typedef struct Ppu {
18 Uint16 width, height;
19 Uint8 *pixels;
20} Ppu;
21
22int ppu_init(Ppu *p, Uint8 hor, Uint8 ver);
23void ppu_pixel(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 color);
24void ppu_1bpp(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy);
25void ppu_2bpp(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy);