SandboXP

Форк
0
/
floppy.js 
461 строка · 12.2 Кб
1
"use strict";
2

3
/**
4
 * @constructor
5
 *
6
 * @param {CPU} cpu
7
 */
8
function FloppyController(cpu, fda_image, fdb_image)
9
{
10
    /** @const @type {IO|undefined} */
11
    this.io = cpu.io;
12

13
    /** @const @type {CPU} */
14
    this.cpu = cpu;
15

16
    /** @const @type {DMA} */
17
    this.dma = cpu.devices.dma;
18

19
    this.bytes_expecting = 0;
20
    this.receiving_command = new Uint8Array(10);
21
    this.receiving_index = 0;
22
    this.next_command = null;
23

24
    this.response_data = new Uint8Array(10);
25
    this.response_index = 0;
26
    this.response_length = 0;
27

28
    this.floppy_size = 0;
29

30
    /* const */
31
    this.fda_image = fda_image;
32

33
    /* const */
34
    this.fdb_image = fdb_image;
35

36

37
    this.status_reg0 = 0;
38
    this.status_reg1 = 0;
39
    this.status_reg2 = 0;
40
    this.drive = 0;
41

42
    this.last_cylinder = 0;
43
    this.last_head = 0;
44
    this.last_sector = 1;
45

46
    // this should actually be write-only ... but people read it anyway
47
    this.dor = 0;
48

49
    if(!fda_image)
50
    {
51
        // Needed for CD emulation provided by seabios
52
        cpu.devices.rtc.cmos_write(CMOS_FLOPPY_DRIVE_TYPE, 4 << 4);
53

54
        this.sectors_per_track = 0;
55
        this.number_of_heads = 0;
56
        this.number_of_cylinders = 0;
57

58
        this.floppy_size = 0;
59
    }
60
    else
61
    {
62
        this.floppy_size = fda_image.byteLength;
63

64
        var floppy_types = {
65
            160  : { type: 1, tracks: 40, sectors: 8 , heads: 1 },
66
            180  : { type: 1, tracks: 40, sectors: 9 , heads: 1 },
67
            200  : { type: 1, tracks: 40, sectors: 10, heads: 1 },
68
            320  : { type: 1, tracks: 40, sectors: 8 , heads: 2 },
69
            360  : { type: 1, tracks: 40, sectors: 9 , heads: 2 },
70
            400  : { type: 1, tracks: 40, sectors: 10, heads: 2 },
71
            720  : { type: 3, tracks: 80, sectors: 9 , heads: 2 },
72
            1200 : { type: 2, tracks: 80, sectors: 15, heads: 2 },
73
            1440 : { type: 4, tracks: 80, sectors: 18, heads: 2 },
74
            1722 : { type: 5, tracks: 82, sectors: 21, heads: 2 },
75
            2880 : { type: 5, tracks: 80, sectors: 36, heads: 2 },
76

77
            // not a real floppy type, used to support sectorlisp and friends
78
            0    : { type: 1, tracks: 1, sectors: 1, heads: 1 },
79
        };
80

81
        var number_of_cylinders,
82
            sectors_per_track,
83
            number_of_heads,
84
            floppy_type = floppy_types[this.floppy_size >> 10];
85

86
        if(floppy_type && ((this.floppy_size & 0x3FF) === 0 || this.floppy_size === 512))
87
        {
88
            cpu.devices.rtc.cmos_write(CMOS_FLOPPY_DRIVE_TYPE, floppy_type.type << 4);
89

90
            sectors_per_track = floppy_type.sectors;
91
            number_of_heads = floppy_type.heads;
92
            number_of_cylinders = floppy_type.tracks;
93
        }
94
        else
95
        {
96
            throw "Unknown floppy size: " + h(fda_image.byteLength);
97
        }
98

99
        this.sectors_per_track = sectors_per_track;
100
        this.number_of_heads = number_of_heads;
101
        this.number_of_cylinders = number_of_cylinders;
102
    }
103

104
    this.io.register_read(0x3F0, this, this.port3F0_read);
105
    this.io.register_read(0x3F2, this, this.port3F2_read);
106
    this.io.register_read(0x3F4, this, this.port3F4_read);
107
    this.io.register_read(0x3F5, this, this.port3F5_read);
108
    this.io.register_read(0x3F7, this, this.port3F7_read);
109

110
    this.io.register_write(0x3F2, this, this.port3F2_write);
111
    this.io.register_write(0x3F5, this, this.port3F5_write);
112
}
113

