blob: 08eca372fe88e210b84b0f28f8ae67869f9b3bfe [file] [log] [blame] [raw]
/**
* No full implementation, just dumping serial output
* to console
*
*/
/** @const */
var DLAB = 0x80;
/**
* @constructor
*/
function UART(cpu, port, adapter)
{
var io = cpu.io,
pic = cpu.devices.pic,
line = "",
baud_rate = 0,
line_control = 0,
line_status = 0,
fifo_control = 0,
interrupt_enable = 0,
// interrupt identification register
iir = 1,
modem_control = 0,
modem_status = 0,
scratch_register = 0,
irq = 0,
input = new ByteQueue(4096);
if(port === 0x3E8 || port === 0x3F8)
{
irq = 4;
}
else if(port === 0x3E8 || port === 0x3E8)
{
irq = 3;
}
else
{
dbg_log("Invalid port: " + h(port), LOG_SERIAL);
return;
}
function data_received(data)
{
input.push(data);
if(interrupt_enable & 1)
{
push_irq();
}
}
adapter.init(data_received);
function push_irq()
{
pic.push_irq(irq);
}
io.register_write(port, function(out_byte)
{
if(line_control & DLAB)
{
baud_rate = baud_rate & ~0xFF | out_byte;
return;
}
//dbg_log("data: " + h(out_byte), LOG_SERIAL);
if(out_byte === 0xFF)
{
return;
}
if(!adapter)
{
return;
}
if(adapter.put_line)
{
if(out_byte === 0x0A)
{
adapter.put_line(line);
line = "";
}
else
{
line += String.fromCharCode(out_byte);
}
}
else
{
adapter.put_str(String.fromCharCode(out_byte));
}
});
io.register_write(port | 1, function(out_byte)
{
if(line_control & DLAB)
{
baud_rate = baud_rate & 0xFF | out_byte << 8;
dbg_log("baud rate: " + h(baud_rate), LOG_SERIAL);
}
else
{
interrupt_enable = out_byte;
dbg_log("interrupt enable: " + h(out_byte), LOG_SERIAL);
}
});
io.register_read(port, function()
{
if(line_control & DLAB)
{
return baud_rate & 0xFF;
}
else
{
var data = input.shift();
if(data === -1)
{
dbg_log("Input empty", LOG_SERIAL);
}
else
{
dbg_log("Input: " + h(data), LOG_SERIAL);
}
return data;
}
});
io.register_read(port | 1, function()
{
if(line_control & DLAB)
{
return baud_rate >> 8;
}
else
{
return interrupt_enable;
}
});
io.register_read(port | 2, function()
{
var ret = iir;
dbg_log("read interrupt identification: " + h(iir), LOG_SERIAL);
iir ^= 1;
return ret;
});
io.register_write(port | 2, function(out_byte)
{
dbg_log("fifo control: " + h(out_byte), LOG_SERIAL);
fifo_control = out_byte;
});
io.register_read(port | 3, function()
{
dbg_log("read line control: " + h(line_control), LOG_SERIAL);
return line_control;
});
io.register_write(port | 3, function(out_byte)
{
dbg_log("line control: " + h(out_byte), LOG_SERIAL);
line_control = out_byte;
});
io.register_read(port | 4, function()
{
return modem_control;
});
io.register_write(port | 4, function(out_byte)
{
dbg_log("modem control: " + h(out_byte), LOG_SERIAL);
modem_control = out_byte;
});
io.register_read(port | 5, function()
{
var line_status = 0;
if(input.length)
{
line_status |= 1;
}
line_status |= 0x20 | 0x40;
dbg_log("read line status: " + h(line_status), LOG_SERIAL);
return line_status;
});
io.register_write(port | 5, function(out_byte)
{
dbg_log("Factory test write", LOG_SERIAL);
});
io.register_read(port | 6, function()
{
dbg_log("read modem status: " + h(modem_status), LOG_SERIAL);
return modem_status;
});
io.register_write(port | 6, function(out_byte)
{
dbg_log("Unkown register write (base+6)", LOG_SERIAL);
});
io.register_read(port | 7, function()
{
return scratch_register;
});
io.register_write(port | 7, function(out_byte)
{
scratch_register = out_byte;
});
}