From 5d7f889102cf25ed18d003e6511496fe7bf1b2dc Mon Sep 17 00:00:00 2001 From: Daniel Newbrook <dwn1c21@soton.ac.uk> Date: Thu, 23 Jan 2025 14:33:25 +0000 Subject: [PATCH] Design verified in Gate simulations --- .gitignore | 14 ++ README.md | 17 +- asic/TSMC28nm/ahb_qspi_constraints.sdc | 11 + asic/TSMC28nm/dc_synthesis.tcl | 22 ++ flist/Top/ahb_QSPI.flist | 1 + flist/Top/ahb_QSPI_ASIC.flist | 15 ++ flist/Top/ahb_QSPI_ASIC_sv.flist | 3 + flist/Top/ahb_QSPI_SIM_GATES.flist | 4 + flows/makefile.asic | 13 ++ logical/apb_qspi_regs/logical/apb_qspi_regs.v | 10 +- .../qspi_controller/logical/qspi_clock_div.v | 36 ++++ .../logical/qspi_controller.sv | 188 ++++++++++-------- logical/top_ahb_qspi/logical/top_ahb_qspi.v | 2 +- makefile | 8 +- verif/cocotb/ahb_qspi_cocotb.v | 11 + verif/cocotb/ahb_qspi_tests.py | 114 ++++++++--- verif/cocotb/makefile | 7 + 17 files changed, 361 insertions(+), 115 deletions(-) create mode 100644 asic/TSMC28nm/ahb_qspi_constraints.sdc create mode 100644 asic/TSMC28nm/dc_synthesis.tcl create mode 100644 flist/Top/ahb_QSPI_ASIC.flist create mode 100644 flist/Top/ahb_QSPI_ASIC_sv.flist create mode 100644 flist/Top/ahb_QSPI_SIM_GATES.flist create mode 100644 flows/makefile.asic create mode 100644 logical/qspi_controller/logical/qspi_clock_div.v diff --git a/.gitignore b/.gitignore index 02d8c92..48df0b8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,19 @@ verif/cocotb/ahb_qspi.vcd verif/cocotb/transcript verif/cocotb/sim_build/ verif/cocotb/__pycache__/ +verif/cocotb/verdiLog +verif/cocotb/novas* +verif/cocotb/vsim.wlf +verif/cocotb/wlft6jORYn +verif/cocotb/inter.fsdb verif/VIP/SST26VF064B.v + +asic/TSMC28nm/*.mr +asic/TSMC28nm/*pvl +asic/TSMC28nm/*.syn +asic/TSMC28nm/command.log +asic/TSMC28nm/default.svf +asic/TSMC28nm/*.log + +imp \ No newline at end of file diff --git a/README.md b/README.md index 5a8c4cf..18bf7e7 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,19 @@ Read bandwidth with 4 KB cache for 512x 32 bit reads, and system clock of 200 MH - Using APB: 5.8 MB/s - Using AHB(uncached, prefetch enabled): 32 MB/s -- Using AHB(cached): 400 MB/s \ No newline at end of file +- Using AHB(cached): 400 MB/s + +## ToDo +- Add programmable clock divider for QSPI +- Add programmable op codes for AHB interface +- Improve writing method over APB? (see below) +- Add interrupts for QSPI finish + +## Writing over APB +Currently the method for writing over APB to the flash is to write up to 4x 32 bit words to the APB registers and then tell the QSPI controller to write. However as there is a long latency after writing over QSPI for the flash to finish, this is not optimal. + +The flash device we are targeting is a SST26VF064B device which allows up to 256 bytes to be written in a single SPI transaction (currently only writing 16 bytes per transaction). So proposals for improving this are as follows + +1. Just simply add an extra 240 bytes of registers to the APB controller. This is the simplest to do but I think that this will inflate the overall area of the IP by too much, however this makes the software side fairly simple. (i.e. write 256 bytes to APB-> send command to QSPI controller-> wait for QSPI transaction to finish-> poll QSPI status until write is complete) +2. Add write fifo. This will be a lot smaller in terms of area. But will have to keep track of how many bytes get written over QSPI to limit to 256. This requires a bit of an overhaul in how the write transaction works but it means we can fully utilise the page program command. Software then becomes a little more complicated (i.e. write N bytes to APB-> send command to QSPI controller-> check if FIFO not full and send more data-> repeat last step 256/N times-> QSPI checks if FIFO is empty whilst the happens and stops transaction when empty-> poll QSPI status until write is complete). + diff --git a/asic/TSMC28nm/ahb_qspi_constraints.sdc b/asic/TSMC28nm/ahb_qspi_constraints.sdc new file mode 100644 index 0000000..a0f491c --- /dev/null +++ b/asic/TSMC28nm/ahb_qspi_constraints.sdc @@ -0,0 +1,11 @@ + +set HCLK "HCLK" +set PCLK "PCLK" + +set HCLK_PERIOD 10 +set PCLK_PERIOD 10 + +create_clock -name "$HCLK" -period $HCLK_PERIOD [get_ports HCLK] +create_clock -name "$PCLK" -period $PCLK_PERIOD [get_ports PCLK] +create_generated_clock -name "QSPI_SCLK" -source [get_ports HCLK] -divide_by 2 [get_pins u_qspi_controller/u_qspi_clock_div/QSPI_SCLK_i] +set_max_fanout 10 [all_inputs] diff --git a/asic/TSMC28nm/dc_synthesis.tcl b/asic/TSMC28nm/dc_synthesis.tcl new file mode 100644 index 0000000..f241b8f --- /dev/null +++ b/asic/TSMC28nm/dc_synthesis.tcl @@ -0,0 +1,22 @@ +set_host_options -max_cores 8 +set top_module top_ahb_qspi + +set search_path [list . $search_path /home/dwn1c21/SoC-Labs/phys_ip/arm/tsmc/cln28ht/sc12mcpp140z_base_svt_c35/r2p0/db] + +set target_library "sc12mcpp140z_cln28ht_base_svt_c35_ssg_cworstt_max_0p81v_125c.db" +set link_library "sc12mcpp140z_cln28ht_base_svt_c35_ssg_cworstt_max_0p81v_125c.db" + +source $env(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/flist/dc_flist.tcl +elaborate $top_module +current_design $top_module + +link + +read_sdc ./ahb_qspi_constraints.sdc + +compile_ultra + +write -format verilog -hierarchy -output $env(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/top_ahb_qspi_gates.v +write_sdf -version 2.1 $env(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/top_ahb_qspi.sdf + +exit \ No newline at end of file diff --git a/flist/Top/ahb_QSPI.flist b/flist/Top/ahb_QSPI.flist index c8b0400..23607c2 100644 --- a/flist/Top/ahb_QSPI.flist +++ b/flist/Top/ahb_QSPI.flist @@ -6,6 +6,7 @@ $(SOCLABS_AHB_QSPI_DIR)/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv $(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller.sv $(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller_mux.v +$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_clock_div.v $(SOCLABS_AHB_QSPI_DIR)/logical/cache_subsytem/logical/cache_subsystem.v -f $(SOCLABS_AHB_QSPI_DIR)/flist/IP/CG092_cache.flist diff --git a/flist/Top/ahb_QSPI_ASIC.flist b/flist/Top/ahb_QSPI_ASIC.flist new file mode 100644 index 0000000..e930349 --- /dev/null +++ b/flist/Top/ahb_QSPI_ASIC.flist @@ -0,0 +1,15 @@ + +$(SOCLABS_AHB_QSPI_DIR)/logical/top_ahb_qspi/logical/top_ahb_qspi.v +$(SOCLABS_AHB_QSPI_DIR)/logical/apb_qspi_regs/logical/apb_qspi_regs.v + +$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller_mux.v +$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_clock_div.v + +$(SOCLABS_AHB_QSPI_DIR)/logical/cache_subsytem/logical/cache_subsystem.v +-f $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_ASIC_sv.flist +-f $(SOCLABS_AHB_QSPI_DIR)/flist/IP/CG092_cache.flist +-f $(SOCLABS_AHB_QSPI_DIR)/flist/IP/corstone_101_ip.flist + +$(SOCLABS_AHB_QSPI_DIR)/logical/cache_models/generic/cache_ram.v + +$(ARM_IP_LIBRARY_PATH)/CG092/CG092-BU-50000-r2p0-00rel0/p_flash_cache_f0/logical/testbench/execution_tb/verilog/p_flash_cache_f0_sp_ram.v \ No newline at end of file diff --git a/flist/Top/ahb_QSPI_ASIC_sv.flist b/flist/Top/ahb_QSPI_ASIC_sv.flist new file mode 100644 index 0000000..4d75241 --- /dev/null +++ b/flist/Top/ahb_QSPI_ASIC_sv.flist @@ -0,0 +1,3 @@ +$(SOCLABS_AHB_QSPI_DIR)/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv + +$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller.sv diff --git a/flist/Top/ahb_QSPI_SIM_GATES.flist b/flist/Top/ahb_QSPI_SIM_GATES.flist new file mode 100644 index 0000000..c9fc784 --- /dev/null +++ b/flist/Top/ahb_QSPI_SIM_GATES.flist @@ -0,0 +1,4 @@ +-f $(SOCLABS_AHB_QSPI_DIR)/flist/VIP/ahb_QSPI_VIP.flist +$(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/top_ahb_qspi_gates.v + +/home/dwn1c21/SoC-Labs/phys_ip/arm/tsmc/cln28ht/sc12mcpp140z_base_svt_c35/r2p0/verilog/sc12mcpp140z_cln28ht_base_svt_c35.v \ No newline at end of file diff --git a/flows/makefile.asic b/flows/makefile.asic new file mode 100644 index 0000000..8bb1ca0 --- /dev/null +++ b/flows/makefile.asic @@ -0,0 +1,13 @@ +# Location to build ASIC files +IMP_ASIC_DIR := $(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/ + + + +TCL_ASIC_FLIST_DIR := $(IMP_ASIC_DIR)/flist +DC_OUTPUT_FILELIST := $(TCL_ASIC_FLIST_DIR)/dc_flist.tcl + +flist_synopsys: + @mkdir -p $(TCL_ASIC_FLIST_DIR) + @(cd $(TCL_ASIC_FLIST_DIR); \ + $(SOCLABS_SOCTOOLS_FLOW_DIR)/bin/filelist_compile.py -t -s -a -f $(DESIGN_VC) -o $(DC_OUTPUT_FILELIST) -i $(FLIST_INCLUDES) -r $(IMP_NANOSOC_ASIC_DIR)/src;) + diff --git a/logical/apb_qspi_regs/logical/apb_qspi_regs.v b/logical/apb_qspi_regs/logical/apb_qspi_regs.v index fefe5b7..458e8c3 100644 --- a/logical/apb_qspi_regs/logical/apb_qspi_regs.v +++ b/logical/apb_qspi_regs/logical/apb_qspi_regs.v @@ -34,11 +34,11 @@ module apb_qspi_regs( ); // Registers // reg0 Control 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -// QSPI_QIO_MODE[0] | |--> QSPI_QIO_MODE [0] -// XIP_ACTIVE [8] |------------------> XIP_ACTIVE [8] -// QSPI_MODE_CODE[23:16] -// QSPI_CONT_READ[24] -// QSPI_NO_CMD[25] +// QSPI_QIO_MODE[0] | | | | | |--> QSPI_QIO_MODE [0] +// XIP_ACTIVE [8] | | | | |------------------> XIP_ACTIVE [8] +// QSPI_MODE_CODE[23:16] | | |<------------------>|----------------------------------------> QSPI_MODE_CODE[23:16] +// QSPI_CONT_READ[24] | |----------------------------------------------------------------> QSPI_CONT_READ[24] +// QSPI_NO_CMD[25] |-------------------------------------------------------------------> QSPI_NO_CMD[25] // reg1 Status diff --git a/logical/qspi_controller/logical/qspi_clock_div.v b/logical/qspi_controller/logical/qspi_clock_div.v new file mode 100644 index 0000000..40b2025 --- /dev/null +++ b/logical/qspi_controller/logical/qspi_clock_div.v @@ -0,0 +1,36 @@ +module qspi_clock_div( + input wire HCLK, + input wire HRESETn, + input wire [7:0] QSPI_CLK_DIV, + input wire [1:0] QSPI_SPI_MODE, + output wire QSPI_SCLK_i +); + +reg [7:0] QSPI_CLK_DIV_COUNTER; +reg QSPI_SCLK_reg; +assign QSPI_SCLK_i = (QSPI_CLK_DIV==8'h00) ? HCLK : QSPI_SCLK_reg; + +// Clock Divider for SCLK +always @(posedge HCLK or negedge HRESETn) begin + if(~HRESETn) begin + QSPI_CLK_DIV_COUNTER<=8'h00; + QSPI_SCLK_reg <= 1'b0; + end else begin + if(QSPI_CLK_DIV==8'h01) begin + QSPI_SCLK_reg <= ~QSPI_SCLK_reg; + end else if(QSPI_CLK_DIV!=8'h00) begin + if(QSPI_CLK_DIV_COUNTER==QSPI_CLK_DIV-1'b1) begin + QSPI_CLK_DIV_COUNTER <= 8'h00; + end else begin + QSPI_SCLK_reg <= ~QSPI_SCLK_reg; + QSPI_CLK_DIV_COUNTER <= QSPI_CLK_DIV_COUNTER + 1; + end + end else begin + QSPI_SCLK_reg <= QSPI_SPI_MODE[1]; + end + end +end + + + +endmodule \ No newline at end of file diff --git a/logical/qspi_controller/logical/qspi_controller.sv b/logical/qspi_controller/logical/qspi_controller.sv index 30fee94..94c1127 100644 --- a/logical/qspi_controller/logical/qspi_controller.sv +++ b/logical/qspi_controller/logical/qspi_controller.sv @@ -13,7 +13,7 @@ module qspi_controller ( input wire QSPI_WRITE, input wire QSPI_ADDR_EN, input wire [3:0] QSPI_DUMMY_CYCLES, - input wire [3:0] QSPI_N_RW_BYTES, + input wire [4:0] QSPI_N_RW_BYTES, input wire [21:0] QSPI_ADDR, input wire [127:0] QSPI_WDATA, output reg [127:0] QSPI_RDATA, @@ -31,34 +31,19 @@ module qspi_controller ( ); -reg [7:0] QSPI_CLK_DIV_COUNTER; -reg QSPI_SCLK_reg; wire QSPI_SCLK_i; reg QSPI_SCLK_e; -assign QSPI_SCLK_i = (QSPI_CLK_DIV==8'h00) ? HCLK : QSPI_SCLK_reg; -assign QSPI_SCLK = (QSPI_SCLK_e==1'b1) ? QSPI_SCLK_i : QSPI_SPI_MODE[1]; +qspi_clock_div u_qspi_clock_div( + .HCLK(HCLK), + .HRESETn(HRESETn), + .QSPI_CLK_DIV(QSPI_CLK_DIV), + .QSPI_SPI_MODE(QSPI_SPI_MODE), + .QSPI_SCLK_i(QSPI_SCLK_i) +); -// Clock Divider for SCLK -always @(posedge HCLK or negedge HRESETn) begin - if(~HRESETn) begin - QSPI_CLK_DIV_COUNTER<=8'h00; - QSPI_SCLK_reg <= 1'b0; - end else begin - if(QSPI_CLK_DIV==8'h01) begin - QSPI_SCLK_reg <= ~QSPI_SCLK_reg; - end else if(QSPI_CLK_DIV!=8'h00) begin - if(QSPI_CLK_DIV_COUNTER==QSPI_CLK_DIV-1'b1) begin - QSPI_CLK_DIV_COUNTER <= 8'h00; - end else begin - QSPI_SCLK_reg <= ~QSPI_SCLK_reg; - QSPI_CLK_DIV_COUNTER <= QSPI_CLK_DIV_COUNTER + 1'b1; - end - end else begin - QSPI_SCLK_reg <= QSPI_SPI_MODE[1]; - end - end -end + +assign QSPI_SCLK = (QSPI_SCLK_e==1'b1) ? QSPI_SCLK_i : QSPI_SPI_MODE[1]; enum {IDLE, NO_FETCH, OP, ADDR, MODE, DUMMY, DATA_O, DATA_I} current_state, next_state; @@ -67,7 +52,7 @@ reg [4:0] addr_counter; reg mode_counter; reg [2:0] data_counter; reg [3:0] dummy_counter; -reg [3:0] byte_counter; +reg [4:0] byte_counter; reg [7:0] op_code; reg [23:0] addr_code; reg [7:0] qspi_mode_reg; @@ -110,11 +95,12 @@ always @(*) begin end OP: begin QSPI_ENABLE_ACK = 1'b1; + next_state = OP; if(QSPI_QIO_MODE==1'b1 & op_counter==3'h1) begin QSPI_ENABLE_ACK = 1'b0; if(QSPI_ADDR_EN) next_state = ADDR; - else if(QSPI_DUMMY_CYCLES>4'h0) + else if(QSPI_DUMMY_CYCLES!=4'h0) next_state = DUMMY; else if(QSPI_READ) next_state = DATA_I; @@ -127,7 +113,7 @@ always @(*) begin QSPI_ENABLE_ACK = 1'b0; if(QSPI_ADDR_EN) next_state = ADDR; - else if(QSPI_DUMMY_CYCLES>4'h0) + else if(QSPI_DUMMY_CYCLES!=4'h0) next_state = DUMMY; else if(QSPI_READ) next_state = DATA_I; @@ -135,6 +121,8 @@ always @(*) begin next_state = DATA_O; else next_state = IDLE; + end else begin + next_state = OP; end end ADDR: begin @@ -144,7 +132,7 @@ always @(*) begin last_QSPI_ADDR = QSPI_ADDR; if(QSPI_CONT_READ) next_state = MODE; - else if(QSPI_DUMMY_CYCLES>4'h0) + else if(QSPI_DUMMY_CYCLES!=4'h0) next_state = DUMMY; else if(QSPI_READ) next_state = DATA_I; @@ -155,7 +143,7 @@ always @(*) begin end else if(QSPI_QIO_MODE==1'b0 & addr_counter==5'h15) begin QSPI_ENABLE_ACK = 1'b0; - if(QSPI_DUMMY_CYCLES>4'h0) + if(QSPI_DUMMY_CYCLES!=4'h0) next_state = DUMMY; else if(QSPI_READ) next_state = DATA_I; @@ -163,11 +151,13 @@ always @(*) begin next_state = DATA_O; else next_state = IDLE; + end else begin + next_state = ADDR; end end MODE: begin if(QSPI_QIO_MODE==1'b1 & mode_counter == 1'b0) begin - if(QSPI_DUMMY_CYCLES>4'h0) + if(QSPI_DUMMY_CYCLES!=4'h0) next_state = DUMMY; else if(QSPI_READ) next_state = DATA_I; @@ -181,35 +171,57 @@ always @(*) begin end end DUMMY: begin - if(dummy_counter >= QSPI_DUMMY_CYCLES - 1'b1) begin + if(dummy_counter >= (QSPI_DUMMY_CYCLES - 1)) begin if(QSPI_WRITE) next_state = DATA_O; else if(QSPI_READ) next_state = DATA_I; else next_state = IDLE; - end + end else begin + next_state = DUMMY; + end end DATA_O: begin - if(QSPI_QIO_MODE==1'b0) begin - - end else begin - if(byte_counter==QSPI_N_RW_BYTES) begin - if(data_counter==3'h0) - next_state = IDLE; + if(byte_counter==5'h1F) begin + next_state = DATA_O; + end else begin + if(QSPI_QIO_MODE==1'b0) begin + if(byte_counter==QSPI_N_RW_BYTES) begin + if(data_counter == 3'h7) + next_state = IDLE; + else + next_state = DATA_O; + end else begin + next_state = DATA_O; + end + end else begin + if(byte_counter==QSPI_N_RW_BYTES) begin + if(data_counter==3'h0) + next_state = IDLE; + else + next_state = DATA_O; + end else begin + next_state = DATA_O; + end end end end DATA_I: begin + next_state = DATA_I; if(QSPI_QIO_MODE==1'b0) begin - if((byte_counter==QSPI_N_RW_BYTES)) begin - if(data_counter==3'h6) + if((byte_counter[3:0]==QSPI_N_RW_BYTES)) begin + if(data_counter==3'h7) next_state = IDLE; + else + next_state = DATA_I; end end else begin - if((byte_counter==QSPI_N_RW_BYTES)) begin - if(data_counter==3'h1) + if((byte_counter==QSPI_N_RW_BYTES+1)) begin + if(data_counter==3'h0) next_state = IDLE; + else + next_state = DATA_I; end end end @@ -220,6 +232,7 @@ reg QSPI_IO_e_int; always @(negedge QSPI_SCLK_i) begin if(current_state==OP) begin + data_in_reg <= 128'd0; QSPI_IO_e_int <= 1'b1; QSPI_SCLK_e <= 1'b1; if(QSPI_QIO_MODE==1'b1) begin @@ -256,7 +269,6 @@ always @(negedge QSPI_SCLK_i) begin end else if(current_state == DUMMY) begin QSPI_IO_e_int <= 1'b1; QSPI_SCLK_e <= 1'b1; - dummy_counter <= dummy_counter + 1'b1; end else if(current_state == MODE) begin QSPI_IO_e_int <=1'b1; QSPI_SCLK_e <= 1'b1; @@ -272,57 +284,69 @@ always @(negedge QSPI_SCLK_i) begin QSPI_IO_o_reg<=4'hF; QSPI_IO_e_int <= 1'b1; end + if(current_state == DATA_I) begin + if(QSPI_QIO_MODE==1'b1) begin + if(byte_counter!=QSPI_N_RW_BYTES+1) + data_in_reg <= {data_in_reg[123:0], QSPI_IO_i}; + end else begin + if(byte_counter!=QSPI_N_RW_BYTES+1) + data_in_reg <= {data_in_reg[126:0], QSPI_IO_i[1]}; + end + end + if(current_state != DATA_O) begin QSPI_WDATA_reg <= QSPI_WDATA; end - if(current_state != DUMMY) begin - dummy_counter <= 4'h0; - end - - end -always @(posedge QSPI_SCLK_i) begin - if(current_state==OP) begin - data_in_reg <= 128'd0; - op_counter<=op_counter+1'b1; - end else begin +always @(posedge QSPI_SCLK_i or negedge HRESETn) begin + if(~HRESETn) begin op_counter <= 3'h0; - end - if(current_state==DATA_I || current_state ==DATA_O) begin - data_counter <= data_counter + 1'b1; - if(QSPI_QIO_MODE==1'b0 && data_counter == 3'h7) begin - byte_counter <= byte_counter+1'b1; - data_counter <= 3'h0; - end else if (QSPI_QIO_MODE==1'b1 && data_counter >= 3'h1) begin - byte_counter <= byte_counter+1'b1; - data_counter <= 3'h0; - end - end else begin data_counter <= 3'h7; - byte_counter <= 4'hF; - end - if(current_state == DATA_I) begin - if(QSPI_QIO_MODE==1'b1) begin - data_in_reg <= {data_in_reg[123:0], QSPI_IO_i}; + byte_counter <= 5'h1F; + dummy_counter <= 4'h0; + addr_counter <= 5'h00; + mode_counter <= 1'b1; + end else begin + if(current_state==OP) begin + op_counter<=op_counter+1; end else begin - data_in_reg <= {data_in_reg[126:0], QSPI_IO_i[1]}; + op_counter <= 3'h0; end - end - if(current_state == ADDR) begin - addr_counter <= addr_counter + 1'b1; - end else begin - addr_counter <= 5'h00; - end + if(current_state==DATA_I || current_state ==DATA_O) begin + data_counter <= data_counter + 1; + if(QSPI_QIO_MODE==1'b0 && data_counter == 3'h7) begin + byte_counter <= byte_counter+1; + data_counter <= 3'h0; + end else if (QSPI_QIO_MODE==1'b1 && data_counter >= 3'h1) begin + byte_counter <= byte_counter+1; + data_counter <= 3'h0; + end + end else begin + data_counter <= 3'h7; + byte_counter <= 5'h1F; + end - if(current_state == MODE) begin - mode_counter <= mode_counter + 1'b1; - end else begin - mode_counter <= 1'b1; - end + if(current_state == DUMMY) begin + dummy_counter <= dummy_counter + 1; + end else begin + dummy_counter <= 4'h0; + end + + if(current_state == ADDR) begin + addr_counter <= addr_counter + 1; + end else begin + addr_counter <= 5'h00; + end + if(current_state == MODE) begin + mode_counter <= mode_counter + 1; + end else begin + mode_counter <= 1'b1; + end + end end // RDATA latch diff --git a/logical/top_ahb_qspi/logical/top_ahb_qspi.v b/logical/top_ahb_qspi/logical/top_ahb_qspi.v index ab151f6..735d925 100644 --- a/logical/top_ahb_qspi/logical/top_ahb_qspi.v +++ b/logical/top_ahb_qspi/logical/top_ahb_qspi.v @@ -407,7 +407,7 @@ qspi_controller u_qspi_controller( .QSPI_WRITE(QSPI_WRITE), .QSPI_ADDR_EN(QSPI_ADDR_EN), .QSPI_DUMMY_CYCLES(QSPI_DUMMY_CYCLES), - .QSPI_N_RW_BYTES(QSPI_N_RW_BYTES), + .QSPI_N_RW_BYTES({1'b0,QSPI_N_RW_BYTES}), .QSPI_ADDR(QSPI_ADDR), .QSPI_QIO_MODE(QSPI_QIO_MODE), .QSPI_WDATA(QSPI_WDATA), diff --git a/makefile b/makefile index 6cf9f96..652c61c 100644 --- a/makefile +++ b/makefile @@ -4,8 +4,9 @@ include $(SOCLABS_AHB_QSPI_DIR)/make.cfg # - Commonly Overloaded Variables #------------------------------------- # Simulator type (mti/vcs/xm) -SIMULATOR = mti - +SIMULATOR = vcs +GATE_SIMS ?= no +export GATE_SIMS #------------------------------------- # - Directory Setups #------------------------------------- @@ -16,6 +17,8 @@ SIM_DIR ?= $(SIM_TOP_DIR) ifeq ($(ASIC),yes) DESIGN_VC ?= $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_ASIC.flist +else ifeq ($(GATE_SIMS),yes) + DESIGN_VC ?= $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_SIM_GATES.flist else DESIGN_VC ?= $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_SIM.flist endif @@ -28,4 +31,5 @@ get_flash_model: #Include flows include ./flows/makefile.simulate include ./flows/makefile.lint +include ./flows/makefile.asic export BP210_DIR \ No newline at end of file diff --git a/verif/cocotb/ahb_qspi_cocotb.v b/verif/cocotb/ahb_qspi_cocotb.v index 119ef53..4a35390 100644 --- a/verif/cocotb/ahb_qspi_cocotb.v +++ b/verif/cocotb/ahb_qspi_cocotb.v @@ -128,6 +128,12 @@ top_ahb_qspi u_top_ahb_qspi( .QSPI_IO_e(QSPI_IO_e) ); +`ifdef GATE_SIMS +initial begin + $sdf_annotate("/home/dwn1c21/SoC-Labs/ahb_qspi/imp/ASIC/top_ahb_qspi.sdf", u_top_ahb_qspi); +end +`endif + assign QSPI_IO[0] = QSPI_IO_e[0] ? QSPI_IO_o[0] : 1'bz; assign QSPI_IO[1] = QSPI_IO_e[1] ? QSPI_IO_o[1] : 1'bz; assign QSPI_IO[2] = QSPI_IO_e[2] ? QSPI_IO_o[2] : 1'bz; @@ -143,5 +149,10 @@ sst26vf064b u_sst26vf064b( .SIO(QSPI_IO), .CEb(QSPI_nCS) ); +defparam u_sst26vf064b.I0.Tbe = 1_000; +defparam u_sst26vf064b.I0.Tse = 1_000; +defparam u_sst26vf064b.I0.Tsce = 1_000; +defparam u_sst26vf064b.I0.Tpp = 1_000; +defparam u_sst26vf064b.I0.Tws = 1000; endmodule \ No newline at end of file diff --git a/verif/cocotb/ahb_qspi_tests.py b/verif/cocotb/ahb_qspi_tests.py index 660fd77..3f2488e 100644 --- a/verif/cocotb/ahb_qspi_tests.py +++ b/verif/cocotb/ahb_qspi_tests.py @@ -22,13 +22,17 @@ class TB: self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) - cocotb.start_soon(Clock(dut.HCLK, 5, units="ns").start()) + self.dut.HRESETn.setimmediatevalue(0) + cocotb.start_soon(Clock(dut.HCLK, 10, units="ns").start()) self.config_ahb_master = AHBLiteMaster(AHBBus.from_prefix(dut,"config", optional_signals = {"hsel":"HSEL", "hready_in":"HREADY_IN", "hburst":"HBURST"}), dut.HCLK, dut.HRESETn) self.data_ahb_master = AHBLiteMaster(AHBBus.from_prefix(dut,"data", optional_signals = {"hsel":"HSEL", "hready_in":"HREADY_IN", "hburst":"HBURST"}), dut.HCLK, dut.HRESETn) async def cycle_reset(self): + await ClockCycles(self.dut.HCLK,1) + await Timer(time=4.5, units='ns') self.dut.HRESETn.setimmediatevalue(0) - await ClockCycles(self.dut.HCLK,20) + await ClockCycles(self.dut.HCLK,40) + await Timer(time=4.5, units='ns') self.dut.HRESETn.setimmediatevalue(1) await ClockCycles(self.dut.HCLK,10) @@ -84,8 +88,8 @@ async def LEAVE_QPI_MODE(dut, tb): data = await tb.config_ahb_master.read(0x04,4) async def QPI_READ_JEDIC(dut, tb): - await tb.config_ahb_master.write(0x08, 0x000210AF) - await tb.config_ahb_master.write(0x08, 0x000213AF) + await tb.config_ahb_master.write(0x08, 0x000220AF) + await tb.config_ahb_master.write(0x08, 0x000223AF) data = await tb.config_ahb_master.read(0x04,4) while(int(data[0]['data'],16)&1): await ClockCycles(dut.HCLK,10) @@ -146,8 +150,18 @@ async def SPI_BLOCK_ERASE(dut, tb): await Timer(time=1, units='ms') async def SPI_READ_STAT_REG(dut,tb): - await tb.config_ahb_master.write(0x08, 0x00001005) - await tb.config_ahb_master.write(0x08, 0x00001305) + await tb.config_ahb_master.write(0x08, 0x00002005) + await tb.config_ahb_master.write(0x08, 0x00002305) + data = await tb.config_ahb_master.read(0x04,4) + while(int(data[0]['data'],16)&1): + await ClockCycles(dut.HCLK,10) + data = await tb.config_ahb_master.read(0x04,4) + data = await tb.config_ahb_master.read(0x10,4) + return (int(data[0]['data'],16)) + +async def QPI_READ_STAT_REG(dut,tb): + await tb.config_ahb_master.write(0x08, 0x00002005) + await tb.config_ahb_master.write(0x08, 0x00002305) data = await tb.config_ahb_master.read(0x04,4) while(int(data[0]['data'],16)&1): await ClockCycles(dut.HCLK,10) @@ -155,6 +169,7 @@ async def SPI_READ_STAT_REG(dut,tb): data = await tb.config_ahb_master.read(0x10,4) return (int(data[0]['data'],16)) + async def SPI_READ_SLOW(dut, tb): # Write Adress await tb.config_ahb_master.write(0x0C, 0x000000) @@ -243,10 +258,10 @@ async def QPI_PAGE_PROGRAM(dut, tb, addr = 0, words=0, n_words = 1): while(int(data[0]['data'],16)&1): await ClockCycles(dut.HCLK,10) data = await tb.config_ahb_master.read(0x04,4) - SPI_STAT = await SPI_READ_STAT_REG(dut, tb) + SPI_STAT = await QPI_READ_STAT_REG(dut, tb) while(SPI_STAT&(1<<24)): - SPI_STAT = await SPI_READ_STAT_REG(dut, tb) - await Timer(time=100, units='us') + SPI_STAT = await QPI_READ_STAT_REG(dut, tb) + await Timer(time=1, units='us') @@ -256,65 +271,82 @@ async def QSPI_TESTS(dut): tb = TB(dut) await tb.cycle_reset() + tb.log.info("Reset SPI") await SPI_RESET(dut, tb) + tb.log.info("Reading JEDIC in SPI mode") ID = 0x4326BF00 rID = await SPI_READ_JEDIC(dut, tb) print(rID) assert rID == ID + tb.log.info("Setting QPI mode") await SET_QPI_MODE(dut, tb) await tb.config_ahb_master.write(0x00,0x1) + + tb.log.info("Reading JEDIC in QPI mode") rID = await QPI_READ_JEDIC(dut, tb) print(rID) assert rID == ID - + + tb.log.info("Enable Write") await SPI_WRITE_ENABLE(dut, tb) - SPI_STAT = await SPI_READ_STAT_REG(dut, tb) + SPI_STAT = await QPI_READ_STAT_REG(dut, tb) WEL = SPI_STAT & (1<<25) assert WEL != 0 + tb.log.info("Clear Protection and enable Write") await SPI_CLR_PROTECTION(dut, tb) await SPI_WRITE_ENABLE(dut, tb) - SPI_STAT = await SPI_READ_STAT_REG(dut, tb) + SPI_STAT = await QPI_READ_STAT_REG(dut, tb) WEL = SPI_STAT & (1<<25) assert WEL != 0 # Write and read 32-bit word + tb.log.info("Page program 4x bytes") data = [0x18273456] await QPI_PAGE_PROGRAM(dut, tb, words=data, n_words=1) + tb.log.info("Read 4x bytes") + await SPI_WRITE_DISABLE(dut,tb) rdata = await QPI_READ_WORDS(dut, tb, n_words=1) assert rdata == data # Write and read 2x 32=bit words + tb.log.info("Page program 8x bytes") data = [0x01234567, 0x89ABCDEF] await SPI_WRITE_ENABLE(dut, tb) await QPI_PAGE_PROGRAM(dut, tb, addr=0x100, words=data, n_words=2) + tb.log.info("Read 8x bytes") await SPI_WRITE_DISABLE(dut,tb) rdata = await QPI_READ_WORDS(dut, tb, addr=0x100, n_words=2) assert rdata == data # Write and read 3x 32=bit words + tb.log.info("Page program 12x bytes") data = [0x13243546, 0x97867564, 0x01234567] await SPI_WRITE_ENABLE(dut, tb) await QPI_PAGE_PROGRAM(dut, tb, addr=0x200, words=data, n_words=3) await SPI_WRITE_DISABLE(dut,tb) + tb.log.info("Read 12x bytes") rdata = await QPI_READ_WORDS(dut, tb, addr=0x200, n_words=3) assert rdata == data # Write and read 4x 32=bit words + tb.log.info("Page program 16x bytes") data = [0x13243546, 0x97867564, 0x89ABCDEF, 0x01234567] await SPI_WRITE_ENABLE(dut, tb) await QPI_PAGE_PROGRAM(dut, tb, addr=0x300, words=data, n_words=4) + tb.log.info("Read 16x bytes") await SPI_WRITE_DISABLE(dut,tb) rdata = await QPI_READ_WORDS(dut, tb, addr=0x300, n_words=4) assert rdata == data - + + tb.log.info("Exit QPI MODE") await LEAVE_QPI_MODE(dut, tb) await tb.config_ahb_master.write(0x00,0x1) @@ -323,42 +355,74 @@ async def QSPI_TESTS(dut): @cocotb.test() async def QSPI_READ_TESTS(dut): + n_reads = 64 + + tb = TB(dut) await tb.cycle_reset() - + tb.log.info("Reset SPI") await SPI_RESET(dut, tb) + tb.log.info("Reading JEDIC in SPI mode") ID = 0x4326BF00 rID = await SPI_READ_JEDIC(dut, tb) - print(rID) assert rID == ID + tb.log.info("Setting QPI mode") await SET_QPI_MODE(dut, tb) await tb.config_ahb_master.write(0x00,0x1) + + tb.log.info("Reading JEDIC in QPI mode") rID = await QPI_READ_JEDIC(dut, tb) - print(rID) assert rID == ID + await SPI_WRITE_ENABLE(dut, tb) + tb.log.info("Clear Protection and enable Write") + await SPI_CLR_PROTECTION(dut, tb) + await SPI_WRITE_ENABLE(dut, tb) + SPI_STAT = await QPI_READ_STAT_REG(dut, tb) + WEL = SPI_STAT & (1<<25) + assert WEL != 0 + + tb.log.info("Page program 512x 16-bytes") + data = [0x13243546, 0x97867564, 0x89ABCDEF, 0x01234567] + for i in range(0,n_reads): + addr = i*16 + await QPI_PAGE_PROGRAM(dut, tb, addr=addr, words=data, n_words=4) + await SPI_WRITE_ENABLE(dut, tb) + tb.log.info("Programmed %d words", i) + + await SPI_WRITE_DISABLE(dut,tb) + + tb.log.info("Read 16x bytes over APB") rDATA = await QPI_READ_WORDS(dut, tb, addr=0x10000, n_words=4, cont_read=True) + + tb.log.info("Set Continuous Read mode") QSPI_CTRL_REG = await tb.config_ahb_master.read(0x00,4) QSPI_CTRL_REG = int(QSPI_CTRL_REG[0]['data'],16) QSPI_CTRL_REG = QSPI_CTRL_REG | (1<<25) - await tb.config_ahb_master.write(0x00, QSPI_CTRL_REG) - - n_reads = 512 + await tb.config_ahb_master.write(0x00, QSPI_CTRL_REG) + tb.log.info("Read %d x 16-bytes over APB in continous read mode",n_reads) start_time = cocotb.utils.get_sim_time(units='ns') for i in range(0,n_reads): - rDATA = await QPI_READ_WORDS(dut, tb, addr=0x10000, n_words=4, cont_read=True) + addr = i*16 + rDATA = await QPI_READ_WORDS(dut, tb, addr=addr, n_words=4, cont_read=True) + assert rDATA==data + tb.log.info("Read %d words", i) + end_time = cocotb.utils.get_sim_time(units='ns') dt= end_time-start_time + + tb.log.info("Set AHB Mode") QSPI_CTRL_REG = await tb.config_ahb_master.read(0x00,4) QSPI_CTRL_REG = int(QSPI_CTRL_REG[0]['data'],16) QSPI_CTRL_REG = QSPI_CTRL_REG | (1<<8) await tb.config_ahb_master.write(0x00, QSPI_CTRL_REG) - + + tb.log.info("Configure Cache") CACHE_STATUS_tmp = await tb.config_ahb_master.read(CACHE_CONFIG_ADDR+0x04,4) CACHE_STATUS = int(CACHE_STATUS_tmp[0]['data'],16) assert CACHE_STATUS==0 @@ -377,15 +441,17 @@ async def QSPI_READ_TESTS(dut): - + tb.log.info("Read %d x 16-bytes over AHB (uncached)",n_reads) start_time_uncached = cocotb.utils.get_sim_time(units='ns') - for i in range(0,n_reads): + for i in range(0,n_reads*4): data = await tb.data_ahb_master.read(i*4,4) end_time_uncached = cocotb.utils.get_sim_time(units='ns') dt_uncached = end_time_uncached - start_time_uncached await Timer(time=10, units='us') + + tb.log.info("Read 512x 16-bytes over AHB (cached)") start_time_cached = cocotb.utils.get_sim_time(units='ns') - for i in range(0,n_reads): + for i in range(0,n_reads*4): data = await tb.data_ahb_master.read(i*4,4) end_time_cached = cocotb.utils.get_sim_time(units='ns') dt_cached = end_time_cached - start_time_cached diff --git a/verif/cocotb/makefile b/verif/cocotb/makefile index 6db4f36..c4a1c90 100644 --- a/verif/cocotb/makefile +++ b/verif/cocotb/makefile @@ -33,6 +33,11 @@ MODULE = ahb_qspi_tests VERILOG_SOURCES += $(SOCLABS_AHB_QSPI_DIR)/verif/cocotb/ahb_qspi_cocotb.v +ifeq ($(GATE_SIMS),yes) + EXTRA_ARGS += +define+ARM_UD_MODEL + EXTRA_ARGS += +define+GATE_SIMS +endif + ifeq ($(SIM), icarus) PLUSARGS += -fst @@ -53,6 +58,8 @@ else ifeq ($(SIM), verilator) endif else ifeq ($(SIM), questa) COMPILE_ARGS += +acc +else ifeq ($(SIM), vcs) + COMPILE_ARGS += -kdb +neg_tchk endif include $(SOCLABS_AHB_QSPI_DIR)/simulate/sim/cocotb/makefile.flist include $(shell cocotb-config --makefiles)/Makefile.sim -- GitLab