114
FloppyController.prototype.get_state = function()
115
{
116
    var state = [];
117

118
    state[0] = this.bytes_expecting;
119
    state[1] = this.receiving_command;
120
    state[2] = this.receiving_index;
121
    //state[3] = this.next_command;
122
    state[4] = this.response_data;
123
    state[5] = this.response_index;
124
    state[6] = this.response_length;
125
    state[7] = this.floppy_size;
126
    state[8] = this.status_reg0;
127
    state[9] = this.status_reg1;
128
    state[10] = this.status_reg2;
129
    state[11] = this.drive;
130
    state[12] = this.last_cylinder;
131
    state[13] = this.last_head;
132
    state[14] = this.last_sector;
133
    state[15] = this.dor;
134
    state[16] = this.sectors_per_track;
135
    state[17] = this.number_of_heads;
136
    state[18] = this.number_of_cylinders;
137

138
    return state;
139
};
140

141
FloppyController.prototype.set_state = function(state)
142
{
143
    this.bytes_expecting = state[0];
144
    this.receiving_command = state[1];
145
    this.receiving_index = state[2];
146
    this.next_command = state[3];
147
    this.response_data = state[4];
148
    this.response_index = state[5];
149
    this.response_length = state[6];
150
    this.floppy_size = state[7];
151
    this.status_reg0 = state[8];
152
    this.status_reg1 = state[9];
153
    this.status_reg2 = state[10];
154
    this.drive = state[11];
155
    this.last_cylinder = state[12];
156
    this.last_head = state[13];
157
    this.last_sector = state[14];
158
    this.dor = state[15];
159
    this.sectors_per_track = state[16];
160
    this.number_of_heads = state[17];
161
    this.number_of_cylinders = state[18];
162
};
163

164
FloppyController.prototype.port3F0_read = function()
165
{
166
    dbg_log("3F0 read", LOG_FLOPPY);
167

168
    return 0;
169
};
170

171

172
FloppyController.prototype.port3F4_read = function()
173
{
174
    dbg_log("3F4 read", LOG_FLOPPY);
175

176
    var return_byte = 0x80;
177

178
    if(this.response_index < this.response_length)
179
    {
180
        return_byte |= 0x40 | 0x10;
181
    }
182

183
    if((this.dor & 8) === 0)
184
    {
185
        return_byte |= 0x20;
186
    }
187

188
    return return_byte;
189
};
190

191
FloppyController.prototype.port3F7_read = function()
192
{
193
    dbg_log("3F7 read", LOG_FLOPPY);
194
    return 0x00;
195
};
196

197
FloppyController.prototype.port3F5_read = function()
198
{
199
    if(this.response_index < this.response_length)
200
    {
201
        dbg_log("3F5 read: " + this.response_data[this.response_index], LOG_FLOPPY);
202
        this.cpu.device_lower_irq(6);
203
        return this.response_data[this.response_index++];
204
    }
205
    else
206
    {
207
        dbg_log("3F5 read, empty", LOG_FLOPPY);
208
        return 0xFF;
209
    }
210
};
211

