diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index b78e239..ea4f142 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -1,9 +1,9 @@ name: CI on: push: - branches: [ main ] + branches: [ main, divide ] pull_request: - branches: [ main ] + branches: [ main, divide ] jobs: @@ -72,8 +72,8 @@ jobs: strategy: fail-fast: false matrix: - unit: [lsu, alu, mul, sld, elem, csr, misc] - main_core: [ibex, cv32e40x] + unit: [lsu, alu, mul, sld, elem, csr, misc, div] + main_core: [ibex] steps: - uses: actions/checkout@v2 with: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..b78e239 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,125 @@ +name: CI +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + + +jobs: + verilator: + runs-on: ubuntu-22.04 + steps: + - uses: actions/cache@v2 + id: cache-verilator + with: + path: /opt/verilator + key: ubuntu-22_04-verilator-4_210 + + - name: Install Verilator + if: steps.cache-verilator.outputs.cache-hit != 'true' + run: | + sudo apt-get update + sudo apt-get install git perl python3 g++ flex bison ccache libfl2 libfl-dev zlib1g zlib1g-dev + git clone https://github.com/verilator/verilator + unset VERILATOR_ROOT + cd verilator + git checkout tags/v4.210 + autoconf + ./configure --prefix /opt/verilator + make + sudo make install + df -h + cd .. + rm -rf verilator + + + lint: + needs: verilator + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: false + + - uses: actions/cache@v2 + id: cache-verilator + with: + path: /opt/verilator + key: ubuntu-22_04-verilator-4_210 + + - name: Abort if no cache + if: steps.cache-verilator.outputs.cache-hit != 'true' + run: exit 1 + + - name: Install packages + run: | + sudo apt-get update + sudo apt-get install git perl python3 g++ ccache libfl2 libfl-dev zlib1g zlib1g-dev + + - name: Install verible and lint + run: | + curl -sSL https://api.github.com/repos/chipsalliance/verible/releases/latest | grep browser_download_url | grep Ubuntu-20.04 | cut -d '"' -f 4 | wget -qi - + mkdir verible + tar -xf verible*.tar.gz -C verible --strip-components=1 + export PATH=$PATH:$PWD/verible/bin:/opt/verilator/bin + cd test && make lint + + + unit: + needs: verilator + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + unit: [lsu, alu, mul, sld, elem, csr, misc] + main_core: [ibex, cv32e40x] + steps: + - uses: actions/checkout@v2 + with: + submodules: true + + - uses: actions/cache@v2 + id: cache-verilator + with: + path: /opt/verilator + key: ubuntu-22_04-verilator-4_210 + + - name: Abort if no cache + if: steps.cache-verilator.outputs.cache-hit != 'true' + run: exit 1 + + - name: Install packages + run: | + sudo apt-get update + sudo apt-get install git perl python3 g++ ccache libfl2 libfl-dev zlib1g zlib1g-dev + sudo apt-get install srecord llvm-14 clang-14 + sudo ln -sf /usr/bin/llvm-objdump-14 /usr/bin/llvm-objdump + sudo ln -sf /usr/bin/llvm-objcopy-14 /usr/bin/llvm-objcopy + + - name: Run tests + shell: bash {0} # disable fail-fast behavior + run: | + export PATH=$PATH:/opt/verilator/bin:/opt/riscv-gcc/bin + verilator --version + retval=0 + while IFS= read -ra line; do + if [ -z "$line" ] || [ "${line:0:1}" = "#" ]; then + continue + fi + echo "$line" > test/${{ matrix.unit }}/test_configs.conf + vcd=`echo "${{ matrix.unit }}_${{ matrix.main_core }}_${line}.vcd" | sed 's/ */_/g'` + make -C test ${{ matrix.unit }} CORE=${{ matrix.main_core }} FULL_LOG=1 TRACE_VCD=$vcd + if [ $? -ne 0 ]; then + retval=1 + fi + done < .github/test_configs.conf + exit $retval + + - name: Archive VCD trace files + if: failure() + uses: actions/upload-artifact@v3 + with: + name: vcd-trace-files + path: | + test/${{ matrix.unit }}/*.vcd diff --git a/.gitignore b/.gitignore index 54060b2..89d3364 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ *.fst *.fst.hier *.gtkw -vproc_config.sv + diff --git a/config.mk b/config.mk old mode 100644 new mode 100755 index 1d57545..c0cc1f5 --- a/config.mk +++ b/config.mk @@ -15,7 +15,7 @@ # - VPROC_PIPELINES: Defines the vector pipelines. Each pipeline is defined by # a string of the form "WIDTH:UNIT[,UNIT]*" where WIDTH is the width in bits # of the pipeline's datapath and each occurence of UNIT selects one of the -# vector execution units (either VLSU, VALU, VMUL, VSLD, or VELEM). +# vector execution units (either VLSU, VALU, VMUL, VSLD, VELEM, or VDIV). # - VPROC_CONFIG: Sets default values for the other parameters (that can be # individually overriden) depending on the desired number of vector # pipelines (choose 1, 2, 3, or 5 pipelines by setting this variable to @@ -28,26 +28,26 @@ ifeq ($(VPROC_CONFIG), compact) VPORT_POLICY ?= some VMEM_W ?= 32 VREG_W ?= 128 - VPROC_PIPELINES ?= $(VMEM_W):VLSU,VALU,VMUL,VSLD,VELEM + VPROC_PIPELINES ?= $(VMEM_W):VLSU,VALU,VMUL,VSLD,VELEM,VDIV else ifeq ($(VPROC_CONFIG), dual) VPORT_POLICY ?= some VMEM_W ?= 32 VREG_W ?= 128 - VPROC_PIPELINES ?= $(VMEM_W):VLSU,VALU,VELEM $(VPIPE_W_VMUL):VMUL,VSLD + VPROC_PIPELINES ?= $(VMEM_W):VLSU,VALU,VELEM,VDIV $(VPIPE_W_VMUL):VMUL,VSLD else ifeq ($(VPROC_CONFIG), triple) VPORT_POLICY ?= some VMEM_W ?= 32 VREG_W ?= 256 - VPROC_PIPELINES ?= $(VMEM_W):VLSU $(VPIPE_W_DFLT):VALU,VELEM $(VPIPE_W_VMUL):VMUL,VSLD + VPROC_PIPELINES ?= $(VMEM_W):VLSU $(VPIPE_W_DFLT):VALU,VELEM,VDIV $(VPIPE_W_VMUL):VMUL,VSLD else ifeq ($(VPROC_CONFIG), legacy) VPORT_POLICY ?= some VMEM_W ?= 32 VREG_W ?= 128 VPROC_PIPELINES ?= $(VMEM_W):VLSU $(VPIPE_W_DFLT):VALU $(VPIPE_W_VMUL):VMUL \ - $(VPIPE_W_DFLT):VSLD 32:VELEM + $(VPIPE_W_DFLT):VSLD 32:VELEM $(VPIPE_W_DFLT):VDIV else $(error Unknown vector coprocessor configuration $(VPROC_CONFIG)) endif @@ -102,7 +102,7 @@ $(VPROC_CONFIG_PKG): width=`echo $$pipe | cut -d ":" -f 1`; \ unit_str=`echo $$pipe | cut -d ":" -f 2 | sed 's/,/, /g'`; \ unit_mask=`echo $$pipe | cut -d ":" -f 2 | sed 's/,/ | /g' | \ - sed "s/V\(LSU\|ALU\|MUL\|SLD\|ELEM\)/(UNIT_CNT'(1) << UNIT_\1)/g"`; \ + sed "s/V\(LSU\|ALU\|MUL\|SLD\|ELEM\|DIV\)/(UNIT_CNT'(1) << UNIT_\1)/g"`; \ vport_cnt=1; \ if echo "$$pipe" | grep -q "VMUL" && [ $$(($$width * 4)) -gt "$(VREG_W)" ]; then \ vport_cnt=2; \ @@ -180,6 +180,7 @@ $(VPROC_CONFIG_PKG): echo " parameter int unsigned VLSU_QUEUE_SZ = 4;" >>$@; \ echo " parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = '0;" >>$@; \ echo " parameter mul_type MUL_TYPE = MUL_GENERIC;" >>$@; \ + echo " parameter div_type DIV_TYPE = DIV_GENERIC;" >>$@; \ echo "" >>$@; \ echo " parameter int unsigned INSTR_QUEUE_SZ = 2;" >>$@; \ echo " parameter bit [BUF_FLAGS_W-1:0] BUF_FLAGS = $${buf_flags};" >>$@; \ diff --git a/demo/rtl/demo_top.sv b/demo/rtl/demo_top.sv index 1101c18..f6ea243 100644 --- a/demo/rtl/demo_top.sv +++ b/demo/rtl/demo_top.sv @@ -4,7 +4,7 @@ module demo_top #( - parameter RAM_FPATH = "", + parameter RAM_FPATH = "/home/hfaroo9/ece498hk-RISCV-V-Extension/src/vicuna/sim/files.txt", parameter int unsigned RAM_SIZE = 262144, parameter bit DIFF_CLK = 1'b0, parameter real SYSCLK_PER = 0.0, @@ -88,8 +88,8 @@ module demo_top #( vproc_top #( .MEM_W ( 32 ), .VMEM_W ( 32 ), - .VREG_TYPE ( vproc_pkg::VREG_XLNX_RAM32M ), - .MUL_TYPE ( vproc_pkg::MUL_XLNX_DSP48E1 ) + .VREG_TYPE ( vproc_pkg::VREG_GENERIC ), + .MUL_TYPE ( vproc_pkg::MUL_GENERIC ) ) vproc ( .clk_i ( clk ), .rst_ni ( rst_n ), diff --git a/prim/rtl/dv_fcov_macros.svh b/prim/rtl/dv_fcov_macros.svh new file mode 100644 index 0000000..9439ea5 --- /dev/null +++ b/prim/rtl/dv_fcov_macros.svh @@ -0,0 +1,113 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Include FCOV RTL by default. Disable it for synthesis and where explicitly requested (by defining +// DV_FCOV_DISABLE). +`ifdef SYNTHESIS + `define DV_FCOV_DISABLE +`elsif YOSYS + `define DV_FCOV_DISABLE +`endif + +// Disable instantiations of FCOV coverpoints or covergroups. +`ifdef VERILATOR + `define DV_FCOV_DISABLE_CP +`elsif DV_FCOV_DISABLE + `define DV_FCOV_DISABLE_CP +`endif + +// Instantiates a covergroup in an interface or module. +// +// This macro assumes that a covergroup of the same name as the NAME_ arg is defined in the +// interface or module. It just adds some extra signals and logic to control the creation of the +// covergroup instance with ~bit en_~. This defaults to 0. It is ORed with the external +// COND_ signal. The testbench can modify it at t = 0 based on the test being run. +// NOTE: This is not meant to be invoked inside a class. +// +// NAME_ : Name of the covergroup. +// COND_ : External condition / expr that controls the creation of the covergroup. +// ARGS_ : Arguments to covergroup instance, if any. Args MUST BE wrapped in (..). +`ifndef DV_FCOV_INSTANTIATE_CG +`ifdef DV_FCOV_DISABLE_CP + `define DV_FCOV_INSTANTIATE_CG(NAME_, COND_ = 1'b1, ARGS_ = ()) +`else + `define DV_FCOV_INSTANTIATE_CG(NAME_, COND_ = 1'b1, ARGS_ = ()) \ + bit en_``NAME_ = 1'b0; \ + NAME_ NAME_``_inst; \ + initial begin \ + /* The #1 delay below allows any part of the tb to control the conditions first at t = 0. */ \ + #1; \ + if ((en_``NAME_) || (COND_)) begin \ + $display("%0t: (%0s:%0d) [%m] %0s", $time, `__FILE__, `__LINE__, \ + {"Creating covergroup ", `"NAME_`"}); \ + NAME_``_inst = new``ARGS_; \ + end \ + end +`endif +`endif + +// Creates a coverpoint for an expression where only the expression true case is of interest for +// coverage (e.g. where the expression indicates an event has occured). +`ifndef DV_FCOV_EXPR_SEEN +`ifdef DV_FCOV_DISABLE_CP + `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) +`else + `define DV_FCOV_EXPR_SEEN(NAME_, EXPR_) cp_``NAME_: coverpoint EXPR_ { bins seen = {1}; } +`endif +`endif + +// Creates a SVA cover that can be used in a covergroup. +// +// This macro creates an unnamed SVA cover from the property (or an expression) `PROP_` and an event +// with the name `EV_NAME_`. When the SVA cover is hit, the event is triggered. A coverpoint can +// cover the `triggered` property of the event. +`ifndef DV_FCOV_SVA +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SVA(EV_NAME_, PROP_, CLK_ = clk_i, RST_ = rst_ni) +`else + `define DV_FCOV_SVA(EV_NAME_, PROP_, CLK_ = clk_i, RST_ = rst_ni) \ + event EV_NAME_; \ + cover property (@(posedge CLK_) disable iff (RST_ == 0) (PROP_)) begin \ + -> EV_NAME_; \ + end +`endif +`endif + +// Coverage support is not always available but it's useful to include extra fcov signals for +// linting purposes. They need to be marked as unused to avoid warnings. +`ifndef DV_FCOV_MARK_UNUSED + `define DV_FCOV_MARK_UNUSED(TYPE_, NAME_) \ + TYPE_ unused_fcov_``NAME_; \ + assign unused_fcov_``NAME_ = fcov_``NAME_; +`endif + +// Define a signal and expression in the design for capture in functional coverage +`ifndef DV_FCOV_SIGNAL +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SIGNAL(TYPE_, NAME_, EXPR_) +`else + `define DV_FCOV_SIGNAL(TYPE_, NAME_, EXPR_) \ + TYPE_ fcov_``NAME_; \ + assign fcov_``NAME_ = EXPR_; \ + `DV_FCOV_MARK_UNUSED(TYPE_, NAME_) +`endif +`endif + +// Define a signal and expression in the design for capture in functional coverage depending on +// design configuration. The input GEN_COND_ must be a constant or parameter. +`ifndef DV_FCOV_SIGNAL_GEN_IF +`ifdef DV_FCOV_DISABLE + `define DV_FCOV_SIGNAL_GEN_IF(TYPE_, NAME_, EXPR_, GEN_COND_, DEFAULT_ = '0) +`else + `define DV_FCOV_SIGNAL_GEN_IF(TYPE_, NAME_, EXPR_, GEN_COND_, DEFAULT_ = '0) \ + TYPE_ fcov_``NAME_; \ + if (GEN_COND_) begin : g_fcov_``NAME_ \ + assign fcov_``NAME_ = EXPR_; \ + end else begin : g_no_fcov_``NAME_ \ + assign fcov_``NAME_ = DEFAULT_; \ + end \ + `DV_FCOV_MARK_UNUSED(TYPE_, NAME_) +`endif +`endif + diff --git a/prim/rtl/prim_assert.sv b/prim/rtl/prim_assert.sv new file mode 100644 index 0000000..bb9251b --- /dev/null +++ b/prim/rtl/prim_assert.sv @@ -0,0 +1,180 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Macros and helper code for using assertions. +// - Provides default clk and rst options to simplify code +// - Provides boiler plate template for common assertions + +`ifndef PRIM_ASSERT_SV +`define PRIM_ASSERT_SV + +/////////////////// +// Helper macros // +/////////////////// + +// Default clk and reset signals used by assertion macros below. +`define ASSERT_DEFAULT_CLK clk_i +`define ASSERT_DEFAULT_RST !rst_ni + +// Converts an arbitrary block of code into a Verilog string +`define PRIM_STRINGIFY(__x) `"__x`" + +// ASSERT_ERROR logs an error message with either `uvm_error or with $error. +// +// This somewhat duplicates `DV_ERROR macro defined in hw/dv/sv/dv_utils/dv_macros.svh. The reason +// for redefining it here is to avoid creating a dependency. +`define ASSERT_ERROR(__name) \ +`ifdef UVM \ + uvm_pkg::uvm_report_error("ASSERT FAILED", `PRIM_STRINGIFY(__name), uvm_pkg::UVM_NONE, \ + `__FILE__, `__LINE__, "", 1); \ +`else \ + $error("%0t: (%0s:%0d) [%m] [ASSERT FAILED] %0s", $time, `__FILE__, `__LINE__, \ + `PRIM_STRINGIFY(__name)); \ +`endif + +// This macro is suitable for conditionally triggering lint errors, e.g., if a Sec parameter takes +// on a non-default value. This may be required for pre-silicon/FPGA evaluation but we don't want +// to allow this for tapeout. +`define ASSERT_STATIC_LINT_ERROR(__name, __prop) \ + localparam int __name = (__prop) ? 1 : 2; \ + always_comb begin \ + logic unused_assert_static_lint_error; \ + unused_assert_static_lint_error = __name'(1'b1); \ + end + +// Static assertions for checks inside SV packages. If the conditions is not true, this will +// trigger an error during elaboration. +`define ASSERT_STATIC_IN_PACKAGE(__name, __prop) \ + function automatic bit assert_static_in_package_``__name(); \ + bit unused_bit [((__prop) ? 1 : -1)]; \ + unused_bit = '{default: 1'b0}; \ + return unused_bit[0]; \ + endfunction + +// The basic helper macros are actually defined in "implementation headers". The macros should do +// the same thing in each case (except for the dummy flavour), but in a way that the respective +// tools support. +// +// If the tool supports assertions in some form, we also define INC_ASSERT (which can be used to +// hide signal definitions that are only used for assertions). +// +// The list of basic macros supported is: +// +// ASSERT_I: Immediate assertion. Note that immediate assertions are sensitive to simulation +// glitches. +// +// ASSERT_INIT: Assertion in initial block. Can be used for things like parameter checking. +// +// ASSERT_INIT_NET: Assertion in initial block. Can be used for initial value of a net. +// +// ASSERT_FINAL: Assertion in final block. Can be used for things like queues being empty at end of +// sim, all credits returned at end of sim, state machines in idle at end of sim. +// +// ASSERT: Assert a concurrent property directly. It can be called as a module (or +// interface) body item. +// +// Note: We use (__rst !== '0) in the disable iff statements instead of (__rst == +// '1). This properly disables the assertion in cases when reset is X at the +// beginning of a simulation. For that case, (reset == '1) does not disable the +// assertion. +// +// ASSERT_NEVER: Assert a concurrent property NEVER happens +// +// ASSERT_KNOWN: Assert that signal has a known value (each bit is either '0' or '1') after reset. +// It can be called as a module (or interface) body item. +// +// COVER: Cover a concurrent property +// +// ASSUME: Assume a concurrent property +// +// ASSUME_I: Assume an immediate property + +`ifdef VERILATOR + `include "prim_assert_dummy_macros.svh" +`elsif SYNTHESIS + `include "prim_assert_dummy_macros.svh" +`elsif YOSYS + `include "prim_assert_yosys_macros.svh" + `define INC_ASSERT +`else + `include "prim_assert_standard_macros.svh" + `define INC_ASSERT +`endif + +////////////////////////////// +// Complex assertion macros // +////////////////////////////// + +// Assert that signal is an active-high pulse with pulse length of 1 clock cycle +`define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + `ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) + +// Assert that a property is true only when an enable signal is set. It can be called as a module +// (or interface) body item. +`define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + `ASSERT(__name, (__enable) |-> (__prop), __clk, __rst) + +// Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is +// set. It can be called as a module (or interface) body item. +`define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + `ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \ + `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) + +////////////////////////////////// +// For formal verification only // +////////////////////////////////// + +// Note that the existing set of ASSERT macros specified above shall be used for FPV, +// thereby ensuring that the assertions are evaluated during DV simulations as well. + +// ASSUME_FPV +// Assume a concurrent property during formal verification only. +`define ASSUME_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef FPV_ON \ + `ASSUME(__name, __prop, __clk, __rst) \ +`endif + +// ASSUME_I_FPV +// Assume a concurrent property during formal verification only. +`define ASSUME_I_FPV(__name, __prop) \ +`ifdef FPV_ON \ + `ASSUME_I(__name, __prop) \ +`endif + +// COVER_FPV +// Cover a concurrent property during formal verification +`define COVER_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ +`ifdef FPV_ON \ + `COVER(__name, __prop, __clk, __rst) \ +`endif + +// FPV assertion that proves that the FSM control flow is linear (no loops) +// The sequence triggers whenever the state changes and stores the current state as "initial_state". +// Then thereafter we must never see that state again until reset. +// It is possible for the reset to release ahead of the clock. +// Create a small "gray" window beyond the usual rst time to avoid +// checking. +`define ASSERT_FPV_LINEAR_FSM(__name, __state, __type, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + `ifdef INC_ASSERT \ + bit __name``_cond; \ + always_ff @(posedge __clk or posedge __rst) begin \ + if (__rst) begin \ + __name``_cond <= 0; \ + end else begin \ + __name``_cond <= 1; \ + end \ + end \ + property __name``_p; \ + __type initial_state; \ + (!$stable(__state) & __name``_cond, initial_state = $past(__state)) |-> \ + (__state != initial_state) until (__rst == 1'b1); \ + endproperty \ + `ASSERT(__name, __name``_p, __clk, __rst) \ + `endif + +`include "prim_assert_sec_cm.svh" +`include "prim_flop_macros.sv" + +`endif // PRIM_ASSERT_SV + diff --git a/prim/rtl/prim_assert_sec_cm.svh b/prim/rtl/prim_assert_sec_cm.svh new file mode 100644 index 0000000..55aa346 --- /dev/null +++ b/prim/rtl/prim_assert_sec_cm.svh @@ -0,0 +1,62 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// // Macros and helper code for security countermeasures. + +`ifndef PRIM_ASSERT_SEC_CM_SVH +`define PRIM_ASSERT_SEC_CM_SVH + +// Helper macros +`define ASSERT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_, MAX_CYCLES_, ERR_NAME_) \ + `ASSERT(FpvSecCm``NAME_``, \ + $rose(PRIM_HIER_.ERR_NAME_) && !(GATE_) \ + |-> ##[0:MAX_CYCLES_] (ALERT_.alert_p)) \ + `ifdef INC_ASSERT \ + assign PRIM_HIER_.unused_assert_connected = 1'b1; \ + `endif \ + `ASSUME_FPV(``NAME_``TriggerAfterAlertInit_S, $stable(rst_ni) == 0 |-> \ + PRIM_HIER_.ERR_NAME_ == 0 [*10]) + +`define ASSERT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_, MAX_CYCLES_, ERR_NAME_, CLK_, RST_) \ + `ASSERT(FpvSecCm``NAME_``, \ + $rose(PRIM_HIER_.ERR_NAME_) && !(GATE_) \ + |-> ##[0:MAX_CYCLES_] (ERR_), CLK_, RST_) \ + `ifdef INC_ASSERT \ + assign PRIM_HIER_.unused_assert_connected = 1'b1; \ + `endif + +// macros for security countermeasures that will trigger alert +`define ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 7) \ + `ASSERT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +`define ASSERT_PRIM_DOUBLE_LFSR_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 7) \ + `ASSERT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +`define ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 7) \ + `ASSERT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_, MAX_CYCLES_, unused_err_o) + +`define ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 7) \ + `ASSERT_ERROR_TRIGGER_ALERT(NAME_, PRIM_HIER_, ALERT_, GATE_, MAX_CYCLES_, err_o) + +`define ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(NAME_, REG_TOP_HIER_, ALERT_, GATE_ = 0, MAX_CYCLES_ = 7) \ + `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ALERT(NAME_, REG_TOP_HIER_.u_prim_reg_we_check.u_prim_onehot_check, ALERT_, GATE_, MAX_CYCLES_) + +// macros for security countermeasures that will trigger other errors +`define ASSERT_PRIM_FSM_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_ = 0, MAX_CYCLES_ = 2, CLK_ = clk_i, RST_ = !rst_ni) \ + `ASSERT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_, MAX_CYCLES_, unused_err_o, CLK_, RST_) + +`define ASSERT_PRIM_COUNT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_ = 0, MAX_CYCLES_ = 2, CLK_ = clk_i, RST_ = !rst_ni) \ + `ASSERT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_, MAX_CYCLES_, err_o, CLK_, RST_) + +`define ASSERT_PRIM_DOUBLE_LFSR_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_ = 0, MAX_CYCLES_ = 2, CLK_ = clk_i, RST_ = !rst_ni) \ + `ASSERT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_, MAX_CYCLES_, err_o, CLK_, RST_) + +`define ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_ = 0, MAX_CYCLES_ = 2, CLK_ = clk_i, RST_ = !rst_ni) \ + `ASSERT_ERROR_TRIGGER_ERR(NAME_, PRIM_HIER_, ERR_, GATE_, MAX_CYCLES_, err_o, CLK_, RST_) + +`define ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ERR(NAME_, REG_TOP_HIER_, ERR_, GATE_ = 0, MAX_CYCLES_ = 7, CLK_ = clk_i, RST_ = !rst_ni) \ + `ASSERT_PRIM_ONEHOT_ERROR_TRIGGER_ERR(NAME_, REG_TOP_HIER_.u_prim_reg_we_check.u_prim_onehot_check, ERR_, GATE_, MAX_CYCLES_, CLK_, RST_) + +`endif // PRIM_ASSERT_SEC_CM_SVH + diff --git a/prim/rtl/prim_assert_standard_macros.svh b/prim/rtl/prim_assert_standard_macros.svh new file mode 100644 index 0000000..5a5222c --- /dev/null +++ b/prim/rtl/prim_assert_standard_macros.svh @@ -0,0 +1,80 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Macro bodies included by prim_assert.sv for tools that support full SystemVerilog and SVA syntax. +// See prim_assert.sv for documentation for each of the macros. + +`define ASSERT_I(__name, __prop) \ + __name: assert (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ + end + +// Formal tools will ignore the initial construct, so use static assertion as a workaround. +// This workaround terminates design elaboration if the __prop predict is false. +// It calls $fatal() with the first argument equal to 2, it outputs the statistics about the memory +// and CPU time. +`define ASSERT_INIT(__name, __prop) \ +`ifdef FPV_ON \ + if (!(__prop)) $fatal(2, "Fatal static assertion [%s]: (%s) is not true.", \ + (__name), (__prop)); \ +`else \ + initial begin \ + __name: assert (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ + end \ + end \ +`endif + +`define ASSERT_INIT_NET(__name, __prop) \ + initial begin \ + // When a net is assigned with a value, the assignment is evaluated after \ + // initial in Xcelium. Add 1ps delay to check value after the assignment is \ + // completed. \ + #1ps; \ + __name: assert (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ + end \ + end \ + +`define ASSERT_FINAL(__name, __prop) \ + final begin \ + __name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \ + else begin \ + `ASSERT_ERROR(__name) \ + end \ + end + +`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ + else begin \ + `ASSERT_ERROR(__name) \ + end + +`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \ + else begin \ + `ASSERT_ERROR(__name) \ + end + +`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + `ASSERT(__name, !$isunknown(__sig), __clk, __rst) + +`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + __name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)); + +`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ + __name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \ + else begin \ + `ASSERT_ERROR(__name) \ + end + +`define ASSUME_I(__name, __prop) \ + __name: assume (__prop) \ + else begin \ + `ASSERT_ERROR(__name) \ + end + diff --git a/prim/rtl/prim_flop_macros.sv b/prim/rtl/prim_flop_macros.sv new file mode 100644 index 0000000..d836103 --- /dev/null +++ b/prim/rtl/prim_flop_macros.sv @@ -0,0 +1,75 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +`ifndef PRIM_FLOP_MACROS_SV +`define PRIM_FLOP_MACROS_SV + +///////////////////////////////////// +// Default Values for Macros below // +///////////////////////////////////// + +`define PRIM_FLOP_CLK clk_i +`define PRIM_FLOP_RST rst_ni +`define PRIM_FLOP_RESVAL '0 + +///////////////////// +// Register Macros // +///////////////////// + +// TODO: define other variations of register macros so that they can be used throughout all designs +// to make the code more concise. + +// Register with asynchronous reset. +`define PRIM_FLOP_A(__d, __q, __resval = `PRIM_FLOP_RESVAL, __clk = `PRIM_FLOP_CLK, __rst_n = `PRIM_FLOP_RST) \ + always_ff @(posedge __clk or negedge __rst_n) begin \ + if (!__rst_n) begin \ + __q <= __resval; \ + end else begin \ + __q <= __d; \ + end \ + end + +/////////////////////////// +// Macro for Sparse FSMs // +/////////////////////////// + +// Simulation tools typically infer FSMs and report coverage for these separately. However, tools +// like Xcelium and VCS seem to have problems inferring FSMs if the state register is not coded in +// a behavioral always_ff block in the same hierarchy. To that end, this uses a modified variant +// with a second behavioral register definition for RTL simulations so that FSMs can be inferred. +// Note that in this variant, the __q output is disconnected from prim_sparse_fsm_flop and attached +// to the behavioral flop. An assertion is added to ensure equivalence between the +// prim_sparse_fsm_flop output and the behavioral flop output in that case. +`define PRIM_FLOP_SPARSE_FSM(__name, __d, __q, __type, __resval = `PRIM_FLOP_RESVAL, __clk = `PRIM_FLOP_CLK, __rst_n = `PRIM_FLOP_RST, __alert_trigger_sva_en = 1) \ + `ifdef SIMULATION \ + prim_sparse_fsm_flop #( \ + .StateEnumT(__type), \ + .Width($bits(__type)), \ + .ResetValue($bits(__type)'(__resval)), \ + .EnableAlertTriggerSVA(__alert_trigger_sva_en), \ + .CustomForceName(`PRIM_STRINGIFY(__q)) \ + ) __name ( \ + .clk_i ( __clk ), \ + .rst_ni ( __rst_n ), \ + .state_i ( __d ), \ + .state_o ( ) \ + ); \ + `PRIM_FLOP_A(__d, __q, __resval, __clk, __rst_n) \ + `ASSERT(``__name``_A, __q === ``__name``.state_o) \ + `else \ + prim_sparse_fsm_flop #( \ + .StateEnumT(__type), \ + .Width($bits(__type)), \ + .ResetValue($bits(__type)'(__resval)), \ + .EnableAlertTriggerSVA(__alert_trigger_sva_en) \ + ) __name ( \ + .clk_i ( __clk ), \ + .rst_ni ( __rst_n ), \ + .state_i ( __d ), \ + .state_o ( __q ) \ + ); \ + `endif + +`endif // PRIM_FLOP_MACROS_SV + diff --git a/rtl/vproc_core.sv b/rtl/vproc_core.sv index 92f385e..0f42283 100644 --- a/rtl/vproc_core.sv +++ b/rtl/vproc_core.sv @@ -28,6 +28,7 @@ module vproc_core import vproc_pkg::*; #( parameter int unsigned VLSU_QUEUE_SZ = vproc_config::VLSU_QUEUE_SZ, parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = vproc_config::VLSU_FLAGS, parameter mul_type MUL_TYPE = vproc_config::MUL_TYPE, + parameter div_type DIV_TYPE = vproc_config::DIV_TYPE, // Miscellaneous configuration parameter int unsigned INSTR_QUEUE_SZ = vproc_config::INSTR_QUEUE_SZ, @@ -264,7 +265,6 @@ module vproc_core import vproc_pkg::*; #( logic pend_load; logic pend_store; } decoder_data; - // signals for decoder and for decoder buffer logic dec_ready, dec_valid, dec_clear; logic dec_buf_valid_q, dec_buf_valid_d; @@ -721,7 +721,7 @@ module vproc_core import vproc_pkg::*; #( generate if (INSTR_QUEUE_SZ > 0) begin vproc_queue #( - .WIDTH ( $bits(decoder_data) ), + .WIDTH ( $bits(decoder_data)), .DEPTH ( INSTR_QUEUE_SZ ) ) instr_queue ( .clk_i ( clk_i ), @@ -975,6 +975,7 @@ module vproc_core import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .DECODER_DATA_T ( decoder_data ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipe ( diff --git a/rtl/vproc_decoder.sv b/rtl/vproc_decoder.sv index 0bd34f1..d70bf89 100644 --- a/rtl/vproc_decoder.sv +++ b/rtl/vproc_decoder.sv @@ -1093,6 +1093,41 @@ module vproc_decoder #( endcase end + /***** ECE 498 HK MODIFICATIONS *****/ + // DIV unit: + {6'b100000, 3'b010}, // vdivu VV + {6'b100000, 3'b110}: begin // vidvu VX + unit_o = UNIT_DIV; // CREATE UNIT_DIV!!! + mode_o.div.op = DIV_VDIV; // CREAT DIV TYPES!!! + mode_o.div.op1_signed = 1'b0; + mode_o.div.op2_signed = 1'b0; + // ... + end + {6'b100001, 3'b010}, // vdiv VV + {6'b100001, 3'b110}: begin // vdiv VX + unit_o = UNIT_DIV; + mode_o.div.op = DIV_VDIV; + mode_o.div.op1_signed = 1'b1; + mode_o.div.op2_signed = 1'b1; + // ... + end + {6'b100010, 3'b010}, // vremu VV + {6'b100010, 3'b110}: begin // vremu VX + unit_o = UNIT_DIV; + mode_o.div.op = DIV_VREM; + mode_o.div.op1_signed = 1'b0; + mode_o.div.op2_signed = 1'b0; + // ... + end + {6'b100011, 3'b010}, // vrem VV + {6'b100011, 3'b110}: begin // vrem VX + unit_o = UNIT_DIV; + mode_o.div.op = DIV_VREM; + mode_o.div.op1_signed = 1'b1; + mode_o.div.op2_signed = 1'b1; + // ... + end + /***** END ECE 498 HK MODIFICATIONS *****/ // MUL unit: {6'b100100, 3'b010}, // vmulhu VV diff --git a/rtl/vproc_div.sv b/rtl/vproc_div.sv new file mode 100644 index 0000000..99d9f0b --- /dev/null +++ b/rtl/vproc_div.sv @@ -0,0 +1,293 @@ +// TODO DO THIS + +module vproc_div #( + parameter int unsigned DIV_OP_W = 64, // DIV unit operand width in bits + parameter vproc_pkg::div_type DIV_TYPE = vproc_pkg::DIV_GENERIC, + parameter bit BUF_OPERANDS = 1'b1, + parameter bit BUF_DIV_IN = 1'b1, + parameter bit BUF_DIV_OUT = 1'b1, + parameter bit BUF_RESULTS = 1'b1, + parameter type CTRL_T = logic, + parameter bit DONT_CARE_ZERO = 1'b0 + )( + input logic clk_i, + input logic async_rst_ni, + input logic sync_rst_ni, + + input logic pipe_in_valid_i, + output logic pipe_in_ready_o, + + input CTRL_T pipe_in_ctrl_i, + input logic [DIV_OP_W -1:0] pipe_in_op1_i, + input logic [DIV_OP_W -1:0] pipe_in_op2_i, + + input logic [DIV_OP_W/8-1:0] pipe_in_mask_i, + + output logic pipe_out_valid_o, + input logic pipe_out_ready_i, + + output CTRL_T pipe_out_ctrl_o, + output logic [DIV_OP_W -1:0] pipe_out_res_o, + output logic [DIV_OP_W/8-1:0] pipe_out_mask_o + ); + + import vproc_pkg::*; + + /////////////////////////////////////////////////////////////////////////// + // DIV BUFFERS + + logic state_ex1_ready, state_ex2_ready, state_ex3_ready, state_res_ready; + logic state_ex1_valid_q, state_ex1_valid_d, state_ex2_valid_q, state_ex3_valid_q, state_res_valid_q; + CTRL_T state_ex1_q, state_ex1_d, state_ex2_q, state_ex3_q, state_res_q; + + logic [DIV_OP_W -1:0] operand1_q, operand1_d; + logic [DIV_OP_W -1:0] operand2_q, operand2_d; + logic [DIV_OP_W/8-1:0] operand_mask_q, operand_mask_d; + logic [DIV_OP_W -1:0] result_q, result_d; + logic [DIV_OP_W/8-1:0] result_mask1_q, result_mask1_d; // mask out stage 1 buffer (DIV_IN) + logic [DIV_OP_W/8-1:0] result_mask2_q, result_mask2_d; // mask out stage 2 buffer (DIV_OUT) + logic [DIV_OP_W/8-1:0] result_mask3_q, result_mask3_d; // mask out stage 3 buffer (RESULTS) + // needed for vregunpack to mask write destinations + generate + if (BUF_OPERANDS) begin + always_ff @(posedge clk_i or negedge async_rst_ni) begin : vproc_div_stage_ex1_valid + if (~async_rst_ni) begin + state_ex1_valid_q <= 1'b0; + end + else if (~sync_rst_ni) begin + state_ex1_valid_q <= 1'b0; + end + else if (state_ex1_ready) begin + state_ex1_valid_q <= state_ex1_valid_d; + end + end + always_ff @(posedge clk_i) begin : vproc_div_stage_ex1 + if (state_ex1_ready & state_ex1_valid_d) begin + state_ex1_q <= state_ex1_d; + operand1_q <= operand1_d; + operand2_q <= operand2_d; + operand_mask_q <= operand_mask_d; + end + end + assign state_ex1_ready = ~state_ex1_valid_q | state_ex2_ready; + end else begin + always_comb begin + state_ex1_valid_q = state_ex1_valid_d; + state_ex1_q = state_ex1_d; + operand1_q = operand1_d; + operand2_q = operand2_d; + operand_mask_q = operand_mask_d; + end + assign state_ex1_ready = state_ex2_ready; + end + + if (BUF_DIV_IN) begin + always_ff @(posedge clk_i or negedge async_rst_ni) begin : vproc_div_stage_ex2_valid + if (~async_rst_ni) begin + state_ex2_valid_q <= 1'b0; + end + else if (~sync_rst_ni) begin + state_ex2_valid_q <= 1'b0; + end + else if (state_ex2_ready) begin + state_ex2_valid_q <= state_ex1_valid_q; + end + end + always_ff @(posedge clk_i) begin : vproc_div_stage_ex2 + if (state_ex2_ready & state_ex1_valid_q) begin + state_ex2_q <= state_ex1_q; + result_mask1_q <= result_mask1_d; + end + end + assign state_ex2_ready = ~state_ex2_valid_q | state_ex3_ready; + end else begin + always_comb begin + state_ex2_valid_q = state_ex1_valid_q; + state_ex2_q = state_ex1_q; + result_mask1_q = result_mask1_d; + end + assign state_ex2_ready = state_ex3_ready; + end + + if (BUF_DIV_OUT) begin + always_ff @(posedge clk_i or negedge async_rst_ni) begin : vproc_div_stage_ex3_valid + if (~async_rst_ni) begin + state_ex3_valid_q <= 1'b0; + end + else if (~sync_rst_ni) begin + state_ex3_valid_q <= 1'b0; + end + else if (state_ex3_ready) begin + state_ex3_valid_q <= state_ex2_valid_q; + end + end + always_ff @(posedge clk_i) begin : vproc_div_stage_ex3 + if (state_ex3_ready & state_ex2_valid_q) begin + state_ex3_q <= state_ex2_q; + result_mask2_q <= result_mask2_d; + end + end + assign state_ex3_ready = ~state_ex3_valid_q | state_res_ready; + end else begin + always_comb begin + state_ex3_valid_q = state_ex2_valid_q; + state_ex3_q = state_ex2_q; + result_mask2_q = result_mask2_d; + end + assign state_ex3_ready = state_res_ready; + end + + if (BUF_RESULTS) begin + always_ff @(posedge clk_i or negedge async_rst_ni) begin : vproc_div_stage_res_valid + if (~async_rst_ni) begin + state_res_valid_q <= 1'b0; + end + else if (~sync_rst_ni) begin + state_res_valid_q <= 1'b0; + end + else if (state_res_ready) begin + state_res_valid_q <= state_ex3_valid_q; + end + end + always_ff @(posedge clk_i) begin : vproc_div_stage_res + if (state_res_ready & state_ex3_valid_q) begin + state_res_q <= state_ex3_q; + result_q <= result_d; + result_mask3_q <= result_mask3_d; + end + end + assign state_res_ready = ~state_res_valid_q | pipe_out_ready_i; + end else begin + always_comb begin + state_res_valid_q = state_ex3_valid_q; + state_res_q = state_ex3_q; + result_q = result_d; + result_mask3_q = result_mask3_d; + end + assign state_res_ready = pipe_out_ready_i; + end + endgenerate + + + /////////////////////////////////////////////////////////////////////////// + // DIV operand conversion + assign pipe_in_ready_o = state_ex1_ready; + assign state_ex1_valid_d = pipe_in_valid_i; + assign state_ex1_d = pipe_in_ctrl_i; + assign operand1_d = pipe_in_op1_i; + assign operand2_d = pipe_in_op2_i; + assign operand_mask_d = pipe_in_mask_i; + + logic [DIV_OP_W/8-1:0] vl_mask; + assign vl_mask = ~state_ex1_q.vl_part_0 ? ({(DIV_OP_W/8){1'b1}} >> (~state_ex1_q.vl_part)) : '0; + assign result_mask1_d = (state_ex1_q.mode.div.masked ? operand_mask_q : {(DIV_OP_W/8){1'b1}}) & vl_mask; + + assign result_mask2_d = result_mask1_q; + assign result_mask3_d = result_mask2_q; + + assign pipe_out_valid_o = state_res_valid_q; + assign pipe_out_ctrl_o = state_res_q; + assign pipe_out_res_o = result_q; + assign pipe_out_mask_o = result_mask3_q; + + + // DIV ARITHMETIC + + logic [DIV_OP_W/8-1:0] op1_signs, op2_signs; + always_comb begin + op1_signs = DONT_CARE_ZERO ? '0 : 'x; + op2_signs = DONT_CARE_ZERO ? '0 : 'x; + for (int i = 0; i < DIV_OP_W/8; i++) begin + op1_signs[i] = state_ex1_q.mode.div.op1_signed & operand1_q[8*i+7]; + op2_signs[i] = state_ex1_q.mode.div.op2_signed & operand2_q[8*i+7]; + end + end + + logic [(DIV_OP_W/8*33)-1:0] div_op1, div_op2; + always_comb begin + div_op1 = DONT_CARE_ZERO ? '0 : 'x; + div_op2 = DONT_CARE_ZERO ? '0 : 'x; + for (int i = 0; i < DIV_OP_W / 32; i++) begin + unique case (state_ex1_q.eew) + VSEW_8: begin + div_op1[33*(4*i+0) +: 33] = {{25{op1_signs[4*i+0]}}, operand1_q[32*(i)+8*0 +: 8]}; + div_op1[33*(4*i+1) +: 33] = {{25{op1_signs[4*i+1]}}, operand1_q[32*(i)+8*1 +: 8]}; + div_op1[33*(4*i+2) +: 33] = {{25{op1_signs[4*i+2]}}, operand1_q[32*(i)+8*2 +: 8]}; + div_op1[33*(4*i+3) +: 33] = {{25{op1_signs[4*i+3]}}, operand1_q[32*(i)+8*3 +: 8]}; + + div_op2[33*(4*i+0) +: 33] = {{25{op2_signs[4*i+0]}}, operand2_q[32*(i)+8*0 +: 8]}; + div_op2[33*(4*i+1) +: 33] = {{25{op2_signs[4*i+1]}}, operand2_q[32*(i)+8*1 +: 8]}; + div_op2[33*(4*i+2) +: 33] = {{25{op2_signs[4*i+2]}}, operand2_q[32*(i)+8*2 +: 8]}; + div_op2[33*(4*i+3) +: 33] = {{25{op2_signs[4*i+3]}}, operand2_q[32*(i)+8*3 +: 8]}; + end + + + VSEW_16:begin + div_op1[33*(2*i+0) +: 33] = {{17{op1_signs[4*i+1]}}, operand1_q[32*i+16*0 +: 16]}; + div_op1[33*(2*i+1) +: 33] = {{17{op1_signs[4*i+3]}}, operand1_q[32*i+16*1 +: 16]}; + + div_op2[33*(2*i+0) +: 33] = {{17{op2_signs[4*i+1]}}, operand2_q[32*i+16*0 +: 16]}; + div_op2[33*(2*i+1) +: 33] = {{17{op2_signs[4*i+3]}}, operand2_q[32*i+16*1 +: 16]}; + end + + VSEW_32: begin + div_op1[33*i +: 33] = {{1{op1_signs[4*i+3]}}, operand1_q[32*i +: 32]}; // operand1_q[32*i +: 32]; + + div_op2[33*i +: 33] = {{1{op2_signs[4*i+3]}}, operand2_q[32*i +: 32]}; // operand2_q[32*i +: 32]; + end + default: ; + endcase + end + end + + // perform unsigned division of xx-bit integers + logic [DIV_OP_W*4-1:0] div_res; + genvar g; + generate + for (g = 0; g < DIV_OP_W / 8; g++) begin + vproc_div_block #( + .DIV_TYPE (DIV_TYPE ), + .BUF_OPS (BUF_DIV_IN ), + .BUF_DIV (BUF_DIV_OUT ), + .BUF_RES (1'b0 ) + ) div_block ( + .clk_i (clk_i ), + .async_rst_ni (async_rst_ni ), + .sync_rst_ni (sync_rst_ni ), + .mod (state_ex2_q.mode.div.op), // tells div_block to mod or not + .op1_i (div_op1 [33*g +: 33] ), + .op2_i (div_op2 [33*g +: 33] ), + .res_o (div_res [32*g +: 32] ) + ); + end + endgenerate + + // compose result + always_comb begin + result_d = DONT_CARE_ZERO ? '0 : 'x; + unique case (state_ex3_q.mode.div.op) + DIV_VDIV, DIV_VREM: begin + unique case (state_ex3_q.eew) + VSEW_8: begin + for (int i = 0; i < (DIV_OP_W / 8 ); i++) + result_d[8 *i +: 8 ] = div_res[32*i +: 8 ]; + end + VSEW_16: begin + for (int i = 0; i < (DIV_OP_W / 16); i++) + result_d[16*i +: 16] = div_res[32*i +: 16]; + end + VSEW_32: begin + for (int i = 0; i < (DIV_OP_W / 32); i++) + result_d[32*i +: 32] = div_res[32*i +: 32]; + end + default: ; + endcase + end + + default: ; + + endcase + end + +endmodule + diff --git a/rtl/vproc_div_block.sv b/rtl/vproc_div_block.sv new file mode 100644 index 0000000..b409e30 --- /dev/null +++ b/rtl/vproc_div_block.sv @@ -0,0 +1,103 @@ +// TODO DO THIS + +module vproc_div_block #( + parameter vproc_pkg::div_type DIV_TYPE = vproc_pkg::DIV_GENERIC, + parameter bit BUF_OPS = 1'b1, // buffer operands (op1_i and op2_i) + parameter bit BUF_DIV = 1'b1, // buffer division result + parameter bit BUF_RES = 1'b1 // buffer final result (res_o) + // Other parameters... + )( + input logic clk_i, + input logic async_rst_ni, + input logic sync_rst_ni, + + input logic mod, // 0 = quotient, 1 = modulo + + input logic [32:0] op1_i, + input logic [32:0] op2_i, + + output logic [31:0] res_o + + ); + + generate + case (DIV_TYPE) + + vproc_pkg::DIV_GENERIC: begin + + logic [32:0] op1_q, op2_q; + logic [32:0] div_q, div_d; + logic [32:0] res_q, res_d; + + if (BUF_OPS) begin + always_ff @(posedge clk_i) begin + op1_q <= op1_i; + op2_q <= op2_i; + end + end else begin + always_comb begin + op1_q = op1_i; + op2_q = op2_i; + end + end + + if (BUF_DIV) begin + always_ff @(posedge clk_i) begin + div_q <= div_d; + end + end else begin + always_comb begin + div_q = div_d; + end + end + + if (BUF_RES) begin + always_ff @(posedge clk_i) begin + res_q <= res_d; + end + end else begin + always_comb begin + res_q = res_d; + end + end + + always_comb begin + unique case(mod) + + // DIV/U + 1'b0 : begin + div_d = $signed(op1_q) / $signed(op2_q); + if (op2_q == '0) begin + div_d = '1; + end + if (op1_q == {1'b1, {32{1'b0}}} && op2_q == '1) begin + div_d = op1_q; + end + + end + + // REM/U + 1'b1 : begin + div_d = $signed(op1_q) % $signed(op2_q); + if (op2_q == 0) begin + div_d = op1_q; + end + if (op1_q == {1'b1, {32{1'b0}}} && op2_q == '1) begin + div_d = '0; + end + end + default: ; + endcase + end + + assign res_d = div_q; + assign res_o = res_q[31:0]; + + end + + default: ; + + endcase + endgenerate + +endmodule diff --git a/rtl/vproc_pipeline.sv b/rtl/vproc_pipeline.sv index e8ea027..1142577 100644 --- a/rtl/vproc_pipeline.sv +++ b/rtl/vproc_pipeline.sv @@ -43,6 +43,7 @@ module vproc_pipeline import vproc_pkg::*; #( parameter int unsigned VLSU_QUEUE_SZ = 4, parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = '0, parameter mul_type MUL_TYPE = MUL_GENERIC, + parameter div_type DIV_TYPE = DIV_GENERIC, parameter type INIT_STATE_T = logic, parameter bit DONT_CARE_ZERO = 1'b0 // initialize don't care values to zero )( @@ -121,7 +122,7 @@ module vproc_pipeline import vproc_pkg::*; #( typedef struct packed { counter_t count; // main counter - counter_t alt_count; // alternative counter (used by some ops) + counter_t alt_count; // alternative counter (used by some ops (UNIT_SLD)) count_inc_e count_inc; // counter increment policy logic [AUX_COUNTER_W-1:0] aux_count; // auxiliary counter (for dyn addr ops) logic [2:0] field_count; // field counter (for segment loads/stores) @@ -679,10 +680,10 @@ module vproc_pipeline import vproc_pkg::*; #( logic last_cycle; logic init_addr; // initialize address (used by LSU) logic requires_flush; - logic alt_count_valid; // alternative counter value is valid - logic [AUX_COUNTER_W-1:0] aux_count; - logic [XIF_ID_W-1:0] id; - op_unit unit; + logic alt_count_valid; // alternative counter value is valid // 75 + logic [AUX_COUNTER_W-1:0] aux_count; // 74, 73 + logic [XIF_ID_W-1:0] id; // 72, 71, 70 + op_unit unit; // unit 67, 68, 69 op_mode mode; cfg_vsew eew; // effective element width cfg_emul emul; // effective MUL factor @@ -822,7 +823,7 @@ module vproc_pipeline import vproc_pkg::*; #( .OP_HOLD_FLAG ( OP_HOLD_FLAG ), .UNPACK_STAGES ( UNPACK_STAGES ), .FLAGS_T ( unpack_flags ), - .CTRL_DATA_W ( $bits(ctrl_t) ), + .CTRL_DATA_W ($bits(ctrl_t) ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) unpack ( .clk_i ( clk_i ), @@ -880,6 +881,7 @@ module vproc_pipeline import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .CTRL_T ( ctrl_t ), .COUNTER_T ( counter_t ), .COUNTER_W ( COUNTER_W ), diff --git a/rtl/vproc_pipeline_wrapper.sv b/rtl/vproc_pipeline_wrapper.sv index 94ae9ad..4ae55c9 100644 --- a/rtl/vproc_pipeline_wrapper.sv +++ b/rtl/vproc_pipeline_wrapper.sv @@ -28,6 +28,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( parameter int unsigned VLSU_QUEUE_SZ = 4, parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = '0, parameter mul_type MUL_TYPE = MUL_GENERIC, + parameter div_type DIV_TYPE = DIV_GENERIC, parameter type DECODER_DATA_T = logic, parameter bit DONT_CARE_ZERO = 1'b0 // initialize don't care values to zero )( @@ -112,7 +113,9 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( // - ELEM unit additionally requires indices -3 and -2, hence a minimum of 5 operands // - if MUL and ELEM units are both present in same pipeline, then all 6 operands are required // - in case a pipeline contains only the SLD unit the operand count is 2 (indices 0 and -1) - localparam int unsigned OP_CNT = UNITS[UNIT_MUL] ? ( + + // ECE498HK edits + localparam int unsigned OP_CNT = (UNITS[UNIT_MUL]) ? ( UNITS[UNIT_ELEM] ? 6 : 4 ) : ( UNITS[UNIT_ELEM] ? 5 : ( @@ -127,7 +130,8 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( // should be fetched at the latest possible stage, since the pipeline waits until the alt count // completes its cycle before accepting the next instruction. localparam int unsigned OP0_SRC = 0; - localparam int unsigned OP1_SRC = (VPORT_CNT >= (UNITS[UNIT_MUL] ? 3 : 2)) ? 1 : 0; + // ece498hk edits + localparam int unsigned OP1_SRC = (VPORT_CNT >= ((UNITS[UNIT_MUL]) ? 3 : 2)) ? 1 : 0; localparam int unsigned OP2_SRC = VPORT_CNT - 1; localparam int unsigned MIN_STAGE = 1; // first possible unpack stage // start by fetching op 0, then op1, except for ELEM unit which needs to fetch op1 first since @@ -165,9 +169,12 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( // operand flags localparam bit OP_DYN_ADDR_OFFSET = UNITS[UNIT_ELEM]; // operand with dynamic addr used localparam bit OP_SECOND_MASK = UNITS[UNIT_ELEM]; // second mask operand used + + // ECE498HK edits + // The fixed-point instructions help preserve precision in narrow operands by supporting scaling and rounding localparam bit OP0_NARROW = UNITS[UNIT_MUL] | UNITS[UNIT_ALU] | UNITS[UNIT_ELEM]; localparam bit OP1_NARROW = UNITS[UNIT_MUL] | UNITS[UNIT_ALU]; - localparam bit OP1_XREG = UNITS[UNIT_MUL] | UNITS[UNIT_ALU]; + localparam bit OP1_XREG = UNITS[UNIT_MUL] | UNITS[UNIT_ALU] | UNITS[UNIT_DIV]; // OPMVX category of instr use GPR x register rs1 as scalar operand. vdiv/vrem supports .vv and .vx localparam bit OP0_ELEMWISE = UNITS[UNIT_LSU] | UNITS[UNIT_ELEM]; localparam bit OP1_ELEMWISE = UNITS[UNIT_LSU] | UNITS[UNIT_ELEM]; localparam bit OPMASK_ELEMWISE = UNITS[UNIT_LSU] | UNITS[UNIT_ELEM]; @@ -178,7 +185,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( localparam int unsigned MAX_RES_W = MAX_OP_W; // result flags - localparam bit RES0_ALWAYS_VREG = ~UNITS[UNIT_LSU] & ~UNITS[UNIT_ALU] & ~UNITS[UNIT_ELEM]; + localparam bit RES0_ALWAYS_VREG = ~UNITS[UNIT_LSU] & ~UNITS[UNIT_ALU] & ~UNITS[UNIT_ELEM]; // true for DIV localparam bit RES0_NARROW = UNITS[UNIT_ALU]; localparam bit RES0_ALLOW_ELEMWISE = UNITS[UNIT_LSU] | UNITS[UNIT_ELEM]; @@ -216,12 +223,14 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( } state_t; // identify the unit of the supplied instruction - logic unit_lsu, unit_alu, unit_mul, unit_sld, unit_elem; - assign unit_lsu = UNITS[UNIT_LSU ] & (pipe_in_data_i.unit == UNIT_LSU ); - assign unit_alu = UNITS[UNIT_ALU ] & (pipe_in_data_i.unit == UNIT_ALU ); - assign unit_mul = UNITS[UNIT_MUL ] & (pipe_in_data_i.unit == UNIT_MUL ); - assign unit_sld = UNITS[UNIT_SLD ] & (pipe_in_data_i.unit == UNIT_SLD ); - assign unit_elem = UNITS[UNIT_ELEM] & (pipe_in_data_i.unit == UNIT_ELEM); + // ECE498HK additions + logic unit_lsu, unit_alu, unit_mul, unit_sld, unit_elem, unit_div; + assign unit_lsu = UNITS[UNIT_LSU ] & (pipe_in_data_i.unit == UNIT_LSU ); + assign unit_alu = UNITS[UNIT_ALU ] & (pipe_in_data_i.unit == UNIT_ALU ); + assign unit_div = UNITS[UNIT_DIV ] & (pipe_in_data_i.unit == UNIT_DIV ); + assign unit_mul = UNITS[UNIT_MUL ] & (pipe_in_data_i.unit == UNIT_MUL ); + assign unit_sld = UNITS[UNIT_SLD ] & (pipe_in_data_i.unit == UNIT_SLD ); + assign unit_elem = UNITS[UNIT_ELEM] & (pipe_in_data_i.unit == UNIT_ELEM); // identify the type of data that vs2 supplies for ELEM instructions logic elem_flush, elem_vs2_data, elem_vs2_mask, elem_vs2_dyn_addr; @@ -450,6 +459,8 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( unique case (1'b1) unit_lsu: state_init.op_flags[OP_CNT-1].vreg = pipe_in_data_i.mode.lsu.masked; unit_alu: state_init.op_flags[OP_CNT-1].vreg = pipe_in_data_i.mode.alu.op_mask != ALU_MASK_NONE; + // ECE498HK additions + unit_div: state_init.op_flags[OP_CNT-1].vreg = pipe_in_data_i.mode.div.masked; unit_mul: state_init.op_flags[OP_CNT-1].vreg = pipe_in_data_i.mode.mul.masked; unit_sld: state_init.op_flags[OP_CNT-1].vreg = pipe_in_data_i.mode.sld.masked; unit_elem: state_init.op_flags[OP_CNT-1].vreg = pipe_in_data_i.mode.elem.masked; @@ -475,11 +486,17 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( state_init.res_narrow[0 ] = pipe_in_data_i.widenarrow == OP_NARROWING; state_init.res_vreg [RES_CNT-1] = pipe_in_data_i.mode.alu.cmp; end + // ECE498HK additions + if (unit_div) begin + state_init.op_vaddr[0] = pipe_in_data_i.rs2.r.vaddr; // for vmadd and vnmsub, MUL stores vaddr in .rd.addr, this is not needed for div + state_init.op_flags[0].sigext = pipe_in_data_i.mode.div.op2_signed; + state_init.op_flags[1].sigext = pipe_in_data_i.mode.div.op1_signed; + end if (unit_mul) begin state_init.op_vaddr[0] = pipe_in_data_i.mode.mul.op2_is_vd ? pipe_in_data_i.rd.addr : pipe_in_data_i.rs2.r.vaddr; state_init.op_flags[0].sigext = pipe_in_data_i.mode.mul.op2_signed; state_init.op_flags[1].sigext = pipe_in_data_i.mode.mul.op1_signed; - state_init.op_flags[(OP_CNT >= 3) ? 2 : 0].vreg = pipe_in_data_i.mode.mul.op == MUL_VMACC; + state_init.op_flags[(OP_CNT >= 3) ? 2 : 0].vreg = pipe_in_data_i.mode.mul.op == MUL_VMACC; // macc is desctructive, vd overwrites addend or minuend state_init.op_vaddr[(OP_CNT >= 3) ? 2 : 0] = pipe_in_data_i.mode.mul.op2_is_vd ? pipe_in_data_i.rs2.r.vaddr : pipe_in_data_i.rd.addr; end if (unit_elem) begin @@ -560,6 +577,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -625,6 +643,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -690,6 +709,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -755,6 +775,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -820,6 +841,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -885,6 +907,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -950,6 +973,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -1015,6 +1039,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( @@ -1080,6 +1105,7 @@ module vproc_pipeline_wrapper import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .INIT_STATE_T ( state_t ), .DONT_CARE_ZERO ( DONT_CARE_ZERO ) ) pipeline ( diff --git a/rtl/vproc_pkg.sv b/rtl/vproc_pkg.sv index b84f18d..e08dfa8 100644 --- a/rtl/vproc_pkg.sv +++ b/rtl/vproc_pkg.sv @@ -40,6 +40,12 @@ typedef enum { MUL_XLNX_DSP48E1 = 1 } mul_type; +/***** ECE 498 HK MODIFICATIONS *****/ +typedef enum { + DIV_GENERIC = 0 +} div_type; +/***** END ECE 498 HK MODIFICATIONS *****/ + typedef enum logic [1:0] { INSTR_INVALID, INSTR_SPECULATIVE, @@ -98,6 +104,7 @@ typedef enum logic [1:0] { typedef enum logic [2:0] { UNIT_LSU, UNIT_ALU, + UNIT_DIV, // ECE 498 HK MODIFICATION UNIT_MUL, UNIT_SLD, UNIT_ELEM, @@ -106,7 +113,8 @@ typedef enum logic [2:0] { } op_unit; // The number of different types of execution units (excludes pseudo-units) -parameter int unsigned UNIT_CNT = 5; +parameter int unsigned UNIT_CNT = 6; +// LSU ALU DIV MUL STD ELEM typedef enum logic [1:0] { COUNT_INC_1, @@ -207,6 +215,24 @@ typedef struct packed { `endif } op_mode_mul; +/***** ECE 498 HK MODIFICATIONS *****/ +typedef enum logic [0:0] { + DIV_VDIV, // divide + DIV_VREM // remainder +} opcode_div; + +typedef struct packed { + // TODO + logic masked; + opcode_div op; + logic op1_signed; + logic op2_signed; +`ifdef VPROC_OP_MODE_UNION + logic [8:0] unused; +`endif +} op_mode_div; +/***** END ECE 498 HK MODIFICATIONS *****/ + typedef enum logic [0:0] { SLD_UP, SLD_DOWN @@ -289,6 +315,7 @@ typedef struct packed { `endif op_mode_lsu lsu; op_mode_alu alu; + op_mode_div div; // ECE 498 HK MODIFICATION op_mode_mul mul; op_mode_sld sld; op_mode_elem elem; diff --git a/rtl/vproc_unit_mux.sv b/rtl/vproc_unit_mux.sv index 95a32b0..2e4e293 100644 --- a/rtl/vproc_unit_mux.sv +++ b/rtl/vproc_unit_mux.sv @@ -15,6 +15,7 @@ module vproc_unit_mux import vproc_pkg::*; #( parameter int unsigned VLSU_QUEUE_SZ = 4, parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = '0, parameter mul_type MUL_TYPE = MUL_GENERIC, + parameter div_type DIV_TYPE = DIV_GENERIC, parameter type CTRL_T = logic, parameter type COUNTER_T = logic, parameter int unsigned COUNTER_W = 0, @@ -132,6 +133,7 @@ module vproc_unit_mux import vproc_pkg::*; #( .VLSU_QUEUE_SZ ( VLSU_QUEUE_SZ ), .VLSU_FLAGS ( VLSU_FLAGS ), .MUL_TYPE ( MUL_TYPE ), + .DIV_TYPE ( DIV_TYPE ), .CTRL_T ( CTRL_T ), .COUNTER_T ( COUNTER_T ), .COUNTER_W ( COUNTER_W ), diff --git a/rtl/vproc_unit_wrapper.sv b/rtl/vproc_unit_wrapper.sv index b631ec3..62b180c 100644 --- a/rtl/vproc_unit_wrapper.sv +++ b/rtl/vproc_unit_wrapper.sv @@ -15,6 +15,7 @@ module vproc_unit_wrapper import vproc_pkg::*; #( parameter int unsigned VLSU_QUEUE_SZ = 4, parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = '0, parameter mul_type MUL_TYPE = MUL_GENERIC, + parameter div_type DIV_TYPE = DIV_GENERIC, parameter type CTRL_T = logic, parameter type COUNTER_T = logic, parameter int unsigned COUNTER_W = 0, @@ -182,6 +183,56 @@ module vproc_unit_wrapper import vproc_pkg::*; #( assign pipe_out_pend_clear_cnt_o = '0; assign pipe_out_instr_done_o = unit_out_ctrl.last_cycle; end + // ECE498HK edits + else if (UNIT == UNIT_DIV) begin + CTRL_T unit_out_ctrl; + logic [MAX_OP_W -1:0] unit_out_res; + logic [MAX_OP_W/8-1:0] unit_out_mask; + vproc_div #( + .DIV_OP_W ( MAX_OP_W ), + .DIV_TYPE ( DIV_TYPE ), + .CTRL_T ( CTRL_T ), + .DONT_CARE_ZERO ( DONT_CARE_ZERO ) + ) div ( + .clk_i ( clk_i ), + .async_rst_ni ( async_rst_ni ), + .sync_rst_ni ( sync_rst_ni ), + + .pipe_in_valid_i ( pipe_in_valid_i ), + .pipe_in_ready_o ( pipe_in_ready_o ), + + .pipe_in_ctrl_i ( pipe_in_ctrl_i ), + .pipe_in_op1_i ( pipe_in_op_data_i[0] ), // TODO double check if this + .pipe_in_op2_i ( pipe_in_op_data_i[1] ), // TODO should be swapped + + .pipe_in_mask_i ( pipe_in_op_data_i[OP_CNT-1][MAX_OP_W/8-1:0] ), + + .pipe_out_valid_o ( pipe_out_valid_o ), + .pipe_out_ready_i ( pipe_out_ready_i ), + + .pipe_out_ctrl_o ( unit_out_ctrl ), + .pipe_out_res_o ( unit_out_res ), + .pipe_out_mask_o ( unit_out_mask ) + ); + always_comb begin + pipe_out_instr_id_o = unit_out_ctrl.id; + pipe_out_eew_o = unit_out_ctrl.eew; + pipe_out_vaddr_o = unit_out_ctrl.res_vaddr; + pipe_out_res_store_o = '0; + pipe_out_res_valid_o = '0; + pipe_out_res_flags_o = '{default: pack_flags'('0)}; + pipe_out_res_data_o = '0; + pipe_out_res_mask_o = '0; + pipe_out_res_flags_o[0].shift = unit_out_ctrl.res_shift; + pipe_out_res_store_o[0] = unit_out_ctrl.res_store; + pipe_out_res_valid_o[0] = pipe_out_valid_o; + pipe_out_res_data_o [0] = unit_out_res; + pipe_out_res_mask_o [0][MAX_OP_W/8-1:0] = unit_out_mask; + end + assign pipe_out_pend_clear_o = unit_out_ctrl.res_store; + assign pipe_out_pend_clear_cnt_o = '0; + assign pipe_out_instr_done_o = unit_out_ctrl.last_cycle; + end else if (UNIT == UNIT_MUL) begin CTRL_T unit_out_ctrl; logic [MAX_OP_W -1:0] unit_out_res; diff --git a/sim/Makefile b/sim/Makefile index f2569cc..fca6bfa 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -86,12 +86,15 @@ $(PROJ_DIR)/obj_dir/Vvproc_top.mk: verilator-version-check $(VPROC_CONFIG_PKG) core=""; \ inc=""; \ src=""; \ + $(info $$SIM_DIR is [${SIM_DIR}]) \ + $(info $$CORE_DIR is [${CORE_DIR}]) \ if echo "$(CORE_DIR)" | grep -q "ibex"; then \ core="-DMAIN_CORE_IBEX"; \ inc="-I$(CORE_DIR)/rtl/ -I$(CORE_DIR)/dv/uvm/core_ibex/common/prim/"; \ inc="$$inc -I$(CORE_DIR)/vendor/lowrisc_ip/dv/sv/dv_utils/"; \ inc="$$inc -I$(CORE_DIR)/vendor/lowrisc_ip/ip/prim/rtl/"; \ inc="$$inc -I$(CORE_DIR)/vendor/lowrisc_ip/ip/prim_generic/rtl/"; \ + cat ibex_pkg.sv; \ src="ibex_pkg.sv prim_pkg.sv prim_assert.sv prim_ram_1p_pkg.sv"; \ src="$$src ibex_register_file_ff.sv"; \ elif echo "$(CORE_DIR)" | grep -q "cv32e40x"; then \ diff --git a/sim/vproc_tb.sv b/sim/vproc_tb.sv index 625ea6e..44ba7b0 100644 --- a/sim/vproc_tb.sv +++ b/sim/vproc_tb.sv @@ -35,8 +35,8 @@ module vproc_tb #( vproc_top #( .MEM_W ( MEM_W ), .VMEM_W ( VMEM_W ), - .VREG_TYPE ( vproc_pkg::VREG_XLNX_RAM32M ), - .MUL_TYPE ( vproc_pkg::MUL_XLNX_DSP48E1 ), + .VREG_TYPE ( vproc_pkg::VREG_GENERIC ), + .MUL_TYPE ( vproc_pkg::MUL_GENERIC ), .ICACHE_SZ ( ICACHE_SZ ), .ICACHE_LINE_W ( ICACHE_LINE_W ), .DCACHE_SZ ( DCACHE_SZ ), @@ -63,7 +63,8 @@ module vproc_tb #( logic mem_rvalid_queue[MEM_LATENCY]; logic [31:0] mem_rdata_queue [MEM_LATENCY]; logic mem_err_queue [MEM_LATENCY]; - always_ff @(posedge clk) begin + always begin + #5; if (mem_req & mem_we) begin for (int i = 0; i < MEM_W/8; i++) begin if (mem_be[i]) begin @@ -91,12 +92,13 @@ module vproc_tb #( mem_rdata <= mem_rdata_queue [MEM_LATENCY-1]; mem_err <= mem_err_queue [MEM_LATENCY-1]; end - for (int i = 0; i < MEM_SZ; i++) begin +// for (int i = 0; i < MEM_SZ; i++) begin // set the don't care values in the memory to 0 during the first rising edge - if ($isunknown(mem[i]) & ($time < 10)) begin - mem[i] <= '0; - end - end +// if ($isunknown(mem[i]) & ($time < 10)) begin +// mem[i] <= '0; +// end +// end + #5; end logic prog_end, done; @@ -105,6 +107,7 @@ module vproc_tb #( integer fd1, fd2, cnt, ref_start, ref_end, dump_start, dump_end; string line, prog_path, ref_path, dump_path; initial begin + $display("STARTING TB"); done = 1'b0; fd1 = $fopen(PROG_PATHS_LIST, "r"); @@ -126,15 +129,30 @@ module vproc_tb #( continue; end + $display("ABOUT TO READ MEM (%s)", prog_path); $readmemh(prog_path, mem); + $display("FINISHED READ MEM"); + + for(int j = 0; j < MEM_SZ; j++) begin + if($isunknown(mem[j])) begin + mem[j] = 0; + end + end fd2 = $fopen(ref_path, "w"); + $display("REF PATH OPEN (%s)", ref_path); for (int j = ref_start / (MEM_W/8); j < ref_end / (MEM_W/8); j++) begin for (int k = 0; k < MEM_W/32; k++) begin + if($isunknown(mem[j][k*32 +: 32])) begin + mem[j][k*32 +: 32] = 0; + end + + // $display("%x", mem[j][k*32 +: 32]); $fwrite(fd2, "%x\n", mem[j][k*32 +: 32]); end end $fclose(fd2); + $display("REF PATH CLOSED"); // reset for 10 cycles #100 @@ -142,12 +160,14 @@ module vproc_tb #( // wait for completion (i.e. request of instr mem addr 0x00000000) //@(posedge prog_end); + $display("STARTING WHILE LOOP"); while (1) begin @(posedge clk); if (prog_end) begin break; end end + $display("OUT OF WHILE LOOP"); fd2 = $fopen(dump_path, "w"); for (int j = dump_start / (MEM_W/8); j < dump_end / (MEM_W/8); j++) begin @@ -159,6 +179,7 @@ module vproc_tb #( end $fclose(fd1); done = 1'b1; + $finish; end endmodule diff --git a/test/Makefile b/test/Makefile index 8bec238..5919029 100644 --- a/test/Makefile +++ b/test/Makefile @@ -15,7 +15,7 @@ TEST_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) SIMULATOR ?= verilator # test directories -TEST_DIRS := lsu alu mul sld elem csr kernel misc +TEST_DIRS := lsu alu mul sld elem csr kernel misc div # test targets TESTS_ALL := $(TEST_DIRS) $(addsuffix /, $(TEST_DIRS)) diff --git a/test/div/vdiv_16.S b/test/div/vdiv_16.S new file mode 100644 index 0000000..60735b9 --- /dev/null +++ b/test/div/vdiv_16.S @@ -0,0 +1,98 @@ + +# vdiv 16 + .text + .global main +main: + la a0, vdata_start + + li t0, 8 + vsetvli t0, t0, e16,m1,tu,mu + + li t0, 7 + + vle16.v v0, (a0) + vdiv.vx v0, v0, t0 + vse16.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xcffd8f22 + .word 0x2672ae3b + .word 0xbc20d744 + .word 0x619780f3 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0xf925efe1 + .word 0x057ef452 + .word 0xf64efa2f + .word 0x0df1edda + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vdiv_32.S b/test/div/vdiv_32.S new file mode 100644 index 0000000..7526e99 --- /dev/null +++ b/test/div/vdiv_32.S @@ -0,0 +1,98 @@ + +# vdiv 32 + .text + .global main +main: + la a0, vdata_start + + li t0, 4 + vsetvli t0, t0, e32,m1,tu,mu + + li t0, 7 + + vle32.v v0, (a0) + vdiv.vx v0, v0, t0 + vse32.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0x1e3afe22 + .word 0x23781b2b + .word 0xb4bd28fa + .word 0xdece3589 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x04519204 + .word 0x05112873 + .word 0xf53f9824 + .word 0xfb4207a6 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vdiv_8.S b/test/div/vdiv_8.S new file mode 100644 index 0000000..b382806 --- /dev/null +++ b/test/div/vdiv_8.S @@ -0,0 +1,98 @@ + +# vdiv 8 + .text + .global main +main: + la a0, vdata_start + + li t0, 16 + vsetvli t0, t0, e8,m1,tu,mu + + li t0, 7 + + vle8.v v0, (a0) + vdiv.vx v0, v0, t0 + vse8.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xce9cfd51 + .word 0xef02b593 + .word 0x3b987927 + .word 0xd3adb9dc + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0xf9f2000b + .word 0xfe00f6f1 + .word 0x08f21105 + .word 0xfaf5f6fb + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vdivu_16.S b/test/div/vdivu_16.S new file mode 100644 index 0000000..a320f0f --- /dev/null +++ b/test/div/vdivu_16.S @@ -0,0 +1,98 @@ + +# vdiv u 16 + .text + .global main +main: + la a0, vdata_start + + li t0, 8 + vsetvli t0, t0, e16,m1,tu,mu + + li t0, 7 + + vle16.v v0, (a0) + vdivu.vx v0, v0, t0 + vse16.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0x6f31f594 + .word 0xe0eb44da + .word 0x4c5d4d64 + .word 0x5eb58465 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x0fe22315 + .word 0x202109d6 + .word 0x0ae80b0e + .word 0x0d8712e9 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vdivu_32.S b/test/div/vdivu_32.S new file mode 100644 index 0000000..85d92a4 --- /dev/null +++ b/test/div/vdivu_32.S @@ -0,0 +1,98 @@ + +# vdiv u 32 + .text + .global main +main: + la a0, vdata_start + + li t0, 4 + vsetvli t0, t0, e32,m1,tu,mu + + li t0, 7 + + vle32.v v0, (a0) + vdivu.vx v0, v0, t0 + vse32.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xf7e77afa + .word 0x9583c2ad + .word 0xa36abb98 + .word 0x80740893 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x236a3623 + .word 0x155bf73d + .word 0x175863f1 + .word 0x1259b815 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vdivu_8.S b/test/div/vdivu_8.S new file mode 100644 index 0000000..91e01d3 --- /dev/null +++ b/test/div/vdivu_8.S @@ -0,0 +1,98 @@ + +# vdiv u 8 + .text + .global main +main: + la a0, vdata_start + + li t0, 16 + vsetvli t0, t0, e8,m1,tu,mu + + li t0, 7 + + vle8.v v0, (a0) + vdivu.vx v0, v0, t0 + vse8.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xdc9a262b + .word 0x73059d6a + .word 0xb795837c + .word 0xe49bbaeb + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x1f160506 + .word 0x1000160f + .word 0x1a151211 + .word 0x20161a21 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vrem_16.S b/test/div/vrem_16.S new file mode 100644 index 0000000..ba6a94e --- /dev/null +++ b/test/div/vrem_16.S @@ -0,0 +1,98 @@ + +# vrem 16 + .text + .global main +main: + la a0, vdata_start + + li t0, 8 + vsetvli t0, t0, e16,m1,tu,mu + + li t0, 7 + + vle16.v v0, (a0) + vrem.vx v0, v0, t0 + vse16.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0x39bd3821 + .word 0x962a2c2d + .word 0xf7003d1f + .word 0x30712f75 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x00040005 + .word 0xfffc0004 + .word 0xffff0002 + .word 0x00040004 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vrem_32.S b/test/div/vrem_32.S new file mode 100644 index 0000000..e7ff380 --- /dev/null +++ b/test/div/vrem_32.S @@ -0,0 +1,98 @@ + +# vrem 32 + .text + .global main +main: + la a0, vdata_start + + li t0, 4 + vsetvli t0, t0, e32,m1,tu,mu + + li t0, 7 + + vle32.v v0, (a0) + vrem.vx v0, v0, t0 + vse32.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xa4b7ef07 + .word 0x37ace96b + .word 0x0ca44246 + .word 0x124fe8c1 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0xfffffffe + .word 0x00000003 + .word 0x00000002 + .word 0x00000002 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vrem_8.S b/test/div/vrem_8.S new file mode 100644 index 0000000..a289fd6 --- /dev/null +++ b/test/div/vrem_8.S @@ -0,0 +1,98 @@ + +# vrem 8 + .text + .global main +main: + la a0, vdata_start + + li t0, 16 + vsetvli t0, t0, e8,m1,tu,mu + + li t0, 7 + + vle8.v v0, (a0) + vrem.vx v0, v0, t0 + vse8.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0x00dedebe + .word 0xae9cb4b0 + .word 0xc273b35d + .word 0xb31ade80 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x00fafafd + .word 0xfbfefafd + .word 0xfa030002 + .word 0x0005fafe + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vremu_16.S b/test/div/vremu_16.S new file mode 100644 index 0000000..3de969c --- /dev/null +++ b/test/div/vremu_16.S @@ -0,0 +1,98 @@ + +# vrem u 16 + .text + .global main +main: + la a0, vdata_start + + li t0, 8 + vsetvli t0, t0, e16,m1,tu,mu + + li t0, 7 + + vle16.v v0, (a0) + vremu.vx v0, v0, t0 + vse16.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xde449e5a + .word 0x392f8ffb + .word 0xd69a5b50 + .word 0x22645570 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x00040001 + .word 0x00020004 + .word 0x00020003 + .word 0x00050004 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vremu_32.S b/test/div/vremu_32.S new file mode 100644 index 0000000..470d0d4 --- /dev/null +++ b/test/div/vremu_32.S @@ -0,0 +1,98 @@ + +# vrem u 32 + .text + .global main +main: + la a0, vdata_start + + li t0, 4 + vsetvli t0, t0, e32,m1,tu,mu + + li t0, 7 + + vle32.v v0, (a0) + vremu.vx v0, v0, t0 + vse32.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0xd26a687a + .word 0xf6f45748 + .word 0x11e2317b + .word 0x9f408209 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x00000001 + .word 0x00000006 + .word 0x00000004 + .word 0x00000004 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/test/div/vremu_8.S b/test/div/vremu_8.S new file mode 100644 index 0000000..95f4d4f --- /dev/null +++ b/test/div/vremu_8.S @@ -0,0 +1,98 @@ + +# vrem u 8 + .text + .global main +main: + la a0, vdata_start + + li t0, 16 + vsetvli t0, t0, e8,m1,tu,mu + + li t0, 7 + + vle8.v v0, (a0) + vremu.vx v0, v0, t0 + vse8.v v0, (a0) + + la a0, vdata_start + la a1, vdata_end + j spill_cache + + + .data + .align 10 + .global vdata_start + .global vdata_end +vdata_start: + .word 0x9164ad46 + .word 0x797b143b + .word 0x076d7359 + .word 0xadaf535f + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vdata_end: + + .align 10 + .global vref_start + .global vref_end +vref_start: + .word 0x05020500 + .word 0x02040603 + .word 0x00040305 + .word 0x05000604 + .word 0x3f44383b + .word 0x37424d54 + .word 0x5e4b5049 + .word 0x4c4c4c4a + .word 0x4a505f3e + .word 0x485e5455 + .word 0x4d4c4a41 + .word 0x373b5451 + .word 0x41454c45 + .word 0x3a3e3738 + .word 0x312f2e2f + .word 0x3d433f45 + .word 0x46424949 + .word 0x494a4d51 + .word 0x49413c38 + .word 0x3e514143 + .word 0x47525353 + .word 0x514e5052 + .word 0x525a5b58 + .word 0x5e575254 + .word 0x56545058 + .word 0x5a534947 + .word 0x4744544f + .word 0x4e515051 + .word 0x5a4b4545 + .word 0x454c4342 + .word 0x40504a3f + .word 0x4448535a +vref_end: + \ No newline at end of file diff --git a/vproc_config.sv b/vproc_config.sv new file mode 100644 index 0000000..5566499 --- /dev/null +++ b/vproc_config.sv @@ -0,0 +1,49 @@ +// Auto-generated on Wed Nov 2 19:23:49 CDT 2022 + +// Vector coprocessor default configuration package +// +// The package defined in this file provides *consistent default values* for +// configuration parameters of the vproc_core module for the configuration +// shown below across different synthesis and simulation workflows. The +// constants defined in this package are intended to be used *exclusively* as +// *default values* for the parameters of the vproc_core module and should +// *not* be used anywhere else in the code, such that a design instantiating +// the vproc_core module can override any parameter with a different value. + +// Configuration details: +// - Vector register width: 128 bits +// - Vector pipelines: +// * Pipeline 0: 32 bits wide, contains VLSU, VALU, VMUL, VSLD, VELEM, VDIV +// Uses 1 128-bit vreg read ports and write port 0 +// - Vector register file needs 2 read ports and 1 write ports +`define MAIN_CORE_IBEX + +package vproc_config; + + import vproc_pkg::*; + + parameter vreg_type VREG_TYPE = VREG_GENERIC; + parameter int unsigned VREG_W = 128; + parameter int unsigned VPORT_RD_CNT = 2; + parameter int unsigned VPORT_RD_W [VPORT_RD_CNT] = '{default: VREG_W}; + parameter int unsigned VPORT_WR_CNT = 1; + parameter int unsigned VPORT_WR_W [VPORT_WR_CNT] = '{default: VREG_W}; + + parameter int unsigned PIPE_CNT = 1; + parameter bit [UNIT_CNT-1:0] PIPE_UNITS [PIPE_CNT] = '{ + (UNIT_CNT'(1) << UNIT_LSU) | (UNIT_CNT'(1) << UNIT_ALU) | (UNIT_CNT'(1) << UNIT_MUL) | (UNIT_CNT'(1) << UNIT_SLD) | (UNIT_CNT'(1) << UNIT_ELEM) | (UNIT_CNT'(1) << UNIT_DIV) + }; + parameter int unsigned PIPE_W [PIPE_CNT] = '{32}; + parameter int unsigned PIPE_VPORT_CNT [PIPE_CNT] = '{1}; + parameter int unsigned PIPE_VPORT_IDX [PIPE_CNT] = '{1}; + parameter int unsigned PIPE_VPORT_WR [PIPE_CNT] = '{0}; + + parameter int unsigned VLSU_QUEUE_SZ = 4; + parameter bit [VLSU_FLAGS_W-1:0] VLSU_FLAGS = '0; + parameter mul_type MUL_TYPE = MUL_GENERIC; + parameter div_type DIV_TYPE = DIV_GENERIC; + + parameter int unsigned INSTR_QUEUE_SZ = 2; + parameter bit [BUF_FLAGS_W-1:0] BUF_FLAGS = (BUF_FLAGS_W'(1) << BUF_DEQUEUE) | (BUF_FLAGS_W'(1) << BUF_VREG_PEND); + +endpackage