Skip to content

Commit ce3562e

Browse files
committed
Emulate UART Interrupt: UART_LSR, UART_IIR, UART_RBR
1 parent e09e8c4 commit ce3562e

File tree

1 file changed

+28
-15
lines changed

1 file changed

+28
-15
lines changed

riscv_cpu.c

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "riscv_cpu_priv.h"
5555

5656
void print_console(void *machine0, const char *buf, int len); ////
57+
char read_input(void); ////
5758
extern uint64_t ecall_addr;
5859
extern uint64_t rdtime_addr;
5960
extern uint64_t dcache_iall_addr;
@@ -393,31 +394,43 @@ int target_read_slow(RISCVCPUState *s, mem_uint_t *pval,
393394

394395
#define UART0_BASE_ADDR 0x04140000
395396
#define CONFIG_16550_REGINCR 4
397+
#define UART_RBR_INCR 0 /* (DLAB =0) Receiver Buffer Register */
396398
#define UART_THR_INCR 0 /* (DLAB =0) Transmit Holding Register */
399+
#define UART_IIR_INCR 2 /* Interrupt ID Register */
397400
#define UART_LSR_INCR 5 /* Line Status Register */
401+
#define UART_RBR_OFFSET (CONFIG_16550_REGINCR*UART_RBR_INCR)
398402
#define UART_THR_OFFSET (CONFIG_16550_REGINCR*UART_THR_INCR)
403+
#define UART_IIR_OFFSET (CONFIG_16550_REGINCR*UART_IIR_INCR)
399404
#define UART_LSR_OFFSET (CONFIG_16550_REGINCR*UART_LSR_INCR)
405+
#define UART_IIR_INTSTATUS (1 << 0) /* Bit 0: Interrupt status (active low) */
406+
#define UART_IIR_INTID_SHIFT (1) /* Bits 1-3: Interrupt identification */
407+
#define UART_IIR_INTID_RDA (2 << UART_IIR_INTID_SHIFT) /* Receive Data Available (RDA) */
408+
#define UART_LSR_DR (1 << 0) /* Bit 0: Data Ready */
400409
#define UART_LSR_THRE (1 << 5) /* Bit 5: Transmitter Holding Register Empty */
401410

402411
// Console Output: Line Status Register
403-
case UART0_BASE_ADDR + UART_LSR_OFFSET:
412+
case UART0_BASE_ADDR + UART_LSR_OFFSET: {
404413
// _info("read UART_LSR_OFFSET\n");
405414
ret = UART_LSR_THRE; // Always return Transmit Holding Register is Empty
415+
if (read_input() != 0) {
416+
ret |= UART_LSR_DR; // Receive Data Available
417+
}
406418
break;
407-
408-
// TODO: Console Input: BL808_UART_INT_STS (0x30002020) must return UART_INT_STS_URX_END_INT (1 << 1)
409-
case 0x30002020:
410-
_info("read BL808_UART_INT_STS\n");
411-
ret = (1 << 1); break;
412-
413-
// TODO: Console Input: BL808_UART_INT_MASK (0x30002024) must NOT return UART_INT_MASK_CR_URX_END_MASK (1 << 1)
414-
case 0x30002024:
415-
_info("read BL808_UART_INT_MASK\n");
416-
ret = 0; break;
417-
418-
// TODO: Console Input: BL808_UART_FIFO_RDATA_OFFSET (0x3000208c) returns the Input Char
419-
case 0x3000208c: {
420-
char read_input(void);
419+
}
420+
// Console Input: Interrupt ID Register
421+
case UART0_BASE_ADDR + UART_IIR_OFFSET: {
422+
_info("read UART_IIR_OFFSET\n");
423+
if (read_input() == 0) {
424+
ret = UART_IIR_INTSTATUS; // Receive Data NOT Available
425+
} else {
426+
ret = UART_IIR_INTID_RDA; // Receive Data Available
427+
}
428+
break;
429+
}
430+
// Console Input: Receiver Buffer Register
431+
case UART0_BASE_ADDR + UART_RBR_OFFSET: {
432+
// Return the Input Buffer
433+
_info("read UART_RBR_OFFSET\n");
421434
ret = read_input();
422435

423436
// Clear the Input Buffer

0 commit comments

Comments
 (0)