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
+```