tools: add riscv-torture

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-07-12 18:13:01 +08:00
parent 18de7f2e00
commit ac245a5d6c
42 changed files with 4893 additions and 0 deletions

4
tools/riscv-torture/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.*.swp
output/test*
output/failedtests
*target/

3
tools/riscv-torture/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "env"]
path = env
url = https://github.com/riscv/riscv-test-env.git

View File

@ -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)'

260
tools/riscv-torture/README Normal file
View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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")
}
}

View File

@ -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)
}

View File

@ -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))
}

View File

@ -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")

View File

@ -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))
}
}
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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"
}
}

View File

@ -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
}
}
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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))
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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)()
}

View File

@ -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))
}

View File

@ -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()
}
}

View File

@ -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
}
}

View File

@ -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.

View File

@ -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)
}
}

View File

@ -0,0 +1 @@
sbt.version=1.4.4

View File

@ -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.

View File

@ -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
}
}