Add simple UART to PicoSoC

This commit is contained in:
Clifford Wolf 2017-08-11 19:30:53 +02:00
parent febb4b1318
commit 99f0cafd19
7 changed files with 222 additions and 7 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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 ),

View File

@ -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

137
picosoc/simpleuart.v Normal file
View File

@ -0,0 +1,137 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* 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

View File

@ -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 ),