212
FloppyController.prototype.port3F5_write = function(reg_byte)
213
{
214
    if(!this.fda_image) return;
215

216
    dbg_log("3F5 write " + h(reg_byte), LOG_FLOPPY);
217

218
    if(this.bytes_expecting > 0)
219
    {
220
        this.receiving_command[this.receiving_index++] = reg_byte;
221

222
        this.bytes_expecting--;
223

224
        if(this.bytes_expecting === 0)
225
        {
226
            if(DEBUG)
227
            {
228
                var log = "3F5 command received: ";
229
                for(var i = 0; i < this.receiving_index; i++)
230
                    log += h(this.receiving_command[i]) + " ";
231
                dbg_log(log, LOG_FLOPPY);
232
            }
233

234
            this.next_command.call(this, this.receiving_command);
235
        }
236
    }
237
    else
238
    {
239
        switch(reg_byte)
240
        {
241
            // TODO
242
            //case 2:
243
                //this.next_command = read_complete_track;
244
                //this.bytes_expecting = 8;
245
                //break;
246
            case 0x03:
247
                this.next_command = this.fix_drive_data;
248
                this.bytes_expecting = 2;
249
                break;
250
            case 0x04:
251
                this.next_command = this.check_drive_status;
252
                this.bytes_expecting = 1;
253
                break;
254
            case 0x05:
255
            case 0xC5:
256
                this.next_command = function(args) { this.do_sector(true, args); };
257
                this.bytes_expecting = 8;
258
                break;
259
            case 0xE6:
260
                this.next_command = function(args) { this.do_sector(false, args); };
261
                this.bytes_expecting = 8;
262
                break;
263
            case 0x07:
264
                this.next_command = this.calibrate;
265
                this.bytes_expecting = 1;
266
                break;
267
            case 0x08:
268
                this.check_interrupt_status();
269
                break;
270
            case 0x4A:
271
                this.next_command = this.read_sector_id;
272
                this.bytes_expecting = 1;
273
                break;
274
            case 0x0F:
275
                this.bytes_expecting = 2;
276
                this.next_command = this.seek;
277
                break;
278
            case 0x0E:
279
                // dump regs
280
                dbg_log("dump registers", LOG_FLOPPY);
281
                this.response_data[0] = 0x80;
282
                this.response_index = 0;
283
                this.response_length = 1;
284

285
                this.bytes_expecting = 0;
286
                break;
287

288
            default:
289
                dbg_assert(false, "Unimplemented floppy command call " + h(reg_byte));
290
        }
291

292
        this.receiving_index = 0;
293
    }
294
};
295

296
FloppyController.prototype.port3F2_read = function()
297
{
298
    dbg_log("read 3F2: DOR", LOG_FLOPPY);
299
    return this.dor;
300
};
301

302
FloppyController.prototype.port3F2_write = function(value)
303
{
304
    if((value & 4) === 4 && (this.dor & 4) === 0)
305
    {
306
        // reset
307
        this.cpu.device_raise_irq(6);
308
    }
309

310
    dbg_log("start motors: " + h(value >> 4), LOG_FLOPPY);
311
    dbg_log("enable dma: " + !!(value & 8), LOG_FLOPPY);
312
    dbg_log("reset fdc: " + !!(value & 4), LOG_FLOPPY);
313
    dbg_log("drive select: " + (value & 3), LOG_FLOPPY);
314
    dbg_log("DOR = " + h(value), LOG_FLOPPY);
315

316
    this.dor = value;
317
};
318

319
FloppyController.prototype.check_drive_status = function(args)
320
{
321
    dbg_log("check drive status", LOG_FLOPPY);
322

323
    this.response_index = 0;
324
    this.response_length = 1;
325
    this.response_data[0] = 1 << 5;
326
};
327

328
FloppyController.prototype.seek = function(args)
329
{
330
    dbg_log("seek", LOG_FLOPPY);
331
    dbg_assert((args[0] & 3) === 0, "Unhandled seek drive");
332

333
    this.last_cylinder = args[1];
334
    this.last_head = args[0] >> 2 & 1;
335

336
    this.raise_irq();
337
};
338

