change floppy.js to prototypical definition5~

This commit is contained in:
Fabian 2014-05-06 06:17:28 +02:00
parent 6ce08cfe02
commit c5fd846319

View file

@ -3,26 +3,34 @@
/** @constructor */ /** @constructor */
function FloppyController(dev, fda_image, fdb_image) function FloppyController(dev, fda_image, fdb_image)
{ {
var
io = dev.io,
pic = dev.pic,
dma = dev.dma,
bytes_expecting = 0, this.io = dev.io;
receiving_command = new Uint8Array(10), this.pic = dev.pic;
receiving_index = 0, this.dma = dev.dma;
next_command,
response_data = new Uint8Array(10), this.bytes_expecting = 0;
response_index = 0, this.receiving_command = new Uint8Array(10);
response_length = 0, this.receiving_index = 0;
this.next_command = null;
floppy_size, this.response_data = new Uint8Array(10);
this.response_index = 0;
this.response_length = 0;
/** @const */ this.floppy_size = 0;
byte_per_sector = 512;
this.buffer = fda_image; this.buffer = fda_image;
this.fda_image = fda_image;
this.fdb_image = fdb_image;
this.status_reg0 = 0;
this.status_reg1 = 0;
this.status_reg2 = 0;
this.drive = 0;
this.last_cylinder = 0;
this.last_head = 0;
this.last_sector = 1;
if(!fda_image) if(!fda_image)
{ {
@ -30,7 +38,7 @@ function FloppyController(dev, fda_image, fdb_image)
return; return;
} }
floppy_size = fda_image.byteLength; this.floppy_size = fda_image.byteLength;
var floppy_types = { var floppy_types = {
160 : { type: 1, tracks: 40, sectors: 8 , heads: 1 }, 160 : { type: 1, tracks: 40, sectors: 8 , heads: 1 },
@ -49,9 +57,9 @@ function FloppyController(dev, fda_image, fdb_image)
var number_of_cylinders, var number_of_cylinders,
sectors_per_track, sectors_per_track,
number_of_heads, number_of_heads,
floppy_type = floppy_types[floppy_size >> 10]; floppy_type = floppy_types[this.floppy_size >> 10];
if(floppy_type && (floppy_size & 0x3FF) === 0) if(floppy_type && (this.floppy_size & 0x3FF) === 0)
{ {
this.type = floppy_type.type; this.type = floppy_type.type;
@ -64,320 +72,316 @@ function FloppyController(dev, fda_image, fdb_image)
throw "Unknown floppy size: " + h(fda_image.byteLength); throw "Unknown floppy size: " + h(fda_image.byteLength);
} }
var status_reg0 = 0, this.sectors_per_track = sectors_per_track;
status_reg1 = 0, this.number_of_heads = number_of_heads;
status_reg2 = 0, this.number_of_cylinders = number_of_cylinders;
drive = 0;
var last_cylinder = 0, this.io.register_read(0x3F0, this.port3F0_read, this);
last_head = 0, this.io.register_read(0x3F2, this.port3F2_read, this);
last_sector = 1; this.io.register_read(0x3F4, this.port3F4_read, this);
this.io.register_read(0x3F5, this.port3F5_read, this);
this.io.register_read(0x3F7, this.port3F7_read, this);
io.register_read(0x3F0, port3F0_read); this.io.register_write(0x3F2, this.port3F2_write, this);
io.register_read(0x3F4, port3F4_read); this.io.register_write(0x3F5, this.port3F5_write, this);
io.register_read(0x3F5, port3F5_read);
io.register_read(0x3F7, port3F7_read);
io.register_write(0x3F5, port3F5_write); }
function port3F0_read() FloppyController.prototype.port3F0_read = function()
{
dbg_log("3F0 read", LOG_DISK);
return 0;
};
FloppyController.prototype.port3F4_read = function()
{
dbg_log("3F4 read", LOG_DISK);
var return_byte = 0x80;
if(this.response_index < this.response_length)
{ {
dbg_log("3F0 read", LOG_DISK); return_byte |= 0x40 | 0x10;
return 0;
};
function port3F4_read()
{
dbg_log("3F4 read", LOG_DISK);
var return_byte = 0x80;
if(response_index < response_length)
{
return_byte |= 0x40 | 0x10;
}
if((dor & 8) === 0)
{
return_byte |= 0x20;
}
return return_byte;
};
function port3F7_read()
{
dbg_log("3F7 read", LOG_DISK);
return 0x00;
} }
function port3F5_read() if((dor & 8) === 0)
{ {
if(response_index < response_length) return_byte |= 0x20;
{ }
dbg_log("3F5 read: " + response_data[response_index], LOG_DISK);
return response_data[response_index++];
}
else
{
dbg_log("3F5 read, empty", LOG_DISK);
return 0xFF;
}
};
function port3F5_write(reg_byte) return return_byte;
};
FloppyController.prototype.port3F7_read = function()
{
dbg_log("3F7 read", LOG_DISK);
return 0x00;
}
FloppyController.prototype.port3F5_read = function()
{
if(this.response_index < this.response_length)
{ {
dbg_log("3F5 write " + h(reg_byte), LOG_DISK); dbg_log("3F5 read: " + this.response_data[this.response_index], LOG_DISK);
return this.response_data[this.response_index++];
}
else
{
dbg_log("3F5 read, empty", LOG_DISK);
return 0xFF;
}
};
if(bytes_expecting > 0) FloppyController.prototype.port3F5_write = function(reg_byte)
{
dbg_log("3F5 write " + h(reg_byte), LOG_DISK);
if(this.bytes_expecting > 0)
{
this.receiving_command[this.receiving_index++] = reg_byte;
this.bytes_expecting--;
if(this.bytes_expecting === 0)
{ {
receiving_command[receiving_index++] = reg_byte; if(DEBUG)
bytes_expecting--;
if(bytes_expecting === 0)
{ {
if(DEBUG) var log = "3F5 command received: ";
{ for(var i = 0; i < this.receiving_index; i++)
var log = "3F5 command received: "; log += h(this.receiving_command[i]) + " ";
for(var i = 0; i < receiving_index; i++) dbg_log(log, LOG_DISK);
log += h(receiving_command[i]) + " ";
dbg_log(log, LOG_DISK);
}
next_command(receiving_command);
}
}
else
{
switch(reg_byte)
{
// TODO
//case 2:
//next_command = read_complete_track;
//bytes_expecting = 8;
//break;
case 0x03:
next_command = fix_drive_data;
bytes_expecting = 2;
break;
case 0x04:
next_command = check_drive_status;
bytes_expecting = 1;
break;
case 0x05:
case 0xC5:
next_command = function(args) { do_sector(true, args); };
bytes_expecting = 8;
break;
case 0xE6:
next_command = function(args) { do_sector(false, args); };
bytes_expecting = 8;
break;
case 0x07:
next_command = calibrate;
bytes_expecting = 1;
break;
case 0x08:
check_interrupt_status();
break;
case 0x4A:
next_command = read_sector_id;
bytes_expecting = 1;
break;
case 0x0F:
bytes_expecting = 2;
next_command = seek;
break;
case 0x0E:
// dump regs
dbg_log("dump registers", LOG_DISK);
response_data[0] = 0x80;
response_index = 0;
response_length = 1;
bytes_expecting = 0;
break;
default:
if(DEBUG) throw "unimpl floppy command call " + h(reg_byte);
} }
receiving_index = 0; this.next_command.call(this, this.receiving_command);
}
};
// this should actually be write-only ... but people read it anyway
var dor = 0;
function port3F2_read()
{
dbg_log("read 3F2: DOR", LOG_DISK);
return dor;
}
io.register_read(0x3F2, port3F2_read);
function port3F2_write(value)
{
if((value & 4) === 4 && (dor & 4) === 0)
{
// reset
pic.push_irq(6);
}
dbg_log("start motors: " + h(value >> 4), LOG_DISK);
dbg_log("enable dma: " + !!(value & 8), LOG_DISK);
dbg_log("reset fdc: " + !!(value & 4), LOG_DISK);
dbg_log("drive select: " + (value & 3), LOG_DISK);
dbg_log("DOR = " + h(value), LOG_DISK);
dor = value;
}
io.register_write(0x3F2, port3F2_write);
function check_drive_status(args)
{
dbg_log("check drive status", LOG_DISK);
response_index = 0;
response_length = 1;
response_data[0] = 1 << 5;
}
function seek(args)
{
dbg_log("seek", LOG_DISK);
last_cylinder = args[1];
last_head = args[0] >> 2 & 1;
if(dor & 8)
{
pic.push_irq(6);
} }
} }
else
function calibrate(args)
{ {
dbg_log("floppy calibrate", LOG_DISK); switch(reg_byte)
if(dor & 8)
{ {
pic.push_irq(6); // TODO
//case 2:
//this.next_command = read_complete_track;
//this.bytes_expecting = 8;
//break;
case 0x03:
this.next_command = this.fix_drive_data;
this.bytes_expecting = 2;
break;
case 0x04:
this.next_command = this.check_drive_status;
this.bytes_expecting = 1;
break;
case 0x05:
case 0xC5:
this.next_command = function(args) { this.do_sector(true, args); };
this.bytes_expecting = 8;
break;
case 0xE6:
this.next_command = function(args) { this.do_sector(false, args); };
this.bytes_expecting = 8;
break;
case 0x07:
this.next_command = this.calibrate;
this.bytes_expecting = 1;
break;
case 0x08:
this.check_interrupt_status();
break;
case 0x4A:
this.next_command = this.read_sector_id;
this.bytes_expecting = 1;
break;
case 0x0F:
this.bytes_expecting = 2;
this.next_command = this.seek;
break;
case 0x0E:
// dump regs
dbg_log("dump registers", LOG_DISK);
this.response_data[0] = 0x80;
this.response_index = 0;
this.response_length = 1;
this.bytes_expecting = 0;
break;
default:
if(DEBUG) throw "unimpl floppy command call " + h(reg_byte);
} }
this.receiving_index = 0;
}
};
// this should actually be write-only ... but people read it anyway
var dor = 0;
FloppyController.prototype.port3F2_read = function()
{
dbg_log("read 3F2: DOR", LOG_DISK);
return dor;
}
FloppyController.prototype.port3F2_write = function(value)
{
if((value & 4) === 4 && (dor & 4) === 0)
{
// reset
this.pic.push_irq(6);
} }
function check_interrupt_status() dbg_log("start motors: " + h(value >> 4), LOG_DISK);
{ dbg_log("enable dma: " + !!(value & 8), LOG_DISK);
// do not trigger an interrupt here dbg_log("reset fdc: " + !!(value & 4), LOG_DISK);
dbg_log("floppy check interrupt status", LOG_DISK); dbg_log("drive select: " + (value & 3), LOG_DISK);
dbg_log("DOR = " + h(value), LOG_DISK);
response_index = 0; dor = value;
response_length = 2;
response_data[0] = 1 << 5; }
response_data[1] = last_cylinder;
}
function do_sector(is_write, args) FloppyController.prototype.check_drive_status = function(args)
{ {
var head = args[2], dbg_log("check drive status", LOG_DISK);
cylinder = args[1],
sector = args[3],
sector_size = 128 << args[4],
read_count = args[5] - args[3] + 1,
read_offset = ((head + number_of_heads * cylinder) * sectors_per_track + sector - 1) * sector_size; this.response_index = 0;
this.response_length = 1;
dbg_log("Floppy Read", LOG_DISK); this.response_data[0] = 1 << 5;
dbg_log("from " + h(read_offset) + " length " + h(read_count * sector_size), LOG_DISK); }
dbg_log(cylinder + " / " + head + " / " + sector, LOG_DISK);
if(!args[4]) FloppyController.prototype.seek = function(args)
{ {
dbg_log("FDC: sector count is zero, use data length instead", LOG_DISK); dbg_log("seek", LOG_DISK);
}
if(is_write) this.last_cylinder = args[1];
{ this.last_head = args[0] >> 2 & 1;
dma.do_write(fda_image, read_offset, read_count * sector_size, 2, done);
}
else
{
dma.do_read(fda_image, read_offset, read_count * sector_size, 2, done);
}
function done(error)
{
if(error)
{
// TODO: Set appropriate bits
return;
}
sector++;
if(sector > sectors_per_track)
{
sector = 1;
head++;
if(head >= number_of_heads)
{
head = 0;
cylinder++;
}
}
last_cylinder = cylinder;
last_head = head;
last_sector = sector;
response_index = 0;
response_length = 7;
response_data[0] = head << 2 | 0x20;
response_data[1] = 0;
response_data[2] = 0;
response_data[3] = cylinder;
response_data[4] = head;
response_data[5] = sector;
response_data[6] = args[4];
if(dor & 8)
{
pic.push_irq(6);
}
}
}
function fix_drive_data(args) if(dor & 8)
{ {
dbg_log("floppy fix drive data " + args, LOG_DISK); this.pic.push_irq(6);
} }
}
function read_sector_id(args)
{ FloppyController.prototype.calibrate = function(args)
dbg_log("floppy read sector id " + args, LOG_DISK); {
dbg_log("floppy calibrate", LOG_DISK);
response_index = 0;
response_length = 7; if(dor & 8)
{
response_data[0] = 0; this.pic.push_irq(6);
response_data[1] = 0; }
response_data[2] = 0; }
response_data[3] = 0;
response_data[4] = 0; FloppyController.prototype.check_interrupt_status = function()
response_data[5] = 0; {
response_data[6] = 0; // do not trigger an interrupt here
dbg_log("floppy check interrupt status", LOG_DISK);
if(dor & 8)
{ this.response_index = 0;
pic.push_irq(6); this.response_length = 2;
}
this.response_data[0] = 1 << 5;
this.response_data[1] = this.last_cylinder;
}
FloppyController.prototype.do_sector = function(is_write, args)
{
var head = args[2],
cylinder = args[1],
sector = args[3],
sector_size = 128 << args[4],
read_count = args[5] - args[3] + 1,
read_offset = ((head + this.number_of_heads * cylinder) * this.sectors_per_track + sector - 1) * sector_size;
dbg_log("Floppy Read", LOG_DISK);
dbg_log("from " + h(read_offset) + " length " + h(read_count * sector_size), LOG_DISK);
dbg_log(cylinder + " / " + head + " / " + sector, LOG_DISK);
if(!args[4])
{
dbg_log("FDC: sector count is zero, use data length instead", LOG_DISK);
}
if(is_write)
{
this.dma.do_write(this.fda_image, read_offset, read_count * sector_size, 2, this.done.bind(this, args, cylinder, head, sector));
}
else
{
this.dma.do_read(this.fda_image, read_offset, read_count * sector_size, 2, this.done.bind(this, args, cylinder, head, sector));
}
};
FloppyController.prototype.done = function(cylinder, args, head, sector, error)
{
if(error)
{
// TODO: Set appropriate bits
return;
}
sector++;
if(sector > this.sectors_per_track)
{
sector = 1;
head++;
if(head >= this.number_of_heads)
{
head = 0;
cylinder++;
}
}
this.last_cylinder = cylinder;
this.last_head = head;
this.last_sector = sector;
this.response_index = 0;
this.response_length = 7;
this.response_data[0] = head << 2 | 0x20;
this.response_data[1] = 0;
this.response_data[2] = 0;
this.response_data[3] = cylinder;
this.response_data[4] = head;
this.response_data[5] = sector;
this.response_data[6] = args[4];
if(dor & 8)
{
this.pic.push_irq(6);
}
}
FloppyController.prototype.fix_drive_data = function(args)
{
dbg_log("floppy fix drive data " + args, LOG_DISK);
}
FloppyController.prototype.read_sector_id = function(args)
{
dbg_log("floppy read sector id " + args, LOG_DISK);
this.response_index = 0;
this.response_length = 7;
this.response_data[0] = 0;
this.response_data[1] = 0;
this.response_data[2] = 0;
this.response_data[3] = 0;
this.response_data[4] = 0;
this.response_data[5] = 0;
this.response_data[6] = 0;
if(dor & 8)
{
this.pic.push_irq(6);
} }
} }