source: buchla-emu/emu/lcd.c@ a86b3ab

Last change on this file since a86b3ab was a86b3ab, checked in by Alexander Heinrich <alex.heinrich@…>, 7 years ago

Formatting.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (C) 2017 The Contributors
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * A copy of the GNU General Public License can be found in the file
15 * "gpl.txt" in the top directory of this repository.
16 */
17
18#include <all.h>
19
20#define ver(...) _ver(lcd_verbose, 0, __VA_ARGS__)
21#define ver2(...) _ver(lcd_verbose, 1, __VA_ARGS__)
22#define ver3(...) _ver(lcd_verbose, 2, __VA_ARGS__)
23
24#define WIN_W (510 * 2)
25#define WIN_H (64 * 2)
26
27#define CON_BGR 0x00000000
28#define CON_DRW 0xFFFFFFFF
29#define CON_FGR ((SDL_Color){ .r = 255, .b = 255, .g = 255, .a = 255 })
30
31#define G_INIT 0x40
32#define G_MWRITE 0x42
33#define G_MREAD 0x43
34#define G_SETSAD 0x44
35#define G_CRSWR 0x46
36#define G_CRSRD 0x47
37#define G_CRSMRT 0x4C
38#define G_CRSMLT 0x4D
39#define G_CRSMUP 0x4E
40#define G_CRSMDN 0x4F
41#define G_ERASE 0x52
42#define G_SLEEP 0x53
43#define G_DSPOFF 0x58
44#define G_DSPON 0x59
45#define G_HSCRL 0x5A
46#define G_OVRLAY 0x5B
47#define G_CGRAM 0x5C
48#define G_CRSFRM 0x5D
49
50#define TXT_W 85
51#define TXT_H 8
52
53#define GFX_W 85
54#define GFX_H 64
55
56#define BASE_TXT 0x0000
57#define BASE_GFX 0x2000
58
59static uint8_t mem_txt[TXT_H * TXT_W];
60static uint8_t mem_gfx[GFX_H * GFX_W];
61
62static SDL_Window *win;
63static SDL_Renderer *ren;
64static SDL_atomic_t frame;
65static SDL_atomic_t clear;
66
67static uint32_t render = 0;
68
69static TTF_Font *fon;
70static int32_t fon_w, fon_h;
71
72static int32_t sur_w, sur_h;
73static SDL_Surface *sur;
74static SDL_Surface *gfx_sur;
75
76static int32_t cur = 0;
77static int32_t cur_c = 0;
78static int32_t dir = 1;
79
80static int32_t current_op = 0x00;
81
82static uint32_t last_val = 0x00;
83static uint32_t last_off = 0;
84static int32_t last_sz = -1;
85static int32_t mult_val_c = 0;
86
87int32_t lcd_verbose = 0;
88
89void lcd_sdl(void)
90{
91 ver3("lcd_sdl()");
92
93 if (SDL_AtomicGet(&clear)) {
94 if (SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0xff) < 0) {
95 fail("SDL_SetRenderDrawColor() failed: %s", SDL_GetError());
96 }
97
98 if (SDL_RenderClear(ren) < 0) {
99 fail("SDL_RenderClear() failed: %s", SDL_GetError());
100 }
101
102 SDL_RenderPresent(ren);
103 SDL_AtomicSet(&clear, 0);
104 return;
105 }
106
107 static int32_t last = 0;
108 int32_t now = SDL_AtomicGet(&frame);
109
110 if (last == now) {
111 ver3("no update");
112 return;
113 }
114
115 last = now;
116
117 if (SDL_FillRect(sur, NULL, CON_BGR) < 0) {
118 fail("SDL_FillRect() failed: %s", SDL_GetError());
119 }
120
121 for (int32_t y = 0; y < TXT_H; ++y) {
122 char line[TXT_W + 1];
123
124 if (SDL_LockMutex(cpu_mutex) < 0) {
125 fail("SDL_LockMutex() failed: %s", SDL_GetError());
126 }
127
128 memcpy(line, mem_txt + y * TXT_W, TXT_W);
129 line[TXT_W] = 0;
130
131 if (SDL_UnlockMutex(cpu_mutex) < 0) {
132 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
133 }
134
135 SDL_Surface *lin = TTF_RenderText_Blended(fon, line, CON_FGR);
136
137 if (lin == NULL) {
138 fail("TTF_RenderText_Blended() failed: %s", TTF_GetError());
139 }
140
141 if (SDL_BlitSurface(lin, NULL, sur, &(SDL_Rect){
142 .x = 0,
143 .y = y * fon_h,
144 .w = TXT_W * fon_w,
145 .h = fon_h
146 })) {
147 fail("SDL_BlitSurface() failed: %s", SDL_GetError());
148 }
149
150 SDL_FreeSurface(lin);
151 }
152
153 SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, sur);
154
155 if (tex == NULL) {
156 fail("SDL_CreateTextureFromSurface() failed: %s", SDL_GetError());
157 }
158
159 if (SDL_RenderCopy(ren, tex, NULL, NULL) < 0) {
160 fail("SDL_RenderCopy() failed: %s", SDL_GetError());
161 }
162
163 for (int32_t y = 0; y < GFX_H * GFX_W; ++y) {
164 for (int32_t p = 7; p > 1; --p) {
165 uint32_t col = CON_BGR;
166 if ((mem_gfx[y] & (1 << p)) > 0) {
167 col = CON_DRW;
168 }
169
170 if (SDL_FillRect(gfx_sur, &(SDL_Rect){
171 .x = y % 85 * fon_w + (8 - p) * fon_w / 6,
172 .y = y / 85 * fon_h / 8,
173 .w = fon_w / 6 + 1,
174 .h = fon_h / 8 + 1
175 }, col) < 0) {
176 fail("SDL_FillRect() failed: %s", SDL_GetError());
177 }
178 }
179 }
180
181 SDL_Texture *gfx_tex = SDL_CreateTextureFromSurface(ren, gfx_sur);
182
183 if (gfx_tex == NULL) {
184 fail("SDL_CreateTextureFromSurface() failed: %s", SDL_GetError());
185 }
186
187 if (SDL_SetTextureBlendMode(gfx_tex, SDL_BLENDMODE_ADD) < 0) {
188 fail("SDL_SetTextureBlendMode() failed: %s", SDL_GetError());
189 }
190
191 if (SDL_RenderCopy(ren, gfx_tex, NULL, NULL) < 0) {
192 fail("SDL_RenderCopy() failed: %s", SDL_GetError());
193 }
194
195 SDL_DestroyTexture(tex);
196 SDL_DestroyTexture(gfx_tex);
197 SDL_RenderPresent(ren);
198}
199
200void lcd_init(void)
201{
202 ver("lcd init");
203
204 win = SDL_CreateWindow("Front LCD", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
205 WIN_W, WIN_H, 0);
206
207 if (win == NULL) {
208 fail("SDL_CreateWindow() failed: %s", SDL_GetError());
209 }
210
211 ren = SDL_CreateRenderer(win, -1, 0);
212
213 if (ren == NULL) {
214 fail("SDL_CreateRenderer() failed: %s", SDL_GetError());
215 }
216
217 SDL_AtomicSet(&clear, 0);
218
219 SDL_AtomicSet(&frame, 1);
220
221 SDL_RWops *ops = SDL_RWFromFile(font, "rb");
222
223 if (ops == NULL) {
224 fail("error while opening font file %s: %s", font, SDL_GetError());
225 }
226
227 fon = TTF_OpenFontRW(ops, 1, 32);
228
229 if (fon == NULL) {
230 fail("error while loading font file %s: %s", font, TTF_GetError());
231 }
232
233 fon_h = TTF_FontLineSkip(fon);
234
235 if (TTF_GlyphMetrics(fon, 'X', NULL, NULL, NULL, NULL, &fon_w) < 0) {
236 fail("error while measuring font width: %s", TTF_GetError());
237 }
238
239 sur_w = TXT_W * fon_w;
240 sur_h = TXT_H * fon_h;
241
242 sur = SDL_CreateRGBSurface(0, sur_w, sur_h, 32, 0, 0, 0, 0);
243
244 if (sur == NULL) {
245 fail("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
246 }
247
248 gfx_sur = SDL_CreateRGBSurface(0, sur_w, sur_h, 32, 0, 0, 0, 0);
249
250 if (gfx_sur == NULL) {
251 fail("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
252 }
253
254 for (int32_t y = 0; y < TXT_W * TXT_H; ++y) {
255 mem_txt[y] = ' ';
256 }
257}
258
259void lcd_quit(void)
260{
261 ver("lcd quit");
262
263 SDL_FreeSurface(sur);
264 SDL_FreeSurface(gfx_sur);
265 TTF_CloseFont(fon);
266
267 SDL_DestroyRenderer(ren);
268 SDL_DestroyWindow(win);
269}
270
271bool lcd_exec(void)
272{
273 ver3("lcd exec");
274 return false;
275}
276
277uint32_t lcd_read(uint32_t off, int32_t sz)
278{
279 ver2("lcd rd %u:%d", off, sz * 8);
280
281 uint32_t rv;
282
283 switch (current_op) {
284 case G_MREAD:
285 if (cur >= BASE_TXT && cur < BASE_TXT + TXT_W * TXT_H) {
286 rv = mem_txt[cur - BASE_TXT];
287 }
288 else if (cur >= BASE_GFX && cur < BASE_GFX + GFX_W * GFX_H) {
289 rv = mem_gfx[cur - BASE_GFX];
290 }
291 else {
292 rv = 0x00;
293 }
294 break;
295
296 default:
297 rv = 0x00;
298 break;
299 }
300 return rv;
301}
302
303void lcd_write(uint32_t off, int32_t sz, uint32_t val)
304{
305 if (last_val != val && mult_val_c > 0) {
306 if (mult_val_c > 1) {
307 ver2("lcd wr %u:%d 0x%0*x was called %u more times", last_off, last_sz * 8, last_sz * 2, last_val, mult_val_c);
308 }
309 else {
310 ver2("lcd wr %u:%d 0x%0*x", last_off, last_sz * 8, last_sz * 2, last_val);
311 }
312
313 ver2("lcd wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
314 mult_val_c = 0;
315 }
316 else if (last_val == val && mult_val_c >= 0) {
317 ++mult_val_c;
318 }
319 else {
320 ver2("lcd wr %u:%d 0x%0*x", off, sz * 8, sz * 2, val);
321 }
322
323 last_val = val;
324 last_off = off;
325 last_sz = sz;
326
327 if (off == 0) {
328 switch (current_op) {
329 case G_MWRITE:
330 if (cur >= BASE_TXT && cur < BASE_TXT + TXT_W * TXT_H) {
331 if (val == 0) {
332 mem_txt[cur - BASE_TXT] = ' ';
333 }
334 else {
335 mem_txt[cur - BASE_TXT] = (uint8_t) val;
336 }
337
338 cur += dir;
339
340 if (render) {
341 SDL_AtomicAdd(&frame, 1);
342 }
343 }
344 else if (cur >= BASE_GFX && cur < BASE_GFX + GFX_W * GFX_H) {
345 mem_gfx[cur - BASE_GFX] = (uint8_t) val;
346 cur += dir;
347
348 if (render) {
349 SDL_AtomicAdd(&frame, 1);
350 }
351 }
352 break;
353
354 case G_CRSWR:
355 if (cur_c == 0) {
356 cur = (int32_t) val;
357 cur_c++;
358 }
359 else if (cur_c == 1) {
360 cur = cur | ((int32_t) val << 8);
361 if (cur < BASE_TXT || (cur >= BASE_TXT + TXT_W * TXT_H && cur < BASE_GFX) || cur >= BASE_GFX + GFX_W * GFX_H) {
362 err("Invalid cur value %d", cur);
363 }
364 cur_c = 0;
365 }
366 break;
367
368 default:
369 break;
370 }
371 }
372 else {
373 switch (val) {
374 case G_MWRITE:
375 current_op = G_MWRITE;
376 break;
377
378 case G_CRSMRT:
379 dir = 1;
380 current_op = G_CRSMRT;
381 break;
382
383 case G_CRSMUP:
384 dir = -85;
385 current_op = G_CRSMUP;
386 break;
387
388 case G_CRSMDN:
389 dir = 85;
390 current_op = G_CRSMDN;
391 break;
392
393 case G_CRSWR:
394 current_op = G_CRSWR;
395 break;
396
397 case G_MREAD:
398 current_op = G_MREAD;
399 break;
400
401 case G_DSPOFF:
402 SDL_AtomicSet(&clear, 1);
403 render = 0;
404 current_op = G_DSPOFF;
405 break;
406
407 case G_DSPON:
408 render = 1;
409 current_op = G_DSPON;
410 break;
411
412 default:
413 current_op = 0x00;
414 break;
415 }
416 }
417}
Note: See TracBrowser for help on using the repository browser.