From 08828b1f127f675acda00694dc228616fdcb062d Mon Sep 17 00:00:00 2001 From: fstolzcode <16044340+fstolzcode@users.noreply.github.com> Date: Fri, 12 Apr 2024 18:25:18 +0200 Subject: [PATCH] new version with controller and sign --- info.yaml | 6 +- src/alu.sv | 226 ------------------------------------- src/{adder.sv => fpu.v} | 27 ++++- src/project.v | 239 +++++++++++++++++++++++----------------- src/uart_rx.sv | 189 ------------------------------- src/uart_rx.v | 207 ++++++++++++++++++++++++++++++++++ src/uart_tx.sv | 97 ---------------- src/uart_tx.v | 187 +++++++++++++++++++++++++++++++ 8 files changed, 556 insertions(+), 622 deletions(-) delete mode 100644 src/alu.sv rename src/{adder.sv => fpu.v} (93%) delete mode 100644 src/uart_rx.sv create mode 100644 src/uart_rx.v delete mode 100644 src/uart_tx.sv create mode 100644 src/uart_tx.v diff --git a/info.yaml b/info.yaml index ff3e88d..ad5b92b 100644 --- a/info.yaml +++ b/info.yaml @@ -16,9 +16,9 @@ project: # List your project's source files here. Source files must be in ./src and you must list each source file separately, one per line: source_files: - "project.v" - - "adder.sv" - - "uart_rx.sv" - - "uart_tx.sv" + - "fpu.v" + - "uart_rx.v" + - "uart_tx.v" # The pinout of your project. Leave unused pins blank. DO NOT delete or add any pins. pinout: diff --git a/src/alu.sv b/src/alu.sv deleted file mode 100644 index 9a606cc..0000000 --- a/src/alu.sv +++ /dev/null @@ -1,226 +0,0 @@ -module full_adder( - input wire a, - input wire b, - input wire c_in, - output wire out, - output wire c_out -); - assign out = a ^ b ^ c_in; - assign c_out = (a & b) | (a & c_in) | (b & c_in); -endmodule - -module shift_register( - input wire clk, - input wire reset, - input wire en, - input wire latch, - input wire left, - input wire shift_in, - input wire [16:0] a, - output wire [16:0] out -); - reg [16:0] shift_reg; - assign out = shift_reg; - always @(posedge clk) begin - if(reset == 1'b1) begin - shift_reg <= 0; - end else if(latch == 1'b1) begin - shift_reg <= a; - end else if(en == 1'b1) begin - if(left == 1'b1) begin - shift_reg <= {shift_reg[15:0],shift_in}; - end else begin - shift_reg <= {shift_in,shift_reg[16:1]}; - end - end - end -endmodule - -module serial_shifter( - input wire clk, - input wire reset, - input wire en, - input wire left, - input wire [16:0] a, - input wire [4:0] amount, - output reg done, - output reg [16:0] out - -); - reg shift_en; - reg shift_latch; - wire [16:0] shift_out; - shift_register internal_shift( - .clk(clk), - .reset(reset), - .en(shift_en), - .latch(shift_latch), - .left(left), - .shift_in(1'b0), - .a(a), - .out(shift_out) - ); - - parameter FSMS_SIZE = 3; - parameter FSMS_IDLE = 3'd0, FSMS_LATCH = 3'd1, FSMS_LATCH_SETTLE = 3'd2, FSMS_SHIFT = 3'd3, FSMS_RESULT = 3'd4; - reg [FSMS_SIZE-1:0] state; - reg [4:0] cnt; - always @(posedge clk) begin - if(reset == 1'b1) begin - out <= 0; - done <= 0; - shift_en <= 0; - shift_latch <= 0; - cnt <= 0; - state <= FSMS_IDLE; - end else begin - case(state) - FSMS_IDLE: begin - done <= 1; - shift_en <= 0; - shift_latch <= 0; - cnt <= 0; - if(en == 1'b1) begin - state <= FSMS_LATCH; - end - end - FSMS_LATCH: begin - done <= 0; - shift_latch <= 1; - state <= FSMS_LATCH_SETTLE; - end - FSMS_LATCH_SETTLE: begin - shift_latch <= 0; - state <= FSMS_SHIFT; - end - FSMS_SHIFT: begin - if(cnt == amount) begin - shift_en <= 0; - state <= FSMS_RESULT; - end else begin - shift_en <= 1; - cnt <= cnt + 1'b1; - end - end - FSMS_RESULT: begin - out <= shift_out; - state <= FSMS_IDLE; - end - endcase - end - end -endmodule - -module serial_adder( - input wire clk, - input wire reset, - input wire en, - input wire [16:0] a, - input wire [16:0] b, - input c_in, - output reg done, - output reg [16:0] out, - output reg c_out -); - - reg shift_en; - reg shift_latch; - wire [16:0] shift_out_a; - shift_register a_shift( - .clk(clk), - .reset(reset), - .en(shift_en), - .latch(shift_latch), - .left(1'b0), - .shift_in(1'b0), - .a(a), - .out(shift_out_a) - ); - - wire [16:0] shift_out_b; - shift_register b_shift( - .clk(clk), - .reset(reset), - .en(shift_en), - .latch(shift_latch), - .left(1'b0), - .shift_in(1'b0), - .a(b), - .out(shift_out_b) - ); - - wire [16:0] shift_out_result; - wire fa_out; - shift_register result_shift( - .clk(clk), - .reset(reset), - .en(shift_en), - .latch(shift_latch), - .left(1'b0), - .shift_in(fa_out), - .a(17'b0), - .out(shift_out_result) - ); - - wire fa_c_out; - reg fa_c_in; - full_adder full_adder_ins( - .a(shift_out_a[0]), - .b(shift_out_b[0]), - .c_in(fa_c_in), - .out(fa_out), - .c_out(fa_c_out) - ); - - parameter FSMA_SIZE = 3; - parameter FSMA_IDLE = 3'd0, FSMA_LATCH = 3'd1, FSMA_LATCH_SETTLE = 3'd2, FSMA_ADD = 3'd3, FSMA_RESULT = 3'd4; - reg [FSMA_SIZE-1:0] state; - reg [4:0] cnt; - always @(posedge clk) begin - if (reset == 1'b1) begin - state <= FSMA_IDLE; - cnt <= 0; - done <= 0; - shift_en <= 0; - shift_latch <= 0; - fa_c_in <= 0; - c_out <= 0; - out <= 0; - end else begin - case(state) - FSMA_IDLE: begin - cnt <= 0; - done <= 1; - shift_en <= 0; - shift_latch <= 0; - fa_c_in <= 0; - if(en == 1'b1) begin - state <= FSMA_LATCH; - end - end - FSMA_LATCH: begin - done <= 0; - shift_latch <= 1; - state <= FSMA_LATCH_SETTLE; - end - FSMA_LATCH_SETTLE: begin - shift_latch <= 0; - state <= FSMA_ADD; - end - FSMA_ADD: begin - shift_en <= 1; - fa_c_in <= (cnt == 5'd0) ? c_in : fa_c_out; - cnt <= cnt + 5'd1; - if(cnt == 5'd17) begin - c_out <= fa_c_out; - state <= FSMA_RESULT; - end - end - FSMA_RESULT: begin - out <= shift_out_result; - state <= FSMA_IDLE; - end - endcase - end - end -endmodule \ No newline at end of file diff --git a/src/adder.sv b/src/fpu.v similarity index 93% rename from src/adder.sv rename to src/fpu.v index 692ef57..ebae954 100644 --- a/src/adder.sv +++ b/src/fpu.v @@ -91,10 +91,13 @@ module fpu( input wire reset, input wire add, input wire sub, + input wire reg1_s, input [6:0] reg1_e, input [14:0] reg1_m, + input wire reg2_s, input [6:0] reg2_e, input [14:0] reg2_m, + output reg res_s, output reg [6:0] res_e, output reg [14:0] res_m, output reg idle @@ -121,10 +124,10 @@ alu_17bit alu( ); -reg [7:0] alu8_a; -reg [7:0] alu8_b; +reg [16:0] alu8_a; +reg [16:0] alu8_b; reg alu8_cin; -wire [7:0] alu8_out; +wire [16:0] alu8_out; wire alu8_cout; alu_8bit alu8( .a(alu8_a), @@ -152,6 +155,7 @@ reg[16:0] ba; reg[16:0] bb; reg operation; +reg bs; always @ (posedge clk) begin : OUTPUT_LOGIC @@ -162,11 +166,13 @@ begin : OUTPUT_LOGIC ALU_IDLE: begin idle <= 1; if(add == 1'b1) begin - operation <= 0; + bs <= reg2_s; + operation <= (reg1_s == reg2_s) ? 0 : 1; state <= ADD0; end else if (sub == 1'b1) begin + bs <= ~reg2_s; + operation <= (reg1_s == reg2_s) ? 1 : 0; state <= ADD0; - operation <= 1; end end ADD0: begin @@ -183,6 +189,8 @@ begin : OUTPUT_LOGIC ab <= 0; aa <= reg1_e; + res_s <= reg1_s; + ba <= {2'b0,reg1_m}; shifter_in <= {2'b0,reg2_m}; shifter_amount <= alu8_out[7:0]; @@ -194,6 +202,8 @@ begin : OUTPUT_LOGIC aa <= 0; ab <= reg2_e; + res_s <= bs; + ba <= {2'b0,reg2_m}; alu8_a <= ~alu8_out; alu8_b <= 1; @@ -210,7 +220,11 @@ begin : OUTPUT_LOGIC ADD3: begin alu8_a <= aa; alu8_b <= ab; - if( (alu_out[16] | alu_out [15]) == 1'b1) begin + if (alu_out[16] == 1'b1) begin + $display("B NEGATIVE SIGN"); + res_s <= ~res_s; + end + if( (alu_out [15]) == 1'b1) begin $display("BE>2"); res_m <= alu_out[15:1]; alu8_cin <= 1; @@ -233,6 +247,7 @@ begin : OUTPUT_LOGIC end SUB0: begin if(alu_out[16] == 1'b1) begin + res_s <= ~res_s; $display("SUB NEGATIVE"); alu_a <= ~alu_out; alu_b <= 1; diff --git a/src/project.v b/src/project.v index 952645c..d1fce12 100644 --- a/src/project.v +++ b/src/project.v @@ -16,6 +16,7 @@ module tt_um_example ( input wire rst_n // reset_n - low to reset ); +wire reset = ~rst_n; assign uo_out[0] = 0; assign uo_out[1] = 0; assign uo_out[2] = 0; @@ -26,186 +27,222 @@ assign uo_out[7] = 0; assign uio_out = 0; assign uio_oe = 0; -wire clk_10MHZ; -assign clk_10MHZ = clk; -wire [7:0] rx_data; -wire rx_valid; +// Clock frequency in hertz. +parameter CLK_HZ = 10000000; +parameter BIT_RATE = 9600; +parameter PAYLOAD_BITS = 8; + +wire [PAYLOAD_BITS-1:0] uart_rx_data; +wire uart_rx_valid; + +wire uart_tx_busy; +reg uart_tx_en; +reg [7:0] uart_tx_data; + + +// UART RX uart_rx #( - .CLK_HZ( 10000000 ), // in Hertz - .BAUD( 9600 ) // max. BAUD is CLK_HZ / 2 -) uart_rx_ins( - .clk(clk_10MHZ), - .nrst(rst_n), - - .rx_data(rx_data), - .rx_done(rx_valid), - .rxd(ui_in[3]) +.BIT_RATE(BIT_RATE), +.PAYLOAD_BITS(PAYLOAD_BITS), +.CLK_HZ (CLK_HZ ) +) i_uart_rx( +.clk (clk ), // Top level system clock input. +.resetn (~reset ), // Asynchronous active low reset. +.uart_rxd (ui_in[3]), // UART Recieve pin. +.uart_rx_en (1'b1 ), // Recieve enable +.uart_rx_break(), // Did we get a BREAK message? +.uart_rx_valid(uart_rx_valid), // Valid data recieved and available. +.uart_rx_data (uart_rx_data) // The recieved data. ); -reg [7:0] tx_data; -reg tx_en; -wire tx_busy; +// +// UART Transmitter module. +// uart_tx #( - .CLK_HZ( 10000000 ), // in Hertz - .BAUD( 9600 ) // max. BAUD is CLK_HZ / 2 -) tx1 ( - .clk(clk_10MHZ), - .nrst(rst_n), - //.tx_do_sample( ), - .tx_data(tx_data), - .tx_start(tx_en), - .tx_busy(tx_busy), - .txd(uo_out[4]) +.BIT_RATE(BIT_RATE), +.PAYLOAD_BITS(PAYLOAD_BITS), +.CLK_HZ (CLK_HZ ) +) i_uart_tx( +.clk (clk ), +.resetn (~reset ), +.uart_txd (uo_out[4]), +.uart_tx_en (uart_tx_en ), +.uart_tx_busy (uart_tx_busy ), +.uart_tx_data (uart_tx_data ) ); -localparam CTRL_SIZE = 4; -localparam CTRL_IDLE = 4'd0,CTRL_SETR1 = 4'd1,CTRL_SETR2 = 4'd2,CTRL_READR1 = 4'd3,CTRL_READR2 = 4'd4,CTRL_READRS = 4'd5,CTRL_ADD=4'd6; - -reg [CTRL_SIZE-1:0] state ;// Seq part of the FSM -reg [CTRL_SIZE-1:0] next_state ;// combo part of FSM +reg r1s; reg [6:0] r1e; reg [14:0] r1m; +reg r2s; reg [6:0] r2e; reg [14:0] r2m; +wire rss; wire [6:0] rse; wire [14:0] rsm; + +localparam CTRL_SIZE = 4; +localparam CTRL_IDLE = 4'd0,CTRL_SETR1 = 4'd1,CTRL_SETR2 = 4'd2,CTRL_READR1 = 4'd3,CTRL_READR2 = 4'd4,CTRL_READRS = 4'd5,CTRL_ADD=4'd6,CTRL_SUB=4'd7,CTRL_WAIT=4'd8; + +reg [CTRL_SIZE-1:0] state ;// Seq part of the FSM +reg [2:0] cnt; reg add; -wire alu_idle; -reg [3:0] cnt; +reg sub; +wire fpu_idle; fpu fpu_inst( - .clk(clk_10MHZ), - .reset(~rst_n), + .clk(clk), + .reset(reset), .add(add), + .sub(sub), + .reg1_s(r1s), .reg1_e(r1e), .reg1_m(r1m), + .reg2_s(r2s), .reg2_e(r2e), .reg2_m(r2m), + .res_s(rss), .res_e(rse), .res_m(rsm), - .idle(alu_idle) - ); + .idle(fpu_idle) +); -always @ (posedge clk_10MHZ) +always @ (posedge clk) begin : OUTPUT_LOGIC - if(rst_n == 1'b0) begin + if(reset == 1'b1) begin state <= CTRL_IDLE; end else begin case(state) CTRL_IDLE : begin - tx_en <= 0; + uart_tx_en <= 0; + uart_tx_data <= 0; cnt <= 0; add <= 0; - if(rx_valid == 1'b1) begin - case(rx_data) + sub <= 0; + if(uart_rx_valid == 1'b1) begin + case(uart_rx_data) 8'b10000001: state <= CTRL_SETR1; 8'b10000010: state <= CTRL_SETR2; - 8'b10000011: state <= CTRL_READR1; - 8'b10000100: state <= CTRL_READR2; - 8'b10000101: state <= CTRL_READRS; - 8'b10001001: state <= CTRL_ADD; + 8'b10000100: state <= CTRL_READR1; + 8'b10001000: state <= CTRL_READR2; + 8'b10010000: state <= CTRL_READRS; + 8'b10100000: state <= CTRL_ADD; + 8'b11000000: state <= CTRL_SUB; default: state <= CTRL_IDLE; endcase end end CTRL_SETR1: begin - if(rx_valid && cnt == 4'd0) begin - r1e <= rx_data[6:0]; + if(uart_rx_valid && cnt == 3'd0) begin + r1s <= uart_rx_data[7]; + r1e <= uart_rx_data[6:0]; cnt <= cnt + 1'b1; - end else if (rx_valid && cnt == 4'd1) begin - r1m[14:7] <= rx_data; + end else if (uart_rx_valid && cnt == 3'd1) begin + r1m[14:7] <= uart_rx_data; cnt <= cnt + 1'b1; - end else if (rx_valid && cnt == 4'd2) begin - r1m[6:0] <= rx_data[7:1]; + end else if (uart_rx_valid && cnt == 3'd2) begin + r1m[6:0] <= uart_rx_data[7:1]; state <= CTRL_IDLE; end end CTRL_SETR2: begin - if(rx_valid && cnt == 4'd0) begin - r2e <= rx_data[6:0]; + if(uart_rx_valid && cnt == 3'd0) begin + r2s <= uart_rx_data[7]; + r2e <= uart_rx_data[6:0]; cnt <= cnt + 1'b1; - end else if (rx_valid && cnt == 4'd1) begin - r2m[14:7] <= rx_data; + end else if (uart_rx_valid && cnt == 3'd1) begin + r2m[14:7] <= uart_rx_data; cnt <= cnt + 1'b1; - end else if (rx_valid && cnt == 4'd2) begin - r2m[6:0] <= rx_data[7:1]; + end else if (uart_rx_valid && cnt == 3'd2) begin + r2m[6:0] <= uart_rx_data[7:1]; state <= CTRL_IDLE; end end CTRL_READR1: begin - if(tx_busy == 1'b1) begin - tx_en <= 0; - end else if(tx_busy == 1'b0 && cnt == 4'd0) begin - tx_data <= {1'b0,r1e}; - tx_en <= 1; + if(uart_tx_busy == 1'b1) begin + uart_tx_en <= 0; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd0) begin + uart_tx_data <= {r1s,r1e}; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd1) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd1) begin cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd2) begin - tx_data <= r1m[14:7]; - tx_en <= 1; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd2) begin + uart_tx_data <= r1m[14:7]; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd3) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd3) begin cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd4) begin - tx_data <= {r1m[6:0],1'b0}; - tx_en <= 1; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd4) begin + uart_tx_data <= {r1m[6:0],1'b0}; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd5) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd5) begin state <= CTRL_IDLE; end end CTRL_READR2: begin - if(tx_busy == 1'b1) begin - tx_en <= 0; - end else if(tx_busy == 1'b0 && cnt == 4'd0) begin - tx_data <= {1'b0,r2e}; - tx_en <= 1; + if(uart_tx_busy == 1'b1) begin + uart_tx_en <= 0; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd0) begin + uart_tx_data <= {r2s,r2e}; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd1) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd1) begin cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd2) begin - tx_data <= r2m[14:7]; - tx_en <= 1; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd2) begin + uart_tx_data <= r2m[14:7]; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd3) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd3) begin cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd4) begin - tx_data <= {r2m[6:0],1'b0}; - tx_en <= 1; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd4) begin + uart_tx_data <= {r2m[6:0],1'b0}; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd5) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd5) begin state <= CTRL_IDLE; end end CTRL_READRS: begin - if(tx_busy == 1'b1) begin - tx_en <= 0; - end else if(tx_busy == 1'b0 && cnt == 4'd0) begin - tx_data <= {1'b0,rse}; - tx_en <= 1; + if(uart_tx_busy == 1'b1) begin + uart_tx_en <= 0; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd0) begin + uart_tx_data <= {rss,rse}; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd1) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd1) begin cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd2) begin - tx_data <= rsm[14:7]; - tx_en <= 1; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd2) begin + uart_tx_data <= rsm[14:7]; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd3) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd3) begin cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd4) begin - tx_data <= {rsm[6:0],1'b0}; - tx_en <= 1; + end else if(uart_tx_busy == 1'b0 && cnt == 3'd4) begin + uart_tx_data <= {rsm[6:0],1'b0}; + uart_tx_en <= 1; cnt <= cnt + 1'b1; - end else if(tx_busy == 1'b0 && cnt == 4'd5) begin + end else if(uart_tx_busy == 1'b0 && cnt == 3'd5) begin state <= CTRL_IDLE; end end CTRL_ADD: begin add <= 1; - state <= CTRL_IDLE; + state <= CTRL_WAIT; + end + CTRL_SUB: begin + sub <= 1; + state <= CTRL_WAIT; + end + CTRL_WAIT: begin + add <= 0; + sub <= 0; + if(fpu_idle == 1'b1) begin + state <= CTRL_IDLE; + end end default: begin state <= CTRL_IDLE; diff --git a/src/uart_rx.sv b/src/uart_rx.sv deleted file mode 100644 index bc85abf..0000000 --- a/src/uart_rx.sv +++ /dev/null @@ -1,189 +0,0 @@ -//------------------------------------------------------------------------------ -// uart_rx.v -// published as part of https://github.com/pConst/basic_verilog -// Konstantin Pavlov, pavlovconst@gmail.com -//------------------------------------------------------------------------------ - -// INFO ------------------------------------------------------------------------ -// Straightforward yet simple UART receiver implementation -// for FPGA written in Verilog -// -// Expects at least one stop bit -// Features continuous data aquisition at BAUD levels up to CLK_HZ / 2 -// Features early asynchronous 'busy' reset -// -// see also "uart_rx.sv" for equivalent SystemVerilog version -// - - -/* --- INSTANTIATION TEMPLATE BEGIN --- - -uart_rx #( - .CLK_HZ( 200_000_000 ), // in Hertz - .BAUD( 9600 ) // max. BAUD is CLK_HZ / 2 -)( - .clk( ), - .nrst( ), - - .rx_data( ), - .rx_done( ), - .rxd( ) -); - ---- INSTANTIATION TEMPLATE END ---*/ - - -module uart_rx #( parameter - CLK_HZ = 200_000_000, - BAUD = 9600 -)( - input clk, - input nrst, - - output reg [7:0] rx_data = 0, - output reg rx_busy = 1'b0, - output reg rx_done, // read strobe - output reg rx_err, - input rxd -); - -parameter BAUD_DIVISOR_2 = (CLK_HZ / BAUD) / 2; - -// synchronizing external rxd pin to avoid metastability -wire rxd_s; -delay #( - .LENGTH( 2 ), - .WIDTH( 1 ) -) rxd_synch ( - .clk( clk ), - .nrst( nrst ), - .ena( 1'b1 ), - .in( rxd ), - .out( rxd_s ) -); - - -wire start_bit_strobe; -edge_detect rxd_fall_detector ( - .clk( clk ), - .anrst( nrst ), - .in( rxd_s ), - .falling( start_bit_strobe ) -); - - -reg [15:0] rx_sample_cntr;// = (BAUD_DIVISOR_2 - 1'b1); - -wire rx_do_sample; -assign rx_do_sample = (rx_sample_cntr[15:0] == 1'b0); - - -// {rx_data[7:0],rx_data_9th_bit} is actually a shift register -reg rx_data_9th_bit; -always @ (posedge clk) begin - if( ~nrst ) begin - rx_data_9th_bit <= 1'b0; - rx_busy <= 1'b0; - rx_sample_cntr <= (BAUD_DIVISOR_2 - 1'b1); - {rx_data[7:0],rx_data_9th_bit} <= 0; - end else begin - if( ~rx_busy ) begin - if( start_bit_strobe ) begin - - // wait for 1,5-bit period till next sample - rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 3 - 1'b1); - rx_busy <= 1'b1; - {rx_data[7:0],rx_data_9th_bit} <= 9'b10000000_0; - - end - end else begin - - if( rx_sample_cntr[15:0] == 0 ) begin - // wait for 1-bit-period till next sample - rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 2 - 1'b1); - end else begin - // counting and sampling only when 'busy' - rx_sample_cntr[15:0] <= rx_sample_cntr[15:0] - 1'b1; - end - - if( rx_do_sample ) begin - if( rx_data_9th_bit == 1'b1 ) begin - // early asynchronous 'busy' reset - rx_busy <= 1'b0; - end else begin - {rx_data[7:0],rx_data_9th_bit} <= {rxd_s, rx_data[7:0]}; - end - end - - end // ~rx_busy - end // ~nrst -end - -always @* begin - // rx_done and rx_busy fall simultaneously - rx_done <= rx_data_9th_bit && rx_do_sample && rxd_s; - rx_err <= rx_data_9th_bit && rx_do_sample && ~rxd_s; -end - -endmodule - -module delay #( parameter - LENGTH = 2, // delay/synchronizer chain length - WIDTH = 1 // signal width -)( - input clk, - input nrst, - input ena, - - input wire in, - output wire out -); - - reg data [1:0]; - - always @(posedge clk) begin - integer i; - if( ~nrst ) begin - data[1] <= 0; - data[0] <= 0; - end else if( ena ) begin - data[1] <= data[0]; - data[0] <= in; - end - end - - assign out = data[1]; - -endmodule - -module edge_detect #( - parameter WIDTH = 1 -)( - input clk, - input anrst, - - input [WIDTH-1:0] in, - - output reg[WIDTH-1:0] rising, - output reg[WIDTH-1:0] falling, - output reg[WIDTH-1:0] both -); - - // data delay line - reg [WIDTH-1:0] in_d; - always_ff @(posedge clk or negedge anrst) begin - if ( ~anrst ) begin - in_d[WIDTH-1:0] <= '0; - end else begin - in_d[WIDTH-1:0] <= in[WIDTH-1:0]; - end - end - - always @(*) begin - rising[WIDTH-1:0] = {WIDTH{anrst}} & (in[WIDTH-1:0] & ~in_d[WIDTH-1:0]); - falling[WIDTH-1:0] = {WIDTH{anrst}} & (~in[WIDTH-1:0] & in_d[WIDTH-1:0]); - - both[WIDTH-1:0] = rising[WIDTH-1:0] | falling[WIDTH-1:0]; - end - -endmodule diff --git a/src/uart_rx.v b/src/uart_rx.v new file mode 100644 index 0000000..30e4e4b --- /dev/null +++ b/src/uart_rx.v @@ -0,0 +1,207 @@ + +// +// Module: uart_rx +// +// Notes: +// - UART reciever module. +// + +module uart_rx( +input wire clk , // Top level system clock input. +input wire resetn , // Asynchronous active low reset. +input wire uart_rxd , // UART Recieve pin. +input wire uart_rx_en , // Recieve enable +output wire uart_rx_break, // Did we get a BREAK message? +output wire uart_rx_valid, // Valid data recieved and available. +output reg [7:0] uart_rx_data // The recieved data. +); + +// --------------------------------------------------------------------------- +// External parameters. +// + +// +// Input bit rate of the UART line. +parameter BIT_RATE = 9600; // bits / sec +localparam BIT_P = 1_000_000_000 * 1/BIT_RATE; // nanoseconds + +// +// Clock frequency in hertz. +parameter CLK_HZ = 10_000_000; +localparam CLK_P = 1_000_000_000 * 1/CLK_HZ; // nanoseconds + +// +// Number of data bits recieved per UART packet. +parameter PAYLOAD_BITS = 8; + +// +// Number of stop bits indicating the end of a packet. +parameter STOP_BITS = 1; + +// -------------------------------------------------------------------------- +// Internal parameters. +// + +// +// Number of clock cycles per uart bit. +localparam CYCLES_PER_BIT = BIT_P / CLK_P; + +// +// Size of the registers which store sample counts and bit durations. +localparam COUNT_REG_LEN = 1+$clog2(CYCLES_PER_BIT); + +// -------------------------------------------------------------------------- +// Internal registers. +// + +// +// Internally latched value of the uart_rxd line. Helps break long timing +// paths from input pins into the logic. +reg rxd_reg; +reg rxd_reg_0; + +// +// Storage for the recieved serial data. +reg [PAYLOAD_BITS-1:0] recieved_data; + +// +// Counter for the number of cycles over a packet bit. +reg [COUNT_REG_LEN-1:0] cycle_counter; + +// +// Counter for the number of recieved bits of the packet. +reg [3:0] bit_counter; + +// +// Sample of the UART input line whenever we are in the middle of a bit frame. +reg bit_sample; + +// +// Current and next states of the internal FSM. +reg [2:0] fsm_state; +reg [2:0] n_fsm_state; + +localparam FSM_IDLE = 0; +localparam FSM_START= 1; +localparam FSM_RECV = 2; +localparam FSM_STOP = 3; + +// --------------------------------------------------------------------------- +// Output assignment +// + +assign uart_rx_break = uart_rx_valid && ~|recieved_data; +assign uart_rx_valid = fsm_state == FSM_STOP && n_fsm_state == FSM_IDLE; + +always @(posedge clk) begin + if(!resetn) begin + uart_rx_data <= {PAYLOAD_BITS{1'b0}}; + end else if (fsm_state == FSM_STOP) begin + uart_rx_data <= recieved_data; + end +end + +// --------------------------------------------------------------------------- +// FSM next state selection. +// + +wire next_bit = cycle_counter == CYCLES_PER_BIT || + fsm_state == FSM_STOP && + cycle_counter == CYCLES_PER_BIT/2; +wire payload_done = bit_counter == PAYLOAD_BITS ; + +// +// Handle picking the next state. +always @(*) begin : p_n_fsm_state + case(fsm_state) + FSM_IDLE : n_fsm_state = rxd_reg ? FSM_IDLE : FSM_START; + FSM_START: n_fsm_state = next_bit ? FSM_RECV : FSM_START; + FSM_RECV : n_fsm_state = payload_done ? FSM_STOP : FSM_RECV ; + FSM_STOP : n_fsm_state = next_bit ? FSM_IDLE : FSM_STOP ; + default : n_fsm_state = FSM_IDLE; + endcase +end + +// --------------------------------------------------------------------------- +// Internal register setting and re-setting. +// + +// +// Handle updates to the recieved data register. +integer i = 0; +always @(posedge clk) begin : p_recieved_data + if(!resetn) begin + recieved_data <= {PAYLOAD_BITS{1'b0}}; + end else if(fsm_state == FSM_IDLE ) begin + recieved_data <= {PAYLOAD_BITS{1'b0}}; + end else if(fsm_state == FSM_RECV && next_bit ) begin + recieved_data[PAYLOAD_BITS-1] <= bit_sample; + for ( i = PAYLOAD_BITS-2; i >= 0; i = i - 1) begin + recieved_data[i] <= recieved_data[i+1]; + end + end +end + +// +// Increments the bit counter when recieving. +always @(posedge clk) begin : p_bit_counter + if(!resetn) begin + bit_counter <= 4'b0; + end else if(fsm_state != FSM_RECV) begin + bit_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(fsm_state == FSM_RECV && next_bit) begin + bit_counter <= bit_counter + 1'b1; + end +end + +// +// Sample the recieved bit when in the middle of a bit frame. +always @(posedge clk) begin : p_bit_sample + if(!resetn) begin + bit_sample <= 1'b0; + end else if (cycle_counter == CYCLES_PER_BIT/2) begin + bit_sample <= rxd_reg; + end +end + + +// +// Increments the cycle counter when recieving. +always @(posedge clk) begin : p_cycle_counter + if(!resetn) begin + cycle_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(next_bit) begin + cycle_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(fsm_state == FSM_START || + fsm_state == FSM_RECV || + fsm_state == FSM_STOP ) begin + cycle_counter <= cycle_counter + 1'b1; + end +end + + +// +// Progresses the next FSM state. +always @(posedge clk) begin : p_fsm_state + if(!resetn) begin + fsm_state <= FSM_IDLE; + end else begin + fsm_state <= n_fsm_state; + end +end + + +// +// Responsible for updating the internal value of the rxd_reg. +always @(posedge clk) begin : p_rxd_reg + if(!resetn) begin + rxd_reg <= 1'b1; + rxd_reg_0 <= 1'b1; + end else if(uart_rx_en) begin + rxd_reg <= rxd_reg_0; + rxd_reg_0 <= uart_rxd; + end +end + + +endmodule \ No newline at end of file diff --git a/src/uart_tx.sv b/src/uart_tx.sv deleted file mode 100644 index 952ba53..0000000 --- a/src/uart_tx.sv +++ /dev/null @@ -1,97 +0,0 @@ -//------------------------------------------------------------------------------ -// uart_tx.v -// published as part of https://github.com/pConst/basic_verilog -// Konstantin Pavlov, pavlovconst@gmail.com -//------------------------------------------------------------------------------ - -// INFO ------------------------------------------------------------------------ -// Straightforward yet simple UART transmitter implementation -// for FPGA written in Verilog -// -// One stop bit setting is hardcoded -// Features continuous data output at BAUD levels up to CLK_HZ / 2 -// Features early asynchronous 'busy' set and reset to gain time to prepare new data -// If multiple UartTX instances should be inferred - make tx_sample_cntr logic -// that is common for all TX instances for effective chip area usage -// -// see also "uart_tx.sv" for equivalent SystemVerilog version -// - - -/* --- INSTANTIATION TEMPLATE BEGIN --- - -uart_tx #( - .CLK_HZ( 200_000_000 ), // in Hertz - .BAUD( 9600 ) // max. BAUD is CLK_HZ / 2 -) tx1 ( - .clk( ), - .nrst( 1'b1 ), - //.tx_do_sample( ), - .tx_data( ), - .tx_start( ), - .tx_busy( ), - .txd( ) -); - ---- INSTANTIATION TEMPLATE END ---*/ - - -module uart_tx #( parameter - CLK_HZ = 200_000_000, - BAUD = 9600 -)( - input clk, - input nrst, - //input tx_do_sample, - - input [7:0] tx_data, - input tx_start, // write strobe - output reg tx_busy = 1'b0, - output reg txd = 1'b1 -); - -parameter BAUD_DIVISOR = CLK_HZ / BAUD; - -reg [9:0] tx_shifter; -reg [15:0] tx_sample_cntr; -always @ (posedge clk) begin - if( (~nrst) || (tx_sample_cntr[15:0] == 0) ) begin - tx_sample_cntr[15:0] <= (BAUD_DIVISOR-1'b1); - end else begin - tx_sample_cntr[15:0] <= tx_sample_cntr[15:0] - 1'b1; - end -end - -wire tx_do_sample; -assign tx_do_sample = (tx_sample_cntr[15:0] == 0); - - -always @ (posedge clk) begin - if( ~nrst ) begin - tx_busy <= 1'b0; - tx_shifter[9:0] <= 0; - txd <= 1'b1; - end else begin - if( ~tx_busy ) begin - // asynchronous data load and 'busy' set - if( tx_start ) begin - tx_shifter[9:0] <= { 1'b1,tx_data[7:0],1'b0 }; - tx_busy <= 1'b1; - end - end else begin - - if( tx_do_sample ) begin // next bit - // txd MUST change only on tx_do_sample although data may be loaded earlier - { tx_shifter[9:0],txd } <= { tx_shifter[9:0],txd } >> 1; - // early asynchronous 'busy' reset - if( ~|tx_shifter[9:1] ) begin - // txd still holds data, but shifter is ready to get new info - tx_busy <= 1'b0; - end - end // tx_do_sample - - end // ~tx_busy - end // ~nrst -end - -endmodule diff --git a/src/uart_tx.v b/src/uart_tx.v new file mode 100644 index 0000000..ed34da7 --- /dev/null +++ b/src/uart_tx.v @@ -0,0 +1,187 @@ + + +// +// Module: uart_tx +// +// Notes: +// - UART transmitter module. +// + +module uart_tx( +input wire clk , // Top level system clock input. +input wire resetn , // Asynchronous active low reset. +output wire uart_txd , // UART transmit pin. +output wire uart_tx_busy, // Module busy sending previous item. +input wire uart_tx_en , // Send the data on uart_tx_data +input wire [7:0] uart_tx_data // The data to be sent +); + +// --------------------------------------------------------------------------- +// External parameters. +// + +// +// Input bit rate of the UART line. +parameter BIT_RATE = 9600; // bits / sec +localparam BIT_P = 1_000_000_000 * 1/BIT_RATE; // nanoseconds + +// +// Clock frequency in hertz. +parameter CLK_HZ = 10_000_000; +localparam CLK_P = 1_000_000_000 * 1/CLK_HZ; // nanoseconds + +// +// Number of data bits recieved per UART packet. +parameter PAYLOAD_BITS = 8; + +// +// Number of stop bits indicating the end of a packet. +parameter STOP_BITS = 1; + +// --------------------------------------------------------------------------- +// Internal parameters. +// + +// +// Number of clock cycles per uart bit. +localparam CYCLES_PER_BIT = BIT_P / CLK_P; + +// +// Size of the registers which store sample counts and bit durations. +localparam COUNT_REG_LEN = 1+$clog2(CYCLES_PER_BIT); + +// --------------------------------------------------------------------------- +// Internal registers. +// + +// +// Internally latched value of the uart_txd line. Helps break long timing +// paths from the logic to the output pins. +reg txd_reg; + +// +// Storage for the serial data to be sent. +reg [PAYLOAD_BITS-1:0] data_to_send; + +// +// Counter for the number of cycles over a packet bit. +reg [COUNT_REG_LEN-1:0] cycle_counter; + +// +// Counter for the number of sent bits of the packet. +reg [3:0] bit_counter; + +// +// Current and next states of the internal FSM. +reg [2:0] fsm_state; +reg [2:0] n_fsm_state; + +localparam FSM_IDLE = 0; +localparam FSM_START= 1; +localparam FSM_SEND = 2; +localparam FSM_STOP = 3; + + +// --------------------------------------------------------------------------- +// FSM next state selection. +// + +assign uart_tx_busy = fsm_state != FSM_IDLE; +assign uart_txd = txd_reg; + +wire next_bit = cycle_counter == CYCLES_PER_BIT; +wire payload_done = bit_counter == PAYLOAD_BITS ; +wire stop_done = bit_counter == STOP_BITS && fsm_state == FSM_STOP; + +// +// Handle picking the next state. +always @(*) begin : p_n_fsm_state + case(fsm_state) + FSM_IDLE : n_fsm_state = uart_tx_en ? FSM_START: FSM_IDLE ; + FSM_START: n_fsm_state = next_bit ? FSM_SEND : FSM_START; + FSM_SEND : n_fsm_state = payload_done ? FSM_STOP : FSM_SEND ; + FSM_STOP : n_fsm_state = stop_done ? FSM_IDLE : FSM_STOP ; + default : n_fsm_state = FSM_IDLE; + endcase +end + +// --------------------------------------------------------------------------- +// Internal register setting and re-setting. +// + +// +// Handle updates to the sent data register. +integer i = 0; +always @(posedge clk) begin : p_data_to_send + if(!resetn) begin + data_to_send <= {PAYLOAD_BITS{1'b0}}; + end else if(fsm_state == FSM_IDLE && uart_tx_en) begin + data_to_send <= uart_tx_data; + end else if(fsm_state == FSM_SEND && next_bit ) begin + for ( i = PAYLOAD_BITS-2; i >= 0; i = i - 1) begin + data_to_send[i] <= data_to_send[i+1]; + end + end +end + + +// +// Increments the bit counter each time a new bit frame is sent. +always @(posedge clk) begin : p_bit_counter + if(!resetn) begin + bit_counter <= 4'b0; + end else if(fsm_state != FSM_SEND && fsm_state != FSM_STOP) begin + bit_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(fsm_state == FSM_SEND && n_fsm_state == FSM_STOP) begin + bit_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(fsm_state == FSM_STOP&& next_bit) begin + bit_counter <= bit_counter + 1'b1; + end else if(fsm_state == FSM_SEND && next_bit) begin + bit_counter <= bit_counter + 1'b1; + end +end + + +// +// Increments the cycle counter when sending. +always @(posedge clk) begin : p_cycle_counter + if(!resetn) begin + cycle_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(next_bit) begin + cycle_counter <= {COUNT_REG_LEN{1'b0}}; + end else if(fsm_state == FSM_START || + fsm_state == FSM_SEND || + fsm_state == FSM_STOP ) begin + cycle_counter <= cycle_counter + 1'b1; + end +end + + +// +// Progresses the next FSM state. +always @(posedge clk) begin : p_fsm_state + if(!resetn) begin + fsm_state <= FSM_IDLE; + end else begin + fsm_state <= n_fsm_state; + end +end + + +// +// Responsible for updating the internal value of the txd_reg. +always @(posedge clk) begin : p_txd_reg + if(!resetn) begin + txd_reg <= 1'b1; + end else if(fsm_state == FSM_IDLE) begin + txd_reg <= 1'b1; + end else if(fsm_state == FSM_START) begin + txd_reg <= 1'b0; + end else if(fsm_state == FSM_SEND) begin + txd_reg <= data_to_send[0]; + end else if(fsm_state == FSM_STOP) begin + txd_reg <= 1'b1; + end +end + +endmodule \ No newline at end of file