Merge branch 'uart-irq' into 'master'
Add UART Receive logic See merge request bslathi19/super6502!5
This commit is contained in:
@@ -117,6 +117,8 @@ SevenSeg segs(
|
||||
.HEX0(HEX0), .HEX1(HEX1), .HEX2(HEX2), .HEX3(HEX3), .HEX4(HEX4), .HEX5(HEX5)
|
||||
);
|
||||
|
||||
logic uart_irq;
|
||||
|
||||
uart uart(
|
||||
.clk_50(clk_50),
|
||||
.clk(clk),
|
||||
@@ -127,6 +129,7 @@ uart uart(
|
||||
.addr(cpu_addr[1:0]),
|
||||
.RXD(UART_RXD),
|
||||
.TXD(UART_TXD),
|
||||
.irq(uart_irq),
|
||||
.data_out(uart_data_out)
|
||||
);
|
||||
|
||||
@@ -135,8 +138,13 @@ always_ff @(posedge clk_50) begin
|
||||
irq_data_out <= '0;
|
||||
else if (irq_cs && ~cpu_rwb)
|
||||
irq_data_out <= irq_data_out & cpu_data_in;
|
||||
else if (~button_1)
|
||||
irq_data_out <= {irq_data_out[7:1], ~button_1};
|
||||
|
||||
else begin
|
||||
if (~button_1)
|
||||
irq_data_out[0] <= '1;
|
||||
if (uart_irq)
|
||||
irq_data_out[1] <= '1;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
131
hw/fpga/uart.sv
131
hw/fpga/uart.sv
@@ -12,6 +12,7 @@ module uart(
|
||||
|
||||
output logic TXD,
|
||||
|
||||
output logic irq,
|
||||
output logic [7:0] data_out
|
||||
);
|
||||
|
||||
@@ -22,18 +23,24 @@ logic [7:0] rx_buf;
|
||||
logic [7:0] status;
|
||||
|
||||
logic tx_flag;
|
||||
logic rx_flag;
|
||||
|
||||
logic tx_flag_set;
|
||||
logic tx_flag_clear;
|
||||
logic rx_flag_set;
|
||||
logic rx_flag_clear;
|
||||
|
||||
assign status[0] = tx_flag | tx_flag_clear;
|
||||
assign status[1] = rx_flag | rx_flag_set;
|
||||
|
||||
assign irq = status[1];
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (rst) begin
|
||||
tx_flag_set <= '0;
|
||||
rx_flag_clear <= '0;
|
||||
tx_buf <= '0;
|
||||
rx_buf <= '0;
|
||||
status[7:1] <= '0;
|
||||
status[7:2] <= '0;
|
||||
end
|
||||
|
||||
if (cs) begin
|
||||
@@ -52,26 +59,31 @@ always_ff @(posedge clk) begin
|
||||
tx_flag_set <= '1;
|
||||
else
|
||||
tx_flag_set <= '0;
|
||||
|
||||
if (rw & cs && addr == 0)
|
||||
rx_flag_clear <= '1;
|
||||
else
|
||||
rx_flag_clear <= '0;
|
||||
end
|
||||
|
||||
// state controller
|
||||
// tx state controller
|
||||
typedef enum bit [2:0] {START, DATA, PARITY, STOP, IDLE} macro_t;
|
||||
struct packed {
|
||||
macro_t macro;
|
||||
logic [3:0] count;
|
||||
} state, next_state;
|
||||
} tx_state, tx_next_state, rx_state, rx_next_state;
|
||||
localparam logic [3:0] maxcount = 4'h7;
|
||||
|
||||
// baud rate: 9600
|
||||
localparam baud = 9600;
|
||||
localparam count = (50000000/baud)-1;
|
||||
logic [14:0] clkdiv;
|
||||
logic [14:0] tx_clkdiv;
|
||||
|
||||
always_ff @(posedge clk_50) begin
|
||||
if (rst) begin
|
||||
clkdiv <= 0;
|
||||
state.macro <= IDLE;
|
||||
state.count <= 3'b0;
|
||||
tx_clkdiv <= 0;
|
||||
tx_state.macro <= IDLE;
|
||||
tx_state.count <= 3'b0;
|
||||
tx_flag <= '0;
|
||||
end else begin
|
||||
if (tx_flag_set)
|
||||
@@ -79,43 +91,43 @@ always_ff @(posedge clk_50) begin
|
||||
else if (tx_flag_clear)
|
||||
tx_flag <= '0;
|
||||
|
||||
if (clkdiv == count) begin
|
||||
clkdiv <= 0;
|
||||
state <= next_state;
|
||||
if (tx_clkdiv == count) begin
|
||||
tx_clkdiv <= 0;
|
||||
tx_state <= tx_next_state;
|
||||
end else begin
|
||||
clkdiv <= clkdiv + 15'b1;
|
||||
tx_clkdiv <= tx_clkdiv + 15'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
tx_next_state = tx_state;
|
||||
|
||||
unique case (state.macro)
|
||||
unique case (tx_state.macro)
|
||||
START: begin
|
||||
next_state.macro = DATA;
|
||||
next_state.count = 3'b0;
|
||||
tx_next_state.macro = DATA;
|
||||
tx_next_state.count = 3'b0;
|
||||
end
|
||||
DATA: begin
|
||||
if (state.count == maxcount) begin
|
||||
next_state.macro = STOP; // or PARITY
|
||||
next_state.count = 3'b0;
|
||||
if (tx_state.count == maxcount) begin
|
||||
tx_next_state.macro = STOP; // or PARITY
|
||||
tx_next_state.count = 3'b0;
|
||||
end else begin
|
||||
next_state.count = state.count + 3'b1;
|
||||
next_state.macro = DATA;
|
||||
tx_next_state.count = tx_state.count + 3'b1;
|
||||
tx_next_state.macro = DATA;
|
||||
end
|
||||
end
|
||||
PARITY: begin
|
||||
end
|
||||
STOP: begin
|
||||
next_state.macro = IDLE;
|
||||
next_state.count = '0;
|
||||
tx_next_state.macro = IDLE;
|
||||
tx_next_state.count = '0;
|
||||
end
|
||||
IDLE: begin
|
||||
if (tx_flag)
|
||||
next_state.macro = START;
|
||||
tx_next_state.macro = START;
|
||||
else
|
||||
next_state.macro = IDLE;
|
||||
tx_next_state.macro = IDLE;
|
||||
end
|
||||
|
||||
default:;
|
||||
@@ -126,12 +138,12 @@ always_comb begin
|
||||
TXD = '1;
|
||||
tx_flag_clear = '0;
|
||||
|
||||
unique case (state.macro)
|
||||
unique case (tx_state.macro)
|
||||
START: begin
|
||||
TXD = '0;
|
||||
end
|
||||
DATA: begin
|
||||
TXD = tx_buf[state.count];
|
||||
TXD = tx_buf[tx_state.count];
|
||||
end
|
||||
PARITY: begin
|
||||
|
||||
@@ -148,4 +160,69 @@ always_comb begin
|
||||
endcase
|
||||
end
|
||||
|
||||
//basically in idle state we need to sample RXD very fast,
|
||||
//then as soon as we detect that RXD is low, we start clkdiv
|
||||
//going and then go into the start state.
|
||||
|
||||
logic [14:0] rx_clkdiv;
|
||||
|
||||
always_ff @(posedge clk_50) begin
|
||||
if (rst) begin
|
||||
rx_buf <= '0;
|
||||
rx_clkdiv <= 0;
|
||||
rx_state.macro <= IDLE;
|
||||
rx_state.count <= 3'b0;
|
||||
end else begin
|
||||
if (rx_flag_set)
|
||||
rx_flag <= '1;
|
||||
else if (rx_flag_clear)
|
||||
rx_flag <= '0;
|
||||
|
||||
if (rx_state.macro == IDLE) begin // Sample constantly in idle state
|
||||
rx_state <= rx_next_state;
|
||||
rx_clkdiv <= count/15'h2; // offset rx clock by 1/2 phase
|
||||
end else begin
|
||||
if (rx_clkdiv == count) begin // other states are as usual
|
||||
rx_clkdiv <= 0;
|
||||
rx_state <= rx_next_state;
|
||||
if (rx_state.macro == DATA)
|
||||
rx_buf[rx_state.count] = RXD;
|
||||
end else begin
|
||||
rx_clkdiv <= rx_clkdiv + 15'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
rx_next_state = rx_state;
|
||||
rx_flag_set = '0;
|
||||
|
||||
unique case (rx_state.macro)
|
||||
IDLE: begin
|
||||
if (~RXD)
|
||||
rx_next_state.macro = START;
|
||||
end
|
||||
START: begin
|
||||
rx_next_state.macro = DATA;
|
||||
rx_next_state.count = 3'b0;
|
||||
end
|
||||
DATA: begin
|
||||
if (rx_state.count == maxcount) begin
|
||||
rx_next_state.macro = STOP;
|
||||
rx_next_state.count = 3'b0;
|
||||
end else begin
|
||||
rx_next_state.count = rx_state.count + 3'b1;
|
||||
rx_next_state.macro = DATA;
|
||||
end
|
||||
end
|
||||
PARITY: begin
|
||||
end
|
||||
STOP: begin
|
||||
rx_flag_set = '1;
|
||||
rx_next_state.macro = IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define BUTTON (1 << 0)
|
||||
#define UART (1 << 1)
|
||||
|
||||
void irq_int();
|
||||
void nmi_int();
|
||||
|
||||
10
sw/irq.c
10
sw/irq.c
@@ -2,12 +2,14 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "interrupt.h"
|
||||
#include "uart.h"
|
||||
|
||||
// This is defined in main.c
|
||||
void puts(const char* s);
|
||||
|
||||
void handle_irq() {
|
||||
uint8_t status;
|
||||
char c;
|
||||
|
||||
puts("Interrupt Detected!\n");
|
||||
|
||||
@@ -17,4 +19,12 @@ void handle_irq() {
|
||||
puts("Button Interrupt!\n");
|
||||
irq_set_status(status & ~BUTTON);
|
||||
}
|
||||
if (status & UART) {
|
||||
puts("UART Interrupt!\n");
|
||||
c = uart_rxb();
|
||||
puts("Received: ");
|
||||
puts(&c);
|
||||
puts("\n");
|
||||
irq_set_status(status & ~UART);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
void uart_txb(uint8_t val);
|
||||
void uart_txb_block(uint8_t val);
|
||||
|
||||
uint8_t uart_rxb();
|
||||
|
||||
uint8_t uart_status();
|
||||
|
||||
#endif
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
.importzp sp, sreg
|
||||
|
||||
.export _uart_txb
|
||||
.export _uart_txb_block
|
||||
.export _uart_txb, _uart_txb_block
|
||||
.export _uart_rxb
|
||||
.export _uart_status
|
||||
|
||||
.autoimport on
|
||||
@@ -23,6 +23,11 @@ _uart_txb_block:
|
||||
bne @1
|
||||
rts
|
||||
|
||||
_uart_rxb:
|
||||
lda UART_RXB ; Read value
|
||||
ldx #$00
|
||||
rts
|
||||
|
||||
_uart_status:
|
||||
lda UART_STATUS
|
||||
ldx #$00
|
||||
|
||||
Reference in New Issue
Block a user