Major rewrite of picosoc spimemio core

This commit is contained in:
Clifford Wolf 2017-08-07 22:36:58 +02:00
parent ff7855900d
commit 8821696748
5 changed files with 410 additions and 81 deletions

3
picosoc/.gitignore vendored
View File

@ -11,3 +11,6 @@
/hx8kdemo.blif
/hx8kdemo.log
/hx8kdemo.rpt
/hx8kdemo_syn.v
/hx8kdemo_syn_tb.vvp
/hx8kdemo_tb.vvp

View File

@ -19,9 +19,24 @@ hx8kprog: hx8kdemo.bin firmware.bin
iceprog hx8kdemo.bin
iceprog -o 1M firmware.bin
hx8ksim: hx8kdemo_tb.vvp firmware.hex
vvp -N $<
hx8ksynsim: hx8kdemo_syn_tb.vvp firmware.hex
vvp -N $<
hx8kdemo.blif: hx8kdemo.v spimemio.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
iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
hx8kdemo_syn_tb.vvp: hx8kdemo_tb.v hx8kdemo_syn.v spiflash.v
iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v`
hx8kdemo_syn.v: hx8kdemo.blif
yosys -p 'read_blif -wideports hx8kdemo.blif; write_verilog hx8kdemo_syn.v'
hx8kdemo.asc: hx8kdemo.pcf hx8kdemo.blif
arachne-pnr -d 8k -o hx8kdemo.asc -p hx8kdemo.pcf hx8kdemo.blif
@ -49,6 +64,7 @@ clean:
rm -f testbench.vvp testbench.vcd spiflash_tb.vvp spiflash_tb.vcd
rm -f firmware.elf firmware_vma.elf firmware.hex firmware.bin
rm -f hx8kdemo.blif hx8kdemo.log hx8kdemo.asc hx8kdemo.rpt hx8kdemo.bin
rm -f hx8kdemo_syn.v hx8kdemo_syn_tb.vvp hx8kdemo_tb.vvp
.PHONY: testbench spiflash_tb hx8kprog clean
.PHONY: testbench spiflash_tb hx8kprog hx8ksim hx8ksynsim clean

View File

@ -19,8 +19,37 @@ sw x5,64(x0)
sw x5,68(x0)
sw x5,72(x0)
sw x5,76(x0)
li x5,0x00008067 # ret
sw x5,80(x0)
sw x5,84(x0)
sw x5,88(x0)
sw x5,92(x0)
sw x5,96(x0)
sw x5,100(x0)
sw x5,104(x0)
sw x5,108(x0)
sw x5,112(x0)
sw x5,116(x0)
sw x5,120(x0)
sw x5,124(x0)
sw x5,128(x0)
sw x5,132(x0)
sw x5,136(x0)
sw x5,140(x0)
sw x5,144(x0)
sw x5,148(x0)
sw x5,152(x0)
sw x5,156(x0)
sw x5,160(x0)
sw x5,164(x0)
sw x5,168(x0)
sw x5,172(x0)
sw x5,176(x0)
sw x5,180(x0)
sw x5,184(x0)
sw x5,188(x0)
sw x5,192(x0)
li x5,0x00008067 # ret
sw x5,196(x0)
# setup gpio address in x5
li x5,0x02000000
@ -48,8 +77,8 @@ sw x6,0(x0)
# calculate new entry point into RAM code
slli x3,x6,2
andi x3,x3,63
addi x3,x3,4
andi x3,x3,127
addi x3,x3,32
# execute RAM code, come back to start of loop
mv x1,x4

66
picosoc/hx8kdemo_tb.v Normal file
View File

@ -0,0 +1,66 @@
/*
* 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.
*
*/
`timescale 1 ns / 1 ps
module testbench;
reg clk;
always #5 clk = (clk === 1'b0);
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
repeat (100000) @(posedge clk);
$finish;
end
wire [7:0] leds;
wire flash_csb;
wire flash_clk;
wire flash_io0;
wire flash_io1;
wire flash_io2;
wire flash_io3;
always @(leds) begin
$display("%b", leds);
end
hx8kdemo uut (
.clk (clk ),
.leds (leds ),
.flash_csb(flash_csb),
.flash_clk(flash_clk),
.flash_io0(flash_io0),
.flash_io1(flash_io1),
.flash_io2(flash_io2),
.flash_io3(flash_io3)
);
spiflash spiflash (
.csb(flash_csb),
.clk(flash_clk),
.io0(flash_io0),
.io1(flash_io1),
.io2(flash_io2),
.io3(flash_io3)
);
endmodule

View File

