diff --git a/EF_QSPI_XIP_CTRL.yaml b/EF_QSPI_XIP_CTRL.yaml index 1975431..e146444 100644 --- a/EF_QSPI_XIP_CTRL.yaml +++ b/EF_QSPI_XIP_CTRL.yaml @@ -20,11 +20,13 @@ info: type": soft status: verified cell_count: + - IP: 1973 - AHBL: 1973 width": "0.0" height": "0.0" technology: n/a clock_freq_mhz: + - IP: 250 - AHBL: 250 digital_supply_voltage: n/a analog_supply_voltage: n/a @@ -40,6 +42,10 @@ parameters: default: 999 description: The number of cycles needed for the s/w reset command; reset time = (RESET_CYCLES + 1) * 2 /(HCLK frequency). +clock: + name: clk + gated: 'no' + external_interface: - name: sck direction: output diff --git a/README.md b/README.md index 082d872..4b50853 100644 --- a/README.md +++ b/README.md @@ -1,99 +1,79 @@ # EF_QSPI_XIP_CTRL -Quad I/O SPI Flash memory controller with support for: -- AHB lite interface -- Execute in Place (XiP) -- Nx16 Direct-Mapped Cache (default: N=32). -Intended to be used with SoCs that have no on-chip flash memory. - - -## Performance -The following data is obtained using Sky130 HD library -| Configuration | # of Cells (K) | Delay (ns) | Idyn (mA/MHz) | Is (nA) | -|---------------|----------------|------------|--------------------------|--------------------| -| 16x16 | 7.2 | 12 | 0.0625 | 20 | -| 32x16 | 14.3 | 17 | 0.126 | 39.5 | - - -AHB-Lite Quad I/O SPI Flash memory controller with direct mapped cache and support for XiP. +A QSPI XiP Flash COntroller with a parameterized Direct-Mapped Cache. ## The wrapped IP The IP comes with an AHBL Wrapper -### Wrapped IP System Integration +#### Wrapped IP System Integration ```verilog EF_QSPI_XIP_CTRL_APB INST ( - `TB_AHBL_SLAVE_CONN, - .sck(sck), - .ce_n(ce_n), - .din(din), - .dout(dout), - .douten(douten) + `TB_AHBL_SLAVE_CONN, + .sck(sck) + .ce_n(ce_n) + .dout(dout) + .din(din) + .douten(douten) ); ``` > **_NOTE:_** `TB_APB_SLAVE_CONN is a convenient macro provided by [BusWrap](https://github.com/efabless/BusWrap/tree/main). +#### Wrappers with DFT support +Wrappers in the directory ``/hdl/rtl/bus_wrappers/DFT`` have an extra input port ``sc_testmode`` to enable the clock gate whenever the scan chain testmode is enabled. ## Implementation example The following table is the result for implementing the EF_QSPI_XIP_CTRL IP with different wrappers using Sky130 PDK and [OpenLane2](https://github.com/efabless/openlane2) flow. |Module | Number of cells | Max. freq | |---|---|---| -|EF_QSPI_XIP_CTRL|534| 384 MHz | -|EF_QSPI_XIP_CTRL_AHBL|13024|40 MHz| +|EF_QSPI_XIP_CTRL|1973| 250 | +|EF_QSPI_XIP_CTRL_AHBL|1973|250| +## The Programmer's Interface + + +### Registers + +|Name|Offset|Reset Value|Access Mode|Description| +|---|---|---|---|---| + +### Clock Gating +The IP has clock gating feature, enabling the selective activation and deactivation of the clock as required through the ``GCLK`` register. This functionality is implemented through the ``ef_util_gating_cell``, which is part of the the common modules library, [ef_util_lib.v](https://github.com/efabless/EF_IP_UTIL/blob/main/hdl/ef_util_lib.v). By default, the cell operates with a behavioral implementation, but when the ``CLKG_SKY130_HD`` macro is enabled, the ``sky130_fd_sc_hd__dlclkp_4`` clock gating cell is used. +**Note:** If you choose the [OpenLane2](https://github.com/efabless/openlane2) flow for implementation and would like to add the clock gating feature, you need to add ``SKY130`` macro to the ``VERILOG_DEFINES`` configuration variable. Update the YAML configuration file as follows: +``` +VERILOG_DEFINES: +- SKY130 +``` ### The Interface - + + + +#### Module Parameters + +|Parameter|Description|Default Value| +|---|---|---| +|NUM_LINES|The cache number of lines.|16| +|LINE_SIZE|The cache line size in bytes.|32| +|RESET_CYCLES|The number of cycles needed for the s/w reset command; reset time = (RESET_CYCLES + 1) * 2 /(HCLK frequency).|999| #### Ports |Port|Direction|Width|Description| |---|---|---|---| -|sck|output|1|spi serial clock| -|ce_n|output|1|slave select signal| -|din|input|4|spi data in| -|dout|output|4|spi data out| -|douten|output|4|spi data out enable| - +|sck|output|1|SPI serial clock| +|ce_n|output|1|SPI chip select (Active Low).| +|dout|output|4|Flash controller SPI data out.| +|din|input|4|Flash controller SPI data in.| +|douten|output|4|Flash controller data out enable (Active Low)| +## Firmware Drivers: +Firmware drivers for EF_QSPI_XIP_CTRL can be found in the [fw](https://github.com/efabless/EF_QSPI_XIP_CTRL/tree/main/fw) directory. EF_QSPI_XIP_CTRL driver documentation is available [here](https://github.com/efabless/EF_QSPI_XIP_CTRL/blob/main/fw/README.md). +You can also find an example C application using the EF_QSPI_XIP_CTRL drivers [here](). ## Installation: You can either clone repo or use [IPM](https://github.com/efabless/IPM) which is an open-source IPs Package Manager * To clone repo: -```git clone https://https://github.com/shalan/EF_QSPI_FLASH_CTRL``` +```git clone https://github.com/efabless/EF_QSPI_XIP_CTRL``` +> **Note:** If you choose this method, you need to clone [EF_IP_UTIL](https://github.com/efabless/EF_IP_UTIL.git) repository, as it includes required modules from the common modules library, [ef_util_lib.v](https://github.com/efabless/EF_IP_UTIL/blob/main/hdl/ef_util_lib.v) * To download via IPM , follow installation guides [here](https://github.com/efabless/IPM/blob/main/README.md) then run ```ipm install EF_QSPI_XIP_CTRL``` -### Run cocotb UVM Testbench: -In IP directory run: - ```shell - cd verify/uvm-python/ - ``` - ##### To run testbench for design with APB - To run all tests: - ```shell - make run_all_tests BUS_TYPE=APB - ``` - To run a certain test: - ```shell - make run_ BUS_TYPE=APB - ``` - To run all tests with a tag: - ```shell - make run_all_tests TAG= BUS_TYPE=APB - ``` - ##### To run testbench for design with APB - To run all tests: - ```shell - make run_all_tests BUS_TYPE=AHB - ``` - To run a certain test: - ```shell - make run_ BUS_TYPE=AHB - ``` - To run all tests with a tag: - ```shell - make run_all_tests TAG= BUS_TYPE=AHB -``` - -## Todo: - - [ ] support for WB bus - - [ ] Support cache configurations other than 16 bytes per line +> **Note:** This method is recommended as it automatically installs [EF_IP_UTIL](https://github.com/efabless/EF_IP_UTIL.git) as a dependency. diff --git a/hdl/rtl/bus_wrappers/EF_QSPI_XIP_CTRL_ahbl.v b/hdl/rtl/bus_wrappers/EF_QSPI_XIP_CTRL_ahbl.v deleted file mode 100644 index 34daba8..0000000 --- a/hdl/rtl/bus_wrappers/EF_QSPI_XIP_CTRL_ahbl.v +++ /dev/null @@ -1,207 +0,0 @@ -/* - Copyright 2020 Mohamed Shalan (mshalan@aucegypt.edu) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -`timescale 1ns/1ps -`default_nettype none - -/* - AHB-Lite Quad I/O flash XiP controller with Nx16 RO Direct-mapped Cache. - Intended to be used to execute only from an external Quad I/O SPI Flash Memory - - Performance (CM0 @ 50MHz using gcc -O2) - - Configuration run-time (msec) - NUM_LINES LINE_SIZE stress hash chacha xtea(256) aes_sbox G. Mean - 128 16 0.208 (4.9x) 0.707 (8.8x) 0.277 (7.4x) 0.212 (11.9x) 0.339 (6.4x) 7.53 - 64 16 0.208 (4.9x) 0.779 (8.0x) 0.277 (7.4x) 0.212 (11.9x) 0.339 (6.4x) 7.39 - 32 16 0.233 (4.4x) 0.869 (7.2x) 0.334 (6.2x) 0.212 (11.9x) 0.339 (6.4x) 6.83 <-- default - 16 16 0.410 (2.5x) 1.259 (5.0x) 0.436 (4.7x) 0.212 (11.9x) 0.339 (6.4x) 5.37 - 8 16 0.692 (1.5x) 2.217 (2.8x) 0.951 (2.2x) 0.218 (11.6x) 0.341 (6.4x) 3.69 - 4 16 0.899 (1.1x) 4.983 (1.3x) 1.723 (1.2x) - 2 16 1.020 (1.0x) 6.243 (1.0x) 2.076 (1.0x) 2.527 ( 1.0x) 2.191 (1.0x) 1.00 - - Miss time is 28 + 4*LINE_SIZE - Line_SIZE Miss Time # of fetched Instr. (32/16) - 16 92 4/8 - 32 156 8/16 - - Software Reset Time = 2/clk x (RESET_CYCLES + 1) -*/ - -module EF_QSPI_XIP_CTRL_ahbl #(parameter NUM_LINES = 16, - LINE_SIZE = 32, - RESET_CYCLES= 999 ) -( - // AHB-Lite Slave Interface - input wire HCLK, - input wire HRESETn, - input wire HSEL, - input wire [31:0] HADDR, - input wire [1:0] HTRANS, - input wire HWRITE, - input wire HREADY, - output reg HREADYOUT, - output wire [31:0] HRDATA, - - // External Interface to Quad I/O - output wire sck, - output wire ce_n, - input wire [3:0] din, - output wire [3:0] dout, - output wire [3:0] douten -); - - localparam [1:0] IDLE = 2'b00; - localparam [1:0] WAIT = 2'b01; - localparam [1:0] RW = 2'b10; - localparam OFF_WIDTH = $clog2(LINE_SIZE); - - // Cache wires/buses - wire [31:0] c_datao; - wire [(LINE_SIZE*8)-1:0] c_line; - wire c_hit; - reg [2:0] c_wr; - wire [23:0] c_A; - - // Flash Reader wires - wire fr_rd; - wire fr_done; - - wire doe; - - reg [1:0] state, nstate; - - //AHB-Lite Address Phase Regs - reg last_HSEL; - reg [31:0] last_HADDR; - reg last_HWRITE; - reg [1:0] last_HTRANS; - reg last_valid; - - wire valid = HSEL & HTRANS[1] & HREADY; - - always@ (posedge HCLK or negedge HRESETn) - begin - if(~HRESETn) begin - last_HSEL <= 'b0; - last_HADDR <= 'b0; - last_HWRITE <= 'b0; - last_HTRANS <= 'b0; - last_valid <= 'b0; - end - else if(HREADY) begin - last_HSEL <= HSEL; - last_HADDR <= HADDR; - last_HWRITE <= HWRITE; - last_HTRANS <= HTRANS; - last_valid <= valid; - end - end - - always @ (posedge HCLK or negedge HRESETn) - if(HRESETn == 0) - state <= IDLE; - else - state <= nstate; - - always @* begin - nstate = IDLE; - case(state) - IDLE : if(valid & c_hit) - nstate = IDLE; - else if(valid & ~c_hit) - nstate = WAIT; - - WAIT : if(c_wr[2]) - nstate = RW; - else - nstate = WAIT; - - RW : nstate = IDLE; - endcase - end - - always @(posedge HCLK or negedge HRESETn) - if(!HRESETn) - HREADYOUT <= 1'b1; - else - case (state) - IDLE : if(valid & c_hit) - HREADYOUT <= 1'b1; - else if(valid & ~c_hit) - HREADYOUT <= 1'b0; - else - HREADYOUT <= 1'b1; - - WAIT : HREADYOUT <= 1'b0; - - RW : HREADYOUT <= 1'b1; - endcase - - assign fr_rd = ( HTRANS[1] & HSEL & HREADY & ~c_hit & (state==IDLE) ) | - ( HTRANS[1] & HSEL & HREADY & ~c_hit & (state==RW) ); - - assign c_A = (state != IDLE) ? last_HADDR[23:0] : HADDR; - - - DMC #( .NUM_LINES(NUM_LINES), - .LINE_SIZE(LINE_SIZE) ) - CACHE ( - .clk(HCLK), - .rst_n(HRESETn), - .A(c_A), - .Do(c_datao), - .hit(c_hit), - .line(c_line), - .wr(c_wr[1]) - ); - - EF_QSPI_XIP_CTRL #( .NUM_LINES(NUM_LINES), - .LINE_SIZE(LINE_SIZE), - .RESET_CYCLES(RESET_CYCLES) ) - FC ( - .clk(HCLK), - .rst_n(HRESETn), - .addr({c_A[23:OFF_WIDTH], {OFF_WIDTH{1'b0}}}), - .rd(fr_rd), - .done(fr_done), - .line(c_line), - .sck(sck), - .ce_n(ce_n), - .din(din), - .dout(dout), - .douten(doe) - ); - - reg [31:0] cdata; - assign HRDATA = cdata; - - always @(posedge HCLK) - case (state) - IDLE: if(valid & c_hit) cdata <= c_datao; - WAIT: if(c_wr[1]) cdata <= c_datao; - endcase - - always @ (posedge HCLK or negedge HRESETn) - if(~HRESETn) - c_wr <= 'b0; - else begin - c_wr[0] <= fr_done; - c_wr[1] <= c_wr[0]; - c_wr[2] <= c_wr[1]; - end - - assign douten = {4{doe}}; - -endmodule \ No newline at end of file diff --git a/ipm_package.bash b/ipm_package.bash new file mode 100644 index 0000000..3b10572 --- /dev/null +++ b/ipm_package.bash @@ -0,0 +1,75 @@ +#!/bin/bash +# to run use bash ipm_package.bash --version x.x.x --ip_name name +# More safety, by turning some bugs into errors. +set -o errexit -o pipefail -o nounset + +# now enjoy the options in order and nicely split until we see -- +# option --output/-o requires 1 argument +LONGOPTS=version:ip_name: +OPTIONS= + +# -temporarily store output to be able to check for errors +# -activate quoting/enhanced mode (e.g. by writing out "--options") +# -pass arguments only via -- "$@" to separate them correctly +# -if getopt fails, it complains itself to stdout +PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") || exit 2 +# read getopt's output this way to handle the quoting right: +eval set -- "$PARSED" +unset PARSED + + +while true; do + case "$1" in + --version) + version="$2" + shift 2 + ;; + --) + --ip_name) + ip_name="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + echo "Programming error" + exit 3 + ;; + esac +done + +echo "+ version=$version" + +# zip needed files + + +tar czf v$version.tar.gz --files-from <(find . | grep -v "\./verify" | grep -v "\./fw/Doxyfile" | grep -v "\./ipm_package.bash" | grep -v ".*\.dev\.v" | grep -v "\./hdl/rtl/bus_wrappers/dft" | grep -v "\.git" | grep -v "\.tar\.gz" | grep -v "\./ip" | grep -v "\./docs" | grep -v "\.\$"; ls "./ip/dependencies.json") +# tar czf v$version.tar.gz \ +# --exclude='verify' \ +# --exclude='hdl/rtl/bus_wrappers/dft' \ +# --exclude='hdl/rtl/bus_wrappers/*.dev.v' \ +# --exclude='ipm_package.bash' \ +# --exclude='fw/Doxyfile' \ +# --include='*.c' \ +# * +# get checksum +shasum -a 256 v$version.tar.gz > v$version.tar.gz.sha256 + +# update yaml +sed -i "s/version.*/version: v$version/" *.yaml +sed -i "s/date.*/date: $(date +"%Y-%m-%d")/" *.yaml + +# create tag +git tag -a $ip_name-v$version -m "Release version $version" +git push origin $ip_name-v$version + +# create release +set -x +if gh release view $ip_name-v$version > /dev/null 2>&1; then + echo "Release $ip_name-v$version already exists. Skipping..." +else + echo "Creating release $ip_name-v$version..." + gh release create $ip_name-v$version v$version.tar.gz -t "$ip_name-v$version" --notes "sha256: $(cat v$version.tar.gz.sha256)" +fi diff --git a/verify/README.md b/verify/README.md new file mode 100644 index 0000000..79a7572 --- /dev/null +++ b/verify/README.md @@ -0,0 +1,31 @@ +## Run cocotb UVM Testbench: +In IP directory run: + ```shell + cd verify/uvm-python/ + ``` + ##### To run testbench for design with APB + To run all tests: + ```shell + make run_all_tests BUS_TYPE=APB + ``` + To run a certain test: + ```shell + make run_ BUS_TYPE=APB + ``` + To run all tests with a tag: + ```shell + make run_all_tests TAG= BUS_TYPE=APB + ``` + ##### To run testbench for design with APB + To run all tests: + ```shell + make run_all_tests BUS_TYPE=AHB + ``` + To run a certain test: + ```shell + make run_ BUS_TYPE=AHB + ``` + To run all tests with a tag: + ```shell + make run_all_tests TAG= BUS_TYPE=AHB +```