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"
11 
12 typedef struct m24_t
13 {
14         mem_mapping_t mapping;
15 
16         uint8_t crtc[32];
17         int crtcreg;
18 
19         uint8_t *vram;
20         uint8_t charbuffer[256];
21 
22         uint8_t  ctrl;
23         uint32_t base;
24 
25         uint8_t cgamode, cgacol;
26         uint8_t stat;
27 
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;
35 
36         int dispontime, dispofftime, vidtime;
37 
38         int firstline, lastline;
39 } m24_t;
40 
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 };
46 
47 void m24_recalctimings(m24_t *m24);
48 
49 
m24_out(uint16_t addr,uint8_t val,void * p)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 }
84 
m24_in(uint16_t addr,void * p)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 }
99 
m24_write(uint32_t addr,uint8_t val,void * p)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 }
107 
m24_read(uint32_t addr,void * p)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 }
113 
m24_recalctimings(m24_t * m24)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 }
135 
m24_poll(void * p)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         uint32_t 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                                         ((uint32_t *)buffer32->line[m24->displine])[c] = cgapal[0];
171                                         if (m24->cgamode & 1) ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = cgapal[0];
172                                         else                  ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = cgapal[0];
173                                 }
174                                 else
175                                 {
176                                         ((uint32_t *)buffer32->line[m24->displine])[c] = cgapal[m24->cgacol & 15];
177                                         if (m24->cgamode & 1) ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = cgapal[m24->cgacol & 15];
178                                         else                  ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = cgapal[m24->cgacol & 15];
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] = cgapal[attr & 15];
191                                                 cols[0] = cgapal[(attr >> 4) & 7];
192                                                 if ((m24->blink & 16) && (attr & 0x80) && !drawcursor)
193                                                         cols[1] = cols[0];
194                                         }
195                                         else
196                                         {
197                                                 cols[1] = cgapal[attr & 15];
198                                                 cols[0] = cgapal[attr >> 4];
199                                         }
200                                         if (drawcursor)
201                                         {
202                                                 for (c = 0; c < 8; c++)
203                                                     ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff;
204                                         }
205                                         else
206                                         {
207                                                 for (c = 0; c < 8; c++)
208                                                     ((uint32_t *)buffer32->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] = cgapal[attr & 15];
223                                                 cols[0] = cgapal[(attr >> 4) & 7];
224                                                 if ((m24->blink & 16) && (attr & 0x80))
225                                                         cols[1] = cols[0];
226                                         }
227                                         else
228                                         {
229                                                 cols[1] = cgapal[attr & 15];
230                                                 cols[0] = cgapal[attr >> 4];
231                                         }
232                                         m24->ma++;
233                                         if (drawcursor)
234                                         {
235                                                 for (c = 0; c < 8; c++)
236                                                     ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] =
237                                                     ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff;
238                                         }
239                                         else
240                                         {
241                                                 for (c = 0; c < 8; c++)
242                                                     ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] =
243                                                     ((uint32_t *)buffer32->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] = cgapal[m24->cgacol & 15];
250                                 col = (m24->cgacol & 16) ? 8 : 0;
251                                 if (m24->cgamode & 4)
252                                 {
253                                         cols[1] = cgapal[col | 3];
254                                         cols[2] = cgapal[col | 4];
255                                         cols[3] = cgapal[col | 7];
256                                 }
257                                 else if (m24->cgacol & 32)
258                                 {
259                                         cols[1] = cgapal[col | 3];
260                                         cols[2] = cgapal[col | 5];
261                                         cols[3] = cgapal[col | 7];
262                                 }
263                                 else
264                                 {
265                                         cols[1] = cgapal[col | 2];
266                                         cols[2] = cgapal[col | 4];
267                                         cols[3] = cgapal[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                                                 ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] =
277                                                 ((uint32_t *)buffer32->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] = cgapal[0];
288                                         cols[1] = cgapal[15];
289                                 }
290                                 else
291                                 {
292                                         dat2 = (m24->sc & 1) * 0x2000;
293                                         cols[0] = cgapal[0];
294                                         cols[1] = cgapal[m24->cgacol & 15];
295                                 }
296                                 for (x = 0; x < m24->crtc[1]; x++)
297                                 {
298                                         dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1];
299                                         m24->ma++;
300                                         for (c = 0; c < 16; c++)
301                                         {
302                                                 ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + c + 8] = cols[dat >> 15];
303                                                 dat <<= 1;
304                                         }
305                                 }
306                         }
307                 }
308                 else
309                 {
310                         cols[0] = cgapal[((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15)];
311                         if (m24->cgamode & 1) hline(buffer32, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]);
312                         else                  hline(buffer32, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]);
313                 }
314 
315                 if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16;
316                 else                  x = (m24->crtc[1] << 4) + 16;
317 
318                 m24->sc = oldsc;
319                 if (m24->vc == m24->crtc[7] && !m24->sc)
320                         m24->stat |= 8;
321                 m24->displine++;
322                 if (m24->displine >= 720) m24->displine = 0;
323         }
324         else
325         {
326 //                pclog("Line poll  %i %i %i %i\n", m24_lineff, vc, sc, vadj);
327                 m24->vidtime += m24->dispontime;
328                 if (m24->dispon) m24->stat &= ~1;
329                 m24->linepos = 0;
330                 m24->lineff ^= 1;
331                 if (m24->lineff)
332                 {
333                         m24->ma = m24->maback;
334                 }
335                 else
336                 {
337                         if (m24->vsynctime)
338                         {
339                                 m24->vsynctime--;
340                                 if (!m24->vsynctime)
341                                    m24->stat &= ~8;
342                         }
343                         if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1)))
344                         {
345                                 m24->con = 0;
346                                 m24->coff = 1;
347                         }
348                         if (m24->vadj)
349                         {
350                                 m24->sc++;
351                                 m24->sc &= 31;
352                                 m24->ma = m24->maback;
353                                 m24->vadj--;
354                                 if (!m24->vadj)
355                                 {
356                                         m24->dispon = 1;
357                                         m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff;
358                                         m24->sc = 0;
359                                 }
360                         }
361                         else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1)))
362                         {
363                                 m24->maback = m24->ma;
364                                 m24->sc = 0;
365                                 oldvc = m24->vc;
366                                 m24->vc++;
367                                 m24->vc &= 127;
368 
369                                 if (m24->vc == m24->crtc[6])
370                                         m24->dispon=0;
371 
372                                 if (oldvc == m24->crtc[4])
373                                 {
374                                         m24->vc = 0;
375                                         m24->vadj = m24->crtc[5];
376                                         if (!m24->vadj) m24->dispon = 1;
377                                         if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff;
378                                         if ((m24->crtc[10] & 0x60) == 0x20) m24->cursoron = 0;
379                                         else                                m24->cursoron = m24->blink & 16;
380                                 }
381 
382                                 if (m24->vc == m24->crtc[7])
383                                 {
384                                         m24->dispon = 0;
385                                         m24->displine = 0;
386                                         m24->vsynctime = (m24->crtc[3] >> 4) + 1;
387                                         if (m24->crtc[7])
388                                         {
389                                                 if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16;
390                                                 else                  x = (m24->crtc[1] << 4) + 16;
391                                                 m24->lastline++;
392                                                 if (x != xsize || (m24->lastline - m24->firstline) != ysize)
393                                                 {
394                                                         xsize = x;
395                                                         ysize = m24->lastline - m24->firstline;
396                                                         if (xsize < 64) xsize = 656;
397                                                         if (ysize < 32) ysize = 200;
398                                                         updatewindowsize(xsize, ysize + 16);
399                                                 }
400 
401                                                 video_blit_memtoscreen(0, m24->firstline - 8, 0, (m24->lastline - m24->firstline) + 16, xsize, (m24->lastline - m24->firstline) + 16);
402                                                 frames++;
403 
404                                                 video_res_x = xsize - 16;
405                                                 video_res_y = ysize;
406                                                 if (m24->cgamode & 1)
407                                                 {
408                                                         video_res_x /= 8;
409                                                         video_res_y /= (m24->crtc[9] + 1) * 2;
410                                                         video_bpp = 0;
411                                                 }
412                                                 else if (!(m24->cgamode & 2))
413                                                 {
414                                                         video_res_x /= 16;
415                                                         video_res_y /= (m24->crtc[9] + 1) * 2;
416                                                         video_bpp = 0;
417                                                 }
418                                                 else if (!(m24->cgamode & 16))
419                                                 {
420                                                         video_res_x /= 2;
421                                                         video_res_y /= 2;
422                                                         video_bpp = 2;
423                                                 }
424                                                 else if (!(m24->ctrl & 1))
425                                                 {
426                                                         video_res_y /= 2;
427                                                         video_bpp = 1;
428                                                 }
429                                         }
430                                         m24->firstline = 1000;
431                                         m24->lastline = 0;
432                                         m24->blink++;
433                                 }
434                         }
435                         else
436                         {
437                                 m24->sc++;
438                                 m24->sc &= 31;
439                                 m24->ma = m24->maback;
440                         }
441                         if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1))))
442                                 m24->con = 1;
443                 }
444                 if (m24->dispon && (m24->cgamode & 1))
445                 {
446                         for (x = 0; x < (m24->crtc[1] << 1); x++)
447                             m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base];
448                 }
449         }
450 }
451 
m24_init()452 void *m24_init()
453 {
454         m24_t *m24 = malloc(sizeof(m24_t));
455         memset(m24, 0, sizeof(m24_t));
456 
457         m24->vram = malloc(0x8000);
458 
459         timer_add(m24_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24);
460         mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL,  NULL, 0, m24);
461         io_sethandler(0x03d0, 0x0010, m24_in, NULL, NULL, m24_out, NULL, NULL, m24);
462         return m24;
463 }
464 
m24_close(void * p)465 void m24_close(void *p)
466 {
467         m24_t *m24 = (m24_t *)p;
468 
469         free(m24->vram);
470         free(m24);
471 }
472 
m24_speed_changed(void * p)473 void m24_speed_changed(void *p)
474 {
475         m24_t *m24 = (m24_t *)p;
476 
477         m24_recalctimings(m24);
478 }
479 
480 device_t m24_device =
481 {
482         "Olivetti M24 (video)",
483         0,
484         m24_init,
485         m24_close,
486         NULL,
487         m24_speed_changed,
488         NULL,
489         NULL
490 };
491