339
FloppyController.prototype.calibrate = function(args)
340
{
341
    dbg_log("floppy calibrate", LOG_FLOPPY);
342

343
    this.raise_irq();
344
};
345

346
FloppyController.prototype.check_interrupt_status = function()
347
{
348
    // do not trigger an interrupt here
349
    dbg_log("floppy check interrupt status", LOG_FLOPPY);
350

351
    this.response_index = 0;
352
    this.response_length = 2;
353

354
    this.response_data[0] = 1 << 5;
355
    this.response_data[1] = this.last_cylinder;
356
};
357

358
FloppyController.prototype.do_sector = function(is_write, args)
359
{
360
    var head = args[2],
361
        cylinder = args[1],
362
        sector = args[3],
363
        sector_size = 128 << args[4],
364
        read_count = args[5] - args[3] + 1,
365

366
        read_offset = ((head + this.number_of_heads * cylinder) * this.sectors_per_track + sector - 1) * sector_size;
367

368
    dbg_log("Floppy " + (is_write ? "Write" : "Read"), LOG_FLOPPY);
369
    dbg_log("from " + h(read_offset) + " length " + h(read_count * sector_size), LOG_FLOPPY);
370
    dbg_log(cylinder + " / " + head + " / " + sector, LOG_FLOPPY);
371

372
    if(!args[4])
373
    {
374
        dbg_log("FDC: sector count is zero, use data length instead", LOG_FLOPPY);
375
    }
376

377
    if(!this.fda_image)
378
    {
379
        return;
380
    }
381

382
    if(is_write)
383
    {
384
        this.dma.do_write(this.fda_image, read_offset, read_count * sector_size, 2, this.done.bind(this, args, cylinder, head, sector));
385
    }
386
    else
387
    {
388
        this.dma.do_read(this.fda_image, read_offset, read_count * sector_size, 2, this.done.bind(this, args, cylinder, head, sector));
389
    }
390
};
391

392
FloppyController.prototype.done = function(args, cylinder, head, sector, error)
393
{
394
    if(error)
395
    {
396
        // TODO: Set appropriate bits
397
        return;
398
    }
399

400
    sector++;
401

402
    if(sector > this.sectors_per_track)
403
    {
404
        sector = 1;
405
        head++;
406

407
        if(head >= this.number_of_heads)
408
        {
409
            head = 0;
410
            cylinder++;
411
        }
412
    }
413

414
    this.last_cylinder = cylinder;
415
    this.last_head = head;
416
    this.last_sector = sector;
417

418
    this.response_index = 0;
419
    this.response_length = 7;
420

421
    this.response_data[0] = head << 2 | 0x20;
422
    this.response_data[1] = 0;
423
    this.response_data[2] = 0;
424
    this.response_data[3] = cylinder;
425
    this.response_data[4] = head;
426
    this.response_data[5] = sector;
427
    this.response_data[6] = args[4];
428

429
    this.raise_irq();
430
};
431

432
FloppyController.prototype.fix_drive_data = function(args)
433
{
434
    dbg_log("floppy fix drive data " + args, LOG_FLOPPY);
435
};
436

437
FloppyController.prototype.read_sector_id = function(args)
438
{
439
    dbg_log("floppy read sector id " + args, LOG_FLOPPY);
440

441
    this.response_index = 0;
442
    this.response_length = 7;
443

444
    this.response_data[0] = 0;
445
    this.response_data[1] = 0;
446
    this.response_data[2] = 0;
447
    this.response_data[3] = 0;
448
    this.response_data[4] = 0;
449
    this.response_data[5] = 0;
450
    this.response_data[6] = 0;
451

452
    this.raise_irq();
453
};
454

455
FloppyController.prototype.raise_irq = function()
456
{
457
    if(this.dor & 8)
458
    {
459
        this.cpu.device_raise_irq(6);
460
    }
461
};
462

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.