2013-11-06 01:12:55 +01:00
|
|
|
/**
|
|
|
|
* No full implementation, just dumping serial output
|
|
|
|
* to console
|
|
|
|
*
|
2014-01-08 03:14:33 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** @const */
|
|
|
|
var DLAB = 0x80;
|
|
|
|
|
|
|
|
/**
|
2013-11-06 01:12:55 +01:00
|
|
|
* @constructor
|
|
|
|
*/
|
2014-06-15 22:25:17 +02:00
|
|
|
function UART(cpu, port, adapter)
|
2013-11-06 01:12:55 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.pic = cpu.devices.pic;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.line = "";
|
|
|
|
this.baud_rate = 0;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.line_control = 0;
|
|
|
|
this.line_status = 0;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.fifo_control = 0;
|
|
|
|
this.interrupt_enable = 0;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
// interrupt identification register
|
|
|
|
this.iir = 1;
|
2014-06-02 22:31:25 +02:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.modem_control = 0;
|
|
|
|
this.modem_status = 0;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.scratch_register = 0;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.irq = 0;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
this.input = new ByteQueue(4096);
|
2014-01-08 03:14:33 +01:00
|
|
|
|
|
|
|
if(port === 0x3E8 || port === 0x3F8)
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.irq = 4;
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
else if(port === 0x3E8 || port === 0x3E8)
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.irq = 3;
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbg_log("Invalid port: " + h(port), LOG_SERIAL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
function data_received(data)
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.input.push(data);
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
if(this.interrupt_enable & 1)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.push_irq();
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
}
|
2014-10-04 20:50:31 +02:00
|
|
|
adapter.init(data_received.bind(this));
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
var io = cpu.io;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_write(port, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
if(this.line_control & DLAB)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.baud_rate = this.baud_rate & ~0xFF | out_byte;
|
2014-01-08 03:14:33 +01:00
|
|
|
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)
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
adapter.put_line(this.line);
|
|
|
|
this.line = "";
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.line += String.fromCharCode(out_byte);
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
adapter.put_str(String.fromCharCode(out_byte));
|
|
|
|
}
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_write(port | 1, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
if(this.line_control & DLAB)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.baud_rate = this.baud_rate & 0xFF | out_byte << 8;
|
|
|
|
dbg_log("baud rate: " + h(this.baud_rate), LOG_SERIAL);
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.interrupt_enable = out_byte;
|
2014-01-08 03:14:33 +01:00
|
|
|
dbg_log("interrupt enable: " + h(out_byte), LOG_SERIAL);
|
|
|
|
}
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2013-11-06 01:12:55 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port, this, function()
|
2013-11-06 01:12:55 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
if(this.line_control & DLAB)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
return this.baud_rate & 0xFF;
|
2014-01-08 03:14:33 +01:00
|
|
|
}
|
|
|
|
else
|
2013-11-06 01:12:55 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
var data = this.input.shift();
|
2014-01-05 03:19:09 +01:00
|
|
|
|
2014-01-08 03:14:33 +01:00
|
|
|
if(data === -1)
|
|
|
|
{
|
|
|
|
dbg_log("Input empty", LOG_SERIAL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dbg_log("Input: " + h(data), LOG_SERIAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 1, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
if(this.line_control & DLAB)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
return this.baud_rate >> 8;
|
2013-11-06 01:12:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
return this.interrupt_enable;
|
2013-11-06 01:12:55 +01:00
|
|
|
}
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2013-12-20 22:05:49 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 2, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
var ret = this.iir;
|
|
|
|
dbg_log("read interrupt identification: " + h(this.iir), LOG_SERIAL);
|
|
|
|
this.iir ^= 1;
|
2014-06-02 22:31:25 +02:00
|
|
|
|
|
|
|
return ret;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
|
|
|
io.register_write(port | 2, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
|
|
|
dbg_log("fifo control: " + h(out_byte), LOG_SERIAL);
|
2014-10-04 20:50:31 +02:00
|
|
|
this.fifo_control = out_byte;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 3, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
dbg_log("read line control: " + h(this.line_control), LOG_SERIAL);
|
|
|
|
return this.line_control;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
|
|
|
io.register_write(port | 3, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
|
|
|
dbg_log("line control: " + h(out_byte), LOG_SERIAL);
|
2014-10-04 20:50:31 +02:00
|
|
|
this.line_control = out_byte;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 4, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
return this.modem_control;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
|
|
|
io.register_write(port | 4, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
|
|
|
dbg_log("modem control: " + h(out_byte), LOG_SERIAL);
|
2014-10-04 20:50:31 +02:00
|
|
|
this.modem_control = out_byte;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 5, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
|
|
|
var line_status = 0;
|
|
|
|
|
2014-10-04 20:50:31 +02:00
|
|
|
if(this.input.length)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
|
|
|
line_status |= 1;
|
|
|
|
}
|
|
|
|
|
2014-06-02 22:31:25 +02:00
|
|
|
line_status |= 0x20 | 0x40;
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-06-02 22:31:25 +02:00
|
|
|
dbg_log("read line status: " + h(line_status), LOG_SERIAL);
|
2014-01-08 03:14:33 +01:00
|
|
|
return line_status;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
|
|
|
io.register_write(port | 5, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-06-02 22:31:25 +02:00
|
|
|
dbg_log("Factory test write", LOG_SERIAL);
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 6, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
dbg_log("read modem status: " + h(this.modem_status), LOG_SERIAL);
|
|
|
|
return this.modem_status;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
|
|
|
io.register_write(port | 6, this, function(out_byte)
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-06-02 22:31:25 +02:00
|
|
|
dbg_log("Unkown register write (base+6)", LOG_SERIAL);
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2014-01-08 03:14:33 +01:00
|
|
|
|
2014-10-21 21:51:42 +02:00
|
|
|
io.register_read(port | 7, this, function()
|
2014-01-08 03:14:33 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
return this.scratch_register;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
|
|
|
io.register_write(port | 7, this, function(out_byte)
|
2013-12-20 22:05:49 +01:00
|
|
|
{
|
2014-10-04 20:50:31 +02:00
|
|
|
this.scratch_register = out_byte;
|
2014-10-21 21:51:42 +02:00
|
|
|
});
|
2013-11-06 01:12:55 +01:00
|
|
|
}
|
2014-10-04 20:50:31 +02:00
|
|
|
|
|
|
|
UART.prototype.push_irq = function()
|
|
|
|
{
|
|
|
|
this.pic.push_irq(this.irq);
|
|
|
|
};
|
|
|
|
|