Line 46... |
Line 46... |
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
|
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
|
before a single character is transmitted or received. */
|
before a single character is transmitted or received. */
|
static unsigned long char_clks(int dll, int dlh, int lcr)
|
static unsigned long char_clks(int dll, int dlh, int lcr)
|
{
|
{
|
float bauds_per_char = 1.;
|
float bauds_per_char = 1.;
|
unsigned long char_clks = ((dlh << 8) + dll) * UART_CLOCK_DIVIDER;
|
unsigned long char_clks = ((dlh << 8) + dll);
|
|
|
if (lcr & UART_LCR_PARITY)
|
if (lcr & UART_LCR_PARITY)
|
bauds_per_char = bauds_per_char + 1.;
|
bauds_per_char = bauds_per_char + 1.;
|
|
|
/* stop bits 1 or two */
|
/* stop bits 1 or two */
|
Line 330... |
Line 330... |
}
|
}
|
uarts[uart].regs.lsr |= UART_LSR_RDRDY;
|
uarts[uart].regs.lsr |= UART_LSR_RDRDY;
|
uarts[uart].istat.timeout_count = 0;
|
uarts[uart].istat.timeout_count = 0;
|
}
|
}
|
|
|
/* Reset. It initializes all registers of all UART devices to zero values,
|
|
(re)opens all RX/TX file streams and places devices in memory address
|
|
space. */
|
|
void uart_reset()
|
|
{
|
|
int i;
|
|
|
|
if (config.sim.verbose && config.nuarts)
|
|
printf("Resetting %u UART(s).\n", config.nuarts);
|
|
|
|
memset(uarts, 0, sizeof(uarts));
|
|
|
|
for(i = 0; i < config.nuarts; i++) {
|
|
if (config.uarts[i].vapi_id) {
|
|
if ((config.uarts[i].vapi_id & VAPI_DEVICE_ID) != i) {
|
|
fprintf (stderr, "ERROR: Wrong vapi_id (0x%x) for uart %i, last byte is required to be %02x; ignoring.\n", config.uarts[i].vapi_id, i, i);
|
|
config.uarts[i].vapi_id = 0;
|
|
uarts[i].txfs = 0;
|
|
} else {
|
|
vapi_install_handler (config.uarts[i].vapi_id, uart_vapi_read);
|
|
register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
|
|
}
|
|
} else if (config.uarts[i].txfile) { /* MM: Try to create stream. */
|
|
if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r"))
|
|
&& !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) {
|
|
debug (0, "WARNING: UART%d has problems with RX file stream.\n", i);
|
|
continue;
|
|
}
|
|
uarts[i].txfs = fopen(config.uarts[i].txfile, "a");
|
|
if (uarts[i].rxfs && uarts[i].txfs && config.sim.verbose) {
|
|
printf("UART%d at 0x%.8x uses ", i, config.uarts[i].baseaddr);
|
|
printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile);
|
|
} else
|
|
debug (1, "WARNING: UART%d has problems with TX file stream.\n", i);
|
|
register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
|
|
}
|
|
|
|
if (config.uarts[i].uart16550)
|
|
uarts[i].fifo_len = 16;
|
|
else
|
|
uarts[i].fifo_len = 1;
|
|
|
|
uarts[i].istat.rxbuf_head = uarts[i].istat.rxbuf_tail = 0;
|
|
uarts[i].istat.txbuf_head = uarts[i].istat.txbuf_tail = 0;
|
|
|
|
uarts[i].istat.break_set = 0;
|
|
uarts[i].istat.timeout_count = 0;
|
|
uarts[i].istat.thre_int = 1; /* FIFO is empty at start */
|
|
uarts[i].slowdown = UART_FGETC_SLOWDOWN;
|
|
|
|
uarts[i].regs.lcr = UART_LCR_RESET;
|
|
uarts[i].vapi.cur_break = uarts[i].vapi.cur_break_cnt = uarts[i].vapi.next_break = 0;
|
|
uarts[i].vapi.next_break_cnt = -1;
|
|
}
|
|
}
|
|
|
|
/* Simulation hook. Must be called every clock cycle to simulate all UART
|
/* Simulation hook. Must be called every clock cycle to simulate all UART
|
devices. It does internal functional UART simulation. */
|
devices. It does internal functional UART simulation. */
|
void uart_clock()
|
void uart_clock16(int i)
|
{
|
{
|
int i, retval;
|
int retval;
|
|
|
for(i = 0; i < config.nuarts; i++) {
|
|
/* If VAPI is not selected, UART communicates with two file streams;
|
/* If VAPI is not selected, UART communicates with two file streams;
|
if VAPI is selected, we use VAPI streams. */
|
if VAPI is selected, we use VAPI streams. */
|
|
|
/* if txfs is corrupted, skip this uart. */
|
/* if txfs is corrupted, skip this uart. */
|
if (!config.uarts[i].vapi_id && !uarts[i].txfs) continue;
|
if (!config.uarts[i].vapi_id && !uarts[i].txfs) return;
|
|
|
if (uarts[i].vapi.next_break_cnt >= 0)
|
if (uarts[i].vapi.next_break_cnt >= 0)
|
if (--uarts[i].vapi.next_break_cnt < 0) {
|
if (--uarts[i].vapi.next_break_cnt < 0) {
|
if (!(uarts[i].vapi.cur_break = uarts[i].vapi.next_break))
|
if (!(uarts[i].vapi.cur_break = uarts[i].vapi.next_break))
|
uarts[i].istat.break_set = 0;
|
uarts[i].istat.break_set = 0;
|
Line 494... |
Line 436... |
} else uarts[i].slowdown = UART_FGETC_SLOWDOWN;
|
} else uarts[i].slowdown = UART_FGETC_SLOWDOWN;
|
}
|
}
|
} else { /* VAPI */
|
} else { /* VAPI */
|
int received = 0;
|
int received = 0;
|
/* do not handle commands while receiving */
|
/* do not handle commands while receiving */
|
if (uarts[i].istat.rxser_full)
|
if (uarts[i].istat.rxser_full) return;
|
break;
|
|
while (!received) {
|
while (!received) {
|
if (uarts[i].vapi_buf_head_ptr != uarts[i].vapi_buf_tail_ptr) {
|
if (uarts[i].vapi_buf_head_ptr != uarts[i].vapi_buf_tail_ptr) {
|
unsigned long data = uarts[i].vapi_buf[uarts[i].vapi_buf_tail_ptr];
|
unsigned long data = uarts[i].vapi_buf[uarts[i].vapi_buf_tail_ptr];
|
debug(4, "Handling: %08x (%i,%i)\n", data, uarts[i].vapi_buf_head_ptr, uarts[i].vapi_buf_tail_ptr);
|
debug(4, "Handling: %08x (%i,%i)\n", data, uarts[i].vapi_buf_head_ptr, uarts[i].vapi_buf_tail_ptr);
|
uarts[i].vapi_buf_tail_ptr = (uarts[i].vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
|
uarts[i].vapi_buf_tail_ptr = (uarts[i].vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
|
Line 601... |
Line 542... |
}
|
}
|
if (!(uarts[i].regs.iir & UART_IIR_NO_INT)) {
|
if (!(uarts[i].regs.iir & UART_IIR_NO_INT)) {
|
debug (4, "uarts[i].regs.iir = %i\t", uarts[i].regs.iir);
|
debug (4, "uarts[i].regs.iir = %i\t", uarts[i].regs.iir);
|
report_interrupt(config.uarts[i].irq);
|
report_interrupt(config.uarts[i].irq);
|
}
|
}
|
|
SCHED_ADD (uart_clock16, i, cycles + UART_CLOCK_DIVIDER);
|
|
}
|
|
|
|
/* Reset. It initializes all registers of all UART devices to zero values,
|
|
(re)opens all RX/TX file streams and places devices in memory address
|
|
space. */
|
|
void uart_reset()
|
|
{
|
|
int i;
|
|
if (config.sim.verbose && config.nuarts) printf("Resetting %u UART(s).\n", config.nuarts);
|
|
memset(uarts, 0, sizeof(uarts));
|
|
|
|
for(i = 0; i < config.nuarts; i++) {
|
|
if (config.uarts[i].vapi_id) {
|
|
if ((config.uarts[i].vapi_id & VAPI_DEVICE_ID) != i) {
|
|
fprintf (stderr, "ERROR: Wrong vapi_id (0x%x) for uart %i, last byte is required to be %02x; ignoring.\n", config.uarts[i].vapi_id, i, i);
|
|
config.uarts[i].vapi_id = 0;
|
|
uarts[i].txfs = 0;
|
|
} else {
|
|
vapi_install_handler (config.uarts[i].vapi_id, uart_vapi_read);
|
|
register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
|
|
}
|
|
} else if (config.uarts[i].txfile) { /* MM: Try to create stream. */
|
|
if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r"))
|
|
&& !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) {
|
|
debug (0, "WARNING: UART%d has problems with RX file stream.\n", i);
|
|
continue;
|
|
}
|
|
uarts[i].txfs = fopen(config.uarts[i].txfile, "a");
|
|
if (uarts[i].rxfs && uarts[i].txfs && config.sim.verbose) {
|
|
printf("UART%d at 0x%.8x uses ", i, config.uarts[i].baseaddr);
|
|
printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile);
|
|
} else
|
|
debug (1, "WARNING: UART%d has problems with TX file stream.\n", i);
|
|
register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
|
|
}
|
|
|
|
if (config.uarts[i].uart16550)
|
|
uarts[i].fifo_len = 16;
|
|
else
|
|
uarts[i].fifo_len = 1;
|
|
|
|
uarts[i].istat.rxbuf_head = uarts[i].istat.rxbuf_tail = 0;
|
|
uarts[i].istat.txbuf_head = uarts[i].istat.txbuf_tail = 0;
|
|
|
|
uarts[i].istat.break_set = 0;
|
|
uarts[i].istat.timeout_count = 0;
|
|
uarts[i].istat.thre_int = 1; /* FIFO is empty at start */
|
|
uarts[i].slowdown = UART_FGETC_SLOWDOWN;
|
|
|
|
uarts[i].regs.lcr = UART_LCR_RESET;
|
|
uarts[i].vapi.cur_break = uarts[i].vapi.cur_break_cnt = uarts[i].vapi.next_break = 0;
|
|
uarts[i].vapi.next_break_cnt = -1;
|
|
SCHED_ADD (uart_clock16, i, cycles + UART_CLOCK_DIVIDER);
|
}
|
}
|
}
|
}
|
|
|
/* Print register values on stdout. */
|
/* Print register values on stdout. */
|
void uart_status()
|
void uart_status()
|