OSDN Git Service

[VM][STATE] Apply new framework to some VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / upd7220_base.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : Neko Project 2
5         Author : Takeda.Toshiya
6         Date   : 2006.12.06 -
7
8         [ uPD7220 ]
9 */
10
11 #include <math.h>
12 #include "upd7220.h"
13 #include "../fifo.h"
14 // -> See also: upd7220_base.cpp .
15
16 #define EVENT_HSYNC_HFP 0
17 #define EVENT_HSYNC_HS  1
18 #define EVENT_HSYNC_HBP 2
19
20 enum {
21         STAT_DRDY       = 0x01,
22         STAT_FULL       = 0x02,
23         STAT_EMPTY      = 0x04,
24         STAT_DRAW       = 0x08,
25         STAT_DMA        = 0x10,
26         STAT_VSYNC      = 0x20,
27         STAT_BLANK      = 0x40,
28         STAT_LPEN       = 0x80,
29 };
30
31
32 void UPD7220_BASE::initialize()
33 {
34         DEVICE::initialize();
35         for(int i = 0; i <= RT_TABLEMAX; i++) {
36                 rt[i] = (int)((double)(1 << RT_MULBIT) * (1 - sqrt(1 - pow((0.70710678118654 * i) / RT_TABLEMAX, 2))));
37         }
38         fo = new FIFO(0x10000);
39         
40         vsync = vblank = false;
41         hsync = hblank = false;
42         master = false;
43         pitch = 40;     // 640dot
44         
45         // -> upd7220.cpp
46 }
47
48 void UPD7220_BASE::release()
49 {
50         fo->release();
51         delete fo;
52 }
53
54 void UPD7220_BASE::reset()
55 {
56         cmd_reset();
57 }
58
59 void UPD7220_BASE::write_dma_io8(uint32_t addr, uint32_t data)
60 {
61         // for dma access
62         switch(cmdreg & 0x18) {
63         case 0x00: // low and high
64                 if(low_high) {
65                         cmd_write_sub(ead * 2 + 1, data & maskh);
66                         ead += dif;
67                 } else {
68                         cmd_write_sub(ead * 2 + 0, data & maskl);
69                 }
70                 low_high = !low_high;
71                 break;
72         case 0x10: // low byte
73                 cmd_write_sub(ead * 2 + 0, data & maskl);
74                 ead += dif;
75                 break;
76         case 0x18: // high byte
77                 cmd_write_sub(ead * 2 + 1, data & maskh);
78                 ead += dif;
79                 break;
80         }
81 }
82
83 uint32_t UPD7220_BASE::read_dma_io8(uint32_t addr)
84 {
85         uint32_t val = 0xff;
86         
87         // for dma access
88         switch(cmdreg & 0x18) {
89         case 0x00: // low and high
90                 if(low_high) {
91                         val = read_vram(ead * 2 + 1);
92                         ead += dif;
93                 } else {
94                         val = read_vram(ead * 2 + 0);
95                 }
96                 low_high = !low_high;
97                 break;
98         case 0x10: // low byte
99                 val =  read_vram(ead * 2 + 0);
100                 ead += dif;
101                 break;
102         case 0x18: // high byte
103                 val =  read_vram(ead * 2 + 1);
104                 ead += dif;
105                 break;
106         }
107         return val;
108 }
109
110 void UPD7220_BASE::write_io8(uint32_t addr, uint32_t data)
111 {
112         // Dummy function
113 }
114
115 uint32_t UPD7220_BASE::read_io8(uint32_t addr)
116 {
117         uint32_t val;
118         
119         switch(addr & 3) {
120         case 0: // status
121                 val = statreg;
122                 if(sync[5] & 0x80) {
123                         val |= vblank ? STAT_BLANK : 0;
124                 } else {
125                         val |= hblank ? STAT_BLANK : 0;
126                 }
127                 val |= vsync ? STAT_VSYNC : 0;
128 //              val |= (params_count == 0) ? STAT_EMPTY : 0;
129                 val |= STAT_EMPTY;
130                 val |= (params_count == 16) ? STAT_FULL : 0;
131                 val |= fo->count() ? STAT_DRDY : 0;
132                 // clear busy stat
133                 statreg &= ~(STAT_DMA | STAT_DRAW);
134                 return val;
135         case 1: // data
136                 if(fo->count()) {
137                         return fo->read();
138                 }
139                 return 0xff;
140         }
141         return 0xff;
142 }
143
144 void UPD7220_BASE::event_pre_frame()
145 {
146         // Dummy func.
147 }
148
149 void UPD7220_BASE::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
150 {
151         cpu_clocks = new_clocks;
152         frames_per_sec = new_frames_per_sec;    // note: refer these params given from the event manager
153         lines_per_frame = new_lines_per_frame;  // because this device may be slave gdc
154         
155         // update event clocks
156         vs = hs = 0;
157 }
158
159 void UPD7220_BASE::event_frame()
160 {
161         if(vs == 0) {
162                 vfp = (int)((double)lines_per_frame * (double)(v1          ) / (double)(v1 + v2 + v3 + v4) + 0.5);
163                 vs  = (int)((double)lines_per_frame * (double)(v1 + v2     ) / (double)(v1 + v2 + v3 + v4) + 0.5);
164                 vbp = (int)((double)lines_per_frame * (double)(v1 + v2 + v3) / (double)(v1 + v2 + v3 + v4) + 0.5);
165                 hfp = (int)((double)cpu_clocks * (double)(h1          ) / frames_per_sec / (double)lines_per_frame / (double)(h1 + h2 + h3 + h4) + 0.5);
166                 hs  = (int)((double)cpu_clocks * (double)(h1 + h2     ) / frames_per_sec / (double)lines_per_frame / (double)(h1 + h2 + h3 + h4) + 0.5);
167                 hbp = (int)((double)cpu_clocks * (double)(h1 + h2 + h3) / frames_per_sec / (double)lines_per_frame / (double)(h1 + h2 + h3 + h4) + 0.5);
168         }
169         if(++blink_cursor >= blink_rate * 4) {
170                 blink_cursor = 0;
171         }
172         if(++blink_attr >= blink_rate * 2) {
173                 blink_attr = 0;
174         }
175 }
176
177 void UPD7220_BASE::event_vline(int v, int clock)
178 {
179         if(v == 0) {
180                 vblank = true;
181         } else if(v == vfp) {
182                 write_signals(&outputs_vsync, 0xffffffff);
183                 vsync = true;
184         } else if(v == vs) {
185                 write_signals(&outputs_vsync, 0);
186                 vsync = false;
187         } else if(v == vbp) {
188                 vblank = false;
189         }
190         hblank = true;
191         register_event_by_clock(this, EVENT_HSYNC_HFP, hfp, false, NULL);
192         register_event_by_clock(this, EVENT_HSYNC_HS,  hs,  false, NULL);
193         register_event_by_clock(this, EVENT_HSYNC_HBP, hbp, false, NULL);
194 }
195
196 void UPD7220_BASE::event_callback(int event_id, int err)
197 {
198         if(event_id == EVENT_HSYNC_HFP) {
199                 hsync = true;
200         } else if(event_id == EVENT_HSYNC_HS) {
201                 hsync = false;
202         } else if(event_id == EVENT_HSYNC_HBP) {
203                 hblank = false;
204         }
205 }
206
207 uint32_t UPD7220_BASE::cursor_addr(uint32_t mask)
208 {
209         if((cs[0] & 0x80) && ((cs[1] & 0x20) || (blink_cursor < blink_rate * 2))) {
210                 return (ead << 1) & mask;
211         }
212         return -1;
213 }
214
215 int UPD7220_BASE::cursor_top()
216 {
217         return cs[1] & 0x1f;
218 }
219
220 int UPD7220_BASE::cursor_bottom()
221 {
222         return cs[2] >> 3;
223 }
224
225 // command process
226
227 void UPD7220_BASE::cmd_reset()
228 {
229         // init gdc params
230         sync[6] = 0x90;
231         sync[7] = 0x01;
232         zoom = zr = zw = 0;
233         ra[0] = ra[1] = ra[2] = 0;
234         ra[3] = 0x1e; /*0x19;*/
235         cs[0] = cs[1] = cs[2] = 0;
236         ead = dad = 0;
237         maskl = maskh = 0xff;
238         mod = 0;
239         blink_cursor = 0;
240         blink_attr = 0;
241         blink_rate = 16;
242         
243         // init fifo
244         params_count = 0;
245         fo->clear();
246         
247         // stop display and drawing
248         start = false;
249         statreg = 0;
250         cmdreg = -1;
251         cmd_write_done = false;
252 }
253
254 void UPD7220_BASE::cmd_sync()
255 {
256         start = ((cmdreg & 1) != 0);
257         for(int i = 0; i < 8 && i < params_count; i++) {
258                 if(sync[i] != params[i]) {
259                         sync[i] = params[i];
260                         sync_changed = true;
261                 }
262         }
263         cmdreg = -1;
264 }
265
266 void UPD7220_BASE::cmd_master()
267 {
268         master = true;
269         cmdreg = -1;
270 }
271
272 void UPD7220_BASE::cmd_slave()
273 {
274         master = false;
275         cmdreg = -1;
276 }
277
278 void UPD7220_BASE::cmd_start()
279 {
280         start = true;
281         cmdreg = -1;
282 }
283
284 void UPD7220_BASE::cmd_stop()
285 {
286         start = false;
287         cmdreg = -1;
288 }
289
290 void UPD7220_BASE::cmd_zoom()
291 {
292         if(params_count > 0) {
293                 uint8_t tmp = params[0];
294                 zr = tmp >> 4;
295                 zw = tmp & 0x0f;
296                 cmdreg = -1;
297         }
298 }
299
300 void UPD7220_BASE::cmd_scroll()
301 {
302         if(params_count > 0) {
303                 ra[cmdreg & 0x0f] = params[0];
304                 if(cmdreg < 0x7f) {
305                         cmdreg++;
306                         params_count = 0;
307                 } else {
308                         cmdreg = -1;
309                 }
310         }
311 }
312
313 void UPD7220_BASE::cmd_csrform()
314 {
315         for(int i = 0; i < params_count; i++) {
316                 cs[i] = params[i];
317         }
318         if(params_count > 2) {
319                 cmdreg = -1;
320         }
321         blink_rate = (cs[1] >> 6) | ((cs[2] & 7) << 2);
322 }
323
324 void UPD7220_BASE::cmd_lpen()
325 {
326         fo->write(lad & 0xff);
327         fo->write((lad >> 8) & 0xff);
328         fo->write((lad >> 16) & 0xff);
329         cmdreg = -1;
330 }
331
332 void UPD7220_BASE::cmd_vectw()
333 {
334         for(int i = 0; i < 11 && i < params_count; i++) {
335                 vect[i] = params[i];
336 //              this->out_debug_log(_T("\tVECT[%d] = %2x\n"), i, vect[i]);
337         }
338         update_vect();
339         cmdreg = -1;
340 }
341
342
343 void UPD7220_BASE::cmd_csrw()
344 {
345         if(params_count > 0) {
346                 ead = params[0];
347                 if(params_count > 1) {
348                         ead |= params[1] << 8;
349                         if(params_count > 2) {
350                                 ead |= params[2] << 16;
351                                 cmdreg = -1;
352                         }
353                 }
354                 dad = (ead >> 20) & 0x0f;
355                 ead &= 0x3ffff;
356         }
357 }
358
359 void UPD7220_BASE::cmd_csrr()
360 {
361         fo->write(ead & 0xff);
362         fo->write((ead >> 8) & 0xff);
363         fo->write((ead >> 16) & 0x03);
364         fo->write(dad & 0xff);
365         fo->write((dad >> 8) & 0xff);
366         cmdreg = -1;
367 }
368
369 void UPD7220_BASE::cmd_mask()
370 {
371         if(params_count > 1) {
372                 maskl = params[0];
373                 maskh = params[1];
374                 cmdreg = -1;
375         }
376 }
377
378 void UPD7220_BASE::cmd_write()
379 {
380         mod = cmdreg & 3;
381         switch(cmdreg & 0x18) {
382         case 0x00: // low and high
383                 if(params_count > 1) {
384                         uint8_t l = params[0] & maskl;
385                         uint8_t h = params[1] & maskh;
386                         for(int i = 0; i < dc + 1; i++) {
387                                 cmd_write_sub(ead * 2 + 0, l);
388                                 cmd_write_sub(ead * 2 + 1, h);
389                                 ead += dif;
390                         }
391                         cmd_write_done = true;
392                         params_count = 0;
393                 }
394                 break;
395         case 0x10: // low byte
396                 if(params_count > 0) {
397                         uint8_t l = params[0] & maskl;
398                         for(int i = 0; i < dc + 1; i++) {
399                                 cmd_write_sub(ead * 2 + 0, l);
400                                 ead += dif;
401                         }
402                         cmd_write_done = true;
403                         params_count = 0;
404                 }
405                 break;
406         case 0x18: // high byte
407                 if(params_count > 0) {
408                         uint8_t h = params[0] & maskh;
409                         for(int i = 0; i < dc + 1; i++) {
410                                 cmd_write_sub(ead * 2 + 1, h);
411                                 ead += dif;
412                         }
413                         cmd_write_done = true;
414                         params_count = 0;
415                 }
416                 break;
417         default: // invalid
418                 cmdreg = -1;
419                 break;
420         }
421 }
422
423 void UPD7220_BASE::cmd_read()
424 {
425         mod = cmdreg & 3;
426         switch(cmdreg & 0x18) {
427         case 0x00: // low and high
428                 for(int i = 0; i < dc; i++) {
429                         fo->write(read_vram(ead * 2 + 0));
430                         fo->write(read_vram(ead * 2 + 1));
431                         ead += dif;
432                 }
433                 break;
434         case 0x10: // low byte
435                 for(int i = 0; i < dc; i++) {
436                         fo->write(read_vram(ead * 2 + 0));
437                         ead += dif;
438                 }
439                 break;
440         case 0x18: // high byte
441                 for(int i = 0; i < dc; i++) {
442                         fo->write(read_vram(ead * 2 + 1));
443                         ead += dif;
444                 }
445                 break;
446         default: // invalid
447                 break;
448         }
449         reset_vect();
450         cmdreg = -1;
451 }
452
453 void UPD7220_BASE::cmd_dmaw()
454 {
455         mod = cmdreg & 3;
456         low_high = false;
457         write_signals(&outputs_drq, 0xffffffff);
458         reset_vect();
459 //      statreg |= STAT_DMA;
460         cmdreg = -1;
461 }
462
463 void UPD7220_BASE::cmd_dmar()
464 {
465         mod = cmdreg & 3;
466         low_high = false;
467         write_signals(&outputs_drq, 0xffffffff);
468         reset_vect();
469 //      statreg |= STAT_DMA;
470         cmdreg = -1;
471 }
472
473 void UPD7220_BASE::cmd_unk_5a()
474 {
475         if(params_count > 2) {
476                 cmdreg = -1;
477         }
478 }
479
480 // command sub
481
482 void UPD7220_BASE::cmd_write_sub(uint32_t addr, uint8_t data)
483 {
484         switch(mod) {
485         case 0: // replace
486                 write_vram(addr, data);
487                 break;
488         case 1: // complement
489                 write_vram(addr, read_vram(addr) ^ data);
490                 break;
491         case 2: // reset
492                 write_vram(addr, read_vram(addr) & ~data);
493                 break;
494         case 3: // set
495                 write_vram(addr, read_vram(addr) | data);
496                 break;
497         }
498 }
499
500 void UPD7220_BASE::write_vram(uint32_t addr, uint8_t data)
501 {
502         if(addr < vram_size) {
503                 if(vram != NULL) {
504                         vram[addr] = data;
505                 } else if(d_vram_bus != NULL) {
506                         d_vram_bus->write_dma_io8(addr, data);
507                 }
508         }
509 }
510
511 uint8_t UPD7220_BASE::read_vram(uint32_t addr)
512 {
513         if(addr < vram_size) {
514                 uint8_t mask = (addr & 1) ? (vram_data_mask >> 8) : (vram_data_mask & 0xff);
515                 if(vram != NULL) {
516                         return (vram[addr] & mask) | ~mask;
517                 } else if(d_vram_bus != NULL) {
518                         return (d_vram_bus->read_dma_io8(addr) & mask) | ~mask;
519                 }
520         }
521         return 0xff;
522 }
523
524 void UPD7220_BASE::update_vect()
525 {
526         dir = vect[0] & 7;
527         dif = vectdir[dir][0] + vectdir[dir][1] * pitch;
528         sl = vect[0] & 0x80;
529         dc = (vect[1] | (vect[ 2] << 8)) & 0x3fff;
530         d  = (vect[3] | (vect[ 4] << 8)) & 0x3fff;
531         d2 = (vect[5] | (vect[ 6] << 8)) & 0x3fff;
532         d1 = (vect[7] | (vect[ 8] << 8)) & 0x3fff;
533         dm = (vect[9] | (vect[10] << 8)) & 0x3fff;
534 }
535
536 void UPD7220_BASE::reset_vect()
537 {
538         vect[ 1] = 0x00;
539         vect[ 2] = 0x00;
540         vect[ 3] = 0x08;
541         vect[ 4] = 0x00;
542         vect[ 5] = 0x08;
543         vect[ 6] = 0x00;
544         vect[ 7] = 0x00;
545         vect[ 8] = 0x00;
546         vect[ 9] = 0x00;
547         vect[10] = 0x00;
548         update_vect();
549 }
550
551
552