OSDN Git Service

[VM][FMTOWNS][MEMORY] Fix setup around memory banks by I/O 0404h and 0480h.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc9801 / cpureg.cpp
1 /*
2         NEC PC-9801VX Emulator 'ePC-9801VX'
3         NEC PC-9801RA Emulator 'ePC-9801RA'
4         NEC PC-98XA Emulator 'ePC-98XA'
5         NEC PC-98XL Emulator 'ePC-98XL'
6         NEC PC-98RL Emulator 'ePC-98RL'
7
8         Author : Takeda.Toshiya
9         Date   : 2017.06.25-
10
11         [ cpu regs ]
12 */
13
14 #include "cpureg.h"
15 #include "membus.h"
16 #include "../i8255.h"
17 #if defined(SUPPORT_32BIT_ADDRESS) || defined(UPPER_I386)
18 #include "../i386_np21.h"
19 //#include "../i386.h"
20 #else
21 //#include "../i286_np21.h"
22 #include "../i286.h"
23 #endif
24 #if defined(HAS_SUB_V30)
25 #include "../i86.h"
26 #include "../i8255.h"
27 #endif
28
29 #define EVENT_WAIT 1
30
31 namespace PC9801 {
32
33 void CPUREG::initialize()
34 {
35         reg_0f0 = 0x00;
36         event_wait = -1;
37 #if defined(HAS_SUB_V30)
38         if(d_v30 != nullptr) {
39                 reg_0f0 = reg_0f0 | ((cpu_mode) ? 1 : 0);
40         }
41 #endif
42 }
43
44 void CPUREG::reset()
45 {
46         d_cpu->set_address_mask(0x000fffff);
47         nmi_enabled = false;
48         init_clock = get_current_clock_uint64() & 0x000000ffffffffff;
49 #if defined(HAS_SUB_V30)
50         if(d_v30 != NULL) {
51                 d_cpu->write_signal(SIG_CPU_BUSREQ,  reg_0f0, 1);
52                 //d_v30->reset();
53                 d_v30->write_signal(SIG_CPU_BUSREQ, ~reg_0f0, 1);
54                 cpu_mode = ((reg_0f0 & 1) != 0);
55                 d_pio->write_signal(SIG_I8255_PORT_B, reg_0f0 << 1, 2);
56         } else {
57                 reg_0f0 &= 0xfe;
58                 cpu_mode = false;
59                 d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 1);
60                 d_pio->write_signal(SIG_I8255_PORT_B, 0, 2);
61         }
62 #endif
63 }
64
65 void CPUREG::write_io8(uint32_t addr, uint32_t data)
66 {
67         switch(addr) {
68         case 0x0050:
69                 nmi_enabled = false;
70                 break;
71         case 0x0052:
72                 nmi_enabled = true;
73                 break;
74         case 0x005f:
75                 // ToDo: Both Pseudo BIOS.
76                 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
77 #if defined(HAS_SUB_V30)
78                 if(d_v30 != NULL) {
79                         d_v30->write_signal(SIG_CPU_BUSREQ, 1, 1);
80                 }
81 #endif
82                 if(event_wait >= 0) {
83                         cancel_event(this, event_wait);
84                         event_wait = -1;
85                 }
86                 register_event(this, EVENT_WAIT, 0.6, false, &event_wait);
87                 break;
88         case 0x00f0:
89                 out_debug_log(_T("00F0h=%02X"), data);
90                 reg_0f0 = data;
91 #if defined(HAS_SUB_V30)
92                 if(d_v30 != NULL) {
93                         write_signals(&outputs_cputype, ((reg_0f0 & 0x01) != 0) ? 0xffffffff : 0x00000000);
94                 } else {
95                         write_signals(&outputs_cputype, 0);
96                 }
97 #else
98                 write_signals(&outputs_cputype, 0);
99 #endif
100                 d_cpu->reset();
101                 d_cpu->set_address_mask(0x000fffff);
102 #if defined(HAS_SUB_V30)
103                 if(d_v30 != NULL) {
104                         d_cpu->write_signal(SIG_CPU_BUSREQ,  reg_0f0, 1);
105                         d_v30->reset();
106                         d_v30->write_signal(SIG_CPU_BUSREQ, ~reg_0f0, 1);
107                         cpu_mode = ((reg_0f0 & 1) != 0);
108                         d_pio->write_signal(SIG_I8255_PORT_B, reg_0f0 << 1, 2);
109                 } else {
110                         reg_0f0 &= 0xfe;
111                         cpu_mode = false;
112                         d_pio->write_signal(SIG_I8255_PORT_B, 0, 2);
113                 }
114 #endif
115                 break;
116         case 0x00f2:
117 #if defined(SUPPORT_32BIT_ADDRESS)
118                 d_cpu->set_address_mask(0xffffffff);
119 #else
120                 d_cpu->set_address_mask(0x00ffffff);
121 #endif
122                 break;
123 #if defined(SUPPORT_32BIT_ADDRESS)
124         case 0x00f6:
125                 switch(data) {
126                 case 0x02:
127                         d_cpu->set_address_mask(0xffffffff);
128                         break;
129                 case 0x03:
130                         d_cpu->set_address_mask(0x000fffff);
131                         break;
132                 }
133                 break;
134 #endif
135         }
136 }
137
138 uint32_t CPUREG::read_io8(uint32_t addr)
139 {
140         uint32_t value;
141
142         switch(addr) {
143         case 0x005c:
144         case 0x005d:
145         case 0x005e:
146         case 0x005f:
147                 {
148                         // Timestamp register (from MAME 0.208)
149                         // 307.2KHz
150                         pair32_t n;
151                         uint64_t c;
152                         uint64_t elapsed;
153                         uint8_t nn;
154                     c = get_current_clock_uint64() & 0x000000ffffffffff;
155                         if(c < init_clock) {
156                                 elapsed = c + 0x0000010000000000 - init_clock;
157                         } else {
158                                 elapsed = c - init_clock;
159                         }
160                         uint64_t ticks = (elapsed * 307200) / get_cpu_clock(0);
161                         n.d = (uint32_t)ticks;
162                         n.b.h3 = 0;
163                         switch(addr & 0x03) {
164                         case 0:
165                                 nn = n.b.l;
166                                 break;
167                         case 1:
168                         case 2: // OK? From NP2 v0.83 20190619
169                                 nn = n.b.h;
170                                 break;
171                         case 3: // OK? From NP2 v0.83 20190619
172                                 nn = n.b.h2;
173                                 break;
174 //                      case 3:
175 //                              nn = 0;
176 //                              break;
177                         }
178                         return (uint32_t)nn;
179                 }
180                 break;
181         case 0x00f0:
182                 value  = 0x00;
183 //#if defined(_PC9821_VARIANTS) || defined(_PC9801NA)
184 //              value |= 0x80; // 1 = PC-9801NA, 0 = PC-9801NA/C
185 //              value |= 0x80; // 1 = PC-9821modelS1, 0 = PC-9821modelS2
186 //              value |= 0x80; // 1 = PC-9821CemodelS1, 0 = PC-9821CemodelS2
187 //              value |= 0x80; // 1 = PC-9821Xt, 0 = PC-9821Xa
188 //              value |= 0x80; // CPU MODE, 1 = High/Low, 0 = Middle (PC-9821Ap/As/Ae/Af)
189 //              value |= 0x40; // ODP, 1 = Existing (PC-9821Ts)
190 //#else
191 #if defined(SUPPORT_SCSI_IF)
192 //              value |= 0x40; // Internal 55-type SCSI-HDD, 0 = Existing
193 #endif
194 #if defined(SUPPORT_SASI_IF)
195 //              value |= 0x20; // Internal 27-type SASI-HDD, 0 = Existing
196 #endif
197 #if defined(_PC9801RA) || defined(_PC9801RS) || defined(_PC9821_VARIANTS) || \
198         defined(_PC98NOTE_VARIANTS) || defined(_PC98DOPLUS)
199         #if !defined(SUPPORT_SASI_IF) || defined(SUPPORT_IDE_IF)
200                 value |= 0x20; // Internal 27-type SASI-HDD, 0 = Existing
201         #endif
202 #else
203                 value |= 0x20;
204 #endif
205                 // ToDo: AMD98
206 //              value |= 0x10; // Unknown
207                 value |= 0x08; // RAM access, 1 = Internal-standard/External-enhanced RAM, 0 = Internal-enhanced RAM
208 //              value |= 0x04; // Refresh mode, 1 = Standard, 0 = High speed
209 #if defined(HAS_SUB_V30)
210                 if((cpu_mode) && (d_v30 != nullptr)) {
211                         // Q: When defined HAS_I86 ?
212                         value |= 0x02; // CPU mode, 1 = V30, 0 = 80286/80386
213                 }
214 #endif
215                 value |= 0x01; // RAM access, 1 = Internal RAM, 0 = External-enhanced RAM
216                 return value;
217         case 0x00f2:
218                 return ((d_cpu->get_address_mask() & (1 << 20)) ? 0x00 : 0x01) | 0xfe;
219                 break;
220         case 0x00f4: // ToDo: DMA SPEED (after 9801DA)
221                 return 0xff;
222                 break;
223 #if defined(SUPPORT_32BIT_ADDRESS)
224         case 0x00f6:
225                 value  = 0x00;
226 #if defined(SUPPORT_HIRESO) && !defined(_PC98RL)
227                 value |= 0x10; // SASI-HDD, 1 = DMA ch0, 0 = DMA ch1
228 #endif
229                 if(nmi_enabled) {
230                         value |= 0x02; // NMI, 1 = Enabled
231                 }
232                 return ((d_cpu->get_address_mask() & (1 << 20)) ? 0x00 : 0x01) | value;
233 #endif
234         }
235         return 0xff;
236 }
237
238 void CPUREG::event_callback(int id, int err)
239 {
240         if(id == EVENT_WAIT) {
241                 // Reset WAIT (Temporally BUSREQ).
242 //#if !defined(SUPPORT_HIRESO)
243                 // ToDo: Both Pseudo BIOS.
244                 uint32_t haltvalue = 0;
245                 uint32_t haltvalue_v30 = 1;
246                 #if defined(HAS_SUB_V30)
247                 if(d_v30 != NULL) {
248                         if(cpu_mode) {
249                                 haltvalue = 1;
250                                 haltvalue_v30 = 0;
251                         }
252                         d_v30->write_signal(SIG_CPU_BUSREQ, haltvalue_v30, 1);
253                 }
254                 #endif
255                 d_cpu->write_signal(SIG_CPU_BUSREQ, haltvalue, 1);
256                 event_wait = -1;
257 //#endif
258         }
259 }
260
261 //#if !defined(SUPPORT_HIRESO)
262 void CPUREG::set_intr_line(bool line, bool pending, uint32_t bit)
263 {
264 #if defined(HAS_SUB_V30)
265         if(d_v30 != NULL) {
266                 if(((reg_0f0 & 1) != 0)){
267                         d_v30->set_intr_line(line, pending, bit);
268                 } else {
269                         d_cpu->set_intr_line(line, pending, bit);
270                 }
271         } else
272 #endif
273         {
274                 d_cpu->set_intr_line(line, pending, bit);
275         }
276 }
277
278 void CPUREG::write_signal(int ch, uint32_t data, uint32_t mask)
279 {
280         if(ch == SIG_CPU_NMI) {
281                 out_debug_log("NMI\n");
282                 //if(nmi_enabled) {
283                         write_signals(&outputs_nmi, data);
284                 //}
285         } else if(ch == SIG_CPUREG_RESET) {
286                 // This don't need at PC9801?
287 //              out_debug_log("RESET FROM CPU!!!\n");
288         }
289 }
290
291 void CPUREG::set_extra_clock(int clock)
292 {
293 #if defined(HAS_SUB_V30)
294         if(cpu_mode) {
295                 d_v30->set_extra_clock(clock);
296         } else {
297                 d_cpu->set_extra_clock(clock);
298         }
299 #endif
300 }
301 //#endif
302
303 #define STATE_VERSION   3
304
305 bool CPUREG::process_state(FILEIO* state_fio, bool loading)
306 {
307         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
308                 return false;
309         }
310         if(!state_fio->StateCheckInt32(this_device_id)) {
311                 return false;
312         }
313         state_fio->StateValue(reg_0f0);
314 #if defined(HAS_SUB_V30)
315         state_fio->StateValue(cpu_mode);
316 #endif
317         state_fio->StateValue(nmi_enabled);
318         state_fio->StateValue(init_clock);
319         state_fio->StateValue(event_wait);
320         return true;
321 }
322
323 }