tools: add riscv-torture
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/4/head
parent
18de7f2e00
commit
ac245a5d6c
|
@ -0,0 +1,4 @@
|
||||||
|
.*.swp
|
||||||
|
output/test*
|
||||||
|
output/failedtests
|
||||||
|
*target/
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "env"]
|
||||||
|
path = env
|
||||||
|
url = https://github.com/riscv/riscv-test-env.git
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Convenience Makefile
|
||||||
|
|
||||||
|
SBT ?= java -Xmx1G -Xss8M -XX:MaxPermSize=128M -jar sbt-launch.jar
|
||||||
|
RTL_CONFIG := DefaultConfig
|
||||||
|
C_SIM := ../emulator/emulator-rocketchip-$(RTL_CONFIG)
|
||||||
|
R_SIM := ../vsim/simv-rocketchip-$(RTL_CONFIG)
|
||||||
|
TEST := output/test.S
|
||||||
|
OPTIONS := $(empty)
|
||||||
|
NUM := 0
|
||||||
|
SUITE := output
|
||||||
|
CONFIG := config/default.config
|
||||||
|
COMMIT := none
|
||||||
|
empty :=
|
||||||
|
space := $(empty) $(empty)
|
||||||
|
cfgopt := $(space)-f$(space)
|
||||||
|
gitopt := $(space)-g$(space)
|
||||||
|
CFG := $(subst $(space),$(cfgopt),$(CONFIG))
|
||||||
|
GITCMT := $(subst $(space),$(gitopt),$(COMMIT))
|
||||||
|
|
||||||
|
.phony: gen ctest rtest itest igentest cgentest rgentest \
|
||||||
|
cnight rnight crnight csuite rsuite \
|
||||||
|
|
||||||
|
gen:
|
||||||
|
$(SBT) 'generator/run -n $(NUM)'
|
||||||
|
|
||||||
|
csuite:
|
||||||
|
for i in `ls $(SUITE) | grep .S` ; do echo $$i ; \
|
||||||
|
result=`make ctest TEST=$(SUITE)/$$i OPTIONS="-s false" | grep 'Simulation failed\|signatures match'` ; \
|
||||||
|
echo $$result ; done
|
||||||
|
rm $(SUITE)/tes*[!.S]
|
||||||
|
|
||||||
|
rsuite:
|
||||||
|
for i in `ls $(SUITE) | grep .S` ; do echo $$i ; \
|
||||||
|
result=`make rtest TEST=$(SUITE)/$$i OPTIONS="-s false" | grep 'Simulation failed\|signatures match'` ; \
|
||||||
|
echo $$result ; done
|
||||||
|
rm $(SUITE)/tes*[!.S]
|
||||||
|
|
||||||
|
crsuite:
|
||||||
|
for i in `ls $(SUITE) | grep .S` ; do echo $$i ; \
|
||||||
|
result=`make crtest TEST=$(SUITE)/$$i OPTIONS="-s false" | grep 'Simulation failed\|signatures match'` ; \
|
||||||
|
echo $$result ; done
|
||||||
|
rm $(SUITE)/tes*[!.S]
|
||||||
|
|
||||||
|
igentest:
|
||||||
|
$(SBT) 'testrun/run'
|
||||||
|
|
||||||
|
cgentest:
|
||||||
|
$(SBT) 'testrun/run -c $(C_SIM) $(OPTIONS)'
|
||||||
|
|
||||||
|
rgentest:
|
||||||
|
$(SBT) 'testrun/run -r $(R_SIM) $(OPTIONS)'
|
||||||
|
|
||||||
|
crgentest:
|
||||||
|
$(SBT) 'testrun/run -c $(C_SIM) -r $(R_SIM) $(OPTIONS)'
|
||||||
|
|
||||||
|
itest:
|
||||||
|
$(SBT) 'testrun/run -a $(TEST) $(OPTIONS)'
|
||||||
|
|
||||||
|
ctest:
|
||||||
|
$(SBT) 'testrun/run -c $(C_SIM) -a $(TEST) $(OPTIONS)'
|
||||||
|
|
||||||
|
rtest:
|
||||||
|
$(SBT) 'testrun/run -r $(R_SIM) -a $(TEST) $(OPTIONS)'
|
||||||
|
|
||||||
|
crtest:
|
||||||
|
$(SBT) 'testrun/run -c $(C_SIM) -r $(R_SIM) -a $(TEST) $(OPTIONS)'
|
||||||
|
|
||||||
|
cnight:
|
||||||
|
$(SBT) 'overnight/run -c $(C_SIM) -g $(COMMIT) $(OPTIONS)'
|
||||||
|
|
||||||
|
rnight:
|
||||||
|
$(SBT) 'overnight/run -r $(R_SIM) -g $(COMMIT) $(OPTIONS)'
|
||||||
|
|
||||||
|
crnight:
|
||||||
|
$(SBT) 'overnight/run -c $(C_SIM) -r $(R_SIM) -g $(COMMIT) $(OPTIONS)'
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
===========================================================================
|
||||||
|
RISC-V Torture Test Generator
|
||||||
|
===========================================================================
|
||||||
|
# Author: Yunsup Lee and Henry Cook
|
||||||
|
# Date: January 29th, 2012
|
||||||
|
# Version: (under version control)
|
||||||
|
|
||||||
|
This is the RISC-V torture test generator and framework. This repository
|
||||||
|
contains three sub-projects that build upon one another. The first,
|
||||||
|
[generator], is used to create a single random torture test. The second,
|
||||||
|
[testrun], is used to run a particular test on particular simulators,
|
||||||
|
diffing the resulting signature with the ISA simulator and optionally
|
||||||
|
creating a derivative test subset that pinpoints the divergence. The third,
|
||||||
|
[overnight], wraps testrun, allowing tests to be run repeatedly for a given
|
||||||
|
duration or until a failure count.
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Instructions
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Modify "config/default.config" to set the parameters desired for building tests
|
||||||
|
(e.g., setting which instructions to use and in which ratio).
|
||||||
|
|
||||||
|
Modify "Makefile" as desired to execute the C simulator or RTL simulator of
|
||||||
|
your choice, and to set the other parameters as you require.
|
||||||
|
|
||||||
|
To build a single test and test it on Spike:
|
||||||
|
|
||||||
|
$ make igentest
|
||||||
|
|
||||||
|
To build single test and run it on the C simulator or RTL simulator, use
|
||||||
|
"make cgentest" or "make rgentest".
|
||||||
|
|
||||||
|
To run overnight tests, you can use "make cnight" and "make rnight".
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Signatures
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Torture works by dumping the register state out to memory at the end of the
|
||||||
|
test program execution. This output is then compared against the output from
|
||||||
|
the Spike ISA simulator.
|
||||||
|
|
||||||
|
The torture program writes the register state to the memory address specified
|
||||||
|
by "xreg_output_data", which is located in the memory section
|
||||||
|
".global begin_signature". The Spike ISA simulator will write out the data
|
||||||
|
found in the "begin_signature" section on exit if provided with the
|
||||||
|
"+signature=" argument:
|
||||||
|
|
||||||
|
$ spike +signature=my_spike_signature.txt test_binary
|
||||||
|
|
||||||
|
The Rocket-chip infrastructure uses the "riscv-fesvr" program to control the
|
||||||
|
execution of the C and RTL simulators. The "riscv-fesvr" also accepts the
|
||||||
|
+signature argument too.
|
||||||
|
|
||||||
|
$ ./csim-rocket-chip +signature=my_rocket_signature.txt test_binary
|
||||||
|
|
||||||
|
A simple diff between the Spike and chip simulator signatures will tell you if
|
||||||
|
any errors have occurred.
|
||||||
|
|
||||||
|
$ diff my_spike_signature.txt my_rocket_signature.txt
|
||||||
|
|
||||||
|
|
||||||
|
**PORTING TORTURE TO YOUR OWN RISC-V PROCESSOR:**
|
||||||
|
|
||||||
|
If you would like to use riscv-torture with your own RISC-V processor, you will
|
||||||
|
need to provide a way to dump the "begin_signature" section to a file.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Low-level Usage
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Some basic use cases are illustrated here (note the Makefile abstracts this for
|
||||||
|
you).
|
||||||
|
|
||||||
|
Make a single test:
|
||||||
|
% ./sbt generator/run
|
||||||
|
% cd output
|
||||||
|
% make
|
||||||
|
% spike +signature=test.sig test
|
||||||
|
|
||||||
|
Take an existing test and diff the signatures of ISA and C simulators:
|
||||||
|
% ./sbt 'testrun/run -a output/test.S -c /path/to/reference-chip/emulator/emulator'
|
||||||
|
|
||||||
|
*** Currently, due to the limiation of scala process library, you cannot
|
||||||
|
torture the RTL simulator ***
|
||||||
|
# Generate a random test and diff the signatures of ISA and RTL simulators:
|
||||||
|
# % ./sbt 'testrun/run -r /path/to/reference-chip/vlsi/build/vcs-sim-rtl/simv'
|
||||||
|
|
||||||
|
Run tests for 30 minutes, email hcook when done, and save failures to dir:
|
||||||
|
% ./sbt 'overnight/run -m 30 -e hcook@eecs.berkeley.edu -p dir'
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Installing
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
% git submodule update --init
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Overnight Overview
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This framework utilizes both the test runner and test generator to perform
|
||||||
|
a long terms serach for failing test cases. It takes the following command
|
||||||
|
line arguments:
|
||||||
|
|
||||||
|
Usage: overnight/run [options]
|
||||||
|
-C <file> | --config <file>
|
||||||
|
config file
|
||||||
|
-p <dir> | --permdir <dir>
|
||||||
|
dir to store failing tests
|
||||||
|
-c <file> | --csim <file>
|
||||||
|
C simulator
|
||||||
|
-r <file> | --rtlsim <file>
|
||||||
|
RTL simulator
|
||||||
|
-e <address> | --email <address>
|
||||||
|
email to report to
|
||||||
|
-t <count> | --threshold <count>
|
||||||
|
number of failures to trigger email
|
||||||
|
-m <int> | --minutes <int>
|
||||||
|
number of minutes to run tests
|
||||||
|
|
||||||
|
You can only generate tests with one instruction mix at a time (based on
|
||||||
|
the setting in the config file). It doesn't matter what simulator you use
|
||||||
|
with the -r and -c flags, they just determines the name used to describe
|
||||||
|
whose diff failed.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Testrun Overview
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This utility compares the signatures generated by passing the -testsig flag
|
||||||
|
to the specified simulators. If it encounters a difference, it subdivides
|
||||||
|
the test into many subtests and searches for which exact program segment
|
||||||
|
reveals the failure. It takes the following command line arguments:
|
||||||
|
|
||||||
|
Usage: testrun/run [options]
|
||||||
|
-C <file> | --config <file>
|
||||||
|
config file
|
||||||
|
-a <file> | --asm <file>
|
||||||
|
input ASM file
|
||||||
|
-c <file> | --csim <file>
|
||||||
|
C simulator
|
||||||
|
-r <file> | --rtlsim <file>
|
||||||
|
RTL simulator
|
||||||
|
-s <boolean> | --seek <boolean>
|
||||||
|
Seek for failing pseg
|
||||||
|
-d <boolean> | --dump <boolean>
|
||||||
|
Dump mismatched signatures
|
||||||
|
|
||||||
|
If you don't specify a asm file, a random one will be generated for you.
|
||||||
|
You can only generate tests with one instruction mix at a time (based on
|
||||||
|
the setting in the config file). It doesn't matter what simulator you use
|
||||||
|
with the -r and -c flags, they just determines the name used to describe
|
||||||
|
whose diff failed. By default, a failed diff will result in the subtest
|
||||||
|
sweep occuring, but this search can be diasbled. Note that the pseg ID
|
||||||
|
reported is actually the pseg following the pseg containing the error.
|
||||||
|
You can optionally dump mistmatched signatures to the dir containing the
|
||||||
|
asm file under test.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Generator Overview
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
To generate a random test, the torture test generator randomly generates
|
||||||
|
many test sequences from a set of test sequences that are written by hand,
|
||||||
|
performs a random register allocation for all test sequences, and finally
|
||||||
|
randomly interleaves instructions from these test sequences. To extend the
|
||||||
|
set of tests or coverage, the programmer needs to write new test sequences.
|
||||||
|
It takes the following command line arguments:
|
||||||
|
|
||||||
|
Usage: generator/run [options]
|
||||||
|
-o <filename> | --output <filename>
|
||||||
|
output filename
|
||||||
|
-C <file> | --config <file>
|
||||||
|
config file
|
||||||
|
|
||||||
|
The following sections describe adding new functionality to the generator.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Test sequence example
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Before we talk about how to write a test sequence, let's look at a very
|
||||||
|
simple example. The following example is a test sequence, which emits an
|
||||||
|
add instruction.
|
||||||
|
|
||||||
|
class SeqADD extends Seq
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any()
|
||||||
|
val src2 = reg_read_any()
|
||||||
|
val dest = reg_write(src1, src2)
|
||||||
|
insts += ADD(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
As I hinted in the overview that the test generator will do register
|
||||||
|
allocation you don't write a string of instructions with architectural
|
||||||
|
registers. You request a virtual registers (i.e., registers that are yet
|
||||||
|
tied down to architectural registers) when you need them, save them in
|
||||||
|
scala values, and use them when you need to (e.g., in an instruction).
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Types of virtual registers
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
- Hidden (position dependent registers): Registers that will have
|
||||||
|
different values when the code is positioned at a different address. An
|
||||||
|
example is registers that hold addresses. Registers that are hidden should
|
||||||
|
be excluded from the output signature.
|
||||||
|
|
||||||
|
- Visible (position independent registers): Registers that are not hidden,
|
||||||
|
therefore will have the same values when the code is positioned at
|
||||||
|
a different address. These registers should be included as part of the
|
||||||
|
output signature.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
How to write a sequence
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Use the following functions to request a register, and generate a string of
|
||||||
|
instructions (look at Inst.scala to see what instructions are available)
|
||||||
|
that uses these virtual registers, and add them to the insts array.
|
||||||
|
|
||||||
|
- reg_read_zero(): returns register x0
|
||||||
|
- reg_read_any(): returns any type of register (hidden or visible)
|
||||||
|
- reg_read_visible(): returns a visible register
|
||||||
|
- reg_write_ra(): returns register ra for write
|
||||||
|
- reg_write_visible(): returns a visible register for write
|
||||||
|
- reg_write_hidden(): returns a hidden register for write
|
||||||
|
- reg_write(regs: Reg*): returns a register that matches the type of regs
|
||||||
|
(if any reg in regs are hidden, the output type is hidden)
|
||||||
|
|
||||||
|
Note that the torture test framework is written in scala, you can use any
|
||||||
|
scala functionality to generate instructions. Look at SeqALU.scala,
|
||||||
|
SeqMem.scala, and SeqBranch.scala to get inspired.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Future TODO
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
- provide support for loops
|
||||||
|
|
||||||
|
- generate statistics of a test to get a sense of coverage
|
||||||
|
+ statistics should include instruction count of each type
|
||||||
|
+ statistics should include register usage
|
||||||
|
|
||||||
|
- complete floating point tests
|
||||||
|
+ add floating point memory move tests
|
||||||
|
+ improve floating point init randomization
|
||||||
|
+ add rounding modes tests
|
||||||
|
|
||||||
|
- complete vector tests
|
||||||
|
+ better randomization
|
||||||
|
+ add SeqVOnly: Tests special vf-only instructions
|
||||||
|
|
||||||
|
- code refactoring
|
||||||
|
+ consolidate RegPool logic
|
||||||
|
+ detect and suppress unallocatable sequences
|
|
@ -0,0 +1,26 @@
|
||||||
|
lazy val commonSettings = Seq(
|
||||||
|
organization := "edu.berkeley.cs",
|
||||||
|
version := "1.1",
|
||||||
|
scalaVersion := "2.11.12",
|
||||||
|
libraryDependencies ++= Seq("com.github.scopt" %% "scopt" % "3.3.0"),
|
||||||
|
libraryDependencies ++= Seq("com.github.scala-incubator.io" %% "scala-io-core" % "0.4.3"),
|
||||||
|
libraryDependencies ++= Seq("com.github.scala-incubator.io" %% "scala-io-file" % "0.4.3")
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val torture = (project in file("."))
|
||||||
|
.settings(commonSettings)
|
||||||
|
.dependsOn(generator, testrun, overnight, fileop)
|
||||||
|
|
||||||
|
lazy val generator = (project in file("generator"))
|
||||||
|
.settings(commonSettings)
|
||||||
|
|
||||||
|
lazy val testrun = (project in file("testrun"))
|
||||||
|
.settings(commonSettings)
|
||||||
|
.dependsOn(generator)
|
||||||
|
|
||||||
|
lazy val overnight = (project in file("overnight"))
|
||||||
|
.settings(commonSettings)
|
||||||
|
.dependsOn(testrun, fileop)
|
||||||
|
|
||||||
|
lazy val fileop = (project in file("fileop"))
|
||||||
|
.settings(commonSettings)
|
|
@ -0,0 +1,52 @@
|
||||||
|
torture.generator.nseqs 200
|
||||||
|
torture.generator.memsize 1024
|
||||||
|
torture.generator.fprnd 0
|
||||||
|
torture.generator.amo false
|
||||||
|
torture.generator.mul true
|
||||||
|
torture.generator.divider true
|
||||||
|
torture.generator.segment true
|
||||||
|
torture.generator.loop true
|
||||||
|
torture.generator.loop_size 64
|
||||||
|
|
||||||
|
torture.generator.mix.xmem 10
|
||||||
|
torture.generator.mix.xbranch 20
|
||||||
|
torture.generator.mix.xalu 70
|
||||||
|
torture.generator.mix.fgen 0
|
||||||
|
torture.generator.mix.fpmem 0
|
||||||
|
torture.generator.mix.fax 0
|
||||||
|
torture.generator.mix.fdiv 0
|
||||||
|
torture.generator.mix.vec 0
|
||||||
|
|
||||||
|
torture.generator.vec.vf 0
|
||||||
|
torture.generator.vec.seq 0
|
||||||
|
torture.generator.vec.memsize 128
|
||||||
|
torture.generator.vec.numsregs 64
|
||||||
|
torture.generator.vec.mul false
|
||||||
|
torture.generator.vec.div false
|
||||||
|
torture.generator.vec.mix true
|
||||||
|
torture.generator.vec.fpu false
|
||||||
|
torture.generator.vec.fma false
|
||||||
|
torture.generator.vec.fcvt false
|
||||||
|
torture.generator.vec.fdiv false
|
||||||
|
torture.generator.vec.amo false
|
||||||
|
torture.generator.vec.seg false
|
||||||
|
torture.generator.vec.stride false
|
||||||
|
torture.generator.vec.pred_alu true
|
||||||
|
torture.generator.vec.pred_mem true
|
||||||
|
|
||||||
|
torture.generator.vec.mix.valu 20
|
||||||
|
torture.generator.vec.mix.vpop 60
|
||||||
|
torture.generator.vec.mix.vmem 20
|
||||||
|
torture.generator.vec.mix.vonly 0
|
||||||
|
|
||||||
|
torture.testrun.maxcycles 10000000
|
||||||
|
torture.testrun.virtual false
|
||||||
|
torture.testrun.seek true
|
||||||
|
torture.testrun.dump false
|
||||||
|
torture.testrun.vec false
|
||||||
|
|
||||||
|
torture.overnight.errors 1
|
||||||
|
torture.overnight.minutes 1
|
||||||
|
torture.overnight.outdir output/failedtests
|
||||||
|
torture.overnight.email your@email.address
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
torture.generator.nseqs 10
|
||||||
|
torture.generator.memsize 1024
|
||||||
|
torture.generator.fprnd 0
|
||||||
|
torture.generator.amo true
|
||||||
|
torture.generator.mul true
|
||||||
|
torture.generator.divider true
|
||||||
|
|
||||||
|
torture.generator.mix.xmem 0
|
||||||
|
torture.generator.mix.xbranch 0
|
||||||
|
torture.generator.mix.xalu 0
|
||||||
|
torture.generator.mix.fgen 0
|
||||||
|
torture.generator.mix.fpmem 0
|
||||||
|
torture.generator.mix.fax 0
|
||||||
|
torture.generator.mix.fdiv 0
|
||||||
|
torture.generator.mix.vec 100
|
||||||
|
|
||||||
|
torture.generator.vec.vf 1
|
||||||
|
torture.generator.vec.seq 40
|
||||||
|
torture.generator.vec.memsize 128
|
||||||
|
torture.generator.vec.numsregs 64
|
||||||
|
torture.generator.vec.mul false
|
||||||
|
torture.generator.vec.div false
|
||||||
|
torture.generator.vec.mix true
|
||||||
|
torture.generator.vec.fpu false
|
||||||
|
torture.generator.vec.fma false
|
||||||
|
torture.generator.vec.fcvt false
|
||||||
|
torture.generator.vec.fdiv false
|
||||||
|
torture.generator.vec.amo true
|
||||||
|
torture.generator.vec.seg false
|
||||||
|
torture.generator.vec.stride false
|
||||||
|
torture.generator.vec.pop false
|
||||||
|
torture.generator.vec.pred_alu false
|
||||||
|
torture.generator.vec.pred_mem false
|
||||||
|
|
||||||
|
torture.generator.vec.mix.valu 50
|
||||||
|
torture.generator.vec.mix.vmem 50
|
||||||
|
torture.generator.vec.mix.vonly 0
|
||||||
|
|
||||||
|
torture.testrun.maxcycles 10000000
|
||||||
|
torture.testrun.virtual false
|
||||||
|
torture.testrun.seek true
|
||||||
|
torture.testrun.dump false
|
||||||
|
torture.testrun.vec true
|
||||||
|
|
||||||
|
torture.overnight.errors 1
|
||||||
|
torture.overnight.minutes 1
|
||||||
|
torture.overnight.outdir output/failedtests
|
||||||
|
torture.overnight.email your@email.address
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
torture.generator.nseqs 1
|
||||||
|
torture.generator.memsize 1024
|
||||||
|
torture.generator.fprnd 0
|
||||||
|
torture.generator.amo true
|
||||||
|
torture.generator.mul true
|
||||||
|
torture.generator.divider true
|
||||||
|
|
||||||
|
torture.generator.mix.xmem 0
|
||||||
|
torture.generator.mix.xbranch 0
|
||||||
|
torture.generator.mix.xalu 0
|
||||||
|
torture.generator.mix.fgen 0
|
||||||
|
torture.generator.mix.fpmem 0
|
||||||
|
torture.generator.mix.fax 0
|
||||||
|
torture.generator.mix.fdiv 0
|
||||||
|
torture.generator.mix.vec 100
|
||||||
|
|
||||||
|
torture.generator.vec.vf 1
|
||||||
|
torture.generator.vec.seq 20
|
||||||
|
torture.generator.vec.memsize 128
|
||||||
|
torture.generator.vec.numsregs 64
|
||||||
|
torture.generator.vec.mul false
|
||||||
|
torture.generator.vec.div false
|
||||||
|
torture.generator.vec.mix true
|
||||||
|
torture.generator.vec.fpu false
|
||||||
|
torture.generator.vec.fma false
|
||||||
|
torture.generator.vec.fcvt false
|
||||||
|
torture.generator.vec.fdiv false
|
||||||
|
torture.generator.vec.amo false
|
||||||
|
torture.generator.vec.seg false
|
||||||
|
torture.generator.vec.stride false
|
||||||
|
torture.generator.vec.pred_alu true
|
||||||
|
torture.generator.vec.pred_mem true
|
||||||
|
|
||||||
|
torture.generator.vec.mix.valu 20
|
||||||
|
torture.generator.vec.mix.vpop 60
|
||||||
|
torture.generator.vec.mix.vmem 20
|
||||||
|
torture.generator.vec.mix.vonly 0
|
||||||
|
|
||||||
|
torture.testrun.maxcycles 10000000
|
||||||
|
torture.testrun.virtual false
|
||||||
|
torture.testrun.seek true
|
||||||
|
torture.testrun.dump false
|
||||||
|
torture.testrun.vec true
|
||||||
|
|
||||||
|
torture.overnight.errors 1
|
||||||
|
torture.overnight.minutes 1
|
||||||
|
torture.overnight.outdir output/failedtests
|
||||||
|
torture.overnight.email your@email.address
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
package torture
|
||||||
|
package fileop
|
||||||
|
|
||||||
|
import scala.sys.process._
|
||||||
|
import scalax.file.Path
|
||||||
|
import scalax.file.FileSystem
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object FileOperations extends App
|
||||||
|
{
|
||||||
|
override def main(args: Array[String]) = { System.exit(0) }
|
||||||
|
|
||||||
|
def compile(dir: Path, compiledFile: Path) =
|
||||||
|
{
|
||||||
|
val workDir = new File(dir.toAbsolute.normalize.path)
|
||||||
|
Process("make -j", workDir).!
|
||||||
|
if (!compiledFile.exists) Process("make -j", workDir).!
|
||||||
|
}
|
||||||
|
|
||||||
|
def compileRemote(dir: Path, compiledFile: Path, host: String, options: String) =
|
||||||
|
{
|
||||||
|
val sshcmd = "ssh " + options + " " + host + " cd " + dir.path + " ; make -j"
|
||||||
|
println(sshcmd)
|
||||||
|
Process(sshcmd).!
|
||||||
|
if (!remotePathExists(compiledFile, host, options)) Process(sshcmd).!
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean(dir: Path) =
|
||||||
|
{
|
||||||
|
val workDir = new File(dir.toAbsolute.normalize.path)
|
||||||
|
Process("make clean", workDir).!
|
||||||
|
}
|
||||||
|
|
||||||
|
def cleanRemote(dir: Path, host: String, options: String) =
|
||||||
|
{
|
||||||
|
val sshcmd = "ssh " + options + " " + host + " cd " + dir.path + " ; make clean"
|
||||||
|
println(sshcmd)
|
||||||
|
Process(sshcmd).!
|
||||||
|
}
|
||||||
|
|
||||||
|
def gitcheckout(oldDir: Path, newDir: Path, commit: String): Unit =
|
||||||
|
{
|
||||||
|
val canonold = oldDir.toAbsolute.normalize.path
|
||||||
|
val canonnew = newDir.toAbsolute.normalize.path
|
||||||
|
if (newDir.exists) return
|
||||||
|
Process("cp -r " + canonold + " " + canonnew).!
|
||||||
|
if (commit.toLowerCase != "none")
|
||||||
|
{
|
||||||
|
println("Checking out commit " + commit + " in " + canonnew)
|
||||||
|
val out = Process("git checkout " + commit, new File(canonnew)).!!
|
||||||
|
println(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def gitcheckoutRemote(oldDir: Path, newDir: Path, commit: String, host: String, options: String) =
|
||||||
|
{
|
||||||
|
if (!remotePathExists(newDir, host, options))
|
||||||
|
{
|
||||||
|
val sshcmd = "ssh " + options + " " + host + " cp -r " + oldDir.path + " " + newDir.path
|
||||||
|
Process(sshcmd).!
|
||||||
|
if (commit.toLowerCase != "none")
|
||||||
|
{
|
||||||
|
val sshgitcheckout = "ssh " + options + " " + host + " cd " + newDir.path + " ; git checkout " + commit
|
||||||
|
println(sshgitcheckout)
|
||||||
|
println(Process(sshgitcheckout).!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def remotePathExists(remote: Path, host: String, options: String): Boolean =
|
||||||
|
{
|
||||||
|
val remoteParentPath = remote.parent.get
|
||||||
|
val cmd = ("ssh "+options+" "+host+" ls " + remoteParentPath.path)
|
||||||
|
val output = (cmd.!!).split("\n")
|
||||||
|
val remoteExists = output.contains(remote.name)
|
||||||
|
remoteExists
|
||||||
|
}
|
||||||
|
|
||||||
|
def copy(from: Path, to: Path): Unit =
|
||||||
|
{
|
||||||
|
from.copyTo(to, replaceExisting=true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def scpFileBack(remotePath: Path, localPath: Path, host: String, options: String): Unit =
|
||||||
|
{
|
||||||
|
val localStr = localPath.path
|
||||||
|
val remoteStr = remotePath.path
|
||||||
|
if (remotePathExists(remotePath, host, options))
|
||||||
|
{
|
||||||
|
println("Copying remote file " + remotePath.name + " from " + host + "to directory " + localStr)
|
||||||
|
val cmd = "scp " +options+" "+host+":"+remoteStr + " " + localStr
|
||||||
|
println(cmd)
|
||||||
|
val exitCode = cmd.!
|
||||||
|
assert(exitCode == 0, println("SCP failed to successfully copy file " + localPath.name))
|
||||||
|
println("Successfully copied remote " + host + " file to directory.\n")
|
||||||
|
} else {
|
||||||
|
println("Could not find remote file " + remoteStr + " on " + host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def scp(localPath: Path, remotePath: Path, host: String, options: String): Unit =
|
||||||
|
{
|
||||||
|
def scpFile(localPath: Path, remotePath: Path): Unit =
|
||||||
|
{
|
||||||
|
val localStr = localPath.path
|
||||||
|
val remoteStr = remotePath.path
|
||||||
|
println("Copying file " + localPath.name + " to " + host + " remote directory " + remoteStr)
|
||||||
|
val cmd = "scp " +options+" "+localStr+" "+host+":"+remoteStr
|
||||||
|
println(cmd)
|
||||||
|
val exitCode = cmd.!
|
||||||
|
assert(exitCode == 0, println("SCP failed to successfully copy file " + localPath.name))
|
||||||
|
println("Successfully copied file to remote "+host+" directory.\n")
|
||||||
|
}
|
||||||
|
def compressDir(dir: String, tgz: String): Unit =
|
||||||
|
{
|
||||||
|
println("Compressing directory to " + tgz)
|
||||||
|
val tarcmd = "tar -czf " + tgz + " " + dir
|
||||||
|
println(tarcmd)
|
||||||
|
val out = tarcmd.!
|
||||||
|
assert (out == 0, println("Failed to properly compress directory."))
|
||||||
|
println("Successfully compressed directory to " + tgz + "\n")
|
||||||
|
}
|
||||||
|
def extractDir(remoteTgz: String, remoteDir: String): Unit =
|
||||||
|
{
|
||||||
|
println("Extracting "+remoteTgz+" to "+host+" remote directory " + remoteDir)
|
||||||
|
val extractcmd = "ssh "+options+" "+host+" tar -xzf " + remoteTgz +" -C " + remoteDir
|
||||||
|
println (extractcmd)
|
||||||
|
val out = extractcmd.!
|
||||||
|
assert (out == 0, println("Failed to extract remote file " + remoteTgz + " to directory " + remoteDir))
|
||||||
|
println("Successfully extracted to remote directory " + remoteDir + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(localPath.exists, println("Local object to be copied does not exist."))
|
||||||
|
if (localPath.isDirectory)
|
||||||
|
{
|
||||||
|
//Zip it up, scp it, then unzip
|
||||||
|
val canonPath: Path = localPath.toAbsolute.normalize
|
||||||
|
val remoteParentPath = remotePath.parent.get
|
||||||
|
val tgzName = canonPath.name + ".tgz"
|
||||||
|
val tgzPath: Path = Path.fromString("../" + tgzName)
|
||||||
|
val remoteTgzPath: Path = (remoteParentPath / Path.fromString(tgzName))
|
||||||
|
|
||||||
|
val cmd = ("ssh "+options+" "+host+" ls " + remoteParentPath.path)
|
||||||
|
val output = (cmd.!!).split("\n")
|
||||||
|
val remoteExists = output.contains(remotePath.name)
|
||||||
|
val remoteTgzExists = output.contains(tgzName)
|
||||||
|
|
||||||
|
if (remoteExists) {
|
||||||
|
println("Remote directory already exists. Skipping copy process.")
|
||||||
|
} else {
|
||||||
|
if (remoteTgzExists) {
|
||||||
|
println(tgzName + " already exists on the remote "+host+" directory. Skipping transfer process.")
|
||||||
|
} else {
|
||||||
|
if(!tgzPath.exists) {
|
||||||
|
compressDir(".", "../"+tgzName)
|
||||||
|
} else {
|
||||||
|
println(tgzName+" already exists. Skipping compression process.")
|
||||||
|
}
|
||||||
|
scpFile(tgzPath, remoteTgzPath)
|
||||||
|
}
|
||||||
|
val out2 = ("ssh "+options+" "+host+" mkdir " + remotePath.path).!!
|
||||||
|
extractDir(remoteTgzPath.path, remotePath.path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scpFile(localPath, remotePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index a85579f..5ec0ed6 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -6,6 +6,7 @@ C_SIM := ../emulator/emulator-rocketchip-$(RTL_CONFIG)
|
||||||
|
R_SIM := ../vsim/simv-rocketchip-$(RTL_CONFIG)
|
||||||
|
TEST := output/test.S
|
||||||
|
OPTIONS := $(empty)
|
||||||
|
+NUM := 0
|
||||||
|
SUITE := output
|
||||||
|
CONFIG := config/default.config
|
||||||
|
COMMIT := none
|
||||||
|
@@ -20,7 +21,7 @@ GITCMT := $(subst $(space),$(gitopt),$(COMMIT))
|
||||||
|
cnight rnight crnight csuite rsuite \
|
||||||
|
|
||||||
|
gen:
|
||||||
|
- $(SBT) 'generator/run $(OPTIONS)'
|
||||||
|
+ $(SBT) 'generator/run -n $(NUM)'
|
||||||
|
|
||||||
|
csuite:
|
||||||
|
for i in `ls $(SUITE) | grep .S` ; do echo $$i ; \
|
||||||
|
diff --git a/generator/src/main/scala/main.scala b/generator/src/main/scala/main.scala
|
||||||
|
index d5a79f5..a7b3b49 100644
|
||||||
|
--- a/generator/src/main/scala/main.scala
|
||||||
|
+++ b/generator/src/main/scala/main.scala
|
||||||
|
@@ -8,7 +8,7 @@ import java.util.Properties
|
||||||
|
import scala.collection.JavaConversions._
|
||||||
|
|
||||||
|
case class Options(var outFileName: String = "test",
|
||||||
|
- var confFileName: String = "config/default.config")
|
||||||
|
+ var confFileName: String = "config/default.config", var numOutFiles: Int = 0)
|
||||||
|
|
||||||
|
object Generator extends App
|
||||||
|
{
|
||||||
|
@@ -17,15 +17,25 @@ object Generator extends App
|
||||||
|
val parser = new OptionParser[Options]("generator/run") {
|
||||||
|
opt[String]('C', "config") valueName("<file>") text("config file") action {(s: String, c) => c.copy(confFileName = s)}
|
||||||
|
opt[String]('o', "output") valueName("<filename>") text("output filename") action {(s: String, c) => c.copy(outFileName = s)}
|
||||||
|
+ opt[Int]('n', "numfiles") valueName("<num_files>") text("number of output files") action {(n: Int, c) => c.copy(numOutFiles = n)}
|
||||||
|
}
|
||||||
|
parser.parse(args, Options()) match {
|
||||||
|
case Some(opts) =>
|
||||||
|
- generate(opts.confFileName, opts.outFileName)
|
||||||
|
+ generate_loop(opts.confFileName, opts.outFileName, opts.numOutFiles)
|
||||||
|
case None =>
|
||||||
|
System.exit(1) //error message printed by parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ def generate_loop(confFile: String, outFileName: String, numOutFiles: Int) = {
|
||||||
|
+ if (numOutFiles > 0) {
|
||||||
|
+ for (i <- 0 to (numOutFiles-1))
|
||||||
|
+ generate(confFile, outFileName + ("_%03d" format (i)))
|
||||||
|
+ } else {
|
||||||
|
+ generate(confFile, outFileName)
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
def generate(confFile: String, outFileName: String): String = {
|
||||||
|
val config = new Properties()
|
||||||
|
val in = new FileInputStream(confFile)
|
|
@ -0,0 +1,39 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
abstract class DataChunk
|
||||||
|
|
||||||
|
class StringData(contents: String) extends DataChunk
|
||||||
|
{
|
||||||
|
override def toString = contents
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemDump(mem: Mem) extends DataChunk
|
||||||
|
{
|
||||||
|
override def toString = mem.dumpdata
|
||||||
|
}
|
||||||
|
|
||||||
|
object MemDump
|
||||||
|
{
|
||||||
|
def apply(mem: Mem) = new MemDump(mem)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemAddrDump(mem: Mem, addrfn: (Int) => Int, memsize: Int) extends DataChunk
|
||||||
|
{
|
||||||
|
override def toString = mem.dumpaddrs(addrfn, memsize)
|
||||||
|
}
|
||||||
|
|
||||||
|
object MemAddrDump
|
||||||
|
{
|
||||||
|
def apply(mem: Mem, addrfn: (Int) => Int, memsize: Int) = new MemAddrDump(mem, addrfn, memsize)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProgSegDump(pseg: ProgSeg) extends DataChunk
|
||||||
|
{
|
||||||
|
override def toString = pseg.toString
|
||||||
|
}
|
||||||
|
|
||||||
|
object ProgSegDump
|
||||||
|
{
|
||||||
|
def apply(pseg: ProgSeg) = new ProgSegDump(pseg)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
object HWRegState extends Enumeration
|
||||||
|
{
|
||||||
|
type HWRegState = Value
|
||||||
|
val VIS, HID, HID2HID, HID2VIS, VIS2HID, VIS2VIS = Value
|
||||||
|
}
|
||||||
|
|
||||||
|
import HWRegState._
|
||||||
|
class HWReg(val name: String, val readable: Boolean, val writable: Boolean)
|
||||||
|
{
|
||||||
|
var state = VIS
|
||||||
|
var readers = 0
|
||||||
|
var backup_state = VIS
|
||||||
|
var backup_readers = 0
|
||||||
|
|
||||||
|
def is_state(states: HWRegState*) = states.toList.contains(state)
|
||||||
|
|
||||||
|
def is_visible() = is_state(VIS, VIS2VIS)
|
||||||
|
|
||||||
|
def is_unallocated = is_state(VIS, HID)
|
||||||
|
//TODO: should this also check readers == 0?
|
||||||
|
|
||||||
|
override def toString = name
|
||||||
|
|
||||||
|
def backup() =
|
||||||
|
{
|
||||||
|
backup_state = state
|
||||||
|
backup_readers = readers
|
||||||
|
}
|
||||||
|
|
||||||
|
def restore() =
|
||||||
|
{
|
||||||
|
state = backup_state
|
||||||
|
readers = backup_readers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object HWReg
|
||||||
|
{
|
||||||
|
// These filters are for allocation purposes
|
||||||
|
def filter_read_zero = (hwreg: HWReg) => (hwreg.name == "x0" || hwreg.name == "x0_shadow")
|
||||||
|
def filter_read_any = (hwreg: HWReg) => hwreg.readable
|
||||||
|
def filter_read_any_other(other: Reg)(hwreg: HWReg) = (hwreg.readable && hwreg.name != other.hwreg.name)
|
||||||
|
def filter_read_visible = (hwreg: HWReg) => hwreg.readable && hwreg.is_state(VIS,VIS2VIS)
|
||||||
|
def filter_write_ra = (hwreg: HWReg) => hwreg.name == "x1" && filter_write_visible(hwreg)
|
||||||
|
def filter_write_visible = (hwreg: HWReg) => hwreg.writable && hwreg.is_state(VIS,HID)
|
||||||
|
def filter_write_hidden = (hwreg: HWReg) => hwreg.writable && (hwreg.is_state(HID) || hwreg.is_state(VIS) && hwreg.readers == 0)
|
||||||
|
def filter_write_visible_other(other: Reg)(hwreg: HWReg) = (hwreg.name != other.hwreg.name && hwreg.writable && hwreg.is_state(VIS,HID))
|
||||||
|
def filter_write_hidden_other(other: Reg)(hwreg: HWReg) = (hwreg.name != other.hwreg.name && hwreg.writable && (hwreg.is_state(HID) || hwreg.is_state(VIS) && hwreg.readers == 0))
|
||||||
|
def filter_write_dep(regs: List[Reg]) =
|
||||||
|
{
|
||||||
|
if (regs.forall(_.hwreg.is_visible)) filter_write_visible
|
||||||
|
else filter_write_hidden
|
||||||
|
}
|
||||||
|
def filter_write_dep_other(other: Reg, regs: List[Reg]) =
|
||||||
|
{
|
||||||
|
if (regs.forall(_.hwreg.is_visible)) filter_write_visible_other(other) _
|
||||||
|
else filter_write_hidden_other(other) _
|
||||||
|
}
|
||||||
|
|
||||||
|
def alloc_read = (hwreg: HWReg) => hwreg.readers += 1
|
||||||
|
def alloc_write(visible: Boolean)(hwreg: HWReg) =
|
||||||
|
{
|
||||||
|
if (hwreg.state == VIS)
|
||||||
|
{
|
||||||
|
if (visible) hwreg.state = VIS2VIS
|
||||||
|
else hwreg.state = VIS2HID
|
||||||
|
}
|
||||||
|
else if (hwreg.state == HID)
|
||||||
|
{
|
||||||
|
if (visible) hwreg.state = HID2VIS
|
||||||
|
else hwreg.state = HID2HID
|
||||||
|
}
|
||||||
|
else println("bug in do_write")
|
||||||
|
}
|
||||||
|
def alloc_write_dep(regs: List[Reg]) = alloc_write(regs.forall(_.hwreg.is_visible)) _
|
||||||
|
|
||||||
|
def free_read = (hwreg: HWReg) => hwreg.readers -= 1
|
||||||
|
def free_write = (hwreg: HWReg) =>
|
||||||
|
{
|
||||||
|
if (hwreg.state == VIS2VIS || hwreg.state == HID2VIS) hwreg.state = VIS
|
||||||
|
else if (hwreg.state == VIS2HID || hwreg.state == HID2HID) hwreg.state = HID
|
||||||
|
else println("bug in free_write")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,282 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
import HWRegState._
|
||||||
|
|
||||||
|
class HWRegPool
|
||||||
|
{
|
||||||
|
val hwregs = new ArrayBuffer[HWReg]
|
||||||
|
|
||||||
|
def backup() = { hwregs.map((x) => x.backup()) }
|
||||||
|
def restore() = { hwregs.map((x) => x.restore()) }
|
||||||
|
|
||||||
|
def is_fully_unallocated = hwregs.forall(_.is_unallocated)
|
||||||
|
def size = hwregs.length
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ScalarRegPool extends HWRegPool
|
||||||
|
{
|
||||||
|
val name: String
|
||||||
|
val regname: String
|
||||||
|
val ldinst: String
|
||||||
|
val stinst: String
|
||||||
|
|
||||||
|
def init_regs() =
|
||||||
|
{
|
||||||
|
var s = name + "_init:\n"
|
||||||
|
s += "\tla x31, " + name + "_init_data\n"
|
||||||
|
for (i <- 0 to hwregs.length-1)
|
||||||
|
s += "\t" + ldinst + " " + hwregs(i) + ", " + 8*i + "(x31)\n"
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def save_regs() =
|
||||||
|
{
|
||||||
|
var s = "\tla x1, " + name + "_output_data\n"
|
||||||
|
for (i <- 0 to hwregs.length-1)
|
||||||
|
if (hwregs(i).is_visible)
|
||||||
|
s += "\t" + stinst + " " + hwregs(i) + ", " + 8*i + "(x1)\n"
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def init_regs_data() =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += name + "_init_data:\n"
|
||||||
|
for (i <- 0 to hwregs.length-1)
|
||||||
|
s += (regname + i + "_init:\t.dword " + "0x%016x\n" format rand_biased) //Change randomization for FRegs
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def output_regs_data() =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += name + "_output_data:\n"
|
||||||
|
for (i <- 0 to hwregs.length-1)
|
||||||
|
s += (regname + i + "_output:\t.dword 0x%016x\n" format rand_dword)
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PoolsMaster extends HWRegPool
|
||||||
|
{
|
||||||
|
val regpools: ArrayBuffer[HWRegPool]
|
||||||
|
override val hwregs = new ArrayBuffer[HWReg] //Override this in subclasses
|
||||||
|
override def is_fully_unallocated = regpools.forall(_.is_fully_unallocated)
|
||||||
|
override def size = regpools.map(_.size).sum
|
||||||
|
def extract_pools() =
|
||||||
|
{
|
||||||
|
regpools
|
||||||
|
}
|
||||||
|
override def backup() =
|
||||||
|
{
|
||||||
|
regpools.map(_.backup()).flatten
|
||||||
|
}
|
||||||
|
override def restore() =
|
||||||
|
{
|
||||||
|
regpools.map(_.restore()).flatten
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XRegsPool extends ScalarRegPool
|
||||||
|
{
|
||||||
|
val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "lw", "sw")
|
||||||
|
|
||||||
|
hwregs += new HWReg("x0", true, false)
|
||||||
|
for (i <- 1 to 31)
|
||||||
|
hwregs += new HWReg("x" + i.toString(), true, true)
|
||||||
|
|
||||||
|
override def save_regs() =
|
||||||
|
{
|
||||||
|
hwregs(1).state = HID
|
||||||
|
super.save_regs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FRegsMaster extends ScalarRegPool with PoolsMaster
|
||||||
|
{
|
||||||
|
val (name,regname,ldinst,stinst) = ("freg","reg_f","fld","fsd") // and flw and fsw
|
||||||
|
val s_reg_num = new ArrayBuffer[Int]
|
||||||
|
val d_reg_num = new ArrayBuffer[Int]
|
||||||
|
|
||||||
|
for (n <- 0 to 31)
|
||||||
|
if(rand_range(0, 1) == 0) s_reg_num += n
|
||||||
|
else d_reg_num += n
|
||||||
|
|
||||||
|
// Ensure each pool has at least 5 members
|
||||||
|
while(s_reg_num.length < 5)
|
||||||
|
{
|
||||||
|
val mv_n = rand_pick(d_reg_num)
|
||||||
|
d_reg_num -= mv_n
|
||||||
|
s_reg_num += mv_n
|
||||||
|
}
|
||||||
|
|
||||||
|
while(d_reg_num.length < 5)
|
||||||
|
{
|
||||||
|
val mv_n = rand_pick(s_reg_num)
|
||||||
|
s_reg_num -= mv_n
|
||||||
|
d_reg_num += mv_n
|
||||||
|
}
|
||||||
|
|
||||||
|
val s_regpool = new FRegsPool(s_reg_num.toArray)
|
||||||
|
val d_regpool = new FRegsPool(d_reg_num.toArray)
|
||||||
|
val regpools = ArrayBuffer(s_regpool.asInstanceOf[HWRegPool],
|
||||||
|
d_regpool.asInstanceOf[HWRegPool])
|
||||||
|
override val hwregs = regpools.map(_.hwregs).flatten
|
||||||
|
|
||||||
|
override def init_regs() = //Wrapper function
|
||||||
|
{
|
||||||
|
var s = "freg_init:\n"+"freg_s_init:\n"+"\tla x1, freg_init_data\n"
|
||||||
|
for ((i, curreg) <- s_reg_num.zip(s_regpool.hwregs))
|
||||||
|
s += "\tflw" + " " + curreg + ", " + 8*i + "(x1)\n"
|
||||||
|
s += "\n"+"freg_d_init:\n"+"\tla x1, freg_init_data\n"
|
||||||
|
for ((i, curreg) <- d_reg_num.zip(d_regpool.hwregs))
|
||||||
|
s += "\tfld" + " " + curreg + ", " + 8*i + "(x1)\n"
|
||||||
|
s += "\n\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
override def save_regs() = //Wrapper function
|
||||||
|
{
|
||||||
|
var s = "freg_save:\n"+"\tla x1, freg_output_data\n"
|
||||||
|
for ((i, curreg) <- s_reg_num.zip(s_regpool.hwregs))
|
||||||
|
if (curreg.is_visible)
|
||||||
|
s += "\tfsw" + " " + curreg + ", " + 8*i + "(x1)\n"
|
||||||
|
s += "\n"+"\tla x1, freg_output_data\n"
|
||||||
|
for ((i, curreg) <- d_reg_num.zip(d_regpool.hwregs))
|
||||||
|
if (curreg.is_visible)
|
||||||
|
s += "\tfsd" + " " + curreg + ", " + 8*i + "(x1)\n"
|
||||||
|
s += "\n\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FRegsPool(reg_nums: Array[Int] = (0 to 31).toArray) extends HWRegPool
|
||||||
|
{
|
||||||
|
for (i <- reg_nums)
|
||||||
|
hwregs += new HWReg("f" + i.toString(), true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
class VRegsMaster(num_xregs: Int, num_pregs: Int, num_sregs: Int) extends PoolsMaster
|
||||||
|
{
|
||||||
|
assert(num_xregs >= 5, "For VRegMaster, num_xregs >=5 enforced")
|
||||||
|
assert(num_pregs >= 1, "For VRegMaster, num_pregs >=1 enforced")
|
||||||
|
|
||||||
|
val x_reg_num = (0 to (num_xregs-1))
|
||||||
|
val p_reg_num = (0 to (num_pregs-1))
|
||||||
|
val s_reg_num = (0 to (num_sregs-1))
|
||||||
|
|
||||||
|
val x_regpool = new VXRegsPool(x_reg_num.toArray)
|
||||||
|
val p_regpool = new VPRegsPool(p_reg_num.toArray)
|
||||||
|
val s_regpool = new VSRegsPool(s_reg_num.toArray)
|
||||||
|
val a_regpool = new VARegsPool()
|
||||||
|
val regpools =
|
||||||
|
ArrayBuffer(x_regpool.asInstanceOf[HWRegPool], p_regpool.asInstanceOf[HWRegPool],
|
||||||
|
s_regpool.asInstanceOf[HWRegPool], a_regpool.asInstanceOf[HWRegPool])
|
||||||
|
override val hwregs = regpools.map(_.hwregs).flatten
|
||||||
|
|
||||||
|
def init_regs() =
|
||||||
|
{
|
||||||
|
var s = "vreg_init:\n"
|
||||||
|
s += s_regpool.init_regs()
|
||||||
|
s
|
||||||
|
}
|
||||||
|
def save_regs() =
|
||||||
|
{
|
||||||
|
var s = "vreg_save:\n"
|
||||||
|
s += s_regpool.save_regs()
|
||||||
|
s
|
||||||
|
}
|
||||||
|
def init_regs_data() =
|
||||||
|
{
|
||||||
|
var s = "vreg_init_data:\n"
|
||||||
|
s += s_regpool.init_regs_data()
|
||||||
|
s
|
||||||
|
}
|
||||||
|
def output_regs_data() =
|
||||||
|
{
|
||||||
|
var s = "vreg_output_data:\n"
|
||||||
|
s += s_regpool.output_regs_data()
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VXRegsPool(reg_nums: Array[Int] = (0 to 255).toArray) extends HWRegPool
|
||||||
|
{
|
||||||
|
for (i <- reg_nums)
|
||||||
|
hwregs += new HWReg("vv" + i.toString(), true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
class VPRegsPool(reg_nums: Array[Int] = (0 to 15).toArray) extends HWRegPool
|
||||||
|
{
|
||||||
|
for (i <- reg_nums)
|
||||||
|
hwregs += new HWReg("vp" + i.toString(), true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
class VSRegsPool(reg_nums: Array[Int] = (0 to 255).toArray) extends HWRegPool
|
||||||
|
{
|
||||||
|
hwregs += new HWReg("vs0", true, false)
|
||||||
|
for (i <- reg_nums.drop(1))
|
||||||
|
hwregs += new HWReg("vs" + i.toString(), true, true)
|
||||||
|
def init_regs() =
|
||||||
|
{
|
||||||
|
var s = "vsreg_init:\n"+"\tla x1, vsreg_init_data\n"
|
||||||
|
for ((i, curreg) <- reg_nums.zip(hwregs))
|
||||||
|
{
|
||||||
|
s += "\tld" + " x2, " + 8*i + "(x1)\n"
|
||||||
|
s += "\tvmcs"+ " " + curreg + ", x2\n"
|
||||||
|
}
|
||||||
|
s += "\n\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
def save_regs() =
|
||||||
|
{
|
||||||
|
hwregs(1).state = HID
|
||||||
|
var s = "vsreg_save:\n"+"\tla x1, vsreg_output_data\n"
|
||||||
|
s += "\tvmcs vs1, x1\n"
|
||||||
|
s += "\tlui x1, %hi(vsreg_save_vf)\n"
|
||||||
|
s += "\tvf %lo(vsreg_save_vf)(x1)\n"
|
||||||
|
s += "\tj vsreg_save_end\n"
|
||||||
|
s += ".align 3\n"
|
||||||
|
s += "vsreg_save_vf:\n"
|
||||||
|
for (curreg <- hwregs.drop(2))
|
||||||
|
if (curreg.is_visible)
|
||||||
|
{
|
||||||
|
s += "\tvssd vs1, " + curreg + "\n"
|
||||||
|
s += "\tvaddi vs1, vs1, 8\n"
|
||||||
|
}
|
||||||
|
s += "\tvstop\n"
|
||||||
|
s += "vsreg_save_end:\n\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
def init_regs_data() =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += "vsreg_init_data:\n"
|
||||||
|
for (i <- 0 to hwregs.length-1)
|
||||||
|
s += ("vs" + i + "_init:\t.dword " + "0x%016x\n" format rand_biased)
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def output_regs_data() =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += "vsreg_output_data:\n"
|
||||||
|
for (i <- 0 to hwregs.length-1)
|
||||||
|
s += ("vs" + i + "_output:\t.dword 0x%016x\n" format rand_dword)
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VARegsPool(reg_nums: Array[Int] = (0 to 31).toArray) extends HWRegPool
|
||||||
|
{
|
||||||
|
for (i <- reg_nums)
|
||||||
|
hwregs += new HWReg("va" + i.toString(), true, true)
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
import HWRegState._
|
||||||
|
|
||||||
|
class HWShadowReg(target:Reg, name: String, readable: Boolean, writeable: Boolean) extends HWReg(name, readable, writeable)
|
||||||
|
{
|
||||||
|
def physical = target
|
||||||
|
override def toString = target.toString
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShadowRegPool extends HWRegPool
|
||||||
|
{
|
||||||
|
def pairings(selecting: (HWReg => Boolean)) = hwregs.filter(selecting).map((reg:HWReg) => (reg, reg.asInstanceOf[HWShadowReg].physical))
|
||||||
|
}
|
|
@ -0,0 +1,535 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
class Inst(opcode: String, val operands: Array[Operand])
|
||||||
|
{
|
||||||
|
def optype(): String = {
|
||||||
|
if (is_alu) return "alu"
|
||||||
|
if (is_cmp) return "cmp"
|
||||||
|
if (is_branch) return "branch"
|
||||||
|
if (is_jalr) return "jalr"
|
||||||
|
if (is_jmp) return "jmp"
|
||||||
|
if (is_la) return "la"
|
||||||
|
if (is_mem) return "mem"
|
||||||
|
if (is_amo) return "amo"
|
||||||
|
if (is_misc) return "misc"
|
||||||
|
if (is_fpalu) return "fpalu"
|
||||||
|
if (is_fpcmp) return "fpcmp"
|
||||||
|
if (is_fpfma) return "fpfma"
|
||||||
|
if (is_fpmem) return "fpmem"
|
||||||
|
if (is_fpcvt) return "fpcvt"
|
||||||
|
if (is_fpmisc) return "fpmisc"
|
||||||
|
if (is_vshared) return "vshared"
|
||||||
|
if (is_valu) return "valu"
|
||||||
|
if (is_vfpalu) return "vfpalu"
|
||||||
|
if (is_vfpfma) return "vfpfma"
|
||||||
|
if (is_vfpcvt) return "vfpcvt"
|
||||||
|
if (is_vsmem) return "vsmem"
|
||||||
|
if (is_vshared) return "vshared"
|
||||||
|
if (is_vcmp) return "vcmp"
|
||||||
|
if (is_vpred) return "vpred"
|
||||||
|
if (is_vmem) return "vmem"
|
||||||
|
if (is_vamo) return "vamo"
|
||||||
|
if (is_vmisc) return "vmisc"
|
||||||
|
return "unknown" //Shouldn't return this.
|
||||||
|
}
|
||||||
|
|
||||||
|
def opcode(): String = { return opcode }
|
||||||
|
|
||||||
|
def is_branch = List("beq", "bne", "blt", "bge", "bltu", "bgeu").contains(opcode)
|
||||||
|
|
||||||
|
def is_jalr = List("jalr").contains(opcode)
|
||||||
|
|
||||||
|
def is_jmp = List("jal").contains(opcode)
|
||||||
|
|
||||||
|
def is_la = opcode == "la"
|
||||||
|
|
||||||
|
def is_mem = List("lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", "sb", "sh", "sw", "sd").contains(opcode)
|
||||||
|
|
||||||
|
def is_amo = List("amoadd.w", "amoswap.w", "amoand.w", "amoor.w", "amomin.w", "amominu.w",
|
||||||
|
"amomax.w", "amomaxu.w", "amoxor.w", "amoadd.d", "amoswap.d", "amoand.d", "amoor.d",
|
||||||
|
"amomin.d", "amominu.d", "amomax.d", "amomaxu.d", "amoxor.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_cmp = List("slti", "sltiu", "slt", "sltu").contains(opcode)
|
||||||
|
|
||||||
|
def is_alu = List("addi", "slli", "xori", "srli", "srai", "ori", "andi",
|
||||||
|
"add", "sub", "sll", "xor", "srl", "sra", "or", "and", "mul", "mulh",
|
||||||
|
"mulhsu", "mulhu", "div", "divu", "rem", "remu", "lui", "addiw", "slliw", "srliw",
|
||||||
|
"sraiw", "addw", "subw", "sllw", "srlw", "sraw", "mulw", "divw", "divuw", "remw",
|
||||||
|
"remuw").contains(opcode)
|
||||||
|
|
||||||
|
def is_fpmem = List("flw", "fld", "fsw", "fsd").contains(opcode)
|
||||||
|
|
||||||
|
def is_fpalu = List("fadd.s", "fsub.s", "fmul.s", "fdiv.s", "fsqrt.s", "fmin.s", "fmax.s",
|
||||||
|
"fadd.d", "fsub.d", "fmul.d", "fdiv.d", "fsqrt.d", "fmin.d", "fmax.d",
|
||||||
|
"fsgnj.s", "fsgnjn.s", "fsgnjx.s", "fsgnj.d", "fsgnjn.d", "fsgnjx.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_fpfma = List("fmadd.s", "fmsub.s", "fnmsub.s", "fnmadd.s",
|
||||||
|
"fmadd.d", "fmsub.d", "fnmsub.d", "fnmadd.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_fpcvt = List("fcvt.s.d", "fcvt.d.s", "fcvt.s.l", "fcvt.s.lu", "fcvt.s.w",
|
||||||
|
"fcvt.s.wu", "fcvt.d.l", "fcvt.d.lu", "fcvt.d.w", "fcvt.d.wu", "fcvt.l.s",
|
||||||
|
"fcvt.lu.s", "fcvt.w.s", "fcvt.wu.s", "fcvt.l.d", "fcvt.lu.d",
|
||||||
|
"fcvt.w.d", "fcvt.wu.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_fpmisc = List("fmovz", "fmovn", "frsr", "fssr", "fmv.s.x", "fmv.x.s",
|
||||||
|
"fmv.d.x", "fmv.x.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_fpcmp = List("feq.s", "flt.s", "fle.s", "feq.d", "flt.d", "fle.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_misc = List("syscall", "break", "rdcycle", "rdtime", "rdinstret",
|
||||||
|
"nop", "li", "mfpcr", "mtpcr", "auipc", "movz", "movn", "fence.i", "fence").contains(opcode)
|
||||||
|
|
||||||
|
def is_vshared = List("vaddi", "vslli", "vxori", "vsrli", "vsrai", "vori", "vandi", "vlui",
|
||||||
|
"vaddiw", "vslliw", "vsrliw", "vsraiw").contains(opcode)
|
||||||
|
|
||||||
|
def is_valu = List("vadd", "vsub", "vsll", "vxor", "vsrl", "vsra", "vor", "vand", "vmul", "vmulh",
|
||||||
|
"vmulhsu", "vmulhu", "vdiv", "vdivu", "vrem", "vremu", "vaddw", "vsubw", "vsllw",
|
||||||
|
"vsrlw", "vsraw", "vmulw", "vdivw", "vdivuw", "vremw", "vremuw").contains(opcode)
|
||||||
|
|
||||||
|
def is_vpred = List("vpop", "vpset", "vpclear").contains(opcode)
|
||||||
|
|
||||||
|
def is_vcmp = List("vcmpeq", "vcmplt", "vcmpltu", "vcmpfeq", "vcmpflt", "vcmfle").contains(opcode)
|
||||||
|
|
||||||
|
def is_vfpalu = List("vfadd.s", "vfsub.s", "vfmul.s", "vfdiv.s", "vfsqrt.s", "vfmin.s", "vfmax.s",
|
||||||
|
"vfadd.d", "vfsub.d", "vfmul.d", "vfdiv.d", "vfsqrt.d", "vfmin.d", "vfmax.d",
|
||||||
|
"vfsgnj.s", "vfsgnjn.s", "vfsgnjx.s", "vfsgnj.d", "vfsgnjn.d", "vfsgnjx.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_vfpfma = List("vfmadd.s", "vfmsub.s", "vfnmsub.s", "vfnmadd.s",
|
||||||
|
"vfmadd.d", "vfmsub.d", "vfnmsub.d", "vfnmadd.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_vfpcvt = List("vfcvt.s.d", "vfcvt.d.s", "vfcvt.s.l", "vfcvt.s.lu", "vfcvt.s.w",
|
||||||
|
"vfcvt.s.wu", "vfcvt.d.l", "vfcvt.d.lu", "vfcvt.d.w", "vfcvt.d.wu", "vfcvt.l.s",
|
||||||
|
"vfcvt.lu.s", "vfcvt.w.s", "vfcvt.wu.s", "vfcvt.l.d", "vfcvt.lu.d",
|
||||||
|
"vfcvt.w.d", "vfcvt.wu.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_vsmem = List("vlsb", "vlsh", "vlsw", "vlsd", "vlsbu", "vlshu", "vlswu", "vssb", "vssh", "vssw", "vssd",
|
||||||
|
"vlab", "vlah", "vlaw", "vlad", "vlabu", "vlahu", "vlawu", "vsab", "vsah", "vsaw", "vsad").contains(opcode)
|
||||||
|
|
||||||
|
def is_vmem = List("vlb", "vlh", "vlw", "vld", "vlbu", "vlhu", "vlwu", "vsb", "vsh", "vsw", "vsd",
|
||||||
|
"vlsegb", "vlsegh", "vlsegw", "vlsegd", "vlsegbu", "vlseghu", "vlsegwu", "vssegb", "vssegh", "vssegw", "vssegd",
|
||||||
|
"vlstb", "vlsth", "vlstw", "vlstd", "vlstbu", "vlsthu", "vlstwu", "vsstb", "vssth", "vsstw", "vsstd",
|
||||||
|
"vlsegstb", "vlsegsth", "vlsegstw", "vlsegstd", "vlsegstbu", "vlsegsthu", "vlsegstwu", "vssegstb", "vssegsth", "vssegstw", "vssegstd",
|
||||||
|
"vlxb", "vlxh", "vlxw", "vlxd", "vlxbu", "vlxhu", "vlxwu", "vsxb", "vsxh", "vsxw", "vsxd",
|
||||||
|
"vlsegxb", "vlsegxh", "vlsegxw", "vlsegxd", "vlsegxbu", "vlsegxhu", "vlsegxwu", "vssegxb", "vssegxh", "vssegxw", "vssegxd").contains(opcode)
|
||||||
|
|
||||||
|
def is_vamo = List("vamoadd.w", "vamoswap.w", "vamoand.w", "vamoor.w", "vamomin.w", "vamominu.w",
|
||||||
|
"vamomax.w", "vamomaxu.w", "vamoxor.w", "vamoadd.d", "vamoswap.d", "vamoand.d", "vamoor.d",
|
||||||
|
"vamomin.d", "vamominu.d", "vamomax.d", "vamomaxu.d", "vamoxor.d").contains(opcode)
|
||||||
|
|
||||||
|
def is_vmisc = List("vsetcfg", "vstop", "vsetvl", "veidx", "vf",
|
||||||
|
"vmcs", "vmca", "fence").contains(opcode)
|
||||||
|
|
||||||
|
override def toString =
|
||||||
|
{
|
||||||
|
operands.find(op => op.isInstanceOf[PredReg]) match {
|
||||||
|
case Some(pred) => pred + " " + opcode +
|
||||||
|
operands.filterNot(op => op.isInstanceOf[PredReg]).mkString(" ", ", ", "")
|
||||||
|
case None => opcode + operands.mkString(" ", ", ", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Opcode(val name: String)
|
||||||
|
{
|
||||||
|
def apply(opnds: Operand*) = new Inst(name, opnds.toArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
object J extends Opcode("j")
|
||||||
|
object JAL extends Opcode("jal")
|
||||||
|
object JALR extends Opcode("jalr")
|
||||||
|
object BEQ extends Opcode("beq")
|
||||||
|
object BNE extends Opcode("bne")
|
||||||
|
object BLT extends Opcode("blt")
|
||||||
|
object BGE extends Opcode("bge")
|
||||||
|
object BLTU extends Opcode("bltu")
|
||||||
|
object BGEU extends Opcode("bgeu")
|
||||||
|
|
||||||
|
object LA extends Opcode("la")
|
||||||
|
object LB extends Opcode("lb")
|
||||||
|
object LH extends Opcode("lh")
|
||||||
|
object LW extends Opcode("lw")
|
||||||
|
object LD extends Opcode("ld")
|
||||||
|
object LBU extends Opcode("lbu")
|
||||||
|
object LHU extends Opcode("lhu")
|
||||||
|
object LWU extends Opcode("lwu")
|
||||||
|
object SB extends Opcode("sb")
|
||||||
|
object SH extends Opcode("sh")
|
||||||
|
object SW extends Opcode("sw")
|
||||||
|
object SD extends Opcode("sd")
|
||||||
|
|
||||||
|
object AMOADD_W extends Opcode("amoadd.w")
|
||||||
|
object AMOSWAP_W extends Opcode("amoswap.w")
|
||||||
|
object AMOAND_W extends Opcode("amoand.w")
|
||||||
|
object AMOOR_W extends Opcode("amoor.w")
|
||||||
|
object AMOMIN_W extends Opcode("amomin.w")
|
||||||
|
object AMOMINU_W extends Opcode("amominu.w")
|
||||||
|
object AMOMAX_W extends Opcode("amomax.w")
|
||||||
|
object AMOMAXU_W extends Opcode("amomaxu.w")
|
||||||
|
object AMOXOR_W extends Opcode("amoxor.w")
|
||||||
|
object AMOADD_D extends Opcode("amoadd.d")
|
||||||
|
object AMOSWAP_D extends Opcode("amoswap.d")
|
||||||
|
object AMOAND_D extends Opcode("amoand.d")
|
||||||
|
object AMOOR_D extends Opcode("amoor.d")
|
||||||
|
object AMOMIN_D extends Opcode("amomin.d")
|
||||||
|
object AMOMINU_D extends Opcode("amominu.d")
|
||||||
|
object AMOMAX_D extends Opcode("amomax.d")
|
||||||
|
object AMOMAXU_D extends Opcode("amomaxu.d")
|
||||||
|
object AMOXOR_D extends Opcode("amoxor.d")
|
||||||
|
|
||||||
|
object ADDI extends Opcode("addi")
|
||||||
|
object SLLI extends Opcode("slli")
|
||||||
|
object SLTI extends Opcode("slti")
|
||||||
|
object SLTIU extends Opcode("sltiu")
|
||||||
|
object XORI extends Opcode("xori")
|
||||||
|
object SRLI extends Opcode("srli")
|
||||||
|
object SRAI extends Opcode("srai")
|
||||||
|
object ORI extends Opcode("ori")
|
||||||
|
object ANDI extends Opcode("andi")
|
||||||
|
object ADD extends Opcode("add")
|
||||||
|
object SUB extends Opcode("sub")
|
||||||
|
object SLL extends Opcode("sll")
|
||||||
|
object SLT extends Opcode("slt")
|
||||||
|
object SLTU extends Opcode("sltu")
|
||||||
|
object XOR extends Opcode("xor")
|
||||||
|
object SRL extends Opcode("srl")
|
||||||
|
object SRA extends Opcode("sra")
|
||||||
|
object OR extends Opcode("or")
|
||||||
|
object AND extends Opcode("and")
|
||||||
|
object MUL extends Opcode("mul")
|
||||||
|
object MULH extends Opcode("mulh")
|
||||||
|
object MULHSU extends Opcode("mulhsu")
|
||||||
|
object MULHU extends Opcode("mulhu")
|
||||||
|
object DIV extends Opcode("div")
|
||||||
|
object DIVU extends Opcode("divu")
|
||||||
|
object REM extends Opcode("rem")
|
||||||
|
object REMU extends Opcode("remu")
|
||||||
|
object LUI extends Opcode("lui")
|
||||||
|
|
||||||
|
object ADDIW extends Opcode("addiw")
|
||||||
|
object SLLIW extends Opcode("slliw")
|
||||||
|
object SRLIW extends Opcode("srliw")
|
||||||
|
object SRAIW extends Opcode("sraiw")
|
||||||
|
object ADDW extends Opcode("addw")
|
||||||
|
object SUBW extends Opcode("subw")
|
||||||
|
object SLLW extends Opcode("sllw")
|
||||||
|
object SRLW extends Opcode("srlw")
|
||||||
|
object SRAW extends Opcode("sraw")
|
||||||
|
object MULW extends Opcode("mulw")
|
||||||
|
object DIVW extends Opcode("divw")
|
||||||
|
object DIVUW extends Opcode("divuw")
|
||||||
|
object REMW extends Opcode("remw")
|
||||||
|
object REMUW extends Opcode("remuw")
|
||||||
|
|
||||||
|
object FLW extends Opcode("flw")
|
||||||
|
object FLD extends Opcode("fld")
|
||||||
|
object FSW extends Opcode("fsw")
|
||||||
|
object FSD extends Opcode("fsd")
|
||||||
|
|
||||||
|
object FADD_S extends Opcode("fadd.s")
|
||||||
|
object FSUB_S extends Opcode("fsub.s")
|
||||||
|
object FMUL_S extends Opcode("fmul.s")
|
||||||
|
object FDIV_S extends Opcode("fdiv.s")
|
||||||
|
object FSQRT_S extends Opcode("fsqrt.s")
|
||||||
|
object FMIN_S extends Opcode("fmin.s")
|
||||||
|
object FMAX_S extends Opcode("fmax.s")
|
||||||
|
object FADD_D extends Opcode("fadd.d")
|
||||||
|
object FSUB_D extends Opcode("fsub.d")
|
||||||
|
object FMUL_D extends Opcode("fmul.d")
|
||||||
|
object FDIV_D extends Opcode("fdiv.d")
|
||||||
|
object FSQRT_D extends Opcode("fsqrt.d")
|
||||||
|
object FMIN_D extends Opcode("fmin.d")
|
||||||
|
object FMAX_D extends Opcode("fmax.d")
|
||||||
|
object FSGNJ_S extends Opcode("fsgnj.s")
|
||||||
|
object FSGNJN_S extends Opcode("fsgnjn.s")
|
||||||
|
object FSGNJX_S extends Opcode("fsgnjx.s")
|
||||||
|
object FSGNJ_D extends Opcode("fsgnj.d")
|
||||||
|
object FSGNJN_D extends Opcode("fsgnjn.d")
|
||||||
|
object FSGNJX_D extends Opcode("fsgnjx.d")
|
||||||
|
|
||||||
|
object FMADD_S extends Opcode("fmadd.s")
|
||||||
|
object FMSUB_S extends Opcode("fmsub.s")
|
||||||
|
object FNMSUB_S extends Opcode("fnmsub.s")
|
||||||
|
object FNMADD_S extends Opcode("fnmadd.s")
|
||||||
|
object FMADD_D extends Opcode("fmadd.d")
|
||||||
|
object FMSUB_D extends Opcode("fmsub.d")
|
||||||
|
object FNMSUB_D extends Opcode("fnmsub.d")
|
||||||
|
object FNMADD_D extends Opcode("fnmadd.d")
|
||||||
|
|
||||||
|
object FCVT_S_D extends Opcode("fcvt.s.d")
|
||||||
|
object FCVT_D_S extends Opcode("fcvt.d.s")
|
||||||
|
object FCVT_S_L extends Opcode("fcvt.s.l")
|
||||||
|
object FCVT_S_LU extends Opcode("fcvt.s.lu")
|
||||||
|
object FCVT_S_W extends Opcode("fcvt.s.w")
|
||||||
|
object FCVT_S_WU extends Opcode("fcvt.s.wu")
|
||||||
|
object FCVT_D_L extends Opcode("fcvt.d.l")
|
||||||
|
object FCVT_D_LU extends Opcode("fcvt.d.lu")
|
||||||
|
object FCVT_D_W extends Opcode("fcvt.d.w")
|
||||||
|
object FCVT_D_WU extends Opcode("fcvt.d.wu")
|
||||||
|
object FCVT_L_S extends Opcode("fcvt.l.s")
|
||||||
|
object FCVT_LU_S extends Opcode("fcvt.lu.s")
|
||||||
|
object FCVT_W_S extends Opcode("fcvt.w.s")
|
||||||
|
object FCVT_WU_S extends Opcode("fcvt.wu.s")
|
||||||
|
object FCVT_L_D extends Opcode("fcvt.l.d")
|
||||||
|
object FCVT_LU_D extends Opcode("fcvt.lu.d")
|
||||||
|
object FCVT_W_D extends Opcode("fcvt.w.d")
|
||||||
|
object FCVT_WU_D extends Opcode("fcvt.wu.d")
|
||||||
|
|
||||||
|
object FMV_X_S extends Opcode("fmv.x.s")
|
||||||
|
object FMV_S_X extends Opcode("fmv.s.x")
|
||||||
|
object FMV_X_D extends Opcode("fmv.x.d")
|
||||||
|
object FMV_D_X extends Opcode("fmv.d.x")
|
||||||
|
|
||||||
|
object FRSR extends Opcode("frsr")
|
||||||
|
object FSSR extends Opcode("fssr")
|
||||||
|
|
||||||
|
object FEQ_S extends Opcode("feq.s")
|
||||||
|
object FLT_S extends Opcode("flt.s")
|
||||||
|
object FLE_S extends Opcode("fle.s")
|
||||||
|
object FEQ_D extends Opcode("feq.d")
|
||||||
|
object FLT_D extends Opcode("flt.d")
|
||||||
|
object FLE_D extends Opcode("fle.d")
|
||||||
|
|
||||||
|
object FENCE_I extends Opcode("fence.i")
|
||||||
|
object FENCE extends Opcode("fence")
|
||||||
|
|
||||||
|
object SYSCALL extends Opcode("syscall")
|
||||||
|
object BREAK extends Opcode("break")
|
||||||
|
object RDCYCLE extends Opcode("rdcycle")
|
||||||
|
object RDTIME extends Opcode("rdtime")
|
||||||
|
object RDINSTRET extends Opcode("rdinstret")
|
||||||
|
object NOP extends Opcode("nop")
|
||||||
|
object LI extends Opcode("li")
|
||||||
|
object MFPCR extends Opcode("mfpcr")
|
||||||
|
object MTPCR extends Opcode("mtpcr")
|
||||||
|
object AUIPC extends Opcode("auipc")
|
||||||
|
|
||||||
|
object VVCFGIVL extends Opcode("vvcfgivl")
|
||||||
|
object VSTOP extends Opcode("vstop")
|
||||||
|
object VSETVL extends Opcode("vsetvl")
|
||||||
|
object VEIDX extends Opcode("veidx")
|
||||||
|
object VF extends Opcode("vf")
|
||||||
|
object VMCS extends Opcode("vmcs")
|
||||||
|
object VMCA extends Opcode("vmca")
|
||||||
|
|
||||||
|
object VADDI extends Opcode("vaddi")
|
||||||
|
object VSLLI extends Opcode("vslli")
|
||||||
|
object VXORI extends Opcode("vxori")
|
||||||
|
object VSRLI extends Opcode("vsrli")
|
||||||
|
object VSRAI extends Opcode("vsrai")
|
||||||
|
object VORI extends Opcode("vori")
|
||||||
|
object VANDI extends Opcode("vandi")
|
||||||
|
object VLUI extends Opcode("vlui")
|
||||||
|
object VADDIW extends Opcode("vaddiw")
|
||||||
|
object VSLLIW extends Opcode("vslliw")
|
||||||
|
object VSRLIW extends Opcode("vsrliw")
|
||||||
|
object VSRAIW extends Opcode("vsraiw")
|
||||||
|
|
||||||
|
object VADD extends Opcode("vadd")
|
||||||
|
object VSUB extends Opcode("vsub")
|
||||||
|
object VSLL extends Opcode("vsll")
|
||||||
|
object VXOR extends Opcode("vxor")
|
||||||
|
object VSRL extends Opcode("vsrl")
|
||||||
|
object VSRA extends Opcode("vsra")
|
||||||
|
object VOR extends Opcode("vor")
|
||||||
|
object VAND extends Opcode("vand")
|
||||||
|
object VMUL extends Opcode("vmul")
|
||||||
|
object VMULH extends Opcode("vmulh")
|
||||||
|
object VMULHSU extends Opcode("vmulhsu")
|
||||||
|
object VMULHU extends Opcode("vmulhu")
|
||||||
|
object VDIV extends Opcode("vdiv")
|
||||||
|
object VDIVU extends Opcode("vdivu")
|
||||||
|
object VREM extends Opcode("vrem")
|
||||||
|
object VREMU extends Opcode("vremu")
|
||||||
|
object VADDW extends Opcode("vaddw")
|
||||||
|
object VSUBW extends Opcode("vsubw")
|
||||||
|
object VSLLW extends Opcode("vsllw")
|
||||||
|
object VSRLW extends Opcode("vsrlw")
|
||||||
|
object VSRAW extends Opcode("vsraw")
|
||||||
|
object VMULW extends Opcode("vmulw")
|
||||||
|
object VDIVW extends Opcode("vdivw")
|
||||||
|
object VDIVUW extends Opcode("vdivuw")
|
||||||
|
object VREMW extends Opcode("vremw")
|
||||||
|
object VREMUW extends Opcode("vremuw")
|
||||||
|
|
||||||
|
object VCMPEQ extends Opcode("vcmpeq")
|
||||||
|
object VCMPLT extends Opcode("vcmplt")
|
||||||
|
object VCMPLTU extends Opcode("vcmpltu")
|
||||||
|
object VCMPFEQ extends Opcode("vcmpfeq")
|
||||||
|
object VCMPFLT extends Opcode("vcmpflt")
|
||||||
|
object VCMPFLE extends Opcode("vcmpfle")
|
||||||
|
|
||||||
|
object VPOP extends Opcode("vpop")
|
||||||
|
object VPSET extends Opcode("vpset")
|
||||||
|
object VPCLEAR extends Opcode("vpclear")
|
||||||
|
|
||||||
|
object VFADD_S extends Opcode("vfadd.s")
|
||||||
|
object VFSUB_S extends Opcode("vfsub.s")
|
||||||
|
object VFMUL_S extends Opcode("vfmul.s")
|
||||||
|
object VFDIV_S extends Opcode("vfdiv.s")
|
||||||
|
object VFSQRT_S extends Opcode("vfsqrt.s")
|
||||||
|
object VFMIN_S extends Opcode("vfmin.s")
|
||||||
|
object VFMAX_S extends Opcode("vfmax.s")
|
||||||
|
object VFADD_D extends Opcode("vfadd.d")
|
||||||
|
object VFSUB_D extends Opcode("vfsub.d")
|
||||||
|
object VFMUL_D extends Opcode("vfmul.d")
|
||||||
|
object VFDIV_D extends Opcode("vfdiv.d")
|
||||||
|
object VFSQRT_D extends Opcode("vfsqrt.d")
|
||||||
|
object VFMIN_D extends Opcode("vfmin.d")
|
||||||
|
object VFMAX_D extends Opcode("vfmax.d")
|
||||||
|
object VFSGNJ_S extends Opcode("vfsgnj.s")
|
||||||
|
object VFSGNJN_S extends Opcode("vfsgnjn.s")
|
||||||
|
object VFSGNJX_S extends Opcode("vfsgnjx.s")
|
||||||
|
object VFSGNJ_D extends Opcode("vfsgnj.d")
|
||||||
|
object VFSGNJN_D extends Opcode("vfsgnjn.d")
|
||||||
|
object VFSGNJX_D extends Opcode("vfsgnjx.d")
|
||||||
|
|
||||||
|
object VFMADD_S extends Opcode("vfmadd.s")
|
||||||
|
object VFMSUB_S extends Opcode("vfmsub.s")
|
||||||
|
object VFNMSUB_S extends Opcode("vfnmsub.s")
|
||||||
|
object VFNMADD_S extends Opcode("vfnmadd.s")
|
||||||
|
object VFMADD_D extends Opcode("vfmadd.d")
|
||||||
|
object VFMSUB_D extends Opcode("vfmsub.d")
|
||||||
|
object VFNMSUB_D extends Opcode("vfnmsub.d")
|
||||||
|
object VFNMADD_D extends Opcode("vfnmadd.d")
|
||||||
|
|
||||||
|
object VFCVT_S_D extends Opcode("vfcvt.s.d")
|
||||||
|
object VFCVT_D_S extends Opcode("vfcvt.d.s")
|
||||||
|
object VFCVT_S_L extends Opcode("vfcvt.s.l")
|
||||||
|
object VFCVT_S_LU extends Opcode("vfcvt.s.lu")
|
||||||
|
object VFCVT_S_W extends Opcode("vfcvt.s.w")
|
||||||
|
object VFCVT_S_WU extends Opcode("vfcvt.s.wu")
|
||||||
|
object VFCVT_D_L extends Opcode("vfcvt.d.l")
|
||||||
|
object VFCVT_D_LU extends Opcode("vfcvt.d.lu")
|
||||||
|
object VFCVT_D_W extends Opcode("vfcvt.d.w")
|
||||||
|
object VFCVT_D_WU extends Opcode("vfcvt.d.wu")
|
||||||
|
object VFCVT_L_S extends Opcode("vfcvt.l.s")
|
||||||
|
object VFCVT_LU_S extends Opcode("vfcvt.lu.s")
|
||||||
|
object VFCVT_W_S extends Opcode("vfcvt.w.s")
|
||||||
|
object VFCVT_WU_S extends Opcode("vfcvt.wu.s")
|
||||||
|
object VFCVT_L_D extends Opcode("vfcvt.l.d")
|
||||||
|
object VFCVT_LU_D extends Opcode("vfcvt.lu.d")
|
||||||
|
object VFCVT_W_D extends Opcode("vfcvt.w.d")
|
||||||
|
object VFCVT_WU_D extends Opcode("vfcvt.wu.d")
|
||||||
|
|
||||||
|
object VLSB extends Opcode("vlsb")
|
||||||
|
object VLSH extends Opcode("vlsh")
|
||||||
|
object VLSW extends Opcode("vlsw")
|
||||||
|
object VLSD extends Opcode("vlsd")
|
||||||
|
object VLSBU extends Opcode("vlsbu")
|
||||||
|
object VLSHU extends Opcode("vlshu")
|
||||||
|
object VLSWU extends Opcode("vlswu")
|
||||||
|
object VSSB extends Opcode("vssb")
|
||||||
|
object VSSH extends Opcode("vssh")
|
||||||
|
object VSSW extends Opcode("vssw")
|
||||||
|
object VSSD extends Opcode("vssd")
|
||||||
|
object VLAB extends Opcode("vlab")
|
||||||
|
object VLAH extends Opcode("vlah")
|
||||||
|
object VLAW extends Opcode("vlaw")
|
||||||
|
object VLAD extends Opcode("vlad")
|
||||||
|
object VLABU extends Opcode("vlabu")
|
||||||
|
object VLAHU extends Opcode("vlahu")
|
||||||
|
object VLAWU extends Opcode("vlawu")
|
||||||
|
object VSAB extends Opcode("vsab")
|
||||||
|
object VSAH extends Opcode("vsah")
|
||||||
|
object VSAW extends Opcode("vsaw")
|
||||||
|
object VSAD extends Opcode("vsad")
|
||||||
|
|
||||||
|
object VLB extends Opcode("vlb")
|
||||||
|
object VLH extends Opcode("vlh")
|
||||||
|
object VLW extends Opcode("vlw")
|
||||||
|
object VLD extends Opcode("vld")
|
||||||
|
object VLBU extends Opcode("vlbu")
|
||||||
|
object VLHU extends Opcode("vlhu")
|
||||||
|
object VLWU extends Opcode("vlwu")
|
||||||
|
object VSB extends Opcode("vsb")
|
||||||
|
object VSH extends Opcode("vsh")
|
||||||
|
object VSW extends Opcode("vsw")
|
||||||
|
object VSD extends Opcode("vsd")
|
||||||
|
|
||||||
|
object VLSEGB extends Opcode("vlsegb")
|
||||||
|
object VLSEGH extends Opcode("vlsegh")
|
||||||
|
object VLSEGW extends Opcode("vlsegw")
|
||||||
|
object VLSEGD extends Opcode("vlsegd")
|
||||||
|
object VLSEGBU extends Opcode("vlsegbu")
|
||||||
|
object VLSEGHU extends Opcode("vlseghu")
|
||||||
|
object VLSEGWU extends Opcode("vlsegwu")
|
||||||
|
object VSSEGB extends Opcode("vssegb")
|
||||||
|
object VSSEGH extends Opcode("vssegh")
|
||||||
|
object VSSEGW extends Opcode("vssegw")
|
||||||
|
object VSSEGD extends Opcode("vssegd")
|
||||||
|
|
||||||
|
object VLSTB extends Opcode("vlstb")
|
||||||
|
object VLSTH extends Opcode("vlsth")
|
||||||
|
object VLSTW extends Opcode("vlstw")
|
||||||
|
object VLSTD extends Opcode("vlstd")
|
||||||
|
object VLSTBU extends Opcode("vlstbu")
|
||||||
|
object VLSTHU extends Opcode("vlsthu")
|
||||||
|
object VLSTWU extends Opcode("vlstwu")
|
||||||
|
object VSSTB extends Opcode("vsstb")
|
||||||
|
object VSSTH extends Opcode("vssth")
|
||||||
|
object VSSTW extends Opcode("vsstw")
|
||||||
|
object VSSTD extends Opcode("vsstd")
|
||||||
|
|
||||||
|
object VLSEGSTB extends Opcode("vlsegstb")
|
||||||
|
object VLSEGSTH extends Opcode("vlsegsth")
|
||||||
|
object VLSEGSTW extends Opcode("vlsegstw")
|
||||||
|
object VLSEGSTD extends Opcode("vlsegstd")
|
||||||
|
object VLSEGSTBU extends Opcode("vlsegstbu")
|
||||||
|
object VLSEGSTHU extends Opcode("vlsegsthu")
|
||||||
|
object VLSEGSTWU extends Opcode("vlsegstwu")
|
||||||
|
object VSSEGSTB extends Opcode("vssegstb")
|
||||||
|
object VSSEGSTH extends Opcode("vssegsth")
|
||||||
|
object VSSEGSTW extends Opcode("vssegstw")
|
||||||
|
object VSSEGSTD extends Opcode("vssegstd")
|
||||||
|
|
||||||
|
object VLXB extends Opcode("vlxb")
|
||||||
|
object VLXH extends Opcode("vlxh")
|
||||||
|
object VLXW extends Opcode("vlxw")
|
||||||
|
object VLXD extends Opcode("vlxd")
|
||||||
|
object VLXBU extends Opcode("vlxbu")
|
||||||
|
object VLXHU extends Opcode("vlxhu")
|
||||||
|
object VLXWU extends Opcode("vlxwu")
|
||||||
|
object VSXB extends Opcode("vsxb")
|
||||||
|
object VSXH extends Opcode("vsxh")
|
||||||
|
object VSXW extends Opcode("vsxw")
|
||||||
|
object VSXD extends Opcode("vsxd")
|
||||||
|
|
||||||
|
object VLSEGXB extends Opcode("vlsegxb")
|
||||||
|
object VLSEGXH extends Opcode("vlsegxh")
|
||||||
|
object VLSEGXW extends Opcode("vlsegxw")
|
||||||
|
object VLSEGXD extends Opcode("vlsegxd")
|
||||||
|
object VLSEGXBU extends Opcode("vlsegxbu")
|
||||||
|
object VLSEGXHU extends Opcode("vlsegxhu")
|
||||||
|
object VLSEGXWU extends Opcode("vlsegxwu")
|
||||||
|
object VSSEGXB extends Opcode("vssegxb")
|
||||||
|
object VSSEGXH extends Opcode("vssegxh")
|
||||||
|
object VSSEGXW extends Opcode("vssegxw")
|
||||||
|
object VSSEGXD extends Opcode("vssegxd")
|
||||||
|
|
||||||
|
object VAMOADD_W extends Opcode("vamoadd.w")
|
||||||
|
object VAMOSWAP_W extends Opcode("vamoswap.w")
|
||||||
|
object VAMOAND_W extends Opcode("vamoand.w")
|
||||||
|
object VAMOOR_W extends Opcode("vamoor.w")
|
||||||
|
object VAMOMIN_W extends Opcode("vamomin.w")
|
||||||
|
object VAMOMINU_W extends Opcode("vamominu.w")
|
||||||
|
object VAMOMAX_W extends Opcode("vamomax.w")
|
||||||
|
object VAMOMAXU_W extends Opcode("vamomaxu.w")
|
||||||
|
object VAMOXOR_W extends Opcode("vamoxor.w")
|
||||||
|
object VAMOADD_D extends Opcode("vamoadd.d")
|
||||||
|
object VAMOSWAP_D extends Opcode("vamoswap.d")
|
||||||
|
object VAMOAND_D extends Opcode("vamoand.d")
|
||||||
|
object VAMOOR_D extends Opcode("vamoor.d")
|
||||||
|
object VAMOMIN_D extends Opcode("vamomin.d")
|
||||||
|
object VAMOMINU_D extends Opcode("vamominu.d")
|
||||||
|
object VAMOMAX_D extends Opcode("vamomax.d")
|
||||||
|
object VAMOMAXU_D extends Opcode("vamomaxu.d")
|
||||||
|
object VAMOXOR_D extends Opcode("vamoxor.d")
|
||||||
|
|
||||||
|
object MOVZ extends Opcode("movz")
|
||||||
|
object MOVN extends Opcode("movn")
|
||||||
|
object FMOVZ extends Opcode("fmovz")
|
||||||
|
object FMOVN extends Opcode("fmovn")
|
||||||
|
|
||||||
|
object FENCE_V extends Opcode("fence")
|
||||||
|
|
||||||
|
object ILLEGAL extends Opcode(".word")
|
|
@ -0,0 +1,121 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class InstSeq extends HWRegAllocator
|
||||||
|
{
|
||||||
|
val insts = new ArrayBuffer[Inst]
|
||||||
|
var inst_ptr = 0
|
||||||
|
val seqname = "Unnamed"
|
||||||
|
|
||||||
|
val extra_code = new ArrayBuffer[DataChunk]
|
||||||
|
val extra_hidden_data = new ArrayBuffer[DataChunk]
|
||||||
|
val extra_visible_data = new ArrayBuffer[DataChunk]
|
||||||
|
|
||||||
|
def is_done = insts.length == inst_ptr
|
||||||
|
|
||||||
|
def next_inst() =
|
||||||
|
{
|
||||||
|
val inst = insts(inst_ptr)
|
||||||
|
inst_ptr += 1
|
||||||
|
inst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object InstSeq
|
||||||
|
{
|
||||||
|
def apply(prob_tbl: ArrayBuffer[(Int, () => InstSeq)]): InstSeq =
|
||||||
|
{
|
||||||
|
var p = rand_range(0, 99)
|
||||||
|
for ((prob, gen_seq) <- prob_tbl)
|
||||||
|
{
|
||||||
|
if (p < prob) return gen_seq()
|
||||||
|
p -= prob
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false, println("Probabilties should have added up to 100%"))
|
||||||
|
new InstSeq()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import HWReg._
|
||||||
|
|
||||||
|
class HWRegAllocator
|
||||||
|
{
|
||||||
|
val regs = new ArrayBuffer[Reg]
|
||||||
|
var allocated = false
|
||||||
|
|
||||||
|
def reg_fn(hwrp: HWRegPool, filter: (HWReg) => Boolean, alloc: (HWReg) => Unit, free: (HWReg) => Unit, consec_regs: Int = 1) =
|
||||||
|
{
|
||||||
|
val reg = new RegNeedsAlloc(hwrp, filter, alloc, free, consec_regs)
|
||||||
|
for(i <- 1 to consec_regs) reg.regs += new Reg
|
||||||
|
regs += reg
|
||||||
|
reg
|
||||||
|
}
|
||||||
|
|
||||||
|
def reg_read_zero(hwrp: HWRegPool) = { reg_fn(hwrp, filter_read_zero, alloc_read, free_read) }
|
||||||
|
def reg_read_any(hwrp: HWRegPool) = { reg_fn(hwrp, filter_read_any, alloc_read, free_read) }
|
||||||
|
def reg_read_any_other(hwrp: HWRegPool, other: Reg) = { reg_fn(hwrp, filter_read_any_other(other), alloc_read, free_read) }
|
||||||
|
def reg_read_visible(hwrp: HWRegPool) = { reg_fn(hwrp, filter_read_visible, alloc_read, free_read) }
|
||||||
|
def reg_read_visible_consec(hwrp: HWRegPool, regs: Int) = { reg_fn(hwrp, filter_read_visible, alloc_read, free_read, regs) }
|
||||||
|
def reg_write_ra(hwrp: HWRegPool) = { reg_fn(hwrp, filter_write_ra, alloc_write(false), free_write) }
|
||||||
|
def reg_write_visible(hwrp: HWRegPool) = { reg_fn(hwrp, filter_write_visible, alloc_write(true), free_write) }
|
||||||
|
def reg_write_visible_consec(hwrp: HWRegPool, regs: Int) = { reg_fn(hwrp, filter_write_visible, alloc_write(true), free_write, regs) }
|
||||||
|
def reg_write_hidden(hwrp: HWRegPool) = { reg_fn(hwrp, filter_write_hidden, alloc_write(false), free_write) }
|
||||||
|
def reg_write(hwrp: HWRegPool, regs: Reg*) = { reg_fn(hwrp, filter_write_dep(regs.toList), alloc_write_dep(regs.toList), free_write) }
|
||||||
|
def reg_write_other(hwrp: HWRegPool, other: Reg, regs: Reg*) = { reg_fn(hwrp, filter_write_dep_other(other, regs.toList), alloc_write_dep(regs.toList), free_write) }
|
||||||
|
|
||||||
|
def allocate_regs(): Boolean =
|
||||||
|
{
|
||||||
|
for (reg <- regs)
|
||||||
|
{
|
||||||
|
val regna = reg.asInstanceOf[RegNeedsAlloc]
|
||||||
|
val candidates = regna.hwrp.hwregs.filter(regna.filter)
|
||||||
|
val consec_regs = regna.consec_regs
|
||||||
|
val hwregs = regna.hwrp.hwregs
|
||||||
|
|
||||||
|
if (candidates.length < consec_regs)
|
||||||
|
return false
|
||||||
|
|
||||||
|
var high = 0
|
||||||
|
val consec_candidates = new ArrayBuffer[Int] // index in hwregs
|
||||||
|
for( hrindex <- 0 to hwregs.length)
|
||||||
|
{
|
||||||
|
if(hrindex < hwregs.length && candidates.contains(hwregs(hrindex)))
|
||||||
|
high += 1 // still seeing consec regs
|
||||||
|
else if (high > 0)
|
||||||
|
{
|
||||||
|
// end of sequence. number all the candidates of this sequence
|
||||||
|
for(i <- high to consec_regs by -1)
|
||||||
|
consec_candidates += hrindex-i
|
||||||
|
high = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(consec_candidates.size == 0)
|
||||||
|
return false
|
||||||
|
val reg_index = rand_pick(consec_candidates)
|
||||||
|
for(i <- reg_index until reg_index+consec_regs){
|
||||||
|
val hwreg = hwregs(i)
|
||||||
|
regna.alloc(hwreg)
|
||||||
|
if(i == reg_index) regna.hwreg = hwreg
|
||||||
|
regna.regs.toArray[Reg].apply(i-reg_index).hwreg = hwreg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allocated = true
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
def free_regs() =
|
||||||
|
{
|
||||||
|
for (reg <- regs)
|
||||||
|
{
|
||||||
|
val regna = reg.asInstanceOf[RegNeedsAlloc]
|
||||||
|
val hwregs = regna.hwrp.hwregs
|
||||||
|
val start = hwregs.indexOf(regna.hwreg)
|
||||||
|
for( i <- start until start+regna.consec_regs ) regna.free(hwregs(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class Mem(name: Array[Operand], val size: Int) extends Operand
|
||||||
|
{
|
||||||
|
def this(namelabel: String, size: Int) = this(Array[Operand](Label(namelabel)), size)
|
||||||
|
|
||||||
|
assert(size % 4 == 0, "Memory size must be multiple of 4")
|
||||||
|
|
||||||
|
override def toString = name.mkString("")
|
||||||
|
|
||||||
|
def dumpdata =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += this.toString + ":\n"
|
||||||
|
if(size % 16 == 0)
|
||||||
|
{
|
||||||
|
for (i <- 0 to (size/8/2 - 1))
|
||||||
|
s += "\t.dword 0x%016x, 0x%016x\n" format (rand_dword, rand_dword)
|
||||||
|
} else if(size % 8 == 0)
|
||||||
|
{
|
||||||
|
for (i <- 0 to (size/8 - 1))
|
||||||
|
s += "\t.dword 0x%016x\n" format (rand_dword)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i <- 0 to (size/4 - 1))
|
||||||
|
s += "\t.word 0x%08x\n" format (rand_word)
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def dumpaddrs(addrfn: (Int) => Int, memsize: Int) =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += this.toString + ":\n"
|
||||||
|
if(size % 16 == 0)
|
||||||
|
{
|
||||||
|
for (i <- 0 to (size/8/2 - 1))
|
||||||
|
s += "\t.dword 0x%016x, 0x%016x\n" format (addrfn(memsize), addrfn(memsize))
|
||||||
|
} else if(size % 8 == 0)
|
||||||
|
{
|
||||||
|
for (i <- 0 to (size/8 - 1))
|
||||||
|
s += "\t.dword 0x%016x\n" format (addrfn(memsize))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i <- 0 to (size/4 - 1))
|
||||||
|
s += "\t.word 0x%08x\n" format (addrfn(memsize))
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VMem(name: Array[Operand], val ut_size: Int, num_ut: Int) extends Mem(name, ut_size*num_ut)
|
||||||
|
{
|
||||||
|
def this(namelabel: String, ut_size: Int, num_ut: Int) = this(Array[Operand](Label(namelabel)), ut_size, num_ut)
|
||||||
|
|
||||||
|
assert(size % 16 == 0, "Per uthread memory size must be multiple of 16")
|
||||||
|
|
||||||
|
override def dumpdata =
|
||||||
|
{
|
||||||
|
var s = "\t.align 8\n"
|
||||||
|
s += this.toString + ":\n"
|
||||||
|
|
||||||
|
for(ut <- 0 to (num_ut-1))
|
||||||
|
{
|
||||||
|
s+= "\t" + this.toString + "_ut_" + ut + ":\n"
|
||||||
|
for (i <- 0 to (ut_size/8/2 - 1))
|
||||||
|
s += "\t.dword 0x%016x, 0x%016x\n" format (rand_dword, rand_dword)
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
abstract class Operand
|
||||||
|
|
||||||
|
class Reg extends Operand
|
||||||
|
{
|
||||||
|
var allocated = false
|
||||||
|
var hwreg = new HWReg("-", false, false)
|
||||||
|
|
||||||
|
override def toString = hwreg.toString
|
||||||
|
}
|
||||||
|
|
||||||
|
class RegNeedsAlloc(
|
||||||
|
val hwrp: HWRegPool,
|
||||||
|
val filter: (HWReg) => Boolean,
|
||||||
|
val alloc: (HWReg) => Unit,
|
||||||
|
val free: (HWReg) => Unit,
|
||||||
|
val consec_regs: Int = 1) extends Reg
|
||||||
|
{
|
||||||
|
val regs = new ArrayBuffer[Reg]
|
||||||
|
}
|
||||||
|
|
||||||
|
class Imm(imm: Int) extends Operand
|
||||||
|
{
|
||||||
|
override def toString = imm.toString
|
||||||
|
}
|
||||||
|
|
||||||
|
class HexImm(imm: Int) extends Operand
|
||||||
|
{
|
||||||
|
override def toString = "0x"+Integer.toHexString(imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
class BaseImm(base: String, imm: Int) extends Operand
|
||||||
|
{
|
||||||
|
override def toString =
|
||||||
|
{
|
||||||
|
if (imm == 0) base
|
||||||
|
else if (imm < 0) base + imm.toString
|
||||||
|
else base + "+" + imm.toString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RegImm(base: Reg, imm: Int) extends Operand
|
||||||
|
{
|
||||||
|
override def toString = imm.toString + "(" + base + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
class RegStrImm(base: Reg, imm: String) extends Operand
|
||||||
|
{
|
||||||
|
override def toString = imm + "(" + base + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Label(val label: String) extends Operand
|
||||||
|
{
|
||||||
|
override def toString = label
|
||||||
|
}
|
||||||
|
|
||||||
|
class PredReg(pred: Reg, neg: Boolean) extends Operand
|
||||||
|
{
|
||||||
|
override def toString =
|
||||||
|
if (neg) "@!" + pred
|
||||||
|
else "@" + pred
|
||||||
|
}
|
||||||
|
|
||||||
|
object Imm
|
||||||
|
{
|
||||||
|
def apply(imm: Int) = new Imm(imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
object HexImm
|
||||||
|
{
|
||||||
|
def apply(imm: Int) = new HexImm(imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
object BaseImm
|
||||||
|
{
|
||||||
|
def apply(base: String, imm: Int) = new BaseImm(base, imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
object RegImm
|
||||||
|
{
|
||||||
|
def apply(base: Reg, imm: Int) = new RegImm(base, imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
object RegStrImm
|
||||||
|
{
|
||||||
|
def apply(base: Reg, imm: String) = new RegStrImm(base, imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Label
|
||||||
|
{
|
||||||
|
def apply(label: String) = new Label(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
object PredReg
|
||||||
|
{
|
||||||
|
def apply(pred: Reg, neg: Boolean) = new PredReg(pred, neg)
|
||||||
|
}
|
|
@ -0,0 +1,563 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import scala.collection.mutable.HashMap
|
||||||
|
import Rand._
|
||||||
|
import java.util.Date
|
||||||
|
import java.text.DateFormat
|
||||||
|
|
||||||
|
class ProgSeg(val name: String)
|
||||||
|
{
|
||||||
|
var insts = new ArrayBuffer[Inst]
|
||||||
|
|
||||||
|
override def toString = ((name + ":\n") /: insts.map((x) => "\t" + x + "\n"))(_ + _)
|
||||||
|
}
|
||||||
|
|
||||||
|
object ProgSeg
|
||||||
|
{
|
||||||
|
var cnt = 0
|
||||||
|
|
||||||
|
def apply() =
|
||||||
|
{
|
||||||
|
val res = new ProgSeg("pseg_" + cnt)
|
||||||
|
cnt += 1
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Prog(memsize: Int, veccfg: Map[String,String], loop : Boolean)
|
||||||
|
{
|
||||||
|
// Setup scalar core memory
|
||||||
|
val core_memory = new Mem("test_memory", memsize)
|
||||||
|
|
||||||
|
// Setup register pools
|
||||||
|
val num_vxregs = rand_range(5, 256)
|
||||||
|
val use_pop = veccfg.getOrElse("pop", "true") == "true"
|
||||||
|
val pred_alu = veccfg.getOrElse("pred_alu", "true") == "true"
|
||||||
|
val pred_mem = veccfg.getOrElse("pred_mem", "true") == "true"
|
||||||
|
val min_pregs = if(pred_alu || pred_mem || use_pop) 2 else 1
|
||||||
|
val num_vpregs = rand_range(min_pregs, 16)
|
||||||
|
val num_vsregs = veccfg.getOrElse("numsregs","64").toInt
|
||||||
|
val max_vl = (Math.floor(256/(num_vxregs-1))).toInt * 8
|
||||||
|
val used_vl = Math.min(max_vl, rand_range(1, max_vl))
|
||||||
|
|
||||||
|
val xregs = new XRegsPool()
|
||||||
|
val fregs = new FRegsMaster()
|
||||||
|
val vregs = new VRegsMaster(num_vxregs, num_vpregs, num_vsregs)
|
||||||
|
|
||||||
|
val fregpools = fregs.extract_pools()
|
||||||
|
val vregpools = vregs.extract_pools()
|
||||||
|
val (fregs_s, fregs_d) = (fregpools(0), fregpools(1))
|
||||||
|
val (vxregs, vpregs, vsregs, varegs) = (vregpools(0), vregpools(1), vregpools(2), vregpools(3))
|
||||||
|
|
||||||
|
val seqs = new ArrayBuffer[InstSeq]
|
||||||
|
val seqs_active = new ArrayBuffer[InstSeq]
|
||||||
|
val progsegs = new ArrayBuffer[ProgSeg]
|
||||||
|
|
||||||
|
var killed_seqs = 0
|
||||||
|
var nseqs = 0
|
||||||
|
var prob_tbl = new ArrayBuffer[(Int, ()=>InstSeq)]
|
||||||
|
|
||||||
|
val opstats = new HashMap[String, scala.collection.mutable.Map[String,Int]]
|
||||||
|
val catstats = new HashMap[String,Int]
|
||||||
|
val seqstats = new HashMap[String,Int].withDefaultValue(0)
|
||||||
|
val vseqstats = new HashMap[String,Int].withDefaultValue(0)
|
||||||
|
val regstats = new HashMap[String,Int].withDefaultValue(0)
|
||||||
|
for (cat <- List(("alu"),("cmp"),("branch"),("jalr"),
|
||||||
|
("jmp"),("la"),("mem"),("amo"),("misc"),("fpalu"),("fpcmp"),
|
||||||
|
("fpfma"),("fpmem"),("fpcvt"),("fpmisc"),("vmem"),("vamo"),("valu"),
|
||||||
|
("vmisc"),("vfpalu"),("vfpfma"),("vfpcvt"),("vsmem"),("vshared"),("vpred"),("vcmp"),("unknown")))
|
||||||
|
{
|
||||||
|
catstats(cat)=0
|
||||||
|
opstats(cat) = new HashMap[String,Int].withDefaultValue(0)
|
||||||
|
}
|
||||||
|
var instcnt = 0
|
||||||
|
|
||||||
|
def seqs_not_allocated = seqs.filter((x) => !x.allocated)
|
||||||
|
def is_seqs_empty = seqs_not_allocated.length == 0
|
||||||
|
def is_seqs_active_empty = seqs_active.length == 0
|
||||||
|
|
||||||
|
def are_pools_fully_unallocated = List(xregs, fregs_s, fregs_d, vxregs, vpregs, vsregs, varegs).forall(_.is_fully_unallocated)
|
||||||
|
|
||||||
|
def seqs_find_active(): Unit =
|
||||||
|
{
|
||||||
|
for (seq <- seqs_not_allocated)
|
||||||
|
{
|
||||||
|
xregs.backup()
|
||||||
|
fregs.backup()
|
||||||
|
vregs.backup()
|
||||||
|
|
||||||
|
if (seq.allocate_regs())
|
||||||
|
{
|
||||||
|
seqs_active += seq
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (are_pools_fully_unallocated)
|
||||||
|
{
|
||||||
|
seqs -= seq
|
||||||
|
killed_seqs += 1
|
||||||
|
seqstats(seq.seqname) -= 1
|
||||||
|
if (seq.seqname == "vec")
|
||||||
|
{
|
||||||
|
for ((seqname, seqcnt) <- seq.asInstanceOf[SeqVec].vseqstats)
|
||||||
|
{
|
||||||
|
vseqstats(seqname) = seqcnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (killed_seqs < (nseqs*5))
|
||||||
|
gen_seq()
|
||||||
|
}
|
||||||
|
xregs.restore()
|
||||||
|
fregs.restore()
|
||||||
|
vregs.restore()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var jalr_labels = new ArrayBuffer[Label]
|
||||||
|
|
||||||
|
def update_stats(inst: Inst) =
|
||||||
|
{
|
||||||
|
catstats(inst.optype) += 1
|
||||||
|
opstats(inst.optype)(inst.opcode) += 1
|
||||||
|
for (operand <- inst.operands)
|
||||||
|
{
|
||||||
|
if (operand.isInstanceOf[Reg])
|
||||||
|
{
|
||||||
|
regstats(operand.toString) += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instcnt += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
def register_stats(): String =
|
||||||
|
{
|
||||||
|
def register_lt(reg1: (String, Int), reg2: (String, Int)): Boolean =
|
||||||
|
{
|
||||||
|
val reghash = HashMap('x'->1,'f'->2,'v'->3,'p'->4,'s'->5,'a'->6)
|
||||||
|
val regname1 = reg1._1
|
||||||
|
val regname2 = reg2._1
|
||||||
|
if (reghash(regname1(0)) == reghash(regname2(0)))
|
||||||
|
{
|
||||||
|
if (regname1(0) == 'v')
|
||||||
|
{
|
||||||
|
if (regname1(1) == regname2(1))
|
||||||
|
{
|
||||||
|
return (regname1.substring(2).toInt < regname2.substring(2).toInt)
|
||||||
|
} else {
|
||||||
|
return (reghash(regname1(1)) < reghash(regname2(1)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (regname1.substring(1).toInt < regname2.substring(1).toInt)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (reghash(regname1(0)) < reghash(regname2(0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sortedRegs = regstats.toSeq.sortWith(register_lt) //TODO: Better way to sort?
|
||||||
|
var s = "---------- Register Accesses ----------\n"
|
||||||
|
for ((regname, cnt) <- sortedRegs)
|
||||||
|
{
|
||||||
|
s += "---------- " + regname + ": " + cnt + " ----------\n"
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def sequence_stats(mix: Map[String, Int], vecmix: Map[String, Int], nseqs: Int, vnseq: Int, vfnum: Int): String =
|
||||||
|
{
|
||||||
|
def seq_lt(seq1: (String, Int), seq2: (String, Int)): Boolean =
|
||||||
|
{
|
||||||
|
val seqhash = HashMap("xmem"->1,"xbranch"->2,"xalu"->3,"vmem"->4,
|
||||||
|
"fgen"->5,"fpmem"->6,"fax"->7,"fdiv"->8,"vec"->9,"vonly"->10,"valu"->11,"Generic"->12).withDefaultValue(100)
|
||||||
|
if (seqhash(seq1._1) == 100 && seqhash(seq2._1) == 100) return (seq1._1 < seq2._1)
|
||||||
|
return seqhash(seq1._1) < seqhash(seq2._1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sortedMix = mix.toSeq.sortWith(seq_lt)
|
||||||
|
val sortedVecmix = vecmix.toSeq.sortWith(seq_lt)
|
||||||
|
var s = "----- Sequence Types Used:"
|
||||||
|
for ((seqtype,percent) <- sortedMix) if (percent > 0) s += " " + seqtype.toUpperCase
|
||||||
|
s += " -----\n"
|
||||||
|
s += "--------------------------------------------------------------------------\n"
|
||||||
|
s += "---------- Configured Sequence Mix ----------\n"
|
||||||
|
for ((seqtype, percent) <- sortedMix)
|
||||||
|
{
|
||||||
|
s += "---------- " + seqtype + ": " + percent + "% ----------\n"
|
||||||
|
}
|
||||||
|
s += "--------------------------------------------------------------------------\n"
|
||||||
|
s += "---------- Configured Vector Sequence Mix ----------\n"
|
||||||
|
for ((seqtype, percent) <- sortedVecmix)
|
||||||
|
{
|
||||||
|
s+= "---------- " + seqtype + ": " + percent + "% ----------\n"
|
||||||
|
}
|
||||||
|
s += "--------------------------------------------------------------------------\n"
|
||||||
|
s += "---------- Generated Sequence Mix ----------\n"
|
||||||
|
s += "---------- nseqs = " + nseqs + " -------------\n"
|
||||||
|
val sortedSeqs = seqstats.toSeq.sortWith(seq_lt)
|
||||||
|
for ((seq, seqcnt) <- sortedSeqs)
|
||||||
|
{
|
||||||
|
s += "---------- " + seq + ": " + seqcnt + " :: %3.3f".format((seqcnt.toDouble/nseqs)*100)
|
||||||
|
s += "% ----------\n"
|
||||||
|
}
|
||||||
|
s += "--------------------------------------------------------------------------\n"
|
||||||
|
s += "---------- Generated Vector Sequence Mix ----------\n"
|
||||||
|
s += "---------- nvseqs = " + vnseq*vfnum*seqstats("vec") + " -------------\n"
|
||||||
|
val sortedVSeqs = vseqstats.toSeq.sortWith(seq_lt)
|
||||||
|
for ((vseq, vseqcnt) <- sortedVSeqs)
|
||||||
|
{
|
||||||
|
s += "---------- " + vseq + ": " + vseqcnt
|
||||||
|
s += " :: %3.3f".format((vseqcnt.toDouble/(vnseq*vfnum*seqstats("vec")))*100)
|
||||||
|
s += "% ----------\n"
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def instruction_stats(): String =
|
||||||
|
{
|
||||||
|
def cat_lt(cat1: (String, Int), cat2: (String, Int)): Boolean =
|
||||||
|
{
|
||||||
|
val cathash = HashMap("alu"->1,"cmp"->2,"branch"->3,"jmp"->4,"jalr"->5,
|
||||||
|
"la"->6,"mem"->7,"amo"->8,"misc"->9,"fpalu"->10,"fpcmp"->11,"fpfma"->12,
|
||||||
|
"fpmem"->13,"fpcvt"->14,"fpmisc"->15,"vmem"->16,"vamo"->17,"valu"->18,"vfpalu"->19,
|
||||||
|
"vfpfma"->20,"vfpcvt"->21,"vsmem"->22,"vshared"->23,"vpred"->24,"vcmp"->25,"vmisc"->26,"unknown"->27)
|
||||||
|
return cathash(cat1._1) < cathash(cat2._1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var s = "---------- Opcode Usage ----------\n"
|
||||||
|
s += "---------- instcnt = " + instcnt + " -------------\n"
|
||||||
|
val sortedCats = catstats.toSeq.sortWith(cat_lt) // TODO: Better way to sort?
|
||||||
|
for ((cat, catcnt) <- sortedCats)
|
||||||
|
{
|
||||||
|
val sortedOps = opstats(cat).toSeq.sortWith(_._1 < _._1) //TODO: Better way to sort?
|
||||||
|
s += "--------------------------------------------------------------------------\n"
|
||||||
|
s += "---------- " + cat.toUpperCase() + " Opcodes: " + catcnt + " :: %3.3f".format((catcnt.toDouble/instcnt)*100)
|
||||||
|
s += "% ----------\n"
|
||||||
|
for ((op, opcnt) <- sortedOps)
|
||||||
|
{
|
||||||
|
s += "-------------------- " + op + ": " + opcnt + " :: %3.3f".format((opcnt.toDouble/instcnt)*100)
|
||||||
|
s += "% ----------\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_time(): String =
|
||||||
|
{
|
||||||
|
val date = new Date()
|
||||||
|
val datestr = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date)
|
||||||
|
"----- Test generated on " + datestr + " -----\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def gen_seq(): Unit =
|
||||||
|
{
|
||||||
|
val nxtseq = InstSeq(prob_tbl)
|
||||||
|
seqs += nxtseq
|
||||||
|
seqstats(nxtseq.seqname) += 1
|
||||||
|
if (nxtseq.seqname == "vec")
|
||||||
|
{
|
||||||
|
for ((seqname, seqcnt) <- nxtseq.asInstanceOf[SeqVec].vseqstats)
|
||||||
|
{
|
||||||
|
vseqstats(seqname) += seqcnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_inst(inst: Inst) =
|
||||||
|
{
|
||||||
|
if (progsegs.length == 0)
|
||||||
|
progsegs += ProgSeg()
|
||||||
|
|
||||||
|
progsegs.last.insts += inst
|
||||||
|
|
||||||
|
val branch_filter = (x: Operand) =>
|
||||||
|
x.isInstanceOf[Label] && x.asInstanceOf[Label].label.indexOf("branch_patch") != -1
|
||||||
|
val branch_patch = inst.operands.indexWhere(branch_filter)
|
||||||
|
if (branch_patch != -1)
|
||||||
|
{
|
||||||
|
progsegs.last.insts += ILLEGAL(Label("0x%08x" format rand_word))
|
||||||
|
progsegs += ProgSeg()
|
||||||
|
inst.operands(branch_patch) = Label(progsegs.last.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
val jalr_filter = (x: Operand) =>
|
||||||
|
x.isInstanceOf[Label] && x.asInstanceOf[Label].label.indexOf("jalr_patch2") != -1
|
||||||
|
val jalr_patch = inst.operands.indexWhere(jalr_filter)
|
||||||
|
if (jalr_patch != -1)
|
||||||
|
{
|
||||||
|
progsegs.last.insts += ILLEGAL(Label("0x%08x" format rand_word))
|
||||||
|
progsegs += ProgSeg()
|
||||||
|
jalr_labels += Label(progsegs.last.name)
|
||||||
|
inst.operands(jalr_patch) = Imm(0)
|
||||||
|
}
|
||||||
|
update_stats(inst)
|
||||||
|
}
|
||||||
|
|
||||||
|
def resolve_jalr_las =
|
||||||
|
{
|
||||||
|
var jalr_count = 0
|
||||||
|
val jalr_la_filter = (x: Operand) =>
|
||||||
|
x.isInstanceOf[Label] && x.asInstanceOf[Label].label.indexOf("jalr_patch1") != -1
|
||||||
|
for (progseg <- progsegs)
|
||||||
|
{
|
||||||
|
for (inst <- progseg.insts)
|
||||||
|
{
|
||||||
|
val jalr_la_patch = inst.operands.indexWhere(jalr_la_filter)
|
||||||
|
if (jalr_la_patch != -1) {
|
||||||
|
inst.operands(jalr_la_patch) = jalr_labels(jalr_count)
|
||||||
|
jalr_count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def names = List("xmem","xbranch","xalu","fgen","fpmem","fax","fdiv","vec")
|
||||||
|
|
||||||
|
def code_body(seqnum: Int, mix: Map[String, Int], veccfg: Map[String, String], use_amo: Boolean, use_mul: Boolean, use_div: Boolean, segment: Boolean) =
|
||||||
|
{
|
||||||
|
val name_to_seq = Map(
|
||||||
|
"xmem" -> (() => new SeqMem(xregs, core_memory, use_amo)),
|
||||||
|
"xbranch" -> (() => new SeqBranch(xregs)),
|
||||||
|
"xalu" -> (() => new SeqALU(xregs, use_mul, use_div)), //true means use_divider, TODO: make better
|
||||||
|
"fgen" -> (() => new SeqFPU(fregs_s, fregs_d)),
|
||||||
|
"fpmem" -> (() => new SeqFPMem(xregs, fregs_s, fregs_d, core_memory)),
|
||||||
|
"fax" -> (() => new SeqFaX(xregs, fregs_s, fregs_d)),
|
||||||
|
"fdiv" -> (() => new SeqFDiv(fregs_s, fregs_d)),
|
||||||
|
"vec" -> (() => new SeqVec(xregs, vxregs, vpregs, vsregs, varegs, used_vl, veccfg)))
|
||||||
|
|
||||||
|
prob_tbl = new ArrayBuffer[(Int, () => InstSeq)]
|
||||||
|
nseqs = seqnum
|
||||||
|
|
||||||
|
for ((name, prob) <- mix)
|
||||||
|
prob_tbl += ((prob, name_to_seq(name)))
|
||||||
|
|
||||||
|
for (i <- 0 to nseqs-1) gen_seq()
|
||||||
|
|
||||||
|
if (segment) { progsegs += ProgSeg() }
|
||||||
|
while (!is_seqs_empty)
|
||||||
|
{
|
||||||
|
seqs_find_active()
|
||||||
|
|
||||||
|
while (!is_seqs_active_empty)
|
||||||
|
{
|
||||||
|
val seq = rand_pick(seqs_active)
|
||||||
|
if(segment) {
|
||||||
|
val inst = seq.next_inst()
|
||||||
|
val branch_filter = (x: Operand) =>
|
||||||
|
x.isInstanceOf[Label] && x.asInstanceOf[Label].label.indexOf("branch_patch") != -1
|
||||||
|
val branch_patch = inst.operands.indexWhere(branch_filter)
|
||||||
|
val jalr_filter1 = (x: Operand) =>
|
||||||
|
x.isInstanceOf[Label] && x.asInstanceOf[Label].label.indexOf("jalr_patch1") != -1
|
||||||
|
val jalr_patch1 = inst.operands.indexWhere(jalr_filter1)
|
||||||
|
val jalr_filter2 = (x: Operand) =>
|
||||||
|
x.isInstanceOf[Label] && x.asInstanceOf[Label].label.indexOf("jalr_patch2") != -1
|
||||||
|
val jalr_patch2 = inst.operands.indexWhere(jalr_filter2)
|
||||||
|
if (jalr_patch1 == -1 && branch_patch == -1 && jalr_patch2 == -1){
|
||||||
|
progsegs.last.insts += inst
|
||||||
|
update_stats(inst)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add_inst(seq.next_inst())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq.is_done)
|
||||||
|
{
|
||||||
|
seq.free_regs()
|
||||||
|
seqs_active -= seq
|
||||||
|
if (seq.isInstanceOf[SeqVec])
|
||||||
|
for (vinst <- seq.asInstanceOf[SeqVec].vinsts)
|
||||||
|
update_stats(vinst)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rand_range(0,99) < 10) seqs_find_active()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Final p_seg
|
||||||
|
progsegs.last.insts += J(Label("reg_dump"))
|
||||||
|
|
||||||
|
if(!segment) { resolve_jalr_las }
|
||||||
|
rand_permute(progsegs)
|
||||||
|
|
||||||
|
if (killed_seqs >= (nseqs*5))
|
||||||
|
{
|
||||||
|
println("Warning: Prog killed an excessive number of sequences. (#X=%d, #Fs=%d, #Fd=%d, #VX=%d, #VP=%d, #VS=%d, #VA=%d)" format (xregs.size, fregs_s.size, fregs_d.size, vxregs.size, vpregs.size, vsregs.size, varegs.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
("" /: progsegs)(_ + _) + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def header(nseqs: Int) =
|
||||||
|
{
|
||||||
|
"// random assembly code generated by RISC-V torture test generator\n" +
|
||||||
|
"// nseqs = " + nseqs + "\n" +
|
||||||
|
"// memsize = " + memsize + "\n" +
|
||||||
|
"\n" +
|
||||||
|
"#include \"riscv_test.h\"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def code_header(using_fpu: Boolean, using_vec: Boolean, fprnd: Int) =
|
||||||
|
{
|
||||||
|
"\n" +
|
||||||
|
(if (using_vec) "RVTEST_RV64UV\n"
|
||||||
|
else if (using_fpu) "RVTEST_RV64UF\n"
|
||||||
|
else "RVTEST_RV32M\n") +
|
||||||
|
"RVTEST_CODE_BEGIN\n" +
|
||||||
|
(if (using_vec) init_vector() else "") +
|
||||||
|
"\n" +
|
||||||
|
"\tj test_start\n" +
|
||||||
|
"\n" +
|
||||||
|
"crash_backward:\n" +
|
||||||
|
"\tRVTEST_FAIL\n" +
|
||||||
|
"\n" +
|
||||||
|
"test_start:\n" +
|
||||||
|
"\n" +
|
||||||
|
// fregs must be initialized before xregs!
|
||||||
|
(if (using_fpu) fregs.init_regs() else "") +
|
||||||
|
(if (using_vec) vregs.init_regs() else "") +
|
||||||
|
xregs.init_regs() +
|
||||||
|
"\tj pseg_0\n" +
|
||||||
|
"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def init_vector() =
|
||||||
|
{
|
||||||
|
"\n" +
|
||||||
|
"\tli x1, " + used_vl + "\n" +
|
||||||
|
"\tvsetcfg " + num_vxregs + ", " + num_vpregs + "\n" +
|
||||||
|
"\tvsetvl x1,x1\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def code_footer(using_fpu: Boolean, using_vec: Boolean, loop: Boolean) =
|
||||||
|
{
|
||||||
|
var s = "reg_dump:\n" +
|
||||||
|
{
|
||||||
|
if(loop){
|
||||||
|
"\tla x1, loop_count\n" +
|
||||||
|
"\tlw x2, 0(x1)\n" +
|
||||||
|
"\taddi x3, x2, -1\n" +
|
||||||
|
"\tsw x3, 0(x1)\n" +
|
||||||
|
"\tbnez x2, pseg_0\n"
|
||||||
|
} else {""}
|
||||||
|
} +
|
||||||
|
// fregs must be saved after xregs
|
||||||
|
xregs.save_regs() +
|
||||||
|
(if(using_fpu) fregs.save_regs() else "") +
|
||||||
|
(if(using_vec) vregs.save_regs() else "") +
|
||||||
|
"\tj test_end\n" +
|
||||||
|
"\n" +
|
||||||
|
"crash_forward:\n" +
|
||||||
|
"\tRVTEST_FAIL\n" +
|
||||||
|
"\n" +
|
||||||
|
"test_end:\n" +
|
||||||
|
"\tRVTEST_PASS\n" +
|
||||||
|
"\n" +
|
||||||
|
"RVTEST_CODE_END\n" +
|
||||||
|
"\n"
|
||||||
|
for(seq <- seqs.filter(_.is_done))
|
||||||
|
{
|
||||||
|
val ns = seq.extra_code.mkString("\n")
|
||||||
|
if(ns.nonEmpty) s += "// extra code for " + seq + "\n" +
|
||||||
|
"\t.align 3\n" + ns + "\n"
|
||||||
|
}
|
||||||
|
s += "\n"
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def data_header() =
|
||||||
|
{
|
||||||
|
"\t.data\n" +
|
||||||
|
"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def output_mem_data(loop_size: Int) =
|
||||||
|
{
|
||||||
|
var s = "// Memory Blocks\n"
|
||||||
|
s += MemDump(core_memory)
|
||||||
|
s += "\n"
|
||||||
|
s += ".align 8\n"
|
||||||
|
s += "loop_count: .word 0x" + Integer.toHexString(loop_size) + "\n\n"
|
||||||
|
for(seq <- seqs.filter(_.is_done))
|
||||||
|
{
|
||||||
|
val ns = seq.extra_visible_data.mkString("\n")
|
||||||
|
if(ns.nonEmpty) s += "// output data for " + seq + "\n" + ns + "\n"
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def data_input(using_fpu: Boolean, using_vec: Boolean) =
|
||||||
|
{
|
||||||
|
var s = "hidden_data:\n"
|
||||||
|
for(seq <- seqs.filter(_.is_done))
|
||||||
|
{
|
||||||
|
val ns = seq.extra_hidden_data.mkString("\n")
|
||||||
|
if(ns.nonEmpty) s += "// hidden data for " + seq + "\n" + ns + "\n"
|
||||||
|
}
|
||||||
|
s += xregs.init_regs_data()
|
||||||
|
s += (if(using_fpu) fregs.init_regs_data() else "")
|
||||||
|
s += (if(using_vec) vregs.init_regs_data() else "")
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
def data_output(using_fpu: Boolean, using_vec: Boolean, loop_size: Int) =
|
||||||
|
{
|
||||||
|
"RVTEST_DATA_BEGIN\n" +
|
||||||
|
"\n" +
|
||||||
|
xregs.output_regs_data() +
|
||||||
|
(if(using_fpu) fregs.output_regs_data() else "") +
|
||||||
|
(if(using_vec) vregs.output_regs_data() else "") +
|
||||||
|
output_mem_data(loop_size) +
|
||||||
|
"RVTEST_DATA_END\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
def data_footer() = ""
|
||||||
|
|
||||||
|
def generate(nseqs: Int, fprnd: Int, mix: Map[String, Int], veccfg: Map[String, String], use_amo: Boolean, use_mul: Boolean, use_div: Boolean, segment : Boolean, loop: Boolean, loop_size: Int) =
|
||||||
|
{
|
||||||
|
// Check if generating any FP operations or Vec unit stuff
|
||||||
|
val using_vec = mix.filterKeys(List("vec") contains _).values.reduce(_+_) > 0
|
||||||
|
val using_fpu = (mix.filterKeys(List("fgen","fpmem","fax","fdiv") contains _).values.reduce(_+_) > 0) || using_vec
|
||||||
|
// TODO: make a config object that is passed around?
|
||||||
|
|
||||||
|
header(nseqs) +
|
||||||
|
code_header(using_fpu, using_vec, fprnd) +
|
||||||
|
code_body(nseqs, mix, veccfg, use_amo, use_mul, use_div, segment) +
|
||||||
|
code_footer(using_fpu, using_vec, loop) +
|
||||||
|
data_header() +
|
||||||
|
data_input(using_fpu, using_vec) +
|
||||||
|
data_output(using_fpu, using_vec, loop_size) +
|
||||||
|
data_footer()
|
||||||
|
}
|
||||||
|
|
||||||
|
def statistics(nseqs: Int, fprnd: Int, mix: Map[String, Int], vnseq: Int, vmemsize: Int, vfnum: Int, vecmix: Map[String, Int],
|
||||||
|
use_amo: Boolean, use_mul: Boolean, use_div: Boolean) =
|
||||||
|
{
|
||||||
|
"--------------------------------------------------------------------------\n" +
|
||||||
|
"-- Statistics for assembly code created by RISCV torture test generator --\n" +
|
||||||
|
get_time() +
|
||||||
|
"--------------------------------------------------------------------------\n" +
|
||||||
|
"---------- instcnt = " + instcnt + " -------------\n" +
|
||||||
|
"---------- nseqs = " + nseqs + " -------------\n" +
|
||||||
|
"---------- memsize = " + memsize + " ----------\n" +
|
||||||
|
"---------- vnseq = " + vnseq + " ----------\n" +
|
||||||
|
"---------- vfnum = " + vfnum + " ----------\n" +
|
||||||
|
"---------- vmemsize = " + vmemsize + " ----------\n" +
|
||||||
|
"---------- fprnd = " + fprnd + " ----------\n" +
|
||||||
|
"---------- use_amo = " + use_amo + " ----------\n" +
|
||||||
|
"---------- use_mul = " + use_mul + " ----------\n" +
|
||||||
|
"---------- use_div = " + use_div + " ----------\n" +
|
||||||
|
"--------------------------------------------------------------------------\n\n" +
|
||||||
|
"--------------------------------------------------------------------------\n" +
|
||||||
|
sequence_stats(mix, vecmix, nseqs, vnseq, vfnum) +
|
||||||
|
"--------------------------------------------------------------------------\n\n" +
|
||||||
|
"--------------------------------------------------------------------------\n" +
|
||||||
|
instruction_stats() +
|
||||||
|
"--------------------------------------------------------------------------\n\n" +
|
||||||
|
"--------------------------------------------------------------------------\n" +
|
||||||
|
register_stats() +
|
||||||
|
"--------------------------------------------------------------------------\n"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
object Rand
|
||||||
|
{
|
||||||
|
def rand_word: Int = Random.nextInt
|
||||||
|
def rand_dword: Long = Random.nextLong
|
||||||
|
|
||||||
|
def rand_range(low: Int, high: Int): Int =
|
||||||
|
{
|
||||||
|
var span = high - low + 1
|
||||||
|
if (low > high) span = low - high + 1
|
||||||
|
low + Random.nextInt(span)
|
||||||
|
}
|
||||||
|
|
||||||
|
def rand_shamt() = rand_range(0, 31)
|
||||||
|
def rand_shamtw() = rand_range(0, 31)
|
||||||
|
def rand_seglen() = rand_range(0, 7)
|
||||||
|
def rand_imm() = rand_range(-2048, 2047)
|
||||||
|
def rand_bigimm() = rand_range(0, 1048575)
|
||||||
|
|
||||||
|
def rand_addr_b(memsize: Int) = rand_range(0, memsize-1)
|
||||||
|
def rand_addr_h(memsize: Int) = rand_range(0, memsize-1) & ~1
|
||||||
|
def rand_addr_w(memsize: Int) = rand_range(0, memsize-1) & ~3
|
||||||
|
def rand_addr_d(memsize: Int) = rand_range(0, memsize-1) & ~7
|
||||||
|
|
||||||
|
def rand_filter(rand: () => Int, filter: (Int) => Boolean) =
|
||||||
|
{
|
||||||
|
var res = rand()
|
||||||
|
while (!filter(res)) res = rand()
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
def rand_pick[T](array: ArrayBuffer[T]) =
|
||||||
|
{
|
||||||
|
array(rand_range(0, array.length-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
def rand_permute[T](array: ArrayBuffer[T]) =
|
||||||
|
{
|
||||||
|
for (i <- 0 to array.length-1)
|
||||||
|
{
|
||||||
|
val j = rand_range(0, array.length-1)
|
||||||
|
val t = array(i)
|
||||||
|
array(i) = array(j)
|
||||||
|
array(j) = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def rand_biased: Long =
|
||||||
|
{
|
||||||
|
val value = rand_dword
|
||||||
|
val s = rand_range(0, 17)
|
||||||
|
|
||||||
|
if (s < 9)
|
||||||
|
{
|
||||||
|
val small = rand_range(0, 9).toLong
|
||||||
|
|
||||||
|
s match
|
||||||
|
{
|
||||||
|
// return a value with a single bit set
|
||||||
|
case 0 => (1 << value & 63)
|
||||||
|
case 1 => (1 << value & 63)
|
||||||
|
// return a valueue with a single bit clear
|
||||||
|
case 2 => ~(1 << value & 63)
|
||||||
|
case 3 => ~(1 << value & 63)
|
||||||
|
// return a small integer around zero
|
||||||
|
case 4 => small
|
||||||
|
// return a very large/very small 8b signed number
|
||||||
|
case 5 => ((0x80L + small) << 56) >> 56
|
||||||
|
// return a very large/very small 16b signed number
|
||||||
|
case 6 => ((0x8000L + small) << 48) >> 48
|
||||||
|
// return a very large/very small 32b signed number
|
||||||
|
case 7 => ((0x80000000L + small) << 32) >> 32
|
||||||
|
// return a very large/very small 64b signed number
|
||||||
|
case 8 => 0x800000000000000L + small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqALU(xregs: HWRegPool, use_mul: Boolean, use_div: Boolean) extends InstSeq //TODO: better configuration
|
||||||
|
{
|
||||||
|
override val seqname = "xalu"
|
||||||
|
def seq_immfn(op: Opcode, immfn: () => Int) = () =>
|
||||||
|
{
|
||||||
|
val dest = reg_write_visible(xregs)
|
||||||
|
val imm = Imm(immfn())
|
||||||
|
insts += op(dest, imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src1(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(xregs)
|
||||||
|
val dest = reg_write(xregs, src1)
|
||||||
|
insts += op(dest, src1, src1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src1_immfn(op: Opcode, immfn: () => Int) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(xregs)
|
||||||
|
val dest = reg_write(xregs, src1)
|
||||||
|
val imm = Imm(immfn())
|
||||||
|
insts += op(dest, src1, imm)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src1_zero(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(xregs)
|
||||||
|
val dest = reg_write(xregs, src1)
|
||||||
|
val tmp = reg_write_visible(xregs)
|
||||||
|
insts += ADDI(tmp, reg_read_zero(xregs), Imm(rand_imm()))
|
||||||
|
insts += op(dest, tmp, tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(xregs)
|
||||||
|
val src2 = reg_read_any(xregs)
|
||||||
|
val dest = reg_write(xregs, src1, src2)
|
||||||
|
insts += op(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2_zero(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(xregs)
|
||||||
|
val dest = reg_write(xregs, src1)
|
||||||
|
val tmp1 = reg_write_visible(xregs)
|
||||||
|
val tmp2 = reg_write_visible(xregs)
|
||||||
|
insts += ADDI(tmp1, reg_read_zero(xregs), Imm(rand_imm()))
|
||||||
|
insts += ADDI(tmp2, reg_read_zero(xregs), Imm(rand_imm()))
|
||||||
|
insts += op(dest, tmp1, tmp2)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
candidates += seq_immfn(LUI, rand_bigimm)
|
||||||
|
candidates += seq_src1_immfn(ADDI, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(SLLI, rand_shamt)
|
||||||
|
candidates += seq_src1_immfn(SLTI, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(SLTIU, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(XORI, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(SRLI, rand_shamt)
|
||||||
|
candidates += seq_src1_immfn(SRAI, rand_shamt)
|
||||||
|
candidates += seq_src1_immfn(ORI, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(ANDI, rand_imm)
|
||||||
|
//candidates += seq_src1_immfn(ADDIW, rand_imm)
|
||||||
|
//candidates += seq_src1_immfn(SLLIW, rand_shamtw)
|
||||||
|
//candidates += seq_src1_immfn(SRLIW, rand_shamtw)
|
||||||
|
//candidates += seq_src1_immfn(SRAIW, rand_shamtw)
|
||||||
|
|
||||||
|
val oplist = new ArrayBuffer[Opcode]
|
||||||
|
|
||||||
|
oplist += (ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND)
|
||||||
|
//oplist += (ADDW, SUBW, SLLW, SRLW, SRAW)
|
||||||
|
if (use_mul) oplist += (MUL, MULH, MULHSU, MULHU)
|
||||||
|
if (use_div) oplist += (DIV, DIVU, REM, REMU)
|
||||||
|
|
||||||
|
for (op <- oplist)
|
||||||
|
{
|
||||||
|
candidates += seq_src1(op)
|
||||||
|
candidates += seq_src1_zero(op)
|
||||||
|
candidates += seq_src2(op)
|
||||||
|
candidates += seq_src2_zero(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqBranch(xregs: HWRegPool) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "xbranch"
|
||||||
|
val taken = Label("__needs_branch_patch")
|
||||||
|
val nottakens = ArrayBuffer[Label](Label("crash_backward"), Label("crash_forward"))
|
||||||
|
val nottaken = rand_pick(nottakens)
|
||||||
|
def reverse_label(l: Label) = if(l == taken) nottaken else taken
|
||||||
|
|
||||||
|
def helper_two_srcs_sameval_samereg_any() = () =>
|
||||||
|
{
|
||||||
|
val reg_src = reg_read_any(xregs)
|
||||||
|
(reg_src, reg_src)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_sameval_samereg_zero() = () =>
|
||||||
|
{
|
||||||
|
val reg_src = reg_read_zero(xregs)
|
||||||
|
(reg_src, reg_src)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_sameval_diffreg_any() = () =>
|
||||||
|
{
|
||||||
|
val reg_src = reg_read_any(xregs)
|
||||||
|
val reg_dst1 = reg_write(xregs, reg_src)
|
||||||
|
val reg_dst2 = reg_write(xregs, reg_dst1)
|
||||||
|
insts += ADDI(reg_dst1, reg_src, Imm(0))
|
||||||
|
insts += ADDI(reg_dst2, reg_dst1, Imm(0))
|
||||||
|
(reg_dst1, reg_dst2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_sameval_diffreg_zero() = () =>
|
||||||
|
{
|
||||||
|
val reg_dst1 = reg_write_visible(xregs)
|
||||||
|
val reg_dst2 = reg_write(xregs)
|
||||||
|
insts += ADDI(reg_dst1, reg_read_zero(xregs), Imm(0))
|
||||||
|
insts += ADDI(reg_dst2, reg_read_zero(xregs), Imm(0))
|
||||||
|
(reg_dst1, reg_dst2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_diffval_diffreg_bothpos() = () =>
|
||||||
|
{
|
||||||
|
val reg_dst1 = reg_write_visible(xregs)
|
||||||
|
val reg_dst2 = reg_write(xregs, reg_dst1)
|
||||||
|
|
||||||
|
insts += ADDI(reg_dst1, reg_read_zero(xregs), Imm(rand_filter(rand_imm, (x) => x > 0)))
|
||||||
|
insts += ADDI(reg_dst2, reg_dst1, Imm(rand_filter(rand_imm, (x) => x > 0)))
|
||||||
|
|
||||||
|
// signed (+, ++), unsigned (+, ++)
|
||||||
|
(reg_dst1, reg_dst2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_diffval_diffreg_bothneg() = () =>
|
||||||
|
{
|
||||||
|
val reg_dst1 = reg_write_visible(xregs)
|
||||||
|
val reg_dst2 = reg_write(xregs, reg_dst1)
|
||||||
|
|
||||||
|
insts += ADDI(reg_dst1, reg_read_zero(xregs), Imm(rand_filter(rand_imm, (x) => x < 0)))
|
||||||
|
insts += ADDI(reg_dst2, reg_dst1, Imm(rand_filter(rand_imm, (x) => x < 0)))
|
||||||
|
|
||||||
|
// signed (-, --), unsigned (++++, +++)
|
||||||
|
(reg_dst1, reg_dst2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_sameval_diffreg_oppositesign() = () =>
|
||||||
|
{
|
||||||
|
val reg_src = reg_read_any(xregs)
|
||||||
|
val reg_dst1 = reg_write(xregs, reg_src)
|
||||||
|
val reg_dst2 = reg_write(xregs, reg_src)
|
||||||
|
val reg_one = reg_write_visible(xregs)
|
||||||
|
val reg_mask = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
|
||||||
|
insts += SLL(reg_one, reg_one, Imm(31))
|
||||||
|
insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
|
||||||
|
insts += XOR(reg_mask, reg_mask, reg_one)
|
||||||
|
insts += AND(reg_dst1, reg_src, reg_mask)
|
||||||
|
insts += OR(reg_dst2, reg_dst1, reg_one)
|
||||||
|
|
||||||
|
// reg_dest1 sign bit 0, reg_dest2 sign bit 1
|
||||||
|
(reg_dst1, reg_dst2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def helper_two_srcs_diffval_diffreg_oppositesign() = () =>
|
||||||
|
{
|
||||||
|
val reg_src1 = reg_read_any(xregs)
|
||||||
|
val reg_src2 = reg_read_any(xregs)
|
||||||
|
val reg_dst1 = reg_write(xregs, reg_src1)
|
||||||
|
val reg_dst2 = reg_write(xregs, reg_src2)
|
||||||
|
val reg_one = reg_write_visible(xregs)
|
||||||
|
val reg_mask = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
|
||||||
|
insts += SLL(reg_one, reg_one, Imm(31))
|
||||||
|
insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
|
||||||
|
insts += XOR(reg_mask, reg_mask, reg_one)
|
||||||
|
insts += AND(reg_dst1, reg_src1, reg_mask)
|
||||||
|
insts += OR(reg_dst2, reg_src2, reg_one)
|
||||||
|
|
||||||
|
// reg_dest1 sign bit 0, reg_dest2 sign bit 1
|
||||||
|
(reg_dst1, reg_dst2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_taken_j() = () =>
|
||||||
|
{
|
||||||
|
insts += J(taken)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_taken_jal() = () =>
|
||||||
|
{
|
||||||
|
val reg_x1 = reg_write_ra(xregs)
|
||||||
|
insts += JAL(taken)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_taken_jalr() = () =>
|
||||||
|
{
|
||||||
|
val reg_x1 = reg_write_ra(xregs)
|
||||||
|
val reg_src1 = reg_read_zero(xregs)
|
||||||
|
val reg_dst1 = reg_write_hidden(xregs)
|
||||||
|
val reg_dst2 = reg_write_hidden(xregs)
|
||||||
|
|
||||||
|
insts += LA(reg_dst1, Label("__needs_jalr_patch1"))
|
||||||
|
insts += JALR(reg_dst2, reg_dst1, Label("__needs_jalr_patch2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_two_regs_and_branch_with_label( op: Opcode, helper: () => (Operand, Operand), label: Label, flip_ops:Boolean = false) = () =>
|
||||||
|
{
|
||||||
|
val regs = helper()
|
||||||
|
if(!flip_ops) insts += op(regs._1, regs._2, label) else insts += op(regs._2, regs._1, label)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These tests have the same labels if the operand order is reversed
|
||||||
|
val reversible_tests = List(
|
||||||
|
(BEQ, helper_two_srcs_sameval_samereg_any, taken),
|
||||||
|
(BEQ, helper_two_srcs_sameval_samereg_zero, taken),
|
||||||
|
(BEQ, helper_two_srcs_sameval_diffreg_any, taken),
|
||||||
|
(BEQ, helper_two_srcs_sameval_diffreg_zero, taken),
|
||||||
|
(BEQ, helper_two_srcs_diffval_diffreg_bothpos, nottaken),
|
||||||
|
(BEQ, helper_two_srcs_diffval_diffreg_bothneg, nottaken),
|
||||||
|
(BEQ, helper_two_srcs_sameval_diffreg_oppositesign, nottaken),
|
||||||
|
(BEQ, helper_two_srcs_diffval_diffreg_oppositesign, nottaken),
|
||||||
|
(BNE, helper_two_srcs_sameval_samereg_any, nottaken),
|
||||||
|
(BNE, helper_two_srcs_sameval_samereg_zero, nottaken),
|
||||||
|
(BNE, helper_two_srcs_sameval_diffreg_any, nottaken),
|
||||||
|
(BNE, helper_two_srcs_sameval_diffreg_zero, nottaken),
|
||||||
|
(BNE, helper_two_srcs_diffval_diffreg_bothpos, taken),
|
||||||
|
(BNE, helper_two_srcs_diffval_diffreg_bothneg, taken),
|
||||||
|
(BNE, helper_two_srcs_sameval_diffreg_oppositesign, taken),
|
||||||
|
(BNE, helper_two_srcs_diffval_diffreg_oppositesign, taken),
|
||||||
|
(BLT, helper_two_srcs_sameval_samereg_any, nottaken),
|
||||||
|
(BLT, helper_two_srcs_sameval_samereg_zero, nottaken),
|
||||||
|
(BLT, helper_two_srcs_sameval_diffreg_any, nottaken),
|
||||||
|
(BLT, helper_two_srcs_sameval_diffreg_zero, nottaken),
|
||||||
|
(BLTU, helper_two_srcs_sameval_samereg_any, nottaken),
|
||||||
|
(BLTU, helper_two_srcs_sameval_samereg_zero, nottaken),
|
||||||
|
(BLTU, helper_two_srcs_sameval_diffreg_any, nottaken),
|
||||||
|
(BLTU, helper_two_srcs_sameval_diffreg_zero, nottaken),
|
||||||
|
(BGE, helper_two_srcs_sameval_samereg_any, taken),
|
||||||
|
(BGE, helper_two_srcs_sameval_samereg_zero, taken),
|
||||||
|
(BGE, helper_two_srcs_sameval_diffreg_any, taken),
|
||||||
|
(BGE, helper_two_srcs_sameval_diffreg_zero, taken),
|
||||||
|
(BGEU, helper_two_srcs_sameval_samereg_any, taken),
|
||||||
|
(BGEU, helper_two_srcs_sameval_samereg_zero, taken),
|
||||||
|
(BGEU, helper_two_srcs_sameval_diffreg_any, taken),
|
||||||
|
(BGEU, helper_two_srcs_sameval_diffreg_zero, taken)
|
||||||
|
)
|
||||||
|
|
||||||
|
// These tests need opposite labels if the operand order is reversed
|
||||||
|
val chiral_tests = List(
|
||||||
|
(BLT, helper_two_srcs_diffval_diffreg_bothpos, taken),
|
||||||
|
(BLT, helper_two_srcs_diffval_diffreg_bothneg, nottaken),
|
||||||
|
(BLT, helper_two_srcs_sameval_diffreg_oppositesign, nottaken),
|
||||||
|
(BLT, helper_two_srcs_diffval_diffreg_oppositesign, nottaken),
|
||||||
|
(BLTU, helper_two_srcs_diffval_diffreg_bothpos, taken),
|
||||||
|
(BLTU, helper_two_srcs_diffval_diffreg_bothneg, nottaken),
|
||||||
|
(BLTU, helper_two_srcs_sameval_diffreg_oppositesign, taken),
|
||||||
|
(BLTU, helper_two_srcs_diffval_diffreg_oppositesign, taken),
|
||||||
|
(BGE, helper_two_srcs_diffval_diffreg_bothpos, nottaken),
|
||||||
|
(BGE, helper_two_srcs_diffval_diffreg_bothneg, taken),
|
||||||
|
(BGE, helper_two_srcs_sameval_diffreg_oppositesign, taken),
|
||||||
|
(BGE, helper_two_srcs_diffval_diffreg_oppositesign, taken),
|
||||||
|
(BGEU, helper_two_srcs_diffval_diffreg_bothpos, nottaken),
|
||||||
|
(BGEU, helper_two_srcs_diffval_diffreg_bothneg, taken),
|
||||||
|
(BGEU, helper_two_srcs_sameval_diffreg_oppositesign, nottaken),
|
||||||
|
(BGEU, helper_two_srcs_diffval_diffreg_oppositesign, nottaken)
|
||||||
|
)
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
candidates += seq_taken_j()
|
||||||
|
candidates += seq_taken_jal()
|
||||||
|
candidates += seq_taken_jalr()
|
||||||
|
|
||||||
|
reversible_tests.foreach( t => candidates += get_two_regs_and_branch_with_label(t._1, t._2, t._3, false))
|
||||||
|
chiral_tests.foreach( t => candidates += get_two_regs_and_branch_with_label(t._1, t._2, t._3, false))
|
||||||
|
chiral_tests.foreach( t => candidates += get_two_regs_and_branch_with_label(t._1, t._2, reverse_label(t._3), true))
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqFDiv(fregs_s: HWRegPool, fregs_d: HWRegPool) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "fdiv"
|
||||||
|
def seq_src1_s(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_s)
|
||||||
|
val dest = reg_write(fregs_s, src1)
|
||||||
|
insts += op(dest, src1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2_s(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_s)
|
||||||
|
val src2 = reg_read_any(fregs_s)
|
||||||
|
val dest = reg_write(fregs_s, src1, src2)
|
||||||
|
insts += op(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src1_d(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_d)
|
||||||
|
val dest = reg_write(fregs_d, src1)
|
||||||
|
insts += op(dest, src1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2_d(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_d)
|
||||||
|
val src2 = reg_read_any(fregs_d)
|
||||||
|
val dest = reg_write(fregs_d, src1, src2)
|
||||||
|
insts += op(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
candidates += seq_src1_s(FSQRT_S)
|
||||||
|
candidates += seq_src1_d(FSQRT_D)
|
||||||
|
candidates += seq_src2_s(FDIV_S)
|
||||||
|
candidates += seq_src2_d(FDIV_D)
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqFPMem(xregs: HWRegPool, fregs_s: HWRegPool, fregs_d: HWRegPool, mem: Mem) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "fpmem"
|
||||||
|
|
||||||
|
def seq_load_addrfn(op: Opcode, addrfn: (Int) => Int, fregpool: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_dest = reg_write_visible(fregpool)
|
||||||
|
val addr = addrfn(mem.size)
|
||||||
|
val imm = rand_imm()
|
||||||
|
insts += LA(reg_addr, BaseImm(mem.toString, addr-imm))
|
||||||
|
insts += op(reg_dest, RegImm(reg_addr, imm))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_store_addrfn(op: Opcode, addrfn: (Int) => Int, fregpool: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_src = reg_read_visible(fregpool)
|
||||||
|
val addr = addrfn(mem.size)
|
||||||
|
val imm = rand_imm()
|
||||||
|
insts += LA(reg_addr, BaseImm(mem.toString, addr-imm))
|
||||||
|
insts += op(reg_src, RegImm(reg_addr, imm))
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
candidates += seq_load_addrfn(FLW, rand_addr_w, fregs_s)
|
||||||
|
candidates += seq_store_addrfn(FSW, rand_addr_w, fregs_s)
|
||||||
|
candidates += seq_load_addrfn(FLD, rand_addr_d, fregs_d)
|
||||||
|
candidates += seq_store_addrfn(FSD, rand_addr_d, fregs_d)
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqFPU(fregs_s: HWRegPool, fregs_d: HWRegPool) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "fgen"
|
||||||
|
def seq_src1_s(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_s)
|
||||||
|
val dest = reg_write(fregs_s, src1)
|
||||||
|
insts += op(dest, src1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2_s(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_s)
|
||||||
|
val src2 = reg_read_any(fregs_s)
|
||||||
|
val dest = reg_write(fregs_s, src1, src2)
|
||||||
|
insts += op(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src3_s(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_s)
|
||||||
|
val src2 = reg_read_any(fregs_s)
|
||||||
|
val src3 = reg_read_any(fregs_s)
|
||||||
|
val dest = reg_write(fregs_s, src1, src2, src3)
|
||||||
|
insts += op(dest, src1, src2, src3)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src1_d(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_d)
|
||||||
|
val dest = reg_write(fregs_d, src1)
|
||||||
|
insts += op(dest, src1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2_d(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_d)
|
||||||
|
val src2 = reg_read_any(fregs_d)
|
||||||
|
val dest = reg_write(fregs_d, src1, src2)
|
||||||
|
insts += op(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src3_d(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(fregs_d)
|
||||||
|
val src2 = reg_read_any(fregs_d)
|
||||||
|
val src3 = reg_read_any(fregs_d)
|
||||||
|
val dest = reg_write(fregs_d, src1, src2, src3)
|
||||||
|
insts += op(dest, src1, src2, src3)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
for (op <- List(FADD_S, FSUB_S, FMUL_S, FMIN_S, FMAX_S))
|
||||||
|
candidates += seq_src2_s(op)
|
||||||
|
|
||||||
|
for (op <- List(FADD_D, FSUB_D, FMUL_D, FMIN_D, FMAX_D))
|
||||||
|
candidates += seq_src2_d(op)
|
||||||
|
|
||||||
|
for (op <- List(FMADD_S, FNMADD_S, FMSUB_S, FNMSUB_S))
|
||||||
|
candidates += seq_src3_s(op)
|
||||||
|
|
||||||
|
for (op <- List(FMADD_D, FNMADD_D, FMSUB_D, FNMSUB_D))
|
||||||
|
candidates += seq_src3_d(op)
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqFaX(xregs: HWRegPool, fregs_s: HWRegPool, fregs_d: HWRegPool) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "fax"
|
||||||
|
def seq_src1(op: Opcode, dst_pool: HWRegPool, src_pool: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(src_pool)
|
||||||
|
val dest = reg_write(dst_pool, src1)
|
||||||
|
insts += op(dest, src1)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2(op: Opcode, dst_pool: HWRegPool, src_pool: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(src_pool)
|
||||||
|
val src2 = reg_read_any(src_pool)
|
||||||
|
val dest = reg_write(dst_pool, src1, src2)
|
||||||
|
insts += op(dest, src1, src2)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
// Intra-FPU Instructions
|
||||||
|
candidates += seq_src1(FCVT_S_D, fregs_s, fregs_d)
|
||||||
|
candidates += seq_src1(FCVT_D_S, fregs_d, fregs_s)
|
||||||
|
|
||||||
|
for (op <- List(FSGNJ_S, FSGNJN_S, FSGNJX_S))
|
||||||
|
candidates += seq_src2(op, fregs_s, fregs_s)
|
||||||
|
|
||||||
|
for (op <- List(FSGNJ_D, FSGNJN_D, FSGNJX_D))
|
||||||
|
candidates += seq_src2(op, fregs_d, fregs_d)
|
||||||
|
|
||||||
|
// X<->F Instructions
|
||||||
|
for (op <- List(FCVT_S_L, FCVT_S_LU, FCVT_S_W, FCVT_S_WU, FMV_S_X))
|
||||||
|
candidates += seq_src1(op, fregs_s, xregs)
|
||||||
|
|
||||||
|
for (op <- List(FCVT_D_L, FCVT_D_LU, FCVT_D_W, FCVT_D_WU, FMV_D_X))
|
||||||
|
candidates += seq_src1(op, fregs_d, xregs)
|
||||||
|
|
||||||
|
for (op <- List(FCVT_L_S, FCVT_LU_S, FCVT_W_S, FCVT_WU_S, FMV_X_S))
|
||||||
|
candidates += seq_src1(op, xregs, fregs_s)
|
||||||
|
|
||||||
|
for (op <- List(FCVT_L_D, FCVT_LU_D, FCVT_W_D, FCVT_WU_D, FMV_X_D))
|
||||||
|
candidates += seq_src1(op, xregs, fregs_d)
|
||||||
|
|
||||||
|
for (op <- List(FEQ_S, FLT_S, FLE_S))
|
||||||
|
candidates += seq_src2(op, xregs, fregs_s)
|
||||||
|
|
||||||
|
for (op <- List(FEQ_D, FLT_D, FLE_D))
|
||||||
|
candidates += seq_src2(op, xregs, fregs_d)
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "xmem"
|
||||||
|
def seq_load_addrfn(op: Opcode, addrfn: (Int) => Int) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_dest = reg_write_visible(xregs)
|
||||||
|
val addr = addrfn(mem.size)
|
||||||
|
val imm = rand_imm()
|
||||||
|
|
||||||
|
insts += LA(reg_addr, BaseImm(mem.toString, addr-imm))
|
||||||
|
insts += op(reg_dest, RegImm(reg_addr, imm))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_store_addrfn(op: Opcode, addrfn: (Int) => Int) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_src = reg_read_visible(xregs)
|
||||||
|
val addr = addrfn(mem.size)
|
||||||
|
val imm = rand_imm()
|
||||||
|
|
||||||
|
insts += LA(reg_addr, BaseImm(mem.toString, addr-imm))
|
||||||
|
insts += op(reg_src, RegImm(reg_addr, imm))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_amo_addrfn(op: Opcode, addrfn: (Int) => Int) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_dest = reg_write_visible(xregs)
|
||||||
|
val reg_src = reg_read_visible(xregs)
|
||||||
|
val addr = addrfn(mem.size)
|
||||||
|
|
||||||
|
insts += LA(reg_addr, BaseImm(mem.toString, addr))
|
||||||
|
insts += op(reg_dest, reg_src, RegImm(reg_addr, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// test st and ld sequences in which the double-word addresses match
|
||||||
|
// but the lower-order bits may differ. Randomize whether the dependency
|
||||||
|
// is ld->st or st->ld.
|
||||||
|
def seq_stld_overlap() = () =>
|
||||||
|
{
|
||||||
|
object AccessType extends Enumeration
|
||||||
|
{
|
||||||
|
type AccessType = Value
|
||||||
|
val byte, ubyte, hword, uhword, word, uword, dword = Value
|
||||||
|
|
||||||
|
def getRandOpAndAddr (dw_addr: Int, is_store: Boolean): (Opcode, Int) =
|
||||||
|
{
|
||||||
|
val typ = AccessType.values.toIndexedSeq(rand_range(0,4))
|
||||||
|
if (is_store)
|
||||||
|
{
|
||||||
|
if (typ == byte || typ ==ubyte) (SB, dw_addr + rand_addr_b(8))
|
||||||
|
else if (typ == hword || typ ==uhword) (SH, dw_addr + rand_addr_h(8))
|
||||||
|
else if (typ == word || typ ==uword) (SW, dw_addr + rand_addr_w(8))
|
||||||
|
else (SD, dw_addr)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (typ == byte) (LB, dw_addr + rand_addr_b(8))
|
||||||
|
else if (typ == ubyte) (LBU, dw_addr + rand_addr_b(8))
|
||||||
|
else if (typ == hword) (LH, dw_addr + rand_addr_h(8))
|
||||||
|
else if (typ == uhword) (LHU, dw_addr + rand_addr_h(8))
|
||||||
|
else if (typ == word) (LW, dw_addr + rand_addr_w(8))
|
||||||
|
else if (typ == uword) (LWU, dw_addr + rand_addr_w(8))
|
||||||
|
else (LD, dw_addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
import AccessType._
|
||||||
|
|
||||||
|
val l_reg_addr = reg_write_hidden(xregs)
|
||||||
|
val s_reg_addr = reg_write_hidden(xregs)
|
||||||
|
val s_reg_src = reg_read_visible(xregs)
|
||||||
|
val l_reg_dest = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
val dw_addr = rand_addr_d(mem.size)
|
||||||
|
val s_imm = rand_imm()
|
||||||
|
val l_imm = rand_imm()
|
||||||
|
|
||||||
|
val (lop, l_addr) = AccessType.getRandOpAndAddr(dw_addr, is_store=false)
|
||||||
|
val (sop, s_addr) = AccessType.getRandOpAndAddr(dw_addr, is_store=true)
|
||||||
|
//println("dwaddr: " + dw_addr + ",sop: " + sop.name + ",lop: " + lop.name + " saddr: " + s_addr + ", laddr: " + l_addr)
|
||||||
|
|
||||||
|
insts += LA(l_reg_addr, BaseImm(mem.toString, l_addr-l_imm))
|
||||||
|
insts += LA(s_reg_addr, BaseImm(mem.toString, s_addr-s_imm))
|
||||||
|
if (math.random < 0.5)
|
||||||
|
{
|
||||||
|
insts += lop(l_reg_dest, RegImm(l_reg_addr, l_imm))
|
||||||
|
insts += sop(s_reg_src, RegImm(s_reg_addr, s_imm))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
insts += sop(s_reg_src, RegImm(s_reg_addr, s_imm))
|
||||||
|
insts += lop(l_reg_dest, RegImm(l_reg_addr, l_imm))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
candidates += seq_stld_overlap()
|
||||||
|
candidates += seq_stld_overlap()
|
||||||
|
|
||||||
|
candidates += seq_load_addrfn(LB, rand_addr_b)
|
||||||
|
candidates += seq_load_addrfn(LBU, rand_addr_b)
|
||||||
|
candidates += seq_load_addrfn(LH, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(LHU, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(LW, rand_addr_w)
|
||||||
|
//candidates += seq_load_addrfn(LWU, rand_addr_w)
|
||||||
|
//candidates += seq_load_addrfn(LD, rand_addr_d)
|
||||||
|
|
||||||
|
candidates += seq_store_addrfn(SB, rand_addr_b)
|
||||||
|
candidates += seq_store_addrfn(SH, rand_addr_h)
|
||||||
|
candidates += seq_store_addrfn(SW, rand_addr_w)
|
||||||
|
//candidates += seq_store_addrfn(SD, rand_addr_d)
|
||||||
|
|
||||||
|
if (use_amo)
|
||||||
|
{
|
||||||
|
candidates += seq_amo_addrfn(AMOADD_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOSWAP_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOAND_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOOR_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOMIN_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOMINU_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOMAX_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOMAXU_W, rand_addr_w)
|
||||||
|
candidates += seq_amo_addrfn(AMOADD_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOSWAP_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOAND_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOOR_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOMIN_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOMINU_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOMAX_D, rand_addr_d)
|
||||||
|
candidates += seq_amo_addrfn(AMOMAXU_D, rand_addr_d)
|
||||||
|
}
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import scala.collection.mutable.HashMap
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqSeq(vregs: HWRegPool, pregs: HWRegPool, def_preg: Reg, sregs: HWRegPool, aregs: HWRegPool, xregs: HWRegPool, mem: Mem, nseqs: Int, mixcfg: Map[String,Int], vl: Int, use_mul: Boolean, use_div: Boolean, use_mix: Boolean, use_fpu: Boolean, use_fma: Boolean, use_fcvt: Boolean, use_fdiv: Boolean, use_amo: Boolean, use_seg: Boolean, use_stride: Boolean, pred_alu: Boolean, pred_mem: Boolean) extends VFInstSeq
|
||||||
|
{
|
||||||
|
val seqs = new ArrayBuffer[VFInstSeq]
|
||||||
|
val seqs_active = new ArrayBuffer[VFInstSeq]
|
||||||
|
var killed_seqs = 0
|
||||||
|
val seqstats = new HashMap[String,Int].withDefaultValue(0)
|
||||||
|
|
||||||
|
def seqs_not_allocated = seqs.filter((x) => !x.allocated)
|
||||||
|
def is_seqs_empty = seqs_not_allocated.length == 0
|
||||||
|
def is_seqs_active_empty = seqs_active.length == 0
|
||||||
|
|
||||||
|
def are_pools_fully_unallocated = List(vregs, pregs, sregs).forall(_.is_fully_unallocated)
|
||||||
|
|
||||||
|
val name_to_seq = Map(
|
||||||
|
"vmem" -> (() => new SeqVMem(xregs, vregs, pregs, def_preg, sregs, aregs, mem.asInstanceOf[VMem], vl, use_amo,use_seg, use_stride, pred_mem)),
|
||||||
|
"valu" -> (() => new SeqVALU(vregs, pregs, def_preg, sregs, use_mul, use_div, use_mix, use_fpu, use_fma, use_fcvt, use_fdiv, pred_alu)), // TODO: Clean up
|
||||||
|
"vpop" -> (() => new SeqVPop(vregs, pregs, def_preg, sregs)),
|
||||||
|
"vonly" -> (() => new SeqVOnly(vregs, pregs, sregs)))
|
||||||
|
|
||||||
|
val prob_tbl = new ArrayBuffer[(Int, () => VFInstSeq)]
|
||||||
|
mixcfg foreach {case(name, prob) => (prob_tbl += ((prob, name_to_seq(name))))}
|
||||||
|
|
||||||
|
def gen_seq(): Unit =
|
||||||
|
{
|
||||||
|
val nxtseq = VFInstSeq(prob_tbl)
|
||||||
|
seqs += nxtseq
|
||||||
|
seqstats(nxtseq.seqname) += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
def seqs_find_active(): Unit =
|
||||||
|
{
|
||||||
|
for (seq <- seqs_not_allocated)
|
||||||
|
{
|
||||||
|
vregs.backup()
|
||||||
|
pregs.backup()
|
||||||
|
sregs.backup()
|
||||||
|
aregs.backup()
|
||||||
|
xregs.backup()
|
||||||
|
|
||||||
|
if (seq.allocate_regs())
|
||||||
|
{
|
||||||
|
seqs_active += seq
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vregs.restore()
|
||||||
|
pregs.restore()
|
||||||
|
sregs.restore()
|
||||||
|
aregs.restore()
|
||||||
|
xregs.restore()
|
||||||
|
// because the setup instructions for a vf seq are only run once we
|
||||||
|
// cannot free va or vs regs to be reused so we kill seqs that can be
|
||||||
|
// allocated
|
||||||
|
seqs -= seq
|
||||||
|
killed_seqs += 1
|
||||||
|
seqstats(seq.seqname) -= 1
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i <- 1 to nseqs) gen_seq()
|
||||||
|
|
||||||
|
while(!is_seqs_empty)
|
||||||
|
{
|
||||||
|
seqs_find_active()
|
||||||
|
|
||||||
|
while(!is_seqs_active_empty)
|
||||||
|
{
|
||||||
|
val seq = rand_pick(seqs_active)
|
||||||
|
if(seq.inst_left) insts += seq.next_inst()
|
||||||
|
if(seq.vinst_left) vinsts += seq.next_vinst()
|
||||||
|
|
||||||
|
if(seq.is_done) {
|
||||||
|
extra_hidden_data.appendAll(seq.extra_hidden_data)
|
||||||
|
seqs_active -= seq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(seq <- seqs) seq.free_regs()
|
||||||
|
|
||||||
|
if(killed_seqs >= (nseqs*5))
|
||||||
|
println("warning: a SeqSeq killed an excessive number of sequences. (#V=%d, #P=%d, #S=%d)" format (vregs.size, pregs.size, sregs.size))
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqVALU(vregs: HWRegPool, pregs: HWRegPool, def_preg: Reg, sregs: HWRegPool, use_mul: Boolean, use_div: Boolean, use_mix: Boolean, use_fpu: Boolean, use_fma: Boolean, use_fcvt: Boolean, use_fdiv: Boolean, use_pred: Boolean) extends VFInstSeq //TODO: better configuration
|
||||||
|
{
|
||||||
|
override val seqname = "valu"
|
||||||
|
val pred = if(use_pred) PredReg(reg_read_any(pregs), false)
|
||||||
|
else PredReg(def_preg, false)
|
||||||
|
|
||||||
|
def seq_src1(op: Opcode, dreg: HWRegPool, s1reg: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(s1reg)
|
||||||
|
val dest = reg_write(dreg, src1)
|
||||||
|
if(dreg == sregs) vinsts += op(dest, src1)
|
||||||
|
else vinsts += op(dest, src1, pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2(op: Opcode, dreg: HWRegPool, s1reg: HWRegPool, s2reg: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(s1reg)
|
||||||
|
val src2 = reg_read_any(s2reg)
|
||||||
|
val dest = reg_write(dreg, src1, src2)
|
||||||
|
if(dreg == sregs) vinsts += op(dest, src1, src2)
|
||||||
|
else vinsts += op(dest, src1, src2, pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src3(op: Opcode, dreg: HWRegPool, s1reg: HWRegPool, s2reg: HWRegPool, s3reg: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val src1 = reg_read_any(s1reg)
|
||||||
|
val src2 = reg_read_any(s2reg)
|
||||||
|
val src3 = reg_read_any(s3reg)
|
||||||
|
val dest = reg_write(dreg, src1, src2, src3)
|
||||||
|
if(dreg == sregs) vinsts += op(dest, src1, src2, src3)
|
||||||
|
else vinsts += op(dest, src1, src2, src3, pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => vinsts.type]
|
||||||
|
|
||||||
|
val oplist1 = new ArrayBuffer[Opcode]
|
||||||
|
val oplist2 = new ArrayBuffer[Opcode]
|
||||||
|
val oplist3 = new ArrayBuffer[Opcode]
|
||||||
|
|
||||||
|
oplist2 += (VADD, VSUB, VSLL, VXOR, VSRL, VSRA, VOR, VAND)
|
||||||
|
oplist2 += (VADDW, VSUBW, VSLLW, VSRLW, VSRAW)
|
||||||
|
if (use_mul) oplist2 += (VMUL, VMULH, VMULHSU, VMULHU, VMULW)
|
||||||
|
if (use_div) oplist2 += (VDIV, VDIVU, VREM, VREMU, VDIVW, VDIVUW, VREMW, VREMUW)
|
||||||
|
if (use_fpu)
|
||||||
|
{
|
||||||
|
oplist2 += (VFADD_S, VFSUB_S, VFMUL_S, VFMIN_S, VFMAX_S,
|
||||||
|
VFADD_D, VFSUB_D, VFMUL_D, VFMIN_D, VFMAX_D,
|
||||||
|
VFSGNJ_S, VFSGNJN_S, VFSGNJX_S, VFSGNJ_D, VFSGNJN_D, VFSGNJX_D)
|
||||||
|
if (use_fdiv)
|
||||||
|
{
|
||||||
|
oplist1 += (VFSQRT_S, VFSQRT_D)
|
||||||
|
oplist2 += (VFDIV_S, VFDIV_D)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (use_fma) oplist3 += (VFMADD_S, VFMSUB_S, VFNMSUB_S, VFNMADD_S,
|
||||||
|
VFMADD_D, VFMSUB_D, VFNMSUB_D, VFNMADD_D)
|
||||||
|
if (use_fcvt) oplist1 += (VFCVT_S_D, VFCVT_D_S, VFCVT_S_L, VFCVT_S_LU, VFCVT_S_W,
|
||||||
|
VFCVT_S_WU, VFCVT_D_L, VFCVT_D_LU, VFCVT_D_W, VFCVT_D_WU, VFCVT_L_S,
|
||||||
|
VFCVT_LU_S, VFCVT_W_S, VFCVT_WU_S, VFCVT_L_D, VFCVT_LU_D,
|
||||||
|
VFCVT_W_D, VFCVT_WU_D)
|
||||||
|
|
||||||
|
for (op <- oplist1)
|
||||||
|
{
|
||||||
|
candidates += seq_src1(op,vregs,vregs)
|
||||||
|
candidates += seq_src1(op,sregs,sregs)
|
||||||
|
|
||||||
|
if (use_mix)
|
||||||
|
{
|
||||||
|
candidates += seq_src1(op,vregs,sregs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (op <- oplist2)
|
||||||
|
{
|
||||||
|
candidates += seq_src2(op,vregs,vregs,vregs)
|
||||||
|
candidates += seq_src2(op,sregs,sregs,sregs)
|
||||||
|
|
||||||
|
if (use_mix)
|
||||||
|
{
|
||||||
|
candidates += seq_src2(op,vregs,vregs,sregs)
|
||||||
|
candidates += seq_src2(op,vregs,sregs,vregs)
|
||||||
|
candidates += seq_src2(op,vregs,sregs,sregs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (op <- oplist3)
|
||||||
|
{
|
||||||
|
candidates += seq_src3(op,vregs,vregs,vregs,vregs)
|
||||||
|
candidates += seq_src3(op,sregs,sregs,sregs,sregs)
|
||||||
|
|
||||||
|
if (use_mix)
|
||||||
|
{
|
||||||
|
candidates += seq_src3(op,vregs,vregs,vregs,sregs)
|
||||||
|
candidates += seq_src3(op,vregs,vregs,sregs,vregs)
|
||||||
|
candidates += seq_src3(op,vregs,vregs,sregs,sregs)
|
||||||
|
candidates += seq_src3(op,vregs,sregs,vregs,sregs)
|
||||||
|
candidates += seq_src3(op,vregs,sregs,sregs,vregs)
|
||||||
|
candidates += seq_src3(op,vregs,sregs,sregs,sregs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
object SeqVMem
|
||||||
|
{
|
||||||
|
var cnt = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class SeqVMem(xregs: HWRegPool, vregs: HWRegPool, pregs: HWRegPool, def_preg: Reg, sregs:HWRegPool, aregs: HWRegPool, mem: VMem, vl: Int, use_amo: Boolean, use_seg: Boolean, use_stride: Boolean, use_pred: Boolean) extends VFInstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "vmem_" + SeqVMem.cnt
|
||||||
|
SeqVMem.cnt += 1
|
||||||
|
val pred = if(use_pred) PredReg(reg_read_any(pregs), false)
|
||||||
|
else PredReg(def_preg, false)
|
||||||
|
|
||||||
|
def helper_setup_address(reg_addr: Reg, reg_vaddr: Reg, m: Mem, baseaddr: Int, reg_vstride: Option[Reg] = None, stride: Int = 0) =
|
||||||
|
{
|
||||||
|
insts += LA(reg_addr, BaseImm(m.toString, baseaddr))
|
||||||
|
insts += VMCA(reg_vaddr, reg_addr)
|
||||||
|
reg_vstride match {
|
||||||
|
case Some(reg) =>
|
||||||
|
{
|
||||||
|
insts += LI(reg_addr, Imm(stride))
|
||||||
|
insts += VMCA(reg, reg_addr)
|
||||||
|
}
|
||||||
|
case None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def helper_setup_scalar(reg_addr: Reg, reg_vaddr: Reg, m: Mem, baseaddr: Int, reg_vstride: Option[Reg] = None, stride: Int = 0) =
|
||||||
|
{
|
||||||
|
insts += LA(reg_addr, BaseImm(m.toString, baseaddr))
|
||||||
|
insts += VMCS(reg_vaddr, reg_addr)
|
||||||
|
reg_vstride match {
|
||||||
|
case Some(reg) =>
|
||||||
|
{
|
||||||
|
insts += LI(reg_addr, Imm(stride))
|
||||||
|
insts += VMCS(reg, reg_addr)
|
||||||
|
}
|
||||||
|
case None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_load_addrfn(op: Opcode, addrfn: (Int) => Int, seg: Option[Int] = None, stride: Option[Reg] = None) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_vaddr = reg_write_hidden(aregs)
|
||||||
|
val reg_dest = seg match {
|
||||||
|
case Some(segs) => reg_write_visible_consec(vregs, segs+1)//resever seglen+1 regs
|
||||||
|
case None => reg_write_visible(vregs)
|
||||||
|
}
|
||||||
|
val addr = addrfn(mem.ut_size)
|
||||||
|
|
||||||
|
helper_setup_address(reg_addr, reg_vaddr, mem, addr, stride, addrfn(mem.ut_size))
|
||||||
|
(seg, stride) match {
|
||||||
|
case (Some(segs), Some(reg)) => vinsts += op(reg_dest, reg_vaddr, reg, Imm(segs), pred)
|
||||||
|
case (Some(segs), None) => vinsts += op(reg_dest, reg_vaddr, Imm(segs), pred)
|
||||||
|
case (None, Some(reg)) => vinsts += op(reg_dest, reg_vaddr, reg, pred)
|
||||||
|
case (None, None) => vinsts += op(reg_dest, reg_vaddr, pred)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_load_seg_addrfn(op: Opcode, addrfn: (Int) => Int, bytes :Int) =
|
||||||
|
{
|
||||||
|
val seglen = rand_seglen
|
||||||
|
assert(bytes*seglen <= mem.ut_size,
|
||||||
|
"Per uthread memory must be larger than seglen*bytes")
|
||||||
|
seq_load_addrfn(op, addrfn, Some(seglen), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_load_stride_addrfn(op: Opcode, addrfn: (Int) => Int) =
|
||||||
|
{
|
||||||
|
val reg_vstride= reg_write_hidden(aregs)
|
||||||
|
seq_load_addrfn(op, addrfn, None, Some(reg_vstride))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_load_seg_stride_addrfn(op: Opcode, addrfn: (Int) => Int, bytes :Int) =
|
||||||
|
{
|
||||||
|
val seglen = rand_seglen
|
||||||
|
assert(bytes*seglen <= mem.ut_size,
|
||||||
|
"Per uthread memory must be larger than seglen*bytes")
|
||||||
|
val reg_vstride= reg_write_hidden(aregs)
|
||||||
|
seq_load_addrfn(op, addrfn, Some(seglen), Some(reg_vstride))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_store_addrfn(op: Opcode, addrfn: (Int) => Int, seg: Option[Int] = None, stride: Option[Reg] = None) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_vaddr = reg_write_hidden(aregs)
|
||||||
|
val reg_src = seg match {
|
||||||
|
case Some(segs) => reg_read_visible_consec(vregs, segs+1) //reserve seglen+1 regs
|
||||||
|
case None => reg_read_visible(vregs)
|
||||||
|
}
|
||||||
|
val addr = addrfn(mem.ut_size)
|
||||||
|
|
||||||
|
helper_setup_address(reg_addr, reg_vaddr, mem, addr, stride, addrfn(mem.ut_size))
|
||||||
|
(seg, stride) match {
|
||||||
|
case (Some(segs), Some(reg)) => vinsts += op(reg_src, reg_vaddr, reg, Imm(segs), pred)
|
||||||
|
case (Some(segs), None) => vinsts += op(reg_src, reg_vaddr, Imm(segs), pred)
|
||||||
|
case (None, Some(reg)) => vinsts += op(reg_src, reg_vaddr, reg, pred)
|
||||||
|
case (None, None) => vinsts += op(reg_src, reg_vaddr, pred)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_store_seg_addrfn(op: Opcode, addrfn: (Int) => Int, bytes: Int) =
|
||||||
|
{
|
||||||
|
val seglen = rand_seglen
|
||||||
|
assert(bytes*seglen <= mem.ut_size,
|
||||||
|
"Per uthread memory must be larger than seglen*bytes")
|
||||||
|
seq_store_addrfn(op, addrfn, Some(seglen), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_store_stride_addrfn(op: Opcode, addrfn: (Int) => Int) =
|
||||||
|
{
|
||||||
|
val reg_vstride= reg_write_hidden(aregs)
|
||||||
|
seq_store_addrfn(op, addrfn, None, Some(reg_vstride))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_store_seg_stride_addrfn(op: Opcode, addrfn: (Int) => Int, bytes: Int) =
|
||||||
|
{
|
||||||
|
val seglen = rand_seglen
|
||||||
|
assert(bytes*seglen <= mem.ut_size,
|
||||||
|
"Per uthread memory must be larger than seglen*bytes")
|
||||||
|
val reg_vstride= reg_write_hidden(aregs)
|
||||||
|
seq_store_addrfn(op, addrfn, Some(seglen), Some(reg_vstride))
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_amo_addrfn(op: Opcode, addrfn: (Int) => Int, addr_reg: HWRegPool, data_reg: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val reg_addr = reg_write_hidden(xregs)
|
||||||
|
val reg_dest = reg_write_visible(vregs)
|
||||||
|
|
||||||
|
val reg_vaddr = reg_write_hidden(addr_reg)
|
||||||
|
val reg_src = reg_read_visible(data_reg)
|
||||||
|
|
||||||
|
if(addr_reg == vregs) { // Generate a vector's worth of addresses
|
||||||
|
val amo_addr_mem = new Mem(seqname+"_amo_addr_init", 8*vl)
|
||||||
|
extra_hidden_data += MemAddrDump(amo_addr_mem, addrfn, mem.size)
|
||||||
|
|
||||||
|
val reg_help = reg_write_hidden(aregs)
|
||||||
|
helper_setup_address(reg_addr, reg_help, amo_addr_mem, 0)
|
||||||
|
|
||||||
|
val reg_xhelp = reg_write_hidden(xregs)
|
||||||
|
val reg_scalar = reg_write_hidden(sregs)
|
||||||
|
helper_setup_scalar(reg_xhelp, reg_scalar, mem, 0)
|
||||||
|
|
||||||
|
vinsts += VLD(reg_vaddr, reg_help, PredReg(def_preg, false))
|
||||||
|
vinsts += VADD(reg_vaddr, reg_vaddr, reg_scalar, PredReg(def_preg, false))
|
||||||
|
} else { // Single address
|
||||||
|
helper_setup_scalar(reg_addr, reg_vaddr, mem, addrfn(mem.size))
|
||||||
|
}
|
||||||
|
|
||||||
|
vinsts += op(reg_dest, RegImm(reg_vaddr, 0), reg_src, pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => vinsts.type]
|
||||||
|
|
||||||
|
candidates += seq_load_addrfn(VLB, rand_addr_b)
|
||||||
|
candidates += seq_load_addrfn(VLBU, rand_addr_b)
|
||||||
|
candidates += seq_load_addrfn(VLH, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(VLHU, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(VLW, rand_addr_w)
|
||||||
|
candidates += seq_load_addrfn(VLWU, rand_addr_w)
|
||||||
|
candidates += seq_load_addrfn(VLD, rand_addr_d)
|
||||||
|
|
||||||
|
candidates += seq_store_addrfn(VSB, rand_addr_b)
|
||||||
|
candidates += seq_store_addrfn(VSH, rand_addr_h)
|
||||||
|
candidates += seq_store_addrfn(VSW, rand_addr_w)
|
||||||
|
candidates += seq_store_addrfn(VSD, rand_addr_d)
|
||||||
|
|
||||||
|
if(use_seg)
|
||||||
|
{
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGB, rand_addr_b, 1)
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGBU, rand_addr_b, 1)
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGH, rand_addr_h, 2)
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGHU, rand_addr_h, 2)
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGW, rand_addr_w, 4)
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGWU, rand_addr_w, 4)
|
||||||
|
candidates += seq_load_seg_addrfn(VLSEGD, rand_addr_d, 8)
|
||||||
|
|
||||||
|
candidates += seq_store_seg_addrfn(VSSEGB, rand_addr_b, 1)
|
||||||
|
candidates += seq_store_seg_addrfn(VSSEGH, rand_addr_h, 2)
|
||||||
|
candidates += seq_store_seg_addrfn(VSSEGW, rand_addr_w, 4)
|
||||||
|
candidates += seq_store_seg_addrfn(VSSEGD, rand_addr_d, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(use_stride)
|
||||||
|
{
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTB, rand_addr_b)
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTBU, rand_addr_b)
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTH, rand_addr_h)
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTHU, rand_addr_h)
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTW, rand_addr_w)
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTWU, rand_addr_w)
|
||||||
|
candidates += seq_load_stride_addrfn(VLSTD, rand_addr_d)
|
||||||
|
|
||||||
|
candidates += seq_store_stride_addrfn(VSSTB, rand_addr_b)
|
||||||
|
candidates += seq_store_stride_addrfn(VSSTH, rand_addr_h)
|
||||||
|
candidates += seq_store_stride_addrfn(VSSTW, rand_addr_w)
|
||||||
|
candidates += seq_store_stride_addrfn(VSSTD, rand_addr_d)
|
||||||
|
if(use_seg)
|
||||||
|
{
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTB, rand_addr_b, 1)
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTBU, rand_addr_b, 1)
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTH, rand_addr_h, 2)
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTHU, rand_addr_h, 2)
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTW, rand_addr_w, 4)
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTWU, rand_addr_w, 4)
|
||||||
|
candidates += seq_load_seg_stride_addrfn(VLSEGSTD, rand_addr_d, 8)
|
||||||
|
|
||||||
|
candidates += seq_store_seg_stride_addrfn(VSSEGSTB, rand_addr_b, 1)
|
||||||
|
candidates += seq_store_seg_stride_addrfn(VSSEGSTH, rand_addr_h, 2)
|
||||||
|
candidates += seq_store_seg_stride_addrfn(VSSEGSTW, rand_addr_w, 4)
|
||||||
|
candidates += seq_store_seg_stride_addrfn(VSSEGSTD, rand_addr_d, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(use_amo)
|
||||||
|
{
|
||||||
|
val amowlist = List(VAMOADD_W, VAMOSWAP_W, VAMOAND_W, VAMOOR_W, VAMOMIN_W,
|
||||||
|
VAMOMINU_W, VAMOMAX_W, VAMOMAXU_W)
|
||||||
|
val amodlist = List(VAMOADD_D, VAMOSWAP_D, VAMOAND_D,
|
||||||
|
VAMOOR_D, VAMOMIN_D, VAMOMINU_D, VAMOMAX_D, VAMOMAXU_D)
|
||||||
|
|
||||||
|
for (amo <- amowlist)
|
||||||
|
{
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_w, sregs, sregs)
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_w, sregs, vregs)
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_w, vregs, sregs)
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_w, vregs, vregs)
|
||||||
|
}
|
||||||
|
for (amo <- amodlist)
|
||||||
|
{
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_d, sregs, sregs)
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_d, sregs, vregs)
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_d, vregs, sregs)
|
||||||
|
candidates += seq_amo_addrfn(amo, rand_addr_d, vregs, vregs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqVOnly(xregs: HWRegPool, fregs_s: HWRegPool, fregs_d: HWRegPool) extends VFInstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "vonly"
|
||||||
|
def seq_xdest(op: Opcode) = () =>
|
||||||
|
{
|
||||||
|
val dest = reg_write_visible(xregs) // Verifiy visible is appropriate for this
|
||||||
|
insts += op(dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
def seq_src2(op: Opcode, using_pool: HWRegPool) = () =>
|
||||||
|
{
|
||||||
|
val src = reg_read_any(using_pool)
|
||||||
|
val pred = reg_read_any(xregs)
|
||||||
|
val dest = reg_write(using_pool, pred, src)
|
||||||
|
insts += op(dest, pred, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => insts.type]
|
||||||
|
|
||||||
|
// Intra-FPU Instructions
|
||||||
|
candidates += seq_xdest(VEIDX)
|
||||||
|
|
||||||
|
for (op <- List(MOVZ, MOVN))
|
||||||
|
candidates += seq_src2(op, xregs)
|
||||||
|
|
||||||
|
for (op <- List(FMOVZ, FMOVN))
|
||||||
|
{
|
||||||
|
candidates += seq_src2(op, fregs_s)
|
||||||
|
candidates += seq_src2(op, fregs_d)
|
||||||
|
}
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
class SeqVPop(vregs: HWRegPool, pregs: HWRegPool, def_preg: Reg, sregs: HWRegPool) extends VFInstSeq //TODO: better configuration
|
||||||
|
{
|
||||||
|
override val seqname = "vpop"
|
||||||
|
|
||||||
|
def seq_src3(pop: Int) = () => {
|
||||||
|
val src1 = reg_read_any(pregs)
|
||||||
|
val src2 = reg_read_any(pregs)
|
||||||
|
val src3 = reg_read_any(pregs)
|
||||||
|
val dest = reg_write(pregs, src1, src2, src3)
|
||||||
|
vinsts += VPOP(dest, src1, src2, src3, HexImm(pop))
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = new ArrayBuffer[() => vinsts.type]
|
||||||
|
|
||||||
|
candidates += seq_src3(rand_word & 0xFF)
|
||||||
|
|
||||||
|
rand_pick(candidates)()
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import scala.collection.mutable.HashMap
|
||||||
|
import Rand._
|
||||||
|
|
||||||
|
object SeqVec
|
||||||
|
{
|
||||||
|
var cnt = 0
|
||||||
|
def get_id = (cnt += 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SeqVec(xregs: HWRegPool, vvregs: HWRegPool, vpregs: HWRegPool, vsregs: HWRegPool, varegs: HWRegPool, vl: Int, cfg: Map[String, String]) extends InstSeq
|
||||||
|
{
|
||||||
|
override val seqname = "vec"
|
||||||
|
val memsize = cfg.getOrElse("memsize", "32").toInt
|
||||||
|
val vfnum = cfg.getOrElse("vf", "10").toInt
|
||||||
|
val seqnum = cfg.getOrElse("seq", "100").toInt
|
||||||
|
val use_mul = cfg.getOrElse("mul", "true") == "true"
|
||||||
|
val use_div = cfg.getOrElse("div", "true") == "true"
|
||||||
|
val use_mix = cfg.getOrElse("mix", "true") == "true"
|
||||||
|
val use_fpu = cfg.getOrElse("fpu", "true") == "true"
|
||||||
|
val use_fma = cfg.getOrElse("fma", "true") == "true"
|
||||||
|
val use_fcvt = cfg.getOrElse("fcvt", "true") == "true"
|
||||||
|
val use_fdiv = cfg.getOrElse("fdiv", "true") == "true"
|
||||||
|
val use_amo = cfg.getOrElse("amo", "true") == "true"
|
||||||
|
val use_seg = cfg.getOrElse("seg", "true") == "true"
|
||||||
|
val use_stride = cfg.getOrElse("stride", "true") == "true"
|
||||||
|
val pred_alu = cfg.getOrElse("pred_alu", "true") == "true"
|
||||||
|
val pred_mem = cfg.getOrElse("pred_mem", "true") == "true"
|
||||||
|
val mixcfg = cfg.filterKeys(_ contains "mix.").map { case (k,v) => (k.split('.')(1), v.toInt) }.asInstanceOf[Map[String,Int]]
|
||||||
|
val vseqstats = new HashMap[String,Int].withDefaultValue(0)
|
||||||
|
val vinsts = new ArrayBuffer[Inst]
|
||||||
|
|
||||||
|
val name = "seqvec_" + SeqVec.cnt
|
||||||
|
SeqVec.cnt += 1
|
||||||
|
override def toString = name
|
||||||
|
|
||||||
|
val xreg_helper = reg_write_hidden(xregs)
|
||||||
|
val vareg_helper = reg_write_hidden(varegs)
|
||||||
|
val vpreg_helper = reg_write_hidden(vpregs)
|
||||||
|
val vec_mem = new VMem(name+"_mem", memsize, vl)
|
||||||
|
extra_visible_data += MemDump(vec_mem)
|
||||||
|
|
||||||
|
// Determine how many per type of vector register need to checkout for writing
|
||||||
|
def get_rand_reg_num(max: Int, min: Int) = // TODO: discuss this
|
||||||
|
{
|
||||||
|
val randtype = rand_range(0, 99)
|
||||||
|
val attempt =
|
||||||
|
if(randtype < 5) // 5% use a lot of registers
|
||||||
|
rand_range(max/2, max)
|
||||||
|
else if(randtype < 10) // 5% use very little registers
|
||||||
|
rand_range(1, 3)
|
||||||
|
else // 90% use moderate number
|
||||||
|
rand_range(3, max/2)
|
||||||
|
Math.max(Math.min(max, attempt),min)
|
||||||
|
}
|
||||||
|
|
||||||
|
val num_xreg = get_rand_reg_num(xregs.size-2, 1) //can't use x0 or xreg_helper
|
||||||
|
|
||||||
|
val num_vvreg = get_rand_reg_num(vvregs.size, 5)
|
||||||
|
val min_pregs = if(pred_alu || pred_mem || mixcfg.getOrElse("vpop",0) > 0) 1 else 0
|
||||||
|
val num_vpreg = get_rand_reg_num(vpregs.size-1, min_pregs) //can't use preg_helper
|
||||||
|
|
||||||
|
val num_vareg = get_rand_reg_num(varegs.size-1, 1) //can't use va0
|
||||||
|
val num_vsreg = get_rand_reg_num(vsregs.size, 1)
|
||||||
|
|
||||||
|
// Create shadow register pools to mimic those registers
|
||||||
|
// allowing us to hold them after SeqSeq finishes
|
||||||
|
val shadow_xregs = new ShadowRegPool
|
||||||
|
val shadow_vvregs = new ShadowRegPool
|
||||||
|
val shadow_vpregs = new ShadowRegPool
|
||||||
|
|
||||||
|
val shadow_varegs = new ShadowRegPool
|
||||||
|
val shadow_vsregs = new ShadowRegPool
|
||||||
|
|
||||||
|
val xregs_checkout = new ArrayBuffer[Reg]
|
||||||
|
val xregs_adding = reg_write_visible_consec(xregs, num_xreg)
|
||||||
|
xregs_adding.asInstanceOf[RegNeedsAlloc].regs.map(hr => {
|
||||||
|
xregs_checkout += hr
|
||||||
|
shadow_xregs.hwregs += new HWShadowReg(hr, "x_shadow", true, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
val vvregs_checkout = new ArrayBuffer[Reg]
|
||||||
|
val vregs_adding = reg_write_visible_consec(vvregs, num_vvreg)
|
||||||
|
vregs_adding.asInstanceOf[RegNeedsAlloc].regs.map(hr => {
|
||||||
|
vvregs_checkout += hr
|
||||||
|
shadow_vvregs.hwregs += new HWShadowReg(hr, "v_shadow", true, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
val vpregs_checkout = new ArrayBuffer[Reg]
|
||||||
|
if(num_vpreg != 0 ) {
|
||||||
|
val vpregs_adding = reg_write_visible_consec(vpregs, num_vpreg)
|
||||||
|
vpregs_adding.asInstanceOf[RegNeedsAlloc].regs.map(hr => {
|
||||||
|
vpregs_checkout += hr
|
||||||
|
shadow_vpregs.hwregs += new HWShadowReg(hr, "p_shadow", true, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
val varegs_checkout = new ArrayBuffer[Reg]
|
||||||
|
val varegs_adding = reg_write_visible_consec(varegs, num_vareg)
|
||||||
|
varegs_adding.asInstanceOf[RegNeedsAlloc].regs.map(hr => {
|
||||||
|
varegs_checkout += hr
|
||||||
|
shadow_varegs.hwregs += new HWShadowReg(hr, "a_shadow", true, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
val vsregs_checkout = new ArrayBuffer[Reg]
|
||||||
|
val vsregs_adding = reg_write_visible_consec(vsregs, num_vsreg)
|
||||||
|
vsregs_adding.asInstanceOf[RegNeedsAlloc].regs.map(hr => {
|
||||||
|
vsregs_checkout += hr
|
||||||
|
shadow_vsregs.hwregs += new HWShadowReg(hr, "s_shadow", true, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Handle initialization of vreg from memories
|
||||||
|
for((vreg,i) <- vvregs_checkout.zipWithIndex)
|
||||||
|
{
|
||||||
|
val init_mem = new Mem(Array(Label(name+"_"), vreg, Label("_init")) , 8*vl)
|
||||||
|
extra_hidden_data += MemDump(init_mem)
|
||||||
|
insts += LA(xreg_helper, init_mem)
|
||||||
|
insts += VMCA(vareg_helper, xreg_helper)
|
||||||
|
val vf_init_block = new ProgSeg(name+"_"+i+"_vf_init")
|
||||||
|
vf_init_block.insts += VPSET(vpreg_helper)
|
||||||
|
vinsts += VPSET(vpreg_helper)
|
||||||
|
vf_init_block.insts += VLD(vreg, vareg_helper, PredReg(vpreg_helper, false))
|
||||||
|
vf_init_block.insts += VSTOP()
|
||||||
|
vinsts += VLD(vreg, vareg_helper)
|
||||||
|
vinsts += VSTOP()
|
||||||
|
extra_code += ProgSegDump(vf_init_block)
|
||||||
|
insts += LUI(xreg_helper, Label("%hi("+vf_init_block.name+")"))
|
||||||
|
insts += VF(RegStrImm(xreg_helper, "%lo("+vf_init_block.name+")"))
|
||||||
|
}
|
||||||
|
|
||||||
|
val vf_init_pred_block = new ProgSeg(name+"_vf_init_pred")
|
||||||
|
for((vpreg,i) <- vpregs_checkout.zipWithIndex)
|
||||||
|
{
|
||||||
|
//try to have different alternate settings
|
||||||
|
if(i % 2 == 0) {
|
||||||
|
vf_init_pred_block.insts += VCMPLT(vpreg,vvregs_checkout(0), vvregs_checkout(1),PredReg(vpreg_helper, false))
|
||||||
|
vinsts += VCMPLT(vpreg,vvregs_checkout(0), vvregs_checkout(1),PredReg(vpreg_helper, false))
|
||||||
|
} else {
|
||||||
|
vf_init_pred_block.insts += VCMPLT(vpreg,vvregs_checkout(2), vvregs_checkout(3),PredReg(vpreg_helper, false))
|
||||||
|
vinsts += VCMPLT(vpreg,vvregs_checkout(2), vvregs_checkout(3),PredReg(vpreg_helper, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vf_init_pred_block.insts += VSTOP()
|
||||||
|
vinsts += VSTOP()
|
||||||
|
extra_code += ProgSegDump(vf_init_pred_block)
|
||||||
|
insts += LUI(xreg_helper, Label("%hi("+vf_init_pred_block.name+")"))
|
||||||
|
insts += VF(RegStrImm(xreg_helper, "%lo("+vf_init_pred_block.name+")"))
|
||||||
|
|
||||||
|
for(i <- 1 to vfnum)
|
||||||
|
{
|
||||||
|
// Create SeqSeq to create some vector instructions
|
||||||
|
val vf_instseq = new SeqSeq(shadow_vvregs, shadow_vpregs, vpreg_helper, shadow_vsregs, shadow_varegs, shadow_xregs, vec_mem, seqnum, mixcfg, vl, use_mul, use_div, use_mix, use_fpu, use_fma, use_fcvt, use_fdiv, use_amo, use_seg, use_stride, pred_alu, pred_mem) //TODO: Enable configuration of enabling mul,div ops
|
||||||
|
for ((seqname, seqcnt) <- vf_instseq.seqstats)
|
||||||
|
{
|
||||||
|
vseqstats(seqname) += seqcnt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump that SeqSeq into a VF Instruction block
|
||||||
|
val vf_block = new ProgSeg(name+"_vf_"+i)
|
||||||
|
//clear vphelper for vmemops
|
||||||
|
vf_block.insts += VPSET(vpreg_helper) //TODO: add vpset and vpop
|
||||||
|
vinsts += VPSET(vpreg_helper) // TODO: add helper function that does these two lines
|
||||||
|
while(!vf_instseq.is_done)
|
||||||
|
{
|
||||||
|
if(vf_instseq.vinst_left)
|
||||||
|
{
|
||||||
|
val vinst = vf_instseq.next_vinst()
|
||||||
|
vf_block.insts += vinst
|
||||||
|
vinsts += vinst
|
||||||
|
}
|
||||||
|
if(vf_instseq.inst_left) insts += vf_instseq.next_inst()
|
||||||
|
}
|
||||||
|
vf_block.insts += VSTOP()
|
||||||
|
vinsts += VSTOP()
|
||||||
|
extra_code += ProgSegDump(vf_block)
|
||||||
|
extra_hidden_data.appendAll(vf_instseq.extra_hidden_data)
|
||||||
|
|
||||||
|
insts += LUI(xreg_helper, Label("%hi("+vf_block.name+")"))
|
||||||
|
insts += VF(RegStrImm(xreg_helper, "%lo("+vf_block.name+")"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling dumping of vreg to output memories
|
||||||
|
for((vreg,i) <- vvregs_checkout.zipWithIndex)
|
||||||
|
{
|
||||||
|
if(vreg.hwreg.is_visible) {
|
||||||
|
val out_mem = new Mem(Array(Label(name+"_"), vreg, Label("_output")) , 8*vl)
|
||||||
|
extra_visible_data += MemDump(out_mem)
|
||||||
|
insts += LA(xreg_helper, out_mem)
|
||||||
|
insts += VMCA(vareg_helper, xreg_helper)
|
||||||
|
val vf_init_block = new ProgSeg(name+"_"+i+"_vf_dump")
|
||||||
|
vf_init_block.insts += VPSET(vpreg_helper)
|
||||||
|
vinsts += VPSET(vpreg_helper)
|
||||||
|
vf_init_block.insts += VSD(vreg, vareg_helper, PredReg(vpreg_helper, false))
|
||||||
|
vf_init_block.insts += VSTOP()
|
||||||
|
vinsts += VSD(vreg, vareg_helper)
|
||||||
|
vinsts += VSTOP()
|
||||||
|
extra_code += ProgSegDump(vf_init_block)
|
||||||
|
insts += LUI(xreg_helper, Label("%hi("+vf_init_block.name+")"))
|
||||||
|
insts += VF(RegStrImm(xreg_helper, "%lo("+vf_init_block.name+")"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fence to close out the vector sequence
|
||||||
|
insts += FENCE_V(Label("// " + name))
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package torture
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import Rand.rand_range
|
||||||
|
|
||||||
|
class VFInstSeq extends InstSeq
|
||||||
|
{
|
||||||
|
val vinsts = new ArrayBuffer[Inst]
|
||||||
|
var vinst_ptr = 0
|
||||||
|
|
||||||
|
override def is_done = insts.length == inst_ptr && vinsts.length == vinst_ptr
|
||||||
|
|
||||||
|
def inst_left = insts.length > inst_ptr
|
||||||
|
def vinst_left = vinsts.length > vinst_ptr
|
||||||
|
|
||||||
|
def next_vinst() =
|
||||||
|
{
|
||||||
|
val vinst = vinsts(vinst_ptr)
|
||||||
|
vinst_ptr += 1
|
||||||
|
vinst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object VFInstSeq
|
||||||
|
{
|
||||||
|
def apply(prob_tbl: ArrayBuffer[(Int, () => VFInstSeq)]): VFInstSeq =
|
||||||
|
{
|
||||||
|
var p = rand_range(0, 99)
|
||||||
|
for ((prob, gen_seq) <- prob_tbl)
|
||||||
|
{
|
||||||
|
if (p < prob) return gen_seq()
|
||||||
|
p -= prob
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false, println("Probabilties should have added up to 100%"))
|
||||||
|
new VFInstSeq()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package torture
|
||||||
|
package generator
|
||||||
|
|
||||||
|
import scopt.OptionParser
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.util.Properties
|
||||||
|
import scala.collection.JavaConversions._
|
||||||
|
|
||||||
|
case class Options(var outFileName: String = "test",
|
||||||
|
var confFileName: String = "config/default.config", var numOutFiles: Int = 0)
|
||||||
|
|
||||||
|
object Generator extends App
|
||||||
|
{
|
||||||
|
override def main(args: Array[String]) =
|
||||||
|
{
|
||||||
|
val parser = new OptionParser[Options]("generator/run") {
|
||||||
|
opt[String]('C', "config") valueName("<file>") text("config file") action {(s: String, c) => c.copy(confFileName = s)}
|
||||||
|
opt[String]('o', "output") valueName("<filename>") text("output filename") action {(s: String, c) => c.copy(outFileName = s)}
|
||||||
|
opt[Int]('n', "numfiles") valueName("<num_files>") text("number of output files") action {(n: Int, c) => c.copy(numOutFiles = n)}
|
||||||
|
}
|
||||||
|
parser.parse(args, Options()) match {
|
||||||
|
case Some(opts) =>
|
||||||
|
generate_loop(opts.confFileName, opts.outFileName, opts.numOutFiles)
|
||||||
|
case None =>
|
||||||
|
System.exit(1) //error message printed by parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_loop(confFile: String, outFileName: String, numOutFiles: Int) = {
|
||||||
|
if (numOutFiles > 0) {
|
||||||
|
for (i <- 0 to (numOutFiles-1))
|
||||||
|
generate(confFile, outFileName + ("_%03d" format (i)))
|
||||||
|
} else {
|
||||||
|
generate(confFile, outFileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate(confFile: String, outFileName: String): String = {
|
||||||
|
val config = new Properties()
|
||||||
|
val in = new FileInputStream(confFile)
|
||||||
|
config.load(in)
|
||||||
|
in.close()
|
||||||
|
val nseqs = config.getProperty("torture.generator.nseqs", "1000").toInt
|
||||||
|
val memsize = config.getProperty("torture.generator.memsize", "1024").toInt
|
||||||
|
val fprnd = config.getProperty("torture.generator.fprnd", "0").toInt
|
||||||
|
val use_amo = (config.getProperty("torture.generator.amo", "true").toLowerCase == "true")
|
||||||
|
val use_mul = (config.getProperty("torture.generator.mul", "true").toLowerCase == "true")
|
||||||
|
val use_div = (config.getProperty("torture.generator.divider", "true").toLowerCase == "true")
|
||||||
|
val mix = config.filterKeys(_ contains "torture.generator.mix").map { case (k,v) => (k.split('.')(3), v.toInt) }.asInstanceOf[Map[String,Int]]
|
||||||
|
val vec = config.filterKeys(_ contains "torture.generator.vec").map { case (k,v) => (k.split('.').drop(3).reduce(_+"."+_), v) }.asInstanceOf[Map[String,String]]
|
||||||
|
val segment = (config.getProperty("torture.generator.segment", "true").toLowerCase == "true")
|
||||||
|
val loop = (config.getProperty("torture.generator.loop", "true").toLowerCase == "true")
|
||||||
|
val loop_size = config.getProperty("torture.generator.loop_size", "256").toInt
|
||||||
|
generate(nseqs, memsize, fprnd, mix, vec, use_amo, use_mul, use_div, outFileName, segment, loop, loop_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate(nseqs: Int, memsize: Int, fprnd : Int, mix: Map[String,Int], veccfg: Map[String,String], use_amo: Boolean, use_mul: Boolean, use_div: Boolean, outFileName: String, segment : Boolean, loop : Boolean, loop_size : Int): String = {
|
||||||
|
assert (mix.values.sum == 100, println("The instruction mix specified in config does not add up to 100%"))
|
||||||
|
assert (mix.keys.forall(List("xmem","xbranch","xalu","fgen","fpmem","fax","fdiv","vec") contains _), println("The instruction mix specified in config contains an unknown sequence type name"))
|
||||||
|
|
||||||
|
val vmemsize = veccfg.getOrElse("memsize", "32").toInt
|
||||||
|
val vnseq = veccfg.getOrElse("seq", "100").toInt
|
||||||
|
val vfnum = veccfg.getOrElse("vf", "10").toInt
|
||||||
|
val vecmix = veccfg.filterKeys(_ contains "mix.").map { case (k,v) => (k.split('.')(1), v.toInt) }.asInstanceOf[Map[String,Int]]
|
||||||
|
assert (vecmix.values.sum == 100, println("The vector instruction mix specified in config does not add up to 100%"))
|
||||||
|
assert (vecmix.keys.forall(List("vmem","valu","vpop","vonly") contains _), println("The vector instruction mix specified in config contains an unknown sequence type name"))
|
||||||
|
|
||||||
|
val prog = new Prog(memsize, veccfg, loop)
|
||||||
|
ProgSeg.cnt = 0
|
||||||
|
SeqVec.cnt = 0
|
||||||
|
val s = prog.generate(nseqs, fprnd, mix, veccfg, use_amo, use_mul, use_div, segment, loop, loop_size)
|
||||||
|
|
||||||
|
val oname = "output/" + outFileName + ".S"
|
||||||
|
val fw = new FileWriter(oname)
|
||||||
|
fw.write(s)
|
||||||
|
fw.close()
|
||||||
|
val stats = prog.statistics(nseqs,fprnd,mix,vnseq,vmemsize,vfnum,vecmix,use_amo,use_mul,use_div)
|
||||||
|
val sname = "output/" + outFileName + ".stats"
|
||||||
|
val fw2 = new FileWriter(sname)
|
||||||
|
fw2.write(stats)
|
||||||
|
fw2.close()
|
||||||
|
oname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#=======================================================================
|
||||||
|
# UCB VLSI FLOW: Makefile for riscv-tests
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# Yunsup Lee (yunsup@cs.berkeley.edu)
|
||||||
|
#
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Sources
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
|
||||||
|
asm_tests = \
|
||||||
|
test.S \
|
||||||
|
|
||||||
|
extra_files =
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Build rules
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
|
||||||
|
RISCV_GCC = riscv64-unknown-elf-gcc
|
||||||
|
RISCV_GCC_OPTS = -nostdlib -nostartfiles -Wa,-march=RVIMAFDXhwacha
|
||||||
|
RISCV_OBJDUMP = riscv64-unknown-elf-objdump --disassemble-all --section=.text --section=.data --section=.bss
|
||||||
|
RISCV_SIM = spike --extension=hwacha
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# Build assembly tests
|
||||||
|
|
||||||
|
asm_tests_bin = $(patsubst %.S, %, $(asm_tests))
|
||||||
|
asm_tests_dump = $(addsuffix .dump, $(asm_tests_bin))
|
||||||
|
asm_tests_sig = $(addsuffix .sig, $(asm_tests_bin))
|
||||||
|
asm_tests_hex = $(addsuffix .hex, $(asm_tests_bin))
|
||||||
|
|
||||||
|
$(asm_tests_dump): %.dump: %
|
||||||
|
$(RISCV_OBJDUMP) $< > $@
|
||||||
|
|
||||||
|
$(asm_tests_bin): %: %.S $(extra_files)
|
||||||
|
$(RISCV_GCC) $(RISCV_GCC_OPTS) -I../env/p -T../env/p/link.ld $< -o $@
|
||||||
|
|
||||||
|
$(asm_tests_hex): %.hex: % $(extra_files)
|
||||||
|
elf2hex 16 16384 $< > $@
|
||||||
|
|
||||||
|
$(asm_tests_sig): %.sig: %
|
||||||
|
$(RISCV_SIM) +signature=$@ $<
|
||||||
|
|
||||||
|
new:
|
||||||
|
cd ..; make gen
|
||||||
|
|
||||||
|
run: $(asm_tests_sig)
|
||||||
|
echo; perl -ne 'print " [$$1] $$ARGV \t$$2\n" if /\*{3}(.{8})\*{3}(.*)/' \
|
||||||
|
$(asm_tests_sig); echo;
|
||||||
|
|
||||||
|
junk += $(asm_tests_bin) $(asm_tests_dump) $(asm_tests_sig) $(asm_tests_hex)
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# Default
|
||||||
|
|
||||||
|
all: $(asm_tests_dump) $(asm_tests_hex)
|
||||||
|
|
||||||
|
#------------------------------------------------------------
|
||||||
|
# Clean up
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(junk)
|
||||||
|
|
||||||
|
clean-all: clean
|
||||||
|
rm -rf test*.S test*.stats test*.hex test*.out test*.dump test test_1* test_pseg_* schad* failedtests/*
|
Binary file not shown.
|
@ -0,0 +1,183 @@
|
||||||
|
package torture
|
||||||
|
package overnight
|
||||||
|
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.util.Properties._
|
||||||
|
import javax.mail._
|
||||||
|
import javax.mail.internet._
|
||||||
|
import scala.collection.JavaConversions._
|
||||||
|
import scala.sys.process._
|
||||||
|
import scalax.file.Path
|
||||||
|
import Path._
|
||||||
|
import scalax.file.PathSet
|
||||||
|
import scalax.file.FileSystem
|
||||||
|
import scopt.OptionParser
|
||||||
|
import java.io.File
|
||||||
|
import java.util.Properties
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import torture.fileop._
|
||||||
|
|
||||||
|
|
||||||
|
case class Options(var timeToRun: Int = Overnight.DefTime,
|
||||||
|
var emailAddress: String = Overnight.DefEmail,
|
||||||
|
var errorThreshold: Int = Overnight.DefThresh,
|
||||||
|
var cSimPath: String = Overnight.DefCSim,
|
||||||
|
var rtlSimPath: String = Overnight.DefRtlSim,
|
||||||
|
var permDir: String = Overnight.DefPermDir,
|
||||||
|
var gitCommit: String = Overnight.DefGitCommit,
|
||||||
|
var confFileName: String = Overnight.DefConfig,
|
||||||
|
var output: Boolean = false,
|
||||||
|
var dumpWaveform: Boolean = false)
|
||||||
|
|
||||||
|
object Overnight extends App
|
||||||
|
{
|
||||||
|
def DefTime = 1
|
||||||
|
def DefEmail = "your@email.address"
|
||||||
|
def DefThresh = 1
|
||||||
|
def DefCSim = ""
|
||||||
|
def DefRtlSim = ""
|
||||||
|
def DefPermDir = "output/failedtests"
|
||||||
|
def DefGitCommit = ""
|
||||||
|
def DefConfig = "config/default.config"
|
||||||
|
|
||||||
|
override def main(args: Array[String]) =
|
||||||
|
{
|
||||||
|
val parser = new OptionParser[Options]("overnight/run") {
|
||||||
|
opt[String]('C', "config") valueName("<file>") text("config file") action {(s: String, c) => c.copy(confFileName = s)}
|
||||||
|
opt[String]('p', "permdir") valueName("<dir>") text("dir to store failing tests") action {(s: String, c) => c.copy(permDir = s)}
|
||||||
|
opt[String]('c', "csim") valueName("<file>") text("C simulator") action {(s: String, c) => c.copy(cSimPath = s)}
|
||||||
|
opt[String]('r', "rtlsim") valueName("<file>") text("RTL simulator") action {(s: String, c) => c.copy(rtlSimPath = s)}
|
||||||
|
opt[String]('e', "email") valueName("<address>") text("email to report to") action {(s: String, c) => c.copy(emailAddress = s)}
|
||||||
|
opt[String]('g', "gitcommit") valueName("<git commit>") text("Git commit to check out") action {(s: String, c) => c.copy(gitCommit = s)}
|
||||||
|
opt[Int]('t', "threshold") valueName("<count>") text("number of failures to trigger email") action {(i: Int, c) => c.copy(errorThreshold = i)}
|
||||||
|
opt[Int]('m', "minutes") valueName("<minutes>") text("number of minutes to run tests") action {(i: Int, c) => c.copy(timeToRun = i)}
|
||||||
|
opt[Unit]("output") abbr("o") text("Write verbose output of simulators to file") action {(_, c) => c.copy(output = true)}
|
||||||
|
opt[Unit]("dumpwaveform") abbr("dump") text("Create a vcd from a csim or a vpd from vsim") action {(_, c) => c.copy(dumpWaveform= true)}
|
||||||
|
}
|
||||||
|
parser.parse(args, Options()) match {
|
||||||
|
case Some(opts) =>
|
||||||
|
overnight(opts.confFileName, opts.permDir, opts.cSimPath, opts.rtlSimPath,
|
||||||
|
opts.emailAddress, opts.gitCommit, opts.errorThreshold, opts.timeToRun, opts.output, opts.dumpWaveform)
|
||||||
|
case None =>
|
||||||
|
System.exit(1) // error message printed by parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def overnight(configFileName: String,
|
||||||
|
outputDir: String,
|
||||||
|
cSimPath: String,
|
||||||
|
rtlSimPath: String,
|
||||||
|
emailAddress: String,
|
||||||
|
gitCommit: String,
|
||||||
|
errorThreshold: Int,
|
||||||
|
timeToRun: Int,
|
||||||
|
output: Boolean,
|
||||||
|
dumpWaveform: Boolean)
|
||||||
|
{
|
||||||
|
val config = new Properties()
|
||||||
|
val configin = new FileInputStream(configFileName)
|
||||||
|
config.load(configin)
|
||||||
|
configin.close()
|
||||||
|
|
||||||
|
val errors = Option(config.getProperty("torture.overnight.errors")) map ( _.toInt )
|
||||||
|
val thresh = if(errorThreshold == DefThresh) errors.getOrElse(DefThresh) else errorThreshold
|
||||||
|
val runtime = Option(config.getProperty("torture.overnight.minutes")) map ( _.toInt )
|
||||||
|
val minutes = if(timeToRun == DefTime) runtime.getOrElse(DefTime) else timeToRun
|
||||||
|
val outdir = Option(config.getProperty("torture.overnight.outdir"))
|
||||||
|
val permDir = if(outputDir == DefPermDir) outdir.getOrElse(DefPermDir) else outputDir
|
||||||
|
val email = Option(config.getProperty("torture.overnight.email"))
|
||||||
|
val address = if(emailAddress == DefEmail) email.getOrElse(DefEmail) else emailAddress
|
||||||
|
|
||||||
|
val startTime = System.currentTimeMillis
|
||||||
|
var endTime = startTime + minutes*60*1000
|
||||||
|
var errCount = 0
|
||||||
|
|
||||||
|
val (cSim, rtlSim) = checkoutRocket(cSimPath, rtlSimPath, gitCommit)
|
||||||
|
while(System.currentTimeMillis < endTime) {
|
||||||
|
val baseName = "test_" + System.currentTimeMillis
|
||||||
|
val newAsmName = generator.Generator.generate(configFileName, baseName)
|
||||||
|
val (failed, test) = testrun.TestRunner.testrun( Some(newAsmName), cSim, rtlSim, true, output, dumpWaveform, configFileName)
|
||||||
|
if(failed) {
|
||||||
|
errCount += 1
|
||||||
|
test foreach { t =>
|
||||||
|
println(t)
|
||||||
|
println(t.last)
|
||||||
|
val permFiles:PathSet[Path] = Path(t.init:_*) * (t.last + "*")
|
||||||
|
val statFile: Path = Path(t.init:_*) / (baseName+".stats")
|
||||||
|
println(permFiles.mkString)
|
||||||
|
println(statFile)
|
||||||
|
permFiles.foreach( f => f.copyTo( Path.fromString(permDir) / f.name, copyAttributes=false))
|
||||||
|
statFile.copyTo(Path.fromString(permDir) / statFile.name, replaceExisting=true, copyAttributes=false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test foreach { t =>
|
||||||
|
val targetFiles:PathSet[Path] = Path(t.init:_*) * (baseName+"*")
|
||||||
|
targetFiles.foreach(_.delete())
|
||||||
|
}
|
||||||
|
if(errCount == thresh) {
|
||||||
|
println("////////////////////////////////////////////////////////////////")
|
||||||
|
println("// Aborting test runs due to error threshold being exceeded //")
|
||||||
|
println("////////////////////////////////////////////////////////////////")
|
||||||
|
endTime = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val permPath: Path = Path.fromString(permDir)
|
||||||
|
if (!address.equalsIgnoreCase(DefEmail))
|
||||||
|
{
|
||||||
|
Some(address) foreach { addr =>
|
||||||
|
val properties = System.getProperties
|
||||||
|
properties.put("mail.smtp.host", "localhost")
|
||||||
|
val hostname = InetAddress.getLocalHost().getHostName()
|
||||||
|
val session = Session.getDefaultInstance(properties)
|
||||||
|
val message = new MimeMessage(session)
|
||||||
|
message.setFrom(new InternetAddress("torture@"+hostname+".millennium.berkeley.edu"))
|
||||||
|
message.setRecipients(Message.RecipientType.TO, addr)
|
||||||
|
message.setText( "Run complete with " + errCount + " errors. Failing tests put in " + permPath.toAbsolute.path )
|
||||||
|
message.setSubject("Run complete on " + hostname)
|
||||||
|
println("////////////////////////////////////////////////////////////////")
|
||||||
|
println("// Sending " + message + " to " + addr)
|
||||||
|
println("////////////////////////////////////////////////////////////////")
|
||||||
|
Transport.send(message)
|
||||||
|
}
|
||||||
|
println("////////////////////////////////////////////////////////////////")
|
||||||
|
println("// Testing complete with " + errCount + " errors.")
|
||||||
|
println("// Failing tests put in " + permPath.toAbsolute.path)
|
||||||
|
println("////////////////////////////////////////////////////////////////")
|
||||||
|
}
|
||||||
|
if(errCount != 0) System.exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
def checkoutRocket(cPath: String, rPath: String, commit: String): (Option[String],Option[String]) =
|
||||||
|
{
|
||||||
|
var cSim: Option[String] = None
|
||||||
|
var rSim: Option[String] = None
|
||||||
|
val cmmt = commit.toUpperCase
|
||||||
|
if (cPath != DefCSim) cSim = Some(cPath)
|
||||||
|
if (rPath != DefRtlSim) rSim = Some(rPath)
|
||||||
|
if (cmmt == "NONE") return (cSim, rSim)
|
||||||
|
|
||||||
|
var rocketDir = ""
|
||||||
|
if (cPath != DefCSim) rocketDir = cPath.substring(0,cPath.length-18)
|
||||||
|
if (rPath != DefRtlSim) rocketDir = rPath.substring(0,rPath.length-36)
|
||||||
|
val rocketPath: Path = Path.fromString(rocketDir)
|
||||||
|
val destPath: Path = (rocketPath / Path("..") / Path("rocket_"+cmmt))
|
||||||
|
val emPath: Path = destPath / Path("emulator")
|
||||||
|
val vcsrelPath: Path = Path.fromString("vlsi-generic/build/vcs-sim-rtl")
|
||||||
|
val vcsPath: Path = destPath / vcsrelPath
|
||||||
|
|
||||||
|
if (!destPath.exists)
|
||||||
|
{
|
||||||
|
FileOperations.gitcheckout(rocketPath, destPath, cmmt)
|
||||||
|
println("Doing make clean in " + emPath.toAbsolute.normalize.path)
|
||||||
|
FileOperations.clean(emPath)
|
||||||
|
println("Doing make clean in " + vcsPath.toAbsolute.normalize.path)
|
||||||
|
FileOperations.clean(vcsPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cPath != DefCSim) FileOperations.compile(emPath, emPath / Path("emulator"))
|
||||||
|
if (rPath != DefRtlSim) FileOperations.compile(vcsPath, vcsPath / Path("simv"))
|
||||||
|
|
||||||
|
if (cPath != DefCSim) cSim = Some(emPath.toAbsolute.normalize.path + "/emulator")
|
||||||
|
if (rPath != DefRtlSim) rSim = Some(vcsPath.toAbsolute.normalize.path + "/simv")
|
||||||
|
(cSim, rSim)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
sbt.version=1.4.4
|
|
@ -0,0 +1,156 @@
|
||||||
|
diff --git a/config/default.config b/config/default.config
|
||||||
|
index 57d5186..233ac5a 100644
|
||||||
|
--- a/config/default.config
|
||||||
|
+++ b/config/default.config
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
torture.generator.nseqs 200
|
||||||
|
torture.generator.memsize 1024
|
||||||
|
torture.generator.fprnd 0
|
||||||
|
-torture.generator.amo true
|
||||||
|
+torture.generator.amo false
|
||||||
|
torture.generator.mul true
|
||||||
|
torture.generator.divider true
|
||||||
|
torture.generator.segment true
|
||||||
|
@@ -10,15 +10,15 @@ torture.generator.loop_size 64
|
||||||
|
|
||||||
|
torture.generator.mix.xmem 10
|
||||||
|
torture.generator.mix.xbranch 20
|
||||||
|
-torture.generator.mix.xalu 50
|
||||||
|
-torture.generator.mix.fgen 10
|
||||||
|
-torture.generator.mix.fpmem 5
|
||||||
|
-torture.generator.mix.fax 3
|
||||||
|
-torture.generator.mix.fdiv 2
|
||||||
|
+torture.generator.mix.xalu 70
|
||||||
|
+torture.generator.mix.fgen 0
|
||||||
|
+torture.generator.mix.fpmem 0
|
||||||
|
+torture.generator.mix.fax 0
|
||||||
|
+torture.generator.mix.fdiv 0
|
||||||
|
torture.generator.mix.vec 0
|
||||||
|
|
||||||
|
-torture.generator.vec.vf 1
|
||||||
|
-torture.generator.vec.seq 20
|
||||||
|
+torture.generator.vec.vf 0
|
||||||
|
+torture.generator.vec.seq 0
|
||||||
|
torture.generator.vec.memsize 128
|
||||||
|
torture.generator.vec.numsregs 64
|
||||||
|
torture.generator.vec.mul false
|
||||||
|
diff --git a/generator/src/main/scala/HWRegPool.scala b/generator/src/main/scala/HWRegPool.scala
|
||||||
|
index fa995a7..027a311 100644
|
||||||
|
--- a/generator/src/main/scala/HWRegPool.scala
|
||||||
|
+++ b/generator/src/main/scala/HWRegPool.scala
|
||||||
|
@@ -86,7 +86,7 @@ trait PoolsMaster extends HWRegPool
|
||||||
|
|
||||||
|
class XRegsPool extends ScalarRegPool
|
||||||
|
{
|
||||||
|
- val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "ld", "sd")
|
||||||
|
+ val (name, regname, ldinst, stinst) = ("xreg", "reg_x", "lw", "sw")
|
||||||
|
|
||||||
|
hwregs += new HWReg("x0", true, false)
|
||||||
|
for (i <- 1 to 31)
|
||||||
|
diff --git a/generator/src/main/scala/Prog.scala b/generator/src/main/scala/Prog.scala
|
||||||
|
index 5a6823d..d78f691 100644
|
||||||
|
--- a/generator/src/main/scala/Prog.scala
|
||||||
|
+++ b/generator/src/main/scala/Prog.scala
|
||||||
|
@@ -404,7 +404,7 @@ class Prog(memsize: Int, veccfg: Map[String,String], loop : Boolean)
|
||||||
|
"\n" +
|
||||||
|
(if (using_vec) "RVTEST_RV64UV\n"
|
||||||
|
else if (using_fpu) "RVTEST_RV64UF\n"
|
||||||
|
- else "RVTEST_RV64U\n") +
|
||||||
|
+ else "RVTEST_RV32M\n") +
|
||||||
|
"RVTEST_CODE_BEGIN\n" +
|
||||||
|
(if (using_vec) init_vector() else "") +
|
||||||
|
"\n" +
|
||||||
|
diff --git a/generator/src/main/scala/Rand.scala b/generator/src/main/scala/Rand.scala
|
||||||
|
index a677d2d..ec0745f 100644
|
||||||
|
--- a/generator/src/main/scala/Rand.scala
|
||||||
|
+++ b/generator/src/main/scala/Rand.scala
|
||||||
|
@@ -15,7 +15,7 @@ object Rand
|
||||||
|
low + Random.nextInt(span)
|
||||||
|
}
|
||||||
|
|
||||||
|
- def rand_shamt() = rand_range(0, 63)
|
||||||
|
+ def rand_shamt() = rand_range(0, 31)
|
||||||
|
def rand_shamtw() = rand_range(0, 31)
|
||||||
|
def rand_seglen() = rand_range(0, 7)
|
||||||
|
def rand_imm() = rand_range(-2048, 2047)
|
||||||
|
diff --git a/generator/src/main/scala/SeqALU.scala b/generator/src/main/scala/SeqALU.scala
|
||||||
|
index a1f27a5..f380697 100644
|
||||||
|
--- a/generator/src/main/scala/SeqALU.scala
|
||||||
|
+++ b/generator/src/main/scala/SeqALU.scala
|
||||||
|
@@ -68,17 +68,17 @@ class SeqALU(xregs: HWRegPool, use_mul: Boolean, use_div: Boolean) extends InstS
|
||||||
|
candidates += seq_src1_immfn(SRAI, rand_shamt)
|
||||||
|
candidates += seq_src1_immfn(ORI, rand_imm)
|
||||||
|
candidates += seq_src1_immfn(ANDI, rand_imm)
|
||||||
|
- candidates += seq_src1_immfn(ADDIW, rand_imm)
|
||||||
|
- candidates += seq_src1_immfn(SLLIW, rand_shamtw)
|
||||||
|
- candidates += seq_src1_immfn(SRLIW, rand_shamtw)
|
||||||
|
- candidates += seq_src1_immfn(SRAIW, rand_shamtw)
|
||||||
|
+ //candidates += seq_src1_immfn(ADDIW, rand_imm)
|
||||||
|
+ //candidates += seq_src1_immfn(SLLIW, rand_shamtw)
|
||||||
|
+ //candidates += seq_src1_immfn(SRLIW, rand_shamtw)
|
||||||
|
+ //candidates += seq_src1_immfn(SRAIW, rand_shamtw)
|
||||||
|
|
||||||
|
val oplist = new ArrayBuffer[Opcode]
|
||||||
|
|
||||||
|
oplist += (ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND)
|
||||||
|
- oplist += (ADDW, SUBW, SLLW, SRLW, SRAW)
|
||||||
|
- if (use_mul) oplist += (MUL, MULH, MULHSU, MULHU, MULW)
|
||||||
|
- if (use_div) oplist += (DIV, DIVU, REM, REMU, DIVW, DIVUW, REMW, REMUW)
|
||||||
|
+ //oplist += (ADDW, SUBW, SLLW, SRLW, SRAW)
|
||||||
|
+ if (use_mul) oplist += (MUL, MULH, MULHSU, MULHU)
|
||||||
|
+ if (use_div) oplist += (DIV, DIVU, REM, REMU)
|
||||||
|
|
||||||
|
for (op <- oplist)
|
||||||
|
{
|
||||||
|
diff --git a/generator/src/main/scala/SeqBranch.scala b/generator/src/main/scala/SeqBranch.scala
|
||||||
|
index bba9895..0d257d7 100644
|
||||||
|
--- a/generator/src/main/scala/SeqBranch.scala
|
||||||
|
+++ b/generator/src/main/scala/SeqBranch.scala
|
||||||
|
@@ -75,7 +75,7 @@ class SeqBranch(xregs: HWRegPool) extends InstSeq
|
||||||
|
val reg_mask = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
|
||||||
|
- insts += SLL(reg_one, reg_one, Imm(63))
|
||||||
|
+ insts += SLL(reg_one, reg_one, Imm(31))
|
||||||
|
insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
|
||||||
|
insts += XOR(reg_mask, reg_mask, reg_one)
|
||||||
|
insts += AND(reg_dst1, reg_src, reg_mask)
|
||||||
|
@@ -95,7 +95,7 @@ class SeqBranch(xregs: HWRegPool) extends InstSeq
|
||||||
|
val reg_mask = reg_write_visible(xregs)
|
||||||
|
|
||||||
|
insts += ADDI(reg_one, reg_read_zero(xregs), Imm(1))
|
||||||
|
- insts += SLL(reg_one, reg_one, Imm(63))
|
||||||
|
+ insts += SLL(reg_one, reg_one, Imm(31))
|
||||||
|
insts += ADDI(reg_mask, reg_read_zero(xregs), Imm(-1))
|
||||||
|
insts += XOR(reg_mask, reg_mask, reg_one)
|
||||||
|
insts += AND(reg_dst1, reg_src1, reg_mask)
|
||||||
|
diff --git a/generator/src/main/scala/SeqMem.scala b/generator/src/main/scala/SeqMem.scala
|
||||||
|
index 3c180ed..53cef34 100644
|
||||||
|
--- a/generator/src/main/scala/SeqMem.scala
|
||||||
|
+++ b/generator/src/main/scala/SeqMem.scala
|
||||||
|
@@ -51,7 +51,7 @@ class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
|
||||||
|
|
||||||
|
def getRandOpAndAddr (dw_addr: Int, is_store: Boolean): (Opcode, Int) =
|
||||||
|
{
|
||||||
|
- val typ = AccessType.values.toIndexedSeq(rand_range(0,6))
|
||||||
|
+ val typ = AccessType.values.toIndexedSeq(rand_range(0,4))
|
||||||
|
if (is_store)
|
||||||
|
{
|
||||||
|
if (typ == byte || typ ==ubyte) (SB, dw_addr + rand_addr_b(8))
|
||||||
|
@@ -110,13 +110,13 @@ class SeqMem(xregs: HWRegPool, mem: Mem, use_amo: Boolean) extends InstSeq
|
||||||
|
candidates += seq_load_addrfn(LH, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(LHU, rand_addr_h)
|
||||||
|
candidates += seq_load_addrfn(LW, rand_addr_w)
|
||||||
|
- candidates += seq_load_addrfn(LWU, rand_addr_w)
|
||||||
|
- candidates += seq_load_addrfn(LD, rand_addr_d)
|
||||||
|
+ //candidates += seq_load_addrfn(LWU, rand_addr_w)
|
||||||
|
+ //candidates += seq_load_addrfn(LD, rand_addr_d)
|
||||||
|
|
||||||
|
candidates += seq_store_addrfn(SB, rand_addr_b)
|
||||||
|
candidates += seq_store_addrfn(SH, rand_addr_h)
|
||||||
|
candidates += seq_store_addrfn(SW, rand_addr_w)
|
||||||
|
- candidates += seq_store_addrfn(SD, rand_addr_d)
|
||||||
|
+ //candidates += seq_store_addrfn(SD, rand_addr_d)
|
||||||
|
|
||||||
|
if (use_amo)
|
||||||
|
{
|
Binary file not shown.
|
@ -0,0 +1,343 @@
|
||||||
|
package torture
|
||||||
|
package testrun
|
||||||
|
|
||||||
|
import scopt.OptionParser
|
||||||
|
import scala.sys.process._
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.util.Properties
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.util.Scanner
|
||||||
|
import java.io.File
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
|
case class Options(var testAsmName: Option[String] = None,
|
||||||
|
var testBinName: Option[String] = None,
|
||||||
|
var cSimPath: Option[String] = None,
|
||||||
|
var rtlSimPath: Option[String] = None,
|
||||||
|
var seekOutFailure: Boolean = false,
|
||||||
|
var output: Boolean = false,
|
||||||
|
var dumpWaveform: Boolean = false,
|
||||||
|
var confFileName: String = "config/default.config")
|
||||||
|
|
||||||
|
abstract sealed class Result
|
||||||
|
case object Failed extends Result
|
||||||
|
case object Mismatched extends Result
|
||||||
|
case object Matched extends Result
|
||||||
|
|
||||||
|
object TestRunner extends App
|
||||||
|
{
|
||||||
|
var opts = new Options()
|
||||||
|
override def main(args: Array[String]) =
|
||||||
|
{
|
||||||
|
//TODO: need to make the class Options above look like the new website should get us to remove the options!
|
||||||
|
val parser = new OptionParser[Options]("testrun/run") {
|
||||||
|
opt[String]('C', "config") valueName("<file>") text("config file") action {(s: String, c) => c.copy(confFileName = s)}
|
||||||
|
opt[String]('a', "asm") valueName("<file>") text("input ASM file") action {(s: String, c) => c.copy(testAsmName = Some(s))}
|
||||||
|
opt[String]('c', "csim") valueName("<file>") text("C simulator") action {(s: String, c) => c.copy(cSimPath = Some(s))}
|
||||||
|
opt[String]('r', "rtlsim") valueName("<file>") text("RTL simulator") action {(s: String, c) => c.copy(rtlSimPath = Some(s))}
|
||||||
|
opt[Unit]("seek") abbr("s") text("Seek for failing pseg") action {(_, c) => c.copy(seekOutFailure = true)}
|
||||||
|
opt[Unit]("output") abbr("o") text("Write verbose output of simulators to file") action {(_, c) => c.copy(output = true)}
|
||||||
|
opt[Unit]("dumpwaveform") abbr("dump") text("Create a vcd from csim or a vpd from vsim") action {(_, c) => c.copy(dumpWaveform= true)}
|
||||||
|
}
|
||||||
|
parser.parse(args, Options()) match {
|
||||||
|
case Some(options) =>
|
||||||
|
{
|
||||||
|
opts = options;
|
||||||
|
testrun(opts.testAsmName, opts.cSimPath, opts.rtlSimPath, opts.seekOutFailure, opts.output, opts.dumpWaveform, opts.confFileName)
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
System.exit(1) // error message printed by parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var virtualMode = false
|
||||||
|
var maxcycles = 10000000
|
||||||
|
var hwacha = true
|
||||||
|
|
||||||
|
def testrun(testAsmName: Option[String],
|
||||||
|
cSimPath: Option[String],
|
||||||
|
rtlSimPath: Option[String],
|
||||||
|
doSeek: Boolean,
|
||||||
|
output: Boolean,
|
||||||
|
dumpWaveform: Boolean,
|
||||||
|
confFileName: String): (Boolean, Option[Seq[String]]) =
|
||||||
|
{
|
||||||
|
|
||||||
|
val config = new Properties()
|
||||||
|
val configin = new FileInputStream(confFileName)
|
||||||
|
config.load(configin)
|
||||||
|
configin.close()
|
||||||
|
|
||||||
|
maxcycles = config.getProperty("torture.testrun.maxcycles", "10000000").toInt
|
||||||
|
virtualMode = (config.getProperty("torture.testrun.virtual", "false").toLowerCase == "true")
|
||||||
|
val dump = (config.getProperty("torture.testrun.dump", "false").toLowerCase == "true")
|
||||||
|
val seek = (config.getProperty("torture.testrun.seek", "true").toLowerCase == "true")
|
||||||
|
hwacha = (config.getProperty("torture.testrun.vec", "true").toLowerCase == "true")
|
||||||
|
|
||||||
|
// Figure out which binary file to test
|
||||||
|
val finalBinName = testAsmName match {
|
||||||
|
case Some(asmName) => compileAsmToBin(asmName)
|
||||||
|
case None => {
|
||||||
|
val gen = generator.Generator
|
||||||
|
val newAsmName = gen.generate(confFileName, "test")
|
||||||
|
compileAsmToBin(newAsmName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the simulators that should be tested
|
||||||
|
val simulators = new ArrayBuffer[(String, (String, Boolean, Boolean, Boolean) => String)]
|
||||||
|
simulators += (("spike",runIsaSim _ ))
|
||||||
|
cSimPath match {
|
||||||
|
case Some(p) => simulators += (("csim",runCSim(p) _ ))
|
||||||
|
case None =>
|
||||||
|
}
|
||||||
|
rtlSimPath match {
|
||||||
|
case Some(p) => simulators += (("rtlsim",runRtlSim(p) _ ))
|
||||||
|
case None =>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the simulators on the complete binary
|
||||||
|
finalBinName match {
|
||||||
|
case Some(binName) => {
|
||||||
|
val res = runSimulators(binName, simulators, false, output, dumpWaveform || dump)
|
||||||
|
val fail_names = res.filter(_._3 == Failed).map(_._1.toString)
|
||||||
|
val mism_names = res.filter(_._3 == Mismatched).map(_._1.toString)
|
||||||
|
val bad_sims = res.filter(_._3 != Matched).map(_._2)
|
||||||
|
if (bad_sims.length > 0) {
|
||||||
|
println("///////////////////////////////////////////////////////")
|
||||||
|
println("// Simulation failed for " + binName + ":")
|
||||||
|
fail_names.foreach(n => println("\t"+n))
|
||||||
|
println("// Mismatched sigs for " + binName + ":")
|
||||||
|
mism_names.foreach(n => println("\t"+n))
|
||||||
|
println("// Rerunning in Debug mode")
|
||||||
|
// run debug for failed/mismatched
|
||||||
|
val resDebug = runSimulators(binName, simulators, true, output, dumpWaveform || dump)
|
||||||
|
println("///////////////////////////////////////////////////////")
|
||||||
|
if(doSeek || seek) {
|
||||||
|
val failName = seekOutFailureBinary(binName, bad_sims, true, output, dumpWaveform || dump)
|
||||||
|
println("///////////////////////////////////////////////////////")
|
||||||
|
println("// Failing pseg identified. Binary at " + failName)
|
||||||
|
println("///////////////////////////////////////////////////////")
|
||||||
|
dumpFromBin(failName)
|
||||||
|
(true, Some(failName.split("/")))
|
||||||
|
} else {
|
||||||
|
dumpFromBin(binName)
|
||||||
|
(true, Some(binName.split("/")))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("///////////////////////////////////////////////////////")
|
||||||
|
println("// All signatures match for " + binName)
|
||||||
|
println("///////////////////////////////////////////////////////")
|
||||||
|
(false, Some(binName.split("/")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case None => {
|
||||||
|
println("Error: ASM file could not be compiled or generated.")
|
||||||
|
(false, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def compileAsmToBin(asmFileName: String): Option[String] = {
|
||||||
|
assert(asmFileName.endsWith(".S"), println("Filename does not end in .S"))
|
||||||
|
val binFileName = asmFileName.dropRight(2)
|
||||||
|
var process = ""
|
||||||
|
if (virtualMode)
|
||||||
|
{
|
||||||
|
println("Virtual mode")
|
||||||
|
val entropy = (new Random()).nextLong()
|
||||||
|
println("entropy: " + entropy)
|
||||||
|
process = "riscv64-unknown-elf-gcc -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -Wa,-march=rv64imafd -DENTROPY=" + entropy + " -std=gnu99 -O2 -I./env/v -I./macros/scalar -T./env/v/link.ld ./env/v/entry.S ./env/v/vm.c " + asmFileName + " -lc -o " + binFileName
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
println("Physical mode")
|
||||||
|
process = "riscv64-unknown-elf-gcc -nostdlib -nostartfiles -Wa,-march=rv64imafd -I./env/p -T./env/p/link.ld " + asmFileName + " -o " + binFileName
|
||||||
|
}
|
||||||
|
val pb = Process(process)
|
||||||
|
val exitCode = pb.!
|
||||||
|
if (exitCode == 0) Some(binFileName) else None
|
||||||
|
}
|
||||||
|
|
||||||
|
def dumpFromBin(binFileName: String): Option[String] = {
|
||||||
|
val dumpFileName = binFileName + ".dump"
|
||||||
|
val pd = Process("riscv64-unknown-elf-objdump --disassemble-all --section=.text --section=.data --section=.bss " + binFileName)
|
||||||
|
val dump = pd.!!
|
||||||
|
val fw = new FileWriter(dumpFileName)
|
||||||
|
fw.write(dump)
|
||||||
|
fw.close()
|
||||||
|
Some(dumpFileName)
|
||||||
|
}
|
||||||
|
def generateHexFromBin(binFileName: String) = {
|
||||||
|
import java.io.File
|
||||||
|
// Determine binary size
|
||||||
|
val binfile = new File(binFileName)
|
||||||
|
|
||||||
|
val hexlines = 2 << (Math.log(binfile.length >>> 4)/Math.log(2)+1).toInt
|
||||||
|
|
||||||
|
val hexFileName = binFileName + ".hex"
|
||||||
|
val pd = Process("elf2hex 16 "+hexlines+" " + binFileName)
|
||||||
|
val hexdump = pd.!!
|
||||||
|
|
||||||
|
val fw = new FileWriter(hexFileName)
|
||||||
|
fw.write(hexdump)
|
||||||
|
fw.close()
|
||||||
|
|
||||||
|
hexFileName
|
||||||
|
}
|
||||||
|
|
||||||
|
def runSim(sim: String, simargs: Seq[String], signature: String, output: Boolean, outName: String, args: Seq[String], invokebin: String): String = {
|
||||||
|
val cmd = Seq(sim) ++ simargs ++ Seq("+signature="+signature) ++ args ++ Seq(invokebin)
|
||||||
|
println("running:"+cmd)
|
||||||
|
if(output) {
|
||||||
|
var fw = new FileWriter(outName+".raw")
|
||||||
|
cmd ! ProcessLogger(
|
||||||
|
{s => fw.write(s+"\n") },
|
||||||
|
{s => fw.write(s+"\n") })
|
||||||
|
fw.close()
|
||||||
|
val fwd = new FileWriter(outName)
|
||||||
|
Process(Seq("cat",outName+".raw")) #| Process("spike-dasm --extension=hwacha") ! ProcessLogger(
|
||||||
|
{s => fwd.write(s+"\n") },
|
||||||
|
{s => fwd.write(s+"\n") })
|
||||||
|
fwd.close()
|
||||||
|
new File(outName+".raw").delete()
|
||||||
|
} else {
|
||||||
|
cmd !!
|
||||||
|
}
|
||||||
|
val sigFile = new File(signature)
|
||||||
|
if(!sigFile.exists()) ""
|
||||||
|
else new Scanner(sigFile).useDelimiter("\\Z").next()
|
||||||
|
}
|
||||||
|
|
||||||
|
def runCSim(sim: String)(bin: String, debug: Boolean, output: Boolean, dump: Boolean): String = {
|
||||||
|
val outputArgs = if(output) Seq("+verbose") else Seq()
|
||||||
|
val dumpArgs = if(dump && debug) Seq("-v"+bin+".vcd") else Seq()
|
||||||
|
val debugArgs = if(debug) outputArgs ++ dumpArgs else Seq()
|
||||||
|
val simArgs = Seq("+max-cycles="+maxcycles) ++ debugArgs
|
||||||
|
val simName = sim
|
||||||
|
runSim(simName, simArgs, bin+".csim.sig", output, bin+".csim.out", Seq(), bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
def runRtlSim(sim: String)(bin: String, debug: Boolean, output: Boolean, dump: Boolean): String = {
|
||||||
|
val outputArgs = if(output) Seq("+verbose") else Seq()
|
||||||
|
val dumpArgs = if(dump && debug) Seq("+vcdplusfile="+bin+".vpd") else Seq()
|
||||||
|
val debugArgs = if(debug) outputArgs ++ dumpArgs else Seq()
|
||||||
|
val simArgs = Seq("+permissive") ++ Seq("+max-cycles="+maxcycles) ++ debugArgs ++ Seq("+permissive-off")
|
||||||
|
val simName = sim
|
||||||
|
runSim(simName, simArgs, bin+".rtlsim.sig", output, bin+".rtlsim.out", Seq(), bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
def runIsaSim(bin: String, debug: Boolean, output: Boolean, dump: Boolean): String = {
|
||||||
|
val debugArgs = if(debug && output) Seq("-d") else Seq()
|
||||||
|
val simArgs = if (hwacha) Seq("--extension=hwacha") else Seq()
|
||||||
|
runSim("spike", simArgs ++ debugArgs, bin+".spike.sig", output, bin+".spike.out", Seq(), bin)
|
||||||
|
}
|
||||||
|
|
||||||
|
def runSimulators(bin: String, simulators: Seq[(String, (String, Boolean, Boolean, Boolean) => String)], debug: Boolean, output: Boolean, dumpWaveform: Boolean): Seq[(String, (String, (String, Boolean, Boolean, Boolean) => String), Result)] = {
|
||||||
|
if(simulators.length == 0) println("Warning: No simulators specified for comparison. Comparing ISA to ISA...")
|
||||||
|
val isa_sig = runIsaSim(bin, debug, output, false)
|
||||||
|
simulators.map { case (name, sim) => {
|
||||||
|
val res =
|
||||||
|
try {
|
||||||
|
if (isa_sig != sim(bin, debug, output, dumpWaveform)) Mismatched
|
||||||
|
else Matched
|
||||||
|
} catch {
|
||||||
|
case e:RuntimeException => Failed
|
||||||
|
}
|
||||||
|
(name, (name, sim), res)
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
def seekOutFailureBinary(bin: String, simulators: Seq[(String, (String, Boolean, Boolean, Boolean) => String)], debug: Boolean, output: Boolean, dumpWaveform: Boolean): String =
|
||||||
|
{
|
||||||
|
// Find failing asm file
|
||||||
|
val source = scala.io.Source.fromFile(bin+".S")
|
||||||
|
val lines = source.mkString
|
||||||
|
source.close()
|
||||||
|
|
||||||
|
// For all psegs
|
||||||
|
val psegFinder = """pseg_\d+""".r
|
||||||
|
val psegNums: List[Int] = psegFinder.findAllIn(lines).map(_.drop(5).toInt).toList
|
||||||
|
var (low, high) = (psegNums.min, psegNums.max)
|
||||||
|
if (low == high)
|
||||||
|
{
|
||||||
|
println("Only one pseg was detected.")
|
||||||
|
return bin
|
||||||
|
}
|
||||||
|
var lastfound = ""
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
val p = (high + low)/2
|
||||||
|
// Replace jump to pseg with jump to reg_dump
|
||||||
|
val psegReplacer = ("pseg_" + p + ":\\n").r
|
||||||
|
val newAsmSource = psegReplacer.replaceAllIn(lines, "pseg_" + p + ":\n\tj reg_dump\n")
|
||||||
|
val newAsmName = bin + "_pseg_" + p + ".S"
|
||||||
|
val fw = new FileWriter(newAsmName)
|
||||||
|
fw.write(newAsmSource)
|
||||||
|
fw.close()
|
||||||
|
|
||||||
|
// Compile new asm and test on sims
|
||||||
|
val newBinName = compileAsmToBin(newAsmName)
|
||||||
|
newBinName match {
|
||||||
|
case Some(b) => {
|
||||||
|
val res = runSimulators(b, simulators, debug, output, dumpWaveform)
|
||||||
|
if (!res.forall(_._3 == Matched)) {
|
||||||
|
lastfound = b
|
||||||
|
high = p-1
|
||||||
|
} else {
|
||||||
|
low = p+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case None => println("Warning: Subset test could not compile.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastfound == "") {
|
||||||
|
println("Warning: No subset tests could compile.")
|
||||||
|
bin
|
||||||
|
} else {
|
||||||
|
lastfound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def seekOutFailure(bin: String, simulators: Seq[(String, (String, Boolean, Boolean, Boolean) => String)], debug: Boolean, output: Boolean, dumpWaveform: Boolean): String = {
|
||||||
|
// Find failing asm file
|
||||||
|
val source = scala.io.Source.fromFile(bin+".S")
|
||||||
|
val lines = source.mkString
|
||||||
|
source.close()
|
||||||
|
|
||||||
|
// For all psegs
|
||||||
|
val psegFinder = """pseg_\d+""".r
|
||||||
|
val psegNums: List[Int] = psegFinder.findAllIn(lines).map(_.drop(5).toInt).toList
|
||||||
|
if (psegNums.min == psegNums.max)
|
||||||
|
{
|
||||||
|
println("Only one pseg was detected.")
|
||||||
|
return bin
|
||||||
|
}
|
||||||
|
for( p <- psegNums.min to psegNums.max) {
|
||||||
|
// Replace jump to pseg with jump to reg_dump
|
||||||
|
val psegReplacer = ("pseg_" + p + ":\\n").r
|
||||||
|
val newAsmSource = psegReplacer.replaceAllIn(lines, "pseg_" + p + ":\n\tj reg_dump\n")
|
||||||
|
val newAsmName = bin + "_pseg_" + p + ".S"
|
||||||
|
val fw = new FileWriter(newAsmName)
|
||||||
|
fw.write(newAsmSource)
|
||||||
|
fw.close()
|
||||||
|
|
||||||
|
// Compile new asm and test on sims
|
||||||
|
val newBinName = compileAsmToBin(newAsmName)
|
||||||
|
newBinName match {
|
||||||
|
case Some(b) => {
|
||||||
|
val res = runSimulators(b, simulators, debug, output, dumpWaveform)
|
||||||
|
if (!res.forall(_._3 == Matched)) {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case None => println("Warning: Subset test could not compile.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("Warning: No subset tests could compile.")
|
||||||
|
bin
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue