OSDN Git Service

[VM][WIP] Use namespace to devices per VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / j3100 / sasi.cpp
1 /*
2         TOSHIBA J-3100GT Emulator 'eJ-3100GT'
3         TOSHIBA J-3100SL Emulator 'eJ-3100SL'
4
5         Author : Takeda.Toshiya
6         Date   : 2011.08.19-
7
8         [ sasi hdd ]
9 */
10
11 #include "sasi.h"
12 #include "../i8259.h"
13
14 #define PHASE_FREE      0
15 #define PHASE_SELECT    1
16 #define PHASE_COMMAND   2
17 #define PHASE_C2        3
18 #define PHASE_SENSE     4
19 #define PHASE_READ      5
20 #define PHASE_WRITE     6
21 #define PHASE_STATUS    7
22 //#define PHASE_MESSAGE 8
23
24 #define STATUS_REQ      0x01
25 #define STATUS_IXD      0x02
26 #define STATUS_CXD      0x04
27 #define STATUS_BSY      0x08
28 #define STATUS_DRQ      0x10
29 #define STATUS_IRQ      0x20
30 //#define STATUS_MSG    0
31
32 #define EVENT_COMMAND   0
33 #define EVENT_STATUS    1
34
35 namespace J3100 {
36
37 void SASI::initialize()
38 {
39         // open hard drive images
40         for(int i = 0; i < 2; i++) {
41                 drive[i].fio = new FILEIO();
42                 if(!drive[i].fio->Fopen(create_local_path(_T("HDD%d.DAT"), i + 1), FILEIO_READ_WRITE_BINARY)) {
43                         delete drive[i].fio;
44                         drive[i].fio = NULL;
45                 }
46                 drive[i].access = false;
47         }
48 }
49
50 void SASI::release()
51 {
52         for(int i = 0; i < 2; i++) {
53                 if(drive[i].fio != NULL) {
54                         drive[i].fio->Fclose();
55                         delete drive[i].fio;
56                         drive[i].fio = NULL;
57                 }
58         }
59 }
60
61 void SASI::reset()
62 {
63         memset(buffer, 0, sizeof(buffer));
64         memset(cmd, 0, sizeof(cmd));
65         memset(status_buf, 0, sizeof(status_buf));
66         
67         phase = PHASE_FREE;
68         sector = 0;
69         blocks = 0;
70         cmd_ptr = 0;
71         unit = 0;
72         buffer_ptr = 0;
73         status = 0;
74         status_irq_drq = 0;
75         error = 0;
76         status_ptr = 0;
77         maskreg = 0;
78 }
79
80 void SASI::write_io8(uint32_t addr, uint32_t data)
81 {
82         switch(addr) {
83         case 0x1f0:
84                 // data
85                 if(phase == PHASE_COMMAND) {
86                         cmd[cmd_ptr++] = data;
87                         if(cmd_ptr == 6) {
88                                 check_cmd();
89                         }
90                 } else if(phase == PHASE_C2) {
91                         if(++status_ptr == 10) {
92                                 set_status(0);
93                         }
94                 } else if(phase == PHASE_WRITE) {
95                         buffer[buffer_ptr++] = data;
96                         if(buffer_ptr == 256) {
97                                 flush(unit);
98                                 if(--blocks) {
99                                         sector++;
100                                         buffer_ptr = 0;
101                                         if(!seek(unit)) {
102                                                 set_status(0x0f);
103                                                 set_drq(false);
104                                         }
105                                 } else {
106                                         set_status(0);
107                                         set_drq(false);
108                                 }
109                         }
110                 }
111                 datareg = data;
112                 break;
113         case 0x1f1:
114                 // reset
115                 reset();
116                 break;
117         case 0x1f2:
118                 // select
119                 phase = PHASE_SELECT;
120                 register_event(this, EVENT_COMMAND, 10, false, NULL);
121                 break;
122         case 0x1f3:
123                 // mask
124                 maskreg = data;
125                 break;
126         }
127 }
128
129 uint32_t SASI::read_io8(uint32_t addr)
130 {
131         uint32_t val = 0;
132         
133         switch(addr) {
134         case 0x1f0:
135                 // data
136                 if(phase == PHASE_READ) {
137                         val = buffer[buffer_ptr++];
138                         if(buffer_ptr == 256) {
139                                 if(--blocks) {
140                                         sector++;
141                                         buffer_ptr = 0;
142                                         if(!seek(unit)) {
143                                                 set_status(0x0f);
144                                                 set_drq(false);
145                                         }
146                                 } else {
147                                         set_status(0);
148                                         set_drq(false);
149                                 }
150                         }
151                 } else if(phase == PHASE_SENSE) {
152                         val = status_buf[status_ptr++];
153                         if(status_ptr == 4) {
154                                 set_status(0);
155                         }
156                 } else if(phase == PHASE_STATUS) {
157 //                      val = error ? 0x02 : status;
158 //                      phase = PHASE_MESSAGE;
159                         val = (error ? 2 : 0) | (unit << 5);
160                         phase = PHASE_FREE;
161 //              } else if(phase == PHASE_MESSAGE) {
162 //                      phase = PHASE_FREE;
163                 }
164                 return val;
165         case 0x1f1:
166                 // status
167                 val = status_irq_drq;
168                 status_irq_drq &= ~STATUS_IRQ;
169                 if(phase != PHASE_FREE) {
170                         val |= STATUS_BSY;
171                 }
172                 if(phase > PHASE_SELECT) {
173                         val |= STATUS_REQ;
174                 }
175                 if(phase == PHASE_COMMAND) {
176                         val |= STATUS_CXD;
177                 }
178                 if(phase == PHASE_SENSE) {
179                         val |= STATUS_IXD;
180                 }
181                 if(phase == PHASE_READ) {
182                         val |= STATUS_IXD;
183                 }
184                 if(phase == PHASE_STATUS) {
185                         val |= STATUS_IXD | STATUS_CXD;
186                 }
187 //              if(phase == PHASE_MESSAGE) {
188 //                      val |= STATUS_IXD | STATUS_CXD | STATUS_MSG;
189 //              }
190                 return val;
191         }
192         return 0xff;
193 }
194
195 void SASI::write_dma_io8(uint32_t addr, uint32_t data)
196 {
197         write_io8(0x1f0, data);
198 }
199
200 uint32_t SASI::read_dma_io8(uint32_t addr)
201 {
202         return read_io8(0x1f0);
203 }
204
205 uint32_t SASI::read_signal(int ch)
206 {
207         // get access status
208         uint32_t stat = (drive[0].access ? 0x10 : 0) | (drive[1].access ? 0x20 : 0);
209         drive[0].access = drive[1].access = false;
210         return stat;
211 }
212
213 void SASI::event_callback(int event_id, int err)
214 {
215         if(event_id == EVENT_COMMAND) {
216                 phase = PHASE_COMMAND;
217                 cmd_ptr = 0;
218         } else if(event_id == EVENT_STATUS) {
219                 phase = PHASE_STATUS;
220                 // raise irq
221                 if(maskreg & 2) {
222 #ifdef TYPE_SL
223                         d_pic->write_signal(SIG_I8259_IR5 | SIG_I8259_CHIP0, 1, 1);
224 #else
225                         d_pic->write_signal(SIG_I8259_IR6 | SIG_I8259_CHIP1, 1, 1);
226 #endif
227                 }
228                 status_irq_drq |= STATUS_IRQ;
229         }
230 }
231
232 void SASI::check_cmd()
233 {
234         unit = (cmd[1] >> 5) & 1;
235         
236         switch(cmd[0]) {
237         case 0x00:
238                 // test drive ready
239                 if(drive[unit].fio != NULL) {
240                         status = 0x00;
241                         set_status(0x00);
242                 } else {
243                         status = 0x02;
244                         set_status(0x7f);
245                 }
246                 break;
247         case 0x01:
248                 // recalib
249                 if(drive[unit].fio != NULL) {
250                         sector = 0;
251                         status = 0x00;
252                         set_status(0x00);
253                 } else {
254                         status = 0x02;
255                         set_status(0x7f);
256                 }
257                 break;
258         case 0x03:
259                 // request sense status
260                 phase = PHASE_SENSE;
261                 status_buf[0] = error;
262                 status_buf[1] = (uint8_t)((unit << 5) | ((sector >> 16) & 0x1f));
263                 status_buf[2] = (uint8_t)(sector >> 8);
264                 status_buf[3] = (uint8_t)sector;
265                 error = 0;
266                 status = 0x00;
267                 status_ptr = 0;
268                 break;
269         case 0x04:
270                 // format drive
271                 sector = 0;
272                 status = 0x00;
273                 set_status(0x0f);
274                 break;
275         case 0x06:
276                 // format track
277                 sector = cmd[1] & 0x1f;
278                 sector = (sector << 8) | cmd[2];
279                 sector = (sector << 8) | cmd[3];
280                 blocks = cmd[4];
281                 status = 0;
282                 if(format(unit)) {
283                         set_status(0);
284                 } else {
285                         set_status(0x0f);
286                 }
287                 break;
288         case 0x08:
289                 // read data
290                 sector = cmd[1] & 0x1f;
291                 sector = (sector << 8) | cmd[2];
292                 sector = (sector << 8) | cmd[3];
293                 blocks = cmd[4];
294                 status = 0;
295                 if(blocks != 0 && seek(unit)) {
296                         phase = PHASE_READ;
297                         buffer_ptr = 0;
298                         set_drq(true);
299                 } else {
300                         set_status(0x0f);
301                 }
302                 break;
303         case 0x0a:
304                 sector = cmd[1] & 0x1f;
305                 sector = (sector << 8) | cmd[2];
306                 sector = (sector << 8) | cmd[3];
307                 blocks = cmd[4];
308                 status = 0;
309                 if(blocks != 0 && seek(unit)) {
310                         phase = PHASE_WRITE;
311                         buffer_ptr = 0;
312                         memset(buffer, 0, sizeof(buffer));
313                         set_drq(true);
314                 } else {
315                         set_status(0x0f);
316                 }
317                 break;
318         case 0x0b:
319                 sector = cmd[1] & 0x1f;
320                 sector = (sector << 8) | cmd[2];
321                 sector = (sector << 8) | cmd[3];
322                 blocks = cmd[4];
323                 status = 0;
324                 set_status(0);
325                 break;
326         case 0xc2:
327                 phase = PHASE_C2;
328                 status_ptr = 0;
329                 status = 0;
330 //              error = 0;
331                 break;
332         default:
333                 // unknown
334                 set_status(0);
335                 break;
336         }
337 }
338
339 void SASI::set_status(uint8_t err)
340 {
341         error = err;
342         register_event(this, EVENT_STATUS, 10, false, NULL);
343 }
344
345 void SASI::set_drq(bool flag)
346 {
347         if(flag) {
348                 status_irq_drq |= STATUS_DRQ;
349         } else {
350                 status_irq_drq &= ~STATUS_DRQ;
351         }
352 }
353
354 bool SASI::seek(int drv)
355 {
356         memset(buffer, 0, sizeof(buffer));
357         
358         if(drive[drv & 1].fio == NULL) {
359                 return false;
360         }
361         if(drive[drv & 1].fio->Fseek(sector * 256, FILEIO_SEEK_SET) != 0) {
362                 return false;
363         }
364         if(drive[drv & 1].fio->Fread(buffer, 256, 1) != 1) {
365                 return false;
366         }
367         drive[drv & 1].access = true;
368         return true;
369 }
370
371 bool SASI::flush(int drv)
372 {
373         if(drive[drv & 1].fio == NULL) {
374                 return false;
375         }
376         if(drive[drv & 1].fio->Fseek(sector * 256, FILEIO_SEEK_SET) != 0) {
377                 return false;
378         }
379         if(drive[drv & 1].fio->Fwrite(buffer, 256, 1) != 1) {
380                 return false;
381         }
382         drive[drv & 1].access = true;
383         return true;
384 }
385
386 bool SASI::format(int drv)
387 {
388         if(drive[drv & 1].fio == NULL) {
389                 return false;
390         }
391         if(drive[drv & 1].fio->Fseek(sector * 256, FILEIO_SEEK_SET) != 0) {
392                 return false;
393         }
394         // format 33 blocks
395         memset(buffer, 0, sizeof(buffer));
396         for(int i = 0; i < 33; i++) {
397                 if(drive[drv & 1].fio->Fwrite(buffer, 256, 1) != 1) {
398                         return false;
399                 }
400                 drive[drv & 1].access = true;
401         }
402         return true;
403 }
404
405 }