From 99f0cafd1955652299e85d98bbdeedb5bbbfd506 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 11 Aug 2017 19:30:53 +0200 Subject: [PATCH] Add simple UART to PicoSoC --- picosoc/Makefile | 6 +- picosoc/README.md | 7 ++- picosoc/firmware.S | 34 +++++++++++ picosoc/hx8kdemo.v | 5 +- picosoc/picosoc.v | 35 ++++++++++- picosoc/simpleuart.v | 137 +++++++++++++++++++++++++++++++++++++++++++ picosoc/testbench.v | 5 ++ 7 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 picosoc/simpleuart.v diff --git a/picosoc/Makefile b/picosoc/Makefile index 8c7a82c..49dc126 100644 --- a/picosoc/Makefile +++ b/picosoc/Makefile @@ -4,7 +4,7 @@ testbench: testbench.vvp firmware.hex vvp -N $< -testbench.vvp: spiflash.v spimemio.v testbench.v picosoc.v ../picorv32.v +testbench.vvp: spiflash.v spimemio.v simpleuart.v testbench.v picosoc.v ../picorv32.v iverilog -s testbench -o $@ $^ spiflash_tb: spiflash_tb.vvp firmware.hex @@ -25,10 +25,10 @@ hx8ksim: hx8kdemo_tb.vvp firmware.hex hx8ksynsim: hx8kdemo_syn_tb.vvp firmware.hex vvp -N $< -hx8kdemo.blif: hx8kdemo.v spimemio.v picosoc.v ../picorv32.v +hx8kdemo.blif: hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v yosys -ql hx8kdemo.log -p 'synth_ice40 -top hx8kdemo -blif hx8kdemo.blif' $^ -hx8kdemo_tb.vvp: hx8kdemo_tb.v hx8kdemo.v spimemio.v picosoc.v ../picorv32.v spiflash.v +hx8kdemo_tb.vvp: hx8kdemo_tb.v hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` hx8kdemo_syn_tb.vvp: hx8kdemo_tb.v hx8kdemo_syn.v spiflash.v diff --git a/picosoc/README.md b/picosoc/README.md index 5d7e2d3..77ea038 100644 --- a/picosoc/README.md +++ b/picosoc/README.md @@ -34,7 +34,12 @@ and upload them to a connected iCE40-HX8K Breakout Board. | 0x00000000 .. 0x00FFFFFF | Internal SRAM | | 0x01000000 .. 0x01FFFFFF | External Serial Flash | | 0x02000000 .. 0x02000003 | SPI Flash Controller Config Register | -| 0x03000000 .. 0x00FFFFFF | Memory mapped user peripherals | +| 0x02000004 .. 0x02000007 | UART Clock Divider Register | +| 0x02000008 .. 0x0200000B | UART Send/Recv Data Register | +| 0x03000000 .. 0xFFFFFFFF | Memory mapped user peripherals | + +Reading from the UART Send/Recv Data Register will return the last received +byte, or -1 (all 32 bits set) when the receive buffer is empty. The example design (hx8kdemo.v) and generic test bench (testbench.v) have 32 GPIO pins mapped to the 32 bit word at address 0x03000000. diff --git a/picosoc/firmware.S b/picosoc/firmware.S index 362a5b0..efd49b4 100644 --- a/picosoc/firmware.S +++ b/picosoc/firmware.S @@ -51,6 +51,40 @@ sw x5,192(x0) li x5,0x00008067 // ret sw x5,196(x0) +// write a few chars to UART +li x5,0x02000004 +li x6,104 +sw x6,0(x5) +li x5,0x02000008 +li x6,'H' +sw x6,0(x5) +li x6,'e' +sw x6,0(x5) +li x6,'l' +sw x6,0(x5) +li x6,'l' +sw x6,0(x5) +li x6,'o' +sw x6,0(x5) +li x6,' ' +sw x6,0(x5) +li x6,'W' +sw x6,0(x5) +li x6,'o' +sw x6,0(x5) +li x6,'r' +sw x6,0(x5) +li x6,'l' +sw x6,0(x5) +li x6,'d' +sw x6,0(x5) +li x6,'!' +sw x6,0(x5) +li x6,'\r' +sw x6,0(x5) +li x6,'\n' +sw x6,0(x5) + #if 0 // switch spimemio to continous qspi ddr mode li x5,0x02000000 diff --git a/picosoc/hx8kdemo.v b/picosoc/hx8kdemo.v index a3ae35b..97f97b1 100644 --- a/picosoc/hx8kdemo.v +++ b/picosoc/hx8kdemo.v @@ -20,7 +20,7 @@ module hx8kdemo ( input clk, - input ser_tx, + output ser_tx, input ser_rx, output [7:0] leds, @@ -90,6 +90,9 @@ module hx8kdemo ( .clk (clk ), .resetn (resetn ), + .ser_tx (ser_tx ), + .ser_rx (ser_rx ), + .flash_csb (flash_csb ), .flash_clk (flash_clk ), diff --git a/picosoc/picosoc.v b/picosoc/picosoc.v index da9b9a9..a648b0e 100644 --- a/picosoc/picosoc.v +++ b/picosoc/picosoc.v @@ -28,6 +28,9 @@ module picosoc ( output [31:0] iomem_wdata, input [31:0] iomem_rdata, + output ser_tx, + input ser_rx, + output flash_csb, output flash_clk, @@ -72,9 +75,19 @@ module picosoc ( wire spimemio_cfgreg_sel = (mem_addr == 32'h 0200_0000); wire [31:0] spimemio_cfgreg_do; - assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel; + wire simpleuart_reg_div_sel = (mem_addr == 32'h 0200_0004); + wire [31:0] simpleuart_reg_div_do; + + wire simpleuart_reg_dat_sel = (mem_addr == 32'h 0200_0008); + wire [31:0] simpleuart_reg_dat_do; + wire simpleuart_reg_dat_wait; + + assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel || + simpleuart_reg_div_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait); + assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata : - spimemio_cfgreg_sel ? spimemio_cfgreg_do : 32'h xxxx_xxxx; + spimemio_cfgreg_sel ? spimemio_cfgreg_do : simpleuart_reg_div_sel ? simpleuart_reg_div_do : + simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : 32'h xxxx_xxxx; picorv32 #( .STACKADDR(STACKADDR), @@ -122,6 +135,24 @@ module picosoc ( .cfgreg_do(spimemio_cfgreg_do) ); + simpleuart simpleuart ( + .clk (clk ), + .resetn (resetn ), + + .ser_tx (ser_tx ), + .ser_rx (ser_rx ), + + .reg_div_we (simpleuart_reg_div_sel ? mem_wstrb : 4'b 0000), + .reg_div_di (mem_wdata), + .reg_div_do (simpleuart_reg_div_do), + + .reg_dat_we (simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0), + .reg_dat_re (simpleuart_reg_dat_sel && !mem_wstrb), + .reg_dat_di (mem_wdata), + .reg_dat_do (simpleuart_reg_dat_do), + .reg_dat_wait(simpleuart_reg_dat_wait) + ); + reg [31:0] memory [0:MEM_WORDS-1]; always @(posedge clk) begin diff --git a/picosoc/simpleuart.v b/picosoc/simpleuart.v new file mode 100644 index 0000000..50808cb --- /dev/null +++ b/picosoc/simpleuart.v @@ -0,0 +1,137 @@ +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +module simpleuart ( + input clk, + input resetn, + + output ser_tx, + input ser_rx, + + input [3:0] reg_div_we, + input [31:0] reg_div_di, + output [31:0] reg_div_do, + + input reg_dat_we, + input reg_dat_re, + input [31:0] reg_dat_di, + output [31:0] reg_dat_do, + output reg_dat_wait +); + reg [31:0] cfg_divider; + + reg [3:0] recv_state; + reg [31:0] recv_divcnt; + reg [7:0] recv_pattern; + reg [7:0] recv_buf_data; + reg recv_buf_valid; + + reg [9:0] send_pattern; + reg [3:0] send_bitcnt; + reg [31:0] send_divcnt; + reg send_dummy; + + assign reg_div_do = cfg_divider; + + assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); + assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; + + always @(posedge clk) begin + if (!resetn) begin + cfg_divider <= 1; + end else begin + if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0]; + if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8]; + if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16]; + if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24]; + end + end + + always @(posedge clk) begin + if (!resetn) begin + recv_state <= 0; + recv_divcnt <= 0; + recv_pattern <= 0; + recv_buf_data <= 0; + recv_buf_valid <= 0; + end else begin + recv_divcnt <= recv_divcnt + 1; + if (reg_dat_re) + recv_buf_valid <= 0; + case (recv_state) + 0: begin + if (!ser_rx) + recv_state <= 1; + recv_divcnt <= 0; + end + 1: begin + if (2*recv_divcnt > cfg_divider) begin + recv_state <= 2; + recv_divcnt <= 0; + end + end + 10: begin + if (recv_divcnt > cfg_divider) begin + recv_buf_data <= recv_pattern; + recv_buf_valid <= 1; + recv_state <= 0; + end + end + default: begin + if (recv_divcnt > cfg_divider) begin + recv_pattern <= {ser_rx, recv_pattern[7:1]}; + recv_state <= recv_state + 1; + recv_divcnt <= 0; + end + end + endcase + end + end + + assign ser_tx = send_pattern[0]; + + always @(posedge clk) begin + if (reg_div_we) + send_dummy <= 1; + send_divcnt <= send_divcnt + 1; + if (!resetn) begin + send_pattern <= ~0; + send_bitcnt <= 0; + send_divcnt <= 0; + send_dummy <= 1; + end else begin + if (send_dummy && !send_bitcnt) begin + send_pattern <= ~0; + send_bitcnt <= 15; + send_divcnt <= 0; + send_dummy <= 0; + end else + if (reg_dat_we && !send_bitcnt) begin + send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0}; + send_bitcnt <= 10; + send_divcnt <= 0; + end else + if (send_divcnt > cfg_divider && send_bitcnt) begin + send_pattern <= {1'b1, send_pattern[9:1]}; + send_bitcnt <= send_bitcnt - 1; + send_divcnt <= 0; + end + end + end +endmodule diff --git a/picosoc/testbench.v b/picosoc/testbench.v index a7e57de..57e0538 100644 --- a/picosoc/testbench.v +++ b/picosoc/testbench.v @@ -78,6 +78,8 @@ module testbench; wire [31:0] iomem_wdata; reg [31:0] iomem_rdata; + wire ser_tx_rx; + reg [31:0] gpio; always @(posedge clk) begin @@ -108,6 +110,9 @@ module testbench; .clk (clk ), .resetn (resetn ), + .ser_tx (ser_tx_rx ), + .ser_rx (ser_tx_rx ), + .flash_csb (flash_csb ), .flash_clk (flash_clk ),