From e84986160f827c3d287fa1e0818aa702b8519344 Mon Sep 17 00:00:00 2001 From: Ruige Lee <295054118@qq.com> Date: Sun, 18 Jun 2023 12:41:33 +0800 Subject: [PATCH] Initial commit --- .github/workflows/template-cleanup.yml | 55 ++++ .github/workflows/test.yml | 27 ++ .gitignore | 341 +++++++++++++++++++++++++ LICENSE | 24 ++ README.md | 101 ++++++++ build.sbt | 25 ++ build.sc | 31 +++ project/build.properties | 1 + project/plugins.sbt | 1 + src/main/scala/gcd/DecoupledGCD.scala | 73 ++++++ src/main/scala/gcd/GCD.scala | 34 +++ src/test/scala/gcd/GCDSpec.scala | 52 ++++ 12 files changed, 765 insertions(+) create mode 100644 .github/workflows/template-cleanup.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.sbt create mode 100644 build.sc create mode 100644 project/build.properties create mode 100644 project/plugins.sbt create mode 100644 src/main/scala/gcd/DecoupledGCD.scala create mode 100644 src/main/scala/gcd/GCD.scala create mode 100644 src/test/scala/gcd/GCDSpec.scala diff --git a/.github/workflows/template-cleanup.yml b/.github/workflows/template-cleanup.yml new file mode 100644 index 0000000..7e8ab1c --- /dev/null +++ b/.github/workflows/template-cleanup.yml @@ -0,0 +1,55 @@ +# Workflow to cleanup projects created from this template +# Adapted from workflow of the same name in https://github.com/JetBrains/intellij-platform-plugin-template +# SPDX-License-Identifier: Apache-2.0 + +name: Template Cleanup +on: + push: + branches: [main] + +jobs: + # Triggered on first push to repos created from the template + template-cleanup: + name: Template Cleanup + runs-on: ubuntu-latest + if: github.event.repository.name != 'chisel-template' + steps: + + - name: Checkout + uses: actions/checkout@v2 + + - name: Cleanup + run: | + export LC_CTYPE=C + export LANG=C + + # Prepare variables + NAME="${GITHUB_REPOSITORY##*/}" + ORG="$GITHUB_REPOSITORY_OWNER" + SAFE_ORG=$(echo $ORG | sed 's/[^a-zA-Z0-9]//g' | tr '[:upper:]' '[:lower:]') + GROUP="com.github.$SAFE_ORG" + + # Replace placeholders + sed -i "s/%NAME%/$NAME/g" build.sbt build.sc README.md + sed -i "s/%REPOSITORY%/${GITHUB_REPOSITORY/\//\\/}/g" README.md + sed -i "s/%ORGANIZATION%/$GROUP/g" build.sbt + + # Remove lines marked with #REMOVE-ON-CLEANUP# + sed -i '/#REMOVE-ON-CLEANUP#/d' README.md + + rm -rf \ + .github/workflows/template-cleanup.yml \ + LICENSE + + - name: Commit + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add . + git commit -m "Template cleanup" + + - name: Push changes + uses: ad-m/github-push-action@v0.6.0 + with: + branch: main + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..3cea806 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Continuous Integration + +on: [push, pull_request] + +jobs: + ci: + name: ci + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Cleanup + run: sed -i "s/%NAME%/test/g" build.sc + - name: Setup Scala + uses: olafurpg/setup-scala@v10 + with: + java-version: adopt@1.8 + - name: Setup Mill + uses: jodersky/setup-mill@v0.2.3 + with: + mill-version: 0.9.7 + - name: Cache Scala + uses: coursier/cache-action@v5 + - name: SBT Test + run: sbt test + - name: mill Test + run: mill _.test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12033d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,341 @@ +### 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 +/.bsp + +# sbt specific +.cache +.history +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# 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* + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100644 index 0000000..f5a9169 --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +Chisel Project Template +======================= + +You've done the [Chisel Bootcamp](https://github.com/freechipsproject/chisel-bootcamp), and now you +are ready to start your own Chisel project. The following procedure should get you started +with a clean running [Chisel3](https://www.chisel-lang.org/) project. + +## Make your own Chisel3 project + +### Dependencies + +#### JDK 8 or newer + +We recommend LTS releases Java 8 and Java 11. You can install the JDK as recommended by your operating system, or use the prebuilt binaries from [AdoptOpenJDK](https://adoptopenjdk.net/). + +#### SBT or mill + +SBT is the most common built tool in the Scala community. You can download it [here](https://www.scala-sbt.org/download.html). +mill is another Scala/Java build tool without obscure DSL like SBT. You can download it [here](https://github.com/com-lihaoyi/mill/releases) + +### How to get started + +#### Create a repository from the template + +This repository is a Github template. You can create your own repository from it by clicking the green `Use this template` in the top right. +Please leave `Include all branches` **unchecked**; checking it will pollute the history of your new repository. +For more information, see ["Creating a repository from a template"](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template). + +#### Wait for the template cleanup workflow to complete + +After using the template to create your own blank project, please wait a minute or two for the `Template cleanup` workflow to run which will removes some template-specific stuff from the repository (like the LICENSE). +Refresh the repository page in your browser until you see a 2nd commit by `actions-user` titled `Template cleanup`. + + +#### Clone your repository + +Once you have created a repository from this template and the `Template cleanup` workflow has completed, you can click the green button to get a link for cloning your repository. +Note that it is easiest to push to a repository if you set up SSH with Github, please see the [related documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/connecting-to-github-with-ssh). SSH is required for pushing to a Github repository when using two-factor authentication. + +```sh +git clone git@github.com:%REPOSITORY%.git +cd %NAME% +``` +(The variables wrapped in `%` will be filled in by the template cleanup) + +#### Set project organization and name in build.sbt + +The cleanup workflow will have attempted to provide sensible defaults for `ThisBuild / organization` and `name` in the `build.sbt`. +Feel free to use your text editor of choice to change them as you see fit. + +#### Clean up the README.md file + +Again, use you editor of choice to make the README specific to your project. + +#### Add a LICENSE file + +It is important to have a LICENSE for open source (or closed source) code. +This template repository has the Unlicense in order to allow users to add any license they want to derivative code. +The Unlicense is stripped when creating a repository from this template so that users do not accidentally unlicense their own work. + +For more information about a license, check out the [Github Docs](https://docs.github.com/en/free-pro-team@latest/github/building-a-strong-community/adding-a-license-to-a-repository). + +#### Commit your changes +```sh +git commit -m 'Starting %NAME%' +git push origin main +``` + +### Did it work? + +You should now have a working Chisel3 project. + +You can run the included test with: +```sh +sbt test +``` + +You should see a whole bunch of output that ends with something like the following lines +``` +[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 +[info] All tests passed. +[success] Total time: 5 s, completed Dec 16, 2020 12:18:44 PM +``` +If you see the above then... + +### It worked! + +You are ready to go. We have a few recommended practices and things to do. + +* Use packages and following conventions for [structure](https://www.scala-sbt.org/1.x/docs/Directories.html) and [naming](http://docs.scala-lang.org/style/naming-conventions.html) +* Package names should be clearly reflected in the testing hierarchy +* Build tests for all your work +* Read more about testing in SBT in the [SBT docs](https://www.scala-sbt.org/1.x/docs/Testing.html) +* This template includes a [test dependency](https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html#Per-configuration+dependencies) on [chiseltest](https://github.com/ucb-bar/chisel-testers2), this is a reasonable starting point for most tests + * You can remove this dependency in the build.sbt file if you want to +* Change the name of your project in the build.sbt file +* Change your README.md + +## Problems? Questions? + +Check out the [Chisel Users Community](https://www.chisel-lang.org/community.html) page for links to get in contact! diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..8ea3c70 --- /dev/null +++ b/build.sbt @@ -0,0 +1,25 @@ +// See README.md for license details. + +ThisBuild / scalaVersion := "2.13.8" +ThisBuild / version := "0.1.0" +ThisBuild / organization := "%ORGANIZATION%" + +val chiselVersion = "3.5.4" + +lazy val root = (project in file(".")) + .settings( + name := "%NAME%", + libraryDependencies ++= Seq( + "edu.berkeley.cs" %% "chisel3" % chiselVersion, + "edu.berkeley.cs" %% "chiseltest" % "0.5.4" % "test" + ), + scalacOptions ++= Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + "-P:chiselplugin:genBundleElements", + ), + addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full), + ) + diff --git a/build.sc b/build.sc new file mode 100644 index 0000000..4ceb137 --- /dev/null +++ b/build.sc @@ -0,0 +1,31 @@ +// import Mill dependency +import mill._ +import mill.define.Sources +import mill.modules.Util +import mill.scalalib.TestModule.ScalaTest +import scalalib._ +// support BSP +import mill.bsp._ + +object %NAME% extends SbtModule { m => + override def millSourcePath = os.pwd + override def scalaVersion = "2.13.8" + override def scalacOptions = Seq( + "-language:reflectiveCalls", + "-deprecation", + "-feature", + "-Xcheckinit", + "-P:chiselplugin:genBundleElements" + ) + override def ivyDeps = Agg( + ivy"edu.berkeley.cs::chisel3:3.5.4", + ) + override def scalacPluginIvyDeps = Agg( + ivy"edu.berkeley.cs:::chisel3-plugin:3.5.4", + ) + object test extends Tests with ScalaTest { + override def ivyDeps = m.ivyDeps() ++ Agg( + ivy"edu.berkeley.cs::chiseltest:0.5.4" + ) + } +} diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..9a19778 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.8.0 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..5708f81 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1 @@ +logLevel := Level.Warn diff --git a/src/main/scala/gcd/DecoupledGCD.scala b/src/main/scala/gcd/DecoupledGCD.scala new file mode 100644 index 0000000..1cd2993 --- /dev/null +++ b/src/main/scala/gcd/DecoupledGCD.scala @@ -0,0 +1,73 @@ +// See README.md for license details. + +package gcd + +import chisel3._ +import chisel3.util.Decoupled + +class GcdInputBundle(val w: Int) extends Bundle { + val value1 = UInt(w.W) + val value2 = UInt(w.W) +} + +class GcdOutputBundle(val w: Int) extends Bundle { + val value1 = UInt(w.W) + val value2 = UInt(w.W) + val gcd = UInt(w.W) +} + +/** + * Compute Gcd using subtraction method. + * Subtracts the smaller from the larger until register y is zero. + * value input register x is then the Gcd. + * Unless first input is zero then the Gcd is y. + * Can handle stalls on the producer or consumer side + */ +class DecoupledGcd(width: Int) extends Module { + val input = IO(Flipped(Decoupled(new GcdInputBundle(width)))) + val output = IO(Decoupled(new GcdOutputBundle(width))) + + val xInitial = Reg(UInt()) + val yInitial = Reg(UInt()) + val x = Reg(UInt()) + val y = Reg(UInt()) + val busy = RegInit(false.B) + val resultValid = RegInit(false.B) + + input.ready := ! busy + output.valid := resultValid + output.bits := DontCare + + when(busy) { + when(x > y) { + x := x - y + }.otherwise { + y := y - x + } + when(x === 0.U || y === 0.U) { + when(x === 0.U) { + output.bits.gcd := y + }.otherwise { + output.bits.gcd := x + } + + output.bits.value1 := xInitial + output.bits.value2 := yInitial + resultValid := true.B + + when(output.ready && resultValid) { + busy := false.B + resultValid := false.B + } + } + }.otherwise { + when(input.valid) { + val bundle = input.deq() + x := bundle.value1 + y := bundle.value2 + xInitial := bundle.value1 + yInitial := bundle.value2 + busy := true.B + } + } +} diff --git a/src/main/scala/gcd/GCD.scala b/src/main/scala/gcd/GCD.scala new file mode 100644 index 0000000..07e434c --- /dev/null +++ b/src/main/scala/gcd/GCD.scala @@ -0,0 +1,34 @@ +// See README.md for license details. + +package gcd + +import chisel3._ + +/** + * Compute GCD using subtraction method. + * Subtracts the smaller from the larger until register y is zero. + * value in register x is then the GCD + */ +class GCD extends Module { + val io = IO(new Bundle { + val value1 = Input(UInt(16.W)) + val value2 = Input(UInt(16.W)) + val loadingValues = Input(Bool()) + val outputGCD = Output(UInt(16.W)) + val outputValid = Output(Bool()) + }) + + val x = Reg(UInt()) + val y = Reg(UInt()) + + when(x > y) { x := x - y } + .otherwise { y := y - x } + + when(io.loadingValues) { + x := io.value1 + y := io.value2 + } + + io.outputGCD := x + io.outputValid := y === 0.U +} diff --git a/src/test/scala/gcd/GCDSpec.scala b/src/test/scala/gcd/GCDSpec.scala new file mode 100644 index 0000000..f9a27f1 --- /dev/null +++ b/src/test/scala/gcd/GCDSpec.scala @@ -0,0 +1,52 @@ +// See README.md for license details. + +package gcd + +import chisel3._ +import chiseltest._ +import org.scalatest.freespec.AnyFreeSpec +import chisel3.experimental.BundleLiterals._ + +/** + * This is a trivial example of how to run this Specification + * From within sbt use: + * {{{ + * testOnly gcd.GcdDecoupledTester + * }}} + * From a terminal shell use: + * {{{ + * sbt 'testOnly gcd.GcdDecoupledTester' + * }}} + */ +class GCDSpec extends AnyFreeSpec with ChiselScalatestTester { + + "Gcd should calculate proper greatest common denominator" in { + test(new DecoupledGcd(16)) { dut => + dut.input.initSource() + dut.input.setSourceClock(dut.clock) + dut.output.initSink() + dut.output.setSinkClock(dut.clock) + + val testValues = for { x <- 0 to 10; y <- 0 to 10} yield (x, y) + val inputSeq = testValues.map { case (x, y) => (new GcdInputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U) } + val resultSeq = testValues.map { case (x, y) => + (new GcdOutputBundle(16)).Lit(_.value1 -> x.U, _.value2 -> y.U, _.gcd -> BigInt(x).gcd(BigInt(y)).U) + } + + fork { + // push inputs into the calculator, stall for 11 cycles one third of the way + val (seq1, seq2) = inputSeq.splitAt(resultSeq.length / 3) + dut.input.enqueueSeq(seq1) + dut.clock.step(11) + dut.input.enqueueSeq(seq2) + }.fork { + // retrieve computations from the calculator, stall for 10 cycles one half of the way + val (seq1, seq2) = resultSeq.splitAt(resultSeq.length / 2) + dut.output.expectDequeueSeq(seq1) + dut.clock.step(10) + dut.output.expectDequeueSeq(seq2) + }.join() + + } + } +}