diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..77cabcc --- /dev/null +++ b/src/main.c | |||
@@ -0,0 +1,155 @@ | |||
1 | #include <string.h> | ||
2 | |||
3 | #include "common.h" | ||
4 | #include "bitmap.h" | ||
5 | #include "text.h" | ||
6 | #include "small-font.c" | ||
7 | |||
8 | #include "uxn/uxn.h" | ||
9 | #include "uxn/uxn.c" | ||
10 | #include "uxn/devices/ppu.h" | ||
11 | #include "uxn/devices/ppu.c" | ||
12 | // #include "uxn/roms/console.c" | ||
13 | #include "uxn/roms/dvd.c" | ||
14 | // #include "uxn/roms/proportional_fonts.c" | ||
15 | // #include "uxn/roms/automata.c" | ||
16 | // #include "uxn/roms/life.c" | ||
17 | |||
18 | static Ppu ppu; | ||
19 | u8 reqdraw = 0; | ||
20 | static Device *devscreen; | ||
21 | |||
22 | void | ||
23 | nil_talk(Device *d, Uint8 b0, Uint8 w) { | ||
24 | (void)d; | ||
25 | (void)b0; | ||
26 | (void)w; | ||
27 | } | ||
28 | |||
29 | void | ||
30 | console_talk(Device *d, u8 b0, u8 w) { | ||
31 | if(!w) { | ||
32 | return; | ||
33 | } | ||
34 | switch(b0) { | ||
35 | case 0x8: txt_printf("%c", d->dat[0x8]); break; | ||
36 | case 0x9: txt_printf("0x%02x", d->dat[0x9]); break; | ||
37 | case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break; | ||
38 | case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | void | ||
43 | system_talk(Device *d, Uint8 b0, Uint8 w) | ||
44 | { | ||
45 | if(!w) { | ||
46 | d->dat[0x2] = d->u->wst.ptr; | ||
47 | d->dat[0x3] = d->u->rst.ptr; | ||
48 | } else { | ||
49 | putcolors(&ppu, &d->dat[0x8]); | ||
50 | reqdraw = 1; | ||
51 | } | ||
52 | (void)b0; | ||
53 | } | ||
54 | |||
55 | void | ||
56 | screen_talk(Device *d, Uint8 b0, Uint8 w) { | ||
57 | if(w && b0 == 0xe) { | ||
58 | Uint16 x = mempeek16(d->dat, 0x8); | ||
59 | Uint16 y = mempeek16(d->dat, 0xa); | ||
60 | Uint8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; | ||
61 | Uint8 *layer = d->dat[0xe] >> 4 & 0x1 ? ppu.fg : ppu.bg; | ||
62 | Uint8 mode = d->dat[0xe] >> 5; | ||
63 | if(!mode) { | ||
64 | putpixel(&ppu, layer, x, y, d->dat[0xe] & 0x3); | ||
65 | } else if(mode-- & 0x1) { | ||
66 | puticn(&ppu, layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4); | ||
67 | } else { | ||
68 | putchr(&ppu, layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4); | ||
69 | } | ||
70 | reqdraw = 1; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | void | ||
75 | redraw(Uint16 *dst, Uxn *u) { | ||
76 | // TODO: The screen will flicker but using Mode4 for double buffering would | ||
77 | // be way too slow. | ||
78 | drawppu(&ppu); | ||
79 | clear_screen_m3(); | ||
80 | // Copy ppu data to framebuffer. | ||
81 | for (size_t j = 0; j < ppu.height; ++j) { | ||
82 | for (size_t i = 0; i < ppu.width; ++i) { | ||
83 | FRAMEBUFFER[j][i] = ppu.output[i + j * ppu.width]; | ||
84 | } | ||
85 | } | ||
86 | reqdraw = 0; | ||
87 | } | ||
88 | |||
89 | void | ||
90 | init_uxn(Uxn *u) { | ||
91 | // Initialize PPU. | ||
92 | initppu(&ppu, 30, 20, 0); | ||
93 | |||
94 | // Copy rom to VM. | ||
95 | memcpy(u->ram.dat + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); | ||
96 | |||
97 | // Prepare devices. | ||
98 | portuxn(u, 0x0, "system", system_talk); | ||
99 | portuxn(u, 0x1, "console", console_talk); | ||
100 | devscreen = portuxn(u, 0x2, "screen", screen_talk); | ||
101 | portuxn(u, 0x3, "---", nil_talk); | ||
102 | portuxn(u, 0x4, "---", nil_talk); | ||
103 | portuxn(u, 0x5, "---", nil_talk); | ||
104 | portuxn(u, 0x6, "---", nil_talk); | ||
105 | portuxn(u, 0x7, "---", nil_talk); | ||
106 | portuxn(u, 0x8, "---", nil_talk); | ||
107 | portuxn(u, 0x9, "---", nil_talk); | ||
108 | portuxn(u, 0xa, "---", nil_talk); | ||
109 | portuxn(u, 0xb, "---", nil_talk); | ||
110 | portuxn(u, 0xc, "---", nil_talk); | ||
111 | portuxn(u, 0xd, "---", nil_talk); | ||
112 | portuxn(u, 0xe, "---", nil_talk); | ||
113 | portuxn(u, 0xf, "---", nil_talk); | ||
114 | mempoke16(devscreen->dat, 2, ppu.hor * 8); | ||
115 | mempoke16(devscreen->dat, 4, ppu.ver * 8); | ||
116 | } | ||
117 | |||
118 | int main(void) { | ||
119 | // Initialize display mode and bg palette. | ||
120 | DISP_CTRL = DISP_MODE_3 | DISP_BG_2; | ||
121 | |||
122 | // Initialize text engine. | ||
123 | txt_init_bitmap( | ||
124 | TXT_MODE_MODE3, | ||
125 | (Font){ | ||
126 | .data = small_font, | ||
127 | .char_width = 4, | ||
128 | .char_height = 8, | ||
129 | .color = COLOR_BLUE, | ||
130 | .char_map = small_font_map, | ||
131 | }); | ||
132 | |||
133 | // Register interrupts. | ||
134 | irq_init(); | ||
135 | irs_set(IRQ_VBLANK, irs_stub); | ||
136 | |||
137 | // Initialize VM. | ||
138 | Uxn u = {0}; | ||
139 | init_uxn(&u); | ||
140 | evaluxn(&u, 0x0100); | ||
141 | |||
142 | // Main loop. | ||
143 | int frame_counter = 0; | ||
144 | while(true) { | ||
145 | bios_vblank_wait(); | ||
146 | poll_keys(); | ||
147 | evaluxn(&u, mempeek16(devscreen->dat, 0)); | ||
148 | if(reqdraw) { | ||
149 | redraw(ppu.output, &u); | ||
150 | } | ||
151 | frame_counter++; | ||
152 | }; | ||
153 | |||
154 | return 0; | ||
155 | } | ||