| @@ -0,0 +1,355 @@ | |||
| ### Project Specific stuff | |||
| test_run_dir/* | |||
| ### XilinxISE template | |||
| # intermediate build files | |||
| *.bgn | |||
| *.bit | |||
| *.bld | |||
| *.cmd_log | |||
| *.drc | |||
| *.ll | |||
| *.lso | |||
| *.msd | |||
| *.msk | |||
| *.ncd | |||
| *.ngc | |||
| *.ngd | |||
| *.ngr | |||
| *.pad | |||
| *.par | |||
| *.pcf | |||
| *.prj | |||
| *.ptwx | |||
| *.rbb | |||
| *.rbd | |||
| *.stx | |||
| *.syr | |||
| *.twr | |||
| *.twx | |||
| *.unroutes | |||
| *.ut | |||
| *.xpi | |||
| *.xst | |||
| *_bitgen.xwbt | |||
| *_envsettings.html | |||
| *_map.map | |||
| *_map.mrp | |||
| *_map.ngm | |||
| *_map.xrpt | |||
| *_ngdbuild.xrpt | |||
| *_pad.csv | |||
| *_pad.txt | |||
| *_par.xrpt | |||
| *_summary.html | |||
| *_summary.xml | |||
| *_usage.xml | |||
| *_xst.xrpt | |||
| # project-wide generated files | |||
| *.gise | |||
| par_usage_statistics.html | |||
| usage_statistics_webtalk.html | |||
| webtalk.log | |||
| webtalk_pn.xml | |||
| # generated folders | |||
| iseconfig/ | |||
| xlnx_auto_0_xdb/ | |||
| xst/ | |||
| _ngo/ | |||
| _xmsgs/ | |||
| ### Eclipse template | |||
| *.pydevproject | |||
| .metadata | |||
| .gradle | |||
| bin/ | |||
| tmp/ | |||
| *.tmp | |||
| *.bak | |||
| *.swp | |||
| *~.nib | |||
| local.properties | |||
| .settings/ | |||
| .loadpath | |||
| # Eclipse Core | |||
| .project | |||
| # External tool builders | |||
| .externalToolBuilders/ | |||
| # Locally stored "Eclipse launch configurations" | |||
| *.launch | |||
| # CDT-specific | |||
| .cproject | |||
| # JDT-specific (Eclipse Java Development Tools) | |||
| .classpath | |||
| # Java annotation processor (APT) | |||
| .factorypath | |||
| # PDT-specific | |||
| .buildpath | |||
| # sbteclipse plugin | |||
| .target | |||
| # TeXlipse plugin | |||
| .texlipse | |||
| ### C template | |||
| # Object files | |||
| *.o | |||
| *.ko | |||
| *.obj | |||
| *.elf | |||
| # Precompiled Headers | |||
| *.gch | |||
| *.pch | |||
| # Libraries | |||
| *.lib | |||
| *.a | |||
| *.la | |||
| *.lo | |||
| # Shared objects (inc. Windows DLLs) | |||
| *.dll | |||
| *.so | |||
| *.so.* | |||
| *.dylib | |||
| # Executables | |||
| *.exe | |||
| *.out | |||
| *.app | |||
| *.i*86 | |||
| *.x86_64 | |||
| *.hex | |||
| # Debug files | |||
| *.dSYM/ | |||
| ### SBT template | |||
| # Simple Build Tool | |||
| # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control | |||
| target/ | |||
| lib_managed/ | |||
| src_managed/ | |||
| project/boot/ | |||
| .history | |||
| .cache | |||
| ### Emacs template | |||
| # -*- mode: gitignore; -*- | |||
| *~ | |||
| \#*\# | |||
| /.emacs.desktop | |||
| /.emacs.desktop.lock | |||
| *.elc | |||
| auto-save-list | |||
| tramp | |||
| .\#* | |||
| # Org-mode | |||
| .org-id-locations | |||
| *_archive | |||
| # flymake-mode | |||
| *_flymake.* | |||
| # eshell files | |||
| /eshell/history | |||
| /eshell/lastdir | |||
| # elpa packages | |||
| /elpa/ | |||
| # reftex files | |||
| *.rel | |||
| # AUCTeX auto folder | |||
| /auto/ | |||
| # cask packages | |||
| .cask/ | |||
| ### Vim template | |||
| [._]*.s[a-w][a-z] | |||
| [._]s[a-w][a-z] | |||
| *.un~ | |||
| Session.vim | |||
| .netrwhist | |||
| *~ | |||
| ### JetBrains template | |||
| # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio | |||
| *.iml | |||
| ## Directory-based project format: | |||
| .idea/ | |||
| # if you remove the above rule, at least ignore the following: | |||
| # User-specific stuff: | |||
| # .idea/workspace.xml | |||
| # .idea/tasks.xml | |||
| # .idea/dictionaries | |||
| # Sensitive or high-churn files: | |||
| # .idea/dataSources.ids | |||
| # .idea/dataSources.xml | |||
| # .idea/sqlDataSources.xml | |||
| # .idea/dynamic.xml | |||
| # .idea/uiDesigner.xml | |||
| # Gradle: | |||
| # .idea/gradle.xml | |||
| # .idea/libraries | |||
| # Mongo Explorer plugin: | |||
| # .idea/mongoSettings.xml | |||
| ## File-based project format: | |||
| *.ipr | |||
| *.iws | |||
| ## Plugin-specific files: | |||
| # IntelliJ | |||
| /out/ | |||
| # mpeltonen/sbt-idea plugin | |||
| .idea_modules/ | |||
| # JIRA plugin | |||
| atlassian-ide-plugin.xml | |||
| # Crashlytics plugin (for Android Studio and IntelliJ) | |||
| com_crashlytics_export_strings.xml | |||
| crashlytics.properties | |||
| crashlytics-build.properties | |||
| ### C++ template | |||
| # Compiled Object files | |||
| *.slo | |||
| *.lo | |||
| *.o | |||
| *.obj | |||
| # Precompiled Headers | |||
| *.gch | |||
| *.pch | |||
| # Compiled Dynamic libraries | |||
| *.so | |||
| *.dylib | |||
| *.dll | |||
| # Fortran module files | |||
| *.mod | |||
| # Compiled Static libraries | |||
| *.lai | |||
| *.la | |||
| *.a | |||
| *.lib | |||
| # Executables | |||
| *.exe | |||
| *.out | |||
| *.app | |||
| ### OSX template | |||
| .DS_Store | |||
| .AppleDouble | |||
| .LSOverride | |||
| # Icon must end with two \r | |||
| Icon | |||
| # Thumbnails | |||
| ._* | |||
| # Files that might appear in the root of a volume | |||
| .DocumentRevisions-V100 | |||
| .fseventsd | |||
| .Spotlight-V100 | |||
| .TemporaryItems | |||
| .Trashes | |||
| .VolumeIcon.icns | |||
| # Directories potentially created on remote AFP share | |||
| .AppleDB | |||
| .AppleDesktop | |||
| Network Trash Folder | |||
| Temporary Items | |||
| .apdisk | |||
| ### Xcode template | |||
| # Xcode | |||
| # | |||
| # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore | |||
| ## Build generated | |||
| build/ | |||
| DerivedData | |||
| ## Various settings | |||
| *.pbxuser | |||
| !default.pbxuser | |||
| *.mode1v3 | |||
| !default.mode1v3 | |||
| *.mode2v3 | |||
| !default.mode2v3 | |||
| *.perspectivev3 | |||
| !default.perspectivev3 | |||
| xcuserdata | |||
| ## Other | |||
| *.xccheckout | |||
| *.moved-aside | |||
| *.xcuserstate | |||
| ### Scala template | |||
| *.class | |||
| *.log | |||
| # sbt specific | |||
| .cache | |||
| .history | |||
| .lib/ | |||
| dist/* | |||
| target/ | |||
| lib_managed/ | |||
| src_managed/ | |||
| project/boot/ | |||
| project/plugins/project/ | |||
| .ensime | |||
| .ensime_cache/ | |||
| # Scala-IDE specific | |||
| .scala_dependencies | |||
| .worksheet | |||
| ### Java template | |||
| *.class | |||
| # Mobile Tools for Java (J2ME) | |||
| .mtj.tmp/ | |||
| # Package Files # | |||
| *.jar | |||
| *.war | |||
| *.ear | |||
| # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | |||
| hs_err_pid* | |||
| *.fir | |||
| *.json | |||
| *.xml | |||
| # ENSIME, metals and friends | |||
| .ensime* | |||
| .metals* | |||
| .bloop* | |||
| .projectile | |||
| target/ | |||
| scratchpad.scala | |||
| log/ | |||
| index.html | |||
| @@ -0,0 +1,31 @@ | |||
| This is the coursework for the graded part of the TDT4255 course at NTNU. | |||
| Since it is the authors opinion that most tools out there are vastly underdesigned, this project comes | |||
| with a lot of added homegrown utilities, including a RISC-V parser, assembler and interpreter. | |||
| When you test a design with a given program, that program is first parsed, then run in a software interpreter | |||
| to get correct output, then assembled into a binary. | |||
| This binary will then be loaded to your synthesized design (your processor) by the test harness provided in | |||
| the skeleton code, along with any initial state. | |||
| Your processor will run the supplied binary, and the changes to state (memory and registers) will be recorded | |||
| and compared with the interpreter log. | |||
| If it matches, your processor works, if not, you get an execution trace, hopefully showing what went wrong and | |||
| where. | |||
| To get started, read the exercise.org file, it goes over the first pieces of the puzzle. | |||
| If you want to learn chisel on your own and use this project please send me some feedback on what you liked, | |||
| disliked and what could have been improved :) | |||
| If you end up using it for a course you're teaching I would be thrilled too. | |||
| In this case, you can spend the time you're saving by sending a pull requests with some improvements! | |||
| Pull requests are more than welcome! | |||
| Nice to have list: | |||
| * More sophisticated test feedback. A detailed error report on why the processor design failed. | |||
| * Scaffolding to run synthesized designs. Preferrably targeting the PYNQ platform. | |||
| * A fix for whatever problems *you* run into when using this project. | |||
| * Either a battery of tests to find corner cases stress testing forwarders, hazard detectors etc, or even better, the tools to generate code with hazards automatically. | |||
| @@ -0,0 +1,49 @@ | |||
| * Tasks | |||
| ** DONE File IO and test | |||
| ** DONE Stop exploding the heap with logs :DDD | |||
| ** DONE Fix DONE instruction for VM termination | |||
| *** DONE Add setting instructions | |||
| ** DONE Add assembler | |||
| ** DONE Chisel tester | |||
| ** DONE Add LF | |||
| ** DONE Redo colors in fansi. ANSI fucks up string formatting | |||
| ** DONE Columnize log events | |||
| ** DONE Chisel test log evaluator | |||
| ** DONE Create giftWrapper script | |||
| ** DONE Better sourceinfo stuff | |||
| Good enough | |||
| ** DONE Test options | |||
| *** DONE How much NOP pad? | |||
| *** DONE Verbosity? | |||
| *** DONE Which tests? | |||
| ** DONE ish Step counter, pretty print VM log, including final memory state | |||
| ** TODO More programs | |||
| *** DONE Real programs | |||
| *** TODO Basic programs | |||
| Needs more | |||
| ** DONE Merge in LF changes | |||
| ** TODO Breakpoints | |||
| *** TODO VM breakpoints | |||
| **** TODO Record breakpoints in chisel tester | |||
| *** TODO Chisel breakpoints | |||
| **** TODO Freeze processor to record state | |||
| **** TODO Record breakpoints in chisel tester | |||
| *** TODO Draw breakpoints in the printer | |||
| ** TODO Calculate steps needed | |||
| ** TODO Unmangle derailed traces | |||
| With incorrect designs the trace printer ends up printing a lot of diveregent | |||
| unsychnronizable blocks | |||
| ** DONE Fix DONE instruction | |||
| *** DONE Parse error | |||
| *** DONE Use DONE address | |||
| ** DONE Hazard generator | |||
| good enough | |||
| * Maybe | |||
| ** DONE Move instruction recording to IMEM rather than IF? | |||
| Only care about what IF gets, won't have to deal with whatever logic is in IF. | |||
| ** DONE Figure out why loading instructions backwards made shit werk | |||
| Not as funny as you'd think. The issue was overwriting the last written instruction with 0 | |||
| @@ -0,0 +1,71 @@ | |||
| def scalacOptionsVersion(scalaVersion: String): Seq[String] = { | |||
| Seq() ++ { | |||
| // If we're building with Scala > 2.11, enable the compile option | |||
| // switch to support our anonymous Bundle definitions: | |||
| // https://github.com/scala/bug/issues/10047 | |||
| CrossVersion.partialVersion(scalaVersion) match { | |||
| case Some((2, scalaMajor: Long)) if scalaMajor < 12 => Seq() | |||
| case _ => Seq("-Xsource:2.11") | |||
| } | |||
| } | |||
| } | |||
| def javacOptionsVersion(scalaVersion: String): Seq[String] = { | |||
| Seq() ++ { | |||
| // Scala 2.12 requires Java 8. We continue to generate | |||
| // Java 7 compatible code for Scala 2.11 | |||
| // for compatibility with old clients. | |||
| CrossVersion.partialVersion(scalaVersion) match { | |||
| case Some((2, scalaMajor: Long)) if scalaMajor < 12 => | |||
| Seq("-source", "1.7", "-target", "1.7") | |||
| case _ => | |||
| Seq("-source", "1.8", "-target", "1.8") | |||
| } | |||
| } | |||
| } | |||
| name := "FiveStage" | |||
| version := "2.0.0" | |||
| scalaVersion := "2.12.8" | |||
| crossScalaVersions := Seq("2.11.12", "2.12.4") | |||
| resolvers ++= Seq( | |||
| Resolver.sonatypeRepo("snapshots"), | |||
| Resolver.sonatypeRepo("releases") | |||
| ) | |||
| // Provide a managed dependency on X if -DXVersion="" is supplied on the command line. | |||
| val defaultVersions = Map( | |||
| "chisel3" -> "3.1.+", | |||
| "chisel-iotesters" -> "1.2.+" | |||
| ) | |||
| libraryDependencies ++= (Seq("chisel3","chisel-iotesters").map { | |||
| dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }) | |||
| val versionOfScala = "2.12.4" | |||
| val fs2Version = "0.10.3" | |||
| val catsVersion = "1.1.0" | |||
| val catsEffectVersion = "0.10" | |||
| libraryDependencies ++= Dependencies.backendDeps.value | |||
| scalacOptions ++= scalacOptionsVersion(scalaVersion.value) | |||
| scalacOptions ++= Seq("-language:reflectiveCalls") | |||
| scalacOptions ++= Seq("-Ypartial-unification") | |||
| javacOptions ++= javacOptionsVersion(scalaVersion.value) | |||
| // testOptions in Test += Tests.Argument("-oF") | |||
| resolvers += Resolver.sonatypeRepo("releases") | |||
| addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7") | |||
| addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.2.4") | |||
| addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full) | |||
| testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-eS") | |||
| addCompilerPlugin("io.tryp" % "splain" % "0.4.1" cross CrossVersion.patch) | |||
| @@ -0,0 +1,25 @@ | |||
| #!/bin/bash | |||
| read -p "Enter your student username (the one you use on badboard): " username | |||
| echo "Cleaning your project" | |||
| ./sbt.sh clean | |||
| echo "Creating archive" | |||
| mkdir wrap | |||
| cp -r src ./wrap/ | |||
| cp build.sbt ./wrap | |||
| cp project/Dependencies.scala ./wrap/project/Dependencies.scala | |||
| cp project/build.properties ./wrap/project/build.properties | |||
| cp sbt.sh ./wrap | |||
| tar czfv $username.gz wrap | |||
| rm -rf ./wrap | |||
| echo "Unwrapping and testing your wrapped package" | |||
| mkdir wrapTest | |||
| tar -C ./wrapTest -xvf $username.gz | |||
| ./wrapTest/wrap/sbt.sh test | |||
| rm -rf ./wrapTest | |||
| echo "If the test output looked good then you're good to go!" | |||
| @@ -0,0 +1,120 @@ | |||
| * Exercise 1 & 2 | |||
| The task in this exercise is to implement a 5-stage pipelined processor for | |||
| the RISCV32I instruction set. | |||
| You will use the skeleton code which comes with a freebies, namely the registers, | |||
| instruction memory and data memory. | |||
| These are contained in the files Registers.scala, Dmem.scala and Imem.scala | |||
| ** Getting started | |||
| In order to make a correct design in a somewhat expedient fashion you need to be | |||
| *methodical!* | |||
| This means you should have a good idea of how your processor should work *before* | |||
| you start writing code. While chisel is more pleasent to work with than other HDLs | |||
| the bricoleur approach is not recommended. | |||
| My recommended approach is therefore to create a sketch of your processor design. | |||
| Start with an overall sketch showing all the components, then drill down. | |||
| In your sketch you will eventually add a box for registers, IMEM and DMEM, which | |||
| should make it clear how the already finished modules fit into the grander design, | |||
| making the skeleton-code less mysterious. | |||
| Next, your focus should be to get the simplest possible program to work, a program | |||
| that simply does a single add operation. Info is progressively being omitted in the | |||
| later steps, after all brevity is ~~the soul of~~ wit | |||
| Step 0: | |||
| In order to verify that the project is set up properly, open sbt in your project root | |||
| by typing ./sbt (or simply sbt if you already use scala). | |||
| sbt, which stands for scala build tool will provide you with a repl where you can | |||
| compile and test your code. | |||
| The initial run will take quite a while to boot as all the necessary stuff is downloaded. | |||
| Step ¼: | |||
| In your console, type `compile` to verify that everything compiles correctly. | |||
| Step ½: | |||
| In your console, type `test` to verify that the tests run, and that chisel can correctly | |||
| build your design. | |||
| This command will unleash the full battery of tests on you. | |||
| Step ¾: | |||
| In your console, type `testOnly FiveStage.SelectedTests` to run only the tests that you | |||
| have defined in the testConf.scala file. | |||
| In the skeleton this will run the simple add test only, but you should alter this | |||
| manifest as you build your processor to run more complex tests as a stopgap between | |||
| running single tests and the full battery. | |||
| Be aware that chisel will make quite a lot of noise during test running. I'm not | |||
| aware of a good way to get rid of this sadly. | |||
| Step 1: | |||
| In order to do this, your processor must be able to select new instructions, so in | |||
| your IF.scala you must increment the PC. | |||
| Step 2: | |||
| Next, the instruction must be forwarded to the ID stage, so you will need to add the | |||
| instruction to the io part of InstructionFetch as an output. | |||
| Step 3: | |||
| Your ID stage must take in an instruction in its io bundle, and decode it. In the | |||
| skeleton code a decoder has already been instantiated in the InstructionDecode module, | |||
| but it is given a dummy instruction. | |||
| Likewise, you must ensure that the register gets the relevant data. | |||
| This can be done by using the instruction class methods (TopLevelSignals.scala) which | |||
| lets us access the relevant part of the instruction with the dot operator. | |||
| For instance: | |||
| #+BEGIN_SRC scala | |||
| myModule.io.funct6 := io.instruction.funct6 | |||
| #+END_SRC | |||
| drives funct6 of `myModule` with the 26th to 31st bit of `instruction`. | |||
| Step 4: | |||
| Your IF should now have an instruction as an OUTPUT, and your ID as an INPUT, however | |||
| they are not connected. This must be done in the CPU class where both the ID and IF are | |||
| instantiated. | |||
| Step 4½: | |||
| You should now verify that the correct control signals are produced. Using printf, ensure | |||
| that: | |||
| + The program counter is increasing in increments of 4 | |||
| + The instruction in ID is as expected | |||
| + The decoder output is as expected | |||
| + The correct operands are fetched from the registers | |||
| Step 5: | |||
| You will now have to create the EX stage. Use the structure of the IF and ID modules to | |||
| guide you here. | |||
| In your EX stage you should have an ALU, preferrable in its own module a la registers in ID. | |||
| While the ALU is hugely complex, it's very easy to describle in hardware design languages! | |||
| Using the same approach as in the decoder should be sufficient: | |||
| #+BEGIN_SRC scala | |||
| val ALUopMap = Array( | |||
| ADD -> (io.op1 + io.op2), | |||
| SUB -> (io.op1 - io.op2), | |||
| ... | |||
| ) | |||
| io.aluResult := MuxLookup(0.U(32.W), io.aluOp, ALUopMap) | |||
| #+END_SRC | |||
| Step 6: | |||
| Your MEM stage does very little when an ADD instruction is executed, so implementing it should | |||
| be easy | |||
| Step 7: | |||
| You now need to actually write the result back to your register bank. | |||
| This should be handled at the CPU level. | |||
| If you sketched your processor already you probably made sure to keep track of the control | |||
| signals for the instruction currently in WB, so writing to the correct register address should | |||
| be easy for you ;) | |||
| Step 8: | |||
| Ensure that the simplest add test works, give yourself a pat on the back, you've just found the | |||
| corner pieces of the puzzle, so filling in the rest is "simply" being methodical. | |||
| @@ -0,0 +1,449 @@ | |||
| -------------------------------------------------------------------------- | |||
| 4.2. Register-Register Arithmetic Instructions | |||
| -------------------------------------------------------------------------- | |||
| * ADD | |||
| - Summary : Addition with 3 GPRs, no overflow exception | |||
| - Assembly : add rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] + R[rs2] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 000 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * SUB | |||
| - Summary : Subtraction with 3 GPRs, no overflow exception | |||
| - Assembly : sub rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] - R[rs2] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0100000 | rs2 | rs1 | 000 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * AND | |||
| - Summary : Bitwise logical AND with 3 GPRs | |||
| - Assembly : and rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] & R[rs2] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 111 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * OR | |||
| - Summary : Bitwise logical OR with 3 GPRs | |||
| - Assembly : or rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] | R[rs2] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 110 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * XOR | |||
| - Summary : Bitwise logical XOR with 3 GPRs | |||
| - Assembly : xor rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] ^ R[rs2] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 100 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * SLT | |||
| - Summary : Record result of signed less-than comparison with 2 GPRs | |||
| - Assembly : slt rd, rs1, rs2 | |||
| - Semantics : R[rd] = ( R[rs1] <s R[rs2] ) | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 010 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| This instruction uses a _signed_ comparison. | |||
| * SLTU | |||
| - Summary : Record result of unsigned less-than comparison with 2 GPRs | |||
| - Assembly : sltu rd, rs1, rs2 | |||
| - Semantics : R[rd] = ( R[rs1] <u R[rs2] ) | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 011 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| This instruction uses an _unsigned_ comparison. | |||
| * SRA | |||
| - Summary : Shift right arithmetic by register value (sign-extend) | |||
| - Assembly : sra rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] >>> R[rs2][4:0] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0100000 | rs2 | rs1 | 101 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| Note that the hardware should ensure that the sign-bit of R[rs1] is | |||
| extended to the right as it does the right shift. The hardware _must_ | |||
| only use the bottom five bits of R[rs2] when performing the shift. | |||
| * SRL | |||
| - Summary : Shift right logical by register value (append zeroes) | |||
| - Assembly : srl rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] >> R[rs2][4:0] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 101 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| Note that the hardware should append zeros to the left as it does the | |||
| right shift. The hardware _must_ only use the bottom five bits of R[rs2] | |||
| when performing the shift. | |||
| * SLL | |||
| - Summary : Shift left logical by register value (append zeroes) | |||
| - Assembly : sll rd, rs1, rs2 | |||
| - Semantics : R[rd] = R[rs1] << R[rs2][4:0] | |||
| - Format : R-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | rs2 | rs1 | 001 | rd | 0110011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| Note that the hardware should append zeros to the right as it does the | |||
| left shift. The hardware _must_ only use the bottom five bits of R[rs2] | |||
| when performing the shift. | |||
| -------------------------------------------------------------------------- | |||
| 4.3. Register-Immediate Arithmetic Instructions | |||
| -------------------------------------------------------------------------- | |||
| * ADDI | |||
| - Summary : Add constant, no overflow exception | |||
| - Assembly : addi rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] + sext(imm) | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 000 | rd | 0010011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| * ANDI | |||
| - Summary : Bitwise logical AND with constant | |||
| - Assembly : andi rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] & sext(imm) | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 111 | rd | 0010011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| * ORI | |||
| - Summary : Bitwise logical OR with constant | |||
| - Assembly : ori rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] | sext(imm) | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 110 | rd | 0010011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| * XORI | |||
| - Summary : Bitwise logical XOR with constant | |||
| - Assembly : xori rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] ^ sext(imm) | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 100 | rd | 0010011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| * SLTI | |||
| - Summary : Set GPR if source GPR < constant, signed comparison | |||
| - Assembly : slti rd, rs1, imm | |||
| - Semantics : R[rd] = ( R[rs1] <s sext(imm) ) | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 010 | rd | 0010011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| * SLTIU | |||
| - Summary : Set GPR if source GPR is < constant, unsigned comparison | |||
| - Assembly : sltiu rd, rs1, imm | |||
| - Semantics : R[rd] = ( R[rs1] <u sext(imm) ) | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 011 | rd | 0010011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| * SRAI | |||
| - Summary : Shift right arithmetic by constant (sign-extend) | |||
| - Assembly : srai rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] >>> imm | |||
| - Format : I-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0100000 | imm | rs1 | 101 | rd | 0010011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| Note that the hardware should ensure that the sign-bit of R[rs1] is | |||
| extended to the right as it does the right shift. | |||
| * SRLI | |||
| - Summary : Shift right logical by constant (append zeroes) | |||
| - Assembly : srli rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] >> imm | |||
| - Format : I-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | imm | rs1 | 101 | rd | 0010011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| Note that the hardware should append zeros to the left as it does the | |||
| right shift. | |||
| * SLLI | |||
| - Summary : Shift left logical constant (append zeroes) | |||
| - Assembly : slli rd, rs1, imm | |||
| - Semantics : R[rd] = R[rs1] << imm | |||
| - Format : I-type | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | 0000000 | imm | rs1 | 001 | rd | 0010011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| Note that the hardware should append zeros to the right as it does the | |||
| left shift. | |||
| * LUI | |||
| - Summary : Load constant into upper bits of word | |||
| - Assembly : lui rd, imm | |||
| - Semantics : R[rd] = imm << 12 | |||
| - Format : U-type, U-immediate | |||
| 31 11 7 6 0 | |||
| +---------------------------------------+---------+-------------+ | |||
| | imm | rd | 0110111 | | |||
| +---------------------------------------+---------+-------------+ | |||
| * AUIPC | |||
| - Summary : Load PC + constant into upper bits of word | |||
| - Assembly : auipc rd, imm | |||
| - Semantics : R[rd] = PC + ( imm << 12 ) | |||
| - Format : U-type, U-immediate | |||
| 31 11 7 6 0 | |||
| +---------------------------------------+---------+-------------+ | |||
| | imm | rd | 0010111 | | |||
| +---------------------------------------+---------+-------------+ | |||
| -------------------------------------------------------------------------- | |||
| 4.4. Memory Instructions | |||
| -------------------------------------------------------------------------- | |||
| * LW | |||
| - Summary : Load word from memory | |||
| - Assembly : lw rd, imm(rs1) | |||
| - Semantics : R[rd] = M_4B[ R[rs1] + sext(imm) ] | |||
| - Format : I-type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 010 | rd | 0000011 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| All addresses used with LW instructions must be four-byte aligned. This | |||
| means the bottom two bits of every effective address (i.e., after the | |||
| base address is added to the offset) will always be zero. | |||
| * SW | |||
| - Summary : Store word into memory | |||
| - Assembly : sw rs2, imm(rs1) | |||
| - Semantics : M_4B[ R[rs1] + sext(imm) ] = R[rs2] | |||
| - Format : S-type, S-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 010 | imm | 0100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| All addresses used with SW instructions must be four-byte aligned. This | |||
| means the bottom two bits of every effective address (i.e., after the | |||
| base address is added to the offset) will always be zero. | |||
| -------------------------------------------------------------------------- | |||
| 4.5. Unconditional Jump Instructions | |||
| -------------------------------------------------------------------------- | |||
| * JAL | |||
| - Summary : Jump to address and place return address in GPR | |||
| - Assembly : jal rd, imm | |||
| - Semantics : R[rd] = PC + 4; PC = PC + sext(imm) | |||
| - Format : U-type, J-immediate | |||
| 31 11 7 6 0 | |||
| +---------------------------------------+---------+-------------+ | |||
| | imm | rd | 1101111 | | |||
| +---------------------------------------+---------+-------------+ | |||
| * JALR | |||
| - Summary : Jump to address and place return address in GPR | |||
| - Assembly : jalr rd, rs1, imm | |||
| - Semantics : R[rd] = PC + 4; PC = ( R[rs1] + sext(imm) ) & 0xfffffffe | |||
| - Format : I-Type, I-immediate | |||
| 31 20 19 15 14 12 11 7 6 0 | |||
| +----------------------+---------+------+---------+-------------+ | |||
| | imm | rs1 | 000 | rd | 1100111 | | |||
| +----------------------+---------+------+---------+-------------+ | |||
| Note that the target address is obtained by adding the 12-bit signed | |||
| I-immediate to the value in register rs1, then setting the | |||
| least-significant bit of the result to zero. In other words, the JALR | |||
| instruction ignores the lowest bit of the calculated target address. | |||
| JALR is used when we want to call different subroutines. | |||
| Consider this jump table: | |||
| mul: | |||
| j mulInt | |||
| j mulFloat | |||
| j mulDouble | |||
| depending on the value in rs1 we can select which subroutine to call | |||
| -------------------------------------------------------------------------- | |||
| 4.6. Conditional Branch Instructions | |||
| -------------------------------------------------------------------------- | |||
| * BEQ | |||
| - Summary : Branch if 2 GPRs are equal | |||
| - Assembly : beq rs1, rs2, imm | |||
| - Semantics : PC = ( R[rs1] == R[rs2] ) ? PC + sext(imm) : PC + 4 | |||
| - Format : S-type, B-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 000 | imm | 1100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * BNE | |||
| - Summary : Branch if 2 GPRs are not equal | |||
| - Assembly : bne rs1, rs2, imm | |||
| - Semantics : PC = ( R[rs1] != R[rs2] ) ? PC + sext(imm) : PC + 4 | |||
| - Format : S-type, B-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 001 | imm | 1100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| * BLT | |||
| - Summary : Branch based on signed comparison of two GPRs | |||
| - Assembly : blt rs1, rs2, imm | |||
| - Semantics : PC = ( R[rs1] <s R[rs2] ) ? PC + sext(imm) : PC + 4 | |||
| - Format : S-type, B-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 100 | imm | 1100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| This instruction uses a _signed_ comparison. | |||
| * BGE | |||
| - Summary : Branch based on signed comparison of two GPRs | |||
| - Assembly : bge rs1, rs2, imm | |||
| - Semantics : PC = ( R[rs1] >=s R[rs2] ) ? PC + sext(imm) : PC + 4 | |||
| - Format : S-type, B-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 101 | imm | 1100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| This instruction uses a _signed_ comparison. | |||
| * BLTU | |||
| - Summary : Branch based on unsigned comparison of two GPRs | |||
| - Assembly : bltu rs1, rs2, imm | |||
| - Semantics : PC = ( R[rs1] <u R[rs2] ) ? PC + sext(imm) : PC + 4 | |||
| - Format : S-type, B-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 110 | imm | 1100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| This instruction uses an _unsigned_ comparison. | |||
| * BGEU | |||
| - Summary : Branch based on unsigned comparison of two GPRs | |||
| - Assembly : bgeu rs1, rs2, imm | |||
| - Semantics : PC = ( R[rs1] >=u R[rs2] ) ? PC + sext(imm) : PC + 4 | |||
| - Format : S-type, B-immediate | |||
| 31 25 24 20 19 15 14 12 11 7 6 0 | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| | imm | rs2 | rs1 | 111 | imm | 1100011 | | |||
| +------------+---------+---------+------+---------+-------------+ | |||
| This instruction uses an _unsigned_ comparison. | |||
| @@ -0,0 +1,30 @@ | |||
| import sbt._ | |||
| object Dependencies { | |||
| val fs2Version = "1.0.0" | |||
| val catsVersion = "1.4.0" | |||
| val catsEffectVersion = "1.0.0" | |||
| // TODO prune deps | |||
| val backendDeps = Def.setting( | |||
| Seq( | |||
| "com.lihaoyi" %% "sourcecode" % "0.1.4", // expert println debugging | |||
| "com.lihaoyi" %% "pprint" % "0.5.3", // pretty print for types and case classes | |||
| "com.lihaoyi" %% "fansi" % "0.2.5", | |||
| "org.typelevel" %% "cats-core" % catsVersion, // abstract category dork stuff | |||
| "org.typelevel" %% "cats-effect" % catsEffectVersion, // IO monad category wank | |||
| "com.chuusai" %% "shapeless" % "2.3.2", // Abstract level category dork stuff | |||
| "org.tpolecat" %% "atto-core" % "0.6.3", // For parsing asm | |||
| "org.tpolecat" %% "atto-refined" % "0.6.3", // For parsing asm | |||
| "com.github.pathikrit" %% "better-files" % "3.7.0", | |||
| "org.atnos" %% "eff" % "5.2.0", | |||
| "com.slamdata" %% "matryoshka-core" % "0.21.3" | |||
| )) | |||
| } | |||
| @@ -0,0 +1 @@ | |||
| sbt.version = 1.1.0 | |||
| @@ -0,0 +1,578 @@ | |||
| #!/usr/bin/env bash | |||
| # | |||
| # A more capable sbt runner, coincidentally also called sbt. | |||
| # Author: Paul Phillips <paulp@improving.org> | |||
| # https://github.com/paulp/sbt-extras | |||
| set -o pipefail | |||
| declare -r sbt_release_version="1.2.8" | |||
| declare -r sbt_unreleased_version="1.2.8" | |||
| declare -r latest_213="2.13.0-RC1" | |||
| declare -r latest_212="2.12.8" | |||
| declare -r latest_211="2.11.12" | |||
| declare -r latest_210="2.10.7" | |||
| declare -r latest_29="2.9.3" | |||
| declare -r latest_28="2.8.2" | |||
| declare -r buildProps="project/build.properties" | |||
| declare -r sbt_launch_ivy_release_repo="http://repo.typesafe.com/typesafe/ivy-releases" | |||
| declare -r sbt_launch_ivy_snapshot_repo="https://repo.scala-sbt.org/scalasbt/ivy-snapshots" | |||
| declare -r sbt_launch_mvn_release_repo="http://repo.scala-sbt.org/scalasbt/maven-releases" | |||
| declare -r sbt_launch_mvn_snapshot_repo="http://repo.scala-sbt.org/scalasbt/maven-snapshots" | |||
| declare -r default_jvm_opts_common="-Xms512m -Xss2m" | |||
| declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" | |||
| declare sbt_jar sbt_dir sbt_create sbt_version sbt_script sbt_new | |||
| declare sbt_explicit_version | |||
| declare verbose noshare batch trace_level | |||
| declare debugUs | |||
| declare java_cmd="java" | |||
| declare sbt_launch_dir="$HOME/.sbt/launchers" | |||
| declare sbt_launch_repo | |||
| # pull -J and -D options to give to java. | |||
| declare -a java_args scalac_args sbt_commands residual_args | |||
| # args to jvm/sbt via files or environment variables | |||
| declare -a extra_jvm_opts extra_sbt_opts | |||
| echoerr () { echo >&2 "$@"; } | |||
| vlog () { [[ -n "$verbose" ]] && echoerr "$@"; } | |||
| die () { echo "Aborting: $*" ; exit 1; } | |||
| setTrapExit () { | |||
| # save stty and trap exit, to ensure echo is re-enabled if we are interrupted. | |||
| SBT_STTY="$(stty -g 2>/dev/null)" | |||
| export SBT_STTY | |||
| # restore stty settings (echo in particular) | |||
| onSbtRunnerExit() { | |||
| [ -t 0 ] || return | |||
| vlog "" | |||
| vlog "restoring stty: $SBT_STTY" | |||
| stty "$SBT_STTY" | |||
| } | |||
| vlog "saving stty: $SBT_STTY" | |||
| trap onSbtRunnerExit EXIT | |||
| } | |||
| # this seems to cover the bases on OSX, and someone will | |||
| # have to tell me about the others. | |||
| get_script_path () { | |||
| local path="$1" | |||
| [[ -L "$path" ]] || { echo "$path" ; return; } | |||
| local -r target="$(readlink "$path")" | |||
| if [[ "${target:0:1}" == "/" ]]; then | |||
| echo "$target" | |||
| else | |||
| echo "${path%/*}/$target" | |||
| fi | |||
| } | |||
| script_path="$(get_script_path "${BASH_SOURCE[0]}")" | |||
| declare -r script_path | |||
| script_name="${script_path##*/}" | |||
| declare -r script_name | |||
| init_default_option_file () { | |||
| local overriding_var="${!1}" | |||
| local default_file="$2" | |||
| if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then | |||
| local envvar_file="${BASH_REMATCH[1]}" | |||
| if [[ -r "$envvar_file" ]]; then | |||
| default_file="$envvar_file" | |||
| fi | |||
| fi | |||
| echo "$default_file" | |||
| } | |||
| sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" | |||
| jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" | |||
| build_props_sbt () { | |||
| [[ -r "$buildProps" ]] && \ | |||
| grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }' | |||
| } | |||
| set_sbt_version () { | |||
| sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" | |||
| [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version | |||
| export sbt_version | |||
| } | |||
| url_base () { | |||
| local version="$1" | |||
| case "$version" in | |||
| 0.7.*) echo "http://simple-build-tool.googlecode.com" ;; | |||
| 0.10.* ) echo "$sbt_launch_ivy_release_repo" ;; | |||
| 0.11.[12]) echo "$sbt_launch_ivy_release_repo" ;; | |||
| 0.*-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" | |||
| echo "$sbt_launch_ivy_snapshot_repo" ;; | |||
| 0.*) echo "$sbt_launch_ivy_release_repo" ;; | |||
| *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" | |||
| echo "$sbt_launch_mvn_snapshot_repo" ;; | |||
| *) echo "$sbt_launch_mvn_release_repo" ;; | |||
| esac | |||
| } | |||
| make_url () { | |||
| local version="$1" | |||
| local base="${sbt_launch_repo:-$(url_base "$version")}" | |||
| case "$version" in | |||
| 0.7.*) echo "$base/files/sbt-launch-0.7.7.jar" ;; | |||
| 0.10.* ) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; | |||
| 0.11.[12]) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; | |||
| 0.*) echo "$base/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; | |||
| *) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; | |||
| esac | |||
| } | |||
| addJava () { vlog "[addJava] arg = '$1'" ; java_args+=("$1"); } | |||
| addSbt () { vlog "[addSbt] arg = '$1'" ; sbt_commands+=("$1"); } | |||
| addScalac () { vlog "[addScalac] arg = '$1'" ; scalac_args+=("$1"); } | |||
| addResidual () { vlog "[residual] arg = '$1'" ; residual_args+=("$1"); } | |||
| addResolver () { addSbt "set resolvers += $1"; } | |||
| addDebugger () { addJava "-Xdebug" ; addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"; } | |||
| setThisBuild () { | |||
| vlog "[addBuild] args = '$*'" | |||
| local key="$1" && shift | |||
| addSbt "set $key in ThisBuild := $*" | |||
| } | |||
| setScalaVersion () { | |||
| [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' | |||
| addSbt "++ $1" | |||
| } | |||
| setJavaHome () { | |||
| java_cmd="$1/bin/java" | |||
| setThisBuild javaHome "_root_.scala.Some(file(\"$1\"))" | |||
| export JAVA_HOME="$1" | |||
| export JDK_HOME="$1" | |||
| export PATH="$JAVA_HOME/bin:$PATH" | |||
| } | |||
| getJavaVersion() { | |||
| local -r str=$("$1" -version 2>&1 | grep -E -e '(java|openjdk) version' | awk '{ print $3 }' | tr -d '"') | |||
| # java -version on java8 says 1.8.x | |||
| # but on 9 and 10 it's 9.x.y and 10.x.y. | |||
| if [[ "$str" =~ ^1\.([0-9]+)\..*$ ]]; then | |||
| echo "${BASH_REMATCH[1]}" | |||
| elif [[ "$str" =~ ^([0-9]+)\..*$ ]]; then | |||
| echo "${BASH_REMATCH[1]}" | |||
| elif [[ -n "$str" ]]; then | |||
| echoerr "Can't parse java version from: $str" | |||
| fi | |||
| } | |||
| checkJava() { | |||
| # Warn if there is a Java version mismatch between PATH and JAVA_HOME/JDK_HOME | |||
| [[ -n "$JAVA_HOME" && -e "$JAVA_HOME/bin/java" ]] && java="$JAVA_HOME/bin/java" | |||
| [[ -n "$JDK_HOME" && -e "$JDK_HOME/lib/tools.jar" ]] && java="$JDK_HOME/bin/java" | |||
| if [[ -n "$java" ]]; then | |||
| pathJavaVersion=$(getJavaVersion java) | |||
| homeJavaVersion=$(getJavaVersion "$java") | |||
| if [[ "$pathJavaVersion" != "$homeJavaVersion" ]]; then | |||
| echoerr "Warning: Java version mismatch between PATH and JAVA_HOME/JDK_HOME, sbt will use the one in PATH" | |||
| echoerr " Either: fix your PATH, remove JAVA_HOME/JDK_HOME or use -java-home" | |||
| echoerr " java version from PATH: $pathJavaVersion" | |||
| echoerr " java version from JAVA_HOME/JDK_HOME: $homeJavaVersion" | |||
| fi | |||
| fi | |||
| } | |||
| java_version () { | |||
| local -r version=$(getJavaVersion "$java_cmd") | |||
| vlog "Detected Java version: $version" | |||
| echo "$version" | |||
| } | |||
| # MaxPermSize critical on pre-8 JVMs but incurs noisy warning on 8+ | |||
| default_jvm_opts () { | |||
| local -r v="$(java_version)" | |||
| if [[ $v -ge 8 ]]; then | |||
| echo "$default_jvm_opts_common" | |||
| else | |||
| echo "-XX:MaxPermSize=384m $default_jvm_opts_common" | |||
| fi | |||
| } | |||
| build_props_scala () { | |||
| if [[ -r "$buildProps" ]]; then | |||
| versionLine="$(grep '^build.scala.versions' "$buildProps")" | |||
| versionString="${versionLine##build.scala.versions=}" | |||
| echo "${versionString%% .*}" | |||
| fi | |||
| } | |||
| execRunner () { | |||
| # print the arguments one to a line, quoting any containing spaces | |||
| vlog "# Executing command line:" && { | |||
| for arg; do | |||
| if [[ -n "$arg" ]]; then | |||
| if printf "%s\n" "$arg" | grep -q ' '; then | |||
| printf >&2 "\"%s\"\n" "$arg" | |||
| else | |||
| printf >&2 "%s\n" "$arg" | |||
| fi | |||
| fi | |||
| done | |||
| vlog "" | |||
| } | |||
| setTrapExit | |||
| if [[ -n "$batch" ]]; then | |||
| "$@" < /dev/null | |||
| else | |||
| "$@" | |||
| fi | |||
| } | |||
| jar_url () { make_url "$1"; } | |||
| is_cygwin () { [[ "$(uname -a)" == "CYGWIN"* ]]; } | |||
| jar_file () { | |||
| is_cygwin \ | |||
| && cygpath -w "$sbt_launch_dir/$1/sbt-launch.jar" \ | |||
| || echo "$sbt_launch_dir/$1/sbt-launch.jar" | |||
| } | |||
| download_url () { | |||
| local url="$1" | |||
| local jar="$2" | |||
| echoerr "Downloading sbt launcher for $sbt_version:" | |||
| echoerr " From $url" | |||
| echoerr " To $jar" | |||
| mkdir -p "${jar%/*}" && { | |||
| if command -v curl > /dev/null 2>&1; then | |||
| curl --fail --silent --location "$url" --output "$jar" | |||
| elif command -v wget > /dev/null 2>&1; then | |||
| wget -q -O "$jar" "$url" | |||
| fi | |||
| } && [[ -r "$jar" ]] | |||
| } | |||
| acquire_sbt_jar () { | |||
| { | |||
| sbt_jar="$(jar_file "$sbt_version")" | |||
| [[ -r "$sbt_jar" ]] | |||
| } || { | |||
| sbt_jar="$HOME/.ivy2/local/org.scala-sbt/sbt-launch/$sbt_version/jars/sbt-launch.jar" | |||
| [[ -r "$sbt_jar" ]] | |||
| } || { | |||
| sbt_jar="$(jar_file "$sbt_version")" | |||
| download_url "$(make_url "$sbt_version")" "$sbt_jar" | |||
| } | |||
| } | |||
| usage () { | |||
| set_sbt_version | |||
| cat <<EOM | |||
| Usage: $script_name [options] | |||
| Note that options which are passed along to sbt begin with -- whereas | |||
| options to this runner use a single dash. Any sbt command can be scheduled | |||
| to run first by prefixing the command with --, so --warn, --error and so on | |||
| are not special. | |||
| Output filtering: if there is a file in the home directory called .sbtignore | |||
| and this is not an interactive sbt session, the file is treated as a list of | |||
| bash regular expressions. Output lines which match any regex are not echoed. | |||
| One can see exactly which lines would have been suppressed by starting this | |||
| runner with the -x option. | |||
| -h | -help print this message | |||
| -v verbose operation (this runner is chattier) | |||
| -d, -w, -q aliases for --debug, --warn, --error (q means quiet) | |||
| -x debug this script | |||
| -trace <level> display stack traces with a max of <level> frames (default: -1, traces suppressed) | |||
| -debug-inc enable debugging log for the incremental compiler | |||
| -no-colors disable ANSI color codes | |||
| -sbt-create start sbt even if current directory contains no sbt project | |||
| -sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt/<version>) | |||
| -sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11+) | |||
| -ivy <path> path to local Ivy repository (default: ~/.ivy2) | |||
| -no-share use all local caches; no sharing | |||
| -offline put sbt in offline mode | |||
| -jvm-debug <port> Turn on JVM debugging, open at the given port. | |||
| -batch Disable interactive mode | |||
| -prompt <expr> Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted | |||
| -script <file> Run the specified file as a scala script | |||
| # sbt version (default: sbt.version from $buildProps if present, otherwise $sbt_release_version) | |||
| -sbt-force-latest force the use of the latest release of sbt: $sbt_release_version | |||
| -sbt-version <version> use the specified version of sbt (default: $sbt_release_version) | |||
| -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version | |||
| -sbt-jar <path> use the specified jar as the sbt launcher | |||
| -sbt-launch-dir <path> directory to hold sbt launchers (default: $sbt_launch_dir) | |||
| -sbt-launch-repo <url> repo url for downloading sbt launcher jar (default: $(url_base "$sbt_version")) | |||
| # scala version (default: as chosen by sbt) | |||
| -28 use $latest_28 | |||
| -29 use $latest_29 | |||
| -210 use $latest_210 | |||
| -211 use $latest_211 | |||
| -212 use $latest_212 | |||
| -213 use $latest_213 | |||
| -scala-home <path> use the scala build at the specified directory | |||
| -scala-version <version> use the specified version of scala | |||
| -binary-version <version> use the specified scala version when searching for dependencies | |||
| # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) | |||
| -java-home <path> alternate JAVA_HOME | |||
| # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution | |||
| # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found | |||
| <default> $(default_jvm_opts) | |||
| JVM_OPTS environment variable holding either the jvm args directly, or | |||
| the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') | |||
| Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. | |||
| -jvm-opts <path> file containing jvm args (if not given, .jvmopts in project root is used if present) | |||
| -Dkey=val pass -Dkey=val directly to the jvm | |||
| -J-X pass option -X directly to the jvm (-J is stripped) | |||
| # passing options to sbt, OR to this runner | |||
| SBT_OPTS environment variable holding either the sbt args directly, or | |||
| the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') | |||
| Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. | |||
| -sbt-opts <path> file containing sbt args (if not given, .sbtopts in project root is used if present) | |||
| -S-X add -X to sbt's scalacOptions (-S is stripped) | |||
| EOM | |||
| } | |||
| process_args () { | |||
| require_arg () { | |||
| local type="$1" | |||
| local opt="$2" | |||
| local arg="$3" | |||
| if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then | |||
| die "$opt requires <$type> argument" | |||
| fi | |||
| } | |||
| while [[ $# -gt 0 ]]; do | |||
| case "$1" in | |||
| -h|-help) usage; exit 0 ;; | |||
| -v) verbose=true && shift ;; | |||
| -d) addSbt "--debug" && shift ;; | |||
| -w) addSbt "--warn" && shift ;; | |||
| -q) addSbt "--error" && shift ;; | |||
| -x) debugUs=true && shift ;; | |||
| -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; | |||
| -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; | |||
| -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; | |||
| -no-share) noshare=true && shift ;; | |||
| -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; | |||
| -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; | |||
| -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; | |||
| -offline) addSbt "set offline in Global := true" && shift ;; | |||
| -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; | |||
| -batch) batch=true && shift ;; | |||
| -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; | |||
| -script) require_arg file "$1" "$2" && sbt_script="$2" && addJava "-Dsbt.main.class=sbt.ScriptMain" && shift 2 ;; | |||
| -sbt-create) sbt_create=true && shift ;; | |||
| -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; | |||
| -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;; | |||
| -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; | |||
| -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; | |||
| -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; | |||
| -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; | |||
| -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; | |||
| -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; | |||
| -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "_root_.scala.Some(file(\"$2\"))" && shift 2 ;; | |||
| -java-home) require_arg path "$1" "$2" && setJavaHome "$2" && shift 2 ;; | |||
| -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; | |||
| -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; | |||
| -D*) addJava "$1" && shift ;; | |||
| -J*) addJava "${1:2}" && shift ;; | |||
| -S*) addScalac "${1:2}" && shift ;; | |||
| -28) setScalaVersion "$latest_28" && shift ;; | |||
| -29) setScalaVersion "$latest_29" && shift ;; | |||
| -210) setScalaVersion "$latest_210" && shift ;; | |||
| -211) setScalaVersion "$latest_211" && shift ;; | |||
| -212) setScalaVersion "$latest_212" && shift ;; | |||
| -213) setScalaVersion "$latest_213" && shift ;; | |||
| new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; | |||
| *) addResidual "$1" && shift ;; | |||
| esac | |||
| done | |||
| } | |||
| # process the direct command line arguments | |||
| process_args "$@" | |||
| # skip #-styled comments and blank lines | |||
| readConfigFile() { | |||
| local end=false | |||
| until $end; do | |||
| read -r || end=true | |||
| [[ $REPLY =~ ^# ]] || [[ -z $REPLY ]] || echo "$REPLY" | |||
| done < "$1" | |||
| } | |||
| # if there are file/environment sbt_opts, process again so we | |||
| # can supply args to this runner | |||
| if [[ -r "$sbt_opts_file" ]]; then | |||
| vlog "Using sbt options defined in file $sbt_opts_file" | |||
| while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbt_opts_file") | |||
| elif [[ -n "$SBT_OPTS" && ! ("$SBT_OPTS" =~ ^@.*) ]]; then | |||
| vlog "Using sbt options defined in variable \$SBT_OPTS" | |||
| IFS=" " read -r -a extra_sbt_opts <<< "$SBT_OPTS" | |||
| else | |||
| vlog "No extra sbt options have been defined" | |||
| fi | |||
| [[ -n "${extra_sbt_opts[*]}" ]] && process_args "${extra_sbt_opts[@]}" | |||
| # reset "$@" to the residual args | |||
| set -- "${residual_args[@]}" | |||
| argumentCount=$# | |||
| # set sbt version | |||
| set_sbt_version | |||
| checkJava | |||
| # only exists in 0.12+ | |||
| setTraceLevel() { | |||
| case "$sbt_version" in | |||
| "0.7."* | "0.10."* | "0.11."* ) echoerr "Cannot set trace level in sbt version $sbt_version" ;; | |||
| *) setThisBuild traceLevel "$trace_level" ;; | |||
| esac | |||
| } | |||
| # set scalacOptions if we were given any -S opts | |||
| [[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[*]}\"" | |||
| [[ -n "$sbt_explicit_version" && -z "$sbt_new" ]] && addJava "-Dsbt.version=$sbt_explicit_version" | |||
| vlog "Detected sbt version $sbt_version" | |||
| if [[ -n "$sbt_script" ]]; then | |||
| residual_args=( "$sbt_script" "${residual_args[@]}" ) | |||
| else | |||
| # no args - alert them there's stuff in here | |||
| (( argumentCount > 0 )) || { | |||
| vlog "Starting $script_name: invoke with -help for other options" | |||
| residual_args=( shell ) | |||
| } | |||
| fi | |||
| # verify this is an sbt dir, -create was given or user attempts to run a scala script | |||
| [[ -r ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_script" || -n "$sbt_new" ]] || { | |||
| cat <<EOM | |||
| $(pwd) doesn't appear to be an sbt project. | |||
| If you want to start sbt anyway, run: | |||
| $0 -sbt-create | |||
| EOM | |||
| exit 1 | |||
| } | |||
| # pick up completion if present; todo | |||
| # shellcheck disable=SC1091 | |||
| [[ -r .sbt_completion.sh ]] && source .sbt_completion.sh | |||
| # directory to store sbt launchers | |||
| [[ -d "$sbt_launch_dir" ]] || mkdir -p "$sbt_launch_dir" | |||
| [[ -w "$sbt_launch_dir" ]] || sbt_launch_dir="$(mktemp -d -t sbt_extras_launchers.XXXXXX)" | |||
| # no jar? download it. | |||
| [[ -r "$sbt_jar" ]] || acquire_sbt_jar || { | |||
| # still no jar? uh-oh. | |||
| echo "Download failed. Obtain the jar manually and place it at $sbt_jar" | |||
| exit 1 | |||
| } | |||
| if [[ -n "$noshare" ]]; then | |||
| for opt in ${noshare_opts}; do | |||
| addJava "$opt" | |||
| done | |||
| else | |||
| case "$sbt_version" in | |||
| "0.7."* | "0.10."* | "0.11."* | "0.12."* ) | |||
| [[ -n "$sbt_dir" ]] || { | |||
| sbt_dir="$HOME/.sbt/$sbt_version" | |||
| vlog "Using $sbt_dir as sbt dir, -sbt-dir to override." | |||
| } | |||
| ;; | |||
| esac | |||
| if [[ -n "$sbt_dir" ]]; then | |||
| addJava "-Dsbt.global.base=$sbt_dir" | |||
| fi | |||
| fi | |||
| if [[ -r "$jvm_opts_file" ]]; then | |||
| vlog "Using jvm options defined in file $jvm_opts_file" | |||
| while read -r opt; do extra_jvm_opts+=("$opt"); done < <(readConfigFile "$jvm_opts_file") | |||
| elif [[ -n "$JVM_OPTS" && ! ("$JVM_OPTS" =~ ^@.*) ]]; then | |||
| vlog "Using jvm options defined in \$JVM_OPTS variable" | |||
| IFS=" " read -r -a extra_jvm_opts <<< "$JVM_OPTS" | |||
| else | |||
| vlog "Using default jvm options" | |||
| IFS=" " read -r -a extra_jvm_opts <<< "$(default_jvm_opts)" | |||
| fi | |||
| # traceLevel is 0.12+ | |||
| [[ -n "$trace_level" ]] && setTraceLevel | |||
| main () { | |||
| execRunner "$java_cmd" \ | |||
| "${extra_jvm_opts[@]}" \ | |||
| "${java_args[@]}" \ | |||
| -jar "$sbt_jar" \ | |||
| "${sbt_commands[@]}" \ | |||
| "${residual_args[@]}" | |||
| } | |||
| # sbt inserts this string on certain lines when formatting is enabled: | |||
| # val OverwriteLine = "\r\u001BM\u001B[2K" | |||
| # ...in order not to spam the console with a million "Resolving" lines. | |||
| # Unfortunately that makes it that much harder to work with when | |||
| # we're not going to print those lines anyway. We strip that bit of | |||
| # line noise, but leave the other codes to preserve color. | |||
| mainFiltered () { | |||
| local -r excludeRegex=$(grep -E -v '^#|^$' ~/.sbtignore | paste -sd'|' -) | |||
| echoLine () { | |||
| local -r line="$1" | |||
| local -r line1="${line//\r\x1BM\x1B\[2K//g}" # This strips the OverwriteLine code. | |||
| local -r line2="${line1//\x1B\[[0-9;]*[JKmsu]//g}" # This strips all codes - we test regexes against this. | |||
| if [[ $line2 =~ $excludeRegex ]]; then | |||
| [[ -n $debugUs ]] && echo "[X] $line1" | |||
| else | |||
| [[ -n $debugUs ]] && echo " $line1" || echo "$line1" | |||
| fi | |||
| } | |||
| echoLine "Starting sbt with output filtering enabled." | |||
| main | while read -r line; do echoLine "$line"; done | |||
| } | |||
| # Only filter if there's a filter file and we don't see a known interactive command. | |||
| # Obviously this is super ad hoc but I don't know how to improve on it. Testing whether | |||
| # stdin is a terminal is useless because most of my use cases for this filtering are | |||
| # exactly when I'm at a terminal, running sbt non-interactively. | |||
| shouldFilter () { [[ -f ~/.sbtignore ]] && ! grep -E -q '\b(shell|console|consoleProject)\b' <<<"${residual_args[@]}"; } | |||
| # run sbt | |||
| if shouldFilter; then mainFiltered; else main; fi | |||
| @@ -0,0 +1,57 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.core.Input | |||
| import chisel3.experimental.MultiIOModule | |||
| import chisel3.experimental._ | |||
| class CPU extends MultiIOModule { | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val setupSignals = Input(new SetupSignals) | |||
| val testReadouts = Output(new TestReadouts) | |||
| val regUpdates = Output(new RegisterUpdates) | |||
| val memUpdates = Output(new MemUpdates) | |||
| val currentPC = Output(UInt(32.W)) | |||
| } | |||
| ) | |||
| /** | |||
| You need to create the classes for these yourself | |||
| */ | |||
| // val IFBarrier = Module(new IFBarrier).io | |||
| // val IDBarrier = Module(new IDBarrier).io | |||
| // val EXBarrier = Module(new EXBarrier).io | |||
| // val MEMBarrier = Module(new MEMBarrier).io | |||
| val ID = Module(new InstructionDecode) | |||
| val IF = Module(new InstructionFetch) | |||
| // val EX = Module(new Execute) | |||
| val MEM = Module(new MemoryFetch) | |||
| // val WB = Module(new Execute) (You may not need this one?) | |||
| /** | |||
| * Setup. You should not change this code | |||
| */ | |||
| IF.testHarness.IMEMsetup := testHarness.setupSignals.IMEMsignals | |||
| ID.testHarness.registerSetup := testHarness.setupSignals.registerSignals | |||
| MEM.testHarness.DMEMsetup := testHarness.setupSignals.DMEMsignals | |||
| testHarness.testReadouts.registerRead := ID.testHarness.registerPeek | |||
| testHarness.testReadouts.DMEMread := MEM.testHarness.DMEMpeek | |||
| /** | |||
| spying stuff | |||
| */ | |||
| testHarness.regUpdates := ID.testHarness.testUpdates | |||
| testHarness.memUpdates := MEM.testHarness.testUpdates | |||
| testHarness.currentPC := IF.testHarness.PC | |||
| /** | |||
| TODO: Your code here | |||
| */ | |||
| } | |||
| @@ -0,0 +1,60 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.util._ | |||
| import chisel3.core.Input | |||
| import chisel3.iotesters.PeekPokeTester | |||
| // From RISC-V reference card | |||
| object ALUOps { | |||
| val ADD = 0.U(4.W) | |||
| val SUB = 1.U(4.W) | |||
| val AND = 2.U(4.W) | |||
| val OR = 3.U(4.W) | |||
| val XOR = 4.U(4.W) | |||
| val SLT = 5.U(4.W) | |||
| val SLL = 6.U(4.W) | |||
| val SLTU = 7.U(4.W) | |||
| val SRL = 8.U(4.W) | |||
| val SRA = 9.U(4.W) | |||
| val COPY_A = 10.U(4.W) | |||
| val COPY_B = 11.U(4.W) | |||
| val DC = 15.U(4.W) | |||
| } | |||
| object lookup { | |||
| def BEQ = BitPat("b?????????????????000?????1100011") | |||
| def BNE = BitPat("b?????????????????001?????1100011") | |||
| def BLT = BitPat("b?????????????????100?????1100011") | |||
| def BGE = BitPat("b?????????????????101?????1100011") | |||
| def BLTU = BitPat("b?????????????????110?????1100011") | |||
| def BGEU = BitPat("b?????????????????111?????1100011") | |||
| def JALR = BitPat("b?????????????????000?????1100111") | |||
| def JAL = BitPat("b?????????????????????????1101111") | |||
| def LUI = BitPat("b?????????????????????????0110111") | |||
| def AUIPC = BitPat("b?????????????????????????0010111") | |||
| def ADDI = BitPat("b?????????????????000?????0010011") | |||
| def SLLI = BitPat("b000000???????????001?????0010011") | |||
| def SLTI = BitPat("b?????????????????010?????0010011") | |||
| def SLTIU = BitPat("b?????????????????011?????0010011") | |||
| def XORI = BitPat("b?????????????????100?????0010011") | |||
| def SRLI = BitPat("b000000???????????101?????0010011") | |||
| def SRAI = BitPat("b010000???????????101?????0010011") | |||
| def ORI = BitPat("b?????????????????110?????0010011") | |||
| def ANDI = BitPat("b?????????????????111?????0010011") | |||
| def ADD = BitPat("b0000000??????????000?????0110011") | |||
| def SUB = BitPat("b0100000??????????000?????0110011") | |||
| def SLL = BitPat("b0000000??????????001?????0110011") | |||
| def SLT = BitPat("b0000000??????????010?????0110011") | |||
| def SLTU = BitPat("b0000000??????????011?????0110011") | |||
| def XOR = BitPat("b0000000??????????100?????0110011") | |||
| def SRL = BitPat("b0000000??????????101?????0110011") | |||
| def SRA = BitPat("b0100000??????????101?????0110011") | |||
| def OR = BitPat("b0000000??????????110?????0110011") | |||
| def AND = BitPat("b0000000??????????111?????0110011") | |||
| def LW = BitPat("b?????????????????010?????0000011") | |||
| def SW = BitPat("b?????????????????010?????0100011") | |||
| } | |||
| @@ -0,0 +1,54 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.experimental.MultiIOModule | |||
| /** | |||
| * This module is already done. Have one on me | |||
| */ | |||
| class DMEM extends MultiIOModule { | |||
| // Don't touch the test harness | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val setup = Input(new DMEMsetupSignals) | |||
| val testUpdates = Output(new MemUpdates) | |||
| }) | |||
| val io = IO( | |||
| new Bundle { | |||
| val writeEnable = Input(Bool()) | |||
| val dataIn = Input(UInt(32.W)) | |||
| val dataAddress = Input(UInt(12.W)) | |||
| val dataOut = Output(UInt(32.W)) | |||
| }) | |||
| val data = SyncReadMem(4096, UInt(32.W)) | |||
| val addressSource = Wire(UInt(32.W)) | |||
| val dataSource = Wire(UInt(32.W)) | |||
| val writeEnableSource = Wire(Bool()) | |||
| // For loading data | |||
| when(testHarness.setup.setup){ | |||
| addressSource := testHarness.setup.dataAddress | |||
| dataSource := testHarness.setup.dataIn | |||
| writeEnableSource := testHarness.setup.writeEnable | |||
| }.otherwise { | |||
| addressSource := io.dataAddress | |||
| dataSource := io.dataIn | |||
| writeEnableSource := io.writeEnable | |||
| } | |||
| testHarness.testUpdates.writeEnable := writeEnableSource | |||
| testHarness.testUpdates.writeData := dataSource | |||
| testHarness.testUpdates.writeAddress := addressSource | |||
| io.dataOut := data(addressSource) | |||
| when(writeEnableSource){ | |||
| data(addressSource) := dataSource | |||
| } | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.util.BitPat | |||
| import chisel3.util.ListLookup | |||
| /** | |||
| * This module is mostly done, but you will have to fill in the blanks in opcodeMap. | |||
| * You may want to add more signals to be decoded in this module depending on your | |||
| * design if you so desire. | |||
| * | |||
| * In the "classic" 5 stage decoder signals such as op1select and immType | |||
| * are not included, however I have added them to my design, and similarily you might | |||
| * find it useful to add more | |||
| */ | |||
| class Decoder() extends Module { | |||
| val io = IO(new Bundle { | |||
| val instruction = Input(new Instruction) | |||
| val controlSignals = Output(new ControlSignals) | |||
| val branchType = Output(UInt(3.W)) | |||
| val op1Select = Output(UInt(1.W)) | |||
| val op2Select = Output(UInt(1.W)) | |||
| val immType = Output(UInt(3.W)) | |||
| val ALUop = Output(UInt(4.W)) | |||
| }) | |||
| import lookup._ | |||
| import Op1Select._ | |||
| import Op2Select._ | |||
| import branchType._ | |||
| import ImmFormat._ | |||
| val N = 0.asUInt(1.W) | |||
| val Y = 1.asUInt(1.W) | |||
| /** | |||
| * In scala we sometimes (ab)use the `->` operator to create tuples. | |||
| * The reason for this is that it serves as convenient sugar to make maps. | |||
| * | |||
| * This doesn't matter to you, just fill in the blanks in the style currently | |||
| * used, I just want to demystify some of the magic. | |||
| * | |||
| * `a -> b` == `(a, b)` == `Tuple2(a, b)` | |||
| */ | |||
| val opcodeMap: Array[(BitPat, List[UInt])] = Array( | |||
| // signal memToReg, regWrite, memRead, memWrite, branch, jump, branchType, Op1Select, Op2Select, ImmSelect, ALUOp | |||
| LW -> List(Y, Y, Y, N, N, N, branchType.DC, rs1, imm, ITYPE, ALUOps.ADD), | |||
| SW -> List(N, N, N, Y, N, N, branchType.DC, rs1, imm, STYPE, ALUOps.ADD), | |||
| ADD -> List(N, Y, N, N, N, N, branchType.DC, rs1, rs2, ImmFormat.DC, ALUOps.ADD), | |||
| SUB -> List(N, Y, N, N, N, N, branchType.DC, rs1, rs2, ImmFormat.DC, ALUOps.SUB), | |||
| /** | |||
| TODO: Fill in the blanks | |||
| */ | |||
| ) | |||
| val NOP = List(N, N, N, N, N, N, branchType.DC, rs1, rs2, ImmFormat.DC, ALUOps.DC) | |||
| val decodedControlSignals = ListLookup( | |||
| io.instruction.asUInt(), | |||
| NOP, | |||
| opcodeMap) | |||
| io.controlSignals.memToReg := decodedControlSignals(0) | |||
| io.controlSignals.regWrite := decodedControlSignals(1) | |||
| io.controlSignals.memRead := decodedControlSignals(2) | |||
| io.controlSignals.memWrite := decodedControlSignals(3) | |||
| io.controlSignals.branch := decodedControlSignals(4) | |||
| io.controlSignals.jump := decodedControlSignals(5) | |||
| io.branchType := decodedControlSignals(6) | |||
| io.op1Select := decodedControlSignals(7) | |||
| io.op2Select := decodedControlSignals(8) | |||
| io.immType := decodedControlSignals(9) | |||
| io.ALUop := decodedControlSignals(10) | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.util.{ BitPat, MuxCase } | |||
| import chisel3.experimental.MultiIOModule | |||
| class InstructionDecode extends MultiIOModule { | |||
| // Don't touch the test harness | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val registerSetup = Input(new RegisterSetupSignals) | |||
| val registerPeek = Output(UInt(32.W)) | |||
| val testUpdates = Output(new RegisterUpdates) | |||
| }) | |||
| val io = IO( | |||
| new Bundle { | |||
| /** | |||
| * TODO: Your code here. | |||
| */ | |||
| } | |||
| ) | |||
| val registers = Module(new Registers) | |||
| val decoder = Module(new Decoder).io | |||
| /** | |||
| * Setup. You should not change this code | |||
| */ | |||
| registers.testHarness.setup := testHarness.registerSetup | |||
| testHarness.registerPeek := registers.io.readData1 | |||
| testHarness.testUpdates := registers.testHarness.testUpdates | |||
| /** | |||
| * TODO: Your code here. | |||
| */ | |||
| registers.io.readAddress1 := 0.U | |||
| registers.io.readAddress2 := 0.U | |||
| registers.io.writeEnable := false.B | |||
| registers.io.writeAddress := 0.U | |||
| registers.io.writeData := 0.U | |||
| decoder.instruction := 0.U.asTypeOf(new Instruction) | |||
| } | |||
| @@ -0,0 +1,59 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.experimental.MultiIOModule | |||
| class InstructionFetch extends MultiIOModule { | |||
| // Don't touch | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val IMEMsetup = Input(new IMEMsetupSignals) | |||
| val PC = Output(UInt()) | |||
| } | |||
| ) | |||
| /** | |||
| * TODO: Add signals for handling events such as jumps | |||
| */ | |||
| val io = IO( | |||
| new Bundle { | |||
| val PC = Output(UInt()) | |||
| }) | |||
| val IMEM = Module(new IMEM) | |||
| val PC = RegInit(UInt(32.W), 0.U) | |||
| /** | |||
| * Setup. You should not change this code | |||
| */ | |||
| IMEM.testHarness.setupSignals := testHarness.IMEMsetup | |||
| testHarness.PC := IMEM.testHarness.requestedAddress | |||
| /** | |||
| * TODO: Your code here. | |||
| * | |||
| * You should expand on or rewrite the code below. | |||
| */ | |||
| io.PC := PC | |||
| IMEM.io.instructionAddress := PC | |||
| PC := PC + 4.U | |||
| val instruction = Wire(new Instruction) | |||
| instruction := IMEM.io.instruction.asTypeOf(new Instruction) | |||
| /** | |||
| * Setup. You should not change this code | |||
| */ | |||
| when(testHarness.IMEMsetup.setup) { | |||
| PC := 0.U | |||
| // TODO: You must set the instruction to Instruction.NOP here. | |||
| // throw new Exception("Just making sure you're seeing the line above") | |||
| } | |||
| } | |||
| @@ -0,0 +1,52 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.experimental.MultiIOModule | |||
| /** | |||
| * This module is finished and does not need to be modified to complete your fivestage. | |||
| * | |||
| * When setup is enabled data is written to the instruction memory. | |||
| * In normal operation this memory is write only (no self modifying code) | |||
| */ | |||
| class IMEM() extends MultiIOModule { | |||
| // Don't touch | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val setupSignals = Input(new IMEMsetupSignals) | |||
| val requestedAddress = Output(UInt()) | |||
| } | |||
| ) | |||
| val io = IO( | |||
| new Bundle { | |||
| val instructionAddress = Input(UInt(32.W)) | |||
| val instruction = Output(UInt(32.W)) | |||
| }) | |||
| /** | |||
| SyncReadMem will output the value of the address signal set in the previous cycle. | |||
| */ | |||
| val instructions = SyncReadMem(4096, UInt(32.W)) | |||
| // The address we want to read at during operation. During setup it acts as a write address | |||
| // leading to the somewhat uninformative name shown here. | |||
| val addressSource = Wire(UInt(32.W)) | |||
| testHarness.requestedAddress := io.instructionAddress | |||
| when(testHarness.setupSignals.setup){ | |||
| addressSource := testHarness.setupSignals.address | |||
| }.otherwise { | |||
| addressSource := io.instructionAddress | |||
| } | |||
| // For loading data | |||
| when(testHarness.setupSignals.setup){ | |||
| instructions(addressSource) := testHarness.setupSignals.instruction | |||
| } | |||
| io.instruction := instructions(addressSource) | |||
| } | |||
| @@ -0,0 +1,41 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.util._ | |||
| import chisel3.experimental.MultiIOModule | |||
| class MemoryFetch() extends MultiIOModule { | |||
| // Don't touch the test harness | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val DMEMsetup = Input(new DMEMsetupSignals) | |||
| val DMEMpeek = Output(UInt(32.W)) | |||
| val testUpdates = Output(new MemUpdates) | |||
| }) | |||
| val io = IO( | |||
| new Bundle { | |||
| }) | |||
| val DMEM = Module(new DMEM) | |||
| /** | |||
| * Setup. You should not change this code | |||
| */ | |||
| DMEM.testHarness.setup := testHarness.DMEMsetup | |||
| testHarness.DMEMpeek := DMEM.io.dataOut | |||
| testHarness.testUpdates := DMEM.testHarness.testUpdates | |||
| /** | |||
| * Your code here. | |||
| */ | |||
| DMEM.io.dataIn := 0.U | |||
| DMEM.io.dataAddress := 0.U | |||
| DMEM.io.writeEnable := false.B | |||
| } | |||
| @@ -0,0 +1,81 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.experimental.MultiIOModule | |||
| /** | |||
| * This module is already done. Have one on me | |||
| * | |||
| * When a write and read conflicts this might result in stale data. | |||
| * This caveat must be handled using a bypass. | |||
| */ | |||
| class Registers() extends MultiIOModule { | |||
| // Don't touch the test harness | |||
| val testHarness = IO( | |||
| new Bundle { | |||
| val setup = Input(new RegisterSetupSignals) | |||
| val testUpdates = Output(new RegisterUpdates) | |||
| } | |||
| ) | |||
| // You shouldn't really touch these either | |||
| val io = IO( | |||
| new Bundle { | |||
| val readAddress1 = Input(UInt(5.W)) | |||
| val readAddress2 = Input(UInt(5.W)) | |||
| val writeEnable = Input(Bool()) | |||
| val writeAddress = Input(UInt(5.W)) | |||
| val writeData = Input(UInt(32.W)) | |||
| val readData1 = Output(UInt(32.W)) | |||
| val readData2 = Output(UInt(32.W)) | |||
| }) | |||
| /** | |||
| * Mem creates asynchronous read, synchronous write. | |||
| * In other words, reading is combinatory. | |||
| */ | |||
| val registerFile = Mem(32, UInt(32.W)) | |||
| val readAddress1 = Wire(UInt(5.W)) | |||
| val readAddress2 = Wire(UInt(5.W)) | |||
| val writeAddress = Wire(UInt(5.W)) | |||
| val writeData = Wire(UInt(32.W)) | |||
| val writeEnable = Wire(Bool()) | |||
| when(testHarness.setup.setup){ | |||
| readAddress1 := testHarness.setup.readAddress | |||
| readAddress2 := io.readAddress2 | |||
| writeData := testHarness.setup.writeData | |||
| writeEnable := testHarness.setup.writeEnable | |||
| writeAddress := testHarness.setup.readAddress | |||
| }.otherwise{ | |||
| readAddress1 := io.readAddress1 | |||
| readAddress2 := io.readAddress2 | |||
| writeData := io.writeData | |||
| writeEnable := io.writeEnable | |||
| writeAddress := io.writeAddress | |||
| } | |||
| testHarness.testUpdates.writeData := writeData | |||
| testHarness.testUpdates.writeEnable := writeEnable | |||
| testHarness.testUpdates.writeAddress := writeAddress | |||
| when(writeEnable){ | |||
| when(writeAddress =/= 0.U){ | |||
| registerFile(writeAddress) := writeData | |||
| } | |||
| } | |||
| io.readData1 := 0.U | |||
| io.readData2 := 0.U | |||
| when(readAddress1 =/= 0.U){ io.readData1 := registerFile(readAddress1) } | |||
| when(readAddress2 =/= 0.U){ io.readData2 := registerFile(readAddress2) } | |||
| } | |||
| @@ -0,0 +1,51 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.core.Wire | |||
| import chisel3.util.{ BitPat, Cat } | |||
| /** | |||
| * Don't touch these | |||
| */ | |||
| class SetupSignals extends Bundle { | |||
| val IMEMsignals = new IMEMsetupSignals | |||
| val DMEMsignals = new DMEMsetupSignals | |||
| val registerSignals = new RegisterSetupSignals | |||
| } | |||
| class IMEMsetupSignals extends Bundle { | |||
| val setup = Bool() | |||
| val address = UInt(32.W) | |||
| val instruction = UInt(32.W) | |||
| } | |||
| class DMEMsetupSignals extends Bundle { | |||
| val setup = Bool() | |||
| val writeEnable = Bool() | |||
| val dataIn = UInt(32.W) | |||
| val dataAddress = UInt(32.W) | |||
| } | |||
| class RegisterSetupSignals extends Bundle { | |||
| val setup = Bool() | |||
| val readAddress = UInt(5.W) | |||
| val writeEnable = Bool() | |||
| val writeAddress = UInt(5.W) | |||
| val writeData = UInt(32.W) | |||
| } | |||
| class TestReadouts extends Bundle { | |||
| val registerRead = UInt(32.W) | |||
| val DMEMread = UInt(32.W) | |||
| } | |||
| class RegisterUpdates extends Bundle { | |||
| val writeEnable = Bool() | |||
| val writeData = UInt(32.W) | |||
| val writeAddress = UInt(5.W) | |||
| } | |||
| class MemUpdates extends Bundle { | |||
| val writeEnable = Bool() | |||
| val writeData = UInt(32.W) | |||
| val writeAddress = UInt(32.W) | |||
| } | |||
| @@ -0,0 +1,75 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.util._ | |||
| import chisel3.core.Input | |||
| import chisel3.iotesters.PeekPokeTester | |||
| /** | |||
| * The top level module. You do not have to change anything here, | |||
| * however you are free to route out signals as you see fit for debugging. | |||
| */ | |||
| class Tile() extends Module{ | |||
| val io = IO( | |||
| new Bundle { | |||
| val DMEMWriteData = Input(UInt(32.W)) | |||
| val DMEMAddress = Input(UInt(32.W)) | |||
| val DMEMWriteEnable = Input(Bool()) | |||
| val DMEMReadData = Output(UInt(32.W)) | |||
| val regsWriteData = Input(UInt(32.W)) | |||
| val regsAddress = Input(UInt(5.W)) | |||
| val regsWriteEnable = Input(Bool()) | |||
| val regsReadData = Output(UInt(32.W)) | |||
| val regsDeviceWriteEnable = Output(Bool()) | |||
| val regsDeviceWriteData = Output(UInt(32.W)) | |||
| val regsDeviceWriteAddress = Output(UInt(5.W)) | |||
| val memDeviceWriteEnable = Output(Bool()) | |||
| val memDeviceWriteData = Output(UInt(32.W)) | |||
| val memDeviceWriteAddress = Output(UInt(32.W)) | |||
| val IMEMWriteData = Input(UInt(32.W)) | |||
| val IMEMAddress = Input(UInt(32.W)) | |||
| val setup = Input(Bool()) | |||
| val currentPC = Output(UInt()) | |||
| }) | |||
| val CPU = Module(new CPU).testHarness | |||
| CPU.setupSignals.IMEMsignals.address := io.IMEMAddress | |||
| CPU.setupSignals.IMEMsignals.instruction := io.IMEMWriteData | |||
| CPU.setupSignals.IMEMsignals.setup := io.setup | |||
| CPU.setupSignals.DMEMsignals.writeEnable := io.DMEMWriteEnable | |||
| CPU.setupSignals.DMEMsignals.dataAddress := io.DMEMAddress | |||
| CPU.setupSignals.DMEMsignals.dataIn := io.DMEMWriteData | |||
| CPU.setupSignals.DMEMsignals.setup := io.setup | |||
| CPU.setupSignals.registerSignals.readAddress := io.regsAddress | |||
| CPU.setupSignals.registerSignals.writeEnable := io.regsWriteEnable | |||
| CPU.setupSignals.registerSignals.writeAddress := io.regsAddress | |||
| CPU.setupSignals.registerSignals.writeData := io.regsWriteData | |||
| CPU.setupSignals.registerSignals.setup := io.setup | |||
| io.DMEMReadData := CPU.testReadouts.DMEMread | |||
| io.regsReadData := CPU.testReadouts.registerRead | |||
| io.regsDeviceWriteAddress := CPU.regUpdates.writeAddress | |||
| io.regsDeviceWriteEnable := CPU.regUpdates.writeEnable | |||
| io.regsDeviceWriteData := CPU.regUpdates.writeData | |||
| io.memDeviceWriteAddress := CPU.memUpdates.writeAddress | |||
| io.memDeviceWriteEnable := CPU.memUpdates.writeEnable | |||
| io.memDeviceWriteData := CPU.memUpdates.writeData | |||
| io.currentPC := CPU.currentPC | |||
| } | |||
| @@ -0,0 +1,105 @@ | |||
| package FiveStage | |||
| import chisel3._ | |||
| import chisel3.core.Wire | |||
| import chisel3.util.{ BitPat, Cat } | |||
| class Instruction extends Bundle(){ | |||
| val instruction = UInt(32.W) | |||
| def opcode = instruction(6, 0) | |||
| def registerRd = instruction(11, 7) | |||
| def funct3 = instruction(14, 12) | |||
| def registerRs1 = instruction(19, 15) | |||
| def registerRs2 = instruction(24, 20) | |||
| def funct7 = instruction(31, 25) | |||
| def funct6 = instruction(26, 31) | |||
| def immediateIType = instruction(31, 20).asSInt | |||
| def immediateSType = Cat(instruction(31, 25), instruction(11,7)).asSInt | |||
| def immediateBType = Cat(instruction(31), instruction(7), instruction(30, 25), instruction(11, 8), 0.U(1.W)).asSInt | |||
| def immediateUType = Cat(instruction(31, 12), 0.U(12.W)).asSInt | |||
| def immediateJType = Cat(instruction(31), instruction(19, 12), instruction(20), instruction(30, 25), instruction(24, 21), 0.U(1.W)).asSInt | |||
| def immediateZType = instruction(19, 15).zext | |||
| } | |||
| object Instruction { | |||
| def bubble(i: Instruction) = | |||
| i.opcode := BitPat.bitPatToUInt(BitPat("b0010011")) | |||
| def default: Instruction = { | |||
| val w = Wire(new Instruction) | |||
| w.instruction := 0.U | |||
| w | |||
| } | |||
| } | |||
| class ControlSignals extends Bundle(){ | |||
| val memToReg = Bool() | |||
| val regWrite = Bool() | |||
| val memRead = Bool() | |||
| val memWrite = Bool() | |||
| val branch = Bool() | |||
| val jump = Bool() | |||
| } | |||
| object ControlSignals { | |||
| def nop: ControlSignals = { | |||
| val b = Wire(new ControlSignals) | |||
| b.memToReg := false.B | |||
| b.regWrite := false.B | |||
| b.memRead := false.B | |||
| b.memWrite := false.B | |||
| b.branch := false.B | |||
| b.jump := false.B | |||
| b | |||
| } | |||
| } | |||
| object branchType { | |||
| val beq = 0.asUInt(3.W) | |||
| val neq = 1.asUInt(3.W) | |||
| val gte = 2.asUInt(3.W) | |||
| val lt = 3.asUInt(3.W) | |||
| val gteu = 4.asUInt(3.W) | |||
| val ltu = 5.asUInt(3.W) | |||
| val jump = 6.asUInt(3.W) | |||
| val DC = 0.asUInt(3.W) | |||
| } | |||
| /** | |||
| these take the role of the alu source signal. | |||
| Used in the decoder. | |||
| In the solution manual I use these to select signals at the decode stage. | |||
| You can choose to instead do this in the execute stage, and you may forego | |||
| using them altogether. | |||
| */ | |||
| object Op1Select { | |||
| val rs1 = 0.asUInt(1.W) | |||
| val PC = 1.asUInt(1.W) | |||
| val DC = 0.asUInt(1.W) | |||
| } | |||
| object Op2Select { | |||
| val rs2 = 0.asUInt(1.W) | |||
| val imm = 1.asUInt(1.W) | |||
| val DC = 0.asUInt(1.W) | |||
| } | |||
| /** | |||
| Used in the decoder | |||
| */ | |||
| object ImmFormat { | |||
| val ITYPE = 0.asUInt(3.W) | |||
| val STYPE = 1.asUInt(3.W) | |||
| val BTYPE = 2.asUInt(3.W) | |||
| val UTYPE = 3.asUInt(3.W) | |||
| val JTYPE = 4.asUInt(3.W) | |||
| val SHAMT = 5.asUInt(3.W) | |||
| val DC = 0.asUInt(3.W) | |||
| } | |||
| @@ -0,0 +1,52 @@ | |||
| main: | |||
| addi x1, zero, 1 | |||
| addi x2, zero, -1 | |||
| addi x3, zero, 3 | |||
| addi x4, zero, 7 | |||
| addi x5, zero, 14 | |||
| addi x6, zero, 28 | |||
| addi x7, zero, 56 | |||
| addi x8, zero, 133 | |||
| addi x9, zero, 258 | |||
| addi x10, x1, -231 | |||
| addi x11, x1, -510 | |||
| slt x12, x1, x1 | |||
| slt x12, x1, x2 | |||
| slt x12, x1, x3 | |||
| slt x12, x2, x1 | |||
| slt x12, x2, x2 | |||
| slt x12, x2, x3 | |||
| sltu x12, x1, x1 | |||
| sltu x12, x1, x2 | |||
| sltu x12, x1, x3 | |||
| sltu x12, x2, x1 | |||
| sltu x12, x2, x2 | |||
| sltu x12, x2, x3 | |||
| sll x14, x1, x1 | |||
| sll x14, x1, x2 | |||
| sll x14, x1, x3 | |||
| srl x14, x1, x1 | |||
| srl x14, x1, x2 | |||
| srl x14, x1, x3 | |||
| sra x14, x1, x1 | |||
| sra x14, x1, x2 | |||
| sra x14, x1, x3 | |||
| and x15, x8, x9 | |||
| and x15, x9, x10 | |||
| or x15, x8, x9 | |||
| or x15, x9, x10 | |||
| xor x15, x8, x9 | |||
| xor x15, x9, x10 | |||
| add x16, x1, x5 | |||
| add x16, x2, x7 | |||
| add x16, x3, x6 | |||
| add x16, x4, x10 | |||
| add x16, x5, x14 | |||
| add x16, x6, x15 | |||
| add x16, x7, x7 | |||
| add x16, x8, x9 | |||
| add x16, x9, x1 | |||
| add x16, x10, x8 | |||
| add x16, x11, x9 | |||
| add x16, x12, x10 | |||
| done | |||
| @@ -0,0 +1,205 @@ | |||
| main: | |||
| ori gp, gp, 0xFFFFFE09 | |||
| and gp, gp, ra | |||
| xor ra, ra, sp | |||
| sra ra, sp, sp | |||
| or sp, ra, ra | |||
| xori ra, sp, 0x003D | |||
| srli sp, sp, 0xFFFFFFF2 | |||
| addi ra, sp, 0x0012 | |||
| add ra, gp, sp | |||
| ori gp, ra, 0xFFFFFFB8 | |||
| sll ra, ra, ra | |||
| sll sp, gp, ra | |||
| slt ra, gp, ra | |||
| srai gp, gp, 0xFFFFFFFB | |||
| slli ra, ra, 0x0007 | |||
| sub sp, gp, sp | |||
| andi ra, gp, 0x002D | |||
| sub gp, gp, sp | |||
| srai ra, gp, 0x0005 | |||
| or sp, ra, sp | |||
| xori ra, gp, 0xFFFFFF54 | |||
| sll ra, sp, ra | |||
| sub gp, gp, sp | |||
| add ra, sp, sp | |||
| sll ra, gp, ra | |||
| add gp, sp, sp | |||
| ori gp, sp, 0xFFFFFE68 | |||
| srli sp, gp, 0xFFFFFFF1 | |||
| sltui ra, ra, 0xFFFFFE5D | |||
| srli ra, gp, 0x0006 | |||
| srai sp, sp, 0x0005 | |||
| andi sp, sp, 0x0129 | |||
| and sp, sp, sp | |||
| slli gp, ra, 0x0001 | |||
| or gp, gp, gp | |||
| or sp, gp, gp | |||
| slli gp, gp, 0x0006 | |||
| srl sp, ra, gp | |||
| sltui gp, ra, 0xFFFFFEC3 | |||
| add sp, gp, sp | |||
| xori ra, ra, 0xFFFFFFA2 | |||
| or gp, gp, sp | |||
| and sp, gp, gp | |||
| srai gp, sp, 0x0008 | |||
| add sp, sp, ra | |||
| slti sp, ra, 0xFFFFFFF7 | |||
| srli gp, ra, 0xFFFFFFFD | |||
| sll gp, ra, gp | |||
| sltu sp, sp, gp | |||
| srli gp, ra, 0x0002 | |||
| ori gp, sp, 0xFFFFFF28 | |||
| srl ra, gp, ra | |||
| slti gp, ra, 0x0054 | |||
| or gp, ra, ra | |||
| ori sp, gp, 0x01D9 | |||
| and sp, ra, ra | |||
| addi sp, gp, 0x0054 | |||
| slli gp, ra, 0xFFFFFFF2 | |||
| ori sp, sp, 0x0093 | |||
| add gp, gp, gp | |||
| and gp, gp, gp | |||
| sltui gp, ra, 0x00DE | |||
| slli sp, gp, 0x000D | |||
| slli sp, ra, 0xFFFFFFF5 | |||
| sltui sp, ra, 0xFFFFFF0E | |||
| and ra, gp, ra | |||
| add gp, sp, sp | |||
| slti ra, sp, 0x008C | |||
| srli ra, sp, 0x0000 | |||
| addi sp, sp, 0x0168 | |||
| slli ra, ra, 0xFFFFFFF3 | |||
| addi ra, gp, 0x012A | |||
| or sp, gp, ra | |||
| add ra, sp, gp | |||
| and gp, ra, ra | |||
| slli ra, gp, 0xFFFFFFF6 | |||
| or sp, gp, sp | |||
| or gp, ra, ra | |||
| ori gp, ra, 0x00EB | |||
| or sp, gp, ra | |||
| ori gp, sp, 0x01DA | |||
| andi ra, ra, 0xFFFFFFE9 | |||
| addi gp, sp, 0x00C9 | |||
| sltui ra, ra, 0xFFFFFF13 | |||
| sltui ra, ra, 0xFFFFFF3A | |||
| sltui sp, gp, 0xFFFFFE5A | |||
| ori sp, sp, 0xFFFFFFFE | |||
| and gp, sp, gp | |||
| sltui sp, ra, 0x0034 | |||
| srl gp, gp, ra | |||
| sll gp, sp, ra | |||
| ori ra, gp, 0xFFFFFEB6 | |||
| sll ra, sp, ra | |||
| sra ra, gp, sp | |||
| sub ra, sp, gp | |||
| xor gp, gp, sp | |||
| sub ra, ra, sp | |||
| srl gp, gp, sp | |||
| andi ra, ra, 0xFFFFFFCB | |||
| ori ra, ra, 0xFFFFFE1B | |||
| andi ra, ra, 0xFFFFFEC8 | |||
| sltui sp, gp, 0x0108 | |||
| sub sp, gp, ra | |||
| slti ra, sp, 0x015D | |||
| slli sp, sp, 0x0004 | |||
| xor gp, sp, ra | |||
| srl ra, gp, ra | |||
| sltui ra, ra, 0xFFFFFF3C | |||
| add sp, sp, sp | |||
| add gp, gp, ra | |||
| andi sp, sp, 0xFFFFFF3A | |||
| srli ra, sp, 0x0004 | |||
| ori sp, gp, 0xFFFFFEAB | |||
| ori sp, ra, 0xFFFFFE95 | |||
| slli sp, sp, 0xFFFFFFF2 | |||
| xori gp, sp, 0x0040 | |||
| slti gp, sp, 0xFFFFFED1 | |||
| or sp, sp, sp | |||
| sltui sp, gp, 0x01B4 | |||
| addi ra, gp, 0x002D | |||
| and sp, gp, gp | |||
| or ra, ra, ra | |||
| or ra, gp, ra | |||
| or ra, gp, ra | |||
| sra ra, ra, gp | |||
| sra gp, ra, sp | |||
| sub ra, sp, ra | |||
| srai ra, ra, 0x000F | |||
| sltu sp, sp, ra | |||
| slli ra, gp, 0xFFFFFFF5 | |||
| slti gp, gp, 0x00E0 | |||
| addi gp, ra, 0xFFFFFF72 | |||
| srl ra, ra, gp | |||
| sltui gp, sp, 0xFFFFFEAA | |||
| xor sp, ra, gp | |||
| and gp, sp, ra | |||
| srli gp, gp, 0x0003 | |||
| xori ra, ra, 0x01BD | |||
| sub ra, gp, sp | |||
| sll gp, ra, gp | |||
| xori ra, sp, 0x0065 | |||
| or ra, sp, ra | |||
| slt sp, gp, ra | |||
| addi ra, sp, 0xFFFFFE34 | |||
| slli gp, sp, 0x0007 | |||
| sll ra, sp, gp | |||
| sltui gp, gp, 0xFFFFFE62 | |||
| slti sp, sp, 0x0019 | |||
| xori ra, gp, 0x0092 | |||
| sltui gp, sp, 0xFFFFFF29 | |||
| srl sp, ra, gp | |||
| xori sp, gp, 0xFFFFFF4C | |||
| add sp, ra, gp | |||
| add sp, gp, ra | |||
| sra sp, sp, gp | |||
| slli sp, ra, 0x0008 | |||
| srl sp, sp, sp | |||
| add sp, gp, ra | |||
| andi sp, sp, 0x0039 | |||
| sll ra, gp, sp | |||
| andi gp, ra, 0xFFFFFECC | |||
| sll sp, sp, sp | |||
| sub sp, sp, ra | |||
| srai ra, sp, 0x0008 | |||
| xor gp, ra, sp | |||
| add sp, sp, sp | |||
| sub gp, ra, gp | |||
| xori gp, sp, 0x01EE | |||
| and ra, ra, ra | |||
| ori gp, ra, 0xFFFFFE96 | |||
| slli ra, gp, 0x0002 | |||
| srli gp, ra, 0x000D | |||
| add ra, sp, sp | |||
| andi sp, gp, 0xFFFFFEC0 | |||
| andi sp, gp, 0xFFFFFE7A | |||
| xori ra, sp, 0x0169 | |||
| xori gp, sp, 0xFFFFFE02 | |||
| andi ra, ra, 0xFFFFFFD1 | |||
| xor ra, sp, gp | |||
| xori gp, gp, 0x00AB | |||
| srl ra, ra, gp | |||
| and ra, ra, sp | |||
| xori gp, sp, 0x005D | |||
| srai sp, sp, 0x000A | |||
| addi ra, sp, 0xFFFFFE19 | |||
| or sp, ra, ra | |||
| addi ra, gp, 0x0084 | |||
| ori sp, sp, 0xFFFFFF3D | |||
| xor gp, ra, gp | |||
| sra ra, ra, gp | |||
| xori ra, sp, 0x0040 | |||
| srai gp, gp, 0x0002 | |||
| xori ra, ra, 0xFFFFFE9A | |||
| sra ra, sp, sp | |||
| ori gp, sp, 0xFFFFFFB8 | |||
| sll sp, ra, ra | |||
| sll sp, ra, gp | |||
| sll gp, sp, sp | |||
| sra gp, ra, ra | |||
| srli gp, gp, 0x0001 | |||
| done | |||
| #regset x1, 123 | |||
| #regset x2, -40 | |||
| #regset x3, 0xFFEE | |||
| @@ -0,0 +1,205 @@ | |||
| main: | |||
| sltui gp, ra, 0x01AE | |||
| srli sp, sp, 0xFFFFFFFB | |||
| addi ra, sp, 0x0177 | |||
| sub sp, ra, sp | |||
| slli sp, ra, 0x000B | |||
| add sp, gp, ra | |||
| slli gp, sp, 0x0006 | |||
| ori sp, ra, 0xFFFFFF64 | |||
| and gp, gp, gp | |||
| andi gp, gp, 0x0084 | |||
| xori ra, ra, 0xFFFFFEB4 | |||
| or sp, ra, ra | |||
| addi sp, ra, 0x0078 | |||
| srli gp, sp, 0x0000 | |||
| srl sp, gp, sp | |||
| andi ra, gp, 0xFFFFFFF4 | |||
| srai ra, ra, 0xFFFFFFFF | |||
| sltu gp, sp, gp | |||
| or sp, ra, gp | |||
| sub ra, gp, ra | |||
| addi sp, gp, 0x017C | |||
| sltui ra, gp, 0xFFFFFF64 | |||
| xori sp, gp, 0x00A1 | |||
| xor ra, sp, gp | |||
| ori gp, ra, 0x00B6 | |||
| add ra, ra, sp | |||
| sltui gp, ra, 0xFFFFFFEC | |||
| sltu gp, sp, ra | |||
| sll sp, ra, gp | |||
| add gp, ra, ra | |||
| or gp, ra, gp | |||
| xor sp, ra, sp | |||
| addi sp, gp, 0xFFFFFF4C | |||
| xor ra, sp, gp | |||
| xori ra, sp, 0xFFFFFF72 | |||
| xori gp, sp, 0xFFFFFE95 | |||
| or ra, ra, ra | |||
| slti ra, gp, 0xFFFFFE75 | |||
| slli sp, sp, 0xFFFFFFFC | |||
| sltui ra, ra, 0xFFFFFE25 | |||
| add sp, ra, gp | |||
| sltui gp, gp, 0xFFFFFFDB | |||
| addi sp, sp, 0x003D | |||
| sll ra, ra, sp | |||
| ori ra, ra, 0x012C | |||
| add gp, ra, gp | |||
| xori sp, sp, 0x0157 | |||
| slti gp, sp, 0xFFFFFF2A | |||
| and sp, ra, ra | |||
| add gp, ra, ra | |||
| sltui ra, gp, 0xFFFFFE56 | |||
| sra gp, gp, ra | |||
| xori sp, gp, 0xFFFFFF0D | |||
| sub sp, gp, ra | |||
| slti ra, ra, 0x0154 | |||
| slli ra, ra, 0x000A | |||
| ori ra, gp, 0xFFFFFEC2 | |||
| ori ra, sp, 0x0075 | |||
| addi gp, sp, 0x0079 | |||
| xor gp, ra, sp | |||
| srli ra, sp, 0xFFFFFFF8 | |||
| slli gp, gp, 0x0006 | |||
| sra sp, gp, gp | |||
| add sp, sp, sp | |||
| slli gp, ra, 0xFFFFFFF0 | |||
| add sp, ra, sp | |||
| srai ra, sp, 0x0005 | |||
| addi ra, gp, 0xFFFFFF83 | |||
| xor gp, sp, ra | |||
| srli ra, ra, 0x0007 | |||
| sll gp, ra, gp | |||
| xori gp, gp, 0x0163 | |||
| add ra, gp, gp | |||
| add sp, ra, ra | |||
| sltu ra, ra, sp | |||
| sll sp, ra, ra | |||
| ori sp, sp, 0xFFFFFF6B | |||
| slli gp, gp, 0xFFFFFFFA | |||
| xori sp, ra, 0x00A7 | |||
| add sp, ra, ra | |||
| add ra, gp, gp | |||
| addi gp, gp, 0xFFFFFFE9 | |||
| sra sp, ra, gp | |||
| add gp, ra, ra | |||
| ori gp, gp, 0x0002 | |||
| addi gp, gp, 0x002F | |||
| sll sp, sp, ra | |||
| srli sp, ra, 0xFFFFFFF2 | |||
| ori gp, sp, 0x00EB | |||
| sra gp, ra, sp | |||
| sra sp, sp, gp | |||
| and gp, ra, ra | |||
| sra ra, ra, gp | |||
| add sp, gp, ra | |||
| srl gp, sp, gp | |||
| add ra, ra, sp | |||
| srai gp, ra, 0xFFFFFFF2 | |||
| srli sp, ra, 0xFFFFFFFC | |||
| ori gp, sp, 0xFFFFFE6E | |||
| and gp, ra, ra | |||
| ori gp, ra, 0xFFFFFFAF | |||
| srl ra, ra, ra | |||
| or sp, ra, ra | |||
| ori gp, sp, 0x0018 | |||
| and gp, gp, gp | |||
| slti gp, ra, 0x00C6 | |||
| sll gp, sp, gp | |||
| srli gp, sp, 0xFFFFFFFA | |||
| add gp, ra, ra | |||
| add gp, ra, sp | |||
| sra sp, ra, ra | |||
| ori sp, ra, 0x0022 | |||
| and gp, gp, gp | |||
| add ra, sp, ra | |||
| sll sp, gp, gp | |||
| ori gp, sp, 0x008E | |||
| slti ra, gp, 0x00B5 | |||
| add sp, ra, sp | |||
| and sp, gp, gp | |||
| addi ra, sp, 0x0145 | |||
| and sp, gp, gp | |||
| sll gp, ra, sp | |||
| addi sp, sp, 0xFFFFFFAF | |||
| xori sp, ra, 0xFFFFFE2C | |||
| srl gp, ra, gp | |||
| sub ra, sp, gp | |||
| add sp, ra, ra | |||
| slli sp, sp, 0x0006 | |||
| sub gp, ra, sp | |||
| sltu sp, ra, gp | |||
| xori ra, ra, 0xFFFFFF9A | |||
| addi sp, sp, 0xFFFFFE12 | |||
| slli ra, ra, 0xFFFFFFFD | |||
| add gp, gp, gp | |||
| xori ra, ra, 0xFFFFFED7 | |||
| andi gp, gp, 0xFFFFFE05 | |||
| and gp, gp, sp | |||
| addi gp, gp, 0xFFFFFEE5 | |||
| slli ra, gp, 0xFFFFFFF6 | |||
| sll sp, gp, gp | |||
| and ra, gp, sp | |||
| ori ra, gp, 0xFFFFFE22 | |||
| srl sp, sp, gp | |||
| srli ra, sp, 0x0005 | |||
| slli ra, ra, 0xFFFFFFFB | |||
| srai ra, ra, 0xFFFFFFF9 | |||
| srli ra, gp, 0xFFFFFFF1 | |||
| andi gp, gp, 0xFFFFFF96 | |||
| sra sp, gp, gp | |||
| srai gp, gp, 0x000F | |||
| sub sp, sp, gp | |||
| sltui ra, ra, 0xFFFFFF41 | |||
| and sp, sp, sp | |||
| xor gp, sp, ra | |||
| srai gp, sp, 0xFFFFFFF6 | |||
| xori gp, gp, 0x00D3 | |||
| or gp, sp, sp | |||
| sltu gp, ra, gp | |||
| slli ra, gp, 0x0002 | |||
| or sp, gp, ra | |||
| addi ra, ra, 0x002B | |||
| addi gp, ra, 0x0035 | |||
| slli sp, gp, 0x0008 | |||
| addi gp, sp, 0x015E | |||
| xor ra, gp, sp | |||
| or ra, gp, ra | |||
| sll ra, gp, ra | |||
| sll gp, gp, ra | |||
| srli gp, ra, 0xFFFFFFF4 | |||
| slt sp, ra, sp | |||
| sltui sp, sp, 0xFFFFFE1C | |||
| ori sp, ra, 0xFFFFFE83 | |||
| andi sp, sp, 0xFFFFFEFC | |||
| addi ra, ra, 0xFFFFFF85 | |||
| ori gp, ra, 0x0084 | |||
| sll gp, gp, ra | |||
| xori gp, sp, 0xFFFFFF6D | |||
| sll gp, sp, gp | |||
| sra ra, sp, ra | |||
| xor ra, gp, sp | |||
| srl ra, ra, sp | |||
| srl ra, ra, sp | |||
| andi gp, ra, 0xFFFFFE7B | |||
| srai ra, sp, 0xFFFFFFF1 | |||
| sub sp, sp, ra | |||
| or sp, gp, gp | |||
| slt ra, ra, gp | |||
| or gp, gp, sp | |||
| srli ra, sp, 0xFFFFFFF5 | |||
| andi ra, gp, 0xFFFFFFD4 | |||
| sra sp, sp, sp | |||
| add sp, ra, sp | |||
| sub gp, ra, sp | |||
| xori ra, gp, 0x0131 | |||
| add sp, sp, ra | |||
| addi sp, gp, 0x0003 | |||
| sll ra, ra, ra | |||
| slli gp, ra, 0x000E | |||
| andi ra, gp, 0xFFFFFE88 | |||
| srai ra, gp, 0xFFFFFFFA | |||
| done | |||
| #regset x1, 123 | |||
| #regset x2, -40 | |||
| #regset x3, 0xFFEE | |||
| @@ -0,0 +1,41 @@ | |||
| main: | |||
| addi x0, x1, 1 | |||
| addi x0, x1, 2 | |||
| addi x0, x1, 3 | |||
| addi x0, x1, 7 | |||
| addi x0, x1, 14 | |||
| addi x0, x1, 28 | |||
| addi x0, x1, 56 | |||
| addi x31, x1, 1 | |||
| addi x31, x1, 2 | |||
| addi x31, x1, 3 | |||
| addi x31, x1, 7 | |||
| addi x31, x1, 14 | |||
| addi x31, x1, 28 | |||
| addi x31, x1, 56 | |||
| addi x31, x1, 133 | |||
| addi x31, x1, 258 | |||
| addi x31, x1, 511 | |||
| addi x31, x1, -1 | |||
| addi x31, x1, -3 | |||
| addi x31, x1, -9 | |||
| addi x31, x1, -98 | |||
| addi x31, x1, -231 | |||
| addi x31, x1, -510 | |||
| addi x30, x0, 1 | |||
| addi x30, x30, 2 | |||
| addi x30, x30, 3 | |||
| addi x30, x30, 7 | |||
| addi x30, x30, 14 | |||
| addi x30, x30, 28 | |||
| addi x30, x30, 56 | |||
| addi x30, x30, 133 | |||
| addi x30, x30, 258 | |||
| addi x30, x30, 511 | |||
| addi x30, x30, -1 | |||
| addi x30, x30, -3 | |||
| addi x30, x30, -9 | |||
| addi x30, x30, -98 | |||
| addi x30, x30, -231 | |||
| addi x30, x30, -510 | |||
| done | |||
| @@ -0,0 +1,37 @@ | |||
| main: | |||
| addi x1, zero, 1 | |||
| addi x2, zero, -1 | |||
| addi x3, zero, 3 | |||
| addi x4, zero, 7 | |||
| addi x5, zero, 14 | |||
| addi x6, zero, 28 | |||
| addi x7, zero, 56 | |||
| addi x8, zero, 133 | |||
| addi x9, zero, 258 | |||
| addi x10, x1, -231 | |||
| addi x11, x1, -510 | |||
| slti x12, x1, 1 | |||
| slti x12, x1, 10 | |||
| slti x12, x1, -10 | |||
| sltiu x13, x1, 1 | |||
| sltiu x13, x1, 10 | |||
| sltiu x13, x1, -10 | |||
| slti x12, x2, 1 | |||
| slti x12, x2, 10 | |||
| slti x12, x2, -10 | |||
| sltiu x13, x2, 1 | |||
| sltiu x13, x2, 10 | |||
| sltiu x13, x2, -10 | |||
| slli x14, x1, 16 | |||
| slli x14, x2, 16 | |||
| srai x14, x1, 16 | |||
| srai x14, x2, 16 | |||
| srli x14, x1, 16 | |||
| srli x14, x2, 16 | |||
| andi x15, x8, 3 | |||
| andi x15, x9, -1 | |||
| ori x15, x8, 3 | |||
| ori x15, x9, -1 | |||
| xori x15, x8, 3 | |||
| xori x15, x9, -1 | |||
| done | |||
| @@ -0,0 +1,35 @@ | |||
| main: | |||
| addi x1, zero, 4 | |||
| addi x2, zero, 4 | |||
| addi x3, zero, 4 | |||
| addi x4, zero, 4 | |||
| lw x3, 0(x3) | |||
| nop | |||
| nop | |||
| lw x3, 0(x3) | |||
| nop | |||
| nop | |||
| lw x3, 0(x3) | |||
| nop | |||
| nop | |||
| lw x3, 0(x3) | |||
| nop | |||
| nop | |||
| lw x2, 0(x2) | |||
| nop | |||
| lw x2, 0(x2) | |||
| nop | |||
| lw x2, 0(x2) | |||
| nop | |||
| lw x2, 0(x2) | |||
| nop | |||
| lw x1, 0(x1) | |||
| lw x1, 0(x1) | |||
| lw x1, 0(x1) | |||
| lw x1, 0(x1) | |||
| done | |||
| #memset 0x0, 4 | |||
| #memset 0x4, 8 | |||
| #memset 0x8, 12 | |||
| #memset 0xc, 16 | |||
| #memset 0x10, 20 | |||
| @@ -0,0 +1,20 @@ | |||
| main: | |||
| addi x1, zero, 4 | |||
| addi x2, zero, 4 | |||
| addi x3, zero, 4 | |||
| addi x4, zero, 4 | |||
| lw x1, 0(x1) | |||
| add x1, x1, x1 | |||
| lw x1, 0(x1) | |||
| sw x1, 4(x1) | |||
| lw x1, 4(x1) | |||
| done | |||
| #memset 0x0, 4 | |||
| #memset 0x4, 8 | |||
| #memset 0x8, 12 | |||
| #memset 0xc, 16 | |||
| #memset 0x10, 20 | |||
| #memset 0x14, 20 | |||
| #memset 0x18, 20 | |||
| #memset 0x1c, 20 | |||
| #memset 0x20, 20 | |||
| @@ -0,0 +1,180 @@ | |||
| main: | |||
| addi sp,sp,-16 | |||
| sw ra,12(sp) | |||
| sw s0,8(sp) | |||
| sw s1,4(sp) | |||
| sw s2,0(sp) | |||
| lw s2,0(zero) | |||
| lw a5,0(s2) | |||
| blez a5,.L17 | |||
| addi s0,s2,4 | |||
| slli a5,a5,2 | |||
| add s2,a5,s0 | |||
| li s1,0 | |||
| .L16: | |||
| addi s0,s0,4 | |||
| lw a0,0(s0) | |||
| call find | |||
| add s1,s1,a0 | |||
| bne s0,s2,.L16 | |||
| .L14: | |||
| mv a0,s1 | |||
| lw ra,12(sp) | |||
| lw s0,8(sp) | |||
| lw s1,4(sp) | |||
| lw s2,0(sp) | |||
| addi sp,sp,16 | |||
| jr ra | |||
| .L17: | |||
| li s1,0 | |||
| j .L14 | |||
| find: | |||
| li a5,4 | |||
| j .L2 | |||
| .L12: | |||
| mv a0,a5 | |||
| ret | |||
| .L13: | |||
| lw a5,0(a5) | |||
| slli a5,a5,1 | |||
| andi a5,a5,508 | |||
| addi a5,a5,4 | |||
| j .L2 | |||
| .L4: | |||
| bge a4,a0,.L9 | |||
| lw a4,0(a5) | |||
| andi a4,a4,256 | |||
| beqz a4,.L10 | |||
| lw a5,0(a5) | |||
| srli a5,a5,7 | |||
| andi a5,a5,508 | |||
| addi a5,a5,4 | |||
| .L2: | |||
| lh a4,2(a5) | |||
| beq a4,a0,.L12 | |||
| ble a4,a0,.L4 | |||
| lw a4,0(a5) | |||
| andi a4,a4,1 | |||
| bnez a4,.L13 | |||
| li a0,-1 | |||
| ret | |||
| .L9: | |||
| li a0,-1 | |||
| ret | |||
| .L10: | |||
| li a0,-1 | |||
| ret | |||
| #memset 0x0, 0x019C | |||
| #memset 0x0004, 0x02D49D03 | |||
| #memset 0x0008, 0x00912305 | |||
| #memset 0x000C, 0x00301307 | |||
| #memset 0x0010, 0x001B0D09 | |||
| #memset 0x0014, 0x00010B00 | |||
| #memset 0x0018, 0x00090000 | |||
| #memset 0x001C, 0x001E110F | |||
| #memset 0x0020, 0x001D0000 | |||
| #memset 0x0024, 0x001E0000 | |||
| #memset 0x0028, 0x00782115 | |||
| #memset 0x002C, 0x00661D17 | |||
| #memset 0x0030, 0x003C1B19 | |||
| #memset 0x0034, 0x00300000 | |||
| #memset 0x0038, 0x00430000 | |||
| #memset 0x003C, 0x00701F00 | |||
| #memset 0x0040, 0x00700000 | |||
| #memset 0x0044, 0x007B0000 | |||
| #memset 0x0048, 0x018E5925 | |||
| #memset 0x004C, 0x00A12B27 | |||
| #memset 0x0050, 0x009F0029 | |||
| #memset 0x0054, 0x00910000 | |||
| #memset 0x0058, 0x011D392D | |||
| #memset 0x005C, 0x00E22F00 | |||
| #memset 0x0060, 0x01190031 | |||
| #memset 0x0064, 0x01090033 | |||
| #memset 0x0068, 0x00E93500 | |||
| #memset 0x006C, 0x00FF3700 | |||
| #memset 0x0070, 0x00FF0000 | |||
| #memset 0x0074, 0x01213F3B | |||
| #memset 0x0078, 0x0120003D | |||
| #memset 0x007C, 0x011F0000 | |||
| #memset 0x0080, 0x01835741 | |||
| #memset 0x0084, 0x016A5543 | |||
| #memset 0x0088, 0x012F4745 | |||
| #memset 0x008C, 0x012E0000 | |||
| #memset 0x0090, 0x014B4F49 | |||
| #memset 0x0094, 0x013A4B00 | |||
| #memset 0x0098, 0x01424D00 | |||
| #memset 0x009C, 0x01460000 | |||
| #memset 0x00A0, 0x015C0051 | |||
| #memset 0x00A4, 0x014D5300 | |||
| #memset 0x00A8, 0x01510000 | |||
| #memset 0x00AC, 0x01730000 | |||
| #memset 0x00B0, 0x018B0000 | |||
| #memset 0x00B4, 0x01BF655B | |||
| #memset 0x00B8, 0x01A2615D | |||
| #memset 0x00BC, 0x01995F00 | |||
| #memset 0x00C0, 0x019F0000 | |||
| #memset 0x00C4, 0x01A46300 | |||
| #memset 0x00C8, 0x01BD0000 | |||
| #memset 0x00CC, 0x027C8967 | |||
| #memset 0x00D0, 0x026C8569 | |||
| #memset 0x00D4, 0x01CC6D6B | |||
| #memset 0x00D8, 0x01C60000 | |||
| #memset 0x00DC, 0x021F7D6F | |||
| #memset 0x00E0, 0x02070071 | |||
| #memset 0x00E4, 0x01D37300 | |||
| #memset 0x00E8, 0x01F67B75 | |||
| #memset 0x00EC, 0x01EF7977 | |||
| #memset 0x00F0, 0x01D70000 | |||
| #memset 0x00F4, 0x01F10000 | |||
| #memset 0x00F8, 0x02060000 | |||
| #memset 0x00FC, 0x0254837F | |||
| #memset 0x0100, 0x023D0081 | |||
| #memset 0x0104, 0x02200000 | |||
| #memset 0x0108, 0x02640000 | |||
| #memset 0x010C, 0x026D8700 | |||
| #memset 0x0110, 0x026E0000 | |||
| #memset 0x0114, 0x02C0008B | |||
| #memset 0x0118, 0x0297998D | |||
| #memset 0x011C, 0x0289978F | |||
| #memset 0x0120, 0x02839591 | |||
| #memset 0x0124, 0x027C9300 | |||
| #memset 0x0128, 0x027E0000 | |||
| #memset 0x012C, 0x02850000 | |||
| #memset 0x0130, 0x028D0000 | |||
| #memset 0x0134, 0x029E009B | |||
| #memset 0x0138, 0x02990000 | |||
| #memset 0x013C, 0x03D4C99F | |||
| #memset 0x0140, 0x0332ADA1 | |||
| #memset 0x0144, 0x02E9A300 | |||
| #memset 0x0148, 0x031AABA5 | |||
| #memset 0x014C, 0x0305A9A7 | |||
| #memset 0x0150, 0x02EC0000 | |||
| #memset 0x0154, 0x03090000 | |||
| #memset 0x0158, 0x032B0000 | |||
| #memset 0x015C, 0x03CC00AF | |||
| #memset 0x0160, 0x0365B7B1 | |||
| #memset 0x0164, 0x0333B300 | |||
| #memset 0x0168, 0x036200B5 | |||
| #memset 0x016C, 0x033E0000 | |||
| #memset 0x0170, 0x03B6C3B9 | |||
| #memset 0x0174, 0x03AA00BB | |||
| #memset 0x0178, 0x039700BD | |||
| #memset 0x017C, 0x037DC1BF | |||
| #memset 0x0180, 0x03750000 | |||
| #memset 0x0184, 0x03870000 | |||
| #memset 0x0188, 0x03C8C7C5 | |||
| #memset 0x018C, 0x03BB0000 | |||
| #memset 0x0190, 0x03C90000 | |||
| #memset 0x0194, 0x03E0CB00 | |||
| #memset 0x0198, 0x03E40000 | |||
| #memset 0x019C, 0x0010 | |||
| #memset 0x01A0, 0x0264 | |||
| #memset 0x01A4, 0x0C0D | |||
| #memset 0x01A8, 0x0031 | |||
| #memset 0x01AC, 0x0206 | |||
| #memset 0x01B0, 0x0891 | |||
| #memset 0x01B4, 0x0043 | |||
| #memset 0x01B8, 0x029E | |||
| #memset 0x01BC, 0x0264 | |||
| #memset 0x01C0, 0x0123 | |||
| #memset 0x01C4, 0x0264 | |||
| @@ -0,0 +1,142 @@ | |||
| main: | |||
| addi sp,sp,-16 | |||
| sw ra,12(sp) | |||
| lw a0,0(zero) | |||
| call find | |||
| lw ra,12(sp) | |||
| addi sp,sp,16 | |||
| jr ra | |||
| find: | |||
| li a5,4 | |||
| .L2: | |||
| lh a4,2(a5) | |||
| beq a4,a0,.L13 | |||
| .L11: | |||
| ble a4,a0,.L4 | |||
| lw a5,0(a5) | |||
| andi a4,a5,1 | |||
| bnez a4,.L14 | |||
| .L10: | |||
| li a0,-1 | |||
| ret | |||
| .L4: | |||
| bge a4,a0,.L10 | |||
| lw a4,0(a5) | |||
| srli a5,a4,7 | |||
| andi a4,a4,256 | |||
| andi a5,a5,508 | |||
| beqz a4,.L10 | |||
| addi a5,a5,4 | |||
| lh a4,2(a5) | |||
| bne a4,a0,.L11 | |||
| .L13: | |||
| mv a0,a5 | |||
| ret | |||
| .L14: | |||
| slli a5,a5,1 | |||
| andi a5,a5,508 | |||
| addi a5,a5,4 | |||
| j .L2 | |||
| #memset 0x0, 0x013A | |||
| #memset 0x0004, 0x02D49D03 | |||
| #memset 0x0008, 0x00912305 | |||
| #memset 0x000C, 0x00301307 | |||
| #memset 0x0010, 0x001B0D09 | |||
| #memset 0x0014, 0x00010B00 | |||
| #memset 0x0018, 0x00090000 | |||
| #memset 0x001C, 0x001E110F | |||
| #memset 0x0020, 0x001D0000 | |||
| #memset 0x0024, 0x001E0000 | |||
| #memset 0x0028, 0x00782115 | |||
| #memset 0x002C, 0x00661D17 | |||
| #memset 0x0030, 0x003C1B19 | |||
| #memset 0x0034, 0x00300000 | |||
| #memset 0x0038, 0x00430000 | |||
| #memset 0x003C, 0x00701F00 | |||
| #memset 0x0040, 0x00700000 | |||
| #memset 0x0044, 0x007B0000 | |||
| #memset 0x0048, 0x018E5925 | |||
| #memset 0x004C, 0x00A12B27 | |||
| #memset 0x0050, 0x009F0029 | |||
| #memset 0x0054, 0x00910000 | |||
| #memset 0x0058, 0x011D392D | |||
| #memset 0x005C, 0x00E22F00 | |||
| #memset 0x0060, 0x01190031 | |||
| #memset 0x0064, 0x01090033 | |||
| #memset 0x0068, 0x00E93500 | |||
| #memset 0x006C, 0x00FF3700 | |||
| #memset 0x0070, 0x00FF0000 | |||
| #memset 0x0074, 0x01213F3B | |||
| #memset 0x0078, 0x0120003D | |||
| #memset 0x007C, 0x011F0000 | |||
| #memset 0x0080, 0x01835741 | |||
| #memset 0x0084, 0x016A5543 | |||
| #memset 0x0088, 0x012F4745 | |||
| #memset 0x008C, 0x012E0000 | |||
| #memset 0x0090, 0x014B4F49 | |||
| #memset 0x0094, 0x013A4B00 | |||
| #memset 0x0098, 0x01424D00 | |||
| #memset 0x009C, 0x01460000 | |||
| #memset 0x00A0, 0x015C0051 | |||
| #memset 0x00A4, 0x014D5300 | |||
| #memset 0x00A8, 0x01510000 | |||
| #memset 0x00AC, 0x01730000 | |||
| #memset 0x00B0, 0x018B0000 | |||
| #memset 0x00B4, 0x01BF655B | |||
| #memset 0x00B8, 0x01A2615D | |||
| #memset 0x00BC, 0x01995F00 | |||
| #memset 0x00C0, 0x019F0000 | |||
| #memset 0x00C4, 0x01A46300 | |||
| #memset 0x00C8, 0x01BD0000 | |||
| #memset 0x00CC, 0x027C8967 | |||
| #memset 0x00D0, 0x026C8569 | |||
| #memset 0x00D4, 0x01CC6D6B | |||
| #memset 0x00D8, 0x01C60000 | |||
| #memset 0x00DC, 0x021F7D6F | |||
| #memset 0x00E0, 0x02070071 | |||
| #memset 0x00E4, 0x01D37300 | |||
| #memset 0x00E8, 0x01F67B75 | |||
| #memset 0x00EC, 0x01EF7977 | |||
| #memset 0x00F0, 0x01D70000 | |||
| #memset 0x00F4, 0x01F10000 | |||
| #memset 0x00F8, 0x02060000 | |||
| #memset 0x00FC, 0x0254837F | |||
| #memset 0x0100, 0x023D0081 | |||
| #memset 0x0104, 0x02200000 | |||
| #memset 0x0108, 0x02640000 | |||
| #memset 0x010C, 0x026D8700 | |||
| #memset 0x0110, 0x026E0000 | |||
| #memset 0x0114, 0x02C0008B | |||
| #memset 0x0118, 0x0297998D | |||
| #memset 0x011C, 0x0289978F | |||
| #memset 0x0120, 0x02839591 | |||
| #memset 0x0124, 0x027C9300 | |||
| #memset 0x0128, 0x027E0000 | |||
| #memset 0x012C, 0x02850000 | |||
| #memset 0x0130, 0x028D0000 | |||
| #memset 0x0134, 0x029E009B | |||
| #memset 0x0138, 0x02990000 | |||
| #memset 0x013C, 0x03D4C99F | |||
| #memset 0x0140, 0x0332ADA1 | |||
| #memset 0x0144, 0x02E9A300 | |||
| #memset 0x0148, 0x031AABA5 | |||
| #memset 0x014C, 0x0305A9A7 | |||
| #memset 0x0150, 0x02EC0000 | |||
| #memset 0x0154, 0x03090000 | |||
| #memset 0x0158, 0x032B0000 | |||
| #memset 0x015C, 0x03CC00AF | |||
| #memset 0x0160, 0x0365B7B1 | |||
| #memset 0x0164, 0x0333B300 | |||
| #memset 0x0168, 0x036200B5 | |||
| #memset 0x016C, 0x033E0000 | |||
| #memset 0x0170, 0x03B6C3B9 | |||
| #memset 0x0174, 0x03AA00BB | |||
| #memset 0x0178, 0x039700BD | |||
| #memset 0x017C, 0x037DC1BF | |||
| #memset 0x0180, 0x03750000 | |||
| #memset 0x0184, 0x03870000 | |||
| #memset 0x0188, 0x03C8C7C5 | |||
| #memset 0x018C, 0x03BB0000 | |||
| #memset 0x0190, 0x03C90000 | |||
| #memset 0x0194, 0x03E0CB00 | |||
| #memset 0x0198, 0x03E40000 | |||
| @@ -0,0 +1,14 @@ | |||
| main: | |||
| add t0, t0, t1 | |||
| add t2, t0, t1 | |||
| add zero, t0, t1 | |||
| add t2, t2, t1 | |||
| add t3, t3, t3 | |||
| add t3, t3, t3 | |||
| add t3, t3, t3 | |||
| nop | |||
| done | |||
| #regset t0,10 | |||
| #regset t1,23 | |||
| #regset t2,43 | |||
| #regset t3,-11 | |||
| @@ -0,0 +1,118 @@ | |||
| main: | |||
| addi sp,sp,-32 | |||
| sw ra,28(sp) | |||
| sw s0,24(sp) | |||
| addi s0,sp,32 | |||
| sw zero,-20(s0) | |||
| li a5,100 | |||
| sw a5,-24(s0) | |||
| lw a1,-20(s0) | |||
| li a0,11 | |||
| call setupmem | |||
| lw a1,-24(s0) | |||
| li a0,11 | |||
| call setupmem | |||
| lw a2,-24(s0) | |||
| lw a1,-20(s0) | |||
| li a0,10 | |||
| call f | |||
| li a5,0 | |||
| mv a0,a5 | |||
| lw ra,28(sp) | |||
| lw s0,24(sp) | |||
| addi sp,sp,32 | |||
| jr ra | |||
| f: | |||
| addi sp,sp,-48 | |||
| sw ra,44(sp) | |||
| sw s0,40(sp) | |||
| sw s1,36(sp) | |||
| addi s0,sp,48 | |||
| sw a0,-36(s0) | |||
| sw a1,-40(s0) | |||
| sw a2,-44(s0) | |||
| lw a5,-36(s0) | |||
| slli a5,a5,2 | |||
| lw a4,-40(s0) | |||
| add a5,a4,a5 | |||
| lw a5,0(a5) | |||
| beqz a5,.L2 | |||
| lw a5,-36(s0) | |||
| slli a5,a5,2 | |||
| lw a4,-44(s0) | |||
| add a5,a4,a5 | |||
| lw a5,0(a5) | |||
| j .L3 | |||
| .L2: | |||
| lw a5,-36(s0) | |||
| bnez a5,.L4 | |||
| li a5,0 | |||
| j .L3 | |||
| .L4: | |||
| lw a4,-36(s0) | |||
| li a5,1 | |||
| bne a4,a5,.L5 | |||
| li a5,1 | |||
| j .L3 | |||
| .L5: | |||
| lw a5,-36(s0) | |||
| addi a5,a5,-1 | |||
| lw a2,-44(s0) | |||
| lw a1,-40(s0) | |||
| mv a0,a5 | |||
| call f | |||
| mv s1,a0 | |||
| lw a5,-36(s0) | |||
| addi a5,a5,-2 | |||
| lw a2,-44(s0) | |||
| lw a1,-40(s0) | |||
| mv a0,a5 | |||
| call f | |||
| mv a5,a0 | |||
| add a5,s1,a5 | |||
| sw a5,-20(s0) | |||
| lw a5,-36(s0) | |||
| slli a5,a5,2 | |||
| lw a4,-40(s0) | |||
| add a5,a4,a5 | |||
| li a4,1 | |||
| sw a4,0(a5) | |||
| lw a5,-36(s0) | |||
| slli a5,a5,2 | |||
| lw a4,-44(s0) | |||
| add a5,a4,a5 | |||
| lw a4,-20(s0) | |||
| sw a4,0(a5) | |||
| lw a5,-20(s0) | |||
| .L3: | |||
| mv a0,a5 | |||
| lw ra,44(sp) | |||
| lw s0,40(sp) | |||
| lw s1,36(sp) | |||
| addi sp,sp,48 | |||
| jr ra | |||
| setupmem: | |||
| addi sp,sp,-48 | |||
| sw s0,44(sp) | |||
| addi s0,sp,48 | |||
| sw a0,-36(s0) | |||
| sw a1,-40(s0) | |||
| sw zero,-20(s0) | |||
| j .L7 | |||
| .L8: | |||
| lw a5,-20(s0) | |||
| slli a5,a5,2 | |||
| lw a4,-40(s0) | |||
| add a5,a4,a5 | |||
| sw zero,0(a5) | |||
| lw a5,-20(s0) | |||
| addi a5,a5,1 | |||
| sw a5,-20(s0) | |||
| .L7: | |||
| lw a4,-20(s0) | |||
| lw a5,-36(s0) | |||
| blt a4,a5,.L8 | |||
| nop | |||
| lw s0,44(sp) | |||
| addi sp,sp,48 | |||
| jr ra | |||
| @@ -0,0 +1,49 @@ | |||
| main: | |||
| addi sp,sp,-16 | |||
| sw ra,12(sp) | |||
| sw s0,8(sp) | |||
| addi s0,sp,16 | |||
| li a0,6 | |||
| call f | |||
| mv a5,a0 | |||
| mv a0,a5 | |||
| lw ra,12(sp) | |||
| lw s0,8(sp) | |||
| addi sp,sp,16 | |||
| jr ra | |||
| f: | |||
| addi sp,sp,-32 | |||
| sw ra,28(sp) | |||
| sw s0,24(sp) | |||
| sw s1,20(sp) | |||
| addi s0,sp,32 | |||
| sw a0,-20(s0) | |||
| lw a5,-20(s0) | |||
| bnez a5,.L2 | |||
| li a5,0 | |||
| j .L3 | |||
| .L2: | |||
| lw a4,-20(s0) | |||
| li a5,1 | |||
| bne a4,a5,.L4 | |||
| li a5,1 | |||
| j .L3 | |||
| .L4: | |||
| lw a5,-20(s0) | |||
| addi a5,a5,-1 | |||
| mv a0,a5 | |||
| call f | |||
| mv s1,a0 | |||
| lw a5,-20(s0) | |||
| addi a5,a5,-2 | |||
| mv a0,a5 | |||
| call f | |||
| mv a5,a0 | |||
| add a5,s1,a5 | |||
| .L3: | |||
| mv a0,a5 | |||
| lw ra,28(sp) | |||
| lw s0,24(sp) | |||
| lw s1,20(sp) | |||
| addi sp,sp,32 | |||
| jr ra | |||
| @@ -0,0 +1,112 @@ | |||
| main: | |||
| addi sp,sp,-32 | |||
| sw ra,28(sp) | |||
| sw s0,24(sp) | |||
| addi s0,sp,32 | |||
| sw zero,-20(s0) | |||
| li a5,32 | |||
| sw a5,-24(s0) | |||
| li a2,7 | |||
| li a1,0 | |||
| lw a0,-20(s0) | |||
| call isPalindrome | |||
| .DEBUG_call1_return: | |||
| mv a5,a0 | |||
| beqz a5,.L2 | |||
| li a2,15 | |||
| li a1,0 | |||
| lw a0,-24(s0) | |||
| call isPalindrome | |||
| .DEBUG_call2_return: | |||
| mv a5,a0 | |||
| beqz a5,.L2 | |||
| li a5,1 | |||
| j .L4 | |||
| .L2: | |||
| li a5,0 | |||
| .L4: | |||
| mv a0,a5 | |||
| lw ra,28(sp) | |||
| lw s0,24(sp) | |||
| addi sp,sp,32 | |||
| jr ra | |||
| isPalindrome: | |||
| addi sp,sp,-48 | |||
| sw ra,44(sp) | |||
| sw s0,40(sp) | |||
| addi s0,sp,48 | |||
| sw a0,-36(s0) | |||
| sw a1,-40(s0) | |||
| sw a2,-44(s0) | |||
| lw a4,-40(s0) | |||
| lw a5,-44(s0) | |||
| blt a4,a5,.L6 | |||
| li a5,1 | |||
| j .L7 | |||
| .L6: | |||
| lw a5,-40(s0) | |||
| slli a5,a5,2 | |||
| lw a4,-36(s0) | |||
| add a5,a4,a5 | |||
| lw a4,0(a5) | |||
| lw a5,-44(s0) | |||
| slli a5,a5,2 | |||
| lw a3,-36(s0) | |||
| add a5,a3,a5 | |||
| lw a5,0(a5) | |||
| sub a5,a4,a5 | |||
| seqz a5,a5 | |||
| andi a5,a5,0xff | |||
| sw a5,-20(s0) | |||
| lw a5,-20(s0) | |||
| beqz a5,.CompareFailed | |||
| lw a5,-40(s0) | |||
| addi a4,a5,1 | |||
| lw a5,-44(s0) | |||
| addi a5,a5,-1 | |||
| mv a2,a5 | |||
| mv a1,a4 | |||
| lw a0,-36(s0) | |||
| call isPalindrome | |||
| mv a5,a0 | |||
| beqz a5,.CompareFailed | |||
| li a5,1 | |||
| j .L7 | |||
| .CompareFailed: | |||
| li a5,0 | |||
| .L7: | |||
| mv a0,a5 | |||
| lw ra,44(sp) | |||
| lw s0,40(sp) | |||
| addi sp,sp,48 | |||
| jr ra | |||
| #memset 0, 10 | |||
| #memset 4, -3 | |||
| #memset 8, 8 | |||
| #memset 12, 0 | |||
| #memset 16, 0 | |||
| #memset 20, 8 | |||
| #memset 24, -3 | |||
| #memset 28, 10 | |||
| #memset 32, 10 | |||
| #memset 36, -3 | |||
| #memset 40, 8 | |||
| #memset 44, 0 | |||
| #memset 48, 0 | |||
| #memset 52, 10 | |||
| #memset 56, -3 | |||
| #memset 60, 8 | |||
| #memset 64, -3 | |||
| #memset 68, 8 | |||
| #memset 72, 10 | |||
| #memset 76, 0 | |||
| #memset 80, 0 | |||
| #memset 84, 8 | |||
| #memset 88, -3 | |||
| #memset 92, 10 | |||
| @@ -0,0 +1,120 @@ | |||
| main: | |||
| addi sp,sp,-16 | |||
| li a2,7 | |||
| li a1,0 | |||
| li a0,0 | |||
| sw ra,12(sp) | |||
| call isPalindrome.part.0 | |||
| .DEBUG_call1_return: | |||
| bnez a0,.L17 | |||
| isPalindrome.part.0: | |||
| slli a4,a1,2 | |||
| slli a3,a2,2 | |||
| add a4,a0,a4 | |||
| add a5,a0,a3 | |||
| lw a4,0(a4) | |||
| lw a5,0(a5) | |||
| beq a4,a5,.L10 | |||
| li a5,0 | |||
| .L6: | |||
| mv a0,a5 | |||
| ret | |||
| .L10: | |||
| addi a1,a1,1 | |||
| addi a2,a2,-1 | |||
| li a5,1 | |||
| bge a1,a2,.L6 | |||
| addi sp,sp,-16 | |||
| sw ra,12(sp) | |||
| call isPalindrome.part.0 | |||
| .DEBUG_call2_return: | |||
| lw ra,12(sp) | |||
| snez a5,a0 | |||
| mv a0,a5 | |||
| addi sp,sp,16 | |||
| jr ra | |||
| .L11: | |||
| lw ra,12(sp) | |||
| addi sp,sp,16 | |||
| jr ra | |||
| .L17: | |||
| li a2,15 | |||
| li a1,0 | |||
| li a0,32 | |||
| call isPalindrome.part.0 | |||
| snez a0,a0 | |||
| j .L11 | |||
| isPalindrome: | |||
| bge a1,a2,.L20 | |||
| slli a3,a2,2 | |||
| slli a4,a1,2 | |||
| add a5,a0,a3 | |||
| add a4,a0,a4 | |||
| lw a7,0(a4) | |||
| lw a6,0(a5) | |||
| li a3,0 | |||
| bne a7,a6,.L28 | |||
| addi a7,a1,1 | |||
| addi a6,a2,-1 | |||
| li a3,1 | |||
| bge a7,a6,.L28 | |||
| lw a7,4(a4) | |||
| lw a6,-4(a5) | |||
| li a3,0 | |||
| bne a7,a6,.L28 | |||
| addi a7,a1,2 | |||
| addi a6,a2,-2 | |||
| li a3,1 | |||
| bge a7,a6,.L28 | |||
| lw a4,8(a4) | |||
| lw a5,-8(a5) | |||
| li a3,0 | |||
| bne a4,a5,.L28 | |||
| addi a1,a1,3 | |||
| addi a2,a2,-3 | |||
| li a3,1 | |||
| bge a1,a2,.L28 | |||
| addi sp,sp,-16 | |||
| sw ra,12(sp) | |||
| call isPalindrome.part.0 | |||
| lw ra,12(sp) | |||
| snez a3,a0 | |||
| mv a0,a3 | |||
| addi sp,sp,16 | |||
| jr ra | |||
| .L20: | |||
| li a3,1 | |||
| .L28: | |||
| mv a0,a3 | |||
| ret | |||
| #memset 0, 10 | |||
| #memset 4, -3 | |||
| #memset 8, 8 | |||
| #memset 12, 0 | |||
| #memset 16, 0 | |||
| #memset 20, 8 | |||
| #memset 24, -3 | |||
| #memset 28, 10 | |||
| #memset 32, 10 | |||
| #memset 36, -3 | |||
| #memset 40, 8 | |||
| #memset 44, 0 | |||
| #memset 48, 0 | |||
| #memset 52, 10 | |||
| #memset 56, -3 | |||
| #memset 60, 8 | |||
| #memset 64, -3 | |||
| #memset 68, 8 | |||
| #memset 72, 10 | |||
| #memset 76, 0 | |||
| #memset 80, 0 | |||
| #memset 84, 8 | |||
| #memset 88, -3 | |||
| #memset 92, 10 | |||
| @@ -0,0 +1,187 @@ | |||
| main: | |||
| addi sp,sp,-32 | |||
| sw ra,28(sp) | |||
| sw s0,24(sp) | |||
| addi s0,sp,32 | |||
| li a5,0 | |||
| lw a5,0(a5) | |||
| sw a5,-20(s0) | |||
| lw a0,-20(s0) | |||
| call find | |||
| mv a5,a0 | |||
| mv a0,a5 | |||
| lw ra,28(sp) | |||
| lw s0,24(sp) | |||
| addi sp,sp,32 | |||
| jr ra | |||
| find: | |||
| addi sp,sp,-64 | |||
| sw s0,60(sp) | |||
| addi s0,sp,64 | |||
| sw a0,-52(s0) | |||
| sw zero,-24(s0) | |||
| li a5,4 | |||
| sw a5,-20(s0) | |||
| sw zero,-28(s0) | |||
| j .L2 | |||
| .WHILE: | |||
| lw a5,-20(s0) | |||
| lh a5,2(a5) | |||
| sw a5,-28(s0) | |||
| lw a4,-28(s0) | |||
| lw a5,-52(s0) | |||
| bne a4,a5,.CHECKLEFT | |||
| lw a5,-20(s0) | |||
| j .L1 | |||
| .CHECKLEFT: | |||
| lw a4,-28(s0) | |||
| lw a5,-52(s0) | |||
| ble a4,a5,.CHECKRIGHT | |||
| lw a5,-20(s0) | |||
| lw a5,0(a5) | |||
| andi a5,a5,1 | |||
| beqz a5,.CHECKRIGHT | |||
| lw a5,-20(s0) | |||
| lw a5,0(a5) | |||
| srli a5,a5,1 | |||
| andi a5,a5,127 | |||
| andi a5,a5,0xff | |||
| sw a5,-32(s0) | |||
| lw a5,-32(s0) | |||
| slli a5,a5,2 | |||
| addi a5,a5,4 | |||
| sw a5,-20(s0) | |||
| j .L2 | |||
| .CHECKRIGHT: | |||
| lw a4,-28(s0) | |||
| lw a5,-52(s0) | |||
| bge a4,a5,.L6 | |||
| lw a5,-20(s0) | |||
| lw a5,0(a5) | |||
| andi a5,a5,256 | |||
| beqz a5,.L6 | |||
| lw a5,-20(s0) | |||
| lw a5,0(a5) | |||
| srli a5,a5,9 | |||
| andi a5,a5,127 | |||
| andi a5,a5,0xff | |||
| sw a5,-36(s0) | |||
| lw a5,-36(s0) | |||
| slli a5,a5,2 | |||
| addi a5,a5,4 | |||
| sw a5,-20(s0) | |||
| j .L2 | |||
| .L6: | |||
| li a5,-1 | |||
| j .L1 | |||
| .L2: | |||
| lw a5,-24(s0) | |||
| beqz a5,.WHILE | |||
| .L1: | |||
| mv a0,a5 | |||
| lw s0,60(sp) | |||
| addi sp,sp,64 | |||
| jr ra | |||
| #memset 0x0, 0x013A | |||
| #memset 0x0004, 0x02D49D03 | |||
| #memset 0x0008, 0x00912305 | |||
| #memset 0x000C, 0x00301307 | |||
| #memset 0x0010, 0x001B0D09 | |||
| #memset 0x0014, 0x00010B00 | |||
| #memset 0x0018, 0x00090000 | |||
| #memset 0x001C, 0x001E110F | |||
| #memset 0x0020, 0x001D0000 | |||
| #memset 0x0024, 0x001E0000 | |||
| #memset 0x0028, 0x00782115 | |||
| #memset 0x002C, 0x00661D17 | |||
| #memset 0x0030, 0x003C1B19 | |||
| #memset 0x0034, 0x00300000 | |||
| #memset 0x0038, 0x00430000 | |||
| #memset 0x003C, 0x00701F00 | |||
| #memset 0x0040, 0x00700000 | |||
| #memset 0x0044, 0x007B0000 | |||
| #memset 0x0048, 0x018E5925 | |||
| #memset 0x004C, 0x00A12B27 | |||
| #memset 0x0050, 0x009F0029 | |||
| #memset 0x0054, 0x00910000 | |||
| #memset 0x0058, 0x011D392D | |||
| #memset 0x005C, 0x00E22F00 | |||
| #memset 0x0060, 0x01190031 | |||
| #memset 0x0064, 0x01090033 | |||
| #memset 0x0068, 0x00E93500 | |||
| #memset 0x006C, 0x00FF3700 | |||
| #memset 0x0070, 0x00FF0000 | |||
| #memset 0x0074, 0x01213F3B | |||
| #memset 0x0078, 0x0120003D | |||
| #memset 0x007C, 0x011F0000 | |||
| #memset 0x0080, 0x01835741 | |||
| #memset 0x0084, 0x016A5543 | |||
| #memset 0x0088, 0x012F4745 | |||
| #memset 0x008C, 0x012E0000 | |||
| #memset 0x0090, 0x014B4F49 | |||
| #memset 0x0094, 0x013A4B00 | |||
| #memset 0x0098, 0x01424D00 | |||
| #memset 0x009C, 0x01460000 | |||
| #memset 0x00A0, 0x015C0051 | |||
| #memset 0x00A4, 0x014D5300 | |||
| #memset 0x00A8, 0x01510000 | |||
| #memset 0x00AC, 0x01730000 | |||
| #memset 0x00B0, 0x018B0000 | |||
| #memset 0x00B4, 0x01BF655B | |||
| #memset 0x00B8, 0x01A2615D | |||
| #memset 0x00BC, 0x01995F00 | |||
| #memset 0x00C0, 0x019F0000 | |||
| #memset 0x00C4, 0x01A46300 | |||
| #memset 0x00C8, 0x01BD0000 | |||
| #memset 0x00CC, 0x027C8967 | |||
| #memset 0x00D0, 0x026C8569 | |||
| #memset 0x00D4, 0x01CC6D6B | |||
| #memset 0x00D8, 0x01C60000 | |||
| #memset 0x00DC, 0x021F7D6F | |||
| #memset 0x00E0, 0x02070071 | |||
| #memset 0x00E4, 0x01D37300 | |||
| #memset 0x00E8, 0x01F67B75 | |||
| #memset 0x00EC, 0x01EF7977 | |||
| #memset 0x00F0, 0x01D70000 | |||
| #memset 0x00F4, 0x01F10000 | |||
| #memset 0x00F8, 0x02060000 | |||
| #memset 0x00FC, 0x0254837F | |||
| #memset 0x0100, 0x023D0081 | |||
| #memset 0x0104, 0x02200000 | |||
| #memset 0x0108, 0x02640000 | |||
| #memset 0x010C, 0x026D8700 | |||
| #memset 0x0110, 0x026E0000 | |||
| #memset 0x0114, 0x02C0008B | |||
| #memset 0x0118, 0x0297998D | |||
| #memset 0x011C, 0x0289978F | |||
| #memset 0x0120, 0x02839591 | |||
| #memset 0x0124, 0x027C9300 | |||
| #memset 0x0128, 0x027E0000 | |||
| #memset 0x012C, 0x02850000 | |||
| #memset 0x0130, 0x028D0000 | |||
| #memset 0x0134, 0x029E009B | |||
| #memset 0x0138, 0x02990000 | |||
| #memset 0x013C, 0x03D4C99F | |||
| #memset 0x0140, 0x0332ADA1 | |||
| #memset 0x0144, 0x02E9A300 | |||
| #memset 0x0148, 0x031AABA5 | |||
| #memset 0x014C, 0x0305A9A7 | |||
| #memset 0x0150, 0x02EC0000 | |||
| #memset 0x0154, 0x03090000 | |||
| #memset 0x0158, 0x032B0000 | |||
| #memset 0x015C, 0x03CC00AF | |||
| #memset 0x0160, 0x0365B7B1 | |||
| #memset 0x0164, 0x0333B300 | |||
| #memset 0x0168, 0x036200B5 | |||
| #memset 0x016C, 0x033E0000 | |||
| #memset 0x0170, 0x03B6C3B9 | |||
| #memset 0x0174, 0x03AA00BB | |||
| #memset 0x0178, 0x039700BD | |||
| #memset 0x017C, 0x037DC1BF | |||
| #memset 0x0180, 0x03750000 | |||
| #memset 0x0184, 0x03870000 | |||
| #memset 0x0188, 0x03C8C7C5 | |||
| #memset 0x018C, 0x03BB0000 | |||
| #memset 0x0190, 0x03C90000 | |||
| #memset 0x0194, 0x03E0CB00 | |||
| #memset 0x0198, 0x03E40000 | |||
| @@ -0,0 +1,38 @@ | |||
| #include <stdio.h> | |||
| // C rmsbolt starter file | |||
| // Local Variables: | |||
| // rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O3" | |||
| // rmsbolt-disassemble: nil | |||
| // End: | |||
| int f(int x, int* isMemoized, int* memoizedVal){ | |||
| if(isMemoized[x]) | |||
| return memoizedVal[x]; | |||
| if (x == 0) return 0; | |||
| if (x == 1) return 1; | |||
| int next = f(x-1, isMemoized, memoizedVal) + f(x-2, isMemoized, memoizedVal); | |||
| isMemoized[x] = 1; | |||
| memoizedVal[x] = next; | |||
| return next; | |||
| } | |||
| void setupmem(int n, int* m) { | |||
| for(int ii = 0; ii < n; ii++){ | |||
| m[ii] = 0; | |||
| } | |||
| } | |||
| int main() { | |||
| int* isMemoized = (int*)0; | |||
| int* memoizedVal = (int*)100; | |||
| setupmem(11, isMemoized); | |||
| setupmem(11, memoizedVal); | |||
| int r = f(10, isMemoized, memoizedVal); | |||
| return r; | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| #include <stdio.h> | |||
| // C rmsbolt starter file | |||
| // Local Variables: | |||
| // rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O0" | |||
| // rmsbolt-disassemble: nil | |||
| // End: | |||
| int f(int x){ | |||
| if (x == 0) return 0; | |||
| if (x == 1) return 1; | |||
| return f(x-1) + f(x-2); | |||
| } | |||
| int main() { | |||
| return f(4); | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| // C rmsbolt starter file | |||
| // Local Variables: | |||
| // rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O3" | |||
| // rmsbolt-disassemble: nil | |||
| // End: | |||
| int main() { | |||
| /* int palindrome[8]; */ | |||
| /* int notAPalindrome[16]; */ | |||
| // Set up "heap" addresses | |||
| int palindrome = (int*)0; | |||
| int notAPalindrome = (int*)32; | |||
| return isPalindrome(palindrome, 0, 7) && isPalindrome(notAPalindrome, 0, 15); | |||
| } | |||
| int isPalindrome(int* word, int start, int stop){ | |||
| if(start >= stop){ | |||
| return 1; | |||
| } | |||
| else{ | |||
| int currentIsPalindrome = (word[start] == word[stop]); | |||
| return currentIsPalindrome && isPalindrome(word, start + 1, stop - 1); | |||
| } | |||
| } | |||
| @@ -0,0 +1,50 @@ | |||
| // C rmsbolt starter file | |||
| // Local Variables: | |||
| // rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O3" | |||
| // rmsbolt-disassemble: nil | |||
| // End: | |||
| /** | |||
| * Represents a binary tree | |||
| */ | |||
| typedef struct { | |||
| unsigned int hasLeft : 1; | |||
| unsigned int leftIndex : 7; | |||
| unsigned int hasRight : 1; | |||
| unsigned int rightIndex : 7; | |||
| int value : 16; | |||
| } node; | |||
| int find(int findMe){ | |||
| int found = 0; | |||
| node* currentNodeIdx = (node*)4; | |||
| int currentValue = 0; | |||
| while(!found){ | |||
| currentValue = currentNodeIdx->value; | |||
| if(currentValue == findMe){ | |||
| return (int)currentNodeIdx; | |||
| } | |||
| if((currentValue > findMe) && currentNodeIdx->hasLeft){ | |||
| int nextNodeIdx = currentNodeIdx->leftIndex; | |||
| currentNodeIdx = (node*)(4 + (nextNodeIdx << 2)); | |||
| continue; | |||
| } | |||
| if((currentValue < findMe) && currentNodeIdx->hasRight){ | |||
| int nextNodeIdx = currentNodeIdx->rightIndex; | |||
| currentNodeIdx = (node*)(4 + (nextNodeIdx << 2)); | |||
| continue; | |||
| } | |||
| return -1; | |||
| } | |||
| } | |||
| int main() { | |||
| int needle = *(int*)0; | |||
| return find(needle); | |||
| } | |||
| @@ -0,0 +1,64 @@ | |||
| // C rmsbolt starter file | |||
| // Local Variables: | |||
| // rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O1" | |||
| // rmsbolt-disassemble: nil | |||
| // End: | |||
| /** | |||
| * Represents a binary tree | |||
| */ | |||
| typedef struct { | |||
| unsigned int hasLeft : 1; | |||
| unsigned int leftIndex : 7; | |||
| unsigned int hasRight : 1; | |||
| unsigned int rightIndex : 7; | |||
| int value : 16; | |||
| } node; | |||
| int find(int findMe){ | |||
| int found = 0; | |||
| node* currentNodeIdx = (node*)4; | |||
| int currentValue = 0; | |||
| while(!found){ | |||
| currentValue = currentNodeIdx->value; | |||
| if(currentValue == findMe){ | |||
| return (int)currentNodeIdx; | |||
| } | |||
| if((currentValue > findMe) && currentNodeIdx->hasLeft){ | |||
| int nextNodeIdx = currentNodeIdx->leftIndex; | |||
| currentNodeIdx = (node*)(4 + (nextNodeIdx << 2)); | |||
| continue; | |||
| } | |||
| if((currentValue < findMe) && currentNodeIdx->hasRight){ | |||
| int nextNodeIdx = currentNodeIdx->rightIndex; | |||
| currentNodeIdx = (node*)(4 + (nextNodeIdx << 2)); | |||
| continue; | |||
| } | |||
| return -1; | |||
| } | |||
| } | |||
| int main() { | |||
| // Where does the needle list start? | |||
| int needles = *(int*)0; | |||
| int sum = 0; | |||
| // How many needles are there? | |||
| int numNeedles = *(int*)needles; | |||
| int nextNeedle = (int)needles + 4; | |||
| // Some useless calculations to make gcc O3 happy | |||
| for(int ii = 0; ii < numNeedles; ii++){ | |||
| nextNeedle += 4; | |||
| int needle = *(int*)(nextNeedle); | |||
| sum += find(needle); | |||
| } | |||
| return sum; | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| #include <stdio.h> | |||
| // C rmsbolt starter file | |||
| // Local Variables: | |||
| // rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O0" | |||
| // rmsbolt-disassemble: nil | |||
| // End: | |||
| int mul(int a, int b) { | |||
| int c = 0; | |||
| int ii = 0; | |||
| for(int ii = 0; ii < a; ii++){ | |||
| c += b; | |||
| } | |||
| return c; | |||
| } | |||
| int square(int a){ | |||
| return mul(a, a); | |||
| } | |||
| int main() { | |||
| int a = 6; | |||
| int b = 0xFFFFFFFE; // MAXVAL - 2, (a + b) = -2 | |||
| int c = -1; //-1 | |||
| int d = 7; //0x4D2 (c + d) = 0x4D1 | |||
| if(square(a+b) > square(c + d)) | |||
| return a; | |||
| else | |||
| return c; | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| main: | |||
| addi sp,sp,-32 | |||
| sw ra,28(sp) | |||
| sw s0,24(sp) | |||
| sw s1,20(sp) | |||
| addi s0,sp,32 | |||
| li a5,6 | |||
| sw a5,-20(s0) | |||
| li a5,-2 | |||
| sw a5,-24(s0) | |||
| li a5,-1 | |||
| sw a5,-28(s0) | |||
| li a5,7 | |||
| sw a5,-32(s0) | |||
| lw a4,-20(s0) | |||
| lw a5,-24(s0) | |||
| add a5,a4,a5 | |||
| mv a0,a5 | |||
| call square | |||
| mv s1,a0 | |||
| lw a4,-28(s0) | |||
| lw a5,-32(s0) | |||
| add a5,a4,a5 | |||
| mv a0,a5 | |||
| call square | |||
| mv a5,a0 | |||
| ble s1,a5,.L8 | |||
| lw a5,-20(s0) | |||
| j .L9 | |||
| .L8: | |||
| lw a5,-28(s0) | |||
| .L9: | |||
| mv a0,a5 | |||
| lw ra,28(sp) | |||
| lw s0,24(sp) | |||
| lw s1,20(sp) | |||
| addi sp,sp,32 | |||
| jr ra | |||
| mul: | |||
| addi sp,sp,-48 | |||
| sw s0,44(sp) | |||
| addi s0,sp,48 | |||
| sw a0,-36(s0) | |||
| sw a1,-40(s0) | |||
| sw zero,-20(s0) | |||
| sw zero,-28(s0) | |||
| sw zero,-24(s0) | |||
| j .L2 | |||
| .L3: | |||
| lw a4,-20(s0) | |||
| lw a5,-40(s0) | |||
| add a5,a4,a5 | |||
| sw a5,-20(s0) | |||
| lw a5,-24(s0) | |||
| addi a5,a5,1 | |||
| sw a5,-24(s0) | |||
| .L2: | |||
| lw a4,-24(s0) | |||
| lw a5,-36(s0) | |||
| blt a4,a5,.L3 | |||
| lw a5,-20(s0) | |||
| mv a0,a5 | |||
| lw s0,44(sp) | |||
| addi sp,sp,48 | |||
| jr ra | |||
| square: | |||
| addi sp,sp,-32 | |||
| sw ra,28(sp) | |||
| sw s0,24(sp) | |||
| addi s0,sp,32 | |||
| sw a0,-20(s0) | |||
| lw a1,-20(s0) | |||
| lw a0,-20(s0) | |||
| call mul | |||
| mv a5,a0 | |||
| mv a0,a5 | |||
| lw ra,28(sp) | |||
| lw s0,24(sp) | |||
| addi sp,sp,32 | |||
| jr ra | |||
| @@ -0,0 +1,78 @@ | |||
| package FiveStage | |||
| import org.scalatest.{Matchers, FlatSpec} | |||
| import cats._ | |||
| import cats.implicits._ | |||
| import fileUtils._ | |||
| import chisel3.iotesters._ | |||
| import scala.collection.mutable.LinkedHashMap | |||
| import fansi.Str | |||
| import Ops._ | |||
| import Data._ | |||
| import VM._ | |||
| import PrintUtils._ | |||
| import LogParser._ | |||
| object Manifest { | |||
| val singleTest = "forward2.s" | |||
| val nopPadded = false | |||
| val singleTestOptions = TestOptions( | |||
| printIfSuccessful = true, | |||
| printErrors = true, | |||
| printParsedProgram = false, | |||
| printVMtrace = false, | |||
| printVMfinal = false, | |||
| printMergedTrace = true, | |||
| nopPadded = nopPadded, | |||
| breakPoints = Nil, // not implemented | |||
| testName = singleTest) | |||
| val allTestOptions: String => TestOptions = name => TestOptions( | |||
| printIfSuccessful = false, | |||
| printErrors = false, | |||
| printParsedProgram = false, | |||
| printVMtrace = false, | |||
| printVMfinal = false, | |||
| printMergedTrace = false, | |||
| nopPadded = nopPadded, | |||
| breakPoints = Nil, // not implemented | |||
| testName = name) | |||
| } | |||
| class SingleTest extends FlatSpec with Matchers { | |||
| it should "just werk" in { | |||
| TestRunner.run(Manifest.singleTestOptions) should be(true) | |||
| } | |||
| } | |||
| class AllTests extends FlatSpec with Matchers { | |||
| it should "just werk" in { | |||
| val werks = getAllTestNames.map{testname => | |||
| say(s"testing $testname") | |||
| val opts = Manifest.allTestOptions(testname) | |||
| (testname, TestRunner.run(opts)) | |||
| } | |||
| if(werks.foldLeft(true)(_ && _._2)) | |||
| say(Console.GREEN + "All tests successful!" + Console.RESET) | |||
| else { | |||
| val success = werks.map(x => if(x._2) 1 else 0).sum | |||
| val total = werks.size | |||
| say(s"$success/$total tests successful") | |||
| werks.foreach{ case(name, success) => | |||
| val msg = if(success) Console.GREEN + s"$name successful" + Console.RESET | |||
| else Console.RED + s"$name failed" + Console.RESET | |||
| say(msg) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,357 @@ | |||
| package FiveStage | |||
| import cats.data.Writer | |||
| import cats._ | |||
| import cats.data._ | |||
| import cats.implicits._ | |||
| import fansi._ | |||
| import PrintUtils._ | |||
| import fileUtils.say | |||
| /** | |||
| * Types and extension methods go here. | |||
| * Maybe it's a litte arbitrary to put VM types here, but op types in Ops.scala | |||
| * Maybe these could be separated to somewhere else. | |||
| */ | |||
| object Data { | |||
| type Label = String | |||
| case class Reg(value: Int) | |||
| case class Imm(value: Int) | |||
| case class Addr(value: Int){ | |||
| def +(that: Addr) = Addr(value + that.value) | |||
| def -(that: Addr) = Addr(value - that.value) | |||
| def step = Addr(value + 4) | |||
| } | |||
| object Reg{ def apply(s: String): Reg = Reg(lookupReg(s).get) } | |||
| type SourceInfo[A] = Writer[List[String], A] | |||
| object SourceInfo { def apply[A](s: String, a: A) = Writer(List(s), a) } | |||
| trait ExecutionEvent | |||
| import PrintUtils._ | |||
| case class RegUpdate(reg: Reg, word: Int) extends ExecutionEvent | |||
| case class MemWrite(addr: Addr, word: Int) extends ExecutionEvent | |||
| case class MemRead(addr: Addr, word: Int) extends ExecutionEvent | |||
| // addr is the target address | |||
| case class PcUpdateJALR(addr: Addr) extends ExecutionEvent | |||
| case class PcUpdateJAL(addr: Addr) extends ExecutionEvent | |||
| case class PcUpdateB(addr: Addr) extends ExecutionEvent | |||
| case class PcUpdate(addr: Addr) extends ExecutionEvent | |||
| case class ExecutionTraceEvent(pc: Addr, event: ExecutionEvent*){ override def toString(): String = s"$pc: " + event.toList.mkString(", ") } | |||
| type ExecutionTrace[A] = Writer[List[ExecutionTraceEvent], A] | |||
| object ExecutionTrace { | |||
| def apply(vm: VM, event: ExecutionTraceEvent*) = Writer(event.toList, vm) | |||
| } | |||
| sealed trait ChiselEvent | |||
| case class ChiselRegEvent(pcAddr: Addr, reg: Reg, word: Int) extends ChiselEvent | |||
| case class ChiselMemWriteEvent(pcAddr: Addr, memAddr: Addr, word: Int) extends ChiselEvent | |||
| type CircuitTrace = (Addr, List[ChiselEvent]) | |||
| /** | |||
| * Not sure these should be defined here instead of in the VM | |||
| */ | |||
| case class Regs(repr: Map[Reg, Int]) { | |||
| def +(a: (Reg, Int)): (Option[RegUpdate], Regs) = | |||
| if(a._1.value == 0) (None, this) | |||
| else (Some(RegUpdate(a._1, a._2)), copy(repr + a)) | |||
| def arith(rd: Reg, operand1: Reg, operand2: Reg, op: (Int, Int) => Int): (Option[RegUpdate], Regs) = | |||
| this + (rd -> op(repr(operand1), repr(operand2))) | |||
| def arithImm(rd: Reg, operand1: Reg, operand2: Imm, op: (Int, Int) => Int): (Option[RegUpdate], Regs) = | |||
| this + (rd -> op(repr(operand1), operand2.value)) | |||
| def compare(operand1: Reg, operand2: Reg, comp: (Int, Int) => Boolean): Boolean = | |||
| comp(repr(operand1), repr(operand2)) | |||
| def apply(setting: TestSetting): Regs = setting match { | |||
| case setting: REGSET => Regs(repr + (setting.rd -> setting.word)) | |||
| case _ => this | |||
| } | |||
| } | |||
| case class DMem(repr: Map[Addr, Int]) { | |||
| def read(addr: Addr): Either[String, (MemRead, Int)] = | |||
| if(addr.value >= 4096) | |||
| Left(s"attempted to read from illegal address ${addr.show}") | |||
| else { | |||
| val readResult = repr.lift(addr).getOrElse(0) | |||
| Right((MemRead(addr, readResult), readResult)) | |||
| } | |||
| def write(addr: Addr, word: Int): Either[String, (MemWrite, DMem)] = | |||
| if(addr.value >= 4096) | |||
| Left(s"attempted to write to illegal address ${addr.show}") | |||
| else { | |||
| Right((MemWrite(addr, word)), DMem(repr + (addr -> word))) | |||
| } | |||
| def apply(setting: TestSetting): DMem = setting match { | |||
| case setting: MEMSET => { | |||
| DMem(repr + (setting.addr -> setting.word)) | |||
| } | |||
| case _ => this | |||
| } | |||
| } | |||
| object Regs{ | |||
| def empty: Regs = Regs((0 to 31).map(x => (Reg(x) -> 0)).toMap) | |||
| def apply(settings: List[TestSetting]): Regs = settings.foldLeft(empty){ | |||
| case(acc, setting) => acc(setting) | |||
| } | |||
| } | |||
| object DMem{ | |||
| def empty: DMem = DMem(Map[Addr, Int]()) | |||
| def apply(settings: List[TestSetting]): DMem = settings.foldLeft(empty){ | |||
| case(acc, setting) => acc(setting) | |||
| } | |||
| } | |||
| implicit class IntOps(i: Int) { | |||
| // Needs backticks to not conflict with xml | |||
| def `u>`(that: Int): Boolean = { | |||
| if((i >= 0) && (that >= 0)) | |||
| i > that | |||
| else if((i < 0) && (that < 0)) | |||
| i > that | |||
| else if((i < 0)) | |||
| true | |||
| else | |||
| false | |||
| } | |||
| def nBitsS: Int = i match { | |||
| case i if (i < 0) => (math.log(math.abs(i.toLong))/math.log(2)).ceil.toInt + 1 | |||
| case i if (i == 0) => 0 | |||
| case i if (i > 0) => (math.log((i + 1).toLong)/math.log(2)).ceil.toInt + 1 | |||
| } | |||
| /** | |||
| * Yes, a negative number technically has a unsigned size, but that depends on integer width, | |||
| * so it is better left as an option | |||
| */ | |||
| def nBitsU: Option[Int] = i match { | |||
| case i if (i < 0) => None | |||
| case i if (i == 0) => Some(0) | |||
| case i if (i > 0) => Some((math.log(i)/math.log(2)).ceil.toInt) | |||
| } | |||
| def field(firstBit: Int, size: Int): Int = { | |||
| val bitsLeft = 31 - firstBit | |||
| val bitsRight = 32 - size | |||
| val leftShifted = i << bitsLeft | |||
| val rightShifted = leftShifted >> bitsRight | |||
| rightShifted | |||
| } | |||
| def splitLoHi(loBits: Int): (Int, Int) = { | |||
| val hiBits = 32 - loBits | |||
| val sep = 31 - loBits | |||
| val lo = i.field(31, loBits) | |||
| val hi = i.field(sep, hiBits) | |||
| (lo, hi) | |||
| } | |||
| def log2: Int = math.ceil(math.log(i.toDouble)/math.log(2.0)).toInt | |||
| } | |||
| implicit class StringOps(s: String) { | |||
| def binary: Int = { | |||
| s.reverse.foldLeft((0, 0)){ | |||
| case((acc, pow), char) if char == '0' => (acc, pow + 1) | |||
| case((acc, pow), char) if char == '1' => (acc + (1 << pow), pow + 1) | |||
| case((acc, pow), char) => assert(false, "malformed binary conversion"); (0, 0) | |||
| }._1 | |||
| } | |||
| } | |||
| implicit class ListOps[A](xs: List[A]) { | |||
| def mkStringN = xs.mkString("\n","\n","\n") | |||
| def splitAtPred(p: (A, A) => Boolean): List[List[A]] = { | |||
| val splitPoints = xs.tail.foldLeft((1, List[Int](), xs.head)){ | |||
| case((idx, acc, pA), a) if(p(pA, a)) => (1, idx :: acc, a) | |||
| case((idx, acc, pA), a) => (idx + 1, acc, a) | |||
| }._2.reverse | |||
| val (blocks, rem) = splitPoints.foldLeft((List[List[A]](), xs)){ | |||
| case((acc, rem), point) => { | |||
| val(block, remainder) = rem.splitAt(point) | |||
| (block :: acc, remainder) | |||
| } | |||
| } | |||
| (rem :: blocks).reverse | |||
| } | |||
| def showN(sep: String)(implicit ev: Fancy[A]): fansi.Str = | |||
| xs.foldLeft(fansi.Str("")){ case(acc, a) => acc ++ a.show ++ fansi.Str(sep) } | |||
| def showN(sep1: String, sep2: String, sep3: String)(implicit ev: Fancy[A]): fansi.Str = | |||
| Str(sep1) ++ xs.foldLeft(fansi.Str("")){ case(acc, a) => acc ++ a.show ++ fansi.Str(sep2) } ++ Str(sep3) | |||
| def shuffle(shuffler: scala.util.Random): List[A] = shuffler.shuffle(xs) | |||
| } | |||
| implicit class NestedListOps[A](xs: List[List[A]]) { | |||
| def zipWithIndexNested: List[List[(A, Int)]] = { | |||
| val startingPoints = xs.scanLeft(0){ case(acc, xs) => acc + xs.size } | |||
| (xs.map(_.zipWithIndex) zip startingPoints).map{ case(withIndex, offset) => | |||
| withIndex.map{ case(a, idx) => (a, idx + offset) } | |||
| } | |||
| } | |||
| } | |||
| import Ops._ | |||
| sealed trait TestSetting | |||
| case class REGSET(rd: Reg, word: Int) extends TestSetting | |||
| case class MEMSET(addr: Addr, word: Int) extends TestSetting | |||
| implicit class ListEitherOps[E,A](es: List[Either[E,A]]) { | |||
| import cats.data.Validated | |||
| def separateXOR: Either[List[E], List[A]] = { | |||
| val (errors, as) = es.map(_.toValidated).separate | |||
| Either.cond(errors.isEmpty, as, errors) | |||
| } | |||
| } | |||
| /** | |||
| * Represents the result of parsing a program, with built in convenience methods for running a VM | |||
| * and assembling the program. | |||
| */ | |||
| case class Program( | |||
| ops : List[SourceInfo[Op]], | |||
| settings : List[TestSetting], | |||
| labelMap : Map[Label, Addr], | |||
| maxSteps : Int = 5000 | |||
| ){ | |||
| def imem: Map[Addr, Op] = | |||
| ops.map(_.run._2).zipWithIndex.map{ case(op, idx) => (Addr(idx*4), op) }.toMap | |||
| /** | |||
| * Loads a VM which can be run to get a trace. | |||
| */ | |||
| def vm: VM = | |||
| VM(settings, imem, labelMap) | |||
| /** | |||
| * A convenient lookup for every instruction, allowing the test runner to check what source line | |||
| * caused an error to happen. | |||
| */ | |||
| val sourceMap: Map[Addr, String] = | |||
| ops.map(_.run._1).zipWithIndex.map{ case(info, idx) => (Addr(idx*4), info.map(_.trim).mkString(", ")) }.toMap | |||
| /** | |||
| * The assembled program | |||
| */ | |||
| def machineCode: Either[String, Map[Addr, Int]] = | |||
| imem.toList | |||
| .sortBy(_._1.value).map{ case(addr, op) => assembler.assembleOp(op, addr, labelMap).map(x => (addr, x)) } | |||
| .sequence | |||
| .map(_.toMap) | |||
| .left.map{ case(error, addr) => s"Assembler error: $error, corresponding to source:\n${sourceMap(addr)}" } | |||
| /** | |||
| * Returns the binary code and the execution trace or an error for convenient error checking. | |||
| */ | |||
| def validate: Either[String, (Map[Addr, Int], ExecutionTrace[VM])] = machineCode.flatMap{ binary => | |||
| val uk = "UNKNOWN" | |||
| val (finish, trace) = VM.run(maxSteps, vm) | |||
| finish match { | |||
| case Failed(s, addr) => Left(s"VM failed with error $s at address $addr\nSource line:\n${sourceMap.lift(addr).getOrElse(uk)}") | |||
| case Timeout => Left(s"VM timed out after $maxSteps steps. This should not happen with the supplied tests") | |||
| case Success => Right(binary, trace) | |||
| } | |||
| } | |||
| def labelMapReverse = labelMap.toList.map(_.swap).toMap | |||
| } | |||
| def lookupReg(s: String): Option[Int] = { | |||
| val regMap = Map( | |||
| "x0" -> 0, | |||
| "x1" -> 1, | |||
| "x2" -> 2, | |||
| "x3" -> 3, | |||
| "x4" -> 4, | |||
| "x5" -> 5, | |||
| "x6" -> 6, | |||
| "x7" -> 7, | |||
| "x8" -> 8, | |||
| "x9" -> 9, | |||
| "x10" -> 10, | |||
| "x11" -> 11, | |||
| "x12" -> 12, | |||
| "x13" -> 13, | |||
| "x14" -> 14, | |||
| "x15" -> 15, | |||
| "x16" -> 16, | |||
| "x17" -> 17, | |||
| "x18" -> 18, | |||
| "x19" -> 19, | |||
| "x20" -> 20, | |||
| "x21" -> 21, | |||
| "x22" -> 22, | |||
| "x23" -> 23, | |||
| "x24" -> 24, | |||
| "x25" -> 25, | |||
| "x26" -> 26, | |||
| "x27" -> 27, | |||
| "x28" -> 28, | |||
| "x29" -> 29, | |||
| "x30" -> 30, | |||
| "x31" -> 31, | |||
| "zero" -> 0, | |||
| "ra" -> 1, | |||
| "sp" -> 2, | |||
| "gp" -> 3, | |||
| "tp" -> 4, | |||
| "t0" -> 5, | |||
| "t1" -> 6, | |||
| "t2" -> 7, | |||
| "s0" -> 8, | |||
| "fp" -> 8, | |||
| "s1" -> 9, | |||
| "a0" -> 10, | |||
| "a1" -> 11, | |||
| "a2" -> 12, | |||
| "a3" -> 13, | |||
| "a4" -> 14, | |||
| "a5" -> 15, | |||
| "a6" -> 16, | |||
| "a7" -> 17, | |||
| "s2" -> 18, | |||
| "s3" -> 19, | |||
| "s4" -> 20, | |||
| "s5" -> 21, | |||
| "s6" -> 22, | |||
| "s7" -> 23, | |||
| "s8" -> 24, | |||
| "s9" -> 25, | |||
| "s10" -> 26, | |||
| "s11" -> 27, | |||
| "t3" -> 28, | |||
| "t4" -> 29, | |||
| "t5" -> 30, | |||
| "t6" -> 31) | |||
| regMap.lift(s) | |||
| } | |||
| } | |||
| @@ -0,0 +1,184 @@ | |||
| package FiveStage | |||
| import Data._ | |||
| import fileUtils.say | |||
| import PrintUtils._ | |||
| /** | |||
| * Helpers for comparing VM and chisel logs | |||
| */ | |||
| object LogParser { | |||
| /** | |||
| * Peeks ahead at the chisel log to see if an expected jump is taken. | |||
| */ | |||
| def fetchUntilJumpTarget(addr: Addr, chiselLog: List[CircuitTrace]): Option[List[CircuitTrace]] = { | |||
| val (head, tail) = chiselLog.splitAt(4) // very arbitrary choice | |||
| val pruned: List[CircuitTrace] = head.dropWhile{ case(myAddr, _) => myAddr != addr } | |||
| pruned.headOption.map(_ => pruned ::: tail) | |||
| } | |||
| /** | |||
| * Fetches a basic block of VM execution trace | |||
| */ | |||
| def splitToBlocks(vmTrace: List[ExecutionTraceEvent]): List[List[ExecutionTraceEvent]] = | |||
| vmTrace.splitAtPred{ case(current, next) => | |||
| !(next.pc == current.pc + Addr(4)) | |||
| } | |||
| /** | |||
| * Fetches a basic block of chisel execution trace | |||
| */ | |||
| def splitToBlocksChisel(chiselTrace: List[CircuitTrace]): List[List[CircuitTrace]] = | |||
| chiselTrace.splitAtPred{ case((current, _), (next, _)) => | |||
| !((next == current + Addr(4)) || (next == current)) | |||
| } | |||
| def guessBlockName(trace: List[Addr], labelMap: Map[Addr, Label]): String = trace.headOption.map(x => labelMap.lift(x) | |||
| .getOrElse(labelMap.lift(trace.head - Addr(4)).getOrElse("UNKNOWN (return jump or misjump)"))).getOrElse("UNKNOWN") | |||
| /** | |||
| * Attempts to merge blocks, patching up when mismatches occur | |||
| * Fails when branchpredictor misjumps, feel free to send a PR | |||
| */ | |||
| type BlockList = List[(List[ExecutionTraceEvent], List[CircuitTrace])] | |||
| def mergeTraces(vmTrace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace]): BlockList = { | |||
| def helper(acc: BlockList, blocs: (List[List[ExecutionTraceEvent]], List[List[CircuitTrace]])): BlockList = blocs match { | |||
| case (vmBlock :: vmTail, chiselBlock :: chiselTail) if (vmBlock.head.pc == chiselBlock.head._1) => | |||
| helper((vmBlock, chiselBlock) :: acc, ((vmTail, chiselTail))) | |||
| case (vmBlock :: vmTail, chiselBlock :: chiselTail) => | |||
| helper((Nil, chiselBlock) :: acc, ((vmBlock :: vmTail, chiselTail))) | |||
| case (Nil, chiselBlock :: chiselTail) => | |||
| helper((Nil, chiselBlock) :: acc, ((Nil, chiselTail))) | |||
| case (vmBlock :: vmTail, Nil) => | |||
| helper((vmBlock, Nil) :: acc, ((vmTail, Nil))) | |||
| case _ => acc.reverse | |||
| } | |||
| helper(Nil, (splitToBlocks(vmTrace), splitToBlocksChisel(chiselTrace))) | |||
| } | |||
| /** | |||
| * Compares register update logs | |||
| */ | |||
| def compareRegs(vmTrace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace]): Option[String] = { | |||
| val vmRegUpdates = vmTrace.zipWithIndex | |||
| .flatMap{ case (e, step) => e.event.toList.map(y => (step, e.pc, y))} | |||
| .collect{ case (step: Int, addr: Addr, x: RegUpdate) => (step, addr, x) } | |||
| val chiselRegUpdates = chiselTrace.zipWithIndex | |||
| .flatMap{ case (e, step) => e._2.map(y => (step, e._1, y))} | |||
| .collect{ case (step: Int, addr: Addr, x: ChiselRegEvent) => (step, addr, x) } | |||
| val errors = (vmRegUpdates zip chiselRegUpdates).map{ | |||
| case((_, _, vmUpdate), (_, _, chiselUpdate)) if ((vmUpdate.reg == chiselUpdate.reg) && (vmUpdate.word == chiselUpdate.word)) => { | |||
| None | |||
| } | |||
| case((vmStep, vmAddr, vmUpdate), (chiselStep, chiselAddr, chiselUpdate)) => { | |||
| val errorString = s"Register update mismatch.\n" ++ | |||
| s"VM: At step $vmStep, at address ${vmAddr.show}, the VM got ${vmUpdate.show}\n" ++ | |||
| s"Circuit: At step $chiselStep, at address ${chiselAddr.show}, the circuit got ${chiselUpdate.show}" | |||
| Some(errorString) | |||
| } | |||
| } | |||
| val error = errors.collect{ case Some(x) => x }.headOption | |||
| val lengthMismatch: Option[String] = (vmRegUpdates, chiselRegUpdates) match { | |||
| case (h :: t, Nil) => Some(s"Your design performed no reg updates. First expected update was at VM step ${h._1}, PC: ${h._2.show}, ${h._3.show}") | |||
| case (Nil, h :: t) => Some(s"Your design performed reg updates, but the VM did not. First update was at step ${h._1}, PC: ${h._2.show}, ${h._3.show}") | |||
| case (hVM :: tVM, hC :: tC) if (tVM.size > tC.size) => { | |||
| val VMremainder = tVM.drop(tC.size) | |||
| val errorString = | |||
| s"VM performed more reg updates than your design.\n" ++ | |||
| s"Your design performed ${chiselRegUpdates.size} updates before terminating, while the VM performed ${vmRegUpdates.size} updates.\n" ++ | |||
| s"The first update your design missed happened at VM step ${VMremainder.head._1}, PC: ${VMremainder.head._2.show} and was ${VMremainder.head._3.show}" | |||
| Some(errorString) | |||
| } | |||
| case (hVM :: tVM, hC :: tC) if (tVM.size < tC.size) => { | |||
| val ChiselRemainder = tC.drop(tVM.size) | |||
| val errorString = | |||
| s"Your design performed more reg updates than the VM.\n" ++ | |||
| s"Your design performed ${chiselRegUpdates.size} updates before terminating, while the VM performed ${vmRegUpdates.size} updates.\n" ++ | |||
| s"The first spurious update your design did happened at cycle ${ChiselRemainder.head._1}, PC: ${ChiselRemainder.head._2.show} and was ${ChiselRemainder.head._3.show}" | |||
| Some(errorString) | |||
| } | |||
| case _ => None | |||
| } | |||
| (error :: lengthMismatch :: Nil).flatten.headOption | |||
| } | |||
| def compareMem(vmTrace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace]): Option[String] = { | |||
| val vmMemUpdates = vmTrace.zipWithIndex | |||
| .flatMap{ case (e, step) => e.event.toList.map(y => (step, e.pc, y))} | |||
| .collect{ case (step: Int, addr: Addr, x: MemWrite) => (step, addr, x) } | |||
| val chiselMemUpdates = chiselTrace.zipWithIndex | |||
| .flatMap{ case (e, step) => e._2.map(y => (step, e._1, y))} | |||
| .collect{ case (step: Int, addr: Addr, x: ChiselMemWriteEvent) => (step, addr, x) } | |||
| val error = (vmMemUpdates zip chiselMemUpdates).map{ | |||
| case((_, _, vmUpdate), (_, _, chiselUpdate)) if ((vmUpdate.addr == chiselUpdate.memAddr) && (vmUpdate.word == chiselUpdate.word)) => | |||
| None | |||
| case((vmStep, vmAddr, vmUpdate), (chiselStep, chiselAddr, chiselUpdate)) => { | |||
| val errorString = s"Mem update mismatch.\n" ++ | |||
| s"VM: At step $vmStep, at address ${vmAddr.show}, the VM got ${vmUpdate.show}\n" ++ | |||
| s"Circuit: At step $chiselStep, at address ${chiselAddr.show}, the circuit got ${chiselUpdate.show}" | |||
| Some(errorString) | |||
| } | |||
| }.collect{ case Some(x) => x }.headOption | |||
| val lengthMismatch = (vmMemUpdates, chiselMemUpdates) match { | |||
| case (h :: t, Nil) => Some(s"Your design performed no mem updates. First expected update was at VM step ${h._1}, PC: ${h._2}, ${h._3}") | |||
| case (Nil, h :: t) => Some(s"Your design performed mem updates, but the VM did not. First spurious update was at step ${h._1}, PC: ${h._2}, ${h._3}") | |||
| case (hVM :: tVM, hC :: tC) if (tVM.size > tC.size) => { | |||
| val VMremainder = tVM.drop(tC.size) | |||
| val errorString = | |||
| s"VM performed more mem updates than your design.\n" ++ | |||
| s"Your design performed ${chiselMemUpdates.size} updates before terminating, while the VM performed ${vmMemUpdates.size} updates.\n" ++ | |||
| s"The first update your design missed happened at VM step ${VMremainder.head._1}, PC: ${VMremainder.head._2} and was ${VMremainder.head._3}" | |||
| Some(errorString) | |||
| } | |||
| case (hVM :: tVM, hC :: tC) if (tVM.size < tC.size) => { | |||
| val ChiselRemainder = tC.drop(tVM.size) | |||
| val errorString = | |||
| s"Your design performed more mem updates than the VM.\n" ++ | |||
| s"Your design performed ${chiselMemUpdates.size} updates before terminating, while the VM performed ${vmMemUpdates.size} updates.\n" ++ | |||
| s"The first spurious update your design did happened at cycle ${ChiselRemainder.head._1}, PC: ${ChiselRemainder.head._2} and was ${ChiselRemainder.head._3}" | |||
| Some(errorString) | |||
| } | |||
| case _ => None | |||
| } | |||
| (error :: lengthMismatch :: Nil).flatten.headOption | |||
| } | |||
| } | |||
| @@ -0,0 +1,124 @@ | |||
| package FiveStage | |||
| import cats.implicits._ | |||
| import fileUtils._ | |||
| import Data._ | |||
| import PrintUtils._ | |||
| object Ops { | |||
| sealed trait Op extends RegLayout | |||
| sealed trait RegLayout | |||
| sealed trait RType extends RegLayout { def rd: Reg; def rs1: Reg; def rs2: Reg } | |||
| sealed trait IType extends RegLayout { def rd: Reg; def rs1: Reg; } | |||
| sealed trait SType extends RegLayout { def rs1: Reg; def rs2: Reg } | |||
| sealed trait UType extends RegLayout { def rd: Reg; } | |||
| sealed trait ImmType | |||
| sealed trait NoImmediate extends ImmType | |||
| sealed trait IImmediate extends ImmType | |||
| sealed trait SImmediate extends ImmType | |||
| sealed trait BImmediate extends ImmType | |||
| sealed trait UImmediate extends ImmType | |||
| sealed trait JImmediate extends ImmType | |||
| sealed trait ShiftImmediate extends ImmType | |||
| sealed trait Comparison { | |||
| def run(rs1Val: Int, rs2Val: Int): Boolean | |||
| } | |||
| case object EQ extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val == rs2Val } | |||
| case object NE extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val != rs2Val } | |||
| case object GE extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val >= rs2Val } | |||
| case object LT extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val < rs2Val } | |||
| case object GEU extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = !(rs1Val `u>` rs2Val) } | |||
| case object LTU extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val `u>` rs2Val } | |||
| case class Branch(rs1: Reg, rs2: Reg, dst: Label, comp: Comparison) extends Op with SType | |||
| object Branch{ | |||
| def beq( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, EQ) | |||
| def bne( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, NE) | |||
| def blt( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, LT) | |||
| def bge( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, GE) | |||
| def bltu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, LTU) | |||
| def bgeu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, GEU) | |||
| def ble( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, GE) | |||
| def bgt( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, LT) | |||
| def bleu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, GEU) | |||
| def bgtu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, LTU) | |||
| def beqz(rs1: Int, dst: Label) = Branch(Reg(rs1), Reg(0), dst, EQ) | |||
| def bnez(rs1: Int, dst: Label) = Branch(Reg(rs1), Reg(0), dst, NE) | |||
| def blez(rs1: Int, dst: Label) = Branch(Reg(rs1), Reg(0), dst, LT) | |||
| } | |||
| sealed trait someDecorator | |||
| sealed trait ArithOp { | |||
| def run(operand1: Int, operand2: Int): Int | |||
| } | |||
| case object ADD extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 + operand2 } | |||
| case object SUB extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 - operand2 } | |||
| case object OR extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 | operand2 } | |||
| case object XOR extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 ^ operand2 } | |||
| case object AND extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 & operand2 } | |||
| case object SLL extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 << operand2 } | |||
| case object SRL extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 >>> operand2 } | |||
| case object SRA extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 >> operand2 } | |||
| case object SLT extends ArithOp { def run(operand1: Int, operand2: Int): Int = if(operand2 > operand1) 1 else 0 } | |||
| case object SLTU extends ArithOp { def run(operand1: Int, operand2: Int): Int = if(operand2 `u>` operand1) 1 else 0 } | |||
| case class Arith(rd: Reg, rs1: Reg, rs2: Reg, op: ArithOp) extends Op with RType | |||
| object Arith { | |||
| def add( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), ADD) | |||
| def sub( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SUB) | |||
| def or( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), OR) | |||
| def xor( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), XOR) | |||
| def and( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), AND) | |||
| def sll( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SLL) | |||
| def srl( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SRL) | |||
| def sra( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SRA) | |||
| def slt( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SLT) | |||
| def sltu(rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SLTU) | |||
| } | |||
| def NOP = ArithImm.nop | |||
| case class ArithImm(rd: Reg, rs1: Reg, imm: Imm, op: ArithOp) extends Op with IType | |||
| object ArithImm { | |||
| def add( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), ADD) | |||
| def or( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), OR) | |||
| def xor( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), XOR) | |||
| def and( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), AND) | |||
| def sll( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SLL) | |||
| def srl( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SRL) | |||
| def sra( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SRA) | |||
| def slt( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SLT) | |||
| def sltu(rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SLTU) | |||
| def nop = add(0, 0, 0) | |||
| } | |||
| case class LUI(rd: Reg, imm: Imm) extends Op with UType | |||
| case class AUIPC(rd: Reg, imm: Imm) extends Op with UType | |||
| case class SW(rs2: Reg, rs1: Reg, offset: Imm) extends Op with SType | |||
| case class LW(rd: Reg, rs1: Reg, offset: Imm) extends Op with IType | |||
| case class JALR(rd: Reg, rs1: Reg, dst: String) extends Op with IType | |||
| case class JAL(rd: Reg, dst: String) extends Op with UType | |||
| object LUI { def apply(rd: Int, imm: Int): LUI = LUI(Reg(rd), Imm(imm)) } | |||
| object AUIPC { def apply(rd: Int, imm: Int): AUIPC = AUIPC(Reg(rd), Imm(imm)) } | |||
| object SW { def apply(rs2: Int, rs1: Int, offset: Int): SW = SW(Reg(rs2), Reg(rs1), Imm(offset)) } | |||
| object LW { def apply(rd: Int, rs1: Int, offset: Int): LW = LW(Reg(rd), Reg(rs1), Imm(offset)) } | |||
| object JAL{ def apply(rd: Int, dst: String): JAL = JAL(Reg(rd), dst) } | |||
| object JALR{ def apply(rd: Int, rs1: Int, dst: String): JALR = JALR(Reg(rd), Reg(rs1), dst) } | |||
| // This op should not be assembled, but will for the sake of simplicity be rendered as a NOP | |||
| case object DONE extends Op with IType { val rd = Reg(0); val rs1 = Reg(0) } | |||
| } | |||
| @@ -0,0 +1,357 @@ | |||
| package FiveStage | |||
| import atto._, Atto._, syntax.refined._ | |||
| import eu.timepit.refined.numeric._ | |||
| import fileUtils.say | |||
| import Ops._ | |||
| import Data._ | |||
| import cats._ | |||
| import cats.data.{ Op => _ } | |||
| import cats.implicits._ | |||
| object Parser { | |||
| def hex : Parser[Int] = string("0x") ~> many1(hexDigit).map{ ds => | |||
| val bi = Integer.parseUnsignedInt(new String(ds.toList.toArray), 16) | |||
| bi.toInt | |||
| } | |||
| def labelDest : Parser[Label] = (takeWhile(_ != ':') <~ char(':')) | |||
| def label : Parser[Label] = takeWhile(_ != ' ') | |||
| def reg : Parser[Int] = takeWhile(x => (x != ',' && x != ')')).map(lookupReg).attempt | |||
| def sep : Parser[Unit] = many(whitespace) *> char(',') *> many(whitespace).void | |||
| def branch : (Parser[Int], Parser[Int], Parser[String]) = (reg <~ sep, reg <~ sep, label) | |||
| def branchZ : (Parser[Int], Parser[String]) = (reg <~ sep, label) | |||
| def arith : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, reg) | |||
| def arithImm : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, hex | int) | |||
| def stringWs(s: String) : Parser[String] = many(whitespace) ~> string(s) <~ many1(whitespace) | |||
| val singleInstruction: Parser[Op] = List( | |||
| //////////////////////////////////////////// | |||
| //// Branches | |||
| stringWs("beq") ~> branch.mapN{Branch.beq}, | |||
| stringWs("bne") ~> branch.mapN{Branch.bne}, | |||
| stringWs("blt") ~> branch.mapN{Branch.blt}, | |||
| stringWs("bge") ~> branch.mapN{Branch.bge}, | |||
| stringWs("bltu") ~> branch.mapN{Branch.bltu}, | |||
| stringWs("bgeu") ~> branch.mapN{Branch.bgtu}, | |||
| // pseudos: | |||
| stringWs("ble") ~> branch.mapN{Branch.ble}, | |||
| stringWs("bgt") ~> branch.mapN{Branch.bgt}, | |||
| stringWs("bleu") ~> branch.mapN{Branch.bleu}, | |||
| stringWs("bgtu") ~> branch.mapN{Branch.bgtu}, | |||
| // Introduce zero | |||
| stringWs("bnez") ~> branchZ.mapN{Branch.bnez}, | |||
| stringWs("beqz") ~> branchZ.mapN{Branch.beqz}, | |||
| stringWs("blez") ~> branchZ.mapN{Branch.blez}, | |||
| //////////////////////////////////////////// | |||
| //// Arith | |||
| stringWs("add") ~> arith.mapN{Arith.add}, | |||
| stringWs("sub") ~> arith.mapN{Arith.sub}, | |||
| stringWs("or") ~> arith.mapN{Arith.or}, | |||
| stringWs("xor") ~> arith.mapN{Arith.xor}, | |||
| stringWs("and") ~> arith.mapN{Arith.and}, | |||
| stringWs("sll") ~> arith.mapN{Arith.sll}, | |||
| stringWs("srl") ~> arith.mapN{Arith.srl}, | |||
| stringWs("sra") ~> arith.mapN{Arith.sra}, | |||
| stringWs("slt") ~> arith.mapN{Arith.slt}, | |||
| stringWs("sltu") ~> arith.mapN{Arith.sltu}, | |||
| // pseudos | |||
| stringWs("mv") ~> (reg <~ sep, reg, ok(0)).mapN{Arith.add}, | |||
| stringWs("nop") ~> (ok(0), ok(0), ok(0)).mapN{Arith.add}, | |||
| // Check if rs1 is not equal to 0. | |||
| // snez rd, rs1 => sltu rd, zero, rs1 | |||
| stringWs("snez") ~> (reg <~ sep, ok(0), reg).mapN{Arith.sltu}, | |||
| //////////////////////////////////////////// | |||
| //// Arith Imm | |||
| stringWs("addi") ~> arithImm.mapN{ArithImm.add}, | |||
| stringWs("ori") ~> arithImm.mapN{ArithImm.or}, | |||
| stringWs("xori") ~> arithImm.mapN{ArithImm.xor}, | |||
| stringWs("andi") ~> arithImm.mapN{ArithImm.and}, | |||
| stringWs("slli") ~> arithImm.mapN{ArithImm.sll}, | |||
| stringWs("srli") ~> arithImm.mapN{ArithImm.srl}, | |||
| stringWs("srai") ~> arithImm.mapN{ArithImm.sra}, | |||
| stringWs("slti") ~> arithImm.mapN{ArithImm.slt}, | |||
| stringWs("sltui") ~> arithImm.mapN{ArithImm.sltu}, | |||
| // pseudos | |||
| stringWs("not") ~> (reg <~ sep, reg, ok(-1)).mapN{ArithImm.xor}, | |||
| // Check if rs1 is less than 1. Only 0 is less than 1 when using unsigned comparison | |||
| // seqz rd, rs1 => sltiu rd, rs1, 1 | |||
| stringWs("seqz") ~> (reg <~ sep, reg, ok(1)).mapN{ArithImm.sltu}, | |||
| stringWs("li") ~> (reg ~ sep ~ int).collect{ | |||
| case((a, b), c) if (c.nBitsS <= 12) => ArithImm.add(a, 0, c) | |||
| }, | |||
| //////////////////////////////////////////// | |||
| //// Jumps | |||
| stringWs("jalr") ~> (reg <~ sep, reg <~ sep, label).mapN{JALR.apply}, | |||
| stringWs("jal") ~> (reg <~ sep, label).mapN{JAL.apply}, | |||
| // pseudos | |||
| // JAL with ra as rd automatically chosen. | |||
| stringWs("call") ~> label.map(label => JAL(regNames.ra, label)), | |||
| // For jr we don't care about where we jumped from. | |||
| stringWs("jr") ~> reg.map(r => JALR(0, r, "zero")), | |||
| // As jr, but with a label rather than a register. | |||
| stringWs("j") ~> label.map(label => JAL(0, label)), | |||
| many(whitespace) ~> string("ret") ~> ok(JALR(0, regNames.ra, "zero")), | |||
| //////////////////////////////////////////// | |||
| //// load/store | |||
| stringWs("sw") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{case (rs2, offset, rs1) => SW(rs2, rs1, offset)}, | |||
| stringWs("lw") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{case (rd, offset, rs1) => LW(rd, rs1, offset)}, | |||
| //////////////////////////////////////////// | |||
| //// others | |||
| stringWs("auipc") ~> (reg <~ sep, int).mapN{AUIPC.apply}, | |||
| stringWs("lui") ~> (reg <~ sep, int).mapN{LUI.apply}, | |||
| many(whitespace) ~> string("nop") ~> ok(Arith.add(0, 0, 0)), | |||
| many(whitespace) ~> string("done") ~> ok(DONE), | |||
| // stringWs("done") ~> ok(DONE), | |||
| ).map(_.widen[Op]).reduce(_|_) | |||
| // def getShiftsHalfWord(offset: Int): (Int, Int) = (offset % 4) match { | |||
| // case 0 => (16, 16) | |||
| // case 1 => ( | |||
| // } | |||
| val multipleInstructions: Parser[List[Op]] = List( | |||
| stringWs("li") ~> (reg <~ sep, int.map(_.splitLoHi(12))).mapN{ case(rd, (lo, hi)) => List( | |||
| LUI(rd, hi), | |||
| ArithImm.add(rd, 0, lo) | |||
| )}.map(_.widen[Op]), | |||
| // NOTE: THESE ARE NOT PSEUDO-OPS IN RISV32I! | |||
| // NOTE: USES A SPECIAL REGISTER | |||
| stringWs("lh") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{ | |||
| case (rd, offset, rs1) if (offset % 4 == 3) => { | |||
| val placeHolder = if(rd == Reg("a0").value) Reg("a1").value else Reg("a0").value | |||
| List( | |||
| SW(placeHolder, 0, 2048), | |||
| LW(placeHolder, rs1.value, (offset & 0xFFFFFF1C)), | |||
| LW(rd.value, rs1.value, (offset & 0xFFFFFF1C) + 4), | |||
| ArithImm.sra(placeHolder, placeHolder, 24), | |||
| ArithImm.sll(rd.value, rd.value, 24), | |||
| ArithImm.sra(rd.value, rd.value, 16), | |||
| Arith.add(rd, rd, placeHolder), | |||
| LW(placeHolder, 0, 2048)).reverse | |||
| } | |||
| case (rd, offset, rs1) if (offset % 4 == 2) => { | |||
| List( | |||
| LW(rd, rs1, (offset & 0xFFFFFF1C)), | |||
| ArithImm.sra(rd, rd, 16) | |||
| ).reverse | |||
| } | |||
| case (rd, offset, rs1) => { | |||
| val leftShift = if((offset % 4) == 0) 16 else 8 | |||
| List( | |||
| LW(rd, rs1, (offset & 0xFFFFFF1C)), | |||
| ArithImm.sll(rd, rd, leftShift), | |||
| ArithImm.sra(rd, rd, 16), | |||
| ).reverse | |||
| } | |||
| }.map(_.widen[Op]), | |||
| ).reduce(_|_) | |||
| val instruction = singleInstruction.map(List(_)) | multipleInstructions | |||
| val setting = List( | |||
| char('#') ~> string("regset") ~> many1(whitespace) ~> (reg.map(Reg.apply) <~ sep, hex | int).mapN{REGSET.apply}, | |||
| char('#') ~> string("memset") ~> many1(whitespace) ~> ((hex | int).map(Addr.apply) <~ sep, hex | int).mapN{MEMSET.apply} | |||
| ).map(_.widen[TestSetting]).reduce(_|_) | |||
| def parseProgram(p: List[String], testOptions: TestOptions): Either[String, Program] = { | |||
| val all = setting || (instruction || labelDest) | |||
| /** | |||
| * The foldhelper represents a traversal through a RISC-V program. | |||
| * | |||
| * When it sees an op it records the operation and appends the source line and its location. | |||
| * If it is in nopPad mode it will also insert NOPs between the parsed ops. | |||
| * After appending ops the address counter is bumbed accordingly | |||
| * | |||
| * When it sees a label destination it checks what the current addres counter is at and creates | |||
| * a link to this address. | |||
| * | |||
| * When it sees a parse error it simply stores the error and keeps going, allowing you to get every error | |||
| * (This works for an ASM program since each line is independent) | |||
| * | |||
| * Lastly, when it sees a test setting it appends that test setting. | |||
| * | |||
| * The reason everything is treated all-in-one is to make it easier to ensure that everything is parsed. | |||
| * If there were separate parsers for ops, labels and settings it would be difficult to find out if errors | |||
| * were simply of the wrong type or a legit error. | |||
| * This is not set in stone, if you're re-architecturing the code maybe it's better to separate parsers? | |||
| * Or maybe have multiple passes? Up to you! | |||
| */ | |||
| case class FoldHelper( | |||
| settings : List[TestSetting], | |||
| ops : List[SourceInfo[Op]], | |||
| labelMap : Map[Label, Addr], | |||
| errors : List[String], | |||
| addrCount : Int){ | |||
| def addSettings (t: TestSetting): FoldHelper = copy(settings = t :: settings) | |||
| def addErrors (t: String): FoldHelper = copy(errors = t :: errors) | |||
| def addLabelMap (t: Label): FoldHelper = copy(labelMap = labelMap + (t -> Addr(addrCount))) | |||
| def addOps (t: List[SourceInfo[Op]]): FoldHelper = { | |||
| if(testOptions.nopPadded){ | |||
| copy( | |||
| ops = t.flatMap(x => (x :: List.fill(4)(SourceInfo("inserted NOP", NOP).widen[Op]))).reverse ::: ops, | |||
| addrCount = addrCount + t.size*4*5) | |||
| } | |||
| else { | |||
| copy(ops = t ::: ops, addrCount = addrCount + t.size*4) | |||
| } | |||
| } | |||
| def program: Either[String, (List[TestSetting], List[SourceInfo[Op]], Map[Label, Addr])] = { | |||
| /** | |||
| * There are two possible ways for a program to successfully terminate, either by explicitly executing | |||
| * a DONE instruction, or by returning from the main method. | |||
| * In the latter case it is necessary to preload the return address register such that the return instruction | |||
| * jumps to a predetermined special done address | |||
| */ | |||
| val hasDONEinstruction = ops.map(_.run._2).contains(DONE) | |||
| val done = copy(settings = REGSET(Reg("sp"), 1024) :: settings, ops = ops.reverse, errors = errors.reverse) | |||
| val withReturnAddress = if(hasDONEinstruction){ | |||
| done | |||
| } | |||
| else | |||
| done.copy(settings = REGSET(Reg("ra"), 0xEB1CEB1C) :: done.settings) // now that's what I call EPIC | |||
| Either.cond(errors.isEmpty, (withReturnAddress.settings, done.ops, labelMap), done.errors).left.map(errors => | |||
| s"Parser errors in ${testOptions.testName}:\n" + errors.mkString("\n")) | |||
| } | |||
| } | |||
| def foldHelper( | |||
| acc: FoldHelper, | |||
| program: List[(Int, String)]): FoldHelper = program match { | |||
| case Nil => acc | |||
| case (lineNo, line) :: t => { | |||
| if(line.isEmpty) | |||
| foldHelper(acc, t) | |||
| else { | |||
| val next = all.parse(line).done.either match { | |||
| case Left(parseError) => acc.addErrors(f"$lineNo%3d" +s":$line\t$parseError") | |||
| case Right(Left(setting)) => acc.addSettings(setting) | |||
| case Right(Right(Right(label))) => acc.addLabelMap(label) | |||
| case Right(Right(Left(ops))) => acc.addOps(ops.map(op => SourceInfo(s"${lineNo.toString.padTo(3, ' ')}:\t$line", op))) | |||
| } | |||
| foldHelper(next, t) | |||
| } | |||
| } | |||
| } | |||
| val results = foldHelper(FoldHelper(Nil, Nil, Map("zero" -> Addr(0)), Nil, 0), p.zipWithIndex.map(_.swap)) | |||
| results.program.map{ case(settings, ops, labelMap) => Program(ops, settings, labelMap) } | |||
| } | |||
| def lookupReg(s: String): Int = { | |||
| val regMap = Map( | |||
| "x0" -> 0, | |||
| "x1" -> 1, | |||
| "x2" -> 2, | |||
| "x3" -> 3, | |||
| "x4" -> 4, | |||
| "x5" -> 5, | |||
| "x6" -> 6, | |||
| "x7" -> 7, | |||
| "x8" -> 8, | |||
| "x9" -> 9, | |||
| "x10" -> 10, | |||
| "x11" -> 11, | |||
| "x12" -> 12, | |||
| "x13" -> 13, | |||
| "x14" -> 14, | |||
| "x15" -> 15, | |||
| "x16" -> 16, | |||
| "x17" -> 17, | |||
| "x18" -> 18, | |||
| "x19" -> 19, | |||
| "x20" -> 20, | |||
| "x21" -> 21, | |||
| "x22" -> 22, | |||
| "x23" -> 23, | |||
| "x24" -> 24, | |||
| "x25" -> 25, | |||
| "x26" -> 26, | |||
| "x27" -> 27, | |||
| "x28" -> 28, | |||
| "x29" -> 29, | |||
| "x30" -> 30, | |||
| "x31" -> 31, | |||
| "zero" -> 0, | |||
| "ra" -> 1, | |||
| "sp" -> 2, | |||
| "gp" -> 3, | |||
| "tp" -> 4, | |||
| "t0" -> 5, | |||
| "t1" -> 6, | |||
| "t2" -> 7, | |||
| "s0" -> 8, | |||
| "fp" -> 8, | |||
| "s1" -> 9, | |||
| "a0" -> 10, | |||
| "a1" -> 11, | |||
| "a2" -> 12, | |||
| "a3" -> 13, | |||
| "a4" -> 14, | |||
| "a5" -> 15, | |||
| "a6" -> 16, | |||
| "a7" -> 17, | |||
| "s2" -> 18, | |||
| "s3" -> 19, | |||
| "s4" -> 20, | |||
| "s5" -> 21, | |||
| "s6" -> 22, | |||
| "s7" -> 23, | |||
| "s8" -> 24, | |||
| "s9" -> 25, | |||
| "s10" -> 26, | |||
| "s11" -> 27, | |||
| "t3" -> 28, | |||
| "t4" -> 29, | |||
| "t5" -> 30, | |||
| "t6" -> 31) | |||
| regMap(s) | |||
| } | |||
| } | |||
| @@ -0,0 +1,171 @@ | |||
| package FiveStage | |||
| import cats._ | |||
| import cats.data.{ Op => _ } | |||
| import cats.implicits._ | |||
| import fileUtils._ | |||
| import Data._ | |||
| import Ops._ | |||
| import PrintUtils._ | |||
| sealed trait Finished | |||
| case object Success extends Finished | |||
| case object Timeout extends Finished | |||
| case class Failed(s: String, addr: Addr) extends Finished | |||
| case class VM( | |||
| dmem : DMem, | |||
| imem : Map[Addr, Op], | |||
| regs : Regs, | |||
| pc : Addr, | |||
| labelMap : Map[Label, Addr]){ | |||
| def stepInstruction: Either[Finished, ExecutionTrace[VM]] = { | |||
| if (pc.value == 0xEB1CEB1C) Left(Success) | |||
| else getOp flatMap { | |||
| case op: Branch => executeBranch(op) | |||
| case op: Arith => executeArith(op) | |||
| case op: ArithImm => executeArithImm(op) | |||
| case op: AUIPC => executeAUIPC(op) | |||
| case op: LUI => executeLUI(op) | |||
| case op: JALR => executeJALR(op) | |||
| case op: JAL => executeJAL(op) | |||
| case op: LW => executeLW(op) | |||
| case op: SW => executeSW(op) | |||
| case DONE => Left(Success) | |||
| } | |||
| } | |||
| private def executeBranch(op: Branch) = { | |||
| getAddr(op.dst).map{ addr => | |||
| val takeBranch = regs.compare(op.rs1, op.rs2, op.comp.run) | |||
| if(takeBranch){ | |||
| val nextVM = copy(pc = addr) | |||
| jump(nextVM, PcUpdateB(nextVM.pc)) | |||
| } | |||
| else { | |||
| step(this) | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * The weird :_* syntax is simply a way to pass a list to a varArgs function. | |||
| * | |||
| * To see why, consider def printMany(a: Any*); printMany(List(1,2,3)) | |||
| * It is now ambiguous if it should print "1, 2, 3" or List(1, 2, 3) | |||
| * | |||
| * This is disambiguated by appending :_*, thus | |||
| * printMany(List(1,2,3):_*) == printMany(1, 2, 3) | |||
| */ | |||
| private def executeArith(op: Arith) = { | |||
| val (regUpdate, nextRegs) = regs.arith(op.rd, op.rs1, op.rs2, op.op.run) | |||
| val nextVM = this.copy(regs = nextRegs) | |||
| Right(step(nextVM, regUpdate.toList:_*)) | |||
| } | |||
| private def executeArithImm(op: ArithImm) = { | |||
| val (regUpdate, nextRegs) = regs.arithImm(op.rd, op.rs1, op.imm, op.op.run) | |||
| val nextVM = this.copy(regs = nextRegs) | |||
| Right(step(nextVM, regUpdate.toList:_*)) | |||
| } | |||
| private def executeLUI(op: LUI) = { | |||
| val (regUpdate, nextRegs) = regs + (op.rd -> (op.imm.value << 12)) | |||
| val nextVM = this.copy(regs = nextRegs) | |||
| Right(step(nextVM, regUpdate.toList:_*)) | |||
| } | |||
| private def executeAUIPC(op: AUIPC) = { | |||
| val (regUpdate, nextRegs) = regs + (op.rd -> (pc.value << 12)) | |||
| val nextVM = this.copy(regs = nextRegs) | |||
| Right(step(nextVM, regUpdate.toList:_*)) | |||
| } | |||
| private def executeJALR(op: JALR) = getAddr(op.dst).map{ targetAddr => | |||
| val nextPc = Addr((regs.repr(op.rs1).value + targetAddr.value) & 0xFFFFFFFE) | |||
| val (regUpdate, nextRegs) = regs + (op.rd -> (pc.step.value)) | |||
| val nextVM = this.copy(regs = nextRegs, pc = nextPc) | |||
| jump(nextVM, (PcUpdateJALR(nextPc) :: regUpdate.toList):_*) | |||
| } | |||
| private def executeJAL(op: JAL) = getAddr(op.dst).map{ targetAddr => | |||
| val nextPc = targetAddr | |||
| val (regUpdate, nextRegs) = regs + (op.rd -> (pc.step.value)) | |||
| val nextVM = this.copy(regs = nextRegs, pc = nextPc) | |||
| jump(nextVM, (PcUpdateJAL(nextPc) :: regUpdate.toList):_*) | |||
| } | |||
| private def executeLW(op: LW) = dmem.read(Addr(regs.repr(op.rs1) + op.offset.value)).map{ case(event, result) => | |||
| val (regUpdate, nextRegs) = regs + (op.rd -> result) | |||
| val nextVM = this.copy(regs = nextRegs) | |||
| step(nextVM, (event :: regUpdate.toList):_*) | |||
| }.left.map(x => Failed(x, pc)) | |||
| private def executeSW(op: SW) = { | |||
| val writeAddress = Addr(regs.repr(op.rs1) + op.offset.value) | |||
| val writeData = regs.repr(op.rs2) | |||
| dmem.write(writeAddress, writeData).map{ case(event, nextDmem) => | |||
| val nextVM = this.copy(dmem = nextDmem) | |||
| step(nextVM, event) | |||
| } | |||
| }.left.map(x => Failed(x, pc)) | |||
| private def step(nextVM: VM, event: ExecutionEvent*) = | |||
| ExecutionTrace(nextVM.stepPC, ExecutionTraceEvent(pc, event:_*)) | |||
| // Same as above, but no stepping | |||
| private def jump(nextVM: VM, event: ExecutionEvent*) = | |||
| ExecutionTrace(nextVM, ExecutionTraceEvent(pc, event:_*)) | |||
| private def stepPC: VM = copy(pc = this.pc.step) | |||
| private def getAddr(dst: Label): Either[Failed, Addr] = | |||
| labelMap.lift(dst).toRight(Failed(s"Label $dst missing", pc)) | |||
| private def getOp: Either[Failed, Op] = | |||
| imem.lift(pc).toRight(Failed(s"Attempted to fetch instruction at illegal address ${pc.show}", pc)) | |||
| } | |||
| object VM { | |||
| val init = VM(DMem.empty, Map[Addr, Op](), Regs.empty, Addr(0), Map[Label, Addr]()) | |||
| def apply(settings: List[TestSetting], imem: Map[Addr, Op], labelMap: Map[Label, Addr]): VM = { | |||
| val (dmem, regs) = settings.foldLeft((DMem.empty, Regs.empty)){ case((dmem, regs), setting) => setting match { | |||
| case setting: REGSET => (dmem, regs(setting)) | |||
| case setting: MEMSET => (dmem(setting), regs) | |||
| } | |||
| } | |||
| VM(dmem, imem, regs, Addr(0), labelMap) | |||
| } | |||
| def run(maxSteps: Int, vm: VM) = { | |||
| def helper(state: ExecutionTrace[VM], step: Int): (Finished, ExecutionTrace[VM]) = { | |||
| if(step > 0){ | |||
| val (log, vm) = state.run | |||
| val next = vm.stepInstruction | |||
| next match { | |||
| case Left(stopped) => (stopped, state) | |||
| case Right(trace) => helper((state >> trace), step - 1) | |||
| } | |||
| } | |||
| else{ | |||
| (Timeout, state) | |||
| } | |||
| } | |||
| helper(ExecutionTrace(vm), maxSteps) | |||
| } | |||
| } | |||
| @@ -0,0 +1,269 @@ | |||
| package FiveStage | |||
| import cats.implicits._ | |||
| import Data._ | |||
| import Ops._ | |||
| import fileUtils._ | |||
| import PrintUtils._ | |||
| object assembler { | |||
| type InstructionFragment = Either[(String, Addr), Int] | |||
| /** | |||
| * Will only be called by applyImmedate, thus error propagation is not needed | |||
| * Kind of a kludge, but it works, don't touch! | |||
| */ | |||
| def setField(firstBit: Int, size: Int, field: Int): Int => Int = instruction => { | |||
| val shiftedField = field << firstBit | |||
| val mask = (1 << size) - 1 | |||
| val shiftedMask = (mask << firstBit) | |||
| val masked = ((~instruction) | shiftedMask) | |||
| val maskedInv = ~(masked) | |||
| val ret = (shiftedField & shiftedMask) | maskedInv | |||
| ret | |||
| } | |||
| def getSubField(firstBit: Int, size: Int): Int => Int = word => { | |||
| val bitsLeft = 32 - firstBit | |||
| val bitsRight = 32 - size | |||
| val leftShifted = word << bitsLeft | |||
| val rightShifted = leftShifted >> bitsRight | |||
| rightShifted | |||
| } | |||
| /** | |||
| Splits the immediate value into fields given by points. | |||
| The order of points is important! | |||
| points is of type idx, size | |||
| */ | |||
| def applyImmediate(immediateBits: Int, immediate: Int, points: List[(Int, Int)]): Int => Int = instruction => { | |||
| def go(instruction: Int, immediateIndex: Int, points: List[(Int,Int)]): Int = points match { | |||
| case h :: t => { | |||
| val (immFirstBit, size) = h | |||
| val firstBit = (immFirstBit - size) + 1 | |||
| val immSubField = getSubField(immediateIndex, size)(immediate) | |||
| val nextImmIndex = immediateIndex - size | |||
| val nextInstruction = setField(firstBit, size, immSubField)(instruction) | |||
| go(nextInstruction, nextImmIndex, points.tail) | |||
| } | |||
| case _ => { | |||
| instruction | |||
| } | |||
| } | |||
| go(instruction, immediateBits, points) | |||
| } | |||
| def applyImmediateU(immediate: Int, points: List[(Int, Int)], addr: Addr): Int => InstructionFragment = instruction => { | |||
| def totalBits = points.foldLeft(0){ case(acc, (first, size)) => acc + size } | |||
| totalBits.nBitsU.toRight("Negative number used as unsigned immediate", addr).flatMap { bits => | |||
| Either.cond(bits < totalBits, applyImmediate(totalBits, immediate, points)(instruction), ("Immediate unsigned too large", addr)) | |||
| } | |||
| } | |||
| def applyImmediateS(immediate: Int, points: List[(Int, Int)], addr: Addr): Int => InstructionFragment = instruction => { | |||
| def totalBits = points.foldLeft(0){ case(acc, (first, size)) => acc + size } | |||
| if(totalBits < immediate.nBitsS) Left((s"Immediate signed too large. immedate: $immediate, immediate.nBitsS = ${immediate.nBitsS}, total bits: $totalBits", addr)) | |||
| else Right(applyImmediate(totalBits, immediate, points)(instruction)) | |||
| } | |||
| /** | |||
| * Used by JALR, LW and arithmetic immediate ops. | |||
| * JALR is sort of the odd man out here as it should be unsigned. | |||
| * This issue should not surface at the very limited address space | |||
| * for your design. (I hope) | |||
| */ | |||
| def setItypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = { | |||
| val points = List((31, 12)) | |||
| val withField = applyImmediateS(immediate, points, addr) | |||
| withField | |||
| } | |||
| /** | |||
| * Used by SW | |||
| */ | |||
| def setStypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = { | |||
| val points = List((31, 7), (11, 5)) | |||
| val withField = applyImmediateS(immediate, points, addr) | |||
| withField | |||
| } | |||
| /** | |||
| * Used by Branches. PC relative jump, thus signed | |||
| * Last bit is not used, hence the shift | |||
| */ | |||
| def setBtypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = { | |||
| val points = List((31, 1), (7, 1), (30, 6), (11, 4)) | |||
| val withField = applyImmediateS((immediate >> 1), points, addr) | |||
| withField | |||
| } | |||
| /** | |||
| * Used by LUI and AUIPC. Unsigned | |||
| */ | |||
| def setUtypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = { | |||
| val points = List((31, 20)) | |||
| val withField = applyImmediateU(immediate, points, addr) | |||
| withField | |||
| } | |||
| /** | |||
| * Used by JAL. PC relative jump, thus signed | |||
| * The last bit is not used, hence the shift | |||
| */ | |||
| def setJtypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = { | |||
| val points = List((31, 1), (19, 8), (20, 1), (30, 10)) | |||
| applyImmediateU((immediate >> 1), points, addr) | |||
| } | |||
| /** | |||
| * Currently not used, thus we allow too larg shifts. | |||
| */ | |||
| def setShiftTypeImmediate(instruction: Int, immediate: Int): Int = { | |||
| val points = List((24, 5)) | |||
| val withField = applyImmediate(5, immediate, points)(instruction) | |||
| withField | |||
| } | |||
| def setOpCode(opcode: Int): Int => Int = setField(0, 7, opcode) | |||
| def setFunct7(funct7: Int): Int => Int = setField(25, 7, funct7) | |||
| def setFunct3(funct3: Int): Int => Int = setField(12, 3, funct3) | |||
| def setRs1(rs1: Int): Int => Int = setField(15, 5, rs1) | |||
| def setRs2(rs2: Int): Int => Int = setField(20, 5, rs2) | |||
| def setRd(rd: Int): Int => Int = setField(7, 5, rd) | |||
| def setOpCode(op: Op): Int => Int = op match { | |||
| case x: Branch => setOpCode("1100011".binary) | |||
| case x: Arith => setOpCode("0110011".binary) | |||
| case x: ArithImm => setOpCode("0010011".binary) | |||
| case x: LW => setOpCode("0000011".binary) | |||
| case x: SW => setOpCode("0100011".binary) | |||
| case x: JALR => setOpCode("1100111".binary) | |||
| case x: JAL => setOpCode("1101111".binary) | |||
| case x: AUIPC => setOpCode("0110111".binary) | |||
| case x: LUI => setOpCode("0010111".binary) | |||
| case DONE => setOpCode("0010011".binary) // done is turned into a NOP in the assembler. | |||
| } | |||
| def setComparisonFunct(cmp: Comparison): Int => Int = cmp match { | |||
| case EQ => setFunct3("000".binary) | |||
| case NE => setFunct3("001".binary) | |||
| case GE => setFunct3("101".binary) | |||
| case LT => setFunct3("100".binary) | |||
| case GEU => setFunct3("111".binary) | |||
| case LTU => setFunct3("110".binary) | |||
| } | |||
| def setBranchDestination(labelMap: Map[Label, Addr], op: Branch, opAddr: Addr): Int => InstructionFragment = instruction => { | |||
| labelMap.lift(op.dst).toRight((s"destination ${op.dst} not found", opAddr)).flatMap{ dstAddr => | |||
| setBtypeImmediate(dstAddr.value - opAddr.value, opAddr)(instruction) | |||
| } | |||
| } | |||
| def setArithFunct(op: ArithOp): Int => Int = op match { | |||
| case ADD => setFunct7("0000000".binary) andThen setFunct3("000".binary) | |||
| case SUB => setFunct7("0100000".binary) andThen setFunct3("000".binary) | |||
| case SLL => setFunct7("0000000".binary) andThen setFunct3("001".binary) | |||
| case SLT => setFunct7("0000000".binary) andThen setFunct3("010".binary) | |||
| case SLTU => setFunct7("0000000".binary) andThen setFunct3("011".binary) | |||
| case XOR => setFunct7("0000000".binary) andThen setFunct3("100".binary) | |||
| case SRL => setFunct7("0000000".binary) andThen setFunct3("101".binary) | |||
| case SRA => setFunct7("0100000".binary) andThen setFunct3("101".binary) | |||
| case OR => setFunct7("0000000".binary) andThen setFunct3("110".binary) | |||
| case AND => setFunct7("0000000".binary) andThen setFunct3("111".binary) | |||
| } | |||
| def assembleRegLayout(op: RegLayout): Int => Int = { | |||
| def assembleRType(op: RType): Int => Int = | |||
| setRd(op.rd.value) andThen | |||
| setRs1(op.rs1.value) andThen | |||
| setRs2(op.rs2.value) | |||
| def assembleIType(op: IType): Int => Int = | |||
| setRd(op.rd.value) andThen | |||
| setRs1(op.rs1.value) | |||
| def assembleSType(op: SType): Int => Int = { | |||
| // say("stype") | |||
| instruction => | |||
| (setRs1(op.rs1.value) andThen | |||
| setRs2(op.rs2.value))(instruction) | |||
| } | |||
| def assembleUType(op: UType): Int => Int = | |||
| setRd(op.rd.value) | |||
| op match { | |||
| case op: RType => assembleRType(op) | |||
| case op: IType => assembleIType(op) | |||
| case op: SType => assembleSType(op) | |||
| case op: UType => assembleUType(op) | |||
| } | |||
| } | |||
| def assembleImmediate(op: Op, addr: Addr, labelMap: Map[Label, Addr]): Int => Either[(String, Addr), Int] = op match { | |||
| case DONE => instruction => Right(instruction) | |||
| case op: Arith => instruction => Right(instruction) | |||
| case op: ArithImm => setItypeImmediate(op.imm.value, addr) | |||
| case op: Branch => setBranchDestination(labelMap, op, addr) | |||
| case op: JALR => instruction => labelMap.lift(op.dst).toRight(s"label ${op.dst} not found", addr).flatMap(addr => setItypeImmediate(addr.value, addr)(instruction)) | |||
| case op: AUIPC => setUtypeImmediate(op.imm.value, addr) | |||
| case op: LUI => setUtypeImmediate(op.imm.value, addr) | |||
| case op: LW => setItypeImmediate(op.offset.value, addr) | |||
| case op: SW => setStypeImmediate(op.offset.value, addr) | |||
| case op: JAL => instruction => { | |||
| val addressDistance = labelMap | |||
| .lift(op.dst).toRight(s"label ${op.dst} not found", addr) | |||
| .map(absoluteAddr => absoluteAddr - addr) | |||
| import PrintUtils._ | |||
| addressDistance.flatMap(distance => | |||
| setJtypeImmediate(distance.value, addr)(instruction)) | |||
| } | |||
| } | |||
| def assembleOp( | |||
| op : Op with RegLayout, | |||
| opAddr : Addr, | |||
| labelMap : Map[Label, Addr]): Either[(String, Addr), Int] = { | |||
| val layout = assembleRegLayout(op) | |||
| val immediate = assembleImmediate(op, opAddr, labelMap) | |||
| val opcode = setOpCode(op) | |||
| val extras: Int => Int = (instruction: Int) => op match { | |||
| case op: Branch => setComparisonFunct(op.comp)(instruction) | |||
| case op: ArithImm => setArithFunct(op.op)(instruction) | |||
| case op: Arith => setArithFunct(op.op)(instruction) | |||
| case op: JALR => setFunct3("000".binary)(instruction) | |||
| case op: LW => setFunct3("010".binary)(instruction) | |||
| case op: SW => setFunct3("010".binary)(instruction) | |||
| case DONE => (setFunct3("000".binary) andThen setFunct7("0000000".binary))(instruction) | |||
| case _ => instruction | |||
| } | |||
| val withOp = opcode(0) | |||
| val withLayout = layout(withOp) | |||
| val withImmediates = immediate(withLayout) | |||
| val withExtras = withImmediates.map(extras) | |||
| val finalOp = (opcode andThen layout andThen extras andThen immediate)(0) | |||
| finalOp | |||
| } | |||
| } | |||
| @@ -0,0 +1,178 @@ | |||
| package FiveStage | |||
| import cats.data.Writer | |||
| import cats._ | |||
| import cats.data.{ Op => _ } | |||
| import cats.implicits._ | |||
| object DTree { | |||
| // opaques WHEN | |||
| type Feature = String | |||
| type Value = String | |||
| type Cls = String | |||
| case class TrainingData(values: Map[Feature, Value], cls: Cls) | |||
| type TestData = Map[Feature, Value] | |||
| // Base | |||
| // def predict(data: TestData): Cls = "Died" | |||
| // Gendered | |||
| def predictStatic(data: TestData): Cls = | |||
| if(data("gender") == "female") | |||
| "survived" | |||
| else "died" | |||
| sealed trait Tree | |||
| case class Node(feature: Feature, children: Map[Value, Tree]) extends Tree | |||
| case class Leaf(cls: Cls) extends Tree | |||
| val genderBased: Tree = Node( | |||
| "gender", Map( | |||
| "female" -> Leaf("survived"), | |||
| "male" -> Leaf("died"), | |||
| )) | |||
| def predict(data: TestData)(tree: Tree): Cls = | |||
| tree match { | |||
| case Leaf(cls) => cls | |||
| case Node(feature, children) => predict(data)(children(data(feature))) | |||
| } | |||
| val data = Map("gender" -> "female", "family size" -> "0", "ticket" -> "1") | |||
| predict(data)(genderBased) // true | |||
| def entropy(classes: List[Cls]): Double = { | |||
| val total = classes.size | |||
| classes.groupBy(identity) | |||
| .mapValues { group => | |||
| val prop = group.size / total | |||
| prop * math.log(1.0 / prop) | |||
| }.values.sum | |||
| } | |||
| def bucketedEntropy(data: List[TrainingData], feature: Feature): Double = { | |||
| val total = data.size | |||
| val bucketed = data.groupBy(_.values(feature)) | |||
| .mapValues(_.map(_.cls)) | |||
| .toMap | |||
| bucketed.values.map { classes => | |||
| val prop = classes.size / total | |||
| prop * entropy(classes) | |||
| }.sum | |||
| } | |||
| def best(data: List[TrainingData], features: Set[Feature]): Feature = features.minBy(bucketedEntropy(data, _)) | |||
| def mostCommonCls(data: List[TrainingData]): Cls = ??? | |||
| def build(data: List[TrainingData], features: Set[Feature]): Tree = { | |||
| if(features.nonEmpty) { | |||
| val feature = best(data, features) | |||
| val buckets = data.groupBy(_.values(feature)) | |||
| Node(feature, buckets.mapValues(build(_, features - feature))) | |||
| } else { | |||
| Leaf(mostCommonCls(data)) | |||
| } | |||
| } | |||
| def withHKT { | |||
| sealed trait Tree[A] | |||
| case class Node[A](feature: Feature, children: Map[Value, A]) extends Tree[A] | |||
| case class Leaf[A](cls: Cls) extends Tree[A] | |||
| // import matryoshka._ | |||
| // import matryoshka.data.Fix | |||
| // import matryoshka.implicits._ | |||
| case class Fix[F[_]](unfix: F[Fix[F]]) | |||
| case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]){ | |||
| def counit: A = head | |||
| def map[B](f: A => B)(implicit ev: Functor[F]): Cofree[F, B] = Cofree(f(head), tail.map(_.map(f))) | |||
| /** | |||
| * Coflatmap alters the value of the node based on its context, then recursively | |||
| * alters its tail independently (which makes sense as it's the only thing Cofree[F, A] => B can do. | |||
| */ | |||
| def coflatMap[B](fa: Cofree[F, A] => B)(implicit ev: Functor[F]): Cofree[F, B] = { | |||
| val b = fa(this) | |||
| val fb = tail.map(_.coflatMap(fa)) | |||
| Cofree(b, fb) | |||
| } | |||
| } | |||
| implicit val treeFunctor: Functor[Tree] = new Functor[Tree] { | |||
| def map[A, B](fa: Tree[A])(f: A => B): Tree[B] = fa match { | |||
| case Node(name, children) => Node(name, children.mapValues(f)) | |||
| case Leaf(cls) => Leaf(cls) | |||
| } | |||
| } | |||
| val genderBased: Fix[Tree] = | |||
| Fix(Node( | |||
| "gender", | |||
| Map( | |||
| "female" -> Fix(Leaf[Fix[Tree]]("survived")), | |||
| "male" -> Fix(Leaf[Fix[Tree]]("died")) | |||
| ))) | |||
| def build: ((List[TrainingData], Set[Feature])) => Tree[(List[TrainingData], Set[Feature])] = { | |||
| case (data, features) => | |||
| if(features.nonEmpty) { | |||
| val feature = best(data, features) | |||
| val buckets = data.groupBy(_.values(feature)) | |||
| val next = buckets.mapValues { subset => (subset, features - feature) } | |||
| Node(feature, next) | |||
| } else { | |||
| Leaf(mostCommonCls(data)) | |||
| } | |||
| } | |||
| def explore(testData: TestData): Fix[Tree] => Cls Either Fix[Tree] = | |||
| fix => fix.unfix match { | |||
| case Leaf(cls) => Left(cls) | |||
| case Node(feature, children) => Right(children.get(testData(feature)).get) | |||
| } | |||
| // Anamorphism: Generalized unfold, builds structures | |||
| def ana[F[_]: Functor, A](f: A => F[A])(a: A): Fix[F] = | |||
| Fix( (f(a)).map(ana(f)) ) | |||
| // Catamorphism: Generalized fold, tears structures down. | |||
| def cata[F[_]: Functor, A](fa: F[A] => A)(f: Fix[F]): A = { | |||
| fa(f.unfix.map(cata(fa))) | |||
| } | |||
| // def hyloSimple[F[_] : Functor, A, B](f: F[B] => B)(g: A => F[A]): A => B | |||
| def hyloSimple[F[_]: Functor, A, B](f: F[B] => B)(g: A => F[A])(a: A): B = | |||
| cata(f)(ana(g)(a)) | |||
| // A more powerful cata | |||
| def para[F[_]: Functor, A](f: F[(Fix[F], A)] => A)(fa: Fix[F]): A = | |||
| f(fa.unfix.map(x => (x, para(f)(x)))) | |||
| // A more powerful ana | |||
| def apo[F[_]: Functor, A](f: A => F[Either[Fix[F], A]])(a: A): Fix[F] = { | |||
| Fix(f(a).map{ | |||
| case Right(a) => apo(f)(a) | |||
| case Left(fix) => fix | |||
| }) | |||
| } | |||
| // When we have cofree | |||
| def histo[F[_]: Functor, A](f: F[Cofree[F, A]] => A)(fix: Fix[F]): A = { | |||
| def toCofree(fix: Fix[F]): Cofree[F, A] = | |||
| Cofree(histo(f)(fix), fix.unfix.map(toCofree)) | |||
| f(fix.unfix.map(toCofree)) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,164 @@ | |||
| package FiveStage | |||
| import cats.data.Writer | |||
| import cats._ | |||
| import cats.data.{ Op => _ } | |||
| import cats.implicits._ | |||
| import fileUtils.say | |||
| object DeletDis { | |||
| def delet = { | |||
| case class Fix[F[_]](unfix: F[Fix[F]]) | |||
| case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]){ | |||
| def counit: A = head | |||
| def map[B](f: A => B)(implicit ev: Functor[F]): Cofree[F, B] = Cofree(f(head), tail.map(_.map(f))) | |||
| /** | |||
| * Coflatmap alters the value of the node based on its context, then recursively | |||
| * alters its tail independently (which makes sense as it's the only thing Cofree[F, A] => B can do. | |||
| */ | |||
| def coflatMap[B](fa: Cofree[F, A] => B)(implicit ev: Functor[F]): Cofree[F, B] = { | |||
| val b = fa(this) | |||
| val fb = tail.map(_.coflatMap(fa)) | |||
| Cofree(b, fb) | |||
| } | |||
| } | |||
| // Anamorphism: Generalized unfold, builds structures | |||
| def ana[F[_]: Functor, A](f: A => F[A])(a: A): Fix[F] = | |||
| Fix( (f(a)).map(ana(f)) ) | |||
| // Catamorphism: Generalized fold, tears structures down. | |||
| def cata[F[_]: Functor, A](fa: F[A] => A)(f: Fix[F]): A = { | |||
| fa(f.unfix.map(cata(fa))) | |||
| } | |||
| // def hyloSimple[F[_] : Functor, A, B](f: F[B] => B)(g: A => F[A]): A => B | |||
| def hylo[F[_]: Functor, A, B](f: F[B] => B)(g: A => F[A])(a: A): B = | |||
| cata(f)(ana(g)(a)) | |||
| // A more powerful cata | |||
| def para[F[_]: Functor, A](f: F[(Fix[F], A)] => A)(fa: Fix[F]): A = | |||
| f(fa.unfix.map(x => (x, para(f)(x)))) | |||
| // A more powerful ana | |||
| def apo[F[_]: Functor, A](f: A => F[Either[Fix[F], A]])(a: A): Fix[F] = { | |||
| Fix(f(a).map{ | |||
| case Right(a) => apo(f)(a) | |||
| case Left(fix) => fix | |||
| }) | |||
| } | |||
| // When we have cofree | |||
| def histo[F[_]: Functor, A](f: F[Cofree[F, A]] => A)(fix: Fix[F]): A = { | |||
| def toCofree(fix: Fix[F]): Cofree[F, A] = | |||
| Cofree(histo(f)(fix), fix.unfix.map(toCofree)) | |||
| f(fix.unfix.map(toCofree)) | |||
| } | |||
| sealed trait StackR | |||
| final case class DoneR(result: Int = 1) extends StackR | |||
| final case class MoreR(stack: StackR, next: Int) extends StackR | |||
| def unfoldStackR(n: Int): StackR = | |||
| if(n > 0) MoreR(unfoldStackR(n-1), n) else DoneR() | |||
| say(unfoldStackR(5)) | |||
| sealed trait Stack[A] | |||
| final case class Done[A](result: Int) extends Stack[A] | |||
| final case class More[A](a: A, next: Int) extends Stack[A] | |||
| object Stack { | |||
| implicit val stackFunctor: Functor[Stack] = new Functor[Stack] { | |||
| def map[A, B](fa: Stack[A])(f: A => B): Stack[B] = fa match { | |||
| case Done(result) => Done(result) | |||
| case More(a, next) => More(f(a), next) | |||
| } | |||
| } | |||
| def done[A](result: Int = 1): Stack[A] = Done(result) | |||
| def more[A](a: A, next: Int): Stack[A] = More(a, next) | |||
| } | |||
| import Stack._ | |||
| val stackCoalgebra: Int => Stack[Int] = | |||
| n => if(n > 0) more(n - 1, n) else done() | |||
| say(ana(stackCoalgebra)(5)) | |||
| val stackAlgebra: Stack[Int] => Int = { | |||
| case Done(result) => result | |||
| case More(acc, next) => acc * next | |||
| } | |||
| say(cata(stackAlgebra)(ana(stackCoalgebra)(5))) | |||
| say(hylo(stackAlgebra)(stackCoalgebra)(5)) | |||
| sealed trait Nat[A] | |||
| final case class Zero[A]() extends Nat[A] | |||
| final case class Succ[A](prev: A) extends Nat[A] | |||
| object Nat { | |||
| implicit val natFunctor: Functor[Nat] = new Functor[Nat] { | |||
| override def map[A, B](na: Nat[A])(f: A => B): Nat[B] = | |||
| na match { | |||
| case Zero() => Zero() | |||
| case Succ(a) => Succ(f(a)) | |||
| } | |||
| } | |||
| } | |||
| val natAlgebra: Nat[Int] => Int = { | |||
| case Zero() => 1 | |||
| case Succ(n) => { | |||
| say(s"nat alg succ $n") | |||
| n + 1 | |||
| } | |||
| } | |||
| val natAlgebraS: Nat[String] => String = { | |||
| case Zero() => "N" | |||
| case Succ(n) => n match { | |||
| case "N" => "NI" | |||
| case "NI" => "NIG" | |||
| case "NIG" => "NIGG" | |||
| case "NIGG" => "NIGGE" | |||
| case "NIGGE" => "NIGGER :-" | |||
| case s => s + "D" | |||
| } | |||
| } | |||
| val natCoalgebra: Int => Nat[Int] = | |||
| n => if (n == 0) Zero() else Succ(n - 1) | |||
| val b = ana(natCoalgebra)(9) | |||
| val c = cata(natAlgebraS)(b) | |||
| say(c) | |||
| val natAlgebraPara: Nat[(Fix[Nat], Int)] => Int = { | |||
| case Zero() => 1 | |||
| case Succ((fix, acc)) => { | |||
| say(s"nat para alg succ $fix, $acc") | |||
| cata(natAlgebra)(fix) * acc | |||
| } | |||
| } | |||
| val build = ana(natCoalgebra)(_) | |||
| say("built") | |||
| val tear = para(natAlgebraPara)(_) | |||
| say(tear(build(5))) | |||
| // say(ana(natCoalgebra)(5)) | |||
| val lastThreeSteps: Fix[Stack] = Fix(More(Fix(More(Fix(More(Fix(Done(1)),1)),2)),3)) | |||
| val stackCoalgebraApo: Int => Stack[Either[Fix[Stack], Int]] = | |||
| n => if(n > 3) more(n - 1, n).map(_.asRight) else lastThreeSteps.unfix.map(_.asLeft) | |||
| } | |||
| } | |||
| @@ -0,0 +1,352 @@ | |||
| package FiveStage | |||
| import cats.data.Writer | |||
| import cats._ | |||
| import cats.data.{ Op => _ } | |||
| import cats.implicits._ | |||
| import fansi._ | |||
| import Ops._ | |||
| import Data._ | |||
| import VM._ | |||
| import fileUtils._ | |||
| object PrintUtils { | |||
| // Minimal typeclass def for being fancy | |||
| trait Fancy[-A] { def s(a: A): fansi.Str } | |||
| implicit class FancyOps[-A](a: A)(implicit ev: Fancy[A]){ def show: fansi.Str = ev.s(a) } | |||
| implicit val DoubleFancy = new Fancy[fansi.Str]{ def s(a: fansi.Str) = a } | |||
| implicit val FancyMonoid = new Monoid[fansi.Str] { | |||
| def empty: fansi.Str = fansi.Str("") | |||
| def combine(self: fansi.Str, that: fansi.Str): fansi.Str = self ++ that | |||
| } | |||
| implicit class ExtraFancy(a: fansi.Str) { | |||
| def leftPad(length: Int): fansi.Str = Str((0 until length).map(_ => ' ').mkString) ++ a | |||
| def replace(from: Char, to: Char): fansi.Str = fansi.Str(a.toString.replace(from, to)) | |||
| def padTo(length: Int, pad: Char = ' '): fansi.Str = a ++ (0 until length - a.length).map(_ => pad).mkString | |||
| def trim: fansi.Str = fansi.Str(a.toString.trim) | |||
| } | |||
| implicit val RegFancy = new Fancy[Reg] { def s(r: Reg) = fansi.Str(regNames.canonicalName.lift(r.value).getOrElse("ERROR")) } | |||
| implicit val ImmFancy = new Fancy[Imm] { def s(r: Imm) = Str(r.value.hs) } | |||
| implicit val AddrFancy = new Fancy[Addr]{ def s(r: Addr) = Str(r.value.hs) } | |||
| implicit val ExecutionEventFancy = new Fancy[ExecutionEvent]{ | |||
| def s(a: ExecutionEvent): fansi.Str = a match { | |||
| case RegUpdate(reg, word) => Str(s"R(${reg.show}) <- 0x${word.hs}") | |||
| case MemWrite(addr, word) => fansi.Color.Blue(s"M[${addr.show}] <- 0x${word.hs}") | |||
| case MemRead(addr, word) => fansi.Color.Red(f"M[${addr.show}] -> 0x${word.hs}") | |||
| // addr is the target address | |||
| case PcUpdateJALR(addr) => fansi.Color.Green(s"PC updated to ${addr.show} via JALR") | |||
| case PcUpdateJAL(addr) => fansi.Color.Magenta(s"PC updated to ${addr.show} via JAL") | |||
| case PcUpdateB(addr) => fansi.Color.Yellow(s"PC updated to ${addr.show} via Branch") | |||
| } | |||
| } | |||
| implicit val ExecutionTraceEventFancy = new Fancy[ExecutionTraceEvent]{ | |||
| def s(a: ExecutionTraceEvent): fansi.Str = a.event.toList match { | |||
| case (h: ExecutionEvent) :: (t: RegUpdate) :: Nil => t.show.padTo(25) ++ h.show | |||
| case (h: MemWrite) :: t :: Nil => t.show.padTo(25) ++ h.show | |||
| case (h: MemRead) :: t :: Nil => t.show.padTo(25) ++ h.show | |||
| case (h: MemWrite) :: Nil => h.show.leftPad(25) | |||
| case (h: MemRead) :: Nil => h.show.leftPad(25) | |||
| case h :: t :: Nil => h.show ++ t.show | |||
| case (h: RegUpdate) :: Nil => h.show | |||
| case h :: Nil => h.show.leftPad(25) | |||
| case _ => Str("") | |||
| } | |||
| } | |||
| implicit val ChiselEventFancy = new Fancy[ChiselEvent]{ | |||
| def s(e: ChiselEvent) = e match { | |||
| case ChiselRegEvent(addr, reg, word) => fansi.Str(s"R(${reg.show}) <- ${word.hs}") | |||
| case ChiselMemWriteEvent(addr, memAddr, word) => fansi.Str(s"M[${memAddr.show}] <- ${word.hs}") | |||
| } | |||
| } | |||
| implicit val RegsFancy = new Fancy[Regs]{ | |||
| def s(e: Regs) = { | |||
| (0 to 9).map{ idx => | |||
| val cols = List.range(idx, 32, 10) | |||
| cols.map{ reg => | |||
| (fansi.Color.Yellow(Reg(reg).show.padTo(5)) ++ Str(e.repr.lift(Reg(reg)).getOrElse(0).hs)).padTo(16) | |||
| }.showN("| ") | |||
| }.toList.showN("\n", "\n", "\n") | |||
| } | |||
| } | |||
| val UNKNOWN = "UNKNOWN" | |||
| def printInstruction(op: Ops.Op, labelMap: Map[Label, Addr]): fansi.Str = op match { | |||
| case op: Branch => fansi.Color.Red(s"B${op.comp}\t${op.rs1.show}, ${op.rs2.show}, ${op.dst.show}\t[${labelMap.lift(op.dst).getOrElse(UNKNOWN)}]") | |||
| case op: Arith => s"${op.op}\t${op.rd.show}, ${op.rs1.show}, ${op.rs2.show}" | |||
| case op: ArithImm => s"${op.op}I\t${op.rd.show}, ${op.rs1.show}, ${op.imm.show}" | |||
| case op: JALR => fansi.Color.Green(s"JALR\t${op.rd.show}, ${op.rs1.show}, ${op.dst.show}\t[${labelMap.lift(op.dst).getOrElse(UNKNOWN)}]") | |||
| case op: JAL => fansi.Color.Magenta(s"JAL\t${op.rd.show}, ${op.dst.show} [${labelMap.lift(op.dst).getOrElse(UNKNOWN)}]") | |||
| case op: LW => s"LW\t${op.rd.show}, ${op.offset.show}(${op.rs1.show})" | |||
| case op: SW => s"SW\t${op.rs2.show}, ${op.offset.show}(${op.rs1.show})" | |||
| case op: LUI => s"LUI\t${op.rd.show}, ${op.imm.show}" | |||
| case op: AUIPC => s"AUIPC\t${op.rd.show}, ${op.imm.show}" | |||
| case DONE => s"DONE" | |||
| } | |||
| implicit class IntPrinters(i: Int) { | |||
| def hs: String = if(i > 65535) f"0x$i%08X" else f"0x$i%04X" | |||
| def binary: String = String.format("%" + 32 + "s", i.toBinaryString) | |||
| .replace(' ', '0').grouped(4) | |||
| .map(x => x + " ").mkString | |||
| } | |||
| def printProgram(vm: VM): String = { | |||
| val withLabels: List[Either[(Addr, Op), (Label, Addr)]] = (vm.imem.toList.map(Left(_)) ::: vm.labelMap.toList.map(Right(_))) | |||
| .sortBy { case Left(x) => x._1.value.toDouble + 0.1; case Right(x) => x._2.value.toDouble } | |||
| withLabels.map{ | |||
| case Left((addr, op)) => s"$addr:\t\t${printInstruction(op, vm.labelMap)}" | |||
| case Right((label, addr)) => s"$addr:\t$label:" | |||
| }.mkString("\n","\n","\n") | |||
| } | |||
| def printProgram(p: Program): String = printProgram(p.vm) | |||
| def printBinary(bin: Map[Addr, Int]): String = { | |||
| bin.toList.sortBy(_._1.value).map{ case(addr, op) => s"$addr: ${op.hs}" }.mkString("\n","\n","\n") | |||
| } | |||
| def printChiselLogEntry(event: (Addr, List[ChiselEvent])): fansi.Str = { | |||
| val (addr, log) = event | |||
| val events = log match { | |||
| case (h: ChiselRegEvent) :: (t: ChiselMemWriteEvent) :: Nil => h.show.padTo(25, ' ') ++ t.show | |||
| case (h: ChiselMemWriteEvent) :: Nil => h.show.leftPad(25) | |||
| case (h: ChiselRegEvent) :: Nil => h.show | |||
| case _ => fansi.Str("") | |||
| } | |||
| events | |||
| } | |||
| def printVMtrace(trace: List[ExecutionTraceEvent], program: Program): String = { | |||
| val blocks: List[List[(ExecutionTraceEvent, Int)]] = LogParser.splitToBlocks(trace).zipWithIndexNested | |||
| blocks.map{ block => | |||
| val name = LogParser.guessBlockName(block.map(_._1.pc), program.labelMapReverse) | |||
| val blockString = block.map{ case(event, idx) => | |||
| Str(s"Step: $idx,").padTo(12) ++ | |||
| Str("PC: ") ++ | |||
| event.pc.show ++ | |||
| Str("\t") ++ | |||
| event.show.padTo(70) ++ | |||
| printSourceLine(event.pc, program) | |||
| } | |||
| fansi.Color.Yellow(name) ++ Str("\n") ++ blockString.showN("\n") | |||
| }.mkStringN | |||
| } | |||
| def printSourceLine(addr: Addr, program: Program): fansi.Str = program.sourceMap.lift(addr).map(fansi.Str(_)).getOrElse(fansi.Str("???")) | |||
| def printMergedTraces( | |||
| mt: (List[ExecutionTraceEvent], List[CircuitTrace]), | |||
| program: Program | |||
| ): List[String] = { | |||
| /** | |||
| * For branch predicting processors we may end up with a spurious block causing a transient | |||
| * desynchronization. Therefore it is necessary to have a certain tolerance before calling a divergence. | |||
| */ | |||
| // TODO: Implement a synchronization test to pinpoint where a desync happens | |||
| // This is not straight forward in the case of processors which perform branch prediction. | |||
| def isSynchronized(desyncs: Int, traces: (List[ExecutionTraceEvent], List[CircuitTrace]) ): Boolean = ??? | |||
| def helper(mt: (List[ExecutionTraceEvent], List[CircuitTrace])): List[List[fansi.Str]] = mt match { | |||
| /** | |||
| * VM trace and execution log synchronized, step both | |||
| */ | |||
| case (hVM :: tVM, hC :: tC) if (hVM.pc == hC._1) => { | |||
| val address = hVM.pc | |||
| val chiselLogEntry = printChiselLogEntry(hC) | |||
| val vmEntry = hVM.show | |||
| val sourceLine = printSourceLine(address, program) | |||
| val line = List(address.show, chiselLogEntry, vmEntry, sourceLine) | |||
| line :: helper((tVM, tC)) | |||
| } | |||
| /** | |||
| * VM trace and execution log unsynchronized, step only chisel trace | |||
| * Helper is called with (hVM :: tVM) to only step the chisel log. | |||
| */ | |||
| case (hVM :: tVM, hC :: tC) => { | |||
| val address = hC._1 | |||
| val chiselLogEntry = printChiselLogEntry(hC) | |||
| val vmEntry = Str("") | |||
| val sourceLine = printSourceLine(address, program) | |||
| val line = List(address.show, chiselLogEntry, vmEntry, sourceLine) | |||
| line :: helper((hVM :: tVM, tC)) | |||
| } | |||
| /** | |||
| * The Block contains no more instructions performed by the VM. This | |||
| * happens naturally since 5-stage pipelines will fetch spurious instructions. | |||
| */ | |||
| case (Nil, hC :: tC) => { | |||
| val address = hC._1 | |||
| val chiselLogEntry = printChiselLogEntry(hC) | |||
| val vmEntry = fansi.Str("") | |||
| val sourceLine = printSourceLine(address, program) | |||
| val line = List(fansi.Color.LightBlue(address.show), chiselLogEntry, vmEntry, sourceLine) | |||
| line :: helper((Nil, tC)) | |||
| } | |||
| /** | |||
| * The Block contains no more instructions performed by the circuit. | |||
| * This happens when the circuit takes a jump the VM does not. | |||
| * This is an error *unless* the circuit has a branch predictor. | |||
| * | |||
| * If you want to you can splice the logs when this happens, but it's typically easy to spot. | |||
| */ | |||
| case (hVM :: tVM, Nil) => { | |||
| val address = hVM.pc | |||
| val chiselLogEntry = fansi.Str("") | |||
| val vmEntry = hVM.show | |||
| val sourceLine = printSourceLine(address, program) | |||
| val line = List(fansi.Color.LightRed(address.show), chiselLogEntry, vmEntry, sourceLine) | |||
| line :: helper((tVM, Nil)) | |||
| } | |||
| case (Nil, Nil) => Nil | |||
| } | |||
| def format(triplet: List[fansi.Str]): String = { | |||
| // Ahh, the GNU toolchain and its tabs | |||
| val annoyingTabCharacter = ' ' | |||
| triplet match { | |||
| case address :: ch :: vm :: source :: Nil => { | |||
| val vmLine: fansi.Str = vm.padTo(60, ' ') | |||
| val chiselLine: fansi.Str = ch.padTo(50, ' ') | |||
| val sourceLines: fansi.Str = source | |||
| ((address ++ Str(":")).padTo(14, ' ') ++ vmLine ++ fansi.Str("| ") ++ chiselLine ++ Str("| ") ++ sourceLines).toString | |||
| } | |||
| case _ => "" | |||
| } | |||
| } | |||
| val blockName = LogParser.guessBlockName(mt._1.map(_.pc), program.labelMapReverse) | |||
| (fansi.Color.Yellow(s"$blockName").padTo(74, ' ').toString ++ "|".padTo(55, ' ') ++ "|") :: helper(mt).map(format) | |||
| } | |||
| def printChiselError(e: Throwable): String = { | |||
| val rawError = """ | |||
| |This typically occurs when you forget to wrap a module | |||
| |e.g | |||
| | | |||
| |class MyBundle extends Bundle { | |||
| | val signal = UInt(32.W) | |||
| |} | |||
| |val mySignal = new MyBundle | |||
| | ^^^^ Wrong! | |||
| |should be | |||
| |val mySignal = Wire(new MyBundle) | |||
| """.stripMargin | |||
| def getFiveStageStacktrace(strace: Array[StackTraceElement]): String = | |||
| strace.map(_.toString).filter(_.contains("FiveStage")).toList.take(5).mkStringN | |||
| e match { | |||
| case e: firrtl.passes.CheckInitialization.RefNotInitializedException => { | |||
| s""" | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| |Your design has unconnected wires!" | |||
| |error:\n" | |||
| |${e.getMessage} | |||
| | | |||
| | | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| """.stripMargin | |||
| } | |||
| case e: chisel3.core.Binding.ExpectedHardwareException => { | |||
| s""" | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| |Your design is using raw chisel types! | |||
| |error:\n | |||
| |${e.getMessage} | |||
| | | |||
| |$rawError | |||
| |The error should be here somewhere: | |||
| |${getFiveStageStacktrace(e.getStackTrace)} | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| """.stripMargin | |||
| } | |||
| case e: firrtl.passes.PassExceptions => { | |||
| val rawErrorMsg = if(e.getMessage.contains("raw")) | |||
| s"One of the errors was use of raw chisel types. $rawError" | |||
| else | |||
| "" | |||
| s""" | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| |Your design has multiple errors! | |||
| |error: | |||
| |${e.getMessage} | |||
| |$rawErrorMsg | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| """.stripMargin | |||
| } | |||
| case e: Exception => { | |||
| s""" | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| |Unexpected Chisel tester error (could be a chisel error I havent accounted for, or a bug in the tester like index out of bounds.) | |||
| |error: | |||
| |${e.getMessage} | |||
| |reduced stacktrace: | |||
| |${getFiveStageStacktrace(e.getStackTrace)} | |||
| |########################################################## | |||
| |########################################################## | |||
| |########################################################## | |||
| """.stripMargin | |||
| } | |||
| } | |||
| } | |||
| def printLogSideBySide(trace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace], program: Program): String = { | |||
| import LogParser._ | |||
| val traces = mergeTraces(trace, chiselTrace).map(x => printMergedTraces((x), program)) | |||
| traces.map(_.mkString("\n")).mkString("\n", "\n--------------------------------------------------------------------------+------------------------------------------------------+-------------------------------\n", "\n") | |||
| } | |||
| } | |||
| @@ -0,0 +1,114 @@ | |||
| package FiveStage | |||
| object regNames { | |||
| val x0 = 0 | |||
| val x1 = 1 | |||
| val x2 = 2 | |||
| val x3 = 3 | |||
| val x4 = 4 | |||
| val x5 = 5 | |||
| val x6 = 6 | |||
| val x7 = 7 | |||
| val x8 = 8 | |||
| val x9 = 9 | |||
| val x10 = 10 | |||
| val x11 = 11 | |||
| val x12 = 12 | |||
| val x13 = 13 | |||
| val x14 = 14 | |||
| val x15 = 15 | |||
| val x16 = 16 | |||
| val x17 = 17 | |||
| val x18 = 18 | |||
| val x19 = 19 | |||
| val x20 = 20 | |||
| val x21 = 21 | |||
| val x22 = 22 | |||
| val x23 = 23 | |||
| val x24 = 24 | |||
| val x25 = 25 | |||
| val x26 = 26 | |||
| val x27 = 27 | |||
| val x28 = 28 | |||
| val x29 = 29 | |||
| val x30 = 30 | |||
| val x31 = 31 | |||
| val zero = 0 | |||
| val ra = 1 | |||
| val sp = 2 | |||
| val gp = 3 | |||
| val tp = 4 | |||
| val t0 = 5 | |||
| val t1 = 6 | |||
| val t2 = 7 | |||
| val s0 = 8 | |||
| val fp = 8 | |||
| val s1 = 9 | |||
| val a0 = 10 | |||
| val a1 = 11 | |||
| val a2 = 12 | |||
| val a3 = 13 | |||
| val a4 = 14 | |||
| val a5 = 15 | |||
| val a6 = 16 | |||
| val a7 = 17 | |||
| val s2 = 18 | |||
| val s3 = 19 | |||
| val s4 = 20 | |||
| val s5 = 21 | |||
| val s6 = 22 | |||
| val s7 = 23 | |||
| val s8 = 24 | |||
| val s9 = 25 | |||
| val s10 = 26 | |||
| val s11 = 27 | |||
| val t3 = 28 | |||
| val t4 = 29 | |||
| val t5 = 30 | |||
| val t6 = 31 | |||
| val canonicalName = Map( | |||
| 0 -> "zero", | |||
| 1 -> "ra", | |||
| 2 -> "sp", | |||
| 3 -> "gp", | |||
| 4 -> "tp", | |||
| 5 -> "t0", | |||
| 6 -> "t1", | |||
| 7 -> "t2", | |||
| 8 -> "s0", | |||
| 8 -> "fp", | |||
| 9 -> "s1", | |||
| 10 -> "a0", | |||
| 11 -> "a1", | |||
| 12 -> "a2", | |||
| 13 -> "a3", | |||
| 14 -> "a4", | |||
| 15 -> "a5", | |||
| 16 -> "a6", | |||
| 17 -> "a7", | |||
| 18 -> "s2", | |||
| 19 -> "s3", | |||
| 20 -> "s4", | |||
| 21 -> "s5", | |||
| 22 -> "s6", | |||
| 23 -> "s7", | |||
| 24 -> "s8", | |||
| 25 -> "s9", | |||
| 26 -> "s10", | |||
| 27 -> "s11", | |||
| 28 -> "t3", | |||
| 29 -> "t4", | |||
| 30 -> "t5", | |||
| 31 -> "t6", | |||
| ) | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| package FiveStage | |||
| import org.scalatest.{Matchers, FlatSpec} | |||
| import cats._ | |||
| import cats.implicits._ | |||
| import fileUtils._ | |||
| import chisel3.iotesters._ | |||
| import scala.collection.mutable.LinkedHashMap | |||
| import fansi.Str | |||
| import Ops._ | |||
| import Data._ | |||
| import VM._ | |||
| import PrintUtils._ | |||
| import LogParser._ | |||
| case class TestOptions( | |||
| printIfSuccessful : Boolean, | |||
| printErrors : Boolean, | |||
| printParsedProgram : Boolean, | |||
| printVMtrace : Boolean, | |||
| printVMfinal : Boolean, | |||
| printMergedTrace : Boolean, | |||
| nopPadded : Boolean, | |||
| breakPoints : List[Int], // Not implemented | |||
| testName : String | |||
| ) | |||
| case class TestResult( | |||
| regError : Option[String], | |||
| memError : Option[String], | |||
| program : String, | |||
| vmTrace : String, | |||
| vmFinal : String, | |||
| sideBySide : String | |||
| ) | |||
| object TestRunner { | |||
| def run(testOptions: TestOptions): Boolean = { | |||
| val testResults = for { | |||
| lines <- fileUtils.readTest(testOptions) | |||
| program <- FiveStage.Parser.parseProgram(lines, testOptions) | |||
| (binary, (trace, finalVM)) <- program.validate.map(x => (x._1, x._2.run)) | |||
| (termitationCause, chiselTrace) <- ChiselTestRunner( | |||
| binary.toList.sortBy(_._1.value).map(_._2), | |||
| program.settings, | |||
| finalVM.pc, | |||
| 1500) | |||
| } yield { | |||
| val traces = mergeTraces(trace, chiselTrace).map(x => printMergedTraces((x), program)) | |||
| val programString = printProgram(program) | |||
| val vmTraceString = printVMtrace(trace, program) | |||
| val vmFinalState = finalVM.regs.show | |||
| val traceString = printLogSideBySide(trace, chiselTrace, program) | |||
| val regError = compareRegs(trace, chiselTrace) | |||
| val memError = compareMem(trace, chiselTrace) | |||
| TestResult( | |||
| regError, | |||
| memError, | |||
| programString, | |||
| vmTraceString, | |||
| vmFinalState.toString, | |||
| traceString) | |||
| } | |||
| testResults.left.foreach{ error => | |||
| say(s"Test was unable to run due to error: $error") | |||
| } | |||
| testResults.map{ testResults => | |||
| val successful = List(testResults.regError, testResults.memError).flatten.headOption.map(_ => false).getOrElse(true) | |||
| if(successful) | |||
| say(s"${testOptions.testName} succesful") | |||
| else | |||
| say(s"${testOptions.testName} failed") | |||
| if(testOptions.printIfSuccessful && successful){ | |||
| if(testOptions.printParsedProgram) say(testResults.program) | |||
| if(testOptions.printVMtrace) say(testResults.vmTrace) | |||
| if(testOptions.printVMfinal) say(testResults.vmFinal) | |||
| if(testOptions.printMergedTrace) say(testResults.sideBySide) | |||
| } | |||
| else{ | |||
| if(testOptions.printErrors){ | |||
| say(testResults.regError.map(_.show.toString).getOrElse("no reg errors")) | |||
| say(testResults.memError.map(_.show.toString).getOrElse("no mem errors")) | |||
| } | |||
| if(testOptions.printParsedProgram) say(testResults.program) | |||
| if(testOptions.printVMtrace) say(testResults.vmTrace) | |||
| if(testOptions.printVMfinal) say(testResults.vmFinal) | |||
| if(testOptions.printMergedTrace) say(testResults.sideBySide) | |||
| } | |||
| successful | |||
| }.toOption.getOrElse(false) | |||
| } | |||
| } | |||
| @@ -0,0 +1,166 @@ | |||
| package FiveStage | |||
| import fileUtils._ | |||
| import Data._ | |||
| import PrintUtils._ | |||
| object TestUtils { | |||
| /** | |||
| * Generate and serialize BTrees for the test runner | |||
| */ | |||
| def generateBTree: Unit = { | |||
| import cats._ | |||
| import cats.implicits._ | |||
| case class AnnotatedNode(value: Int, index: Int, left: Option[AnnotatedNode], right: Option[AnnotatedNode]){ | |||
| def find(key: Int): Unit = { | |||
| say(s"at $index (${(4 + (index << 2)).hs})-> ${value.hs}, looking for ${key.hs}") | |||
| if(value == key) | |||
| say("found it") | |||
| else if(key < value) | |||
| left.map{x => say("going left\n"); x.find(key)}.getOrElse("gave up") | |||
| else | |||
| right.map{x => say("going right\n"); x.find(key)}.getOrElse("gave up") | |||
| } | |||
| } | |||
| def printAnnoTree(tree: AnnotatedNode, depth: Int): String = { | |||
| val ls = tree.left.map(n => printAnnoTree(n, depth + 2)).getOrElse("left empty") | |||
| val rs = tree.right.map(n => printAnnoTree(n, depth + 2)).getOrElse("right empty") | |||
| val pads = "|".padTo(2, ' ')*depth | |||
| s"${tree.value.hs} at ${tree.index.hs}\n$pads$ls\n$pads$rs" | |||
| } | |||
| case class Node(value: Int, left: Option[Node], right: Option[Node]){ | |||
| def append(v: Int): Node = if(v < value) | |||
| copy(left = left.map(_.append(v)).orElse(Some(Node(v)))) | |||
| else | |||
| copy(right = right.map(_.append(v)).orElse(Some(Node(v)))) | |||
| } | |||
| object Node { | |||
| def apply(v: Int): Node = Node(v, None, None) | |||
| } | |||
| def annotate(n: Int, root: Node): (AnnotatedNode, Int) = { | |||
| (root.left, root.right) match { | |||
| case (None, None) => { | |||
| (AnnotatedNode(root.value, n, None, None), n + 1) | |||
| } | |||
| case (Some(node), None) => { | |||
| val (annotated, next) = annotate(n+1, node) | |||
| (AnnotatedNode(root.value, n, Some(annotated), None), next) | |||
| } | |||
| case (None, Some(node)) => { | |||
| val (annotated, next) = annotate(n+1, node) | |||
| (AnnotatedNode(root.value, n, None, Some(annotated)), next) | |||
| } | |||
| case (Some(left), Some(right)) => { | |||
| val (leftAnno, leftNext) = annotate(n+1, left) | |||
| val (rightAnno, rightNext) = annotate(leftNext, right) | |||
| (AnnotatedNode(root.value, n, Some(leftAnno), Some(rightAnno)), rightNext) | |||
| } | |||
| } | |||
| } | |||
| def foldAnno(root: Option[AnnotatedNode]): List[Int] = { | |||
| root.map{ root => | |||
| val leftIndex = root.left.map(_.index).getOrElse(0) | |||
| val hasLeft = root.left.map(_ => 1).getOrElse(0) | |||
| val rightIndex = root.right.map(_.index).getOrElse(0) | |||
| val hasRight = root.right.map(_ => 1).getOrElse(0) | |||
| val entry = hasLeft + (leftIndex << 1) + (hasRight << 8) + (rightIndex << 9) + (root.value << 16) | |||
| say(s"with leftIndex: ${leftIndex.hs}, rightIndex: ${rightIndex.hs}, value: ${root.value.hs} we got ${entry.hs}") | |||
| entry :: foldAnno(root.left) ::: foldAnno(root.right) | |||
| }.getOrElse(Nil) | |||
| } | |||
| import scala.util.Random | |||
| val r = new scala.util.Random(0xF01D1EF7) | |||
| def randInt = r.nextInt(1000) | |||
| val seed = (0 to 100).map(_ => randInt).toList | |||
| val btree = seed.foldLeft(Node(randInt, None, None)){ case(acc, n) => acc.append(n)} | |||
| val annoTree = annotate(0, btree) | |||
| say(foldAnno(Some(annoTree._1)).zipWithIndex.map{case(m, idx) => s"#memset ${(4 + (idx*4)).hs}, ${m.hs}"}.mkStringN) | |||
| } | |||
| /** | |||
| * Generates a random program filled with hazards | |||
| */ | |||
| def generateHazardsForward(steps: Int) : Unit = { | |||
| // val r = new scala.util.Random(0xF01D1EF7) | |||
| val r = new scala.util.Random(0xF01D1EF8) | |||
| import Ops._ | |||
| val active = List(1, 2, 3) | |||
| val initVM = { | |||
| val init = VM.init | |||
| val init1 = init.copy(regs = (init.regs + (Reg(1) -> 123))._2) | |||
| val init2 = init.copy(regs = (init1.regs + (Reg(2) -> -40))._2) | |||
| val init3 = init.copy(regs = (init2.regs + (Reg(3) -> 0xFFEE))._2) | |||
| init3 | |||
| } | |||
| def generateInstruction: (Int, (String, Op)) = { | |||
| val rd = active.shuffle(r).head | |||
| val rs1 = active.shuffle(r).head | |||
| val rs2 = active.shuffle(r).head | |||
| val imm = r.nextInt(1024) - 512 | |||
| val shift = r.nextInt(32) - 16 | |||
| val choices = List( | |||
| (s"add ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.add(rd, rs1, rs2)), | |||
| (s"sub ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sub(rd, rs1, rs2)), | |||
| (s"or ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.or(rd, rs1, rs2)), | |||
| (s"xor ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.xor(rd, rs1, rs2)), | |||
| (s"and ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.and(rd, rs1, rs2)), | |||
| (s"sll ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sll(rd, rs1, rs2)), | |||
| (s"srl ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.srl(rd, rs1, rs2)), | |||
| (s"sra ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sra(rd, rs1, rs2)), | |||
| (s"slt ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.slt(rd, rs1, rs2)), | |||
| (s"sltu ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sltu(rd, rs1, rs2)), | |||
| (s"addi ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.add(rd, rs1, imm)), | |||
| (s"ori ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.or(rd, rs1, imm)), | |||
| (s"xori ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.xor(rd, rs1, imm)), | |||
| (s"andi ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.and(rd, rs1, imm)), | |||
| (s"slli ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(shift).show}", ArithImm.sll(rd, rs1, shift)), | |||
| (s"srli ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(shift).show}", ArithImm.srl(rd, rs1, shift)), | |||
| (s"srai ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(shift).show}", ArithImm.sra(rd, rs1, shift)), | |||
| (s"slti ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.slt(rd, rs1, imm)), | |||
| (s"sltiu ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.sltu(rd, rs1, imm))) | |||
| (rd, choices.shuffle(r).head) | |||
| } | |||
| def helper(attempts: Int, steps: Int, vm: VM): Unit = { | |||
| if((attempts > 10) || (steps == 0)) | |||
| () | |||
| else{ | |||
| val (nextRd, (nS, nextOp)) = generateInstruction | |||
| val withOp = vm.copy(imem = vm.imem + (vm.pc -> nextOp)) | |||
| val nextVmE = withOp.stepInstruction | |||
| val nextVm = nextVmE.toOption.get.run._2 | |||
| if(nextVm.regs.repr(Reg(nextRd)) == 0) | |||
| helper(attempts + 1, steps, vm) | |||
| else { | |||
| say(nS) | |||
| helper(0, steps - 1, nextVm) | |||
| } | |||
| } | |||
| } | |||
| helper(0, steps, initVM) | |||
| } | |||
| } | |||
| @@ -0,0 +1,188 @@ | |||
| package FiveStage | |||
| import chisel3.iotesters._ | |||
| import scala.collection.mutable.LinkedHashMap | |||
| import fileUtils.say | |||
| import Data._ | |||
| import PrintUtils._ | |||
| private class ChiselTestRunner ( | |||
| instructions : List[Int], | |||
| settings : List[TestSetting], | |||
| c : Tile, | |||
| d : PeekPokeTester[Tile], | |||
| terminalAddress : Addr, | |||
| maxSteps : Int) { | |||
| /** | |||
| * Currently unused as it is quite nontrivial to figure out whether read data is actually used. | |||
| * Still, with the necessary scaffolding these can be correlated with reg writes to figure out | |||
| * if they are valid or not. | |||
| */ | |||
| case class ChiselMemReadEvent(pcAddr: Addr, memAddr: Addr, word: Int) | |||
| private def setup = { | |||
| d.poke(d.dut.io.setup, 1) | |||
| val initDMem = DMem(settings).repr.toList | |||
| val initRegs = Regs(settings).repr.toList | |||
| setupImem(instructions) | |||
| setupRegs(initRegs) | |||
| setupDmem(initDMem) | |||
| // flush | |||
| d.step(1) | |||
| disableTestSignals | |||
| d.step(5) | |||
| d.poke(d.dut.io.setup, 0) | |||
| def disableTestSignals: Unit = { | |||
| d.poke(d.dut.io.DMEMWriteData, 0) | |||
| d.poke(d.dut.io.DMEMAddress, 0) | |||
| d.poke(d.dut.io.DMEMWriteEnable, 0) | |||
| d.poke(d.dut.io.regsWriteData, 0) | |||
| d.poke(d.dut.io.regsAddress, 0) | |||
| d.poke(d.dut.io.regsWriteEnable, 0) | |||
| d.poke(d.dut.io.IMEMWriteData, 0) | |||
| d.poke(d.dut.io.IMEMAddress, 4092) | |||
| } | |||
| def setupRegs(regs: List[(Reg, Int)]) = { | |||
| regs.foreach{ case(reg, word) => | |||
| d.poke(d.dut.io.setup, 1) | |||
| d.poke(d.dut.io.regsWriteEnable, 1) | |||
| d.poke(d.dut.io.regsWriteData, BigInt(word)) | |||
| d.poke(d.dut.io.regsAddress, reg.value) | |||
| d.step(1) | |||
| } | |||
| d.poke(d.dut.io.regsWriteEnable, 0) | |||
| d.poke(d.dut.io.regsWriteData, 0) | |||
| d.poke(d.dut.io.regsAddress, 0) | |||
| } | |||
| def setupDmem(mem: List[(Addr, Int)]) = { | |||
| mem.foreach { case (addr, word) => | |||
| d.poke(d.dut.io.setup, 1) | |||
| d.poke(d.dut.io.DMEMWriteEnable, 1) | |||
| d.poke(d.dut.io.DMEMWriteData, word) | |||
| d.poke(d.dut.io.DMEMAddress, addr.value) | |||
| d.step(1) | |||
| } | |||
| d.poke(d.dut.io.DMEMWriteEnable, 0) | |||
| d.poke(d.dut.io.DMEMWriteData, 0) | |||
| d.poke(d.dut.io.DMEMAddress, 0) | |||
| } | |||
| def setupImem(instructions: List[Int]) = { | |||
| (0 until instructions.length).foreach{ ii => | |||
| d.poke(d.dut.io.IMEMAddress, ii*4) | |||
| d.poke(d.dut.io.IMEMWriteData, instructions(ii).toInt) | |||
| d.step(1) | |||
| } | |||
| d.poke(d.dut.io.IMEMAddress, 4092) // Ensures that we don't overwrite an instruction. Bandaid for lack of IMEM.writeEnable | |||
| d.poke(d.dut.io.IMEMWriteData, 0) | |||
| } | |||
| } | |||
| private def getPC = Addr(d.peek(d.dut.io.currentPC).toInt) | |||
| private def getDMemWriteAddress = Addr(d.peek(d.dut.io.memDeviceWriteAddress).toInt) | |||
| private def getRegWriteAddress = Reg(d.peek(d.dut.io.regsDeviceWriteAddress).toInt) | |||
| private def getRegUpdate: Option[ChiselRegEvent] = { | |||
| if( | |||
| (d.peek(d.dut.io.regsDeviceWriteEnable) == 1) && | |||
| (getRegWriteAddress.value != 0) | |||
| ){ | |||
| val regWriteAddress = getRegWriteAddress | |||
| val regWriteData = d.peek(d.dut.io.regsDeviceWriteData).toInt | |||
| val regUpdate = ChiselRegEvent(getPC, regWriteAddress, regWriteData) | |||
| Some(regUpdate) | |||
| } | |||
| else | |||
| None | |||
| } | |||
| private def getMemWrite: Option[ChiselMemWriteEvent] = { | |||
| if(d.peek(d.dut.io.memDeviceWriteEnable) == 1) { | |||
| val memWriteAddress = getDMemWriteAddress | |||
| val memWriteData = d.peek(d.dut.io.memDeviceWriteData).toInt | |||
| val memUpdate = ChiselMemWriteEvent(getPC, memWriteAddress, memWriteData) | |||
| Some(memUpdate) | |||
| } | |||
| else | |||
| None | |||
| } | |||
| private def stepOne: CircuitTrace = { | |||
| val state = (getPC, List(getRegUpdate, getMemWrite).flatten) | |||
| // say(d.peek(d.dut.io).toList.mkStringN) | |||
| d.step(1) | |||
| state | |||
| } | |||
| private def go(log: List[CircuitTrace], timeOut: Int): (Option[String], List[CircuitTrace]) = { | |||
| if(timeOut == 0){ | |||
| (Some("Chisel tester timed out before reaching termination address"), log.reverse) | |||
| } | |||
| else if(getPC == terminalAddress){ | |||
| (None, (flush ::: log).reverse) | |||
| } | |||
| else { | |||
| val step = stepOne | |||
| go(step :: log, timeOut - 1) | |||
| } | |||
| } | |||
| // After finishing, let the circuit run until all updates can be committed. | |||
| private def flush: List[CircuitTrace] = | |||
| (0 to 3).map(_ => stepOne).reverse.toList | |||
| /** | |||
| * Run the entire shebang | |||
| */ | |||
| def run: (Option[String], List[CircuitTrace]) = { | |||
| setup | |||
| go(Nil, maxSteps) | |||
| } | |||
| } | |||
| object ChiselTestRunner { | |||
| def apply( | |||
| binary : List[Int], | |||
| settings : List[TestSetting], | |||
| terminalAddress : Addr, | |||
| maxSteps : Int): Either[String, (Option[String], List[CircuitTrace])] = { | |||
| var sideEffectExtravaganza: Option[(Option[String], List[CircuitTrace])] = None | |||
| val error: Either[String, Boolean] = scala.util.Try { | |||
| chisel3.iotesters.Driver(() => new Tile(), "treadle") { c => | |||
| new PeekPokeTester(c) { | |||
| val testRunner = new ChiselTestRunner( | |||
| binary, | |||
| settings, | |||
| c, | |||
| this, | |||
| terminalAddress, | |||
| maxSteps | |||
| ) | |||
| val log = testRunner.run | |||
| sideEffectExtravaganza = Some(log) | |||
| } | |||
| } | |||
| }.toEither.left.map{printChiselError} | |||
| error.flatMap{ e => | |||
| sideEffectExtravaganza.toRight("Unknown test failure, please let me know") | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,94 @@ | |||
| package FiveStage | |||
| import chisel3.iotesters._ | |||
| import java.io.File | |||
| import java.nio.file.Path | |||
| import scala.collection.mutable.LinkedHashMap | |||
| // import cats.effect.ContextShift | |||
| import cats.implicits._ | |||
| import cats._ | |||
| import cats.syntax._ | |||
| import cats.Applicative._ | |||
| import atto._, Atto._ | |||
| object fileUtils { | |||
| def say(word: Any)(implicit filename: sourcecode.File, line: sourcecode.Line): Unit = { | |||
| val fname = filename.value.split("/").last | |||
| println(Console.YELLOW + s"[${fname}: ${sourcecode.Line()}]" + Console.RESET + s" - $word") | |||
| } | |||
| def sayRed(word: Any)(implicit filename: sourcecode.File, line: sourcecode.Line): Unit = { | |||
| val fname = filename.value.split("/").last | |||
| println(Console.YELLOW + s"[${fname}: ${sourcecode.Line()}]" + Console.RED + s" - $word") | |||
| } | |||
| def sayGreen(word: Any)(implicit filename: sourcecode.File, line: sourcecode.Line): Unit = { | |||
| val fname = filename.value.split("/").last | |||
| println(Console.YELLOW + s"[${fname}: ${sourcecode.Line()}]" + Console.GREEN + s" - $word") | |||
| } | |||
| def getListOfFiles(dir: String): List[File] = | |||
| (new File(dir)).listFiles.filter(_.isFile).toList | |||
| def getListOfFiles(dir: Path): List[File] = | |||
| dir.toFile().listFiles.filter(_.isFile).toList | |||
| def getListOfFolders(dir: String): List[File] = | |||
| (new File(dir)).listFiles.filter(_.isDirectory).toList | |||
| def getListOfFolders(dir: Path): List[File] = | |||
| dir.toFile().listFiles.filter(_.isDirectory).toList | |||
| def getListOfFilesRecursive(dir: String): List[File] = { | |||
| getListOfFiles(dir) ::: getListOfFolders(dir).flatMap(f => | |||
| getListOfFilesRecursive(f.getPath) | |||
| ) | |||
| } | |||
| import cats.implicits._ | |||
| import java.nio.file.Paths | |||
| import java.util.concurrent.Executors | |||
| import scala.concurrent.ExecutionContext | |||
| def relativeFile(name: String) = { | |||
| new File(getClass.getClassLoader.getResource(name).getPath) | |||
| } | |||
| def getTestDir: File = | |||
| new File(getClass.getClassLoader.getResource("tests").getPath) | |||
| def getAllTests: List[File] = getListOfFilesRecursive(getTestDir.getPath) | |||
| .filter( f => f.getPath.endsWith(".s") ) | |||
| def getAllTestNames: List[String] = getAllTests.map(_.toString.split("/").takeRight(1).mkString) | |||
| def clearTestResults = { | |||
| try { | |||
| val testResults = relativeFile("/testResults") | |||
| testResults.delete() | |||
| } | |||
| catch { | |||
| case _:Throwable => () | |||
| } | |||
| } | |||
| /** | |||
| * Read an assembly file. | |||
| */ | |||
| def readTest(testOptions: TestOptions): Either[String, List[String]] = { | |||
| // Ahh, the GNU toolchain and its tabs | |||
| val annoyingTabCharacter = ' ' | |||
| getAllTests.filter(_.getName.contains(testOptions.testName)).headOption.toRight(s"File not found: ${testOptions.testName}").flatMap{ filename => | |||
| import scala.io.Source | |||
| scala.util.Try( | |||
| Source.fromFile(filename) | |||
| .getLines.toList | |||
| .map(_.replace(annoyingTabCharacter, ' '))) | |||
| .toOption | |||
| .toRight(s"Error reading $filename") | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| // package FiveStage | |||
| // import chisel3._ | |||
| // import chisel3.iotesters._ | |||
| // import org.scalatest.{Matchers, FlatSpec} | |||
| // import spire.math.{UInt => Uint} | |||
| // import fileUtils._ | |||
| // import cats.implicits._ | |||
| // import RISCVutils._ | |||
| // import RISCVasm._ | |||
| // import riscala._ | |||
| // import utilz._ | |||
| // class AllTests extends FlatSpec with Matchers { | |||
| // val results = fileUtils.getAllTests.map{f => | |||
| // val result = TestRunner.runTest(f.getPath, false) | |||
| // (f.getName, result) | |||
| // } | |||
| // makeReport(results) | |||
| // } | |||
| // /** | |||
| // This is for you to run more verbose testing. | |||
| // */ | |||
| // class SelectedTests extends FlatSpec with Matchers { | |||
| // val tests = List( | |||
| // "matMul.s" | |||
| // ) | |||
| // if(!tests.isEmpty){ | |||
| // val results = fileUtils.getAllTests.filter(f => tests.contains(f.getName)).map{ f => | |||
| // val result = TestRunner.runTest(f.getPath, true) | |||
| // (f.getName, result) | |||
| // } | |||
| // makeReport(results) | |||
| // } | |||
| // } | |||