This commit is contained in:
Mikhail Yenuchenko
2026-01-20 16:23:00 +03:00
commit c8ab0ca4f7
107 changed files with 285173 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
sync.ffs_db

23
LICENSE Normal file
View File

@@ -0,0 +1,23 @@
# Solderpad Hardware Licence Version 2.0
This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation.
1. The definitions set out in the Apache License are modified as follows:
Copyright any reference to copyright (whether capitalised or not) includes Rights (as defined below).
Contribution also includes any design, as well as any work of authorship.
Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof.
Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works).
Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks).
Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files.
Work also includes a design or work of authorship, whether in Source form or other Object form.
2. Grant of Licence
2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist.

314
Makefile Normal file
View File

@@ -0,0 +1,314 @@
#------------------------------------------------------------------------------
# Makefile for SCR1
#------------------------------------------------------------------------------
# PARAMETERS
# CFG = <MAX, BASE, MIN, CUSTOM>
# BUS = <AHB, AXI>
export CFG ?= MAX
export BUS ?= AHB
ifeq ($(CFG), MAX)
# Predefined configuration SCR1_CFG_RV32IMC_MAX
override ARCH := IMC
override VECT_IRQ := 1
override IPIC := 1
override TCM := 1
override SIM_CFG_DEF := SCR1_CFG_RV32IMC_MAX
else
ifeq ($(CFG), BASE)
# Predefined configuration SCR1_CFG_RV32IC_BASE
override ARCH := IC
override VECT_IRQ := 1
override IPIC := 1
override TCM := 1
override SIM_CFG_DEF := SCR1_CFG_RV32IC_BASE
else
ifeq ($(CFG), MIN)
# Predefined configuration SCR1_CFG_RV32EC_MIN
override ARCH := EC
override VECT_IRQ := 0
override IPIC := 0
override TCM := 1
override SIM_CFG_DEF := SCR1_CFG_RV32EC_MIN
else
# CUSTOM configuration. Parameters can be overwritten
# These options are for compiling tests only. Set the corresponding RTL parameters manually in the file scr1_arch_description.svh.
# ARCH = <IMC, IC, IM, I, EMC, EM, EC, E>
# VECT_IRQ = <0, 1>
# IPIC = <0, 1>
# TCM = <0, 1>
ARCH ?= IMC
VECT_IRQ ?= 0
IPIC ?= 0
TCM ?= 0
SIM_CFG_DEF = SCR1_CFG_$(CFG)
endif
endif
endif
# export all overrided variables
export ARCH
export VECT_IRQ
export IPIC
export TCM
export SIM_CFG_DEF
ARCH_lowercase = $(shell echo $(ARCH) | tr A-Z a-z)
BUS_lowercase = $(shell echo $(BUS) | tr A-Z a-z)
ifeq ($(ARCH_lowercase),)
ARCH_tmp = imc
else
ifneq (,$(findstring e,$(ARCH_lowercase)))
ARCH_tmp += e
EXT_CFLAGS += -D__RVE_EXT
else
ARCH_tmp += i
endif
ifneq (,$(findstring m,$(ARCH_lowercase)))
ARCH_tmp := $(ARCH_tmp)m
endif
ifneq (,$(findstring c,$(ARCH_lowercase)))
ARCH_tmp := $(ARCH_tmp)c
EXT_CFLAGS += -D__RVC_EXT
endif
ifneq (,$(findstring b,$(ARCH_lowercase)))
ARCH_tmp := $(ARCH_tmp)b
endif
endif
override ARCH=$(ARCH_tmp)
# Use this parameter to enable tracelog
TRACE ?= 0
ifeq ($(TRACE), 1)
export SIM_TRACE_DEF = SCR1_TRACE_LOG_EN
else
export SIM_TRACE_DEF = SCR1_TRACE_LOG_DIS
endif
# Use this parameter to pass additional options for simulation build command
SIM_BUILD_OPTS ?=
# Use this parameter to set the list of tests to run
# TARGETS = <riscv_isa, riscv_compliance, riscv_arch, coremark, dhrystone21, hello, isr_sample>
export TARGETS :=
export XLEN ?= 32
export ABI ?= ilp32
# Testbench memory delay patterns\
(FFFFFFFF - no delay, 00000000 - random delay, 00000001 - max delay)
imem_pattern ?= FFFFFFFF
dmem_pattern ?= FFFFFFFF
VCS_OPTS ?=
MODELSIM_OPTS ?=
NCSIM_OPTS ?=
VERILATOR_OPTS ?=
current_goal := $(MAKECMDGOALS:run_%=%)
ifeq ($(current_goal),)
current_goal := verilator
endif
# Paths
export root_dir := $(shell pwd)
export tst_dir := $(root_dir)/sim/tests
export inc_dir := $(tst_dir)/common
export bld_dir := $(root_dir)/build/$(current_goal)_$(BUS)_$(CFG)_$(ARCH)_IPIC_$(IPIC)_TCM_$(TCM)_VIRQ_$(VECT_IRQ)_TRACE_$(TRACE)
test_results := $(bld_dir)/test_results.txt
test_info := $(bld_dir)/test_info
sim_results := $(bld_dir)/sim_results.txt
todo_list := $(bld_dir)/todo.txt
# Environment
export CROSS_PREFIX ?= riscv64-unknown-elf-
export RISCV_GCC ?= $(CROSS_PREFIX)gcc
export RISCV_OBJDUMP ?= $(CROSS_PREFIX)objdump -D
export RISCV_OBJCOPY ?= $(CROSS_PREFIX)objcopy -O verilog
export RISCV_READELF ?= $(CROSS_PREFIX)readelf -s
#--
ifneq (,$(findstring axi,$(BUS_lowercase)))
export rtl_top_files := axi_top.files
export rtl_tb_files := axi_tb.files
export top_module := scr1_top_tb_axi
else
export rtl_top_files := ahb_top.files
export rtl_tb_files := ahb_tb.files
export top_module := scr1_top_tb_ahb
endif
ifneq (,$(findstring e,$(ARCH_lowercase)))
# Tests can be compiled for RVE only if gcc version 8.0.0 or higher
GCCVERSIONGT7 := $(shell expr `$(RISCV_GCC) -dumpfullversion | cut -f1 -d'.'` \> 7)
ifeq "$(GCCVERSIONGT7)" "1"
ABI := ilp32e
endif
endif
#--
ifeq (,$(findstring e,$(ARCH_lowercase)))
# Comment this target if you don't want to run the riscv_isa
TARGETS += riscv_isa
# Comment this target if you don't want to run the riscv_compliance
TARGETS += riscv_compliance
endif
# Comment this target if you don't want to run the riscv_arch
TARGETS += riscv_arch
# Comment this target if you don't want to run the isr_sample
TARGETS += isr_sample
# Comment this target if you don't want to run the coremark
TARGETS += coremark
# Comment this target if you don't want to run the dhrystone
TARGETS += dhrystone21
# Comment this target if you don't want to run the hello test
TARGETS += hello
# When RVE extension is on, we want to exclude some tests, even if they are given from the command line
ifneq (,$(findstring e,$(ARCH_lowercase)))
excluded := riscv_isa riscv_compliance
excluded := $(filter $(excluded), $(TARGETS))
$(foreach test,$(excluded),$(warning Warning! $(test) test is not intended to run on an RVE extension, skipping it))
override TARGETS := $(filter-out $(excluded), $(TARGETS))
endif
ifeq (,$(strip $(TARGETS)))
$(error Error! No tests included, aborting)
endif
# Targets
.PHONY: tests run_modelsim run_vcs run_ncsim run_verilator run_verilator_wf
default: clean_test_list run_verilator
clean_test_list:
rm -f $(test_info)
echo_out: tests
@echo " Test | build | simulation " ;
@echo "$$(cat $(test_results))"
tests: $(TARGETS)
$(test_info): clean_test_list clean_hex tests
cd $(bld_dir)
isr_sample: | $(bld_dir)
$(MAKE) -C $(tst_dir)/isr_sample ARCH=$(ARCH) IPIC=$(IPIC) VECT_IRQ=$(VECT_IRQ)
dhrystone21: | $(bld_dir)
$(MAKE) -C $(tst_dir)/benchmarks/dhrystone21 EXT_CFLAGS="$(EXT_CFLAGS)" ARCH=$(ARCH)
coremark: | $(bld_dir)
-$(MAKE) -C $(tst_dir)/benchmarks/coremark EXT_CFLAGS="$(EXT_CFLAGS)" ARCH=$(ARCH)
riscv_isa: | $(bld_dir)
$(MAKE) -C $(tst_dir)/riscv_isa ARCH=$(ARCH)
riscv_compliance: | $(bld_dir)
$(MAKE) -C $(tst_dir)/riscv_compliance ARCH=$(ARCH)
riscv_arch: | $(bld_dir)
$(MAKE) -C $(tst_dir)/riscv_arch ARCH=$(ARCH)
hello: | $(bld_dir)
-$(MAKE) -C $(tst_dir)/hello EXT_CFLAGS="$(EXT_CFLAGS)" ARCH=$(ARCH)
clean_hex: | $(bld_dir)
$(RM) $(bld_dir)/*.hex
$(bld_dir):
mkdir -p $(bld_dir)
run_vcs: $(test_info)
$(MAKE) -C $(root_dir)/sim build_vcs SIM_CFG_DEF=$(SIM_CFG_DEF) SIM_TRACE_DEF=$(SIM_TRACE_DEF) SIM_BUILD_OPTS="$(SIM_BUILD_OPTS)";
printf "" > $(test_results);
cd $(bld_dir); \
$(bld_dir)/simv -V \
+test_info=$(test_info) \
+test_results=$(test_results) \
+imem_pattern=$(imem_pattern) \
+dmem_pattern=$(dmem_pattern) \
$(VCS_OPTS) | tee $(sim_results) ;\
printf " Test | build | simulation \n" ; \
printf "$$(cat $(test_results)) \n"
run_modelsim: $(test_info)
$(MAKE) -C $(root_dir)/sim build_modelsim SIM_CFG_DEF=$(SIM_CFG_DEF) SIM_TRACE_DEF=$(SIM_TRACE_DEF) SIM_BUILD_OPTS="$(SIM_BUILD_OPTS)"; \
printf "" > $(test_results); \
cd $(bld_dir); \
vsim -c -do "run -all" +nowarn3691 \
+test_info=$(test_info) \
+test_results=$(test_results) \
+imem_pattern=$(imem_pattern) \
+dmem_pattern=$(dmem_pattern) \
work.$(top_module) \
$(MODELSIM_OPTS) | tee $(sim_results) ;\
printf "Simulation performed on $$(vsim -version) \n" ;\
printf " Test | build | simulation \n" ; \
printf "$$(cat $(test_results)) \n"
run_ncsim: $(test_info)
$(MAKE) -C $(root_dir)/sim build_ncsim SIM_CFG_DEF=$(SIM_CFG_DEF) SIM_TRACE_DEF=$(SIM_TRACE_DEF) SIM_BUILD_OPTS="$(SIM_BUILD_OPTS)";
printf "" > $(test_results);
cd $(bld_dir); \
irun \
-R \
-64bit \
+test_info=$(test_info) \
+test_results=$(test_results) \
+imem_pattern=$(imem_pattern) \
+dmem_pattern=$(dmem_pattern) \
$(NCSIM_OPTS) | tee $(sim_results) ;\
printf "Simulation performed on $$(irun -version) \n" ;\
printf " Test | build | simulation \n" ; \
printf "$$(cat $(test_results)) \n"
run_verilator: $(test_info)
$(MAKE) -C $(root_dir)/sim build_verilator SIM_CFG_DEF=$(SIM_CFG_DEF) SIM_TRACE_DEF=$(SIM_TRACE_DEF) SIM_BUILD_OPTS="$(SIM_BUILD_OPTS)";
printf "" > $(test_results);
cd $(bld_dir); \
echo $(top_module) | tee $(sim_results); \
$(bld_dir)/verilator/V$(top_module) \
+test_info=$(test_info) \
+test_results=$(test_results) \
+imem_pattern=$(imem_pattern) \
+dmem_pattern=$(dmem_pattern) \
$(VERILATOR_OPTS) | tee -a $(sim_results) ;\
printf "Simulation performed on $$(verilator -version) \n" ;\
printf " Test | build | simulation \n" ; \
printf "$$(cat $(test_results)) \n"
run_verilator_wf: $(test_info)
$(MAKE) -C $(root_dir)/sim build_verilator_wf SIM_CFG_DEF=$(SIM_CFG_DEF) SIM_TRACE_DEF=$(SIM_TRACE_DEF) SIM_BUILD_OPTS="$(SIM_BUILD_OPTS)";
printf "" > $(test_results);
cd $(bld_dir); \
echo $(top_module) | tee $(sim_results); \
$(bld_dir)/verilator/V$(top_module) \
+test_info=$(test_info) \
+test_results=$(test_results) \
+imem_pattern=$(imem_pattern) \
+dmem_pattern=$(dmem_pattern) \
$(VERILATOR_OPTS) | tee -a $(sim_results) ;\
printf "Simulation performed on $$(verilator -version) \n" ;\
printf " Test | build | simulation \n" ; \
printf "$$(cat $(test_results)) \n"
clean:
$(RM) -R $(root_dir)/build/*
# $(MAKE) -C $(tst_dir)/benchmarks/dhrystone21 clean
# $(MAKE) -C $(tst_dir)/riscv_isa clean
# $(MAKE) -C $(tst_dir)/riscv_compliance clean
# $(MAKE) -C $(tst_dir)/riscv_arch clean
# $(RM) $(test_info)

198
README.md Normal file
View File

@@ -0,0 +1,198 @@
# SCR1 RISC-V Core
SCR1 is an open-source and free to use RISC-V compatible MCU-class core, designed and maintained by Syntacore. It is industry-grade and silicon-proven (including full-wafer production), works out of the box in all major EDA flows and Verilator, and comes with extensive collateral and documentation.
![SCR1 cluster](./docs/img/scr1_cluster.svg)
## Key features
* Open sourced under SHL-license (see LICENSE file) - unrestricted commercial use allowed
* RV32I or RV32E ISA base + optional RVM and RVC standard extensions
* Machine privilege mode only
* 2 to 4 stage pipeline
* Optional Integrated Programmable Interrupt Controller with 16 IRQ lines
* Optional RISC-V Debug subsystem with JTAG interface
* Optional on-chip Tightly-Coupled Memory
* 32-bit AXI4/AHB-Lite external interface
* Written in SystemVerilog
* Optimized for area and power
* 3 predefined recommended configurations
* A number of fine-tuning options for custom configuration
* Verification suite provided
* Extensive documentation
For more information on core architecture, see [SCR1 External Architecture Specification](https://github.com/syntacore/scr1/blob/master/docs/scr1_eas.pdf).
For more information on project usage, see [SCR1 User Manual](https://github.com/syntacore/scr1/blob/master/docs/scr1_um.pdf).
## Repository contents
|Folder | Description
|------ | -----------
|**dependencies**                 | **Dependent submodules**
|├─ riscv-tests                   | Common source files for RISC-V ISA tests
|├─ riscv_arch               | Common source files for RISC-V Architectural tests
|├─ riscv-compliance               | Common source files for RISC-V Compliance tests
|└─ coremark                       | Common source files for EEMBC's CoreMark® benchmark
|**docs** | **SCR1 documentation**
|├─ scr1_eas.pdf                   | SCR1 External Architecture Specification
|└─ scr1_um.pdf                   | SCR1 User Manual
|**sim** | **Tests and scripts for simulation**
|├─ tests/common                   | Common source files for tests
|├─ tests/riscv_isa               | RISC-V ISA tests platform specific source files
|├─ tests/riscv_compliance         | RISC-V Compliance platform specific source files
|├─ tests/benchmarks/dhrystone21   | Dhrystone 2.1 benchmark source files
|├─ tests/benchmarks/coremark     | EEMBC's CoreMark® benchmark platform specific source files
|├─ tests/isr_sample               | Sample program "Interrupt Service Routine"
|├─ tests/hello | Sample program "Hello"
|└─ verilator_wrap | Wrappers for Verilator simulation
|**src** | **SCR1 RTL source and testbench files**
|├─ includes | Header files
|├─ core | Core top source files
|├─ top | Cluster source files
|└─ tb | Testbench files
## SCR1 source file lists
SCR1 source file lists of SCR1 can be found in [./src](https://github.com/syntacore/scr1/tree/master/src):
* **core.files** - all synthesized file sources of the SCR1 core
* **ahb_top.files** - synthesized file sources of AHB cluster
* **axi_top.files** - synthesized file sources of AXI cluster
* **ahb_tb.files** - testbench file sources for AHB cluster (for simulation only)
* **axi_tb.files** - testbench file sources for AXI cluster (for simulation only)
Library with header files to include is [./src/includes/](https://github.com/syntacore/scr1/tree/master/src/includes)
## Simulation quick start guide
The project contains testbenches, test sources and scripts to quickly start the SCR1 simulation. Before starting the simulation, make sure you have:
* installed RISC-V GCC toolchain,
* installed one of the supported simulators,
* initialized submodules with test sources.
### Requirements
#### Operating system
GCC toolchain and make-scripts are supported by most popular Linux-like operating systems.
To run from Windows you can use an additional compatibility layer, such as WSL or Cygwin.
#### RISC-V GCC toolchain
RISC-V GCC toolchain is required to compile the software. You can use pre-built binaries or build the toolchain from scratch.
##### Using pre-built binary tools
Pre-built RISC-V GCC toolchain with support for all SCR1 architectural configurations is available for download from https://syntacore.com/tools/development-tools.
1. Download the archive for your platform.
2. Extract the archive to preferred directory `<GCC_INSTALL_PATH>`.
3. Add the `<GCC_INSTALL_PATH>/bin` folder to the $PATH environment variable:
```
export PATH=<GCC_INSTALL_PATH>/bin:$PATH
```
##### Building tools from source
You can build the RISC-V GCC toolchain from sources, stored in official repo https://github.com/riscv/riscv-gnu-toolchain
Instructions on how to prepare and build the toolchain can be found on https://github.com/riscv/riscv-gnu-toolchain/blob/master/README.md
We recommend using the multilib compiler. Please note that RV32IC, RV32E, RV32EM, RV32EMC, RV32EC architectural configurations are not included in the compiler by default. If you plan to use them, you will need to include the appropriate libraries by yourself before building.
After the building, be sure to add the `<GCC_INSTALL_PATH>/bin` folder to the $PATH environment variable
#### HDL simulators
Currently supported simulators:
* Verilator (last verified version: v5.014)
* Mentor Graphics ModelSim (last verified version: INTEL FPGA STARTER EDITION 2020.1)
* Synopsys VCS (last verified version: S-2021.09-1)
* Cadence NCSim (last verified version: 22.09-s004)
Please note that RTL simulator executables should be in your $PATH variable.
#### Tests preparation
The simulation package includes the following tests:
* **hello** - "Hello" sample program
* **isr_sample** - "Interrupt Service Routine" sample program
* **riscv_isa** - RISC-V ISA tests (submodule)
* **riscv_arch** - RISC-V Architectural tests (submodule)
* **riscv_compliance** - RISC-V Compliance tests (submodule)
* **dhrystone21** - Dhrystone 2.1 benchmark
* **coremark** - EEMBC's CoreMark® benchmark (submodule)
After the main SCR1 repository has been cloned execute the following command:
```
git submodule update --init --recursive
```
This command will initialized submodules with test sources.
### Running simulation
To build RTL, compile and run tests from the repo root folder you have to call Makefile.
By default, you may simply call Makefile without any parameters:
``` sh
   make
```
In this case simulation will run on Verilator with following parameters: `CFG=MAX BUS=AHB TRACE=0 TARGETS="hello isr_sample riscv_isa riscv_compliance dhrystone21 coremark"`.
Makefile supports:
* choice of simulator - `run_<SIMULATOR> = <run_vcs, run_modelsim, run_ncsim, run_verilator, run_verilator_wf>`
* selection of external interface - `BUS = <AHB, AXI>`,
* configuration setup - `CFG = <MAX, BASE, MIN, CUSTOM>`,
* parameters for CUSTOM configuration - `ARCH = <IMC, IC, IM, I, EMC, EM, EC, E>, VECT_IRQ = <0, 1>, IPIC = <0, 1>, TCM = <0, 1>`
* tests subset to run - `TARGETS = <hello, isr_sample, riscv_isa, riscv_compliance, riscv_arch, dhrystone21, coremark>`
* enabling tracelog - `TRACE = <0, 1>`
* and any additional options to pass to the simulator - `SIM_BUILD_OPTS`.
Examples:
``` sh
   make run_verilator_wf CFG=MAX BUS=AXI TARGETS="riscv_isa riscv_compliance" TRACE=1
   make run_vcs CFG=BASE BUS=AHB TARGETS="dhrystone21 coremark" SIM_BUILD_OPTS="-gui"
   make run_modelsim CFG=CUSTOM BUS=AXI ARCH=I VECT_IRQ=1 IPIC=1 TCM=0 TARGETS=isr_sample
```
Build and run parameters can be configured in the `./Makefile`.
After all the tests have finished, the results can be found in `build/<SIM_CFG>/test_results.txt`.
**IMPORTANT:** To ensure correct rebuild, please clean build directory between simulation runs:
``` sh
  make clean
```
Please refer to the *"Simulation environment"* chapter of the [SCR1 User Manual](https://github.com/syntacore/scr1/blob/master/docs/scr1_um.pdf) for more information on setting up a simulation run.
## SCR1 SDKs
FPGA-based SDKs are available at the <https://github.com/syntacore/scr1-sdk>.
Repo contains:
* Pre-build images and open designs for several standard FPGAs boards:
* Digilent Arty (Xilinx)
* Digilent Nexys 4 DDR (Xilinx)
* Arria V GX Starter (Intel)
* Terasic DE10-Lite (Intel)
* Software package:
* Bootloader
* Zephyr RTOS
* Tests\SW samples
* User Guides for SDKs and tools
## Contacts
Report an issue: <https://github.com/syntacore/scr1/issues>
Ask a question: scr1@syntacore.com

619
docs/img/scr1_cluster.svg Normal file
View File

@@ -0,0 +1,619 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Создано Microsoft Visio, экспорт SVG scr1_cluster.svg scr1_cluster -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="5.73958in" height="5.11458in"
viewBox="0 0 413.25 368.25" xml:space="preserve" color-interpolation-filters="sRGB" class="st12">
<v:documentProperties v:langID="2057" v:viewMarkup="false"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#dcedfa;stroke:#243740;stroke-linecap:butt;stroke-width:0.75}
.st2 {fill:#b1ddf0;stroke:#243740;stroke-linecap:butt;stroke-width:0.75}
.st3 {fill:#b0e3e6;stroke:#243740;stroke-linecap:butt;stroke-width:0.75}
.st4 {fill:none}
.st5 {stroke:#243740;stroke-linecap:butt;stroke-width:1.5}
.st6 {fill:#243740;stroke:#243740;stroke-linecap:butt;stroke-width:1.5}
.st7 {fill:none;stroke:none;stroke-linecap:butt;stroke-width:0.75}
.st8 {fill:#243740;font-family:Calibri;font-size:0.75em;font-weight:bold}
.st9 {fill:#243740;font-family:Calibri;font-size:0.833336em;font-weight:bold}
.st10 {fill:#0c0c0c;font-family:Calibri;font-size:0.833336em;font-weight:bold}
.st11 {font-size:1em}
.st12 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<title>scr1_cluster</title>
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="19" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
<g id="shape2-1" v:mID="2" v:groupContext="shape" transform="translate(60.375,-30.375)">
<title>Лист.2</title>
<path d="M0 356.55 A11.7003 11.7003 -180 0 0 11.7 368.25 L280.8 368.25 A11.7003 11.7003 -180 0 0 292.5 356.55 L292.5
42.45 A11.7003 11.7003 -180 0 0 280.8 30.75 L11.7 30.75 A11.7003 11.7003 -180 0 0 0 42.45 L0 356.55 Z"
class="st1"/>
</g>
<g id="shape3-3" v:mID="3" v:groupContext="shape" transform="translate(67.875,-210.375)">
<title>Лист.3</title>
<path d="M0 362.85 A5.40013 5.40013 -180 0 0 5.4 368.25 L272.1 368.25 A5.40013 5.40013 -180 0 0 277.5 362.85 L277.5 238.65
A5.40013 5.40013 -180 0 0 272.1 233.25 L5.4 233.25 A5.40013 5.40013 -180 0 0 0 238.65 L0 362.85 Z"
class="st2"/>
</g>
<g id="shape4-5" v:mID="4" v:groupContext="shape" transform="translate(75.375,-217.875)">
<title>Лист.4</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape5-7" v:mID="5" v:groupContext="shape" transform="translate(142.875,-217.875)">
<title>Лист.5</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape6-9" v:mID="6" v:groupContext="shape" transform="translate(210.375,-217.875)">
<title>Лист.6</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape7-11" v:mID="7" v:groupContext="shape" transform="translate(277.875,-217.875)">
<title>Лист.7</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape8-13" v:mID="8" v:groupContext="shape" transform="translate(142.875,-255.375)">
<title>Лист.8</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape9-15" v:mID="9" v:groupContext="shape" transform="translate(75.375,-255.375)">
<title>Лист.9</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape10-17" v:mID="10" v:groupContext="shape" transform="translate(210.375,-255.375)">
<title>Лист.10</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape11-19" v:mID="11" v:groupContext="shape" transform="translate(52.305,-307.635)">
<title>Лист.11</title>
<path d="M16.14 368.01 L8.07 368.01 L8.07 368.23 L0 368.25 L16.14 368.01 Z" class="st4"/>
<path d="M16.14 368.01 L8.07 368.01 L8.07 368.23 L0 368.25" class="st5"/>
</g>
<g id="shape12-22" v:mID="12" v:groupContext="shape" transform="translate(68.445,-305.25)">
<title>Лист.12</title>
<path d="M5.25 365.62 L0 368.25 L0 363 L5.25 365.62 Z" class="st6"/>
</g>
<g id="shape13-24" v:mID="13" v:groupContext="shape" transform="translate(47.055,-305.01)">
<title>Лист.13</title>
<path d="M0 365.63 L5.24 363 L5.25 368.25 L0 365.63 Z" class="st6"/>
</g>
<g id="shape14-26" v:mID="14" v:groupContext="shape" transform="translate(75.375,-292.875)">
<title>Лист.14</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 -0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape15-28" v:mID="15" v:groupContext="shape" transform="translate(277.875,-255.375)">
<title>Лист.15</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape16-30" v:mID="16" v:groupContext="shape" transform="translate(142.875,-292.875)">
<title>Лист.16</title>
<path d="M0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 -0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape17-32" v:mID="17" v:groupContext="shape" transform="translate(344.805,-307.635)">
<title>Лист.17</title>
<path d="M0 368.01 L8.07 368.01 L8.07 368.23 L16.14 368.25 L0 368.01 Z" class="st4"/>
<path d="M0 368.01 L8.07 368.01 L8.07 368.23 L16.14 368.25" class="st5"/>
</g>
<g id="shape18-35" v:mID="18" v:groupContext="shape" transform="translate(339.555,-305.25)">
<title>Лист.18</title>
<path d="M0 365.62 L5.25 363 L5.25 368.25 L0 365.62 Z" class="st6"/>
</g>
<g id="shape19-37" v:mID="19" v:groupContext="shape" transform="translate(360.945,-305.01)">
<title>Лист.19</title>
<path d="M5.25 365.63 L0 368.25 L0.01 363 L5.25 365.63 Z" class="st6"/>
</g>
<g id="shape20-39" v:mID="20" v:groupContext="shape" transform="translate(277.875,-292.875)">
<title>Лист.20</title>
<path d="M-0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 -0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape21-41" v:mID="21" v:groupContext="shape" transform="translate(210.375,-292.875)">
<title>Лист.21</title>
<path d="M-0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L55.5 368.25 A4.5001 4.5001 -180 0 0 60 363.75 L60 342.75 A4.5001
4.5001 -180 0 0 55.5 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 -0 342.75 L0 363.75 Z" class="st3"/>
</g>
<g id="shape22-43" v:mID="22" v:groupContext="shape" transform="translate(150.375,-123.375)">
<title>Лист.22</title>
<path d="M0 360.37 A7.87518 7.87518 -180 0 0 7.87 368.25 L104.62 368.25 A7.87518 7.87518 -180 0 0 112.5 360.37 L112.5
323.63 A7.87518 7.87518 -180 0 0 104.62 315.75 L7.87 315.75 A7.87518 7.87518 -180 0 0 0 323.63 L0 360.37
Z" class="st2"/>
</g>
<g id="shape23-45" v:mID="23" v:groupContext="shape" transform="translate(195.375,-85.875)">
<title>Лист.23</title>
<path d="M-0 363.75 A4.5001 4.5001 -180 0 0 4.5 368.25 L63 368.25 A4.5001 4.5001 -180 0 0 67.5 363.75 L67.5 342.75 A4.5001
4.5001 -180 0 0 63 338.25 L4.5 338.25 A4.5001 4.5001 -180 0 0 -0 342.75 L0 363.75 Z" class="st2"/>
</g>
<g id="shape24-47" v:mID="24" v:groupContext="shape" transform="translate(120.375,-149.625)">
<title>Лист.24</title>
<path d="M0 359.43 L0 368.25 L23.07 368.25 L0 359.43 Z" class="st4"/>
<path d="M0 359.43 L0 368.25 L23.07 368.25" class="st5"/>
</g>
<g id="shape25-50" v:mID="25" v:groupContext="shape" transform="translate(117.75,-158.445)">
<title>Лист.25</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape26-52" v:mID="26" v:groupContext="shape" transform="translate(143.445,-147)">
<title>Лист.26</title>
<path d="M5.25 365.63 L0 368.25 L0 363 L5.25 365.63 Z" class="st6"/>
</g>
<g id="shape27-54" v:mID="27" v:groupContext="shape" transform="translate(105.375,-202.305)">
<title>Лист.27</title>
<path d="M0 368.25 L0 359.61 L0 368.25 Z" class="st4"/>
<path d="M0 368.25 L0 359.61" class="st5"/>
</g>
<g id="shape28-57" v:mID="28" v:groupContext="shape" transform="translate(102.75,-197.055)">
<title>Лист.28</title>
<path d="M2.63 368.25 L0 363 L5.25 363 L2.63 368.25 Z" class="st6"/>
</g>
<g id="shape29-59" v:mID="29" v:groupContext="shape" transform="translate(102.75,-210.945)">
<title>Лист.29</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape30-61" v:mID="30" v:groupContext="shape" transform="translate(75.375,-165.375)">
<title>Лист.30</title>
<path d="M0 368.25 L12 338.25 L48 338.25 L60 368.25 L0 368.25 Z" class="st2"/>
</g>
<g id="shape31-63" v:mID="31" v:groupContext="shape" transform="translate(269.805,-149.625)">
<title>Лист.31</title>
<path d="M23.07 359.43 L23.07 368.25 L0 368.25 L23.07 359.43 Z" class="st4"/>
<path d="M23.07 359.43 L23.07 368.25 L0 368.25" class="st5"/>
</g>
<g id="shape32-66" v:mID="32" v:groupContext="shape" transform="translate(290.25,-158.445)">
<title>Лист.32</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape33-68" v:mID="33" v:groupContext="shape" transform="translate(264.555,-147)">
<title>Лист.33</title>
<path d="M0 365.63 L5.25 363 L5.25 368.25 L0 365.63 Z" class="st6"/>
</g>
<g id="shape34-70" v:mID="34" v:groupContext="shape" transform="translate(277.875,-165.375)">
<title>Лист.34</title>
<path d="M0 368.25 L12 338.25 L48 338.25 L60 368.25 L0 368.25 Z" class="st2"/>
</g>
<g id="shape35-72" v:mID="35" v:groupContext="shape" transform="translate(307.875,-202.305)">
<title>Лист.35</title>
<path d="M0 359.61 L0 368.25 L0 359.61 Z" class="st4"/>
<path d="M0 359.61 L0 368.25" class="st5"/>
</g>
<g id="shape36-75" v:mID="36" v:groupContext="shape" transform="translate(305.25,-210.945)">
<title>Лист.36</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape37-77" v:mID="37" v:groupContext="shape" transform="translate(305.25,-197.055)">
<title>Лист.37</title>
<path d="M2.63 368.25 L0 363 L5.25 363 L2.63 368.25 Z" class="st6"/>
</g>
<g id="shape38-79" v:mID="38" v:groupContext="shape" transform="translate(269.805,-100.875)">
<title>Лист.38</title>
<path d="M0 368.25 L38.07 368.25 L38.07 310.68 L0 368.25 Z" class="st4"/>
<path d="M0 368.25 L38.07 368.25 L38.07 310.68" class="st5"/>
</g>
<g id="shape39-82" v:mID="39" v:groupContext="shape" transform="translate(264.555,-98.25)">
<title>Лист.39</title>
<path d="M0 365.62 L5.25 363 L5.25 368.25 L0 365.62 Z" class="st6"/>
</g>
<g id="shape40-84" v:mID="40" v:groupContext="shape" transform="translate(305.25,-158.445)">
<title>Лист.40</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape41-86" v:mID="41" v:groupContext="shape" transform="translate(90.375,-89.805)">
<title>Лист.41</title>
<path d="M0 368.25 L0 299.61 L0 368.25 Z" class="st4"/>
<path d="M0 368.25 L0 299.61" class="st5"/>
</g>
<g id="shape42-89" v:mID="42" v:groupContext="shape" transform="translate(87.75,-84.555)">
<title>Лист.42</title>
<path d="M2.63 368.25 L0 363 L5.25 363 L2.63 368.25 Z" class="st6"/>
</g>
<g id="shape43-91" v:mID="43" v:groupContext="shape" transform="translate(87.75,-158.445)">
<title>Лист.43</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape44-93" v:mID="44" v:groupContext="shape" transform="translate(75.375,-45.375)">
<title>Лист.44</title>
<path d="M0 362.62 A5.62513 5.62513 -180 0 0 5.63 368.25 L54.38 368.25 A5.62513 5.62513 -180 0 0 60 362.62 L60 336.38
A5.62513 5.62513 -180 0 0 54.38 330.75 L5.62 330.75 A5.62513 5.62513 -180 0 0 0 336.38 L0 362.62 Z"
class="st2"/>
</g>
<g id="shape45-95" v:mID="45" v:groupContext="shape" transform="translate(277.875,-45.375)">
<title>Лист.45</title>
<path d="M0 362.62 A5.62513 5.62513 -180 0 0 5.63 368.25 L54.38 368.25 A5.62513 5.62513 -180 0 0 60 362.62 L60 336.38
A5.62513 5.62513 -180 0 0 54.38 330.75 L5.62 330.75 A5.62513 5.62513 -180 0 0 0 336.38 L0 362.62 Z"
class="st2"/>
</g>
<g id="shape46-97" v:mID="46" v:groupContext="shape" transform="translate(322.875,-89.805)">
<title>Лист.46</title>
<path d="M0 299.61 L0 368.25 L0 299.61 Z" class="st4"/>
<path d="M0 299.61 L0 368.25" class="st5"/>
</g>
<g id="shape47-100" v:mID="47" v:groupContext="shape" transform="translate(320.25,-158.445)">
<title>Лист.47</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape48-102" v:mID="48" v:groupContext="shape" transform="translate(320.25,-84.555)">
<title>Лист.48</title>
<path d="M2.63 368.25 L0 363 L5.25 363 L2.63 368.25 Z" class="st6"/>
</g>
<g id="shape49-104" v:mID="49" v:groupContext="shape" transform="translate(367.875,-300.375)">
<title>Лист.49</title>
<rect x="0" y="353.25" width="45" height="15" class="st7"/>
</g>
<g id="shape50-106" v:mID="50" v:groupContext="shape" transform="translate(354.35,-302.925)">
<title>Лист.50</title>
<desc>JTAG I/F</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="36.025" cy="362.85" width="72.06" height="10.8"/>
<rect x="0" y="357.45" width="72.05" height="10.8" class="st7"/>
<text x="20.5" y="365.55" class="st8" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>JTAG I/F</text> </g>
<g id="shape51-109" v:mID="51" v:groupContext="shape" transform="translate(0.375,-300.375)">
<title>Лист.51</title>
<rect x="0" y="353.25" width="45" height="15" class="st7"/>
</g>
<g id="shape52-111" v:mID="52" v:groupContext="shape" transform="translate(-8.65,-302.925)">
<title>Лист.52</title>
<desc>IRQ I/F</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="31.525" cy="362.85" width="63.05" height="10.8"/>
<rect x="0" y="357.45" width="63.05" height="10.8" class="st7"/>
<text x="18.49" y="365.55" class="st8" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>IRQ I/F</text> </g>
<g id="shape53-114" v:mID="53" v:groupContext="shape" transform="translate(67.875,-0.375)">
<title>Лист.53</title>
<rect x="0" y="353.25" width="75" height="15" class="st7"/>
</g>
<g id="shape54-116" v:mID="54" v:groupContext="shape" transform="translate(55.85,-2.925)">
<title>Лист.54</title>
<desc>AHB/AXI I/F</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="49.525" cy="362.85" width="99.05" height="10.8"/>
<rect x="0" y="357.45" width="99.05" height="10.8" class="st7"/>
<text x="24.37" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>AHB/AXI I/F</text> </g>
<g id="shape55-119" v:mID="55" v:groupContext="shape" transform="translate(105.375,-22.305)">
<title>Лист.55</title>
<path d="M0 352.11 L0 368.25 L0 352.11 Z" class="st4"/>
<path d="M0 352.11 L0 368.25" class="st5"/>
</g>
<g id="shape56-122" v:mID="56" v:groupContext="shape" transform="translate(102.75,-38.445)">
<title>Лист.56</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape57-124" v:mID="57" v:groupContext="shape" transform="translate(102.75,-17.055)">
<title>Лист.57</title>
<path d="M2.63 368.25 L0 363 L5.25 363 L2.63 368.25 Z" class="st6"/>
</g>
<g id="shape58-126" v:mID="58" v:groupContext="shape" transform="translate(270.375,-0.375)">
<title>Лист.58</title>
<rect x="0" y="353.25" width="75" height="15" class="st7"/>
</g>
<g id="shape59-128" v:mID="59" v:groupContext="shape" transform="translate(258.35,-2.925)">
<title>Лист.59</title>
<desc>AHB/AXI I/F</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="49.525" cy="362.85" width="99.06" height="10.8"/>
<rect x="0" y="357.45" width="99.05" height="10.8" class="st7"/>
<text x="24.37" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>AHB/AXI I/F</text> </g>
<g id="shape60-131" v:mID="60" v:groupContext="shape" transform="translate(307.875,-22.305)">
<title>Лист.60</title>
<path d="M0 352.11 L0 368.25 L0 352.11 Z" class="st4"/>
<path d="M0 352.11 L0 368.25" class="st5"/>
</g>
<g id="shape61-134" v:mID="61" v:groupContext="shape" transform="translate(305.25,-38.445)">
<title>Лист.61</title>
<path d="M2.63 363 L5.25 368.25 L0 368.25 L2.63 363 Z" class="st6"/>
</g>
<g id="shape62-136" v:mID="62" v:groupContext="shape" transform="translate(305.25,-17.055)">
<title>Лист.62</title>
<path d="M2.63 368.25 L0 363 L5.25 363 L2.63 368.25 Z" class="st6"/>
</g>
<g id="shape63-138" v:mID="63" v:groupContext="shape" transform="translate(67.875,-349.125)">
<title>Лист.63</title>
<rect x="0" y="353.25" width="82.5" height="15" class="st7"/>
</g>
<g id="shape64-140" v:mID="64" v:groupContext="shape" transform="translate(82.675,-351.45)">
<title>Лист.64</title>
<desc>SCR1 cluster</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="43.325" cy="362.85" width="86.65" height="10.8"/>
<rect x="0" y="357.45" width="86.65" height="10.8" class="st7"/>
<text x="0" y="365.85" class="st10" v:langID="2057"><v:paragraph/><v:tabList/>SCR1 cluster</text> </g>
<g id="shape65-143" v:mID="65" v:groupContext="shape" transform="translate(75.375,-326.625)">
<title>Лист.65</title>
<rect x="0" y="353.25" width="75" height="15" class="st7"/>
</g>
<g id="shape66-145" v:mID="66" v:groupContext="shape" transform="translate(76.85,-329.175)">
<title>Лист.66</title>
<desc>SCR1 core</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="0" y="365.85" class="st10" v:langID="2057"><v:paragraph/><v:tabList/>SCR1 core</text> </g>
<g id="shape67-148" v:mID="67" v:groupContext="shape" transform="translate(90.375,-300.375)">
<title>Лист.67</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape68-150" v:mID="68" v:groupContext="shape" transform="translate(64.125,-301.95)">
<title>Лист.68</title>
<desc>Interrupt Controller</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.05" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="23.5" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Interrupt <v:lf/><tspan
x="21.65" dy="1.2em" class="st11">Controller</tspan></text> </g>
<g id="shape69-154" v:mID="69" v:groupContext="shape" transform="translate(157.875,-300.375)">
<title>Лист.69</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape70-156" v:mID="70" v:groupContext="shape" transform="translate(132.35,-302.925)">
<title>Лист.70</title>
<desc>System Control Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="26.99" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>System <v:lf/><tspan
x="17.59" dy="1.2em" class="st11">Control Unit</tspan></text> </g>
<g id="shape71-160" v:mID="71" v:groupContext="shape" transform="translate(225.375,-300.375)">
<title>Лист.71</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape72-162" v:mID="72" v:groupContext="shape" transform="translate(204.35,-302.925)">
<title>Лист.72</title>
<desc>Debug Module</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="36.025" cy="362.85" width="72.06" height="10.8"/>
<rect x="0" y="357.45" width="72.05" height="10.8" class="st7"/>
<text x="23.96" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Debug <v:lf/><tspan
x="21.47" dy="1.2em" class="st11">Module</tspan></text> </g>
<g id="shape73-166" v:mID="73" v:groupContext="shape" transform="translate(292.875,-300.375)">
<title>Лист.73</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape74-168" v:mID="74" v:groupContext="shape" transform="translate(267.35,-302.925)">
<title>Лист.74</title>
<desc>TAP Controller</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="33.18" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>TAP<v:lf/><tspan
x="21.65" dy="1.2em" class="st11">Controller</tspan></text> </g>
<g id="shape75-172" v:mID="75" v:groupContext="shape" transform="translate(90.375,-262.875)">
<title>Лист.75</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape76-174" v:mID="76" v:groupContext="shape" transform="translate(64.85,-265.425)">
<title>Лист.76</title>
<desc>Control-Status Register File</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.05" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="13.57" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Control-Status <v:lf/><tspan
x="17.71" dy="1.2em" class="st11">Register File</tspan></text> </g>
<g id="shape77-178" v:mID="77" v:groupContext="shape" transform="translate(191.625,-142.125)">
<title>Лист.77</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape78-180" v:mID="78" v:groupContext="shape" transform="translate(162,-144)">
<title>Лист.78</title>
<desc>Tightly-Coupled Memory</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="45" cy="362.85" width="90" height="10.8"/>
<rect x="0" y="357.45" width="90" height="10.8" class="st7"/>
<text x="12.25" y="359.85" class="st9" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Tightly-Coupled <tspan
x="27.21" dy="1.2em" class="st11">Memory</tspan></text> </g>
<g id="shape79-184" v:mID="79" v:groupContext="shape" transform="translate(214.125,-93.375)">
<title>Лист.79</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape80-186" v:mID="80" v:groupContext="shape" transform="translate(206.6,-95.925)">
<title>Лист.80</title>
<desc>Timer</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="22.525" cy="362.85" width="45.05" height="10.8"/>
<rect x="0" y="357.45" width="45.05" height="10.8" class="st7"/>
<text x="10.46" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>Timer</text> </g>
<g id="shape81-189" v:mID="81" v:groupContext="shape" transform="translate(157.875,-225.375)">
<title>Лист.81</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape82-191" v:mID="82" v:groupContext="shape" transform="translate(132.35,-227.925)">
<title>Лист.82</title>
<desc>Instruction Decode Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="20.16" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Instruction <v:lf/><tspan
x="17.41" dy="1.2em" class="st11">Decode Unit</tspan></text> </g>
<g id="shape83-195" v:mID="83" v:groupContext="shape" transform="translate(225.375,-225.375)">
<title>Лист.83</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape84-197" v:mID="84" v:groupContext="shape" transform="translate(199.85,-227.925)">
<title>Лист.84</title>
<desc>Execution Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="22.2" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Execution <v:lf/><tspan
x="32.51" dy="1.2em" class="st11">Unit</tspan></text> </g>
<g id="shape85-201" v:mID="85" v:groupContext="shape" transform="translate(292.875,-225.375)">
<title>Лист.85</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape86-203" v:mID="86" v:groupContext="shape" transform="translate(267.35,-227.925)">
<title>Лист.86</title>
<desc>Load-Store Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="20.22" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Load-Store <v:lf/><tspan
x="32.51" dy="1.2em" class="st11">Unit</tspan></text> </g>
<g id="shape87-207" v:mID="87" v:groupContext="shape" transform="translate(225.375,-262.875)">
<title>Лист.87</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape88-209" v:mID="88" v:groupContext="shape" transform="translate(199.85,-265.425)">
<title>Лист.88</title>
<desc>Trigger Debug Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="27.46" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Trigger <v:lf/><tspan
x="19.42" dy="1.2em" class="st11">Debug Unit</tspan></text> </g>
<g id="shape89-213" v:mID="89" v:groupContext="shape" transform="translate(90.375,-67.875)">
<title>Лист.89</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape90-215" v:mID="90" v:groupContext="shape" transform="translate(87.35,-66.675)">
<title>Лист.90</title>
<desc>IMEM</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="18.025" cy="362.85" width="36.05" height="10.8"/>
<rect x="0" y="357.45" width="36.05" height="10.8" class="st7"/>
<text x="5.51" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>IMEM</text> </g>
<g id="shape91-218" v:mID="91" v:groupContext="shape" transform="translate(90.375,-58.875)">
<title>Лист.91</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape92-220" v:mID="92" v:groupContext="shape" transform="translate(73.85,-57.675)">
<title>Лист.92</title>
<desc>AHB/AXI</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="31.525" cy="362.85" width="63.05" height="10.8"/>
<rect x="0" y="357.45" width="63.05" height="10.8" class="st7"/>
<text x="13.27" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>AHB/AXI</text> </g>
<g id="shape93-223" v:mID="93" v:groupContext="shape" transform="translate(90.375,-49.875)">
<title>Лист.93</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape94-225" v:mID="94" v:groupContext="shape" transform="translate(78.35,-48.675)">
<title>Лист.94</title>
<desc>bridge</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="27.025" cy="362.85" width="54.05" height="10.8"/>
<rect x="0" y="357.45" width="54.05" height="10.8" class="st7"/>
<text x="13.77" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>bridge</text> </g>
<g id="shape95-228" v:mID="95" v:groupContext="shape" transform="translate(292.875,-67.875)">
<title>Лист.95</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape96-230" v:mID="96" v:groupContext="shape" transform="translate(289.85,-66.675)">
<title>Лист.96</title>
<desc>DMEM</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="18.025" cy="362.85" width="36.05" height="10.8"/>
<rect x="0" y="357.45" width="36.05" height="10.8" class="st7"/>
<text x="3.69" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>DMEM</text> </g>
<g id="shape97-233" v:mID="97" v:groupContext="shape" transform="translate(292.875,-58.875)">
<title>Лист.97</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape98-235" v:mID="98" v:groupContext="shape" transform="translate(276.35,-57.675)">
<title>Лист.98</title>
<desc>AHB/AXI</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="31.525" cy="362.85" width="63.05" height="10.8"/>
<rect x="0" y="357.45" width="63.05" height="10.8" class="st7"/>
<text x="13.27" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>AHB/AXI</text> </g>
<g id="shape99-238" v:mID="99" v:groupContext="shape" transform="translate(292.875,-49.875)">
<title>Лист.99</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape100-240" v:mID="100" v:groupContext="shape" transform="translate(280.85,-48.675)">
<title>Лист.100</title>
<desc>bridge</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="27.025" cy="362.85" width="54.05" height="10.8"/>
<rect x="0" y="357.45" width="54.05" height="10.8" class="st7"/>
<text x="13.77" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>bridge</text> </g>
<g id="shape101-243" v:mID="101" v:groupContext="shape" transform="translate(90.375,-180.375)">
<title>Лист.101</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape102-245" v:mID="102" v:groupContext="shape" transform="translate(87.35,-179.175)">
<title>Лист.102</title>
<desc>IMEM</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="18.025" cy="362.85" width="36.05" height="10.8"/>
<rect x="0" y="357.45" width="36.05" height="10.8" class="st7"/>
<text x="5.51" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>IMEM</text> </g>
<g id="shape103-248" v:mID="103" v:groupContext="shape" transform="translate(90.375,-171.375)">
<title>Лист.103</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape104-250" v:mID="104" v:groupContext="shape" transform="translate(78.35,-170.175)">
<title>Лист.104</title>
<desc>router</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="27.025" cy="362.85" width="54.05" height="10.8"/>
<rect x="0" y="357.45" width="54.05" height="10.8" class="st7"/>
<text x="13.85" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>router</text> </g>
<g id="shape105-253" v:mID="105" v:groupContext="shape" transform="translate(292.875,-180.375)">
<title>Лист.105</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape106-255" v:mID="106" v:groupContext="shape" transform="translate(289.85,-179.175)">
<title>Лист.106</title>
<desc>DMEM</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="18.025" cy="362.85" width="36.05" height="10.8"/>
<rect x="0" y="357.45" width="36.05" height="10.8" class="st7"/>
<text x="3.69" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>DMEM</text> </g>
<g id="shape107-258" v:mID="107" v:groupContext="shape" transform="translate(292.875,-171.375)">
<title>Лист.107</title>
<rect x="0" y="360.75" width="30" height="7.5" class="st7"/>
</g>
<g id="shape108-260" v:mID="108" v:groupContext="shape" transform="translate(280.85,-170.175)">
<title>Лист.108</title>
<desc>router</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="27.025" cy="362.85" width="54.05" height="10.8"/>
<rect x="0" y="357.45" width="54.05" height="10.8" class="st7"/>
<text x="13.85" y="365.85" class="st9" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>router</text> </g>
<g id="shape109-263" v:mID="109" v:groupContext="shape" transform="translate(157.875,-262.875)">
<title>Лист.109</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape110-265" v:mID="110" v:groupContext="shape" transform="translate(132.35,-265.425)">
<title>Лист.110</title>
<desc>Multi-Port Register File</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="21.06" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Multi-Port <v:lf/><tspan
x="17.71" dy="1.2em" class="st11">Register File</tspan></text> </g>
<g id="shape111-269" v:mID="111" v:groupContext="shape" transform="translate(292.875,-262.875)">
<title>Лист.111</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape112-271" v:mID="112" v:groupContext="shape" transform="translate(267.35,-265.425)">
<title>Лист.112</title>
<desc>Hart Debug Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.06" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="32.31" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hart <v:lf/><tspan
x="19.42" dy="1.2em" class="st11">Debug Unit</tspan></text> </g>
<g id="shape113-275" v:mID="113" v:groupContext="shape" transform="translate(90.375,-225.375)">
<title>Лист.113</title>
<rect x="0" y="353.25" width="30" height="15" class="st7"/>
</g>
<g id="shape114-277" v:mID="114" v:groupContext="shape" transform="translate(64.85,-227.925)">
<title>Лист.114</title>
<desc>Instruction Fetch Unit</desc>
<v:textBlock v:margins="rect(0,0,0,0)"/>
<v:textRect cx="40.525" cy="362.85" width="81.05" height="10.8"/>
<rect x="0" y="357.45" width="81.05" height="10.8" class="st7"/>
<text x="20.16" y="360.15" class="st8" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Instruction<v:newlineChar/><tspan
x="21.3" dy="1.2em" class="st11">Fetch Unit</tspan></text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

227917
docs/scr1_eas.pdf Normal file

File diff suppressed because one or more lines are too long

25640
docs/scr1_um.pdf Normal file

File diff suppressed because it is too large Load Diff

138
sim/Makefile Normal file
View File

@@ -0,0 +1,138 @@
# src_dir := $(dir $(lastword $(MAKEFILE_LIST)))
rtl_src_dir := $(root_dir)/src/
rtl_core_files ?= core.files
rtl_top_files ?= ahb_top.files
rtl_tb_files ?= ahb_tb.files
rtl_inc_dir ?= $(root_dir)/src/includes
rtl_inc_tb_dir ?= $(root_dir)/src/tb
top_module ?= scr1_top_tb_ahb
rtl_core_list := $(addprefix $(rtl_src_dir),$(shell cat $(rtl_src_dir)$(rtl_core_files)))
rtl_top_list := $(addprefix $(rtl_src_dir),$(shell cat $(rtl_src_dir)$(rtl_top_files)))
rtl_tb_list := $(addprefix $(rtl_src_dir),$(shell cat $(rtl_src_dir)$(rtl_tb_files)))
sv_list := $(rtl_core_list) $(rtl_top_list) $(rtl_tb_list)
ifeq ($(MAKECMDGOALS), $(filter $(MAKECMDGOALS),build_verilator build_verilator_wf))
ifeq ($(BUS),AHB)
export scr1_wrapper := $(root_dir)/sim/verilator_wrap/scr1_ahb_wrapper.c
endif
ifeq ($(BUS),AXI)
export scr1_wrapper := $(root_dir)/sim/verilator_wrap/scr1_axi_wrapper.c
endif
export verilator_ver ?= $(shell expr `verilator --version | cut -f2 -d' '`)
export verilator_ver_5x ?= $(shell expr `verilator --version | cut -f2 -d' '` \>= 5)
ifeq "$(verilator_ver_5x)" "1"
VERILATOR_5X_OPTS ?= --no-timing # conservative way
endif
endif
.PHONY: build_modelsim build_vcs build_ncsim build_verilator build_verilator_wf
default: build_modelsim
build_modelsim: $(sv_list)
cd $(bld_dir); \
vlib work; \
vmap work work; \
vlog -work work -O1 -mfcu -sv \
+incdir+$(rtl_inc_dir) \
+incdir+$(rtl_inc_tb_dir) \
+nowarnSVCHK \
+define+SCR1_TRGT_SIMULATION \
+define+$(SIM_TRACE_DEF) \
+define+$(SIM_CFG_DEF) \
$(SIM_BUILD_OPTS) \
$(sv_list)
build_vcs: $(sv_list)
cd $(bld_dir); \
vcs \
-full64 \
-lca \
-sverilog \
-notice \
+lint=all,noVCDE,noNS,noVNGS,noSVA-DIU,noSVA-CE,noSVA-NSVU \
-timescale=1ns/1ps \
+incdir+$(rtl_inc_dir) \
+incdir+$(rtl_inc_tb_dir) \
+define+SCR1_TRGT_SIMULATION \
+define+$(SIM_TRACE_DEF) \
+define+$(SIM_CFG_DEF) \
-nc \
-debug_all \
$(SIM_BUILD_OPTS) \
$(sv_list)
build_ncsim: $(sv_list)
cd $(bld_dir); \
irun \
-elaborate \
-64bit \
-disable_sem2009 \
-verbose \
-timescale 1ns/1ps \
-incdir $(rtl_inc_dir) \
-incdir $(rtl_inc_tb_dir) \
-debug \
+define+SCR1_TRGT_SIMULATION \
+define+$(SIM_TRACE_DEF) \
+define+$(SIM_CFG_DEF) \
$(SIM_BUILD_OPTS) \
$(sv_list) \
-top $(top_module)
build_verilator: $(sv_list)
cd $(bld_dir); \
verilator \
-cc \
-sv \
+1800-2017ext+sv \
-Wno-fatal \
$(VERILATOR_5X_OPTS) \
--top-module $(top_module) \
-DSCR1_TRGT_SIMULATION \
-D$(SIM_TRACE_DEF) \
-D$(SIM_CFG_DEF) \
--clk clk \
--exe $(scr1_wrapper) \
--Mdir $(bld_dir)/verilator \
-I$(rtl_inc_dir) \
-I$(rtl_inc_tb_dir) \
$(SIM_BUILD_OPTS) \
$(sv_list); \
cd verilator; \
$(MAKE) -f V$(top_module).mk;
build_verilator_wf: $(sv_list)
cd $(bld_dir); \
verilator \
-cc \
-sv \
+1800-2017ext+sv \
-Wno-fatal \
$(VERILATOR_5X_OPTS) \
--top-module $(top_module) \
-DSCR1_TRGT_SIMULATION \
-D$(SIM_TRACE_DEF) \
-D$(SIM_CFG_DEF) \
-CFLAGS -DVCD_TRACE -CFLAGS -DTRACE_LVLV=20 \
-CFLAGS -DVCD_FNAME=simx.vcd \
--clk clk \
--exe $(scr1_wrapper) \
--trace \
--trace-params \
--trace-structs \
--trace-underscore \
--Mdir $(bld_dir)/verilator \
-I$(rtl_inc_dir) \
-I$(rtl_inc_tb_dir) \
$(SIM_BUILD_OPTS) \
$(sv_list); \
cd verilator; \
$(MAKE) -f V$(top_module).mk;

View File

@@ -0,0 +1,27 @@
src_dir := $(dir $(lastword $(MAKEFILE_LIST)))
depend_dir := $(src_dir)/../../../../dependencies/coremark
ADD_FLAGS := -flto
ADD_LDFLAGS := -flto
ifeq ("$(ITERATIONS)","")
ITERATIONS=1
endif
ADD_CFLAGS += -DITERATIONS=$(ITERATIONS)
ADD_VPATH := $(depend_dir)
ADD_incs := -I$(src_dir)/src -I$(depend_dir)
c_src := core_portme.c sc_print.c
coremark_src := ./src/core_list_join.c ./src/core_matrix.c ./src/core_main.c ./src/core_util.c ./src/core_state.c
c_src += core_list_join.c core_matrix.c core_main.c core_util.c core_state.c
include $(inc_dir)/common.mk
default: log_requested_tgt $(bld_dir)/coremark.elf $(bld_dir)/coremark.hex $(bld_dir)/coremark.dump
log_requested_tgt:
echo coremark.hex>> $(bld_dir)/test_info
clean:
$(RM) $(c_objs) $(asm_objs) $(bld_dir)/coremark.hex $(bld_dir)/coremark.dump

View File

@@ -0,0 +1,141 @@
/*
File : core_portme.c
*/
/*
Author : Shay Gal-On, EEMBC
Legal : TODO!
*/
#include <stdio.h>
#include <stdlib.h>
#include "coremark.h"
#include "core_portme.h"
#include "riscv_csr_encoding.h"
#include "sc_test.h"
#if VALIDATION_RUN
volatile ee_s32 seed1_volatile=0x3415;
volatile ee_s32 seed2_volatile=0x3415;
volatile ee_s32 seed3_volatile=0x66;
#endif
#if PERFORMANCE_RUN
volatile ee_s32 seed1_volatile=0x0;
volatile ee_s32 seed2_volatile=0x0;
volatile ee_s32 seed3_volatile=0x66;
#endif
#if PROFILE_RUN
volatile ee_s32 seed1_volatile=0x8;
volatile ee_s32 seed2_volatile=0x8;
volatile ee_s32 seed3_volatile=0x8;
#endif
volatile ee_s32 seed4_volatile=ITERATIONS;
volatile ee_s32 seed5_volatile=0;
/* Porting : Timing functions
How to capture time and convert to seconds must be ported to whatever is supported by the platform.
e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc.
Sample implementation for standard time.h and windows.h definitions included.
*/
#if 1
CORETIMETYPE barebones_clock() {
unsigned long n;
__asm__ __volatile__ (
"rdtime %0"
: "=r" (n));
return n;
}
#define CLOCKS_PER_SEC 10000000
/* Define : TIMER_RES_DIVIDER
Divider to trade off timer resolution and total time that can be measured.
Use lower values to increase resolution, but make sure that overflow does not occur.
If there are issues with the return value overflowing, increase this value.
*/
/* #define NSECS_PER_SEC CLOCKS_PER_SEC */
/* #define CORETIMETYPE clock_t */
#define GETMYTIME(_t) (*_t=barebones_clock())
#define MYTIMEDIFF(fin,ini) ((fin)-(ini))
#define TIMER_RES_DIVIDER 1
#define SAMPLE_TIME_IMPLEMENTATION 1
#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER)
#else
#endif
/** Define Host specific (POSIX), or target specific global time variables. */
static CORETIMETYPE start_time_val, stop_time_val;
/* Function : start_time
This function will be called right before starting the timed portion of the benchmark.
Implementation may be capturing a system timer (as implemented in the example code)
or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0.
*/
void start_time(void) {
GETMYTIME(&start_time_val );
}
/* Function : stop_time
This function will be called right after ending the timed portion of the benchmark.
Implementation may be capturing a system timer (as implemented in the example code)
or other system parameters - e.g. reading the current value of cpu cycles counter.
*/
void stop_time(void) {
GETMYTIME(&stop_time_val );
}
/* Function : get_time
Return an abstract "ticks" number that signifies time on the system.
Actual value returned may be cpu cycles, milliseconds or any other value,
as long as it can be converted to seconds by <time_in_secs>.
This methodology is taken to accomodate any hardware or simulated platform.
The sample implementation returns millisecs by default,
and the resolution is controlled by <TIMER_RES_DIVIDER>
*/
CORE_TICKS get_time(void) {
CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val));
return elapsed;
}
/* Function : time_in_secs
Convert the value returned by get_time to seconds.
The <secs_ret> type is used to accomodate systems with no support for floating point.
Default implementation implemented by the EE_TICKS_PER_SEC macro above.
*/
secs_ret time_in_secs(CORE_TICKS ticks) {
secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC;
return retval;
}
ee_u32 default_num_contexts=1;
/* Function : portable_init
Target specific initialization code
Test for some common mistakes.
*/
void portable_init(core_portable *p, int *argc, char *argv[])
{
ee_printf("CoreMark 1.0\n");
if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) {
ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer! (%u != %u)\n", sizeof(ee_ptr_int), sizeof(ee_u8 *));
}
if (sizeof(ee_u32) != 4) {
ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type! (%u)\n", sizeof(ee_u32));
}
p->portable_id=1;
}
/* Function : portable_fini
Target specific final code
*/
void portable_fini(core_portable *p)
{
p->portable_id=0;
report_results(0, 0, 0, 0, 0);
/* results[0].iterations * 10000000/(total_time) */
/* extern void tohost_exit(long code); */
/* tohost_exit(0); */
}

View File

@@ -0,0 +1,210 @@
/* File : core_portme.h */
/*
Author : Shay Gal-On, EEMBC
Legal : TODO!
*/
/* Topic : Description
This file contains configuration constants required to execute on different platforms
*/
#ifndef CORE_PORTME_H
#define CORE_PORTME_H
/************************/
/* Data types and settings */
/************************/
/* Configuration : HAS_FLOAT
Define to 1 if the platform supports floating point.
*/
#ifndef HAS_FLOAT
#define HAS_FLOAT 0
#endif
/* Configuration : HAS_TIME_H
Define to 1 if platform has the time.h header file,
and implementation of functions thereof.
*/
#ifndef HAS_TIME_H
#define HAS_TIME_H 0
#endif
/* Configuration : USE_CLOCK
Define to 1 if platform has the time.h header file,
and implementation of functions thereof.
*/
#ifndef USE_CLOCK
#define USE_CLOCK 0
#endif
/* Configuration : HAS_STDIO
Define to 1 if the platform has stdio.h.
*/
#ifndef HAS_STDIO
#define HAS_STDIO 1
#endif
/* Configuration : HAS_PRINTF
Define to 1 if the platform has stdio.h and implements the printf function.
*/
#ifndef HAS_PRINTF
#define HAS_PRINTF 0
#endif
#include "sc_print.h"
#define ee_printf sc_printf
/* static inline int ee_printf(const char *fmt, ...) {} */
/* Configuration : CORE_TICKS
Define type of return from the timing functions.
*/
/* #include <time.h> */
/* typedef clock_t CORE_TICKS; */
#include <stdint.h>
#include <stddef.h>
#define CORETIMETYPE uint32_t
typedef uint32_t CORE_TICKS;
/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION
Initialize these strings per platform
*/
#ifndef COMPILER_VERSION
#ifdef __GNUC__
#define COMPILER_VERSION "GCC"__VERSION__
#else
#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)"
#endif
#endif
#ifndef COMPILER_FLAGS
#define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */
#endif
#ifndef MEM_LOCATION
/* #define MEM_LOCATION "STACK" */
#define MEM_LOCATION "STATIC"
#endif
/* Data Types :
To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in <core_portme.h>.
*Imprtant* :
ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!!
*/
typedef int16_t ee_s16;
typedef uint16_t ee_u16;
typedef int32_t ee_s32;
typedef float ee_f32;
typedef uint8_t ee_u8;
typedef uint32_t ee_u32;
typedef uintptr_t ee_ptr_int;
typedef size_t ee_size_t;
/* align_mem :
This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks.
*/
#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3))
/* Configuration : SEED_METHOD
Defines method to get seed values that cannot be computed at compile time.
Valid values :
SEED_ARG - from command line.
SEED_FUNC - from a system function.
SEED_VOLATILE - from volatile variables.
*/
#ifndef SEED_METHOD
#define SEED_METHOD SEED_VOLATILE
#endif
/* Configuration : MEM_METHOD
Defines method to get a block of memry.
Valid values :
MEM_MALLOC - for platforms that implement malloc and have malloc.h.
MEM_STATIC - to use a static memory array.
MEM_STACK - to allocate the data block on the stack (NYI).
*/
#ifndef MEM_METHOD
/* #define MEM_METHOD MEM_STACK */
#define MEM_METHOD MEM_STATIC
#endif
/* Configuration : MULTITHREAD
Define for parallel execution
Valid values :
1 - only one context (default).
N>1 - will execute N copies in parallel.
Note :
If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined.
Two sample implementations are provided. Use <USE_PTHREAD> or <USE_FORK> to enable them.
It is valid to have a different implementation of <core_start_parallel> and <core_end_parallel> in <core_portme.c>,
to fit a particular architecture.
*/
#ifndef MULTITHREAD
#define MULTITHREAD 1
#define USE_PTHREAD 0
#define USE_FORK 0
#define USE_SOCKET 0
#endif
/* Configuration : MAIN_HAS_NOARGC
Needed if platform does not support getting arguments to main.
Valid values :
0 - argc/argv to main is supported
1 - argc/argv to main is not supported
Note :
This flag only matters if MULTITHREAD has been defined to a value greater then 1.
*/
#ifndef MAIN_HAS_NOARGC
#define MAIN_HAS_NOARGC 1
#endif
/* Configuration : MAIN_HAS_NORETURN
Needed if platform does not support returning a value from main.
Valid values :
0 - main returns an int, and return value will be 0.
1 - platform does not support returning a value from main
*/
#ifndef MAIN_HAS_NORETURN
#define MAIN_HAS_NORETURN 0
#endif
/* Variable : default_num_contexts
Not used for this simple port, must cintain the value 1.
*/
extern ee_u32 default_num_contexts;
typedef struct CORE_PORTABLE_S {
ee_u8 portable_id;
} core_portable;
/* target specific init/fini */
void portable_init(core_portable *p, int *argc, char *argv[]);
void portable_fini(core_portable *p);
#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN)
#if (TOTAL_DATA_SIZE==1200)
#define PROFILE_RUN 1
#elif (TOTAL_DATA_SIZE==2000)
#define PERFORMANCE_RUN 1
#else
#define VALIDATION_RUN 1
#endif
#endif
typedef ee_s16 MATDAT;
typedef ee_s32 MATRES;
ee_u16 crcu8(ee_u8 data, ee_u16 crc ) __attribute__ ((hot));
ee_u16 crcu16(ee_u16 newval, ee_u16 crc) __attribute__ ((hot));
ee_u16 crcu32(ee_u32 newval, ee_u16 crc) __attribute__ ((hot));
ee_u16 crc16(ee_s16 newval, ee_u16 crc) __attribute__ ((hot));
ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) __attribute__ ((hot));
void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) __attribute__ ((hot));
void matrix_mul_vect(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) __attribute__ ((hot));
void matrix_mul_matrix(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) __attribute__ ((hot));
void matrix_mul_matrix_bitextract(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B) __attribute__ ((hot));
void matrix_add_const(ee_u32 N, MATDAT *A, MATDAT val) __attribute__ ((hot));
#endif /* CORE_PORTME_H */

View File

@@ -0,0 +1,17 @@
src_dir := $(dir $(lastword $(MAKEFILE_LIST)))
ADD_FLAGS := -flto
ADD_LDFLAGS := -flto
ADD_CFLAGS := -DSELF_TIMED=1 -DTIME=1
c_src := sc_print.c dhry_1.c dhry_2.c
include $(inc_dir)/common.mk
default: log_requested_tgt $(bld_dir)/dhrystone21.elf $(bld_dir)/dhrystone21.hex $(bld_dir)/dhrystone21.dump
log_requested_tgt:
@echo dhrystone21.hex>> $(bld_dir)/test_info
clean:
$(RM) $(c_objs) $(asm_objs) $(bld_dir)/dhrystone21.elf $(bld_dir)/dhrystone21.hex $(bld_dir)/dhrystone21.dump

View File

@@ -0,0 +1,446 @@
/*****************************************************************************
* The BYTE UNIX Benchmarks - Release 3
* Module: dhry.h SID: 3.4 5/15/91 19:30:21
*
*****************************************************************************
* Bug reports, patches, comments, suggestions should be sent to:
*
* Ben Smith, Rick Grehan or Tom Yager
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
*
*****************************************************************************
* Modification Log:
* addapted from:
*
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry.h (part 1 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
* Siemens AG, AUT E 51
* Postfach 3220
* 8520 Erlangen
* Germany (West)
* Phone: [+49]-9131-7-20330
* (8-17 Central European Time)
* Usenet: ..!mcvax!unido!estevax!weicker
*
* Original Version (in Ada) published in
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
* pp. 1013 - 1030, together with the statistics
* on which the distribution of statements etc. is based.
*
* In this C version, the following C library functions are used:
* - strcpy, strcmp (inside the measurement loop)
* - printf, scanf (outside the measurement loop)
* In addition, Berkeley UNIX system calls "times ()" or "time ()"
* are used for execution time measurement. For measurements
* on other systems, these calls have to be changed.
*
* Collection of Results:
* Reinhold Weicker (address see above) and
*
* Rick Richardson
* PC Research. Inc.
* 94 Apple Orchard Drive
* Tinton Falls, NJ 07724
* Phone: (201) 834-1378 (9-17 EST)
* Usenet: ...!seismo!uunet!pcrat!rick
*
* Please send results to Rick Richardson and/or Reinhold Weicker.
* Complete information should be given on hardware and software used.
* Hardware information includes: Machine type, CPU, type and size
* of caches; for microprocessors: clock frequency, memory speed
* (number of wait states).
* Software information includes: Compiler (and runtime library)
* manufacturer and version, compilation switches, OS version.
* The Operating System version may give an indication about the
* compiler; Dhrystone itself performs no OS calls in the measurement loop.
*
* The complete output generated by the program should be mailed
* such that at least some checks for correctness can be made.
*
***************************************************************************
*
* History: This version C/2.1 has been made for two reasons:
*
* 1) There is an obvious need for a common C version of
* Dhrystone, since C is at present the most popular system
* programming language for the class of processors
* (microcomputers, minicomputers) where Dhrystone is used most.
* There should be, as far as possible, only one C version of
* Dhrystone such that results can be compared without
* restrictions. In the past, the C versions distributed
* by Rick Richardson (Version 1.1) and by Reinhold Weicker
* had small (though not significant) differences.
*
* 2) As far as it is possible without changes to the Dhrystone
* statistics, optimizing compilers should be prevented from
* removing significant statements.
*
* This C version has been developed in cooperation with
* Rick Richardson (Tinton Falls, NJ), it incorporates many
* ideas from the "Version 1.1" distributed previously by
* him over the UNIX network Usenet.
* I also thank Chaim Benedelac (National Semiconductor),
* David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
* for their help with comments on earlier versions of the
* benchmark.
*
* Changes: In the initialization part, this version follows mostly
* Rick Richardson's version distributed via Usenet, not the
* version distributed earlier via floppy disk by Reinhold Weicker.
* As a concession to older compilers, names have been made
* unique within the first 8 characters.
* Inside the measurement loop, this version follows the
* version previously distributed by Reinhold Weicker.
*
* At several places in the benchmark, code has been added,
* but within the measurement loop only in branches that
* are not executed. The intention is that optimizing compilers
* should be prevented from moving code out of the measurement
* loop, or from removing code altogether. Since the statements
* that are executed within the measurement loop have NOT been
* changed, the numbers defining the "Dhrystone distribution"
* (distribution of statements, operand types and locality)
* still hold. Except for sophisticated optimizing compilers,
* execution times for this version should be the same as
* for previous versions.
*
* Since it has proven difficult to subtract the time for the
* measurement loop overhead in a correct way, the loop check
* has been made a part of the benchmark. This does have
* an impact - though a very minor one - on the distribution
* statistics which have been updated for this version.
*
* All changes within the measurement loop are described
* and discussed in the companion paper "Rationale for
* Dhrystone version 2".
*
* Because of the self-imposed limitation that the order and
* distribution of the executed statements should not be
* changed, there are still cases where optimizing compilers
* may not generate code for some statements. To a certain
* degree, this is unavoidable for small synthetic benchmarks.
* Users of the benchmark are advised to check code listings
* whether code is generated for all statements of Dhrystone.
*
* Version 2.1 is identical to version 2.0 distributed via
* the UNIX network Usenet in March 1988 except that it corrects
* some minor deficiencies that were found by users of version 2.0.
* The only change within the measurement loop is that a
* non-executed "else" part was added to the "if" statement in
* Func_3, and a non-executed "else" part removed from Proc_3.
*
***************************************************************************
*
* Defines: The following "Defines" are possible:
* -DREG=register (default: Not defined)
* As an approximation to what an average C programmer
* might do, the "register" storage class is applied
* (if enabled by -DREG=register)
* - for local variables, if they are used (dynamically)
* five or more times
* - for parameters if they are used (dynamically)
* six or more times
* Note that an optimal "register" strategy is
* compiler-dependent, and that "register" declarations
* do not necessarily lead to faster execution.
* -DNOSTRUCTASSIGN (default: Not defined)
* Define if the C compiler does not support
* assignment of structures.
* -DNOENUMS (default: Not defined)
* Define if the C compiler does not support
* enumeration types.
* -DTIMES (default)
* -DTIME
* The "times" function of UNIX (returning process times)
* or the "time" function (returning wallclock time)
* is used for measurement.
* For single user machines, "time ()" is adequate. For
* multi-user machines where you cannot get single-user
* access, use the "times ()" function. If you have
* neither, use a stopwatch in the dead of night.
* "printf"s are provided marking the points "Start Timer"
* and "Stop Timer". DO NOT use the UNIX "time(1)"
* command, as this will measure the total time to
* run this program, which will (erroneously) include
* the time to allocate storage (malloc) and to perform
* the initialization.
* -DHZ=nnn
* In Berkeley UNIX, the function "times" returns process
* time in 1/HZ seconds, with HZ = 60 for most systems.
* CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
* A VALUE.
*
***************************************************************************
*
* Compilation model and measurement (IMPORTANT):
*
* This C version of Dhrystone consists of three files:
* - dhry.h (this file, containing global definitions and comments)
* - dhry_1.c (containing the code corresponding to Ada package Pack_1)
* - dhry_2.c (containing the code corresponding to Ada package Pack_2)
*
* The following "ground rules" apply for measurements:
* - Separate compilation
* - No procedure merging
* - Otherwise, compiler optimizations are allowed but should be indicated
* - Default results are those without register declarations
* See the companion paper "Rationale for Dhrystone Version 2" for a more
* detailed discussion of these ground rules.
*
* For 16-Bit processors (e.g. 80186, 80286), times for all compilation
* models ("small", "medium", "large" etc.) should be given if possible,
* together with a definition of these models for the compiler system used.
*
**************************************************************************
*
* Dhrystone (C version) statistics:
*
* [Comment from the first distribution, updated for version 2.
* Note that because of language differences, the numbers are slightly
* different from the Ada version.]
*
* The following program contains statements of a high level programming
* language (here: C) in a distribution considered representative:
*
* assignments 52 (51.0 %)
* control statements 33 (32.4 %)
* procedure, function calls 17 (16.7 %)
*
* 103 statements are dynamically executed. The program is balanced with
* respect to the three aspects:
*
* - statement type
* - operand type
* - operand locality
* operand global, local, parameter, or constant.
*
* The combination of these three aspects is balanced only approximately.
*
* 1. Statement Type:
* ----------------- number
*
* V1 = V2 9
* (incl. V1 = F(..)
* V = Constant 12
* Assignment, 7
* with array element
* Assignment, 6
* with record component
* --
* 34 34
*
* X = Y +|-|"&&"|"|" Z 5
* X = Y +|-|"==" Constant 6
* X = X +|- 1 3
* X = Y *|/ Z 2
* X = Expression, 1
* two operators
* X = Expression, 1
* three operators
* --
* 18 18
*
* if .... 14
* with "else" 7
* without "else" 7
* executed 3
* not executed 4
* for ... 7 | counted every time
* while ... 4 | the loop condition
* do ... while 1 | is evaluated
* switch ... 1
* break 1
* declaration with 1
* initialization
* --
* 34 34
*
* P (...) procedure call 11
* user procedure 10
* library procedure 1
* X = F (...)
* function call 6
* user function 5
* library function 1
* --
* 17 17
* ---
* 103
*
* The average number of parameters in procedure or function calls
* is 1.82 (not counting the function values as implicit parameters).
*
*
* 2. Operators
* ------------
* number approximate
* percentage
*
* Arithmetic 32 50.8
*
* + 21 33.3
* - 7 11.1
* * 3 4.8
* / (int div) 1 1.6
*
* Comparison 27 42.8
*
* == 9 14.3
* /= 4 6.3
* > 1 1.6
* < 3 4.8
* >= 1 1.6
* <= 9 14.3
*
* Logic 4 6.3
*
* && (AND-THEN) 1 1.6
* | (OR) 1 1.6
* ! (NOT) 2 3.2
*
* -- -----
* 63 100.1
*
*
* 3. Operand Type (counted once per operand reference):
* ---------------
* number approximate
* percentage
*
* Integer 175 72.3 %
* Character 45 18.6 %
* Pointer 12 5.0 %
* String30 6 2.5 %
* Array 2 0.8 %
* Record 2 0.8 %
* --- -------
* 242 100.0 %
*
* When there is an access path leading to the final operand (e.g. a record
* component), only the final data type on the access path is counted.
*
*
* 4. Operand Locality:
* -------------------
* number approximate
* percentage
*
* local variable 114 47.1 %
* global variable 22 9.1 %
* parameter 45 18.6 %
* value 23 9.5 %
* reference 22 9.1 %
* function result 6 2.5 %
* constant 55 22.7 %
* --- -------
* 242 100.0 %
*
*
* The program does not compute anything meaningful, but it is syntactically
* and semantically correct. All variables have a value assigned to them
* before they are used as a source operand.
*
* There has been no explicit effort to account for the effects of a
* cache, or to balance the use of long or short displacements for code or
* data.
*
***************************************************************************
*/
/* Compiler and system dependent definitions: */
#ifndef TIME
#define TIMES
#endif
/* Use times(2) time function unless */
/* explicitly defined otherwise */
#ifdef TIMES
#include <sys/types.h>
#include <sys/times.h>
/* for "times" */
#endif
#define Mic_secs_Per_Second 1000000
/* Berkeley UNIX C returns process times in seconds/HZ */
#ifdef NOSTRUCTASSIGN
#define structassign(d, s) memcpy(&(d), &(s), sizeof(d))
#else
#define structassign(d, s) d = s
#endif
#ifdef NOENUM
#define Ident_1 0
#define Ident_2 1
#define Ident_3 2
#define Ident_4 3
#define Ident_5 4
typedef int Enumeration;
#else
typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
Enumeration;
#endif
/* for boolean and enumeration types in Ada, Pascal */
/* General definitions: */
#include <stdio.h>
#include <string.h>
/* for strcpy, strcmp */
#define Null 0
/* Value of a Null pointer */
#define true 1
#define false 0
typedef int One_Thirty;
typedef int One_Fifty;
typedef char Capital_Letter;
typedef int Boolean;
typedef char Str_30 [31];
typedef int Arr_1_Dim [50];
typedef int Arr_2_Dim [50] [50];
typedef struct record
{
struct record *Ptr_Comp;
Enumeration Discr;
union {
struct {
Enumeration Enum_Comp;
int Int_Comp;
char Str_Comp [31];
} var_1;
struct {
Enumeration E_Comp_2;
char Str_2_Comp [31];
} var_2;
struct {
char Ch_1_Comp;
char Ch_2_Comp;
} var_3;
} variant;
} Rec_Type, *Rec_Pointer;
#include "sc_print.h"
#include "csr.h"
# define printf sc_printf
#define HZ 1000000
static long time(long *x)
{
return rdcycle();
}

View File

@@ -0,0 +1,461 @@
/*****************************************************************************
* The BYTE UNIX Benchmarks - Release 3
* Module: dhry_1.c SID: 3.4 5/15/91 19:30:21
*
*****************************************************************************
* Bug reports, patches, comments, suggestions should be sent to:
*
* Ben Smith, Rick Grehan or Tom Yager
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
*
*****************************************************************************
*
* *** WARNING **** With BYTE's modifications applied, results obtained with
* ******* this version of the Dhrystone program may not be applicable
* to other versions.
*
* Modification Log:
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
* Andy Kahn <kahn@zk3.dec.com>
*
* Adapted from:
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* Version: C, Version 2.1
*
* File: dhry_1.c (part 2 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
***************************************************************************/
char SCCSid[] = "@(#) @(#)dhry_1.c:3.4 -- 5/15/91 19:30:21";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dhry.h"
//#include "timeit.c"
unsigned long Run_Index;
/*
void report()
{
fprintf(stderr,"COUNT|%ld|1|lps\n", Run_Index);
exit(0);
}
*/
/* Global Variables: */
Rec_Pointer Ptr_Glob,
Next_Ptr_Glob;
int Int_Glob;
Boolean Bool_Glob;
char Ch_1_Glob,
Ch_2_Glob;
int Arr_1_Glob [50];
int Arr_2_Glob [50] [50];
Enumeration Func_1 ();
/* forward declaration necessary since Enumeration may not simply be int */
#ifndef REG
Boolean Reg = false;
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#else
Boolean Reg = true;
#endif
/* variables for time measurement: */
#ifdef TIMES
struct tms time_info;
/* extern int times (); */
/* see library function "times" */
#define Too_Small_Time 120
/* Measurements should last at least about 2 seconds */
#endif
#ifdef TIME
extern long time();
/* see library function "time" */
#define Too_Small_Time 2
/* Measurements should last at least 2 seconds */
#endif
long Begin_Time,
End_Time,
User_Time;
#if 0
float Microseconds,
Dhrystones_Per_Second;
#else
long Microseconds,
Dhrystones_Per_Second;
#endif
/* end of variables for time measurement */
void Proc_1 (REG Rec_Pointer Ptr_Val_Par);
void Proc_2 (One_Fifty *Int_Par_Ref);
void Proc_3 (Rec_Pointer *Ptr_Ref_Par);
void Proc_4 (void);
void Proc_5 (void);
extern Boolean Func_2(Str_30, Str_30);
extern void Proc_6(Enumeration, Enumeration *);
extern void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
extern void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
int main (argc, argv)
int argc;
char *argv[];
/* main program, corresponds to procedures */
/* Main and Proc_0 in the Ada version */
{
#ifdef SELF_TIMED
int Number_Of_Runs;
#else /* SELF_TIMED */
int duration;
#endif /* SELF_TIMED */
One_Fifty Int_1_Loc;
REG One_Fifty Int_2_Loc;
One_Fifty Int_3_Loc;
REG char Ch_Index;
Enumeration Enum_Loc;
Str_30 Str_1_Loc;
Str_30 Str_2_Loc;
/* Initializations */
#if 0
Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
#else
static Rec_Type glob1, glob2;
Next_Ptr_Glob = &glob1;
Ptr_Glob = &glob2;
#endif
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
Ptr_Glob->Discr = Ident_1;
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
Ptr_Glob->variant.var_1.Int_Comp = 40;
strcpy (Ptr_Glob->variant.var_1.Str_Comp,
"DHRYSTONE PROGRAM, SOME STRING");
strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
Arr_2_Glob [8][7] = 10;
/* Was missing in published program. Without this statement, */
/* Arr_2_Glob [8][7] would have an undefined value. */
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
/* overflow may occur for this array element. */
#ifdef SELF_TIMED
Number_Of_Runs = 500;//500000;
if (argc >= 2) {
Number_Of_Runs = atoi(argv[1]);
}
printf ("\n");
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
printf ("\n");
if (Reg)
{
printf ("Program compiled with 'register' attribute\n");
printf ("\n");
}
else
{
printf ("Program compiled without 'register' attribute\n");
printf ("\n");
}
#ifdef PRATTLE
printf ("Please give the number of runs through the benchmark: ");
{
int n;
scanf ("%d", &n);
Number_Of_Runs = n;
}
printf ("\n");
#endif /* PRATTLE */
printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
Run_Index = 0;
#else /* SELF_TIMED */
if (argc != 2) {
fprintf(stderr, "Usage: %s duration\n", argv[0]);
exit(1);
}
duration = atoi(argv[1]);
Run_Index = 0;
wake_me(duration, report);
#endif /* SELF_TIMED */
/***************/
/* Start timer */
/***************/
#ifdef SELF_TIMED
#ifdef TIMES
times (&time_info);
Begin_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
Begin_Time = time ( (long *) 0);
#endif
#endif /* SELF_TIMED */
#ifdef SELF_TIMED
for (Run_Index = 1; Run_Index <= Number_Of_Runs ; ++Run_Index)
#else /* SELF_TIMED */
for (Run_Index = 1; ; ++Run_Index)
#endif /* SELF_TIMED */
{
Proc_5();
Proc_4();
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
Int_1_Loc = 2;
Int_2_Loc = 3;
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
Enum_Loc = Ident_2;
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
/* Bool_Glob == 1 */
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
{
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
/* Int_3_Loc == 7 */
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
/* Int_3_Loc == 7 */
Int_1_Loc += 1;
} /* while */
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
/* Int_Glob == 5 */
Proc_1 (Ptr_Glob);
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
/* loop body executed twice */
{
if (Enum_Loc == Func_1 (Ch_Index, 'C'))
/* then, not executed */
{
Proc_6 (Ident_1, &Enum_Loc);
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
Int_2_Loc = Run_Index;
Int_Glob = Run_Index;
}
}
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
Int_2_Loc = Int_2_Loc * Int_1_Loc;
Int_1_Loc = Int_2_Loc / Int_3_Loc;
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
Proc_2 (&Int_1_Loc);
/* Int_1_Loc == 5 */
} /* loop "for Run_Index" */
/**************/
/* Stop timer */
/**************/
#ifdef SELF_TIMED
#ifdef TIMES
times (&time_info);
End_Time = (long) time_info.tms_utime;
#endif
#ifdef TIME
End_Time = time ( (long *) 0);
#endif
#endif /* SELF_TIMED */
/* BYTE version never executes this stuff */
#ifdef SELF_TIMED
printf ("Execution ends\n");
printf ("\n");
printf ("Final values of the variables used in the benchmark:\n");
printf ("\n");
printf ("Int_Glob: %d\n", Int_Glob);
printf (" should be: %d\n", 5);
printf ("Bool_Glob: %d\n", Bool_Glob);
printf (" should be: %d\n", 1);
printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
printf (" should be: %c\n", 'A');
printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
printf (" should be: %c\n", 'B');
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
printf (" should be: %d\n", 7);
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
printf (" should be: Number_Of_Runs + 10\n");
printf ("Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent)\n");
printf (" Discr: %d\n", Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 2);
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 17);
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Next_Ptr_Glob->\n");
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
printf (" should be: (implementation-dependent), same as above\n");
printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
printf (" should be: %d\n", 0);
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
printf (" should be: %d\n", 1);
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
printf (" should be: %d\n", 18);
printf (" Str_Comp: %s\n",
Next_Ptr_Glob->variant.var_1.Str_Comp);
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
printf ("Int_1_Loc: %d\n", Int_1_Loc);
printf (" should be: %d\n", 5);
printf ("Int_2_Loc: %d\n", Int_2_Loc);
printf (" should be: %d\n", 13);
printf ("Int_3_Loc: %d\n", Int_3_Loc);
printf (" should be: %d\n", 7);
printf ("Enum_Loc: %d\n", Enum_Loc);
printf (" should be: %d\n", 1);
printf ("Str_1_Loc: %s\n", Str_1_Loc);
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
printf ("Str_2_Loc: %s\n", Str_2_Loc);
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
printf ("\n");
User_Time = End_Time - Begin_Time;
if (User_Time < Too_Small_Time)
{
printf ("Measured time too small to obtain meaningful results\n");
printf ("Please increase number of runs\n");
printf ("\n");
}
else
{
#if 0
#ifdef TIME
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ (float) Number_Of_Runs;
Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
#else
Microseconds = (float) User_Time * Mic_secs_Per_Second
/ ((float) HZ * ((float) Number_Of_Runs));
Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
/ (float) User_Time;
#endif
#else
Microseconds = ((User_Time / Number_Of_Runs) * Mic_secs_Per_Second) / HZ;
Dhrystones_Per_Second = (HZ * Number_Of_Runs) / User_Time;
sc_printf("Number_Of_Runs= %ld, HZ= %ld\n", Number_Of_Runs, HZ);
sc_printf("Time: begin= %ld, end= %ld, diff= %ld\n", Begin_Time, End_Time, User_Time);
sc_printf("Microseconds for one run through Dhrystone: %ld\n", Microseconds);
sc_printf("Dhrystones per Second: %ld\n", Dhrystones_Per_Second);
#endif
}
#endif /* SELF_TIMED */
}
void Proc_1 (REG Rec_Pointer Ptr_Val_Par)
/* executed once */
{
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
/* == Ptr_Glob_Next */
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
/* corresponds to "rename" in Ada, "with" in Pascal */
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
Next_Record->variant.var_1.Int_Comp
= Ptr_Val_Par->variant.var_1.Int_Comp;
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
Proc_3 (&Next_Record->Ptr_Comp);
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
== Ptr_Glob->Ptr_Comp */
if (Next_Record->Discr == Ident_1)
/* then, executed */
{
Next_Record->variant.var_1.Int_Comp = 6;
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
&Next_Record->variant.var_1.Enum_Comp);
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
&Next_Record->variant.var_1.Int_Comp);
}
else /* not executed */
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
} /* Proc_1 */
void Proc_2 (One_Fifty *Int_Par_Ref)
/* executed once */
/* *Int_Par_Ref == 1, becomes 4 */
{
One_Fifty Int_Loc;
Enumeration Enum_Loc;
Enum_Loc = 0;
Int_Loc = *Int_Par_Ref + 10;
do /* executed once */
if (Ch_1_Glob == 'A')
/* then, executed */
{
Int_Loc -= 1;
*Int_Par_Ref = Int_Loc - Int_Glob;
Enum_Loc = Ident_1;
} /* if */
while (Enum_Loc != Ident_1); /* true */
} /* Proc_2 */
void Proc_3 (Rec_Pointer *Ptr_Ref_Par)
/* executed once */
/* Ptr_Ref_Par becomes Ptr_Glob */
{
if (Ptr_Glob != Null)
/* then, executed */
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
} /* Proc_3 */
void Proc_4 (void) /* without parameters */
/* executed once */
{
Boolean Bool_Loc;
Bool_Loc = Ch_1_Glob == 'A';
Bool_Glob = Bool_Loc | Bool_Glob;
Ch_2_Glob = 'B';
} /* Proc_4 */
void Proc_5 (void) /* without parameters */
/*******/
/* executed once */
{
Ch_1_Glob = 'A';
Bool_Glob = false;
} /* Proc_5 */
/* Procedure for the assignment of structures, */
/* if the C compiler doesn't support this feature */
#ifdef NOSTRUCTASSIGN
memcpy (d, s, l)
register char *d;
register char *s;
register int l;
{
while (l--) *d++ = *s++;
}
#endif

View File

@@ -0,0 +1,209 @@
/*****************************************************************************
* The BYTE UNIX Benchmarks - Release 3
* Module: dhry_2.c SID: 3.4 5/15/91 19:30:22
*
*****************************************************************************
* Bug reports, patches, comments, suggestions should be sent to:
*
* Ben Smith, Rick Grehan or Tom Yager
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
*
*****************************************************************************
* Modification Log:
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
* Andy Kahn <kahn@zk3.dec.com>
*
* Adapted from:
*
* "DHRYSTONE" Benchmark Program
* -----------------------------
*
* **** WARNING **** See warning in n.dhry_1.c
*
* Version: C, Version 2.1
*
* File: dhry_2.c (part 3 of 3)
*
* Date: May 25, 1988
*
* Author: Reinhold P. Weicker
*
****************************************************************************/
/* SCCSid is defined in dhry_1.c */
#include <string.h>
#include "dhry.h"
#ifndef REG
#define REG
/* REG becomes defined as empty */
/* i.e. no register variables */
#endif
extern int Int_Glob;
extern char Ch_1_Glob;
void Proc_6(Enumeration, Enumeration *);
void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
Enumeration Func_1(Capital_Letter, Capital_Letter);
Boolean Func_2(Str_30, Str_30);
Boolean Func_3(Enumeration);
void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
/* executed once */
/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
{
*Enum_Ref_Par = Enum_Val_Par;
if (! Func_3 (Enum_Val_Par))
/* then, not executed */
*Enum_Ref_Par = Ident_4;
switch (Enum_Val_Par)
{
case Ident_1:
*Enum_Ref_Par = Ident_1;
break;
case Ident_2:
if (Int_Glob > 100)
/* then */
*Enum_Ref_Par = Ident_1;
else *Enum_Ref_Par = Ident_4;
break;
case Ident_3: /* executed */
*Enum_Ref_Par = Ident_2;
break;
case Ident_4: break;
case Ident_5:
*Enum_Ref_Par = Ident_3;
break;
} /* switch */
} /* Proc_6 */
void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
One_Fifty Int_1_Par_Val;
One_Fifty Int_2_Par_Val;
One_Fifty *Int_Par_Ref;
/**********************************************/
/* executed three times */
/* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
/* Int_Par_Ref becomes 7 */
/* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
/* Int_Par_Ref becomes 17 */
/* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
/* Int_Par_Ref becomes 18 */
{
One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 2;
*Int_Par_Ref = Int_2_Par_Val + Int_Loc;
} /* Proc_7 */
void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
/*********************************************************************/
/* executed once */
/* Int_Par_Val_1 == 3 */
/* Int_Par_Val_2 == 7 */
Arr_1_Dim Arr_1_Par_Ref;
Arr_2_Dim Arr_2_Par_Ref;
int Int_1_Par_Val;
int Int_2_Par_Val;
{
REG One_Fifty Int_Index;
REG One_Fifty Int_Loc;
Int_Loc = Int_1_Par_Val + 5;
Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
Int_Glob = 5;
} /* Proc_8 */
Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
/*************************************************/
/* executed three times */
/* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
/* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
/* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
{
Capital_Letter Ch_1_Loc;
Capital_Letter Ch_2_Loc;
Ch_1_Loc = Ch_1_Par_Val;
Ch_2_Loc = Ch_1_Loc;
if (Ch_2_Loc != Ch_2_Par_Val)
/* then, executed */
return (Ident_1);
else /* not executed */
{
Ch_1_Glob = Ch_1_Loc;
return (Ident_2);
}
} /* Func_1 */
Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
/*************************************************/
/* executed once */
/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
Str_30 Str_1_Par_Ref;
Str_30 Str_2_Par_Ref;
{
REG One_Thirty Int_Loc;
Capital_Letter Ch_Loc;
Ch_Loc = 'A';
Int_Loc = 2;
while (Int_Loc <= 2) /* loop body executed once */
if (Func_1 (Str_1_Par_Ref[Int_Loc],
Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
/* then, executed */
{
Ch_Loc = 'A';
Int_Loc += 1;
} /* if, while */
if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
/* then, not executed */
Int_Loc = 7;
if (Ch_Loc == 'R')
/* then, not executed */
return (true);
else /* executed */
{
if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
/* then, not executed */
{
Int_Loc += 7;
Int_Glob = Int_Loc;
return (true);
}
else /* executed */
return (false);
} /* if Ch_Loc */
} /* Func_2 */
Boolean Func_3 (Enum_Par_Val)
/***************************/
/* executed once */
/* Enum_Par_Val == Ident_3 */
Enumeration Enum_Par_Val;
{
Enumeration Enum_Loc;
Enum_Loc = Enum_Par_Val;
if (Enum_Loc == Ident_3)
/* then, executed */
return (true);
else /* not executed */
return (false);
} /* Func_3 */

24
sim/tests/common/LICENSE Normal file
View File

@@ -0,0 +1,24 @@
Copyright (c) 2012-2015, The Regents of the University of California (Regents).
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Regents nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@@ -0,0 +1,47 @@
ADD_ASM_MACRO ?= -D__ASSEMBLY__=1
FLAGS = -O3 -funroll-loops -fpeel-loops -fgcse-sm -fgcse-las $(ADD_FLAGS)
FLAGS_STR = "$(FLAGS)"
CFLAGS_COMMON = -static -std=gnu99 -fno-common -fno-builtin-printf -DTCM=$(TCM)
CFLAGS_ARCH = -Wa,-march=rv32$(ARCH)_zicsr_zifencei -march=rv32$(ARCH)_zicsr_zifencei -mabi=$(ABI)
CFLAGS := $(FLAGS) $(EXT_CFLAGS) \
$(CFLAGS_COMMON) \
$(CFLAGS_ARCH) \
-DFLAGS_STR=\"$(FLAGS_STR)\" \
$(ADD_CFLAGS)
LDFLAGS ?= -nostartfiles -nostdlib -lc -lgcc -march=rv32$(ARCH)_zicsr_zifencei -mabi=$(ABI) --specs=nano.specs $(ADD_LDFLAGS)
ifeq (,$(findstring 0,$(TCM)))
ld_script ?= $(inc_dir)/link_tcm.ld
asm_src ?= crt_tcm.S
else
ld_script ?= $(inc_dir)/link.ld
asm_src ?= crt.S
endif
#this is optional assembly files from project
asm_src += $(asm_src_in_project)
VPATH += $(src_dir) $(inc_dir) $(ADD_VPATH)
incs += -I$(src_dir) -I$(inc_dir) $(ADD_incs)
c_objs := $(addprefix $(bld_dir)/,$(patsubst %.c, %.o, $(c_src)))
asm_objs := $(addprefix $(bld_dir)/,$(patsubst %.S, %.o, $(asm_src)))
$(bld_dir)/%.o: %.S
$(RISCV_GCC) $(CFLAGS) $(ADD_ASM_MACRO) -c $(incs) $< -o $@
$(bld_dir)/%.o: %.c
$(RISCV_GCC) $(CFLAGS) -c $(incs) $< -o $@
$(bld_dir)/%.elf: $(ld_script) $(c_objs) $(asm_objs)
$(RISCV_GCC) -o $@ -T $^ $(LDFLAGS)
$(bld_dir)/%.hex: $(bld_dir)/%.elf
$(RISCV_OBJCOPY) $^ $@
$(bld_dir)/%.dump: $(bld_dir)/%.elf
$(RISCV_OBJDUMP) -D -w -x -S $^ > $@

146
sim/tests/common/crt.S Normal file
View File

@@ -0,0 +1,146 @@
/// Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
/// @file <crt.S>
///
#include "riscv_csr_encoding.h"
#include "sc_test.h"
# define LREG lw
# define SREG sw
# define REGBYTES 4
.globl _start
.globl main
.globl trap_entry
.globl handle_trap
.globl sc_exit
.weak trap_entry, handle_trap
.text
.org (64*3)
.balign 64
machine_trap_entry:
j trap_entry
.balign 64
_start:
#ifndef __RVE_EXT
zero_int_regs 1, 31
#else
zero_int_regs 1, 15
#endif
# Global pointer init
.option push
.option norelax
la gp, __global_pointer$
.option pop
# clear bss
la a1, __BSS_START__
la a2, __BSS_END__
j 4f
3: sw zero, 0(a1)
add a1, a1, 4
4: bne a1, a2, 3b
la sp, __C_STACK_TOP__
// Timer init
li t0, mtime_ctrl
li t1, (1 << SCR1_MTIME_CTRL_EN) // enable, use internal clock
sw t1, (t0)
li t0, mtime_div
li t1, (100-1) // divide by 100
sw t1, (t0)
li t0, mtimecmp
li t1, -1
sw t1, (t0) // max value for mtimecmp
sw t1, 4(t0)
li a0, 0
li a1, 0
call main
tail sc_exit
trap_entry:
addi sp, sp, -272
SREG x1, 1*REGBYTES(sp)
SREG x2, 2*REGBYTES(sp)
SREG x3, 3*REGBYTES(sp)
SREG x4, 4*REGBYTES(sp)
SREG x5, 5*REGBYTES(sp)
SREG x6, 6*REGBYTES(sp)
SREG x7, 7*REGBYTES(sp)
SREG x8, 8*REGBYTES(sp)
SREG x9, 9*REGBYTES(sp)
SREG x10, 10*REGBYTES(sp)
SREG x11, 11*REGBYTES(sp)
SREG x12, 12*REGBYTES(sp)
SREG x13, 13*REGBYTES(sp)
SREG x14, 14*REGBYTES(sp)
SREG x15, 15*REGBYTES(sp)
#ifndef __RVE_EXT
SREG x16, 16*REGBYTES(sp)
SREG x17, 17*REGBYTES(sp)
SREG x18, 18*REGBYTES(sp)
SREG x19, 19*REGBYTES(sp)
SREG x20, 20*REGBYTES(sp)
SREG x21, 21*REGBYTES(sp)
SREG x22, 22*REGBYTES(sp)
SREG x23, 23*REGBYTES(sp)
SREG x24, 24*REGBYTES(sp)
SREG x25, 25*REGBYTES(sp)
SREG x26, 26*REGBYTES(sp)
SREG x27, 27*REGBYTES(sp)
SREG x28, 28*REGBYTES(sp)
SREG x29, 29*REGBYTES(sp)
SREG x30, 30*REGBYTES(sp)
SREG x31, 31*REGBYTES(sp)
#endif // __RVE_EXT
csrr a0, mcause
csrr a1, mepc
mv a2, sp
call handle_trap
LREG x1, 1*REGBYTES(sp)
LREG x2, 2*REGBYTES(sp)
LREG x3, 3*REGBYTES(sp)
LREG x4, 4*REGBYTES(sp)
LREG x5, 5*REGBYTES(sp)
LREG x6, 6*REGBYTES(sp)
LREG x7, 7*REGBYTES(sp)
LREG x8, 8*REGBYTES(sp)
LREG x9, 9*REGBYTES(sp)
LREG x10, 10*REGBYTES(sp)
LREG x11, 11*REGBYTES(sp)
LREG x12, 12*REGBYTES(sp)
LREG x13, 13*REGBYTES(sp)
LREG x14, 14*REGBYTES(sp)
LREG x15, 15*REGBYTES(sp)
#ifndef __RVE_EXT
LREG x16, 16*REGBYTES(sp)
LREG x17, 17*REGBYTES(sp)
LREG x18, 18*REGBYTES(sp)
LREG x19, 19*REGBYTES(sp)
LREG x20, 20*REGBYTES(sp)
LREG x21, 21*REGBYTES(sp)
LREG x22, 22*REGBYTES(sp)
LREG x23, 23*REGBYTES(sp)
LREG x24, 24*REGBYTES(sp)
LREG x25, 25*REGBYTES(sp)
LREG x26, 26*REGBYTES(sp)
LREG x27, 27*REGBYTES(sp)
LREG x28, 28*REGBYTES(sp)
LREG x29, 29*REGBYTES(sp)
LREG x30, 30*REGBYTES(sp)
LREG x31, 31*REGBYTES(sp)
#endif // __RVE_EXT
addi sp, sp, 272
mret
handle_trap:
j SIM_EXIT
// end of crt.S

155
sim/tests/common/crt_tcm.S Normal file
View File

@@ -0,0 +1,155 @@
/// Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
/// @file <crt_tcm.S>
///
#include "riscv_csr_encoding.h"
#include "reloc.h"
#include "sc_test.h"
# define LREG lw
# define SREG sw
# define REGBYTES 4
.globl _start
.globl main
.globl trap_entry
.globl handle_trap
.globl sc_exit
.weak trap_entry, handle_trap
.section .text.init
.org (64*3)
.align 6;
machine_trap_entry:
j trap_entry
.align 6
_start:
#ifndef __RVE_EXT
zero_int_regs 1, 31
#else
zero_int_regs 1, 15
#endif
# Global pointer init
.option push
.option norelax
la gp, __global_pointer$
.option pop
RELOC_PROC;
// init tdata
mv a1, tp
la a2, _tdata_end
j 6f
5: lw a3, 0(a0)
sw a3, 0(a1)
add a0, a0, 4
add a1, a1, 4
6: bne a0, a2, 5b
// clear tbss
j 8f
7: sw zero, 0(a1)
add a1, a1, 4
8: bne a1, a4, 7b
// Timer init
li t0, mtime_ctrl
li t1, (1 << SCR1_MTIME_CTRL_EN) // enable, use internal clock
sw t1, (t0)
li t0, mtime_div
li t1, (100-1) // divide by 100
sw t1, (t0)
li t0, mtimecmp
li t1, -1
sw t1, (t0) // max value for mtimecmp
sw t1, 4(t0)
li a0, 0
li a1, 0
call main
tail sc_exit
trap_entry:
addi sp, sp, -272
SREG x1, 1*REGBYTES(sp)
SREG x2, 2*REGBYTES(sp)
SREG x3, 3*REGBYTES(sp)
SREG x4, 4*REGBYTES(sp)
SREG x5, 5*REGBYTES(sp)
SREG x6, 6*REGBYTES(sp)
SREG x7, 7*REGBYTES(sp)
SREG x8, 8*REGBYTES(sp)
SREG x9, 9*REGBYTES(sp)
SREG x10, 10*REGBYTES(sp)
SREG x11, 11*REGBYTES(sp)
SREG x12, 12*REGBYTES(sp)
SREG x13, 13*REGBYTES(sp)
SREG x14, 14*REGBYTES(sp)
SREG x15, 15*REGBYTES(sp)
#ifndef __RVE_EXT
SREG x16, 16*REGBYTES(sp)
SREG x17, 17*REGBYTES(sp)
SREG x18, 18*REGBYTES(sp)
SREG x19, 19*REGBYTES(sp)
SREG x20, 20*REGBYTES(sp)
SREG x21, 21*REGBYTES(sp)
SREG x22, 22*REGBYTES(sp)
SREG x23, 23*REGBYTES(sp)
SREG x24, 24*REGBYTES(sp)
SREG x25, 25*REGBYTES(sp)
SREG x26, 26*REGBYTES(sp)
SREG x27, 27*REGBYTES(sp)
SREG x28, 28*REGBYTES(sp)
SREG x29, 29*REGBYTES(sp)
SREG x30, 30*REGBYTES(sp)
SREG x31, 31*REGBYTES(sp)
#endif // __RVE_EXT
csrr a0, mcause
csrr a1, mepc
mv a2, sp
call handle_trap
LREG x1, 1*REGBYTES(sp)
LREG x2, 2*REGBYTES(sp)
LREG x3, 3*REGBYTES(sp)
LREG x4, 4*REGBYTES(sp)
LREG x5, 5*REGBYTES(sp)
LREG x6, 6*REGBYTES(sp)
LREG x7, 7*REGBYTES(sp)
LREG x8, 8*REGBYTES(sp)
LREG x9, 9*REGBYTES(sp)
LREG x10, 10*REGBYTES(sp)
LREG x11, 11*REGBYTES(sp)
LREG x12, 12*REGBYTES(sp)
LREG x13, 13*REGBYTES(sp)
LREG x14, 14*REGBYTES(sp)
LREG x15, 15*REGBYTES(sp)
#ifndef __RVE_EXT
LREG x16, 16*REGBYTES(sp)
LREG x17, 17*REGBYTES(sp)
LREG x18, 18*REGBYTES(sp)
LREG x19, 19*REGBYTES(sp)
LREG x20, 20*REGBYTES(sp)
LREG x21, 21*REGBYTES(sp)
LREG x22, 22*REGBYTES(sp)
LREG x23, 23*REGBYTES(sp)
LREG x24, 24*REGBYTES(sp)
LREG x25, 25*REGBYTES(sp)
LREG x26, 26*REGBYTES(sp)
LREG x27, 27*REGBYTES(sp)
LREG x28, 28*REGBYTES(sp)
LREG x29, 29*REGBYTES(sp)
LREG x30, 30*REGBYTES(sp)
LREG x31, 31*REGBYTES(sp)
#endif // __RVE_EXT
addi sp, sp, 272
mret
handle_trap:
j SIM_EXIT
// end of crt.S

113
sim/tests/common/csr.h Normal file
View File

@@ -0,0 +1,113 @@
/// Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
/// @file <csr.h>
/// Architecture specific CSR's defs and inlines
#ifndef SCR_CSR_H
#define SCR_CSR_H
#include <stdint.h>
#include <stdbool.h>
#define __xstringify(s) __stringify(s)
#define __stringify(s) #s
#ifdef read_csr
#undef read_csr
#endif
#ifdef write_csr
#undef write_csr
#endif
#ifdef swap_csr
#undef swap_csr
#endif
#ifdef set_csr
#undef set_csr
#endif
#ifdef clear_csr
#undef clear_csr
#endif
#ifdef rdtime
#undef rdtime
#endif
#ifdef rdcycle
#undef rdcycle
#endif
#ifdef rdinstret
#undef rdinstret
#endif
#define read_csr(reg) \
({ \
unsigned long __tmp; \
asm volatile ("csrr %0, " __xstringify(reg) : "=r"(__tmp)); \
__tmp; \
})
#define write_csr(reg, val) \
do { \
if (__builtin_constant_p(val) && (val) == 0) \
asm volatile ("csrw " __xstringify(reg) ", zero" ::); \
else if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
asm volatile ("csrw " __xstringify(reg) ", %0" :: "i"(val)); \
else \
asm volatile ("csrw " __xstringify(reg) ", %0" :: "r"(val)); \
} while (0)
#define swap_csr(reg, val) \
({ \
unsigned long __tmp; \
if (__builtin_constant_p(val) && (val) == 0) \
asm volatile ("csrrw %0, " __xstringify(reg) ", zero" : "=r"(__tmp) :); \
else if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
asm volatile ("csrrw %0, " __xstringify(reg) ", %1" : "=r"(__tmp) : "i"(val)); \
else \
asm volatile ("csrrw %0, " __xstringify(reg) ", %1" : "=r"(__tmp) : "r"(val)); \
__tmp; \
})
#define set_csr(reg, bit) \
({ \
unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrs %0, " __xstringify(reg) ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrs %0, " __xstringify(reg) ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; \
})
#define clear_csr(reg, bit) \
({ \
unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrc %0, " __xstringify(reg) ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrc %0, " __xstringify(reg) ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; \
})
#define rdtime() read_csr(time)
#define rdcycle() read_csr(cycle)
#define rdinstret() read_csr(instret)
static inline unsigned long __attribute__((const)) hartid()
{
unsigned long res;
asm ("csrr %0, mhartid" : "=r"(res));
return res;
}
static inline unsigned long __attribute__((const)) impid()
{
unsigned long res;
asm ("csrr %0, mimpid" : "=r"(res));
return res;
}
#endif // SCR_CSR_H

99
sim/tests/common/link.ld Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
* @file <link.ld>
* @brief bare metal tests' linker script
*/
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
MEMORY {
RAM (rwx) : ORIGIN = 0x0, LENGTH = 64K
}
STACK_SIZE = 1024;
CL_SIZE = 32;
SECTIONS {
/* code segment */
.text.init 0 : {
FILL(0);
. = 0x100 - 12;
SIM_EXIT = .;
LONG(0x13);
SIM_STOP = .;
LONG(0x6F);
LONG(-1);
. = 0x100;
PROVIDE(__TEXT_START__ = .);
*(.text.init)
} >RAM
.text : {
*crt.o(.text .text.*)
*(.text .text.*)
*(sc_test_section)
. = ALIGN(CL_SIZE);
PROVIDE(__TEXT_END__ = .);
} >RAM
/* data segment */
.data : {
*(.data .data.*)
. = ALIGN(CL_SIZE);
} >RAM
.sdata : {
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
. = ALIGN(CL_SIZE);
} >RAM
/* thread-local data segment */
.tdata : {
PROVIDE(_tls_data = .);
PROVIDE(_tdata_begin = .);
*(.tdata .tdata.*)
PROVIDE(_tdata_end = .);
. = ALIGN(CL_SIZE);
} >RAM
.tbss : {
PROVIDE(__BSS_START__ = .);
*(.tbss .tbss.*)
. = ALIGN(CL_SIZE);
PROVIDE(_tbss_end = .);
} >RAM
/* bss segment */
.sbss : {
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
} >RAM
.bss : {
*(.bss .bss.*)
. = ALIGN(CL_SIZE);
PROVIDE(__BSS_END__ = .);
} >RAM
_end = .;
PROVIDE(__end = .);
/* End of uninitalized data segement */
.stack ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE : {
FILL(0);
PROVIDE(__STACK_START__ = .);
. += STACK_SIZE;
PROVIDE(__C_STACK_TOP__ = .);
PROVIDE(__STACK_END__ = .);
} >RAM
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
* @file <link.ld>
* @brief bare metal tests' linker script
*/
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
MEMORY {
RAM (rwx) : ORIGIN = 0x0, LENGTH = 64K
TCM (rwx) : ORIGIN = 0x00480000, LENGTH = 64K
}
STACK_SIZE = 1024;
CL_SIZE = 32;
SECTIONS {
/* code segment */
.text.init ORIGIN(RAM) : {
FILL(0);
. = 0x100 - 12;
SIM_EXIT = .;
LONG(0x13);
SIM_STOP = .;
LONG(0x6F);
LONG(-1);
. = 0x100;
*crt_tcm.o(.text .text.*)
*(.text.init)
. = ALIGN(CL_SIZE);
} >RAM
__reloc_start = .;
.text : {
PROVIDE(__TEXT_START__ = .);
*(.text .text.*)
*(sc_test_section)
. = ALIGN(CL_SIZE);
PROVIDE(__TEXT_END__ = .);
} >TCM AT>RAM
.rodata ALIGN(CL_SIZE) : {
__global_pointer$ = . + 0x800;
*(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*)
. = ALIGN(CL_SIZE);
LONG(0x13);
. = ALIGN(CL_SIZE);
} >TCM AT>RAM
/* data segment */
.data ALIGN(CL_SIZE) : {
PROVIDE(__DATA_START__ = .);
*(.data .data.*)
. = ALIGN(CL_SIZE);
} >TCM AT>RAM
.sdata ALIGN(CL_SIZE) : {
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
. = ALIGN(CL_SIZE);
PROVIDE(__DATA_END__ = .);
} >TCM AT>RAM
/* thread-local data segment */
.tdata ALIGN(CL_SIZE) : {
PROVIDE(_tls_data = .);
PROVIDE(_tdata_begin = .);
*(.tdata .tdata.*)
PROVIDE(_tdata_end = .);
. = ALIGN(CL_SIZE);
} >TCM AT>RAM
.tbss ALIGN(CL_SIZE) : {
PROVIDE(_tbss_begin = .);
*(.tbss .tbss.*)
. = ALIGN(CL_SIZE);
PROVIDE(_tbss_end = .);
} >TCM AT>RAM
/* bss segment */
.sbss ALIGN(CL_SIZE) : {
PROVIDE(__BSS_START__ = .);
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
. = ALIGN(CL_SIZE);
} >TCM AT>RAM
.bss ALIGN(CL_SIZE) : {
*(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)
. = ALIGN(CL_SIZE);
PROVIDE(__BSS_END__ = .);
} >TCM AT>RAM
_end = .;
PROVIDE(__end = .);
/* End of uninitalized data segement */
.stack ORIGIN(TCM) + LENGTH(TCM) - STACK_SIZE : {
PROVIDE(__STACK_START__ = .);
. += STACK_SIZE;
PROVIDE(__C_STACK_TOP__ = .);
PROVIDE(__STACK_END__ = .);
} >TCM
/DISCARD/ : {
*(.eh_frame .eh_frame.*)
}
}

37
sim/tests/common/reloc.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef RELOC_H
#define RELOC_H
#if (TCM == 1)
#define RELOC_PROC \
la a0, __reloc_start; \
la a1, __TEXT_START__; \
la a2, __DATA_END__; \
beq a0, a1, 21f; \
j 2f; \
1: lw a3, 0(a0); \
sw a3, 0(a1); \
add a0, a0, 4; \
add a1, a1, 4; \
2: bne a1, a2, 1b; \
/* clear bss */ \
la a2, __BSS_START__; \
21: la a1, __BSS_END__; \
j 4f; \
3: sw zero, 0(a2); \
add a2, a2, 4; \
4: bne a1, a2, 3b; \
/* init stack */ \
la sp, __C_STACK_TOP__; \
/* init hart0 TLS */ \
la a0, _tdata_begin; \
la a2, _tbss_end; \
sub a1, a2, a0; \
la a4, __STACK_START__; \
sub tp, a4, a1;
#else // #if TCM
#define RELOC_PROC
#endif // #else #if TCM
#endif //

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,819 @@
// See LICENSE for license details.
#ifndef __RISCV_MACROS_H
#define __RISCV_MACROS_H
#include "riscv_csr_encoding.h"
#include "sc_test.h"
//-----------------------------------------------------------------------
// Begin Macro
//-----------------------------------------------------------------------
#define RVTEST_RV64U \
.macro init; \
.endm
#define RVTEST_RV64UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV32U \
.macro init; \
.endm
#define RVTEST_RV32UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV64M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV64S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#define RVTEST_RV32M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV32S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#if __riscv_xlen == 64
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
#else
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
#endif
#define INIT_PMP \
la t0, 1f; \
csrw mtvec, t0; \
li t0, -1; /* Set up a PMP to permit all accesses */ \
csrw pmpaddr0, t0; \
li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \
csrw pmpcfg0, t0; \
.balign 4; \
1:
#define INIT_SPTBR \
la t0, 1f; \
csrw mtvec, t0; \
csrwi sptbr, 0; \
.balign 4; \
1:
#define DELEGATE_NO_TRAPS
#define RVTEST_ENABLE_SUPERVISOR \
li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \
csrs mstatus, a0; \
li a0, SIP_SSIP | SIP_STIP; \
csrs mideleg, a0; \
#define RVTEST_ENABLE_MACHINE \
li a0, MSTATUS_MPP; \
csrs mstatus, a0; \
#define RVTEST_FP_ENABLE \
li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
csrs mstatus, a0; \
csrwi fcsr, 0
#define RISCV_MULTICORE_DISABLE \
csrr a0, mhartid; \
1: bnez a0, 1b
#define EXTRA_TVEC_USER
#define EXTRA_TVEC_SUPERVISOR
#define EXTRA_TVEC_HYPERVISOR
#define EXTRA_TVEC_MACHINE
#define EXTRA_INIT
#define EXTRA_INIT_TIMER
#define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */
#define RVTEST_CODE_BEGIN \
.section .text.init; \
.org 0xC0, 0x00; \
.balign 64; \
.weak stvec_handler; \
.weak mtvec_handler; \
trap_vector: \
/* test whether the test came from pass/fail */ \
csrr a4, mcause; \
li a5, CAUSE_USER_ECALL; \
beq a4, a5, _report; \
li a5, CAUSE_SUPERVISOR_ECALL; \
beq a4, a5, _report; \
li a5, CAUSE_MACHINE_ECALL; \
beq a4, a5, _report; \
/* if an mtvec_handler is defined, jump to it */ \
la a4, mtvec_handler; \
beqz a4, 1f; \
jr a4; \
/* was it an interrupt or an exception? */ \
1: csrr a4, mcause; \
bgez a4, handle_exception; \
INTERRUPT_HANDLER; \
handle_exception: \
/* we don't know how to handle whatever the exception was */ \
other_exception: \
/* some unhandlable exception occurred */ \
li a0, 0x1; \
_report: \
j sc_exit; \
.balign 64; \
.globl _start; \
_start: \
RISCV_MULTICORE_DISABLE; \
/*INIT_SPTBR;*/ \
/*INIT_PMP;*/ \
DELEGATE_NO_TRAPS; \
li TESTNUM, 0; \
la t0, trap_vector; \
csrw mtvec, t0; \
CHECK_XLEN; \
/* if an stvec_handler is defined, delegate exceptions to it */ \
la t0, stvec_handler; \
beqz t0, 1f; \
csrw stvec, t0; \
li t0, (1 << CAUSE_LOAD_PAGE_FAULT) | \
(1 << CAUSE_STORE_PAGE_FAULT) | \
(1 << CAUSE_FETCH_PAGE_FAULT) | \
(1 << CAUSE_MISALIGNED_FETCH) | \
(1 << CAUSE_USER_ECALL) | \
(1 << CAUSE_BREAKPOINT); \
csrw medeleg, t0; \
csrr t1, medeleg; \
bne t0, t1, other_exception; \
1: csrwi mstatus, 0; \
init; \
EXTRA_INIT; \
EXTRA_INIT_TIMER; \
la t0, _run_test; \
csrw mepc, t0; \
csrr a0, mhartid; \
mret; \
.section .text; \
_run_test:
//-----------------------------------------------------------------------
// End Macro
//-----------------------------------------------------------------------
#define RVTEST_CODE_END ecall: ecall
//-----------------------------------------------------------------------
// Pass/Fail Macro
//-----------------------------------------------------------------------
#define RVTEST_PASS \
fence; \
mv a1, TESTNUM; \
li a0, 0x0; \
ecall
#define TESTNUM x28
#define RVTEST_FAIL \
fence; \
mv a1, TESTNUM; \
li a0, 0x1; \
ecall
//-----------------------------------------------------------------------
// Data Section Macro
//-----------------------------------------------------------------------
#define EXTRA_DATA
#define RVTEST_DATA_BEGIN \
EXTRA_DATA \
.pushsection .tohost,"aw",@progbits; \
.balign 64; .global tohost; tohost: .dword 0; \
.balign 64; .global fromhost; fromhost: .dword 0; \
.popsection; \
.balign 16; \
.global begin_regstate; begin_regstate: .dword 0; .dword 0; .dword 0; \
.balign 16; \
.global begin_signature; begin_signature:
#define RVTEST_DATA_END .balign 16; .global end_signature; end_signature:
#-----------------------------------------------------------------------
# Helper macros
#-----------------------------------------------------------------------
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
#define TEST_CASE( testnum, testreg, correctval, code... ) \
test_ ## testnum: \
code; \
li x29, MASK_XLEN(correctval); \
li TESTNUM, testnum; \
bne testreg, x29, fail;
# We use a macro hack to simpify code generation for various numbers
# of bubble cycles.
#define TEST_INSERT_NOPS_0
#define TEST_INSERT_NOPS_1 nop; TEST_INSERT_NOPS_0
#define TEST_INSERT_NOPS_2 nop; TEST_INSERT_NOPS_1
#define TEST_INSERT_NOPS_3 nop; TEST_INSERT_NOPS_2
#define TEST_INSERT_NOPS_4 nop; TEST_INSERT_NOPS_3
#define TEST_INSERT_NOPS_5 nop; TEST_INSERT_NOPS_4
#define TEST_INSERT_NOPS_6 nop; TEST_INSERT_NOPS_5
#define TEST_INSERT_NOPS_7 nop; TEST_INSERT_NOPS_6
#define TEST_INSERT_NOPS_8 nop; TEST_INSERT_NOPS_7
#define TEST_INSERT_NOPS_9 nop; TEST_INSERT_NOPS_8
#define TEST_INSERT_NOPS_10 nop; TEST_INSERT_NOPS_9
#-----------------------------------------------------------------------
# RV64UI MACROS
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Tests for instructions with immediate operand
#-----------------------------------------------------------------------
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x3, result, \
li x1, MASK_XLEN(val1); \
inst x3, x1, SEXT_IMM(imm); \
)
#define TEST_IMM_OP_RVC( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x1, result, \
li x1, val1; \
inst x1, imm; \
)
#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
inst x1, x1, SEXT_IMM(imm); \
)
#define TEST_IMM_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
inst x3, x1, SEXT_IMM(imm); \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x3, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_IMM_SRC1_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
TEST_CASE( testnum, x3, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x3, x1, SEXT_IMM(imm); \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_IMM_ZEROSRC1( testnum, inst, result, imm ) \
TEST_CASE( testnum, x1, result, \
inst x1, x0, SEXT_IMM(imm); \
)
#define TEST_IMM_ZERODEST( testnum, inst, val1, imm ) \
TEST_CASE( testnum, x0, 0, \
li x1, MASK_XLEN(val1); \
inst x0, x1, SEXT_IMM(imm); \
)
#-----------------------------------------------------------------------
# Tests for vector config instructions
#-----------------------------------------------------------------------
#define TEST_VSETCFGIVL( testnum, nxpr, nfpr, bank, vl, result ) \
TEST_CASE( testnum, x1, result, \
li x1, (bank << 12); \
vsetcfg x1,nxpr,nfpr; \
li x1, vl; \
vsetvl x1,x1; \
)
#define TEST_VVCFG( testnum, nxpr, nfpr, bank, vl, result ) \
TEST_CASE( testnum, x1, result, \
li x1, (bank << 12) | (nfpr << 6) | nxpr; \
vsetcfg x1; \
li x1, vl; \
vsetvl x1,x1; \
)
#define TEST_VSETVL( testnum, nxpr, nfpr, bank, vl, result ) \
TEST_CASE( testnum, x1, result, \
li x1, (bank << 12); \
vsetcfg x1,nxpr,nfpr; \
li x1, vl; \
vsetvl x1, x1; \
)
#-----------------------------------------------------------------------
# Tests for an instruction with register operands
#-----------------------------------------------------------------------
#define TEST_R_OP( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x3, result, \
li x1, val1; \
inst x3, x1; \
)
#define TEST_R_SRC1_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x1, result, \
li x1, val1; \
inst x1, x1; \
)
#define TEST_R_DEST_BYPASS( testnum, nop_cycles, inst, result, val1 ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, val1; \
inst x3, x1; \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x3, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#-----------------------------------------------------------------------
# Tests for an instruction with register-register operands
#-----------------------------------------------------------------------
#define TEST_RR_OP( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x3, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x3, x1, x2; \
)
#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x1, x1, x2; \
)
#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x2, x1, x2; \
)
#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
inst x1, x1, x1; \
)
#define TEST_RR_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, val2 ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x3, x1, x2; \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x3, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
TEST_CASE( testnum, x3, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## src1_nops \
li x2, MASK_XLEN(val2); \
TEST_INSERT_NOPS_ ## src2_nops \
inst x3, x1, x2; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
TEST_CASE( testnum, x3, result, \
li x4, 0; \
1: li x2, MASK_XLEN(val2); \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## src2_nops \
inst x3, x1, x2; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_ZEROSRC1( testnum, inst, result, val ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val); \
inst x2, x0, x1; \
)
#define TEST_RR_ZEROSRC2( testnum, inst, result, val ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val); \
inst x2, x1, x0; \
)
#define TEST_RR_ZEROSRC12( testnum, inst, result ) \
TEST_CASE( testnum, x1, result, \
inst x1, x0, x0; \
)
#define TEST_RR_ZERODEST( testnum, inst, val1, val2 ) \
TEST_CASE( testnum, x0, 0, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x0, x1, x2; \
)
#-----------------------------------------------------------------------
# Test memory instructions
#-----------------------------------------------------------------------
#define TEST_LD_OP( testnum, inst, result, offset, base ) \
TEST_CASE( testnum, x3, result, \
la x1, base; \
inst x3, offset(x1); \
)
#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
TEST_CASE( testnum, x3, result, \
la x1, base; \
li x2, result; \
store_inst x2, offset(x1); \
load_inst x3, offset(x1); \
)
#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x1, base; \
inst x3, offset(x1); \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x3, 0; \
li x29, result; \
bne x6, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b; \
#define TEST_LD_SRC1_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x1, base; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x3, offset(x1); \
li x29, result; \
bne x3, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_ST_SRC12_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x1, result; \
TEST_INSERT_NOPS_ ## src1_nops \
la x2, base; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x3, offset(x2); \
li x29, result; \
bne x3, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_ST_SRC21_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x2, base; \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, result; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x3, offset(x2); \
li x29, result; \
bne x3, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# Test branch instructions
#-----------------------------------------------------------------------
#define TEST_BR1_OP_TAKEN( testnum, inst, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x1, val1; \
inst x1, 2f; \
bne x0, TESTNUM, fail; \
1: bne x0, TESTNUM, 3f; \
2: inst x1, 1b; \
bne x0, TESTNUM, fail; \
3:
#define TEST_BR1_OP_NOTTAKEN( testnum, inst, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x1, val1; \
inst x1, 1f; \
bne x0, TESTNUM, 2f; \
1: bne x0, TESTNUM, fail; \
2: inst x1, 1b; \
3:
#define TEST_BR1_SRC1_BYPASS( testnum, nop_cycles, inst, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x1, val1; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x1, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_BR2_OP_TAKEN( testnum, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x1, val1; \
li x2, val2; \
inst x1, x2, 2f; \
bne x0, TESTNUM, fail; \
1: bne x0, TESTNUM, 3f; \
2: inst x1, x2, 1b; \
bne x0, TESTNUM, fail; \
3:
#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x1, val1; \
li x2, val2; \
inst x1, x2, 1f; \
bne x0, TESTNUM, 2f; \
1: bne x0, TESTNUM, fail; \
2: inst x1, x2, 1b; \
3:
#define TEST_BR2_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x1, val1; \
TEST_INSERT_NOPS_ ## src1_nops \
li x2, val2; \
TEST_INSERT_NOPS_ ## src2_nops \
inst x1, x2, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_BR2_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: li x2, val2; \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, val1; \
TEST_INSERT_NOPS_ ## src2_nops \
inst x1, x2, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# Test jump instructions
#-----------------------------------------------------------------------
#define TEST_JR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x6, 2f; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x6; \
bne x0, TESTNUM, fail; \
2: addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_JALR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
test_ ## testnum: \
li TESTNUM, testnum; \
li x4, 0; \
1: la x6, 2f; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x19, x6, 0; \
bne x0, TESTNUM, fail; \
2: addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# RV64UF MACROS
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Tests floating-point instructions
#-----------------------------------------------------------------------
#define qNaNf 0f:7fc00000
#define sNaNf 0f:7f800001
#define qNaN 0d:7ff8000000000000
#define sNaN 0d:7ff0000000000001
#define TEST_FP_OP_S_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
flw f0, 0(a0); \
flw f1, 4(a0); \
flw f2, 8(a0); \
lw a3, 12(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
j 2f; \
.balign 4; \
.data; \
test_ ## testnum ## _data: \
.float val1; \
.float val2; \
.float val3; \
.result; \
.text; \
2:
#define TEST_FP_OP_D_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
fld f0, 0(a0); \
fld f1, 8(a0); \
fld f2, 16(a0); \
ld a3, 24(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
j 2f; \
.data; \
.balign 8; \
test_ ## testnum ## _data: \
.double val1; \
.double val2; \
.double val3; \
.result; \
.text; \
2:
#define TEST_FCVT_S_D( testnum, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fmv.x.d a0, f3)
#define TEST_FCVT_D_S( testnum, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \
fcvt.d.s f3, f0; fcvt.s.d f3, f3; fmv.x.s a0, f3)
#define TEST_FP_OP1_S( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.s a0, f3)
#define TEST_FP_OP1_D( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.d a0, f3)
#define TEST_FP_OP1_S_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.s a0, f3)
#define TEST_FP_OP1_D_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.d a0, f3)
#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.s a0, f3)
#define TEST_FP_OP2_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.d a0, f3)
#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.s a0, f3)
#define TEST_FP_OP3_D( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.d a0, f3)
#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_CMP_OP_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FP_CMP_OP_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FCLASS_S(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.s.x fa0, a0; \
fclass.s a0, fa0)
#define TEST_FCLASS_D(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.d.x fa0, a0; \
fclass.d a0, fa0)
#define TEST_INT_FP_OP_S( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
lw a3, 0(a0); \
li a0, val1; \
inst f0, a0; \
fsflags x0; \
fmv.x.s a0, f0; \
bne a0, a3, fail; \
j 1f; \
.balign 4; \
test_ ## testnum ## _data: \
.float result; \
1:
#define TEST_INT_FP_OP_D( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
ld a3, 0(a0); \
li a0, val1; \
inst f0, a0; \
fsflags x0; \
fmv.x.d a0, f0; \
bne a0, a3, fail; \
j 1f; \
.balign 8; \
test_ ## testnum ## _data: \
.double result; \
1:
#-----------------------------------------------------------------------
# Pass and fail code (assumes test num is in TESTNUM)
#-----------------------------------------------------------------------
#define TEST_PASSFAIL \
bne x0, TESTNUM, pass; \
fail: \
RVTEST_FAIL; \
pass: \
RVTEST_PASS \
#-----------------------------------------------------------------------
# Test data section
#-----------------------------------------------------------------------
#define TEST_DATA
#endif

282
sim/tests/common/sc_print.c Normal file
View File

@@ -0,0 +1,282 @@
/// Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
/// @file <sc_print.c>
///
#include <string.h>
#include <stdarg.h>
#include "sc_print.h"
#define SC_SIM_OUTPORT (0xf0000000)
#define CHAR_BIT (8)
static void
sc_puts(long str, long strlen) {
volatile char *out_ptr = (volatile char*)SC_SIM_OUTPORT;
const char *in_ptr = (const char*)str;
for (long len = strlen; len > 0; --len)
*out_ptr = *in_ptr++;
}
#undef putchar
int
putchar(int ch) {
static __thread char buf[64] __attribute__((aligned(64)));
static __thread int buflen = 0;
buf[buflen++] = ch;
if ( ch == '\n' || buflen == sizeof(buf) ) {
sc_puts((long)buf, buflen);
buflen = 0;
}
return 0;
}
static void
printf_putch(int ch, void** data)
{
putchar(ch);
}
static void
print(const char *str)
{
sc_puts((long)str, strlen(str));
}
static long long
getint(va_list *ap, int lflag)
{
if ( lflag >= 2 )
return va_arg(*ap, long long);
else if ( lflag )
return va_arg(*ap, long);
else
return va_arg(*ap, int);
}
static unsigned long long
getuint(va_list *ap, int lflag)
{
if ( lflag >= 2 )
return va_arg(*ap, unsigned long long);
else if ( lflag )
return va_arg(*ap, unsigned long);
else
return va_arg(*ap, unsigned int);
}
static inline void
printnum(void(*putch)(int, void**),
void **putdat,
unsigned long long num,
unsigned base,
int width,
int padc,
int hex_A)
{
unsigned digs[sizeof(num) * CHAR_BIT];
int pos = 0;
for ( ;; ) {
digs[pos++] = num % base;
if ( num < base )
break;
num /= base;
}
while ( width-- > pos )
putch(padc, putdat);
while ( pos-- > 0 )
putch(digs[pos] + (digs[pos] >= 10 ? hex_A - 10 : '0'), putdat);
}
static void
vprintfmt(void(*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
{
register const char* p;
const char* last_fmt;
register int ch;
int err;
unsigned long long num;
int base;
int lflag;
int width;
int precision;
int altflag;
char padc;
int hex_A = 'a';
for ( ;; ) {
while ( (ch = *(unsigned char *)fmt) != '%' ) {
if ( ch == '\0' )
return;
++fmt;
putch(ch, putdat);
}
++fmt;
// Process a %-escape sequence
last_fmt = fmt;
padc = ' ';
width = -1;
precision = -1;
lflag = 0;
altflag = 0;
reswitch:
switch ( ch = *(unsigned char *)fmt++ ) {
// flag to pad on the right
case '-':
padc = '-';
goto reswitch;
// flag to pad with 0's instead of spaces
case '0':
padc = '0';
goto reswitch;
// width field
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
for ( precision = 0;; ++fmt ) {
precision = precision * 10 + ch - '0';
ch = *fmt;
if ( ch < '0' || ch > '9' )
break;
}
goto process_precision;
case '*':
precision = va_arg(ap, int);
goto process_precision;
case '.':
if ( width < 0 )
width = 0;
goto reswitch;
case '#':
altflag = 1;
goto reswitch;
process_precision:
if ( width < 0 ) {
width = precision;
precision = -1;
}
goto reswitch;
// long flag (doubled for long long)
case 'l':
lflag++;
goto reswitch;
// character
case 'c':
putch(va_arg(ap, int), putdat);
break;
// string
case 's':
if ( (p = va_arg(ap, char *)) == NULL )
p = "(null)";
if ( width > 0 && padc != '-' )
for ( width -= strnlen(p, precision); width > 0; width-- )
putch(padc, putdat);
for ( ; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width-- ) {
putch(ch, putdat);
p++;
}
for ( ; width > 0; width-- )
putch(' ', putdat);
break;
// (signed) decimal
case 'd':
num = getint(&ap, lflag);
if ( (long long)num < 0 ) {
putch('-', putdat);
num = -(long long)num;
}
base = 10;
goto signed_number;
case 'f':
{
// #ifndef nopfloat
// double num = getdouble(&ap, lflag);
// printdoubleF(putch, putdat, num, width, precision, padc);
// #endif
}
break;
// unsigned decimal
case 'u':
base = 10;
goto unsigned_number;
// (unsigned) octal
case 'o':
// should do something with padding so it's always 3 octits
base = 8;
goto unsigned_number;
// pointer
case 'p':
// static_assert(sizeof(long) == sizeof(void*));
lflag = 1;
putch('0', putdat);
putch('x', putdat);
/* fall through to 'x' */
// (unsigned) hexadecimal
case 'x':
hex_A = 'a';
base = 16;
goto unsigned_number;
case 'X':
hex_A = 'A';
base = 16;
unsigned_number:
num = getuint(&ap, lflag);
signed_number:
printnum(putch, putdat, num, base, width, padc, hex_A);
break;
// escaped '%' character
case '%':
putch(ch, putdat);
break;
// unrecognized escape sequence - just print it literally
default:
putch('%', putdat);
fmt = last_fmt;
break;
}
}
}
int
sc_printf(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintfmt(printf_putch, NULL, fmt, ap);
va_end(ap);
return 0; // incorrect return value, but who cares, anyway?
}

View File

@@ -0,0 +1,10 @@
/// Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
/// @file <sc_print.h>
///
#ifndef SC_PRINT_H
#define SC_PRINT_H
extern int sc_printf(const char* fmt, ...);
#endif // SC_PRINT_H

View File

@@ -0,0 +1,48 @@
/// Copyright by Syntacore LLC © 2016, 2017. See LICENSE for details
/// @file <sc_test.h>
///
#ifndef SC_TEST_H
#define SC_TEST_H
#if defined(__ASSEMBLER__)
.altmacro
.macro zero_int_reg regn
mv x\regn, zero
.endm
.macro zero_int_regs reg_first, reg_last
.set regn, \reg_first
.rept \reg_last - \reg_first + 1
zero_int_reg %(regn)
.set regn, regn+1
.endr
.endm
#define report_results(result) \
li a0, result; \
la t0, sc_exit; \
jr t0;
.pushsection sc_test_section, "ax"
sc_exit: la t0, SIM_EXIT; jr t0;
.balign 32
.popsection
#define sc_pass report_results(0x0)
#define sc_fail report_results(0x1)
#else
extern void sc_exit(unsigned result, unsigned res0, unsigned res1, unsigned res2, unsigned res3)
__attribute__ ((noinline, noreturn));
static inline void __attribute__ ((noreturn))
report_results(unsigned result, unsigned res0, unsigned res1, unsigned res2, unsigned res3)
{
sc_exit(result, res0, res1, res2, res3);
}
#endif
#endif // SC_TEST_H

View File

@@ -0,0 +1,20 @@
#ifndef __SCR1__SPECIFIC
#define __SCR1__SPECIFIC
#define mcounten 0x7E0
// Memory-mapped registers
#define mtime_ctrl 0x00490000
#define mtime_div 0x00490004
#define mtime 0x00490008
#define mtimeh 0x0049000C
#define mtimecmp 0x00490010
#define mtimecmph 0x00490014
#define SCR1_MTIME_CTRL_EN 0
#define SCR1_MTIME_CTRL_CLKSRC 1
#define SCR1_MTIME_CTRL_WR_MASK 0x3
#define SCR1_MTIME_DIV_WR_MASK 0x3FF
#endif // _SCR1__SPECIFIC

13
sim/tests/hello/Makefile Normal file
View File

@@ -0,0 +1,13 @@
src_dir := $(dir $(lastword $(MAKEFILE_LIST)))
c_src := sc_print.c hello.c
include $(inc_dir)/common.mk
default: log_requested_tgt $(bld_dir)/hello.elf $(bld_dir)/hello.hex $(bld_dir)/hello.dump
log_requested_tgt:
echo hello.hex>> $(bld_dir)/test_info
clean:
$(RM) $(c_objs) $(asm_objs) $(bld_dir)/hello.elf $(bld_dir)/hello.hex $(bld_dir)/hello.dump

7
sim/tests/hello/hello.c Normal file
View File

@@ -0,0 +1,7 @@
#include "sc_print.h"
int main()
{
sc_printf("Hello from SCR1!\n");
return 0;
}

View File

@@ -0,0 +1,26 @@
src_dir := $(dir $(lastword $(MAKEFILE_LIST)))
LDFLAGS := -nostartfiles -nostdlib -march=rv32$(ARCH)_zicsr_zifencei -mabi=$(ABI)
ADD_ASM_MACRO := -DASM
ifeq ($(IPIC) ,1)
ADD_ASM_MACRO += -DIPIC_ENABLED
endif
ifeq ($(VECT_IRQ) ,1)
ADD_ASM_MACRO += -DVECT_IRQ_ENABLED
endif
asm_src := isr_sample.S
# override ld script
ld_script := $(inc_dir)/link.ld
include $(inc_dir)/common.mk
default: log_requested_tgt $(bld_dir)/isr_sample.elf $(bld_dir)/isr_sample.hex $(bld_dir)/isr_sample.dump
log_requested_tgt:
echo isr_sample.hex >> $(bld_dir)/test_info
clean:
$(RM)$(asm_objs) $(bld_dir)/isr_sample.elf $(bld_dir)/isr_sample.hex $(bld_dir)/isr_sample.dump

View File

@@ -0,0 +1,291 @@
#include "riscv_macros.h"
#include "sc_test.h"
.altmacro
// global interrupt bit
#define MSIE (1 << IRQ_M_SOFT) //machine software interrupt enable
#define MTIE (1 << IRQ_M_TIMER) //machine timer interrupt enable
#define MEIE (1 << IRQ_M_EXT) //machine external interrupt enable
#define MCAUSE_EXT_IRQ (1 << 31 | IRQ_M_EXT)
#define MCAUSE_SOFT_IRQ (1 << 31 | IRQ_M_SOFT)
#define MCAUSE_TMR_IRQ (1 << 31 | IRQ_M_TIMER)
// IPIC
#define IRQ_LINES_ADDR 0xF0000100 // simulation
#define TRIG_EXT_IRQ_ADDR 0xF0000100 // external irq is triggered when tb memory is set to non-zero
#define TRIG_SW_IRQ_ADDR 0xF0000200 // software irq is triggered when tb memory is set to non-zero
#define IPIC_EOI 0xBF4 // end of interrupt
#define IPIC_SOI 0xBF5 // start of interrupt
#define IPIC_IDX 0xBF6 // index register
#define IPIC_ICSR 0xBF7 // interrupt control status register
// IPIC Interrupt Constrol Status Register
#define IPIC_ICSR_IP (1 << 0) // interrupt pending
#define IPIC_ICSR_IE (1 << 1) // interrupt enable
#define IPIC_ICSR_IM (1 << 2) // interrupt mode (0/1: level/edge)
#define IPIC_ICSR_INV (1 << 3) // line inversion
#define IPIC_ICSR_IS (1 << 4) // in service
// Interrupt lines in use
#define IPIC_IRQ_LINE9 9
#define EXT_IRQ_LINE_COMMON 0
#include "timer.h"
#include "reloc.h"
.macro jmp_sc_exit
la t0, sc_exit
jr t0
.endm
.section .text.init
.option norvc
.globl _start
// -----------------------------------------------------------------
// Trap handlers
// 0xXXXXXX00
.option norvc
.org (64*3)
//0xXXXXXXC0
.balign 64
machine_trap_entry:
vec_usr_soft:
#ifdef VECT_IRQ_ENABLED
trap_entry:
j _trap_fail
vec_supervisor_soft:
j _trap_fail
vec_reserved1:
j _trap_fail
vec_machine_soft:
j vec_machine_soft_handler
vec_usr_tmr:
j _trap_fail
vec_supervisor_tmr:
j _trap_fail
vec_reserved2:
j _trap_fail
vec_machine_tmr:
j vec_machine_tmr_handler
vec_usr_ext:
j _trap_fail
vec_supervisor_ext:
j _trap_fail
vec_reserved3:
j _trap_fail
vec_machine_ext:
j vec_machine_ext_handler
vec_reserved4:
j _trap_fail
j _trap_fail
j _trap_fail
j _trap_fail
#else
trap_entry:
j direct_irq_handler
vec_supervisor_soft:
j _trap_fail
vec_reserved1:
j _trap_fail
vec_machine_soft:
j _trap_fail
vec_usr_tmr:
j _trap_fail
vec_supervisor_tmr:
j _trap_fail
vec_reserved2:
j _trap_fail
vec_machine_tmr:
j _trap_fail
vec_usr_ext:
j _trap_fail
vec_supervisor_ext:
j _trap_fail
vec_reserved3:
j _trap_fail
vec_machine_ext:
j _trap_fail
vec_reserved4:
j _trap_fail
j _trap_fail
j _trap_fail
j _trap_fail
#endif // ifdef VECT_IRQ_ENABLED
.balign 64
_start:
la t0, machine_trap_entry
csrw mtvec, t0
la t0, test_start
jr (t0)
// -----------------------------------------------------------------
.option norvc
.balign 64
test_start:
la t0, trap_entry
csrw mtvec, t0 // set mtvec to trap_entry
#ifdef VECT_IRQ_ENABLED
csrsi mtvec, 1 // set vectored mode
#else
csrsi mtvec, 0 // set direct mode
#endif
/// configuring timer interrupt ///
_reset_mtimecmp; // reset timer
_run_timer; // run timer
csrs mstatus, MSTATUS_MIE // enable global interrupt
li a0, MTIE
csrs mie, a0 // enable timer interrupt
li t2, 0 // reset timer counter = 0 (updated in isr)
_read_mtime s1 // read timer value
addi s1, s1, 256
_write_mtimecmp_32 s1
wfi
/// configuring external interrupt ///
csrw mie, zero // disable all interrupts
li t0, IRQ_LINES_ADDR
sh zero, (t0) // set all exterinal interrupt lines low
#ifdef IPIC_ENABLED
li t0, IPIC_IRQ_LINE9
csrw IPIC_IDX, t0 // set IPIC to expect interupt on line 9...
li t0, (IPIC_ICSR_IE | IPIC_ICSR_IM)
csrw IPIC_ICSR, t0 // ....enable interrupt,set edge interrupt mode
#endif
li t0, MEIE
csrs mie, t0 // enable external interrupt
li t0, TRIG_EXT_IRQ_ADDR
#ifdef IPIC_ENABLED
li t1, (1 << IPIC_IRQ_LINE9)
#else
li t1, (1 << EXT_IRQ_LINE_COMMON)
#endif
sh t1, (t0) //send command to generate external interrupt on line 9 to testbench
nop
nop
nop
nop //wait for external interrupt
/// configuring software interrupt ///
csrw mie, zero // disable all interrupts
li t0, TRIG_SW_IRQ_ADDR
li t1, 0x00000001
sh t1, (t0) //send command to generate software interrupt
li t0, MSIE
csrs mie, t0 // enable software interrupt
nop
nop
nop
nop //wait for software interrupt
li s1, 3
li a0, 0
beq t2, s1, 1f
li a0, -1
1:
jmp_sc_exit
#ifndef VECT_IRQ_ENABLED
direct_irq_handler:
csrr a1, mcause
li a5, MCAUSE_TMR_IRQ //0x80000007 -- mcause = tmr.irq
beq a1, a5, vec_machine_tmr_handler
li a5, MCAUSE_SOFT_IRQ //0x80000003 -- mcause = soft.irq
beq a1, a5, vec_machine_soft_handler
li a5, MCAUSE_EXT_IRQ //0x8000000B -- mcause = ext.irq
beq a1, a5, vec_machine_ext_handler
mret
#endif
vec_machine_tmr_handler:
csrr a1, mcause
li a5, MCAUSE_TMR_IRQ //0x80000007 -- mcause = tmr.irq
li a0, -1
bne a1, a5, check_fail
csrr t1, mip
li t0, MIP_MTIP
and t0, t1, t0
beqz t0, check_fail
#ifdef IPIC_ENABLED
csrw IPIC_SOI, zero
csrw IPIC_EOI, zero
#endif
_reset_mtimecmp
csrr t1, mip
andi t1, t1, MIP_MTIP
bne t1, zero, check_fail
addi t2, t2, 1 // tmr irq counter update
mret
vec_machine_ext_handler:
csrr a1, mcause
li a5, MCAUSE_EXT_IRQ //0x8000000B -- mcause = ext.irq
li a0, -1
bne a1, a5, check_fail
csrr t1, mip
li t0, MIP_MEIP
and t0, t1, t0
beqz t0, check_fail
#ifdef IPIC_ENABLED
csrw IPIC_SOI, zero
csrw IPIC_EOI, zero
#endif
li t0, MEIE
csrc mie, t0 // disable software interrupt
li t0, TRIG_EXT_IRQ_ADDR
li t1, EXT_IRQ_LINE_COMMON
sh t1, (t0) // send command to disable external interrupt
csrr t1, mip
li t0, MIP_MEIP
bne t1, zero, check_fail
addi t2, t2, 1 // ext irq counter update
mret
vec_machine_soft_handler:
csrr a1, mcause
li a5, MCAUSE_SOFT_IRQ //0x80000003 -- mcause = soft.irq
li a0, -1
bne a1, a5, check_fail
csrr t1, mip
li t0, MIP_MSIP
and t0, t1, t0
beqz t0, check_fail
#ifdef IPIC_ENABLED
csrw IPIC_SOI, zero
csrw IPIC_EOI, zero
#endif
li t0, MSIE
csrc mie, t0 // disable software interrupt
li t0, TRIG_SW_IRQ_ADDR
li t1, 0x00000000
sh t1, (t0) // send command to stop generating software interrupt
li t0, MIP_MSIP
csrc mip, t0
csrr t1, mip
li t0, MIP_MSIP
and t1, t1, t0
bne t1, zero, check_fail
addi t2, t2, 1 // ext irq counter update
mret
check_fail:
la t0, sc_exit
jr t0
_trap_fail:
li a0, -1
j check_fail

View File

@@ -0,0 +1,180 @@
#ifndef __TIMER__H
#define __TIMER__H
#define MEM_MTIME_MASK 0xF0000000
#define MEM_MTIME_CTRL 0x00490000
#define MEM_MTIME_DIV 0x00490004
#define MEM_MTIME 0x00490008
#define MEM_MTIMEH 0x0049000C
#define MEM_MTIMECMP 0x00490010
#define MEM_MTIMECMPH 0x00490014
#define TMP t0
#define TMP2 t1
#define TMP3 t2
#if defined(__ASSEMBLER__)
// Reset
.macro _reset_mtime
li TMP, MEM_MTIME
sw zero, 0(TMP)
sw zero, 4(TMP)
.endm
.macro _reset_mtimecmp
li TMP, MEM_MTIMECMP
not TMP2, zero
sw TMP2, 0(TMP)
sw TMP2, 4(TMP)
.endm
// Write
.macro _write_mtime_ctrl reg
li TMP, MEM_MTIME_CTRL
sw \reg, 0(TMP)
.endm
.macro _write_mtime_div reg
li TMP, MEM_MTIME_DIV
sw \reg, 0(TMP)
.endm
.macro _write_mtimecmp_32 reg
li TMP, MEM_MTIMECMP
li TMP2, -1
sw TMP2, 0(TMP)
sw zero, 4(TMP)
sw \reg, 0(TMP)
.endm
.macro _write_mtime reg
li TMP, MEM_MTIME
sw \reg, 0(TMP)
.endm
.macro _read_mtime reg
li TMP, MEM_MTIME
lw \reg, 0(TMP)
.endm
// Read
.macro _read_mtimecmp reg
li TMP, MEM_MTIMECMP
lw \reg, 0(TMP)
.endm
.macro _read_mtime_ctrl reg
li TMP, MEM_MTIME_CTRL
lw \reg, 0(TMP)
.endm
.macro _read_mtime_div reg
li TMP, MEM_MTIME_DIV
lw \reg, 0(TMP)
.endm
// Misc
.macro _run_timer
li TMP, MEM_MTIME_CTRL
lw TMP2, 0(TMP)
li TMP3, (1 << SCR1_MTIME_CTRL_EN)
or TMP2, TMP2, TMP3
sw TMP2, 0(TMP)
.endm
.macro _stop_timer
li TMP, MEM_MTIME_CTRL
lw TMP2, 0(TMP)
li TMP3, (1 << SCR1_MTIME_CTRL_EN)
not TMP3, TMP3
and TMP2, TMP2, TMP3
sw TMP2, 0(TMP)
.endm
#else /// #if defined(__ASSEMBLER__)
#include <stdint.h>
#include "scr1_specific.h"
static inline void reset_mtime(void)
{
volatile uint32_t *mem_mtime = (volatile uint32_t *)MEM_MTIME;
mem_mtime[0] = 0;
mem_mtime[1] = 0;
}
static inline void reset_mtimecmp(void)
{
volatile uint32_t *reset_mtimecmp = (volatile uint32_t *)MEM_MTIMECMP;
reset_mtimecmp[0] = -1;
reset_mtimecmp[1] = -1;
}
static inline void write_mtime_ctrl(uint32_t val)
{
volatile uint32_t *mem_mtime_ctrl = (volatile uint32_t *)MEM_MTIME_CTRL;
*mem_mtime_ctrl = val;
}
static inline void write_mtime_div(uint32_t val)
{
volatile uint32_t *mem_mtime_div = (volatile uint32_t *)MEM_MTIME_DIV;
*mem_mtime_div = val;
}
static inline void write_mtimecmp_32(uint32_t val)
{
volatile uint32_t *mem_mtime_cmp = (volatile uint32_t *)MEM_MTIMECMP;
mem_mtime_cmp[0] = -1;
mem_mtime_cmp[1] = 0;
mem_mtime_cmp[0] = val;
}
static inline void write_mtime(uint32_t val)
{
volatile uint32_t *mem_mtime = (volatile uint32_t *)MEM_MTIME;
*mem_mtime = val;
}
static inline uint32_t read_mtime(void)
{
volatile uint32_t *mem_mtime = (volatile uint32_t *)MEM_MTIME;
return *mem_mtime;
}
static inline uint32_t read_mtimecmp(void)
{
volatile uint32_t *mem_mtime_cmp = (volatile uint32_t *)MEM_MTIMECMP;
return *mem_mtime_cmp;
}
static inline uint32_t read_mtime_ctrl(void)
{
volatile uint32_t *mem_mtime_ctrl = (volatile uint32_t *)MEM_MTIME_CTRL;
return *mem_mtime_ctrl;
}
static inline uint32_t read_mtime_div(void)
{
volatile uint32_t *mem_mtime_div = (volatile uint32_t *)MEM_MTIME_DIV;
return *mem_mtime_div;
}
static inline void run_timer(void)
{
volatile uint32_t *mem_mtime_ctrl = (volatile uint32_t *)MEM_MTIME_CTRL;
*mem_mtime_ctrl |= 1 << SCR1_MTIME_CTRL_EN;
}
static inline void stop_timer(void)
{
volatile uint32_t *mem_mtime_ctrl = (volatile uint32_t *)MEM_MTIME_CTRL;
*mem_mtime_ctrl &= ~(1 << SCR1_MTIME_CTRL_EN);
}
#endif /// #else #if defined(__ASSEMBLER__)
#endif // #ifndef __TIMER__H

View File

@@ -0,0 +1,260 @@
## @file
## Syntacore SCR* tests
##
## @copyright 2015-2018 Syntacore. All rights reserved.
## RISCV-Compliance
##
XLEN ?= 32
ABI ?= ilp32
ARCH ?=im
override ARCH :=rv$(XLEN)$(ARCH)
$(info >>> ARCH := $(ARCH))
src_dir := $(CURDIR)
RISCV_ARCH_TESTS := $(src_dir)/../../../dependencies/riscv-arch/
#I IM IMC IC
#EM EMC EC
ifeq (e,$(findstring e, $(ARCH)))
ifeq (e,$(findstring e,$(ARCH)))
$(info >>> E32 TESTS)
included_e += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32e_unratified/E/src/*))
arch_set += $(included_e)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32e_unratified/E/*/*.reference_output)
endif
ifeq (c,$(findstring c,$(ARCH)))
$(info >>> EC32 TESTS)
included_ec += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32e_unratified/C/src/*))
arch_set += $(included_ec)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32e_unratified/C/*/*.reference_output)
endif
ifeq (m,$(findstring m,$(ARCH)))
$(info >>> EM32 TESTS)
included_em += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32e_unratified/M/src/*))
arch_set += $(included_em)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32e_unratified/M/*/*.reference_output)
endif
else ## ifdef SCR_BASE_RVE_EXT
ifeq (i,$(findstring i, $(ARCH)))
ifeq (i,$(findstring i,$(ARCH)))
$(info >>> I32 TESTS)
included_i += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/I/src/*))
included_ip += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/privilege/src/*))
included_i += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/Zifencei/src/*))
included_i += $(included_ip)
arch_set += $(included_i)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/I/*/*.reference_output)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/privilege/*/*.reference_output)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/Zifencei/*/*.reference_output)
endif
ifeq (c,$(findstring c,$(ARCH)))
$(info >>> IC32 TESTS)
included_ic += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/C/src/*))
arch_set += $(included_ic)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/C/*/*.reference_output)
endif
ifeq (m,$(findstring m,$(ARCH)))
$(info >>> IM32 TESTS)
included_im += $(filter %.S,\
$(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/M/src/*))
arch_set += $(included_im)
reference_src += $(wildcard $(RISCV_ARCH_TESTS)/riscv-test-suite/rv32i_m/M/*/*.reference_output)
endif
endif
endif
$(info >>>$(ARCH) set included)
ifeq ($(arch_set),)
$(info >>> No arch tests included)
endif
$(info >>>>> arch set: $(arch_set))
dst_dir := $(bld_dir)
test_name := riscv_arch
bld_dir := $(addprefix $(dst_dir)/, $(test_name))
obj_dir := $(bld_dir)/riscv_arch_objs
ifeq ($(ARCH),$(filter $(ARCH),rv32im))
cut_list += misalign-blt-01 misalign-jal-01 misalign-beq-01 misalign2-jalr-01 misalign-bgeu-01 misalign-bltu-01 misalign-bge-01 misalign-bne-01 # privilege test used mtvec
endif
ifeq ($(ARCH),$(filter $(ARCH),rv32ic))
cut_list += misalign-lw-01 misalign-sh-01 misalign-lhu-01 misalign-lh-01 ecall misalign-sw-01 # privilege test used mtvec
endif
cut_list += bne-01 blt-01 beq-01 bge-01 jal-01 bltu-01 bgeu-01 # i - base
cut_list += ebreak cebreak-01 cswsp-01 # C - base
testnames := $(basename $(notdir $(arch_set)))
filtered := $(filter-out $(cut_list),$(testnames))
objs := $(addprefix $(bld_dir)/,$(filtered:%=%.o))
test_elf := $(addprefix $(dst_dir)/arch_,$(filtered:%=%.elf))
test_hex := $(addprefix $(dst_dir)/arch_,$(filtered:%=%.hex))
test_dump := $(addprefix $(bld_dir)/arch_,$(filtered:%=%.dump))
arch_macros_file := $(root_dir)/sim/tests/riscv_arch/model_test.h
arch_output ?= true
ifeq (e,$(findstring e,$(ARCH)))
EXT_CFLAGS += -DRVTEST_E
endif
# Set name file for RV32I
testnames_i := $(basename $(notdir $(included_i)))
testnames_im := $(basename $(notdir $(included_im)))
testnames_ic := $(basename $(notdir $(included_ic)))
testnames_ib := $(basename $(notdir $(included_ib)))
filtered_i := $(filter-out $(cut_list),$(testnames_i))
filtered_im := $(filter-out $(cut_list),$(testnames_im))
filtered_ic := $(filter-out $(cut_list),$(testnames_ic))
filtered_ib := $(filter-out $(cut_list),$(testnames_ib))
# Set name file for RVE
testnames_e := $(basename $(notdir $(included_e)))
testnames_em := $(basename $(notdir $(included_em)))
testnames_ec := $(basename $(notdir $(included_ec)))
filtered_e := $(filter-out $(cut_list),$(testnames_e))
filtered_em := $(filter-out $(cut_list),$(testnames_em))
filtered_ec := $(filter-out $(cut_list),$(testnames_ec))
CFLAGS := -I$(inc_dir) -I$(src_dir) -DASM -mabi=$(ABI) $(EXT_CFLAGS) -DXLEN=$(XLEN) -D__riscv_xlen=$(XLEN) -w
LDFLAGS := -static -fvisibility=hidden -nostdlib -nostartfiles -T$(inc_dir)/link.ld -march=$(ARCH) -mabi=$(ABI)
GCCVERSIONGT7 := $(shell expr `$(RISCV_GCC) -dumpfullversion | cut -f1 -d'.'` \> 7)
ifeq "$(GCCVERSIONGT7)" "1"
LDFLAGS += -mno-relax
endif
VPATH += $(src_dir) $(bld_dir) $(obj_dir) $(asm_path) $(ref_path) $(RISCV_ARCH_TESTS)
ifeq ($(arch_output), true)
CFLAGS += -D_ARCH_OUTPUT
endif
default: clean log_requested_tgt check_version cp_asm ref_data $(test_elf) $(test_hex) $(test_dump)
define compile_template
$(obj_dir)/$(1).o: $(obj_dir) cp_asm
$(RISCV_GCC) -c $$(bld_dir)/arch_asm/$(1).S $$(CFLAGS) -Wa,$(2) $(2) -o $$@
endef
define preprocessing
for test_asm in $(1); do \
march_tmp=$$test_asm ; \
march_tmp=$${march_tmp%/src*} ; \
march_tmp=$$(basename $$march_tmp) ; \
file_name="$$(basename $${test_asm})" ; \
$(RISCV_GCC) $(CFLAGS) -Wa,$(2) $(2) -E $$test_asm \
-o $(bld_dir)/arch_asm/$$file_name ; \
done
endef
define preprocessing_privilege
for test_asm in $(1); do \
march_tmp=$$test_asm ; \
march_tmp=$${march_tmp%/src*} ; \
march_tmp=$$(basename $$march_tmp) ; \
file_name="$$(basename $${test_asm})" ; \
$(RISCV_GCC) $(CFLAGS) -Drvtest_mtrap_routine=True -Dmhandler -Wa,$(2) $(2) -E $$test_asm \
-o $(bld_dir)/arch_asm/$$file_name ; \
done
endef
$(foreach SRC,$(filtered_i),$(eval $(call compile_template,$(SRC),-march=rv32i_zicsr_zifencei)))
$(foreach SRC,$(filtered_im),$(eval $(call compile_template,$(SRC),-march=rv32im_zicsr_zifencei)))
$(foreach SRC,$(filtered_ic),$(eval $(call compile_template,$(SRC),-march=rv32ic_zicsr_zifencei)))
$(foreach SRC,$(filtered_e),$(eval $(call compile_template,$(SRC),-march=rv32e_zicsr_zifencei)))
$(foreach SRC,$(filtered_em),$(eval $(call compile_template,$(SRC),-march=rv32em_zicsr_zifencei)))
$(foreach SRC,$(filtered_ec),$(eval $(call compile_template,$(SRC),-march=rv32ec_zicsr_zifencei)))
log_requested_tgt: $(bld_dir)
$(foreach test_name, $(filtered), $(eval $(shell echo arch_$(test_name).hex >> $(bld_dir)/../test_info)))
$(bld_dir) :
mkdir -p $(bld_dir)
$(obj_dir) : | ref_data
mkdir -p $(obj_dir)
$(dst_dir)/arch_%.elf: $(obj_dir)/%.o | $(dep_files)
$(RISCV_GCC) $^ $(LDFLAGS) -o $@ -g
$(dst_dir)/arch_%.hex: $(dst_dir)/arch_%.elf
$(RISCV_OBJCOPY) $^ $@
$(bld_dir)/arch_%.dump: $(dst_dir)/arch_%.elf
$(RISCV_OBJDUMP) -D -w -x -S $^ > $@
ref_data:
mkdir -p $(bld_dir)/ref_data
for files in $(reference_src) ; do \
sed_input=$$files ; \
sed_output=$$(basename $${files%.*}) ; \
sed "s/\r$$//; \
s/\(........\)/\1,/g; \
s/.$$//; s/\(.*\),\(.*\),\(.*\),\(.*\)/\4,\3,\2,\1/;" \
$$sed_input > $(bld_dir)/ref_data/$$sed_output; \
done
cp_asm:
mkdir -p $(bld_dir)/arch_asm
$(call preprocessing,$(included_i),-march=rv32i)
$(call preprocessing_privilege,$(included_ip),-march=rv32i)
$(call preprocessing,$(included_im),-march=rv32im)
$(call preprocessing,$(included_ic),-march=rv32ic)
$(call preprocessing,$(included_e),-march=rv32e)
$(call preprocessing,$(included_em),-march=rv32em)
$(call preprocessing,$(included_ec),-march=rv32ec)
riscv_arch_tests_dir := $(if $(RISCV_ARCH_TESTS), $(RISCV_ARCH_TESTS), ./undefined)
riscv_tests_commit := 9141cf9274b610d059199e8aa2e21f54a0bc6a6e
## commit hash readed from local copy of https://github.com/riscv/riscv-arch-test.git
tmp_commit = $(shell cd $(riscv_arch_tests_dir) 2>/dev/null && git log -1 | grep "commit" | cut -f2 -d ' ')
is_commit_good = $(if $(subst $(riscv_tests_commit),,$(tmp_commit)),false,true)
# Color
RED=\033[0;31m
NC=\033[0m
check_version : $(riscv_arch_tests_dir)
@if [ ! -d $(riscv_arch_tests_dir) ]; then \
echo -e "$(RED)==========================================================================" &&\
echo " Error! Environment variable RISCV_ARCH_TESTS='$(riscv_arch_tests_dir)' " &&\
echo " directory not exist!" && \
echo "==========================================================================$(NC)" ; \
fi
ifneq ($(is_commit_good),true)
@echo -e "$(RED)=========================================================================="
@echo " Warning! Execution of test code is not guaranteed "
@echo " while using the current commit of repository located at : $(riscv_arch_tests_dir) ."
@echo " "
@echo " riscv_arch repository must point to commit $(riscv_tests_commit)!"
@echo -e "==========================================================================$(NC)"
endif
$(riscv_arch_tests_dir) :.
ifndef RISCV_ARCH_TESTS
@echo -e "$(RED)=========================================================================="
@echo " Error! Environment variable RISCV_ARCH_TESTS not set!"
@echo " You must set the environment variable RISCV_ARCH_TESTS"
@echo " The variable should point to the local copy of the"
@echo " repository https://github.com/riscv/riscv-arch-test.git"
@echo " with the commit $(riscv_tests_commit)"
@echo -e "==========================================================================$(NC)"
exit 1
endif
clean:
$(RM) -R $(test_elf) $(test_hex) $(bld_dir)
.PHONY: check_version clean ref_data cp_asm default

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
// RISC-V Compliance Test Header File
// Copyright (c) 2017, Codasip Ltd. All Rights Reserved.
// See LICENSE for license details.
//
// Description: Common header file for RV32I tests
#ifndef _COMPLIANCE_TEST_H
#define _COMPLIANCE_TEST_H
#include "riscv_test.h"
#include "encoding.h"
//-----------------------------------------------------------------------
// RV Compliance Macros
//-----------------------------------------------------------------------
#define RV_COMPLIANCE_HALT \
#define RV_COMPLIANCE_RV32M \
RVTEST_RV32M \
#define RV_COMPLIANCE_CODE_BEGIN \
RVTEST_CODE_BEGIN_OLD \
#define RV_COMPLIANCE_CODE_END \
RVTEST_CODE_END_OLD \
#define RV_COMPLIANCE_DATA_BEGIN \
RVTEST_DATA_BEGIN_OLD \
#define RV_COMPLIANCE_DATA_END \
RVTEST_DATA_END_OLD \
#endif// RISC-V Compliance IO Test Header File
/*
* Copyright (c) 2005-2018 Imperas Software Ltd., www.imperas.com
*
* 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.
*
*/
#ifndef _COMPLIANCE_IO_H
#define _COMPLIANCE_IO_H
//-----------------------------------------------------------------------
// RV IO Macros (Non functional)
//-----------------------------------------------------------------------
#ifdef _ARCH_OUTPUT
#define RVTEST_IO_PUSH(_SP) \
la _SP, begin_regstate; \
sw x3, 0(_SP); \
sw x4, 4(_SP); \
sw x5, 8(_SP);
#define RVTEST_IO_POP(_SP) \
la _SP, begin_regstate; \
lw x3, 0(_SP); \
lw x4, 4(_SP); \
lw x5, 8(_SP);
#define RVTEST_IO_WRITE_STR(_SP, _STR) \
.section .data.string; \
20001: \
.string _STR; \
.section .text.init; \
RVTEST_IO_PUSH(_SP) \
li x3, 0xF0000000; \
la x4, 20001b; \
2: lb x5, 0(x4); \
sb x5, 0(x3); \
beq x5, zero, 1f; \
add x4, x4, 1; \
j 2b; \
1: RVTEST_IO_POP(_SP)
#else // #ifdef _ARCH_OUTPUT
#define RVTEST_IO_WRITE_STR(_SP, _STR)
#endif // #end #ifdef _ARCH_OUTPUT
#define RVTEST_IO_INIT
#define RVTEST_IO_CHECK()
#define RVTEST_IO_ASSERT_GPR_EQ(_SP, _R, _I)
#define RVTEST_IO_ASSERT_SFPR_EQ(_F, _R, _I)
#define RVTEST_IO_ASSERT_DFPR_EQ(_D, _R, _I)
#define RVTEST_IO_ASSERT_EQ(_R, _I)
#endif // _COMPLIANCE_IO_H

View File

@@ -0,0 +1,253 @@
// See LICENSE for license details.
#ifndef _ENV_PHYSICAL_SINGLE_CORE_H
#define _ENV_PHYSICAL_SINGLE_CORE_H
#include "encoding.h"
#include "sc_test.h"
.noaltmacro
//-----------------------------------------------------------------------
// Begin Macro
//-----------------------------------------------------------------------
#define RVTEST_RV64U \
.macro init; \
.endm
#define RVTEST_RV64UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV32U \
.macro init; \
.endm
#define RVTEST_RV32UF \
.macro init; \
RVTEST_FP_ENABLE; \
.endm
#define RVTEST_RV64M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV64S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#define RVTEST_RV32M \
.macro init; \
RVTEST_ENABLE_MACHINE; \
.endm
#define RVTEST_RV32S \
.macro init; \
RVTEST_ENABLE_SUPERVISOR; \
.endm
#if __riscv_xlen == 64
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
#else
# define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
#endif
#define INIT_PMP \
la t0, 1f; \
csrw mtvec, t0; \
li t0, -1; /* Set up a PMP to permit all accesses */ \
csrw pmpaddr0, t0; \
li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \
csrw pmpcfg0, t0; \
.align 2; \
1:
#define INIT_SATP \
la t0, 1f; \
csrw mtvec, t0; \
csrwi satp, 0; \
.align 2; \
1:
#define DELEGATE_NO_TRAPS \
la t0, 1f; \
csrw mtvec, t0; \
csrwi medeleg, 0; \
csrwi mideleg, 0; \
csrwi mie, 0; \
.align 2; \
1:
#define RVTEST_ENABLE_SUPERVISOR \
li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \
csrs mstatus, a0; \
li a0, SIP_SSIP | SIP_STIP; \
csrs mideleg, a0; \
#define RVTEST_ENABLE_MACHINE \
li a0, MSTATUS_MPP; \
csrs mstatus, a0; \
#define RVTEST_FP_ENABLE \
li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
csrs mstatus, a0; \
csrwi fcsr, 0
#define RISCV_MULTICORE_DISABLE \
csrr a0, mhartid; \
1: bnez a0, 1b
#define EXTRA_TVEC_USER
#define EXTRA_TVEC_MACHINE
#define EXTRA_INIT
#define EXTRA_INIT_TIMER
#define PRIV_MISA_S 0
//
// undefine some unusable CSR Accesses if no PRIV Mode present
//
#if defined(PRIV_MISA_S)
# if (PRIV_MISA_S==0)
# undef INIT_SATP
# define INIT_SATP
# undef INIT_PMP
# define INIT_PMP
# undef DELEGATE_NO_TRAPS
# define DELEGATE_NO_TRAPS
# undef RVTEST_ENABLE_SUPERVISOR
# define RVTEST_ENABLE_SUPERVISOR
# endif
#endif
#if defined(PRIV_MISA_U)
# if (PRIV_MISA_U==0)
# endif
#endif
#if defined(TRAPHANDLER)
#include TRAPHANDLER
#endif
#define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */
#define RVTEST_CODE_BEGIN_OLD \
.section .text.init; \
.balign 512; \
.weak stvec_handler; \
.weak mtvec_handler; \
.globl _start; \
_start: \
/* reset vector */ \
j reset_vector; \
.balign 64; \
trap_vector: \
/* test whether the test came from pass/fail */ \
csrr a4, mcause; \
li a5, CAUSE_USER_ECALL; \
beq a4, a5, write_tohost; \
li a5, CAUSE_SUPERVISOR_ECALL; \
beq a4, a5, write_tohost; \
li a5, CAUSE_MACHINE_ECALL; \
beq a4, a5, write_tohost; \
/* if an mtvec_handler is defined, jump to it */ \
la a4, mtvec_handler; \
beqz a4, 1f; \
jr a4; \
/* was it an interrupt or an exception? */ \
1: csrr a4, mcause; \
bgez a4, handle_exception; \
INTERRUPT_HANDLER; \
handle_exception: \
/* we don't know how to handle whatever the exception was */ \
other_exception: \
/* some unhandlable exception occurred */ \
1: ori TESTNUM, TESTNUM, 1337; \
write_tohost: \
tail sc_exit; \
reset_vector: \
RISCV_MULTICORE_DISABLE; \
INIT_SATP; \
INIT_PMP; \
DELEGATE_NO_TRAPS; \
li TESTNUM, 0; \
la t0, trap_vector; \
csrw mtvec, t0; \
CHECK_XLEN; \
/* if an stvec_handler is defined, delegate exceptions to it */ \
la t0, stvec_handler; \
beqz t0, 1f; \
csrw stvec, t0; \
li t0, (1 << CAUSE_LOAD_PAGE_FAULT) | \
(1 << CAUSE_STORE_PAGE_FAULT) | \
(1 << CAUSE_FETCH_PAGE_FAULT) | \
(1 << CAUSE_MISALIGNED_FETCH) | \
(1 << CAUSE_USER_ECALL) | \
(1 << CAUSE_BREAKPOINT); \
csrw medeleg, t0; \
csrr t1, medeleg; \
bne t0, t1, other_exception; \
1: csrwi mstatus, 0; \
init; \
EXTRA_INIT; \
EXTRA_INIT_TIMER; \
la t0, 1f; \
csrw mepc, t0; \
csrr a0, mhartid; \
mret; \
1: \
begin_testcode:
//-----------------------------------------------------------------------
// End Macro
//-----------------------------------------------------------------------
#define RVTEST_CODE_END_OLD \
end_testcode: \
ecall;
//-----------------------------------------------------------------------
// Pass/Fail Macro
//-----------------------------------------------------------------------
#define RVTEST_SYNC fence
//#define RVTEST_SYNC nop
#define RVTEST_PASS \
RVTEST_SYNC; \
li TESTNUM, 1; \
SWSIG (0, TESTNUM); \
ecall
#define TESTNUM gp
#define RVTEST_FAIL \
RVTEST_SYNC; \
1: beqz TESTNUM, 1b; \
sll TESTNUM, TESTNUM, 1; \
or TESTNUM, TESTNUM, 1; \
SWSIG (0, TESTNUM); \
la x1, end_testcode; \
jr x1;
//-----------------------------------------------------------------------
// Data Section Macro
//-----------------------------------------------------------------------
#define EXTRA_DATA
#define RVTEST_DATA_BEGIN_OLD \
.align 4; .global begin_signature; begin_signature:
#define RVTEST_DATA_END_OLD \
.balign 4; .global end_signature; end_signature: \
EXTRA_DATA \
.pushsection .tohost,"aw",@progbits; \
.align 8; .global tohost; tohost: .dword 0; \
.align 8; .global fromhost; fromhost: .dword 0; \
.popsection; \
.align 8; .global begin_regstate; begin_regstate: \
.word 128; \
.align 8; .global end_regstate; end_regstate: \
.word 4;
#endif

View File

@@ -0,0 +1,199 @@
## @file
## Syntacore SCR* tests
##
## @copyright 2015-2018 Syntacore. All rights reserved.
## RISCV-Compliance
##
ARCH ?=im
override ARCH:=rv32$(ARCH)
src_dir := $(CURDIR)
RISCV_COMPLIANCE_TESTS := $(src_dir)/../../../dependencies/riscv-compliance/
#I IM IMC IC
#EM EMC EC
ifeq (rv32e,$(findstring rv32e,$(ARCH)))
$(info >>> RV32E - no compliance tests)
else ## ifdef SCR_BASE_RVE_EXT
#ifeq (rv32i,$(findstring rv32i,$(ARCH)))
ifeq ($(ARCH),$(filter $(ARCH),rv32i rv32im rv32imc rv32ic))
$(info >>> I32 TESTS)
included_i += $(filter %.S,\
$(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32i/src/*))
included_i += $(filter %.S,\
$(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32Zicsr/src/*))
included_i += $(filter %.S,\
$(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32Zifencei/src/*))
compliance_set += $(included_i)
endif
#$(if or ifeq(rv32im,$(findstring rv32im,$(ARCH))), (rv32imc,$(findstring rv32imc,$(ARCH))))
ifeq ($(ARCH),$(filter $(ARCH), rv32im rv32imc))
$(info >>> IM32 TESTS)
included_im += $(filter %.S,\
$(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32im/src/*))
compliance_set += $(included_im)
endif ##
ifeq (rv32imc,$(findstring rv32imc,$(ARCH)))
$(info >>> IMC32 TESTS)
included_imc += $(filter %.S,\
$(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32imc/src/*))
compliance_set += $(included_imc)
endif ## ifeq (rv32imc,$(findstring rv32imc,$(ARCH)))
ifeq (rv32ic,$(findstring rv32ic,$(ARCH)))
endif
endif ##
$(info >>>$(ARCH) set included)
ifeq ($(compliance_set),)
$(info >>> No compliance tests included)
endif
$(info >>>>> compliance set: $(compliance_set))
dst_dir := $(bld_dir)
test_name := riscv_compliance
bld_dir := $(addprefix $(dst_dir)/, $(test_name))
obj_dir := $(bld_dir)/riscv_compliance_objs
#cut_list += scall csr shamt simple
cut_list += I-MISALIGN_JMP-01 I-MISALIGN_LDST-01 I-EBREAK-01 I-ECALL-01
reference_src += $(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32i*/*/*.reference_output)
reference_src += $(wildcard $(RISCV_COMPLIANCE_TESTS)/riscv-test-suite/rv32Zi*/*/*.reference_output)
testnames := $(basename $(notdir $(compliance_set)))
filtered := $(filter-out $(cut_list),$(testnames))
objs := $(addprefix $(bld_dir)/,$(filtered:%=%.o))
test_elf := $(addprefix $(dst_dir)/compliance_,$(filtered:%=%.elf))
test_hex := $(addprefix $(dst_dir)/compliance_,$(filtered:%=%.hex))
test_dump := $(addprefix $(bld_dir)/compliance_,$(filtered:%=%.dump))
compliance_macros_file := $(root_dir)/sim/tests/riscv_compliance/compliance_io.h
compliance_output ?= true
testnames_i := $(basename $(notdir $(included_i)))
testnames_im := $(basename $(notdir $(included_im)))
testnames_imc := $(basename $(notdir $(included_imc)))
filtered_i := $(filter-out $(cut_list),$(testnames_i))
filtered_im := $(filter-out $(cut_list),$(testnames_im))
filtered_imc := $(filter-out $(cut_list),$(testnames_imc))
# ARCH_FLAGS := -Wa,-march=rv32im -march=rv32im
# ARCH_FLAGS_C := -Wa,-march=rv32imc -march=rv32imc
CFLAGS := -I$(inc_dir) -I$(src_dir) -DASM -mabi=ilp32 -D__riscv_xlen=32 -w
LDFLAGS := -static -fvisibility=hidden -nostdlib -nostartfiles -T$(inc_dir)/link.ld -march=$(ARCH)_zicsr_zifencei -mabi=ilp32
GCCVERSIONGT7 := $(shell expr `$(RISCV_GCC) -dumpfullversion | cut -f1 -d'.'` \> 7)
ifeq "$(GCCVERSIONGT7)" "1"
LDFLAGS += -mno-relax
endif
VPATH += $(src_dir) $(bld_dir) $(obj_dir) $(asm_path) $(ref_path) $(RISCV_COMPLIANCE_TESTS)
ifeq ($(compliance_output), true)
CFLAGS += -D_COMPLIANCE_OUTPUT
endif
default: clean log_requested_tgt check_version cp_asm ref_data $(test_elf) $(test_hex) $(test_dump)
define compile_template
$(obj_dir)/$(1).o: $(obj_dir) cp_asm
$(RISCV_GCC) -c $$(bld_dir)/compliance_asm/$(1).S $$(CFLAGS) -Wa,$(2) $(2) -o $$@
endef
define preprocessing
for test_asm in $(1); do \
march_tmp=$$test_asm ; \
march_tmp=$${march_tmp%/src*} ; \
march_tmp=$$(basename $$march_tmp) ; \
file_name="$$(basename $${test_asm})" ; \
$(RISCV_GCC) $(CFLAGS) -Wa,$(2) $(2) -E $$test_asm \
-o $(bld_dir)/compliance_asm/$$file_name ; \
done
endef
$(foreach SRC,$(filtered_i),$(eval $(call compile_template,$(SRC),-march=rv32i_zicsr_zifencei)))
$(foreach SRC,$(filtered_im),$(eval $(call compile_template,$(SRC),-march=rv32im_zicsr_zifencei)))
$(foreach SRC,$(filtered_imc),$(eval $(call compile_template,$(SRC),-march=rv32imc_zicsr_zifencei)))
log_requested_tgt: $(bld_dir)
$(foreach test_name, $(filtered), $(eval $(shell echo compliance_$(test_name).hex >> $(bld_dir)/../test_info)))
$(bld_dir) :
mkdir -p $(bld_dir)
$(obj_dir) : | ref_data
mkdir -p $(obj_dir)
$(dst_dir)/compliance_%.elf: $(obj_dir)/%.o | $(dep_files)
$(RISCV_GCC) $^ $(LDFLAGS) -o $@ -g
$(dst_dir)/compliance_%.hex: $(dst_dir)/compliance_%.elf
$(RISCV_OBJCOPY) $^ $@
$(bld_dir)/compliance_%.dump: $(dst_dir)/compliance_%.elf
$(RISCV_OBJDUMP) -D -w -x -S $^ > $@
ref_data:
mkdir -p $(bld_dir)/ref_data
for files in $(reference_src) ; do \
sed_input=$$files ; \
sed_output=$$(basename $${files%.*}) ; \
sed "s/\r$$//; \
s/\(........\)/\1,/g; \
s/.$$//; s/\(.*\),\(.*\),\(.*\),\(.*\)/\4,\3,\2,\1/;" \
$$sed_input > $(bld_dir)/ref_data/$$sed_output; \
done
cp_asm:
mkdir -p $(bld_dir)/compliance_asm
$(call preprocessing,$(included_i),-march=rv32i_zicsr_zifencei)
$(call preprocessing,$(included_im),-march=rv32im_zicsr_zifencei)
$(call preprocessing,$(included_imc),-march=rv32imc_zicsr_zifencei)
riscv_compliance_tests_dir := $(if $(RISCV_COMPLIANCE_TESTS), $(RISCV_COMPLIANCE_TESTS), ./undefined)
riscv_tests_commit := d51259b2a949be3af02e776c39e135402675ac9b
## commit hash readed from local copy of https://github.com/riscv/riscv-compliance
tmp_commit = $(shell cd $(riscv_compliance_tests_dir) 2>/dev/null && git log -1 | grep "commit" | cut -f2 -d ' ')
is_commit_good = $(if $(subst $(riscv_tests_commit),,$(tmp_commit)),false,true)
# Color
RED=\033[0;31m
NC=\033[0m
check_version : $(riscv_compliance_tests_dir)
@if [ ! -d $(riscv_compliance_tests_dir) ]; then \
echo -e "$(RED)==========================================================================" &&\
echo " Error! Environment variable RISCV_COMPLIANCE_TESTS='$(riscv_compliance_tests_dir)' " &&\
echo " directory not exist!" && \
echo "==========================================================================$(NC)" ; \
fi
ifneq ($(is_commit_good),true)
@echo -e "$(RED)=========================================================================="
@echo " Warning! Execution of test code is not guaranteed "
@echo " while using the current commit of repository located at : $(riscv_compliance_tests_dir) ."
@echo " "
@echo " riscv_compliance repository must point to commit $(riscv_tests_commit)!"
@echo -e "==========================================================================$(NC)"
endif
$(riscv_compliance_tests_dir) :.
ifndef RISCV_COMPLIANCE_TESTS
@echo -e "$(RED)=========================================================================="
@echo " Error! Environment variable RISCV_COMPLIANCE_TESTS not set!"
@echo " You must set the environment variable RISCV_COMPLIANCE_TESTS"
@echo " The variable should point to the local copy of the"
@echo " repository https://github.com/riscv/riscv-compliance"
@echo " with the commit $(riscv_tests_commit)"
@echo -e "==========================================================================$(NC)"
exit 1
endif
clean:
$(RM) -R $(test_elf) $(test_hex) $(bld_dir)
.PHONY: check_version clean ref_data cp_asm default

View File

@@ -0,0 +1,683 @@
/*
COPY OF /riscv-compliance/riscv-test-env/aw_test_macros.h
*/
// See LICENSE for license details.
#ifndef __TEST_MACROS_SCALAR_H
#define __TEST_MACROS_SCALAR_H
#-----------------------------------------------------------------------
# Helper macros
#-----------------------------------------------------------------------
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
#define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1: srli a0, a0, 31; la t0, begin_signature; sw a0, 0(t0)
#define TESTNUM gp
#define SWSIG( testnum, testreg ) \
la x28, test_res; \
sw testreg, (testnum<<2)(x28); \
#
# Address = base+(testnum<<2)
# sw testreg, (testnum<<2)(basereg)
#
#define TEST_CASE( testnum, testreg, correctval, code... ) \
test_ ## testnum: \
code; \
li x29, MASK_XLEN(correctval); \
li TESTNUM, testnum; \
SWSIG(testnum,testreg); \
bne testreg, x29, fail;
# We use a macro hack to simpify code generation for various numbers
# of bubble cycles.
#define TEST_INSERT_NOPS_0
#define TEST_INSERT_NOPS_1 nop; TEST_INSERT_NOPS_0
#define TEST_INSERT_NOPS_2 nop; TEST_INSERT_NOPS_1
#define TEST_INSERT_NOPS_3 nop; TEST_INSERT_NOPS_2
#define TEST_INSERT_NOPS_4 nop; TEST_INSERT_NOPS_3
#define TEST_INSERT_NOPS_5 nop; TEST_INSERT_NOPS_4
#define TEST_INSERT_NOPS_6 nop; TEST_INSERT_NOPS_5
#define TEST_INSERT_NOPS_7 nop; TEST_INSERT_NOPS_6
#define TEST_INSERT_NOPS_8 nop; TEST_INSERT_NOPS_7
#define TEST_INSERT_NOPS_9 nop; TEST_INSERT_NOPS_8
#define TEST_INSERT_NOPS_10 nop; TEST_INSERT_NOPS_9
#-----------------------------------------------------------------------
# RV64UI MACROS
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Tests for instructions with immediate operand
#-----------------------------------------------------------------------
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x30, result, \
li x1, MASK_XLEN(val1); \
inst x30, x1, SEXT_IMM(imm); \
)
#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
inst x1, x1, SEXT_IMM(imm); \
)
#define TEST_IMM_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
inst x30, x1, SEXT_IMM(imm); \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x30, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_IMM_SRC1_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \
TEST_CASE( testnum, x30, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x30, x1, SEXT_IMM(imm); \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_IMM_ZEROSRC1( testnum, inst, result, imm ) \
TEST_CASE( testnum, x1, result, \
inst x1, x0, SEXT_IMM(imm); \
)
#define TEST_IMM_ZERODEST( testnum, inst, val1, imm ) \
TEST_CASE( testnum, x0, 0, \
li x1, MASK_XLEN(val1); \
inst x0, x1, SEXT_IMM(imm); \
)
#-----------------------------------------------------------------------
# Tests for an instruction with register operands
#-----------------------------------------------------------------------
#define TEST_R_OP( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x30, result, \
li x1, val1; \
inst x30, x1; \
)
#define TEST_R_SRC1_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x1, result, \
li x1, val1; \
inst x1, x1; \
)
#define TEST_R_DEST_BYPASS( testnum, nop_cycles, inst, result, val1 ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, val1; \
inst x30, x1; \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x30, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#-----------------------------------------------------------------------
# Tests for an instruction with register-register operands
#-----------------------------------------------------------------------
#define TEST_RR_OP( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x30, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x30, x1, x2; \
)
#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x1, x1, x2; \
)
#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x2, x1, x2; \
)
#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \
TEST_CASE( testnum, x1, result, \
li x1, MASK_XLEN(val1); \
inst x1, x1, x1; \
)
#define TEST_RR_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, val2 ) \
TEST_CASE( testnum, x6, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x30, x1, x2; \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x30, 0; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
TEST_CASE( testnum, x30, result, \
li x4, 0; \
1: li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## src1_nops \
li x2, MASK_XLEN(val2); \
TEST_INSERT_NOPS_ ## src2_nops \
inst x30, x1, x2; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \
TEST_CASE( testnum, x30, result, \
li x4, 0; \
1: li x2, MASK_XLEN(val2); \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, MASK_XLEN(val1); \
TEST_INSERT_NOPS_ ## src2_nops \
inst x30, x1, x2; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
)
#define TEST_RR_ZEROSRC1( testnum, inst, result, val ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val); \
inst x2, x0, x1; \
)
#define TEST_RR_ZEROSRC2( testnum, inst, result, val ) \
TEST_CASE( testnum, x2, result, \
li x1, MASK_XLEN(val); \
inst x2, x1, x0; \
)
#define TEST_RR_ZEROSRC12( testnum, inst, result ) \
TEST_CASE( testnum, x1, result, \
inst x1, x0, x0; \
)
#define TEST_RR_ZERODEST( testnum, inst, val1, val2 ) \
TEST_CASE( testnum, x0, 0, \
li x1, MASK_XLEN(val1); \
li x2, MASK_XLEN(val2); \
inst x0, x1, x2; \
)
#-----------------------------------------------------------------------
# Test memory instructions
#-----------------------------------------------------------------------
#define TEST_LD_OP( testnum, inst, result, offset, base ) \
TEST_CASE( testnum, x30, result, \
la x1, base; \
inst x30, offset(x1); \
)
#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \
TEST_CASE( testnum, x30, result, \
la x1, base; \
li x2, result; \
store_inst x2, offset(x1); \
load_inst x30, offset(x1); \
)
#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: la x1, base; \
inst x30, offset(x1); \
TEST_INSERT_NOPS_ ## nop_cycles \
addi x6, x30, 0; \
li x29, result; \
bne x6, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b; \
#define TEST_LD_SRC1_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: la x1, base; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x30, offset(x1); \
li x29, result; \
bne x30, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_ST_SRC12_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: li x1, result; \
TEST_INSERT_NOPS_ ## src1_nops \
la x2, base; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x30, offset(x2); \
li x29, result; \
bne x30, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_ST_SRC21_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: la x2, base; \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, result; \
TEST_INSERT_NOPS_ ## src2_nops \
store_inst x1, offset(x2); \
load_inst x30, offset(x2); \
li x29, result; \
bne x30, x29, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_BR2_OP_TAKEN( testnum, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x1, val1; \
li x2, val2; \
inst x1, x2, 2f; \
bne x0, TESTNUM, fail; \
1: bne x0, TESTNUM, 3f; \
2: inst x1, x2, 1b; \
bne x0, TESTNUM, fail; \
3:
#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x1, val1; \
li x2, val2; \
inst x1, x2, 1f; \
bne x0, TESTNUM, 2f; \
1: bne x0, TESTNUM, fail; \
2: inst x1, x2, 1b; \
3:
#define TEST_BR2_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: li x1, val1; \
TEST_INSERT_NOPS_ ## src1_nops \
li x2, val2; \
TEST_INSERT_NOPS_ ## src2_nops \
inst x1, x2, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_BR2_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: li x2, val2; \
TEST_INSERT_NOPS_ ## src1_nops \
li x1, val1; \
TEST_INSERT_NOPS_ ## src2_nops \
inst x1, x2, fail; \
addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# Test jump instructions
#-----------------------------------------------------------------------
#define TEST_JR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: la x6, 2f; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x6; \
bne x0, TESTNUM, fail; \
2: addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#define TEST_JALR_SRC1_BYPASS( testnum, nop_cycles, inst ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
li x4, 0; \
1: la x6, 2f; \
TEST_INSERT_NOPS_ ## nop_cycles \
inst x19, x6, 0; \
bne x0, TESTNUM, fail; \
2: addi x4, x4, 1; \
li x5, 2; \
bne x4, x5, 1b \
#-----------------------------------------------------------------------
# RV64UF MACROS
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Tests floating-point instructions
#-----------------------------------------------------------------------
#define qNaNf 0f:7fc00000
#define sNaNf 0f:7f800001
#define qNaN 0d:7ff8000000000000
#define sNaN 0d:7ff0000000000001
#define TEST_FP_OP_S_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
la a0, test_ ## testnum ## _data ;\
flw f0, 0(a0); \
flw f1, 4(a0); \
flw f2, 8(a0); \
lw a3, 12(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 2; \
test_ ## testnum ## _data: \
.float val1; \
.float val2; \
.float val3; \
.result; \
.popsection
#define TEST_FP_OP_D_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
la a0, test_ ## testnum ## _data ;\
fld f0, 0(a0); \
fld f1, 8(a0); \
fld f2, 16(a0); \
ld a3, 24(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.double val1; \
.double val2; \
.double val3; \
.result; \
.popsection
// TODO: assign a separate mem location for the comparison address?
#define TEST_FP_OP_D32_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
la a0, test_ ## testnum ## _data ;\
fld f0, 0(a0); \
fld f1, 8(a0); \
fld f2, 16(a0); \
lw a3, 24(a0); \
lw t1, 28(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne t1, t2, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.double val1; \
.double val2; \
.double val3; \
.result; \
.popsection
#define TEST_FCVT_S_D32( testnum, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_FCVT_S_D( testnum, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fmv.x.d a0, f3)
#define TEST_FCVT_D_S( testnum, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \
fcvt.d.s f3, f0; fcvt.s.d f3, f3; fmv.x.s a0, f3)
#define TEST_FP_OP1_S( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.s a0, f3)
#define TEST_FP_OP1_D32( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
inst f3, f0; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP1_D( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.d a0, f3)
#define TEST_FP_OP1_S_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.s a0, f3)
#define TEST_FP_OP1_D32_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP1_D_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fmv.x.d a0, f3)
#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.s a0, f3)
#define TEST_FP_OP2_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
inst f3, f0, f1; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP2_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
inst f3, f0, f1; fmv.x.d a0, f3)
#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.s a0, f3)
#define TEST_FP_OP3_D32( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, val3, \
inst f3, f0, f1, f2; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
// ^: store computation result in address from a0, load high-word into t2
#define TEST_FP_OP3_D( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, val3, \
inst f3, f0, f1, f2; fmv.x.d a0, f3)
#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_INT_OP_D32( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst a0, f0, f1; li t2, 0)
#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst a0, f0, rm)
#define TEST_FP_CMP_OP_S( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FP_CMP_OP_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
inst a0, f0, f1; li t2, 0)
#define TEST_FP_CMP_OP_D( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
inst a0, f0, f1)
#define TEST_FCLASS_S(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.s.x fa0, a0; \
fclass.s a0, fa0)
#define TEST_FCLASS_D32(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, \
la a0, test_ ## testnum ## _data ;\
fld fa0, 0(a0); \
fclass.d a0, fa0) \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.dword input; \
.popsection
#define TEST_FCLASS_D(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, li a0, input; fmv.d.x fa0, a0; \
fclass.d a0, fa0)
#define TEST_INT_FP_OP_S( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
la a0, test_ ## testnum ## _data ;\
lw a3, 0(a0); \
li a0, val1; \
inst f0, a0; \
fsflags x0; \
fmv.x.s a0, f0; \
bne a0, a3, fail; \
.pushsection .data; \
.align 2; \
test_ ## testnum ## _data: \
.float result; \
.popsection
#define TEST_INT_FP_OP_D32( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
la a0, test_ ## testnum ## _data ;\
lw a3, 0(a0); \
lw a4, 4(a0); \
li a1, val1; \
inst f0, a1; \
\
fsd f0, 0(a0); \
lw a1, 4(a0); \
lw a0, 0(a0); \
\
fsflags x0; \
bne a0, a3, fail; \
bne a1, a4, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.double result; \
.popsection
#define TEST_INT_FP_OP_D( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
la a0, test_ ## testnum ## _data ;\
ld a3, 0(a0); \
li a0, val1; \
inst f0, a0; \
fsflags x0; \
fmv.x.d a0, f0; \
bne a0, a3, fail; \
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.double result; \
.popsection
// We need some special handling here to allow 64-bit comparison in 32-bit arch
// TODO: find a better name and clean up when intended for general usage?
#define TEST_CASE_D32( testnum, testreg1, testreg2, correctval, code... ) \
test_ ## testnum: \
code; \
la x31, test_ ## testnum ## _data ; \
lw x29, 0(x31); \
lw x31, 4(x31); \
li TESTNUM, testnum; \
SWSIG (testnum, TESTNUM);\
bne testreg1, x29, fail;\
bne testreg2, x31, fail;\
.pushsection .data; \
.align 3; \
test_ ## testnum ## _data: \
.dword correctval; \
.popsection
// ^ x30 is used in some other macros, to avoid issues we use x31 for upper word
#-----------------------------------------------------------------------
# Pass and fail code (assumes test num is in TESTNUM)
#-----------------------------------------------------------------------
#define TEST_PASSFAIL \
bne x0, TESTNUM, pass; \
fail: \
RVTEST_FAIL; \
pass: \
RVTEST_PASS \
#-----------------------------------------------------------------------
# Test data section
#-----------------------------------------------------------------------
#define TEST_DATA
#endif

View File

@@ -0,0 +1,70 @@
// RISC-V Compliance IO Test Header File
/*
* Copyright (c) 2005-2018 Imperas Software Ltd., www.imperas.com
*
* 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.
*
*/
#ifndef _COMPLIANCE_IO_H
#define _COMPLIANCE_IO_H
//-----------------------------------------------------------------------
// RV IO Macros (Non functional)
//-----------------------------------------------------------------------
#ifdef _COMPLIANCE_OUTPUT
#define RVTEST_IO_PUSH(_SP) \
la _SP, begin_regstate; \
sw x3, 0(_SP); \
sw x4, 4(_SP); \
sw x5, 8(_SP);
#define RVTEST_IO_POP(_SP) \
la _SP, begin_regstate; \
lw x3, 0(_SP); \
lw x4, 4(_SP); \
lw x5, 8(_SP);
#define RVTEST_IO_WRITE_STR(_SP, _STR) \
.section .data.string; \
20001: \
.string _STR; \
.section .text; \
RVTEST_IO_PUSH(_SP) \
li x3, 0xF0000000; \
la x4, 20001b; \
2: lb x5, 0(x4); \
sb x5, 0(x3); \
beq x5, zero, 1f; \
add x4, x4, 1; \
j 2b; \
1: RVTEST_IO_POP(_SP)
#else // #ifdef _COMPLIANCE_OUTPUT
#define RVTEST_IO_WRITE_STR(_SP, _STR)
#endif // #end #ifdef _COMPLIANCE_OUTPUT
#define RVTEST_IO_INIT
#define RVTEST_IO_CHECK()
#define RVTEST_IO_ASSERT_GPR_EQ(_SP, _R, _I)
#define RVTEST_IO_ASSERT_SFPR_EQ(_F, _R, _I)
#define RVTEST_IO_ASSERT_DFPR_EQ(_D, _R, _I)
#define RVTEST_IO_ASSERT_EQ(_R, _I)
#endif // _COMPLIANCE_IO_H

View File

@@ -0,0 +1,31 @@
// RISC-V Compliance Test Header File
// Copyright (c) 2017, Codasip Ltd. All Rights Reserved.
// See LICENSE for license details.
//
// Description: Common header file for RV32I tests
#ifndef _COMPLIANCE_TEST_H
#define _COMPLIANCE_TEST_H
//-----------------------------------------------------------------------
// RV Compliance Macros
//-----------------------------------------------------------------------
#define RV_COMPLIANCE_HALT \
#define RV_COMPLIANCE_RV32M \
RVTEST_RV32M \
#define RV_COMPLIANCE_CODE_BEGIN \
RVTEST_CODE_BEGIN \
#define RV_COMPLIANCE_CODE_END \
RVTEST_CODE_END \
#define RV_COMPLIANCE_DATA_BEGIN \
RVTEST_DATA_BEGIN \
#define RV_COMPLIANCE_DATA_END \
RVTEST_DATA_END \
#endif

View File

@@ -0,0 +1,7 @@
#ifndef _RISCV_TEST_H
#define _RISCV_TEST_H
#include "test_macros.h"
#endif

View File

@@ -0,0 +1,463 @@
// RISC-V Compliance IO Test Header File
/*
* Copyright (c) 2005-2018 Imperas Software Ltd., www.imperas.com
*
* 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.
*
*/
#include "riscv_macros.h"
//
// In general the following registers are reserved
// ra, a0, t0, t1
// Additionally on an assertion violation, t1, t2 are overwritten
// x1, x10, x5, x6, x7 respectively
// Floating registers reserved
// f5
//
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
// Base function for integer operations
#define TEST_CASE(testreg, destreg, correctval, swreg, offset, code... ) \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(testreg, destreg, correctval) \
// Base functions for single precision floating point operations
#define TEST_CASE_FP(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg1, 0(a0); \
flw reg2, 4(a0); \
lw t1, 8(a0); \
code; \
fsw destreg, offset(swreg); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, t1, correctval) \
.pushsection .data; \
.align 3; \
test_ ## test_num ## _data: \
.float val1; \
.float val2; \
.word correctval; \
.popsection
#define TEST_CASE_FP_I(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
lw t1, 0(a0); \
code; \
fsw destreg, offset(swreg); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, t1, correctval) \
.pushsection .data; \
.align 1; \
test_ ## test_num ## _data: \
.word correctval; \
.popsection
#define TEST_CASE_FP_I2(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg, 0(a0); \
lw t1, 4(a0); \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
.pushsection .data; \
.align 2; \
test_ ## test_num ## _data: \
.float val; \
.word correctval; \
.popsection
#define TEST_CASE_FP_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg1, 0(a0); \
flw reg2, 4(a0); \
flw reg3, 8(a0); \
lw t1, 12(a0); \
code; \
fsw destreg, offset(swreg); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, t1, correctval) \
.pushsection .data; \
.align 4; \
test_ ## test_num ## _data: \
.float val1; \
.float val2; \
.float val3; \
.word correctval; \
.popsection
#define TEST_CASE_FP_FMVXS(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg, 0(a0); \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
.pushsection .data; \
.align 1; \
test_ ## test_num ## _data: \
.float val; \
.popsection
#define TEST_CASE_FP_FMVSX(test_num, destreg, reg, correctval, val, swreg, offset, code...) \
la a0, test_ ## test_num ## _data; \
li reg, val; \
code; \
fsw destreg, offset(swreg); \
lw a1, 0(a0); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, a1, correctval) \
.pushsection .data; \
.align 1; \
test_ ## test_num ## _data: \
.word correctval; \
.popsection
// Base functions for double precision floating point operations - rv32d
#define TEST_CASE_FPD(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
fld reg1, 0(a0); \
fld reg2, 8(a0); \
code; \
fsd destreg, offset(swreg); \
lw t1, 16(a0); \
lw t2, 20(a0); \
la a0, store_ ## test_num ## _data; \
fsd destreg, 0(a0); \
lw a1, 0(a0); \
lw a2, 4(a0); \
RVTEST_IO_ASSERT_DFPR_EQ(destreg, t2, t1, a2, a1, correctval) \
.pushsection .data; \
.align 3; \
test_ ## test_num ## _data: \
.double val1; \
.double val2; \
.dword correctval; \
.popsection; \
.pushsection .data; \
store_ ## test_num ## _data: \
.fill 1, 8, -1; \
.popsection
#define TEST_CASE_FPD_I(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
code; \
fsd destreg, offset(swreg); \
lw t1, 0(a0); \
lw t2, 4(a0); \
la a0, store_ ## test_num ## _data; \
fsd destreg, 0(a0); \
lw a1, 0(a0); \
lw a2, 4(a0); \
RVTEST_IO_ASSERT_DFPR_EQ(destreg, t2, t1, a2, a1, correctval) \
.pushsection .data; \
.align 1; \
test_ ## test_num ## _data: \
.dword correctval; \
.popsection; \
store_ ## test_num ## _data: \
.fill 1, 8, -1; \
.popsection
#define TEST_CASE_FPD_I2(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
fld reg, 0(a0); \
lw t1, 8(a0); \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
.pushsection .data; \
.align 2; \
test_ ## test_num ## _data: \
.double val; \
.word correctval; \
.popsection
#define TEST_CASE_FPD_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
fld reg1, 0(a0); \
fld reg2, 8(a0); \
fld reg3, 16(a0); \
code; \
fsd destreg, offset(swreg); \
lw t1, 24(a0); \
lw t2, 28(a0); \
la a0, store_ ## test_num ## _data; \
fsd destreg, 0(a0); \
lw a1, 0(a0); \
lw a2, 4(a0); \
RVTEST_IO_ASSERT_DFPR_EQ(destreg, t2, t1, a2, a1, correctval) \
.pushsection .data; \
.align 4; \
test_ ## test_num ## _data: \
.double val1; \
.double val2; \
.double val3; \
.dword correctval; \
.popsection; \
.pushsection .data; \
store_ ## test_num ## _data: \
.fill 1, 8, -1; \
.popsection
//Tests for a instructions with register-register operand
#define TEST_RR_OP(inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li reg1, MASK_XLEN(val1); \
li reg2, MASK_XLEN(val2); \
inst destreg, reg1, reg2; \
)
#define TEST_RR_SRC1( inst, destreg, reg, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val1); \
li reg, MASK_XLEN(val2); \
inst destreg, destreg, reg; \
)
#define TEST_RR_SRC2( inst, destreg, reg, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val1); \
li destreg, MASK_XLEN(val2); \
inst destreg, reg, destreg; \
)
#define TEST_RR_SRC12( inst, destreg, correctval, val, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val1); \
inst destreg, destreg, destreg; \
)
#define TEST_RR_ZERO1( inst, destreg, reg, correctval, val, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, x0, reg; \
)
#define TEST_RR_ZERO2( inst, destreg, reg, correctval, val, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg, x0; \
)
#define TEST_RR_ZERO12( inst, destreg, correctval, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
inst destreg, x0, x0; \
)
#define TEST_RR_ZERODEST( inst, reg1, reg2, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, x0, 0, swreg, offset, \
li reg1, MASK_XLEN(val1); \
li reg2, MASK_XLEN(val2); \
inst x0, reg1, reg2; \
)
//Tests for a instructions with register-immediate operand
#define TEST_IMM_OP( inst, destreg, reg, correctval, val, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg, SEXT_IMM(imm); \
)
#define TEST_IMM_SRC( inst, destreg, correctval, val, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val); \
inst destreg, destreg, SEXT_IMM(imm); \
)
#define TEST_IMM_ZEROSRC( inst, destreg, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
inst destreg, x0, SEXT_IMM(imm); \
)
#define TEST_IMM_ZERODEST( inst, reg, val, imm, swreg, offset, testreg) \
TEST_CASE(testreg, x0, 0, swreg, offset, \
li reg, MASK_XLEN(val); \
inst x0, reg, SEXT_IMM(imm); \
)
#define TEST_IMM_ONEREG( inst, destreg, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
inst destreg, SEXT_IMM(imm); \
)
#define TEST_AUIPC(inst, destreg, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
1: \
inst destreg, imm; \
la swreg, 1b; \
sub destreg, destreg, swreg; \
)
//Tests for a compressed instruction
#define TEST_CR_OP( inst, destreg, reg, correctval, val1, val2, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val1); \
li destreg, MASK_XLEN(val2); \
inst destreg, reg; \
)
#define TEST_CI_OP( inst, destreg, correctval, val, imm, swreg, offset, testreg) \
TEST_CASE(testreg, destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val); \
inst destreg, imm; \
)
#define TEST_CI_OP_NOREG(inst, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg,x0, correctval, swreg, offset, \
inst imm; \
)
//Tests for floating point instructions - single precision
#define TEST_FP_OP(test_num, inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset) \
TEST_CASE_FP(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, \
inst destreg, reg1, reg2; \
)
#define TEST_FP_ONEREG(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP(test_num, destreg, reg, reg, correctval, val, val, swreg, offset, \
inst destreg, reg; \
)
#define TEST_FP_4REG(test_num, inst, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset) \
TEST_CASE_FP_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, \
inst destreg, reg1, reg2, reg3; \
)
#define TEST_FP_I(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_I(test_num, destreg, reg, correctval, val, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg; \
)
#define TEST_FP_I2(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_I2(test_num, destreg, reg, correctval, val, swreg, offset, \
inst destreg, reg; \
)
//Tests for floating point instructions - double precision
#define TEST_FPD_OP(test_num, inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset) \
TEST_CASE_FPD(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, \
inst destreg, reg1, reg2; \
)
#define TEST_FPD_ONEREG(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FPD(test_num, destreg, reg, reg, correctval, val, val, swreg, offset, \
inst destreg, reg; \
)
#define TEST_FPD_4REG(test_num, inst, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset) \
TEST_CASE_FPD_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, \
inst destreg, reg1, reg2, reg3; \
)
#define TEST_FPD_I(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FPD_I(test_num, destreg, reg, correctval, val, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg; \
)
#define TEST_FPD_I2(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FPD_I2(test_num, destreg, reg, correctval, val, swreg, offset, \
inst destreg, reg; \
)
#define TEST_CADDI16SP(correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg,x2, correctval, swreg, offset, \
c.addi16sp x2, imm; \
)
#define TEST_CADDI4SPN(destreg, correctval, imm, swreg, offset, testreg) \
TEST_CASE(testreg,destreg, correctval, swreg, offset, \
c.addi4spn destreg, x2, SEXT_IMM(imm); \
)
#define TEST_CJL(inst, reg, val, swreg, offset) \
li x10, val; \
la reg, 1f; \
inst reg; \
li x10, 0x123ab; \
1: \
sw x10, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, x10, val); \
#define ABS(x) ((x >> 11) ^ x) - (x >> 11)
#define TEST_CJ(inst, reg, val, swreg, offset) \
li reg, val; \
inst 1f; \
li reg, 0x123ab; \
1: \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, val); \
#define TEST_CL(inst, reg, imm, swreg, offset) \
la reg, test_data; \
inst reg, imm(reg); \
sw reg, offset(swreg); \
// lw reg, imm(x2)
// c.lwsp reg, imm(x2)
#define TEST_CLWSP(reg, imm, swreg, offset) \
la x2, test_data; \
c.lwsp reg, imm(x2); \
sw reg, offset(swreg); \
#define TEST_CSW(test_data, inst, reg1, reg2, val, imm, swreg, offset) \
li reg1, val; \
la reg2, test_data; \
inst reg1, imm(reg2); \
lw reg1, imm(reg2); \
sw reg1, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg1, val); \
#define TEST_CSWSP(test_data, reg, val, imm, swreg, offset) \
la x2, test_data; \
li reg, val; \
c.swsp reg, imm(x2); \
lw reg, imm(x2); \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, val); \
#define TEST_CBEQZ(reg, val, swreg, offset) \
li reg, val; \
c.sub reg, reg; \
c.beqz reg, 3f; \
li reg, 0x123ab; \
3: \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, 0x0); \
#define TEST_CBNEZ(reg, val, swreg, offset) \
li reg, val; \
c.bnez reg, 4f; \
li reg, 0x0; \
4: \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, val); \
#define TEST_FMVXS(test_num, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_FMVXS(test_num, destreg, reg, correctval, val, swreg, offset, \
fmv.x.s destreg, reg; \
)
#define TEST_FMVSX(test_num, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_FMVSX(test_num, destreg, reg, correctval, val, swreg, offset, \
fmv.s.x destreg, reg; \
)
#define SWSIG(a,b)

View File

@@ -0,0 +1,593 @@
// RISC-V Compliance Test Header File
// Copyright (c) 2017, Codasip Ltd. All Rights Reserved.
// See LICENSE for license details.
//
// Description: Common header file for RV32I tests
#ifndef _TEST_MACROS_H
#define _TEST_MACROS_H
#include "riscv_macros.h"
// RISC-V Compliance IO Test Header File
/*
* Copyright (c) 2005-2018 Imperas Software Ltd., www.imperas.com
*
* 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.
*
*/
//
// In general the following registers are reserved
// ra, a0, t0, t1
// Additionally on an assertion violation, t1, t2 are overwritten
// x1, x10, x5, x6, x7 respectively
// Floating registers reserved
// f5
//
#define MASK_XLEN(x) ((x) & ((1 << (__riscv_xlen - 1) << 1) - 1))
#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11))
// Base function for integer operations
#define TEST_CASE(destreg, correctval, swreg, offset, code... ) \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
// Base functions for single precision floating point operations
#define TEST_CASE_FP(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg1, 0(a0); \
flw reg2, 4(a0); \
lw t1, 8(a0); \
code; \
fsw destreg, offset(swreg); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, t1, correctval) \
.pushsection .data; \
.balign 8; \
test_ ## test_num ## _data: \
.float val1; \
.float val2; \
.word correctval; \
.popsection
#define TEST_CASE_FP_I(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
lw t1, 0(a0); \
code; \
fsw destreg, offset(swreg); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, t1, correctval) \
.pushsection .data; \
.balign 2; \
test_ ## test_num ## _data: \
.word correctval; \
.popsection
#define TEST_CASE_FP_I2(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg, 0(a0); \
lw t1, 4(a0); \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
.pushsection .data; \
.balign 4; \
test_ ## test_num ## _data: \
.float val; \
.word correctval; \
.popsection
#define TEST_CASE_FP_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg1, 0(a0); \
flw reg2, 4(a0); \
flw reg3, 8(a0); \
lw t1, 12(a0); \
code; \
fsw destreg, offset(swreg); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, t1, correctval) \
.pushsection .data; \
.balign 16; \
test_ ## test_num ## _data: \
.float val1; \
.float val2; \
.float val3; \
.word correctval; \
.popsection
#define TEST_CASE_FP_FMVXS(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
flw reg, 0(a0); \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
.pushsection .data; \
.balign 2; \
test_ ## test_num ## _data: \
.float val; \
.popsection
#define TEST_CASE_FP_FMVSX(test_num, destreg, reg, correctval, val, swreg, offset, code...) \
la a0, test_ ## test_num ## _data; \
li reg, val; \
code; \
fsw destreg, offset(swreg); \
lw a1, 0(a0); \
RVTEST_IO_ASSERT_SFPR_EQ(destreg, a1, correctval) \
.pushsection .data; \
.balign 2; \
test_ ## test_num ## _data: \
.word correctval; \
.popsection
// Base functions for double precision floating point operations - rv32d
#define TEST_CASE_FPD(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
fld reg1, 0(a0); \
fld reg2, 8(a0); \
code; \
fsd destreg, offset(swreg); \
lw t1, 16(a0); \
lw t2, 20(a0); \
la a0, store_ ## test_num ## _data; \
fsd destreg, 0(a0); \
lw a1, 0(a0); \
lw a2, 4(a0); \
RVTEST_IO_ASSERT_DFPR_EQ(destreg, t2, t1, a2, a1, correctval) \
.pushsection .data; \
.balign 8; \
test_ ## test_num ## _data: \
.double val1; \
.double val2; \
.dword correctval; \
.popsection; \
.pushsection .data; \
store_ ## test_num ## _data: \
.fill 1, 8, -1; \
.popsection
#define TEST_CASE_FPD_I(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
code; \
fsd destreg, offset(swreg); \
lw t1, 0(a0); \
lw t2, 4(a0); \
la a0, store_ ## test_num ## _data; \
fsd destreg, 0(a0); \
lw a1, 0(a0); \
lw a2, 4(a0); \
RVTEST_IO_ASSERT_DFPR_EQ(destreg, t2, t1, a2, a1, correctval) \
.pushsection .data; \
.balign 2; \
test_ ## test_num ## _data: \
.dword correctval; \
.popsection; \
store_ ## test_num ## _data: \
.fill 1, 8, -1; \
.popsection
#define TEST_CASE_FPD_I2(test_num, destreg, reg, correctval, val, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
fld reg, 0(a0); \
lw t1, 8(a0); \
code; \
sw destreg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, destreg, correctval) \
.pushsection .data; \
.balign 4; \
test_ ## test_num ## _data: \
.double val; \
.word correctval; \
.popsection
#define TEST_CASE_FPD_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, code... ) \
la a0, test_ ## test_num ## _data; \
fld reg1, 0(a0); \
fld reg2, 8(a0); \
fld reg3, 16(a0); \
code; \
fsd destreg, offset(swreg); \
lw t1, 24(a0); \
lw t2, 28(a0); \
la a0, store_ ## test_num ## _data; \
fsd destreg, 0(a0); \
lw a1, 0(a0); \
lw a2, 4(a0); \
RVTEST_IO_ASSERT_DFPR_EQ(destreg, t2, t1, a2, a1, correctval) \
.pushsection .data; \
.balign 16; \
test_ ## test_num ## _data: \
.double val1; \
.double val2; \
.double val3; \
.dword correctval; \
.popsection; \
.pushsection .data; \
store_ ## test_num ## _data: \
.fill 1, 8, -1; \
.popsection
//Tests for a instructions with register-register operand
#define TEST_RR_OP(inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li reg1, MASK_XLEN(val1); \
li reg2, MASK_XLEN(val2); \
inst destreg, reg1, reg2; \
)
#define TEST_RR_SRC1( inst, destreg, reg, correctval, val1, val2, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val1); \
li reg, MASK_XLEN(val2); \
inst destreg, destreg, reg; \
)
#define TEST_RR_SRC2( inst, destreg, reg, correctval, val1, val2, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val1); \
li destreg, MASK_XLEN(val2); \
inst destreg, reg, destreg; \
)
#define TEST_RR_SRC12( inst, destreg, correctval, val, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val1); \
inst destreg, destreg, destreg; \
)
#define TEST_RR_ZERO1( inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, x0, reg; \
)
#define TEST_RR_ZERO2( inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg, x0; \
)
#define TEST_RR_ZERO12( inst, destreg, correctval, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
inst destreg, x0, x0; \
)
#define TEST_RR_ZERODEST( inst, reg1, reg2, val1, val2, swreg, offset) \
TEST_CASE( x0, 0, swreg, offset, \
li reg1, MASK_XLEN(val1); \
li reg2, MASK_XLEN(val2); \
inst x0, reg1, reg2; \
)
//Tests for a instructions with register-immediate operand
#define TEST_IMM_OP( inst, destreg, reg, correctval, val, imm, swreg, offset) \
TEST_CASE ( destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg, SEXT_IMM(imm); \
)
#define TEST_IMM_SRC( inst, destreg, correctval, val, imm, swreg, offset) \
TEST_CASE ( destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val); \
inst destreg, destreg, SEXT_IMM(imm); \
)
#define TEST_IMM_ZEROSRC( inst, destreg, correctval, imm, swreg, offset) \
TEST_CASE ( destreg, correctval, swreg, offset, \
inst destreg, x0, SEXT_IMM(imm); \
)
#define TEST_IMM_ZERODEST( inst, reg, val, imm, swreg, offset) \
TEST_CASE ( x0, 0, swreg, offset, \
li reg, MASK_XLEN(val); \
inst x0, reg, SEXT_IMM(imm); \
)
#define TEST_IMM_ONEREG( inst, destreg, correctval, imm, swreg, offset) \
TEST_CASE ( destreg, correctval, swreg, offset, \
inst destreg, SEXT_IMM(imm); \
)
#define TEST_AUIPC(inst, destreg, correctval, imm, swreg, offset) \
TEST_CASE ( destreg, correctval, swreg, offset, \
1: \
inst destreg, SEXT_IMM(imm); \
la swreg, 1b; \
sub destreg, destreg, swreg; \
)
//Tests for a compressed instruction
#define TEST_CR_OP( inst, destreg, reg, correctval, val1, val2, swreg, offset) \
TEST_CASE ( destreg, correctval, swreg, offset, \
li reg, MASK_XLEN(val1); \
li destreg, MASK_XLEN(val2); \
inst destreg, reg; \
)
#define TEST_CI_OP( inst, destreg, correctval, val, imm, swreg, offset) \
TEST_CASE( destreg, correctval, swreg, offset, \
li destreg, MASK_XLEN(val); \
inst destreg, imm; \
)
#define TEST_CI_OP_NOREG(inst, correctval, imm, swreg, offset) \
TEST_CASE (x0, correctval, swreg, offset, \
inst imm; \
)
//Tests for floating point instructions - single precision
#define TEST_FP_OP(test_num, inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset) \
TEST_CASE_FP(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, \
inst destreg, reg1, reg2; \
)
#define TEST_FP_ONEREG(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP(test_num, destreg, reg, reg, correctval, val, val, swreg, offset, \
inst destreg, reg; \
)
#define TEST_FP_4REG(test_num, inst, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset) \
TEST_CASE_FP_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, \
inst destreg, reg1, reg2, reg3; \
)
#define TEST_FP_I(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_I(test_num, destreg, reg, correctval, val, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg; \
)
#define TEST_FP_I2(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_I2(test_num, destreg, reg, correctval, val, swreg, offset, \
inst destreg, reg; \
)
//Tests for floating point instructions - double precision
#define TEST_FPD_OP(test_num, inst, destreg, reg1, reg2, correctval, val1, val2, swreg, offset) \
TEST_CASE_FPD(test_num, destreg, reg1, reg2, correctval, val1, val2, swreg, offset, \
inst destreg, reg1, reg2; \
)
#define TEST_FPD_ONEREG(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FPD(test_num, destreg, reg, reg, correctval, val, val, swreg, offset, \
inst destreg, reg; \
)
#define TEST_FPD_4REG(test_num, inst, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset) \
TEST_CASE_FPD_4REG(test_num, destreg, reg1, reg2, reg3, correctval, val1, val2, val3, swreg, offset, \
inst destreg, reg1, reg2, reg3; \
)
#define TEST_FPD_I(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FPD_I(test_num, destreg, reg, correctval, val, swreg, offset, \
li reg, MASK_XLEN(val); \
inst destreg, reg; \
)
#define TEST_FPD_I2(test_num, inst, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FPD_I2(test_num, destreg, reg, correctval, val, swreg, offset, \
inst destreg, reg; \
)
#define TEST_CADDI16SP(correctval, imm, swreg, offset) \
TEST_CASE(x2, correctval, swreg, offset, \
c.addi16sp x2, imm; \
)
#define TEST_CADDI4SPN(destreg, correctval, imm, swreg, offset) \
TEST_CASE(destreg, correctval, swreg, offset, \
c.addi4spn destreg, x2, SEXT_IMM(imm); \
)
#define TEST_CJL(inst, reg, val, swreg, offset) \
li x10, val; \
la reg, 1f; \
inst reg; \
li x10, 0x123ab; \
1: \
sw x10, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, x10, val); \
#define ABS(x) ((x >> 11) ^ x) - (x >> 11)
#define TEST_CJ(inst, reg, val, swreg, offset) \
li reg, val; \
inst 1f; \
li reg, 0x123ab; \
1: \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, val); \
#define TEST_CL(inst, reg, imm, swreg, offset) \
la reg, test_data; \
inst reg, imm(reg); \
sw reg, offset(swreg); \
// lw reg, imm(x2)
// c.lwsp reg, imm(x2)
#define TEST_CLWSP(reg, imm, swreg, offset) \
la x2, test_data; \
c.lwsp reg, imm(x2); \
sw reg, offset(swreg); \
#define TEST_CSW(test_data, inst, reg1, reg2, val, imm, swreg, offset) \
li reg1, val; \
la reg2, test_data; \
inst reg1, imm(reg2); \
lw reg1, imm(reg2); \
sw reg1, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg1, val); \
#define TEST_CSWSP(test_data, reg, val, imm, swreg, offset) \
la x2, test_data; \
li reg, val; \
c.swsp reg, imm(x2); \
lw reg, imm(x2); \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, val); \
#define TEST_CBEQZ(reg, val, swreg, offset) \
li reg, val; \
c.sub reg, reg; \
c.beqz reg, 3f; \
li reg, 0x123ab; \
3: \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, 0x0); \
#define TEST_CBNEZ(reg, val, swreg, offset) \
li reg, val; \
c.bnez reg, 4f; \
li reg, 0x0; \
4: \
sw reg, offset(swreg); \
RVTEST_IO_ASSERT_GPR_EQ(x31, reg, val); \
#define TEST_FMVXS(test_num, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_FMVXS(test_num, destreg, reg, correctval, val, swreg, offset, \
fmv.x.s destreg, reg; \
)
#define TEST_FMVSX(test_num, destreg, reg, correctval, val, swreg, offset) \
TEST_CASE_FP_FMVSX(test_num, destreg, reg, correctval, val, swreg, offset, \
fmv.s.x destreg, reg; \
)
#define SWSIG(a,b)
#if __riscv_xlen == 64
#define SATP_MODE SATP64_MODE
#else
#define SATP_MODE SATP32_MODE
#endif
#define SATP32_MODE 0x80000000
#define SATP32_ASID 0x7FC00000
#define SATP32_PPN 0x003FFFFF
#define SATP64_MODE 0xF000000000000000
#define SATP64_ASID 0x0FFFF00000000000
#define SATP64_PPN 0x00000FFFFFFFFFFF
#define SATP_MODE_OFF 0
#define SATP_MODE_SV32 1
#define SATP_MODE_SV39 8
#define SATP_MODE_SV48 9
#define SATP_MODE_SV57 10
#define SATP_MODE_SV64 11
#define TEST_FP_OP2_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \
inst f3, f0, f1; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_CASE_D32( testnum, testreg1, testreg2, correctval, code... ) \
test_ ## testnum: \
code; \
la x31, test_ ## testnum ## _data ; \
lw x29, 0(x31); \
lw x31, 4(x31); \
li TESTNUM, testnum; \
bne testreg1, x29, fail;\
bne testreg2, x31, fail;\
.pushsection .data; \
.balign 8; \
test_ ## testnum ## _data: \
.dword correctval; \
.popsection
#define TEST_FP_OP_D32_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
fld f0, 0(a0); \
fld f1, 8(a0); \
fld f2, 16(a0); \
lw a3, 24(a0); \
lw t1, 28(a0); \
code; \
fsflags a1, x0; \
li a2, flags; \
bne a0, a3, fail; \
bne t1, t2, fail; \
bne a1, a2, fail; \
.pushsection .data; \
.balign 8; \
test_ ## testnum ## _data: \
.double val1; \
.double val2; \
.double val3; \
.result; \
.popsection
#define TEST_FP_OP1_D32( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, 0.0, 0.0, \
inst f3, f0; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_FCLASS_D32(testnum, correct, input) \
TEST_CASE(testnum, a0, correct, \
la a0, test_ ## testnum ## _data ;\
fld fa0, 0(a0); \
fclass.d a0, fa0) \
.pushsection .data; \
.balign 8; \
test_ ## testnum ## _data: \
.dword input; \
.popsection
#define TEST_FP_CMP_OP_D32( testnum, inst, flags, result, val1, val2 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, val2, 0.0, \
inst a0, f0, f1; li t2, 0)
#define TEST_INT_FP_OP_D32( testnum, inst, result, val1 ) \
test_ ## testnum: \
li TESTNUM, testnum; \
la a0, test_ ## testnum ## _data ;\
lw a3, 0(a0); \
lw a4, 4(a0); \
li a1, val1; \
inst f0, a1; \
\
fsd f0, 0(a0); \
lw a1, 4(a0); \
lw a0, 0(a0); \
\
fsflags x0; \
bne a0, a3, fail; \
bne a1, a4, fail; \
.pushsection .data; \
.balign 8; \
test_ ## testnum ## _data: \
.double result; \
.popsection
#define TEST_FCVT_S_D32( testnum, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \
fcvt.s.d f3, f0; fcvt.d.s f3, f3; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_FP_OP3_D32( testnum, inst, flags, result, val1, val2, val3 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, double result, val1, val2, val3, \
inst f3, f0, f1, f2; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#define TEST_FP_OP1_D32_DWORD_RESULT( testnum, inst, flags, result, val1 ) \
TEST_FP_OP_D32_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \
inst f3, f0; fsd f3, 0(a0); lw t2, 4(a0); lw a0, 0(a0))
#endif

View File

@@ -0,0 +1,93 @@
include rv32_tests.inc
ARCH_tmp := imf
ifneq (,$(findstring c,$(ARCH_lowercase)))
ARCH_tmp := $(ARCH_tmp)c
endif
override ARCH := $(ARCH_tmp)
src_dir := $(CURDIR)
obj_dir := $(bld_dir)/riscv_objs
test_list := $(patsubst %.S, %, $(notdir $(rv32_isa_tests)))
objs := $(addprefix $(obj_dir)/,$(test_list:%=%.o))
test_elf := $(addprefix $(bld_dir)/,$(test_list:%=%.elf))
test_hex := $(addprefix $(bld_dir)/,$(test_list:%=%.hex))
test_dump := $(addprefix $(bld_dir)/,$(test_list:%=%.dump))
CFLAGS := -I$(inc_dir) -I$(src_dir) -DASM -Wa,-march=rv32$(ARCH)_zicsr_zifencei -march=rv32$(ARCH)_zicsr_zifencei -mabi=ilp32f -D__riscv_xlen=32
LDFLAGS := -static -fvisibility=hidden -nostdlib -nostartfiles -T$(inc_dir)/link.ld -march=rv32$(ARCH)_zicsr_zifencei -mabi=ilp32f
RISCV_TESTS := $(src_dir)/../../../dependencies/riscv-tests/
VPATH += $(src_dir) $(bld_dir) $(obj_dir) $(RISCV_TESTS)
default: log_requested_tgt check_riscv_tests $(test_elf) $(test_hex) $(test_dump)
define compile_template
$(obj_dir)/$$(basename $(notdir $(SRC))).o: $$(SRC) | $(obj_dir)
$(RISCV_GCC) -c $$< $(CFLAGS) -o $$@
endef
$(foreach SRC,$(rv32_isa_tests), $(eval $(compile_template)))
log_requested_tgt:
$(foreach test_name, $(test_list), $(eval $(shell echo $(test_name).hex >> $(bld_dir)/test_info)))
$(obj_dir) :
mkdir -p $(obj_dir)
$(bld_dir)/%.elf: $(obj_dir)/%.o | $(obj_dir)
$(RISCV_GCC) $^ $(LDFLAGS) -o $@
$(bld_dir)/%.hex: $(bld_dir)/%.elf
$(RISCV_OBJCOPY) $^ $@
$(bld_dir)/%.dump: $(bld_dir)/%.elf
$(RISCV_OBJDUMP) -D -w -x -S $^ > $@
clean:
$(RM) $(test_elf) $(test_hex) $(test_dump) $(objs)
$(RM) -R $(obj_dir)
.PHONY: check_riscv_tests
riscv_tests_dir := $(if $(RISCV_TESTS), $(RISCV_TESTS), ./undefined)
riscv_tests_commit := 5f8a4918c6482e65c67a2b7decd5c2af3e3fe0e5
## commit hash readed from local copy of https://github.com/riscv/riscv-tests
tmp_commit = $(shell cd $(riscv_tests_dir) 2>/dev/null && git log -1 | grep "commit" | cut -f2 -d ' ')
is_commit_good = $(if $(subst $(riscv_tests_commit),,$(tmp_commit)),false,true)
# Color
RED=\033[0;31m
NC=\033[0m
check_riscv_tests : $(riscv_tests_dir)
@if [ ! -d $(riscv_tests_dir) ]; then \
echo -e "$(RED)==========================================================================" &&\
echo " Error! Environment variable RISCV_TESTS='$(riscv_tests_dir)' " &&\
echo " directory not exist!" && \
echo "==========================================================================$(NC)" ; \
fi
ifneq ($(is_commit_good),true)
@echo -e "$(RED)=========================================================================="
@echo " Warning! Execution of test code is not guaranteed "
@echo " while using the current commit of repositorylocated at : $(riscv_tests_dir) ."
@echo " "
@echo " Riscv-tests repository must point to commit $(riscv_tests_commit)!"
@echo -e "==========================================================================$(NC)"
endif
$(riscv_tests_dir) :.
ifndef RISCV_TESTS
@echo -e "$(RED)=========================================================================="
@echo " Error! Environment variable RISCV_TESTS not set!"
@echo " You must set the environment variable RISCV_TESTS"
@echo " The variable should point to the local copy of the"
@echo " repository https://github.com/riscv/riscv-tests"
@echo " with the commit $(riscv_tests_commit)"
@echo -e "==========================================================================$(NC)"
exit 1
endif

View File

@@ -0,0 +1,6 @@
#ifndef __RISCV__TEST__H
#define __RISCV__TEST__H
#include "riscv_macros.h"
#endif // #ifndef __RISCV__TEST__H

View File

@@ -0,0 +1,66 @@
ARCH_lowercase = $(shell echo $(ARCH) | tr A-Z a-z)
rv32_isa_tests += isa/rv32ui/add.S \
isa/rv32ui/addi.S \
isa/rv32ui/and.S \
isa/rv32ui/andi.S \
isa/rv32ui/auipc.S \
isa/rv32ui/beq.S \
isa/rv32ui/bge.S \
isa/rv32ui/bgeu.S \
isa/rv32ui/blt.S \
isa/rv32ui/bltu.S \
isa/rv32ui/bne.S \
isa/rv32mi/csr.S \
isa/rv32ui/fence_i.S \
isa/rv32mi/illegal.S \
isa/rv32ui/jal.S \
isa/rv32ui/jalr.S \
isa/rv32ui/lb.S \
isa/rv32ui/lbu.S \
isa/rv32ui/lh.S \
isa/rv32ui/lhu.S \
isa/rv32ui/lui.S \
isa/rv32ui/lw.S \
isa/rv32mi/ma_addr.S \
isa/rv32mi/ma_fetch.S \
isa/rv32mi/mcsr.S \
isa/rv32ui/or.S \
isa/rv32ui/ori.S \
isa/rv32ui/sb.S \
isa/rv32mi/sbreak.S \
isa/rv32mi/scall.S \
isa/rv32ui/sh.S \
isa/rv32mi/shamt.S \
isa/rv32ui/simple.S \
isa/rv32ui/sll.S \
isa/rv32ui/slli.S \
isa/rv32ui/slt.S \
isa/rv32ui/slti.S \
isa/rv32ui/sltiu.S \
isa/rv32ui/sltu.S \
isa/rv32ui/sra.S \
isa/rv32ui/srai.S \
isa/rv32ui/srl.S \
isa/rv32ui/srli.S \
isa/rv32ui/sub.S \
isa/rv32ui/sw.S \
isa/rv32ui/xor.S \
isa/rv32ui/xori.S
ifneq (,$(findstring m,$(ARCH_lowercase)))
rv32_isa_tests += isa/rv32um/div.S \
isa/rv32um/divu.S \
isa/rv32um/mul.S \
isa/rv32um/mulh.S \
isa/rv32um/mulhsu.S \
isa/rv32um/mulhu.S \
isa/rv32um/rem.S \
isa/rv32um/remu.S
endif ## ifeq (m,$(findstring m,$(ARCH_lowercase)))
ifneq (,$(findstring c,$(ARCH_lowercase)))
rv32_isa_tests += isa/rv32uc/rvc.S
endif ## ifeq (m,$(findstring c,$(ARCH_lowercase)))

View File

@@ -0,0 +1,7 @@
#ifndef __TEST__MACROS__H
#define __TEST__MACROS__H
#define sptbr satp
#define mbadaddr mtval
#endif

View File

@@ -0,0 +1,56 @@
#include <stdio.h>
#include <verilated.h>
#include "Vscr1_top_tb_ahb.h"
#ifdef VCD_TRACE
#include "verilated_vcd_c.h"
#endif // #ifdef VCD_TRACE
#define STRINGIFY(s) _STRINGIFY(s)
#define _STRINGIFY(s) #s
Vscr1_top_tb_ahb *top;
vluint64_t main_time = 0;
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
top = new Vscr1_top_tb_ahb;
#ifdef VCD_TRACE
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
#ifdef TRACE_LVLV
top->trace(tfp, TRACE_LVLV);
#else
top->trace(tfp, 99); // Trace 99 levels of hierarchy by default
#endif // #ifdef TRACE_LVLV
#ifdef VCD_FNAME
tfp->open(STRINGIFY(VCD_FNAME));
#else
tfp->open("./simx.vcd");
#endif // #ifdef VCD_FNAME
#endif // #ifdef VCD_TRACE
while (!Verilated::gotFinish()) {
if ((main_time % 10) == 1) {
top->clk = 1;
}
if ((main_time % 10) == 6) {
top->clk = 0;
}
top->eval();
main_time++;
#ifdef VCD_TRACE
tfp->dump(main_time);
#endif // #ifdef VCD_TRACE
}
top->final();
#ifdef VCD_TRACE
tfp->close();
#endif // #ifdef VCD_TRACE
delete top;
}

View File

@@ -0,0 +1,55 @@
#include <stdio.h>
#include <verilated.h>
#include "Vscr1_top_tb_axi.h"
#ifdef VCD_TRACE
#include "verilated_vcd_c.h"
#endif // #ifdef VCD_TRACE
#define STRINGIFY(s) _STRINGIFY(s)
#define _STRINGIFY(s) #s
Vscr1_top_tb_axi *top;
vluint64_t main_time = 0;
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
top = new Vscr1_top_tb_axi;
#ifdef VCD_TRACE
Verilated::traceEverOn(true);
VerilatedVcdC* tfp = new VerilatedVcdC;
#ifdef TRACE_LVLV
top->trace(tfp, TRACE_LVLV);
#else
top->trace(tfp, 99); // Trace 99 levels of hierarchy by default
#endif // #ifdef TRACE_LVLV
#ifdef VCD_FNAME
tfp->open(STRINGIFY(VCD_FNAME));
#else
tfp->open("./simx.vcd");
#endif // #ifdef VCD_FNAME
#endif // #ifdef VCD_TRACE
while (!Verilated::gotFinish()) {
if ((main_time % 10) == 1) {
top->clk = 1;
}
if ((main_time % 10) == 6) {
top->clk = 0;
}
top->eval();
main_time++;
#ifdef VCD_TRACE
tfp->dump(main_time);
#endif // #ifdef VCD_TRACE
}
top->final();
#ifdef VCD_TRACE
tfp->close();
#endif // #ifdef VCD_TRACE
delete top;
}

3
src/ahb_tb.files Normal file
View File

@@ -0,0 +1,3 @@
core/pipeline/scr1_tracelog.sv
tb/scr1_memory_tb_ahb.sv
tb/scr1_top_tb_ahb.sv

8
src/ahb_top.files Normal file
View File

@@ -0,0 +1,8 @@
top/scr1_dmem_router.sv
top/scr1_imem_router.sv
top/scr1_dp_memory.sv
top/scr1_tcm.sv
top/scr1_timer.sv
top/scr1_dmem_ahb.sv
top/scr1_imem_ahb.sv
top/scr1_top_ahb.sv

3
src/axi_tb.files Normal file
View File

@@ -0,0 +1,3 @@
core/pipeline/scr1_tracelog.sv
tb/scr1_memory_tb_axi.sv
tb/scr1_top_tb_axi.sv

7
src/axi_top.files Normal file
View File

@@ -0,0 +1,7 @@
top/scr1_dmem_router.sv
top/scr1_imem_router.sv
top/scr1_dp_memory.sv
top/scr1_tcm.sv
top/scr1_timer.sv
top/scr1_mem_axi.sv
top/scr1_top_axi.sv

21
src/core.files Normal file
View File

@@ -0,0 +1,21 @@
core/pipeline/scr1_pipe_hdu.sv
core/pipeline/scr1_pipe_tdu.sv
core/pipeline/scr1_ipic.sv
core/pipeline/scr1_pipe_csr.sv
core/pipeline/scr1_pipe_exu.sv
core/pipeline/scr1_pipe_ialu.sv
core/pipeline/scr1_pipe_idu.sv
core/pipeline/scr1_pipe_ifu.sv
core/pipeline/scr1_pipe_lsu.sv
core/pipeline/scr1_pipe_mprf.sv
core/pipeline/scr1_pipe_top.sv
core/primitives/scr1_reset_cells.sv
core/primitives/scr1_cg.sv
core/scr1_clk_ctrl.sv
core/scr1_tapc_shift_reg.sv
core/scr1_tapc.sv
core/scr1_tapc_synchronizer.sv
core/scr1_core_top.sv
core/scr1_dm.sv
core/scr1_dmi.sv
core/scr1_scu.sv

View File

@@ -0,0 +1,605 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_ipic.sv>
/// @brief Integrated Programmable Interrupt Controller (IPIC)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Synchronizes IRQ lines (optional)
// - Detects level and edge (with optional lines inversion) of IRQ lines
// - Setups interrupts handling (mode, inversion, enable)
// - Provides information about pending interrupts and interrupts currently in
// service
// - Generates interrupt request to CSR
//
// Structure:
// - IRQ lines handling (synchronization, level and edge detection) logic
// - IPIC registers:
// - CISV
// - CICSR
// - EOI
// - SOI
// - IDX
// - IPR
// - ISVR
// - IER
// - IMR
// - IINVR
// - ICSR
// - Priority interrupt generation logic
//
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_IPIC_EN
`include "scr1_ipic.svh"
module scr1_ipic
(
// Common
input logic rst_n, // IPIC reset
input logic clk, // IPIC clock
// External Interrupt lines
input logic [SCR1_IRQ_LINES_NUM-1:0] soc2ipic_irq_lines_i, // External IRQ lines
// CSR <-> IPIC interface
input logic csr2ipic_r_req_i, // IPIC read request
input logic csr2ipic_w_req_i, // IPIC write request
input logic [2:0] csr2ipic_addr_i, // IPIC address
input logic [`SCR1_XLEN-1:0] csr2ipic_wdata_i, // IPIC write data
output logic [`SCR1_XLEN-1:0] ipic2csr_rdata_o, // IPIC read data
output logic ipic2csr_irq_m_req_o // IRQ request from IPIC
);
//-------------------------------------------------------------------------------
// Local types declaration
//-------------------------------------------------------------------------------
typedef struct {
logic vd;
logic idx;
} type_scr1_search_one_2_s;
typedef struct {
logic vd;
logic [SCR1_IRQ_IDX_WIDTH-1:0] idx;
} type_scr1_search_one_16_s;
typedef struct packed {
logic ip;
logic ie;
logic im;
logic inv;
logic isv;
logic [SCR1_IRQ_LINES_WIDTH-1:0] line;
} type_scr1_icsr_m_s;
typedef struct packed {
logic ip;
logic ie;
} type_scr1_cicsr_s;
//-------------------------------------------------------------------------------
// Local functions declaration
//-------------------------------------------------------------------------------
function automatic type_scr1_search_one_2_s scr1_search_one_2(
input logic [1:0] din
);
type_scr1_search_one_2_s tmp;
begin
tmp.vd = |din;
tmp.idx = ~din[0];
return tmp;
end
endfunction : scr1_search_one_2
function automatic type_scr1_search_one_16_s scr1_search_one_16(
input logic [15:0] din
);
begin
logic [7:0] stage1_vd;
logic [3:0] stage2_vd;
logic [1:0] stage3_vd;
logic stage1_idx [7:0];
logic [1:0] stage2_idx [3:0];
logic [2:0] stage3_idx [1:0];
type_scr1_search_one_16_s result;
// Stage 1
for (int unsigned i=0; i<8; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_search_one_2(din[(i+1)*2-1-:2]);
stage1_vd[i] = tmp.vd;
stage1_idx[i] = tmp.idx;
end
// Stage 2
for (int unsigned i=0; i<4; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_search_one_2(stage1_vd[(i+1)*2-1-:2]);
stage2_vd[i] = tmp.vd;
stage2_idx[i] = (~tmp.idx) ? {tmp.idx, stage1_idx[2*i]} : {tmp.idx, stage1_idx[2*i+1]};
end
// Stage 3
for (int unsigned i=0; i<2; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_search_one_2(stage2_vd[(i+1)*2-1-:2]);
stage3_vd[i] = tmp.vd;
stage3_idx[i] = (~tmp.idx) ? {tmp.idx, stage2_idx[2*i]} : {tmp.idx, stage2_idx[2*i+1]};
end
// Stage 4
result.vd = |stage3_vd;
result.idx = (stage3_vd[0]) ? {1'b0, stage3_idx[0]} : {1'b1, stage3_idx[1]};
return result;
end
endfunction : scr1_search_one_16
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// IRQ lines handling signals
//------------------------------------------------------------------------------
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines; // Internal IRQ lines
`ifdef SCR1_IPIC_SYNC_EN
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_sync;
`endif // SCR1_IPIC_SYNC_EN
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_dly; // Internal IRQ lines delayed for 1 cycle
logic [SCR1_IRQ_VECT_NUM-1:0] irq_edge_detected; // IRQ lines edge detected flags
logic [SCR1_IRQ_VECT_NUM-1:0] irq_lvl; // IRQ lines level
// IPIC registers
//------------------------------------------------------------------------------
// CISV register
logic ipic_cisv_upd; // Current Interrupt Vecotr in Service register update
logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_ff; // Current Interrupt Vector in Service register
logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_next; // Current Interrupt Vector in Service register next value
// CICS register (CICSR)
logic cicsr_wr_req; // Write request to Current Interrupt Control Status register
type_scr1_cicsr_s ipic_cicsr; // Current Interrupt Control Status register
// EOI register
logic eoi_wr_req; // Write request to End of Interrupt register
logic ipic_eoi_req; // Request to end the interrupt that is currently in service
// SOI register
logic soi_wr_req; // Write request to Start of Interrupt register
logic ipic_soi_req; // Request to start the interrupt
// IDX register (IDXR)
logic idxr_wr_req; // Write request to Index register
logic [SCR1_IRQ_IDX_WIDTH-1:0] ipic_idxr_ff; // Index register
// IP register (IPR)
logic ipic_ipr_upd; // Interrupt pending register update
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_ff; // Interrupt pending register
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_next; // Interrupt pending register next value
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_cond; // Interrupt pending clear condition
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_req; // Interrupt pending clear request
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr; // Interrupt pending clear operation
// ISV register (ISVR)
logic ipic_isvr_upd; // Interrupt Serviced register update
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_ff; // Interrupt Serviced register
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_next; // Interrupt Serviced register next value
// IE register (IER)
logic ipic_ier_upd; // Interrupt enable register update
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_ff; // Interrupt enable register
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_next; // Interrupt enable register next value
// IM register (IMR)
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_ff; // Interrupt mode register
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_next; // Interrupt mode register next value
// IINV register (IINVR)
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_ff; // Interrupt Inversion register
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_next; // Interrupt Inversion register next value
// ICS register (ICSR)
logic icsr_wr_req; // Write request to Interrupt Control Status register
type_scr1_icsr_m_s ipic_icsr; // Interrupt Control Status register
// Priority interrupt generation signals
//------------------------------------------------------------------------------
// Serviced interrupt signals
logic irq_serv_vd; // There is an interrupt in service
logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_serv_idx; // Index of an interrupt that is currently in service
// Requested interrupt signals
logic irq_req_vd; // There is a requested interrupt
logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_req_idx; // Index of a requested interrupt
// Interrupt requested on "end of the previous interrupt" signals
logic irq_eoi_req_vd; // There is a requested interrupt when the previous one has ended
logic [SCR1_IRQ_IDX_WIDTH-1:0] irq_eoi_req_idx; // Index of an interrupt requested when the previous one has ended
logic [SCR1_IRQ_VECT_NUM-1:0] irq_req_v; // Vector of interrupts that are pending and enabled
logic irq_start_vd; // Request to start an interrupt is valid
logic irq_hi_prior_pnd; // There is a pending IRQ with a priority higher than of the interrupt that is currently in service
type_scr1_search_one_16_s irr_priority; // Structure for vd and idx of the requested interrupt
type_scr1_search_one_16_s isvr_priority_eoi; // Structure for vd and idx of the interrupt requested when the previous interrupt has ended
logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_eoi; // Interrupt Serviced register when the previous interrupt has ended
//------------------------------------------------------------------------------
// IRQ lines handling
//------------------------------------------------------------------------------
`ifdef SCR1_IPIC_SYNC_EN
// IRQ lines synchronization
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
irq_lines_sync <= '0;
irq_lines <= '0;
end else begin
irq_lines_sync <= soc2ipic_irq_lines_i;
irq_lines <= irq_lines_sync;
end
end
`else // SCR1_IPIC_SYNC_EN
assign irq_lines = soc2ipic_irq_lines_i;
`endif // SCR1_IPIC_SYNC_EN
// IRQ lines level detection
//------------------------------------------------------------------------------
assign irq_lvl = irq_lines ^ ipic_iinvr_next;
// IRQ lines edge detection
//------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
irq_lines_dly <= '0;
end else begin
irq_lines_dly <= irq_lines;
end
end
assign irq_edge_detected = (irq_lines_dly ^ irq_lines) & irq_lvl;
//------------------------------------------------------------------------------
// IPIC registers read/write interface
//------------------------------------------------------------------------------
// Read Logic
//------------------------------------------------------------------------------
// Read data multiplexer
always_comb begin
ipic2csr_rdata_o = '0;
if (csr2ipic_r_req_i) begin
case (csr2ipic_addr_i)
SCR1_IPIC_CISV : begin
ipic2csr_rdata_o[SCR1_IRQ_VECT_WIDTH-1:0] = irq_serv_vd
? ipic_cisv_ff
: SCR1_IRQ_VOID_VECT_NUM;
end
SCR1_IPIC_CICSR : begin
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_cicsr.ip;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_cicsr.ie;
end
SCR1_IPIC_IPR : begin
ipic2csr_rdata_o = `SCR1_XLEN'(ipic_ipr_ff);
end
SCR1_IPIC_ISVR : begin
ipic2csr_rdata_o = `SCR1_XLEN'(ipic_isvr_ff);
end
SCR1_IPIC_EOI,
SCR1_IPIC_SOI : begin
ipic2csr_rdata_o = '0;
end
SCR1_IPIC_IDX : begin
ipic2csr_rdata_o = `SCR1_XLEN'(ipic_idxr_ff);
end
SCR1_IPIC_ICSR : begin
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_icsr.ip;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_icsr.ie;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IM] = ipic_icsr.im;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_INV] = ipic_icsr.inv;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_PRV_MSB:
SCR1_IPIC_ICSR_PRV_LSB] = SCR1_IPIC_PRV_M;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_IS] = ipic_icsr.isv;
ipic2csr_rdata_o[SCR1_IPIC_ICSR_LN_MSB-1:
SCR1_IPIC_ICSR_LN_LSB] = ipic_icsr.line;
end
default : begin
ipic2csr_rdata_o = 'x;
end
endcase
end
end
// Write logic
//------------------------------------------------------------------------------
// Register selection
always_comb begin
cicsr_wr_req = 1'b0;
eoi_wr_req = 1'b0;
soi_wr_req = 1'b0;
idxr_wr_req = 1'b0;
icsr_wr_req = 1'b0;
if (csr2ipic_w_req_i) begin
case (csr2ipic_addr_i)
SCR1_IPIC_CISV : begin end // Quiet Read-Only
SCR1_IPIC_CICSR: cicsr_wr_req = 1'b1;
SCR1_IPIC_IPR : begin end
SCR1_IPIC_ISVR : begin end // Quiet Read-Only
SCR1_IPIC_EOI : eoi_wr_req = 1'b1;
SCR1_IPIC_SOI : soi_wr_req = 1'b1;
SCR1_IPIC_IDX : idxr_wr_req = 1'b1;
SCR1_IPIC_ICSR : icsr_wr_req = 1'b1;
default : begin // Illegal IPIC register address
cicsr_wr_req = 'x;
eoi_wr_req = 'x;
soi_wr_req = 'x;
idxr_wr_req = 'x;
icsr_wr_req = 'x;
end
endcase
end
end
//------------------------------------------------------------------------------
// IPIC registers
//------------------------------------------------------------------------------
//
// Registers:
// - Current Interrupt Vector in Service (CISV) register
// - Current Interrupt Control Status (CICSR) register
// - End of Interrupt (EOI) register
// - Start of Interrupt (SOI) register
// - Index (IDX) register
// - Interrupt Pending Register (IPR)
// - Interrupt Serviced Register (ISVR)
// - Interrupt Enable Register (IER)
// - Interrupt Mode Register (IMR)
// - Interrupt Inversion Register (IINVR)
// - Interrupt Control Status Register (ICSR)
//
// CISV register
//------------------------------------------------------------------------------
// Contains number of the interrupt vector currently in service. When no
// interrupts are in service, contains number of the void interrupt vector (0x10).
// The register cannot contain all 0's
assign ipic_cisv_upd = irq_start_vd | ipic_eoi_req;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_cisv_ff <= SCR1_IRQ_VOID_VECT_NUM;
end else if (ipic_cisv_upd) begin
ipic_cisv_ff <= ipic_cisv_next;
end
end
assign ipic_cisv_next = irq_start_vd ? {1'b0, irq_req_idx}
: ipic_eoi_req ? irq_eoi_req_vd ? {1'b0, irq_eoi_req_idx}
: SCR1_IRQ_VOID_VECT_NUM
: 1'b0;
assign irq_serv_idx = ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-2:0];
assign irq_serv_vd = ~ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-1];
// CICSR register
//------------------------------------------------------------------------------
// Shows whether the interrupt currently in service is pending and enabled
assign ipic_cicsr.ip = ipic_ipr_ff[irq_serv_idx] & irq_serv_vd;
assign ipic_cicsr.ie = ipic_ier_ff[irq_serv_idx] & irq_serv_vd;
// EOI register
//------------------------------------------------------------------------------
// Writing any value to EOI register ends the interrupt which is currently in service
assign ipic_eoi_req = eoi_wr_req & irq_serv_vd;
// SOI register
//------------------------------------------------------------------------------
// Writing any value to SOI activates start of interrupt if one of the following
// conditions is true:
// - There is at least one pending interrupt with IE and ISR is zero
// - There is at least one pending interrupt with IE and higher priority than the
// interrupts currently in service
assign ipic_soi_req = soi_wr_req & irq_req_vd;
// IDX register
//------------------------------------------------------------------------------
// Defines the number of interrupt vector which is accessed through the IPIC_ICSR
// register
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_idxr_ff <= '0;
end else if (idxr_wr_req) begin
ipic_idxr_ff <= csr2ipic_wdata_i[SCR1_IRQ_IDX_WIDTH-1:0];
end
end
// IPR
//------------------------------------------------------------------------------
// For every IRQ line shows whether there is a pending interrupt
assign ipic_ipr_upd = (ipic_ipr_next != ipic_ipr_ff);
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_ipr_ff <= '0;
end else if (ipic_ipr_upd) begin
ipic_ipr_ff <= ipic_ipr_next;
end
end
always_comb begin
ipic_ipr_clr_req = '0;
if (csr2ipic_w_req_i) begin
case (csr2ipic_addr_i)
SCR1_IPIC_CICSR: ipic_ipr_clr_req[irq_serv_idx] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP]
& irq_serv_vd;
SCR1_IPIC_IPR : ipic_ipr_clr_req = csr2ipic_wdata_i[SCR1_IRQ_VECT_NUM-1:0];
SCR1_IPIC_SOI : ipic_ipr_clr_req[irq_req_idx] = irq_req_vd;
SCR1_IPIC_ICSR : ipic_ipr_clr_req[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP];
default : begin end
endcase
end
end
assign ipic_ipr_clr_cond = ~irq_lvl | ipic_imr_next;
assign ipic_ipr_clr = ipic_ipr_clr_req & ipic_ipr_clr_cond;
always_comb begin
ipic_ipr_next = '0;
for (int unsigned i=0; i<SCR1_IRQ_VECT_NUM; ++i) begin
ipic_ipr_next[i] = ipic_ipr_clr[i] ? 1'b0
: ~ipic_imr_ff[i] ? irq_lvl[i]
: ipic_ipr_ff[i] | irq_edge_detected[i];
end
end
// ISVR
//------------------------------------------------------------------------------
// For every IRQ line shows whether the interrupt is in service or not
assign ipic_isvr_upd = irq_start_vd | ipic_eoi_req;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_isvr_ff <= '0;
end else if (ipic_isvr_upd) begin
ipic_isvr_ff <= ipic_isvr_next;
end
end
always_comb begin
ipic_isvr_eoi = ipic_isvr_ff;
if (irq_serv_vd) begin
ipic_isvr_eoi[irq_serv_idx] = 1'b0;
end
end
always_comb begin
ipic_isvr_next = ipic_isvr_ff;
if (irq_start_vd) begin
ipic_isvr_next[irq_req_idx] = 1'b1;
end else if (ipic_eoi_req) begin
ipic_isvr_next = ipic_isvr_eoi;
end
end
// IER
//------------------------------------------------------------------------------
// Enables/disables interrupt for every IRQ line
assign ipic_ier_upd = cicsr_wr_req | icsr_wr_req;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_ier_ff <= '0;
end else if (ipic_ier_upd) begin
ipic_ier_ff <= ipic_ier_next;
end
end
always_comb begin
ipic_ier_next = ipic_ier_ff;
if (cicsr_wr_req) begin
ipic_ier_next[irq_serv_idx] = irq_serv_vd
? csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE]
: ipic_ier_ff[irq_serv_idx];
end else if (icsr_wr_req) begin
ipic_ier_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE];
end
end
// IMR
//------------------------------------------------------------------------------
// For every IRQ line sets either Level (0) or Edge (1) detection
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_imr_ff <= '0;
end else if (icsr_wr_req) begin
ipic_imr_ff <= ipic_imr_next;
end
end
always_comb begin
ipic_imr_next = ipic_imr_ff;
if (icsr_wr_req) begin
ipic_imr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IM];
end
end
// IINVR
//------------------------------------------------------------------------------
// For every IRQ line defines whether it should be inverted or not
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
ipic_iinvr_ff <= '0;
end else if (icsr_wr_req) begin
ipic_iinvr_ff <= ipic_iinvr_next;
end
end
always_comb begin
ipic_iinvr_next = ipic_iinvr_ff;
if (icsr_wr_req) begin
ipic_iinvr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_INV];
end
end
// ICSR
//------------------------------------------------------------------------------
// Holds control and status information about the interrupt defined by Index Register
assign ipic_icsr.ip = ipic_ipr_ff [ipic_idxr_ff];
assign ipic_icsr.ie = ipic_ier_ff [ipic_idxr_ff];
assign ipic_icsr.im = ipic_imr_ff [ipic_idxr_ff];
assign ipic_icsr.inv = ipic_iinvr_ff[ipic_idxr_ff];
assign ipic_icsr.isv = ipic_isvr_ff [ipic_idxr_ff];
assign ipic_icsr.line = SCR1_IRQ_LINES_WIDTH'(ipic_idxr_ff);
//------------------------------------------------------------------------------
// Priority IRQ generation logic
//------------------------------------------------------------------------------
assign irq_req_v = ipic_ipr_ff & ipic_ier_ff;
assign irr_priority = scr1_search_one_16(irq_req_v);
assign irq_req_vd = irr_priority.vd;
assign irq_req_idx = irr_priority.idx;
assign isvr_priority_eoi = scr1_search_one_16(ipic_isvr_eoi);
assign irq_eoi_req_vd = isvr_priority_eoi.vd;
assign irq_eoi_req_idx = isvr_priority_eoi.idx;
assign irq_hi_prior_pnd = irq_req_idx < irq_serv_idx;
assign ipic2csr_irq_m_req_o = irq_req_vd & (~irq_serv_vd | irq_hi_prior_pnd);
assign irq_start_vd = ipic2csr_irq_m_req_o & ipic_soi_req;
endmodule : scr1_ipic
`endif // SCR1_IPIC_EN

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,904 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_hdu.sv>
/// @brief HART Debug Unit (HDU)
///
//------------------------------------------------------------------------------
//
//
// Functionality:
// - Controls HART state (RUN, Debug RUN, Debug HALTED)
// - Setups Debug Mode execution
// - Provides status information about Debug Mode execution
// - Provides Program Buffer functionality (a few instructions execution while
// in Debug Mode)
// - Provides access to Debug CSRs
//
// Structure:
// - Debug state FSM
// - HART Control logic
// - HART Status logic
// - Program Buffer
// - Debug CSRs
// - HDU <-> DM interface
// - HDU <-> EXU interface
// - HDU <-> IFU interface
// - HDU <-> CSR interface
// - HDU <-> TDU interface
//
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_arch_types.svh"
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_hdu.svh"
module scr1_pipe_hdu #(parameter HART_PBUF_INSTR_REGOUT_EN = 1'b1) (
// Common signals
input logic rst_n, // HDU reset
input logic clk, // HDU clock
input logic clk_en, // HDU clock enable
`ifdef SCR1_CLKCTRL_EN
input logic clk_pipe_en, // Pipeline clock enable
`endif // SCR1_CLKCTRL_EN
input logic pipe2hdu_rdc_qlfy_i, // Pipeline RDC qualifier
// HDU <-> CSR i/f
input logic csr2hdu_req_i, // CSR i/f request
input type_scr1_csr_cmd_sel_e csr2hdu_cmd_i, // CSR i/f command
input logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr_i, // CSR i/f address
input logic [`SCR1_XLEN-1:0] csr2hdu_wdata_i, // CSR i/f write data
output type_scr1_csr_resp_e hdu2csr_resp_o, // CSR i/f response
output logic [`SCR1_XLEN-1:0] hdu2csr_rdata_o, // CSR i/f read data
// HDU <-> DM i/f
// HART Run Control i/f
input logic dm2hdu_cmd_req_i, // DM-HART Command request
input type_scr1_hdu_dbgstates_e dm2hdu_cmd_i, // DM-HART Command
output logic hdu2dm_cmd_resp_o, // DM-HART Command response
output logic hdu2dm_cmd_rcode_o, // DM-HART Command return code: 0 - Ok; 1 - Error
output logic hdu2dm_hart_event_o, // DM-HART Event: 1 if HART debug state changed
output type_scr1_hdu_hartstatus_s hdu2dm_hart_status_o, // DM-HART Status
// Program Buffer i/f
output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] hdu2dm_pbuf_addr_o, // Program Buffer address - so far request only for 1 instruction
input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2hdu_pbuf_instr_i, // Program Buffer instruction
// HART Abstract Data regs i/f
output logic hdu2dm_dreg_req_o, // Abstract Data Register request
output logic hdu2dm_dreg_wr_o, // Abstract Data Register write
output logic [`SCR1_XLEN-1:0] hdu2dm_dreg_wdata_o, // Abstract Data Register write data
input logic dm2hdu_dreg_resp_i, // Abstract Data Register response
input logic dm2hdu_dreg_fail_i, // Abstract Data Register fail
input logic [`SCR1_XLEN-1:0] dm2hdu_dreg_rdata_i, // Abstract Data Register read data
`ifdef SCR1_TDU_EN
// HDU <-> TDU interface
output logic hdu2tdu_hwbrk_dsbl_o, // Disables BRKM
input logic tdu2hdu_dmode_req_i, // Trigger Module requests transition to debug mode
input logic exu2hdu_ibrkpt_hw_i, // Hardware breakpoint on current instruction
`endif // SCR1_TDU_EN
// HART Run Status
input logic pipe2hdu_exu_busy_i, // EXU busy
input logic pipe2hdu_instret_i, // Instruction retired (with or without exception)
input logic pipe2hdu_init_pc_i, // Reset exit
// HART Halt Status
input logic pipe2hdu_exu_exc_req_i, // Exception request
input logic pipe2hdu_brkpt_i, // Software Breakpoint (EBREAK)
// HDU <-> EXU i/f
// HART Run Control
output logic hdu2exu_pbuf_fetch_o, // Fetch instruction from Program Buffer
output logic hdu2exu_no_commit_o, // Forbid instruction commitment
output logic hdu2exu_irq_dsbl_o, // Disable IRQ
output logic hdu2exu_pc_advmt_dsbl_o, // Forbid PC advancement
output logic hdu2exu_dmode_sstep_en_o, // Enable single-step
// HART state
output logic hdu2exu_dbg_halted_o, // Debug halted state
output logic hdu2exu_dbg_run2halt_o, // Transition to debug halted state
output logic hdu2exu_dbg_halt2run_o, // Transition to run state
output logic hdu2exu_dbg_run_start_o, // First cycle of run state
// PC interface
input logic [`SCR1_XLEN-1:0] pipe2hdu_pc_curr_i, // Current PC
output logic [`SCR1_XLEN-1:0] hdu2exu_dbg_new_pc_o, // New PC for resume
// HDU <-> IFU i/f
// Program Buffer Instruction interface
input logic ifu2hdu_pbuf_instr_rdy_i, // Program Buffer Instruction i/f ready
output logic hdu2ifu_pbuf_instr_vd_o, // Program Buffer Instruction valid
output logic hdu2ifu_pbuf_instr_err_o, // Program Buffer Instruction i/f error
output logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_o // Program Buffer Instruction itself
);
//------------------------------------------------------------------------------
// Local Parameters
//------------------------------------------------------------------------------
localparam int unsigned SCR1_HDU_TIMEOUT = 64; // must be power of 2
localparam int unsigned SCR1_HDU_TIMEOUT_WIDTH = $clog2(SCR1_HDU_TIMEOUT);
//------------------------------------------------------------------------------
// Local Signals
//------------------------------------------------------------------------------
// Debug FSM
//------------------------------------------------------------------------------
// FSM control signals
logic dm_dhalt_req;
logic dm_run_req;
logic dm_cmd_run;
logic dm_cmd_dhalted;
logic dm_cmd_drun;
// Debug state FSM signals
type_scr1_hdu_dbgstates_e dbg_state;
type_scr1_hdu_dbgstates_e dbg_state_next;
logic dbg_state_dhalted;
logic dbg_state_drun;
logic dbg_state_run;
logic dbg_state_reset;
// FSM transition, update and event registers
logic dfsm_trans;
logic dfsm_trans_next;
logic dfsm_update;
logic dfsm_update_next;
logic dfsm_event;
logic dfsm_event_next;
// HART Control signals
//------------------------------------------------------------------------------
logic hart_resume_req;
logic hart_halt_req;
logic hart_cmd_req;
// HART Run Control register
logic hart_runctrl_upd;
logic hart_runctrl_clr;
type_scr1_hdu_runctrl_s hart_runctrl;
// HART halt request timeout counter signals
logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt;
logic [SCR1_HDU_TIMEOUT_WIDTH-1:0] halt_req_timeout_cnt_next;
logic halt_req_timeout_cnt_en;
logic halt_req_timeout_flag;
// HART Status signals
//------------------------------------------------------------------------------
type_scr1_hdu_haltstatus_s hart_haltstatus;
type_scr1_hdu_haltcause_e hart_haltcause;
logic hart_halt_pnd;
logic hart_halt_ack;
// Debug mode cause decoder signals
logic dmode_cause_sstep;
logic dmode_cause_except;
logic dmode_cause_ebreak;
logic dmode_cause_any;
`ifdef SCR1_TDU_EN
logic dmode_cause_tmreq;
`endif // SCR1_TDU_EN
// Program Buffer FSM
//------------------------------------------------------------------------------
// PBUF FSM control signals
logic ifu_handshake_done;
logic pbuf_exc_inj_req;
logic pbuf_exc_inj_end;
logic pbuf_start_fetch;
// PBUF FSM signals
type_scr1_hdu_pbufstates_e pbuf_fsm_curr;
type_scr1_hdu_pbufstates_e pbuf_fsm_next;
logic pbuf_fsm_idle;
logic pbuf_fsm_fetch;
logic pbuf_fsm_excinj;
// PBUF address signals
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_ff;
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pbuf_addr_next;
logic pbuf_addr_end;
logic pbuf_addr_next_vd;
logic pbuf_instr_wait_latching;
// Debugs CSRs
//------------------------------------------------------------------------------
// CSRs write/read interface signals
logic csr_upd_on_halt;
logic csr_wr;
logic [`SCR1_XLEN-1:0] csr_wr_data;
logic [`SCR1_XLEN-1:0] csr_rd_data;
// Debug Control and Status register (DCSR)
logic csr_dcsr_sel;
logic csr_dcsr_wr;
type_scr1_hdu_dcsr_s csr_dcsr_in;
type_scr1_hdu_dcsr_s csr_dcsr_out;
logic csr_dcsr_ebreakm;
logic csr_dcsr_stepie;
logic csr_dcsr_step;
logic [SCR1_HDU_DCSR_CAUSE_BIT_L-
SCR1_HDU_DCSR_CAUSE_BIT_R:0] csr_dcsr_cause;
// Debug Program Counter register (DPC)
logic csr_dpc_sel;
logic csr_dpc_wr;
logic [`SCR1_XLEN-1:0] csr_dpc_ff;
logic [`SCR1_XLEN-1:0] csr_dpc_next;
logic [`SCR1_XLEN-1:0] csr_dpc_out;
// Debug Scratch register 0 (DSCRATCH0)
logic csr_addr_dscratch0;
logic csr_dscratch0_sel;
logic csr_dscratch0_wr;
logic [`SCR1_XLEN-1:0] csr_dscratch0_out;
type_scr1_csr_resp_e csr_dscratch0_resp;
//------------------------------------------------------------------------------
// Debug state FSM logic
//------------------------------------------------------------------------------
//
// Debug state FSM logic consists of the following functional units:
// - FSM control logic
// - Debug state FSM
// - FSM transition, update and event registers
//
// FSM control logic
//------------------------------------------------------------------------------
assign dm_cmd_dhalted = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DHALTED);
assign dm_cmd_run = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_RUN);
assign dm_cmd_drun = (dm2hdu_cmd_i == SCR1_HDU_DBGSTATE_DRUN);
assign dm_dhalt_req = dm2hdu_cmd_req_i & dm_cmd_dhalted;
assign dm_run_req = dm2hdu_cmd_req_i & (dm_cmd_run | dm_cmd_drun);
// Debug state FSM
//------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
dbg_state <= SCR1_HDU_DBGSTATE_RESET;
end else begin
dbg_state <= dbg_state_next;
end
end
always_comb begin
if (~pipe2hdu_rdc_qlfy_i) begin
dbg_state_next = SCR1_HDU_DBGSTATE_RESET;
end else begin
case (dbg_state)
SCR1_HDU_DBGSTATE_RESET: begin
dbg_state_next = ~pipe2hdu_init_pc_i ? SCR1_HDU_DBGSTATE_RESET
: dm_dhalt_req ? SCR1_HDU_DBGSTATE_DHALTED
: SCR1_HDU_DBGSTATE_RUN;
end
SCR1_HDU_DBGSTATE_RUN: begin
dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED
: SCR1_HDU_DBGSTATE_RUN;
end
SCR1_HDU_DBGSTATE_DHALTED: begin
dbg_state_next = ~dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED
: dm_cmd_drun ? SCR1_HDU_DBGSTATE_DRUN
: SCR1_HDU_DBGSTATE_RUN;
end
SCR1_HDU_DBGSTATE_DRUN: begin
dbg_state_next = dfsm_update ? SCR1_HDU_DBGSTATE_DHALTED
: SCR1_HDU_DBGSTATE_DRUN;
end
default: begin
`ifdef SCR1_XPROP_EN
dbg_state_next = SCR1_HDU_DBGSTATE_XXX;
`else // SCR1_XPROP_EN
dbg_state_next = dbg_state;
`endif // SCR1_XPROP_EN
end
endcase
end
end
assign dbg_state_dhalted = (dbg_state == SCR1_HDU_DBGSTATE_DHALTED);
assign dbg_state_drun = (dbg_state == SCR1_HDU_DBGSTATE_DRUN);
assign dbg_state_run = (dbg_state == SCR1_HDU_DBGSTATE_RUN);
assign dbg_state_reset = (dbg_state == SCR1_HDU_DBGSTATE_RESET);
// FSM transition, update and event registers
//------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
dfsm_trans <= 1'b0;
dfsm_update <= 1'b0;
dfsm_event <= 1'b0;
end else begin
dfsm_trans <= dfsm_trans_next;
dfsm_update <= dfsm_update_next;
dfsm_event <= dfsm_event_next;
end
end
always_comb begin
dfsm_trans_next = 1'b0;
dfsm_update_next = 1'b0;
dfsm_event_next = 1'b0;
if (~pipe2hdu_rdc_qlfy_i) begin
dfsm_trans_next = 1'b0;
dfsm_update_next = 1'b0;
dfsm_event_next = 1'b1;
end else begin
case (dbg_state)
SCR1_HDU_DBGSTATE_RESET: begin
dfsm_trans_next = 1'b0;
dfsm_update_next = 1'b0;
dfsm_event_next = pipe2hdu_init_pc_i & ~dm2hdu_cmd_req_i;
end
SCR1_HDU_DBGSTATE_RUN,
SCR1_HDU_DBGSTATE_DRUN: begin
dfsm_trans_next = ~dfsm_update ? hart_halt_pnd : dfsm_trans;
dfsm_update_next = ~dfsm_update & hart_halt_ack;
dfsm_event_next = dfsm_update;
end
SCR1_HDU_DBGSTATE_DHALTED: begin
dfsm_trans_next = ~dfsm_update ? ~dfsm_trans & dm_run_req
: dfsm_trans;
dfsm_update_next = ~dfsm_update & dfsm_trans;
dfsm_event_next = dfsm_update;
end
default : begin
dfsm_trans_next = 'X;
dfsm_update_next = 'X;
dfsm_event_next = 'X;
end
endcase
end
end
//------------------------------------------------------------------------------
// HART Control logic
//------------------------------------------------------------------------------
//
// HART Control logic consists of the following functional units:
// - Control signals
// - HART Run Control register
// - HART Halt Request Time-Out counter
//
// Control logic
always_comb begin
hart_cmd_req = 1'b0;
if (~pipe2hdu_rdc_qlfy_i) begin
hart_cmd_req = 1'b0;
end else begin
case (dbg_state)
SCR1_HDU_DBGSTATE_RESET : hart_cmd_req = dm2hdu_cmd_req_i;
SCR1_HDU_DBGSTATE_DHALTED: hart_cmd_req = (dfsm_update | dfsm_trans);
SCR1_HDU_DBGSTATE_RUN,
SCR1_HDU_DBGSTATE_DRUN : hart_cmd_req = ~dfsm_update & dfsm_trans;
default : hart_cmd_req = 'X;
endcase
end
end
assign hart_halt_req = dm_cmd_dhalted & hart_cmd_req;
assign hart_resume_req = (dm_cmd_run | dm_cmd_drun) & hart_cmd_req;
// HART Run Control register
//------------------------------------------------------------------------------
assign hart_runctrl_clr = (dbg_state_run | dbg_state_drun)
& (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED);
assign hart_runctrl_upd = dbg_state_dhalted & dfsm_trans_next;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
hart_runctrl.irq_dsbl <= 1'b0;
hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL;
hart_runctrl.pc_advmt_dsbl <= 1'b0;
hart_runctrl.hwbrkpt_dsbl <= 1'b0;
hart_runctrl.redirect <= '0;
end else if(clk_en) begin
if (hart_runctrl_clr) begin
hart_runctrl <= '0;
end else begin
if (hart_runctrl_upd) begin
if (~dm_cmd_drun) begin
// Case : resume to RUN state
hart_runctrl.irq_dsbl <= csr_dcsr_step ? ~csr_dcsr_stepie : 1'b0;
hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_NORMAL;
hart_runctrl.pc_advmt_dsbl <= 1'b0;
hart_runctrl.hwbrkpt_dsbl <= 1'b0;
hart_runctrl.redirect.sstep <= csr_dcsr_step;
hart_runctrl.redirect.ebreak <= csr_dcsr_ebreakm;
end else begin
// Case : resume to DRUN state
hart_runctrl.irq_dsbl <= 1'b1;
hart_runctrl.fetch_src <= SCR1_HDU_FETCH_SRC_PBUF;
hart_runctrl.pc_advmt_dsbl <= 1'b1;
hart_runctrl.hwbrkpt_dsbl <= 1'b1;
hart_runctrl.redirect.sstep <= 1'b0;
hart_runctrl.redirect.ebreak <= 1'b1;
end
end
end
end
end
// HART Halt Request Time-Out counter
//------------------------------------------------------------------------------
// HART goes into halt state only if the halt request is present for timeout period
// of time
assign halt_req_timeout_cnt_en = hdu2exu_dbg_halt2run_o
| (hart_halt_req & ~hdu2exu_dbg_run2halt_o);
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
halt_req_timeout_cnt <= '1;
end else if (halt_req_timeout_cnt_en) begin
halt_req_timeout_cnt <= halt_req_timeout_cnt_next;
end
end
assign halt_req_timeout_cnt_next = hdu2exu_dbg_halt2run_o ? '1
: (hart_halt_req & ~hdu2exu_dbg_run2halt_o) ? halt_req_timeout_cnt - 1'b1
: halt_req_timeout_cnt;
assign halt_req_timeout_flag = ~|halt_req_timeout_cnt;
//------------------------------------------------------------------------------
// HART Status logic
//------------------------------------------------------------------------------
//
// HART Status logic consists of the following functional units:
// - Debug mode cause decoder
// - Hart halt status cause encoder
// - Hart halt status register
//
// Debug mode cause decoder
//------------------------------------------------------------------------------
assign dmode_cause_sstep = hart_runctrl.redirect.sstep & pipe2hdu_instret_i;
assign dmode_cause_except = dbg_state_drun & pipe2hdu_exu_exc_req_i
& ~pipe2hdu_brkpt_i
`ifdef SCR1_TDU_EN
& ~exu2hdu_ibrkpt_hw_i
`endif // SCR1_TDU_EN
;
assign dmode_cause_ebreak = hart_runctrl.redirect.ebreak & pipe2hdu_brkpt_i;
`ifdef SCR1_TDU_EN
assign dmode_cause_tmreq = tdu2hdu_dmode_req_i & exu2hdu_ibrkpt_hw_i;
`endif // SCR1_TDU_EN
assign dmode_cause_any = dmode_cause_sstep | dmode_cause_ebreak | dmode_cause_except
| hart_halt_req
`ifdef SCR1_TDU_EN
| dmode_cause_tmreq
`endif // SCR1_TDU_EN
;
// HART halt cause encoder
//------------------------------------------------------------------------------
always_comb begin
case (1'b1)
`ifdef SCR1_TDU_EN
dmode_cause_tmreq : hart_haltcause = SCR1_HDU_HALTCAUSE_TMREQ;
`endif // SCR1_TDU_EN
dmode_cause_ebreak : hart_haltcause = SCR1_HDU_HALTCAUSE_EBREAK;
hart_halt_req : hart_haltcause = SCR1_HDU_HALTCAUSE_DMREQ;
dmode_cause_sstep : hart_haltcause = SCR1_HDU_HALTCAUSE_SSTEP;
default : hart_haltcause = SCR1_HDU_HALTCAUSE_NONE;
endcase
end
// HART halt status register
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
hart_haltstatus <= '0;
end else if (hart_halt_ack) begin
hart_haltstatus.except <= dmode_cause_except;
hart_haltstatus.cause <= hart_haltcause;
end
end
assign hart_halt_pnd = (dfsm_trans | dm_dhalt_req) & ~hart_halt_ack;
assign hart_halt_ack = ~hdu2exu_dbg_halted_o
& (halt_req_timeout_flag | (~pipe2hdu_exu_busy_i & dmode_cause_any));
//------------------------------------------------------------------------------
// Program Buffer (PBUF) logic
//------------------------------------------------------------------------------
//
// Program Buffer allows to execute small programs in debug mode
//
// To terminate Program Buffer execution exception should be raised. There are 2
// cases:
// - One of PBUF instructions raise an exception
// - No PBUF instruction raise an exception before the last PBUF instruction has
// been issued. In this case FSM goes into EXCINJECT state and an "Instruction
// fetch access fault" exception is injected
// PBUF FSM
//------------------------------------------------------------------------------
assign ifu_handshake_done = hdu2ifu_pbuf_instr_vd_o & ifu2hdu_pbuf_instr_rdy_i;
assign pbuf_addr_end = (pbuf_addr_ff == (SCR1_HDU_PBUF_ADDR_SPAN-1));
assign pbuf_start_fetch = dbg_state_dhalted & (dbg_state_next == SCR1_HDU_DBGSTATE_DRUN);
assign pbuf_exc_inj_req = ifu_handshake_done & pbuf_addr_end;
assign pbuf_exc_inj_end = pipe2hdu_exu_exc_req_i | ifu_handshake_done;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
pbuf_fsm_curr <= SCR1_HDU_PBUFSTATE_IDLE;
end else if(clk_en) begin
pbuf_fsm_curr <= pbuf_fsm_next;
end
end
always_comb begin
case (pbuf_fsm_curr)
SCR1_HDU_PBUFSTATE_IDLE: begin
pbuf_fsm_next = pbuf_start_fetch ? SCR1_HDU_PBUFSTATE_FETCH
: SCR1_HDU_PBUFSTATE_IDLE;
end
SCR1_HDU_PBUFSTATE_FETCH: begin
pbuf_fsm_next = pipe2hdu_exu_exc_req_i ? SCR1_HDU_PBUFSTATE_WAIT4END
: pbuf_exc_inj_req ? SCR1_HDU_PBUFSTATE_EXCINJECT
: SCR1_HDU_PBUFSTATE_FETCH;
end
SCR1_HDU_PBUFSTATE_EXCINJECT: begin
pbuf_fsm_next = pbuf_exc_inj_end ? SCR1_HDU_PBUFSTATE_WAIT4END
: SCR1_HDU_PBUFSTATE_EXCINJECT;
end
SCR1_HDU_PBUFSTATE_WAIT4END: begin
pbuf_fsm_next = hdu2exu_dbg_halted_o ? SCR1_HDU_PBUFSTATE_IDLE
: SCR1_HDU_PBUFSTATE_WAIT4END;
end
endcase
end
assign pbuf_fsm_idle = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_IDLE);
assign pbuf_fsm_fetch = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_FETCH);
assign pbuf_fsm_excinj = (pbuf_fsm_curr == SCR1_HDU_PBUFSTATE_EXCINJECT);
// Program Buffer address register
//------------------------------------------------------------------------------
assign pbuf_addr_next_vd = pbuf_fsm_fetch & ifu_handshake_done
& ~pipe2hdu_exu_exc_req_i & ~pbuf_addr_end;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
pbuf_addr_ff <= '0;
end else if(clk_en) begin
pbuf_addr_ff <= pbuf_addr_next;
end
end
assign pbuf_addr_next = pbuf_fsm_idle ? '0
: pbuf_addr_next_vd ? pbuf_addr_ff + 1'b1
: pbuf_addr_ff;
// Pass instruction from debug program buffer to cpu pipeline with two options:
// - through register, better for frequency
// - through wires, better for area
generate if (HART_PBUF_INSTR_REGOUT_EN) begin
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
pbuf_instr_wait_latching <= 1'b0;
end else begin
pbuf_instr_wait_latching <= ifu_handshake_done;
end
end
end else begin
assign pbuf_instr_wait_latching = 1'b0;
end endgenerate
//------------------------------------------------------------------------------
// Debug CSRs
//------------------------------------------------------------------------------
assign csr_upd_on_halt = (dbg_state_reset | dbg_state_run)
& (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED);
// CSRs select logic
//------------------------------------------------------------------------------
always_comb begin : csr_if_regsel
csr_dcsr_sel = 1'b0;
csr_dpc_sel = 1'b0;
csr_dscratch0_sel = 1'b0;
//csr_dscratch1_sel = 1'b0;
if (csr2hdu_req_i) begin
case (csr2hdu_addr_i)
SCR1_HDU_DBGCSR_OFFS_DCSR : csr_dcsr_sel = 1'b1;
SCR1_HDU_DBGCSR_OFFS_DPC : csr_dpc_sel = 1'b1;
SCR1_HDU_DBGCSR_OFFS_DSCRATCH0: csr_dscratch0_sel = 1'b1;
default : begin
csr_dcsr_sel = 1'bX;
csr_dpc_sel = 1'bX;
csr_dscratch0_sel = 1'bX;
end
endcase
end
end : csr_if_regsel
// CSRs read interface
//------------------------------------------------------------------------------
assign csr_rd_data = csr_dcsr_out | csr_dpc_out | csr_dscratch0_out;
// CSRs write interface
//------------------------------------------------------------------------------
assign csr_wr = csr2hdu_req_i;
always_comb begin : csr_if_write
csr_wr_data = '0;
if (csr2hdu_req_i) begin
case (csr2hdu_cmd_i)
SCR1_CSR_CMD_WRITE : csr_wr_data = csr2hdu_wdata_i;
SCR1_CSR_CMD_SET : csr_wr_data = csr_rd_data | csr2hdu_wdata_i;
SCR1_CSR_CMD_CLEAR : csr_wr_data = csr_rd_data & (~csr2hdu_wdata_i);
default : csr_wr_data = 'X;
endcase
end
end : csr_if_write
// Debug Control and Status register
//------------------------------------------------------------------------------
// Setups the HART behaviour in Debug Mode and holds Debug status information
always_comb begin
csr_dcsr_in = csr_wr_data;
csr_dcsr_wr = csr_wr & csr_dcsr_sel;
csr_dcsr_out = '0;
if (csr_dcsr_sel) begin
csr_dcsr_out.xdebugver = SCR1_HDU_DEBUGCSR_DCSR_XDEBUGVER;
csr_dcsr_out.ebreakm = csr_dcsr_ebreakm;
csr_dcsr_out.stepie = csr_dcsr_stepie;
csr_dcsr_out.step = csr_dcsr_step;
csr_dcsr_out.prv = 2'b11;
csr_dcsr_out.cause = csr_dcsr_cause;
end
end
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
csr_dcsr_ebreakm <= 1'b0;
csr_dcsr_stepie <= 1'b0;
csr_dcsr_step <= 1'b0;
end else if(clk_en) begin
if (csr_dcsr_wr) begin
csr_dcsr_ebreakm <= csr_dcsr_in.ebreakm;
csr_dcsr_stepie <= csr_dcsr_in.stepie;
csr_dcsr_step <= csr_dcsr_in.step;
end
end
end
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
csr_dcsr_cause <= 1'b0;
end else if(clk_en) begin
if(csr_upd_on_halt) begin
csr_dcsr_cause <= hart_haltstatus.cause;
end
end
end
// Debug PC register
//------------------------------------------------------------------------------
// Saves the virtual address of the next instruction to be executed when Debug
// Mode is entered. Could be changed by debugger
assign csr_dpc_wr = csr_wr & csr_dpc_sel;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
csr_dpc_ff <= '0;
end else if(clk_en) begin
csr_dpc_ff <= csr_dpc_next;
end
end
assign csr_dpc_next = csr_upd_on_halt ? pipe2hdu_pc_curr_i
: csr_dpc_wr ? csr_wr_data
: csr_dpc_ff;
assign csr_dpc_out = csr_dpc_sel ? csr_dpc_ff : '0;
// Debug Scratch 0 register
//------------------------------------------------------------------------------
assign csr_dscratch0_resp = (~dm2hdu_dreg_resp_i | dm2hdu_dreg_fail_i)
? SCR1_CSR_RESP_ER
: SCR1_CSR_RESP_OK;
assign csr_dscratch0_out = csr_dscratch0_sel ? dm2hdu_dreg_rdata_i : '0;
//------------------------------------------------------------------------------
// HDU <-> DM interface
//------------------------------------------------------------------------------
assign hdu2dm_hart_event_o = dfsm_event;
// HART status
always_comb begin
hdu2dm_hart_status_o = '0;
hdu2dm_hart_status_o.dbg_state = dbg_state;
hdu2dm_hart_status_o.except = dbg_state_dhalted & hart_haltstatus.except;
hdu2dm_hart_status_o.ebreak = dbg_state_dhalted & (hart_haltstatus.cause == SCR1_HDU_HALTCAUSE_EBREAK);
end
assign hdu2dm_cmd_rcode_o = dbg_state_reset
? ~pipe2hdu_rdc_qlfy_i | ~pipe2hdu_init_pc_i | ~dm2hdu_cmd_req_i
: ~pipe2hdu_rdc_qlfy_i | ~dfsm_update;
always_comb begin
hdu2dm_cmd_resp_o = 1'b0;
case (dbg_state)
SCR1_HDU_DBGSTATE_RESET: begin
hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & pipe2hdu_init_pc_i & dm2hdu_cmd_req_i;
end
SCR1_HDU_DBGSTATE_RUN: begin
hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i & dfsm_update & dm2hdu_cmd_req_i;
end
SCR1_HDU_DBGSTATE_DHALTED: begin
hdu2dm_cmd_resp_o = pipe2hdu_rdc_qlfy_i ? dfsm_update : dm2hdu_cmd_req_i;
end
SCR1_HDU_DBGSTATE_DRUN: begin
hdu2dm_cmd_resp_o = (~pipe2hdu_rdc_qlfy_i | dfsm_update) & dm2hdu_cmd_req_i;
end
default: begin
hdu2dm_cmd_resp_o = 'X;
end
endcase
end
assign hdu2dm_pbuf_addr_o = pbuf_addr_ff;
assign hdu2dm_dreg_req_o = csr_dscratch0_sel;
assign hdu2dm_dreg_wr_o = csr_wr & csr_dscratch0_sel;
assign hdu2dm_dreg_wdata_o = csr_wr_data;
//------------------------------------------------------------------------------
// HDU <-> EXU interface
//------------------------------------------------------------------------------
assign hdu2exu_dbg_halted_o = (dbg_state_next == SCR1_HDU_DBGSTATE_DHALTED)
| (~pipe2hdu_rdc_qlfy_i & ~dbg_state_run);
assign hdu2exu_dbg_run_start_o = dbg_state_dhalted & pipe2hdu_rdc_qlfy_i & dfsm_update;
assign hdu2exu_dbg_halt2run_o = hdu2exu_dbg_halted_o & hart_resume_req
`ifdef SCR1_CLKCTRL_EN
& clk_pipe_en
`endif // SCR1_CLKCTRL_EN
;
assign hdu2exu_dbg_run2halt_o = hart_halt_ack;
assign hdu2exu_pbuf_fetch_o = hart_runctrl.fetch_src;
assign hdu2exu_irq_dsbl_o = hart_runctrl.irq_dsbl;
assign hdu2exu_pc_advmt_dsbl_o = hart_runctrl.pc_advmt_dsbl;
// No change in arch. state if dmode caused by breakpoint
assign hdu2exu_no_commit_o = dmode_cause_ebreak
`ifdef SCR1_TDU_EN
| dmode_cause_tmreq
`endif // SCR1_TDU_EN
;
assign hdu2exu_dmode_sstep_en_o = hart_runctrl.redirect.sstep;
assign hdu2exu_dbg_new_pc_o = csr_dpc_ff;
//------------------------------------------------------------------------------
// HDU <-> IFU interface
//------------------------------------------------------------------------------
assign hdu2ifu_pbuf_instr_vd_o = (pbuf_fsm_fetch | pbuf_fsm_excinj)
& ~pbuf_instr_wait_latching;
assign hdu2ifu_pbuf_instr_err_o = pbuf_fsm_excinj;
generate if (HART_PBUF_INSTR_REGOUT_EN) begin
always_ff @(posedge clk) begin
hdu2ifu_pbuf_instr_o <= dm2hdu_pbuf_instr_i;
end
end else begin
assign hdu2ifu_pbuf_instr_o = dm2hdu_pbuf_instr_i;
end endgenerate
//------------------------------------------------------------------------------
// HDU <-> CSR interface
//------------------------------------------------------------------------------
assign csr_addr_dscratch0 = (csr2hdu_addr_i == SCR1_HDU_DBGCSR_OFFS_DSCRATCH0);
assign hdu2csr_resp_o = ~dbg_state_drun ? SCR1_CSR_RESP_ER
: csr_addr_dscratch0 ? csr_dscratch0_resp
: csr2hdu_req_i ? SCR1_CSR_RESP_OK
: SCR1_CSR_RESP_ER;
assign hdu2csr_rdata_o = csr_rd_data;
`ifdef SCR1_TDU_EN
//------------------------------------------------------------------------------
// HDU <-> TDU interface
//------------------------------------------------------------------------------
assign hdu2tdu_hwbrk_dsbl_o = hart_runctrl.hwbrkpt_dsbl;
`endif // SCR1_TDU_EN
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
SVA_HDU_XCHECK_COMMON :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown( {rst_n,clk,clk_en,csr2hdu_req_i,pipe2hdu_rdc_qlfy_i} )
)
else $error("HDU Error: common signals are in X state");
SVA_HDU_XCHECK_CSR_INTF :
assert property (
@(negedge clk) disable iff (~rst_n)
csr2hdu_req_i |-> !$isunknown( {csr2hdu_cmd_i,csr2hdu_addr_i,csr2hdu_wdata_i} )
)
else $error("HDU Error: CSR i/f is in X state");
SVA_HDU_XCHECK_DM_INTF :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown( {dm2hdu_cmd_req_i,dm2hdu_cmd_i,dm2hdu_dreg_resp_i,
dm2hdu_dreg_fail_i} )
)
else $error("HDU Error: DM i/f is in X state");
SVA_HDU_XCHECK_TDU_INTF :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown( {tdu2hdu_dmode_req_i,exu2hdu_ibrkpt_hw_i} )
)
else $error("HDU Error: TDU i/f is in X state");
SVA_HDU_XCHECK_HART_INTF :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown( {pipe2hdu_exu_busy_i,pipe2hdu_instret_i,pipe2hdu_init_pc_i,pipe2hdu_exu_exc_req_i,pipe2hdu_brkpt_i,
pipe2hdu_pc_curr_i,ifu2hdu_pbuf_instr_rdy_i} )
)
else $error("HDU Error: HART i/f is in X state");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_hdu
`endif // SCR1_DBG_EN

View File

@@ -0,0 +1,720 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_ialu.sv>
/// @brief Integer Arithmetic Logic Unit (IALU)
///
//-------------------------------------------------------------------------------
//
// Functionality:
// - Performs addition/subtraction and arithmetic and branch comparisons
// - Performs logical operations (AND(I), OR(I), XOR(I))
// - Performs address calculation for branch, jump, DMEM load and store and AUIPC
// instructions
// - Performs shift operations
// - Performs MUL/DIV operations
//
// Structure:
// - Main adder
// - Address adder
// - Shift logic
// - MUL/DIV logic
// - Output result multiplexer
//
//-------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_search_ms1.svh"
module scr1_pipe_ialu (
`ifdef SCR1_RVM_EXT
// Common
input logic clk, // IALU clock
input logic rst_n, // IALU reset
input logic exu2ialu_rvm_cmd_vd_i, // MUL/DIV command valid
output logic ialu2exu_rvm_res_rdy_o, // MUL/DIV result ready
`endif // SCR1_RVM_EXT
// Main adder
input logic [`SCR1_XLEN-1:0] exu2ialu_main_op1_i, // main ALU 1st operand
input logic [`SCR1_XLEN-1:0] exu2ialu_main_op2_i, // main ALU 2nd operand
input type_scr1_ialu_cmd_sel_e exu2ialu_cmd_i, // IALU command
output logic [`SCR1_XLEN-1:0] ialu2exu_main_res_o, // main ALU result
output logic ialu2exu_cmp_res_o, // IALU comparison result
// Address adder
input logic [`SCR1_XLEN-1:0] exu2ialu_addr_op1_i, // Address adder 1st operand
input logic [`SCR1_XLEN-1:0] exu2ialu_addr_op2_i, // Address adder 2nd operand
output logic [`SCR1_XLEN-1:0] ialu2exu_addr_res_o // Address adder result
);
//-------------------------------------------------------------------------------
// Local parameters declaration
//-------------------------------------------------------------------------------
`ifdef SCR1_RVM_EXT
`ifdef SCR1_FAST_MUL
localparam SCR1_MUL_WIDTH = `SCR1_XLEN;
localparam SCR1_MUL_RES_WIDTH = 2 * `SCR1_XLEN;
localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + 1;
`else
localparam SCR1_MUL_STG_NUM = 32;
localparam SCR1_MUL_WIDTH = 32 / SCR1_MUL_STG_NUM;
localparam SCR1_MUL_CNT_INIT = 32'b1 << (`SCR1_XLEN/SCR1_MUL_WIDTH - 2);
localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + SCR1_MUL_WIDTH;
`endif // ~SCR1_FAST_MUL
localparam SCR1_DIV_WIDTH = 1;
localparam SCR1_DIV_CNT_INIT = 32'b1 << (`SCR1_XLEN/SCR1_DIV_WIDTH - 2);
`endif // SCR1_RVM_EXT
//-------------------------------------------------------------------------------
// Local types declaration
//-------------------------------------------------------------------------------
typedef struct packed {
logic z; // Zero
logic s; // Sign
logic o; // Overflow
logic c; // Carry
} type_scr1_ialu_flags_s;
`ifdef SCR1_RVM_EXT
typedef enum logic [1:0] {
SCR1_IALU_MDU_FSM_IDLE,
SCR1_IALU_MDU_FSM_ITER,
SCR1_IALU_MDU_FSM_CORR
} type_scr1_ialu_fsm_state;
typedef enum logic [1:0] {
SCR1_IALU_MDU_NONE,
SCR1_IALU_MDU_MUL,
SCR1_IALU_MDU_DIV
} type_scr1_ialu_mdu_cmd;
`endif // SCR1_RVM_EXT
//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------
// Main adder signals
logic [`SCR1_XLEN:0] main_sum_res; // Main adder result
type_scr1_ialu_flags_s main_sum_flags; // Main adder flags
logic main_sum_pos_ovflw; // Main adder positive overflow
logic main_sum_neg_ovflw; // Main adder negative overflow
logic main_ops_diff_sgn; // Main adder operands have different signs
logic main_ops_non_zero; // Both main adder operands are NOT 0
// Shifter signals
logic ialu_cmd_shft; // IALU command is shift
logic signed [`SCR1_XLEN-1:0] shft_op1; // SHIFT operand 1
logic [4:0] shft_op2; // SHIFT operand 2
logic [1:0] shft_cmd; // SHIFT command: 00 - logical left, 10 - logical right, 11 - arithmetical right
logic [`SCR1_XLEN-1:0] shft_res; // SHIFT result
// MUL/DIV signals
`ifdef SCR1_RVM_EXT
// MUL/DIV FSM control signals
logic mdu_cmd_is_iter; // MDU Command is iterative
logic mdu_iter_req; // Request iterative stage
logic mdu_iter_rdy; // Iteration is ready
logic mdu_corr_req; // DIV/REM(U) correction request
logic div_corr_req; // Correction request for DIV operation
logic rem_corr_req; // Correction request for REM(U) operations
// MUL/DIV FSM signals
type_scr1_ialu_fsm_state mdu_fsm_ff; // Current FSM state
type_scr1_ialu_fsm_state mdu_fsm_next; // Next FSM state
logic mdu_fsm_idle; // MDU FSM is in IDLE state
`ifdef SCR1_TRGT_SIMULATION
logic mdu_fsm_iter; // MDU FSM is in ITER state
`endif // SCR1_TRGT_SIMULATION
logic mdu_fsm_corr; // MDU FSM is in CORR state
// MDU command signals
type_scr1_ialu_mdu_cmd mdu_cmd; // MDU command: 00 - NONE, 01 - MUL, 10 - DIV
logic mdu_cmd_mul; // MDU command is MUL(HSU)
logic mdu_cmd_div; // MDU command is DIV(U)/REM(U)
logic [1:0] mul_cmd; // MUL command: 00 - MUL, 01 - MULH, 10 - MULHSU, 11 - MULHU
logic mul_cmd_hi; // High part of MUL result is requested
logic [1:0] div_cmd; // DIV command: 00 - DIV, 01 - DIVU, 10 - REM, 11 - REMU
logic div_cmd_div; // DIV command is DIV
logic div_cmd_rem; // DIV command is REM(U)
// Multiplier signals
logic mul_op1_is_sgn; // First MUL operand is signed
logic mul_op2_is_sgn; // Second MUL operand is signed
logic mul_op1_sgn; // First MUL operand is negative
logic mul_op2_sgn; // Second MUL operand is negative
logic signed [`SCR1_XLEN:0] mul_op1; // MUL operand 1
logic signed [SCR1_MUL_WIDTH:0] mul_op2; // MUL operand 1
`ifdef SCR1_FAST_MUL
logic signed [SCR1_MUL_RES_WIDTH-1:0] mul_res; // MUL result
`else // ~SCR1_FAST_MUL
logic signed [SCR1_MDU_SUM_WIDTH:0] mul_part_prod;
logic [`SCR1_XLEN-1:0] mul_res_hi;
logic [`SCR1_XLEN-1:0] mul_res_lo;
`endif // ~SCR1_FAST_MUL
// Divisor signals
logic div_ops_are_sgn;
logic div_op1_is_neg;
logic div_op2_is_neg;
logic div_res_rem_c;
logic [`SCR1_XLEN-1:0] div_res_rem;
logic [`SCR1_XLEN-1:0] div_res_quo;
logic div_quo_bit;
logic div_dvdnd_lo_upd;
logic [`SCR1_XLEN-1:0] div_dvdnd_lo_ff;
logic [`SCR1_XLEN-1:0] div_dvdnd_lo_next;
// MDU adder signals
logic mdu_sum_sub; // MDU adder operation: 0 - add, 1 - sub
logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_op1; // MDU adder operand 1
logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_op2; // MDU adder operand 2
logic signed [SCR1_MDU_SUM_WIDTH-1:0] mdu_sum_res; // MDU adder result
// MDU iteration counter signals
logic mdu_iter_cnt_en;
logic [`SCR1_XLEN-1:0] mdu_iter_cnt;
logic [`SCR1_XLEN-1:0] mdu_iter_cnt_next;
// Intermediate results registers
logic mdu_res_upd;
logic mdu_res_c_ff;
logic mdu_res_c_next;
logic [`SCR1_XLEN-1:0] mdu_res_hi_ff;
logic [`SCR1_XLEN-1:0] mdu_res_hi_next;
logic [`SCR1_XLEN-1:0] mdu_res_lo_ff;
logic [`SCR1_XLEN-1:0] mdu_res_lo_next;
`endif // SCR1_RVM_EXT
//-------------------------------------------------------------------------------
// Main adder
//-------------------------------------------------------------------------------
//
// Main adder is used for the following types of operations:
// - Addition/subtraction (ADD/ADDI/SUB)
// - Branch comparisons (BEQ/BNE/BLT(U)/BGE(U))
// - Arithmetic comparisons (SLT(U)/SLTI(U))
//
// Carry out (MSB of main_sum_res) is evaluated correctly because the result
// width equals to the maximum width of both the right-hand and left-hand side variables
always_comb begin
main_sum_res = (exu2ialu_cmd_i != SCR1_IALU_CMD_ADD)
? ({1'b0, exu2ialu_main_op1_i} - {1'b0, exu2ialu_main_op2_i}) // Subtraction and comparison
: ({1'b0, exu2ialu_main_op1_i} + {1'b0, exu2ialu_main_op2_i}); // Addition
main_sum_pos_ovflw = ~exu2ialu_main_op1_i[`SCR1_XLEN-1]
& exu2ialu_main_op2_i[`SCR1_XLEN-1]
& main_sum_res[`SCR1_XLEN-1];
main_sum_neg_ovflw = exu2ialu_main_op1_i[`SCR1_XLEN-1]
& ~exu2ialu_main_op2_i[`SCR1_XLEN-1]
& ~main_sum_res[`SCR1_XLEN-1];
// FLAGS1 - flags for comparison (result of subtraction)
main_sum_flags.c = main_sum_res[`SCR1_XLEN];
main_sum_flags.z = ~|main_sum_res[`SCR1_XLEN-1:0];
main_sum_flags.s = main_sum_res[`SCR1_XLEN-1];
main_sum_flags.o = main_sum_pos_ovflw | main_sum_neg_ovflw;
end
//-------------------------------------------------------------------------------
// Address adder
//-------------------------------------------------------------------------------
//
// Additional adder is used for the following types of operations:
// - PC-based address calculation (AUIPC)
// - IMEM branch address calculation (BEQ/BNE/BLT(U)/BGE(U))
// - IMEM jump address calculation (JAL/JALR)
// - DMEM load address calculation (LB(U)/LH(U)/LW)
// - DMEM store address calculation (SB/SH/SW)
//
assign ialu2exu_addr_res_o = exu2ialu_addr_op1_i + exu2ialu_addr_op2_i;
//-------------------------------------------------------------------------------
// Shift logic
//-------------------------------------------------------------------------------
//
// Shift logic supports the following types of shift operations:
// - Logical left shift (SLLI/SLL)
// - Logical right shift (SRLI/SRL)
// - Arithmetic right shift (SRAI/SRA)
//
assign ialu_cmd_shft = (exu2ialu_cmd_i == SCR1_IALU_CMD_SLL)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_SRL)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_SRA);
assign shft_cmd = ialu_cmd_shft
? {(exu2ialu_cmd_i != SCR1_IALU_CMD_SLL),
(exu2ialu_cmd_i == SCR1_IALU_CMD_SRA)}
: 2'b00;
always_comb begin
shft_op1 = exu2ialu_main_op1_i;
shft_op2 = exu2ialu_main_op2_i[4:0];
case (shft_cmd)
2'b10 : shft_res = shft_op1 >> shft_op2;
2'b11 : shft_res = shft_op1 >>> shft_op2;
default : shft_res = shft_op1 << shft_op2;
endcase
end
`ifdef SCR1_RVM_EXT
//-------------------------------------------------------------------------------
// MUL/DIV logic
//-------------------------------------------------------------------------------
//
// MUL/DIV instructions use the following functional units:
// - MUL/DIV FSM control logic, including iteration number counter
// - MUL/DIV FSM
// - MUL logic
// - DIV logic
// - MDU adder to produce an intermediate result
// - 2 registers to save the intermediate result (shared between MUL and DIV
// operations)
//
//-------------------------------------------------------------------------------
// MUL/DIV FSM Control logic
//-------------------------------------------------------------------------------
assign mdu_cmd_div = (exu2ialu_cmd_i == SCR1_IALU_CMD_DIV)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_REM)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU);
assign mdu_cmd_mul = (exu2ialu_cmd_i == SCR1_IALU_CMD_MUL)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU)
| (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU);
assign mdu_cmd = mdu_cmd_div ? SCR1_IALU_MDU_DIV
: mdu_cmd_mul ? SCR1_IALU_MDU_MUL
: SCR1_IALU_MDU_NONE;
assign main_ops_non_zero = |exu2ialu_main_op1_i & |exu2ialu_main_op2_i;
assign main_ops_diff_sgn = exu2ialu_main_op1_i[`SCR1_XLEN-1]
^ exu2ialu_main_op2_i[`SCR1_XLEN-1];
`ifdef SCR1_FAST_MUL
assign mdu_cmd_is_iter = mdu_cmd_div;
`else // ~SCR1_FAST_MUL
assign mdu_cmd_is_iter = mdu_cmd_mul | mdu_cmd_div;
`endif // ~SCR1_FAST_MUL
assign mdu_iter_req = mdu_cmd_is_iter ? (main_ops_non_zero & mdu_fsm_idle) : 1'b0;
assign mdu_iter_rdy = mdu_iter_cnt[0];
assign div_cmd_div = (div_cmd == 2'b00);
assign div_cmd_rem = div_cmd[1];
// Correction request signals
assign div_corr_req = div_cmd_div & main_ops_diff_sgn;
assign rem_corr_req = div_cmd_rem & |div_res_rem & (div_op1_is_neg ^ div_res_rem_c);
assign mdu_corr_req = mdu_cmd_div & (div_corr_req | rem_corr_req);
// MDU iteration counter
//------------------------------------------------------------------------------
assign mdu_iter_cnt_en = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
always_ff @(posedge clk) begin
if (mdu_iter_cnt_en) begin
mdu_iter_cnt <= mdu_iter_cnt_next;
end
end
assign mdu_iter_cnt_next = ~mdu_fsm_idle ? mdu_iter_cnt >> 1
: mdu_cmd_div ? SCR1_DIV_CNT_INIT
`ifndef SCR1_FAST_MUL
: mdu_cmd_mul ? SCR1_MUL_CNT_INIT
`endif // ~SCR1_FAST_MUL
: mdu_iter_cnt;
//-------------------------------------------------------------------------------
// MUL/DIV FSM
//-------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
mdu_fsm_ff <= SCR1_IALU_MDU_FSM_IDLE;
end else begin
mdu_fsm_ff <= mdu_fsm_next;
end
end
always_comb begin
mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE;
if (exu2ialu_rvm_cmd_vd_i) begin
case (mdu_fsm_ff)
SCR1_IALU_MDU_FSM_IDLE : begin
mdu_fsm_next = mdu_iter_req ? SCR1_IALU_MDU_FSM_ITER
: SCR1_IALU_MDU_FSM_IDLE;
end
SCR1_IALU_MDU_FSM_ITER : begin
mdu_fsm_next = ~mdu_iter_rdy ? SCR1_IALU_MDU_FSM_ITER
: mdu_corr_req ? SCR1_IALU_MDU_FSM_CORR
: SCR1_IALU_MDU_FSM_IDLE;
end
SCR1_IALU_MDU_FSM_CORR : begin
mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE;
end
endcase
end
end
assign mdu_fsm_idle = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_IDLE);
`ifdef SCR1_TRGT_SIMULATION
assign mdu_fsm_iter = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_ITER);
`endif // SCR1_TRGT_SIMULATION
assign mdu_fsm_corr = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_CORR);
//-------------------------------------------------------------------------------
// Multiplier logic
//-------------------------------------------------------------------------------
//
// Multiplication has 2 options: fast (1 cycle) and Radix-2 (32 cycles) multiplication.
//
// 1. Fast multiplication uses the straightforward approach when 2 operands are
// multiplied in one cycle
//
// 2. Radix-2 multiplication uses 2 registers (high and low part of multiplication)
//
// Radix-2 algorithm:
// 1. Initialize registers
// 2. Create a partial product by multiplying multiplicand by the LSB of multiplier
// 3. Add the partial product to the previous (intermediate) value of multiplication
// result (stored into high and low parts of multiplication result register)
// 4. Shift the low part of multiplication result register right
// 4. Store the addition result into the high part of multiplication result register
// 6. If iteration is not ready, go to step 2. Otherwise multiplication is done
//
//
assign mul_cmd = {((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU)),
((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH))};
assign mul_cmd_hi = |mul_cmd;
assign mul_op1_is_sgn = ~&mul_cmd;
assign mul_op2_is_sgn = ~mul_cmd[1];
assign mul_op1_sgn = mul_op1_is_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1];
assign mul_op2_sgn = mul_op2_is_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1];
`ifdef SCR1_FAST_MUL
assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0;
assign mul_op2 = mdu_cmd_mul ? $signed({mul_op2_sgn, exu2ialu_main_op2_i}) : '0;
assign mul_res = mdu_cmd_mul ? mul_op1 * mul_op2 : $signed('0);
`else // ~SCR1_FAST_MUL
assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0;
assign mul_op2 = ~mdu_cmd_mul ? '0
: mdu_fsm_idle ? $signed({1'b0, exu2ialu_main_op2_i[SCR1_MUL_WIDTH-1:0]})
: $signed({(mdu_iter_cnt[0] & mul_op2_is_sgn & mdu_res_lo_ff[SCR1_MUL_WIDTH-1]),
mdu_res_lo_ff[SCR1_MUL_WIDTH-1:0]});
assign mul_part_prod = mdu_cmd_mul ? mul_op1 * mul_op2 : $signed('0);
assign {mul_res_hi, mul_res_lo} = ~mdu_cmd_mul ? '0
: mdu_fsm_idle ? ({mdu_sum_res, exu2ialu_main_op2_i[`SCR1_XLEN-1:SCR1_MUL_WIDTH]})
: ({mdu_sum_res, mdu_res_lo_ff[`SCR1_XLEN-1:SCR1_MUL_WIDTH]});
`endif // ~SCR1_FAST_MUL
//-------------------------------------------------------------------------------
// Divider logic
//-------------------------------------------------------------------------------
//
// Division uses a non-restoring algorithm. 3 registers are used:
// - Remainder register
// - Quotient register
// - Dividend low part register (for corner case quotient bit calculation)
//
// Algorithm:
// 1. Initialize registers
// 2. Shift remainder and dividend low part registers left
// 3. Compare remainder register with the divisor (taking previous quotient bit
// and operands signs into account) and calculate quotient bit based on the
// comparison results
// 4. Shift quotient register left, append quotient bit to the quotient register
// 5. If iteration is not ready, go to step 2. Otherwise go to step 6
// 6. Do correction if necessary, otherwise division is done
//
// Quotient bit calculation has a corner case:
// When dividend is negative result carry bit check takes into account only
// the case of remainder register been greater than divisor. To handle
// equality case we should check if both the comparison result and the
// lower part of dividend are zero
//
assign div_cmd = {((exu2ialu_cmd_i == SCR1_IALU_CMD_REM) | (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU)),
((exu2ialu_cmd_i == SCR1_IALU_CMD_REMU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU))};
assign div_ops_are_sgn = ~div_cmd[0];
assign div_op1_is_neg = div_ops_are_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1];
assign div_op2_is_neg = div_ops_are_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1];
always_comb begin
div_res_rem_c = '0;
div_res_rem = '0;
div_res_quo = '0;
div_quo_bit = 1'b0;
if (mdu_cmd_div & ~mdu_fsm_corr) begin
div_res_rem_c = mdu_sum_res[SCR1_MDU_SUM_WIDTH-1];
div_res_rem = mdu_sum_res[SCR1_MDU_SUM_WIDTH-2:0];
div_quo_bit = ~(div_op1_is_neg ^ div_res_rem_c)
| (div_op1_is_neg & ({mdu_sum_res, div_dvdnd_lo_next} == '0));
div_res_quo = mdu_fsm_idle
? {'0, div_quo_bit}
: {mdu_res_lo_ff[`SCR1_XLEN-2:0], div_quo_bit};
end
end
// Dividend low part register
//------------------------------------------------------------------------------
assign div_dvdnd_lo_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
always_ff @(posedge clk) begin
if (div_dvdnd_lo_upd) begin
div_dvdnd_lo_ff <= div_dvdnd_lo_next;
end
end
assign div_dvdnd_lo_next = (~mdu_cmd_div | mdu_fsm_corr) ? '0
: mdu_fsm_idle ? exu2ialu_main_op1_i << 1
: div_dvdnd_lo_ff << 1;
//-------------------------------------------------------------------------------
// MDU adder
//-------------------------------------------------------------------------------
always_comb begin
mdu_sum_sub = 1'b0;
mdu_sum_op1 = '0;
mdu_sum_op2 = '0;
case (mdu_cmd)
SCR1_IALU_MDU_DIV : begin
logic sgn;
logic inv;
sgn = mdu_fsm_corr ? div_op1_is_neg ^ mdu_res_c_ff
: mdu_fsm_idle ? 1'b0
: ~mdu_res_lo_ff[0];
inv = div_ops_are_sgn & main_ops_diff_sgn;
mdu_sum_sub = ~inv ^ sgn;
mdu_sum_op1 = mdu_fsm_corr ? $signed({1'b0, mdu_res_hi_ff})
: mdu_fsm_idle ? $signed({div_op1_is_neg, exu2ialu_main_op1_i[`SCR1_XLEN-1]})
: $signed({mdu_res_hi_ff, div_dvdnd_lo_ff[`SCR1_XLEN-1]});
mdu_sum_op2 = $signed({div_op2_is_neg, exu2ialu_main_op2_i});
end
`ifndef SCR1_FAST_MUL
SCR1_IALU_MDU_MUL : begin
mdu_sum_op1 = mdu_fsm_idle
? '0
: $signed({(mul_op1_is_sgn & mdu_res_hi_ff[`SCR1_XLEN-1]), mdu_res_hi_ff});
mdu_sum_op2 = mul_part_prod;
end
`endif // SCR1_FAST_MUL
default : begin end
endcase
mdu_sum_res = mdu_sum_sub
? (mdu_sum_op1 - mdu_sum_op2)
: (mdu_sum_op1 + mdu_sum_op2);
end
//-------------------------------------------------------------------------------
// MUL/DIV intermediate results registers
//-------------------------------------------------------------------------------
assign mdu_res_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
always_ff @(posedge clk) begin
if (mdu_res_upd) begin
mdu_res_c_ff <= mdu_res_c_next;
mdu_res_hi_ff <= mdu_res_hi_next;
mdu_res_lo_ff <= mdu_res_lo_next;
end
end
assign mdu_res_c_next = mdu_cmd_div ? div_res_rem_c : mdu_res_c_ff;
assign mdu_res_hi_next = mdu_cmd_div ? div_res_rem
`ifndef SCR1_FAST_MUL
: mdu_cmd_mul ? mul_res_hi
`endif // SCR1_FAST_MUL
: mdu_res_hi_ff;
assign mdu_res_lo_next = mdu_cmd_div ? div_res_quo
`ifndef SCR1_FAST_MUL
: mdu_cmd_mul ? mul_res_lo
`endif // SCR1_FAST_MUL
: mdu_res_lo_ff;
`endif // SCR1_RVM_EXT
//-------------------------------------------------------------------------------
// Operation result forming
//-------------------------------------------------------------------------------
always_comb begin
ialu2exu_main_res_o = '0;
ialu2exu_cmp_res_o = 1'b0;
`ifdef SCR1_RVM_EXT
ialu2exu_rvm_res_rdy_o = 1'b1;
`endif // SCR1_RVM_EXT
case (exu2ialu_cmd_i)
SCR1_IALU_CMD_AND : begin
ialu2exu_main_res_o = exu2ialu_main_op1_i & exu2ialu_main_op2_i;
end
SCR1_IALU_CMD_OR : begin
ialu2exu_main_res_o = exu2ialu_main_op1_i | exu2ialu_main_op2_i;
end
SCR1_IALU_CMD_XOR : begin
ialu2exu_main_res_o = exu2ialu_main_op1_i ^ exu2ialu_main_op2_i;
end
SCR1_IALU_CMD_ADD : begin
ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0];
end
SCR1_IALU_CMD_SUB : begin
ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0];
end
SCR1_IALU_CMD_SUB_LT : begin
ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.s ^ main_sum_flags.o);
ialu2exu_cmp_res_o = main_sum_flags.s ^ main_sum_flags.o;
end
SCR1_IALU_CMD_SUB_LTU : begin
ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.c);
ialu2exu_cmp_res_o = main_sum_flags.c;
end
SCR1_IALU_CMD_SUB_EQ : begin
ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.z);
ialu2exu_cmp_res_o = main_sum_flags.z;
end
SCR1_IALU_CMD_SUB_NE : begin
ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.z);
ialu2exu_cmp_res_o = ~main_sum_flags.z;
end
SCR1_IALU_CMD_SUB_GE : begin
ialu2exu_main_res_o = `SCR1_XLEN'(~(main_sum_flags.s ^ main_sum_flags.o));
ialu2exu_cmp_res_o = ~(main_sum_flags.s ^ main_sum_flags.o);
end
SCR1_IALU_CMD_SUB_GEU : begin
ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.c);
ialu2exu_cmp_res_o = ~main_sum_flags.c;
end
SCR1_IALU_CMD_SLL,
SCR1_IALU_CMD_SRL,
SCR1_IALU_CMD_SRA: begin
ialu2exu_main_res_o = shft_res;
end
`ifdef SCR1_RVM_EXT
SCR1_IALU_CMD_MUL,
SCR1_IALU_CMD_MULHU,
SCR1_IALU_CMD_MULHSU,
SCR1_IALU_CMD_MULH : begin
`ifdef SCR1_FAST_MUL
ialu2exu_main_res_o = mul_cmd_hi
? mul_res[SCR1_MUL_RES_WIDTH-1:`SCR1_XLEN]
: mul_res[`SCR1_XLEN-1:0];
`else // ~SCR1_FAST_MUL
case (mdu_fsm_ff)
SCR1_IALU_MDU_FSM_IDLE : begin
ialu2exu_main_res_o = '0;
ialu2exu_rvm_res_rdy_o = ~mdu_iter_req;
end
SCR1_IALU_MDU_FSM_ITER : begin
ialu2exu_main_res_o = mul_cmd_hi ? mul_res_hi : mul_res_lo;
ialu2exu_rvm_res_rdy_o = mdu_iter_rdy;
end
endcase
`endif // ~SCR1_FAST_MUL
end
SCR1_IALU_CMD_DIV,
SCR1_IALU_CMD_DIVU,
SCR1_IALU_CMD_REM,
SCR1_IALU_CMD_REMU : begin
case (mdu_fsm_ff)
SCR1_IALU_MDU_FSM_IDLE : begin
ialu2exu_main_res_o = (|exu2ialu_main_op2_i | div_cmd_rem)
? exu2ialu_main_op1_i
: '1;
ialu2exu_rvm_res_rdy_o = ~mdu_iter_req;
end
SCR1_IALU_MDU_FSM_ITER : begin
ialu2exu_main_res_o = div_cmd_rem ? div_res_rem : div_res_quo;
ialu2exu_rvm_res_rdy_o = mdu_iter_rdy & ~mdu_corr_req;
end
SCR1_IALU_MDU_FSM_CORR : begin
ialu2exu_main_res_o = div_cmd_rem
? mdu_sum_res[`SCR1_XLEN-1:0]
: -mdu_res_lo_ff[`SCR1_XLEN-1:0];
ialu2exu_rvm_res_rdy_o = 1'b1;
end
endcase
end
`endif // SCR1_RVM_EXT
default : begin end
endcase
end
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
`ifdef SCR1_RVM_EXT
// X checks
SCR1_SVA_IALU_XCHECK : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({exu2ialu_rvm_cmd_vd_i, mdu_fsm_ff})
) else $error("IALU Error: unknown values");
SCR1_SVA_IALU_XCHECK_QUEUE : assert property (
@(negedge clk) disable iff (~rst_n)
exu2ialu_rvm_cmd_vd_i |->
!$isunknown({exu2ialu_main_op1_i, exu2ialu_main_op2_i, exu2ialu_cmd_i})
) else $error("IALU Error: unknown values in queue");
// Behavior checks
SCR1_SVA_IALU_ILL_STATE : assert property (
@(negedge clk) disable iff (~rst_n)
$onehot0({~exu2ialu_rvm_cmd_vd_i, mdu_fsm_iter, mdu_fsm_corr})
) else $error("IALU Error: illegal state");
SCR1_SVA_IALU_JUMP_FROM_IDLE : assert property (
@(negedge clk) disable iff (~rst_n)
(mdu_fsm_idle & (~exu2ialu_rvm_cmd_vd_i | ~mdu_iter_req)) |=> mdu_fsm_idle
) else $error("EXU Error: illegal jump from IDLE state");
SCR1_SVA_IALU_IDLE_TO_ITER : assert property (
@(negedge clk) disable iff (~rst_n)
(mdu_fsm_idle & exu2ialu_rvm_cmd_vd_i & mdu_iter_req) |=> mdu_fsm_iter
) else $error("EXU Error: illegal change state form IDLE to ITER");
SCR1_SVA_IALU_JUMP_FROM_ITER : assert property (
@(negedge clk) disable iff (~rst_n)
(mdu_fsm_iter & ~mdu_iter_rdy) |=> mdu_fsm_iter
) else $error("EXU Error: illegal jump from ITER state");
SCR1_SVA_IALU_ITER_TO_IDLE : assert property (
@(negedge clk) disable iff (~rst_n)
(mdu_fsm_iter & mdu_iter_rdy & ~mdu_corr_req) |=> mdu_fsm_idle
) else $error("EXU Error: illegal state change ITER to IDLE");
SCR1_SVA_IALU_ITER_TO_CORR : assert property (
@(negedge clk) disable iff (~rst_n)
(mdu_fsm_iter & mdu_iter_rdy & mdu_corr_req) |=> mdu_fsm_corr
) else $error("EXU Error: illegal state change ITER to CORR");
SCR1_SVA_IALU_CORR_TO_IDLE : assert property (
@(negedge clk) disable iff (~rst_n)
mdu_fsm_corr |=> mdu_fsm_idle
) else $error("EXU Error: illegal state stay in CORR");
`endif // SCR1_RVM_EXT
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_ialu

View File

@@ -0,0 +1,940 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_idu.sv>
/// @brief Instruction Decoder Unit (IDU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Decodes the instruction and creates the appropriate control signals for EXU
//
// Structure:
// - Instruction decoder
// - IDU <-> IFU i/f
// - IDU <-> EXU i/f
//
//------------------------------------------------------------------------------
`include "scr1_memif.svh"
`include "scr1_arch_types.svh"
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_arch_description.svh"
module scr1_pipe_idu
(
`ifdef SCR1_TRGT_SIMULATION
input logic rst_n, // IDU reset
input logic clk, // IDU clock
`endif // SCR1_TRGT_SIMULATION
// IFU <-> IDU interface
output logic idu2ifu_rdy_o, // IDU ready for new data
input logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr_i, // IFU instruction
input logic ifu2idu_imem_err_i, // Instruction access fault exception
input logic ifu2idu_err_rvi_hi_i, // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
input logic ifu2idu_vd_i, // IFU request
// IDU <-> EXU interface
output logic idu2exu_req_o, // IDU request
output type_scr1_exu_cmd_s idu2exu_cmd_o, // IDU command
output logic idu2exu_use_rs1_o, // Instruction uses rs1
output logic idu2exu_use_rs2_o, // Instruction uses rs2
`ifndef SCR1_NO_EXE_STAGE
output logic idu2exu_use_rd_o, // Instruction uses rd
output logic idu2exu_use_imm_o, // Instruction uses immediate
`endif // SCR1_NO_EXE_STAGE
input logic exu2idu_rdy_i // EXU ready for new data
);
//-------------------------------------------------------------------------------
// Local parameters declaration
//-------------------------------------------------------------------------------
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_ZERO_ADDR = 5'd0;
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_RA_ADDR = 5'd1;
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_SP_ADDR = 5'd2;
//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------
logic [`SCR1_IMEM_DWIDTH-1:0] instr;
type_scr1_instr_type_e instr_type;
type_scr1_rvi_opcode_e rvi_opcode;
logic rvi_illegal;
logic [2:0] funct3;
logic [6:0] funct7;
logic [11:0] funct12;
logic [4:0] shamt;
`ifdef SCR1_RVC_EXT
logic rvc_illegal;
`endif // SCR1_RVC_EXT
`ifdef SCR1_RVE_EXT
logic rve_illegal;
`endif // SCR1_RVE_EXT
//-------------------------------------------------------------------------------
// Instruction decoding
//-------------------------------------------------------------------------------
assign idu2ifu_rdy_o = exu2idu_rdy_i;
assign idu2exu_req_o = ifu2idu_vd_i;
assign instr = ifu2idu_instr_i;
// RVI / RVC
assign instr_type = type_scr1_instr_type_e'(instr[1:0]);
// RVI / RVC fields
assign rvi_opcode = type_scr1_rvi_opcode_e'(instr[6:2]); // RVI
assign funct3 = (instr_type == SCR1_INSTR_RVI) ? instr[14:12] : instr[15:13]; // RVI / RVC
assign funct7 = instr[31:25]; // RVI
assign funct12 = instr[31:20]; // RVI (SYSTEM)
assign shamt = instr[24:20]; // RVI
// RV32I(MC) decode
always_comb begin
// Defaults
idu2exu_cmd_o.instr_rvc = 1'b0;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_NONE;
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_NONE;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_NONE;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_NONE;
idu2exu_cmd_o.jump_req = 1'b0;
idu2exu_cmd_o.branch_req = 1'b0;
idu2exu_cmd_o.mret_req = 1'b0;
idu2exu_cmd_o.fencei_req = 1'b0;
idu2exu_cmd_o.wfi_req = 1'b0;
idu2exu_cmd_o.rs1_addr = '0;
idu2exu_cmd_o.rs2_addr = '0;
idu2exu_cmd_o.rd_addr = '0;
idu2exu_cmd_o.imm = '0;
idu2exu_cmd_o.exc_req = 1'b0;
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_INSTR_MISALIGN;
// Clock gating
idu2exu_use_rs1_o = 1'b0;
idu2exu_use_rs2_o = 1'b0;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b0;
idu2exu_use_imm_o = 1'b0;
`endif // SCR1_NO_EXE_STAGE
rvi_illegal = 1'b0;
`ifdef SCR1_RVE_EXT
rve_illegal = 1'b0;
`endif // SCR1_RVE_EXT
`ifdef SCR1_RVC_EXT
rvc_illegal = 1'b0;
`endif // SCR1_RVC_EXT
// Check for IMEM access fault
if (ifu2idu_imem_err_i) begin
idu2exu_cmd_o.exc_req = 1'b1;
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_INSTR_ACCESS_FAULT;
idu2exu_cmd_o.instr_rvc = ifu2idu_err_rvi_hi_i;
end else begin // no imem fault
case (instr_type)
SCR1_INSTR_RVI : begin
idu2exu_cmd_o.rs1_addr = instr[19:15];
idu2exu_cmd_o.rs2_addr = instr[24:20];
idu2exu_cmd_o.rd_addr = instr[11:7];
case (rvi_opcode)
SCR1_OPCODE_AUIPC : begin
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_SUM2;
idu2exu_cmd_o.imm = {instr[31:12], 12'b0};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_AUIPC
SCR1_OPCODE_LUI : begin
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM;
idu2exu_cmd_o.imm = {instr[31:12], 12'b0};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_LUI
SCR1_OPCODE_JAL : begin
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
idu2exu_cmd_o.jump_req = 1'b1;
idu2exu_cmd_o.imm = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_JAL
SCR1_OPCODE_LOAD : begin
idu2exu_use_rs1_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU;
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]};
case (funct3)
3'b000 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LB;
3'b001 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LH;
3'b010 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW;
3'b100 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LBU;
3'b101 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LHU;
default : rvi_illegal = 1'b1;
endcase // funct3
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_LOAD
SCR1_OPCODE_STORE : begin
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:25], instr[11:7]};
case (funct3)
3'b000 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SB;
3'b001 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SH;
3'b010 : idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW;
default : rvi_illegal = 1'b1;
endcase // funct3
`ifdef SCR1_RVE_EXT
if (instr[19] | instr[24]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_STORE
SCR1_OPCODE_OP : begin
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
case (funct7)
7'b0000000 : begin
case (funct3)
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL;
3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT;
3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU;
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR;
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL;
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR;
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND;
endcase // funct3
end // 7'b0000000
7'b0100000 : begin
case (funct3)
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB;
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA;
default : rvi_illegal = 1'b1;
endcase // funct3
end // 7'b0100000
`ifdef SCR1_RVM_EXT
7'b0000001 : begin
case (funct3)
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MUL;
3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULH;
3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULHSU;
3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_MULHU;
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_DIV;
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_DIVU;
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_REM;
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_REMU;
endcase // funct3
end // 7'b0000001
`endif // SCR1_RVM_EXT
default : rvi_illegal = 1'b1;
endcase // funct7
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19] | instr[24]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_OP
SCR1_OPCODE_OP_IMM : begin
idu2exu_use_rs1_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]};
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
case (funct3)
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD; // ADDI
3'b010 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT; // SLTI
3'b011 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU; // SLTIU
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR; // XORI
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR; // ORI
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND; // ANDI
3'b001 : begin
case (funct7)
7'b0000000 : begin
// SLLI
idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL;
end
default : rvi_illegal = 1'b1;
endcase // funct7
end
3'b101 : begin
case (funct7)
7'b0000000 : begin
// SRLI
idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL;
end
7'b0100000 : begin
// SRAI
idu2exu_cmd_o.imm = `SCR1_XLEN'(shamt); // zero-extend
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA;
end
default : rvi_illegal = 1'b1;
endcase // funct7
end
endcase // funct3
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_OP_IMM
SCR1_OPCODE_MISC_MEM : begin
case (funct3)
3'b000 : begin
if (~|{instr[31:28], instr[19:15], instr[11:7]}) begin
// FENCE = NOP
end
else rvi_illegal = 1'b1;
end
3'b001 : begin
if (~|{instr[31:15], instr[11:7]}) begin
// FENCE.I
idu2exu_cmd_o.fencei_req = 1'b1;
end
else rvi_illegal = 1'b1;
end
default : rvi_illegal = 1'b1;
endcase // funct3
end // SCR1_OPCODE_MISC_MEM
SCR1_OPCODE_BRANCH : begin
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.imm = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
idu2exu_cmd_o.branch_req = 1'b1;
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
case (funct3)
3'b000 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_EQ;
3'b001 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_NE;
3'b100 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LT;
3'b101 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_GE;
3'b110 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_LTU;
3'b111 : idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_GEU;
default : rvi_illegal = 1'b1;
endcase // funct3
`ifdef SCR1_RVE_EXT
if (instr[19] | instr[24]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_BRANCH
SCR1_OPCODE_JALR : begin
idu2exu_use_rs1_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
case (funct3)
3'b000 : begin
// JALR
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
idu2exu_cmd_o.jump_req = 1'b1;
idu2exu_cmd_o.imm = {{21{instr[31]}}, instr[30:20]};
end
default : rvi_illegal = 1'b1;
endcase
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end // SCR1_OPCODE_JALR
SCR1_OPCODE_SYSTEM : begin
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.imm = `SCR1_XLEN'({funct3, instr[31:20]}); // {funct3, CSR address}
case (funct3)
3'b000 : begin
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b0;
idu2exu_use_imm_o = 1'b0;
`endif // SCR1_NO_EXE_STAGE
case ({instr[19:15], instr[11:7]})
10'd0 : begin
case (funct12)
12'h000 : begin
// ECALL
idu2exu_cmd_o.exc_req = 1'b1;
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_ECALL_M;
end
12'h001 : begin
// EBREAK
idu2exu_cmd_o.exc_req = 1'b1;
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_BREAKPOINT;
end
12'h302 : begin
// MRET
idu2exu_cmd_o.mret_req = 1'b1;
end
12'h105 : begin
// WFI
idu2exu_cmd_o.wfi_req = 1'b1;
end
default : rvi_illegal = 1'b1;
endcase // funct12
end
default : rvi_illegal = 1'b1;
endcase // {instr[19:15], instr[11:7]}
end
3'b001 : begin
// CSRRW
idu2exu_use_rs1_o = 1'b1;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_WRITE;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b010 : begin
// CSRRS
idu2exu_use_rs1_o = 1'b1;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_SET;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b011 : begin
// CSRRC
idu2exu_use_rs1_o = 1'b1;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_CLEAR;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_REG;
`ifdef SCR1_RVE_EXT
if (instr[11] | instr[19]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b101 : begin
// CSRRWI
idu2exu_use_rs1_o = 1'b1; // zimm
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_WRITE;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM;
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b110 : begin
// CSRRSI
idu2exu_use_rs1_o = 1'b1; // zimm
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_SET;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM;
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b111 : begin
// CSRRCI
idu2exu_use_rs1_o = 1'b1; // zimm
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_CSR;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_CLEAR;
idu2exu_cmd_o.csr_op = SCR1_CSR_OP_IMM;
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
default : rvi_illegal = 1'b1;
endcase // funct3
end // SCR1_OPCODE_SYSTEM
default : begin
rvi_illegal = 1'b1;
end
endcase // rvi_opcode
end // SCR1_INSTR_RVI
`ifdef SCR1_RVC_EXT
// Quadrant 0
SCR1_INSTR_RVC0 : begin
idu2exu_cmd_o.instr_rvc = 1'b1;
idu2exu_use_rs1_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
case (funct3)
3'b000 : begin
if (~|instr[12:5]) rvc_illegal = 1'b1;
// C.ADDI4SPN
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
idu2exu_cmd_o.rd_addr = {2'b01, instr[4:2]};
idu2exu_cmd_o.imm = {22'd0, instr[10:7], instr[12:11], instr[5], instr[6], 2'b00};
end
3'b010 : begin
// C.LW
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU;
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
idu2exu_cmd_o.rd_addr = {2'b01, instr[4:2]};
idu2exu_cmd_o.imm = {25'd0, instr[5], instr[12:10], instr[6], 2'b00};
end
3'b110 : begin
// C.SW
idu2exu_use_rs2_o = 1'b1;
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW;
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
idu2exu_cmd_o.rs2_addr = {2'b01, instr[4:2]};
idu2exu_cmd_o.imm = {25'd0, instr[5], instr[12:10], instr[6], 2'b00};
end
default : begin
rvc_illegal = 1'b1;
end
endcase // funct3
end // Quadrant 0
// Quadrant 1
SCR1_INSTR_RVC1 : begin
idu2exu_cmd_o.instr_rvc = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
case (funct3)
3'b000 : begin
// C.ADDI / C.NOP
idu2exu_use_rs1_o = 1'b1;
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
idu2exu_cmd_o.rs1_addr = instr[11:7];
idu2exu_cmd_o.rd_addr = instr[11:7];
idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b001 : begin
// C.JAL
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
idu2exu_cmd_o.jump_req = 1'b1;
idu2exu_cmd_o.rd_addr = SCR1_MPRF_RA_ADDR;
idu2exu_cmd_o.imm = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0};
end
3'b010 : begin
// C.LI
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM;
idu2exu_cmd_o.rd_addr = instr[11:7];
idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b011 : begin
if (~|{instr[12], instr[6:2]}) rvc_illegal = 1'b1;
if (instr[11:7] == SCR1_MPRF_SP_ADDR) begin
// C.ADDI16SP
idu2exu_use_rs1_o = 1'b1;
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
idu2exu_cmd_o.rd_addr = SCR1_MPRF_SP_ADDR;
idu2exu_cmd_o.imm = {{23{instr[12]}}, instr[4:3], instr[5], instr[2], instr[6], 4'd0};
end else begin
// C.LUI
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IMM;
idu2exu_cmd_o.rd_addr = instr[11:7];
idu2exu_cmd_o.imm = {{15{instr[12]}}, instr[6:2], 12'd0};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
end
3'b100 : begin
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
idu2exu_cmd_o.rd_addr = {2'b01, instr[9:7]};
idu2exu_cmd_o.rs2_addr = {2'b01, instr[4:2]};
idu2exu_use_rs1_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
case (instr[11:10])
2'b00 : begin
if (instr[12]) rvc_illegal = 1'b1;
// C.SRLI
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.imm = {27'd0, instr[6:2]};
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRL;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
end
2'b01 : begin
if (instr[12]) rvc_illegal = 1'b1;
// C.SRAI
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.imm = {27'd0, instr[6:2]};
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SRA;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
end
2'b10 : begin
// C.ANDI
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
idu2exu_cmd_o.imm = {{27{instr[12]}}, instr[6:2]};
end
2'b11 : begin
idu2exu_use_rs2_o = 1'b1;
case ({instr[12], instr[6:5]})
3'b000 : begin
// C.SUB
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
end
3'b001 : begin
// C.XOR
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_XOR;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
end
3'b010 : begin
// C.OR
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_OR;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
end
3'b011 : begin
// C.AND
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_AND;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
end
default : begin
rvc_illegal = 1'b1;
end
endcase // {instr[12], instr[6:5]}
end
endcase // instr[11:10]
end // funct3 == 3'b100
3'b101 : begin
// C.J
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.jump_req = 1'b1;
idu2exu_cmd_o.imm = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0};
end
3'b110 : begin
// C.BEQZ
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_EQ;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.branch_req = 1'b1;
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
idu2exu_cmd_o.rs2_addr = SCR1_MPRF_ZERO_ADDR;
idu2exu_cmd_o.imm = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0};
end
3'b111 : begin
// C.BNEZ
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SUB_NE;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_PC_IMM;
idu2exu_cmd_o.branch_req = 1'b1;
idu2exu_cmd_o.rs1_addr = {2'b01, instr[9:7]};
idu2exu_cmd_o.rs2_addr = SCR1_MPRF_ZERO_ADDR;
idu2exu_cmd_o.imm = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0};
end
endcase // funct3
end // Quadrant 1
// Quadrant 2
SCR1_INSTR_RVC2 : begin
idu2exu_cmd_o.instr_rvc = 1'b1;
idu2exu_use_rs1_o = 1'b1;
case (funct3)
3'b000 : begin
if (instr[12]) rvc_illegal = 1'b1;
// C.SLLI
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.rs1_addr = instr[11:7];
idu2exu_cmd_o.rd_addr = instr[11:7];
idu2exu_cmd_o.imm = {27'd0, instr[6:2]};
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_SLL;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b010 : begin
if (~|instr[11:7]) rvc_illegal = 1'b1;
// C.LWSP
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_LW;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_LSU;
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
idu2exu_cmd_o.rd_addr = instr[11:7];
idu2exu_cmd_o.imm = {24'd0, instr[3:2], instr[12], instr[6:4], 2'b00};
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
3'b100 : begin
if (~instr[12]) begin
if (|instr[6:2]) begin
// C.MV
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_ZERO_ADDR;
idu2exu_cmd_o.rs2_addr = instr[6:2];
idu2exu_cmd_o.rd_addr = instr[11:7];
`ifdef SCR1_RVE_EXT
if (instr[11]|instr[6]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end else begin
if (~|instr[11:7]) rvc_illegal = 1'b1;
// C.JR
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.jump_req = 1'b1;
idu2exu_cmd_o.rs1_addr = instr[11:7];
idu2exu_cmd_o.imm = 0;
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
end else begin // instr[12] == 1
if (~|instr[11:2]) begin
// C.EBREAK
idu2exu_cmd_o.exc_req = 1'b1;
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_BREAKPOINT;
end else if (~|instr[6:2]) begin
// C.JALR
idu2exu_use_rs1_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_INC_PC;
idu2exu_cmd_o.jump_req = 1'b1;
idu2exu_cmd_o.rs1_addr = instr[11:7];
idu2exu_cmd_o.rd_addr = SCR1_MPRF_RA_ADDR;
idu2exu_cmd_o.imm = 0;
`ifdef SCR1_RVE_EXT
if (instr[11]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end else begin
// C.ADD
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_ADD;
idu2exu_cmd_o.ialu_op = SCR1_IALU_OP_REG_REG;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_IALU;
idu2exu_cmd_o.rs1_addr = instr[11:7];
idu2exu_cmd_o.rs2_addr = instr[6:2];
idu2exu_cmd_o.rd_addr = instr[11:7];
`ifdef SCR1_RVE_EXT
if (instr[11]|instr[6]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
end // instr[12] == 1
end
3'b110 : begin
// C.SWSP
idu2exu_use_rs1_o = 1'b1;
idu2exu_use_rs2_o = 1'b1;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.sum2_op = SCR1_SUM2_OP_REG_IMM;
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_SW;
idu2exu_cmd_o.rs1_addr = SCR1_MPRF_SP_ADDR;
idu2exu_cmd_o.rs2_addr = instr[6:2];
idu2exu_cmd_o.imm = {24'd0, instr[8:7], instr[12:9], 2'b00};
`ifdef SCR1_RVE_EXT
if (instr[6]) rve_illegal = 1'b1;
`endif // SCR1_RVE_EXT
end
default : begin
rvc_illegal = 1'b1;
end
endcase // funct3
end // Quadrant 2
default : begin
`ifdef SCR1_XPROP_EN
rvi_illegal = 1'b1;
`endif // SCR1_XPROP_EN
end
`else // SCR1_RVC_EXT
default : begin
idu2exu_cmd_o.instr_rvc = 1'b1;
rvi_illegal = 1'b1;
end
`endif // SCR1_RVC_EXT
endcase // instr_type
end // no imem fault
// At this point the instruction is fully decoded
// given that no imem fault has happened
// Check illegal instruction
if (
rvi_illegal
`ifdef SCR1_RVC_EXT
| rvc_illegal
`endif
`ifdef SCR1_RVE_EXT
| rve_illegal
`endif
) begin
idu2exu_cmd_o.ialu_cmd = SCR1_IALU_CMD_NONE;
idu2exu_cmd_o.lsu_cmd = SCR1_LSU_CMD_NONE;
idu2exu_cmd_o.csr_cmd = SCR1_CSR_CMD_NONE;
idu2exu_cmd_o.rd_wb_sel = SCR1_RD_WB_NONE;
idu2exu_cmd_o.jump_req = 1'b0;
idu2exu_cmd_o.branch_req = 1'b0;
idu2exu_cmd_o.mret_req = 1'b0;
idu2exu_cmd_o.fencei_req = 1'b0;
idu2exu_cmd_o.wfi_req = 1'b0;
idu2exu_use_rs1_o = 1'b0;
idu2exu_use_rs2_o = 1'b0;
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_rd_o = 1'b0;
`endif // SCR1_NO_EXE_STAGE
`ifndef SCR1_MTVAL_ILLEGAL_INSTR_EN
idu2exu_use_imm_o = 1'b0;
`else // SCR1_MTVAL_ILLEGAL_INSTR_EN
`ifndef SCR1_NO_EXE_STAGE
idu2exu_use_imm_o = 1'b1;
`endif // SCR1_NO_EXE_STAGE
idu2exu_cmd_o.imm = instr;
`endif // SCR1_MTVAL_ILLEGAL_INSTR_EN
idu2exu_cmd_o.exc_req = 1'b1;
idu2exu_cmd_o.exc_code = SCR1_EXC_CODE_ILLEGAL_INSTR;
end
end // RV32I(MC) decode
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
// X checks
SCR1_SVA_IDU_XCHECK : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({ifu2idu_vd_i, exu2idu_rdy_i})
) else $error("IDU Error: unknown values");
// Behavior checks
SCR1_SVA_IDU_IALU_CMD_RANGE : assert property (
@(negedge clk) disable iff (~rst_n)
(ifu2idu_vd_i & ~ifu2idu_imem_err_i) |->
((idu2exu_cmd_o.ialu_cmd >= SCR1_IALU_CMD_NONE) &
(idu2exu_cmd_o.ialu_cmd <=
`ifdef SCR1_RVM_EXT
SCR1_IALU_CMD_REMU
`else
SCR1_IALU_CMD_SRA
`endif // SCR1_RVM_EXT
))
) else $error("IDU Error: IALU_CMD out of range");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_idu

View File

@@ -0,0 +1,826 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_ifu.sv>
/// @brief Instruction Fetch Unit (IFU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Controls instruction fetching process:
// - Fetches instructions either from IMEM or from Program Buffer, supporting
// pending IMEM instructions handling
// - Handles new PC misalignment and constructs the correct instruction (supports
// RVI and RVC instructions)
// - Either stores instructions in the instruction queue or bypasses to the
// IDU if the corresponding option is used
// - Flushes instruction queue if requested
//
// Structure:
// - Instruction queue
// - IFU FSM
// - IFU <-> IMEM i/f
// - IFU <-> IDU i/f
// - IFU <-> HDU i/f
//
//------------------------------------------------------------------------------
`include "scr1_memif.svh"
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_hdu.svh"
`endif // SCR1_DBG_EN
module scr1_pipe_ifu
(
// Control signals
input logic rst_n, // IFU reset
input logic clk, // IFU clock
input logic pipe2ifu_stop_fetch_i, // Stop instruction fetch
// IFU <-> IMEM interface
input logic imem2ifu_req_ack_i, // Instruction memory request acknowledgement
output logic ifu2imem_req_o, // Instruction memory request
output type_scr1_mem_cmd_e ifu2imem_cmd_o, // Instruction memory command (READ/WRITE)
output logic [`SCR1_IMEM_AWIDTH-1:0] ifu2imem_addr_o, // Instruction memory address
input logic [`SCR1_IMEM_DWIDTH-1:0] imem2ifu_rdata_i, // Instruction memory read data
input type_scr1_mem_resp_e imem2ifu_resp_i, // Instruction memory response
// IFU <-> EXU New PC interface
input logic exu2ifu_pc_new_req_i, // New PC request (jumps, branches, traps etc)
input logic [`SCR1_XLEN-1:0] exu2ifu_pc_new_i, // New PC
`ifdef SCR1_DBG_EN
// IFU <-> HDU Program Buffer interface
input logic hdu2ifu_pbuf_fetch_i, // Fetch instructions provided by Program Buffer
output logic ifu2hdu_pbuf_rdy_o, // Program Buffer Instruction i/f ready
input logic hdu2ifu_pbuf_vd_i, // Program Buffer Instruction valid
input logic hdu2ifu_pbuf_err_i, // Program Buffer Instruction i/f error
input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr_i, // Program Buffer Instruction itself
`endif // SCR1_DBG_EN
`ifdef SCR1_CLKCTRL_EN
output logic ifu2pipe_imem_txns_pnd_o, // There are pending imem transactions
`endif // SCR1_CLKCTRL_EN
// IFU <-> IDU interface
input logic idu2ifu_rdy_i, // IDU ready for new data
output logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr_o, // IFU instruction
output logic ifu2idu_imem_err_o, // Instruction access fault exception
output logic ifu2idu_err_rvi_hi_o, // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
output logic ifu2idu_vd_o // IFU request
);
//------------------------------------------------------------------------------
// Local parameters declaration
//------------------------------------------------------------------------------
localparam SCR1_IFU_Q_SIZE_WORD = 2;
localparam SCR1_IFU_Q_SIZE_HALF = SCR1_IFU_Q_SIZE_WORD * 2;
localparam SCR1_TXN_CNT_W = 3;
localparam SCR1_IFU_QUEUE_ADR_W = $clog2(SCR1_IFU_Q_SIZE_HALF);
localparam SCR1_IFU_QUEUE_PTR_W = SCR1_IFU_QUEUE_ADR_W + 1;
localparam SCR1_IFU_Q_FREE_H_W = $clog2(SCR1_IFU_Q_SIZE_HALF + 1);
localparam SCR1_IFU_Q_FREE_W_W = $clog2(SCR1_IFU_Q_SIZE_WORD + 1);
//------------------------------------------------------------------------------
// Local types declaration
//------------------------------------------------------------------------------
typedef enum logic {
SCR1_IFU_FSM_IDLE,
SCR1_IFU_FSM_FETCH
} type_scr1_ifu_fsm_e;
typedef enum logic[1:0] {
SCR1_IFU_QUEUE_WR_NONE, // No write to queue
SCR1_IFU_QUEUE_WR_FULL, // Write 32 rdata bits to queue
SCR1_IFU_QUEUE_WR_HI // Write 16 upper rdata bits to queue
} type_scr1_ifu_queue_wr_e;
typedef enum logic[1:0] {
SCR1_IFU_QUEUE_RD_NONE, // No queue read
SCR1_IFU_QUEUE_RD_HWORD, // Read halfword
SCR1_IFU_QUEUE_RD_WORD // Read word
} type_scr1_ifu_queue_rd_e;
`ifdef SCR1_NO_DEC_STAGE
typedef enum logic[1:0] {
SCR1_BYPASS_NONE, // No bypass
SCR1_BYPASS_RVC, // Bypass RVC
SCR1_BYPASS_RVI_RDATA_QUEUE, // Bypass RVI, rdata+queue
SCR1_BYPASS_RVI_RDATA // Bypass RVI, rdata only
} type_scr1_bypass_e;
`endif // SCR1_NO_DEC_STAGE
typedef enum logic [2:0] {
// SCR1_IFU_INSTR_<UPPER_16_BITS>_<LOWER_16_BITS>
SCR1_IFU_INSTR_NONE, // No valid instruction
SCR1_IFU_INSTR_RVI_HI_RVI_LO, // Full RV32I instruction
SCR1_IFU_INSTR_RVC_RVC,
SCR1_IFU_INSTR_RVI_LO_RVC,
SCR1_IFU_INSTR_RVC_RVI_HI,
SCR1_IFU_INSTR_RVI_LO_RVI_HI,
SCR1_IFU_INSTR_RVC_NV, // Instruction after unaligned new_pc
SCR1_IFU_INSTR_RVI_LO_NV // Instruction after unaligned new_pc
} type_scr1_ifu_instr_e;
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// Instruction queue signals
//------------------------------------------------------------------------------
// New PC unaligned flag register
logic new_pc_unaligned_ff;
logic new_pc_unaligned_next;
logic new_pc_unaligned_upd;
// IMEM instruction type decoder
logic instr_hi_is_rvi;
logic instr_lo_is_rvi;
type_scr1_ifu_instr_e instr_type;
// Register to store if the previous IMEM instruction had low part of RVI instruction
// in its high part
logic instr_hi_rvi_lo_ff;
logic instr_hi_rvi_lo_next;
// Queue read/write size decoders
type_scr1_ifu_queue_rd_e q_rd_size;
logic q_rd_vd;
logic q_rd_none;
logic q_rd_hword;
type_scr1_ifu_queue_wr_e q_wr_size;
logic q_wr_none;
logic q_wr_full;
// Write/read pointer registers
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_rptr;
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_rptr_next;
logic q_rptr_upd;
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_wptr;
logic [SCR1_IFU_QUEUE_PTR_W-1:0] q_wptr_next;
logic q_wptr_upd;
// Instruction queue control signals
logic q_wr_en;
logic q_flush_req;
// Queue data registers
logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data [SCR1_IFU_Q_SIZE_HALF];
logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data_head;
logic [`SCR1_IMEM_DWIDTH/2-1:0] q_data_next;
// Queue error flags registers
logic q_err [SCR1_IFU_Q_SIZE_HALF];
logic q_err_head;
logic q_err_next;
// Instruction queue status signals
logic q_is_empty;
logic q_has_free_slots;
logic q_has_1_ocpd_hw;
logic q_head_is_rvc;
logic q_head_is_rvi;
logic [SCR1_IFU_Q_FREE_H_W-1:0] q_ocpd_h;
logic [SCR1_IFU_Q_FREE_H_W-1:0] q_free_h_next;
logic [SCR1_IFU_Q_FREE_W_W-1:0] q_free_w_next;
// IFU FSM signals
//------------------------------------------------------------------------------
// IFU FSM control signals
logic ifu_fetch_req;
logic ifu_stop_req;
type_scr1_ifu_fsm_e ifu_fsm_curr;
type_scr1_ifu_fsm_e ifu_fsm_next;
logic ifu_fsm_fetch;
// IMEM signals
//------------------------------------------------------------------------------
// IMEM response signals
logic imem_resp_ok;
logic imem_resp_er;
logic imem_resp_er_discard_pnd;
logic imem_resp_discard_req;
logic imem_resp_received;
logic imem_resp_vd;
logic imem_handshake_done;
logic [15:0] imem_rdata_lo;
logic [31:16] imem_rdata_hi;
// IMEM address signals
logic imem_addr_upd;
logic [`SCR1_XLEN-1:2] imem_addr_ff;
logic [`SCR1_XLEN-1:2] imem_addr_next;
// IMEM pending transactions counter
logic imem_pnd_txns_cnt_upd;
logic [SCR1_TXN_CNT_W-1:0] imem_pnd_txns_cnt;
logic [SCR1_TXN_CNT_W-1:0] imem_pnd_txns_cnt_next;
logic [SCR1_TXN_CNT_W-1:0] imem_vd_pnd_txns_cnt;
logic imem_pnd_txns_q_full;
// IMEM responses discard counter
logic imem_resp_discard_cnt_upd;
logic [SCR1_TXN_CNT_W-1:0] imem_resp_discard_cnt;
logic [SCR1_TXN_CNT_W-1:0] imem_resp_discard_cnt_next;
`ifdef SCR1_NEW_PC_REG
logic new_pc_req_ff;
`endif // SCR1_NEW_PC_REG
// Instruction bypass signals
`ifdef SCR1_NO_DEC_STAGE
type_scr1_bypass_e instr_bypass_type;
logic instr_bypass_vd;
`endif // SCR1_NO_DEC_STAGE
//------------------------------------------------------------------------------
// Instruction queue
//------------------------------------------------------------------------------
//
// Instruction queue consists of the following functional units:
// - New PC unaligned flag register
// - Instruction type decoder, including register to store if the previous
// IMEM instruction had low part of RVI instruction in its high part
// - Read/write size decoders
// - Read/write pointer registers
// - Data and error flag registers
// - Status logic
//
// New PC unaligned flag register
//------------------------------------------------------------------------------
assign new_pc_unaligned_upd = exu2ifu_pc_new_req_i | imem_resp_vd;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
new_pc_unaligned_ff <= 1'b0;
end else if (new_pc_unaligned_upd) begin
new_pc_unaligned_ff <= new_pc_unaligned_next;
end
end
assign new_pc_unaligned_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[1]
: ~imem_resp_vd ? new_pc_unaligned_ff
: 1'b0;
// Instruction type decoder
//------------------------------------------------------------------------------
assign instr_hi_is_rvi = &imem2ifu_rdata_i[17:16];
assign instr_lo_is_rvi = &imem2ifu_rdata_i[1:0];
always_comb begin
instr_type = SCR1_IFU_INSTR_NONE;
if (imem_resp_ok & ~imem_resp_discard_req) begin
if (new_pc_unaligned_ff) begin
instr_type = instr_hi_is_rvi ? SCR1_IFU_INSTR_RVI_LO_NV
: SCR1_IFU_INSTR_RVC_NV;
end else begin // ~new_pc_unaligned_ff
if (instr_hi_rvi_lo_ff) begin
instr_type = instr_hi_is_rvi ? SCR1_IFU_INSTR_RVI_LO_RVI_HI
: SCR1_IFU_INSTR_RVC_RVI_HI;
end else begin // SCR1_OTHER
case ({instr_hi_is_rvi, instr_lo_is_rvi})
2'b00 : instr_type = SCR1_IFU_INSTR_RVC_RVC;
2'b10 : instr_type = SCR1_IFU_INSTR_RVI_LO_RVC;
default : instr_type = SCR1_IFU_INSTR_RVI_HI_RVI_LO;
endcase
end
end
end
end
// Register to store if the previous IMEM instruction had low part of RVI
// instruction in its high part
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
instr_hi_rvi_lo_ff <= 1'b0;
end else begin
if (exu2ifu_pc_new_req_i) begin
instr_hi_rvi_lo_ff <= 1'b0;
end else if (imem_resp_vd) begin
instr_hi_rvi_lo_ff <= instr_hi_rvi_lo_next;
end
end
end
assign instr_hi_rvi_lo_next = (instr_type == SCR1_IFU_INSTR_RVI_LO_NV)
| (instr_type == SCR1_IFU_INSTR_RVI_LO_RVI_HI)
| (instr_type == SCR1_IFU_INSTR_RVI_LO_RVC);
// Queue write/read size decoders
//------------------------------------------------------------------------------
// Queue read size decoder
assign q_rd_vd = ~q_is_empty & ifu2idu_vd_o & idu2ifu_rdy_i;
assign q_rd_hword = q_head_is_rvc | q_err_head
`ifdef SCR1_NO_DEC_STAGE
| (q_head_is_rvi & instr_bypass_vd)
`endif // SCR1_NO_DEC_STAGE
;
assign q_rd_size = ~q_rd_vd ? SCR1_IFU_QUEUE_RD_NONE
: q_rd_hword ? SCR1_IFU_QUEUE_RD_HWORD
: SCR1_IFU_QUEUE_RD_WORD;
assign q_rd_none = (q_rd_size == SCR1_IFU_QUEUE_RD_NONE);
// Queue write size decoder
always_comb begin
q_wr_size = SCR1_IFU_QUEUE_WR_NONE;
if (~imem_resp_discard_req) begin
if (imem_resp_ok) begin
`ifdef SCR1_NO_DEC_STAGE
case (instr_type)
SCR1_IFU_INSTR_NONE : q_wr_size = SCR1_IFU_QUEUE_WR_NONE;
SCR1_IFU_INSTR_RVI_LO_NV : q_wr_size = SCR1_IFU_QUEUE_WR_HI;
SCR1_IFU_INSTR_RVC_NV : q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i)
? SCR1_IFU_QUEUE_WR_NONE
: SCR1_IFU_QUEUE_WR_HI;
SCR1_IFU_INSTR_RVI_HI_RVI_LO: q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i)
? SCR1_IFU_QUEUE_WR_NONE
: SCR1_IFU_QUEUE_WR_FULL;
SCR1_IFU_INSTR_RVC_RVC,
SCR1_IFU_INSTR_RVI_LO_RVC,
SCR1_IFU_INSTR_RVC_RVI_HI,
SCR1_IFU_INSTR_RVI_LO_RVI_HI: q_wr_size = (instr_bypass_vd & idu2ifu_rdy_i)
? SCR1_IFU_QUEUE_WR_HI
: SCR1_IFU_QUEUE_WR_FULL;
endcase // instr_type
`else // SCR1_NO_DEC_STAGE
case (instr_type)
SCR1_IFU_INSTR_NONE : q_wr_size = SCR1_IFU_QUEUE_WR_NONE;
SCR1_IFU_INSTR_RVC_NV,
SCR1_IFU_INSTR_RVI_LO_NV : q_wr_size = SCR1_IFU_QUEUE_WR_HI;
default : q_wr_size = SCR1_IFU_QUEUE_WR_FULL;
endcase // instr_type
`endif // SCR1_NO_DEC_STAGE
end else if (imem_resp_er) begin
q_wr_size = SCR1_IFU_QUEUE_WR_FULL;
end // imem_resp_er
end // ~imem_resp_discard_req
end
assign q_wr_none = (q_wr_size == SCR1_IFU_QUEUE_WR_NONE);
assign q_wr_full = (q_wr_size == SCR1_IFU_QUEUE_WR_FULL);
// Write/read pointer registers
//------------------------------------------------------------------------------
assign q_flush_req = exu2ifu_pc_new_req_i | pipe2ifu_stop_fetch_i;
// Queue write pointer register
assign q_wptr_upd = q_flush_req | ~q_wr_none;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
q_wptr <= '0;
end else if (q_wptr_upd) begin
q_wptr <= q_wptr_next;
end
end
assign q_wptr_next = q_flush_req ? '0
: ~q_wr_none ? q_wptr + (q_wr_full ? SCR1_IFU_QUEUE_PTR_W'('b010) : SCR1_IFU_QUEUE_PTR_W'('b001))
: q_wptr;
// Queue read pointer register
assign q_rptr_upd = q_flush_req | ~q_rd_none;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
q_rptr <= '0;
end else if (q_rptr_upd) begin
q_rptr <= q_rptr_next;
end
end
assign q_rptr_next = q_flush_req ? '0
: ~q_rd_none ? q_rptr + (q_rd_hword ? SCR1_IFU_QUEUE_PTR_W'('b001) : SCR1_IFU_QUEUE_PTR_W'('b010))
: q_rptr;
// Queue data and error flag registers
//------------------------------------------------------------------------------
assign imem_rdata_hi = imem2ifu_rdata_i[31:16];
assign imem_rdata_lo = imem2ifu_rdata_i[15:0];
assign q_wr_en = imem_resp_vd & ~q_flush_req;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
q_data <= '{SCR1_IFU_Q_SIZE_HALF{'0}};
q_err <= '{SCR1_IFU_Q_SIZE_HALF{1'b0}};
end else if (q_wr_en) begin
case (q_wr_size)
SCR1_IFU_QUEUE_WR_HI : begin
q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_rdata_hi;
q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_resp_er;
end
SCR1_IFU_QUEUE_WR_FULL : begin
q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_rdata_lo;
q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr)] <= imem_resp_er;
q_data[SCR1_IFU_QUEUE_ADR_W'(q_wptr + 1'b1)] <= imem_rdata_hi;
q_err [SCR1_IFU_QUEUE_ADR_W'(q_wptr + 1'b1)] <= imem_resp_er;
end
endcase
end
end
assign q_data_head = q_data [SCR1_IFU_QUEUE_ADR_W'(q_rptr)];
assign q_data_next = q_data [SCR1_IFU_QUEUE_ADR_W'(q_rptr + 1'b1)];
assign q_err_head = q_err [SCR1_IFU_QUEUE_ADR_W'(q_rptr)];
assign q_err_next = q_err [SCR1_IFU_QUEUE_ADR_W'(q_rptr + 1'b1)];
// Queue status logic
//------------------------------------------------------------------------------
assign q_ocpd_h = SCR1_IFU_Q_FREE_H_W'(q_wptr - q_rptr);
assign q_free_h_next = SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF - (q_wptr - q_rptr_next));
assign q_free_w_next = SCR1_IFU_Q_FREE_W_W'(q_free_h_next >> 1'b1);
assign q_is_empty = (q_rptr == q_wptr);
assign q_has_free_slots = (SCR1_TXN_CNT_W'(q_free_w_next) > imem_vd_pnd_txns_cnt);
assign q_has_1_ocpd_hw = (q_ocpd_h == SCR1_IFU_Q_FREE_H_W'(1));
assign q_head_is_rvi = &(q_data_head[1:0]);
assign q_head_is_rvc = ~q_head_is_rvi;
//------------------------------------------------------------------------------
// IFU FSM
//------------------------------------------------------------------------------
// IFU FSM control signals
assign ifu_fetch_req = exu2ifu_pc_new_req_i & ~pipe2ifu_stop_fetch_i;
assign ifu_stop_req = pipe2ifu_stop_fetch_i
| (imem_resp_er_discard_pnd & ~exu2ifu_pc_new_req_i);
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
ifu_fsm_curr <= SCR1_IFU_FSM_IDLE;
end else begin
ifu_fsm_curr <= ifu_fsm_next;
end
end
always_comb begin
case (ifu_fsm_curr)
SCR1_IFU_FSM_IDLE : begin
ifu_fsm_next = ifu_fetch_req ? SCR1_IFU_FSM_FETCH
: SCR1_IFU_FSM_IDLE;
end
SCR1_IFU_FSM_FETCH : begin
ifu_fsm_next = ifu_stop_req ? SCR1_IFU_FSM_IDLE
: SCR1_IFU_FSM_FETCH;
end
endcase
end
assign ifu_fsm_fetch = (ifu_fsm_curr == SCR1_IFU_FSM_FETCH);
//------------------------------------------------------------------------------
// IFU <-> IMEM interface
//------------------------------------------------------------------------------
//
// IFU <-> IMEM interface consists of the following functional units:
// - IMEM response logic
// - IMEM address register
// - Pending IMEM transactions counter
// - IMEM discard responses counter
// - IFU <-> IMEM interface output signals
//
// IMEM response logic
//------------------------------------------------------------------------------
assign imem_resp_er = (imem2ifu_resp_i == SCR1_MEM_RESP_RDY_ER);
assign imem_resp_ok = (imem2ifu_resp_i == SCR1_MEM_RESP_RDY_OK);
assign imem_resp_received = imem_resp_ok | imem_resp_er;
assign imem_resp_vd = imem_resp_received & ~imem_resp_discard_req;
assign imem_resp_er_discard_pnd = imem_resp_er & ~imem_resp_discard_req;
assign imem_handshake_done = ifu2imem_req_o & imem2ifu_req_ack_i;
// IMEM address register
//------------------------------------------------------------------------------
assign imem_addr_upd = imem_handshake_done | exu2ifu_pc_new_req_i;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
imem_addr_ff <= '0;
end else if (imem_addr_upd) begin
imem_addr_ff <= imem_addr_next;
end
end
`ifndef SCR1_NEW_PC_REG
assign imem_addr_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[`SCR1_XLEN-1:2] + imem_handshake_done
: &imem_addr_ff[5:2] ? imem_addr_ff + imem_handshake_done
: {imem_addr_ff[`SCR1_XLEN-1:6], imem_addr_ff[5:2] + imem_handshake_done};
`else // SCR1_NEW_PC_REG
assign imem_addr_next = exu2ifu_pc_new_req_i ? exu2ifu_pc_new_i[`SCR1_XLEN-1:2]
: &imem_addr_ff[5:2] ? imem_addr_ff + imem_handshake_done
: {imem_addr_ff[`SCR1_XLEN-1:6], imem_addr_ff[5:2] + imem_handshake_done};
`endif // SCR1_NEW_PC_REG
// Pending IMEM transactions counter
//------------------------------------------------------------------------------
// Pending IMEM transactions occur if IFU request has been acknowledged, but
// response comes in the next cycle or later
assign imem_pnd_txns_cnt_upd = imem_handshake_done ^ imem_resp_received;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
imem_pnd_txns_cnt <= '0;
end else if (imem_pnd_txns_cnt_upd) begin
imem_pnd_txns_cnt <= imem_pnd_txns_cnt_next;
end
end
assign imem_pnd_txns_cnt_next = imem_pnd_txns_cnt + (imem_handshake_done - imem_resp_received);
assign imem_pnd_txns_q_full = &imem_pnd_txns_cnt;
// IMEM discard responses counter
//------------------------------------------------------------------------------
// IMEM instructions should be discarded in the following 2 cases:
// 1. New PC is requested by jump, branch, mret or other instruction
// 2. IMEM response was erroneous and not discarded
//
// In both cases the number of instructions to be discarded equals to the number
// of pending instructions.
// In the 1st case we don't need all the instructions that haven't been fetched
// yet, since the PC has changed.
// In the 2nd case, since the IMEM responce was erroneous there is no guarantee
// that subsequent IMEM instructions would be valid.
assign imem_resp_discard_cnt_upd = exu2ifu_pc_new_req_i | imem_resp_er
| (imem_resp_ok & imem_resp_discard_req);
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
imem_resp_discard_cnt <= '0;
end else if (imem_resp_discard_cnt_upd) begin
imem_resp_discard_cnt <= imem_resp_discard_cnt_next;
end
end
`ifndef SCR1_NEW_PC_REG
assign imem_resp_discard_cnt_next = exu2ifu_pc_new_req_i ? imem_pnd_txns_cnt_next - imem_handshake_done
: imem_resp_er_discard_pnd ? imem_pnd_txns_cnt_next
: imem_resp_discard_cnt - 1'b1;
`else // SCR1_NEW_PC_REG
assign imem_resp_discard_cnt_next = exu2ifu_pc_new_req_i | imem_resp_er_discard_pnd
? imem_pnd_txns_cnt_next
: imem_resp_discard_cnt - 1'b1;
`endif // SCR1_NEW_PC_REG
assign imem_vd_pnd_txns_cnt = imem_pnd_txns_cnt - imem_resp_discard_cnt;
assign imem_resp_discard_req = |imem_resp_discard_cnt;
// IFU <-> IMEM interface output signals
//------------------------------------------------------------------------------
`ifndef SCR1_NEW_PC_REG
assign ifu2imem_req_o = (exu2ifu_pc_new_req_i & ~imem_pnd_txns_q_full & ~pipe2ifu_stop_fetch_i)
| (ifu_fsm_fetch & ~imem_pnd_txns_q_full & q_has_free_slots);
assign ifu2imem_addr_o = exu2ifu_pc_new_req_i
? {exu2ifu_pc_new_i[`SCR1_XLEN-1:2], 2'b00}
: {imem_addr_ff, 2'b00};
`else // SCR1_NEW_PC_REG
assign ifu2imem_req_o = ifu_fsm_fetch & ~imem_pnd_txns_q_full & q_has_free_slots;
assign ifu2imem_addr_o = {imem_addr_ff, 2'b00};
`endif // SCR1_NEW_PC_REG
assign ifu2imem_cmd_o = SCR1_MEM_CMD_RD;
`ifdef SCR1_CLKCTRL_EN
assign ifu2pipe_imem_txns_pnd_o = |imem_pnd_txns_cnt;
`endif // SCR1_CLKCTRL_EN
//------------------------------------------------------------------------------
// IFU <-> IDU interface
//------------------------------------------------------------------------------
//
// IFU <-> IDU interface consists of the following functional units:
// - Instruction bypass type decoder
// - IFU <-> IDU status signals
// - Output instruction multiplexer
//
`ifdef SCR1_NO_DEC_STAGE
// Instruction bypass type decoder
//------------------------------------------------------------------------------
assign instr_bypass_vd = (instr_bypass_type != SCR1_BYPASS_NONE);
always_comb begin
instr_bypass_type = SCR1_BYPASS_NONE;
if (imem_resp_vd) begin
if (q_is_empty) begin
case (instr_type)
SCR1_IFU_INSTR_RVC_NV,
SCR1_IFU_INSTR_RVC_RVC,
SCR1_IFU_INSTR_RVI_LO_RVC : begin
instr_bypass_type = SCR1_BYPASS_RVC;
end
SCR1_IFU_INSTR_RVI_HI_RVI_LO : begin
instr_bypass_type = SCR1_BYPASS_RVI_RDATA;
end
default : begin end
endcase // instr_type
end else if (q_has_1_ocpd_hw & q_head_is_rvi) begin
if (instr_hi_rvi_lo_ff) begin
instr_bypass_type = SCR1_BYPASS_RVI_RDATA_QUEUE;
end
end
end // imem_resp_vd
end
// IFU <-> IDU interface status signals
//------------------------------------------------------------------------------
always_comb begin
ifu2idu_vd_o = 1'b0;
ifu2idu_imem_err_o = 1'b0;
ifu2idu_err_rvi_hi_o = 1'b0;
if (ifu_fsm_fetch | ~q_is_empty) begin
if (instr_bypass_vd) begin
ifu2idu_vd_o = 1'b1;
ifu2idu_imem_err_o = (instr_bypass_type == SCR1_BYPASS_RVI_RDATA_QUEUE)
? (imem_resp_er | q_err_head)
: imem_resp_er;
ifu2idu_err_rvi_hi_o = (instr_bypass_type == SCR1_BYPASS_RVI_RDATA_QUEUE) & imem_resp_er;
end else if (~q_is_empty) begin
if (q_has_1_ocpd_hw) begin
ifu2idu_vd_o = q_head_is_rvc | q_err_head;
ifu2idu_imem_err_o = q_err_head;
ifu2idu_err_rvi_hi_o = ~q_err_head & q_head_is_rvi & q_err_next;
end else begin
ifu2idu_vd_o = 1'b1;
ifu2idu_imem_err_o = q_err_head ? 1'b1 : (q_head_is_rvi & q_err_next);
end
end // ~q_is_empty
end
`ifdef SCR1_DBG_EN
if (hdu2ifu_pbuf_fetch_i) begin
ifu2idu_vd_o = hdu2ifu_pbuf_vd_i;
ifu2idu_imem_err_o = hdu2ifu_pbuf_err_i;
end
`endif // SCR1_DBG_EN
end
// Output instruction multiplexer
//------------------------------------------------------------------------------
always_comb begin
case (instr_bypass_type)
SCR1_BYPASS_RVC : begin
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'(new_pc_unaligned_ff ? imem_rdata_hi
: imem_rdata_lo);
end
SCR1_BYPASS_RVI_RDATA : begin
ifu2idu_instr_o = imem2ifu_rdata_i;
end
SCR1_BYPASS_RVI_RDATA_QUEUE: begin
ifu2idu_instr_o = {imem_rdata_lo, q_data_head};
end
default : begin
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'(q_head_is_rvc ? q_data_head
: {q_data_next, q_data_head});
end
endcase // instr_bypass_type
`ifdef SCR1_DBG_EN
if (hdu2ifu_pbuf_fetch_i) begin
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'({'0, hdu2ifu_pbuf_instr_i});
end
`endif // SCR1_DBG_EN
end
`else // SCR1_NO_DEC_STAGE
// IFU <-> IDU interface status signals
//------------------------------------------------------------------------------
always_comb begin
ifu2idu_vd_o = 1'b0;
ifu2idu_imem_err_o = 1'b0;
ifu2idu_err_rvi_hi_o = 1'b0;
if (~q_is_empty) begin
if (q_has_1_ocpd_hw) begin
ifu2idu_vd_o = q_head_is_rvc | q_err_head;
ifu2idu_imem_err_o = q_err_head;
end else begin
ifu2idu_vd_o = 1'b1;
ifu2idu_imem_err_o = q_err_head ? 1'b1 : (q_head_is_rvi & q_err_next);
ifu2idu_err_rvi_hi_o = ~q_err_head & q_head_is_rvi & q_err_next;
end
end // ~q_is_empty
`ifdef SCR1_DBG_EN
if (hdu2ifu_pbuf_fetch_i) begin
ifu2idu_vd_o = hdu2ifu_pbuf_vd_i;
ifu2idu_imem_err_o = hdu2ifu_pbuf_err_i;
end
`endif // SCR1_DBG_EN
end
// Output instruction multiplexer
//------------------------------------------------------------------------------
always_comb begin
ifu2idu_instr_o = q_head_is_rvc ? `SCR1_IMEM_DWIDTH'(q_data_head)
: {q_data_next, q_data_head};
`ifdef SCR1_DBG_EN
if (hdu2ifu_pbuf_fetch_i) begin
ifu2idu_instr_o = `SCR1_IMEM_DWIDTH'({'0, hdu2ifu_pbuf_instr_i});
end
`endif // SCR1_DBG_EN
end
`endif // SCR1_NO_DEC_STAGE
`ifdef SCR1_DBG_EN
assign ifu2hdu_pbuf_rdy_o = idu2ifu_rdy_i;
`endif // SCR1_DBG_EN
`ifdef SCR1_TRGT_SIMULATION
//------------------------------------------------------------------------------
// Assertions
//------------------------------------------------------------------------------
// X checks
SCR1_SVA_IFU_XCHECK : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({imem2ifu_req_ack_i, idu2ifu_rdy_i, exu2ifu_pc_new_req_i})
) else $error("IFU Error: unknown values");
SCR1_SVA_IFU_XCHECK_REQ : assert property (
@(negedge clk) disable iff (~rst_n)
ifu2imem_req_o |-> !$isunknown({ifu2imem_addr_o, ifu2imem_cmd_o})
) else $error("IFU Error: unknown {ifu2imem_addr_o, ifu2imem_cmd_o}");
// Behavior checks
SCR1_SVA_IFU_DRC_UNDERFLOW : assert property (
@(negedge clk) disable iff (~rst_n)
~imem_resp_discard_req |=> ~(imem_resp_discard_cnt == SCR1_TXN_CNT_W'('1))
) else $error("IFU Error: imem_resp_discard_cnt underflow");
SCR1_SVA_IFU_DRC_RANGE : assert property (
@(negedge clk) disable iff (~rst_n)
(imem_resp_discard_cnt >= 0) & (imem_resp_discard_cnt <= imem_pnd_txns_cnt)
) else $error("IFU Error: imem_resp_discard_cnt out of range");
SCR1_SVA_IFU_QUEUE_OVF : assert property (
@(negedge clk) disable iff (~rst_n)
(q_ocpd_h >= SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF-1)) |->
((q_ocpd_h == SCR1_IFU_Q_FREE_H_W'(SCR1_IFU_Q_SIZE_HALF-1)) ? (q_wr_size != SCR1_IFU_QUEUE_WR_FULL)
: (q_wr_size == SCR1_IFU_QUEUE_WR_NONE))
) else $error("IFU Error: queue overflow");
SCR1_SVA_IFU_IMEM_ERR_BEH : assert property (
@(negedge clk) disable iff (~rst_n)
(imem_resp_er & ~imem_resp_discard_req & ~exu2ifu_pc_new_req_i) |=>
(ifu_fsm_curr == SCR1_IFU_FSM_IDLE) & (imem_resp_discard_cnt == imem_pnd_txns_cnt)
) else $error("IFU Error: incorrect behavior after memory error");
SCR1_SVA_IFU_NEW_PC_REQ_BEH : assert property (
@(negedge clk) disable iff (~rst_n)
exu2ifu_pc_new_req_i |=> q_is_empty
) else $error("IFU Error: incorrect behavior after exu2ifu_pc_new_req_i");
SCR1_SVA_IFU_IMEM_ADDR_ALIGNED : assert property (
@(negedge clk) disable iff (~rst_n)
ifu2imem_req_o |-> ~|ifu2imem_addr_o[1:0]
) else $error("IFU Error: unaligned IMEM access");
SCR1_SVA_IFU_STOP_FETCH : assert property (
@(negedge clk) disable iff (~rst_n)
pipe2ifu_stop_fetch_i |=> (ifu_fsm_curr == SCR1_IFU_FSM_IDLE)
) else $error("IFU Error: fetch not stopped");
SCR1_SVA_IFU_IMEM_FAULT_RVI_HI : assert property (
@(negedge clk) disable iff (~rst_n)
ifu2idu_err_rvi_hi_o |-> ifu2idu_imem_err_o
) else $error("IFU Error: ifu2idu_imem_err_o == 0");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_ifu

View File

@@ -0,0 +1,351 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_lsu.sv>
/// @brief Load/Store Unit (LSU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Performs load and store operations in Data Memory
// - Generates DMEM address misalign and access fault exceptions
// - Passes DMEM operations information to TDU and generates LSU breakpoint exception
//
// Structure:
// - FSM
// - Exceptions logic
// - LSU <-> EXU interface
// - LSU <-> DMEM interface
// - LSU <-> TDU interface
//
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`include "scr1_arch_types.svh"
`include "scr1_memif.svh"
`include "scr1_riscv_isa_decoding.svh"
`ifdef SCR1_TDU_EN
`include "scr1_tdu.svh"
`endif // SCR1_TDU_EN
module scr1_pipe_lsu (
// Common
input logic rst_n, // LSU reset
input logic clk, // LSU clock
// LSU <-> EXU interface
input logic exu2lsu_req_i, // Request to LSU
input type_scr1_lsu_cmd_sel_e exu2lsu_cmd_i, // LSU command
input logic [`SCR1_XLEN-1:0] exu2lsu_addr_i, // Address of DMEM
input logic [`SCR1_XLEN-1:0] exu2lsu_sdata_i, // Data for store
output logic lsu2exu_rdy_o, // LSU received DMEM response
output logic [`SCR1_XLEN-1:0] lsu2exu_ldata_o, // Load data
output logic lsu2exu_exc_o, // Exception from LSU
output type_scr1_exc_code_e lsu2exu_exc_code_o, // Exception code
`ifdef SCR1_TDU_EN
// LSU <-> TDU interface
output type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_o, // Data address stream monitoring
input logic tdu2lsu_ibrkpt_exc_req_i, // Instruction BP exception request
input logic tdu2lsu_dbrkpt_exc_req_i, // Data BP exception request
`endif // SCR1_TDU_EN
// LSU <-> DMEM interface
output logic lsu2dmem_req_o, // Data memory request
output type_scr1_mem_cmd_e lsu2dmem_cmd_o, // Data memory command (READ/WRITE)
output type_scr1_mem_width_e lsu2dmem_width_o, // Data memory data width
output logic [`SCR1_DMEM_AWIDTH-1:0] lsu2dmem_addr_o, // Data memory address
output logic [`SCR1_DMEM_DWIDTH-1:0] lsu2dmem_wdata_o, // Data memory write data
input logic dmem2lsu_req_ack_i, // Data memory request acknowledge
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2lsu_rdata_i, // Data memory read data
input type_scr1_mem_resp_e dmem2lsu_resp_i // Data memory response
);
//------------------------------------------------------------------------------
// Local types declaration
//------------------------------------------------------------------------------
typedef enum logic {
SCR1_LSU_FSM_IDLE,
SCR1_LSU_FSM_BUSY
} type_scr1_lsu_fsm_e;
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// LSU FSM signals
type_scr1_lsu_fsm_e lsu_fsm_curr; // LSU FSM current state
type_scr1_lsu_fsm_e lsu_fsm_next; // LSU FSM next state
logic lsu_fsm_idle; // LSU FSM is in IDLE state
// LSU Command register signals
logic lsu_cmd_upd; // LSU Command register update
type_scr1_lsu_cmd_sel_e lsu_cmd_ff; // LSU Command register value
logic lsu_cmd_ff_load; // Registered LSU Command is load
logic lsu_cmd_ff_store; // Registered LSU Command is store
// DMEM command and width flags
logic dmem_cmd_load; // DMEM command is load
logic dmem_cmd_store; // DMEM Command is store
logic dmem_wdth_word; // DMEM data width is WORD
logic dmem_wdth_hword; // DMEM data width is HALFWORD
logic dmem_wdth_byte; // DMEM data width is BYTE
// DMEM response and request control signals
logic dmem_resp_ok; // DMEM response is OK
logic dmem_resp_er; // DMEM response is erroneous
logic dmem_resp_received; // DMEM response is received
logic dmem_req_vd; // DMEM request is valid (req_ack received)
// Exceptions signals
logic lsu_exc_req; // LSU exception request
logic dmem_addr_mslgn; // DMEM address is misaligned
logic dmem_addr_mslgn_l; // DMEM load address is misaligned
logic dmem_addr_mslgn_s; // DMEM store address is misaligned
`ifdef SCR1_TDU_EN
logic lsu_exc_hwbrk; // LSU hardware breakpoint exception
`endif // SCR1_TDU_EN
//------------------------------------------------------------------------------
// Control logic
//------------------------------------------------------------------------------
// DMEM response and request control signals
assign dmem_resp_ok = (dmem2lsu_resp_i == SCR1_MEM_RESP_RDY_OK);
assign dmem_resp_er = (dmem2lsu_resp_i == SCR1_MEM_RESP_RDY_ER);
assign dmem_resp_received = dmem_resp_ok | dmem_resp_er;
assign dmem_req_vd = exu2lsu_req_i & dmem2lsu_req_ack_i & ~lsu_exc_req;
// LSU load and store command flags
assign dmem_cmd_load = (exu2lsu_cmd_i == SCR1_LSU_CMD_LB )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LBU)
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LH )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LHU)
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LW );
assign dmem_cmd_store = (exu2lsu_cmd_i == SCR1_LSU_CMD_SB )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SH )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SW );
// LSU data width flags
assign dmem_wdth_word = (exu2lsu_cmd_i == SCR1_LSU_CMD_LW )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SW );
assign dmem_wdth_hword = (exu2lsu_cmd_i == SCR1_LSU_CMD_LH )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LHU)
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SH );
assign dmem_wdth_byte = (exu2lsu_cmd_i == SCR1_LSU_CMD_LB )
| (exu2lsu_cmd_i == SCR1_LSU_CMD_LBU)
| (exu2lsu_cmd_i == SCR1_LSU_CMD_SB );
// LSU command register
assign lsu_cmd_upd = lsu_fsm_idle & dmem_req_vd;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
lsu_cmd_ff <= SCR1_LSU_CMD_NONE;
end else if (lsu_cmd_upd) begin
lsu_cmd_ff <= exu2lsu_cmd_i;
end
end
// LSU registered load and store command flags
assign lsu_cmd_ff_load = (lsu_cmd_ff == SCR1_LSU_CMD_LB )
| (lsu_cmd_ff == SCR1_LSU_CMD_LBU)
| (lsu_cmd_ff == SCR1_LSU_CMD_LH )
| (lsu_cmd_ff == SCR1_LSU_CMD_LHU)
| (lsu_cmd_ff == SCR1_LSU_CMD_LW );
assign lsu_cmd_ff_store = (lsu_cmd_ff == SCR1_LSU_CMD_SB )
| (lsu_cmd_ff == SCR1_LSU_CMD_SH )
| (lsu_cmd_ff == SCR1_LSU_CMD_SW );
//------------------------------------------------------------------------------
// LSU FSM
//------------------------------------------------------------------------------
//
// LSU FSM is used to control the LSU <-> DMEM interface
//
//
// Updating LSU FSM state
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
lsu_fsm_curr <= SCR1_LSU_FSM_IDLE;
end else begin
lsu_fsm_curr <= lsu_fsm_next;
end
end
// LSU FSM next state logic
always_comb begin
case (lsu_fsm_curr)
SCR1_LSU_FSM_IDLE: begin
lsu_fsm_next = dmem_req_vd ? SCR1_LSU_FSM_BUSY
: SCR1_LSU_FSM_IDLE;
end
SCR1_LSU_FSM_BUSY: begin
lsu_fsm_next = dmem_resp_received ? SCR1_LSU_FSM_IDLE
: SCR1_LSU_FSM_BUSY;
end
endcase
end
assign lsu_fsm_idle = (lsu_fsm_curr == SCR1_LSU_FSM_IDLE);
//------------------------------------------------------------------------------
// Exceptions logic
//------------------------------------------------------------------------------
//
// The following types of exceptions are supported:
// - Load address misalign
// - Load access fault
// - Store address misalign
// - Store access fault
// - LSU breakpoint exception
//
// DMEM addr misalign logic
assign dmem_addr_mslgn = exu2lsu_req_i & ( (dmem_wdth_hword & exu2lsu_addr_i[0])
| (dmem_wdth_word & |exu2lsu_addr_i[1:0]));
assign dmem_addr_mslgn_l = dmem_addr_mslgn & dmem_cmd_load;
assign dmem_addr_mslgn_s = dmem_addr_mslgn & dmem_cmd_store;
// Exception code logic
always_comb begin
case (1'b1)
dmem_resp_er : lsu2exu_exc_code_o = lsu_cmd_ff_load ? SCR1_EXC_CODE_LD_ACCESS_FAULT
: lsu_cmd_ff_store ? SCR1_EXC_CODE_ST_ACCESS_FAULT
: SCR1_EXC_CODE_INSTR_MISALIGN;
`ifdef SCR1_TDU_EN
lsu_exc_hwbrk : lsu2exu_exc_code_o = SCR1_EXC_CODE_BREAKPOINT;
`endif // SCR1_TDU_EN
dmem_addr_mslgn_l: lsu2exu_exc_code_o = SCR1_EXC_CODE_LD_ADDR_MISALIGN;
dmem_addr_mslgn_s: lsu2exu_exc_code_o = SCR1_EXC_CODE_ST_ADDR_MISALIGN;
default : lsu2exu_exc_code_o = SCR1_EXC_CODE_INSTR_MISALIGN;
endcase // 1'b1
end
assign lsu_exc_req = dmem_addr_mslgn_l | dmem_addr_mslgn_s
`ifdef SCR1_TDU_EN
| lsu_exc_hwbrk
`endif // SCR1_TDU_EN
;
//------------------------------------------------------------------------------
// LSU <-> EXU interface
//------------------------------------------------------------------------------
assign lsu2exu_rdy_o = dmem_resp_received;
assign lsu2exu_exc_o = dmem_resp_er | lsu_exc_req;
// Sign- or zero-extending data received from DMEM
always_comb begin
case (lsu_cmd_ff)
SCR1_LSU_CMD_LH : lsu2exu_ldata_o = {{16{dmem2lsu_rdata_i[15]}}, dmem2lsu_rdata_i[15:0]};
SCR1_LSU_CMD_LHU: lsu2exu_ldata_o = { 16'b0, dmem2lsu_rdata_i[15:0]};
SCR1_LSU_CMD_LB : lsu2exu_ldata_o = {{24{dmem2lsu_rdata_i[7]}}, dmem2lsu_rdata_i[7:0]};
SCR1_LSU_CMD_LBU: lsu2exu_ldata_o = { 24'b0, dmem2lsu_rdata_i[7:0]};
default : lsu2exu_ldata_o = dmem2lsu_rdata_i;
endcase // lsu_cmd_ff
end
//------------------------------------------------------------------------------
// LSU <-> DMEM interface
//------------------------------------------------------------------------------
assign lsu2dmem_req_o = exu2lsu_req_i & ~lsu_exc_req & lsu_fsm_idle;
assign lsu2dmem_addr_o = exu2lsu_addr_i;
assign lsu2dmem_wdata_o = exu2lsu_sdata_i;
assign lsu2dmem_cmd_o = dmem_cmd_store ? SCR1_MEM_CMD_WR : SCR1_MEM_CMD_RD;
assign lsu2dmem_width_o = dmem_wdth_byte ? SCR1_MEM_WIDTH_BYTE
: dmem_wdth_hword ? SCR1_MEM_WIDTH_HWORD
: SCR1_MEM_WIDTH_WORD;
`ifdef SCR1_TDU_EN
//------------------------------------------------------------------------------
// LSU <-> TDU interface
//------------------------------------------------------------------------------
assign lsu2tdu_dmon_o.vd = exu2lsu_req_i & lsu_fsm_idle & ~tdu2lsu_ibrkpt_exc_req_i;
assign lsu2tdu_dmon_o.addr = exu2lsu_addr_i;
assign lsu2tdu_dmon_o.load = dmem_cmd_load;
assign lsu2tdu_dmon_o.store = dmem_cmd_store;
assign lsu_exc_hwbrk = (exu2lsu_req_i & tdu2lsu_ibrkpt_exc_req_i)
| tdu2lsu_dbrkpt_exc_req_i;
`endif // SCR1_TDU_EN
`ifdef SCR1_TRGT_SIMULATION
//------------------------------------------------------------------------------
// Assertions
//------------------------------------------------------------------------------
// X checks
SCR1_SVA_LSU_XCHECK_CTRL : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({exu2lsu_req_i, lsu_fsm_curr
`ifdef SCR1_TDU_EN
, tdu2lsu_ibrkpt_exc_req_i, tdu2lsu_dbrkpt_exc_req_i
`endif // SCR1_TDU_EN
})
) else $error("LSU Error: unknown control value");
SCR1_SVA_LSU_XCHECK_CMD : assert property (
@(negedge clk) disable iff (~rst_n)
exu2lsu_req_i |-> !$isunknown({exu2lsu_cmd_i, exu2lsu_addr_i})
) else $error("LSU Error: undefined CMD or address");
SCR1_SVA_LSU_XCHECK_SDATA : assert property (
@(negedge clk) disable iff (~rst_n)
(exu2lsu_req_i & (lsu2dmem_cmd_o == SCR1_MEM_CMD_WR)) |-> !$isunknown({exu2lsu_sdata_i})
) else $error("LSU Error: undefined store data");
SCR1_SVA_LSU_XCHECK_EXC : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2exu_exc_o |-> !$isunknown(lsu2exu_exc_code_o)
) else $error("LSU Error: exception code undefined");
SCR1_SVA_LSU_IMEM_CTRL : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2dmem_req_o |-> !$isunknown({lsu2dmem_cmd_o, lsu2dmem_width_o, lsu2dmem_addr_o})
) else $error("LSU Error: undefined dmem control");
SCR1_SVA_LSU_IMEM_ACK : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2dmem_req_o |-> !$isunknown(dmem2lsu_req_ack_i)
) else $error("LSU Error: undefined dmem ack");
SCR1_SVA_LSU_IMEM_WDATA : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2dmem_req_o & (lsu2dmem_cmd_o == SCR1_MEM_CMD_WR)
|-> !$isunknown(lsu2dmem_wdata_o[8:0])
) else $error("LSU Error: undefined dmem wdata");
// Behavior checks
SCR1_SVA_LSU_EXC_ONEHOT : assert property (
@(negedge clk) disable iff (~rst_n)
$onehot0({dmem_resp_er, dmem_addr_mslgn_l, dmem_addr_mslgn_s})
) else $error("LSU Error: more than one exception at a time");
SCR1_SVA_LSU_UNEXPECTED_DMEM_RESP : assert property (
@(negedge clk) disable iff (~rst_n)
lsu_fsm_idle |-> ~dmem_resp_received
) else $error("LSU Error: not expecting memory response");
SCR1_SVA_LSU_REQ_EXC : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2exu_exc_o |-> exu2lsu_req_i
) else $error("LSU Error: impossible exception");
`ifdef SCR1_TDU_EN
SCR1_COV_LSU_MISALIGN_BRKPT : cover property (
@(negedge clk) disable iff (~rst_n)
(dmem_addr_mslgn_l | dmem_addr_mslgn_s) & lsu_exc_hwbrk
);
`endif // SCR1_TDU_EN
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_lsu

View File

@@ -0,0 +1,167 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_mprf.sv>
/// @brief Multi Port Register File (MPRF)
///
`include "scr1_arch_description.svh"
`include "scr1_arch_types.svh"
module scr1_pipe_mprf (
// Common
`ifdef SCR1_MPRF_RST_EN
input logic rst_n, // MPRF reset
`endif // SCR1_MPRF_RST_EN
input logic clk, // MPRF clock
// EXU <-> MPRF interface
input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr_i, // MPRF rs1 read address
output logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data_o, // MPRF rs1 read data
input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr_i, // MPRF rs2 read address
output logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data_o, // MPRF rs2 read data
input logic exu2mprf_w_req_i, // MPRF write request
input logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr_i, // MPRF rd write address
input logic [`SCR1_XLEN-1:0] exu2mprf_rd_data_i // MPRF rd write data
);
//-------------------------------------------------------------------------------
// Local types declaration
//-------------------------------------------------------------------------------
logic wr_req_vd;
logic rs1_addr_vd;
logic rs2_addr_vd;
`ifdef SCR1_MPRF_RAM
logic rs1_addr_vd_ff;
logic rs2_addr_vd_ff;
logic rs1_new_data_req;
logic rs2_new_data_req;
logic rs1_new_data_req_ff;
logic rs2_new_data_req_ff;
logic read_new_data_req;
logic [`SCR1_XLEN-1:0] rd_data_ff;
logic [`SCR1_XLEN-1:0] rs1_data_ff;
logic [`SCR1_XLEN-1:0] rs2_data_ff;
// when using RAM, 2 memories are needed because 3 simultaneous independent
// write/read operations can occur
`ifdef SCR1_TRGT_FPGA_INTEL_MAX10
(* ramstyle = "M9K" *) logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1];
(* ramstyle = "M9K" *) logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1];
`elsif SCR1_TRGT_FPGA_INTEL_ARRIAV
(* ramstyle = "M10K" *) logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1];
(* ramstyle = "M10K" *) logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1];
`else
logic [`SCR1_XLEN-1:0] mprf_int [1:`SCR1_MPRF_SIZE-1];
logic [`SCR1_XLEN-1:0] mprf_int2 [1:`SCR1_MPRF_SIZE-1];
`endif
`else // distributed logic implementation
type_scr1_mprf_v [1:`SCR1_MPRF_SIZE-1] mprf_int;
`endif
//------------------------------------------------------------------------------
// MPRF control logic
//------------------------------------------------------------------------------
// control signals common for distributed logic and RAM implementations
assign rs1_addr_vd = |exu2mprf_rs1_addr_i;
assign rs2_addr_vd = |exu2mprf_rs2_addr_i;
assign wr_req_vd = exu2mprf_w_req_i & |exu2mprf_rd_addr_i;
// RAM implementation specific control signals
`ifdef SCR1_MPRF_RAM
assign rs1_new_data_req = wr_req_vd & ( exu2mprf_rs1_addr_i == exu2mprf_rd_addr_i );
assign rs2_new_data_req = wr_req_vd & ( exu2mprf_rs2_addr_i == exu2mprf_rd_addr_i );
assign read_new_data_req = rs1_new_data_req | rs2_new_data_req;
always_ff @( posedge clk ) begin
rs1_addr_vd_ff <= rs1_addr_vd;
rs2_addr_vd_ff <= rs2_addr_vd;
rs1_new_data_req_ff <= rs1_new_data_req;
rs2_new_data_req_ff <= rs2_new_data_req;
end
`endif // SCR1_MPRF_RAM
`ifdef SCR1_MPRF_RAM
//-------------------------------------------------------------------------------
// RAM implementation
//-------------------------------------------------------------------------------
// RAM is implemented with 2 simple dual-port memories with sync read operation;
// logic for "write-first" RDW behavior is implemented externally to the embedded
// memory blocks
// bypass new wr_data to the read output if write/read collision occurs
assign mprf2exu_rs1_data_o = ( rs1_new_data_req_ff ) ? rd_data_ff
: (( rs1_addr_vd_ff ) ? rs1_data_ff
: '0 );
assign mprf2exu_rs2_data_o = ( rs2_new_data_req_ff ) ? rd_data_ff
: (( rs2_addr_vd_ff ) ? rs2_data_ff
: '0 );
always_ff @( posedge clk ) begin
if ( read_new_data_req ) begin
rd_data_ff <= exu2mprf_rd_data_i;
end
end
// synchronous read operation
always_ff @( posedge clk ) begin
rs1_data_ff <= mprf_int[exu2mprf_rs1_addr_i];
rs2_data_ff <= mprf_int2[exu2mprf_rs2_addr_i];
end
// write operation
always_ff @( posedge clk ) begin
if ( wr_req_vd ) begin
mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
mprf_int2[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
end
end
`else // distributed logic implementation
//------------------------------------------------------------------------------
// distributed logic implementation
//------------------------------------------------------------------------------
// asynchronous read operation
assign mprf2exu_rs1_data_o = ( rs1_addr_vd ) ? mprf_int[exu2mprf_rs1_addr_i] : '0;
assign mprf2exu_rs2_data_o = ( rs2_addr_vd ) ? mprf_int[exu2mprf_rs2_addr_i] : '0;
// write operation
`ifdef SCR1_MPRF_RST_EN
always_ff @( posedge clk, negedge rst_n ) begin
if ( ~rst_n ) begin
mprf_int <= '{default: '0};
end else if ( wr_req_vd ) begin
mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
end
end
`else // ~SCR1_MPRF_RST_EN
always_ff @( posedge clk ) begin
if ( wr_req_vd ) begin
mprf_int[exu2mprf_rd_addr_i] <= exu2mprf_rd_data_i;
end
end
`endif // ~SCR1_MPRF_RST_EN
`endif
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
`ifdef SCR1_MPRF_RST_EN
SCR1_SVA_MPRF_WRITEX : assert property (
@(negedge clk) disable iff (~rst_n)
exu2mprf_w_req_i |-> !$isunknown({exu2mprf_rd_addr_i, (|exu2mprf_rd_addr_i ? exu2mprf_rd_data_i : `SCR1_XLEN'd0)})
) else $error("MPRF error: unknown values");
`endif // SCR1_MPRF_RST_EN
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_mprf

View File

@@ -0,0 +1,610 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_tdu.sv>
/// @brief Trigger Debug Unit (TDU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Provides read/write interface for TDU CSRs
// - Provides triggers functionality:
// - Supports triggers either in both Debug and M modes or in Debug mode only
// - Supports virtual address matching (load, store, exec) triggers
// - Supports instruction count triggers
// - Supports the following actions on trigger firing:
// - Breakpoint exception raising
// - Debug Mode entering
// - Supports triggers chaining
//
// Structure:
// - CSR read/write i/f
// - TDU CSRs:
// - TSELECT
// - TDATA1/MCONTROL/ICOUNT
// - TDATA2
// - TINFO
// - TDU <-> EXU i/f
// - TDU <-> LSU i/f
// - TDU <-> HDU i/f
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_TDU_EN
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_tdu.svh"
module scr1_pipe_tdu (
// Common signals
input logic rst_n, // TDU reset
input logic clk, // TDU clock
input logic clk_en, // TDU clock enable
input logic tdu_dsbl_i, // TDU Disable
// TDU <-> CSR interface
input logic csr2tdu_req_i, // CSR-TDU i/f request
input type_scr1_csr_cmd_sel_e csr2tdu_cmd_i, // CSR-TDU i/f command
input logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr_i, // CSR-TDU i/f address
input logic [SCR1_TDU_DATA_W-1:0] csr2tdu_wdata_i, // CSR-TDU i/f write data
output logic [SCR1_TDU_DATA_W-1:0] tdu2csr_rdata_o, // CSR-TDU i/f read data
output type_scr1_csr_resp_e tdu2csr_resp_o, // CSR-TDU i/f response
// TDU <-> EXU interface
input type_scr1_brkm_instr_mon_s exu2tdu_imon_i, // Instruction stream monitoring
output logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] tdu2exu_ibrkpt_match_o, // Instruction BP match
output logic tdu2exu_ibrkpt_exc_req_o, // Instruction BP exception request
input logic [SCR1_TDU_ALLTRIG_NUM-1 : 0] exu2tdu_bp_retire_i, // Map of BPs being retired
// TDU <-> LSU interface
`ifndef SCR1_TDU_EN
output logic tdu2lsu_brk_en_o, // TDU-LSU Breakpoint enable
`endif // SCR1_TDU_EN
output logic tdu2lsu_ibrkpt_exc_req_o, // TDU-LSU Instruction BP exception request
input type_scr1_brkm_lsu_mon_s lsu2tdu_dmon_i, // TDU-LSU Data address stream monitoring
output logic [SCR1_TDU_MTRIG_NUM-1 : 0] tdu2lsu_dbrkpt_match_o, // TDU-LSU Data BP match
output logic tdu2lsu_dbrkpt_exc_req_o, // TDU-LSU Data BP exception request
// TDU <-> HDU interface
output logic tdu2hdu_dmode_req_o // Debug Mode redirection request
);
//------------------------------------------------------------------------------
// Local parameters declaration
//------------------------------------------------------------------------------
localparam int unsigned MTRIG_NUM = SCR1_TDU_MTRIG_NUM;
localparam int unsigned ALLTRIG_NUM = SCR1_TDU_ALLTRIG_NUM;
localparam int unsigned ALLTRIG_W = $clog2(ALLTRIG_NUM+1);
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// TDU CSRs read/write i/f signals
//------------------------------------------------------------------------------
// Write signals
logic csr_wr_req;
logic [SCR1_TDU_DATA_W-1:0] csr_wr_data;
// Register select
logic csr_addr_tselect;
logic [MTRIG_NUM-1:0] csr_addr_mcontrol;
logic [MTRIG_NUM-1:0] csr_addr_tdata2;
`ifdef SCR1_TDU_ICOUNT_EN
logic csr_addr_icount;
`endif // SCR1_TDU_ICOUNT_EN
// TDU CSRs
//------------------------------------------------------------------------------
// TSELECT register
logic csr_tselect_upd;
logic [ALLTRIG_W-1:0] csr_tselect_ff;
// MCONTROL register
logic [MTRIG_NUM-1:0] csr_mcontrol_wr_req;
logic [MTRIG_NUM-1:0] csr_mcontrol_clk_en;
logic [MTRIG_NUM-1:0] csr_mcontrol_upd;
logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_dmode_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_m_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_m_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_load_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_load_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_store_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_store_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_action_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_action_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_hit_ff;
logic [MTRIG_NUM-1:0] csr_mcontrol_hit_next;
logic [MTRIG_NUM-1:0] csr_mcontrol_exec_hit;
logic [MTRIG_NUM-1:0] csr_mcontrol_ldst_hit;
// ICOUNT register
`ifdef SCR1_TDU_ICOUNT_EN
logic csr_icount_wr_req;
logic csr_icount_clk_en;
logic csr_icount_upd;
logic csr_icount_dmode_ff;
logic csr_icount_dmode_next;
logic csr_icount_m_ff;
logic csr_icount_m_next;
logic csr_icount_action_ff;
logic csr_icount_action_next;
logic csr_icount_hit_ff;
logic csr_icount_hit_next;
logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0]
csr_icount_count_ff;
logic [SCR1_TDU_ICOUNT_COUNT_HI-SCR1_TDU_ICOUNT_COUNT_LO:0]
csr_icount_count_next;
logic csr_icount_skip_ff;
logic csr_icount_skip_next;
logic csr_icount_decr_en;
logic csr_icount_count_decr;
logic csr_icount_skip_dsbl;
logic csr_icount_hit;
`endif // SCR1_TDU_ICOUNT_EN
// TDATA2 register
logic [MTRIG_NUM-1:0] csr_tdata2_upd;
logic [MTRIG_NUM-1:0] [SCR1_TDU_DATA_W-1:0] csr_tdata2_ff;
//------------------------------------------------------------------------------
// CSR read/write interface
//------------------------------------------------------------------------------
// Read logic
//------------------------------------------------------------------------------
assign tdu2csr_resp_o = csr2tdu_req_i ? SCR1_CSR_RESP_OK : SCR1_CSR_RESP_ER;
always_comb begin
tdu2csr_rdata_o = '0;
if (csr2tdu_req_i) begin
case (csr2tdu_addr_i)
SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin
tdu2csr_rdata_o = {'0, csr_tselect_ff};
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
tdu2csr_rdata_o = csr_tdata2_ff[i];
end
end
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI:
SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_MCONTROL_TYPE_VAL;
tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_mcontrol_dmode_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MASKMAX_HI:
SCR1_TDU_MCONTROL_MASKMAX_LO] = SCR1_TDU_MCONTROL_MASKMAX_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_HIT] = csr_mcontrol_hit_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_SELECT] = SCR1_TDU_MCONTROL_SELECT_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TIMING] = SCR1_TDU_MCONTROL_TIMING_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_ACTION_HI:
SCR1_TDU_MCONTROL_ACTION_LO] = {5'b0, csr_mcontrol_action_ff[i]};
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_CHAIN] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_MATCH_HI:
SCR1_TDU_MCONTROL_MATCH_LO] = 4'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_M] = csr_mcontrol_m_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_RESERVEDA] = SCR1_TDU_MCONTROL_RESERVEDA_VAL;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_S] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_U] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_EXECUTE] = csr_mcontrol_exec_ff [i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_STORE] = csr_mcontrol_store_ff[i];
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_LOAD] = csr_mcontrol_load_ff [i];
end
end
`ifdef SCR1_TDU_ICOUNT_EN
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
tdu2csr_rdata_o[SCR1_TDU_TDATA1_TYPE_HI:
SCR1_TDU_TDATA1_TYPE_LO] = SCR1_TDU_ICOUNT_TYPE_VAL;
tdu2csr_rdata_o[SCR1_TDU_TDATA1_DMODE] = csr_icount_dmode_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_HIT] = csr_icount_hit_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_COUNT_HI:
SCR1_TDU_ICOUNT_COUNT_LO] = csr_icount_count_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_U] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_S] = 1'b0;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_M] = csr_icount_m_ff;
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_ACTION_HI:
SCR1_TDU_ICOUNT_ACTION_LO] = {5'b0, csr_icount_action_ff};
end
`endif // SCR1_TDU_ICOUNT_EN
end
SCR1_CSR_ADDR_TDU_OFFS_TINFO : begin
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
tdu2csr_rdata_o[SCR1_TDU_MCONTROL_TYPE_VAL] = 1'b1;
end
end
`ifdef SCR1_TDU_ICOUNT_EN
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
tdu2csr_rdata_o[SCR1_TDU_ICOUNT_TYPE_VAL] = 1'b1;
end
`endif // SCR1_TDU_ICOUNT_EN
end
default : begin
end
endcase
end
end
// Write logic
//------------------------------------------------------------------------------
always_comb begin
csr_wr_req = 1'b0;
csr_wr_data = '0;
case (csr2tdu_cmd_i)
SCR1_CSR_CMD_WRITE: begin
csr_wr_req = 1'b1;
csr_wr_data = csr2tdu_wdata_i;
end
SCR1_CSR_CMD_SET : begin
csr_wr_req = |csr2tdu_wdata_i;
csr_wr_data = tdu2csr_rdata_o | csr2tdu_wdata_i;
end
SCR1_CSR_CMD_CLEAR: begin
csr_wr_req = |csr2tdu_wdata_i;
csr_wr_data = tdu2csr_rdata_o & ~csr2tdu_wdata_i;
end
default : begin
end
endcase
end
// Register selection
//------------------------------------------------------------------------------
always_comb begin
csr_addr_tselect = 1'b0;
csr_addr_tdata2 = '0;
csr_addr_mcontrol = '0;
`ifdef SCR1_TDU_ICOUNT_EN
csr_addr_icount = '0;
`endif // SCR1_TDU_ICOUNT_EN
if (csr2tdu_req_i) begin
case (csr2tdu_addr_i)
SCR1_CSR_ADDR_TDU_OFFS_TSELECT: begin
csr_addr_tselect = 1'b1;
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA1 : begin
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
if(csr_tselect_ff == ALLTRIG_W'(i)) begin
csr_addr_mcontrol[i] = 1'b1;
end
end
`ifdef SCR1_TDU_ICOUNT_EN
if(csr_tselect_ff == ALLTRIG_W'(SCR1_TDU_ALLTRIG_NUM - 1'b1)) begin
csr_addr_icount = 1'b1;
end
`endif // SCR1_TDU_ICOUNT_EN
end
SCR1_CSR_ADDR_TDU_OFFS_TDATA2 : begin
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
if(csr_tselect_ff == ALLTRIG_W'(i) ) begin
csr_addr_tdata2[i] = 1'b1;
end
end
end
default : begin
end
endcase
end
end
//------------------------------------------------------------------------------
// TDU CSRs
//------------------------------------------------------------------------------
//
// TDU CSRs consist of the following registers:
// - TSELECT
// - TDATA1/MCONTROL/ICOUNT (depending on the type field value)
// - TDATA2
//
// TSELECT register
//------------------------------------------------------------------------------
// Determines which trigger is accessible through the other trigger registers
assign csr_tselect_upd = clk_en & csr_addr_tselect & csr_wr_req
& (csr_wr_data[ALLTRIG_W-1:0] < ALLTRIG_W'(ALLTRIG_NUM));
always_ff @(negedge rst_n, posedge clk) begin
if(~rst_n) begin
csr_tselect_ff <= '0;
end else if(csr_tselect_upd) begin
csr_tselect_ff <= csr_wr_data[ALLTRIG_W-1:0];
end
end
`ifdef SCR1_TDU_ICOUNT_EN
// ICOUNT register
//------------------------------------------------------------------------------
// Provides a trigger that fires when the certain number of instructions has retired
// Is intended to be used as a single step trigger (in this case count must be 1)
assign csr_icount_wr_req = csr_addr_icount & csr_wr_req;
assign csr_icount_clk_en = clk_en & (csr_icount_wr_req | csr_icount_m_ff);
assign csr_icount_upd = ~csr_icount_dmode_ff
? csr_icount_wr_req
: tdu_dsbl_i & csr_icount_wr_req;
always_ff @(negedge rst_n, posedge clk) begin
if(~rst_n) begin
csr_icount_dmode_ff <= 1'b0;
csr_icount_m_ff <= 1'b0;
csr_icount_action_ff <= 1'b0;
csr_icount_hit_ff <= 1'b0;
csr_icount_count_ff <= '0;
csr_icount_skip_ff <= 1'b0;
end else if (csr_icount_clk_en) begin
csr_icount_dmode_ff <= csr_icount_dmode_next;
csr_icount_m_ff <= csr_icount_m_next;
csr_icount_action_ff <= csr_icount_action_next;
csr_icount_hit_ff <= csr_icount_hit_next;
csr_icount_count_ff <= csr_icount_count_next;
csr_icount_skip_ff <= csr_icount_skip_next;
end
end
assign csr_icount_decr_en = (~tdu_dsbl_i & csr_icount_m_ff)
? exu2tdu_imon_i.vd & (csr_icount_count_ff != 14'b0)
: 1'b0;
assign csr_icount_count_decr = exu2tdu_imon_i.req & csr_icount_decr_en & ~csr_icount_skip_ff;
assign csr_icount_skip_dsbl = exu2tdu_imon_i.req & csr_icount_decr_en & csr_icount_skip_ff;
always_comb begin
if (csr_icount_upd) begin
csr_icount_dmode_next = csr_wr_data[SCR1_TDU_TDATA1_DMODE];
csr_icount_m_next = csr_wr_data[SCR1_TDU_ICOUNT_M];
csr_icount_action_next = (csr_wr_data[SCR1_TDU_ICOUNT_ACTION_HI
:SCR1_TDU_ICOUNT_ACTION_LO] == 'b1);
csr_icount_hit_next = csr_wr_data[SCR1_TDU_ICOUNT_HIT];
csr_icount_count_next = csr_wr_data[SCR1_TDU_ICOUNT_COUNT_HI:SCR1_TDU_ICOUNT_COUNT_LO];
end else begin
csr_icount_dmode_next = csr_icount_dmode_ff;
csr_icount_m_next = csr_icount_m_ff;
csr_icount_action_next = csr_icount_action_ff;
csr_icount_hit_next = exu2tdu_bp_retire_i[ALLTRIG_NUM - 1'b1]
? 1'b1
: csr_icount_hit_ff;
csr_icount_count_next = csr_icount_count_decr
? csr_icount_count_ff - 1'b1
: csr_icount_count_ff;
end
end
assign csr_icount_skip_next = csr_icount_wr_req ? csr_wr_data[SCR1_TDU_ICOUNT_M]
: csr_icount_skip_dsbl ? 1'b0
: csr_icount_skip_ff;
`endif // SCR1_TDU_ICOUNT_EN
// MCONTROL registers
//------------------------------------------------------------------------------
// Provides a trigger that fires on the virtual address (stored in TDATA2) match
// (load, store, exec options supported). Triggers chaining supported
genvar trig;
generate
for (trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig) begin : gblock_mtrig
assign csr_mcontrol_wr_req[trig] = csr_addr_mcontrol[trig] & csr_wr_req;
assign csr_mcontrol_clk_en[trig] = clk_en
& (csr_mcontrol_wr_req[trig] | csr_mcontrol_m_ff[trig]);
assign csr_mcontrol_upd [trig] = ~csr_mcontrol_dmode_ff[trig]
? csr_mcontrol_wr_req[trig]
: tdu_dsbl_i & csr_mcontrol_wr_req[trig];
always_ff @(negedge rst_n, posedge clk) begin
if(~rst_n) begin
csr_mcontrol_dmode_ff [trig] <= 1'b0;
csr_mcontrol_m_ff [trig] <= 1'b0;
csr_mcontrol_exec_ff [trig] <= 1'b0;
csr_mcontrol_load_ff [trig] <= 1'b0;
csr_mcontrol_store_ff [trig] <= 1'b0;
csr_mcontrol_action_ff[trig] <= 1'b0;
csr_mcontrol_hit_ff [trig] <= 1'b0;
end else if(csr_mcontrol_clk_en[trig]) begin
csr_mcontrol_dmode_ff [trig] <= csr_mcontrol_dmode_next[trig];
csr_mcontrol_m_ff [trig] <= csr_mcontrol_m_next[trig];
csr_mcontrol_exec_ff [trig] <= csr_mcontrol_exec_next[trig];
csr_mcontrol_load_ff [trig] <= csr_mcontrol_load_next[trig];
csr_mcontrol_store_ff [trig] <= csr_mcontrol_store_next[trig];
csr_mcontrol_action_ff[trig] <= csr_mcontrol_action_next[trig];
csr_mcontrol_hit_ff [trig] <= csr_mcontrol_hit_next[trig];
end
end
always_comb begin
if (csr_mcontrol_upd[trig]) begin
csr_mcontrol_dmode_next [trig] = csr_wr_data[SCR1_TDU_TDATA1_DMODE];
csr_mcontrol_m_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_M];
csr_mcontrol_exec_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_EXECUTE];
csr_mcontrol_load_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_LOAD];
csr_mcontrol_store_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_STORE];
csr_mcontrol_action_next[trig] = (csr_wr_data[SCR1_TDU_MCONTROL_ACTION_HI
:SCR1_TDU_MCONTROL_ACTION_LO] == 'b1);
csr_mcontrol_hit_next [trig] = csr_wr_data[SCR1_TDU_MCONTROL_HIT];
end else begin
csr_mcontrol_dmode_next [trig] = csr_mcontrol_dmode_ff [trig];
csr_mcontrol_m_next [trig] = csr_mcontrol_m_ff [trig];
csr_mcontrol_exec_next [trig] = csr_mcontrol_exec_ff [trig];
csr_mcontrol_load_next [trig] = csr_mcontrol_load_ff [trig];
csr_mcontrol_store_next [trig] = csr_mcontrol_store_ff [trig];
csr_mcontrol_action_next[trig] = csr_mcontrol_action_ff[trig];
csr_mcontrol_hit_next [trig] = exu2tdu_bp_retire_i[trig]
? 1'b1
: csr_mcontrol_hit_ff[trig];
end
end
// TDATA2 register
//------------------------------------------------------------------------------
assign csr_tdata2_upd[trig] = ~csr_mcontrol_dmode_ff[trig]
? clk_en & csr_addr_tdata2[trig] & csr_wr_req
: clk_en & csr_addr_tdata2[trig] & csr_wr_req & tdu_dsbl_i;
always_ff @(posedge clk) begin
if (csr_tdata2_upd[trig]) begin
csr_tdata2_ff[trig] <= csr_wr_data;
end
end
end
endgenerate // gblock_mtrig
//------------------------------------------------------------------------------
// TDU <-> EXU interface
//------------------------------------------------------------------------------
assign csr_icount_hit = ~tdu_dsbl_i & csr_icount_m_ff
? exu2tdu_imon_i.vd & (csr_icount_count_ff == 14'b1) & ~csr_icount_skip_ff
: 1'b0;
`ifndef SCR1_TDU_ICOUNT_EN
assign tdu2exu_ibrkpt_match_o = csr_mcontrol_exec_hit;
assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit;
`else
assign tdu2exu_ibrkpt_match_o = {csr_icount_hit, csr_mcontrol_exec_hit};
assign tdu2exu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit;
`endif // SCR1_TDU_ICOUNT_EN
//------------------------------------------------------------------------------
// TDU <-> LSU interface
//------------------------------------------------------------------------------
// Breakpoint logic
//------------------------------------------------------------------------------
generate
for (trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig) begin : gblock_break_trig
assign csr_mcontrol_exec_hit[trig] = ~tdu_dsbl_i
& csr_mcontrol_m_ff[trig]
& csr_mcontrol_exec_ff[trig]
& exu2tdu_imon_i.vd
& exu2tdu_imon_i.addr == csr_tdata2_ff[trig];
end
endgenerate
`ifndef SCR1_TDU_ICOUNT_EN
assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit;
`else
assign tdu2lsu_ibrkpt_exc_req_o = |csr_mcontrol_exec_hit | csr_icount_hit;
`endif // SCR1_TDU_ICOUNT_EN
// Watchpoint logic
//------------------------------------------------------------------------------
generate
for( trig = 0; $unsigned(trig) < MTRIG_NUM; ++trig ) begin : gblock_watch_trig
assign csr_mcontrol_ldst_hit[trig] = ~tdu_dsbl_i
& csr_mcontrol_m_ff[trig]
& lsu2tdu_dmon_i.vd
& ( (csr_mcontrol_load_ff [trig] & lsu2tdu_dmon_i.load)
| (csr_mcontrol_store_ff[trig] & lsu2tdu_dmon_i.store))
& lsu2tdu_dmon_i.addr == csr_tdata2_ff[trig];
end
endgenerate
assign tdu2lsu_dbrkpt_match_o = csr_mcontrol_ldst_hit;
assign tdu2lsu_dbrkpt_exc_req_o = |csr_mcontrol_ldst_hit;
`ifndef SCR1_TDU_EN
assign tdu2lsu_brk_en_o = |csr_mcontrol_m_ff | csr_icount_m_ff;
`endif // SCR1_TDU_EN
//------------------------------------------------------------------------------
// TDU <-> HDU interface
//------------------------------------------------------------------------------
always_comb begin
tdu2hdu_dmode_req_o = 1'b0;
for(int unsigned i = 0; i < MTRIG_NUM; ++i) begin
tdu2hdu_dmode_req_o |= (csr_mcontrol_action_ff[i] & exu2tdu_bp_retire_i[i]);
end
`ifdef SCR1_TDU_ICOUNT_EN
tdu2hdu_dmode_req_o |= (csr_icount_action_ff & exu2tdu_bp_retire_i[ALLTRIG_NUM-1]);
`endif // SCR1_TDU_ICOUNT_EN
end
`ifdef SCR1_TRGT_SIMULATION
//------------------------------------------------------------------------------
// Assertion
//------------------------------------------------------------------------------
SVA_TDU_X_CONTROL : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({clk_en, tdu_dsbl_i, csr2tdu_req_i,
exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i})
) else $error("TDU Error: control signals is X - %0b", {clk_en,
tdu_dsbl_i, csr2tdu_req_i, exu2tdu_imon_i.vd, lsu2tdu_dmon_i.vd, exu2tdu_bp_retire_i});
SVA_DM_X_CLK_EN : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(clk_en)
) else $error("TDU Error: clk_en control signals is X");
SVA_DM_X_DSBL : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(tdu_dsbl_i)
) else $error("TDU Error: tdu_dsbl_i control signals is X");
SVA_DM_X_CSR2TDU_REQ : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(csr2tdu_req_i)
) else $error("TDU Error: csr2tdu_req_i control signals is X");
SVA_DM_X_I_MON_VD : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(exu2tdu_imon_i.vd)
) else $error("TDU Error: exu2tdu_imon_i.vd control signals is X");
SVA_DM_X_D_MON_VD : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(lsu2tdu_dmon_i.vd)
) else $error("TDU Error: lsu2tdu_dmon_i.vd control signals is X");
SVA_DM_X_BP_RETIRE : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(exu2tdu_bp_retire_i)
) else $error("TDU Error: exu2tdu_bp_retire_i control signals is X");
SVA_TDU_X_CSR : assert property (
@(negedge clk) disable iff (~rst_n)
csr2tdu_req_i |-> !$isunknown({csr2tdu_cmd_i,csr2tdu_addr_i})
) else $error("TDU Error: csr is X");
SVA_TDU_XW_CSR : assert property (
@(negedge clk) disable iff (~rst_n)
(csr2tdu_req_i & csr_wr_req) |-> !$isunknown(csr2tdu_wdata_i)
) else $error("TDU Error: csr wdata is X ");
SVA_TDU_X_IMON : assert property (
@(negedge clk) disable iff (~rst_n)
exu2tdu_imon_i.vd |-> !$isunknown({exu2tdu_imon_i.req,exu2tdu_imon_i.addr})
) else $error("TDU Error: imonitor is X");
SVA_TDU_X_DMON : assert property (
@(negedge clk) disable iff (~rst_n)
lsu2tdu_dmon_i.vd |-> !$isunknown({lsu2tdu_dmon_i})
) else $error("TDU Error: dmonitor is X");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_tdu
`endif // SCR1_TDU_EN

View File

@@ -0,0 +1,825 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_top.sv>
/// @brief SCR1 pipeline top
///
`include "scr1_arch_description.svh"
`include "scr1_memif.svh"
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_csr.svh"
`ifdef SCR1_IPIC_EN
`include "scr1_ipic.svh"
`endif // SCR1_IPIC_EN
`ifdef SCR1_DBG_EN
`include "scr1_hdu.svh"
`endif // SCR1_DBG_EN
`ifdef SCR1_TDU_EN
`include "scr1_tdu.svh"
`endif // SCR1_TDU_EN
module scr1_pipe_top (
// Common
input logic pipe_rst_n, // Pipe reset
`ifdef SCR1_DBG_EN
input logic pipe2hdu_rdc_qlfy_i, // Pipe RDC qualifier
input logic dbg_rst_n, // Debug reset
`endif // SCR1_DBG_EN
input logic clk, // Pipe clock
// Instruction Memory Interface
output logic pipe2imem_req_o, // IMEM request
output type_scr1_mem_cmd_e pipe2imem_cmd_o, // IMEM command
output logic [`SCR1_IMEM_AWIDTH-1:0] pipe2imem_addr_o, // IMEM address
input logic imem2pipe_req_ack_i, // IMEM request acknowledge
input logic [`SCR1_IMEM_DWIDTH-1:0] imem2pipe_rdata_i, // IMEM read data
input type_scr1_mem_resp_e imem2pipe_resp_i, // IMEM response
// Data Memory Interface
output logic pipe2dmem_req_o, // DMEM request
output type_scr1_mem_cmd_e pipe2dmem_cmd_o, // DMEM command
output type_scr1_mem_width_e pipe2dmem_width_o, // DMEM data width
output logic [`SCR1_DMEM_AWIDTH-1:0] pipe2dmem_addr_o, // DMEM address
output logic [`SCR1_DMEM_DWIDTH-1:0] pipe2dmem_wdata_o, // DMEM write data
input logic dmem2pipe_req_ack_i, // DMEM request acknowledge
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2pipe_rdata_i, // DMEM read data
input type_scr1_mem_resp_e dmem2pipe_resp_i, // DMEM response
`ifdef SCR1_DBG_EN
// Debug interface:
input logic dbg_en, // 1 - debug operations enabled
// DM <-> Pipeline: HART Run Control i/f
input logic dm2pipe_active_i, // Debug Module active flag
input logic dm2pipe_cmd_req_i, // Request from Debug Module
input type_scr1_hdu_dbgstates_e dm2pipe_cmd_i, // Command from Debug Module
output logic pipe2dm_cmd_resp_o, // Response to Debug Module
output logic pipe2dm_cmd_rcode_o, // Debug Module return code: 0 - Ok; 1 - Error
output logic pipe2dm_hart_event_o, // HART event flag
output type_scr1_hdu_hartstatus_s pipe2dm_hart_status_o, // HART status
// DM <-> Pipeline: Program Buffer - HART instruction execution i/f
output logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] pipe2dm_pbuf_addr_o, // Program Buffer address
input logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm2pipe_pbuf_instr_i, // Program Buffer instruction
// DM <-> Pipeline: HART Abstract Data regs i/f
output logic pipe2dm_dreg_req_o, // Abstract Data Register request
output logic pipe2dm_dreg_wr_o, // Abstract Data Register write
output logic [`SCR1_XLEN-1:0] pipe2dm_dreg_wdata_o, // Abstract Data Register write data
input logic dm2pipe_dreg_resp_i, // Abstract Data Register response
input logic dm2pipe_dreg_fail_i, // Abstract Data Register fail - possibly not needed?
input logic [`SCR1_XLEN-1:0] dm2pipe_dreg_rdata_i, // Abstract Data Register read data
// DM <-> Pipeling: PC i/f
output logic [`SCR1_XLEN-1:0] pipe2dm_pc_sample_o, // Current PC for sampling
`endif // SCR1_DBG_EN
// IRQ
`ifdef SCR1_IPIC_EN
input logic [SCR1_IRQ_LINES_NUM-1:0] soc2pipe_irq_lines_i, // External interrupt request lines
`else // SCR1_IPIC_EN
input logic soc2pipe_irq_ext_i, // External interrupt request
`endif // SCR1_IPIC_EN
input logic soc2pipe_irq_soft_i, // Software generated interrupt request
input logic soc2pipe_irq_mtimer_i, // Machine timer interrupt request
// Memory-mapped external timer
input logic [63:0] soc2pipe_mtimer_val_i, // Machine timer value
`ifdef SCR1_CLKCTRL_EN
// CLK_CTRL interface
output logic pipe2clkctl_sleep_req_o, // CLK disable request to CLK gating circuit
output logic pipe2clkctl_wake_req_o, // CLK enable request to CLK gating circuit
input logic clkctl2pipe_clk_alw_on_i, // Not gated CLK
input logic clkctl2pipe_clk_dbgc_i, // CLK for HDU (not gated for now)
input logic clkctl2pipe_clk_en_i, // CLK enabled flag
`endif // SCR1_CLKCTRL_EN
// Fuse
input logic [`SCR1_XLEN-1:0] soc2pipe_fuse_mhartid_i // Fuse MHARTID value
);
//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------
// Pipeline control
logic [`SCR1_XLEN-1:0] curr_pc; // Current PC
logic [`SCR1_XLEN-1:0] next_pc; // Is written to MEPC on interrupt trap
logic new_pc_req; // New PC request (jumps, branches, traps etc)
logic [`SCR1_XLEN-1:0] new_pc; // New PC
logic stop_fetch; // Stop IFU
logic exu_exc_req; // Exception request
logic brkpt; // Breakpoint (sw) on current instruction
logic exu_init_pc; // Reset exit
logic wfi_run2halt; // Transition to WFI halted state
logic instret; // Instruction retirement (with or without exception)
`ifndef SCR1_CSR_REDUCED_CNT
logic instret_nexc; // Instruction retirement (without exception)
`endif // SCR1_CSR_REDUCED_CNT
`ifdef SCR1_IPIC_EN
logic ipic2csr_irq; // IRQ request from IPIC
`endif // SCR1_IPIC_EN
`ifdef SCR1_TDU_EN
`ifdef SCR1_DBG_EN
logic brkpt_hw; // Hardware breakpoint on current instruction
`endif // SCR1_DBG_EN
`endif // SCR1_TDU_EN
`ifdef SCR1_CLKCTRL_EN
logic imem_txns_pending; // There are pending imem transactions
logic wfi_halted; // WFI halted state
`endif // SCR1_CLKCTRL_EN
// IFU <-> IDU
logic ifu2idu_vd; // IFU request
logic [`SCR1_IMEM_DWIDTH-1:0] ifu2idu_instr; // IFU instruction
logic ifu2idu_imem_err; // IFU instruction access fault
logic ifu2idu_err_rvi_hi; // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
logic idu2ifu_rdy; // IDU ready for new data
// IDU <-> EXU
logic idu2exu_req; // IDU request
type_scr1_exu_cmd_s idu2exu_cmd; // IDU command (see scr1_riscv_isa_decoding.svh)
logic idu2exu_use_rs1; // Instruction uses rs1
logic idu2exu_use_rs2; // Instruction uses rs2
`ifndef SCR1_NO_EXE_STAGE
logic idu2exu_use_rd; // Instruction uses rd
logic idu2exu_use_imm; // Instruction uses immediate
`endif // SCR1_NO_EXE_STAGE
logic exu2idu_rdy; // EXU ready for new data
// EXU <-> MPRF
logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs1_addr; // MPRF rs1 read address
logic [`SCR1_XLEN-1:0] mprf2exu_rs1_data; // MPRF rs1 read data
logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rs2_addr; // MPRF rs2 read address
logic [`SCR1_XLEN-1:0] mprf2exu_rs2_data; // MPRF rs2 read data
logic exu2mprf_w_req; // MPRF write request
logic [`SCR1_MPRF_AWIDTH-1:0] exu2mprf_rd_addr; // MPRF rd write address
logic [`SCR1_XLEN-1:0] exu2mprf_rd_data; // MPRF rd write data
// EXU <-> CSR
logic [SCR1_CSR_ADDR_WIDTH-1:0] exu2csr_rw_addr; // CSR read/write address
logic exu2csr_r_req; // CSR read request
logic [`SCR1_XLEN-1:0] csr2exu_r_data; // CSR read data
logic exu2csr_w_req; // CSR write request
type_scr1_csr_cmd_sel_e exu2csr_w_cmd; // CSR write command
logic [`SCR1_XLEN-1:0] exu2csr_w_data; // CSR write data
logic csr2exu_rw_exc; // CSR read/write access exception
// EXU <-> CSR event interface
logic exu2csr_take_irq; // Take IRQ trap
logic exu2csr_take_exc; // Take exception trap
logic exu2csr_mret_update; // MRET update CSR
logic exu2csr_mret_instr; // MRET instruction
type_scr1_exc_code_e exu2csr_exc_code; // Exception code (see scr1_arch_types.svh)
logic [`SCR1_XLEN-1:0] exu2csr_trap_val; // Trap value
logic [`SCR1_XLEN-1:0] csr2exu_new_pc; // Exception/IRQ/MRET new PC
logic csr2exu_irq; // IRQ request
logic csr2exu_ip_ie; // Some IRQ pending and locally enabled
logic csr2exu_mstatus_mie_up; // MSTATUS or MIE update in the current cycle
`ifdef SCR1_IPIC_EN
// CSR <-> IPIC
logic csr2ipic_r_req; // IPIC read request
logic csr2ipic_w_req; // IPIC write request
logic [2:0] csr2ipic_addr; // IPIC address
logic [`SCR1_XLEN-1:0] csr2ipic_wdata; // IPIC write data
logic [`SCR1_XLEN-1:0] ipic2csr_rdata; // IPIC read data
`endif // SCR1_IPIC_EN
`ifdef SCR1_TDU_EN
// CSR <-> TDU
logic csr2tdu_req; // Request to TDU
type_scr1_csr_cmd_sel_e csr2tdu_cmd; // TDU command
logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr; // TDU address
logic [`SCR1_XLEN-1:0] csr2tdu_wdata; // TDU write data
logic [`SCR1_XLEN-1:0] tdu2csr_rdata; // TDU read data
type_scr1_csr_resp_e tdu2csr_resp; // TDU response
`ifdef SCR1_DBG_EN
// Qualified TDU input signals from pipe_rst_n
// reset domain:
logic csr2tdu_req_qlfy; // Request to TDU
`endif // SCR1_DBG_EN
// EXU/LSU <-> TDU
type_scr1_brkm_instr_mon_s exu2tdu_i_mon; // Instruction monitor
type_scr1_brkm_lsu_mon_s lsu2tdu_d_mon; // Data monitor
logic [SCR1_TDU_ALLTRIG_NUM-1:0] tdu2exu_i_match; // Instruction breakpoint(s) match
logic [SCR1_TDU_MTRIG_NUM-1:0] tdu2lsu_d_match; // Data breakpoint(s) match
logic tdu2exu_i_x_req; // Instruction breakpoint exception
logic tdu2lsu_i_x_req; // Instruction breakpoint exception
logic tdu2lsu_d_x_req; // Data breakpoint exception
logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_bp_retire; // Instruction with breakpoint flag retire
`ifdef SCR1_DBG_EN
// Qualified TDU input signals from pipe_rst_n
// reset domain:
type_scr1_brkm_instr_mon_s exu2tdu_i_mon_qlfy; // Instruction monitor
type_scr1_brkm_lsu_mon_s lsu2tdu_d_mon_qlfy; // Data monitor
logic [SCR1_TDU_ALLTRIG_NUM-1:0] exu2tdu_bp_retire_qlfy; // Instruction with breakpoint flag retire
`endif // SCR1_DBG_EN
`endif // SCR1_TDU_EN
`ifdef SCR1_DBG_EN
// Debug signals:
logic fetch_pbuf; // Fetch instructions provided by Program Buffer (via HDU)
logic csr2hdu_req; // Request to HDU
type_scr1_csr_cmd_sel_e csr2hdu_cmd; // HDU command
logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr; // HDU address
logic [`SCR1_XLEN-1:0] csr2hdu_wdata; // HDU write data
logic [`SCR1_XLEN-1:0] hdu2csr_rdata; // HDU read data
type_scr1_csr_resp_e hdu2csr_resp; // HDU response
// Qualified HDU input signals from pipe_rst_n
// reset domain:
logic csr2hdu_req_qlfy; // Request to HDU
logic hwbrk_dsbl; // Disables TDU
logic hdu_hwbrk_dsbl; // Disables TDU
logic tdu2hdu_dmode_req; // TDU requests transition to debug mode
logic exu_no_commit; // Forbid instruction commitment
logic exu_irq_dsbl; // Disable IRQ
logic exu_pc_advmt_dsbl; // Forbid PC advancement
logic exu_dmode_sstep_en; // Enable single-step
logic dbg_halted; // Debug halted state
logic dbg_run2halt; // Transition to debug halted state
logic dbg_halt2run; // Transition to run state
logic dbg_run_start; // First cycle of run state
logic [`SCR1_XLEN-1:0] dbg_new_pc; // New PC as starting point for HART Resume
logic ifu2hdu_pbuf_rdy;
logic hdu2ifu_pbuf_vd;
logic hdu2ifu_pbuf_err;
logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] hdu2ifu_pbuf_instr;
// Qualified HDU input signals from pipe_rst_n reset domain:
logic ifu2hdu_pbuf_rdy_qlfy;
logic exu_busy_qlfy;
logic instret_qlfy;
logic exu_init_pc_qlfy;
logic exu_exc_req_qlfy;
logic brkpt_qlfy;
`endif // SCR1_DBG_EN
logic exu_busy;
`ifndef SCR1_CLKCTRL_EN
logic pipe2clkctl_wake_req_o;
`endif // SCR1_CLKCTRL_EN
//-------------------------------------------------------------------------------
// Pipeline logic
//-------------------------------------------------------------------------------
assign stop_fetch = wfi_run2halt
`ifdef SCR1_DBG_EN
| fetch_pbuf
`endif // SCR1_DBG_EN
;
`ifdef SCR1_CLKCTRL_EN
assign pipe2clkctl_sleep_req_o = wfi_halted & ~imem_txns_pending;
assign pipe2clkctl_wake_req_o = csr2exu_ip_ie
`ifdef SCR1_DBG_EN
| dm2pipe_active_i
`endif // SCR1_DBG_EN
;
`endif // SCR1_CLKCTRL_EN
`ifdef SCR1_DBG_EN
assign pipe2dm_pc_sample_o = curr_pc;
`endif // SCR1_DBG_EN
//-------------------------------------------------------------------------------
// Instruction fetch unit
//-------------------------------------------------------------------------------
scr1_pipe_ifu i_pipe_ifu (
.rst_n (pipe_rst_n ),
.clk (clk ),
// Instruction memory interface
.imem2ifu_req_ack_i (imem2pipe_req_ack_i),
.ifu2imem_req_o (pipe2imem_req_o ),
.ifu2imem_cmd_o (pipe2imem_cmd_o ),
.ifu2imem_addr_o (pipe2imem_addr_o ),
.imem2ifu_rdata_i (imem2pipe_rdata_i ),
.imem2ifu_resp_i (imem2pipe_resp_i ),
// New PC interface
.exu2ifu_pc_new_req_i (new_pc_req ),
.exu2ifu_pc_new_i (new_pc ),
.pipe2ifu_stop_fetch_i (stop_fetch ),
`ifdef SCR1_DBG_EN
// IFU <-> HDU Program Buffer interface
.hdu2ifu_pbuf_fetch_i (fetch_pbuf ),
.ifu2hdu_pbuf_rdy_o (ifu2hdu_pbuf_rdy ),
.hdu2ifu_pbuf_vd_i (hdu2ifu_pbuf_vd ),
.hdu2ifu_pbuf_err_i (hdu2ifu_pbuf_err ),
.hdu2ifu_pbuf_instr_i (hdu2ifu_pbuf_instr ),
`endif // SCR1_DBG_EN
`ifdef SCR1_CLKCTRL_EN
.ifu2pipe_imem_txns_pnd_o (imem_txns_pending ),
`endif // SCR1_CLKCTRL_EN
// IFU <-> IDU interface
.idu2ifu_rdy_i (idu2ifu_rdy ),
.ifu2idu_instr_o (ifu2idu_instr ),
.ifu2idu_imem_err_o (ifu2idu_imem_err ),
.ifu2idu_err_rvi_hi_o (ifu2idu_err_rvi_hi ),
.ifu2idu_vd_o (ifu2idu_vd )
);
//-------------------------------------------------------------------------------
// Instruction decode unit
//-------------------------------------------------------------------------------
scr1_pipe_idu i_pipe_idu (
`ifdef SCR1_TRGT_SIMULATION
.rst_n (pipe_rst_n ),
.clk (clk ),
`endif // SCR1_TRGT_SIMULATION
.idu2ifu_rdy_o (idu2ifu_rdy ),
.ifu2idu_instr_i (ifu2idu_instr ),
.ifu2idu_imem_err_i (ifu2idu_imem_err ),
.ifu2idu_err_rvi_hi_i (ifu2idu_err_rvi_hi),
.ifu2idu_vd_i (ifu2idu_vd ),
.idu2exu_req_o (idu2exu_req ),
.idu2exu_cmd_o (idu2exu_cmd ),
.idu2exu_use_rs1_o (idu2exu_use_rs1 ),
.idu2exu_use_rs2_o (idu2exu_use_rs2 ),
`ifndef SCR1_NO_EXE_STAGE
.idu2exu_use_rd_o (idu2exu_use_rd ),
.idu2exu_use_imm_o (idu2exu_use_imm ),
`endif // SCR1_NO_EXE_STAGE
.exu2idu_rdy_i (exu2idu_rdy )
);
//-------------------------------------------------------------------------------
// Execution unit
//-------------------------------------------------------------------------------
scr1_pipe_exu i_pipe_exu (
.rst_n (pipe_rst_n ),
.clk (clk ),
`ifdef SCR1_CLKCTRL_EN
.clk_alw_on (clkctl2pipe_clk_alw_on_i),
.clk_pipe_en (clkctl2pipe_clk_en_i),
`endif // SCR1_CLKCTRL_EN
// IDU <-> EXU interface
.idu2exu_req_i (idu2exu_req ),
.exu2idu_rdy_o (exu2idu_rdy ),
.idu2exu_cmd_i (idu2exu_cmd ),
.idu2exu_use_rs1_i (idu2exu_use_rs1 ),
.idu2exu_use_rs2_i (idu2exu_use_rs2 ),
`ifndef SCR1_NO_EXE_STAGE
.idu2exu_use_rd_i (idu2exu_use_rd ),
.idu2exu_use_imm_i (idu2exu_use_imm ),
`endif // SCR1_NO_EXE_STAGE
// EXU <-> MPRF interface
.exu2mprf_rs1_addr_o (exu2mprf_rs1_addr ),
.mprf2exu_rs1_data_i (mprf2exu_rs1_data ),
.exu2mprf_rs2_addr_o (exu2mprf_rs2_addr ),
.mprf2exu_rs2_data_i (mprf2exu_rs2_data ),
.exu2mprf_w_req_o (exu2mprf_w_req ),
.exu2mprf_rd_addr_o (exu2mprf_rd_addr ),
.exu2mprf_rd_data_o (exu2mprf_rd_data ),
// EXU <-> CSR read/write interface
.exu2csr_rw_addr_o (exu2csr_rw_addr ),
.exu2csr_r_req_o (exu2csr_r_req ),
.csr2exu_r_data_i (csr2exu_r_data ),
.exu2csr_w_req_o (exu2csr_w_req ),
.exu2csr_w_cmd_o (exu2csr_w_cmd ),
.exu2csr_w_data_o (exu2csr_w_data ),
.csr2exu_rw_exc_i (csr2exu_rw_exc ),
// EXU <-> CSR event interface
.exu2csr_take_irq_o (exu2csr_take_irq ),
.exu2csr_take_exc_o (exu2csr_take_exc ),
.exu2csr_mret_update_o (exu2csr_mret_update ),
.exu2csr_mret_instr_o (exu2csr_mret_instr ),
.exu2csr_exc_code_o (exu2csr_exc_code ),
.exu2csr_trap_val_o (exu2csr_trap_val ),
.csr2exu_new_pc_i (csr2exu_new_pc ),
.csr2exu_irq_i (csr2exu_irq ),
.csr2exu_ip_ie_i (csr2exu_ip_ie ),
.csr2exu_mstatus_mie_up_i (csr2exu_mstatus_mie_up ),
// EXU <-> DMEM interface
.exu2dmem_req_o (pipe2dmem_req_o ),
.exu2dmem_cmd_o (pipe2dmem_cmd_o ),
.exu2dmem_width_o (pipe2dmem_width_o ),
.exu2dmem_addr_o (pipe2dmem_addr_o ),
.exu2dmem_wdata_o (pipe2dmem_wdata_o ),
.dmem2exu_req_ack_i (dmem2pipe_req_ack_i ),
.dmem2exu_rdata_i (dmem2pipe_rdata_i ),
.dmem2exu_resp_i (dmem2pipe_resp_i ),
`ifdef SCR1_DBG_EN
// EXU <-> HDU interface
.hdu2exu_no_commit_i (exu_no_commit ),
.hdu2exu_irq_dsbl_i (exu_irq_dsbl ),
.hdu2exu_pc_advmt_dsbl_i (exu_pc_advmt_dsbl ),
.hdu2exu_dmode_sstep_en_i (exu_dmode_sstep_en ),
.hdu2exu_pbuf_fetch_i (fetch_pbuf ),
.hdu2exu_dbg_halted_i (dbg_halted ),
.hdu2exu_dbg_run2halt_i (dbg_run2halt ),
.hdu2exu_dbg_halt2run_i (dbg_halt2run ),
.hdu2exu_dbg_run_start_i (dbg_run_start ),
.hdu2exu_dbg_new_pc_i (dbg_new_pc ),
`endif // SCR1_DBG_EN
`ifdef SCR1_TDU_EN
// EXU <-> TDU interface
.exu2tdu_imon_o (exu2tdu_i_mon ),
.tdu2exu_ibrkpt_match_i (tdu2exu_i_match ),
.tdu2exu_ibrkpt_exc_req_i (tdu2exu_i_x_req ),
.lsu2tdu_dmon_o (lsu2tdu_d_mon ),
.tdu2lsu_ibrkpt_exc_req_i (tdu2lsu_i_x_req ),
.tdu2lsu_dbrkpt_match_i (tdu2lsu_d_match ),
.tdu2lsu_dbrkpt_exc_req_i (tdu2lsu_d_x_req ),
.exu2tdu_ibrkpt_ret_o (exu2tdu_bp_retire ),
`ifdef SCR1_DBG_EN
.exu2hdu_ibrkpt_hw_o (brkpt_hw ),
`endif // SCR1_DBG_EN
`endif // SCR1_TDU_EN
// EXU control
.exu2pipe_exc_req_o (exu_exc_req ),
.exu2pipe_brkpt_o (brkpt ),
.exu2pipe_init_pc_o (exu_init_pc ),
.exu2pipe_wfi_run2halt_o (wfi_run2halt ),
.exu2pipe_instret_o (instret ),
`ifndef SCR1_CSR_REDUCED_CNT
.exu2csr_instret_no_exc_o (instret_nexc ),
`endif // SCR1_CSR_REDUCED_CNT
.exu2pipe_exu_busy_o (exu_busy ),
// PC interface
`ifdef SCR1_CLKCTRL_EN
.exu2pipe_wfi_halted_o (wfi_halted ),
`endif // SCR1_CLKCTRL_EN
.exu2pipe_pc_curr_o (curr_pc ),
.exu2csr_pc_next_o (next_pc ),
.exu2ifu_pc_new_req_o (new_pc_req ),
.exu2ifu_pc_new_o (new_pc )
);
//-------------------------------------------------------------------------------
// Multi-port register file
//-------------------------------------------------------------------------------
scr1_pipe_mprf i_pipe_mprf (
`ifdef SCR1_MPRF_RST_EN
.rst_n (pipe_rst_n ),
`endif // SCR1_MPRF_RST_EN
.clk (clk ),
// EXU <-> MPRF interface
.exu2mprf_rs1_addr_i (exu2mprf_rs1_addr),
.mprf2exu_rs1_data_o (mprf2exu_rs1_data),
.exu2mprf_rs2_addr_i (exu2mprf_rs2_addr),
.mprf2exu_rs2_data_o (mprf2exu_rs2_data),
.exu2mprf_w_req_i (exu2mprf_w_req ),
.exu2mprf_rd_addr_i (exu2mprf_rd_addr ),
.exu2mprf_rd_data_i (exu2mprf_rd_data )
);
//-------------------------------------------------------------------------------
// Control and status registers
//-------------------------------------------------------------------------------
scr1_pipe_csr i_pipe_csr (
.rst_n (pipe_rst_n ),
.clk (clk ),
`ifndef SCR1_CSR_REDUCED_CNT
`ifdef SCR1_CLKCTRL_EN
.clk_alw_on (clkctl2pipe_clk_alw_on_i),
`endif // SCR1_CLKCTRL_EN
`endif // SCR1_CSR_REDUCED_CNT
// EXU <-> CSR read/write interface
.exu2csr_r_req_i (exu2csr_r_req ),
.exu2csr_rw_addr_i (exu2csr_rw_addr ),
.csr2exu_r_data_o (csr2exu_r_data ),
.exu2csr_w_req_i (exu2csr_w_req ),
.exu2csr_w_cmd_i (exu2csr_w_cmd ),
.exu2csr_w_data_i (exu2csr_w_data ),
.csr2exu_rw_exc_o (csr2exu_rw_exc ),
// EXU <-> CSR event interface
.exu2csr_take_irq_i (exu2csr_take_irq ),
.exu2csr_take_exc_i (exu2csr_take_exc ),
.exu2csr_mret_update_i (exu2csr_mret_update ),
.exu2csr_mret_instr_i (exu2csr_mret_instr ),
.exu2csr_exc_code_i (exu2csr_exc_code ),
.exu2csr_trap_val_i (exu2csr_trap_val ),
.csr2exu_new_pc_o (csr2exu_new_pc ),
.csr2exu_irq_o (csr2exu_irq ),
.csr2exu_ip_ie_o (csr2exu_ip_ie ),
.csr2exu_mstatus_mie_up_o (csr2exu_mstatus_mie_up ),
`ifdef SCR1_IPIC_EN
// CSR <-> IPIC interface
.csr2ipic_r_req_o (csr2ipic_r_req ),
.csr2ipic_w_req_o (csr2ipic_w_req ),
.csr2ipic_addr_o (csr2ipic_addr ),
.csr2ipic_wdata_o (csr2ipic_wdata ),
.ipic2csr_rdata_i (ipic2csr_rdata ),
`endif // SCR1_IPIC_EN
// CSR <-> PC interface
.exu2csr_pc_curr_i (curr_pc ),
.exu2csr_pc_next_i (next_pc ),
`ifndef SCR1_CSR_REDUCED_CNT
.exu2csr_instret_no_exc_i (instret_nexc ),
`endif // SCR1_CSR_REDUCED_CNT
// IRQ
`ifdef SCR1_IPIC_EN
.soc2csr_irq_ext_i (ipic2csr_irq ),
`else // SCR1_IPIC_EN
.soc2csr_irq_ext_i (soc2pipe_irq_ext_i ),
`endif // SCR1_IPIC_EN
.soc2csr_irq_soft_i (soc2pipe_irq_soft_i ),
.soc2csr_irq_mtimer_i (soc2pipe_irq_mtimer_i ),
// Memory-mapped external timer
.soc2csr_mtimer_val_i (soc2pipe_mtimer_val_i ),
`ifdef SCR1_DBG_EN
// CSR <-> HDU interface
.csr2hdu_req_o (csr2hdu_req ),
.csr2hdu_cmd_o (csr2hdu_cmd ),
.csr2hdu_addr_o (csr2hdu_addr ),
.csr2hdu_wdata_o (csr2hdu_wdata ),
.hdu2csr_rdata_i (hdu2csr_rdata ),
.hdu2csr_resp_i (hdu2csr_resp ),
.hdu2csr_no_commit_i (exu_no_commit ),
`endif // SCR1_DBG_EN
`ifdef SCR1_TDU_EN
// CSR <-> TDU interface
.csr2tdu_req_o (csr2tdu_req ),
.csr2tdu_cmd_o (csr2tdu_cmd ),
.csr2tdu_addr_o (csr2tdu_addr ),
.csr2tdu_wdata_o (csr2tdu_wdata ),
.tdu2csr_rdata_i (tdu2csr_rdata ),
.tdu2csr_resp_i (tdu2csr_resp ),
`endif // SCR1_TDU_EN
.soc2csr_fuse_mhartid_i (soc2pipe_fuse_mhartid_i )
);
//-------------------------------------------------------------------------------
// Integrated programmable interrupt controller
//-------------------------------------------------------------------------------
`ifdef SCR1_IPIC_EN
scr1_ipic i_pipe_ipic (
.rst_n (pipe_rst_n ),
`ifdef SCR1_CLKCTRL_EN
.clk (clkctl2pipe_clk_alw_on_i),
`else // SCR1_CLKCTRL_EN
.clk (clk ),
`endif // SCR1_CLKCTRL_EN
.soc2ipic_irq_lines_i (soc2pipe_irq_lines_i ),
.csr2ipic_r_req_i (csr2ipic_r_req ),
.csr2ipic_w_req_i (csr2ipic_w_req ),
.csr2ipic_addr_i (csr2ipic_addr ),
.csr2ipic_wdata_i (csr2ipic_wdata ),
.ipic2csr_rdata_o (ipic2csr_rdata ),
.ipic2csr_irq_m_req_o (ipic2csr_irq )
);
`endif // SCR1_IPIC_EN
//-------------------------------------------------------------------------------
// Breakpoint module
//-------------------------------------------------------------------------------
`ifdef SCR1_TDU_EN
scr1_pipe_tdu i_pipe_tdu (
// Common signals
`ifdef SCR1_DBG_EN
.rst_n (dbg_rst_n ),
`else
.rst_n (pipe_rst_n ),
`endif // SCR1_DBG_EN
.clk (clk ),
.clk_en (1'b1 ),
`ifdef SCR1_DBG_EN
.tdu_dsbl_i (hwbrk_dsbl ),
`else // SCR1_DBG_EN
.tdu_dsbl_i (1'b0 ),
`endif // SCR1_DBG_EN
// TDU <-> CSR interface
`ifdef SCR1_DBG_EN
.csr2tdu_req_i (csr2tdu_req_qlfy ),
.csr2tdu_cmd_i (csr2tdu_cmd ),
.csr2tdu_addr_i (csr2tdu_addr ),
.csr2tdu_wdata_i (csr2tdu_wdata ),
`else // SCR1_DBG_EN
.csr2tdu_req_i (csr2tdu_req ),
.csr2tdu_cmd_i (csr2tdu_cmd ),
.csr2tdu_addr_i (csr2tdu_addr ),
.csr2tdu_wdata_i (csr2tdu_wdata ),
`endif // SCR1_DBG_EN
.tdu2csr_rdata_o (tdu2csr_rdata ),
.tdu2csr_resp_o (tdu2csr_resp ),
// TDU <-> EXU interface
`ifdef SCR1_DBG_EN
.exu2tdu_imon_i (exu2tdu_i_mon_qlfy ),
`else // SCR1_DBG_EN
.exu2tdu_imon_i (exu2tdu_i_mon ),
`endif // SCR1_DBG_EN
.tdu2exu_ibrkpt_match_o (tdu2exu_i_match ),
.tdu2exu_ibrkpt_exc_req_o (tdu2exu_i_x_req ),
`ifdef SCR1_DBG_EN
.exu2tdu_bp_retire_i (exu2tdu_bp_retire_qlfy),
`else // SCR1_DBG_EN
.exu2tdu_bp_retire_i (exu2tdu_bp_retire ),
`endif // SCR1_DBG_EN
// TDU <-> LSU interface
.tdu2lsu_ibrkpt_exc_req_o (tdu2lsu_i_x_req ),
`ifdef SCR1_DBG_EN
.lsu2tdu_dmon_i (lsu2tdu_d_mon_qlfy ),
`else // SCR1_DBG_EN
.lsu2tdu_dmon_i (lsu2tdu_d_mon ),
`endif // SCR1_DBG_EN
.tdu2lsu_dbrkpt_match_o (tdu2lsu_d_match ),
.tdu2lsu_dbrkpt_exc_req_o (tdu2lsu_d_x_req ),
// EPU I/F
`ifdef SCR1_DBG_EN
.tdu2hdu_dmode_req_o (tdu2hdu_dmode_req )
`else // SCR1_DBG_EN
.tdu2hdu_dmode_req_o ( )
`endif // SCR1_DBG_EN
);
`ifdef SCR1_DBG_EN
assign hwbrk_dsbl = (~dbg_en) | hdu_hwbrk_dsbl;
//
assign csr2tdu_req_qlfy = dbg_en & csr2tdu_req & pipe2hdu_rdc_qlfy_i;
//
assign exu2tdu_i_mon_qlfy.vd = exu2tdu_i_mon.vd & pipe2hdu_rdc_qlfy_i;
assign exu2tdu_i_mon_qlfy.req = exu2tdu_i_mon.req;
assign exu2tdu_i_mon_qlfy.addr = exu2tdu_i_mon.addr;
assign lsu2tdu_d_mon_qlfy.vd = lsu2tdu_d_mon.vd & pipe2hdu_rdc_qlfy_i;
assign lsu2tdu_d_mon_qlfy.load = lsu2tdu_d_mon.load;
assign lsu2tdu_d_mon_qlfy.store = lsu2tdu_d_mon.store;
assign lsu2tdu_d_mon_qlfy.addr = lsu2tdu_d_mon.addr;
assign exu2tdu_bp_retire_qlfy = exu2tdu_bp_retire & {$bits(exu2tdu_bp_retire){pipe2hdu_rdc_qlfy_i}};
`endif // SCR1_DBG_EN
`endif // SCR1_TDU_EN
//-------------------------------------------------------------------------------
// HART Debug Unit (HDU)
//-------------------------------------------------------------------------------
`ifdef SCR1_DBG_EN
scr1_pipe_hdu i_pipe_hdu (
// Common signals
.rst_n (dbg_rst_n ),
.clk_en (dm2pipe_active_i ),
`ifdef SCR1_CLKCTRL_EN
.clk_pipe_en (clkctl2pipe_clk_en_i ),
.clk (clkctl2pipe_clk_dbgc_i),
`else
.clk (clk ),
`endif // SCR1_CLKCTRL_EN
// Control/status registers i/f
.csr2hdu_req_i (csr2hdu_req_qlfy ),
.csr2hdu_cmd_i (csr2hdu_cmd ),
.csr2hdu_addr_i (csr2hdu_addr ),
.csr2hdu_wdata_i (csr2hdu_wdata ),
.hdu2csr_resp_o (hdu2csr_resp ),
.hdu2csr_rdata_o (hdu2csr_rdata ),
// HART Run Control i/f
.pipe2hdu_rdc_qlfy_i (pipe2hdu_rdc_qlfy_i ),
.dm2hdu_cmd_req_i (dm2pipe_cmd_req_i ),
.dm2hdu_cmd_i (dm2pipe_cmd_i ),
.hdu2dm_cmd_resp_o (pipe2dm_cmd_resp_o ),
.hdu2dm_cmd_rcode_o (pipe2dm_cmd_rcode_o ),
.hdu2dm_hart_event_o (pipe2dm_hart_event_o ),
.hdu2dm_hart_status_o (pipe2dm_hart_status_o ),
// Program Buffer - HART instruction execution i/f
.hdu2dm_pbuf_addr_o (pipe2dm_pbuf_addr_o ),
.dm2hdu_pbuf_instr_i (dm2pipe_pbuf_instr_i ),
// HART Abstract Data regs i/f
.hdu2dm_dreg_req_o (pipe2dm_dreg_req_o ),
.hdu2dm_dreg_wr_o (pipe2dm_dreg_wr_o ),
.hdu2dm_dreg_wdata_o (pipe2dm_dreg_wdata_o ),
.dm2hdu_dreg_resp_i (dm2pipe_dreg_resp_i ),
.dm2hdu_dreg_fail_i (dm2pipe_dreg_fail_i ),
.dm2hdu_dreg_rdata_i (dm2pipe_dreg_rdata_i ),
//
`ifdef SCR1_TDU_EN
// HDU <-> TDU interface
.hdu2tdu_hwbrk_dsbl_o (hdu_hwbrk_dsbl ),
.tdu2hdu_dmode_req_i (tdu2hdu_dmode_req ),
.exu2hdu_ibrkpt_hw_i (brkpt_hw ),
`endif // SCR1_TDU_EN
// HART Run Status
.pipe2hdu_exu_busy_i (exu_busy_qlfy ),
.pipe2hdu_instret_i (instret_qlfy ),
.pipe2hdu_init_pc_i (exu_init_pc_qlfy ),
// HART Halt Status
.pipe2hdu_exu_exc_req_i (exu_exc_req_qlfy ),
.pipe2hdu_brkpt_i (brkpt_qlfy ),
// HART Run Control
.hdu2exu_pbuf_fetch_o (fetch_pbuf ),
.hdu2exu_no_commit_o (exu_no_commit ),
.hdu2exu_irq_dsbl_o (exu_irq_dsbl ),
.hdu2exu_pc_advmt_dsbl_o (exu_pc_advmt_dsbl ),
.hdu2exu_dmode_sstep_en_o (exu_dmode_sstep_en ),
// HART state
.hdu2exu_dbg_halted_o (dbg_halted ),
.hdu2exu_dbg_run2halt_o (dbg_run2halt ),
.hdu2exu_dbg_halt2run_o (dbg_halt2run ),
.hdu2exu_dbg_run_start_o (dbg_run_start ),
// PC interface
.pipe2hdu_pc_curr_i (curr_pc ),
.hdu2exu_dbg_new_pc_o (dbg_new_pc ),
// Prgram Buffer Instruction interface
.ifu2hdu_pbuf_instr_rdy_i (ifu2hdu_pbuf_rdy_qlfy ),
.hdu2ifu_pbuf_instr_vd_o (hdu2ifu_pbuf_vd ),
.hdu2ifu_pbuf_instr_err_o (hdu2ifu_pbuf_err ),
.hdu2ifu_pbuf_instr_o (hdu2ifu_pbuf_instr )
);
assign csr2hdu_req_qlfy = csr2hdu_req & dbg_en & pipe2hdu_rdc_qlfy_i;
//
assign exu_busy_qlfy = exu_busy & {$bits(exu_busy){pipe2hdu_rdc_qlfy_i}};
assign instret_qlfy = instret & {$bits(instret){pipe2hdu_rdc_qlfy_i}};
assign exu_init_pc_qlfy = exu_init_pc & {$bits(exu_init_pc){pipe2hdu_rdc_qlfy_i}};
assign exu_exc_req_qlfy = exu_exc_req & {$bits(exu_exc_req){pipe2hdu_rdc_qlfy_i}};
assign brkpt_qlfy = brkpt & {$bits(brkpt){pipe2hdu_rdc_qlfy_i}};
assign ifu2hdu_pbuf_rdy_qlfy = ifu2hdu_pbuf_rdy & {$bits(ifu2hdu_pbuf_rdy){pipe2hdu_rdc_qlfy_i}};
`endif // SCR1_DBG_EN
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Tracelog
//-------------------------------------------------------------------------------
scr1_tracelog i_tracelog (
.rst_n (pipe_rst_n ),
.clk (clk )
`ifdef SCR1_TRACE_LOG_EN
,
.soc2pipe_fuse_mhartid_i (soc2pipe_fuse_mhartid_i ),
// MPRF
.mprf2trace_int_i (i_pipe_mprf.mprf_int ),
.mprf2trace_wr_en_i (i_pipe_mprf.exu2mprf_w_req_i ),
.mprf2trace_wr_addr_i (i_pipe_mprf.exu2mprf_rd_addr_i ),
.mprf2trace_wr_data_i (i_pipe_mprf.exu2mprf_rd_data_i ),
// EXU
.exu2trace_update_pc_en_i (i_pipe_exu.update_pc_en ),
.exu2trace_update_pc_i (i_pipe_exu.update_pc ),
// IFU
.ifu2trace_instr_i (i_pipe_ifu.ifu2idu_instr_o ),
// CSR
.csr2trace_mstatus_mie_i (i_pipe_csr.csr_mstatus_mie_ff ),
.csr2trace_mstatus_mpie_i (i_pipe_csr.csr_mstatus_mpie_ff ),
.csr2trace_mtvec_base_i (i_pipe_csr.csr_mtvec_base ),
.csr2trace_mtvec_mode_i (i_pipe_csr.csr_mtvec_mode ),
.csr2trace_mie_meie_i (i_pipe_csr.csr_mie_meie_ff ),
.csr2trace_mie_mtie_i (i_pipe_csr.csr_mie_mtie_ff ),
.csr2trace_mie_msie_i (i_pipe_csr.csr_mie_msie_ff ),
.csr2trace_mip_meip_i (i_pipe_csr.csr_mip_meip ),
.csr2trace_mip_mtip_i (i_pipe_csr.csr_mip_mtip ),
.csr2trace_mip_msip_i (i_pipe_csr.csr_mip_msip ),
.csr2trace_mepc_i (i_pipe_csr.csr_mepc_ff ),
.csr2trace_mcause_irq_i (i_pipe_csr.csr_mcause_i_ff ),
.csr2trace_mcause_ec_i (i_pipe_csr.csr_mcause_ec_ff ),
.csr2trace_mtval_i (i_pipe_csr.csr_mtval_ff ),
// Events
.csr2trace_e_exc_i (i_pipe_csr.e_exc ),
.csr2trace_e_irq_i (i_pipe_csr.e_irq ),
.pipe2trace_e_wake_i (pipe2clkctl_wake_req_o )
`endif // SCR1_TRACE_LOG_EN
);
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_pipe_top

View File

@@ -0,0 +1,453 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tracelog.sv>
/// @brief Core tracelog module
///
`include "scr1_arch_description.svh"
`include "scr1_arch_types.svh"
`include "scr1_csr.svh"
`ifdef SCR1_TRGT_SIMULATION
module scr1_tracelog (
input logic rst_n, // Tracelog reset
input logic clk // Tracelog clock
`ifdef SCR1_TRACE_LOG_EN
,
input logic [`SCR1_XLEN-1:0] soc2pipe_fuse_mhartid_i, // Fuse MHARTID
// MPRF
`ifdef SCR1_MPRF_RAM
input logic [`SCR1_XLEN-1:0] mprf2trace_int_i [1:`SCR1_MPRF_SIZE-1], // MPRF registers content
`else // SCR1_MPRF_RAM
input type_scr1_mprf_v [1:`SCR1_MPRF_SIZE-1] mprf2trace_int_i, // MPRF registers content
`endif // SCR1_MPRF_RAM
input logic mprf2trace_wr_en_i, // MPRF write enable
input logic [`SCR1_MPRF_AWIDTH-1:0] mprf2trace_wr_addr_i, // MPRF write address
input logic [`SCR1_XLEN-1:0] mprf2trace_wr_data_i, // MPRF write data
// EXU
input logic exu2trace_update_pc_en_i, // PC updated flag
input logic [`SCR1_XLEN-1:0] exu2trace_update_pc_i, // Next PC value
// IFU
input logic [`SCR1_IMEM_DWIDTH-1:0] ifu2trace_instr_i, // Current instruction from IFU stage
// CSR
input logic csr2trace_mstatus_mie_i, // CSR MSTATUS.mie bit
input logic csr2trace_mstatus_mpie_i, // CSR MSTATUS.mpie bit
input logic [`SCR1_XLEN-1:6] csr2trace_mtvec_base_i, // CSR MTVEC.
input logic csr2trace_mtvec_mode_i, // CSR MTVEC.
input logic csr2trace_mie_meie_i, // CSR MIE.meie bit
input logic csr2trace_mie_mtie_i, // CSR MIE.mtie bit
input logic csr2trace_mie_msie_i, // CSR MIE.msie bit
input logic csr2trace_mip_meip_i, // CSR MIP.meip bit
input logic csr2trace_mip_mtip_i, // CSR MIP.mtip bit
input logic csr2trace_mip_msip_i, // CSR MIP.msip bit
`ifdef SCR1_RVC_EXT
input logic [`SCR1_XLEN-1:1] csr2trace_mepc_i, // CSR MEPC register
`else // SCR1_RVC_EXT
input logic [`SCR1_XLEN-1:2] csr2trace_mepc_i, // CSR MEPC register
`endif // SCR1_RVC_EXT
input logic csr2trace_mcause_irq_i, // CSR MCAUSE.interrupt bit
input type_scr1_exc_code_e csr2trace_mcause_ec_i, // CSR MCAUSE.exception_code bit
input logic [`SCR1_XLEN-1:0] csr2trace_mtval_i, // CSR MTVAL register
// Events
input logic csr2trace_e_exc_i, // exception event
input logic csr2trace_e_irq_i, // interrupt event
input logic pipe2trace_e_wake_i // pipe wakeup event
`endif // SCR1_TRACE_LOG_EN
);
//-------------------------------------------------------------------------------
// Local types declaration
//-------------------------------------------------------------------------------
`ifdef SCR1_TRACE_LOG_EN
typedef struct {
logic [`SCR1_XLEN-1:0] INT_00_ZERO ;
logic [`SCR1_XLEN-1:0] INT_01_RA ;
logic [`SCR1_XLEN-1:0] INT_02_SP ;
logic [`SCR1_XLEN-1:0] INT_03_GP ;
logic [`SCR1_XLEN-1:0] INT_04_TP ;
logic [`SCR1_XLEN-1:0] INT_05_T0 ;
logic [`SCR1_XLEN-1:0] INT_06_T1 ;
logic [`SCR1_XLEN-1:0] INT_07_T2 ;
logic [`SCR1_XLEN-1:0] INT_08_S0 ;
logic [`SCR1_XLEN-1:0] INT_09_S1 ;
logic [`SCR1_XLEN-1:0] INT_10_A0 ;
logic [`SCR1_XLEN-1:0] INT_11_A1 ;
logic [`SCR1_XLEN-1:0] INT_12_A2 ;
logic [`SCR1_XLEN-1:0] INT_13_A3 ;
logic [`SCR1_XLEN-1:0] INT_14_A4 ;
logic [`SCR1_XLEN-1:0] INT_15_A5 ;
`ifndef SCR1_RVE_EXT
logic [`SCR1_XLEN-1:0] INT_16_A6 ;
logic [`SCR1_XLEN-1:0] INT_17_A7 ;
logic [`SCR1_XLEN-1:0] INT_18_S2 ;
logic [`SCR1_XLEN-1:0] INT_19_S3 ;
logic [`SCR1_XLEN-1:0] INT_20_S4 ;
logic [`SCR1_XLEN-1:0] INT_21_S5 ;
logic [`SCR1_XLEN-1:0] INT_22_S6 ;
logic [`SCR1_XLEN-1:0] INT_23_S7 ;
logic [`SCR1_XLEN-1:0] INT_24_S8 ;
logic [`SCR1_XLEN-1:0] INT_25_S9 ;
logic [`SCR1_XLEN-1:0] INT_26_S10 ;
logic [`SCR1_XLEN-1:0] INT_27_S11 ;
logic [`SCR1_XLEN-1:0] INT_28_T3 ;
logic [`SCR1_XLEN-1:0] INT_29_T4 ;
logic [`SCR1_XLEN-1:0] INT_30_T5 ;
logic [`SCR1_XLEN-1:0] INT_31_T6 ;
`endif // SCR1_RVE_EXT
} type_scr1_ireg_name_s;
typedef struct packed {
logic [`SCR1_XLEN-1:0] mstatus;
logic [`SCR1_XLEN-1:0] mtvec;
logic [`SCR1_XLEN-1:0] mie;
logic [`SCR1_XLEN-1:0] mip;
logic [`SCR1_XLEN-1:0] mepc;
logic [`SCR1_XLEN-1:0] mcause;
logic [`SCR1_XLEN-1:0] mtval;
} type_scr1_csr_trace_s;
`endif // SCR1_TRACE_LOG_EN
//-------------------------------------------------------------------------------
// Local Signal Declaration
//-------------------------------------------------------------------------------
`ifdef SCR1_TRACE_LOG_EN
type_scr1_ireg_name_s mprf_int_alias;
time current_time;
// Tracelog control signals
logic trace_flag;
logic trace_update;
logic trace_update_r;
byte event_type;
logic [`SCR1_XLEN-1:0] trace_pc;
logic [`SCR1_XLEN-1:0] trace_npc;
logic [`SCR1_IMEM_DWIDTH-1:0] trace_instr;
type_scr1_csr_trace_s csr_trace1;
// File handlers
int unsigned trace_fhandler_core;
// MPRF signals
logic mprf_up;
logic [`SCR1_MPRF_AWIDTH-1:0] mprf_addr;
logic [`SCR1_XLEN-1:0] mprf_wdata;
string hart;
string test_name;
`endif // SCR1_TRACE_LOG_EN
//-------------------------------------------------------------------------------
// Local tasks
//-------------------------------------------------------------------------------
`ifdef SCR1_TRACE_LOG_EN
task trace_write_common;
$fwrite(trace_fhandler_core, "%16d ", current_time);
// $fwrite(trace_fhandler_core, " 0 ");
$fwrite(trace_fhandler_core, " %s ", event_type);
$fwrite(trace_fhandler_core, " %8x ", trace_pc);
$fwrite(trace_fhandler_core, " %8x ", trace_instr);
$fwrite(trace_fhandler_core, " %8x ", trace_npc);
endtask // trace_write_common
task trace_write_int_walias;
case (mprf_addr)
0 : $fwrite(trace_fhandler_core, " x00_zero ");
1 : $fwrite(trace_fhandler_core, " x01_ra ");
2 : $fwrite(trace_fhandler_core, " x02_sp ");
3 : $fwrite(trace_fhandler_core, " x03_gp ");
4 : $fwrite(trace_fhandler_core, " x04_tp ");
5 : $fwrite(trace_fhandler_core, " x05_t0 ");
6 : $fwrite(trace_fhandler_core, " x06_t1 ");
7 : $fwrite(trace_fhandler_core, " x07_t2 ");
8 : $fwrite(trace_fhandler_core, " x08_s0 ");
9 : $fwrite(trace_fhandler_core, " x09_s1 ");
10 : $fwrite(trace_fhandler_core, " x10_a0 ");
11 : $fwrite(trace_fhandler_core, " x11_a1 ");
12 : $fwrite(trace_fhandler_core, " x12_a2 ");
13 : $fwrite(trace_fhandler_core, " x13_a3 ");
14 : $fwrite(trace_fhandler_core, " x14_a4 ");
15 : $fwrite(trace_fhandler_core, " x15_a5 ");
`ifndef SCR1_RVE_EXT
16 : $fwrite(trace_fhandler_core, " x16_a6 ");
17 : $fwrite(trace_fhandler_core, " x17_a7 ");
18 : $fwrite(trace_fhandler_core, " x18_s2 ");
19 : $fwrite(trace_fhandler_core, " x19_s3 ");
20 : $fwrite(trace_fhandler_core, " x20_s4 ");
21 : $fwrite(trace_fhandler_core, " x21_s5 ");
22 : $fwrite(trace_fhandler_core, " x22_s6 ");
23 : $fwrite(trace_fhandler_core, " x23_s7 ");
24 : $fwrite(trace_fhandler_core, " x24_s8 ");
25 : $fwrite(trace_fhandler_core, " x25_s9 ");
26 : $fwrite(trace_fhandler_core, " x26_s10 ");
27 : $fwrite(trace_fhandler_core, " x27_s11 ");
28 : $fwrite(trace_fhandler_core, " x28_t3 ");
29 : $fwrite(trace_fhandler_core, " x29_t4 ");
30 : $fwrite(trace_fhandler_core, " x30_t5 ");
31 : $fwrite(trace_fhandler_core, " x31_t6 ");
`endif // SCR1_RVE_EXT
default: begin
$fwrite(trace_fhandler_core, " xxx ");
end
endcase
endtask
//-------------------------------------------------------------------------------
// MPRF Registers assignment
//-------------------------------------------------------------------------------
assign mprf_int_alias.INT_00_ZERO = '0;
assign mprf_int_alias.INT_01_RA = mprf2trace_int_i[1];
assign mprf_int_alias.INT_02_SP = mprf2trace_int_i[2];
assign mprf_int_alias.INT_03_GP = mprf2trace_int_i[3];
assign mprf_int_alias.INT_04_TP = mprf2trace_int_i[4];
assign mprf_int_alias.INT_05_T0 = mprf2trace_int_i[5];
assign mprf_int_alias.INT_06_T1 = mprf2trace_int_i[6];
assign mprf_int_alias.INT_07_T2 = mprf2trace_int_i[7];
assign mprf_int_alias.INT_08_S0 = mprf2trace_int_i[8];
assign mprf_int_alias.INT_09_S1 = mprf2trace_int_i[9];
assign mprf_int_alias.INT_10_A0 = mprf2trace_int_i[10];
assign mprf_int_alias.INT_11_A1 = mprf2trace_int_i[11];
assign mprf_int_alias.INT_12_A2 = mprf2trace_int_i[12];
assign mprf_int_alias.INT_13_A3 = mprf2trace_int_i[13];
assign mprf_int_alias.INT_14_A4 = mprf2trace_int_i[14];
assign mprf_int_alias.INT_15_A5 = mprf2trace_int_i[15];
`ifndef SCR1_RVE_EXT
assign mprf_int_alias.INT_16_A6 = mprf2trace_int_i[16];
assign mprf_int_alias.INT_17_A7 = mprf2trace_int_i[17];
assign mprf_int_alias.INT_18_S2 = mprf2trace_int_i[18];
assign mprf_int_alias.INT_19_S3 = mprf2trace_int_i[19];
assign mprf_int_alias.INT_20_S4 = mprf2trace_int_i[20];
assign mprf_int_alias.INT_21_S5 = mprf2trace_int_i[21];
assign mprf_int_alias.INT_22_S6 = mprf2trace_int_i[22];
assign mprf_int_alias.INT_23_S7 = mprf2trace_int_i[23];
assign mprf_int_alias.INT_24_S8 = mprf2trace_int_i[24];
assign mprf_int_alias.INT_25_S9 = mprf2trace_int_i[25];
assign mprf_int_alias.INT_26_S10 = mprf2trace_int_i[26];
assign mprf_int_alias.INT_27_S11 = mprf2trace_int_i[27];
assign mprf_int_alias.INT_28_T3 = mprf2trace_int_i[28];
assign mprf_int_alias.INT_29_T4 = mprf2trace_int_i[29];
assign mprf_int_alias.INT_30_T5 = mprf2trace_int_i[30];
assign mprf_int_alias.INT_31_T6 = mprf2trace_int_i[31];
`endif // SCR1_RVE_EXT
`endif // SCR1_TRACE_LOG_EN
//-------------------------------------------------------------------------------
// Legacy time counter
//-------------------------------------------------------------------------------
// The counter is left for compatibility with the current UVM environment
int time_cnt;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
time_cnt <= 0;
end else begin
time_cnt <= time_cnt + 1;
end
end
//-------------------------------------------------------------------------------
// Initial part pipeline tracelog
//-------------------------------------------------------------------------------
`ifdef SCR1_TRACE_LOG_EN
// Files opening and writing initial header
initial begin
$timeformat(-9, 0, " ns", 10);
#1 hart.hextoa(soc2pipe_fuse_mhartid_i);
trace_fhandler_core = $fopen({"tracelog_core_", hart, ".log"}, "w");
// Writing initial header
$fwrite(trace_fhandler_core, "# RTL_ID %h\n", SCR1_CSR_MIMPID);
$fwrite(trace_fhandler_core, "#\n");
// $fwrite(trace_fhandler_core, "# R - return from trap:\n");
// $fwrite(trace_fhandler_core, "# 1 - MRET\n");
// $fwrite(trace_fhandler_core, "# 0 - no return\n");
$fwrite(trace_fhandler_core, "# Events:\n");
$fwrite(trace_fhandler_core, "# N - no event\n");
$fwrite(trace_fhandler_core, "# E - exception\n");
$fwrite(trace_fhandler_core, "# I - interrupt\n");
$fwrite(trace_fhandler_core, "# W - wakeup\n");
end
// Core reset logging and header printing
always @(posedge rst_n) begin
$fwrite(trace_fhandler_core, "# =====================================================================================\n");
`ifndef VERILATOR
$fwrite(trace_fhandler_core, "# %16d ns : Core Reset\n", $time());
`else
$fwrite(trace_fhandler_core, "# : Core Reset\n");
`endif
$fwrite(trace_fhandler_core, "# =====================================================================================\n");
$fwrite(trace_fhandler_core, "# Test: %s\n", test_name);
$fwrite(trace_fhandler_core, "# Time ");
// $fwrite(trace_fhandler_core, " R ");
$fwrite(trace_fhandler_core, " Ev ");
$fwrite(trace_fhandler_core, " Curr_PC ");
$fwrite(trace_fhandler_core, " Instr ");
$fwrite(trace_fhandler_core, " Next_PC ");
$fwrite(trace_fhandler_core, " Reg ");
$fwrite(trace_fhandler_core, " Value ");
$fwrite(trace_fhandler_core, "\n");
$fwrite(trace_fhandler_core, "# =====================================================================================\n");
end
//-------------------------------------------------------------------------------
// Common trace part
//-------------------------------------------------------------------------------
assign trace_flag = 1'b1;
assign trace_update = (exu2trace_update_pc_en_i | mprf2trace_wr_en_i) & trace_flag;
always_ff @(posedge clk) begin
if (~rst_n) begin
current_time <= 0;
event_type <= "N";
trace_pc <= 'x;
trace_npc <= 'x;
trace_instr <= 'x;
trace_update_r <= 1'b0;
mprf_up <= '0;
mprf_addr <= '0;
mprf_wdata <= '0;
end else begin
trace_update_r <= trace_update;
if (trace_update) begin
`ifdef VERILATOR
current_time <= time_cnt;
`else
current_time <= $time();
`endif
trace_pc <= trace_npc;
trace_npc <= exu2trace_update_pc_i;
trace_instr <= ifu2trace_instr_i;
if (csr2trace_e_exc_i) begin
// Exception
event_type <= "E";
end
else if (csr2trace_e_irq_i) begin
// IRQ
event_type <= "I";
end
else if (pipe2trace_e_wake_i) begin
// Wake
event_type <= "W";
end
else begin
// No event
event_type <= "N";
end
end
// Write log signals
mprf_up <= mprf2trace_wr_en_i;
mprf_addr <= mprf2trace_wr_en_i ? mprf2trace_wr_addr_i : 'x;
mprf_wdata <= mprf2trace_wr_en_i ? mprf2trace_wr_data_i : 'x;
end
end
//-------------------------------------------------------------------------------
// Core MPRF logging
//-------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
end else begin
if (trace_update_r) begin
trace_write_common();
case (event_type)
"W" : begin
// Wakeup
if (csr_trace1.mip & csr_trace1.mie) begin
$fwrite(trace_fhandler_core, " mip %08x\n", csr_trace1.mip );
trace_write_common();
$fwrite(trace_fhandler_core, " mie %08x", csr_trace1.mie );
end
end
"N" : begin
// Regular
if (mprf_up && mprf_addr != 0) begin
// $fwrite(trace_fhandler_core, " x%2d %08x", mprf_addr, mprf_wdata);
trace_write_int_walias();
$fwrite(trace_fhandler_core, " %08x", mprf_wdata);
end else begin
$fwrite(trace_fhandler_core, " --- --------");
end
end
"R" : begin
// MRET
$fwrite(trace_fhandler_core, " mstatus %08x", csr_trace1.mstatus);
end
"E", "I": begin
// IRQ/Exception
$fwrite(trace_fhandler_core, " mstatus %08x\n", csr_trace1.mstatus);
trace_write_common();
$fwrite(trace_fhandler_core, " mepc %08x\n", csr_trace1.mepc);
trace_write_common();
$fwrite(trace_fhandler_core, " mcause %08x\n", csr_trace1.mcause);
trace_write_common();
$fwrite(trace_fhandler_core, " mtval %08x", csr_trace1.mtval);
end
default : begin
$fwrite(trace_fhandler_core, "\n");
end
endcase
$fwrite(trace_fhandler_core, "\n");
end
end
end
//-------------------------------------------------------------------------------
// Core CSR logging
//-------------------------------------------------------------------------------
always_comb begin
csr_trace1.mtvec = {csr2trace_mtvec_base_i, 4'd0, 2'(csr2trace_mtvec_mode_i)};
csr_trace1.mepc =
`ifdef SCR1_RVC_EXT
{csr2trace_mepc_i, 1'b0};
`else // SCR1_RVC_EXT
{csr2trace_mepc_i, 2'b00};
`endif // SCR1_RVC_EXT
csr_trace1.mcause = {csr2trace_mcause_irq_i, type_scr1_csr_mcause_ec_v'(csr2trace_mcause_ec_i)};
csr_trace1.mtval = csr2trace_mtval_i;
csr_trace1.mstatus = '0;
csr_trace1.mie = '0;
csr_trace1.mip = '0;
csr_trace1.mstatus[SCR1_CSR_MSTATUS_MIE_OFFSET] = csr2trace_mstatus_mie_i;
csr_trace1.mstatus[SCR1_CSR_MSTATUS_MPIE_OFFSET] = csr2trace_mstatus_mpie_i;
csr_trace1.mstatus[SCR1_CSR_MSTATUS_MPP_OFFSET+1:SCR1_CSR_MSTATUS_MPP_OFFSET] = SCR1_CSR_MSTATUS_MPP;
csr_trace1.mie[SCR1_CSR_MIE_MSIE_OFFSET] = csr2trace_mie_msie_i;
csr_trace1.mie[SCR1_CSR_MIE_MTIE_OFFSET] = csr2trace_mie_mtie_i;
csr_trace1.mie[SCR1_CSR_MIE_MEIE_OFFSET] = csr2trace_mie_meie_i;
csr_trace1.mip[SCR1_CSR_MIE_MSIE_OFFSET] = csr2trace_mip_msip_i;
csr_trace1.mip[SCR1_CSR_MIE_MTIE_OFFSET] = csr2trace_mip_mtip_i;
csr_trace1.mip[SCR1_CSR_MIE_MEIE_OFFSET] = csr2trace_mip_meip_i;
end
`endif // SCR1_TRACE_LOG_EN
endmodule : scr1_tracelog
`endif // SCR1_TRGT_SIMULATION

View File

@@ -0,0 +1,32 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_cg.sv>
/// @brief SCR1 clock gate primitive
///
`include "scr1_arch_description.svh"
`ifdef SCR1_CLKCTRL_EN
module scr1_cg (
input logic clk,
input logic clk_en,
input logic test_mode,
output logic clk_out
);
// The code below is a clock gate model for simulation.
// For synthesis, it should be replaced by implementation-specific
// clock gate code.
logic latch_en;
always_latch begin
if (~clk) begin
latch_en <= test_mode | clk_en;
end
end
assign clk_out = latch_en & clk;
endmodule : scr1_cg
`endif // SCR1_CLKCTRL_EN

View File

@@ -0,0 +1,231 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_sync_rstn.sv>
/// @brief Cells for reset handling
///
//--------------------------------------------------------------------
// Reset Buffer Cell
//--------------------------------------------------------------------
module scr1_reset_buf_cell (
input logic rst_n,
input logic clk,
input logic test_mode,
input logic test_rst_n,
input logic reset_n_in,
output logic reset_n_out,
output logic reset_n_status
);
logic reset_n_ff;
logic reset_n_status_ff;
logic rst_n_mux;
assign rst_n_mux = (test_mode == 1'b1) ? test_rst_n : rst_n;
always_ff @(negedge rst_n_mux, posedge clk) begin
if (~rst_n_mux) begin
reset_n_ff <= 1'b0;
end else begin
reset_n_ff <= reset_n_in;
end
end
assign reset_n_out = (test_mode == 1'b1) ? test_rst_n : reset_n_ff;
always_ff @(negedge rst_n_mux, posedge clk) begin
if (~rst_n_mux) begin
reset_n_status_ff <= 1'b0;
end else begin
reset_n_status_ff <= reset_n_in;
end
end
assign reset_n_status = reset_n_status_ff;
endmodule : scr1_reset_buf_cell
//--------------------------------------------------------------------
// Reset CDC Synchronization Cell
//--------------------------------------------------------------------
module scr1_reset_sync_cell #(
parameter int unsigned STAGES_AMOUNT = 2
) (
input logic rst_n,
input logic clk,
input logic test_rst_n,
input logic test_mode,
input logic rst_n_in,
output logic rst_n_out
);
logic [STAGES_AMOUNT-1:0] rst_n_dff;
logic local_rst_n_in;
assign local_rst_n_in = (test_mode == 1'b1) ? test_rst_n : rst_n;
generate
if (STAGES_AMOUNT == 1)
begin : gen_reset_sync_cell_single
always_ff @(negedge local_rst_n_in, posedge clk) begin
if (~local_rst_n_in) begin
rst_n_dff <= 1'b0;
end else begin
rst_n_dff <= rst_n_in;
end
end
end : gen_reset_sync_cell_single
else // STAGES_AMOUNT > 1
begin : gen_reset_sync_cell_multi
always_ff @(negedge local_rst_n_in, posedge clk)
begin
if (~local_rst_n_in) begin
rst_n_dff <= '0;
end else begin
rst_n_dff <= {rst_n_dff[STAGES_AMOUNT-2:0], rst_n_in};
end
end
end : gen_reset_sync_cell_multi
endgenerate
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : rst_n_dff[STAGES_AMOUNT-1];
endmodule : scr1_reset_sync_cell
//--------------------------------------------------------------------
// Data CDC/RDC Synchronization Cell
//--------------------------------------------------------------------
module scr1_data_sync_cell #(
parameter int unsigned STAGES_AMOUNT = 1
) (
input logic rst_n,
input logic clk,
input logic data_in,
output logic data_out
);
logic [STAGES_AMOUNT-1:0] data_dff;
generate
if (STAGES_AMOUNT == 1)
begin : gen_data_sync_cell_single
always_ff @(negedge rst_n, posedge clk)
begin
if (~rst_n) begin
data_dff <= 1'b0;
end else begin
data_dff <= data_in;
end
end
end : gen_data_sync_cell_single
else // STAGES_AMOUNT > 1
begin : gen_data_sync_cell_multi
always_ff @(negedge rst_n, posedge clk)
begin
if (~rst_n) begin
data_dff <= '0;
end else begin
data_dff <= {data_dff[STAGES_AMOUNT-2:0], data_in};
end
end
end : gen_data_sync_cell_multi
endgenerate
assign data_out = data_dff[STAGES_AMOUNT-1];
endmodule : scr1_data_sync_cell
//--------------------------------------------------------------------
// Reset / RDC Qualifyer Adapter Cell
// (Reset Generation Cell w/ RDC Qualifyer Adaptation circuitry)
//--------------------------------------------------------------------
// Total stages amount =
// 1 Front Sync stage \
// + 1 (delay introduced by the reset output buffer register)
//--------------------------------------------------------------------
module scr1_reset_qlfy_adapter_cell_sync (
input logic rst_n,
input logic clk,
input logic test_rst_n,
input logic test_mode,
input logic reset_n_in_sync,
output logic reset_n_out_qlfy,
output logic reset_n_out,
output logic reset_n_status
);
logic rst_n_mux;
logic reset_n_front_ff;
// Front sync stage
assign rst_n_mux = (test_mode == 1'b1) ? test_rst_n : rst_n;
always_ff @(negedge rst_n_mux, posedge clk) begin
if (~rst_n_mux) begin
reset_n_front_ff <= 1'b0;
end else begin
reset_n_front_ff <= reset_n_in_sync;
end
end
// Sync reset output for all reset qualifier chains targeting this reset domain
// (for reset-domain-crossings with the given reset domain as a destination).
assign reset_n_out_qlfy = reset_n_front_ff;
// Reset output buffer
scr1_reset_buf_cell
i_reset_output_buf (
.rst_n (rst_n),
.clk (clk),
.test_mode (test_mode),
.test_rst_n (test_rst_n),
.reset_n_in (reset_n_front_ff),
.reset_n_out (reset_n_out),
.reset_n_status (reset_n_status)
);
endmodule : scr1_reset_qlfy_adapter_cell_sync
module scr1_reset_and2_cell (
input logic [1:0] rst_n_in,
input logic test_rst_n,
input logic test_mode,
output logic rst_n_out
);
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : (&rst_n_in);
endmodule : scr1_reset_and2_cell
module scr1_reset_and3_cell (
input logic [2:0] rst_n_in,
input logic test_rst_n,
input logic test_mode,
output logic rst_n_out
);
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : (&rst_n_in);
endmodule : scr1_reset_and3_cell
module scr1_reset_mux2_cell (
input logic [1:0] rst_n_in,
input logic select,
input logic test_rst_n,
input logic test_mode,
output logic rst_n_out
);
assign rst_n_out = (test_mode == 1'b1) ? test_rst_n : rst_n_in[select];
endmodule : scr1_reset_mux2_cell

55
src/core/scr1_clk_ctrl.sv Normal file
View File

@@ -0,0 +1,55 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_clk_ctrl.sv>
/// @brief SCR1 clock control
///
`include "scr1_arch_description.svh"
`ifdef SCR1_CLKCTRL_EN
module scr1_clk_ctrl (
input logic clk, // Clock control module clock
input logic rst_n, // Clock control module reset
input logic test_mode, // DFT Test Mode
input logic test_rst_n, // DFT Test reset
input logic pipe2clkctl_sleep_req_i, // CLK disable request from pipe
input logic pipe2clkctl_wake_req_i, // CLK enable request from pipe
output logic clkctl2pipe_clk_alw_on_o, // Not gated pipe CLK
output logic clkctl2pipe_clk_o, // Gated pipe
output logic clkctl2pipe_clk_en_o, // CLK enabled flag
output logic clkctl2pipe_clk_dbgc_o // CLK for pipe debug subsystem
);
logic ctrl_rst_n;
assign clkctl2pipe_clk_alw_on_o = clk;
assign clkctl2pipe_clk_dbgc_o = clk;
assign ctrl_rst_n = (test_mode) ? test_rst_n : rst_n;
always_ff @(posedge clk, negedge ctrl_rst_n) begin
if (~ctrl_rst_n) begin
clkctl2pipe_clk_en_o <= 1'b1;
end else begin
if (clkctl2pipe_clk_en_o) begin
if (pipe2clkctl_sleep_req_i & ~pipe2clkctl_wake_req_i) begin
clkctl2pipe_clk_en_o <= 1'b0;
end
end else begin // ~clkctl2pipe_clk_en_o
if (pipe2clkctl_wake_req_i) begin
clkctl2pipe_clk_en_o <= 1'b1;
end
end // pipeline
end
end
scr1_cg i_scr1_cg_pipe (
.clk (clk ),
.clk_en (clkctl2pipe_clk_en_o),
.test_mode (test_mode ),
.clk_out (clkctl2pipe_clk_o )
);
endmodule : scr1_clk_ctrl
`endif // SCR1_CLKCTRL_EN

521
src/core/scr1_core_top.sv Normal file
View File

@@ -0,0 +1,521 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_core_top.sv>
/// @brief SCR1 core top
///
`include "scr1_arch_description.svh"
`include "scr1_arch_types.svh"
`include "scr1_memif.svh"
`ifdef SCR1_DBG_EN
`include "scr1_tapc.svh"
`include "scr1_dm.svh"
`include "scr1_hdu.svh"
`endif // SCR1_DBG_EN
`ifdef SCR1_IPIC_EN
`include "scr1_ipic.svh"
`endif // SCR1_IPIC_EN
module scr1_core_top (
// Common
input logic pwrup_rst_n, // Power-Up reset
input logic rst_n, // Regular reset
input logic cpu_rst_n, // CPU reset
input logic test_mode, // DFT Test Mode
input logic test_rst_n, // DFT Test Reset
input logic clk, // Core clock
output logic core_rst_n_o, // Core reset
output logic core_rdc_qlfy_o, // Core RDC qualifier
`ifdef SCR1_DBG_EN
output logic sys_rst_n_o, // System reset
output logic sys_rdc_qlfy_o, // System RDC qualifier
`endif // SCR1_DBG_EN
// Fuses
input logic [`SCR1_XLEN-1:0] core_fuse_mhartid_i, // Fuse MHARTID value
`ifdef SCR1_DBG_EN
input logic [31:0] tapc_fuse_idcode_i, // Fuse IDCODE value
`endif // SCR1_DBG_EN
// IRQ
`ifdef SCR1_IPIC_EN
input logic [SCR1_IRQ_LINES_NUM-1:0] core_irq_lines_i, // External interrupt request lines
`else
input logic core_irq_ext_i, // External interrupt request
`endif // SCR1_IPIC_EN
input logic core_irq_soft_i, // Software generated interrupt request
input logic core_irq_mtimer_i, // Machine timer interrupt request
// Memory-mapped external timer
input logic [63:0] core_mtimer_val_i, // Machine timer value
`ifdef SCR1_DBG_EN
// Debug Interface
input logic tapc_trst_n, // Test Reset (TRSTn)
input logic tapc_tck, // Test Clock (TCK)
input logic tapc_tms, // Test Mode Select (TMS)
input logic tapc_tdi, // Test Data Input (TDI)
output logic tapc_tdo, // Test Data Output (TDO)
output logic tapc_tdo_en, // TDO Enable, signal for TDO buffer control
`endif // SCR1_DBG_EN
// Instruction Memory Interface
input logic imem2core_req_ack_i, // IMEM request acknowledge
output logic core2imem_req_o, // IMEM request
output type_scr1_mem_cmd_e core2imem_cmd_o, // IMEM command
output logic [`SCR1_IMEM_AWIDTH-1:0] core2imem_addr_o, // IMEM address
input logic [`SCR1_IMEM_DWIDTH-1:0] imem2core_rdata_i, // IMEM read data
input type_scr1_mem_resp_e imem2core_resp_i, // IMEM response
// Data Memory Interface
input logic dmem2core_req_ack_i, // DMEM request acknowledge
output logic core2dmem_req_o, // DMEM request
output type_scr1_mem_cmd_e core2dmem_cmd_o, // DMEM command
output type_scr1_mem_width_e core2dmem_width_o, // DMEM data width
output logic [`SCR1_DMEM_AWIDTH-1:0] core2dmem_addr_o, // DMEM address
output logic [`SCR1_DMEM_DWIDTH-1:0] core2dmem_wdata_o, // DMEM write data
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem2core_rdata_i, // DMEM read data
input type_scr1_mem_resp_e dmem2core_resp_i // DMEM response
);
//-------------------------------------------------------------------------------
// Local parameters
//-------------------------------------------------------------------------------
localparam int unsigned SCR1_CORE_TOP_RST_SYNC_STAGES_NUM = 2;
//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------
// Reset Logic
`ifdef SCR1_DBG_EN
`else // SCR1_DBG_EN
logic core_rst_n_in_sync;
logic core_rst_n_qlfy;
logic core_rst_n_status;
`endif // SCR1_DBG_EN
logic core_rst_n;
logic core_rst_n_status_sync;
logic core_rst_status;
logic core2hdu_rdc_qlfy;
logic core2dm_rdc_qlfy;
logic pwrup_rst_n_sync;
logic rst_n_sync;
logic cpu_rst_n_sync;
`ifdef SCR1_DBG_EN
// TAPC-DM Interface
logic tapc_dmi_ch_sel;
logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc_dmi_ch_id;
logic tapc_dmi_ch_capture;
logic tapc_dmi_ch_shift;
logic tapc_dmi_ch_update;
logic tapc_dmi_ch_tdi;
logic tapc_dmi_ch_tdo;
//
logic tapc_dmi_ch_sel_tapout;
logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc_dmi_ch_id_tapout;
logic tapc_dmi_ch_capture_tapout;
logic tapc_dmi_ch_shift_tapout;
logic tapc_dmi_ch_update_tapout;
logic tapc_dmi_ch_tdi_tapout;
logic tapc_dmi_ch_tdo_tapin;
//
logic dmi_req;
logic dmi_wr;
logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi_addr;
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi_wdata;
logic dmi_resp;
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi_rdata;
// TAPC-SCU Interface
logic tapc_scu_ch_sel;
logic tapc_scu_ch_sel_tapout;
logic tapc_scu_ch_tdo;
logic tapc_ch_tdo;
// SCU nets
logic sys_rst_n;
logic sys_rst_status;
logic hdu_rst_n;
logic hdu2dm_rdc_qlfy;
logic ndm_rst_n;
logic dm_rst_n;
logic hart_rst_n;
`endif // SCR1_DBG_EN
`ifdef SCR1_DBG_EN
// DM-Pipeline Interface
// HART Run Control i/f
logic dm_active;
logic dm_cmd_req;
type_scr1_hdu_dbgstates_e dm_cmd;
logic dm_cmd_resp;
logic dm_cmd_resp_qlfy;
logic dm_cmd_rcode;
logic dm_hart_event;
logic dm_hart_event_qlfy;
type_scr1_hdu_hartstatus_s dm_hart_status;
type_scr1_hdu_hartstatus_s dm_hart_status_qlfy;
// Program Buffer - HART instruction execution i/f
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] dm_pbuf_addr;
logic [SCR1_HDU_PBUF_ADDR_WIDTH-1:0] dm_pbuf_addr_qlfy;
logic [SCR1_HDU_CORE_INSTR_WIDTH-1:0] dm_pbuf_instr;
// HART Abstract Data regs i/f
logic dm_dreg_req;
logic dm_dreg_req_qlfy;
logic dm_dreg_wr;
logic [SCR1_HDU_DATA_REG_WIDTH-1:0] dm_dreg_wdata;
logic dm_dreg_resp;
logic dm_dreg_fail;
logic [SCR1_HDU_DATA_REG_WIDTH-1:0] dm_dreg_rdata;
logic [`SCR1_XLEN-1 : 0] dm_pc_sample;
logic [`SCR1_XLEN-1 : 0] dm_pc_sample_qlfy;
`endif // SCR1_DBG_EN
`ifdef SCR1_CLKCTRL_EN
// Global clock gating logic
logic sleep_pipe;
logic wake_pipe;
logic clk_pipe;
logic clk_pipe_en;
logic clk_dbgc;
logic clk_alw_on;
`endif // SCR1_CLKCTRL_EN
//-------------------------------------------------------------------------------
// Reset Logic
//-------------------------------------------------------------------------------
`ifdef SCR1_DBG_EN
scr1_scu i_scu (
// Global signals
.pwrup_rst_n (pwrup_rst_n ),
.rst_n (rst_n ),
.cpu_rst_n (cpu_rst_n ),
.test_mode (test_mode ),
.test_rst_n (test_rst_n ),
.clk (clk ),
// TAPC scan-chains
.tapcsync2scu_ch_sel_i (tapc_scu_ch_sel ),
.tapcsync2scu_ch_id_i ('0 ),
.tapcsync2scu_ch_capture_i (tapc_dmi_ch_capture),
.tapcsync2scu_ch_shift_i (tapc_dmi_ch_shift ),
.tapcsync2scu_ch_update_i (tapc_dmi_ch_update ),
.tapcsync2scu_ch_tdi_i (tapc_dmi_ch_tdi ),
.scu2tapcsync_ch_tdo_o (tapc_scu_ch_tdo ),
// Input sync resets:
.ndm_rst_n_i (ndm_rst_n ),
.hart_rst_n_i (hart_rst_n ),
// Generated resets
.sys_rst_n_o (sys_rst_n ),
.core_rst_n_o (core_rst_n ),
.dm_rst_n_o (dm_rst_n ),
.hdu_rst_n_o (hdu_rst_n ),
// Resets statuses
.sys_rst_status_o (sys_rst_status ),
.core_rst_status_o (core_rst_status ),
// Reset Domain Crossing (RDC) qualifiers
.sys_rdc_qlfy_o (sys_rdc_qlfy_o ),
.core_rdc_qlfy_o (core_rdc_qlfy_o ),
.core2hdu_rdc_qlfy_o (core2hdu_rdc_qlfy ),
.core2dm_rdc_qlfy_o (core2dm_rdc_qlfy ),
.hdu2dm_rdc_qlfy_o (hdu2dm_rdc_qlfy )
);
assign sys_rst_n_o = sys_rst_n;
// Reset inputs are assumed synchronous
assign pwrup_rst_n_sync = pwrup_rst_n;
`else // SCR1_DBG_EN
// Reset inputs are assumed synchronous
assign pwrup_rst_n_sync = pwrup_rst_n;
assign rst_n_sync = rst_n;
assign cpu_rst_n_sync = cpu_rst_n;
assign core_rst_n_in_sync = rst_n_sync & cpu_rst_n_sync;
// Core Reset: core_rst_n
scr1_reset_qlfy_adapter_cell_sync i_core_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (core_rst_n_in_sync),
.reset_n_out_qlfy (core_rst_n_qlfy ),
.reset_n_out (core_rst_n ),
.reset_n_status (core_rst_n_status )
);
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_CORE_TOP_RST_SYNC_STAGES_NUM)
) i_core_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (core_rst_n_status ),
.data_out (core_rst_n_status_sync)
);
assign core_rst_status = ~core_rst_n_status_sync;
assign core_rdc_qlfy_o = core_rst_n_qlfy;
`endif // SCR1_DBG_EN
assign core_rst_n_o = core_rst_n;
//-------------------------------------------------------------------------------
// SCR1 pipeline
//-------------------------------------------------------------------------------
scr1_pipe_top i_pipe_top (
// Control
.pipe_rst_n (core_rst_n ),
`ifdef SCR1_DBG_EN
.pipe2hdu_rdc_qlfy_i (core2hdu_rdc_qlfy ),
.dbg_rst_n (hdu_rst_n ),
`endif // SCR1_DBG_EN
`ifndef SCR1_CLKCTRL_EN
.clk (clk ),
`else // SCR1_CLKCTRL_EN
.clk (clk_pipe ),
.pipe2clkctl_sleep_req_o (sleep_pipe ),
.pipe2clkctl_wake_req_o (wake_pipe ),
.clkctl2pipe_clk_alw_on_i (clk_alw_on ),
.clkctl2pipe_clk_dbgc_i (clk_dbgc ),
.clkctl2pipe_clk_en_i (clk_pipe_en ),
`endif // SCR1_CLKCTRL_EN
// Instruction memory interface
.pipe2imem_req_o (core2imem_req_o ),
.pipe2imem_cmd_o (core2imem_cmd_o ),
.pipe2imem_addr_o (core2imem_addr_o ),
.imem2pipe_req_ack_i (imem2core_req_ack_i ),
.imem2pipe_rdata_i (imem2core_rdata_i ),
.imem2pipe_resp_i (imem2core_resp_i ),
// Data memory interface
.pipe2dmem_req_o (core2dmem_req_o ),
.pipe2dmem_cmd_o (core2dmem_cmd_o ),
.pipe2dmem_width_o (core2dmem_width_o ),
.pipe2dmem_addr_o (core2dmem_addr_o ),
.pipe2dmem_wdata_o (core2dmem_wdata_o ),
.dmem2pipe_req_ack_i (dmem2core_req_ack_i ),
.dmem2pipe_rdata_i (dmem2core_rdata_i ),
.dmem2pipe_resp_i (dmem2core_resp_i ),
`ifdef SCR1_DBG_EN
// Debug interface:
.dbg_en (1'b1 ),
// Debug interface:
// DM <-> Pipeline: HART Run Control i/f
.dm2pipe_active_i (dm_active ),
.dm2pipe_cmd_req_i (dm_cmd_req ),
.dm2pipe_cmd_i (dm_cmd ),
.pipe2dm_cmd_resp_o (dm_cmd_resp ),
.pipe2dm_cmd_rcode_o (dm_cmd_rcode ),
.pipe2dm_hart_event_o (dm_hart_event ),
.pipe2dm_hart_status_o (dm_hart_status ),
// DM <-> Pipeline: Program Buffer - HART instruction execution i/f
.pipe2dm_pbuf_addr_o (dm_pbuf_addr ),
.dm2pipe_pbuf_instr_i (dm_pbuf_instr ),
// DM <-> Pipeline: HART Abstract Data regs i/f
.pipe2dm_dreg_req_o (dm_dreg_req ),
.pipe2dm_dreg_wr_o (dm_dreg_wr ),
.pipe2dm_dreg_wdata_o (dm_dreg_wdata ),
.dm2pipe_dreg_resp_i (dm_dreg_resp ),
.dm2pipe_dreg_fail_i (dm_dreg_fail ),
.dm2pipe_dreg_rdata_i (dm_dreg_rdata ),
// DM <-> Pipeline: PC i/f
.pipe2dm_pc_sample_o (dm_pc_sample ),
`endif // SCR1_DBG_EN
// IRQ
`ifdef SCR1_IPIC_EN
.soc2pipe_irq_lines_i (core_irq_lines_i ),
`else // SCR1_IPIC_EN
.soc2pipe_irq_ext_i (core_irq_ext_i ),
`endif // SCR1_IPIC_EN
.soc2pipe_irq_soft_i (core_irq_soft_i ),
.soc2pipe_irq_mtimer_i (core_irq_mtimer_i ),
// Memory-mapped external timer
.soc2pipe_mtimer_val_i (core_mtimer_val_i ),
// Fuse
.soc2pipe_fuse_mhartid_i (core_fuse_mhartid_i )
);
`ifdef SCR1_DBG_EN
//-------------------------------------------------------------------------------
// TAP Controller (TAPC)
//-------------------------------------------------------------------------------
scr1_tapc i_tapc (
// JTAG signals
.tapc_trst_n (tapc_trst_n ),
.tapc_tck (tapc_tck ),
.tapc_tms (tapc_tms ),
.tapc_tdi (tapc_tdi ),
.tapc_tdo (tapc_tdo ),
.tapc_tdo_en (tapc_tdo_en ),
// Fuses
.soc2tapc_fuse_idcode_i (tapc_fuse_idcode_i ),
// DMI/SCU scan-chains
.tapc2tapcsync_scu_ch_sel_o (tapc_scu_ch_sel_tapout ),
.tapc2tapcsync_dmi_ch_sel_o (tapc_dmi_ch_sel_tapout ),
.tapc2tapcsync_ch_id_o (tapc_dmi_ch_id_tapout ),
.tapc2tapcsync_ch_capture_o (tapc_dmi_ch_capture_tapout),
.tapc2tapcsync_ch_shift_o (tapc_dmi_ch_shift_tapout ),
.tapc2tapcsync_ch_update_o (tapc_dmi_ch_update_tapout ),
.tapc2tapcsync_ch_tdi_o (tapc_dmi_ch_tdi_tapout ),
.tapcsync2tapc_ch_tdo_i (tapc_dmi_ch_tdo_tapin )
);
scr1_tapc_synchronizer i_tapc_synchronizer (
// System common signals
.pwrup_rst_n (pwrup_rst_n_sync ),
.dm_rst_n (dm_rst_n ),
.clk (clk ),
// JTAG common signals
.tapc_trst_n (tapc_trst_n ),
.tapc_tck (tapc_tck ),
// DMI/SCU scan-chains
.tapc2tapcsync_scu_ch_sel_i (tapc_scu_ch_sel_tapout ),
.tapcsync2scu_ch_sel_o (tapc_scu_ch_sel ),
.tapc2tapcsync_dmi_ch_sel_i (tapc_dmi_ch_sel_tapout ),
.tapcsync2dmi_ch_sel_o (tapc_dmi_ch_sel ),
.tapc2tapcsync_ch_id_i (tapc_dmi_ch_id_tapout ),
.tapcsync2core_ch_id_o (tapc_dmi_ch_id ),
.tapc2tapcsync_ch_capture_i (tapc_dmi_ch_capture_tapout),
.tapcsync2core_ch_capture_o (tapc_dmi_ch_capture ),
.tapc2tapcsync_ch_shift_i (tapc_dmi_ch_shift_tapout ),
.tapcsync2core_ch_shift_o (tapc_dmi_ch_shift ),
.tapc2tapcsync_ch_update_i (tapc_dmi_ch_update_tapout ),
.tapcsync2core_ch_update_o (tapc_dmi_ch_update ),
.tapc2tapcsync_ch_tdi_i (tapc_dmi_ch_tdi_tapout ),
.tapcsync2core_ch_tdi_o (tapc_dmi_ch_tdi ),
.tapc2tapcsync_ch_tdo_i (tapc_dmi_ch_tdo_tapin ),
.tapcsync2core_ch_tdo_o (tapc_ch_tdo )
);
assign tapc_ch_tdo = (tapc_scu_ch_tdo & tapc_scu_ch_sel)
| (tapc_dmi_ch_tdo & tapc_dmi_ch_sel);
scr1_dmi i_dmi (
.rst_n (dm_rst_n ),
.clk (clk ),
// TAP scan-chains
.tapcsync2dmi_ch_sel_i (tapc_dmi_ch_sel ),
.tapcsync2dmi_ch_id_i (tapc_dmi_ch_id ),
.tapcsync2dmi_ch_capture_i (tapc_dmi_ch_capture),
.tapcsync2dmi_ch_shift_i (tapc_dmi_ch_shift ),
.tapcsync2dmi_ch_update_i (tapc_dmi_ch_update ),
.tapcsync2dmi_ch_tdi_i (tapc_dmi_ch_tdi ),
.dmi2tapcsync_ch_tdo_o (tapc_dmi_ch_tdo ),
// DMI
.dm2dmi_resp_i (dmi_resp ),
.dm2dmi_rdata_i (dmi_rdata ),
.dmi2dm_req_o (dmi_req ),
.dmi2dm_wr_o (dmi_wr ),
.dmi2dm_addr_o (dmi_addr ),
.dmi2dm_wdata_o (dmi_wdata )
);
`endif // SCR1_DBG_EN
`ifdef SCR1_DBG_EN
//-------------------------------------------------------------------------------
// Debug Module (DM)
//-------------------------------------------------------------------------------
assign dm_cmd_resp_qlfy = dm_cmd_resp & {$bits(dm_cmd_resp){hdu2dm_rdc_qlfy}};
assign dm_hart_event_qlfy = dm_hart_event & {$bits(dm_hart_event){hdu2dm_rdc_qlfy}};
assign dm_hart_status_qlfy.dbg_state = hdu2dm_rdc_qlfy ? dm_hart_status.dbg_state
: SCR1_HDU_DBGSTATE_RESET;
assign dm_hart_status_qlfy.except = dm_hart_status.except;
assign dm_hart_status_qlfy.ebreak = dm_hart_status.ebreak;
assign dm_pbuf_addr_qlfy = dm_pbuf_addr & {$bits(dm_pbuf_addr){hdu2dm_rdc_qlfy}};
assign dm_dreg_req_qlfy = dm_dreg_req & {$bits(dm_dreg_req){hdu2dm_rdc_qlfy}};
assign dm_pc_sample_qlfy = dm_pc_sample & {$bits(dm_pc_sample){core2dm_rdc_qlfy}};
scr1_dm i_dm (
// Common signals
.rst_n (dm_rst_n ),
.clk (clk ),
// DM internal interface
.dmi2dm_req_i (dmi_req ),
.dmi2dm_wr_i (dmi_wr ),
.dmi2dm_addr_i (dmi_addr ),
.dmi2dm_wdata_i (dmi_wdata ),
.dm2dmi_resp_o (dmi_resp ),
.dm2dmi_rdata_o (dmi_rdata ),
// DM <-> Pipeline: HART Run Control i/f
.ndm_rst_n_o (ndm_rst_n ),
.hart_rst_n_o (hart_rst_n ),
.dm2pipe_active_o (dm_active ),
.dm2pipe_cmd_req_o (dm_cmd_req ),
.dm2pipe_cmd_o (dm_cmd ),
.pipe2dm_cmd_resp_i (dm_cmd_resp_qlfy ),
.pipe2dm_cmd_rcode_i (dm_cmd_rcode ),
.pipe2dm_hart_event_i (dm_hart_event_qlfy ),
.pipe2dm_hart_status_i (dm_hart_status_qlfy ),
.soc2dm_fuse_mhartid_i (core_fuse_mhartid_i ),
.pipe2dm_pc_sample_i (dm_pc_sample_qlfy ),
// DM <-> Pipeline: HART Abstract Command / Program Buffer i/f
.pipe2dm_pbuf_addr_i (dm_pbuf_addr_qlfy ),
.dm2pipe_pbuf_instr_o (dm_pbuf_instr ),
// DM <-> Pipeline: HART Abstract Data regs i/f
.pipe2dm_dreg_req_i (dm_dreg_req_qlfy ),
.pipe2dm_dreg_wr_i (dm_dreg_wr ),
.pipe2dm_dreg_wdata_i (dm_dreg_wdata ),
.dm2pipe_dreg_resp_o (dm_dreg_resp ),
.dm2pipe_dreg_fail_o (dm_dreg_fail ),
.dm2pipe_dreg_rdata_o (dm_dreg_rdata )
);
`endif // SCR1_DBG_EN
`ifdef SCR1_CLKCTRL_EN
//-------------------------------------------------------------------------------
// Global clock gating logic
//-------------------------------------------------------------------------------
scr1_clk_ctrl i_clk_ctrl (
.clk (clk ),
.rst_n (core_rst_n ),
.test_mode (test_mode ),
.test_rst_n (test_rst_n ),
// Sleep/wake interface
.pipe2clkctl_sleep_req_i (sleep_pipe ),
.pipe2clkctl_wake_req_i (wake_pipe ),
// Clocks
.clkctl2pipe_clk_alw_on_o (clk_alw_on ),
.clkctl2pipe_clk_o (clk_pipe ),
.clkctl2pipe_clk_en_o (clk_pipe_en),
.clkctl2pipe_clk_dbgc_o (clk_dbgc )
);
`endif // SCR1_CLKCTRL_EN
endmodule : scr1_core_top

1427
src/core/scr1_dm.sv Normal file

File diff suppressed because it is too large Load Diff

182
src/core/scr1_dmi.sv Normal file
View File

@@ -0,0 +1,182 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dmi.sv>
/// @brief Debug Module Interface (DMI)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Provides TAPC with access to Debug Module (DM) and DTMCS
//
// Structure:
// - DMI <-> TAP interface
// - DMI <-> DM interface
//
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_dm.svh"
module scr1_dmi (
// System
input logic rst_n, // DMI unit reset
input logic clk, // DMI unit clock
// TAP interface
input logic tapcsync2dmi_ch_sel_i, // Debug Transport Module Chain Select
input logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapcsync2dmi_ch_id_i, // Debug Transport Module Chain ID
input logic tapcsync2dmi_ch_capture_i, // Debug Transport Module Chain Capture
input logic tapcsync2dmi_ch_shift_i, // Debug Transport Module Chain Shift
input logic tapcsync2dmi_ch_update_i, // Debug Transport Module Chain Update
input logic tapcsync2dmi_ch_tdi_i, // Debug Transport Module Chain TDI
output logic dmi2tapcsync_ch_tdo_o, // Debug Transport Module Chain TDO
// DM interface
input logic dm2dmi_resp_i, // DMI response
input logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm2dmi_rdata_i, // DMI read data
output logic dmi2dm_req_o, // DMI request
output logic dmi2dm_wr_o, // DMI write
output logic [SCR1_DBG_DMI_ADDR_WIDTH-1:0] dmi2dm_addr_o, // DMI address
output logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dmi2dm_wdata_o // DMI write data
);
//------------------------------------------------------------------------------
// Local parameters declaration
//------------------------------------------------------------------------------
// Debug Transport Module Status parameters
//------------------------------------------------------------------------------
localparam DTMCS_RESERVEDB_HI = 5'd31;
localparam DTMCS_RESERVEDB_LO = 5'd18;
localparam DTMCS_DMIHARDRESET = 5'd17;
localparam DTMCS_DMIRESET = 5'd16;
localparam DTMCS_RESERVEDA = 5'd15;
localparam DTMCS_IDLE_HI = 5'd14;
localparam DTMCS_IDLE_LO = 5'd12;
localparam DTMCS_DMISTAT_HI = 5'd11;
localparam DTMCS_DMISTAT_LO = 5'd10;
localparam DTMCS_ABITS_HI = 5'd9;
localparam DTMCS_ABITS_LO = 5'd4;
localparam DTMCS_VERSION_HI = 5'd3;
localparam DTMCS_VERSION_LO = 5'd0;
// Debug Module Interface parameters
//------------------------------------------------------------------------------
localparam DMI_OP_LO = 5'd0;
localparam DMI_OP_HI = DMI_OP_LO + SCR1_DBG_DMI_OP_WIDTH - 1;
localparam DMI_DATA_LO = DMI_OP_HI + 1;
localparam DMI_DATA_HI = DMI_DATA_LO + SCR1_DBG_DMI_DATA_WIDTH - 1;
localparam DMI_ADDR_LO = DMI_DATA_HI + 1;
localparam DMI_ADDR_HI = DMI_ADDR_LO + SCR1_DBG_DMI_ADDR_WIDTH - 1;
//------------------------------------------------------------------------------
// Local signals declaration
//------------------------------------------------------------------------------
// TAP data register
logic tap_dr_upd;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_ff;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_shift;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_rdata;
logic [SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:0] tap_dr_next;
// DM read data register
logic dm_rdata_upd;
logic [SCR1_DBG_DMI_DATA_WIDTH-1:0] dm_rdata_ff;
logic tapc_dmi_access_req;
logic tapc_dtmcs_sel;
//------------------------------------------------------------------------------
// DMI <-> TAP interface
//------------------------------------------------------------------------------
// TAPC read data multiplexer
//------------------------------------------------------------------------------
assign tapc_dtmcs_sel = (tapcsync2dmi_ch_id_i == 1'd1);
// DMI operation is always successful in the current implementation
always_comb begin
tap_dr_rdata = '0;
if(tapc_dtmcs_sel) begin
tap_dr_rdata[DTMCS_RESERVEDB_HI:DTMCS_RESERVEDB_LO] = 'b0;
tap_dr_rdata[DTMCS_DMIHARDRESET] = 'b0;
tap_dr_rdata[DTMCS_DMIRESET] = 'b0;
tap_dr_rdata[DTMCS_RESERVEDA] = 'b0;
tap_dr_rdata[DTMCS_IDLE_HI:DTMCS_IDLE_LO] = 'b0;
tap_dr_rdata[DTMCS_DMISTAT_HI:DTMCS_DMISTAT_LO] = 'b0;
tap_dr_rdata[DTMCS_ABITS_HI :DTMCS_ABITS_LO] = SCR1_DBG_DMI_ADDR_WIDTH;
tap_dr_rdata[DTMCS_VERSION_LO] = 1'b1;
end else begin
tap_dr_rdata[DMI_ADDR_HI:DMI_ADDR_LO] = 'b0;
tap_dr_rdata[DMI_DATA_HI:DMI_DATA_LO] = dm_rdata_ff;
tap_dr_rdata[DMI_OP_HI :DMI_OP_LO] = 'b0;
end
end
assign tap_dr_shift = tapc_dtmcs_sel
? {9'b0, tapcsync2dmi_ch_tdi_i, tap_dr_ff[SCR1_DBG_DMI_DR_DTMCS_WIDTH-1:1]}
: {tapcsync2dmi_ch_tdi_i, tap_dr_ff[SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH-1:1]};
// TAP data register
//------------------------------------------------------------------------------
assign tap_dr_upd = tapcsync2dmi_ch_capture_i | tapcsync2dmi_ch_shift_i;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
tap_dr_ff <= '0;
end else if(tap_dr_upd) begin
tap_dr_ff <= tap_dr_next;
end
end
assign tap_dr_next = tapcsync2dmi_ch_capture_i ? tap_dr_rdata
: tapcsync2dmi_ch_shift_i ? tap_dr_shift
: tap_dr_ff;
assign dmi2tapcsync_ch_tdo_o = tap_dr_ff[0];
//------------------------------------------------------------------------------
// DMI <-> DM interface
//------------------------------------------------------------------------------
assign tapc_dmi_access_req = tapcsync2dmi_ch_update_i & tapcsync2dmi_ch_sel_i
& (tapcsync2dmi_ch_id_i == 2'd2);
always_comb begin
dmi2dm_req_o = 1'b0;
dmi2dm_wr_o = 1'b0;
dmi2dm_addr_o = 1'b0;
dmi2dm_wdata_o = 1'b0;
if(tapc_dmi_access_req) begin
dmi2dm_req_o = tap_dr_ff[DMI_OP_HI :DMI_OP_LO] != 2'b00;
dmi2dm_wr_o = tap_dr_ff[DMI_OP_HI :DMI_OP_LO] == 2'b10;
dmi2dm_addr_o = tap_dr_ff[DMI_ADDR_HI:DMI_ADDR_LO];
dmi2dm_wdata_o = tap_dr_ff[DMI_DATA_HI:DMI_DATA_LO];
end
end
// DM read data register
//------------------------------------------------------------------------------
assign dm_rdata_upd = dmi2dm_req_o & dm2dmi_resp_i & ~dmi2dm_wr_o;
always_ff @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
dm_rdata_ff <= '0;
end else if (dm_rdata_upd) begin
dm_rdata_ff <= dm2dmi_rdata_i;
end
end
endmodule : scr1_dmi
`endif // SCR1_DBG_EN

516
src/core/scr1_scu.sv Normal file
View File

@@ -0,0 +1,516 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_scu.sv>
/// @brief System Control Unit (SCU)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Generates System, Core, HDU and DM resets and their qualifier signals
// - Provides debugger with software System and Core resets generation functionality
// - Allows to set the behavior of DM and HDU resets
// - Shows resets Statuses and Sticky Statuses
// Structure:
// - TAPC scan-chain interface
// - SCU CSRs write/read interface
// - SCU CSRS:
// - CONTROL register
// - MODE register
// - STATUS register
// - STICKY_STATUS register
// - Reset logic
// - System Reset
// - Core Reset
// - DM Reset
// - HDU Reset
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`include "scr1_scu.svh"
`ifdef SCR1_DBG_EN
module scr1_scu (
// Global signals
input logic pwrup_rst_n, // Power-Up Reset
input logic rst_n, // Regular Reset
input logic cpu_rst_n, // CPU Reset
input logic test_mode, // DFT Test Mode
input logic test_rst_n, // DFT Test Reset
input logic clk, // SCU clock
// TAPC scan-chains
input logic tapcsync2scu_ch_sel_i, // TAPC Chain Select
input logic tapcsync2scu_ch_id_i, // TAPC Chain ID
input logic tapcsync2scu_ch_capture_i, // TAPC Chain Capture
input logic tapcsync2scu_ch_shift_i, // TAPC Chain Shift
input logic tapcsync2scu_ch_update_i, // TAPC Chain Update
input logic tapcsync2scu_ch_tdi_i, // TAPC Chain TDI
output logic scu2tapcsync_ch_tdo_o, // TAPC Chain TDO
// Input sync resets:
input logic ndm_rst_n_i, // Non-DM Reset input from DM
input logic hart_rst_n_i, // HART Reset from DM
// Generated resets
output logic sys_rst_n_o, // System/Cluster Reset
output logic core_rst_n_o, // Core Reset
output logic dm_rst_n_o, // Debug Module Reset
output logic hdu_rst_n_o, // HART Debug Unit Reset
// Resets statuses
output logic sys_rst_status_o, // System Reset Status (sync'ed to POR reset domain)
output logic core_rst_status_o, // Core Reset Status (sync'ed to POR reset domain)
// Reset Domain Crossing (RDC) qualifiers
output logic sys_rdc_qlfy_o, // System/Cluster-to-ExternalSOC Reset Domain Crossing Qualifier
output logic core_rdc_qlfy_o, // Core-to-ExternalSOC Reset Domain Crossing Qualifier
output logic core2hdu_rdc_qlfy_o, // Core-to-HDU Reset Domain Crossing Qualifier
output logic core2dm_rdc_qlfy_o, // Core-to-DM Reset Domain Crossing Qualifier
output logic hdu2dm_rdc_qlfy_o // HDU-to-DM Reset Domain Crossing Qualifier
);
//------------------------------------------------------------------------------
// Local Parameters
//======================================================================================================================
localparam int unsigned SCR1_SCU_RST_SYNC_STAGES_NUM = 2;
//------------------------------------------------------------------------------
// Local Signals
//------------------------------------------------------------------------------
// SCU CSR write/read i/f
//------------------------------------------------------------------------------
// TAPC scan-chain control logic
logic scu_csr_req;
logic tapc_dr_cap_req;
logic tapc_dr_shft_req;
logic tapc_dr_upd_req;
// TAPC shift register signals
logic tapc_shift_upd;
type_scr1_scu_sysctrl_dr_s tapc_shift_ff;
type_scr1_scu_sysctrl_dr_s tapc_shift_next;
// TAPC shadow register signals
type_scr1_scu_sysctrl_dr_s tapc_shadow_ff;
// SCU CSR write/read i/f
//------------------------------------------------------------------------------
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_wdata;
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] scu_csr_rdata;
// SCU CSRs signals
//------------------------------------------------------------------------------
// Control register
type_scr1_scu_sysctrl_control_reg_s scu_control_ff;
logic scu_control_wr_req;
// Mode register
type_scr1_scu_sysctrl_mode_reg_s scu_mode_ff;
logic scu_mode_wr_req;
// Status register
type_scr1_scu_sysctrl_status_reg_s scu_status_ff;
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_dly;
type_scr1_scu_sysctrl_status_reg_s scu_status_ff_posedge;
// Sticky Status register
type_scr1_scu_sysctrl_status_reg_s scu_sticky_sts_ff;
logic scu_sticky_sts_wr_req;
// Reset logic signals
//------------------------------------------------------------------------------
// Input resets synchronization signals
logic pwrup_rst_n_sync;
logic rst_n_sync;
logic cpu_rst_n_sync;
// System Reset signals
logic sys_rst_n_in;
logic sys_rst_n_status;
logic sys_rst_n_status_sync;
logic sys_rst_n_qlfy;
logic sys_reset_n;
// Core Reset signals
logic core_rst_n_in_sync;
logic core_rst_n_status;
logic core_rst_n_status_sync;
logic core_rst_n_qlfy;
logic core_reset_n;
// HDU Reset signals
logic hdu_rst_n_in_sync;
logic hdu_rst_n_status;
logic hdu_rst_n_status_sync;
logic hdu_rst_n_qlfy;
// DM Reset signals
logic dm_rst_n_in;
logic dm_rst_n_status;
//------------------------------------------------------------------------------
// TAPC scan-chain i/f
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - TAPC scan-chain control logic
// - TAPC shift register
// - TAPC shadow register
//
// TAPC scan-chain control logic
//------------------------------------------------------------------------------
assign scu_csr_req = tapcsync2scu_ch_sel_i & (tapcsync2scu_ch_id_i == '0);
assign tapc_dr_cap_req = scu_csr_req & tapcsync2scu_ch_capture_i;
assign tapc_dr_shft_req = scu_csr_req & tapcsync2scu_ch_shift_i;
assign tapc_dr_upd_req = scu_csr_req & tapcsync2scu_ch_update_i;
// TAPC shift register
//------------------------------------------------------------------------------
assign tapc_shift_upd = tapc_dr_cap_req | tapc_dr_shft_req;
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
tapc_shift_ff <= '0;
end else if (tapc_shift_upd) begin
tapc_shift_ff <= tapc_shift_next;
end
end
assign tapc_shift_next = tapc_dr_cap_req ? tapc_shadow_ff
: tapc_dr_shft_req ? {tapcsync2scu_ch_tdi_i, tapc_shift_ff[$bits(type_scr1_scu_sysctrl_dr_s)-1:1]}
: tapc_shift_ff;
// TAPC shadow register
//------------------------------------------------------------------------------
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
tapc_shadow_ff <= '0;
end else if (tapc_dr_upd_req) begin
tapc_shadow_ff.op <= tapc_shift_ff.op;
tapc_shadow_ff.addr <= tapc_shift_ff.addr;
tapc_shadow_ff.data <= scu_csr_wdata;
end
end
assign scu2tapcsync_ch_tdo_o = tapc_shift_ff[0];
//------------------------------------------------------------------------------
// SCU CSRs write/read interface
//------------------------------------------------------------------------------
// Write interface
//------------------------------------------------------------------------------
// Register selection logic
always_comb begin
scu_control_wr_req = 1'b0;
scu_mode_wr_req = 1'b0;
scu_sticky_sts_wr_req = 1'b0;
if (tapc_dr_upd_req && (tapc_shift_ff.op != SCR1_SCU_SYSCTRL_OP_READ)) begin
case (tapc_shift_ff.addr)
SCR1_SCU_SYSCTRL_ADDR_CONTROL: scu_control_wr_req = 1'b1;
SCR1_SCU_SYSCTRL_ADDR_MODE : scu_mode_wr_req = 1'b1;
SCR1_SCU_SYSCTRL_ADDR_STICKY : scu_sticky_sts_wr_req = (tapc_shift_ff.op == SCR1_SCU_SYSCTRL_OP_CLRBITS);
default : begin end
endcase
end
end
// Write data construction
always_comb begin
scu_csr_wdata = '0;
if (tapc_dr_upd_req) begin
case (tapc_shift_ff.op)
SCR1_SCU_SYSCTRL_OP_WRITE : scu_csr_wdata = tapc_shift_ff.data;
SCR1_SCU_SYSCTRL_OP_READ : scu_csr_wdata = scu_csr_rdata;
SCR1_SCU_SYSCTRL_OP_SETBITS: scu_csr_wdata = scu_csr_rdata | tapc_shift_ff.data;
SCR1_SCU_SYSCTRL_OP_CLRBITS: scu_csr_wdata = scu_csr_rdata & (~tapc_shift_ff.data);
default : begin end
endcase
end
end
// Read interface
//------------------------------------------------------------------------------
// Read data multiplexer
always_comb begin
scu_csr_rdata = '0;
if (tapc_dr_upd_req) begin
case (tapc_shift_ff.addr)
SCR1_SCU_SYSCTRL_ADDR_CONTROL: scu_csr_rdata = scu_control_ff;
SCR1_SCU_SYSCTRL_ADDR_MODE : scu_csr_rdata = scu_mode_ff;
SCR1_SCU_SYSCTRL_ADDR_STATUS : scu_csr_rdata = scu_status_ff;
SCR1_SCU_SYSCTRL_ADDR_STICKY : scu_csr_rdata = scu_sticky_sts_ff;
default : scu_csr_rdata = 'x;
endcase
end
end
//------------------------------------------------------------------------------
// SCU CSRs
//------------------------------------------------------------------------------
//
// Registers:
// - CONTROL register
// - MODE register
// - STATUS register
// - STICKY_STATUS register
//
// CONTROL register
//------------------------------------------------------------------------------
// Allows debugger to generate System and Core resets
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_control_ff <= '0;
end else if (scu_control_wr_req) begin
scu_control_ff <= scu_csr_wdata;
end
end
// MODE register
//------------------------------------------------------------------------------
// Sets reset behavior for DM Reset and HDU Reset signals
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_mode_ff <= '0;
end else if (scu_mode_wr_req) begin
scu_mode_ff <= scu_csr_wdata;
end
end
// STATUS register
//------------------------------------------------------------------------------
// Holds the status of every output reset signal (System, Core, DM and HDU)
assign scu_status_ff.sys_reset = sys_rst_status_o ;
assign scu_status_ff.core_reset = core_rst_status_o;
assign scu_status_ff.dm_reset = ~dm_rst_n_status;
assign scu_status_ff.hdu_reset = ~hdu_rst_n_status_sync;
// Status Register positive edge detection logic
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_status_ff_dly <= '0;
end else begin
scu_status_ff_dly <= scu_status_ff;
end
end
assign scu_status_ff_posedge = scu_status_ff & ~scu_status_ff_dly;
// STICKY_STATUS register
//------------------------------------------------------------------------------
// For every output reset signal shows if it was asserted since the last bit clearing
always_ff @(posedge clk, negedge pwrup_rst_n_sync) begin
if (~pwrup_rst_n_sync) begin
scu_sticky_sts_ff <= '0;
end else begin
for (int unsigned i = 0; i < $bits(type_scr1_scu_sysctrl_status_reg_s); ++i) begin
if (scu_status_ff_posedge[i]) begin
scu_sticky_sts_ff[i] <= 1'b1;
end else if (scu_sticky_sts_wr_req) begin
scu_sticky_sts_ff[i] <= scu_csr_wdata[i];
end
end
end
end
//------------------------------------------------------------------------------
// Reset logic
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - System Reset logic
// - Core Reset logic
// - Hart Debug Unit Reset logic
// - Debug Module Reset logic
//
// Reset inputs are assumed synchronous
assign pwrup_rst_n_sync = pwrup_rst_n;
assign rst_n_sync = rst_n;
assign cpu_rst_n_sync = cpu_rst_n;
// Intermediate resets:
assign sys_reset_n = ~scu_control_ff.sys_reset;
assign core_reset_n = ~scu_control_ff.core_reset;
// System/Cluster Reset: sys_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_qlfy_adapter_cell_sync i_sys_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (sys_rst_n_in ),
.reset_n_out_qlfy (sys_rst_n_qlfy ),
.reset_n_out (sys_rst_n_o ),
.reset_n_status (sys_rst_n_status)
);
assign sys_rst_n_in = sys_reset_n & ndm_rst_n_i & rst_n_sync;
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
) i_sys_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (sys_rst_n_status ),
.data_out (sys_rst_n_status_sync)
);
assign sys_rst_status_o = ~sys_rst_n_status_sync;
// System/Cluster-to-ExternalSOC RDC qualifier
assign sys_rdc_qlfy_o = sys_rst_n_qlfy;
// Core Reset: core_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_qlfy_adapter_cell_sync i_core_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (core_rst_n_in_sync),
.reset_n_out_qlfy (core_rst_n_qlfy ),
.reset_n_out (core_rst_n_o ),
.reset_n_status (core_rst_n_status )
);
assign core_rst_n_in_sync = sys_rst_n_in & hart_rst_n_i & core_reset_n & cpu_rst_n_sync;
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
) i_core_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (core_rst_n_status ),
.data_out (core_rst_n_status_sync)
);
assign core_rst_status_o = ~core_rst_n_status_sync;
// Core Reset RDC Qualifiers:
// - Core-to-ExternalSOC RDC Qlfy
assign core_rdc_qlfy_o = core_rst_n_qlfy;
// - Core-to-HDU RDC Qlfy
assign core2hdu_rdc_qlfy_o = core_rst_n_qlfy;
// - Core-to-DebugModule RDC Qlfy
assign core2dm_rdc_qlfy_o = core_rst_n_qlfy;
// Hart Debug Unit Reset: hdu_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_qlfy_adapter_cell_sync i_hdu_rstn_qlfy_adapter_cell_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.test_rst_n (test_rst_n ),
.test_mode (test_mode ),
.reset_n_in_sync (hdu_rst_n_in_sync),
.reset_n_out_qlfy (hdu_rst_n_qlfy ),
.reset_n_out (hdu_rst_n_o ),
.reset_n_status (hdu_rst_n_status )
);
assign hdu_rst_n_in_sync = scu_mode_ff.hdu_rst_bhv | core_rst_n_in_sync;
scr1_data_sync_cell #(
.STAGES_AMOUNT (SCR1_SCU_RST_SYNC_STAGES_NUM)
) i_hdu_rstn_status_sync (
.rst_n (pwrup_rst_n_sync ),
.clk (clk ),
.data_in (hdu_rst_n_status ),
.data_out (hdu_rst_n_status_sync)
);
// Hart Debug Unit Reset RDC Qualifiers:
// - HDU-to-DebugModule RDC Qlfy
assign hdu2dm_rdc_qlfy_o = hdu_rst_n_qlfy;
// Debug Module Reset: dm_rst_n_o
//------------------------------------------------------------------------------
scr1_reset_buf_cell i_dm_rstn_buf_cell (
.rst_n (pwrup_rst_n_sync),
.clk (clk ),
.test_mode (test_mode ),
.test_rst_n (test_rst_n ),
.reset_n_in (dm_rst_n_in ),
.reset_n_out (dm_rst_n_o ),
.reset_n_status (dm_rst_n_status )
);
assign dm_rst_n_in = ~scu_mode_ff.dm_rst_bhv | sys_reset_n;
`ifdef SCR1_TRGT_SIMULATION
//--------------------------------------------------------------------
// Assertions
//--------------------------------------------------------------------
`ifndef VERILATOR
// Preventing some assertions to be raised at 0 sim time or in the first cycle
initial begin
$assertoff(0, scr1_scu);
repeat (2) @(posedge clk) begin end
$asserton(0, scr1_scu);
end
`endif // VERILATOR
// X checks
SCR1_SVA_SCU_RESETS_XCHECK : assert property (
@(negedge clk)
!$isunknown({pwrup_rst_n, rst_n, cpu_rst_n, ndm_rst_n_i, hart_rst_n_i})
) else $error("SCU resets error: unknown values of input resets");
// Qualifiers checks
SCR1_SVA_SCU_SYS2SOC_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(sys_rst_n_o) |-> $fell($past(sys_rdc_qlfy_o))
) else $error("SCU sys2soc qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_CORE2SOC_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(core_rst_n_o) |-> $fell($past(core_rdc_qlfy_o))
) else $error("SCU core2soc qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_CORE2HDU_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(core_rst_n_o) |-> $fell($past(core2hdu_rdc_qlfy_o))
) else $error("SCU core2hdu qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_CORE2DM_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(core_rst_n_o) |-> $fell($past(core2dm_rdc_qlfy_o))
) else $error("SCU core2dm qlfy error: qlfy wasn't raised prior to reset");
SCR1_SVA_SCU_HDU2DM_QLFY_CHECK : assert property (
@(negedge clk) disable iff (~pwrup_rst_n)
$fell(hdu_rst_n_o) |-> $fell($past(hdu2dm_rdc_qlfy_o))
) else $error("SCU hdu2dm qlfy error: qlfy wasn't raised prior to reset");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_scu
`endif // SCR1_DBG_EN

457
src/core/scr1_tapc.sv Normal file
View File

@@ -0,0 +1,457 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc.sv>
/// @brief TAP Controller (TAPC)
///
//------------------------------------------------------------------------------
//
// Functionality:
// - Controls TAP operation
// - Allows debugger to access TAP Data registers and DMI/SCU scan-chains via
// command written in Instruction register
//
// Structure:
// - Synchronous reset generation
// - TAPC FSM
// - TAPC Instruction Registers
// - TAPC DRs/DMI/SCU scan-chains
// - TAPC TDO enable and output Registers
// - TAPC Data Registers
// - BYPASS
// - IDCODE
// - BUILD ID
//
//------------------------------------------------------------------------------
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_tapc.svh"
`include "scr1_dm.svh"
module scr1_tapc (
// JTAG signals
input logic tapc_trst_n, // Test Reset (TRSTn)
input logic tapc_tck, // Test Clock (TCK)
input logic tapc_tms, // Test Mode Select (TMS)
input logic tapc_tdi, // Test Data Input (TDI)
output logic tapc_tdo, // Test Data Output (TDO)
output logic tapc_tdo_en, // TDO Enable, signal for TDO buffer control
// Fuses:
input logic [31:0] soc2tapc_fuse_idcode_i, // IDCODE value from fuses
// DMI/SCU scan-chains
output logic tapc2tapcsync_scu_ch_sel_o, // SCU Chain Select
output logic tapc2tapcsync_dmi_ch_sel_o, // DMI Chain Select
output logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc2tapcsync_ch_id_o, // DMI/SCU Chain Identifier
output logic tapc2tapcsync_ch_capture_o, // DMI/SCU Chain Capture
output logic tapc2tapcsync_ch_shift_o, // DMI/SCU Chain Shift
output logic tapc2tapcsync_ch_update_o, // DMI/SCU Chain Update
output logic tapc2tapcsync_ch_tdi_o, // DMI/SCU Chain TDI
input logic tapcsync2tapc_ch_tdo_i // DMI/SCU Chain TDO
);
//------------------------------------------------------------------------------
// Local Signals
//------------------------------------------------------------------------------
logic trst_n_int; // Sync reset signal
// TAPC FSM signals
//------------------------------------------------------------------------------
type_scr1_tap_state_e tap_fsm_ff; // TAP's current state
type_scr1_tap_state_e tap_fsm_next; // TAP's next state
// Control signals
logic tap_fsm_reset;
logic tap_fsm_ir_upd;
logic tap_fsm_ir_cap;
logic tap_fsm_ir_shft;
// Registered control signals
logic tap_fsm_ir_shift_ff;
logic tap_fsm_ir_shift_next;
logic tap_fsm_dr_capture_ff;
logic tap_fsm_dr_capture_next;
logic tap_fsm_dr_shift_ff;
logic tap_fsm_dr_shift_next;
logic tap_fsm_dr_update_ff;
logic tap_fsm_dr_update_next;
// TAPC Instruction Registers signals
//------------------------------------------------------------------------------
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_shift_ff; // Instruction Shift Register
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_shift_next; // Instruction Shift Register next value
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_ff; // Instruction Register
logic [SCR1_TAP_INSTRUCTION_WIDTH-1:0] tap_ir_next; // Instruction Register next value
// TAPC Data Registers signals
//------------------------------------------------------------------------------
// BYPASS register
logic dr_bypass_sel;
logic dr_bypass_tdo;
// IDCODE register
logic dr_idcode_sel;
logic dr_idcode_tdo;
// BUILD ID register
logic dr_bld_id_sel;
logic dr_bld_id_tdo;
logic dr_out;
// TDO registers
//------------------------------------------------------------------------------
// TDO enable register
logic tdo_en_ff;
logic tdo_en_next;
// TDO output register
logic tdo_out_ff;
logic tdo_out_next;
//------------------------------------------------------------------------------
// TAPC Synchronous Reset logic
//------------------------------------------------------------------------------
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
trst_n_int <= 1'b0;
end else begin
trst_n_int <= ~tap_fsm_reset;
end
end
//------------------------------------------------------------------------------
// TAP's FSM
//------------------------------------------------------------------------------
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_fsm_ff <= SCR1_TAP_STATE_RESET;
end else begin
tap_fsm_ff <= tap_fsm_next;
end
end
always_comb begin
case (tap_fsm_ff)
SCR1_TAP_STATE_RESET : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_RESET : SCR1_TAP_STATE_IDLE;
SCR1_TAP_STATE_IDLE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE;
SCR1_TAP_STATE_DR_SEL_SCAN: tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_SEL_SCAN : SCR1_TAP_STATE_DR_CAPTURE;
SCR1_TAP_STATE_DR_CAPTURE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT1 : SCR1_TAP_STATE_DR_SHIFT;
SCR1_TAP_STATE_DR_SHIFT : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT1 : SCR1_TAP_STATE_DR_SHIFT;
SCR1_TAP_STATE_DR_EXIT1 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_UPDATE : SCR1_TAP_STATE_DR_PAUSE;
SCR1_TAP_STATE_DR_PAUSE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_EXIT2 : SCR1_TAP_STATE_DR_PAUSE;
SCR1_TAP_STATE_DR_EXIT2 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_UPDATE : SCR1_TAP_STATE_DR_SHIFT;
SCR1_TAP_STATE_DR_UPDATE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE;
SCR1_TAP_STATE_IR_SEL_SCAN: tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_RESET : SCR1_TAP_STATE_IR_CAPTURE;
SCR1_TAP_STATE_IR_CAPTURE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT1 : SCR1_TAP_STATE_IR_SHIFT;
SCR1_TAP_STATE_IR_SHIFT : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT1 : SCR1_TAP_STATE_IR_SHIFT;
SCR1_TAP_STATE_IR_EXIT1 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_UPDATE : SCR1_TAP_STATE_IR_PAUSE;
SCR1_TAP_STATE_IR_PAUSE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_EXIT2 : SCR1_TAP_STATE_IR_PAUSE;
SCR1_TAP_STATE_IR_EXIT2 : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_IR_UPDATE : SCR1_TAP_STATE_IR_SHIFT;
SCR1_TAP_STATE_IR_UPDATE : tap_fsm_next = tapc_tms ? SCR1_TAP_STATE_DR_SEL_SCAN : SCR1_TAP_STATE_IDLE;
`ifdef SCR1_XPROP_EN
default : tap_fsm_next = SCR1_TAP_STATE_XXX;
`else // SCR1_XPROP_EN
default : tap_fsm_next = tap_fsm_ff;
`endif // SCR1_XPROP_EN
endcase
end
assign tap_fsm_reset = (tap_fsm_ff == SCR1_TAP_STATE_RESET);
assign tap_fsm_ir_upd = (tap_fsm_ff == SCR1_TAP_STATE_IR_UPDATE);
assign tap_fsm_ir_cap = (tap_fsm_ff == SCR1_TAP_STATE_IR_CAPTURE);
assign tap_fsm_ir_shft = (tap_fsm_ff == SCR1_TAP_STATE_IR_SHIFT);
//------------------------------------------------------------------------------
// TAPC Instruction Registers
//------------------------------------------------------------------------------
// TAPC Instruction Shift register
//------------------------------------------------------------------------------
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_ir_shift_ff <= '0;
end else if (~trst_n_int) begin
tap_ir_shift_ff <= '0;
end else begin
tap_ir_shift_ff <= tap_ir_shift_next;
end
end
assign tap_ir_shift_next = tap_fsm_ir_cap ? {{($bits(tap_ir_shift_ff)-1){1'b0}}, 1'b1}
: tap_fsm_ir_shft ? {tapc_tdi, tap_ir_shift_ff[$left(tap_ir_shift_ff):1]}
: tap_ir_shift_ff;
// TAPC Instruction register
//------------------------------------------------------------------------------
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_ir_ff <= SCR1_TAP_INSTR_IDCODE;
end else if (~trst_n_int) begin
tap_ir_ff <= SCR1_TAP_INSTR_IDCODE;
end else begin
tap_ir_ff <= tap_ir_next;
end
end
assign tap_ir_next = tap_fsm_ir_upd ? tap_ir_shift_ff : tap_ir_ff;
//------------------------------------------------------------------------------
// Control signals
//------------------------------------------------------------------------------
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_fsm_ir_shift_ff <= 1'b0;
end else if (~trst_n_int) begin
tap_fsm_ir_shift_ff <= 1'b0;
end else begin
tap_fsm_ir_shift_ff <= tap_fsm_ir_shift_next;
end
end
assign tap_fsm_ir_shift_next = (tap_fsm_next == SCR1_TAP_STATE_IR_SHIFT);
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_fsm_dr_capture_ff <= 1'b0;
end else if (~trst_n_int) begin
tap_fsm_dr_capture_ff <= 1'b0;
end else begin
tap_fsm_dr_capture_ff <= tap_fsm_dr_capture_next;
end
end
assign tap_fsm_dr_capture_next = (tap_fsm_next == SCR1_TAP_STATE_DR_CAPTURE);
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_fsm_dr_shift_ff <= 1'b0;
end else if (~trst_n_int) begin
tap_fsm_dr_shift_ff <= 1'b0;
end else begin
tap_fsm_dr_shift_ff <= tap_fsm_dr_shift_next;
end
end
assign tap_fsm_dr_shift_next = (tap_fsm_next == SCR1_TAP_STATE_DR_SHIFT);
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tap_fsm_dr_update_ff <= 1'b0;
end else if (~trst_n_int) begin
tap_fsm_dr_update_ff <= 1'b0;
end else begin
tap_fsm_dr_update_ff <= tap_fsm_dr_update_next;
end
end
assign tap_fsm_dr_update_next = (tap_fsm_next == SCR1_TAP_STATE_DR_UPDATE);
//------------------------------------------------------------------------------
// TAPC DRs/DMI/SCU scan-chains
//------------------------------------------------------------------------------
//
// Consists of the following functional units:
// - Data source/destination decoder
// - DMI channel ID decoder
// - Read data multiplexer
// Data source/destination decoder
//------------------------------------------------------------------------------
always_comb begin
dr_bypass_sel = 1'b0;
dr_idcode_sel = 1'b0;
dr_bld_id_sel = 1'b0;
tapc2tapcsync_scu_ch_sel_o = 1'b0;
tapc2tapcsync_dmi_ch_sel_o = 1'b0;
case (tap_ir_ff)
SCR1_TAP_INSTR_DTMCS : tapc2tapcsync_dmi_ch_sel_o = 1'b1;
SCR1_TAP_INSTR_DMI_ACCESS: tapc2tapcsync_dmi_ch_sel_o = 1'b1;
SCR1_TAP_INSTR_IDCODE : dr_idcode_sel = 1'b1;
SCR1_TAP_INSTR_BYPASS : dr_bypass_sel = 1'b1;
SCR1_TAP_INSTR_BLD_ID : dr_bld_id_sel = 1'b1;
SCR1_TAP_INSTR_SCU_ACCESS: tapc2tapcsync_scu_ch_sel_o = 1'b1;
default : dr_bypass_sel = 1'b1;
endcase
end
// DMI channel ID decoder
//------------------------------------------------------------------------------
always_comb begin
tapc2tapcsync_ch_id_o = '0;
case (tap_ir_ff)
SCR1_TAP_INSTR_DTMCS : tapc2tapcsync_ch_id_o = 'd1;
SCR1_TAP_INSTR_DMI_ACCESS: tapc2tapcsync_ch_id_o = 'd2;
default : tapc2tapcsync_ch_id_o = '0;
endcase
end
// Read data multiplexer
//------------------------------------------------------------------------------
always_comb begin
dr_out = 1'b0;
case (tap_ir_ff)
SCR1_TAP_INSTR_DTMCS : dr_out = tapcsync2tapc_ch_tdo_i;
SCR1_TAP_INSTR_DMI_ACCESS: dr_out = tapcsync2tapc_ch_tdo_i;
SCR1_TAP_INSTR_IDCODE : dr_out = dr_idcode_tdo;
SCR1_TAP_INSTR_BYPASS : dr_out = dr_bypass_tdo;
SCR1_TAP_INSTR_BLD_ID : dr_out = dr_bld_id_tdo;
SCR1_TAP_INSTR_SCU_ACCESS: dr_out = tapcsync2tapc_ch_tdo_i;
default : dr_out = dr_bypass_tdo;
endcase
end
//------------------------------------------------------------------------------
// TDO enable and output registers
//------------------------------------------------------------------------------
// TDO enable register
//------------------------------------------------------------------------------
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tdo_en_ff <= 1'b0;
end else if (~trst_n_int) begin
tdo_en_ff <= 1'b0;
end else begin
tdo_en_ff <= tdo_en_next;
end
end
assign tdo_en_next = tap_fsm_dr_shift_ff | tap_fsm_ir_shift_ff;
// TDO output register
//------------------------------------------------------------------------------
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tdo_out_ff <= 1'b0;
end else if (~trst_n_int) begin
tdo_out_ff <= 1'b0;
end else begin
tdo_out_ff <= tdo_out_next;
end
end
assign tdo_out_next = tap_fsm_dr_shift_ff ? dr_out
: tap_fsm_ir_shift_ff ? tap_ir_shift_ff[0]
: 1'b0;
// TAPC TDO signals
assign tapc_tdo_en = tdo_en_ff;
assign tapc_tdo = tdo_out_ff;
//------------------------------------------------------------------------------
// TAPC Data Registers
//------------------------------------------------------------------------------
//
// Registers:
// - BYPASS register
// - IDCODE register
// - BUILD ID register
// BYPASS register
//------------------------------------------------------------------------------
// 1-bit mandatory IEEE 1149.1 compliant register
scr1_tapc_shift_reg #(
.SCR1_WIDTH (SCR1_TAP_DR_BYPASS_WIDTH),
.SCR1_RESET_VALUE (SCR1_TAP_DR_BYPASS_WIDTH'(0))
) i_bypass_reg (
.clk (tapc_tck ),
.rst_n (tapc_trst_n ),
.rst_n_sync (trst_n_int ),
.fsm_dr_select (dr_bypass_sel ),
.fsm_dr_capture (tap_fsm_dr_capture_ff),
.fsm_dr_shift (tap_fsm_dr_shift_ff ),
.din_serial (tapc_tdi ),
.din_parallel (1'b0 ),
.dout_serial (dr_bypass_tdo ),
.dout_parallel ( )
);
// IDCODE register
//------------------------------------------------------------------------------
// Holds the Device ID value (mandatory IEEE 1149.1 compliant register)
scr1_tapc_shift_reg #(
.SCR1_WIDTH (SCR1_TAP_DR_IDCODE_WIDTH),
.SCR1_RESET_VALUE (SCR1_TAP_DR_IDCODE_WIDTH'(0))
) i_tap_idcode_reg (
.clk (tapc_tck ),
.rst_n (tapc_trst_n ),
.rst_n_sync (trst_n_int ),
.fsm_dr_select (dr_idcode_sel ),
.fsm_dr_capture (tap_fsm_dr_capture_ff ),
.fsm_dr_shift (tap_fsm_dr_shift_ff ),
.din_serial (tapc_tdi ),
.din_parallel (soc2tapc_fuse_idcode_i),
.dout_serial (dr_idcode_tdo ),
.dout_parallel ( )
);
// BUILD ID register
//------------------------------------------------------------------------------
// Holds the BUILD ID value
scr1_tapc_shift_reg #(
.SCR1_WIDTH (SCR1_TAP_DR_BLD_ID_WIDTH),
.SCR1_RESET_VALUE (SCR1_TAP_DR_BLD_ID_WIDTH'(0))
) i_tap_dr_bld_id_reg (
.clk (tapc_tck ),
.rst_n (tapc_trst_n ),
.rst_n_sync (trst_n_int ),
.fsm_dr_select (dr_bld_id_sel ),
.fsm_dr_capture (tap_fsm_dr_capture_ff),
.fsm_dr_shift (tap_fsm_dr_shift_ff ),
.din_serial (tapc_tdi ),
.din_parallel (SCR1_TAP_BLD_ID_VALUE),
.dout_serial (dr_bld_id_tdo ),
.dout_parallel ( )
);
//------------------------------------------------------------------------------
// DMI/SCU scan-chains signals
//------------------------------------------------------------------------------
assign tapc2tapcsync_ch_tdi_o = tapc_tdi;
assign tapc2tapcsync_ch_capture_o = tap_fsm_dr_capture_ff;
assign tapc2tapcsync_ch_shift_o = tap_fsm_dr_shift_ff;
assign tapc2tapcsync_ch_update_o = tap_fsm_dr_update_ff;
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
// X checks
SCR1_SVA_TAPC_XCHECK : assert property (
@(posedge tapc_tck) disable iff (~tapc_trst_n)
!$isunknown({tapc_tms, tapc_tdi})
) else $error("TAPC error: unknown values");
SCR1_SVA_TAPC_XCHECK_NEGCLK : assert property (
@(negedge tapc_tck) disable iff (tap_fsm_ff != SCR1_TAP_STATE_DR_SHIFT)
!$isunknown({tapcsync2tapc_ch_tdo_i})
) else $error("TAPC @negedge error: unknown values");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_tapc
`endif // SCR1_DBG_EN

View File

@@ -0,0 +1,112 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc_shift_reg.sv>
/// @brief TAPC shift register. Parameterized implementation of JTAG TAPC's Shift Register.
///
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
module scr1_tapc_shift_reg #(
parameter int unsigned SCR1_WIDTH = 8, // Register width, bits
parameter logic [SCR1_WIDTH-1:0] SCR1_RESET_VALUE = '0 // Register's value after reset
) (
input logic clk, // Clock
input logic rst_n, // Async reset
input logic rst_n_sync, // Sync reset
// TAP FSM's control signals:
input logic fsm_dr_select, // - for this DR selection (operation enabling);
input logic fsm_dr_capture, // - to capture parallel input's data into shift register;
input logic fsm_dr_shift, // - to enable data shifting;
// Inputs:
input logic din_serial, // - serial (shift_reg[msb/SCR1_WIDTH]);
input logic [SCR1_WIDTH-1:0] din_parallel, // - parallel (shift register's input).
// Outputs:
output logic dout_serial, // - serial (shift_reg[0]);
output logic [SCR1_WIDTH-1:0] dout_parallel // - parallel (shift register's output).
);
//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------
logic [SCR1_WIDTH-1:0] shift_reg;
//-------------------------------------------------------------------------------
// Shift register
//-------------------------------------------------------------------------------
generate
if (SCR1_WIDTH > 1)
begin : dr_shift_reg
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n) begin
shift_reg <= SCR1_RESET_VALUE;
end
else if (~rst_n_sync) begin
shift_reg <= SCR1_RESET_VALUE;
end
else if (fsm_dr_select & fsm_dr_capture) begin
shift_reg <= din_parallel;
end
else if (fsm_dr_select & fsm_dr_shift) begin
shift_reg <= {din_serial, shift_reg[SCR1_WIDTH-1:1]};
end
end
end
else begin : dr_shift_reg
always_ff @(posedge clk, negedge rst_n)
begin
if (~rst_n) begin
shift_reg <= SCR1_RESET_VALUE;
end
else if (~rst_n_sync) begin
shift_reg <= SCR1_RESET_VALUE;
end
else if (fsm_dr_select & fsm_dr_capture) begin
shift_reg <= din_parallel;
end
else if (fsm_dr_select & fsm_dr_shift) begin
shift_reg <= din_serial;
end
end
end
endgenerate
//-------------------------------------------------------------------------------
// Parallel output
//-------------------------------------------------------------------------------
assign dout_parallel = shift_reg;
//-------------------------------------------------------------------------------
// Serial output
//-------------------------------------------------------------------------------
assign dout_serial = shift_reg[0];
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
// X checks
SCR1_SVA_TAPC_SHIFTREG_XCHECK : assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown({
rst_n_sync,
fsm_dr_select,
fsm_dr_capture,
fsm_dr_shift,
din_serial,
din_parallel
})
) else begin
$error("TAPC Shift Reg error: unknown values");
end
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_tapc_shift_reg
`endif // SCR1_DBG_EN

View File

@@ -0,0 +1,183 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc_synchronizer.sv>
/// @brief TAPC clock domain crossing synchronizer
///
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
`include "scr1_tapc.svh"
`include "scr1_dm.svh"
module scr1_tapc_synchronizer (
// System common signals
input logic pwrup_rst_n, // Power-Up Reset
input logic dm_rst_n, // Debug Module Reset
input logic clk, // System Clock (SysCLK)
// JTAG common signals
input logic tapc_trst_n, // JTAG Test Reset (TRSTn)
input logic tapc_tck, // JTAG Test Clock (TCK)
// DMI/SCU scan-chains
input logic tapc2tapcsync_scu_ch_sel_i, // SCU Chain Select input (TCK domain)
output logic tapcsync2scu_ch_sel_o, // SCU Chain Select output (SysCLK domain)
input logic tapc2tapcsync_dmi_ch_sel_i, // DMI Chain Select input (TCK domain)
output logic tapcsync2dmi_ch_sel_o, // DMI Chain Select output (SysCLK domain)
input logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapc2tapcsync_ch_id_i, // DMI/SCU Chain Identifier input (TCK domain)
output logic [SCR1_DBG_DMI_CH_ID_WIDTH-1:0] tapcsync2core_ch_id_o, // DMI/SCU Chain Identifier output (SysCLK domain)
input logic tapc2tapcsync_ch_capture_i, // DMI/SCU Chain Capture input (TCK domain)
output logic tapcsync2core_ch_capture_o, // DMI/SCU Chain Capture output (SysCLK domain)
input logic tapc2tapcsync_ch_shift_i, // DMI/SCU Chain Shift input (TCK domain)
output logic tapcsync2core_ch_shift_o, // DMI/SCU Chain Shift output (SysCLK domain)
input logic tapc2tapcsync_ch_update_i, // DMI/SCU Chain Update input (TCK domain)
output logic tapcsync2core_ch_update_o, // DMI/SCU Chain Update output (SysCLK domain)
input logic tapc2tapcsync_ch_tdi_i, // DMI/SCU Chain TDI input (TCK domain)
output logic tapcsync2core_ch_tdi_o, // DMI/SCU Chain TDI output (SysCLK domain)
output logic tapc2tapcsync_ch_tdo_i, // DMI/SCU Chain TDO output (TCK domain)
input logic tapcsync2core_ch_tdo_o // DMI/SCU Chain TDO input (SysCLK domain)
);
//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------
logic tck_divpos;
logic tck_divneg;
logic tck_rise_load;
logic tck_rise_reset;
logic tck_fall_load;
logic tck_fall_reset;
logic [3:0] tck_divpos_sync;
logic [3:0] tck_divneg_sync;
logic [2:0] dmi_ch_capture_sync;
logic [2:0] dmi_ch_shift_sync;
logic [2:0] dmi_ch_tdi_sync;
//-------------------------------------------------------------------------------
// Logic
//-------------------------------------------------------------------------------
always_ff @(posedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tck_divpos <= 1'b0;
end else begin
tck_divpos <= ~tck_divpos;
end
end
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
tck_divneg <= 1'b0;
end else begin
tck_divneg <= ~tck_divneg;
end
end
always_ff @(posedge clk, negedge pwrup_rst_n) begin
if (~pwrup_rst_n) begin
tck_divpos_sync <= 4'd0;
tck_divneg_sync <= 4'd0;
end else begin
tck_divpos_sync <= {tck_divpos_sync[2:0], tck_divpos};
tck_divneg_sync <= {tck_divneg_sync[2:0], tck_divneg};
end
end
assign tck_rise_load = tck_divpos_sync[2] ^ tck_divpos_sync[1];
assign tck_rise_reset = tck_divpos_sync[3] ^ tck_divpos_sync[2];
assign tck_fall_load = tck_divneg_sync[2] ^ tck_divneg_sync[1];
assign tck_fall_reset = tck_divneg_sync[3] ^ tck_divneg_sync[2];
always_ff @(posedge clk, negedge pwrup_rst_n) begin
if (~pwrup_rst_n) begin
tapcsync2core_ch_update_o <= '0;
end else begin
if (tck_fall_load) begin
tapcsync2core_ch_update_o <= tapc2tapcsync_ch_update_i;
end else if (tck_fall_reset) begin
tapcsync2core_ch_update_o <= '0;
end
end
end
always_ff @(negedge tapc_tck, negedge tapc_trst_n) begin
if (~tapc_trst_n) begin
dmi_ch_capture_sync[0] <= '0;
dmi_ch_shift_sync[0] <= '0;
end else begin
dmi_ch_capture_sync[0] <= tapc2tapcsync_ch_capture_i;
dmi_ch_shift_sync[0] <= tapc2tapcsync_ch_shift_i;
end
end
always_ff @(posedge clk, negedge pwrup_rst_n) begin
if (~pwrup_rst_n) begin
dmi_ch_capture_sync[2:1] <= '0;
dmi_ch_shift_sync[2:1] <= '0;
end else begin
dmi_ch_capture_sync[2:1] <= {dmi_ch_capture_sync[1], dmi_ch_capture_sync[0]};
dmi_ch_shift_sync[2:1] <= {dmi_ch_shift_sync[1], dmi_ch_shift_sync[0]};
end
end
always_ff @(posedge clk, negedge pwrup_rst_n) begin
if (~pwrup_rst_n) begin
dmi_ch_tdi_sync <= '0;
end else begin
dmi_ch_tdi_sync <= {dmi_ch_tdi_sync[1:0], tapc2tapcsync_ch_tdi_i};
end
end
always_ff @(posedge clk, negedge pwrup_rst_n) begin
if (~pwrup_rst_n) begin
tapcsync2core_ch_capture_o <= '0;
tapcsync2core_ch_shift_o <= '0;
tapcsync2core_ch_tdi_o <= '0;
end else begin
if (tck_rise_load) begin
tapcsync2core_ch_capture_o <= dmi_ch_capture_sync[2];
tapcsync2core_ch_shift_o <= dmi_ch_shift_sync[2];
tapcsync2core_ch_tdi_o <= dmi_ch_tdi_sync[2];
end else if (tck_rise_reset) begin
tapcsync2core_ch_capture_o <= '0;
tapcsync2core_ch_shift_o <= '0;
tapcsync2core_ch_tdi_o <= '0;
end
end
end
always_ff @(posedge clk, negedge dm_rst_n) begin
if (~dm_rst_n) begin
tapcsync2dmi_ch_sel_o <= '0;
tapcsync2core_ch_id_o <= '0;
end else begin
if (tck_rise_load) begin
tapcsync2dmi_ch_sel_o <= tapc2tapcsync_dmi_ch_sel_i;
tapcsync2core_ch_id_o <= tapc2tapcsync_ch_id_i;
end
end
end
always_ff @(posedge clk, negedge pwrup_rst_n) begin
if (~pwrup_rst_n) begin
tapcsync2scu_ch_sel_o <= '0;
end else begin
if (tck_rise_load) begin
tapcsync2scu_ch_sel_o <= tapc2tapcsync_scu_ch_sel_i;
end
end
end
assign tapc2tapcsync_ch_tdo_i = tapcsync2core_ch_tdo_o;
endmodule : scr1_tapc_synchronizer
`endif // SCR1_DBG_EN

59
src/includes/scr1_ahb.svh Normal file
View File

@@ -0,0 +1,59 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_ahb.svh>
/// @brief AHB header file
///
`ifndef SCR1_AHB_SVH
`define SCR1_AHB_SVH
`include "scr1_arch_description.svh"
parameter SCR1_AHB_WIDTH = 32;
// Encoding for HTRANS signal
parameter logic [1:0] SCR1_HTRANS_IDLE = 2'b00;
parameter logic [1:0] SCR1_HTRANS_NONSEQ = 2'b10;
`ifdef SCR1_XPROP_EN
parameter logic [1:0] SCR1_HTRANS_ERR = 'x;
`else // SCR1_XPROP_EN
parameter logic [1:0] SCR1_HTRANS_ERR = '0;
`endif // SCR1_XPROP_EN
// Encoding for HBURST signal
parameter logic [2:0] SCR1_HBURST_SINGLE = 3'b000;
`ifdef SCR1_XPROP_EN
parameter logic [2:0] SCR1_HBURST_ERR = 'x;
`else // SCR1_XPROP_EN
parameter logic [1:0] SCR1_HBURST_ERR = '0;
`endif // SCR1_XPROP_EN
// Encoding for HSIZE signal
parameter logic [2:0] SCR1_HSIZE_8B = 3'b000;
parameter logic [2:0] SCR1_HSIZE_16B = 3'b001;
parameter logic [2:0] SCR1_HSIZE_32B = 3'b010;
`ifdef SCR1_XPROP_EN
parameter logic [2:0] SCR1_HSIZE_ERR = 'x;
`else // SCR1_XPROP_EN
parameter logic [2:0] SCR1_HSIZE_ERR = '0;
`endif // SCR1_XPROP_EN
// Encoding HPROT signal
// HPROT[0] : 0 - instr; 1 - data
// HPROT[1] : 0 - user; 1 - privilege
// HPROT[2] : 0 - not buffer; 1 - buffer
// HPROT[3] : 0 - cacheable; 1 - cacheable
parameter SCR1_HPROT_DATA = 0;
parameter SCR1_HPROT_PRV = 1;
parameter SCR1_HPROT_BUF = 2;
parameter SCR1_HPROT_CACHE = 3;
// Encoding HRESP signal
parameter logic SCR1_HRESP_OKAY = 1'b0;
parameter logic SCR1_HRESP_ERROR = 1'b1;
`ifdef SCR1_XPROP_EN
parameter logic SCR1_HRESP_ERR = 1'bx;
`else // SCR1_XPROP_EN
parameter logic SCR1_HRESP_ERR = 1'b0;
`endif // SCR1_XPROP_EN
`endif // SCR1_AHB_SVH

View File

@@ -0,0 +1,215 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_arch_description.svh>
/// @brief Architecture description file
///
`ifndef SCR1_ARCH_DESCRIPTION_SVH
`define SCR1_ARCH_DESCRIPTION_SVH
//------------------------------------------------------------------------------
// CORE FUNDAMENTAL PARAMETERS
//------------------------------------------------------------------------------
// SCR1 core identifiers
`define SCR1_MIMPID 32'h22011200
`define SCR1_MVENDORID 32'h00000000
// Width of main registers and buses
`define SCR1_XLEN 32
`define SCR1_IMEM_AWIDTH `SCR1_XLEN
`define SCR1_IMEM_DWIDTH `SCR1_XLEN
`define SCR1_DMEM_AWIDTH `SCR1_XLEN
`define SCR1_DMEM_DWIDTH `SCR1_XLEN
// TAP IDCODE
`define SCR1_TAP_IDCODE 'hDEB11001
`ifdef SCR1_ARCH_CUSTOM
//------------------------------------------------------------------------------
// INCLUDE SCR1_ARCH_CUSTOM.SVH
//------------------------------------------------------------------------------
// The external file scr1_arch_custom.svh is used for the open SCR1-SDK project,
// and can also be used for any custom projects.
// The file sets:
// - target platform (FPGA/ASIC), which affects the choice of logical constructs;
// - device build ID;
// - address constants;
// - could enables configuration parameters.
// Possible targets:
// `define SCR1_TRGT_FPGA_INTEL // target platform is Intel FPGAs
// `define SCR1_TRGT_FPGA_INTEL_MAX10 // target platform is Intel MAX 10 FPGAs (used in the SCR1-SDK project)
// `define SCR1_TRGT_FPGA_INTEL_ARRIAV // target platform is Intel Arria V FPGAs (used in the SCR1-SDK project)
// `define SCR1_TRGT_FPGA_XILINX // target platform is Xilinx FPGAs (used in the SCR1-SDK project)
// `define SCR1_TRGT_ASIC // target platform is ASIC
// `define SCR1_TRGT_SIMULATION // target is simulation (enable simulation code)
`include "scr1_arch_custom.svh"
`endif // SCR1_ARCH_CUSTOM
//------------------------------------------------------------------------------
// RECOMMENDED CORE ARCHITECTURE CONFIGURATIONS
//------------------------------------------------------------------------------
// Uncomment one of these defines to set the recommended configuration:
//`define SCR1_CFG_RV32IMC_MAX
//`define SCR1_CFG_RV32IC_BASE
//`define SCR1_CFG_RV32EC_MIN
// If all defines are commented, custom configuration will be used (see below)
//------------------------------------------------------------------------------
// READ-ONLY: settings for recommended configurations
`ifdef SCR1_CFG_RV32IMC_MAX
`define SCR1_RVI_EXT
`define SCR1_RVM_EXT
`define SCR1_RVC_EXT
parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 26;
`define SCR1_MTVEC_MODE_EN
`define SCR1_FAST_MUL
`define SCR1_MPRF_RST_EN
`define SCR1_MCOUNTEN_EN
`define SCR1_DBG_EN
`define SCR1_TDU_EN
parameter int unsigned SCR1_TDU_TRIG_NUM = 4;
`define SCR1_TDU_ICOUNT_EN
`define SCR1_IPIC_EN
`define SCR1_IPIC_SYNC_EN
`define SCR1_TCM_EN
`elsif SCR1_CFG_RV32IC_BASE
`define SCR1_RVI_EXT
`define SCR1_RVC_EXT
parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 16;
`define SCR1_MTVEC_MODE_EN
`define SCR1_NO_DEC_STAGE
`define SCR1_MPRF_RST_EN
`define SCR1_MCOUNTEN_EN
`define SCR1_DBG_EN
`define SCR1_TDU_EN
parameter int unsigned SCR1_TDU_TRIG_NUM = 2;
`define SCR1_TDU_ICOUNT_EN
`define SCR1_IPIC_EN
`define SCR1_IPIC_SYNC_EN
`define SCR1_TCM_EN
`elsif SCR1_CFG_RV32EC_MIN
`define SCR1_RVE_EXT
`define SCR1_RVC_EXT
parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 0;
`define SCR1_NO_DEC_STAGE
`define SCR1_NO_EXE_STAGE
`define SCR1_TCM_EN
`else // begin custom configuration section
//------------------------------------------------------------------------------
// CUSTOM CORE ARCHITECTURE CONFIGURATION
//------------------------------------------------------------------------------
// To fine-tune custom configuration, you can change the values in this section.
// Make sure that the defines of the recommended configurations are commented,
// otherwise this section will be inactive.
// RISC-V ISA options
//`define SCR1_RVE_EXT // enable RV32E base integer instruction set, otherwise RV32I will be used
`define SCR1_RVM_EXT // enable standard extension "M" for integer hardware multiplier and divider
`define SCR1_RVC_EXT // enable standard extension "C" for compressed instructions
parameter int unsigned SCR1_MTVEC_BASE_WR_BITS = 26; // number of writable high-order bits in MTVEC.base field
// legal values are 0 to 26
// read-only bits are hardwired to reset value
`define SCR1_MTVEC_MODE_EN // enable writable MTVEC.mode field to allow vectored irq mode, otherwise only direct mode is possible
`ifndef SCR1_RVE_EXT
`define SCR1_RVI_EXT // RV32E base integer instruction set if SCR1_RVE_EXT is not enabled
`endif // ~SCR1_RVE_EXT
// Core pipeline options (power-performance-area optimization)
`define SCR1_NO_DEC_STAGE // disable register between IFU and IDU
`define SCR1_NO_EXE_STAGE // disable register between IDU and EXU
`define SCR1_NEW_PC_REG // enable register in IFU for New_PC value
`define SCR1_FAST_MUL // enable fast one-cycle multiplication, otherwise multiplication takes 32 cycles
`define SCR1_CLKCTRL_EN // enable global clock gating
`define SCR1_MPRF_RST_EN // enable reset for MPRF
`define SCR1_MCOUNTEN_EN // enable custom MCOUNTEN CSR for counter control
// Uncore options
`define SCR1_DBG_EN // enable Debug Subsystem (TAPC, DM, SCU, HDU)
`define SCR1_TDU_EN // enable Trigger Debug Unit (hardware breakpoints)
parameter int unsigned SCR1_TDU_TRIG_NUM = 2; // number of hardware triggers
`define SCR1_TDU_ICOUNT_EN // enable hardware triggers on instruction counter
`define SCR1_IPIC_EN // enable Integrated Programmable Interrupt Controller
`define SCR1_IPIC_SYNC_EN // enable IPIC synchronizer
`define SCR1_TCM_EN // enable Tightly-Coupled Memory
`endif // end custom configuration section
//------------------------------------------------------------------------------
// CORE INTEGRATION OPTIONS
//------------------------------------------------------------------------------
// Bypasses on AXI/AHB bridge I/O
`define SCR1_IMEM_AHB_IN_BP // bypass instruction memory AHB bridge input register
`define SCR1_IMEM_AHB_OUT_BP // bypass instruction memory AHB bridge output register
`define SCR1_DMEM_AHB_IN_BP // bypass data memory AHB bridge input register
`define SCR1_DMEM_AHB_OUT_BP // bypass data memory AHB bridge output register
`define SCR1_IMEM_AXI_REQ_BP // bypass instruction memory AXI bridge request register
`define SCR1_IMEM_AXI_RESP_BP // bypass instruction memory AXI bridge response register
`define SCR1_DMEM_AXI_REQ_BP // bypass data memory AXI bridge request register
`define SCR1_DMEM_AXI_RESP_BP // bypass data memory AXI bridge response register
`ifndef SCR1_ARCH_CUSTOM
// Default address constants (if scr1_arch_custom.svh is not used)
parameter bit [`SCR1_XLEN-1:0] SCR1_ARCH_RST_VECTOR = 'h200; // Reset vector value (start address after reset)
parameter bit [`SCR1_XLEN-1:0] SCR1_ARCH_MTVEC_BASE = 'h1C0; // MTVEC.base field reset value, or constant value for MTVEC.base bits that are hardwired
parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TCM_ADDR_MASK = 'hFFFF0000; // TCM mask and size; size in bytes is two's complement of the mask value
parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TCM_ADDR_PATTERN = 'h00480000; // TCM address match pattern
parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TIMER_ADDR_MASK = 'hFFFFFFE0; // Timer mask
parameter bit [`SCR1_DMEM_AWIDTH-1:0] SCR1_TIMER_ADDR_PATTERN = 'h00490000; // Timer address match pattern
// Device build ID
`define SCR1_ARCH_BUILD_ID `SCR1_MIMPID
`endif // SCR1_ARCH_CUSTOM
//------------------------------------------------------------------------------
// TARGET-SPECIFIC OPTIONS
//------------------------------------------------------------------------------
// RAM-based MPRF can be used for Intel FPGAs only
`ifdef SCR1_TRGT_FPGA_INTEL
`define SCR1_MPRF_RAM // implements MPRF with dedicated RAM blocks
`endif
// EXU_STAGE_BYPASS and MPRF_RST_EN must be disabled for RAM-based MPRF
`ifdef SCR1_MPRF_RAM
`undef SCR1_NO_EXE_STAGE
`undef SCR1_MPRF_RST_EN
`endif
//------------------------------------------------------------------------------
// SIMULATION OPTIONS
//------------------------------------------------------------------------------
//`define SCR1_TRGT_SIMULATION // enable simulation code (automatically defined by root makefile)
//`define SCR1_TRACE_LOG_EN // enable tracelog
//`define SCR1_XPROP_EN // enable X-propagation
// Addresses used in testbench
localparam [`SCR1_XLEN-1:0] SCR1_SIM_EXIT_ADDR = 32'h0000_00F8;
localparam [`SCR1_XLEN-1:0] SCR1_SIM_PRINT_ADDR = 32'hF000_0000;
localparam [`SCR1_XLEN-1:0] SCR1_SIM_EXT_IRQ_ADDR = 32'hF000_0100;
localparam [`SCR1_XLEN-1:0] SCR1_SIM_SOFT_IRQ_ADDR = 32'hF000_0200;
`endif // SCR1_ARCH_DESCRIPTION_SVH

View File

@@ -0,0 +1,72 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_arch_types.svh>
/// @brief Pipeline types description file
///
`ifndef SCR1_ARCH_TYPES_SVH
`define SCR1_ARCH_TYPES_SVH
`include "scr1_arch_description.svh"
//-------------------------------------------------------------------------------
// MPRF and CSR parameters
//-------------------------------------------------------------------------------
`ifdef SCR1_RVE_EXT
`define SCR1_MPRF_AWIDTH 4
`define SCR1_MPRF_SIZE 16
`else // SCR1_RVE_EXT
`define SCR1_MPRF_AWIDTH 5
`define SCR1_MPRF_SIZE 32
`endif // SCR1_RVE_EXT
typedef logic [`SCR1_XLEN-1:0] type_scr1_mprf_v;
typedef logic [`SCR1_XLEN-1:0] type_scr1_pc_v;
parameter int unsigned SCR1_CSR_ADDR_WIDTH = 12;
parameter int unsigned SCR1_CSR_MTVEC_BASE_ZERO_BITS = 6;
parameter int unsigned SCR1_CSR_MTVEC_BASE_VAL_BITS = `SCR1_XLEN-SCR1_CSR_MTVEC_BASE_ZERO_BITS;
parameter bit [`SCR1_XLEN-1:SCR1_CSR_MTVEC_BASE_ZERO_BITS] SCR1_CSR_MTVEC_BASE_WR_RST_VAL =
SCR1_CSR_MTVEC_BASE_VAL_BITS'(SCR1_ARCH_MTVEC_BASE >> SCR1_CSR_MTVEC_BASE_ZERO_BITS);
parameter int unsigned SCR1_CSR_MTVEC_BASE_RO_BITS = (`SCR1_XLEN-(SCR1_CSR_MTVEC_BASE_ZERO_BITS+SCR1_MTVEC_BASE_WR_BITS));
`define SCR1_MTVAL_ILLEGAL_INSTR_EN
//-------------------------------------------------------------------------------
// Exception and IRQ codes
//-------------------------------------------------------------------------------
parameter int unsigned SCR1_EXC_CODE_WIDTH_E = 4;
// Exceptions
typedef enum logic [SCR1_EXC_CODE_WIDTH_E-1:0] {
SCR1_EXC_CODE_INSTR_MISALIGN = 4'd0, // from EXU
SCR1_EXC_CODE_INSTR_ACCESS_FAULT = 4'd1, // from IFU
SCR1_EXC_CODE_ILLEGAL_INSTR = 4'd2, // from IDU or CSR
SCR1_EXC_CODE_BREAKPOINT = 4'd3, // from IDU or BRKM
SCR1_EXC_CODE_LD_ADDR_MISALIGN = 4'd4, // from LSU
SCR1_EXC_CODE_LD_ACCESS_FAULT = 4'd5, // from LSU
SCR1_EXC_CODE_ST_ADDR_MISALIGN = 4'd6, // from LSU
SCR1_EXC_CODE_ST_ACCESS_FAULT = 4'd7, // from LSU
SCR1_EXC_CODE_ECALL_M = 4'd11 // from IDU
} type_scr1_exc_code_e;
// IRQs, reset
parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_IRQ_M_SOFTWARE = 4'd3;
parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_IRQ_M_TIMER = 4'd7;
parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_IRQ_M_EXTERNAL = 4'd11;
parameter bit [SCR1_EXC_CODE_WIDTH_E-1:0] SCR1_EXC_CODE_RESET = 4'd0;
//-------------------------------------------------------------------------------
// Operand width for BRKM
//-------------------------------------------------------------------------------
typedef enum logic [1:0] {
SCR1_OP_WIDTH_BYTE = 2'b00,
SCR1_OP_WIDTH_HALF = 2'b01,
SCR1_OP_WIDTH_WORD = 2'b10
`ifdef SCR1_XPROP_EN
,
SCR1_OP_WIDTH_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_op_width_e;
`endif //SCR1_ARCH_TYPES_SVH

196
src/includes/scr1_csr.svh Normal file
View File

@@ -0,0 +1,196 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_csr.svh>
/// @brief CSR mapping/description file
///
`ifndef SCR1_CSR_SVH
`define SCR1_CSR_SVH
`include "scr1_arch_description.svh"
`include "scr1_arch_types.svh"
`include "scr1_ipic.svh"
`ifdef SCR1_RVE_EXT
`define SCR1_CSR_REDUCED_CNT
`endif // SCR1_RVE_EXT
`ifdef SCR1_CSR_REDUCED_CNT
`undef SCR1_MCOUNTEN_EN
`endif // SCR1_CSR_REDUCED_CNT
//-------------------------------------------------------------------------------
// CSR addresses (standard)
//-------------------------------------------------------------------------------
// Machine Information Registers (read-only)
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MVENDORID = SCR1_CSR_ADDR_WIDTH'('hF11);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MARCHID = SCR1_CSR_ADDR_WIDTH'('hF12);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MIMPID = SCR1_CSR_ADDR_WIDTH'('hF13);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MHARTID = SCR1_CSR_ADDR_WIDTH'('hF14);
// Machine Trap Setup (read-write)
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MSTATUS = SCR1_CSR_ADDR_WIDTH'('h300);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MISA = SCR1_CSR_ADDR_WIDTH'('h301);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MIE = SCR1_CSR_ADDR_WIDTH'('h304);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MTVEC = SCR1_CSR_ADDR_WIDTH'('h305);
// Machine Trap Handling (read-write)
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MSCRATCH = SCR1_CSR_ADDR_WIDTH'('h340);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MEPC = SCR1_CSR_ADDR_WIDTH'('h341);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCAUSE = SCR1_CSR_ADDR_WIDTH'('h342);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MTVAL = SCR1_CSR_ADDR_WIDTH'('h343);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MIP = SCR1_CSR_ADDR_WIDTH'('h344);
// Machine Counters/Timers (read-write)
`ifndef SCR1_CSR_REDUCED_CNT
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCYCLE = SCR1_CSR_ADDR_WIDTH'('hB00);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MINSTRET = SCR1_CSR_ADDR_WIDTH'('hB02);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCYCLEH = SCR1_CSR_ADDR_WIDTH'('hB80);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MINSTRETH = SCR1_CSR_ADDR_WIDTH'('hB82);
`endif // SCR1_CSR_REDUCED_CNT
// Shadow Counters/Timers (read-only)
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TIME = SCR1_CSR_ADDR_WIDTH'('hC01);
`ifndef SCR1_CSR_REDUCED_CNT
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_CYCLE = SCR1_CSR_ADDR_WIDTH'('hC00);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_INSTRET = SCR1_CSR_ADDR_WIDTH'('hC02);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TIMEH = SCR1_CSR_ADDR_WIDTH'('hC81);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_CYCLEH = SCR1_CSR_ADDR_WIDTH'('hC80);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_INSTRETH = SCR1_CSR_ADDR_WIDTH'('hC82);
`endif // SCR1_CSR_REDUCED_CNT
`ifdef SCR1_DBG_EN
//parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_DBGC_SCRATCH = 'h7C8;
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_HDU_MBASE = SCR1_CSR_ADDR_WIDTH'('h7B0);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_HDU_MSPAN = SCR1_CSR_ADDR_WIDTH'('h004); // must be power of 2
`endif // SCR1_DBG_EN
//-------------------------------------------------------------------------------
// CSR addresses (non-standard)
//-------------------------------------------------------------------------------
`ifdef SCR1_MCOUNTEN_EN
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_MCOUNTEN = SCR1_CSR_ADDR_WIDTH'('h7E0);
`endif // SCR1_MCOUNTEN_EN
`ifdef SCR1_TDU_EN
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_MBASE = SCR1_CSR_ADDR_WIDTH'('h7A0);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_MSPAN = SCR1_CSR_ADDR_WIDTH'('h008); // must be power of 2
`endif // SCR1_TDU_EN
`ifdef SCR1_IPIC_EN
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_BASE = SCR1_CSR_ADDR_WIDTH'('hBF0);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_CISV = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_CISV );
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_CICSR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_CICSR);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_IPR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_IPR );
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_ISVR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_ISVR );
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_EOI = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_EOI );
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_SOI = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_SOI );
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_IDX = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_IDX );
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_IPIC_ICSR = (SCR1_CSR_ADDR_IPIC_BASE + SCR1_IPIC_ICSR );
`endif // SCR1_IPIC_EN
//-------------------------------------------------------------------------------
// CSR definitions
//-------------------------------------------------------------------------------
// General
parameter bit [`SCR1_XLEN-1:0] SCR1_RST_VECTOR = SCR1_ARCH_RST_VECTOR;
// Reset values
parameter bit SCR1_CSR_MIE_MSIE_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MIE_MTIE_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MIE_MEIE_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MIP_MSIP_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MIP_MTIP_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MIP_MEIP_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MSTATUS_MIE_RST_VAL = 1'b0;
parameter bit SCR1_CSR_MSTATUS_MPIE_RST_VAL = 1'b1;
// MISA
`define SCR1_RVC_ENC `SCR1_XLEN'h0004
`define SCR1_RVE_ENC `SCR1_XLEN'h0010
`define SCR1_RVI_ENC `SCR1_XLEN'h0100
`define SCR1_RVM_ENC `SCR1_XLEN'h1000
parameter bit [1:0] SCR1_MISA_MXL_32 = 2'd1;
parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MISA = (SCR1_MISA_MXL_32 << (`SCR1_XLEN-2))
`ifndef SCR1_RVE_EXT
| `SCR1_RVI_ENC
`else // SCR1_RVE_EXT
| `SCR1_RVE_ENC
`endif // SCR1_RVE_EXT
`ifdef SCR1_RVC_EXT
| `SCR1_RVC_ENC
`endif // SCR1_RVC_EXT
`ifdef SCR1_RVM_EXT
| `SCR1_RVM_ENC
`endif // SCR1_RVM_EXT
;
// MVENDORID
parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MVENDORID = `SCR1_MVENDORID;
// MARCHID
parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MARCHID = `SCR1_XLEN'd8;
// MIMPID
parameter bit [`SCR1_XLEN-1:0] SCR1_CSR_MIMPID = `SCR1_MIMPID;
// MSTATUS
parameter bit [1:0] SCR1_CSR_MSTATUS_MPP = 2'b11;
parameter int unsigned SCR1_CSR_MSTATUS_MIE_OFFSET = 3;
parameter int unsigned SCR1_CSR_MSTATUS_MPIE_OFFSET = 7;
parameter int unsigned SCR1_CSR_MSTATUS_MPP_OFFSET = 11;
// MTVEC
// bits [5:0] are always zero
parameter bit [`SCR1_XLEN-1:SCR1_CSR_MTVEC_BASE_ZERO_BITS] SCR1_CSR_MTVEC_BASE_RST_VAL = SCR1_CSR_MTVEC_BASE_WR_RST_VAL;
parameter bit SCR1_CSR_MTVEC_MODE_DIRECT = 1'b0;
`ifdef SCR1_MTVEC_MODE_EN
parameter bit SCR1_CSR_MTVEC_MODE_VECTORED = 1'b1;
`endif // SCR1_MTVEC_MODE_EN
// MIE, MIP
parameter int unsigned SCR1_CSR_MIE_MSIE_OFFSET = 3;
parameter int unsigned SCR1_CSR_MIE_MTIE_OFFSET = 7;
parameter int unsigned SCR1_CSR_MIE_MEIE_OFFSET = 11;
`ifdef SCR1_MCOUNTEN_EN
// MCOUNTEN
parameter int unsigned SCR1_CSR_MCOUNTEN_CY_OFFSET = 0;
parameter int unsigned SCR1_CSR_MCOUNTEN_IR_OFFSET = 2;
`endif // SCR1_MCOUNTEN_EN
// MCAUSE
typedef logic [`SCR1_XLEN-2:0] type_scr1_csr_mcause_ec_v;
// MCYCLE, MINSTRET
`ifdef SCR1_CSR_REDUCED_CNT
parameter int unsigned SCR1_CSR_COUNTERS_WIDTH = 32;
`else // ~SCR1_CSR_REDUCED_CNT
parameter int unsigned SCR1_CSR_COUNTERS_WIDTH = 64;
`endif // ~SCR1_CSR_REDUCED_CNT
// HPM
parameter bit [6:0] SCR1_CSR_ADDR_HPMCOUNTER_MASK = 7'b1100000;
parameter bit [6:0] SCR1_CSR_ADDR_HPMCOUNTERH_MASK = 7'b1100100;
parameter bit [6:0] SCR1_CSR_ADDR_MHPMCOUNTER_MASK = 7'b1011000;
parameter bit [6:0] SCR1_CSR_ADDR_MHPMCOUNTERH_MASK = 7'b1011100;
parameter bit [6:0] SCR1_CSR_ADDR_MHPMEVENT_MASK = 7'b0011001;
//-------------------------------------------------------------------------------
// Types declaration
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_CSR_RESP_OK,
SCR1_CSR_RESP_ER
`ifdef SCR1_XPROP_EN
,
SCR1_CSR_RESP_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_csr_resp_e;
`endif // SCR1_CSR_SVH

141
src/includes/scr1_dm.svh Normal file
View File

@@ -0,0 +1,141 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dm.svh>
/// @brief Debug Module header file
///
`ifndef SCR1_INCLUDE_DM_DEFS
`define SCR1_INCLUDE_DM_DEFS
`include "scr1_arch_description.svh"
`include "scr1_hdu.svh"
`include "scr1_csr.svh"
parameter SCR1_DBG_DMI_ADDR_WIDTH = 6'd7;
parameter SCR1_DBG_DMI_DATA_WIDTH = 6'd32;
parameter SCR1_DBG_DMI_OP_WIDTH = 2'd2;
parameter SCR1_DBG_DMI_CH_ID_WIDTH = 2'd2;
parameter SCR1_DBG_DMI_DR_DTMCS_WIDTH = 6'd32;
parameter SCR1_DBG_DMI_DR_DMI_ACCESS_WIDTH = SCR1_DBG_DMI_OP_WIDTH +
SCR1_DBG_DMI_DATA_WIDTH +
SCR1_DBG_DMI_ADDR_WIDTH;
// Debug Module addresses
parameter SCR1_DBG_DATA0 = 7'h4;
parameter SCR1_DBG_DATA1 = 7'h5;
parameter SCR1_DBG_DMCONTROL = 7'h10;
parameter SCR1_DBG_DMSTATUS = 7'h11;
parameter SCR1_DBG_HARTINFO = 7'h12;
parameter SCR1_DBG_ABSTRACTCS = 7'h16;
parameter SCR1_DBG_COMMAND = 7'h17;
parameter SCR1_DBG_ABSTRACTAUTO = 7'h18;
parameter SCR1_DBG_PROGBUF0 = 7'h20;
parameter SCR1_DBG_PROGBUF1 = 7'h21;
parameter SCR1_DBG_PROGBUF2 = 7'h22;
parameter SCR1_DBG_PROGBUF3 = 7'h23;
parameter SCR1_DBG_PROGBUF4 = 7'h24;
parameter SCR1_DBG_PROGBUF5 = 7'h25;
parameter SCR1_DBG_HALTSUM0 = 7'h40;
// DMCONTROL
parameter SCR1_DBG_DMCONTROL_HALTREQ = 5'd31;
parameter SCR1_DBG_DMCONTROL_RESUMEREQ = 5'd30;
parameter SCR1_DBG_DMCONTROL_HARTRESET = 5'd29;
parameter SCR1_DBG_DMCONTROL_ACKHAVERESET = 5'd28;
parameter SCR1_DBG_DMCONTROL_RESERVEDB = 5'd27;
parameter SCR1_DBG_DMCONTROL_HASEL = 5'd26;
parameter SCR1_DBG_DMCONTROL_HARTSELLO_HI = 5'd25;
parameter SCR1_DBG_DMCONTROL_HARTSELLO_LO = 5'd16;
parameter SCR1_DBG_DMCONTROL_HARTSELHI_HI = 5'd15;
parameter SCR1_DBG_DMCONTROL_HARTSELHI_LO = 5'd6;
parameter SCR1_DBG_DMCONTROL_RESERVEDA_HI = 5'd5;
parameter SCR1_DBG_DMCONTROL_RESERVEDA_LO = 5'd2;
parameter SCR1_DBG_DMCONTROL_NDMRESET = 5'd1;
parameter SCR1_DBG_DMCONTROL_DMACTIVE = 5'd0;
// DMSTATUS
parameter SCR1_DBG_DMSTATUS_RESERVEDC_HI = 5'd31;
parameter SCR1_DBG_DMSTATUS_RESERVEDC_LO = 5'd23;
parameter SCR1_DBG_DMSTATUS_IMPEBREAK = 5'd22;
parameter SCR1_DBG_DMSTATUS_RESERVEDB_HI = 5'd21;
parameter SCR1_DBG_DMSTATUS_RESERVEDB_LO = 5'd20;
parameter SCR1_DBG_DMSTATUS_ALLHAVERESET = 5'd19;
parameter SCR1_DBG_DMSTATUS_ANYHAVERESET = 5'd18;
parameter SCR1_DBG_DMSTATUS_ALLRESUMEACK = 5'd17;
parameter SCR1_DBG_DMSTATUS_ANYRESUMEACK = 5'd16;
parameter SCR1_DBG_DMSTATUS_ALLNONEXISTENT = 5'd15;
parameter SCR1_DBG_DMSTATUS_ANYNONEXISTENT = 5'd14;
parameter SCR1_DBG_DMSTATUS_ALLUNAVAIL = 5'd13;
parameter SCR1_DBG_DMSTATUS_ANYUNAVAIL = 5'd12;
parameter SCR1_DBG_DMSTATUS_ALLRUNNING = 5'd11;
parameter SCR1_DBG_DMSTATUS_ANYRUNNING = 5'd10;
parameter SCR1_DBG_DMSTATUS_ALLHALTED = 5'd9;
parameter SCR1_DBG_DMSTATUS_ANYHALTED = 5'd8;
parameter SCR1_DBG_DMSTATUS_AUTHENTICATED = 5'd7;
parameter SCR1_DBG_DMSTATUS_AUTHBUSY = 5'd6;
parameter SCR1_DBG_DMSTATUS_RESERVEDA = 5'd5;
parameter SCR1_DBG_DMSTATUS_DEVTREEVALID = 5'd4;
parameter SCR1_DBG_DMSTATUS_VERSION_HI = 5'd3;
parameter SCR1_DBG_DMSTATUS_VERSION_LO = 5'd0;
// COMMANDS
parameter SCR1_DBG_COMMAND_TYPE_HI = 5'd31;
parameter SCR1_DBG_COMMAND_TYPE_LO = 5'd24;
parameter SCR1_DBG_COMMAND_TYPE_WDTH = SCR1_DBG_COMMAND_TYPE_HI
- SCR1_DBG_COMMAND_TYPE_LO;
parameter SCR1_DBG_COMMAND_ACCESSREG_RESERVEDB = 5'd23;
parameter SCR1_DBG_COMMAND_ACCESSREG_SIZE_HI = 5'd22;
parameter SCR1_DBG_COMMAND_ACCESSREG_SIZE_LO = 5'd20;
parameter SCR1_DBG_COMMAND_ACCESSREG_SIZE_WDTH = SCR1_DBG_COMMAND_ACCESSREG_SIZE_HI
- SCR1_DBG_COMMAND_ACCESSREG_SIZE_LO;
parameter SCR1_DBG_COMMAND_ACCESSREG_RESERVEDA = 5'd19;
parameter SCR1_DBG_COMMAND_ACCESSREG_POSTEXEC = 5'd18;
parameter SCR1_DBG_COMMAND_ACCESSREG_TRANSFER = 5'd17;
parameter SCR1_DBG_COMMAND_ACCESSREG_WRITE = 5'd16;
parameter SCR1_DBG_COMMAND_ACCESSREG_REGNO_HI = 5'd15;
parameter SCR1_DBG_COMMAND_ACCESSREG_REGNO_LO = 5'd0;
parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMVIRTUAL = 5'd23;
parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_HI = 5'd22;
parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMSIZE_LO = 5'd20;
parameter SCR1_DBG_COMMAND_ACCESSMEM_AAMPOSTINC = 5'd19;
parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_HI = 5'd18;
parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDB_LO = 5'd17;
parameter SCR1_DBG_COMMAND_ACCESSMEM_WRITE = 5'd16;
parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_HI = 5'd13;
parameter SCR1_DBG_COMMAND_ACCESSMEM_RESERVEDA_LO = 5'd0;
// ABSTRACTCS
parameter SCR1_DBG_ABSTRACTCS_RESERVEDD_HI = 5'd31;
parameter SCR1_DBG_ABSTRACTCS_RESERVEDD_LO = 5'd29;
parameter SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_HI = 5'd28;
parameter SCR1_DBG_ABSTRACTCS_PROGBUFSIZE_LO = 5'd24;
parameter SCR1_DBG_ABSTRACTCS_RESERVEDC_HI = 5'd23;
parameter SCR1_DBG_ABSTRACTCS_RESERVEDC_LO = 5'd13;
parameter SCR1_DBG_ABSTRACTCS_BUSY = 5'd12;
parameter SCR1_DBG_ABSTRACTCS_RESERVEDB = 5'd11;
parameter SCR1_DBG_ABSTRACTCS_CMDERR_HI = 5'd10;
parameter SCR1_DBG_ABSTRACTCS_CMDERR_LO = 5'd8;
parameter SCR1_DBG_ABSTRACTCS_CMDERR_WDTH = SCR1_DBG_ABSTRACTCS_CMDERR_HI
- SCR1_DBG_ABSTRACTCS_CMDERR_LO;
parameter SCR1_DBG_ABSTRACTCS_RESERVEDA_HI = 5'd7;
parameter SCR1_DBG_ABSTRACTCS_RESERVEDA_LO = 5'd4;
parameter SCR1_DBG_ABSTRACTCS_DATACOUNT_HI = 5'd3;
parameter SCR1_DBG_ABSTRACTCS_DATACOUNT_LO = 5'd0;
// HARTINFO
parameter SCR1_DBG_HARTINFO_RESERVEDB_HI = 5'd31;
parameter SCR1_DBG_HARTINFO_RESERVEDB_LO = 5'd24;
parameter SCR1_DBG_HARTINFO_NSCRATCH_HI = 5'd23;
parameter SCR1_DBG_HARTINFO_NSCRATCH_LO = 5'd20;
parameter SCR1_DBG_HARTINFO_RESERVEDA_HI = 5'd19;
parameter SCR1_DBG_HARTINFO_RESERVEDA_LO = 5'd17;
parameter SCR1_DBG_HARTINFO_DATAACCESS = 5'd16;
parameter SCR1_DBG_HARTINFO_DATASIZE_HI = 5'd15;
parameter SCR1_DBG_HARTINFO_DATASIZE_LO = 5'd12;
parameter SCR1_DBG_HARTINFO_DATAADDR_HI = 5'd11;
parameter SCR1_DBG_HARTINFO_DATAADDR_LO = 5'd0;
`endif // SCR1_INCLUDE_DM_DEFS

165
src/includes/scr1_hdu.svh Normal file
View File

@@ -0,0 +1,165 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_pipe_hdu.svh>
/// @brief HART Debug Unit definitions file
///
`ifdef SCR1_DBG_EN
`ifndef SCR1_INCLUDE_HDU_DEFS
`define SCR1_INCLUDE_HDU_DEFS
`include "scr1_arch_description.svh"
`include "scr1_csr.svh"
`ifdef SCR1_MMU_EN
`define SCR1_HDU_FEATURE_MPRVEN
`endif // SCR1_MMU_EN
//==============================================================================
// Parameters
//==============================================================================
//localparam int unsigned SCR1_HDU_DEBUGCSR_BASE_ADDR = 12'h7B0;
localparam int unsigned SCR1_HDU_DEBUGCSR_ADDR_SPAN = SCR1_CSR_ADDR_HDU_MSPAN;
localparam int unsigned SCR1_HDU_DEBUGCSR_ADDR_WIDTH = $clog2(SCR1_HDU_DEBUGCSR_ADDR_SPAN);
localparam bit [3:0] SCR1_HDU_DEBUGCSR_DCSR_XDEBUGVER = 4'h4;
localparam int unsigned SCR1_HDU_PBUF_ADDR_SPAN = 8;
localparam int unsigned SCR1_HDU_PBUF_ADDR_WIDTH = $clog2(SCR1_HDU_PBUF_ADDR_SPAN);
localparam int unsigned SCR1_HDU_DATA_REG_WIDTH = 32;
localparam int unsigned SCR1_HDU_CORE_INSTR_WIDTH = 32;
//==============================================================================
// Types
//==============================================================================
// HART Debug States:
typedef enum logic [1:0] {
SCR1_HDU_DBGSTATE_RESET = 2'b00,
SCR1_HDU_DBGSTATE_RUN = 2'b01,
SCR1_HDU_DBGSTATE_DHALTED = 2'b10,
SCR1_HDU_DBGSTATE_DRUN = 2'b11
`ifdef SCR1_XPROP_EN
,
SCR1_HDU_DBGSTATE_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_hdu_dbgstates_e;
typedef enum logic [1:0] {
SCR1_HDU_PBUFSTATE_IDLE = 2'b00,
SCR1_HDU_PBUFSTATE_FETCH = 2'b01,
SCR1_HDU_PBUFSTATE_EXCINJECT = 2'b10,
SCR1_HDU_PBUFSTATE_WAIT4END = 2'b11
`ifdef SCR1_XPROP_EN
,
SCR1_HDU_PBUFSTATE_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_hdu_pbufstates_e;
typedef enum logic {
SCR1_HDU_HARTCMD_RESUME = 1'b0,
SCR1_HDU_HARTCMD_HALT = 1'b1
`ifdef SCR1_XPROP_EN
,
SCR1_HDU_HARTCMD_XXX = 1'bX
`endif // SCR1_XPROP_EN
} type_scr1_hdu_hart_command_e;
typedef enum logic {
SCR1_HDU_FETCH_SRC_NORMAL = 1'b0,
SCR1_HDU_FETCH_SRC_PBUF = 1'b1
`ifdef SCR1_XPROP_EN
,
SCR1_HDU_FETCH_SRC_XXX = 1'bX
`endif // SCR1_XPROP_EN
} type_scr1_hdu_fetch_src_e;
typedef struct packed {
//logic reset_n;
logic except;
logic ebreak;
type_scr1_hdu_dbgstates_e dbg_state;
} type_scr1_hdu_hartstatus_s;
// Debug Mode Redirection control:
typedef struct packed {
logic sstep; // Single Step
logic ebreak; // Redirection after EBREAK execution
} type_scr1_hdu_redirect_s;
typedef struct packed {
logic irq_dsbl;
type_scr1_hdu_fetch_src_e fetch_src;
logic pc_advmt_dsbl;
logic hwbrkpt_dsbl;
type_scr1_hdu_redirect_s redirect;
} type_scr1_hdu_runctrl_s;
// HART Halt Status:
typedef enum logic [2:0] {
SCR1_HDU_HALTCAUSE_NONE = 3'b000,
SCR1_HDU_HALTCAUSE_EBREAK = 3'b001,
SCR1_HDU_HALTCAUSE_TMREQ = 3'b010,
SCR1_HDU_HALTCAUSE_DMREQ = 3'b011,
SCR1_HDU_HALTCAUSE_SSTEP = 3'b100,
SCR1_HDU_HALTCAUSE_RSTEXIT = 3'b101
`ifdef SCR1_XPROP_EN
,
SCR1_HDU_HALTCAUSE_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_hdu_haltcause_e;
typedef struct packed {
logic except;
type_scr1_hdu_haltcause_e cause;
} type_scr1_hdu_haltstatus_s;
// Debug CSR map
localparam SCR1_HDU_DBGCSR_OFFS_DCSR = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd0 );
localparam SCR1_HDU_DBGCSR_OFFS_DPC = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd1 );
localparam SCR1_HDU_DBGCSR_OFFS_DSCRATCH0 = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd2 );
localparam SCR1_HDU_DBGCSR_OFFS_DSCRATCH1 = SCR1_HDU_DEBUGCSR_ADDR_WIDTH'( 'd3 );
localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DCSR = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DCSR;
localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DPC = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DPC;
localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DSCRATCH0 = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DSCRATCH0;
localparam bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_HDU_DBGCSR_ADDR_DSCRATCH1 = SCR1_CSR_ADDR_HDU_MBASE + SCR1_HDU_DBGCSR_OFFS_DSCRATCH1;
// Debug CSRs :: DCSR
typedef enum int {
SCR1_HDU_DCSR_PRV_BIT_R = 0,
SCR1_HDU_DCSR_PRV_BIT_L = 1,
SCR1_HDU_DCSR_STEP_BIT = 2,
SCR1_HDU_DCSR_RSRV0_BIT_R = 3,
SCR1_HDU_DCSR_RSRV0_BIT_L = 5,
SCR1_HDU_DCSR_CAUSE_BIT_R = 6,
SCR1_HDU_DCSR_CAUSE_BIT_L = 8,
SCR1_HDU_DCSR_RSRV1_BIT_R = 9,
SCR1_HDU_DCSR_RSRV1_BIT_L = 10,
SCR1_HDU_DCSR_STEPIE_BIT = 11,
SCR1_HDU_DCSR_RSRV2_BIT_R = 12,
SCR1_HDU_DCSR_RSRV2_BIT_L = 14,
SCR1_HDU_DCSR_EBREAKM_BIT = 15,
SCR1_HDU_DCSR_RSRV3_BIT_R = 16,
SCR1_HDU_DCSR_RSRV3_BIT_L = 27,
SCR1_HDU_DCSR_XDEBUGVER_BIT_R = 28,
SCR1_HDU_DCSR_XDEBUGVER_BIT_L = 31
} type_scr1_hdu_dcsr_bits_e;
//localparam int unsigned SCR1_HDU_DEBUGCSR_DCSR_PRV_WIDTH = SCR1_HDU_DCSR_PRV_BIT_L-SCR1_HDU_DCSR_PRV_BIT_R+1;
typedef struct packed {
logic [SCR1_HDU_DCSR_XDEBUGVER_BIT_L-SCR1_HDU_DCSR_XDEBUGVER_BIT_R:0] xdebugver;
logic [SCR1_HDU_DCSR_RSRV3_BIT_L-SCR1_HDU_DCSR_RSRV3_BIT_R:0] rsrv3;
logic ebreakm;
logic [SCR1_HDU_DCSR_RSRV2_BIT_L-SCR1_HDU_DCSR_RSRV2_BIT_R:0] rsrv2;
logic stepie;
logic [SCR1_HDU_DCSR_RSRV1_BIT_L-SCR1_HDU_DCSR_RSRV1_BIT_R:0] rsrv1;
logic [SCR1_HDU_DCSR_CAUSE_BIT_L-SCR1_HDU_DCSR_CAUSE_BIT_R:0] cause;
logic [SCR1_HDU_DCSR_RSRV0_BIT_L-SCR1_HDU_DCSR_RSRV0_BIT_R:0] rsrv0;
logic step;
logic [SCR1_HDU_DCSR_PRV_BIT_L-SCR1_HDU_DCSR_PRV_BIT_R:0] prv;
} type_scr1_hdu_dcsr_s;
`endif // SCR1_INCLUDE_HDU_DEFS
`endif // SCR1_DBG_EN

View File

@@ -0,0 +1,58 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_ipic.svh>
/// @brief IPIC header file
///
`ifndef SCR1_IPIC_SVH
`define SCR1_IPIC_SVH
`include "scr1_arch_description.svh"
`ifdef SCR1_IPIC_EN
//-------------------------------------------------------------------------------
// Parameters declaration
//-------------------------------------------------------------------------------
parameter SCR1_IRQ_VECT_NUM = 16; // must be power of 2 in the current implementation
parameter SCR1_IRQ_VECT_WIDTH = $clog2(SCR1_IRQ_VECT_NUM+1);
parameter SCR1_IRQ_LINES_NUM = SCR1_IRQ_VECT_NUM;
parameter SCR1_IRQ_LINES_WIDTH = $clog2(SCR1_IRQ_LINES_NUM);
parameter logic [SCR1_IRQ_VECT_WIDTH-1:0] SCR1_IRQ_VOID_VECT_NUM = SCR1_IRQ_VECT_WIDTH'(SCR1_IRQ_VECT_NUM);
parameter SCR1_IRQ_IDX_WIDTH = $clog2(SCR1_IRQ_VECT_NUM);
// Address decoding parameters
parameter logic [2:0] SCR1_IPIC_CISV = 3'h0; // RO
parameter logic [2:0] SCR1_IPIC_CICSR = 3'h1; // {IP, IE}
parameter logic [2:0] SCR1_IPIC_IPR = 3'h2; // RW1C
parameter logic [2:0] SCR1_IPIC_ISVR = 3'h3; // RO
parameter logic [2:0] SCR1_IPIC_EOI = 3'h4; // RZW
parameter logic [2:0] SCR1_IPIC_SOI = 3'h5; // RZW
parameter logic [2:0] SCR1_IPIC_IDX = 3'h6; // RW
parameter logic [2:0] SCR1_IPIC_ICSR = 3'h7; // RW
parameter SCR1_IPIC_ICSR_IP = 0;
parameter SCR1_IPIC_ICSR_IE = 1;
parameter SCR1_IPIC_ICSR_IM = 2;
parameter SCR1_IPIC_ICSR_INV = 3;
parameter SCR1_IPIC_ICSR_IS = 4;
parameter SCR1_IPIC_ICSR_PRV_LSB = 8;
parameter SCR1_IPIC_ICSR_PRV_MSB = 9;
parameter SCR1_IPIC_ICSR_LN_LSB = 12;
parameter SCR1_IPIC_ICSR_LN_MSB = SCR1_IPIC_ICSR_LN_LSB
+ SCR1_IRQ_LINES_WIDTH;
parameter logic [1:0] SCR1_IPIC_PRV_M = 2'b11;
//-------------------------------------------------------------------------------
// Types declaration
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_CSR2IPIC_RD,
SCR1_CSR2IPIC_WR
`ifdef SCR1_XPROP_EN
,
SCR1_CSR2IPIC_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_csr2ipic_wr_e;
`endif // SCR1_IPIC_EN
`endif // SCR1_IPIC_SVH

View File

@@ -0,0 +1,49 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_memif.svh>
/// @brief Memory interface definitions file
///
`ifndef SCR1_MEMIF_SVH
`define SCR1_MEMIF_SVH
`include "scr1_arch_description.svh"
//-------------------------------------------------------------------------------
// Memory command enum
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_MEM_CMD_RD = 1'b0,
SCR1_MEM_CMD_WR = 1'b1
`ifdef SCR1_XPROP_EN
,
SCR1_MEM_CMD_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_mem_cmd_e;
//-------------------------------------------------------------------------------
// Memory data width enum
//-------------------------------------------------------------------------------
typedef enum logic[1:0] {
SCR1_MEM_WIDTH_BYTE = 2'b00,
SCR1_MEM_WIDTH_HWORD = 2'b01,
SCR1_MEM_WIDTH_WORD = 2'b10
`ifdef SCR1_XPROP_EN
,
SCR1_MEM_WIDTH_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_mem_width_e;
//-------------------------------------------------------------------------------
// Memory response enum
//-------------------------------------------------------------------------------
typedef enum logic[1:0] {
SCR1_MEM_RESP_NOTRDY = 2'b00,
SCR1_MEM_RESP_RDY_OK = 2'b01,
SCR1_MEM_RESP_RDY_ER = 2'b10
`ifdef SCR1_XPROP_EN
,
SCR1_MEM_RESP_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_mem_resp_e;
`endif // SCR1_MEMIF_SVH

View File

@@ -0,0 +1,185 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_riscv_isa_decoding.svh>
/// @brief RISC-V ISA definitions file
///
`ifndef SCR1_RISCV_ISA_DECODING_SVH
`define SCR1_RISCV_ISA_DECODING_SVH
`include "scr1_arch_description.svh"
`include "scr1_arch_types.svh"
//-------------------------------------------------------------------------------
// Instruction types
//-------------------------------------------------------------------------------
typedef enum logic [1:0] {
SCR1_INSTR_RVC0 = 2'b00,
SCR1_INSTR_RVC1 = 2'b01,
SCR1_INSTR_RVC2 = 2'b10,
SCR1_INSTR_RVI = 2'b11
} type_scr1_instr_type_e;
//-------------------------------------------------------------------------------
// RV32I opcodes (bits 6:2)
//-------------------------------------------------------------------------------
typedef enum logic [6:2] {
SCR1_OPCODE_LOAD = 5'b00000,
SCR1_OPCODE_MISC_MEM = 5'b00011,
SCR1_OPCODE_OP_IMM = 5'b00100,
SCR1_OPCODE_AUIPC = 5'b00101,
SCR1_OPCODE_STORE = 5'b01000,
SCR1_OPCODE_OP = 5'b01100,
SCR1_OPCODE_LUI = 5'b01101,
SCR1_OPCODE_BRANCH = 5'b11000,
SCR1_OPCODE_JALR = 5'b11001,
SCR1_OPCODE_JAL = 5'b11011,
SCR1_OPCODE_SYSTEM = 5'b11100
} type_scr1_rvi_opcode_e;
//-------------------------------------------------------------------------------
// IALU main operands
//-------------------------------------------------------------------------------
localparam SCR1_IALU_OP_ALL_NUM_E = 2;
localparam SCR1_IALU_OP_WIDTH_E = $clog2(SCR1_IALU_OP_ALL_NUM_E);
typedef enum logic [SCR1_IALU_OP_WIDTH_E-1:0] {
SCR1_IALU_OP_REG_IMM, // op1 = rs1; op2 = imm
SCR1_IALU_OP_REG_REG // op1 = rs1; op2 = rs2
} type_scr1_ialu_op_sel_e;
//-------------------------------------------------------------------------------
// IALU main commands
//-------------------------------------------------------------------------------
`ifdef SCR1_RVM_EXT
localparam SCR1_IALU_CMD_ALL_NUM_E = 23;
`else // ~SCR1_RVM_EXT
localparam SCR1_IALU_CMD_ALL_NUM_E = 15;
`endif // ~SCR1_RVM_EXT
localparam SCR1_IALU_CMD_WIDTH_E = $clog2(SCR1_IALU_CMD_ALL_NUM_E);
typedef enum logic [SCR1_IALU_CMD_WIDTH_E-1:0] {
SCR1_IALU_CMD_NONE = '0, // IALU disable
SCR1_IALU_CMD_AND, // op1 & op2
SCR1_IALU_CMD_OR, // op1 | op2
SCR1_IALU_CMD_XOR, // op1 ^ op2
SCR1_IALU_CMD_ADD, // op1 + op2
SCR1_IALU_CMD_SUB, // op1 - op2
SCR1_IALU_CMD_SUB_LT, // op1 < op2
SCR1_IALU_CMD_SUB_LTU, // op1 u< op2
SCR1_IALU_CMD_SUB_EQ, // op1 = op2
SCR1_IALU_CMD_SUB_NE, // op1 != op2
SCR1_IALU_CMD_SUB_GE, // op1 >= op2
SCR1_IALU_CMD_SUB_GEU, // op1 u>= op2
SCR1_IALU_CMD_SLL, // op1 << op2
SCR1_IALU_CMD_SRL, // op1 >> op2
SCR1_IALU_CMD_SRA // op1 >>> op2
`ifdef SCR1_RVM_EXT
,
SCR1_IALU_CMD_MUL, // low(unsig(op1) * unsig(op2))
SCR1_IALU_CMD_MULHU, // high(unsig(op1) * unsig(op2))
SCR1_IALU_CMD_MULHSU, // high(op1 * unsig(op2))
SCR1_IALU_CMD_MULH, // high(op1 * op2)
SCR1_IALU_CMD_DIV, // op1 / op2
SCR1_IALU_CMD_DIVU, // op1 u/ op2
SCR1_IALU_CMD_REM, // op1 % op2
SCR1_IALU_CMD_REMU // op1 u% op2
`endif // SCR1_RVM_EXT
} type_scr1_ialu_cmd_sel_e;
//-------------------------------------------------------------------------------
// IALU SUM2 operands (result is JUMP/BRANCH target, LOAD/STORE address)
//-------------------------------------------------------------------------------
localparam SCR1_SUM2_OP_ALL_NUM_E = 2;
localparam SCR1_SUM2_OP_WIDTH_E = $clog2(SCR1_SUM2_OP_ALL_NUM_E);
typedef enum logic [SCR1_SUM2_OP_WIDTH_E-1:0] {
SCR1_SUM2_OP_PC_IMM, // op1 = curr_pc; op2 = imm (AUIPC, target new_pc for JAL and branches)
SCR1_SUM2_OP_REG_IMM // op1 = rs1; op2 = imm (target new_pc for JALR, LOAD/STORE address)
`ifdef SCR1_XPROP_EN
,
SCR1_SUM2_OP_ERROR = 'x
`endif // SCR1_XPROP_EN
} type_scr1_ialu_sum2_op_sel_e;
//-------------------------------------------------------------------------------
// LSU commands
//-------------------------------------------------------------------------------
localparam SCR1_LSU_CMD_ALL_NUM_E = 9;
localparam SCR1_LSU_CMD_WIDTH_E = $clog2(SCR1_LSU_CMD_ALL_NUM_E);
typedef enum logic [SCR1_LSU_CMD_WIDTH_E-1:0] {
SCR1_LSU_CMD_NONE = '0,
SCR1_LSU_CMD_LB,
SCR1_LSU_CMD_LH,
SCR1_LSU_CMD_LW,
SCR1_LSU_CMD_LBU,
SCR1_LSU_CMD_LHU,
SCR1_LSU_CMD_SB,
SCR1_LSU_CMD_SH,
SCR1_LSU_CMD_SW
} type_scr1_lsu_cmd_sel_e;
//-------------------------------------------------------------------------------
// CSR operands
//-------------------------------------------------------------------------------
localparam SCR1_CSR_OP_ALL_NUM_E = 2;
localparam SCR1_CSR_OP_WIDTH_E = $clog2(SCR1_CSR_OP_ALL_NUM_E);
typedef enum logic [SCR1_CSR_OP_WIDTH_E-1:0] {
SCR1_CSR_OP_IMM,
SCR1_CSR_OP_REG
} type_scr1_csr_op_sel_e;
//-------------------------------------------------------------------------------
// CSR commands
//-------------------------------------------------------------------------------
localparam SCR1_CSR_CMD_ALL_NUM_E = 4;
localparam SCR1_CSR_CMD_WIDTH_E = $clog2(SCR1_CSR_CMD_ALL_NUM_E);
typedef enum logic [SCR1_CSR_CMD_WIDTH_E-1:0] {
SCR1_CSR_CMD_NONE = '0,
SCR1_CSR_CMD_WRITE,
SCR1_CSR_CMD_SET,
SCR1_CSR_CMD_CLEAR
} type_scr1_csr_cmd_sel_e;
//-------------------------------------------------------------------------------
// MPRF rd writeback source
//-------------------------------------------------------------------------------
localparam SCR1_RD_WB_ALL_NUM_E = 7;
localparam SCR1_RD_WB_WIDTH_E = $clog2(SCR1_RD_WB_ALL_NUM_E);
typedef enum logic [SCR1_RD_WB_WIDTH_E-1:0] {
SCR1_RD_WB_NONE = '0,
SCR1_RD_WB_IALU, // IALU main result
SCR1_RD_WB_SUM2, // IALU SUM2 result (AUIPC)
SCR1_RD_WB_IMM, // LUI
SCR1_RD_WB_INC_PC, // JAL(R)
SCR1_RD_WB_LSU, // Load from DMEM
SCR1_RD_WB_CSR // Read CSR
} type_scr1_rd_wb_sel_e;
//-------------------------------------------------------------------------------
// IDU to EXU full command structure
//-------------------------------------------------------------------------------
localparam SCR1_GPR_FIELD_WIDTH = 5;
typedef struct packed {
logic instr_rvc; // used with a different meaning for IFU access fault exception
type_scr1_ialu_op_sel_e ialu_op;
type_scr1_ialu_cmd_sel_e ialu_cmd;
type_scr1_ialu_sum2_op_sel_e sum2_op;
type_scr1_lsu_cmd_sel_e lsu_cmd;
type_scr1_csr_op_sel_e csr_op;
type_scr1_csr_cmd_sel_e csr_cmd;
type_scr1_rd_wb_sel_e rd_wb_sel;
logic jump_req;
logic branch_req;
logic mret_req;
logic fencei_req;
logic wfi_req;
logic [SCR1_GPR_FIELD_WIDTH-1:0] rs1_addr; // also used as zimm for CSRRxI instructions
logic [SCR1_GPR_FIELD_WIDTH-1:0] rs2_addr;
logic [SCR1_GPR_FIELD_WIDTH-1:0] rd_addr;
logic [`SCR1_XLEN-1:0] imm; // used as {funct3, CSR address} for CSR instructions
// used as instruction field for illegal instruction exception
logic exc_req;
type_scr1_exc_code_e exc_code;
} type_scr1_exu_cmd_s;
`endif // SCR1_RISCV_ISA_DECODING_SVH

84
src/includes/scr1_scu.svh Normal file
View File

@@ -0,0 +1,84 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_scu.svh>
/// @brief SCU header file
///
`ifndef SCR1_INCLUDE_SCU_DEFS
`define SCR1_INCLUDE_SCU_DEFS
//`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
//==============================================================================
// Parameters
//==============================================================================
localparam int unsigned SCR1_SCU_DR_SYSCTRL_OP_WIDTH = 2;
localparam int unsigned SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH = 2;
localparam int unsigned SCR1_SCU_DR_SYSCTRL_DATA_WIDTH = 4;
//==============================================================================
// Types
//==============================================================================
typedef enum logic [SCR1_SCU_DR_SYSCTRL_OP_WIDTH-1:0] {
SCR1_SCU_SYSCTRL_OP_WRITE = 2'h0,
SCR1_SCU_SYSCTRL_OP_READ = 2'h1,
SCR1_SCU_SYSCTRL_OP_SETBITS = 2'h2,
SCR1_SCU_SYSCTRL_OP_CLRBITS = 2'h3
`ifdef SCR1_XPROP_EN
,
SCR1_SCU_SYSCTRL_OP_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_scu_sysctrl_op_e;
typedef enum logic [SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH-1:0] {
SCR1_SCU_SYSCTRL_ADDR_CONTROL = 2'h0,
SCR1_SCU_SYSCTRL_ADDR_MODE = 2'h1,
SCR1_SCU_SYSCTRL_ADDR_STATUS = 2'h2,
SCR1_SCU_SYSCTRL_ADDR_STICKY = 2'h3
`ifdef SCR1_XPROP_EN
,
SCR1_SCU_SYSCTRL_ADDR_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_scu_sysctrl_addr_e;
typedef struct packed {
logic [SCR1_SCU_DR_SYSCTRL_DATA_WIDTH-1:0] data;
logic [SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH-1:0] addr;
logic [SCR1_SCU_DR_SYSCTRL_OP_WIDTH-1:0] op;
} type_scr1_scu_sysctrl_dr_s;
typedef enum int unsigned {
SCR1_SCU_DR_SYSCTRL_OP_BIT_R = 'h0,
SCR1_SCU_DR_SYSCTRL_OP_BIT_L = SCR1_SCU_DR_SYSCTRL_OP_WIDTH-1,
SCR1_SCU_DR_SYSCTRL_ADDR_BIT_R = SCR1_SCU_DR_SYSCTRL_OP_WIDTH,
SCR1_SCU_DR_SYSCTRL_ADDR_BIT_L = SCR1_SCU_DR_SYSCTRL_OP_WIDTH +
SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH - 1,
SCR1_SCU_DR_SYSCTRL_DATA_BIT_R = SCR1_SCU_DR_SYSCTRL_OP_WIDTH +
SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH,
SCR1_SCU_DR_SYSCTRL_DATA_BIT_L = SCR1_SCU_DR_SYSCTRL_OP_WIDTH +
SCR1_SCU_DR_SYSCTRL_ADDR_WIDTH +
SCR1_SCU_DR_SYSCTRL_DATA_WIDTH - 1
} type_scr1_scu_sysctrl_dr_bits_e;
typedef struct packed {
logic [1:0] rsrv;
logic core_reset;
logic sys_reset;
} type_scr1_scu_sysctrl_control_reg_s;
typedef struct packed {
logic [1:0] rsrv;
logic hdu_rst_bhv;
logic dm_rst_bhv;
} type_scr1_scu_sysctrl_mode_reg_s;
typedef struct packed {
logic hdu_reset;
logic dm_reset;
logic core_reset;
logic sys_reset;
} type_scr1_scu_sysctrl_status_reg_s;
`endif // SCR1_DBG_EN
`endif // SCR1_INCLUDE_SCU_DEFS

View File

@@ -0,0 +1,94 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_search_ms1.svh>
/// @brief Most significant one search function
///
`ifndef SCR1_SEARCH_MS1_SVH
`define SCR1_SEARCH_MS1_SVH
//-------------------------------------------------------------------------------
// Local types declaration
//-------------------------------------------------------------------------------
typedef struct {
logic vd;
logic idx;
} type_scr1_search_one_2_s;
typedef struct {
logic vd;
logic [4:0] idx;
} type_scr1_search_one_32_s;
//-------------------------------------------------------------------------------
// Leading Zeros Count Function
//-------------------------------------------------------------------------------
function automatic type_scr1_search_one_2_s scr1_lead_zeros_cnt_2(
input logic [1:0] din
);
type_scr1_search_one_2_s tmp;
begin
tmp.vd = |din;
tmp.idx = ~din[1];
return tmp;
end
endfunction : scr1_lead_zeros_cnt_2
function automatic logic [4:0] scr1_lead_zeros_cnt_32(
input logic [31:0] din
);
begin
logic [15:0] stage1_vd;
logic [7:0] stage2_vd;
logic [3:0] stage3_vd;
logic [1:0] stage4_vd;
logic stage1_idx [15:0];
logic [1:0] stage2_idx [7:0];
logic [2:0] stage3_idx [3:0];
logic [3:0] stage4_idx [1:0];
type_scr1_search_one_32_s tmp;
logic [4:0] res;
// Stage 1
for (int unsigned i=0; i<16; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_lead_zeros_cnt_2(din[(i+1)*2-1-:2]);
stage1_vd[i] = tmp.vd;
stage1_idx[i] = tmp.idx;
end
// Stage 2
for (int unsigned i=0; i<8; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_lead_zeros_cnt_2(stage1_vd[(i+1)*2-1-:2]);
stage2_vd[i] = tmp.vd;
stage2_idx[i] = (tmp.idx) ? {tmp.idx, stage1_idx[2*i]} : {tmp.idx, stage1_idx[2*i+1]};
end
// Stage 3
for (int unsigned i=0; i<4; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_lead_zeros_cnt_2(stage2_vd[(i+1)*2-1-:2]);
stage3_vd[i] = tmp.vd;
stage3_idx[i] = (tmp.idx) ? {tmp.idx, stage2_idx[2*i]} : {tmp.idx, stage2_idx[2*i+1]};
end
// Stage 4
for (int unsigned i=0; i<2; ++i) begin
type_scr1_search_one_2_s tmp;
tmp = scr1_lead_zeros_cnt_2(stage3_vd[(i+1)*2-1-:2]);
stage4_vd[i] = tmp.vd;
stage4_idx[i] = (tmp.idx) ? {tmp.idx, stage3_idx[2*i]} : {tmp.idx, stage3_idx[2*i+1]};
end
// Stage 5
tmp.vd = |stage4_vd;
tmp.idx = (stage4_vd[1]) ? {1'b0, stage4_idx[1]} : {1'b1, stage4_idx[0]};
res = tmp.idx;
return res;
end
endfunction : scr1_lead_zeros_cnt_32
`endif // SCR1_SEARCH_MS1_SVH

View File

@@ -0,0 +1,66 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tapc.svh>
/// @brief TAPC header file
///
`ifndef SCR1_INCLUDE_TAPC_DEFS
`define SCR1_INCLUDE_TAPC_DEFS
`include "scr1_arch_description.svh"
`ifdef SCR1_DBG_EN
//==============================================================================
// Parameters
//==============================================================================
localparam int unsigned SCR1_TAP_STATE_WIDTH = 4;
localparam int unsigned SCR1_TAP_INSTRUCTION_WIDTH = 5;
localparam int unsigned SCR1_TAP_DR_IDCODE_WIDTH = 32;
localparam int unsigned SCR1_TAP_DR_BLD_ID_WIDTH = 32;
localparam int unsigned SCR1_TAP_DR_BYPASS_WIDTH = 1;
//localparam bit [SCR1_TAP_DR_IDCODE_WIDTH-1:0] SCR1_TAP_IDCODE_RISCV_SC = `SCR1_TAP_IDCODE;
localparam bit [SCR1_TAP_DR_BLD_ID_WIDTH-1:0] SCR1_TAP_BLD_ID_VALUE = `SCR1_MIMPID;
//==============================================================================
// Types
//==============================================================================
typedef enum logic [SCR1_TAP_STATE_WIDTH-1:0] {
SCR1_TAP_STATE_RESET,
SCR1_TAP_STATE_IDLE,
SCR1_TAP_STATE_DR_SEL_SCAN,
SCR1_TAP_STATE_DR_CAPTURE,
SCR1_TAP_STATE_DR_SHIFT,
SCR1_TAP_STATE_DR_EXIT1,
SCR1_TAP_STATE_DR_PAUSE,
SCR1_TAP_STATE_DR_EXIT2,
SCR1_TAP_STATE_DR_UPDATE,
SCR1_TAP_STATE_IR_SEL_SCAN,
SCR1_TAP_STATE_IR_CAPTURE,
SCR1_TAP_STATE_IR_SHIFT,
SCR1_TAP_STATE_IR_EXIT1,
SCR1_TAP_STATE_IR_PAUSE,
SCR1_TAP_STATE_IR_EXIT2,
SCR1_TAP_STATE_IR_UPDATE
`ifdef SCR1_XPROP_EN
,
SCR1_TAP_STATE_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_tap_state_e;
typedef enum logic [SCR1_TAP_INSTRUCTION_WIDTH - 1:0] {
SCR1_TAP_INSTR_IDCODE = 5'h01,
SCR1_TAP_INSTR_BLD_ID = 5'h04,
SCR1_TAP_INSTR_SCU_ACCESS = 5'h09,
SCR1_TAP_INSTR_DTMCS = 5'h10,
SCR1_TAP_INSTR_DMI_ACCESS = 5'h11,
SCR1_TAP_INSTR_BYPASS = 5'h1F
`ifdef SCR1_XPROP_EN
,
SCR1_TAP_INSTR_XXX = 'X
`endif // SCR1_XPROP_EN
} type_scr1_tap_instr_e;
`endif // SCR1_DBG_EN
`endif // SCR1_INCLUDE_TAPC_DEFS

121
src/includes/scr1_tdu.svh Normal file
View File

@@ -0,0 +1,121 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_tdu.svh>
/// @brief Trigger Debug Module header
///
`ifndef SCR1_INCLUDE_TDU_DEFS
`define SCR1_INCLUDE_TDU_DEFS
//`include "scr1_arch_description.svh"
`ifdef SCR1_TDU_EN
//`include "scr1_csr.svh"
`include "scr1_arch_description.svh"
//`include "scr1_arch_types.svh"
`include "scr1_csr.svh"
parameter int unsigned SCR1_TDU_MTRIG_NUM = SCR1_TDU_TRIG_NUM;
`ifdef SCR1_TDU_ICOUNT_EN
parameter int unsigned SCR1_TDU_ALLTRIG_NUM = SCR1_TDU_MTRIG_NUM + 1'b1;
`else
parameter int unsigned SCR1_TDU_ALLTRIG_NUM = SCR1_TDU_MTRIG_NUM;
`endif
parameter int unsigned SCR1_TDU_ADDR_W = `SCR1_XLEN;
parameter int unsigned SCR1_TDU_DATA_W = `SCR1_XLEN;
// Register map
parameter SCR1_CSR_ADDR_TDU_OFFS_W = 3;
parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TSELECT = SCR1_CSR_ADDR_TDU_OFFS_W'(0);
parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TDATA1 = SCR1_CSR_ADDR_TDU_OFFS_W'(1);
parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TDATA2 = SCR1_CSR_ADDR_TDU_OFFS_W'(2);
parameter bit [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] SCR1_CSR_ADDR_TDU_OFFS_TINFO = SCR1_CSR_ADDR_TDU_OFFS_W'(4);
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TSELECT = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TSELECT;
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TDATA1 = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TDATA1;
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TDATA2 = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TDATA2;
parameter bit [SCR1_CSR_ADDR_WIDTH-1:0] SCR1_CSR_ADDR_TDU_TINFO = SCR1_CSR_ADDR_TDU_MBASE + SCR1_CSR_ADDR_TDU_OFFS_TINFO;
// TDATA1
parameter int unsigned SCR1_TDU_TDATA1_TYPE_HI = `SCR1_XLEN-1;
parameter int unsigned SCR1_TDU_TDATA1_TYPE_LO = `SCR1_XLEN-4;
parameter int unsigned SCR1_TDU_TDATA1_DMODE = `SCR1_XLEN-5;
// TDATA1: constant bits values
parameter bit SCR1_TDU_TDATA1_DMODE_VAL = 1'b0;
// MCONTROL: bits number
parameter int unsigned SCR1_TDU_MCONTROL_MASKMAX_HI = `SCR1_XLEN-6;
parameter int unsigned SCR1_TDU_MCONTROL_MASKMAX_LO = `SCR1_XLEN-11;
parameter int unsigned SCR1_TDU_MCONTROL_RESERVEDB_HI = `SCR1_XLEN-12;
parameter int unsigned SCR1_TDU_MCONTROL_RESERVEDB_LO = 21;
parameter int unsigned SCR1_TDU_MCONTROL_HIT = 20;
parameter int unsigned SCR1_TDU_MCONTROL_SELECT = 19;
parameter int unsigned SCR1_TDU_MCONTROL_TIMING = 18;
parameter int unsigned SCR1_TDU_MCONTROL_ACTION_HI = 17;
parameter int unsigned SCR1_TDU_MCONTROL_ACTION_LO = 12;
parameter int unsigned SCR1_TDU_MCONTROL_CHAIN = 11;
parameter int unsigned SCR1_TDU_MCONTROL_MATCH_HI = 10;
parameter int unsigned SCR1_TDU_MCONTROL_MATCH_LO = 7;
parameter int unsigned SCR1_TDU_MCONTROL_M = 6;
parameter int unsigned SCR1_TDU_MCONTROL_RESERVEDA = 5;
parameter int unsigned SCR1_TDU_MCONTROL_S = 4;
parameter int unsigned SCR1_TDU_MCONTROL_U = 3;
parameter int unsigned SCR1_TDU_MCONTROL_EXECUTE = 2;
parameter int unsigned SCR1_TDU_MCONTROL_STORE = 1;
parameter int unsigned SCR1_TDU_MCONTROL_LOAD = 0;
// MCONTROL: constant bits values
parameter bit [SCR1_TDU_TDATA1_TYPE_HI-SCR1_TDU_TDATA1_TYPE_LO:0]
SCR1_TDU_MCONTROL_TYPE_VAL = 2'd2;
parameter bit SCR1_TDU_MCONTROL_SELECT_VAL = 1'b0;
parameter bit SCR1_TDU_MCONTROL_TIMING_VAL = 1'b0;
parameter bit [SCR1_TDU_MCONTROL_MASKMAX_HI-SCR1_TDU_MCONTROL_MASKMAX_LO:0]
SCR1_TDU_MCONTROL_MASKMAX_VAL = 1'b0;
parameter bit SCR1_TDU_MCONTROL_RESERVEDA_VAL = 1'b0;
// ICOUNT: bits number
parameter int unsigned SCR1_TDU_ICOUNT_DMODE = `SCR1_XLEN-5;
parameter int unsigned SCR1_TDU_ICOUNT_RESERVEDB_HI = `SCR1_XLEN-6;
parameter int unsigned SCR1_TDU_ICOUNT_RESERVEDB_LO = 25;
parameter int unsigned SCR1_TDU_ICOUNT_HIT = 24;
parameter int unsigned SCR1_TDU_ICOUNT_COUNT_HI = 23;
parameter int unsigned SCR1_TDU_ICOUNT_COUNT_LO = 10;
parameter int unsigned SCR1_TDU_ICOUNT_M = 9;
parameter int unsigned SCR1_TDU_ICOUNT_RESERVEDA = 8;
parameter int unsigned SCR1_TDU_ICOUNT_S = 7;
parameter int unsigned SCR1_TDU_ICOUNT_U = 6;
parameter int unsigned SCR1_TDU_ICOUNT_ACTION_HI = 5;
parameter int unsigned SCR1_TDU_ICOUNT_ACTION_LO = 0;
// ICOUNT: constant bits values
parameter bit [SCR1_TDU_TDATA1_TYPE_HI-SCR1_TDU_TDATA1_TYPE_LO:0]
SCR1_TDU_ICOUNT_TYPE_VAL = 2'd3;
parameter bit [SCR1_TDU_ICOUNT_RESERVEDB_HI-SCR1_TDU_ICOUNT_RESERVEDB_LO:0]
SCR1_TDU_ICOUNT_RESERVEDB_VAL = 1'b0;
parameter bit SCR1_TDU_ICOUNT_RESERVEDA_VAL = 1'b0;
// CPU pipeline monitors
typedef struct packed {
logic vd;
logic req;
logic [`SCR1_XLEN-1:0] addr;
} type_scr1_brkm_instr_mon_s;
typedef struct packed {
logic vd;
logic load;
logic store;
logic [`SCR1_XLEN-1:0] addr;
} type_scr1_brkm_lsu_mon_s;
`endif // SCR1_TDU_EN
`endif // SCR1_INCLUDE_TDU_DEFS

View File

@@ -0,0 +1,601 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_memory_tb_ahb.sv>
/// @brief AHB memory testbench
///
`include "scr1_arch_description.svh"
`include "scr1_ahb.svh"
`include "scr1_ipic.svh"
module scr1_memory_tb_ahb #(
parameter SCR1_MEM_POWER_SIZE = 16
)
(
// Control
input logic rst_n,
input logic clk,
`ifdef SCR1_IPIC_EN
output logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines,
`else // SCR1_IPIC_EN
output logic ext_irq,
`endif // SCR1_IPIC_EN
output logic soft_irq,
input integer imem_req_ack_stall_in,
input integer dmem_req_ack_stall_in,
// Instruction Memory Interface
// input logic [3:0] imem_hprot,
// input logic [2:0] imem_hburst,
input logic [2:0] imem_hsize,
input logic [1:0] imem_htrans,
input logic [SCR1_AHB_WIDTH-1:0] imem_haddr,
output logic imem_hready,
output logic [SCR1_AHB_WIDTH-1:0] imem_hrdata,
output logic imem_hresp,
// Memory Interface
// input logic [3:0] dmem_hprot,
// input logic [2:0] dmem_hburst,
input logic [2:0] dmem_hsize,
input logic [1:0] dmem_htrans,
input logic [SCR1_AHB_WIDTH-1:0] dmem_haddr,
input logic dmem_hwrite,
input logic [SCR1_AHB_WIDTH-1:0] dmem_hwdata,
output logic dmem_hready,
output logic [SCR1_AHB_WIDTH-1:0] dmem_hrdata,
output logic dmem_hresp
);
//-------------------------------------------------------------------------------
// Local Types
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_AHB_STATE_IDLE = 1'b0,
SCR1_AHB_STATE_DATA = 1'b1,
SCR1_AHB_STATE_ERR = 1'bx
} type_scr1_ahb_state_e;
//-------------------------------------------------------------------------------
// Memory definition
//-------------------------------------------------------------------------------
logic [7:0] memory [0:2**SCR1_MEM_POWER_SIZE-1];
`ifdef SCR1_IPIC_EN
logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines_reg;
`else // SCR1_IPIC_EN
logic ext_irq_reg;
`endif // SCR1_IPIC_EN
logic soft_irq_reg;
logic [7:0] mirage [0:2**SCR1_MEM_POWER_SIZE-1];
bit mirage_en;
bit mirage_rangeen;
bit [SCR1_AHB_WIDTH-1:0] mirage_adrlo = '1;
bit [SCR1_AHB_WIDTH-1:0] mirage_adrhi = '1;
`ifdef VERILATOR
logic [255:0] test_file;
`else // VERILATOR
string test_file;
`endif // VERILATOR
bit test_file_init;
//-------------------------------------------------------------------------------
// Local functions
//-------------------------------------------------------------------------------
function logic [SCR1_AHB_WIDTH-1:0] scr1_read_mem(
logic [SCR1_AHB_WIDTH-1:0] addr,
logic [3:0] r_be,
logic [3:0] w_hazard,
logic [SCR1_AHB_WIDTH-1:0] w_data,
bit mirage_en
);
logic [SCR1_AHB_WIDTH-1:0] tmp;
logic [SCR1_MEM_POWER_SIZE-1:0] addr_mirage;
begin
scr1_read_mem = 'x;
if(~mirage_en) begin
for (int unsigned i=0; i<4; ++i) begin
tmp[(8*(i+1)-1)-:8] = (r_be[i])
? (w_hazard[i])
? w_data[(8*(i+1)-1)-:8]
: memory[addr+i]
: 'x;
end
end
else begin
addr_mirage = addr;
for (int i = 0; i < 4; ++i) begin
tmp[ (i*8)+:8 ] = (r_be[i])
? (w_hazard[i])
? w_data[(i*8)+:8]
: mirage[addr_mirage+i]
: 'x;
end
end
return tmp;
end
endfunction : scr1_read_mem
function void scr1_write_mem(
logic [SCR1_AHB_WIDTH-1:0] addr,
logic [3:0] w_be,
logic [SCR1_AHB_WIDTH-1:0] data,
bit mirage_en
);
logic [SCR1_MEM_POWER_SIZE-1:0] addr_mirage;
begin
for (int unsigned i=0; i<4; ++i) begin
if (w_be[i]) begin
if(~mirage_en)
memory[addr+i] <= data[(8*(i+1)-1)-:8];
else begin
addr_mirage = addr;
mirage[addr_mirage+i] <= data[(8*(i+1)-1)-:8];
end
end
end
end
endfunction : scr1_write_mem
function logic [3:0] scr1_be_form(
input logic [1:0] offset,
input logic [1:0] hsize
);
logic [3:0] tmp;
begin
case (hsize)
SCR1_HSIZE_8B : begin
tmp = 4'b0001 << offset;
end
SCR1_HSIZE_16B : begin
tmp = 4'b0011 << offset;
end
SCR1_HSIZE_32B : begin
tmp = 4'b1111;
end
endcase
return tmp;
end
endfunction : scr1_be_form
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
// IMEM access
type_scr1_ahb_state_e imem_ahb_state;
logic [SCR1_AHB_WIDTH-1:0] imem_ahb_addr;
logic [SCR1_AHB_WIDTH-1:0] imem_req_ack_stall;
bit imem_req_ack_rnd;
logic imem_req_ack;
logic imem_req_ack_nc;
logic [3:0] imem_be;
logic [SCR1_AHB_WIDTH-1:0] imem_hrdata_l;
logic [3:0] imem_wr_hazard;
// DMEM access
logic [SCR1_AHB_WIDTH-1:0] dmem_req_ack_stall;
bit dmem_req_ack_rnd;
logic dmem_req_ack;
logic dmem_req_ack_nc;
logic [3:0] dmem_be;
type_scr1_ahb_state_e dmem_ahb_state;
logic [SCR1_AHB_WIDTH-1:0] dmem_ahb_addr;
logic dmem_ahb_wr;
logic [2:0] dmem_ahb_size;
logic [3:0] dmem_ahb_be;
logic [SCR1_AHB_WIDTH-1:0] dmem_hrdata_l;
logic [3:0] dmem_wr_hazard;
//-------------------------------------------------------------------------------
// Instruction memory ready
//-------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
imem_req_ack_stall <= imem_req_ack_stall_in;
imem_req_ack_rnd <= 1'b0;
end else begin
if (imem_req_ack_stall == '0) begin
imem_req_ack_rnd <= $random;
end else begin
imem_req_ack_stall <= ((imem_ahb_state == SCR1_AHB_STATE_DATA) | ~imem_req_ack_stall[0]) ? {imem_req_ack_stall[0], imem_req_ack_stall[31:1]} : imem_req_ack_stall;
end
end
end
assign imem_req_ack = (imem_req_ack_stall == 32'd0) ? imem_req_ack_rnd : imem_req_ack_stall[0];
//-------------------------------------------------------------------------------
// Instruction memory AHB FSM
//-------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
imem_ahb_state <= SCR1_AHB_STATE_IDLE;
end else begin
case (imem_ahb_state)
SCR1_AHB_STATE_IDLE : begin
// if (imem_req_ack) begin
case (imem_htrans)
SCR1_HTRANS_IDLE : begin
imem_ahb_state <= SCR1_AHB_STATE_IDLE;
end
SCR1_HTRANS_NONSEQ : begin
imem_ahb_state <= SCR1_AHB_STATE_DATA;
end
default : begin
imem_ahb_state <= SCR1_AHB_STATE_ERR;
end
endcase
// end
end
SCR1_AHB_STATE_DATA : begin
if (imem_req_ack) begin
case (imem_htrans)
SCR1_HTRANS_IDLE : begin
imem_ahb_state <= SCR1_AHB_STATE_IDLE;
end
SCR1_HTRANS_NONSEQ : begin
imem_ahb_state <= SCR1_AHB_STATE_DATA;
end
default : begin
imem_ahb_state <= SCR1_AHB_STATE_ERR;
end
endcase
end
end
default : begin
imem_ahb_state <= SCR1_AHB_STATE_ERR;
end
endcase
end
end
//-------------------------------------------------------------------------------
// Address data generation
//-------------------------------------------------------------------------------
assign imem_be = scr1_be_form(2'b00, imem_hsize);
assign imem_wr_hazard = (dmem_ahb_wr & (imem_haddr[SCR1_AHB_WIDTH-1:2] == dmem_ahb_addr[SCR1_AHB_WIDTH-1:2])) ? imem_be & dmem_ahb_be : '0;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
imem_ahb_addr <= 'x;
imem_hrdata_l <= 'x;
end else begin
case (imem_ahb_state)
SCR1_AHB_STATE_IDLE : begin
// if (imem_req_ack) begin
case (imem_htrans)
SCR1_HTRANS_IDLE : begin
end
SCR1_HTRANS_NONSEQ : begin
imem_ahb_addr <= imem_haddr;
if(mirage_rangeen & imem_haddr>=mirage_adrlo & imem_haddr<mirage_adrhi)
imem_hrdata_l <= scr1_read_mem({imem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, imem_be, imem_wr_hazard, dmem_hwdata, 1'b1);
else
imem_hrdata_l <= scr1_read_mem({imem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, imem_be, imem_wr_hazard, dmem_hwdata, 1'b0);
end
default : begin
imem_ahb_addr <= 'x;
imem_hrdata_l <= 'x;
end
endcase
// end
end
SCR1_AHB_STATE_DATA : begin
if (imem_req_ack) begin
case (imem_htrans)
SCR1_HTRANS_IDLE : begin
imem_ahb_addr <= 'x;
imem_hrdata_l <= 'x;
end
SCR1_HTRANS_NONSEQ : begin
imem_ahb_addr <= imem_haddr;
if(mirage_rangeen & imem_haddr>=mirage_adrlo & imem_haddr<mirage_adrhi)
imem_hrdata_l <= scr1_read_mem({imem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, imem_be, imem_wr_hazard, dmem_hwdata, 1'b1);
else
imem_hrdata_l <= scr1_read_mem({imem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, imem_be, imem_wr_hazard, dmem_hwdata, 1'b0);
end
default : begin
imem_ahb_addr <= 'x;
imem_hrdata_l <= 'x;
end
endcase
end
end
default : begin
imem_ahb_addr <= 'x;
imem_hrdata_l <= 'x;
end
endcase
end
end
//-------------------------------------------------------------------------------
// Instruction Memory response
//-------------------------------------------------------------------------------
always_comb begin
imem_hready = 1'b1;
imem_hresp = SCR1_HRESP_OKAY;
imem_hrdata = 'x;
case (imem_ahb_state)
SCR1_AHB_STATE_IDLE : begin
end
SCR1_AHB_STATE_DATA : begin
if (imem_req_ack) begin
imem_hready = 1'b1;
imem_hresp = SCR1_HRESP_OKAY;
imem_hrdata = imem_hrdata_l;
end
end
default : begin
end
endcase
end
//-------------------------------------------------------------------------------
// Data memory ready
//-------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
dmem_req_ack_stall <= dmem_req_ack_stall_in;
dmem_req_ack_rnd <= 1'b0;
end else begin
if (dmem_req_ack_stall == 32'd0) begin
dmem_req_ack_rnd <= $random;
end else begin
dmem_req_ack_stall <= ((dmem_ahb_state == SCR1_AHB_STATE_DATA) | ~dmem_req_ack_stall[0]) ? {dmem_req_ack_stall[0], dmem_req_ack_stall[31:1]} : dmem_req_ack_stall;
end
end
end
assign dmem_req_ack = (dmem_req_ack_stall == 32'd0) ? dmem_req_ack_rnd : dmem_req_ack_stall[0];
//-------------------------------------------------------------------------------
// Data memory AHB FSM
//-------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
dmem_ahb_state <= SCR1_AHB_STATE_IDLE;
end else begin
case (dmem_ahb_state)
SCR1_AHB_STATE_IDLE : begin
// if (dmem_req_ack) begin
case (dmem_htrans)
SCR1_HTRANS_IDLE : begin
dmem_ahb_state <= SCR1_AHB_STATE_IDLE;
end
SCR1_HTRANS_NONSEQ : begin
dmem_ahb_state <= SCR1_AHB_STATE_DATA;
end
default : begin
dmem_ahb_state <= SCR1_AHB_STATE_ERR;
end
endcase
// end
end
SCR1_AHB_STATE_DATA : begin
if (dmem_req_ack) begin
case (dmem_htrans)
SCR1_HTRANS_IDLE : begin
dmem_ahb_state <= SCR1_AHB_STATE_IDLE;
end
SCR1_HTRANS_NONSEQ : begin
if (~dmem_hwrite) begin
case (dmem_haddr)
SCR1_SIM_SOFT_IRQ_ADDR,
SCR1_SIM_EXT_IRQ_ADDR
: begin
// Skip access, switch to SCR1_AHB_STATE_IDLE
dmem_ahb_state <= SCR1_AHB_STATE_IDLE;
end
default : begin
dmem_ahb_state <= SCR1_AHB_STATE_DATA;
end
endcase
end
end
default : begin
dmem_ahb_state <= SCR1_AHB_STATE_ERR;
end
endcase
end
end
default : begin
dmem_ahb_state <= SCR1_AHB_STATE_ERR;
end
endcase
end
end
//-------------------------------------------------------------------------------
// Address command latch
//-------------------------------------------------------------------------------
assign dmem_be = scr1_be_form(dmem_haddr[1:0], dmem_hsize);
assign dmem_wr_hazard = (dmem_ahb_wr & (dmem_haddr[SCR1_AHB_WIDTH-1:2] == dmem_ahb_addr[SCR1_AHB_WIDTH-1:2])) ? dmem_be & dmem_ahb_be : '0;
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
dmem_ahb_addr <= 'x;
dmem_ahb_wr <= 1'b0;
dmem_ahb_size <= SCR1_HSIZE_ERR;
dmem_ahb_be <= '0;
end else begin
case (dmem_ahb_state)
SCR1_AHB_STATE_IDLE : begin
// if (dmem_req_ack) begin
case (dmem_htrans)
SCR1_HTRANS_IDLE : begin
end
SCR1_HTRANS_NONSEQ : begin
dmem_ahb_addr <= dmem_haddr;
dmem_ahb_wr <= dmem_hwrite;
dmem_ahb_size <= dmem_hsize;
dmem_ahb_be <= dmem_be;
if (~dmem_hwrite) begin
case (dmem_haddr)
// Reading Soft IRQ value
SCR1_SIM_SOFT_IRQ_ADDR : begin
dmem_hrdata_l <= '0;
dmem_hrdata_l[0] <= soft_irq_reg;
end
`ifdef SCR1_IPIC_EN
// Reading IRQ Lines values
SCR1_SIM_EXT_IRQ_ADDR : begin
dmem_hrdata_l <= '0;
dmem_hrdata_l[SCR1_IRQ_LINES_NUM-1:0] <= irq_lines_reg;
end
`else // SCR1_IPIC_EN
// Reading External IRQ value
SCR1_SIM_EXT_IRQ_ADDR : begin
dmem_hrdata_l <= '0;
dmem_hrdata_l[0] <= ext_irq_reg;
end
`endif // SCR1_IPIC_EN
// Regular read operation
default : begin
if(mirage_rangeen & dmem_haddr>=mirage_adrlo & dmem_haddr<mirage_adrhi)
dmem_hrdata_l <= scr1_read_mem({dmem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, dmem_be, dmem_wr_hazard, dmem_hwdata, 1'b1);
else
dmem_hrdata_l <= scr1_read_mem({dmem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, dmem_be, dmem_wr_hazard, dmem_hwdata, 1'b0);
end
endcase
end
end
default : begin
dmem_ahb_addr <= 'x;
dmem_ahb_wr <= 'x;
dmem_ahb_size <= SCR1_HSIZE_ERR;
dmem_hrdata_l <= 'x;
end
endcase
// end
end
SCR1_AHB_STATE_DATA : begin
if (dmem_req_ack) begin
case (dmem_htrans)
SCR1_HTRANS_IDLE : begin
dmem_ahb_addr <= 'x;
dmem_ahb_wr <= 1'b0;
dmem_ahb_size <= SCR1_HSIZE_ERR;
end
SCR1_HTRANS_NONSEQ : begin
dmem_ahb_addr <= dmem_haddr;
dmem_ahb_wr <= dmem_hwrite;
dmem_ahb_size <= dmem_hsize;
dmem_ahb_be <= dmem_be;
if (~dmem_hwrite) begin
case (dmem_haddr)
SCR1_SIM_SOFT_IRQ_ADDR,
SCR1_SIM_EXT_IRQ_ADDR
: begin
// Skip access, switch to SCR1_AHB_STATE_IDLE
end
default : begin
if(mirage_rangeen & dmem_haddr>=mirage_adrlo & dmem_haddr<mirage_adrhi)
dmem_hrdata_l <= scr1_read_mem({dmem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, dmem_be, dmem_wr_hazard, dmem_hwdata, 1'b1);
else
dmem_hrdata_l <= scr1_read_mem({dmem_haddr[SCR1_AHB_WIDTH-1:2], 2'b00}, dmem_be, dmem_wr_hazard, dmem_hwdata, 1'b0);
end
endcase
end
end
default : begin
dmem_ahb_addr <= 'x;
dmem_ahb_wr <= 'x;
dmem_ahb_size <= SCR1_HSIZE_ERR;
dmem_ahb_be <= 'x;
dmem_hrdata_l <= 'x;
end
endcase
end
end
default : begin
dmem_ahb_addr <= 'x;
dmem_ahb_wr <= 'x;
dmem_ahb_size <= SCR1_HSIZE_ERR;
dmem_hrdata_l <= 'x;
end
endcase
end
end
//-------------------------------------------------------------------------------
// Data Memory response
//-------------------------------------------------------------------------------
always_comb begin
dmem_hready = 1'b0;
dmem_hresp = SCR1_HRESP_ERROR;
dmem_hrdata = 'x;
case (dmem_ahb_state)
SCR1_AHB_STATE_IDLE : begin
if (dmem_req_ack) begin
dmem_hready = 1'b1;
end
end
SCR1_AHB_STATE_DATA : begin
if (dmem_req_ack) begin
dmem_hready = 1'b1;
dmem_hresp = SCR1_HRESP_OKAY;
if (~dmem_ahb_wr) begin
dmem_hrdata = dmem_hrdata_l;
end
end
end
default : begin
end
endcase
end
//-------------------------------------------------------------------------------
// Data Memory write
//-------------------------------------------------------------------------------
always @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
soft_irq_reg <= '0;
`ifdef SCR1_IPIC_EN
irq_lines_reg <= '0;
`else // SCR1_IPIC_EN
ext_irq_reg <= '0;
`endif // SCR1_IPIC_EN
if (test_file_init) $readmemh(test_file, memory);
end else begin
if ((dmem_ahb_state == SCR1_AHB_STATE_DATA) & dmem_req_ack & dmem_ahb_wr) begin
case (dmem_ahb_addr)
// Printing character in the simulation console
SCR1_SIM_PRINT_ADDR : begin
$write("%c", dmem_hwdata[7:0]);
end
// Writing Soft IRQ value
SCR1_SIM_SOFT_IRQ_ADDR : begin
soft_irq_reg <= dmem_hwdata[0];
end
`ifdef SCR1_IPIC_EN
// Writing IRQ Lines values
SCR1_SIM_EXT_IRQ_ADDR : begin
irq_lines_reg <= dmem_hwdata[SCR1_IRQ_LINES_NUM-1:0];
end
`else // SCR1_IPIC_EN
// Writing External IRQ value
SCR1_SIM_EXT_IRQ_ADDR : begin
ext_irq_reg <= dmem_hwdata[0];
end
`endif // SCR1_IPIC_EN
// Regular write operation
default : begin
if(mirage_rangeen & dmem_ahb_addr>=mirage_adrlo & dmem_ahb_addr<mirage_adrhi)
scr1_write_mem({dmem_ahb_addr[SCR1_AHB_WIDTH-1:2], 2'b00}, dmem_ahb_be, dmem_hwdata, 1'b1);
else
scr1_write_mem({dmem_ahb_addr[SCR1_AHB_WIDTH-1:2], 2'b00}, dmem_ahb_be, dmem_hwdata, 1'b0);
end
endcase
end
end
end
`ifdef SCR1_IPIC_EN
assign irq_lines = irq_lines_reg;
`else // SCR1_IPIC_EN
assign ext_irq = ext_irq_reg;
`endif // SCR1_IPIC_EN
assign soft_irq = soft_irq_reg;
endmodule : scr1_memory_tb_ahb

View File

@@ -0,0 +1,393 @@
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
/// @file <scr1_memory_tb_axi.sv>
/// @brief AXI memory testbench
///
`include "scr1_arch_description.svh"
`include "scr1_ipic.svh"
module scr1_memory_tb_axi #(
parameter SIZE = 1*1024*1024,
parameter N_IF = 2,
parameter W_ID = 4,
parameter W_ADR = 32,
parameter W_DATA = 32
)
(
// System
input logic rst_n,
input logic clk,
`ifdef SCR1_IPIC_EN
output logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines,
`else // SCR1_IPIC_EN
output logic ext_irq,
`endif // SCR1_IPIC_EN
output logic soft_irq,
// Write address channel
input logic [N_IF-1:0] awvalid,
input logic [N_IF-1:0] [W_ID-1:0] awid,
input logic [N_IF-1:0] [W_ADR-1:0] awaddr,
input logic [N_IF-1:0] [2:0] awsize,
input logic [N_IF-1:0] [7:0] awlen,
output logic [N_IF-1:0] awready,
// Write data channel
input logic [N_IF-1:0] wvalid,
input logic [N_IF-1:0] [W_DATA-1:0] wdata,
input logic [N_IF-1:0] [W_DATA/8-1:0] wstrb,
input logic [N_IF-1:0] wlast,
output logic [N_IF-1:0] wready,
// Write response channel
input logic [N_IF-1:0] bready,
output logic [N_IF-1:0] bvalid,
output logic [N_IF-1:0] [W_ID-1:0] bid,
output logic [N_IF-1:0] [1:0] bresp,
// Read address channel
input logic [N_IF-1:0] arvalid,
input logic [N_IF-1:0] [W_ID-1:0] arid,
input logic [N_IF-1:0] [W_ADR-1:0] araddr,
input logic [N_IF-1:0] [1:0] arburst,
input logic [N_IF-1:0] [2:0] arsize,
input logic [N_IF-1:0] [7:0] arlen,
output logic [N_IF-1:0] arready,
// Read data channel
input logic [N_IF-1:0] rready,
output logic [N_IF-1:0] rvalid,
output logic [N_IF-1:0] [W_ID-1:0] rid,
output logic [N_IF-1:0] [W_DATA-1:0] rdata,
output logic [N_IF-1:0] rlast,
output logic [N_IF-1:0] [1:0] rresp
);
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
logic [7:0] memory [0:SIZE-1];
logic [N_IF-1:0] [W_ADR-1:0] awaddr_hold;
logic [N_IF-1:0] [2:0] awsize_hold;
genvar gi;
genvar gj;
`ifdef SCR1_IPIC_EN
logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines_reg;
`else // SCR1_IPIC_EN
logic ext_irq_reg;
`endif // SCR1_IPIC_EN
logic soft_irq_reg;
`ifdef VERILATOR
logic [255:0] test_file;
`else // VERILATOR
string test_file;
`endif // VERILATOR
bit test_file_init;
//-------------------------------------------------------------------------------
// Local functions
//-------------------------------------------------------------------------------
function automatic logic [W_DATA-1:0] mem_read (
logic [W_ADR:0] adr, // starting address of READ burst operation
int bytes_num, // number of bytes to read
int bytes_max // number of bytes in data width
);
logic [W_ADR:0] byte_lane; // positional number of byte to read
mem_read = 'x;
byte_lane = 0;
// Storing the positional number of byte to read
for(int i=0; i<$clog2(bytes_max); ++i) begin
byte_lane[i] = adr[i];
end
// READ burst operation
for(int i=byte_lane; i<bytes_max & bytes_num!=0; ++i) begin
// Reading Soft IRQ value
if (adr[W_ADR-1:1] == SCR1_SIM_SOFT_IRQ_ADDR[W_ADR-1:1]) begin
mem_read[0] = soft_irq_reg;
`ifdef SCR1_IPIC_EN
// Reading IRQ Lines values
end else if (adr[W_ADR-1:1] == SCR1_SIM_EXT_IRQ_ADDR[W_ADR-1:1]) begin
if (i*8 < SCR1_IRQ_LINES_NUM) begin
if (SCR1_IRQ_LINES_NUM < 8) begin
mem_read[(i*8)+:8] = irq_lines_reg;
end else begin
mem_read[(i*8)+:8] = irq_lines_reg[(i*8)+:8];
end
end
`else // SCR1_IPIC_EN
// Reading External IRQ value
end else if (adr[W_ADR-1:1] == SCR1_SIM_EXT_IRQ_ADDR[W_ADR-1:1]) begin
mem_read[0] = ext_irq_reg;
`endif // SCR1_IPIC_EN
// Regular read operation
end else begin
mem_read[(i*8)+:8] = memory[adr];
end
adr = adr+1'b1;
bytes_num = bytes_num - 1'b1;
end
endfunction : mem_read
function automatic void mem_write (
logic [W_ADR-1:0] adr, // starting address of WRITE burst operation
logic [W_DATA-1:0] data, // data to write
logic [(W_DATA/8)-1:0] bytes_en, // bytes write strobes
int bytes_num, // number of bytes to write
int bytes_max // number of bytes in data width
);
logic[W_ADR:0] byte_lane; // positional number of byte to write
byte_lane = 0;
// Storing the positional number of byte to write
for(int i=0; i<$clog2(bytes_max); ++i) begin
byte_lane[i] = adr[i];
end
// WRITE burst operation
for(int i=byte_lane; i<bytes_max & bytes_num!=0; ++i) begin
// Printing character in the simulation console
if(bytes_en[i] & adr == SCR1_SIM_PRINT_ADDR) begin
$write("%c",data[(i*8)+:8]);
// Writing Soft IRQ value
end else if(bytes_en[0] & adr[W_ADR-1:1] == SCR1_SIM_SOFT_IRQ_ADDR[W_ADR-1:1]) begin
soft_irq_reg <= data[0];
`ifdef SCR1_IPIC_EN
// Writing IRQ Lines values
end else if(bytes_en[i] & adr[W_ADR-1:1] == SCR1_SIM_EXT_IRQ_ADDR[W_ADR-1:1]) begin
if( i*8 < SCR1_IRQ_LINES_NUM ) begin
if( SCR1_IRQ_LINES_NUM < 8 ) begin
irq_lines_reg <= data[SCR1_IRQ_LINES_NUM-1:0];
end else begin
irq_lines_reg[(i*8)+:8] <= data[(i*8)+:8];
end
end
`else
// Writing External IRQ value
end else if(bytes_en[0] & adr[W_ADR-1:1] == SCR1_SIM_EXT_IRQ_ADDR[W_ADR-1:1]) begin
ext_irq_reg <= data[0];
`endif // SCR1_IPIC_EN
// Regular write operation
end else if (bytes_en[i]) begin
memory[adr] = data[(i*8)+:8];
end
adr = adr+1'b1;
bytes_num = bytes_num-1'b1;
end
endfunction : mem_write
`ifdef SCR1_IPIC_EN
assign irq_lines = irq_lines_reg;
`else // SCR1_IPIC_EN
assign ext_irq = ext_irq_reg;
`endif // SCR1_IPIC_EN
assign soft_irq = soft_irq_reg;
generate for(gi=0; gi<N_IF; ++gi) begin : rw_if
//-------------------------------------------------------------------------------
// Read operation
//-------------------------------------------------------------------------------
always @(posedge clk, negedge rst_n) begin
if(~rst_n) begin
arready[gi] <= 1'b1;
rvalid[gi] <= 1'b0;
rresp[gi] <= 2'd3;
rdata[gi] <= 'x;
rlast[gi] <= 1'b0;
rid[gi] <= '0;
end else begin
// Read data: acked
if( rvalid[gi] & rready[gi] ) begin
arready[gi] <= 1'b1;
rvalid[gi] <= 1'b0;
end else if( rvalid[gi] & !rready[gi] ) begin
arready[gi] <= 1'b0;
end
// Read data: valid
if( arvalid[gi] & arready[gi] & ~(rvalid[gi] & !rready[gi]) ) begin
rvalid[gi] <= 1'b1;
rresp[gi] <= '0;
rlast[gi] <= 1'b1;
rid[gi] <= arid[gi];
rdata[gi] <= mem_read( araddr[gi],
2**arsize[gi],
W_DATA/8 );
end
end
end
//-------------------------------------------------------------------------------
// Write operation
//-------------------------------------------------------------------------------
always @(posedge clk, negedge rst_n) begin
if (~rst_n) begin
bvalid[gi] <= '0;
bresp[gi] <= 2'd3;
awready[gi] <= 1'b1;
wready[gi] <= 1'b1;
soft_irq_reg <= '0;
`ifdef SCR1_IPIC_EN
irq_lines_reg <= '0;
`else // SCR1_IPIC_EN
ext_irq_reg <= '0;
`endif // SCR1_IPIC_EN
if (test_file_init) $readmemh(test_file, memory);
end else begin
// Write data: response
if( bvalid[gi] & bready[gi] ) begin
bvalid[gi] <= 1'b0;
awready[gi] <= 1'b1;
wready[gi] <= 1'b1;
end else if( bvalid[gi] & !bready[gi] ) begin
awready[gi] <= 1'b0;
wready[gi] <= 1'b0;
end
// Write data: get address
if( awvalid[gi] & awready[gi] & ~(bvalid[gi] & !bready[gi]) ) begin
bid <= awid[gi];
if( ~wvalid[gi] ) begin
awaddr_hold[gi] <= awaddr[gi];
awsize_hold[gi] <= awsize[gi];
awready[gi] <= 1'b0;
end
end
// Write data: get data
if( wvalid[gi] & wready[gi] & wlast[gi] ) begin
bvalid[gi] <= 1'b1;
bresp[gi] <= '0;
mem_write( awready[gi] ? awaddr[gi] : awaddr_hold[gi],
wdata[gi],
wstrb[gi],
2**(awready[gi] ? awsize[gi] : awsize_hold[gi]),
W_DATA/8 );
end
end
end
//`ifndef VERILATOR
//-------------------------------------------------------------------------------
// Assertions
//-------------------------------------------------------------------------------
SVA_TBMEM_AWADDR_404 :
assert property (
@(negedge clk) disable iff (~rst_n)
awvalid[gi] |-> awaddr[gi]<SIZE | awaddr[gi]==SCR1_SIM_PRINT_ADDR
| awaddr[gi]==SCR1_SIM_SOFT_IRQ_ADDR
| awaddr[gi]==SCR1_SIM_EXT_IRQ_ADDR
)
else $error("TBMEM: awaddr[%0d] >= SIZE",gi);
SVA_TBMEM_X_AWVALID :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(awvalid[gi])
)
else $error("TBMEM: X state on awvalid[%0d]",gi);
SVA_TBMEM_X_AWCHANNEL :
assert property (
@(negedge clk) disable iff (~rst_n)
awvalid[gi] |-> !$isunknown({awid[gi],awaddr[gi],awsize[gi],awlen[gi]})
)
else $error("TBMEM: X state on aw channel[%0d]",gi);
SVA_TBMEM_AWLEN :
assert property (
@(negedge clk) disable iff (~rst_n)
awvalid[gi] |-> awlen[gi]==0
)
else $error("TBMEM: awlen[%0d] = %0d is not supported",gi,awlen[gi]);
SVA_TBMEM_X_WVALID :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(wvalid[gi])
)
else $error("TBMEM: X state on wvalid[%0d]",gi);
SVA_TBMEM_X_WCHANNEL :
assert property (
@(negedge clk) disable iff (~rst_n)
wvalid[gi] |-> !$isunknown({wstrb[gi],wlast[gi]})
)
else $error("TBMEM: X state on w channel[%0d]",gi);
for(gj=0; gj<W_DATA/8; ++gj) begin : SVA_TBMEM_X_WSTRB
WDATA :
assert property (
@(negedge clk) disable iff (~rst_n)
(wvalid[gi] & wstrb[gi][gj]) |-> !$isunknown(wdata[gi][(gj*8)+:8])
)
else $error("TBMEM: X state on wdata with wstrb[%0d][%0d]",gi,gj);
end
SVA_TBMEM_X_BREADY :
assert property (
@(negedge clk) disable iff (~rst_n)
bvalid[gi] |-> !$isunknown(bready[gi])
)
else $error("TBMEM: X state on bready[%0d]",gi);
SVA_TBMEM_ARADDR_404 :
assert property (
@(negedge clk) disable iff (~rst_n)
arvalid[gi] |-> araddr[gi]<SIZE | araddr[gi]==SCR1_SIM_PRINT_ADDR
| awaddr[gi]==SCR1_SIM_SOFT_IRQ_ADDR
| awaddr[gi]==SCR1_SIM_EXT_IRQ_ADDR
)
else $error("TBMEM: awaddr[%0d] >= SIZE",gi);
SVA_TBMEM_X_ARVALID :
assert property (
@(negedge clk) disable iff (~rst_n)
!$isunknown(arvalid[gi])
)
else $error("TBMEM: X state on arvalid[%0d]",gi);
SVA_TBMEM_X_ARCHANNEL :
assert property (
@(negedge clk) disable iff (~rst_n)
arvalid[gi] |-> !$isunknown({arid[gi],araddr[gi],arsize[gi],arlen[gi]})
)
else $error("TBMEM: X state on ar channel[%0d]",gi);
SVA_TBMEM_ARLEN :
assert property (
@(negedge clk) disable iff (~rst_n)
arvalid[gi] |-> arlen[gi]==0
)
else $error("TBMEM: arlen[%0d] = %0d is not supported",gi,arlen[gi]);
SVA_TBMEM_X_RREADY :
assert property (
@(negedge clk) disable iff (~rst_n)
rvalid[gi] |-> !$isunknown(rready[gi])
)
else $error("TBMEM: X state on rready[%0d]",gi);
//`endif // VERILATOR
end endgenerate
endmodule : scr1_memory_tb_axi

393
src/tb/scr1_top_tb_ahb.sv Normal file
View File

@@ -0,0 +1,393 @@
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
/// @file <scr1_top_tb_ahb.sv>
/// @brief SCR1 top testbench AHB
///
`include "scr1_arch_description.svh"
`include "scr1_ahb.svh"
`ifdef SCR1_IPIC_EN
`include "scr1_ipic.svh"
`endif // SCR1_IPIC_EN
module scr1_top_tb_ahb (
`ifdef VERILATOR
input logic clk
`endif // VERILATOR
);
//-------------------------------------------------------------------------------
// Local parameters
//-------------------------------------------------------------------------------
localparam SCR1_MEM_SIZE = 1024*1024;
localparam TIMEOUT = 'd2000_000;//20ms;
localparam ARCH = 'h1;
localparam COMPLIANCE = 'h2;
localparam ADDR_START = 'h200;
localparam ADDR_TRAP_VECTOR = 'h240;
localparam ADDR_TRAP_DEFAULT = 'h1C0;
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
logic rst_n;
`ifndef VERILATOR
logic clk = 1'b0;
`endif // VERILATOR
logic rtc_clk = 1'b0;
`ifdef SCR1_IPIC_EN
logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines;
`else // SCR1_IPIC_EN
logic ext_irq;
`endif // SCR1_IPIC_EN
logic soft_irq;
logic [31:0] fuse_mhartid;
integer imem_req_ack_stall;
integer dmem_req_ack_stall;
logic test_mode = 1'b0;
`ifdef SCR1_DBG_EN
logic trst_n;
logic tck;
logic tms;
logic tdi;
logic tdo;
logic tdo_en;
`endif // SCR1_DBG_EN
// Instruction Memory Interface
logic [3:0] imem_hprot;
logic [2:0] imem_hburst;
logic [2:0] imem_hsize;
logic [1:0] imem_htrans;
logic [SCR1_AHB_WIDTH-1:0] imem_haddr;
logic imem_hready;
logic [SCR1_AHB_WIDTH-1:0] imem_hrdata;
logic imem_hresp;
// Memory Interface
logic [3:0] dmem_hprot;
logic [2:0] dmem_hburst;
logic [2:0] dmem_hsize;
logic [1:0] dmem_htrans;
logic [SCR1_AHB_WIDTH-1:0] dmem_haddr;
logic dmem_hwrite;
logic [SCR1_AHB_WIDTH-1:0] dmem_hwdata;
logic dmem_hready;
logic [SCR1_AHB_WIDTH-1:0] dmem_hrdata;
logic dmem_hresp;
// Wathdogs
int unsigned watchdogs_cnt;
int unsigned f_results;
int unsigned f_info;
string s_results;
string s_info;
`ifdef SIGNATURE_OUT
string s_testname;
bit b_single_run_flag;
`endif // SIGNATURE_OUT
`ifdef VERILATOR
logic [255:0] test_file;
`else // VERILATOR
string test_file;
`endif // VERILATOR
bit test_running;
int unsigned tests_passed;
int unsigned tests_total;
bit [1:0] rst_cnt;
bit rst_init;
`ifdef VERILATOR
function int identify_test (logic [255:0] testname);
bit res;
logic [79:0] pattern_compliance;
logic [22:0] pattern_arch;
begin
pattern_compliance = 80'h636f6d706c69616e6365; // compliance
pattern_arch = 'h61726368; // arch
res = 0;
for (int i = 0; i<= 176; i++) begin
if(testname[i+:80] == pattern_compliance) begin
return COMPLIANCE;
end
end
for (int i = 0; i<= 233; i++) begin
if(testname[i+:23] == pattern_arch) begin
return ARCH;
end
end
`ifdef SIGNATURE_OUT
return ~res;
`else
return res;
`endif
end
endfunction : identify_test
function logic [255:0] get_filename (logic [255:0] testname);
logic [255:0] res;
int i, j;
begin
testname[7:0] = 8'h66;
testname[15:8] = 8'h6C;
testname[23:16] = 8'h65;
for (i = 0; i <= 248; i += 8) begin
if (testname[i+:8] == 0) begin
break;
end
end
i -= 8;
for (j = 255; i >= 0;i -= 8) begin
res[j-:8] = testname[i+:8];
j -= 8;
end
for (; j >= 0;j -= 8) begin
res[j-:8] = 0;
end
return res;
end
endfunction : get_filename
function logic [255:0] get_ref_filename (logic [255:0] testname);
logic [255:0] res;
int i, j;
logic [79:0] pattern_compliance;
logic [22:0] pattern_arch;
begin
pattern_compliance = 80'h636f6d706c69616e6365; // compliance
pattern_arch = 'h61726368; // arch
for(int i = 0; i <= 176; i++) begin
if(testname[i+:80] == pattern_compliance) begin
testname[(i-8)+:88] = 0;
break;
end
end
for(int i = 0; i <= 233; i++) begin
if(testname[i+:23] == pattern_arch) begin
testname[(i-8)+:31] = 0;
break;
end
end
for(i = 32; i <= 248; i += 8) begin
if(testname[i+:8] == 0) break;
end
i -= 8;
for(j = 255; i > 24; i -= 8) begin
res[j-:8] = testname[i+:8];
j -= 8;
end
for(; j >=0;j -= 8) begin
res[j-:8] = 0;
end
return res;
end
endfunction : get_ref_filename
function logic [2047:0] remove_trailing_whitespaces (logic [2047:0] str);
int i;
begin
for (i = 0; i <= 2040; i += 8) begin
if (str[i+:8] != 8'h20) begin
break;
end
end
str = str >> i;
return str;
end
endfunction: remove_trailing_whitespaces
`else // VERILATOR
function int identify_test (string testname);
begin
if (testname.substr(0, 3) == "arch") begin
return ARCH;
end else if (testname.substr(0, 9) == "compliance") begin
return COMPLIANCE;
end else begin
return 0;
end
end
endfunction : identify_test
function string get_filename (string testname);
int length;
begin
length = testname.len();
testname[length-1] = "f";
testname[length-2] = "l";
testname[length-3] = "e";
return testname;
end
endfunction : get_filename
function string get_ref_filename (string testname);
begin
if (identify_test(test_file) == COMPLIANCE) begin
return testname.substr(11, testname.len() - 5);
end else if (identify_test(test_file) == ARCH) begin
return testname.substr(5, testname.len() - 5);
end
end
endfunction : get_ref_filename
`endif // VERILATOR
`ifndef VERILATOR
always #5 clk = ~clk; // 100 MHz
always #500 rtc_clk = ~rtc_clk; // 1 MHz
`endif // VERILATOR
// Reset logic
assign rst_n = &rst_cnt;
always_ff @(posedge clk) begin
if (rst_init) rst_cnt <= '0;
else if (~&rst_cnt) rst_cnt <= rst_cnt + 1'b1;
end
`ifdef SCR1_DBG_EN
initial begin
trst_n = 1'b0;
tck = 1'b0;
tdi = 1'b0;
#900ns trst_n = 1'b1;
#500ns tms = 1'b1;
#800ns tms = 1'b0;
#500ns trst_n = 1'b0;
#100ns tms = 1'b1;
end
`endif // SCR1_DBG_EN
//-------------------------------------------------------------------------------
// Run tests
//-------------------------------------------------------------------------------
`include "scr1_top_tb_runtests.sv"
//-------------------------------------------------------------------------------
// Core instance
//-------------------------------------------------------------------------------
scr1_top_ahb i_top (
// Reset
.pwrup_rst_n (rst_n ),
.rst_n (rst_n ),
.cpu_rst_n (rst_n ),
`ifdef SCR1_DBG_EN
.sys_rst_n_o ( ),
.sys_rdc_qlfy_o ( ),
`endif // SCR1_DBG_EN
// Clock
.clk (clk ),
.rtc_clk (rtc_clk ),
// Fuses
.fuse_mhartid (fuse_mhartid ),
`ifdef SCR1_DBG_EN
.fuse_idcode (`SCR1_TAP_IDCODE ),
`endif // SCR1_DBG_EN
// IRQ
`ifdef SCR1_IPIC_EN
.irq_lines (irq_lines ),
`else // SCR1_IPIC_EN
.ext_irq (ext_irq ),
`endif // SCR1_IPIC_EN
.soft_irq (soft_irq ),
// DFT
.test_mode (1'b0 ),
.test_rst_n (1'b1 ),
`ifdef SCR1_DBG_EN
// JTAG
.trst_n (trst_n ),
.tck (tck ),
.tms (tms ),
.tdi (tdi ),
.tdo (tdo ),
.tdo_en (tdo_en ),
`endif // SCR1_DBG_EN
// Instruction Memory Interface
.imem_hprot (imem_hprot ),
.imem_hburst (imem_hburst ),
.imem_hsize (imem_hsize ),
.imem_htrans (imem_htrans ),
.imem_hmastlock (),
.imem_haddr (imem_haddr ),
.imem_hready (imem_hready ),
.imem_hrdata (imem_hrdata ),
.imem_hresp (imem_hresp ),
// Data Memory Interface
.dmem_hprot (dmem_hprot ),
.dmem_hburst (dmem_hburst ),
.dmem_hsize (dmem_hsize ),
.dmem_htrans (dmem_htrans ),
.dmem_hmastlock (),
.dmem_haddr (dmem_haddr ),
.dmem_hwrite (dmem_hwrite ),
.dmem_hwdata (dmem_hwdata ),
.dmem_hready (dmem_hready ),
.dmem_hrdata (dmem_hrdata ),
.dmem_hresp (dmem_hresp )
);
//-------------------------------------------------------------------------------
// Memory instance
//-------------------------------------------------------------------------------
scr1_memory_tb_ahb #(
.SCR1_MEM_POWER_SIZE ($clog2(SCR1_MEM_SIZE))
) i_memory_tb (
// Control
.rst_n (rst_n),
.clk (clk),
`ifdef SCR1_IPIC_EN
.irq_lines (irq_lines),
`else // SCR1_IPIC_EN
.ext_irq (ext_irq),
`endif // SCR1_IPIC_EN
.soft_irq (soft_irq),
.imem_req_ack_stall_in (imem_req_ack_stall),
.dmem_req_ack_stall_in (dmem_req_ack_stall),
// Instruction Memory Interface
// .imem_hprot (imem_hprot ),
// .imem_hburst (imem_hburst),
.imem_hsize (imem_hsize ),
.imem_htrans (imem_htrans),
.imem_haddr (imem_haddr ),
.imem_hready (imem_hready),
.imem_hrdata (imem_hrdata),
.imem_hresp (imem_hresp ),
// Data Memory Interface
// .dmem_hprot (dmem_hprot ),
// .dmem_hburst (dmem_hburst),
.dmem_hsize (dmem_hsize ),
.dmem_htrans (dmem_htrans),
.dmem_haddr (dmem_haddr ),
.dmem_hwrite (dmem_hwrite),
.dmem_hwdata (dmem_hwdata),
.dmem_hready (dmem_hready),
.dmem_hrdata (dmem_hrdata),
.dmem_hresp (dmem_hresp )
);
endmodule : scr1_top_tb_ahb

544
src/tb/scr1_top_tb_axi.sv Normal file
View File

@@ -0,0 +1,544 @@
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
/// @file <scr1_top_tb_axi.sv>
/// @brief SCR1 top testbench AXI
///
`include "scr1_arch_description.svh"
`ifdef SCR1_IPIC_EN
`include "scr1_ipic.svh"
`endif // SCR1_IPIC_EN
module scr1_top_tb_axi (
`ifdef VERILATOR
input logic clk
`endif // VERILATOR
);
//------------------------------------------------------------------------------
// Local parameters
//------------------------------------------------------------------------------
localparam SCR1_MEM_SIZE = 1024*1024;
localparam TIMEOUT = 'd2000_000;//20ms;
localparam ARCH = 'h1;
localparam COMPLIANCE = 'h2;
localparam ADDR_START = 'h200;
localparam ADDR_TRAP_VECTOR = 'h240;
localparam ADDR_TRAP_DEFAULT = 'h1C0;
//------------------------------------------------------------------------------
// Local signal declaration
//------------------------------------------------------------------------------
logic rst_n;
`ifndef VERILATOR
logic clk = 1'b0;
`endif // VERILATOR
logic rtc_clk = 1'b0;
logic [31:0] fuse_mhartid;
integer imem_req_ack_stall;
integer dmem_req_ack_stall;
`ifdef SCR1_IPIC_EN
logic [SCR1_IRQ_LINES_NUM-1:0] irq_lines;
`else // SCR1_IPIC_EN
logic ext_irq;
`endif // SCR1_IPIC_EN
logic soft_irq;
`ifdef SCR1_DBG_EN
logic trst_n;
logic tck;
logic tms;
logic tdi;
logic tdo;
logic tdo_en;
`endif // SCR1_DBG_EN
// Instruction Memory
logic [3:0] io_axi_imem_awid;
logic [31:0] io_axi_imem_awaddr;
logic [7:0] io_axi_imem_awlen;
logic [2:0] io_axi_imem_awsize;
logic [1:0] io_axi_imem_awburst;
logic io_axi_imem_awlock;
logic [3:0] io_axi_imem_awcache;
logic [2:0] io_axi_imem_awprot;
logic [3:0] io_axi_imem_awregion;
logic [3:0] io_axi_imem_awuser;
logic [3:0] io_axi_imem_awqos;
logic io_axi_imem_awvalid;
logic io_axi_imem_awready;
logic [31:0] io_axi_imem_wdata;
logic [3:0] io_axi_imem_wstrb;
logic io_axi_imem_wlast;
logic [3:0] io_axi_imem_wuser;
logic io_axi_imem_wvalid;
logic io_axi_imem_wready;
logic [3:0] io_axi_imem_bid;
logic [1:0] io_axi_imem_bresp;
logic io_axi_imem_bvalid;
logic [3:0] io_axi_imem_buser;
logic io_axi_imem_bready;
logic [3:0] io_axi_imem_arid;
logic [31:0] io_axi_imem_araddr;
logic [7:0] io_axi_imem_arlen;
logic [2:0] io_axi_imem_arsize;
logic [1:0] io_axi_imem_arburst;
logic io_axi_imem_arlock;
logic [3:0] io_axi_imem_arcache;
logic [2:0] io_axi_imem_arprot;
logic [3:0] io_axi_imem_arregion;
logic [3:0] io_axi_imem_aruser;
logic [3:0] io_axi_imem_arqos;
logic io_axi_imem_arvalid;
logic io_axi_imem_arready;
logic [3:0] io_axi_imem_rid;
logic [31:0] io_axi_imem_rdata;
logic [1:0] io_axi_imem_rresp;
logic io_axi_imem_rlast;
logic [3:0] io_axi_imem_ruser;
logic io_axi_imem_rvalid;
logic io_axi_imem_rready;
// Data Memory
logic [3:0] io_axi_dmem_awid;
logic [31:0] io_axi_dmem_awaddr;
logic [7:0] io_axi_dmem_awlen;
logic [2:0] io_axi_dmem_awsize;
logic [1:0] io_axi_dmem_awburst;
logic io_axi_dmem_awlock;
logic [3:0] io_axi_dmem_awcache;
logic [2:0] io_axi_dmem_awprot;
logic [3:0] io_axi_dmem_awregion;
logic [3:0] io_axi_dmem_awuser;
logic [3:0] io_axi_dmem_awqos;
logic io_axi_dmem_awvalid;
logic io_axi_dmem_awready;
logic [31:0] io_axi_dmem_wdata;
logic [3:0] io_axi_dmem_wstrb;
logic io_axi_dmem_wlast;
logic [3:0] io_axi_dmem_wuser;
logic io_axi_dmem_wvalid;
logic io_axi_dmem_wready;
logic [3:0] io_axi_dmem_bid;
logic [1:0] io_axi_dmem_bresp;
logic io_axi_dmem_bvalid;
logic [3:0] io_axi_dmem_buser;
logic io_axi_dmem_bready;
logic [3:0] io_axi_dmem_arid;
logic [31:0] io_axi_dmem_araddr;
logic [7:0] io_axi_dmem_arlen;
logic [2:0] io_axi_dmem_arsize;
logic [1:0] io_axi_dmem_arburst;
logic io_axi_dmem_arlock;
logic [3:0] io_axi_dmem_arcache;
logic [2:0] io_axi_dmem_arprot;
logic [3:0] io_axi_dmem_arregion;
logic [3:0] io_axi_dmem_aruser;
logic [3:0] io_axi_dmem_arqos;
logic io_axi_dmem_arvalid;
logic io_axi_dmem_arready;
logic [3:0] io_axi_dmem_rid;
logic [31:0] io_axi_dmem_rdata;
logic [1:0] io_axi_dmem_rresp;
logic io_axi_dmem_rlast;
logic [3:0] io_axi_dmem_ruser;
logic io_axi_dmem_rvalid;
logic io_axi_dmem_rready;
// Wathdogs
int unsigned watchdogs_cnt;
int unsigned f_results;
int unsigned f_info;
string s_results;
string s_info;
`ifdef SIGNATURE_OUT
string s_testname;
bit b_single_run_flag;
`endif // SIGNATURE_OUT
`ifdef VERILATOR
logic [255:0] test_file;
`else // VERILATOR
string test_file;
`endif // VERILATOR
bit test_running;
int unsigned tests_passed;
int unsigned tests_total;
bit [1:0] rst_cnt;
bit rst_init;
`ifdef VERILATOR
function int identify_test (logic [255:0] testname);
bit res;
logic [79:0] pattern_compliance;
logic [22:0] pattern_arch;
begin
pattern_compliance = 80'h636f6d706c69616e6365; // compliance
pattern_arch = 'h61726368; // arch
res = 0;
for (int i = 0; i<= 176; i++) begin
if(testname[i+:80] == pattern_compliance) begin
return COMPLIANCE;
end
end
for (int i = 0; i<= 233; i++) begin
if(testname[i+:23] == pattern_arch) begin
return ARCH;
end
end
`ifdef SIGNATURE_OUT
return ~res;
`else
return res;
`endif
end
endfunction : identify_test
function logic [255:0] get_filename (logic [255:0] testname);
logic [255:0] res;
int i, j;
begin
testname[7:0] = 8'h66;
testname[15:8] = 8'h6C;
testname[23:16] = 8'h65;
for (i = 0; i <= 248; i += 8) begin
if (testname[i+:8] == 0) begin
break;
end
end
i -= 8;
for (j = 255; i >= 0;i -= 8) begin
res[j-:8] = testname[i+:8];
j -= 8;
end
for (; j >= 0;j -= 8) begin
res[j-:8] = 0;
end
return res;
end
endfunction : get_filename
function logic [255:0] get_ref_filename (logic [255:0] testname);
logic [255:0] res;
int i, j;
logic [79:0] pattern_compliance;
logic [22:0] pattern_arch;
begin
pattern_compliance = 80'h636f6d706c69616e6365; // compliance
pattern_arch = 'h61726368; // arch
for(int i = 0; i <= 176; i++) begin
if(testname[i+:80] == pattern_compliance) begin
testname[(i-8)+:88] = 0;
break;
end
end
for(int i = 0; i <= 233; i++) begin
if(testname[i+:23] == pattern_arch) begin
testname[(i-8)+:31] = 0;
break;
end
end
for(i = 32; i <= 248; i += 8) begin
if(testname[i+:8] == 0) break;
end
i -= 8;
for(j = 255; i > 24; i -= 8) begin
res[j-:8] = testname[i+:8];
j -= 8;
end
for(; j >=0;j -= 8) begin
res[j-:8] = 0;
end
return res;
end
endfunction : get_ref_filename
function logic [2047:0] remove_trailing_whitespaces (logic [2047:0] str);
int i;
begin
for (i = 0; i <= 2040; i += 8) begin
if (str[i+:8] != 8'h20) begin
break;
end
end
str = str >> i;
return str;
end
endfunction: remove_trailing_whitespaces
`else // VERILATOR
function int identify_test (string testname);
begin
if (testname.substr(0, 3) == "arch") begin
return ARCH;
end else if (testname.substr(0, 9) == "compliance") begin
return COMPLIANCE;
end else begin
return 0;
end
end
endfunction : identify_test
function string get_filename (string testname);
int length;
begin
length = testname.len();
testname[length-1] = "f";
testname[length-2] = "l";
testname[length-3] = "e";
return testname;
end
endfunction : get_filename
function string get_ref_filename (string testname);
begin
if (identify_test(test_file) == COMPLIANCE) begin
return testname.substr(11, testname.len() - 5);
end else if (identify_test(test_file) == ARCH) begin
return testname.substr(5, testname.len() - 5);
end
end
endfunction : get_ref_filename
`endif // VERILATOR
`ifndef VERILATOR
always #5 clk = ~clk; // 100 MHz
always #500 rtc_clk = ~rtc_clk; // 1 MHz
`endif // VERILATOR
// Reset logic
assign rst_n = &rst_cnt;
always_ff @(posedge clk) begin
if (rst_init) rst_cnt <= '0;
else if (~&rst_cnt) rst_cnt <= rst_cnt + 1'b1;
end
`ifdef SCR1_DBG_EN
initial begin
trst_n = 1'b0;
tck = 1'b0;
tdi = 1'b0;
#900ns trst_n = 1'b1;
#500ns tms = 1'b1;
#800ns tms = 1'b0;
#500ns trst_n = 1'b0;
#100ns tms = 1'b1;
end
`endif // SCR1_DBG_EN
//-------------------------------------------------------------------------------
// Run tests
//-------------------------------------------------------------------------------
`include "scr1_top_tb_runtests.sv"
//------------------------------------------------------------------------------
// Core instance
//------------------------------------------------------------------------------
scr1_top_axi i_top (
// Reset
.pwrup_rst_n (rst_n ),
.rst_n (rst_n ),
.cpu_rst_n (rst_n ),
`ifdef SCR1_DBG_EN
.sys_rst_n_o ( ),
.sys_rdc_qlfy_o ( ),
`endif // SCR1_DBG_EN
// Clock
.clk (clk ),
.rtc_clk (rtc_clk ),
// Fuses
.fuse_mhartid (fuse_mhartid ),
`ifdef SCR1_DBG_EN
.fuse_idcode (`SCR1_TAP_IDCODE ),
`endif // SCR1_DBG_EN
// IRQ
`ifdef SCR1_IPIC_EN
.irq_lines (irq_lines ),
`else // SCR1_IPIC_EN
.ext_irq (ext_irq ),
`endif // SCR1_IPIC_EN
.soft_irq (soft_irq ),
// DFT
.test_mode (1'b0 ),
.test_rst_n (1'b1 ),
`ifdef SCR1_DBG_EN
// JTAG
.trst_n (trst_n ),
.tck (tck ),
.tms (tms ),
.tdi (tdi ),
.tdo (tdo ),
.tdo_en (tdo_en ),
`endif // SCR1_DBG_EN
// Instruction memory interface
.io_axi_imem_awid (io_axi_imem_awid ),
.io_axi_imem_awaddr (io_axi_imem_awaddr ),
.io_axi_imem_awlen (io_axi_imem_awlen ),
.io_axi_imem_awsize (io_axi_imem_awsize ),
.io_axi_imem_awburst (),
.io_axi_imem_awlock (),
.io_axi_imem_awcache (),
.io_axi_imem_awprot (),
.io_axi_imem_awregion (),
.io_axi_imem_awuser (),
.io_axi_imem_awqos (),
.io_axi_imem_awvalid (io_axi_imem_awvalid ),
.io_axi_imem_awready (io_axi_imem_awready ),
.io_axi_imem_wdata (io_axi_imem_wdata ),
.io_axi_imem_wstrb (io_axi_imem_wstrb ),
.io_axi_imem_wlast (io_axi_imem_wlast ),
.io_axi_imem_wuser (),
.io_axi_imem_wvalid (io_axi_imem_wvalid ),
.io_axi_imem_wready (io_axi_imem_wready ),
.io_axi_imem_bid (io_axi_imem_bid ),
.io_axi_imem_bresp (io_axi_imem_bresp ),
.io_axi_imem_bvalid (io_axi_imem_bvalid ),
.io_axi_imem_buser (4'd0 ),
.io_axi_imem_bready (io_axi_imem_bready ),
.io_axi_imem_arid (io_axi_imem_arid ),
.io_axi_imem_araddr (io_axi_imem_araddr ),
.io_axi_imem_arlen (io_axi_imem_arlen ),
.io_axi_imem_arsize (io_axi_imem_arsize ),
.io_axi_imem_arburst (io_axi_imem_arburst ),
.io_axi_imem_arlock (),
.io_axi_imem_arcache (),
.io_axi_imem_arprot (),
.io_axi_imem_arregion (),
.io_axi_imem_aruser (),
.io_axi_imem_arqos (),
.io_axi_imem_arvalid (io_axi_imem_arvalid ),
.io_axi_imem_arready (io_axi_imem_arready ),
.io_axi_imem_rid (io_axi_imem_rid ),
.io_axi_imem_rdata (io_axi_imem_rdata ),
.io_axi_imem_rresp (io_axi_imem_rresp ),
.io_axi_imem_rlast (io_axi_imem_rlast ),
.io_axi_imem_ruser (4'd0 ),
.io_axi_imem_rvalid (io_axi_imem_rvalid ),
.io_axi_imem_rready (io_axi_imem_rready ),
// Data memory interface
.io_axi_dmem_awid (io_axi_dmem_awid ),
.io_axi_dmem_awaddr (io_axi_dmem_awaddr ),
.io_axi_dmem_awlen (io_axi_dmem_awlen ),
.io_axi_dmem_awsize (io_axi_dmem_awsize ),
.io_axi_dmem_awburst (),
.io_axi_dmem_awlock (),
.io_axi_dmem_awcache (),
.io_axi_dmem_awprot (),
.io_axi_dmem_awregion (),
.io_axi_dmem_awuser (),
.io_axi_dmem_awqos (),
.io_axi_dmem_awvalid (io_axi_dmem_awvalid ),
.io_axi_dmem_awready (io_axi_dmem_awready ),
.io_axi_dmem_wdata (io_axi_dmem_wdata ),
.io_axi_dmem_wstrb (io_axi_dmem_wstrb ),
.io_axi_dmem_wlast (io_axi_dmem_wlast ),
.io_axi_dmem_wuser (),
.io_axi_dmem_wvalid (io_axi_dmem_wvalid ),
.io_axi_dmem_wready (io_axi_dmem_wready ),
.io_axi_dmem_bid (io_axi_dmem_bid ),
.io_axi_dmem_bresp (io_axi_dmem_bresp ),
.io_axi_dmem_bvalid (io_axi_dmem_bvalid ),
.io_axi_dmem_buser (4'd0 ),
.io_axi_dmem_bready (io_axi_dmem_bready ),
.io_axi_dmem_arid (io_axi_dmem_arid ),
.io_axi_dmem_araddr (io_axi_dmem_araddr ),
.io_axi_dmem_arlen (io_axi_dmem_arlen ),
.io_axi_dmem_arsize (io_axi_dmem_arsize ),
.io_axi_dmem_arburst (io_axi_dmem_arburst ),
.io_axi_dmem_arlock (),
.io_axi_dmem_arcache (),
.io_axi_dmem_arprot (),
.io_axi_dmem_arregion (),
.io_axi_dmem_aruser (),
.io_axi_dmem_arqos (),
.io_axi_dmem_arvalid (io_axi_dmem_arvalid ),
.io_axi_dmem_arready (io_axi_dmem_arready ),
.io_axi_dmem_rid (io_axi_dmem_rid ),
.io_axi_dmem_rdata (io_axi_dmem_rdata ),
.io_axi_dmem_rresp (io_axi_dmem_rresp ),
.io_axi_dmem_rlast (io_axi_dmem_rlast ),
.io_axi_dmem_ruser (4'd0 ),
.io_axi_dmem_rvalid (io_axi_dmem_rvalid ),
.io_axi_dmem_rready (io_axi_dmem_rready )
);
//-------------------------------------------------------------------------------
// Memory instance
//-------------------------------------------------------------------------------
scr1_memory_tb_axi #(
.SIZE (SCR1_MEM_SIZE),
.N_IF (2 ),
.W_ADR (32 ),
.W_DATA (32 )
) i_memory_tb (
// Common
.rst_n (rst_n),
.clk (clk),
`ifdef SCR1_IPIC_EN
.irq_lines (irq_lines),
`else // SCR1_IPIC_EN
.ext_irq (ext_irq),
`endif // SCR1_IPIC_EN
.soft_irq (soft_irq),
// Write address channel
.awid ( {io_axi_imem_awid, io_axi_dmem_awid} ),
.awaddr ( {io_axi_imem_awaddr, io_axi_dmem_awaddr} ),
.awsize ( {io_axi_imem_awsize, io_axi_dmem_awsize} ),
.awlen ( {io_axi_imem_awlen, io_axi_dmem_awlen} ),
.awvalid ( {io_axi_imem_awvalid,io_axi_dmem_awvalid} ),
.awready ( {io_axi_imem_awready,io_axi_dmem_awready} ),
// Write data channel
.wdata ( {io_axi_imem_wdata, io_axi_dmem_wdata} ),
.wstrb ( {io_axi_imem_wstrb, io_axi_dmem_wstrb} ),
.wvalid ( {io_axi_imem_wvalid, io_axi_dmem_wvalid} ),
.wlast ( {io_axi_imem_wlast, io_axi_dmem_wlast} ),
.wready ( {io_axi_imem_wready, io_axi_dmem_wready} ),
// Write response channel
.bready ( {io_axi_imem_bready, io_axi_dmem_bready} ),
.bvalid ( {io_axi_imem_bvalid, io_axi_dmem_bvalid} ),
.bid ( {io_axi_imem_bid, io_axi_dmem_bid} ),
.bresp ( {io_axi_imem_bresp, io_axi_dmem_bresp} ),
// Read address channel
.arid ( {io_axi_imem_arid, io_axi_dmem_arid} ),
.araddr ( {io_axi_imem_araddr, io_axi_dmem_araddr} ),
.arburst ( {io_axi_imem_arburst,io_axi_dmem_arburst} ),
.arsize ( {io_axi_imem_arsize, io_axi_dmem_arsize} ),
.arlen ( {io_axi_imem_arlen, io_axi_dmem_arlen} ),
.arvalid ( {io_axi_imem_arvalid,io_axi_dmem_arvalid} ),
.arready ( {io_axi_imem_arready,io_axi_dmem_arready} ),
// Read data channel
.rvalid ( {io_axi_imem_rvalid, io_axi_dmem_rvalid} ),
.rready ( {io_axi_imem_rready, io_axi_dmem_rready} ),
.rid ( {io_axi_imem_rid, io_axi_dmem_rid} ),
.rdata ( {io_axi_imem_rdata, io_axi_dmem_rdata} ),
.rlast ( {io_axi_imem_rlast, io_axi_dmem_rlast} ),
.rresp ( {io_axi_imem_rresp, io_axi_dmem_rresp} )
);
endmodule : scr1_top_tb_axi

View File

@@ -0,0 +1,224 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_top_tb_runtests.sv>
/// @brief SCR1 testbench run tests
///
//-------------------------------------------------------------------------------
// Run tests
//-------------------------------------------------------------------------------
initial begin
$value$plusargs("imem_pattern=%h", imem_req_ack_stall);
$value$plusargs("dmem_pattern=%h", dmem_req_ack_stall);
`ifdef SIGNATURE_OUT
$value$plusargs("test_name=%s", s_testname);
b_single_run_flag = 1;
`else // SIGNATURE_OUT
$value$plusargs("test_info=%s", s_info);
$value$plusargs("test_results=%s", s_results);
f_info = $fopen(s_info, "r");
f_results = $fopen(s_results, "a");
`endif // SIGNATURE_OUT
fuse_mhartid = 0;
end
always_ff @(posedge clk) begin
bit test_pass;
bit test_error;
int unsigned f_test;
watchdogs_cnt <= watchdogs_cnt + 'b1;
if (test_running) begin
test_pass = 1;
rst_init <= 1'b0;
if ((i_top.i_core_top.i_pipe_top.curr_pc == SCR1_SIM_EXIT_ADDR) & ~rst_init & &rst_cnt) begin
`ifdef VERILATOR
logic [255:0] full_filename;
full_filename = test_file;
`else // VERILATOR
string full_filename;
full_filename = test_file;
`endif // VERILATOR
if (identify_test(test_file)) begin
logic [31:0] tmpv, start, stop, ref_data, test_data, start_addr, trap_addr;
integer fd;
logic [31:0] code;
`ifdef VERILATOR
logic [2047:0] tmpstr;
`else // VERILATOR
string tmpstr;
`endif // VERILATOR
test_running <= 1'b0;
test_pass = 1;
test_error = 0;
$sformat(tmpstr, "riscv64-unknown-elf-readelf -s %s | grep 'begin_signature\\|end_signature\\| _start\\|trap_vector' | awk '{print $2}' > elfinfo", get_filename(test_file));
fd = $fopen("script.sh", "w");
if (fd == 0) begin
$write("Can't open script.sh\n");
test_error = 1;
end
$fwrite(fd, "%s", tmpstr);
$fclose(fd);
$system("sh script.sh");
fd = $fopen("elfinfo", "r");
if (fd == 0) begin
$write("Can't open elfinfo\n");
test_error = 1;
end
if ($fscanf(fd,"%h\n%h\n%h\n%h", trap_addr, start, stop, start_addr) != 4) begin
$write("Wrong elfinfo data\n");
test_error = 1;
end
if ((trap_addr != ADDR_TRAP_VECTOR & trap_addr != ADDR_TRAP_DEFAULT) | start_addr != ADDR_START) begin
$write("\nError trap_vector %h or/and _start %h are incorrectly aligned and are not at their address\n", trap_addr, start_addr);
test_error = 1;
end
if (start > stop) begin
tmpv = start;
start = stop;
stop = tmpv;
end
$fclose(fd);
`ifdef SIGNATURE_OUT
$sformat(tmpstr, "%s.signature.output", s_testname);
`ifdef VERILATOR
tmpstr = remove_trailing_whitespaces(tmpstr);
`endif
fd = $fopen(tmpstr, "w");
while ((start != stop)) begin
test_data = {i_memory_tb.memory[start+3], i_memory_tb.memory[start+2], i_memory_tb.memory[start+1], i_memory_tb.memory[start]};
$fwrite(fd, "%x", test_data);
$fwrite(fd, "%s", "\n");
start += 4;
end
$fclose(fd);
`else //SIGNATURE_OUT
if (identify_test(test_file) == COMPLIANCE) begin
$sformat(tmpstr, "riscv_compliance/ref_data/%s", get_ref_filename(test_file));
end else if (identify_test(test_file) == ARCH) begin
$sformat(tmpstr, "riscv_arch/ref_data/%s", get_ref_filename(test_file));
end
`ifdef VERILATOR
tmpstr = remove_trailing_whitespaces(tmpstr);
`endif
fd = $fopen(tmpstr,"r");
if (fd == 0) begin
$write("Can't open reference_data file: %s\n", tmpstr);
test_error = 1;
end
while (!$feof(fd) && (start != stop)) begin
if (($fscanf(fd, "%h", ref_data)=='h1)) begin
test_data = {i_memory_tb.memory[start+3], i_memory_tb.memory[start+2], i_memory_tb.memory[start+1], i_memory_tb.memory[start]};
test_pass &= (ref_data == test_data);
start += 4;
end else begin
$write("Wrong $fscanf\n");
test_pass = 0;
end
end
$fclose(fd);
tests_total += 1;
tests_passed += (test_pass & !test_error);
watchdogs_cnt <= '0;
if ((test_pass & !test_error)) begin
$write("\033[0;32mTest passed\033[0m\n");
end else begin
$write("\033[0;31mTest failed\033[0m\n");
end
`endif // SIGNATURE_OUT
end else begin
test_running <= 1'b0;
test_pass = (i_top.i_core_top.i_pipe_top.i_pipe_mprf.mprf_int[10] == 0);
tests_total += 1;
tests_passed += (test_pass & !test_error);
watchdogs_cnt <= '0;
`ifndef SIGNATURE_OUT
if ((test_pass & !test_error)) begin
$write("\033[0;32mTest passed\033[0m\n");
end else begin
$write("\033[0;31mTest failed\033[0m\n");
end
`endif //SIGNATURE_OUT
end
$fwrite(f_results, "%s\t\t%s\t%s\n", test_file, "OK" , ((test_pass & !test_error) ? "PASS" : "__FAIL"));
end
end else begin
`ifdef SIGNATURE_OUT
if ((s_testname.len() != 0) && (b_single_run_flag)) begin
$sformat(test_file, "%s.bin", s_testname);
`else // SIGNATURE_OUT
if (f_info) begin
`ifdef VERILATOR
if ($fgets(test_file,f_info)) begin
test_file = test_file >> 8; // < Removing trailing LF symbol ('\n')
`else // VERILATOR
if (!$feof(f_info)) begin
void'($fscanf(f_info, "%s\n", test_file));
`endif // VERILATOR
`endif // SIGNATURE_OUT
f_test = $fopen(test_file,"r");
if (f_test != 0) begin
// Launch new test
`ifdef SCR1_TRACE_LOG_EN
i_top.i_core_top.i_pipe_top.i_tracelog.test_name = test_file;
`endif // SCR1_TRACE_LOG_EN
i_memory_tb.test_file = test_file;
i_memory_tb.test_file_init = 1'b1;
`ifndef SIGNATURE_OUT
$write("\033[0;34m---Test: %s\033[0m\n", test_file);
`endif //SIGNATURE_OUT
test_running <= 1'b1;
rst_init <= 1'b1;
`ifdef SIGNATURE_OUT
b_single_run_flag = 0;
`endif
end else begin
$fwrite(f_results, "%s\t\t%s\t%s\n", test_file, "__FAIL", "--------");
end
end else begin
// Exit
`ifndef SIGNATURE_OUT
$display("\n#--------------------------------------");
$display("# Summary: %0d/%0d tests passed", tests_passed, tests_total);
$display("#--------------------------------------\n");
$fclose(f_info);
$fclose(f_results);
`endif
$finish();
end
`ifndef SIGNATURE_OUT
end else begin
$write("\033[0;31mError: could not open file %s\033[0m\n", s_info);
$finish();
end
`endif // SIGNATURE_OUT
end
if (watchdogs_cnt == TIMEOUT) begin
if (test_file == "watchdog.hex") begin
tests_total += 'b1;
tests_passed += 'b1;
$fwrite(f_results, "%s\t\t%s\t%s\n", test_file, "OK" , "PASS");
test_running <= '0;
watchdogs_cnt <= '0;
end else begin
tests_total += 'b1;
tests_passed += 'b0;
$write("\033[0;31mError: TIMEOUT %s\033[0m\n", test_file);
$fwrite(f_results, "%s\t\t%s\t%s\n", test_file, "OK" , "__FAIL");
test_running <= '0;
watchdogs_cnt <= '0;
end
end
end

480
src/top/scr1_dmem_ahb.sv Normal file
View File

@@ -0,0 +1,480 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dmem_ahb.sv>
/// @brief Data memory AHB bridge
///
`include "scr1_ahb.svh"
`include "scr1_memif.svh"
module scr1_dmem_ahb (
// Control Signals
input logic rst_n,
input logic clk,
// Core Interface
output logic dmem_req_ack,
input logic dmem_req,
input type_scr1_mem_cmd_e dmem_cmd,
input type_scr1_mem_width_e dmem_width,
input logic [SCR1_AHB_WIDTH-1:0] dmem_addr,
input logic [SCR1_AHB_WIDTH-1:0] dmem_wdata,
output logic [SCR1_AHB_WIDTH-1:0] dmem_rdata,
output type_scr1_mem_resp_e dmem_resp,
// AHB Interface
output logic [3:0] hprot,
output logic [2:0] hburst,
output logic [2:0] hsize,
output logic [1:0] htrans,
output logic hmastlock,
output logic [SCR1_AHB_WIDTH-1:0] haddr,
output logic hwrite,
output logic [SCR1_AHB_WIDTH-1:0] hwdata,
input logic hready,
input logic [SCR1_AHB_WIDTH-1:0] hrdata,
input logic hresp
);
//-------------------------------------------------------------------------------
// Local Parameters
//-------------------------------------------------------------------------------
`ifndef SCR1_DMEM_AHB_OUT_BP
localparam SCR1_FIFO_WIDTH = 2;
localparam SCR1_FIFO_CNT_WIDTH = $clog2(SCR1_FIFO_WIDTH+1);
`endif // SCR1_DMEM_AHB_OUT_BP
//-------------------------------------------------------------------------------
// Local type declaration
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_FSM_ADDR = 1'b0,
SCR1_FSM_DATA = 1'b1
`ifdef SCR1_XPROP_EN
,
SCR1_FSM_ERR = 1'bx
`endif // SCR1_XPROP_EN
} type_scr1_fsm_e;
typedef struct packed {
logic hwrite;
logic [2:0] hwidth;
logic [SCR1_AHB_WIDTH-1:0] haddr;
logic [SCR1_AHB_WIDTH-1:0] hwdata;
} type_scr1_req_fifo_s;
typedef struct packed {
logic [2:0] hwidth;
logic [1:0] haddr;
logic [SCR1_AHB_WIDTH-1:0] hwdata;
} type_scr1_data_fifo_s;
typedef struct packed {
logic hresp;
logic [2:0] hwidth;
logic [1:0] haddr;
logic [SCR1_AHB_WIDTH-1:0] hrdata;
} type_scr1_resp_fifo_s;
//-------------------------------------------------------------------------------
// Local functions
//-------------------------------------------------------------------------------
function automatic logic [2:0] scr1_conv_mem2ahb_width (
input type_scr1_mem_width_e dmem_width
);
logic [2:0] tmp;
begin
case (dmem_width)
SCR1_MEM_WIDTH_BYTE : begin
tmp = SCR1_HSIZE_8B;
end
SCR1_MEM_WIDTH_HWORD : begin
tmp = SCR1_HSIZE_16B;
end
SCR1_MEM_WIDTH_WORD : begin
tmp = SCR1_HSIZE_32B;
end
default : begin
tmp = SCR1_HSIZE_ERR;
end
endcase
return tmp;
end
endfunction : scr1_conv_mem2ahb_width
function automatic logic[SCR1_AHB_WIDTH-1:0] scr1_conv_mem2ahb_wdata (
input logic [1:0] dmem_addr,
input type_scr1_mem_width_e dmem_width,
input logic [SCR1_AHB_WIDTH-1:0] dmem_wdata
);
logic [SCR1_AHB_WIDTH-1:0] tmp;
begin
`ifdef SCR1_XPROP_EN
tmp = 'x;
`else // SCR1_XPROP_EN
tmp = '0;
`endif // SCR1_XPROP_EN
case (dmem_width)
SCR1_MEM_WIDTH_BYTE : begin
case (dmem_addr)
2'b00 : begin
tmp[7:0] = dmem_wdata[7:0];
end
2'b01 : begin
tmp[15:8] = dmem_wdata[7:0];
end
2'b10 : begin
tmp[23:16] = dmem_wdata[7:0];
end
2'b11 : begin
tmp[31:24] = dmem_wdata[7:0];
end
default : begin
end
endcase
end
SCR1_MEM_WIDTH_HWORD : begin
case (dmem_addr[1])
1'b0 : begin
tmp[15:0] = dmem_wdata[15:0];
end
1'b1 : begin
tmp[31:16] = dmem_wdata[15:0];
end
default : begin
end
endcase
end
SCR1_MEM_WIDTH_WORD : begin
tmp = dmem_wdata;
end
default : begin
end
endcase
return tmp;
end
endfunction : scr1_conv_mem2ahb_wdata
function automatic logic[SCR1_AHB_WIDTH-1:0] scr1_conv_ahb2mem_rdata (
input logic [2:0] hwidth,
input logic [1:0] haddr,
input logic [SCR1_AHB_WIDTH-1:0] hrdata
);
logic [SCR1_AHB_WIDTH-1:0] tmp;
begin
`ifdef SCR1_XPROP_EN
tmp = 'x;
`else // SCR1_XPROP_EN
tmp = '0;
`endif // SCR1_XPROP_EN
case (hwidth)
SCR1_HSIZE_8B : begin
case (haddr)
2'b00 : tmp[7:0] = hrdata[7:0];
2'b01 : tmp[7:0] = hrdata[15:8];
2'b10 : tmp[7:0] = hrdata[23:16];
2'b11 : tmp[7:0] = hrdata[31:24];
default : begin
end
endcase
end
SCR1_HSIZE_16B : begin
case (haddr[1])
1'b0 : tmp[15:0] = hrdata[15:0];
1'b1 : tmp[15:0] = hrdata[31:16];
default : begin
end
endcase
end
SCR1_HSIZE_32B : begin
tmp = hrdata;
end
default : begin
end
endcase
return tmp;
end
endfunction : scr1_conv_ahb2mem_rdata
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
type_scr1_fsm_e fsm;
logic req_fifo_rd;
logic req_fifo_wr;
logic req_fifo_up;
`ifdef SCR1_DMEM_AHB_OUT_BP
type_scr1_req_fifo_s req_fifo_new;
type_scr1_req_fifo_s req_fifo_r;
type_scr1_req_fifo_s [0:0] req_fifo;
`else // SCR1_DMEM_AHB_OUT_BP
type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo;
type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo_new;
logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt;
logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt_new;
`endif // SCR1_DMEM_AHB_OUT_BP
logic req_fifo_empty;
logic req_fifo_full;
type_scr1_data_fifo_s data_fifo;
type_scr1_resp_fifo_s resp_fifo;
logic resp_fifo_hready;
//-------------------------------------------------------------------------------
// Interface to Core
//-------------------------------------------------------------------------------
assign dmem_req_ack = ~req_fifo_full;
assign req_fifo_wr = ~req_fifo_full & dmem_req;
assign dmem_rdata = scr1_conv_ahb2mem_rdata(resp_fifo.hwidth, resp_fifo.haddr, resp_fifo.hrdata);
assign dmem_resp = (resp_fifo_hready)
? (resp_fifo.hresp == SCR1_HRESP_OKAY)
? SCR1_MEM_RESP_RDY_OK
: SCR1_MEM_RESP_RDY_ER
: SCR1_MEM_RESP_NOTRDY ;
//-------------------------------------------------------------------------------
// REQ_FIFO
//-------------------------------------------------------------------------------
`ifdef SCR1_DMEM_AHB_OUT_BP
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
req_fifo_full <= 1'b0;
end else begin
if (~req_fifo_full) begin
req_fifo_full <= dmem_req & ~req_fifo_rd;
end else begin
req_fifo_full <= ~req_fifo_rd;
end
end
end
assign req_fifo_empty = ~(req_fifo_full | dmem_req);
assign req_fifo_up = ~req_fifo_rd & req_fifo_wr;
always_ff @(posedge clk) begin
if (req_fifo_up) begin
req_fifo_r <= req_fifo_new;
end
end
assign req_fifo_new.hwrite = dmem_req ? (dmem_cmd == SCR1_MEM_CMD_WR) : 1'b0;
assign req_fifo_new.hwidth = dmem_req ? scr1_conv_mem2ahb_width(dmem_width) : '0;
assign req_fifo_new.haddr = dmem_req ? dmem_addr : '0;
assign req_fifo_new.hwdata = (dmem_req & (dmem_cmd == SCR1_MEM_CMD_WR))
? scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata)
: '0;
assign req_fifo[0] = (req_fifo_full) ? req_fifo_r: req_fifo_new;
`else // SCR1_DMEM_AHB_OUT_BP
always_comb begin
req_fifo_up = 1'b0;
req_fifo_cnt_new = req_fifo_cnt;
req_fifo_new = req_fifo;
case ({req_fifo_rd, req_fifo_wr})
2'b00 : begin
// nothing todo
end
2'b01: begin
// FIFO write
req_fifo_up = 1'b1;
req_fifo_new[req_fifo_cnt].hwrite = (dmem_cmd == SCR1_MEM_CMD_WR);
req_fifo_new[req_fifo_cnt].hwidth = scr1_conv_mem2ahb_width(dmem_width);
req_fifo_new[req_fifo_cnt].haddr = dmem_addr;
req_fifo_new[req_fifo_cnt].hwdata = scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata);
req_fifo_cnt_new = req_fifo_cnt + 1'b1;
end
2'b10 : begin
// FIFO read
req_fifo_up = 1'b1;
req_fifo_new[0] = req_fifo_new[1];
req_fifo_new[1].hwrite = 1'b0;
req_fifo_new[1].hwidth = SCR1_HSIZE_32B;
`ifdef SCR1_XPROP_EN
req_fifo_new[1].haddr = 'x;
req_fifo_new[1].hwdata = 'x;
`endif // SCR1_XPROP_EN
req_fifo_cnt_new = req_fifo_cnt - 1'b1;
end
2'b11 : begin
// Read and Write FIFO. It is possible only when fifo_cnt = 1
req_fifo_up = 1'b1;
req_fifo_new[0].hwrite = (dmem_cmd == SCR1_MEM_CMD_WR);
req_fifo_new[0].hwidth = scr1_conv_mem2ahb_width(dmem_width);
req_fifo_new[0].haddr = dmem_addr;
req_fifo_new[0].hwdata = scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata);
end
default : begin
`ifdef SCR1_XPROP_EN
req_fifo_up = 'x;
req_fifo_cnt_new = 'x;
req_fifo_new = 'x;
`endif // SCR1_XPROP_EN
end
endcase
end
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
req_fifo_cnt <= '0;
end else begin
if (req_fifo_up) begin
req_fifo_cnt <= req_fifo_cnt_new;
end
end
end
assign req_fifo_full = (req_fifo_cnt == SCR1_FIFO_WIDTH);
assign req_fifo_empty = ~(|req_fifo_cnt);
always_ff @(posedge clk) begin
if (req_fifo_up) begin
req_fifo <= req_fifo_new;
end
end
`endif // SCR1_DMEM_AHB_OUT_BP
//-------------------------------------------------------------------------------
// FSM
//-------------------------------------------------------------------------------
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
fsm <= SCR1_FSM_ADDR;
end else begin
case (fsm)
SCR1_FSM_ADDR : begin
if (hready) begin
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
end
end
SCR1_FSM_DATA : begin
if (hready) begin
if (hresp == SCR1_HRESP_OKAY) begin
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
end else begin
fsm <= SCR1_FSM_ADDR;
end
end
end
default : begin
`ifdef SCR1_XPROP_EN
fsm <= SCR1_FSM_ERR;
`endif // SCR1_XPROP_EN
end
endcase
end
end
always_comb begin
req_fifo_rd = 1'b0;
case (fsm)
SCR1_FSM_ADDR : begin
if (hready) begin
req_fifo_rd = ~req_fifo_empty;
end
end
SCR1_FSM_DATA : begin
if (hready) begin
req_fifo_rd = ~req_fifo_empty & (hresp == SCR1_HRESP_OKAY);
end
end
default : begin
req_fifo_rd = 1'bx;
end
endcase
end
//-------------------------------------------------------------------------------
// FIFO data
//-------------------------------------------------------------------------------
always_ff @(posedge clk) begin
case (fsm)
SCR1_FSM_ADDR : begin
if (~req_fifo_empty) begin
data_fifo.hwidth <= req_fifo[0].hwidth;
data_fifo.haddr <= req_fifo[0].haddr[1:0];
data_fifo.hwdata <= req_fifo[0].hwdata;
end
end
SCR1_FSM_DATA : begin
if (hready) begin
if (hresp == SCR1_HRESP_OKAY) begin
if (~req_fifo_empty) begin
data_fifo.hwidth <= req_fifo[0].hwidth;
data_fifo.haddr <= req_fifo[0].haddr[1:0];
data_fifo.hwdata <= req_fifo[0].hwdata;
end
end
end
end
default : begin
end
endcase
end
//-------------------------------------------------------------------------------
// FIFO response
//-------------------------------------------------------------------------------
`ifdef SCR1_DMEM_AHB_IN_BP
assign resp_fifo_hready = (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
assign resp_fifo.hresp = hresp;
assign resp_fifo.hwidth = data_fifo.hwidth;
assign resp_fifo.haddr = data_fifo.haddr;
assign resp_fifo.hrdata = hrdata;
`else // SCR1_DMEM_AHB_IN_BP
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
resp_fifo_hready <= 1'b0;
end else begin
resp_fifo_hready <= (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
end
end
always_ff @(posedge clk) begin
if (hready & (fsm == SCR1_FSM_DATA)) begin
resp_fifo.hresp <= hresp;
resp_fifo.hwidth <= data_fifo.hwidth;
resp_fifo.haddr <= data_fifo.haddr;
resp_fifo.hrdata <= hrdata;
end
end
`endif // SCR1_DMEM_AHB_IN_BP
//-------------------------------------------------------------------------------
// Interface to AHB
//-------------------------------------------------------------------------------
assign hprot[SCR1_HPROT_DATA] = 1'b1;
assign hprot[SCR1_HPROT_PRV] = 1'b0;
assign hprot[SCR1_HPROT_BUF] = 1'b0;
assign hprot[SCR1_HPROT_CACHE] = 1'b0;
assign hburst = SCR1_HBURST_SINGLE;
assign hsize = req_fifo[0].hwidth;
assign hmastlock = 1'b0;
always_comb begin
htrans = SCR1_HTRANS_IDLE;
case (fsm)
SCR1_FSM_ADDR : begin
if (~req_fifo_empty) begin
htrans = SCR1_HTRANS_NONSEQ;
end
end
SCR1_FSM_DATA : begin
if (hready) begin
if (hresp == SCR1_HRESP_OKAY) begin
if (~req_fifo_empty) begin
htrans = SCR1_HTRANS_NONSEQ;
end
end
end
end
default : begin
htrans = SCR1_HTRANS_ERR;
end
endcase
end
assign haddr = req_fifo[0].haddr;
assign hwrite = req_fifo[0].hwrite;
assign hwdata = data_fifo.hwdata;
endmodule : scr1_dmem_ahb

278
src/top/scr1_dmem_router.sv Normal file
View File

@@ -0,0 +1,278 @@
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
/// @file <scr1_dmem_router.sv>
/// @brief Data memory router
///
`include "scr1_memif.svh"
`include "scr1_arch_description.svh"
module scr1_dmem_router
#(
parameter SCR1_PORT1_ADDR_MASK = `SCR1_DMEM_AWIDTH'hFFFF0000,
parameter SCR1_PORT1_ADDR_PATTERN = `SCR1_DMEM_AWIDTH'h00010000,
parameter SCR1_PORT2_ADDR_MASK = `SCR1_DMEM_AWIDTH'hFFFF0000,
parameter SCR1_PORT2_ADDR_PATTERN = `SCR1_DMEM_AWIDTH'h00020000
)
(
// Control signals
input logic rst_n,
input logic clk,
// Core interface
output logic dmem_req_ack,
input logic dmem_req,
input type_scr1_mem_cmd_e dmem_cmd,
input type_scr1_mem_width_e dmem_width,
input logic [`SCR1_DMEM_AWIDTH-1:0] dmem_addr,
input logic [`SCR1_DMEM_DWIDTH-1:0] dmem_wdata,
output logic [`SCR1_DMEM_DWIDTH-1:0] dmem_rdata,
output type_scr1_mem_resp_e dmem_resp,
// PORT0 interface
input logic port0_req_ack,
output logic port0_req,
output type_scr1_mem_cmd_e port0_cmd,
output type_scr1_mem_width_e port0_width,
output logic [`SCR1_DMEM_AWIDTH-1:0] port0_addr,
output logic [`SCR1_DMEM_DWIDTH-1:0] port0_wdata,
input logic [`SCR1_DMEM_DWIDTH-1:0] port0_rdata,
input type_scr1_mem_resp_e port0_resp,
// PORT1 interface
input logic port1_req_ack,
output logic port1_req,
output type_scr1_mem_cmd_e port1_cmd,
output type_scr1_mem_width_e port1_width,
output logic [`SCR1_DMEM_AWIDTH-1:0] port1_addr,
output logic [`SCR1_DMEM_DWIDTH-1:0] port1_wdata,
input logic [`SCR1_DMEM_DWIDTH-1:0] port1_rdata,
input type_scr1_mem_resp_e port1_resp,
// PORT2 interface
input logic port2_req_ack,
output logic port2_req,
output type_scr1_mem_cmd_e port2_cmd,
output type_scr1_mem_width_e port2_width,
output logic [`SCR1_DMEM_AWIDTH-1:0] port2_addr,
output logic [`SCR1_DMEM_DWIDTH-1:0] port2_wdata,
input logic [`SCR1_DMEM_DWIDTH-1:0] port2_rdata,
input type_scr1_mem_resp_e port2_resp
);
//-------------------------------------------------------------------------------
// Local types declaration
//-------------------------------------------------------------------------------
typedef enum logic {
SCR1_FSM_ADDR,
SCR1_FSM_DATA
} type_scr1_fsm_e;
typedef enum logic [1:0] {
SCR1_SEL_PORT0,
SCR1_SEL_PORT1,
SCR1_SEL_PORT2
} type_scr1_sel_e;
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
type_scr1_fsm_e fsm;
type_scr1_sel_e port_sel;
type_scr1_sel_e port_sel_r;
logic [`SCR1_DMEM_DWIDTH-1:0] sel_rdata;
type_scr1_mem_resp_e sel_resp;
logic sel_req_ack;
//-------------------------------------------------------------------------------
// FSM
//-------------------------------------------------------------------------------
always_comb begin
port_sel = SCR1_SEL_PORT0;
if ((dmem_addr & SCR1_PORT1_ADDR_MASK) == SCR1_PORT1_ADDR_PATTERN) begin
port_sel = SCR1_SEL_PORT1;
end else if ((dmem_addr & SCR1_PORT2_ADDR_MASK) == SCR1_PORT2_ADDR_PATTERN) begin
port_sel = SCR1_SEL_PORT2;
end
end
always_ff @(negedge rst_n, posedge clk) begin
if (~rst_n) begin
fsm <= SCR1_FSM_ADDR;
port_sel_r <= SCR1_SEL_PORT0;
end else begin
case (fsm)
SCR1_FSM_ADDR : begin
if (dmem_req & sel_req_ack) begin
fsm <= SCR1_FSM_DATA;
port_sel_r <= port_sel;
end
end
SCR1_FSM_DATA : begin
case (sel_resp)
SCR1_MEM_RESP_RDY_OK : begin
if (dmem_req & sel_req_ack) begin
fsm <= SCR1_FSM_DATA;
port_sel_r <= port_sel;
end else begin
fsm <= SCR1_FSM_ADDR;
end
end
SCR1_MEM_RESP_RDY_ER : begin
fsm <= SCR1_FSM_ADDR;
end
default : begin
end
endcase
end
default : begin
end
endcase
end
end
always_comb begin
if ((fsm == SCR1_FSM_ADDR) | ((fsm == SCR1_FSM_DATA) & (sel_resp == SCR1_MEM_RESP_RDY_OK))) begin
case (port_sel)
SCR1_SEL_PORT0 : sel_req_ack = port0_req_ack;
SCR1_SEL_PORT1 : sel_req_ack = port1_req_ack;
SCR1_SEL_PORT2 : sel_req_ack = port2_req_ack;
default : sel_req_ack = 1'b0;
endcase
end else begin
sel_req_ack = 1'b0;
end
end
always_comb begin
case (port_sel_r)
SCR1_SEL_PORT0 : begin
sel_rdata = port0_rdata;
sel_resp = port0_resp;
end
SCR1_SEL_PORT1 : begin
sel_rdata = port1_rdata;
sel_resp = port1_resp;
end
SCR1_SEL_PORT2 : begin
sel_rdata = port2_rdata;
sel_resp = port2_resp;
end
default : begin
sel_rdata = '0;
sel_resp = SCR1_MEM_RESP_RDY_ER;
end
endcase
end
//-------------------------------------------------------------------------------
// Interface to core
//-------------------------------------------------------------------------------
assign dmem_req_ack = sel_req_ack;
assign dmem_rdata = sel_rdata;
assign dmem_resp = sel_resp;
//-------------------------------------------------------------------------------
// Interface to PORT0
//-------------------------------------------------------------------------------
always_comb begin
port0_req = 1'b0;
case (fsm)
SCR1_FSM_ADDR : begin
port0_req = dmem_req & (port_sel == SCR1_SEL_PORT0);
end
SCR1_FSM_DATA : begin
if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin
port0_req = dmem_req & (port_sel == SCR1_SEL_PORT0);
end
end
default : begin
end
endcase
end
`ifdef SCR1_XPROP_EN
assign port0_cmd = (port_sel == SCR1_SEL_PORT0) ? dmem_cmd : SCR1_MEM_CMD_ERROR;
assign port0_width = (port_sel == SCR1_SEL_PORT0) ? dmem_width : SCR1_MEM_WIDTH_ERROR;
assign port0_addr = (port_sel == SCR1_SEL_PORT0) ? dmem_addr : 'x;
assign port0_wdata = (port_sel == SCR1_SEL_PORT0) ? dmem_wdata : 'x;
`else // SCR1_XPROP_EN
assign port0_cmd = dmem_cmd ;
assign port0_width = dmem_width;
assign port0_addr = dmem_addr ;
assign port0_wdata = dmem_wdata;
`endif // SCR1_XPROP_EN
//-------------------------------------------------------------------------------
// Interface to PORT1
//-------------------------------------------------------------------------------
always_comb begin
port1_req = 1'b0;
case (fsm)
SCR1_FSM_ADDR : begin
port1_req = dmem_req & (port_sel == SCR1_SEL_PORT1);
end
SCR1_FSM_DATA : begin
if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin
port1_req = dmem_req & (port_sel == SCR1_SEL_PORT1);
end
end
default : begin
end
endcase
end
`ifdef SCR1_XPROP_EN
assign port1_cmd = (port_sel == SCR1_SEL_PORT1) ? dmem_cmd : SCR1_MEM_CMD_ERROR;
assign port1_width = (port_sel == SCR1_SEL_PORT1) ? dmem_width : SCR1_MEM_WIDTH_ERROR;
assign port1_addr = (port_sel == SCR1_SEL_PORT1) ? dmem_addr : 'x;
assign port1_wdata = (port_sel == SCR1_SEL_PORT1) ? dmem_wdata : 'x;
`else // SCR1_XPROP_EN
assign port1_cmd = dmem_cmd ;
assign port1_width = dmem_width;
assign port1_addr = dmem_addr ;
assign port1_wdata = dmem_wdata;
`endif // SCR1_XPROP_EN
//-------------------------------------------------------------------------------
// Interface to PORT2
//-------------------------------------------------------------------------------
always_comb begin
port2_req = 1'b0;
case (fsm)
SCR1_FSM_ADDR : begin
port2_req = dmem_req & (port_sel == SCR1_SEL_PORT2);
end
SCR1_FSM_DATA : begin
if (sel_resp == SCR1_MEM_RESP_RDY_OK) begin
port2_req = dmem_req & (port_sel == SCR1_SEL_PORT2);
end
end
default : begin
end
endcase
end
`ifdef SCR1_XPROP_EN
assign port2_cmd = (port_sel == SCR1_SEL_PORT2) ? dmem_cmd : SCR1_MEM_CMD_ERROR;
assign port2_width = (port_sel == SCR1_SEL_PORT2) ? dmem_width : SCR1_MEM_WIDTH_ERROR;
assign port2_addr = (port_sel == SCR1_SEL_PORT2) ? dmem_addr : 'x;
assign port2_wdata = (port_sel == SCR1_SEL_PORT2) ? dmem_wdata : 'x;
`else // SCR1_XPROP_EN
assign port2_cmd = dmem_cmd ;
assign port2_width = dmem_width;
assign port2_addr = dmem_addr ;
assign port2_wdata = dmem_wdata;
`endif // SCR1_XPROP_EN
`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------
SCR1_SVA_DMEM_RT_XCHECK : assert property (
@(negedge clk) disable iff (~rst_n)
dmem_req |-> !$isunknown({port_sel, dmem_cmd, dmem_width})
) else $error("DMEM router Error: unknown values");
`endif // SCR1_TRGT_SIMULATION
endmodule : scr1_dmem_router

111
src/top/scr1_dp_memory.sv Normal file
View File

@@ -0,0 +1,111 @@
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
/// @file <scr1_dp_memory.sv>
/// @brief Dual-port synchronous memory with byte enable inputs
///
`include "scr1_arch_description.svh"
`ifdef SCR1_TCM_EN
module scr1_dp_memory
#(
parameter SCR1_WIDTH = 32,
parameter SCR1_SIZE = `SCR1_IMEM_AWIDTH'h00010000,
parameter SCR1_NBYTES = SCR1_WIDTH / 8
)
(
input logic clk,
// Port A
input logic rena,
input logic [$clog2(SCR1_SIZE)-1:2] addra,
output logic [SCR1_WIDTH-1:0] qa,
// Port B
input logic renb,
input logic wenb,
input logic [SCR1_NBYTES-1:0] webb,
input logic [$clog2(SCR1_SIZE)-1:2] addrb,
input logic [SCR1_WIDTH-1:0] datab,
output logic [SCR1_WIDTH-1:0] qb
);
`ifdef SCR1_TRGT_FPGA_INTEL
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
`ifdef SCR1_TRGT_FPGA_INTEL_MAX10
(* ramstyle = "M9K" *) logic [SCR1_NBYTES-1:0][7:0] memory_array [0:(SCR1_SIZE/SCR1_NBYTES)-1];
`elsif SCR1_TRGT_FPGA_INTEL_ARRIAV
(* ramstyle = "M10K" *) logic [SCR1_NBYTES-1:0][7:0] memory_array [0:(SCR1_SIZE/SCR1_NBYTES)-1];
`endif
logic [3:0] wenbb;
//-------------------------------------------------------------------------------
// Port B memory behavioral description
//-------------------------------------------------------------------------------
assign wenbb = {4{wenb}} & webb;
always_ff @(posedge clk) begin
if (wenb) begin
if (wenbb[0]) begin
memory_array[addrb][0] <= datab[0+:8];
end
if (wenbb[1]) begin
memory_array[addrb][1] <= datab[8+:8];
end
if (wenbb[2]) begin
memory_array[addrb][2] <= datab[16+:8];
end
if (wenbb[3]) begin
memory_array[addrb][3] <= datab[24+:8];
end
end
qb <= memory_array[addrb];
end
//-------------------------------------------------------------------------------
// Port A memory behavioral description
//-------------------------------------------------------------------------------
always_ff @(posedge clk) begin
qa <= memory_array[addra];
end
`else // SCR1_TRGT_FPGA_INTEL
// CASE: OTHERS - SCR1_TRGT_FPGA_XILINX, SIMULATION, ASIC etc
localparam int unsigned RAM_SIZE_WORDS = SCR1_SIZE/SCR1_NBYTES;
//-------------------------------------------------------------------------------
// Local signal declaration
//-------------------------------------------------------------------------------
`ifdef SCR1_TRGT_FPGA_XILINX
(* ram_style = "block" *) logic [SCR1_WIDTH-1:0] ram_block [RAM_SIZE_WORDS-1:0];
`else // ASIC or SIMULATION
logic [SCR1_WIDTH-1:0] ram_block [RAM_SIZE_WORDS-1:0];
`endif
//-------------------------------------------------------------------------------
// Port A memory behavioral description
//-------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (rena) begin
qa <= ram_block[addra];
end
end
//-------------------------------------------------------------------------------
// Port B memory behavioral description
//-------------------------------------------------------------------------------
always_ff @(posedge clk) begin
if (wenb) begin
for (int i=0; i<SCR1_NBYTES; i++) begin
if (webb[i]) begin
ram_block[addrb][i*8 +: 8] <= datab[i*8 +: 8];
end
end
end
if (renb) begin
qb <= ram_block[addrb];
end
end
`endif // SCR1_TRGT_FPGA_INTEL
endmodule : scr1_dp_memory
`endif // SCR1_TCM_EN

Some files were not shown because too many files have changed in this diff Show More