uart: support RX

This commit is contained in:
Zihao Yu 2024-01-09 02:19:15 +08:00
parent 28190b0c3e
commit fd00b7854b
7 changed files with 59 additions and 17 deletions

View File

@ -7,5 +7,6 @@
1. 拨动右边的8个拨码开关, 可控制对应LED的亮灭
1. 按下按钮可将8~12号中对应的LED亮灭效果取反
1. 8个数码管流水显示数字0-7
1. 窗口右侧为VGA输出, 将会展示一张图片
1. 窗口左下角为VGA输出, 将会展示一张图片
1. 窗口右侧中部为UART RX输入, 鼠标选中后可输入字符串, 按回车后字符串将通过UART RX端输入, 通过回环连接从UART TX端输出, 显示在右上方终端
1. 敲击键盘, 终端将会输出按键的扫描码

View File

@ -22,3 +22,6 @@ seg7 (SEG7A, SEG7B, SEG7C, SEG7D, SEG7E, SEG7F, SEG7G, DEC7P)
ps2_clk PS2_CLK
ps2_data PS2_DAT
uart_tx UART_TX
uart_rx UART_RX

View File

@ -5,6 +5,8 @@ module top(
input [7:0] sw,
input ps2_clk,
input ps2_data,
input uart_rx,
output uart_tx,
output [15:0] ledr,
output VGA_CLK,
output VGA_HSYNC,
@ -77,6 +79,11 @@ vmem my_vmem(
.vga_data(vga_data)
);
uart my_uart(
.tx(uart_tx),
.rx(uart_rx)
);
endmodule
module vmem(

6
example/vsrc/uart.v Normal file
View File

@ -0,0 +1,6 @@
module uart (
output tx,
input rx
);
assign tx = rx;
endmodule

View File

@ -8,10 +8,11 @@
class UART : public Component{
private:
Term *tx_term, *rx_term;
int state;
int tx_state, rx_state;
uint16_t divisor;
uint8_t data;
uint8_t tx_data, rx_data;
std::string rx_input;
std::string rx_sending_str;
static constexpr const char *rx_input_prompt = "UART TX (Press Enter to issue): ";
bool tx_update_gui, rx_update_gui;
uint8_t *p_tx;
@ -22,7 +23,8 @@ public:
virtual void update_gui();
virtual void update_state();
void tx_check();
void tx_receive();
void rx_send();
void rx_getchar(uint8_t);
};

View File

@ -25,7 +25,10 @@ void nvboard_update() {
extern UART* uart;
extern int16_t uart_divisor_cnt;
if (unlikely((-- uart_divisor_cnt) < 0)) uart->tx_check();
if (unlikely((-- uart_divisor_cnt) < 0)) {
uart->tx_receive();
uart->rx_send();
}
static uint64_t last = 0;
static int cpf = 1; // count per frame

View File

@ -10,7 +10,7 @@ int16_t uart_divisor_cnt = 0;
UART::UART(SDL_Renderer *rend, int cnt, int init_val, int ct, int x, int y, int w, int h):
Component(rend, cnt, init_val, ct),
state(0), divisor(16), tx_update_gui(false) {
tx_state(0), rx_state(0), divisor(16), tx_update_gui(false) {
tx_term = new Term(rend, x, y, w, h);
rx_term = new Term(rend, x, y + h, w, 20);
uart_divisor_cnt = divisor - 1;
@ -20,7 +20,9 @@ UART::UART(SDL_Renderer *rend, int cnt, int init_val, int ct, int x, int y, int
rx_term->feed_str(rx_input_prompt);
rx_input = "";
rx_sending_str = "";
rx_update_gui = true;
pin_poke(UART_RX, 1);
}
UART::~UART() {
@ -30,30 +32,48 @@ UART::~UART() {
void UART::update_gui() { // everything is done in update_state()
}
void UART::tx_check() {
void UART::tx_receive() {
uart_divisor_cnt = divisor - 1;
uint8_t tx = *p_tx;
if (state == 0) { // idle
if (tx_state == 0) { // idle
if (!tx) { // start bit
data = 0;
state ++;
tx_data = 0;
tx_state ++;
}
} else if (state >= 1 && state <= 8) { // data
data = (tx << 7) | (data >> 1); // data bit
state ++;
} else if (state == 9) {
} else if (tx_state >= 1 && tx_state <= 8) { // data
tx_data = (tx << 7) | (tx_data >> 1); // data bit
tx_state ++;
} else if (tx_state == 9) {
if (tx) { // stop bit
state = 0;
tx_term->feed_ch(data);
tx_state = 0;
tx_term->feed_ch(tx_data);
tx_update_gui = true;
}
}
}
void UART::rx_send() {
// the uart_divisor_cnt is maintained in tx_receive()
if (rx_state == 0) { // idle
rx_data = rx_sending_str[0];
if (rx_data == '\0') return;
rx_sending_str.erase(0, 1);
pin_poke(UART_RX, 0); // start bit
rx_state ++;
} else if (rx_state >= 1 && rx_state <= 8) { // data
pin_poke(UART_RX, rx_data & 1); // data bit
rx_data >>= 1;
rx_state ++;
} else if (rx_state == 9) {
pin_poke(UART_RX, 1); // stop bit
rx_state = 0;
}
}
void UART::rx_getchar(uint8_t ch) {
if (ch == '\n') {
printf("Get RX input = %s\n", rx_input.c_str());
rx_sending_str += rx_input;
rx_term->clear();
rx_term->feed_str(rx_input_prompt);
rx_input = "";