diff options
-rw-r--r-- | src/main.c | 124 | ||||
-rw-r--r-- | src/ppu.c | 85 | ||||
-rw-r--r-- | src/ppu.h | 25 |
3 files changed, 156 insertions, 78 deletions
@@ -4,6 +4,7 @@ | |||
4 | #include "rom.c" | 4 | #include "rom.c" |
5 | 5 | ||
6 | static Uxn u; | 6 | static Uxn u; |
7 | static Ppu ppu; | ||
7 | static Device *devscreen; | 8 | static Device *devscreen; |
8 | static Device *devctrl; | 9 | static Device *devctrl; |
9 | static Device *devmouse; | 10 | static 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 | ||
33 | static void | 36 | static void |
34 | docolors(Device *d) { | 37 | docolors(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 | ||
43 | void | 49 | void |
44 | system_talk(Device *d, u8 b0, u8 w) { | 50 | system_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 | ||
65 | void | 69 | void |
66 | screen_talk(Device *d, u8 b0, u8 w) { | 70 | screen_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 | ||
103 | static void | 89 | static void |
@@ -111,8 +97,8 @@ audio_talk(Device *d, u8 b0, u8 w) { | |||
111 | 97 | ||
112 | void | 98 | void |
113 | datetime_talk(Device *d, u8 b0, u8 w) { | 99 | datetime_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 | ||
121 | void | 107 | void |
122 | file_talk(Device *d, u8 b0, u8 w) { | 108 | file_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 | |||
131 | init_uxn() { | 117 | init_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 | ||
160 | void main(void) { | 146 | void 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 | } |
@@ -1,14 +1,85 @@ | |||
1 | #include "common.h" | 1 | #include "common.h" |
2 | #include "ppu.h" | ||
3 | |||
4 | |||
5 | /* | ||
6 | Copyright (c) 2021 Devine Lu Linvega | ||
7 | Copyright (c) 2021 Andrew Alderwick | ||
8 | Copyright (c) 2021 Bad Diode | ||
9 | |||
10 | Permission to use, copy, modify, and distribute this software for any | ||
11 | purpose with or without fee is hereby granted, provided that the above | ||
12 | copyright notice and this permission notice appear in all copies. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
15 | WITH REGARD TO THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #define SCREEN_WIDTH 64 * 8 / 2 | ||
19 | #define SCREEN_HEIGHT 40 * 8 / 2 | ||
2 | 20 | ||
3 | static u32 *framebuffer = 0; | 21 | static u32 *framebuffer = 0; |
4 | 22 | ||
5 | #define SCREEN_WIDTH 800 | 23 | static u32 palette[16]; |
6 | #define SCREEN_HEIGHT 600 | 24 | static u8 pixels_buf[SCREEN_WIDTH * SCREEN_HEIGHT]; |
7 | 25 | ||
8 | static u32 palette[4]; | 26 | static 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 | ||
10 | void | 33 | void |
11 | ppu_init(void) { | 34 | ppu_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 | |||
44 | void | ||
45 | ppu_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 | |||
60 | void | ||
61 | ppu_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 | |||
78 | int | ||
79 | ppu_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 | /* | ||
2 | Copyright (c) 2021 Devine Lu Linvega | ||
3 | Copyright (c) 2021 Andrew Alderwick | ||
4 | |||
5 | Permission to use, copy, modify, and distribute this software for any | ||
6 | purpose with or without fee is hereby granted, provided that the above | ||
7 | copyright notice and this permission notice appear in all copies. | ||
8 | |||
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | WITH REGARD TO THIS SOFTWARE. | ||
11 | */ | ||
12 | |||
13 | typedef unsigned char Uint8; | ||
14 | typedef unsigned short Uint16; | ||
15 | typedef unsigned int Uint32; | ||
16 | |||
17 | typedef struct Ppu { | ||
18 | Uint16 width, height; | ||
19 | Uint8 *pixels; | ||
20 | } Ppu; | ||
21 | |||
22 | int ppu_init(Ppu *p, Uint8 hor, Uint8 ver); | ||
23 | void ppu_pixel(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 color); | ||
24 | void ppu_1bpp(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy); | ||
25 | void ppu_2bpp(Ppu *p, Uint8 layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy); | ||