PCem
view src/vid_olivetti_m24.c @ 154:d0d530adce12
Initial port to Linux (using Allegro).
64-bit fixes.
Some changes to aid portability.
A few other tweaks.
| author | TomW |
|---|---|
| date | Thu Sep 04 21:07:24 2014 +0100 |
| parents | b53e148867e5 |
| children |
line source
1 /*Olivetti M24 video emulation
2 Essentially double-res CGA*/
3 #include <stdlib.h>
4 #include "ibm.h"
5 #include "device.h"
6 #include "io.h"
7 #include "mem.h"
8 #include "timer.h"
9 #include "video.h"
10 #include "vid_olivetti_m24.h"
12 typedef struct m24_t
13 {
14 mem_mapping_t mapping;
16 uint8_t crtc[32];
17 int crtcreg;
19 uint8_t *vram;
20 uint8_t charbuffer[256];
22 uint8_t ctrl;
23 uint32_t base;
25 uint8_t cgamode, cgacol;
26 uint8_t stat;
28 int linepos, displine;
29 int sc, vc;
30 int con, coff, cursoron, blink;
31 int vsynctime, vadj;
32 int lineff;
33 uint16_t ma, maback;
34 int dispon;
36 int dispontime, dispofftime, vidtime;
38 int firstline, lastline;
39 } m24_t;
41 static uint8_t crtcmask[32] =
42 {
43 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff,
44 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
45 };
47 void m24_recalctimings(m24_t *m24);
50 void m24_out(uint16_t addr, uint8_t val, void *p)
51 {
52 m24_t *m24 = (m24_t *)p;
53 uint8_t old;
54 // pclog("m24_out %04X %02X\n", addr, val);
55 switch (addr)
56 {
57 case 0x3d4:
58 m24->crtcreg = val & 31;
59 return;
60 case 0x3d5:
61 old = m24->crtc[m24->crtcreg];
62 m24->crtc[m24->crtcreg] = val & crtcmask[m24->crtcreg];
63 if (old != val)
64 {
65 if (m24->crtcreg < 0xe || m24->crtcreg > 0x10)
66 {
67 fullchange = changeframecount;
68 m24_recalctimings(m24);
69 }
70 }
71 return;
72 case 0x3d8:
73 m24->cgamode = val;
74 return;
75 case 0x3d9:
76 m24->cgacol = val;
77 return;
78 case 0x3de:
79 m24->ctrl = val;
80 m24->base = (val & 0x08) ? 0x4000 : 0;
81 return;
82 }
83 }
85 uint8_t m24_in(uint16_t addr, void *p)
86 {
87 m24_t *m24 = (m24_t *)p;
88 switch (addr)
89 {
90 case 0x3d4:
91 return m24->crtcreg;
92 case 0x3d5:
93 return m24->crtc[m24->crtcreg];
94 case 0x3da:
95 return m24->stat;
96 }
97 return 0xff;
98 }
100 void m24_write(uint32_t addr, uint8_t val, void *p)
101 {
102 m24_t *m24 = (m24_t *)p;
103 m24->vram[addr & 0x7FFF]=val;
104 m24->charbuffer[ ((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val;
105 m24->charbuffer[(((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val;
106 }
108 uint8_t m24_read(uint32_t addr, void *p)
109 {
110 m24_t *m24 = (m24_t *)p;
111 return m24->vram[addr & 0x7FFF];
112 }
114 void m24_recalctimings(m24_t *m24)
115 {
116 double _dispontime, _dispofftime, disptime;
117 if (m24->cgamode & 1)
118 {
119 disptime = m24->crtc[0] + 1;
120 _dispontime = m24->crtc[1];
121 }
122 else
123 {
124 disptime = (m24->crtc[0] + 1) << 1;
125 _dispontime = m24->crtc[1] << 1;
126 }
127 _dispofftime = disptime - _dispontime;
128 // printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]);
129 _dispontime *= CGACONST / 2;
130 _dispofftime *= CGACONST / 2;
131 // printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92);
132 m24->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
133 m24->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
134 }
136 void m24_poll(void *p)
137 {
138 m24_t *m24 = (m24_t *)p;
139 uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff;
140 int drawcursor;
141 int x, c;
142 int oldvc;
143 uint8_t chr, attr;
144 uint16_t dat, dat2;
145 int cols[4];
146 int col;
147 int oldsc;
148 if (!m24->linepos)
149 {
150 // pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine);
151 m24->vidtime += m24->dispofftime;
152 m24->stat |= 1;
153 m24->linepos = 1;
154 oldsc = m24->sc;
155 if ((m24->crtc[8] & 3) == 3)
156 m24->sc = (m24->sc << 1) & 7;
157 if (m24->dispon)
158 {
159 pclog("dispon %i\n", m24->linepos);
160 if (m24->displine < m24->firstline)
161 {
162 m24->firstline = m24->displine;
163 // printf("Firstline %i\n",firstline);
164 }
165 m24->lastline = m24->displine;
166 for (c = 0; c < 8; c++)
167 {
168 if ((m24->cgamode & 0x12) == 0x12)
169 {
170 buffer->line[m24->displine][c] = 0;
171 if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0;
172 else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = 0;
173 }
174 else
175 {
176 buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16;
177 if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16;
178 else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16;
179 }
180 }
181 if (m24->cgamode & 1)
182 {
183 for (x = 0; x < m24->crtc[1]; x++)
184 {
185 chr = m24->charbuffer[ x << 1];
186 attr = m24->charbuffer[(x << 1) + 1];
187 drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron);
188 if (m24->cgamode & 0x20)
189 {
190 cols[1] = (attr & 15) + 16;
191 cols[0] = ((attr >> 4) & 7) + 16;
192 if ((m24->blink & 16) && (attr & 0x80) && !drawcursor)
193 cols[1] = cols[0];
194 }
195 else
196 {
197 cols[1] = (attr & 15) + 16;
198 cols[0] = (attr >> 4) + 16;
199 }
200 if (drawcursor)
201 {
202 for (c = 0; c < 8; c++)
203 buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
204 }
205 else
206 {
207 for (c = 0; c < 8; c++)
208 buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0];
209 }
210 m24->ma++;
211 }
212 }
213 else if (!(m24->cgamode & 2))
214 {
215 for (x = 0; x < m24->crtc[1]; x++)
216 {
217 chr = m24->vram[((m24->ma << 1) & 0x3fff) + m24->base];
218 attr = m24->vram[(((m24->ma << 1) + 1) & 0x3fff) + m24->base];
219 drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron);
220 if (m24->cgamode & 0x20)
221 {
222 cols[1] = (attr & 15) + 16;
223 cols[0] = ((attr >> 4) & 7) + 16;
224 if ((m24->blink & 16) && (attr & 0x80))
225 cols[1] = cols[0];
226 }
227 else
228 {
229 cols[1] = (attr & 15) + 16;
230 cols[0] = (attr >> 4) + 16;
231 }
232 m24->ma++;
233 if (drawcursor)
234 {
235 for (c = 0; c < 8; c++)
236 buffer->line[m24->displine][(x << 4) + (c << 1) + 8] =
237 buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15;
238 }
239 else
240 {
241 for (c = 0; c < 8; c++)
242 buffer->line[m24->displine][(x << 4) + (c << 1) + 8] =
243 buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0];
244 }
245 }
246 }
247 else if (!(m24->cgamode & 16))
248 {
249 cols[0] = (m24->cgacol & 15) | 16;
250 col = (m24->cgacol & 16) ? 24 : 16;
251 if (m24->cgamode & 4)
252 {
253 cols[1] = col | 3;
254 cols[2] = col | 4;
255 cols[3] = col | 7;
256 }
257 else if (m24->cgacol & 32)
258 {
259 cols[1] = col | 3;
260 cols[2] = col | 5;
261 cols[3] = col | 7;
262 }
263 else
264 {
265 cols[1] = col | 2;
266 cols[2] = col | 4;
267 cols[3] = col | 6;
268 }
269 for (x = 0; x < m24->crtc[1]; x++)
270 {
271 dat = (m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + m24->base] << 8) |
272 m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base];
273 m24->ma++;
274 for (c = 0; c < 8; c++)
275 {
276 buffer->line[m24->displine][(x << 4) + (c << 1) + 8] =
277 buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14];
278 dat <<= 2;
279 }
280 }
281 }
282 else
283 {
284 if (m24->ctrl & 1)
285 {
286 dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000);
287 cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16;
288 }
289 else
290 {
291 dat2 = (m24->sc & 1) * 0x2000;
292 cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16;
293 }
294 for (x = 0; x < m24->crtc[1]; x++)
295 {
296 dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1];
297 m24->ma++;
298 for (c = 0; c < 16; c++)
299 {
300 buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15];
301 dat <<= 1;
302 }
303 }
304 }
305 }
306 else
307 {
308 cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16;
309 if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]);
310 else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]);
311 }
313 if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16;
314 else x = (m24->crtc[1] << 4) + 16;
316 m24->sc = oldsc;
317 if (m24->vc == m24->crtc[7] && !m24->sc)
318 m24->stat |= 8;
319 m24->displine++;
320 if (m24->displine >= 720) m24->displine = 0;
321 }
322 else
323 {
324 // pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj);
325 m24->vidtime += m24->dispontime;
326 if (m24->dispon) m24->stat &= ~1;
327 m24->linepos = 0;
328 m24->lineff ^= 1;
329 if (m24->lineff)
330 {
331 m24->ma = m24->maback;
332 }
333 else
334 {
335 if (m24->vsynctime)
336 {
337 m24->vsynctime--;
338 if (!m24->vsynctime)
339 m24->stat &= ~8;
340 }
341 if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1)))
342 {
343 m24->con = 0;
344 m24->coff = 1;
345 }
346 if (m24->vadj)
347 {
348 m24->sc++;
349 m24->sc &= 31;
350 m24->ma = m24->maback;
351 m24->vadj--;
352 if (!m24->vadj)
353 {
354 m24->dispon = 1;
355 m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff;
356 m24->sc = 0;
357 }
358 }
359 else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1)))
360 {
361 m24->maback = m24->ma;
362 m24->sc = 0;
363 oldvc = m24->vc;
364 m24->vc++;
365 m24->vc &= 127;
367 if (m24->vc == m24->crtc[6])
368 m24->dispon=0;
370 if (oldvc == m24->crtc[4])
371 {
372 m24->vc = 0;
373 m24->vadj = m24->crtc[5];
374 if (!m24->vadj) m24->dispon = 1;
375 if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff;
376 if ((m24->crtc[10] & 0x60) == 0x20) m24->cursoron = 0;
377 else m24->cursoron = m24->blink & 16;
378 }
380 if (m24->vc == m24->crtc[7])
381 {
382 m24->dispon = 0;
383 m24->displine = 0;
384 m24->vsynctime = (m24->crtc[3] >> 4) + 1;
385 if (m24->crtc[7])
386 {
387 if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16;
388 else x = (m24->crtc[1] << 4) + 16;
389 m24->lastline++;
390 if (x != xsize || (m24->lastline - m24->firstline) != ysize)
391 {
392 xsize = x;
393 ysize = m24->lastline - m24->firstline;
394 if (xsize < 64) xsize = 656;
395 if (ysize < 32) ysize = 200;
396 updatewindowsize(xsize, ysize + 16);
397 }
398 startblit();
399 video_blit_memtoscreen_8(0, m24->firstline - 8, xsize, (m24->lastline - m24->firstline) + 16);
400 frames++;
401 endblit();
402 video_res_x = xsize - 16;
403 video_res_y = ysize;
404 if (m24->cgamode & 1)
405 {
406 video_res_x /= 8;
407 video_res_y /= (m24->crtc[9] + 1) * 2;
408 video_bpp = 0;
409 }
410 else if (!(m24->cgamode & 2))
411 {
412 video_res_x /= 16;
413 video_res_y /= (m24->crtc[9] + 1) * 2;
414 video_bpp = 0;
415 }
416 else if (!(m24->cgamode & 16))
417 {
418 video_res_x /= 2;
419 video_res_y /= 2;
420 video_bpp = 2;
421 }
422 else if (!(m24->ctrl & 1))
423 {
424 video_res_y /= 2;
425 video_bpp = 1;
426 }
427 }
428 m24->firstline = 1000;
429 m24->lastline = 0;
430 m24->blink++;
431 }
432 }
433 else
434 {
435 m24->sc++;
436 m24->sc &= 31;
437 m24->ma = m24->maback;
438 }
439 if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1))))
440 m24->con = 1;
441 }
442 if (m24->dispon && (m24->cgamode & 1))
443 {
444 for (x = 0; x < (m24->crtc[1] << 1); x++)
445 m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base];
446 }
447 }
448 }
450 void *m24_init()
451 {
452 int c;
453 m24_t *m24 = malloc(sizeof(m24_t));
454 memset(m24, 0, sizeof(m24_t));
456 m24->vram = malloc(0x8000);
458 timer_add(m24_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24);
459 mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL, NULL, 0, m24);
460 io_sethandler(0x03d0, 0x0010, m24_in, NULL, NULL, m24_out, NULL, NULL, m24);
461 return m24;
462 }
464 void m24_close(void *p)
465 {
466 m24_t *m24 = (m24_t *)p;
468 free(m24->vram);
469 free(m24);
470 }
472 void m24_speed_changed(void *p)
473 {
474 m24_t *m24 = (m24_t *)p;
476 m24_recalctimings(m24);
477 }
479 device_t m24_device =
480 {
481 "Olivetti M24 (video)",
482 0,
483 m24_init,
484 m24_close,
485 NULL,
486 m24_speed_changed,
487 NULL,
488 NULL
489 };
