OSDN Git Service

[VM][General][WIP] Start to merge upstream 2018-10-14.Open branch upstream_20181014 .
[csp-qt/common_source_project-fm7.git] / source / src / vm / x1 / iobus.cpp
1 /*
2         SHARP X1 Emulator 'eX1'
3         SHARP X1twin Emulator 'eX1twin'
4         SHARP X1turbo Emulator 'eX1turbo'
5         SHARP X1turboZ Emulator 'eX1turboZ'
6
7         Author : Takeda.Toshiya
8         Date   : 2009.03.14-
9
10         [ 8bit i/o bus ]
11 */
12
13 #include "iobus.h"
14 #include "io_wait.h"
15 #ifdef _X1TURBO_FEATURE
16 #include "io_wait_hireso.h"
17 #endif
18 #include "display.h"
19
20 namespace X1 {
21
22 #ifdef _X1TURBOZ
23 #define AEN     ((zmode1 & 0x80) != 0)
24 #define APEN    ((zmode2 & 0x80) != 0)
25 #define APRD    ((zmode2 & 0x08) != 0)
26 #endif
27
28 void IOBUS::initialize()
29 {
30         prev_clock = vram_wait_index = 0;
31         column40 = true;
32 }
33
34 void IOBUS::reset()
35 {
36         memset(vram, 0, sizeof(vram));
37         vram_b = vram + 0x0000;
38         vram_r = vram + 0x4000;
39         vram_g = vram + 0x8000;
40         vram_mode = signal = false;
41         vdisp = 0;
42 #ifdef _X1TURBO_FEATURE
43         memset(crtc_regs, 0, sizeof(crtc_regs));
44         crtc_ch = 0;
45         hireso = true;
46 #endif
47 }
48
49 void IOBUS::write_signal(int id, uint32_t data, uint32_t mask)
50 {
51         // H -> L
52         bool next = ((data & 0x20) != 0);
53         if(signal && !next) {
54                 vram_mode = true;
55         }
56         signal = next;
57         column40 = ((data & 0x40) != 0);
58 }
59
60 void IOBUS::write_io8w(uint32_t addr, uint32_t data, int* wait)
61 {
62         write_port8(addr, data, false, wait);
63 }
64
65 uint32_t IOBUS::read_io8w(uint32_t addr, int* wait)
66 {
67         return read_port8(addr, false, wait);
68 }
69
70 void IOBUS::write_dma_io8w(uint32_t addr, uint32_t data, int* wait)
71 {
72         write_port8(addr, data, true, wait);
73 }
74
75 uint32_t IOBUS::read_dma_io8w(uint32_t addr, int* wait)
76 {
77         return read_port8(addr, true, wait);
78 }
79
80 void IOBUS::write_port8(uint32_t addr, uint32_t data, bool is_dma, int* wait)
81 {
82         // vram access
83         switch(addr & 0xc000) {
84         case 0x0000:
85                 if(vram_mode) {
86                         vram_b[addr & 0x3fff] = data;
87                         vram_r[addr & 0x3fff] = data;
88                         vram_g[addr & 0x3fff] = data;
89                         *wait = get_vram_wait();
90                         return;
91                 }
92                 break;
93         case 0x4000:
94                 if(vram_mode) {
95                         vram_r[addr & 0x3fff] = data;
96                         vram_g[addr & 0x3fff] = data;
97                 } else {
98                         vram_b[addr & 0x3fff] = data;
99                 }
100                 *wait = get_vram_wait();
101                 return;
102         case 0x8000:
103                 if(vram_mode) {
104                         vram_b[addr & 0x3fff] = data;
105                         vram_g[addr & 0x3fff] = data;
106                 } else {
107                         vram_r[addr & 0x3fff] = data;
108                 }
109                 *wait = get_vram_wait();
110                 return;
111         case 0xc000:
112                 if(vram_mode) {
113                         vram_b[addr & 0x3fff] = data;
114                         vram_r[addr & 0x3fff] = data;
115                 } else {
116                         vram_g[addr & 0x3fff] = data;
117                 }
118                 *wait = get_vram_wait();
119                 return;
120         }
121 #ifdef _X1TURBO_FEATURE
122         if(addr == 0x1fd0) {
123                 int ofs = (data & 0x10) ? 0xc000 : 0;
124                 vram_b = vram + 0x0000 + ofs;
125                 vram_r = vram + 0x4000 + ofs;
126                 vram_g = vram + 0x8000 + ofs;
127         } else if((addr & 0xff0f) == 0x1800) {
128                 crtc_ch = data;
129         } else if((addr & 0xff0f) == 0x1801 && crtc_ch < 18) {
130                 crtc_regs[crtc_ch] = data;
131                 // update vram wait
132                 int ch_height = (crtc_regs[9] & 0x1f) + 1;
133                 int vt_total = ((crtc_regs[4] & 0x7f) + 1) * ch_height + (crtc_regs[5] & 0x1f);
134                 hireso = (vt_total > 400);
135 #ifdef _X1TURBOZ
136         } else if(addr == 0x1fb0) {
137                 zmode1 = data;
138         } else if(addr == 0x1fc5) {
139                 if(AEN) {
140                         zmode2 = data;
141                 }
142 #endif
143         }
144 #endif
145         if(is_dma) {
146                 d_io->write_dma_io8(addr, data & 0xff);
147         } else {
148                 d_io->write_io8(addr, data & 0xff);
149         }
150         switch(addr & 0xff00) {
151 #ifdef _X1TURBOZ
152         case 0x1000:    // analog palette
153         case 0x1100:
154         case 0x1200:
155                 if(AEN && APEN && !APRD) {
156 //              if(AEN) {
157                         *wait = get_vram_wait(); // temporary
158                 } else {
159                         *wait = 0;
160                 }
161                 break;
162 #endif
163         case 0x1900:    // sub cpu
164         case 0x1b00:    // psg
165         case 0x1c00:    // psg
166                 *wait = 1;
167                 break;
168         default:
169                 *wait = 0;
170                 break;
171         }
172 }
173
174 uint32_t IOBUS::read_port8(uint32_t addr, bool is_dma, int* wait)
175 {
176         // vram access
177         vram_mode = false;
178         switch(addr & 0xc000) {
179         case 0x4000:
180                 *wait = get_vram_wait();
181                 return vram_b[addr & 0x3fff];
182         case 0x8000:
183                 *wait = get_vram_wait();
184                 return vram_r[addr & 0x3fff];
185         case 0xc000:
186                 *wait = get_vram_wait();
187                 return vram_g[addr & 0x3fff];
188         }
189         uint32_t val = is_dma ? d_io->read_dma_io8(addr) : d_io->read_io8(addr);;
190         if((addr & 0xff0f) == 0x1a01) {
191                 // hack: cpu detects vblank
192                 if((vdisp & 0x80) && !(val & 0x80)) {
193                         d_display->write_signal(SIG_DISPLAY_DETECT_VBLANK, 1, 1);
194                 }
195                 vdisp = val;
196         }
197         switch(addr & 0xff00) {
198 #ifdef _X1TURBOZ
199         case 0x1000:    // analog palette
200         case 0x1100:
201         case 0x1200:
202                 if(AEN && APEN && APRD) {
203 //              if(AEN) {
204                         *wait = get_vram_wait(); // temporary
205                 } else {
206                         *wait = 0;
207                 }
208                 break;
209 #endif
210         case 0x1900:    // sub cpu
211         case 0x1b00:    // psg
212         case 0x1c00:    // psg
213                 *wait = 1;
214                 break;
215         default:
216                 *wait = 0;
217                 break;
218         }
219         return val & 0xff;
220 }
221
222 int IOBUS::get_vram_wait()
223 {
224         vram_wait_index += get_passed_clock(prev_clock);
225         vram_wait_index %= 2112;
226         prev_clock = get_current_clock();
227 #ifdef _X1TURBO_FEATURE
228         int tmp_index = (vram_wait_index + d_cpu->get_extra_clock()) % 2112; // consider dma access
229         if(hireso) {
230                 return column40 ? vram_wait_40_hireso[tmp_index] : vram_wait_80_hireso[tmp_index];
231         } else
232 #else
233         #define tmp_index vram_wait_index
234 #endif
235         return column40 ? vram_wait_40[tmp_index] : vram_wait_80[tmp_index];
236 }
237
238 #define STATE_VERSION   3
239
240 bool IOBUS::process_state(FILEIO* state_fio, bool loading)
241 {
242         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
243                 return false;
244         }
245         if(!state_fio->StateCheckInt32(this_device_id)) {
246                 return false;
247         }
248         state_fio->StateBuffer(vram, sizeof(vram), 1);
249         state_fio->StateBool(vram_mode);
250         state_fio->StateBool(signal);
251         if(loading) {
252                 vram_b = vram + state_fio->FgetInt32_LE();
253                 vram_r = vram + state_fio->FgetInt32_LE();
254                 vram_g = vram + state_fio->FgetInt32_LE();
255         } else {
256                 state_fio->FputInt32_LE((int)(vram_b - vram));
257                 state_fio->FputInt32_LE((int)(vram_r - vram));
258                 state_fio->FputInt32_LE((int)(vram_g - vram));
259         }
260         state_fio->StateValue(vdisp);
261         state_fio->StateValue(prev_clock);
262         state_fio->StateValue(vram_wait_index);
263         state_fio->StateValue(column40);
264 #ifdef _X1TURBO_FEATURE
265         state_fio->StateArray(crtc_regs, sizeof(crtc_regs), 1);
266         state_fio->StateValue(crtc_ch);
267         state_fio->StateValue(hireso);
268 #ifdef _X1TURBOZ
269         state_fio->StateValue(zmode1);
270         state_fio->StateValue(zmode2);
271 #endif
272 #endif
273         return true;
274 }
275
276 }