@ -21,10 +21,225 @@ module spimemio (
input clk, resetn,
input valid,
output reg ready,
output ready,
input [23:0] addr,
output reg [31:0] rdata,
output flash_csb,
output flash_clk,
output flash_io0_oe,
output flash_io1_oe,
output flash_io2_oe,
output flash_io3_oe,
output flash_io0_do,
output flash_io1_do,
output flash_io2_do,
output flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di
);
reg xfer_resetn;
reg din_valid;
wire din_ready;
reg [7:0] din_data;
reg din_cont;
reg din_qspi;
reg din_ddr;
reg din_rd;
wire dout_valid;
wire [7:0] dout_data;
reg [23:0] buffer;
reg [3:0] buffer_wen;
reg [23:0] rd_addr;
reg rd_valid;
reg rd_wait;
reg rd_inc;
assign ready = valid && (addr == rd_addr) && rd_valid;
wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
spimemio_xfer xfer (
.clk (clk ),
.resetn (xfer_resetn ),
.din_valid (din_valid ),
.din_ready (din_ready ),
.din_data (din_data ),
.din_cont (din_cont ),
.din_qspi (din_qspi ),
.din_ddr (din_ddr ),
.din_rd (din_rd ),
.dout_valid (dout_valid ),
.dout_data (dout_data ),
.flash_csb (flash_csb ),
.flash_clk (flash_clk ),
.flash_io0_oe (flash_io0_oe),
.flash_io1_oe (flash_io1_oe),
.flash_io2_oe (flash_io2_oe),
.flash_io3_oe (flash_io3_oe),
.flash_io0_do (flash_io0_do),
.flash_io1_do (flash_io1_do),
.flash_io2_do (flash_io2_do),
.flash_io3_do (flash_io3_do),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di)
);
reg [3:0] state;
always @(posedge clk) begin
xfer_resetn <= 1;
din_valid <= 0;
din_data <= 8'h 00;
if (!resetn) begin
state <= 0;
xfer_resetn <= 0;
rd_valid <= 0;
din_cont <= 0;
din_qspi <= 0;
din_ddr <= 0;
din_rd <= 0;
end else begin
if (dout_valid && buffer_wen[0]) buffer[ 7: 0] <= dout_data;
if (dout_valid && buffer_wen[1]) buffer[15: 8] <= dout_data;
if (dout_valid && buffer_wen[2]) buffer[23:16] <= dout_data;
if (dout_valid && buffer_wen[3]) begin
rdata <= {dout_data, buffer};
rd_addr <= rd_inc ? rd_addr + 4 : addr;
rd_valid <= 1;
rd_wait <= rd_inc;
rd_inc <= 1;
end
if (dout_valid && buffer_wen) begin
buffer_wen <= 0;
end
if (valid)
rd_wait <= 0;
case (state)
0: begin
din_valid <= 1;
din_data <= 8'h ff;
if (din_ready)
state <= 1;
end
1: begin
if (dout_valid) begin
xfer_resetn <= 0;
state <= 2;
end
end
2: begin
din_valid <= 1;
din_data <= 8'h ab;
if (din_ready)
state <= 3;
end
3: begin
if (dout_valid) begin
xfer_resetn <= 0;
state <= 4;
end
end
4: begin
rd_inc <= 0;
din_valid <= 1;
din_data <= 8'h 03;
if (din_ready)
state <= 5;
end
5: begin
if (valid && !ready) begin
din_valid <= 1;
din_data <= addr[23:16];
if (din_ready)
state <= 6;
end
end
6: begin
din_valid <= 1;
din_data <= addr[15:8];
if (din_ready)
state <= 7;
end
7: begin
din_valid <= 1;
din_data <= addr[7:0];
if (din_ready)
state <= 8;
end
8: begin
din_valid <= 1;
din_data <= 8'h 00;
if (din_ready) begin
buffer_wen <= 4'b 0001;
state <= 9;
end
end
9: begin
din_valid <= 1;
din_data <= 8'h 00;
if (din_ready) begin
buffer_wen <= 4'b 0010;
state <= 10;
end
end
10: begin
din_valid <= 1;
din_data <= 8'h 00;
if (din_ready) begin
buffer_wen <= 4'b 0100;
state <= 11;
end
end
11: begin
if (!rd_wait || valid) begin
din_valid <= 1;
din_data <= 8'h 00;
if (din_ready) begin
buffer_wen <= 4'b 1000;
state <= 8;
end
end
end
endcase
if (jump) begin
rd_inc <= 0;
rd_valid <= 0;
xfer_resetn <= 0;
state <= 4;
end
end
end
endmodule
module spimemio_xfer (
input clk, resetn,
input din_valid,
output din_ready,
input [7:0] din_data,
input din_cont,
input din_qspi,
input din_ddr,
input din_rd,
output dout_valid,
output [7:0] dout_data,
output reg flash_csb,
output reg flash_clk,
@ -43,91 +258,91 @@ module spimemio (
input flash_io2_di,
input flash_io3_di
);
parameter ENABLE_PREFETCH = 1;
localparam [3:0] mode_spi = 0;
reg [3:0] mode;
reg [23:0] addr_q;
reg addr_q_vld;
reg [7:0] obuffer;
reg [7:0] ibuffer;
reg [31:0] buffer;
reg [6:0] xfer_cnt;
reg pulse_csb_8;
reg xfer_wait;
reg prefetch;
reg [3:0] count;
reg xfer_cont;
reg xfer_qspi;
reg xfer_ddr;
reg xfer_rd;
reg [7:0] next_obuffer;
reg [7:0] next_ibuffer;
reg [3:0] next_count;
reg fetch_next;
reg last_fetch_next;
assign din_ready = din_valid && resetn && fetch_next;
assign dout_valid = fetch_next && !last_fetch_next;
assign dout_data = ibuffer;
always @* begin
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
flash_io0_do = 0;
flash_io1_do = 0;
flash_io2_do = 0;
flash_io3_do = 0;
next_obuffer = obuffer;
next_ibuffer = ibuffer;
next_count = count;
fetch_next = 0;
case (mode)
mode_spi: begin
flash_io0_oe = 1;
flash_io0_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[6:0], 1'b 0};
next_count = count - |count;
end else begin
next_ibuffer = {ibuffer[6:0], flash_io1_di};
end
fetch_next = (next_count == 0);
end
endcase
end
always @(posedge clk) begin
ready <= 0;
if (!resetn) begin
addr_q_vld <= 0;
xfer_wait <= 0;
prefetch <= 0;
xfer_cnt <= 16;
pulse_csb_8 <= 1;
buffer <= {8'h FF, 8'h AB, 16'h 0000};
mode <= mode_spi;
last_fetch_next <= 1;
flash_csb <= 1;
flash_clk <= 1;
flash_io0_oe <= 0;
flash_io1_oe <= 0;
flash_io2_oe <= 0;
flash_io3_oe <= 0;
flash_io0_do <= 0;
flash_io1_do <= 0;
flash_io2_do <= 0;
flash_io3_do <= 0;
end else
if (xfer_cnt) begin
if (xfer_cnt == 8 && pulse_csb_8) begin
pulse_csb_8 <= 0;
flash_csb <= 1;
end else
if (flash_csb) begin
flash_clk <= 0;
count <= 0;
end else begin
last_fetch_next <= fetch_next;
if (count) begin
flash_clk <= !flash_clk && !flash_csb;
obuffer <= next_obuffer;
ibuffer <= next_ibuffer;
count <= next_count;
end
if (din_valid && din_ready) begin
flash_csb <= 0;
end else
if (flash_clk) begin
flash_clk <= 0;
flash_io0_oe <= 1;
flash_io0_do <= buffer[31];
end else begin
flash_clk <= 1;
buffer <= {buffer, flash_io1_di};
xfer_cnt <= xfer_cnt - 1;
end
end else
if (xfer_wait) begin
ready <= 1;
rdata <= {buffer[7:0], buffer[15:8], buffer[23:16], buffer[31:24]};
xfer_wait <= 0;
end else
if (valid && !ready) begin
if (addr_q_vld && addr_q == addr) begin
addr_q <= addr + 4;
addr_q_vld <= 1;
if (!prefetch)
xfer_cnt <= 32;
xfer_wait <= 1;
prefetch <= 0;
end else begin
flash_csb <= 1;
buffer <= {8'h 03, addr};
addr_q <= addr + 4;
addr_q_vld <= 1;
xfer_cnt <= 64;
xfer_wait <= 1;
prefetch <= 0;
end
end else if (ENABLE_PREFETCH && !prefetch) begin
prefetch <= 1;
xfer_cnt <= 32;
end
if (ENABLE_PREFETCH && resetn && prefetch && valid && !ready && addr_q != addr) begin
prefetch <= 0;
xfer_cnt <= 0;
xfer_wait <= 0;
flash_clk <= 1;
obuffer <= din_data;
ibuffer <= 8'h 00;
count <= 8;
xfer_cont <= din_cont;
xfer_qspi <= din_qspi;
xfer_ddr <= din_ddr;
xfer_rd <= din_rd;
end
end
end
endmodule