├── .gitignore ├── .mill-jvm-opts ├── .scalafmt.conf ├── build.sc ├── common.sc ├── configs ├── SDRAMControllerMain.json └── SDRAMControllerTestBenchMain.json ├── elaborator └── src │ ├── Elaborator.scala │ ├── SDRAMController.scala │ └── SDRAMControllerTestBench.scala ├── flake.lock ├── flake.nix ├── nix ├── overlay.nix ├── pkgs │ ├── add-determinism │ │ ├── Cargo.lock │ │ ├── default.nix │ │ └── marshalparser.nix │ ├── circt-full.nix │ ├── dependencies │ │ ├── _sources │ │ │ ├── generated.json │ │ │ └── generated.nix │ │ └── nvfetcher.toml │ ├── espresso.nix │ ├── mill-builder.nix │ ├── project-dependencies.nix │ └── vcs-fhs-env.nix └── sdram │ ├── default.nix │ ├── dpi-lib.nix │ ├── elaborate.nix │ ├── mlirbc.nix │ ├── rtl.nix │ ├── sdram.nix │ ├── vcs-wrapper.sh │ ├── vcs.nix │ └── verilated.nix ├── readme.md ├── sdramcontroller └── src │ ├── AXI4MasterAgent.scala │ ├── SDRAMController.scala │ ├── SDRAMControllerInterface.scala │ ├── SDRAMControllerRTL.scala │ └── SDRAMControllerTestBench.scala ├── sdramemu ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── common │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── plusarg.rs │ │ └── rtl_config.rs └── src │ ├── dpi.rs │ ├── drive.rs │ └── lib.rs ├── signal.rc ├── sysBusyPLog ├── .446698biyun-highfreq-32.conf └── .453318biyun-highfreq-32.conf └── sysProgressPLog └── .446552biyun-highfreq-32.conf /.gitignore: -------------------------------------------------------------------------------- 1 | .envrc 2 | .direnv/ 3 | .bloop 4 | .bsp/ 5 | .metals/ 6 | .vscode/ 7 | out/ 8 | result* 9 | /dependencies/ 10 | target/ 11 | novas.conf 12 | novas.rc 13 | sdram-sim-result/ 14 | verdiLog/ 15 | *.rc 16 | -------------------------------------------------------------------------------- /.mill-jvm-opts: -------------------------------------------------------------------------------- 1 | -Dhttp.proxyHost=172.24.6.3 2 | -Dhttp.proxyPort=8964 3 | -Dhttps.proxyHost=172.24.6.3 4 | -Dhttps.proxyPort=8964 5 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = "3.7.15" 2 | runner.dialect = scala213 3 | 4 | maxColumn = 120 5 | align = most 6 | continuationIndent.defnSite = 2 7 | assumeStandardLibraryStripMargin = true 8 | docstrings.style = SpaceAsterisk 9 | lineEndings = preserve 10 | includeCurlyBraceInSelectChains = false 11 | danglingParentheses.preset = true 12 | 13 | align.tokens.add = [ 14 | { 15 | code = ":" 16 | } 17 | ] 18 | 19 | newlines.beforeCurlyLambdaParams = never 20 | newlines.alwaysBeforeMultilineDef = false 21 | newlines.implicitParamListModifierForce = [before] 22 | 23 | verticalMultiline.atDefnSite = true 24 | 25 | optIn.annotationNewlines = true 26 | 27 | rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix] 28 | -------------------------------------------------------------------------------- /build.sc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | import mill._ 5 | import mill.scalalib._ 6 | import mill.define.{Command, TaskModule} 7 | import mill.scalalib.publish._ 8 | import mill.scalalib.scalafmt._ 9 | import mill.scalalib.TestModule.Utest 10 | import mill.util.Jvm 11 | import coursier.maven.MavenRepository 12 | import $file.dependencies.chisel.build 13 | import $file.dependencies.`chisel-interface`.common 14 | import $file.common 15 | 16 | object deps { 17 | val scalaVer = "2.13.14" 18 | val mainargs = ivy"com.lihaoyi::mainargs:0.5.0" 19 | val oslib = ivy"com.lihaoyi::os-lib:0.9.1" 20 | val upickle = ivy"com.lihaoyi::upickle:3.3.1" 21 | } 22 | 23 | object chisel extends Chisel 24 | 25 | trait Chisel extends millbuild.dependencies.chisel.build.Chisel { 26 | def crossValue = deps.scalaVer 27 | override def millSourcePath = os.pwd / "dependencies" / "chisel" 28 | } 29 | 30 | object axi4 extends AXI4 31 | trait AXI4 extends millbuild.dependencies.`chisel-interface`.common.AXI4Module { 32 | override def millSourcePath = 33 | os.pwd / "dependencies" / "chisel-interface" / "axi4" 34 | def scalaVersion = T(deps.scalaVer) 35 | 36 | def chiselModule = Some(chisel) 37 | def chiselPluginJar = T(Some(chisel.pluginModule.jar())) 38 | def chiselIvy = None 39 | def chiselPluginIvy = None 40 | def mainargsIvy: Dep = deps.mainargs 41 | } 42 | 43 | object dwbb extends DWBB 44 | trait DWBB extends millbuild.dependencies.`chisel-interface`.common.DWBBModule { 45 | override def millSourcePath = 46 | os.pwd / "dependencies" / "chisel-interface" / "dwbb" 47 | def scalaVersion = T(deps.scalaVer) 48 | 49 | def mainargsIvy = deps.mainargs 50 | 51 | def chiselModule = Some(chisel) 52 | def chiselPluginJar = T(Some(chisel.pluginModule.jar())) 53 | def chiselIvy = None 54 | def chiselPluginIvy = None 55 | } 56 | 57 | object sdram extends SDRAM 58 | trait SDRAM 59 | extends millbuild.dependencies.`chisel-interface`.common.SDRAMModule { 60 | override def millSourcePath = 61 | os.pwd / "dependencies" / "chisel-interface" / "sdram" 62 | def scalaVersion = deps.scalaVer 63 | 64 | def mainargsIvy = deps.mainargs 65 | 66 | def chiselModule = Some(chisel) 67 | def chiselPluginJar = T(Some(chisel.pluginModule.jar())) 68 | def chiselIvy = None 69 | def chiselPluginIvy = None 70 | } 71 | 72 | object sdramcontroller 73 | extends millbuild.common.SDRAMControllerModule 74 | with ScalafmtModule { 75 | def millSourcePath = os.pwd / "sdramcontroller" 76 | def scalaVersion = T(deps.scalaVer) 77 | def axi4Module = axi4 78 | def dwbbModule = dwbb 79 | def sdramModule = sdram 80 | def mainargsIvy = deps.mainargs 81 | 82 | def chiselModule = Some(chisel) 83 | def chiselPluginJar = T(Some(chisel.pluginModule.jar())) 84 | def chiselPluginIvy = None 85 | def chiselIvy = None 86 | } 87 | 88 | object elaborator extends Elaborator 89 | trait Elaborator extends millbuild.common.ElaboratorModule { 90 | def scalaVersion = T(deps.scalaVer) 91 | 92 | def panamaconverterModule = panamaconverter 93 | 94 | def circtInstallPath = 95 | T.input(PathRef(os.Path(T.ctx().env("CIRCT_INSTALL_PATH")))) 96 | 97 | def generators = Seq(sdramcontroller) 98 | 99 | def mainargsIvy = deps.mainargs 100 | 101 | def chiselModule = Some(chisel) 102 | def chiselPluginJar = T(Some(chisel.pluginModule.jar())) 103 | def chiselPluginIvy = None 104 | def chiselIvy = None 105 | } 106 | 107 | object panamaconverter extends PanamaConverter 108 | trait PanamaConverter extends millbuild.dependencies.chisel.build.PanamaConverter { 109 | def crossValue = deps.scalaVer 110 | 111 | override def millSourcePath = 112 | os.pwd / "dependencies" / "chisel" / "panamaconverter" 113 | 114 | def scalaVersion = T(deps.scalaVer) 115 | } 116 | -------------------------------------------------------------------------------- /common.sc: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | import mill._ 5 | import mill.scalalib._ 6 | 7 | trait HasChisel extends ScalaModule { 8 | // Define these for building chisel from source 9 | def chiselModule: Option[ScalaModule] 10 | 11 | override def moduleDeps = super.moduleDeps ++ chiselModule 12 | 13 | def chiselPluginJar: T[Option[PathRef]] 14 | 15 | override def scalacOptions = T( 16 | super.scalacOptions() ++ chiselPluginJar().map(path => s"-Xplugin:${path.path}") ++ Seq("-Ymacro-annotations") 17 | ) 18 | 19 | override def scalacPluginClasspath: T[Agg[PathRef]] = T(super.scalacPluginClasspath() ++ chiselPluginJar()) 20 | 21 | // Define these for building chisel from ivy 22 | def chiselIvy: Option[Dep] 23 | 24 | override def ivyDeps = T(super.ivyDeps() ++ chiselIvy) 25 | 26 | def chiselPluginIvy: Option[Dep] 27 | 28 | override def scalacPluginIvyDeps: T[Agg[Dep]] = T( 29 | super.scalacPluginIvyDeps() ++ chiselPluginIvy.map(Agg(_)).getOrElse(Agg.empty[Dep]) 30 | ) 31 | } 32 | 33 | trait SDRAMControllerModule extends HasChisel { 34 | // Use for elaboration. 35 | def mainargsIvy: Dep 36 | def dwbbModule: ScalaModule 37 | def axi4Module: ScalaModule 38 | def sdramModule: ScalaModule 39 | override def moduleDeps: Seq[JavaModule] = 40 | super.moduleDeps ++ Seq(sdramModule, axi4Module, dwbbModule) 41 | override def ivyDeps = T(super.ivyDeps() ++ Some(mainargsIvy)) 42 | } 43 | 44 | trait ElaboratorModule extends ScalaModule with HasChisel { 45 | def generators: Seq[ScalaModule] 46 | def panamaconverterModule: ScalaModule 47 | def circtInstallPath: T[PathRef] 48 | override def moduleDeps = super.moduleDeps ++ Seq(panamaconverterModule) ++ generators 49 | def mainargsIvy: Dep 50 | override def ivyDeps = T(super.ivyDeps() ++ Seq(mainargsIvy)) 51 | override def javacOptions = T(super.javacOptions() ++ Seq("--enable-preview", "--release", "21")) 52 | override def forkArgs: T[Seq[String]] = T( 53 | super.forkArgs() ++ Seq( 54 | "--enable-native-access=ALL-UNNAMED", 55 | "--enable-preview", 56 | s"-Djava.library.path=${circtInstallPath().path / "lib"}" 57 | ) 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /configs/SDRAMControllerMain.json: -------------------------------------------------------------------------------- 1 | { 2 | "axiParameter": { 3 | "idWidth": 4, 4 | "dataWidth": 32, 5 | "addrWidth": 32, 6 | "userReqWidth": 0, 7 | "userDataWidth": 0, 8 | "userRespWidth": 0, 9 | "hasAW": true, 10 | "hasW": true, 11 | "hasB": true, 12 | "hasAR": true, 13 | "hasR": true, 14 | "supportId": true, 15 | "supportRegion": false, 16 | "supportLen": true, 17 | "supportSize": true, 18 | "supportBurst": true, 19 | "supportLock": false, 20 | "supportCache": false, 21 | "supportQos": false, 22 | "supportStrb": true, 23 | "supportResp": false, 24 | "supportProt": false 25 | }, 26 | "sdramParameter": { 27 | "dataWidth": 16, 28 | "csWidth": 1 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /configs/SDRAMControllerTestBenchMain.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdramControllerParameter": { 3 | "axiParameter": { 4 | "idWidth": 4, 5 | "dataWidth": 32, 6 | "addrWidth": 32, 7 | "userReqWidth": 0, 8 | "userDataWidth": 0, 9 | "userRespWidth": 0, 10 | "hasAW": true, 11 | "hasW": true, 12 | "hasB": true, 13 | "hasAR": true, 14 | "hasR": true, 15 | "supportId": true, 16 | "supportRegion": false, 17 | "supportLen": true, 18 | "supportSize": true, 19 | "supportBurst": true, 20 | "supportLock": false, 21 | "supportCache": false, 22 | "supportQos": false, 23 | "supportStrb": true, 24 | "supportResp": false, 25 | "supportProt": false 26 | }, 27 | "sdramParameter": { 28 | "dataWidth": 16, 29 | "csWidth": 1 30 | } 31 | }, 32 | "testVerbatimParameter": { 33 | "useAsyncReset": false, 34 | "initFunctionName": "cosim_init", 35 | "dumpFunctionName": "dump_wave", 36 | "clockFlipTick": 5, 37 | "resetFlipTick": 100 38 | }, 39 | "timeout": 100000 40 | } 41 | -------------------------------------------------------------------------------- /elaborator/src/Elaborator.scala: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | // SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | package org.chipsalliance.chisel.elaborator 4 | 5 | import chisel3.RawModule 6 | import chisel3.experimental.{SerializableModule, SerializableModuleGenerator, SerializableModuleParameter} 7 | import mainargs.TokensReader 8 | 9 | import scala.reflect.runtime.universe 10 | import scala.reflect.runtime.universe.{runtimeMirror, typeOf} 11 | 12 | // TODO: this will be upstreamed to Chisel 13 | trait Elaborator { 14 | implicit object PathRead extends TokensReader.Simple[os.Path] { 15 | def shortName = "path" 16 | def read(strs: Seq[String]) = Right(os.Path(strs.head, os.pwd)) 17 | } 18 | 19 | def configImpl[P <: SerializableModuleParameter: universe.TypeTag]( 20 | parameter: P 21 | )( 22 | implicit rwP: upickle.default.Writer[P] 23 | ) = os.write.over( 24 | os.pwd / s"${getClass.getSimpleName.replace("$", "")}.json", 25 | upickle.default.write(parameter) 26 | ) 27 | 28 | def designImpl[M <: SerializableModule[P]: universe.TypeTag, P <: SerializableModuleParameter: universe.TypeTag]( 29 | parameter: os.Path, 30 | runFirtool: Boolean, 31 | targetDir: os.Path = os.pwd 32 | )( 33 | implicit 34 | rwP: upickle.default.Reader[P] 35 | ) = { 36 | var fir: firrtl.ir.Circuit = null 37 | val annos = Seq( 38 | new chisel3.stage.phases.Elaborate, 39 | new chisel3.stage.phases.Convert 40 | ).foldLeft( 41 | Seq( 42 | chisel3.stage.ChiselGeneratorAnnotation(() => 43 | SerializableModuleGenerator( 44 | runtimeMirror(getClass.getClassLoader) 45 | .runtimeClass(typeOf[M].typeSymbol.asClass) 46 | .asInstanceOf[Class[M]], 47 | upickle.default.read[P](os.read(parameter)) 48 | ).module().asInstanceOf[RawModule] 49 | ) 50 | ): firrtl.AnnotationSeq 51 | ) { case (annos, stage) => stage.transform(annos) } 52 | .flatMap { 53 | case firrtl.stage.FirrtlCircuitAnnotation(circuit) => 54 | fir = circuit 55 | None 56 | case _: chisel3.stage.DesignAnnotation[_] => None 57 | case _: chisel3.stage.ChiselCircuitAnnotation => None 58 | case a => Some(a) 59 | } 60 | val annoJsonFile = targetDir / s"${fir.main}.anno.json" 61 | val firFile = targetDir / s"${fir.main}.fir" 62 | val svFile = targetDir / s"${fir.main}.sv" 63 | os.write.over(firFile, fir.serialize) 64 | os.write.over( 65 | annoJsonFile, 66 | firrtl.annotations.JsonProtocol.serializeRecover(annos) 67 | ) 68 | if (runFirtool) { 69 | os.proc( 70 | "firtool", 71 | s"--annotation-file=${annoJsonFile}", 72 | s"${firFile}", 73 | s"-o", 74 | s"${svFile}", 75 | "--strip-debug-info", 76 | "--verification-flavor=sva", 77 | "--extract-test-code" 78 | ).call(os.pwd) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /elaborator/src/SDRAMController.scala: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | package oscc.sdramcontroller.elaborator 4 | 5 | import mainargs._ 6 | import org.chipsalliance.amba.axi4.bundle.AXI4BundleParameter 7 | import org.chipsalliance.chisel.elaborator.Elaborator 8 | import org.chipsalliance.jedec.sdram.SDRAMParameter 9 | import oscc.sdramcontroller.{SDRAMController, SDRAMControllerParameter} 10 | 11 | /** This is used for other tools, IP-XACT will also live here in the future. */ 12 | object SDRAMControllerMain extends Elaborator { 13 | 14 | @main 15 | def config(@arg(name = "parameter") parameter: SDRAMControllerParameterMain) = 16 | configImpl(parameter.convert) 17 | 18 | @main 19 | def design( 20 | @arg(name = "parameter") parameter: os.Path = os.pwd / s"${getClass.getSimpleName.replace("$", "")}.json", 21 | @arg(name = "run-firtool") runFirtool: mainargs.Flag, 22 | @arg(name = "target-dir") targetDir: os.Path 23 | ) = designImpl[SDRAMController, SDRAMControllerParameter](parameter, runFirtool.value, targetDir) 24 | 25 | implicit def AXI4BundleParameterMainParser: ParserForClass[AXI4BundleParameterMain] = 26 | ParserForClass[AXI4BundleParameterMain] 27 | 28 | implicit def SDRAMParameterMainParser: ParserForClass[SDRAMParameterMain] = 29 | ParserForClass[SDRAMParameterMain] 30 | 31 | implicit def SDRAMControllerParameterMainParser: ParserForClass[SDRAMControllerParameterMain] = 32 | ParserForClass[SDRAMControllerParameterMain] 33 | 34 | @main 35 | case class AXI4BundleParameterMain( 36 | @arg(name = "idWidth") idWidth: Int, 37 | @arg(name = "dataWidth") dataWidth: Int, 38 | @arg(name = "addrWidth") addrWidth: Int) { 39 | def convert: AXI4BundleParameter = AXI4BundleParameter( 40 | idWidth, 41 | dataWidth, 42 | addrWidth, 43 | userReqWidth = 0, 44 | userDataWidth = 0, 45 | userRespWidth = 0, 46 | hasAW = true, 47 | hasW = true, 48 | hasB = true, 49 | hasAR = true, 50 | hasR = true, 51 | supportId = true, 52 | supportRegion = false, 53 | supportLen = true, 54 | supportSize = true, 55 | supportBurst = true, 56 | supportLock = false, 57 | supportCache = false, 58 | supportQos = false, 59 | supportStrb = true, 60 | supportResp = false, 61 | supportProt = false 62 | ) 63 | } 64 | 65 | @main 66 | case class SDRAMParameterMain( 67 | @arg(name = "dataWidth") dataWidth: Int, 68 | @arg(name = "csWidth") csWidth: Int) { 69 | def convert: SDRAMParameter = SDRAMParameter( 70 | dataWidth, 71 | csWidth 72 | ) 73 | } 74 | 75 | @main 76 | case class SDRAMControllerParameterMain( 77 | @arg(name = "axiParameter") axiParameter: AXI4BundleParameterMain, 78 | @arg(name = "sdramParameter") sdramParameter: SDRAMParameterMain) { 79 | def convert: SDRAMControllerParameter = 80 | SDRAMControllerParameter(axiParameter.convert, sdramParameter.convert) 81 | } 82 | 83 | def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) 84 | } 85 | -------------------------------------------------------------------------------- /elaborator/src/SDRAMControllerTestBench.scala: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | package oscc.sdramcontroller.elaborator 4 | 5 | import mainargs._ 6 | import org.chipsalliance.amba.axi4.bundle.AXI4BundleParameter 7 | import org.chipsalliance.chisel.elaborator.Elaborator 8 | import org.chipsalliance.jedec.sdram.SDRAMParameter 9 | import oscc.sdramcontroller.TestVerbatimParameter 10 | import oscc.sdramcontroller.elaborator.SDRAMControllerMain._ 11 | 12 | import oscc.sdramcontroller.{SDRAMControllerTestBench, SDRAMControllerTestBenchParameter} 13 | 14 | /** This is used for other tools, IP-XACT will also live here in the future. */ 15 | object SDRAMControllerTestBenchMain extends Elaborator { 16 | @main 17 | def config(@arg(name = "parameter") parameter: SDRAMControllerTestBenchParameterMain) = 18 | configImpl(parameter.convert) 19 | 20 | @main 21 | def design( 22 | @arg(name = "parameter") parameter: os.Path = os.pwd / s"${getClass.getSimpleName.replace("$", "")}.json", 23 | @arg(name = "run-firtool") runFirtool: mainargs.Flag, 24 | @arg(name = "target-dir") targetDir: os.Path 25 | ) = designImpl[SDRAMControllerTestBench, SDRAMControllerTestBenchParameter]( 26 | parameter, 27 | runFirtool.value, 28 | targetDir 29 | ) 30 | 31 | implicit def TestVerbatimParameterMainParser: ParserForClass[TestVerbatimParameterMain] = 32 | ParserForClass[TestVerbatimParameterMain] 33 | 34 | implicit def SDRAMControllerTestBenchParameterMainParser: ParserForClass[SDRAMControllerTestBenchParameterMain] = 35 | ParserForClass[SDRAMControllerTestBenchParameterMain] 36 | 37 | case class TestVerbatimParameterMain( 38 | @arg(name = "useAsyncReset") useAsyncReset: Boolean, 39 | @arg(name = "initFunctionName") initFunctionName: String, 40 | @arg(name = "dumpFunctionName") dumpFunctionName: String, 41 | @arg(name = "clockFlipTick") clockFlipTick: Int, 42 | @arg(name = "resetFlipTick") resetFlipTick: Int) { 43 | def convert: TestVerbatimParameter = TestVerbatimParameter( 44 | useAsyncReset: Boolean, 45 | initFunctionName: String, 46 | dumpFunctionName: String, 47 | clockFlipTick: Int, 48 | resetFlipTick: Int 49 | ) 50 | } 51 | case class SDRAMControllerTestBenchParameterMain( 52 | @arg(name = "sdramControllerParameter") sdramControllerParameter: SDRAMControllerParameterMain, 53 | @arg(name = "testVerbatimParameter") testVerbatimParameter: TestVerbatimParameterMain, 54 | @arg(name = "timeout") timeout: Int) { 55 | def convert: SDRAMControllerTestBenchParameter = 56 | SDRAMControllerTestBenchParameter(sdramControllerParameter.convert, testVerbatimParameter.convert, timeout) 57 | } 58 | 59 | def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) 60 | } 61 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1710146030, 9 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1724819573, 24 | "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixos-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | { 4 | description = "Chisel Nix"; 5 | 6 | inputs = { 7 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 8 | flake-utils.url = "github:numtide/flake-utils"; 9 | }; 10 | 11 | outputs = inputs@{ self, nixpkgs, flake-utils }: 12 | let overlay = import ./nix/overlay.nix; 13 | in { 14 | # System-independent attr 15 | inherit inputs; 16 | overlays.default = overlay; 17 | } // flake-utils.lib.eachDefaultSystem (system: 18 | let 19 | pkgs = import nixpkgs { 20 | overlays = [ overlay ]; 21 | inherit system; 22 | }; 23 | in 24 | { 25 | formatter = pkgs.nixpkgs-fmt; 26 | legacyPackages = pkgs; 27 | devShells.default = pkgs.mkShell ({ 28 | inputsFrom = [ pkgs.sdram.sdram-compiled pkgs.sdram.tb-dpi-lib ]; 29 | nativeBuildInputs = [ pkgs.cargo pkgs.rustfmt pkgs.rust-analyzer pkgs.clippy pkgs.nixfmt-rfc-style pkgs.nixpkgs-fmt ]; 30 | RUST_SRC_PATH = 31 | "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; 32 | } // pkgs.sdram.tb-dpi-lib.env); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /nix/overlay.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | final: prev: { 5 | espresso = final.callPackage ./pkgs/espresso.nix { }; 6 | mill = 7 | let jre = final.jdk21; 8 | in (prev.mill.override { inherit jre; }).overrideAttrs 9 | (_: { passthru = { inherit jre; }; }); 10 | fetchMillDeps = final.callPackage ./pkgs/mill-builder.nix { }; 11 | circt-full = final.callPackage ./pkgs/circt-full.nix { }; 12 | add-determinism = 13 | final.callPackage ./pkgs/add-determinism { }; # faster strip-undetereminism 14 | 15 | # Using VCS need to set VC_STATIC_HOME and SNPSLMD_LICENSE_FILE to impure env, and add sandbox dir to VC_STATIC_HOME 16 | # Remember to add "--impure" flag for nix to read this value from environment 17 | vcStaticHome = builtins.getEnv "VC_STATIC_HOME"; 18 | snpslmdLicenseFile = builtins.getEnv "SNPSLMD_LICENSE_FILE"; 19 | dwbb = builtins.getEnv "DWBB_DIR"; 20 | vcs-fhs-env = assert final.lib.assertMsg (final.vcStaticHome != "") 21 | "You forget to set VC_STATIC_HOME or the '--impure' flag"; 22 | assert final.lib.assertMsg (final.snpslmdLicenseFile != "") 23 | "You forget to set SNPSLMD_LICENSE_FILE or the '--impure' flag"; 24 | final.callPackage ./pkgs/vcs-fhs-env.nix { }; 25 | 26 | projectDependencies = final.callPackage ./pkgs/project-dependencies.nix { }; 27 | 28 | sdram = final.callPackage ./sdram { }; 29 | } 30 | -------------------------------------------------------------------------------- /nix/pkgs/add-determinism/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "add-determinism" 7 | version = "0.2.0" 8 | dependencies = [ 9 | "anyhow", 10 | "chrono", 11 | "clap", 12 | "ctor", 13 | "indoc", 14 | "log", 15 | "nix", 16 | "pyo3", 17 | "regex", 18 | "tempfile", 19 | "time", 20 | "walkdir", 21 | "zip", 22 | ] 23 | 24 | [[package]] 25 | name = "adler" 26 | version = "1.0.2" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 29 | 30 | [[package]] 31 | name = "aho-corasick" 32 | version = "1.1.3" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 35 | dependencies = [ 36 | "memchr", 37 | ] 38 | 39 | [[package]] 40 | name = "android-tzdata" 41 | version = "0.1.1" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 44 | 45 | [[package]] 46 | name = "android_system_properties" 47 | version = "0.1.5" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 50 | dependencies = [ 51 | "libc", 52 | ] 53 | 54 | [[package]] 55 | name = "anstream" 56 | version = "0.6.14" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 59 | dependencies = [ 60 | "anstyle", 61 | "anstyle-parse", 62 | "anstyle-query", 63 | "anstyle-wincon", 64 | "colorchoice", 65 | "is_terminal_polyfill", 66 | "utf8parse", 67 | ] 68 | 69 | [[package]] 70 | name = "anstyle" 71 | version = "1.0.7" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 74 | 75 | [[package]] 76 | name = "anstyle-parse" 77 | version = "0.2.4" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 80 | dependencies = [ 81 | "utf8parse", 82 | ] 83 | 84 | [[package]] 85 | name = "anstyle-query" 86 | version = "1.0.3" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" 89 | dependencies = [ 90 | "windows-sys", 91 | ] 92 | 93 | [[package]] 94 | name = "anstyle-wincon" 95 | version = "3.0.3" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 98 | dependencies = [ 99 | "anstyle", 100 | "windows-sys", 101 | ] 102 | 103 | [[package]] 104 | name = "anyhow" 105 | version = "1.0.83" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" 108 | 109 | [[package]] 110 | name = "autocfg" 111 | version = "1.3.0" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 114 | 115 | [[package]] 116 | name = "bitflags" 117 | version = "2.5.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 120 | 121 | [[package]] 122 | name = "bumpalo" 123 | version = "3.16.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 126 | 127 | [[package]] 128 | name = "byteorder" 129 | version = "1.5.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 132 | 133 | [[package]] 134 | name = "cc" 135 | version = "1.0.97" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" 138 | 139 | [[package]] 140 | name = "cfg-if" 141 | version = "1.0.0" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 144 | 145 | [[package]] 146 | name = "cfg_aliases" 147 | version = "0.1.1" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" 150 | 151 | [[package]] 152 | name = "chrono" 153 | version = "0.4.38" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 156 | dependencies = [ 157 | "android-tzdata", 158 | "iana-time-zone", 159 | "js-sys", 160 | "num-traits", 161 | "wasm-bindgen", 162 | "windows-targets", 163 | ] 164 | 165 | [[package]] 166 | name = "clap" 167 | version = "4.5.4" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" 170 | dependencies = [ 171 | "clap_builder", 172 | "clap_derive", 173 | ] 174 | 175 | [[package]] 176 | name = "clap_builder" 177 | version = "4.5.2" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 180 | dependencies = [ 181 | "anstream", 182 | "anstyle", 183 | "clap_lex", 184 | "strsim", 185 | ] 186 | 187 | [[package]] 188 | name = "clap_derive" 189 | version = "4.5.4" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" 192 | dependencies = [ 193 | "heck 0.5.0", 194 | "proc-macro2", 195 | "quote", 196 | "syn 2.0.63", 197 | ] 198 | 199 | [[package]] 200 | name = "clap_lex" 201 | version = "0.7.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 204 | 205 | [[package]] 206 | name = "colorchoice" 207 | version = "1.0.1" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 210 | 211 | [[package]] 212 | name = "core-foundation-sys" 213 | version = "0.8.6" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 216 | 217 | [[package]] 218 | name = "crc32fast" 219 | version = "1.4.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" 222 | dependencies = [ 223 | "cfg-if", 224 | ] 225 | 226 | [[package]] 227 | name = "crossbeam-utils" 228 | version = "0.8.19" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" 231 | 232 | [[package]] 233 | name = "ctor" 234 | version = "0.1.26" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" 237 | dependencies = [ 238 | "quote", 239 | "syn 1.0.109", 240 | ] 241 | 242 | [[package]] 243 | name = "deranged" 244 | version = "0.3.11" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 247 | dependencies = [ 248 | "powerfmt", 249 | ] 250 | 251 | [[package]] 252 | name = "errno" 253 | version = "0.3.9" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 256 | dependencies = [ 257 | "libc", 258 | "windows-sys", 259 | ] 260 | 261 | [[package]] 262 | name = "fastrand" 263 | version = "2.1.0" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 266 | 267 | [[package]] 268 | name = "flate2" 269 | version = "1.0.30" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" 272 | dependencies = [ 273 | "crc32fast", 274 | "libz-sys", 275 | "miniz_oxide", 276 | ] 277 | 278 | [[package]] 279 | name = "heck" 280 | version = "0.4.1" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 283 | 284 | [[package]] 285 | name = "heck" 286 | version = "0.5.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 289 | 290 | [[package]] 291 | name = "iana-time-zone" 292 | version = "0.1.60" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 295 | dependencies = [ 296 | "android_system_properties", 297 | "core-foundation-sys", 298 | "iana-time-zone-haiku", 299 | "js-sys", 300 | "wasm-bindgen", 301 | "windows-core", 302 | ] 303 | 304 | [[package]] 305 | name = "iana-time-zone-haiku" 306 | version = "0.1.2" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 309 | dependencies = [ 310 | "cc", 311 | ] 312 | 313 | [[package]] 314 | name = "indoc" 315 | version = "2.0.5" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" 318 | 319 | [[package]] 320 | name = "is_terminal_polyfill" 321 | version = "1.70.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 324 | 325 | [[package]] 326 | name = "js-sys" 327 | version = "0.3.69" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 330 | dependencies = [ 331 | "wasm-bindgen", 332 | ] 333 | 334 | [[package]] 335 | name = "libc" 336 | version = "0.2.154" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" 339 | 340 | [[package]] 341 | name = "libz-sys" 342 | version = "1.1.16" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" 345 | dependencies = [ 346 | "cc", 347 | "pkg-config", 348 | "vcpkg", 349 | ] 350 | 351 | [[package]] 352 | name = "linux-raw-sys" 353 | version = "0.4.13" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 356 | 357 | [[package]] 358 | name = "lock_api" 359 | version = "0.4.12" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 362 | dependencies = [ 363 | "autocfg", 364 | "scopeguard", 365 | ] 366 | 367 | [[package]] 368 | name = "log" 369 | version = "0.4.21" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 372 | 373 | [[package]] 374 | name = "memchr" 375 | version = "2.7.2" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 378 | 379 | [[package]] 380 | name = "memoffset" 381 | version = "0.9.1" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 384 | dependencies = [ 385 | "autocfg", 386 | ] 387 | 388 | [[package]] 389 | name = "miniz_oxide" 390 | version = "0.7.2" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 393 | dependencies = [ 394 | "adler", 395 | ] 396 | 397 | [[package]] 398 | name = "nix" 399 | version = "0.28.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" 402 | dependencies = [ 403 | "bitflags", 404 | "cfg-if", 405 | "cfg_aliases", 406 | "libc", 407 | "memoffset", 408 | ] 409 | 410 | [[package]] 411 | name = "num-conv" 412 | version = "0.1.0" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 415 | 416 | [[package]] 417 | name = "num-traits" 418 | version = "0.2.19" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 421 | dependencies = [ 422 | "autocfg", 423 | ] 424 | 425 | [[package]] 426 | name = "once_cell" 427 | version = "1.19.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 430 | 431 | [[package]] 432 | name = "parking_lot" 433 | version = "0.12.2" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" 436 | dependencies = [ 437 | "lock_api", 438 | "parking_lot_core", 439 | ] 440 | 441 | [[package]] 442 | name = "parking_lot_core" 443 | version = "0.9.10" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 446 | dependencies = [ 447 | "cfg-if", 448 | "libc", 449 | "redox_syscall", 450 | "smallvec", 451 | "windows-targets", 452 | ] 453 | 454 | [[package]] 455 | name = "pkg-config" 456 | version = "0.3.30" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 459 | 460 | [[package]] 461 | name = "portable-atomic" 462 | version = "1.6.0" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" 465 | 466 | [[package]] 467 | name = "powerfmt" 468 | version = "0.2.0" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 471 | 472 | [[package]] 473 | name = "proc-macro2" 474 | version = "1.0.82" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" 477 | dependencies = [ 478 | "unicode-ident", 479 | ] 480 | 481 | [[package]] 482 | name = "pyo3" 483 | version = "0.20.3" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" 486 | dependencies = [ 487 | "cfg-if", 488 | "indoc", 489 | "libc", 490 | "memoffset", 491 | "parking_lot", 492 | "portable-atomic", 493 | "pyo3-build-config", 494 | "pyo3-ffi", 495 | "pyo3-macros", 496 | "unindent", 497 | ] 498 | 499 | [[package]] 500 | name = "pyo3-build-config" 501 | version = "0.20.3" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" 504 | dependencies = [ 505 | "once_cell", 506 | "target-lexicon", 507 | ] 508 | 509 | [[package]] 510 | name = "pyo3-ffi" 511 | version = "0.20.3" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" 514 | dependencies = [ 515 | "libc", 516 | "pyo3-build-config", 517 | ] 518 | 519 | [[package]] 520 | name = "pyo3-macros" 521 | version = "0.20.3" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" 524 | dependencies = [ 525 | "proc-macro2", 526 | "pyo3-macros-backend", 527 | "quote", 528 | "syn 2.0.63", 529 | ] 530 | 531 | [[package]] 532 | name = "pyo3-macros-backend" 533 | version = "0.20.3" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" 536 | dependencies = [ 537 | "heck 0.4.1", 538 | "proc-macro2", 539 | "pyo3-build-config", 540 | "quote", 541 | "syn 2.0.63", 542 | ] 543 | 544 | [[package]] 545 | name = "quote" 546 | version = "1.0.36" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 549 | dependencies = [ 550 | "proc-macro2", 551 | ] 552 | 553 | [[package]] 554 | name = "redox_syscall" 555 | version = "0.5.1" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" 558 | dependencies = [ 559 | "bitflags", 560 | ] 561 | 562 | [[package]] 563 | name = "regex" 564 | version = "1.10.4" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" 567 | dependencies = [ 568 | "aho-corasick", 569 | "memchr", 570 | "regex-automata", 571 | "regex-syntax", 572 | ] 573 | 574 | [[package]] 575 | name = "regex-automata" 576 | version = "0.4.6" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 579 | dependencies = [ 580 | "aho-corasick", 581 | "memchr", 582 | "regex-syntax", 583 | ] 584 | 585 | [[package]] 586 | name = "regex-syntax" 587 | version = "0.8.3" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" 590 | 591 | [[package]] 592 | name = "rustix" 593 | version = "0.38.34" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 596 | dependencies = [ 597 | "bitflags", 598 | "errno", 599 | "libc", 600 | "linux-raw-sys", 601 | "windows-sys", 602 | ] 603 | 604 | [[package]] 605 | name = "same-file" 606 | version = "1.0.6" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 609 | dependencies = [ 610 | "winapi-util", 611 | ] 612 | 613 | [[package]] 614 | name = "scopeguard" 615 | version = "1.2.0" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 618 | 619 | [[package]] 620 | name = "serde" 621 | version = "1.0.201" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" 624 | dependencies = [ 625 | "serde_derive", 626 | ] 627 | 628 | [[package]] 629 | name = "serde_derive" 630 | version = "1.0.201" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" 633 | dependencies = [ 634 | "proc-macro2", 635 | "quote", 636 | "syn 2.0.63", 637 | ] 638 | 639 | [[package]] 640 | name = "smallvec" 641 | version = "1.13.2" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 644 | 645 | [[package]] 646 | name = "strsim" 647 | version = "0.11.1" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 650 | 651 | [[package]] 652 | name = "syn" 653 | version = "1.0.109" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 656 | dependencies = [ 657 | "proc-macro2", 658 | "quote", 659 | "unicode-ident", 660 | ] 661 | 662 | [[package]] 663 | name = "syn" 664 | version = "2.0.63" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" 667 | dependencies = [ 668 | "proc-macro2", 669 | "quote", 670 | "unicode-ident", 671 | ] 672 | 673 | [[package]] 674 | name = "target-lexicon" 675 | version = "0.12.14" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" 678 | 679 | [[package]] 680 | name = "tempfile" 681 | version = "3.10.1" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 684 | dependencies = [ 685 | "cfg-if", 686 | "fastrand", 687 | "rustix", 688 | "windows-sys", 689 | ] 690 | 691 | [[package]] 692 | name = "time" 693 | version = "0.3.36" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 696 | dependencies = [ 697 | "deranged", 698 | "num-conv", 699 | "powerfmt", 700 | "serde", 701 | "time-core", 702 | ] 703 | 704 | [[package]] 705 | name = "time-core" 706 | version = "0.1.2" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 709 | 710 | [[package]] 711 | name = "unicode-ident" 712 | version = "1.0.12" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 715 | 716 | [[package]] 717 | name = "unindent" 718 | version = "0.2.3" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" 721 | 722 | [[package]] 723 | name = "utf8parse" 724 | version = "0.2.1" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 727 | 728 | [[package]] 729 | name = "vcpkg" 730 | version = "0.2.15" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 733 | 734 | [[package]] 735 | name = "walkdir" 736 | version = "2.5.0" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 739 | dependencies = [ 740 | "same-file", 741 | "winapi-util", 742 | ] 743 | 744 | [[package]] 745 | name = "wasm-bindgen" 746 | version = "0.2.92" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 749 | dependencies = [ 750 | "cfg-if", 751 | "wasm-bindgen-macro", 752 | ] 753 | 754 | [[package]] 755 | name = "wasm-bindgen-backend" 756 | version = "0.2.92" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 759 | dependencies = [ 760 | "bumpalo", 761 | "log", 762 | "once_cell", 763 | "proc-macro2", 764 | "quote", 765 | "syn 2.0.63", 766 | "wasm-bindgen-shared", 767 | ] 768 | 769 | [[package]] 770 | name = "wasm-bindgen-macro" 771 | version = "0.2.92" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 774 | dependencies = [ 775 | "quote", 776 | "wasm-bindgen-macro-support", 777 | ] 778 | 779 | [[package]] 780 | name = "wasm-bindgen-macro-support" 781 | version = "0.2.92" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 784 | dependencies = [ 785 | "proc-macro2", 786 | "quote", 787 | "syn 2.0.63", 788 | "wasm-bindgen-backend", 789 | "wasm-bindgen-shared", 790 | ] 791 | 792 | [[package]] 793 | name = "wasm-bindgen-shared" 794 | version = "0.2.92" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 797 | 798 | [[package]] 799 | name = "winapi-util" 800 | version = "0.1.8" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" 803 | dependencies = [ 804 | "windows-sys", 805 | ] 806 | 807 | [[package]] 808 | name = "windows-core" 809 | version = "0.52.0" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 812 | dependencies = [ 813 | "windows-targets", 814 | ] 815 | 816 | [[package]] 817 | name = "windows-sys" 818 | version = "0.52.0" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 821 | dependencies = [ 822 | "windows-targets", 823 | ] 824 | 825 | [[package]] 826 | name = "windows-targets" 827 | version = "0.52.5" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 830 | dependencies = [ 831 | "windows_aarch64_gnullvm", 832 | "windows_aarch64_msvc", 833 | "windows_i686_gnu", 834 | "windows_i686_gnullvm", 835 | "windows_i686_msvc", 836 | "windows_x86_64_gnu", 837 | "windows_x86_64_gnullvm", 838 | "windows_x86_64_msvc", 839 | ] 840 | 841 | [[package]] 842 | name = "windows_aarch64_gnullvm" 843 | version = "0.52.5" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 846 | 847 | [[package]] 848 | name = "windows_aarch64_msvc" 849 | version = "0.52.5" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 852 | 853 | [[package]] 854 | name = "windows_i686_gnu" 855 | version = "0.52.5" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 858 | 859 | [[package]] 860 | name = "windows_i686_gnullvm" 861 | version = "0.52.5" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 864 | 865 | [[package]] 866 | name = "windows_i686_msvc" 867 | version = "0.52.5" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 870 | 871 | [[package]] 872 | name = "windows_x86_64_gnu" 873 | version = "0.52.5" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 876 | 877 | [[package]] 878 | name = "windows_x86_64_gnullvm" 879 | version = "0.52.5" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 882 | 883 | [[package]] 884 | name = "windows_x86_64_msvc" 885 | version = "0.52.5" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 888 | 889 | [[package]] 890 | name = "zip" 891 | version = "0.6.6" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" 894 | dependencies = [ 895 | "byteorder", 896 | "crc32fast", 897 | "crossbeam-utils", 898 | "flate2", 899 | "time", 900 | ] 901 | -------------------------------------------------------------------------------- /nix/pkgs/add-determinism/default.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib 5 | , rustPlatform 6 | , fetchFromGitHub 7 | , pkg-config 8 | , zlib 9 | , python3 10 | , cargoLockFile ? ./Cargo.lock 11 | , ... 12 | }@args: 13 | 14 | let 15 | marshalparser = args.marshalparser or python3.pkgs.callPackage ./marshalparser.nix { }; 16 | pyEnv = python3.withPackages (ps: [ marshalparser ]); 17 | in 18 | rustPlatform.buildRustPackage { 19 | pname = "add-determinism"; 20 | version = "unstable-2024-05-11"; 21 | 22 | src = fetchFromGitHub { 23 | owner = "keszybz"; 24 | repo = "add-determinism"; 25 | rev = "f27f0ac8899876d0e3ad36cd4450f51bf6fa3195"; 26 | hash = "sha256-a4PIiQ9T4cTUv7Y4nMjJB+sWLBoOi4ptQF5ApgykO4Y="; 27 | }; 28 | 29 | # this project has no Cargo.lock now 30 | cargoLock = { 31 | lockFile = cargoLockFile; 32 | }; 33 | 34 | postPatch = '' 35 | ln -s ${cargoLockFile} Cargo.lock 36 | ''; 37 | 38 | passthru = { inherit pyEnv marshalparser; }; 39 | 40 | nativeBuildInputs = [ 41 | pyEnv 42 | pkg-config 43 | ]; 44 | 45 | propagatedBuildInputs = [ pyEnv ]; 46 | 47 | buildInputs = [ 48 | zlib 49 | ]; 50 | 51 | meta = with lib; { 52 | description = "Build postprocessor to reset metadata fields for build reproducibility"; 53 | homepage = "https://github.com/keszybz/add-determinism"; 54 | license = licenses.gpl3Only; 55 | mainProgram = "add-determinism"; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /nix/pkgs/add-determinism/marshalparser.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib 5 | , python3 6 | , fetchPypi 7 | }: 8 | 9 | python3.pkgs.buildPythonPackage rec { 10 | pname = "marshalparser"; 11 | version = "0.3.4"; 12 | pyproject = true; 13 | 14 | src = fetchPypi { 15 | inherit pname version; 16 | hash = "sha256-Zk4AMCG3Y52Ghq1yykLidujGiRU3v8eDM7f/s6QsGqI="; 17 | }; 18 | 19 | nativeBuildInputs = [ 20 | python3.pkgs.setuptools 21 | python3.pkgs.wheel 22 | ]; 23 | 24 | passthru.optional-dependencies = with python3.pkgs; { 25 | test = [ pytest ]; 26 | }; 27 | 28 | pythonImportsCheck = [ "marshalparser" ]; 29 | 30 | meta = with lib; { 31 | description = "Parser for byte-cache .pyc files"; 32 | homepage = "https://pypi.org/project/marshalparser/"; 33 | license = licenses.mit; 34 | mainProgram = "marshalparser"; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /nix/pkgs/circt-full.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { symlinkJoin, circt }: 5 | symlinkJoin { 6 | name = "circt-full"; 7 | paths = [ 8 | circt 9 | circt.lib 10 | circt.dev 11 | 12 | circt.llvm 13 | circt.llvm.lib 14 | circt.llvm.dev 15 | ]; 16 | 17 | inherit (circt) meta; 18 | } 19 | -------------------------------------------------------------------------------- /nix/pkgs/dependencies/_sources/generated.json: -------------------------------------------------------------------------------- 1 | { 2 | "chisel": { 3 | "cargoLocks": null, 4 | "date": null, 5 | "extract": null, 6 | "name": "chisel", 7 | "passthru": null, 8 | "pinned": false, 9 | "src": { 10 | "deepClone": false, 11 | "fetchSubmodules": false, 12 | "leaveDotGit": false, 13 | "name": null, 14 | "owner": "chipsalliance", 15 | "repo": "chisel", 16 | "rev": "f347914dee389cebbe48ac4ef2e350e5ac1d267a", 17 | "sha256": "sha256-4sdVOhXt2Y4pmzLpImi+jvpi2exJ5f0vuN+iLnueESk=", 18 | "type": "github" 19 | }, 20 | "version": "f347914dee389cebbe48ac4ef2e350e5ac1d267a" 21 | }, 22 | "chisel-interface": { 23 | "cargoLocks": null, 24 | "date": "2024-09-02", 25 | "extract": null, 26 | "name": "chisel-interface", 27 | "passthru": null, 28 | "pinned": false, 29 | "src": { 30 | "deepClone": false, 31 | "fetchSubmodules": false, 32 | "leaveDotGit": false, 33 | "name": null, 34 | "owner": "chipsalliance", 35 | "repo": "chisel-interface", 36 | "rev": "bc958139345d327e7dc98c8f9f689b914a8fa2fb", 37 | "sha256": "sha256-TH7ZzZwglaZ98roLZqdAKTV3emIgWo5/tR9xIJA51BU=", 38 | "type": "github" 39 | }, 40 | "version": "bc958139345d327e7dc98c8f9f689b914a8fa2fb" 41 | } 42 | } -------------------------------------------------------------------------------- /nix/pkgs/dependencies/_sources/generated.nix: -------------------------------------------------------------------------------- 1 | # This file was generated by nvfetcher, please do not modify it manually. 2 | { fetchgit, fetchurl, fetchFromGitHub, dockerTools }: 3 | { 4 | chisel = { 5 | pname = "chisel"; 6 | version = "f347914dee389cebbe48ac4ef2e350e5ac1d267a"; 7 | src = fetchFromGitHub { 8 | owner = "chipsalliance"; 9 | repo = "chisel"; 10 | rev = "f347914dee389cebbe48ac4ef2e350e5ac1d267a"; 11 | fetchSubmodules = false; 12 | sha256 = "sha256-4sdVOhXt2Y4pmzLpImi+jvpi2exJ5f0vuN+iLnueESk="; 13 | }; 14 | }; 15 | chisel-interface = { 16 | pname = "chisel-interface"; 17 | version = "bc958139345d327e7dc98c8f9f689b914a8fa2fb"; 18 | src = fetchFromGitHub { 19 | owner = "chipsalliance"; 20 | repo = "chisel-interface"; 21 | rev = "bc958139345d327e7dc98c8f9f689b914a8fa2fb"; 22 | fetchSubmodules = false; 23 | sha256 = "sha256-TH7ZzZwglaZ98roLZqdAKTV3emIgWo5/tR9xIJA51BU="; 24 | }; 25 | date = "2024-09-02"; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /nix/pkgs/dependencies/nvfetcher.toml: -------------------------------------------------------------------------------- 1 | [chisel] 2 | src.manual = "f347914dee389cebbe48ac4ef2e350e5ac1d267a" 3 | fetch.github = "chipsalliance/chisel" 4 | 5 | [chisel-interface] 6 | src.git = "https://github.com/chipsalliance/chisel-interface" 7 | src.branch = "sdram" 8 | fetch.github = "chipsalliance/chisel-interface" 9 | -------------------------------------------------------------------------------- /nix/pkgs/espresso.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { stdenv 5 | , fetchFromGitHub 6 | , cmake 7 | , ninja 8 | , version ? "2.4" 9 | , srcHash ? "sha256-z5By57VbmIt4sgRgvECnLbZklnDDWUA6fyvWVyXUzsI=" 10 | }: 11 | stdenv.mkDerivation { 12 | pname = "espresso"; 13 | inherit version; 14 | nativeBuildInputs = [ cmake ninja ]; 15 | src = fetchFromGitHub { 16 | owner = "chipsalliance"; 17 | repo = "espresso"; 18 | rev = "v${version}"; 19 | hash = srcHash; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /nix/pkgs/mill-builder.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { stdenvNoCC, mill, writeText, makeSetupHook, runCommand, lib }: 5 | 6 | { name, src, millDepsHash, ... }@args: 7 | 8 | let 9 | mill-rt-version = lib.head (lib.splitString "+" mill.jre.version); 10 | self = stdenvNoCC.mkDerivation ({ 11 | name = "${name}-mill-deps"; 12 | inherit src; 13 | 14 | nativeBuildInputs = [ 15 | mill 16 | ] ++ (args.nativeBuildInputs or [ ]); 17 | 18 | impureEnvVars = [ "JAVA_OPTS" ]; 19 | 20 | buildPhase = '' 21 | runHook preBuild 22 | export JAVA_OPTS="-Duser.home=$TMPDIR $JAVA_OPTS" 23 | 24 | # Use "https://repo1.maven.org/maven2/" only to keep dependencies integrity 25 | export COURSIER_REPOSITORIES="central" 26 | 27 | mill -i __.prepareOffline 28 | mill -i __.scalaCompilerClasspath 29 | runHook postBuild 30 | ''; 31 | 32 | installPhase = '' 33 | runHook preInstall 34 | mkdir -p $out/.cache 35 | mv $TMPDIR/.cache/coursier $out/.cache/coursier 36 | runHook postInstall 37 | ''; 38 | 39 | outputHashAlgo = "sha256"; 40 | outputHashMode = "recursive"; 41 | outputHash = millDepsHash; 42 | 43 | dontShrink = true; 44 | dontPatchELF = true; 45 | 46 | passthru.setupHook = makeSetupHook 47 | { 48 | name = "mill-setup-hook.sh"; 49 | propagatedBuildInputs = [ mill ]; 50 | } 51 | (writeText "mill-setup-hook" '' 52 | setupMillCache() { 53 | local tmpdir=$(mktemp -d) 54 | export JAVA_OPTS="$JAVA_OPTS -Duser.home=$tmpdir" 55 | 56 | mkdir -p "$tmpdir"/.cache "$tmpdir/.mill/ammonite" 57 | 58 | cp -r "${self}"/.cache/coursier "$tmpdir"/.cache/ 59 | touch "$tmpdir/.mill/ammonite/rt-${mill-rt-version}.jar" 60 | 61 | echo "JAVA HOME dir set to $tmpdir" 62 | } 63 | 64 | postUnpackHooks+=(setupMillCache) 65 | ''); 66 | } // (builtins.removeAttrs args [ "name" "src" "millDepsHash" "nativeBuildInputs" ])); 67 | in 68 | self 69 | -------------------------------------------------------------------------------- /nix/pkgs/project-dependencies.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { pkgs, makeSetupHook, writeText, lib, generatedNixPath ? ./dependencies/_sources/generated.nix }: 5 | 6 | let 7 | submodules = lib.filterAttrs (_: v: v ? src) (pkgs.callPackage generatedNixPath { }); 8 | makeRemote = module: "git@github.com:${module.src.owner}/${module.src.repo}.git"; 9 | in 10 | { 11 | setupHook = makeSetupHook { name = "submodules-setup.sh"; } (writeText "submodules-setup.sh" ('' 12 | _setupOneSubmodule() { 13 | src="$1" 14 | name="$2" 15 | 16 | echo "[nix-shell] linking '$src' to 'dependencies/$name'" 17 | ln -sfT "$src" "dependencies/$name" 18 | } 19 | 20 | _setupOneSubmoduleEditable() { 21 | name="$1"; shift 22 | remote="$1"; shift 23 | rev="$1"; shift 24 | depDir="dependencies/$name" 25 | 26 | if [ -d "$depDir" -a ! -L "$depDir" ]; then 27 | echo "[nix-shell] ignored existing submodule directory '$depDir', remove them if you want a update" 28 | else 29 | if [ -L "$depDir" ]; then 30 | echo "[nix-shell] replacing symlink '$depDir' with full git worktree" 31 | rm "$depDir" 32 | else 33 | echo "[nix-shell] fetching submodule $name" 34 | fi 35 | 36 | git clone $remote $depDir 37 | git -C $depDir -c advice.detachedHead=false checkout $rev 38 | fi 39 | } 40 | 41 | setupSubmodules() { 42 | mkdir -p dependencies 43 | '' + lib.concatLines (lib.mapAttrsToList (k: v: "_setupOneSubmodule '${v.src}' '${k}'") submodules) + '' 44 | } 45 | 46 | # for use of shellHook 47 | setupSubmodulesEditable() { 48 | mkdir -p dependencies 49 | '' + lib.concatLines (lib.mapAttrsToList (k: v: "_setupOneSubmoduleEditable '${k}' '${makeRemote v}' '${v.src.rev}'") submodules) + '' 50 | } 51 | prePatchHooks+=(setupSubmodules) 52 | '')); 53 | sources = submodules; 54 | } 55 | -------------------------------------------------------------------------------- /nix/pkgs/vcs-fhs-env.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { buildFHSEnv 5 | , vcStaticHome 6 | , snpslmdLicenseFile 7 | }: 8 | buildFHSEnv { 9 | name = "vcs-fhs-env"; 10 | 11 | profile = '' 12 | [ ! -e "${vcStaticHome}" ] && echo "env VC_STATIC_HOME not set" && exit 1 13 | [ ! -d "${vcStaticHome}" ] && echo "VC_STATIC_HOME not accessible" && exit 1 14 | [ -z "${snpslmdLicenseFile}" ] && echo "env SNPS LICENSE not set" && exit 1 15 | export VC_STATIC_HOME=${vcStaticHome} 16 | 17 | export TCL_TZ=UTC 18 | export VC_STATIC_HOME=$VC_STATIC_HOME 19 | export VCS_HOME=$VC_STATIC_HOME/vcs-mx 20 | export VCS_TARGET_ARCH=amd64 21 | export VCS_ARCH_OVERRIDE=linux 22 | export VERDI_HOME=$VC_STATIC_HOME/verdi 23 | export NOVAS_HOME=$VC_STATIC_HOME/verdi 24 | export SPYGLASS_HOME=$VC_STATIC_HOME/SG_COMPAT/SPYGLASS_HOME 25 | export SNPS_VERDI_CBUG_LCA=1 26 | export SNPSLMD_LICENSE_FILE=${snpslmdLicenseFile} 27 | 28 | export PATH=$VC_STATIC_HOME/bin:$PATH 29 | export PATH=$VC_STATIC_HOME/verdi/bin:$PATH 30 | export PATH=$VC_STATIC_HOME/vcs-mx/bin:$PATH 31 | export PATH=$VC_STATIC_HOME/SG_COMPAT/SPYGLASS_HOME/bin:$PATH 32 | 33 | export LD_LIBRARY_PATH=/usr/lib64/ 34 | export LD_LIBRARY_PATH=$VC_STATIC_HOME/verdi/share/PLI/lib/LINUX64:$LD_LIBRARY_PATH 35 | export LD_LIBRARY_PATH=$VC_STATIC_HOME/verdi/share/NPI/lib/LINUX64:$LD_LIBRARY_PATH 36 | 37 | export _oldVcsEnvPath="$PATH" 38 | preHook() { 39 | PATH="$PATH:$_oldVcsEnvPath" 40 | } 41 | export -f preHook 42 | ''; 43 | targetPkgs = (ps: with ps; [ 44 | libGL 45 | util-linux 46 | libxcrypt-legacy 47 | coreutils-full 48 | ncurses5 49 | gmp5 50 | bzip2 51 | glib 52 | bc 53 | time 54 | elfutils 55 | ncurses5 56 | e2fsprogs 57 | cyrus_sasl 58 | expat 59 | sqlite 60 | nssmdns 61 | (libkrb5.overrideAttrs rec { 62 | version = "1.18.2"; 63 | src = fetchurl { 64 | url = "https://kerberos.org/dist/krb5/${lib.versions.majorMinor version}/krb5-${version}.tar.gz"; 65 | hash = "sha256-xuTJ7BqYFBw/XWbd8aE1VJBQyfq06aRiDumyIIWHOuA="; 66 | }; 67 | sourceRoot = "krb5-${version}/src"; 68 | }) 69 | (gnugrep.overrideAttrs rec { 70 | version = "3.1"; 71 | doCheck = false; 72 | src = fetchurl { 73 | url = "mirror://gnu/grep/grep-${version}.tar.xz"; 74 | hash = "sha256-22JcerO7PudXs5JqXPqNnhw5ka0kcHqD3eil7yv3oH4="; 75 | }; 76 | }) 77 | keyutils 78 | graphite2 79 | libpulseaudio 80 | libxml2 81 | gcc 82 | gnumake 83 | xorg.libX11 84 | xorg.libXft 85 | xorg.libXScrnSaver 86 | xorg.libXext 87 | xorg.libxcb 88 | xorg.libXau 89 | xorg.libXrender 90 | xorg.libXcomposite 91 | xorg.libXi 92 | zlib 93 | ]); 94 | } 95 | -------------------------------------------------------------------------------- /nix/sdram/default.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib, newScope, }: 5 | lib.makeScope newScope (scope: 6 | let 7 | designTarget = "SDRAMController"; 8 | tbTarget = "SDRAMControllerTestBench"; 9 | dpiLibName = "sdramemu"; 10 | in 11 | { 12 | # RTL 13 | sdram-compiled = scope.callPackage ./sdram.nix { target = designTarget; }; 14 | elaborate = scope.callPackage ./elaborate.nix { 15 | elaborator = scope.sdram-compiled.elaborator; 16 | }; 17 | mlirbc = scope.callPackage ./mlirbc.nix { }; 18 | rtl = scope.callPackage ./rtl.nix { }; 19 | 20 | # Testbench 21 | tb-compiled = scope.callPackage ./sdram.nix { target = tbTarget; }; 22 | tb-elaborate = scope.callPackage ./elaborate.nix { 23 | elaborator = scope.tb-compiled.elaborator; 24 | }; 25 | tb-mlirbc = 26 | scope.callPackage ./mlirbc.nix { elaborate = scope.tb-elaborate; }; 27 | tb-rtl = scope.callPackage ./rtl.nix { mlirbc = scope.tb-mlirbc; }; 28 | tb-dpi-lib = scope.callPackage ./dpi-lib.nix { inherit dpiLibName; }; 29 | 30 | verilated = scope.callPackage ./verilated.nix { 31 | rtl = scope.tb-rtl.override { enable-layers = [ "Verification" ]; }; 32 | dpi-lib = scope.tb-dpi-lib; 33 | }; 34 | verilated-trace = scope.verilated.override { 35 | dpi-lib = scope.verilated.dpi-lib.override { enable-trace = true; }; 36 | }; 37 | vcs = scope.callPackage ./vcs.nix { 38 | dpi-lib = scope.tb-dpi-lib.override { 39 | sv2023 = false; 40 | vpi = true; 41 | timescale = 1000; 42 | }; 43 | rtl = scope.tb-rtl.override { 44 | enable-layers = [ "Verification" "Verification.Assert" ]; 45 | }; 46 | }; 47 | vcs-trace = scope.vcs.override { 48 | dpi-lib = scope.vcs.dpi-lib.override { enable-trace = true; }; 49 | }; 50 | 51 | # TODO: designConfig should be read from OM 52 | tbConfig = with builtins; 53 | fromJSON (readFile ./../../configs/${tbTarget}Main.json); 54 | 55 | }) 56 | 57 | -------------------------------------------------------------------------------- /nix/sdram/dpi-lib.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib 5 | , rustPlatform 6 | , tbConfig 7 | , dpiLibName 8 | , sv2023 ? true 9 | , vpi ? false 10 | , enable-trace ? false 11 | , timescale ? 1 12 | }: 13 | 14 | rustPlatform.buildRustPackage rec { 15 | name = "dpi-lib"; 16 | src = ./../../${dpiLibName}; 17 | cargoHash = "sha256-Bqq3zA807Dr+QBKfaAjxkNgJ2ZzSco0sUJ2ioNfHACk="; 18 | buildFeatures = lib.optionals sv2023 [ "sv2023" ] 19 | ++ lib.optionals vpi [ "vpi" ] ++ lib.optionals enable-trace [ "trace" ]; 20 | 21 | env = { 22 | TIMEOUT = tbConfig.timeout; 23 | CLOCK_FLIP_TIME = tbConfig.testVerbatimParameter.clockFlipTick * timescale; 24 | }; 25 | 26 | passthru = { 27 | inherit enable-trace; 28 | inherit env; 29 | libOutName = "lib${dpiLibName}.a"; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /nix/sdram/elaborate.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | # TODO: in the future, we may need to add circtbindng pass and set it by default. 5 | { stdenvNoCC, espresso, circt, elaborator }: 6 | 7 | stdenvNoCC.mkDerivation { 8 | name = "${elaborator.name}-elaborate"; 9 | 10 | nativeBuildInputs = [ espresso circt ]; 11 | 12 | src = ./../../configs; 13 | passthru = { 14 | inherit elaborator; 15 | inherit (elaborator) target; 16 | }; 17 | 18 | buildCommand = '' 19 | mkdir -p elaborate $out 20 | 21 | ${elaborator}/bin/elaborator design --parameter $src/${elaborator.target}Main.json --target-dir elaborate 22 | 23 | firtool elaborate/*.fir \ 24 | --annotation-file elaborate/*.anno.json \ 25 | --emit-bytecode \ 26 | --parse-only \ 27 | -o $out/$name.mlirbc 28 | ''; 29 | } 30 | -------------------------------------------------------------------------------- /nix/sdram/mlirbc.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { stdenvNoCC 5 | , circt 6 | , elaborate 7 | }: 8 | 9 | stdenvNoCC.mkDerivation { 10 | name = "${elaborate.name}-mlirbc"; 11 | 12 | nativeBuildInputs = [ circt ]; 13 | 14 | passthru = { 15 | inherit elaborate; 16 | inherit (elaborate) target; 17 | }; 18 | 19 | buildCommand = '' 20 | mkdir $out 21 | 22 | firtool ${elaborate}/${elaborate.name}.mlirbc \ 23 | --emit-bytecode \ 24 | -O=debug \ 25 | --preserve-values=named \ 26 | --lowering-options=verifLabels \ 27 | --output-final-mlir=$out/$name-lowered.mlirbc 28 | ''; 29 | } 30 | -------------------------------------------------------------------------------- /nix/sdram/rtl.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib 5 | , stdenvNoCC 6 | , circt 7 | , mlirbc 8 | , mfcArgs ? [ 9 | "-O=release" 10 | "--split-verilog" 11 | "--preserve-values=all" 12 | "--lowering-options=verifLabels,omitVersionComment" 13 | "--strip-debug-info" 14 | ] 15 | , enable-layers ? [ ] 16 | }: 17 | let 18 | processLayer = lib.map (str: "./" + lib.replaceStrings [ "." ] [ "/" ] str); 19 | enableLayersDirs = processLayer enable-layers; 20 | in 21 | stdenvNoCC.mkDerivation { 22 | name = "${mlirbc.name}-rtl"; 23 | nativeBuildInputs = [ circt ]; 24 | 25 | passthru = { 26 | inherit mlirbc; 27 | inherit (mlirbc) target; 28 | }; 29 | 30 | src = ./../../sdramcontroller; 31 | 32 | buildCommand = '' 33 | mkdir -p $out 34 | 35 | firtool ${mlirbc}/${mlirbc.name}-lowered.mlirbc -o $out ${ 36 | lib.escapeShellArgs mfcArgs 37 | } 38 | 39 | cp $src/extmodules/*.v $out 40 | 41 | pushd $out 42 | find . ${ 43 | lib.concatStringsSep " " enableLayersDirs 44 | } -maxdepth 1 \( -name "*.sv" -o -name "*.v" \) -type f -print > ./filelist.f 45 | popd 46 | ''; 47 | } 48 | -------------------------------------------------------------------------------- /nix/sdram/sdram.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib 5 | , stdenv 6 | , fetchMillDeps 7 | , makeWrapper 8 | , jdk21 9 | 10 | # chisel deps 11 | , mill 12 | , espresso 13 | , circt-full 14 | , jextract-21 15 | , add-determinism 16 | 17 | , projectDependencies 18 | 19 | , target 20 | }: 21 | 22 | let 23 | self = stdenv.mkDerivation rec { 24 | name = "sdram"; 25 | 26 | mainClass = "oscc.sdramcontroller.elaborator.${target}Main"; 27 | 28 | src = with lib.fileset; 29 | toSource { 30 | root = ./../..; 31 | fileset = unions [ 32 | ./../../build.sc 33 | ./../../common.sc 34 | ./../../sdramcontroller 35 | ./../../elaborator 36 | ]; 37 | }; 38 | 39 | passthru = { 40 | millDeps = fetchMillDeps { 41 | inherit name; 42 | src = with lib.fileset; 43 | toSource { 44 | root = ./../..; 45 | fileset = unions [ ./../../build.sc ./../../common.sc ]; 46 | }; 47 | millDepsHash = "sha256-vG0sLWwKrCcpZuqXolz3UKQTZD1R9jk2p2psNaMiLl0="; 48 | nativeBuildInputs = [ projectDependencies.setupHook ]; 49 | }; 50 | 51 | editable = self.overrideAttrs (_: { 52 | shellHook = '' 53 | setupSubmodulesEditable 54 | mill mill.bsp.BSP/install 0 55 | ''; 56 | }); 57 | 58 | inherit target; 59 | }; 60 | 61 | passthru.elaborateTarget = target; 62 | 63 | shellHook = '' 64 | setupSubmodules 65 | ''; 66 | 67 | nativeBuildInputs = [ 68 | mill 69 | circt-full 70 | jextract-21 71 | add-determinism 72 | espresso 73 | 74 | makeWrapper 75 | passthru.millDeps.setupHook 76 | 77 | projectDependencies.setupHook 78 | ]; 79 | 80 | env.CIRCT_INSTALL_PATH = circt-full; 81 | 82 | outputs = [ "out" "elaborator" ]; 83 | 84 | meta.mainProgram = "elaborator"; 85 | 86 | buildPhase = '' 87 | mill -i '__.assembly' 88 | ''; 89 | 90 | installPhase = '' 91 | mkdir -p $out/share/java 92 | 93 | add-determinism -j $NIX_BUILD_CORES out/elaborator/assembly.dest/out.jar 94 | 95 | mv out/elaborator/assembly.dest/out.jar $out/share/java/elaborator.jar 96 | 97 | mkdir -p $elaborator/bin 98 | makeWrapper ${jdk21}/bin/java $elaborator/bin/elaborator \ 99 | --add-flags "--enable-preview -Djava.library.path=${circt-full}/lib -cp $out/share/java/elaborator.jar ${mainClass}" 100 | ''; 101 | }; 102 | in 103 | self 104 | -------------------------------------------------------------------------------- /nix/sdram/vcs-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!@shell@ 2 | 3 | _EXTRA_ARGS="$@" 4 | 5 | if ((${VERBOSE:-0})); then 6 | set -x 7 | fi 8 | 9 | _DATE_BIN=@dateBin@ 10 | _VCS_SIM_BIN=@vcsSimBin@ 11 | _VCS_SIM_DAIDIR=@vcsSimDaidir@ 12 | _VCS_FHS_ENV=@vcsFhsEnv@ 13 | 14 | _NOW=$("$_DATE_BIN" "+%Y-%m-%d-%H-%M-%S") 15 | _SDRAM_SIM_RESULT_DIR=${SDRAM_SIM_RESULT_DIR:-"sdram-sim-result"} 16 | _CURRENT="$_SDRAM_SIM_RESULT_DIR"/all/"$_NOW" 17 | mkdir -p "$_CURRENT" 18 | ln -sfn "all/$_NOW" "$_SDRAM_SIM_RESULT_DIR/result" 19 | 20 | cp "$_VCS_SIM_BIN" "$_CURRENT/" 21 | cp -r "$_VCS_SIM_DAIDIR" "$_CURRENT/" 22 | 23 | chmod -R +w "$_CURRENT" 24 | 25 | pushd "$_CURRENT" >/dev/null 26 | 27 | _emu_name=$(basename "$_VCS_SIM_BIN") 28 | _daidir=$(basename "$_VCS_SIM_DAIDIR") 29 | 30 | export LD_LIBRARY_PATH="$PWD/$_daidir:$LD_LIBRARY_PATH" 31 | 32 | "$_VCS_FHS_ENV" -c "./$_emu_name $_EXTRA_ARGS" &> >(tee vcs-emu-journal.log) 33 | 34 | if ((${DATA_ONLY:-0})); then 35 | rm -f "./$_emu_name" 36 | fi 37 | 38 | set -e _emu_name _daidir 39 | 40 | popd >/dev/null 41 | 42 | echo "VCS emulator finished, result saved in $_SDRAM_SIM_RESULT_DIR/result" 43 | -------------------------------------------------------------------------------- /nix/sdram/vcs.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib 5 | , bash 6 | , stdenv 7 | , rtl 8 | , dpi-lib 9 | , vcs-fhs-env 10 | , dwbb 11 | , runCommand 12 | }: 13 | 14 | let 15 | binName = "sdram-vcs-simulator"; 16 | in 17 | stdenv.mkDerivation (finalAttr: { 18 | name = "vcs"; 19 | 20 | # Add "sandbox = relaxed" into /etc/nix/nix.conf, and run `systemctl restart nix-daemon` 21 | # 22 | # run nix build with "--impure" flag to build this package without chroot 23 | # require license 24 | __noChroot = true; 25 | dontPatchELF = true; 26 | 27 | src = rtl; 28 | 29 | meta.mainProgram = binName; 30 | 31 | buildPhase = '' 32 | runHook preBuild 33 | 34 | echo "[nix] running VCS" 35 | fhsBash=${vcs-fhs-env}/bin/vcs-fhs-env 36 | VERDI_HOME=$("$fhsBash" -c "printenv VERDI_HOME") 37 | "$fhsBash" vcs \ 38 | -sverilog \ 39 | -y ${dwbb}/sim_ver \ 40 | +libext+.v+ \ 41 | -full64 \ 42 | -timescale=1ns/1ps \ 43 | +v2k \ 44 | -sverilog \ 45 | -Mupdate \ 46 | +define+DUMP_FSDB \ 47 | -debug_acc+all \ 48 | -debug_region+cell+encrypt \ 49 | -P $VERDI_HOME/share/PLI/VCS/LINUX64/novas.tab $VERDI_HOME/share/PLI/VCS/LINUX64/pli.a \ 50 | ${ 51 | lib.optionalString dpi-lib.enable-trace '' 52 | -debug_access+pp+dmptf+thread \ 53 | -kdb=common_elab,hgldd_all'' 54 | } \ 55 | -file filelist.f \ 56 | -assert enable_diag \ 57 | ${dpi-lib}/lib/${dpi-lib.libOutName} \ 58 | -o ${binName} 59 | 60 | runHook postBuild 61 | ''; 62 | 63 | passthru = { 64 | inherit (dpi-lib) enable-trace; 65 | inherit vcs-fhs-env; 66 | inherit dpi-lib; 67 | inherit rtl; 68 | 69 | tests.simple-sim = runCommand "${binName}-test" { __noChroot = true; } '' 70 | export SDRAM_SIM_RESULT_DIR="$(mktemp -d)" 71 | export DATA_ONLY=1 72 | ${finalAttr.finalPackage}/bin/${binName} 73 | 74 | mkdir -p "$out" 75 | cp -vr "$SDRAM_SIM_RESULT_DIR"/result/* "$out/" 76 | ''; 77 | }; 78 | 79 | shellHook = '' 80 | echo "[nix] entering fhs env" 81 | ${vcs-fhs-env}/bin/vcs-fhs-env 82 | ''; 83 | 84 | installPhase = '' 85 | runHook preInstall 86 | 87 | mkdir -p $out/bin $out/lib 88 | cp ${binName} $out/lib 89 | cp -r ${binName}.daidir $out/lib 90 | 91 | substitute ${./vcs-wrapper.sh} $out/bin/${binName} \ 92 | --subst-var-by shell "${bash}/bin/bash" \ 93 | --subst-var-by dateBin "$(command -v date)" \ 94 | --subst-var-by vcsSimBin "$out/lib/${binName}" \ 95 | --subst-var-by vcsSimDaidir "$out/lib/${binName}.daidir" \ 96 | --subst-var-by vcsFhsEnv "${vcs-fhs-env}/bin/vcs-fhs-env" 97 | chmod +x $out/bin/${binName} 98 | 99 | runHook postInstall 100 | ''; 101 | }) 102 | -------------------------------------------------------------------------------- /nix/sdram/verilated.nix: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # SPDX-FileCopyrightText: 2024 Jiuyang Liu 3 | 4 | { lib, stdenv, rtl, verilator, zlib, dpi-lib, thread-num ? 8 }: 5 | let vName = "V${rtl.target}"; 6 | in stdenv.mkDerivation { 7 | name = "verilated"; 8 | 9 | src = rtl; 10 | 11 | nativeBuildInputs = [ verilator ]; 12 | 13 | # zlib is required for Rust to link against? 14 | # IIRC: zlib is required for 15 | propagatedBuildInputs = [ zlib ]; 16 | 17 | passthru = { 18 | inherit dpi-lib; 19 | inherit (rtl) target; 20 | }; 21 | 22 | meta.mainProgram = vName; 23 | 24 | buildPhase = '' 25 | runHook preBuild 26 | 27 | echo "[nix] running verilator" 28 | echo `ls` 29 | verilator \ 30 | ${lib.optionalString dpi-lib.enable-trace "--trace-fst"} \ 31 | --timing \ 32 | --threads ${toString thread-num} \ 33 | -O1 \ 34 | --main \ 35 | --exe \ 36 | --cc -f filelist.f --top ${rtl.target} ${dpi-lib}/lib/${dpi-lib.libOutName} 37 | 38 | echo "[nix] building verilated C lib" 39 | 40 | # backup srcs 41 | mkdir -p $out/share 42 | cp -r obj_dir $out/share/verilated_src 43 | 44 | # We can't use -C here because the Makefile is generated with relative path 45 | cd obj_dir 46 | make -j "$NIX_BUILD_CORES" -f ${vName}.mk ${vName} 47 | 48 | runHook postBuild 49 | ''; 50 | 51 | installPhase = '' 52 | runHook preInstall 53 | 54 | mkdir -p $out/{include,lib,bin} 55 | cp *.h $out/include 56 | cp *.a $out/lib 57 | cp ${vName} $out/bin 58 | 59 | runHook postInstall 60 | ''; 61 | 62 | # nix fortify hardening add `-O2` gcc flag, 63 | # we'd like verilator to controll optimization flags, so disable it. 64 | # `-O2` will make gcc build time in verilating extremely long 65 | hardeningDisable = [ "fortify" ]; 66 | } 67 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # SDRAM 2 | 3 | ## Dev Guide 4 | 5 | 1. Install Nix 6 | 2. Enter development environment: 7 | 8 | ```bash 9 | nix develop .#sdram. 10 | ``` 11 | 12 | 3. Setup Mill BSP 13 | 14 | ```bash 15 | mill mill.bsp.BSP/install 16 | ``` 17 | 18 | 4. Open your favorite IDE 19 | 20 | ## Elaborate Verilog 21 | 22 | Use this line to generate a json config at `PWD`, you can config the parameter on the command-line. 23 | 24 | ```bash 25 | # rtl config 26 | nix run .#sdram.sdram-compiled.elaborator -- config --idWidth 4 --dataWidth 32 --addrWidth 32 --csWidth 4 27 | 28 | # testbench config 29 | nix run .#sdram.tb-compiled.elaborator -- config --idWidth 4 --dataWidth 32 --addrWidth 32 --csWidth 4 --useAsyncReset false --initFunctionName cosim_init --dumpFunctionName dump_wave --clockFlipTick 1 --resetFlipTick 100 --timeout 10000 30 | ``` 31 | 32 | Use this line to generate the Verilog at `result`, based on the config in `configs` directory. 33 | 34 | ```bash 35 | nix build .#sdram.rtl 36 | ``` 37 | 38 | or elaborate design with testbench: 39 | 40 | ```bash 41 | nix build .#sdram.tb-rtl 42 | ``` 43 | 44 | Generated Verilog will be placed at `result` by default, which can be specified with `-O` 45 | 46 | ## Run VCS Simulation 47 | 48 | ```bash 49 | nix run .#sdram.vcs-trace --impure -- +dump-range=0,10000 +wave-path=trace +fsdb+sva_success 50 | ``` 51 | 52 | ## Update dependency 53 | 54 | ### Build from source dependencies 55 | 56 | ```bash 57 | pushd nix/pkgs/dependencies && nix run nixpkgs#nvfetcher && popd 58 | ``` 59 | 60 | ### Other dependencies 61 | 62 | ```bash 63 | nix flake update 64 | ``` 65 | -------------------------------------------------------------------------------- /sdramcontroller/src/AXI4MasterAgent.scala: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Beijing Institute of Open Source Chip 2 | package oscc.sdramcontroller 3 | 4 | import chisel3._ 5 | import chisel3.ltl.AssertProperty 6 | import chisel3.util.circt.dpi.{ 7 | RawClockedVoidFunctionCall, 8 | RawUnclockedNonVoidFunctionCall, 9 | RawClockedNonVoidFunctionCall 10 | } 11 | import chisel3.util.{isPow2, log2Ceil} 12 | import org.chipsalliance.amba.axi4.bundle._ 13 | import chisel3.ltl.Sequence._ 14 | 15 | case class AXI4MasterAgentParameter( 16 | name: String, 17 | axiParameter: AXI4BundleParameter, 18 | outstanding: Int, 19 | readPayloadSize: Int, 20 | writePayloadSize: Int 21 | ) 22 | 23 | class AXI4MasterAgentInterface(parameter: AXI4MasterAgentParameter) 24 | extends Bundle { 25 | val clock: Clock = Input(Clock()) 26 | val reset: Reset = Input(Reset()) 27 | val channelId: UInt = Input(Const(UInt(64.W))) 28 | // don't issue read DPI 29 | val gateRead: Bool = Input(Bool()) 30 | // don't issue write DPI 31 | val gateWrite: Bool = Input(Bool()) 32 | val channel = org.chipsalliance.amba.axi4.bundle.verilog 33 | .irrevocable(parameter.axiParameter) 34 | } 35 | 36 | class WritePayload( 37 | length: Int, 38 | idWidth: Int, 39 | addrWidth: Int, 40 | dataWidth: Int, 41 | awUserWidth: Int, 42 | wUserWidth: Int 43 | ) extends Bundle { 44 | val id = UInt(math.max(8, idWidth).W) 45 | val len = UInt(8.W) 46 | val addr = UInt(addrWidth.W) 47 | val data = Vec(length, UInt(dataWidth.W)) 48 | // For dataWidth <= 8, align strb to u8 for a simple C-API 49 | val strb = Vec(length, UInt(math.max(8, dataWidth / 8).W)) 50 | val wUser = Vec(length, UInt(math.max(8, wUserWidth).W)) 51 | val awUser = UInt(math.max(8, awUserWidth).W) 52 | val dataValid = UInt(8.W) 53 | val burst = UInt(8.W) 54 | val cache = UInt(8.W) 55 | val lock = UInt(8.W) 56 | val prot = UInt(8.W) 57 | val qos = UInt(8.W) 58 | val region = UInt(8.W) 59 | val size = UInt(8.W) 60 | } 61 | 62 | class ReadAddressPayload(addrWidth: Int, idWidth: Int, userWidth: Int) 63 | extends Bundle { 64 | val addr = UInt(addrWidth.W) 65 | val id = UInt(math.max(8, idWidth).W) 66 | val user = UInt(math.max(8, userWidth).W) 67 | val burst = UInt(8.W) 68 | val cache = UInt(8.W) 69 | val len = UInt(8.W) 70 | val lock = UInt(8.W) 71 | val prot = UInt(8.W) 72 | val qos = UInt(8.W) 73 | val region = UInt(8.W) 74 | val size = UInt(8.W) 75 | val valid = UInt(8.W) 76 | } 77 | 78 | // consume transaction from DPI, drive RTL signal 79 | class AXI4MasterAgent(parameter: AXI4MasterAgentParameter) 80 | extends FixedIORawModule[AXI4MasterAgentInterface]( 81 | new AXI4MasterAgentInterface(parameter) 82 | ) { 83 | dontTouch(io) 84 | io.channel match { 85 | case channel: AXI4RWIrrevocableVerilog => 86 | new WriteManager(channel) 87 | new ReadManager(channel) 88 | case channel: AXI4ROIrrevocableVerilog => 89 | new ReadManager(channel) 90 | case channel: AXI4WOIrrevocableVerilog => 91 | new WriteManager(channel) 92 | } 93 | 94 | private class WriteManager( 95 | channel: AWChannel 96 | with AWFlowControl 97 | with WChannel 98 | with WFlowControl 99 | with BChannel 100 | with BFlowControl 101 | ) { 102 | withClockAndReset(io.clock, io.reset) { 103 | class AWValueType extends Bundle { 104 | val payload = new WritePayload( 105 | parameter.writePayloadSize, 106 | parameter.axiParameter.idWidth, 107 | parameter.axiParameter.addrWidth, 108 | parameter.axiParameter.dataWidth, 109 | parameter.axiParameter.awUserWidth, 110 | parameter.axiParameter.wUserWidth 111 | ) 112 | val index = UInt(log2Ceil(parameter.writePayloadSize).W) 113 | val addrValid = Bool() 114 | val writeEnable = Bool() 115 | } 116 | 117 | val awFifo = 118 | RegInit(0.U.asTypeOf(Vec(parameter.outstanding, new AWValueType))) 119 | require(isPow2(parameter.outstanding), "Need to handle pointers") 120 | val awWPtr = 121 | RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) 122 | val awRPtr = 123 | RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) 124 | val wRPtr = RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) 125 | val awCount = RegInit(0.U(32.W)) 126 | // AW 127 | val doIssueAWPayload = RegInit(false.B) 128 | when(awFifo(awWPtr).payload.dataValid === 0.U && !awFifo(awWPtr).addrValid && !io.reset.asBool) { 129 | val payload_wire = WireInit(0.U.asTypeOf(new WritePayload( 130 | parameter.writePayloadSize, 131 | parameter.axiParameter.idWidth, 132 | parameter.axiParameter.addrWidth, 133 | parameter.axiParameter.dataWidth, 134 | parameter.axiParameter.awUserWidth, 135 | parameter.axiParameter.wUserWidth 136 | ))) 137 | payload_wire := RawClockedNonVoidFunctionCall( 138 | s"axi_write_ready_${parameter.name}", 139 | new WritePayload( 140 | parameter.writePayloadSize, 141 | parameter.axiParameter.idWidth, 142 | parameter.axiParameter.addrWidth, 143 | parameter.axiParameter.dataWidth, 144 | parameter.axiParameter.awUserWidth, 145 | parameter.axiParameter.wUserWidth 146 | ) 147 | )(io.clock, when.cond && !io.gateWrite) 148 | when(doIssueAWPayload && payload_wire.dataValid === 1.U) { 149 | awFifo(awWPtr).payload := payload_wire 150 | awFifo(awWPtr).index := 0.U 151 | awFifo(awWPtr).addrValid := true.B 152 | awFifo(awRPtr).writeEnable := false.B 153 | awWPtr := awWPtr + 1.U 154 | }.elsewhen(!doIssueAWPayload) { 155 | doIssueAWPayload := true.B 156 | } 157 | } 158 | channel.AWADDR := awFifo(awRPtr).payload.addr 159 | channel.AWVALID := awFifo(awRPtr).addrValid 160 | channel.AWSIZE := awFifo(awRPtr).payload.size 161 | channel.AWBURST := awFifo(awRPtr).payload.burst 162 | channel.AWLOCK := awFifo(awRPtr).payload.lock 163 | channel.AWCACHE := awFifo(awRPtr).payload.cache 164 | channel.AWPROT := awFifo(awRPtr).payload.prot 165 | channel.AWQOS := awFifo(awRPtr).payload.qos 166 | channel.AWREGION := awFifo(awRPtr).payload.region 167 | channel.AWID := awFifo(awRPtr).payload.id 168 | channel.AWLEN := awFifo(awRPtr).payload.len 169 | channel.AWUSER := awFifo(awRPtr).payload.awUser 170 | val awFire = channel.AWREADY && channel.AWVALID 171 | when(awFire) { 172 | awFifo(awRPtr).addrValid := false.B 173 | awFifo(awRPtr).writeEnable := true.B 174 | awRPtr := awRPtr + 1.U 175 | awCount := awCount + 1.U 176 | } 177 | 178 | // W 179 | val wFire = channel.WREADY && channel.WVALID 180 | val wCount = RegInit(0.U(32.W)) 181 | channel.WDATA := awFifo(wRPtr).payload.data( 182 | awFifo(wRPtr).index 183 | ) 184 | channel.WSTRB := awFifo(wRPtr).payload.strb( 185 | awFifo(wRPtr).index 186 | ) 187 | channel.WUSER := awFifo(wRPtr).payload.wUser( 188 | awFifo(wRPtr).index 189 | ) 190 | channel.WLAST := awFifo(wRPtr).index >= awFifo( 191 | wRPtr 192 | ).payload.len 193 | channel.WVALID := awFifo(wRPtr).payload.dataValid =/= 0.U && awFifo(wRPtr).writeEnable 194 | when(wFire) { 195 | when(channel.WLAST) { 196 | awFifo(wRPtr).payload.dataValid := 0.U 197 | wRPtr := wRPtr + 1.U 198 | wCount := wCount + 1.U 199 | }.otherwise( 200 | awFifo(wRPtr).index := awFifo( 201 | wRPtr 202 | ).index + 1.U 203 | ) 204 | } 205 | 206 | // B 207 | channel.BREADY := true.B // note: keep it simple and stupid, handle corner cases in Rust 208 | val bFire = channel.BREADY && channel.BVALID 209 | when(bFire) { 210 | RawClockedVoidFunctionCall(s"axi_write_done_${parameter.name}")( 211 | io.clock, 212 | when.cond && !io.gateWrite, 213 | channel.BID.asTypeOf(UInt(8.W)), 214 | channel.BRESP.asTypeOf(UInt(8.W)), 215 | channel.BUSER.asTypeOf(UInt(8.W)) 216 | ) 217 | } 218 | 219 | AssertProperty(BoolSequence(awCount >= wCount)) 220 | } 221 | } 222 | 223 | private class ReadManager( 224 | channel: ARChannel with ARFlowControl with RChannel with RFlowControl 225 | ) { 226 | withClockAndReset(io.clock, io.reset) { 227 | class ARValueType extends Bundle { 228 | val payload = new ReadAddressPayload( 229 | parameter.axiParameter.addrWidth, 230 | parameter.axiParameter.idWidth, 231 | parameter.axiParameter.userDataWidth 232 | ) 233 | } 234 | 235 | val arFifo: Vec[ARValueType] = 236 | RegInit(0.U.asTypeOf(Vec(parameter.outstanding, new ARValueType))) 237 | require(isPow2(parameter.outstanding), "Need to handle pointers") 238 | val arWPtr = 239 | RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) 240 | val arRPtr = 241 | RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) 242 | val arCount = RegInit(0.U(32.W)) 243 | val doIssueARPayload = RegInit(false.B) 244 | 245 | // AR 246 | when(arFifo(arWPtr).payload.valid === 0.U && !io.reset.asBool) { 247 | val payload_wire = WireInit(0.U.asTypeOf(new ReadAddressPayload( 248 | parameter.axiParameter.addrWidth, 249 | parameter.axiParameter.idWidth, 250 | parameter.axiParameter.arUserWidth 251 | ))) 252 | payload_wire := RawClockedNonVoidFunctionCall( 253 | s"axi_read_ready_${parameter.name}", 254 | new ReadAddressPayload( 255 | parameter.axiParameter.addrWidth, 256 | parameter.axiParameter.idWidth, 257 | parameter.axiParameter.arUserWidth 258 | ) 259 | )( 260 | io.clock, when.cond && !io.gateRead 261 | ) 262 | when(doIssueARPayload && payload_wire.valid === 1.U) { 263 | arFifo(arWPtr).payload := payload_wire 264 | arWPtr := arWPtr + 1.U 265 | }.elsewhen(!doIssueARPayload) { 266 | doIssueARPayload := true.B 267 | } 268 | } 269 | val arFire = channel.ARREADY && channel.ARVALID 270 | when(arFire) { 271 | arFifo(arRPtr).payload.valid := false.B 272 | arRPtr := arRPtr + 1.U 273 | arCount := arCount + 1.U 274 | } 275 | channel.ARVALID := arFifo(arRPtr).payload.valid 276 | channel.ARADDR := arFifo(arRPtr).payload.addr 277 | channel.ARBURST := arFifo(arRPtr).payload.burst 278 | channel.ARCACHE := arFifo(arRPtr).payload.cache 279 | channel.ARID := arFifo(arRPtr).payload.id 280 | channel.ARLEN := arFifo(arRPtr).payload.len 281 | channel.ARLOCK := arFifo(arRPtr).payload.lock 282 | channel.ARPROT := arFifo(arRPtr).payload.prot 283 | channel.ARQOS := arFifo(arRPtr).payload.qos 284 | channel.ARREGION := arFifo(arRPtr).payload.region 285 | channel.ARSIZE := arFifo(arRPtr).payload.size 286 | channel.ARUSER := arFifo(arRPtr).payload.user 287 | 288 | // R 289 | channel.RREADY := true.B 290 | val rCount = RegInit(0.U(32.W)) 291 | val rFire = channel.RREADY && channel.RVALID 292 | val rdataFifo = RegInit(VecInit(Seq.fill(parameter.readPayloadSize)(0.U(32.W)))) 293 | val wIndex = RegInit(0.U(8.W)) 294 | when(rFire) { 295 | rdataFifo(wIndex) := channel.RDATA; 296 | when(channel.RLAST) { 297 | rCount := rCount + 1.U 298 | wIndex := 0.U 299 | RawClockedVoidFunctionCall( 300 | s"axi_read_done_${parameter.name}" 301 | )( 302 | io.clock, 303 | when.cond && !io.gateRead, 304 | rdataFifo.asTypeOf(UInt((32 * parameter.readPayloadSize).W)), 305 | (wIndex + 1.U).asTypeOf(UInt(8.W)), 306 | channel.RDATA.asTypeOf(UInt(32.W)), 307 | channel.RID.asTypeOf(UInt(8.W)), 308 | channel.RRESP.asTypeOf(UInt(8.W)), 309 | channel.RUSER.asTypeOf(UInt(8.W)) 310 | ) 311 | }.otherwise { 312 | wIndex := wIndex + 1.U 313 | } 314 | } 315 | AssertProperty(BoolSequence(arCount >= rCount)) 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /sdramcontroller/src/SDRAMController.scala: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Beijing Institute of Open Source Chip 2 | package oscc.sdramcontroller 3 | 4 | import chisel3._ 5 | import chisel3.experimental.SerializableModule 6 | 7 | class SDRAMController(val parameter: SDRAMControllerParameter) 8 | extends FixedIORawModule[SDRAMControllerInterface]( 9 | new SDRAMControllerInterface(parameter) 10 | ) 11 | with SerializableModule[SDRAMControllerParameter] 12 | with SDRAMControllerRTL 13 | with Public 14 | with ImplicitClock 15 | with ImplicitReset { 16 | lazy val interface: SDRAMControllerInterface = io 17 | 18 | def implicitClock: Clock = io.clock 19 | 20 | def implicitReset: Reset = io.reset 21 | } 22 | -------------------------------------------------------------------------------- /sdramcontroller/src/SDRAMControllerInterface.scala: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Beijing Institute of Open Source Chip 2 | package oscc.sdramcontroller 3 | 4 | import chisel3._ 5 | import chisel3.experimental.SerializableModuleParameter 6 | import chisel3.experimental.dataview.DataViewable 7 | import org.chipsalliance.amba.axi4.bundle._ 8 | import org.chipsalliance.jedec.sdram.{SDRAMChiselType, SDRAMParameter} 9 | import upickle.default 10 | 11 | import scala.collection.immutable.SeqMap 12 | 13 | object SDRAMControllerParameter { 14 | implicit def rw: default.ReadWriter[SDRAMControllerParameter] = 15 | upickle.default.macroRW[SDRAMControllerParameter] 16 | } 17 | 18 | case class SDRAMControllerParameter( 19 | axiParameter: AXI4BundleParameter, 20 | sdramParameter: SDRAMParameter) 21 | extends SerializableModuleParameter { 22 | require(axiParameter.supportId, "doesn't support id") 23 | require(axiParameter.supportLen, "doesn't support len") 24 | require(axiParameter.supportSize, "doesn't support size") 25 | require(axiParameter.supportBurst, "should support burst") 26 | require(axiParameter.supportStrb, "doesn't support strb") 27 | 28 | require(!axiParameter.supportLock, "doesn't support lock") 29 | require(!axiParameter.supportRegion, "doesn't support region") 30 | require(!axiParameter.supportCache, "doesn't support cache") 31 | require(!axiParameter.supportQos, "doesn't support qos") 32 | require(!axiParameter.supportResp, "doesn't support resp") 33 | require(!axiParameter.supportProt, "doesn't support prot") 34 | // require( 35 | // axiParameter.dataWidth == sdramParameter.dataWidth, 36 | // "data width of axi and sdram should same, please inter busip before controller." 37 | // ) 38 | } 39 | 40 | class SDRAMControllerInterface(val parameter: SDRAMControllerParameter) extends Record { 41 | val elements: SeqMap[String, Data] = SeqMap.from( 42 | Seq( 43 | "clock" -> Input(Clock()), 44 | // TODO: we only support sync reset for now. 45 | "reset" -> Input(Bool()), 46 | "AXI" -> Flipped(verilog.irrevocable(parameter.axiParameter)), 47 | // TODO: we should have two types of SDRAM: IO(has inout), Digital(no inout, has dir.) 48 | "SDRAM" -> new SDRAMChiselType(parameter.sdramParameter) 49 | ) 50 | ) 51 | def clock: Clock = elements("clock").asInstanceOf[Clock] 52 | def reset: Bool = elements("reset").asInstanceOf[Bool] 53 | def axi: AXI4RWIrrevocable = elements("AXI") 54 | .asInstanceOf[AXI4RWIrrevocableVerilog] 55 | .viewAs[AXI4RWIrrevocable] 56 | def sdram: SDRAMChiselType = elements("SDRAM").asInstanceOf[SDRAMChiselType] 57 | } 58 | 59 | trait HasSDRAMControllerInterface { 60 | lazy val clock = interface.clock 61 | lazy val reset = interface.reset 62 | lazy val axi = interface.axi 63 | lazy val sdram = interface.sdram 64 | val parameter: SDRAMControllerParameter 65 | val interface: SDRAMControllerInterface 66 | } 67 | -------------------------------------------------------------------------------- /sdramcontroller/src/SDRAMControllerRTL.scala: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | // SPDX-FileCopyrightText: 2015-2019 Ultra-Embedded.com 3 | // SPDX-FileCopyrightText: 2024 Beijing Institute of Open Source Chip 4 | // TODO: change package to oscc 5 | package oscc.sdramcontroller 6 | 7 | import chisel3._ 8 | import chisel3.experimental.hierarchy.{Instance, Instantiate} 9 | import chisel3.util._ 10 | import org.chipsalliance.amba.axi4.bundle.`enum`.burst.{FIXED, INCR, WARP} 11 | import org.chipsalliance.dwbb.wrapper.DW_fifo_s1_sf.DW_fifo_s1_sf 12 | 13 | // This is what RTL designer need to implement, as well as necessary verification signal definitions. 14 | 15 | /** The RTL here is rewrite from 16 | * [[https://github.com/ultraembedded/core_sdram_axi4]]. 17 | */ 18 | trait SDRAMControllerRTL extends HasSDRAMControllerInterface { 19 | // ========================================================================== 20 | // SDRAM Utils 21 | // ========================================================================== 22 | /** Calculate the next address of AXI4 bus. */ 23 | private def calculateAddressNext( 24 | addr: UInt, 25 | axType: UInt, 26 | axLen: UInt, 27 | axSize: UInt 28 | ): UInt = { 29 | val shiftAmount = (1.U << axSize).asUInt 30 | MuxLookup(axType, addr + shiftAmount)( 31 | Seq( 32 | FIXED -> addr, 33 | INCR -> (addr + shiftAmount), 34 | WARP -> { 35 | val mask = Cat(axLen, "b11".U(2.W)).pad(32) 36 | (addr & (~mask).asUInt) | ((addr + shiftAmount) & mask) 37 | } 38 | ) 39 | ) 40 | } 41 | 42 | // ========================================================================== 43 | // SDRAM Main 44 | // ========================================================================== 45 | withClockAndReset(clock, reset) { 46 | val SDRAM_READ_LATENCY = 3 47 | 48 | // ======================================================================== 49 | // AXI4 Request and Response 50 | // ======================================================================== 51 | // ------------------------------------------------------------------------ 52 | // AXI4 Request Wires and Registers 53 | // ------------------------------------------------------------------------ 54 | /** AXI4 read and write request length */ 55 | val req_len_q = RegInit(0.U(8.W)) 56 | /** AXI4 read and write addr */ 57 | val req_addr_q = RegInit(0.U(32.W)) 58 | val req_addr_q_before = RegInit(0.U(32.W)) 59 | val req_addr_q_before_read_delay = RegInit(0.U((32 * (SDRAM_READ_LATENCY + 1)).W)) 60 | /** AXI4 write request enable */ 61 | val req_wr_q = RegInit(false.B) 62 | val req_wr_q_q = RegInit(false.B) 63 | /** AXI4 read request enable */ 64 | val req_rd_q = RegInit(false.B) 65 | /** AXI4 read and write request id */ 66 | val req_id_q = RegInit(0.U(4.W)) 67 | /** AXI4 read and write burst type */ 68 | val req_axburst_q = RegInit(0.U(2.W)) 69 | /** AXI4 read and write burst length */ 70 | val req_axlen_q = RegInit(0.U(8.W)) 71 | val req_axsize_q = RegInit(0.U(3.W)) 72 | /** AXI4 read and write priority, when ar or aw handshake happen, it will 73 | * flip value, ensure that when neither the read nor the write request is 74 | * in the hold state, if prio is high, write is executed, otherwise read is 75 | * executed. 76 | */ 77 | val req_prio_q = RegInit(false.B) 78 | /** SDRAM write mask, it cotains both enable and mask functions. when it 79 | * don't equal 4'b0000, it represent write is enable. Since the data bit of 80 | * AXI4 is 32 and that of SDRAM is 16, write operation is divided into 2 81 | * steps, the lower 2 bit of mask are used for the first write (WRITE0), 82 | * and the upper 2 bit are used for the second write (WRITE1). 83 | */ 84 | val ram_wr = WireInit(0.U(4.W)) 85 | /** SDRAM read enalbe */ 86 | val ram_rd = WireInit(0.U(1.W)) 87 | /** SDRAM accept enable */ 88 | val ram_accept = WireInit(false.B) 89 | 90 | dontTouch(req_len_q) 91 | dontTouch(req_addr_q) 92 | dontTouch(req_wr_q) 93 | dontTouch(req_wr_q_q) 94 | dontTouch(req_rd_q) 95 | dontTouch(req_id_q) 96 | dontTouch(req_axburst_q) 97 | dontTouch(req_axlen_q) 98 | dontTouch(req_prio_q) 99 | dontTouch(ram_wr) 100 | dontTouch(ram_rd) 101 | dontTouch(ram_accept) 102 | 103 | req_wr_q_q := req_wr_q 104 | 105 | /** When SDRAM mode is brust, let it perform read or write operation 106 | * continuously before request ends. 107 | */ 108 | when((ram_wr =/= 0.U || ram_rd === 1.U) && ram_accept) { 109 | when(req_len_q === 0.U) { 110 | req_rd_q := false.B 111 | req_wr_q := false.B 112 | } 113 | req_addr_q := calculateAddressNext(req_addr_q, req_axburst_q, req_axlen_q, req_axsize_q) 114 | req_addr_q_before := req_addr_q 115 | req_len_q := req_len_q - 1.U 116 | } 117 | 118 | req_addr_q_before_read_delay := Cat(req_addr_q_before, req_addr_q_before_read_delay) >> 32.U 119 | 120 | /** When read or write handshake happens, update request registers. */ 121 | when(axi.aw.valid && axi.aw.ready) { 122 | when(axi.w.valid && axi.w.ready) { 123 | req_wr_q := !axi.w.bits.last 124 | req_len_q := axi.aw.bits.len - 1.U 125 | req_id_q := axi.aw.bits.id 126 | req_axburst_q := axi.aw.bits.burst 127 | req_axlen_q := axi.aw.bits.len 128 | req_axsize_q := axi.aw.bits.size 129 | req_addr_q := calculateAddressNext( 130 | axi.aw.bits.addr, 131 | axi.aw.bits.burst, 132 | axi.aw.bits.len, 133 | axi.aw.bits.size 134 | ) 135 | req_addr_q_before := axi.aw.bits.addr 136 | } 137 | .otherwise { 138 | req_wr_q := true.B 139 | req_len_q := axi.aw.bits.len 140 | req_id_q := axi.aw.bits.id 141 | req_axburst_q := axi.aw.bits.burst 142 | req_axlen_q := axi.aw.bits.len 143 | req_axsize_q := axi.aw.bits.size 144 | req_addr_q := axi.aw.bits.addr 145 | req_addr_q_before := req_addr_q 146 | } 147 | req_prio_q := !req_prio_q 148 | } 149 | .elsewhen(axi.ar.valid && axi.ar.ready) { 150 | req_rd_q := (axi.ar.bits.len =/= 0.U) 151 | req_len_q := axi.ar.bits.len - 1.U 152 | req_addr_q := calculateAddressNext( 153 | axi.ar.bits.addr, 154 | axi.ar.bits.burst, 155 | axi.ar.bits.len, 156 | axi.ar.bits.size 157 | ) 158 | req_addr_q_before := axi.ar.bits.addr 159 | req_id_q := axi.ar.bits.id 160 | req_axburst_q := axi.ar.bits.burst 161 | req_axlen_q := axi.ar.bits.len 162 | req_axsize_q := axi.ar.bits.size 163 | req_prio_q := !req_prio_q 164 | } 165 | 166 | /** AXI4 read request hold status */ 167 | val req_hold_rd_q = RegInit(false.B) 168 | /** AXI4 write request hold status */ 169 | val req_hold_wr_q = RegInit(false.B) 170 | 171 | dontTouch(req_hold_rd_q) 172 | dontTouch(req_hold_wr_q) 173 | 174 | /** When AXI4 read or write request is enable and cannot accept data, assert 175 | * corresponding hold status, otherwise deassert. 176 | */ 177 | when(ram_rd === 1.U && !ram_accept) { 178 | req_hold_rd_q := true.B 179 | } 180 | .elsewhen(ram_accept) { 181 | req_hold_rd_q := false.B 182 | } 183 | when(ram_wr =/= 0.U && !ram_accept) { 184 | req_hold_wr_q := true.B 185 | } 186 | .elsewhen(ram_accept) { 187 | req_hold_wr_q := false.B 188 | } 189 | 190 | // ------------------------------------------------------------------------ 191 | // AXI4 Request Tracking 192 | // ------------------------------------------------------------------------ 193 | /** AXI4 request push enable */ 194 | val req_push_w = ((ram_rd === 1.U) || (ram_wr =/= 0.U)) && ram_accept 195 | /** AXI4 request input control Req[5]: Request Status, 0 = Write, 1 = Read 196 | * Req[4]: AXI4 Address or Request Length Status, 0 = Length > 1, 1 = 197 | * Length equal 0 Req[3 : 0]: AXI4 Address ID 198 | */ 199 | val req_in_w = WireInit(0.U(6.W)) 200 | /** AXI4 request output valid enable */ 201 | val req_out_valid_w = WireInit(false.B) 202 | /** AXI4 request out control */ 203 | val req_out_w = WireInit(0.U(6.W)) 204 | val req_out_wr_r = RegInit(false.B) 205 | val req_out_rd_r = RegInit(0.U(SDRAM_READ_LATENCY.W)) 206 | /** AXI4 response accept enable */ 207 | val resp_accept_w = WireInit(false.B) 208 | /** AXI4 request FIFO accept enable */ 209 | val req_fifo_accept_w = WireInit(false.B) 210 | /** SDRAM read data */ 211 | val ram_read_data_w = WireInit(0.U(32.W)) 212 | /** SDRAM ack enable */ 213 | val ram_ack_w = WireInit(false.B) 214 | /** SDRAM accept enable */ 215 | val ram_accept_w = WireInit(false.B) 216 | 217 | dontTouch(req_push_w) 218 | dontTouch(req_in_w) 219 | dontTouch(req_out_valid_w) 220 | dontTouch(req_out_w) 221 | dontTouch(req_out_rd_r) 222 | dontTouch(resp_accept_w) 223 | dontTouch(req_fifo_accept_w) 224 | dontTouch(ram_read_data_w) 225 | dontTouch(ram_ack_w) 226 | dontTouch(ram_accept_w) 227 | 228 | when(axi.ar.valid && axi.ar.ready) { 229 | req_in_w := Cat(1.U(1.W), axi.ar.bits.len === 0.U, axi.ar.bits.id) 230 | } 231 | .elsewhen(axi.aw.valid && axi.aw.ready) { 232 | req_in_w := Cat(0.U(1.W), axi.aw.bits.len === 0.U, axi.aw.bits.id) 233 | } 234 | .otherwise { 235 | req_in_w := Cat(ram_rd, req_len_q === 0.U, req_id_q) 236 | } 237 | 238 | val u_requests: Instance[DW_fifo_s1_sf] = Instantiate(new DW_fifo_s1_sf( 239 | org.chipsalliance.dwbb.interface.DW_fifo_s1_sf.Parameter( 240 | width = req_in_w.getWidth, 241 | depth = 4, 242 | aeLevel = 1, 243 | afLevel = 1, 244 | errMode = "pointer_latched", 245 | rstMode = "async_with_mem" 246 | ) 247 | )) 248 | u_requests.io.clk := clock 249 | u_requests.io.rst_n := !reset 250 | 251 | u_requests.io.data_in := req_in_w 252 | u_requests.io.push_req_n := !req_push_w 253 | req_fifo_accept_w := !u_requests.io.full 254 | 255 | u_requests.io.diag_n := true.B 256 | u_requests.io.pop_req_n := !resp_accept_w 257 | req_out_w := u_requests.io.data_out 258 | req_out_valid_w := !u_requests.io.empty 259 | 260 | dontTouch(u_requests.io) 261 | 262 | val resp_is_write_w = Mux(req_out_valid_w, ~req_out_w(5), false.B) 263 | val resp_is_read_w = Mux(req_out_valid_w, req_out_w(5), false.B) 264 | val resp_is_last_w = req_out_w(4) 265 | val resp_id_w = req_out_w(3, 0) 266 | 267 | dontTouch(resp_is_write_w) 268 | dontTouch(resp_is_read_w) 269 | dontTouch(resp_is_last_w) 270 | dontTouch(resp_id_w) 271 | 272 | // ------------------------------------------------------------------------ 273 | // AXI4 Response Buffering 274 | // ------------------------------------------------------------------------ 275 | val resp_valid_w = WireInit(false.B) 276 | 277 | val u_response: Instance[DW_fifo_s1_sf] = Instantiate(new DW_fifo_s1_sf( 278 | org.chipsalliance.dwbb.interface.DW_fifo_s1_sf.Parameter( 279 | width = ram_read_data_w.getWidth, 280 | depth = 4, 281 | aeLevel = 1, 282 | afLevel = 1, 283 | errMode = "pointer_latched", 284 | rstMode = "async_with_mem" 285 | ) 286 | )) 287 | u_response.io.clk := clock 288 | u_response.io.rst_n := !reset 289 | 290 | val ram_addr_w_out = WireInit(0.U(32.W)) 291 | 292 | u_response.io.data_in := ram_read_data_w >> (req_addr_q_before_read_delay(1, 0) << 3.U) 293 | u_response.io.push_req_n := !ram_ack_w 294 | 295 | u_response.io.diag_n := true.B 296 | u_response.io.pop_req_n := !resp_accept_w 297 | axi.r.bits.data := u_response.io.data_out 298 | resp_valid_w := !u_response.io.empty 299 | 300 | dontTouch(u_response.io) 301 | 302 | // ------------------------------------------------------------------------ 303 | // AXI4 Request 304 | // ------------------------------------------------------------------------ 305 | val write_prio_w = (!req_prio_q && !req_hold_rd_q) || req_hold_wr_q 306 | val read_prio_w = (req_prio_q && !req_hold_wr_q) || req_hold_rd_q 307 | 308 | dontTouch(write_prio_w) 309 | dontTouch(read_prio_w) 310 | 311 | val write_active_w = (axi.aw.valid || req_wr_q) && 312 | !req_rd_q && 313 | req_fifo_accept_w && 314 | (write_prio_w || req_wr_q || !axi.ar.valid) 315 | val read_active_w = (axi.ar.valid || req_rd_q) && 316 | !req_wr_q && 317 | req_fifo_accept_w && 318 | (read_prio_w || req_rd_q || !axi.aw.valid) 319 | 320 | dontTouch(write_active_w) 321 | dontTouch(read_active_w) 322 | 323 | axi.aw.ready := write_active_w && !req_wr_q && ram_accept_w && req_fifo_accept_w; 324 | axi.w.ready := write_active_w && ram_accept_w && req_fifo_accept_w; 325 | axi.ar.ready := read_active_w && !req_rd_q && ram_accept_w && req_fifo_accept_w; 326 | dontTouch(axi.aw.ready) 327 | dontTouch(axi.w.ready) 328 | dontTouch(axi.ar.ready) 329 | 330 | val addr_w = Mux( 331 | req_wr_q || req_rd_q, 332 | req_addr_q, 333 | Mux(write_active_w, axi.aw.bits.addr, axi.ar.bits.addr) 334 | ) 335 | 336 | dontTouch(addr_w) 337 | 338 | // val wr_w = write_active_w && axi.w.valid 339 | val wr_w = write_active_w 340 | val rd_w = read_active_w 341 | 342 | dontTouch(wr_w) 343 | dontTouch(rd_w) 344 | 345 | val ram_addr_w = addr_w 346 | ram_addr_w_out := addr_w 347 | val ram_write_data_w = axi.w.bits.data 348 | val ram_rd_w = rd_w 349 | val ram_wr_w = Mux(wr_w, axi.w.bits.strb, 0.U(4.W)) 350 | 351 | dontTouch(ram_addr_w) 352 | dontTouch(ram_write_data_w) 353 | dontTouch(ram_rd_w) 354 | dontTouch(ram_wr_w) 355 | 356 | // ------------------------------------------------------------------------ 357 | // AXI4 Response 358 | // ------------------------------------------------------------------------ 359 | // axi.b.valid := resp_valid_w && resp_is_write_w.asBool && resp_is_last_w 360 | axi.b.valid := Mux(req_axlen_q =/= 0.U, 361 | resp_valid_w && resp_is_write_w.asBool && resp_is_last_w, 362 | resp_valid_w && resp_is_write_w.asBool && resp_is_last_w && !req_wr_q_q) 363 | axi.b.bits.resp := 0.U(2.W) 364 | axi.b.bits.id := resp_id_w 365 | axi.b.bits.user := 0.U 366 | 367 | dontTouch(axi.b.valid) 368 | dontTouch(axi.b.bits.resp) 369 | dontTouch(axi.b.bits.id) 370 | dontTouch(axi.b.bits.user) 371 | 372 | axi.r.valid := resp_valid_w && resp_is_read_w 373 | axi.r.bits.resp := 0.U(2.W) 374 | axi.r.bits.id := resp_id_w 375 | axi.r.bits.last := resp_is_last_w 376 | axi.r.bits.user := 0.U 377 | 378 | dontTouch(axi.r.valid) 379 | dontTouch(axi.r.bits.resp) 380 | dontTouch(axi.r.bits.id) 381 | dontTouch(axi.r.bits.last) 382 | dontTouch(axi.r.bits.user) 383 | 384 | resp_accept_w := (axi.r.valid && axi.r.ready) || 385 | (axi.b.valid && axi.b.ready) || 386 | (resp_valid_w && resp_is_write_w.asBool && !resp_is_last_w) 387 | 388 | dontTouch(resp_accept_w) 389 | 390 | // ======================================================================== 391 | // SDRAM Controller 392 | // ======================================================================== 393 | // ------------------------------------------------------------------------ 394 | // SDRAM Parameters 395 | // ------------------------------------------------------------------------ 396 | /** SDRAM External Parameters (User can customize them) */ 397 | val SDRAM_MHZ = 100 398 | val SDRAM_ADDR_W = 24 399 | val SDRAM_COL_W = 9 400 | 401 | /** SDRAM Internal Parameters */ 402 | /** SDRAM Data Width */ 403 | val SDRAM_DATA_W = 16 404 | 405 | /** SDRAM Bank Width */ 406 | val SDRAM_BANK_W = 2 407 | 408 | /** SDRAM Bank Number */ 409 | val SDRAM_BANK_N = 1 << SDRAM_BANK_W 410 | 411 | /** SDRAM DQM Width */ 412 | val SDRAM_DQM_W = 2 413 | 414 | /** SDRAM Row Width */ 415 | // 13 416 | val SDRAM_ROW_W = SDRAM_ADDR_W - SDRAM_COL_W - SDRAM_BANK_W 417 | 418 | /** SDRAM Refresh Counter */ 419 | // 8192 = 1 << 13 420 | val SDRAM_REFRESH_CNT = 1 << SDRAM_ROW_W 421 | 422 | /** SDRAM INIT time (100us) */ 423 | // 5000 = 100000 / (1000 / 50) 424 | val SDRAM_TIME_INIT = 100000 / (1000 / SDRAM_MHZ) 425 | 426 | /** SDRAM Timing Parameters */ 427 | /** Time per cycle */ 428 | val SDRAM_CYCLE_NS = 1000 / SDRAM_MHZ 429 | 430 | /** Cycles between ACTIVE and READ/WRITE */ 431 | val SDRAM_CYCLES_TRCD = (20 + (SDRAM_CYCLE_NS - 1)) / SDRAM_CYCLE_NS 432 | 433 | /** Cycles between PRECHARGE and ACTIVE */ 434 | val SDRAM_CYCLES_TRP = (20 + (SDRAM_CYCLE_NS - 1)) / SDRAM_CYCLE_NS 435 | 436 | /** Cycles between REFRESH and OTHER COMMAND */ 437 | val SDRAM_CYCLES_TRFC = (60 + (SDRAM_CYCLE_NS - 1)) / SDRAM_CYCLE_NS 438 | 439 | /** Cycles of REFRESH */ 440 | // 390 = 64000 * 50 / 8192 441 | val SDRAM_CYCLES_REFRESH = (64000 * SDRAM_MHZ) / SDRAM_REFRESH_CNT - 1 442 | 443 | /** The NO OPERATION (NOP) command is used to perform a NOP to the selected 444 | * device (CS# is LOW). This prevents unwanted commands from being 445 | * registered during idle or wait states. Operations already in progress 446 | * are not affected. 447 | */ 448 | val CMD_NOP = "b0111".U(4.W) 449 | 450 | /** The mode registers are loaded via inputs A[n : 0] (where An is the most 451 | * significant address term), BA0, and BA1(see "Mode Register"). The LOAD 452 | * MODE REGISTER command can only be issued when all banks are idle and a 453 | * subsequent executable command cannot be issued until tMRD is met. 454 | */ 455 | val CMD_LMR = "b0000".U(4.W) 456 | 457 | /** The ACTIVE command is used to activate a row in a particular bank for a 458 | * subsequent access. The value on the BA0, BA1 inputs selects the bank, 459 | * and the address provided selects the row. This row remains active for 460 | * accesses until a PRECHARGE command is issued to that bank. A PRECHARGE 461 | * command must be issued before opening a different row in the same bank. 462 | */ 463 | val CMD_ACTIVE = "b0011".U(4.W) 464 | 465 | /** The READ command is used to initiate a burst read access to an active 466 | * row. The values on the BA0 and BA1 inputs select the bank; the address 467 | * provided selects the starting column location. The value on input A10 468 | * determines whether auto precharge is used. If auto precharge is 469 | * selected, the row being accessed is precharged at the end of the READ 470 | * burst; if auto precharge is not selected, the row remains open for 471 | * subsequent accesses. Read data appears on the DQ subject to the logic 472 | * level on the DQM inputs two clocks earlier. If a given DQM signal was 473 | * registered HIGH, the corresponding DQ will be High-Z two clocks later; 474 | * if the DQM signal was registered LOW, the DQ will provide valid data. 475 | */ 476 | val CMD_READ = "b0101".U(4.W) 477 | 478 | /** The WRITE command is used to initiate a burst write access to an active 479 | * row. The values on the BA0 and BA1 inputs select the bank; the address 480 | * provided selects the starting column ocation. The value on input A10 481 | * determines whether auto precharge is used. If auto precharge is 482 | * selected, the row being accessed is precharged at the end of the write 483 | * burst; if auto precharge is not selected, the row remains open for 484 | * subsequent accesses. Input data appearing on the DQ is written to the 485 | * memory array, subject to the DQM input logic level appearing coincident 486 | * with the data. If a given DQM signal is registered LOW, the 487 | * corresponding data is written to memory; if the DQM signal is registered 488 | * HIGH, the corresponding data inputs are ignored and a WRITE is not 489 | * executed to that byte/column location. 490 | */ 491 | val CMD_WRITE = "b0100".U(4.W) 492 | 493 | /** The PRECHARGE command is used to deactivate the open row in a particular 494 | * bank or the open row in all banks. The bank(s) will be available for a 495 | * subsequent row access a specified time (tRP) after the PRECHARGE command 496 | * is issued. Input A10 determines whether one or all banks are to be 497 | * precharged, and in the case where only one bank is precharged, inputs 498 | * BA0 and BA1 select the bank. Otherwise BA0 and BA1 are treated as "Don’t 499 | * Care." After a bank has been precharged, it is in the idle state and 500 | * must be activated prior to any READ or WRITE commands are issued to that 501 | * bank. 502 | */ 503 | val CMD_PRECHARGE = "b0010".U(4.W) 504 | 505 | /** AUTO REFRESH is used during normal operation of the SDRAM and is 506 | * analogous to CAS#-BEFORE-RAS# (CBR) refresh in conventional DRAMs. This 507 | * command is nonpersistent, so it must be issued each time a refresh is 508 | * required. All active banks must be precharged prior to issuing an AUTO 509 | * REFRESH command. The AUTO REFRESH command should not be issued until the 510 | * minimum tRP has been met after the PRECHARGE command, as shown in 511 | * Bank/Row Activation. 512 | */ 513 | val CMD_REFRESH = "b0001".U(4.W) 514 | 515 | /** Mode Register Definition (A[12 : 00]) A[12 : 10]: Reserved. A[09]: Write 516 | * Burst Mode. When A[09] = 0, the burst length programmed via A[02 : 00] 517 | * applies to both READ and WRITE bursts; when A[09] = 1, the programmed 518 | * burst length applies to READ bursts, but write accesses are 519 | * single-location (nonburst) accesses. 0 -> Programmed Burst Length 1 - > 520 | * Single Location Access A[08 : 07]: Operating Mode. The normal operating 521 | * mode is selected by setting A[07] and A[08] to zero; the other 522 | * combinations of values for A[07] and A[08] are reserved for future use. 523 | * Reserved states should not be used because unknown operation or 524 | * incompatibility with future versions may result. 00 -> Standard 525 | * Operation xx -> All other states reserved A[06 : 04]: CAS Latency. The 526 | * CAS latency (CL) is the delay, in clock cycles, between the registration 527 | * of a READ command and the availability of the output data. The latency 528 | * can be set to two or three clocks. 001 -> 1 010 -> 2 011 -> 3 A[03]: 529 | * Burst Type. Accesses within a given burst can be programmed to be either 530 | * sequential or interleaved; this is referred to as the burst type and is 531 | * selected via bit A[03]. 0 -> Sequential 1 -> Interleaved A[02 : 00]: 532 | * Burst Length. Read and write accesses to the device are burst oriented, 533 | * and the burst length (BL) is programmable. The burst length determines 534 | * the maximum number of column locations that can be accessed for a given 535 | * READ or WRITE command. Burst lengths of 1, 2, 4, 8, or continuous 536 | * locations are available for both the sequential and the interleaved 537 | * burst types, and a continuous page burst is available for the sequential 538 | * type. The continuous page burst is used in conjunction with the BURST 539 | * TERMINATE command to generate arbitrary burst lengths. 000 -> 1 001 -> 2 540 | * 010 -> 4 011 -> 8 111 -> Full Page(Only A[03] = 0, Burst Type is 541 | * Sequential] 542 | * ----------------------------------------------------------------------- 543 | * SDRAM Mode: CAS Latency = 2, Burst Type = Sequential, Burst Length = 2 544 | */ 545 | val MODE_REGISTER = Cat( 546 | "b000".U(3.W), 547 | 0.U(1.W), 548 | 0.U(2.W), 549 | "b010".U(3.W), 550 | 0.U(1.W), 551 | "b001".U(3.W) 552 | ) 553 | 554 | /** SDRAM State Machines */ 555 | val STATE_W = 4 556 | val STATE_INIT = 0.U(STATE_W.W) 557 | val STATE_DELAY = 1.U(STATE_W.W) 558 | val STATE_IDLE = 2.U(STATE_W.W) 559 | val STATE_ACTIVATE = 3.U(STATE_W.W) 560 | val STATE_READ = 4.U(STATE_W.W) 561 | val STATE_READ_WAIT = 5.U(STATE_W.W) 562 | val STATE_WRITE0 = 6.U(STATE_W.W) 563 | val STATE_WRITE1 = 7.U(STATE_W.W) 564 | val STATE_PRECHARGE = 8.U(STATE_W.W) 565 | val STATE_REFRESH = 9.U(STATE_W.W) 566 | 567 | /** A10 is special bit in A[12 : 00], when current state is PRECHARGE, if 568 | * A10 is 1, it represent all 4 banks will be precharged; When current 569 | * state is READ or WRITE, if A10 is 1, a precharge of the bank/row that is 570 | * addressed with the READ or WRITE command is automatically performed upon 571 | * completion of the READ or WRITE burst, except in the continuous page 572 | * burst mode where auto precharge does not apply. 573 | */ 574 | val BIT_AUTO_PRECHARGE = 10 575 | val BIT_ALL_BANKS = 10 576 | 577 | // ------------------------------------------------------------------------ 578 | // SDRAM Wires and Registers 579 | // ------------------------------------------------------------------------ 580 | /** SDRAM Read or Write request */ 581 | val ram_req_w = (ram_wr_w =/= 0.U) || ram_rd_w 582 | /** SDRAM Command */ 583 | val command_q = RegInit(CMD_NOP) 584 | /** SDRAM Row Address */ 585 | val addr_q = RegInit(0.U(SDRAM_ROW_W.W)) 586 | /** SDRAM Data */ 587 | val data_q = RegInit(0.U(SDRAM_DATA_W.W)) 588 | /** SDRAM Read Enable */ 589 | val data_rd_en_q = RegInit(true.B) 590 | /** SDRAM DQM */ 591 | val dqm_q = RegInit(0.U(SDRAM_DQM_W.W)) 592 | /** SDRAM Clock Enable */ 593 | val cke_q = RegInit(false.B) 594 | /** SDRAM Bank Address */ 595 | val bank_q = RegInit(0.U(SDRAM_BANK_W.W)) 596 | /** During READ and WRITE command, use buffer to receive stable data. */ 597 | /** SDRAM Data Buffer */ 598 | val data_buffer_q = RegInit(0.U(SDRAM_DATA_W.W)) 599 | /** SDRAM DQM Buffer */ 600 | val dqm_buffer_q = RegInit(0.U(SDRAM_DQM_W.W)) 601 | /** SDRAM Input Data */ 602 | val sdram_data_in_w = WireInit(0.U(SDRAM_DATA_W.W)) 603 | /** SDRAM Refresh Enable */ 604 | val refresh_q = RegInit(false.B) 605 | /** SDRAM Open Row Enable (Every bit represents different bank) */ 606 | val row_open_q = RegInit(0.U(SDRAM_BANK_N.W)) 607 | /** SDRAM Active Row Enable */ 608 | val active_row_q = RegInit(VecInit.fill(SDRAM_BANK_N)(0.U(SDRAM_ROW_W.W))) 609 | /** Current State */ 610 | val state_q = RegInit(STATE_INIT) 611 | /** Next State */ 612 | val next_state_r = RegInit(STATE_INIT) 613 | /** Next State wire*/ 614 | val next_state_r_w = WireInit(STATE_INIT) 615 | /** Target State (Next). When current state is ACTIVATE, use it to indicate 616 | * whether next state is READ or WRITE. When current state is PRECHARGE, 617 | * REFRESH priority is higher than ACTIVE, if target state is REFRESH, let 618 | * next state is REFRESH, otherwise is ACTIVATE. 619 | */ 620 | val target_state_r = RegInit(STATE_IDLE) 621 | /** Target State (Next) wire */ 622 | val target_state_r_w = WireInit(STATE_IDLE) 623 | /** Target State (Current) */ 624 | val target_state_q = RegInit(STATE_IDLE) 625 | /** Deleay State (Used for all delay operations) */ 626 | val delay_state_q = RegInit(STATE_IDLE) 627 | 628 | dontTouch(ram_req_w) 629 | dontTouch(command_q) 630 | dontTouch(addr_q) 631 | dontTouch(data_q) 632 | dontTouch(data_rd_en_q) 633 | dontTouch(dqm_q) 634 | dontTouch(cke_q) 635 | dontTouch(bank_q) 636 | dontTouch(data_buffer_q) 637 | dontTouch(dqm_buffer_q) 638 | dontTouch(sdram_data_in_w) 639 | dontTouch(refresh_q) 640 | dontTouch(row_open_q) 641 | dontTouch(active_row_q) 642 | dontTouch(state_q) 643 | dontTouch(next_state_r) 644 | dontTouch(next_state_r_w) 645 | dontTouch(target_state_r) 646 | dontTouch(target_state_r_w) 647 | dontTouch(target_state_q) 648 | dontTouch(delay_state_q) 649 | 650 | /** SDRAM Column Address (Current) */ 651 | // {4'b0, ram_addr_w[9 : 2], 1'b0} 652 | val addr_col_w = Cat( 653 | Fill(SDRAM_ROW_W - SDRAM_COL_W, 0.U(1.W)), 654 | ram_addr_w(SDRAM_COL_W, 2), 655 | 0.U(1.W) 656 | ) 657 | /** SDRAM Row Address (Current) */ 658 | // ram_addr_w[24 : 12] 659 | val addr_row_w = ram_addr_w(SDRAM_ADDR_W, SDRAM_COL_W + 2 + 1) 660 | /** SDRAM Bank Address (Current) */ 661 | // ram_addr_w[11 : 10] 662 | val addr_bank_w = ram_addr_w(SDRAM_COL_W + 2, SDRAM_COL_W + 2 - 1) 663 | 664 | dontTouch(addr_col_w) 665 | dontTouch(addr_row_w) 666 | dontTouch(addr_bank_w) 667 | 668 | // ------------------------------------------------------------------------ 669 | // SDRAM State Machine 670 | // ------------------------------------------------------------------------ 671 | /** Todo: Use Decode api and Mux1H to refactor state machine */ 672 | /* SDRAM State Truth Table 673 | * +------------+----------------------+---------------------------------------------------+ 674 | * | Current | CS#, RAS#, CAS#, WE# | Action | 675 | * +------------+----------------------+---------------------------------------------------+ 676 | * | * | 1XXX/0111 | NOP | 677 | * +------------+----------------------+---------------------------------------------------+ 678 | * | | 0011 | ACTIVE (select and activate row) | 679 | * | +----------------------+---------------------------------------------------+ 680 | * | | 0001 | AUTO REFRESH | 681 | * | Idle +----------------------+---------------------------------------------------+ 682 | * | | 0000 | LOAD MODE REGISTER | 683 | * | +----------------------+---------------------------------------------------+ 684 | * | | 0010 | PRECHARGE | 685 | * +------------+----------------------+---------------------------------------------------+ 686 | * | | 0101 | READ (select column and start READ burst) | 687 | * | +----------------------+---------------------------------------------------+ 688 | * | Row active | 0100 | WRITE (select column and start WRITE burst) | 689 | * | +----------------------+---------------------------------------------------+ 690 | * | | 0010 | PRECHARGE (deactivate row in bank or banks) | 691 | * +------------+----------------------+---------------------------------------------------+ 692 | * | | 0101 | READ (select column and start new READ burst) | 693 | * | +----------------------+---------------------------------------------------+ 694 | * | | 0100 | WRITE (select column and start WRITE burst) | 695 | * | Read +----------------------+---------------------------------------------------+ 696 | * | | 0010 | PRECHARGE (truncate READ burst, start PRECHARGE) | 697 | * | +----------------------+---------------------------------------------------+ 698 | * | | 0110 | BURST TERMINATE | 699 | * +------------+----------------------+---------------------------------------------------+ 700 | * | | 0101 | READ (select column and start new READ burst) | 701 | * | +----------------------+---------------------------------------------------+ 702 | * | | 0100 | WRITE (select column and start WRITE burst) | 703 | * | Write +----------------------+---------------------------------------------------+ 704 | * | | 0010 | PRECHARGE (truncate WRITE burst, start PRECHARGE) | 705 | * | +----------------------+---------------------------------------------------+ 706 | * | | 0110 | BURST TERMINATE | 707 | * +------------+----------------------+---------------------------------------------------+ 708 | */ 709 | 710 | next_state_r_w := state_q 711 | target_state_r_w := target_state_q 712 | 713 | switch(state_q) { 714 | /** Next State is IDLE, when the number of refresh is reached. */ 715 | is(STATE_INIT) { 716 | when(refresh_q) { 717 | next_state_r_w := STATE_IDLE 718 | } 719 | } 720 | /** IDLE is the most important STATE, it determine which state to jump to 721 | * next based on conditions such as refresh counter, request enable, and 722 | * row open, etc. 723 | */ 724 | is(STATE_IDLE) { 725 | when(refresh_q) { 726 | /** Close open rows, then refresh */ 727 | when(row_open_q =/= 0.U) { 728 | next_state_r_w := STATE_PRECHARGE 729 | } 730 | .otherwise { 731 | next_state_r_w := STATE_REFRESH 732 | } 733 | target_state_r_w := STATE_REFRESH 734 | } 735 | .elsewhen(ram_req_w) { 736 | /** Open row and active row hit at the same time */ 737 | when( 738 | row_open_q(addr_bank_w) && 739 | (addr_row_w === active_row_q(addr_bank_w)) 740 | ) { 741 | when(!ram_rd_w) { 742 | next_state_r_w := STATE_WRITE0 743 | }.otherwise { 744 | next_state_r_w := STATE_READ 745 | } 746 | } 747 | /** Open row miss, close it and open new row */ 748 | .elsewhen(row_open_q(addr_bank_w)) { 749 | next_state_r_w := STATE_PRECHARGE 750 | when(!ram_rd_w) { 751 | target_state_r_w := STATE_WRITE0 752 | }.otherwise { 753 | target_state_r_w := STATE_READ 754 | } 755 | } 756 | /** No open row, open row */ 757 | .otherwise { 758 | next_state_r_w := STATE_ACTIVATE 759 | when(!ram_rd_w) { 760 | target_state_r_w := STATE_WRITE0 761 | }.otherwise { 762 | target_state_r_w := STATE_READ 763 | } 764 | } 765 | } 766 | } 767 | /** Before executing READ or WRITE, ACTIVATE must be executed, so by 768 | * getting the value of target state, state machine can jump to the 769 | * corresponding READ or WRITE state. 770 | */ 771 | is(STATE_ACTIVATE) { 772 | next_state_r_w := target_state_r_w 773 | } 774 | /** Next State is READ_WAIT */ 775 | is(STATE_READ) { 776 | next_state_r_w := STATE_READ_WAIT 777 | } 778 | /** Default next state is IDLE, but if another READ request with no 779 | * refresh come, and its bank hits and row is active, next state is still 780 | * READ. 781 | */ 782 | is(STATE_READ_WAIT) { 783 | next_state_r_w := STATE_IDLE 784 | when(!refresh_q && ram_req_w && ram_rd_w) { 785 | when( 786 | row_open_q(addr_bank_w) && 787 | (addr_row_w === active_row_q(addr_bank_w)) 788 | ) { 789 | next_state_r_w := STATE_READ 790 | } 791 | } 792 | } 793 | /** Next State is WRITE1 */ 794 | is(STATE_WRITE0) { 795 | next_state_r_w := STATE_WRITE1 796 | } 797 | /** Default next state is IDLE, but if another WRITE request with no 798 | * refresh come, and its bank hits and row is active, next state is still 799 | * WRITE. 800 | */ 801 | is(STATE_WRITE1) { 802 | next_state_r_w := STATE_IDLE 803 | when(!refresh_q && ram_req_w && ram_wr_w =/= 0.U) { 804 | when( 805 | row_open_q(addr_bank_w) && 806 | (addr_row_w === active_row_q(addr_bank_w)) 807 | ) { 808 | next_state_r_w := STATE_WRITE0 809 | } 810 | } 811 | } 812 | /** REFRESH priority is higher than ACTIVE, if target state is REFRESH, 813 | * let next state is REFRESH, otherwise is ACTIVATE. 814 | */ 815 | is(STATE_PRECHARGE) { 816 | when(target_state_r_w === STATE_REFRESH) { 817 | next_state_r_w := STATE_REFRESH 818 | }.otherwise { 819 | next_state_r_w := STATE_ACTIVATE 820 | } 821 | } 822 | /** Next State is IDLE */ 823 | is(STATE_REFRESH) { 824 | next_state_r_w := STATE_IDLE 825 | } 826 | is(STATE_DELAY) { 827 | next_state_r_w := delay_state_q 828 | } 829 | } 830 | next_state_r := next_state_r_w 831 | target_state_r := target_state_r_w 832 | 833 | // ------------------------------------------------------------------------ 834 | // SDRAM Delay Operation 835 | // ------------------------------------------------------------------------ 836 | val DELAY_W = 4 837 | 838 | /** SDRAM Delay (Current) */ 839 | val delay_w = WireInit(0.U(DELAY_W.W)) 840 | /** SDRAM Delay (Next) */ 841 | val delay_r = RegInit(0.U(DELAY_W.W)) 842 | 843 | dontTouch(delay_w) 844 | dontTouch(delay_r) 845 | 846 | delay_r := 0.U(DELAY_W.W) 847 | 848 | switch(state_q) { 849 | is(STATE_ACTIVATE) { 850 | delay_w := SDRAM_CYCLES_TRCD.asUInt 851 | } 852 | is(STATE_READ_WAIT) { 853 | delay_w := SDRAM_READ_LATENCY.asUInt 854 | /** When READ request come, open row and active row hit at the same 855 | * time, don't delay. 856 | */ 857 | when(!refresh_q && ram_req_w && ram_rd_w) { 858 | when( 859 | row_open_q(addr_bank_w) && 860 | (addr_row_w === active_row_q(addr_bank_w)) 861 | ) { 862 | delay_w := 0.U(DELAY_W.W) 863 | } 864 | } 865 | } 866 | is(STATE_PRECHARGE) { 867 | delay_w := SDRAM_CYCLES_TRP.asUInt 868 | } 869 | is(STATE_REFRESH) { 870 | delay_w := SDRAM_CYCLES_TRFC.asUInt 871 | } 872 | } 873 | delay_r := delay_w 874 | 875 | switch(state_q) { 876 | is(STATE_DELAY) { 877 | delay_r := Mux(delay_r =/= 0.U(DELAY_W.W), delay_r - 1.U(DELAY_W.W), delay_r) 878 | } 879 | } 880 | 881 | /** Record target state */ 882 | // target_state_q := target_state_r 883 | target_state_q := target_state_r_w 884 | 885 | /** Record delayed state */ 886 | when (state_q =/= STATE_DELAY && delay_w =/= 0.U(DELAY_W.W)) { 887 | delay_state_q := next_state_r_w 888 | } 889 | 890 | /** Update actual state */ 891 | when (delay_w =/= 0.U(DELAY_W.W)) { 892 | state_q := STATE_DELAY 893 | } 894 | .elsewhen (delay_r === 0.U(DELAY_W.W)) { 895 | state_q := next_state_r_w; 896 | } 897 | 898 | // ------------------------------------------------------------------------ 899 | // SDRAM Refresh Operation 900 | // ------------------------------------------------------------------------ 901 | /** SDRAM Refresh Counter Width */ 902 | val REFRESH_CNT_W = 17 903 | 904 | /** Make ensure INIT is complete */ 905 | val refresh_timer_q = RegInit((SDRAM_TIME_INIT + 100).U(REFRESH_CNT_W.W)) 906 | 907 | dontTouch(refresh_timer_q) 908 | 909 | when(refresh_timer_q === 0.U(REFRESH_CNT_W.W)) { 910 | refresh_timer_q := SDRAM_CYCLES_REFRESH.asUInt 911 | } 912 | .otherwise { 913 | refresh_timer_q := refresh_timer_q - 1.U 914 | } 915 | 916 | when(refresh_timer_q === 0.U(REFRESH_CNT_W.W)) { 917 | refresh_q := true.B 918 | } 919 | .elsewhen (state_q === STATE_REFRESH) { 920 | refresh_q := false.B 921 | } 922 | 923 | // ------------------------------------------------------------------------ 924 | // SDRAM Input Sampling 925 | // ------------------------------------------------------------------------ 926 | /** Use 2-level register to implement input data samping, ensure input data 927 | * is obtained correctly. 928 | */ 929 | val sample_data0_q = RegInit(0.U(SDRAM_DATA_W.W)) 930 | val sample_data_q = RegInit(0.U(SDRAM_DATA_W.W)) 931 | 932 | dontTouch(sample_data0_q) 933 | dontTouch(sample_data_q) 934 | 935 | sample_data0_q := sdram_data_in_w 936 | sample_data_q := sample_data0_q 937 | 938 | // ------------------------------------------------------------------------ 939 | // SDRAM Command Output 940 | // ------------------------------------------------------------------------ 941 | command_q := CMD_NOP 942 | addr_q := 0.U(SDRAM_ROW_W.W) 943 | bank_q := 0.U(SDRAM_BANK_W.W) 944 | data_rd_en_q := true.B 945 | 946 | switch(state_q) { 947 | is(STATE_INIT) { 948 | when(refresh_timer_q === 50.U) { 949 | cke_q := true.B 950 | } 951 | .elsewhen(refresh_timer_q === 40.U) { 952 | command_q := CMD_PRECHARGE 953 | /** Precharge all banks */ 954 | addr_q := addr_q | (1.U(1.W) << BIT_ALL_BANKS) 955 | } 956 | .elsewhen(refresh_timer_q === 20.U || refresh_timer_q === 30.U) { 957 | command_q := CMD_REFRESH 958 | } 959 | .elsewhen(refresh_timer_q === 10.U) { 960 | command_q := CMD_LMR 961 | addr_q := MODE_REGISTER 962 | } 963 | .otherwise { 964 | command_q := CMD_NOP 965 | addr_q := 0.U(SDRAM_ROW_W.W) 966 | bank_q := 0.U(SDRAM_BANK_W.W) 967 | } 968 | } 969 | is(STATE_ACTIVATE) { 970 | command_q := CMD_ACTIVE 971 | addr_q := addr_row_w 972 | bank_q := addr_bank_w 973 | 974 | active_row_q(addr_bank_w) := addr_row_w 975 | row_open_q := row_open_q | (1.U(1.W) << addr_bank_w) 976 | } 977 | is(STATE_PRECHARGE) { 978 | command_q := CMD_PRECHARGE 979 | when(target_state_r === STATE_REFRESH) { 980 | /** Precharge all banks */ 981 | addr_q := addr_q | (1.U(1.W) << BIT_ALL_BANKS) 982 | /** Close all open rows */ 983 | row_open_q := 0.U(SDRAM_BANK_N.W) 984 | } 985 | .otherwise { 986 | /** Precharge specific bank */ 987 | addr_q := addr_q | (0.U(1.W) << BIT_ALL_BANKS) 988 | bank_q := addr_bank_w 989 | /** Close specific open row */ 990 | row_open_q := row_open_q | (0.U(1.W) << addr_bank_w) 991 | } 992 | } 993 | is(STATE_REFRESH) { 994 | command_q := CMD_REFRESH 995 | addr_q := 0.U(SDRAM_ROW_W.W) 996 | bank_q := 0.U(SDRAM_BANK_W.W) 997 | } 998 | is(STATE_READ) { 999 | command_q := CMD_READ 1000 | /** Disable AUTO PRECHARGE (auto close of row) */ 1001 | addr_q := addr_col_w | (0.U(1.W) << BIT_AUTO_PRECHARGE) 1002 | bank_q := addr_bank_w 1003 | 1004 | dqm_q := 0.U(SDRAM_DQM_W.W) 1005 | } 1006 | is(STATE_WRITE0) { 1007 | when (req_wr_q) { 1008 | command_q := CMD_WRITE 1009 | /** Disable AUTO PRECHARGE (auto close of row) */ 1010 | addr_q := addr_col_w | (0.U(1.W) << BIT_AUTO_PRECHARGE) 1011 | bank_q := addr_bank_w 1012 | data_q := ram_write_data_w(15, 0) 1013 | 1014 | /** Because data width is 16 bit, only 2 bits are needed to implement 1015 | * byte mask. Low effective. 1016 | */ 1017 | dqm_q := ~ram_wr_w(1, 0) 1018 | dqm_buffer_q := ~ram_wr_w(3, 2) 1019 | 1020 | data_rd_en_q := false.B 1021 | } 1022 | } 1023 | is(STATE_WRITE1) { 1024 | when (req_wr_q_q) { 1025 | command_q := CMD_NOP 1026 | data_q := data_buffer_q 1027 | 1028 | /** Disable AUTO PRECHARGE (auto close of row) */ 1029 | addr_q := addr_q | (0.U(1.W) << BIT_AUTO_PRECHARGE) 1030 | 1031 | dqm_q := dqm_buffer_q 1032 | } 1033 | } 1034 | } 1035 | 1036 | // ------------------------------------------------------------------------ 1037 | // SDRAM READ State Record 1038 | // ------------------------------------------------------------------------ 1039 | /** The length of register represents READ Latency, each bit represents 1040 | * whether the controller state is READ in different cycle. 1041 | */ 1042 | val rd_q = RegInit(0.U((SDRAM_READ_LATENCY + 2).W)) 1043 | 1044 | dontTouch(rd_q) 1045 | 1046 | rd_q := Cat(rd_q(SDRAM_READ_LATENCY, 0), state_q === STATE_READ) 1047 | 1048 | // ------------------------------------------------------------------------ 1049 | // SDRAM Data Buffer 1050 | // ------------------------------------------------------------------------ 1051 | /** Because SDRAM data width is 16bit, it is neccessary to store high 16-bit 1052 | * data to buffer temporarily. 1053 | */ 1054 | when(state_q === STATE_WRITE0) { 1055 | data_buffer_q := ram_write_data_w(31, 16) 1056 | } 1057 | /** Judge state in the next cycle after delay, if it is READ, then store 1058 | * input sampling to buffer. 1059 | */ 1060 | .elsewhen(rd_q(SDRAM_READ_LATENCY + 1)) { 1061 | data_buffer_q := sample_data_q 1062 | } 1063 | ram_read_data_w := Cat(sample_data_q, data_buffer_q) 1064 | 1065 | // ------------------------------------------------------------------------ 1066 | // SDRAM ACK 1067 | // ------------------------------------------------------------------------ 1068 | /** Pulling signal high indicates that READ or WRITE is complete. */ 1069 | val ack_q = RegInit(false.B) 1070 | 1071 | dontTouch(ack_q) 1072 | 1073 | when(state_q === STATE_WRITE1) { 1074 | ack_q := true.B 1075 | } 1076 | .elsewhen(rd_q(SDRAM_READ_LATENCY + 1)) { 1077 | ack_q := true.B 1078 | } 1079 | .otherwise { 1080 | ack_q := false.B 1081 | } 1082 | 1083 | ram_ack_w := ack_q 1084 | 1085 | /** Pulling signal high indicates that AXI4 read address, write address, 1086 | * write data requests can be accepted for SDRAM. 1087 | */ 1088 | ram_accept_w := (state_q === STATE_READ || state_q === STATE_WRITE0) 1089 | dontTouch(ram_accept_w) 1090 | 1091 | // ------------------------------------------------------------------------ 1092 | // SDRAM Innput / Output 1093 | // ------------------------------------------------------------------------ 1094 | // TODO: this is forbidden in RTL, use CTS blackbox instead. 1095 | sdram.ck.foreach(_ := (clock.asBool).asBool.asClock) 1096 | sdram.cke := cke_q 1097 | sdram.cs := command_q(3) 1098 | sdram.ras := command_q(2) 1099 | sdram.cas := command_q(1) 1100 | sdram.we := command_q(0) 1101 | sdram.dqm := dqm_q 1102 | sdram.ba := bank_q 1103 | sdram.a := addr_q 1104 | sdram.dqDir := ~data_rd_en_q 1105 | sdram.dqo := data_q 1106 | 1107 | sdram_data_in_w := sdram.dqi 1108 | 1109 | ram_wr := ram_wr_w 1110 | ram_rd := ram_rd_w 1111 | ram_accept := ram_accept_w 1112 | 1113 | val dbg_state = WireDefault(BigInt("554e4b4e4f574e", 16).U(80.W)) // "UNKNOWN" 1114 | switch (state_q) { 1115 | is(STATE_INIT) { dbg_state := BigInt("494e4954", 16).U(80.W) } // "INIT" 1116 | is(STATE_DELAY) { dbg_state := BigInt("44454c4159", 16).U(80.W) } // "DELAY" 1117 | is(STATE_IDLE) { dbg_state := BigInt("49444c45", 16).U(80.W) } // "IDLE" 1118 | is(STATE_ACTIVATE) { dbg_state := BigInt("4143544956415445", 16).U(80.W) } // "ACTIVATE" 1119 | is(STATE_READ) { dbg_state := BigInt("52454144", 16).U(80.W) } // "READ" 1120 | is(STATE_READ_WAIT) { dbg_state := BigInt("524541445f57414954", 16).U(80.W) } // "READ_WAIT" 1121 | is(STATE_WRITE0) { dbg_state := BigInt("575249544530", 16).U(80.W) } // "WRITE0" 1122 | is(STATE_WRITE1) { dbg_state := BigInt("575249544531", 16).U(80.W) } // "WRITE1" 1123 | is(STATE_PRECHARGE) { dbg_state := BigInt("505245434841524745", 16).U(80.W) } // "PRECHARGE" 1124 | is(STATE_REFRESH) { dbg_state := BigInt("52454652455348", 16).U(80.W) } // "REFRESH" 1125 | } 1126 | 1127 | val dbg_cmd = WireDefault(BigInt("554e4b4e4f574e", 16).U(80.W)) // "UNKNOWN" 1128 | switch (command_q) { 1129 | is (CMD_NOP) { dbg_cmd := BigInt("4E4F50", 16).U(80.W) } // "NOP" 1130 | is (CMD_LMR) { dbg_cmd := BigInt("4C4D52", 16).U(80.W) } // "LMR" 1131 | is (CMD_ACTIVE) { dbg_cmd := BigInt("414354495645", 16).U(80.W) } // "ACTIVE" 1132 | is (CMD_READ) { dbg_cmd := BigInt("52454144", 16).U(80.W) } // "READ" 1133 | is (CMD_WRITE) { dbg_cmd := BigInt("5752495445", 16).U(80.W) } // "WRITE" 1134 | is (CMD_PRECHARGE) { dbg_cmd := BigInt("505245434841524745", 16).U(80.W) } // "PRECHARGE" 1135 | is (CMD_REFRESH) { dbg_cmd := BigInt("52454652455348", 16).U(80.W) } // "REFRESH" 1136 | } 1137 | } 1138 | } 1139 | -------------------------------------------------------------------------------- /sdramcontroller/src/SDRAMControllerTestBench.scala: -------------------------------------------------------------------------------- 1 | package oscc.sdramcontroller 2 | 3 | import chisel3._ 4 | import chisel3.experimental.hierarchy.{instantiable, public, Instance, Instantiate} 5 | import chisel3.experimental.{SerializableModule, SerializableModuleParameter} 6 | import chisel3.properties.{Class, Property} 7 | import chisel3.util.{Counter, HasExtModuleInline} 8 | import chisel3.util.circt.dpi.{RawClockedNonVoidFunctionCall, RawUnclockedNonVoidFunctionCall} 9 | import chisel3.experimental.dataview.DataViewable 10 | 11 | import scala.util.chaining._ 12 | import org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocableVerilog 13 | import org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocable.viewVerilog 14 | 15 | object SDRAMControllerTestBenchParameter { 16 | implicit def rwP: upickle.default.ReadWriter[SDRAMControllerTestBenchParameter] = 17 | upickle.default.macroRW 18 | } 19 | 20 | case class SDRAMControllerTestBenchParameter( 21 | sdramControllerParameter: SDRAMControllerParameter, 22 | testVerbatimParameter: TestVerbatimParameter, 23 | timeout: Int) 24 | extends SerializableModuleParameter 25 | 26 | class W9825G6KHInterface extends Bundle { 27 | val Dq_i = Input(UInt(32.W)) 28 | val Dq_o = Output(UInt(32.W)) 29 | val Addr = Input(UInt(13.W)) 30 | val Bs = Input(UInt(2.W)) 31 | val Clk = Input(Clock()) 32 | val Cke = Input(Bool()) 33 | val Cs_n = Input(Bool()) 34 | val Ras_n = Input(Bool()) 35 | val Cas_n = Input(Bool()) 36 | val We_n = Input(Bool()) 37 | val Dqm = Input(UInt(4.W)) 38 | } 39 | 40 | @public 41 | class W9825G6KH extends FixedIOExtModule(new W9825G6KHInterface) 42 | 43 | class SDRAMControllerTestBench(val parameter: SDRAMControllerTestBenchParameter) 44 | extends RawModule 45 | with SerializableModule[SDRAMControllerTestBenchParameter] 46 | with ImplicitClock 47 | with ImplicitReset { 48 | val verbatim: Instance[TestVerbatim] = Instantiate(new TestVerbatim(parameter.testVerbatimParameter)) 49 | val dut: Instance[SDRAMController] = Instantiate(new SDRAMController(parameter.sdramControllerParameter)) 50 | val agent = Instantiate( 51 | new AXI4MasterAgent( 52 | AXI4MasterAgentParameter( 53 | name = "axi4Probe", 54 | axiParameter = dut.io.axi.parameter, 55 | outstanding = 4, 56 | readPayloadSize = 256, 57 | writePayloadSize = 256 58 | ) 59 | ) 60 | ).tap(_.suggestName(s"axi4_channel_probe")) 61 | 62 | val initFlag = RegInit(false.B) 63 | dut.io := DontCare 64 | dut.io.clock := implicitClock 65 | dut.io.reset := implicitReset 66 | 67 | agent.io.channel <> dut.io.axi.viewAs[AXI4RWIrrevocableVerilog] 68 | agent.io.clock := implicitClock 69 | agent.io.reset := implicitReset 70 | agent.io.channelId := 0.U 71 | agent.io.gateRead := false.B 72 | agent.io.gateWrite := false.B 73 | 74 | when(!initFlag) { 75 | initFlag := true.B 76 | } 77 | val hasBeenReset = RegNext(true.B, false.B) 78 | 79 | // For each timeout ticks, check it 80 | val watchdogCode = RawClockedNonVoidFunctionCall("cosim_watchdog", UInt(8.W))(agent.io.clock, true.B) 81 | when(watchdogCode =/= 0.U) { 82 | stop(cf"""{"event":"SimulationStop","reason": ${watchdogCode}}\n""") 83 | } 84 | 85 | /** SDRAM <-> DUT */ 86 | Seq 87 | .fill(parameter.sdramControllerParameter.sdramParameter.csWidth) { 88 | Instantiate(new W9825G6KH).io 89 | } 90 | .zipWithIndex 91 | .foreach { case (bundle, index) => 92 | bundle.Addr := dut.io.sdram.a 93 | bundle.Bs := dut.io.sdram.ba 94 | bundle.Cke := dut.io.sdram.cke(index).asBool 95 | bundle.Clk := dut.io.sdram.ck(index) 96 | bundle.Cs_n := dut.io.sdram.cs(index).asBool 97 | bundle.Dq_i := dut.io.sdram.dqo 98 | dut.io.sdram.dqi := bundle.Dq_o 99 | bundle.Dqm := dut.io.sdram.dqm 100 | bundle.Ras_n := dut.io.sdram.ras 101 | bundle.We_n := dut.io.sdram.we 102 | bundle.Cas_n := dut.io.sdram.cas 103 | } 104 | 105 | override protected def implicitClock: Clock = verbatim.io.clock 106 | 107 | override protected def implicitReset: Reset = verbatim.io.reset 108 | } 109 | 110 | // Don't touch 111 | 112 | object TestVerbatimParameter { 113 | implicit def rwP: upickle.default.ReadWriter[TestVerbatimParameter] = 114 | upickle.default.macroRW 115 | } 116 | 117 | case class TestVerbatimParameter( 118 | useAsyncReset: Boolean, 119 | initFunctionName: String, 120 | dumpFunctionName: String, 121 | clockFlipTick: Int, 122 | resetFlipTick: Int) 123 | extends SerializableModuleParameter 124 | 125 | @instantiable 126 | class TestVerbatimOM(parameter: TestVerbatimParameter) extends Class { 127 | val useAsyncReset: Property[Boolean] = IO(Output(Property[Boolean]())) 128 | val initFunctionName: Property[String] = IO(Output(Property[String]())) 129 | val dumpFunctionName: Property[String] = IO(Output(Property[String]())) 130 | val clockFlipTick: Property[Int] = IO(Output(Property[Int]())) 131 | val resetFlipTick: Property[Int] = IO(Output(Property[Int]())) 132 | 133 | useAsyncReset := Property(parameter.useAsyncReset) 134 | initFunctionName := Property(parameter.initFunctionName) 135 | dumpFunctionName := Property(parameter.dumpFunctionName) 136 | clockFlipTick := Property(parameter.clockFlipTick) 137 | resetFlipTick := Property(parameter.resetFlipTick) 138 | } 139 | 140 | /** Test blackbox for clockgen, wave dump and extra testbench-only codes. */ 141 | class TestVerbatimInterface(parameter: TestVerbatimParameter) extends Bundle { 142 | val clock: Clock = Output(Clock()) 143 | val reset: Reset = Output( 144 | if (parameter.useAsyncReset) AsyncReset() else Bool() 145 | ) 146 | } 147 | 148 | @instantiable 149 | class TestVerbatim(parameter: TestVerbatimParameter) 150 | extends FixedIOExtModule(new TestVerbatimInterface(parameter)) 151 | with HasExtModuleInline { 152 | setInline( 153 | s"$desiredName.sv", 154 | s"""module $desiredName(output reg clock, output reg reset); 155 | | export "DPI-C" function ${parameter.dumpFunctionName}; 156 | | function ${parameter.dumpFunctionName}(input string file); 157 | |`ifdef VCS 158 | | $$fsdbDumpfile(file); 159 | | $$fsdbDumpvars("+all"); 160 | | $$fsdbDumpSVA; 161 | | $$fsdbDumpon; 162 | |`endif 163 | |`ifdef VERILATOR 164 | | $$dumpfile(file); 165 | | $$dumpvars(0); 166 | |`endif 167 | | endfunction; 168 | | 169 | | import "DPI-C" context function void ${parameter.initFunctionName}(); 170 | | initial begin 171 | | ${parameter.initFunctionName}(); 172 | | clock = 1'b0; 173 | | reset = 1'b1; 174 | | end 175 | | initial #(${parameter.resetFlipTick}) reset = 1'b0; 176 | | always #${parameter.clockFlipTick} clock = ~clock; 177 | |endmodule 178 | |""".stripMargin 179 | ) 180 | } 181 | -------------------------------------------------------------------------------- /sdramemu/.gitignore: -------------------------------------------------------------------------------- 1 | target/** 2 | -------------------------------------------------------------------------------- /sdramemu/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.89" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" 19 | 20 | [[package]] 21 | name = "byteorder" 22 | version = "1.5.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 25 | 26 | [[package]] 27 | name = "cfg-if" 28 | version = "1.0.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 31 | 32 | [[package]] 33 | name = "common" 34 | version = "1.0.0" 35 | dependencies = [ 36 | "anyhow", 37 | "tracing", 38 | "tracing-subscriber", 39 | ] 40 | 41 | [[package]] 42 | name = "getrandom" 43 | version = "0.2.15" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 46 | dependencies = [ 47 | "cfg-if", 48 | "libc", 49 | "wasi", 50 | ] 51 | 52 | [[package]] 53 | name = "hex" 54 | version = "0.4.3" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 57 | 58 | [[package]] 59 | name = "lazy_static" 60 | version = "1.5.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 63 | 64 | [[package]] 65 | name = "libc" 66 | version = "0.2.159" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" 69 | 70 | [[package]] 71 | name = "log" 72 | version = "0.4.22" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 75 | 76 | [[package]] 77 | name = "matchers" 78 | version = "0.1.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 81 | dependencies = [ 82 | "regex-automata 0.1.10", 83 | ] 84 | 85 | [[package]] 86 | name = "memchr" 87 | version = "2.7.4" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 90 | 91 | [[package]] 92 | name = "nu-ansi-term" 93 | version = "0.46.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 96 | dependencies = [ 97 | "overload", 98 | "winapi", 99 | ] 100 | 101 | [[package]] 102 | name = "once_cell" 103 | version = "1.20.2" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 106 | 107 | [[package]] 108 | name = "overload" 109 | version = "0.1.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 112 | 113 | [[package]] 114 | name = "pin-project-lite" 115 | version = "0.2.14" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 118 | 119 | [[package]] 120 | name = "ppv-lite86" 121 | version = "0.2.20" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 124 | dependencies = [ 125 | "zerocopy", 126 | ] 127 | 128 | [[package]] 129 | name = "proc-macro2" 130 | version = "1.0.86" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 133 | dependencies = [ 134 | "unicode-ident", 135 | ] 136 | 137 | [[package]] 138 | name = "quote" 139 | version = "1.0.37" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 142 | dependencies = [ 143 | "proc-macro2", 144 | ] 145 | 146 | [[package]] 147 | name = "rand" 148 | version = "0.8.5" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 151 | dependencies = [ 152 | "libc", 153 | "rand_chacha", 154 | "rand_core", 155 | ] 156 | 157 | [[package]] 158 | name = "rand_chacha" 159 | version = "0.3.1" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 162 | dependencies = [ 163 | "ppv-lite86", 164 | "rand_core", 165 | ] 166 | 167 | [[package]] 168 | name = "rand_core" 169 | version = "0.6.4" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 172 | dependencies = [ 173 | "getrandom", 174 | ] 175 | 176 | [[package]] 177 | name = "regex" 178 | version = "1.11.0" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" 181 | dependencies = [ 182 | "aho-corasick", 183 | "memchr", 184 | "regex-automata 0.4.8", 185 | "regex-syntax 0.8.5", 186 | ] 187 | 188 | [[package]] 189 | name = "regex-automata" 190 | version = "0.1.10" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 193 | dependencies = [ 194 | "regex-syntax 0.6.29", 195 | ] 196 | 197 | [[package]] 198 | name = "regex-automata" 199 | version = "0.4.8" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 202 | dependencies = [ 203 | "aho-corasick", 204 | "memchr", 205 | "regex-syntax 0.8.5", 206 | ] 207 | 208 | [[package]] 209 | name = "regex-syntax" 210 | version = "0.6.29" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 213 | 214 | [[package]] 215 | name = "regex-syntax" 216 | version = "0.8.5" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 219 | 220 | [[package]] 221 | name = "sdramemu" 222 | version = "1.0.0" 223 | dependencies = [ 224 | "common", 225 | "hex", 226 | "once_cell", 227 | "rand", 228 | "svdpi", 229 | "tracing", 230 | ] 231 | 232 | [[package]] 233 | name = "sharded-slab" 234 | version = "0.1.7" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 237 | dependencies = [ 238 | "lazy_static", 239 | ] 240 | 241 | [[package]] 242 | name = "smallvec" 243 | version = "1.13.2" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 246 | 247 | [[package]] 248 | name = "svdpi" 249 | version = "0.0.1" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "9248c35a9b58d508b60d40b6f5ab8173760b32445d055e90822f57f09b9d0f58" 252 | 253 | [[package]] 254 | name = "syn" 255 | version = "2.0.79" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" 258 | dependencies = [ 259 | "proc-macro2", 260 | "quote", 261 | "unicode-ident", 262 | ] 263 | 264 | [[package]] 265 | name = "thread_local" 266 | version = "1.1.8" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 269 | dependencies = [ 270 | "cfg-if", 271 | "once_cell", 272 | ] 273 | 274 | [[package]] 275 | name = "tracing" 276 | version = "0.1.40" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 279 | dependencies = [ 280 | "pin-project-lite", 281 | "tracing-attributes", 282 | "tracing-core", 283 | ] 284 | 285 | [[package]] 286 | name = "tracing-attributes" 287 | version = "0.1.27" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 290 | dependencies = [ 291 | "proc-macro2", 292 | "quote", 293 | "syn", 294 | ] 295 | 296 | [[package]] 297 | name = "tracing-core" 298 | version = "0.1.32" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 301 | dependencies = [ 302 | "once_cell", 303 | "valuable", 304 | ] 305 | 306 | [[package]] 307 | name = "tracing-log" 308 | version = "0.2.0" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 311 | dependencies = [ 312 | "log", 313 | "once_cell", 314 | "tracing-core", 315 | ] 316 | 317 | [[package]] 318 | name = "tracing-subscriber" 319 | version = "0.3.18" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 322 | dependencies = [ 323 | "matchers", 324 | "nu-ansi-term", 325 | "once_cell", 326 | "regex", 327 | "sharded-slab", 328 | "smallvec", 329 | "thread_local", 330 | "tracing", 331 | "tracing-core", 332 | "tracing-log", 333 | ] 334 | 335 | [[package]] 336 | name = "unicode-ident" 337 | version = "1.0.13" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 340 | 341 | [[package]] 342 | name = "valuable" 343 | version = "0.1.0" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 346 | 347 | [[package]] 348 | name = "wasi" 349 | version = "0.11.0+wasi-snapshot-preview1" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 352 | 353 | [[package]] 354 | name = "winapi" 355 | version = "0.3.9" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 358 | dependencies = [ 359 | "winapi-i686-pc-windows-gnu", 360 | "winapi-x86_64-pc-windows-gnu", 361 | ] 362 | 363 | [[package]] 364 | name = "winapi-i686-pc-windows-gnu" 365 | version = "0.4.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 368 | 369 | [[package]] 370 | name = "winapi-x86_64-pc-windows-gnu" 371 | version = "0.4.0" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 374 | 375 | [[package]] 376 | name = "zerocopy" 377 | version = "0.7.35" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 380 | dependencies = [ 381 | "byteorder", 382 | "zerocopy-derive", 383 | ] 384 | 385 | [[package]] 386 | name = "zerocopy-derive" 387 | version = "0.7.35" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 390 | dependencies = [ 391 | "proc-macro2", 392 | "quote", 393 | "syn", 394 | ] 395 | -------------------------------------------------------------------------------- /sdramemu/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdramemu" 3 | edition = "2021" 4 | version = "1.0.0" 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | 9 | [dependencies] 10 | common = { path = "./common" } 11 | svdpi = { version = "0.0.1" } 12 | tracing = "0.1.40" 13 | hex = "0.4.3" 14 | rand = "0.8" 15 | once_cell = "1.20.2" 16 | 17 | [features] 18 | sv2023 = ["svdpi/sv2023"] 19 | vpi = ["svdpi/vpi"] 20 | trace = [] 21 | default = ["trace", "vpi"] 22 | -------------------------------------------------------------------------------- /sdramemu/common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "common" 3 | edition = "2021" 4 | version = "1.0.0" 5 | 6 | [dependencies] 7 | anyhow = "1.0.79" 8 | tracing = "0.1.40" 9 | tracing-subscriber = { version = "0.3", features = ["env-filter", "ansi"] } 10 | -------------------------------------------------------------------------------- /sdramemu/common/src/lib.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use plusarg::PlusArgMatcher; 3 | use tracing::Level; 4 | use tracing_subscriber::{EnvFilter, FmtSubscriber}; 5 | 6 | pub mod rtl_config; 7 | pub mod plusarg; 8 | 9 | pub struct CommonArgs { 10 | 11 | /// Log level: trace, debug, info, warn, error 12 | pub log_level: String, 13 | 14 | /// vlen config 15 | pub vlen: u32, 16 | 17 | /// dlen config 18 | pub dlen: u32, 19 | 20 | } 21 | 22 | pub static MEM_SIZE: usize = 1usize << 32; 23 | 24 | impl CommonArgs { 25 | 26 | pub fn setup_logger(&self) -> Result<()> { 27 | // setup log 28 | let log_level: Level = self.log_level.parse()?; 29 | let global_logger = FmtSubscriber::builder() 30 | .with_env_filter(EnvFilter::from_default_env()) 31 | .with_max_level(log_level) 32 | .without_time() 33 | .with_target(false) 34 | .with_ansi(true) 35 | .compact() 36 | .finish(); 37 | tracing::subscriber::set_global_default(global_logger) 38 | .expect("internal error: fail to setup log subscriber"); 39 | Ok(()) 40 | } 41 | 42 | pub fn from_plusargs(matcher: &PlusArgMatcher) -> Self { 43 | Self { 44 | log_level: matcher.try_match("log-level").unwrap_or("info").into(), 45 | vlen:matcher.try_match("vlen").unwrap_or("32").parse().unwrap(), 46 | dlen:matcher.try_match("dlen").unwrap_or("32").parse().unwrap(), 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sdramemu/common/src/plusarg.rs: -------------------------------------------------------------------------------- 1 | pub struct PlusArgMatcher { 2 | plusargs: Vec, 3 | } 4 | 5 | impl PlusArgMatcher { 6 | pub fn from_args() -> Self { 7 | let plusargs = std::env::args() 8 | .filter(|arg| arg.starts_with('+')) 9 | .collect(); 10 | 11 | Self { plusargs } 12 | } 13 | 14 | pub fn try_match(&self, arg_name: &str) -> Option<&str> { 15 | let prefix = &format!("+{arg_name}="); 16 | 17 | for plusarg in &self.plusargs { 18 | if plusarg.starts_with(prefix) { 19 | return Some(&plusarg[prefix.len()..]); 20 | } 21 | } 22 | None 23 | } 24 | 25 | pub fn match_(&self, arg_name: &str) -> &str { 26 | self.try_match(arg_name).unwrap_or_else(|| { 27 | tracing::error!("required plusarg '+{arg_name}=' not found"); 28 | panic!("failed to match '+{arg_name}='"); 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sdramemu/common/src/rtl_config.rs: -------------------------------------------------------------------------------- 1 | pub struct RTLConfig { 2 | pub vlen: u32, 3 | pub dlen: u32, 4 | } 5 | 6 | // TODO: read from json 7 | 8 | impl RTLConfig { 9 | pub fn xlen(&self) -> u32 { 10 | 32 // TODO: configurable 11 | } 12 | 13 | pub fn vlen_in_bytes(&self) -> u32 { 14 | self.vlen / 8 15 | } 16 | 17 | pub fn lane_num(&self) -> u32 { 18 | self.dlen / self.xlen() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sdramemu/src/dpi.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused_variables)] 3 | 4 | use crate::drive::Driver; 5 | use crate::{OfflineArgs, AXI_SIZE}; 6 | use common::plusarg::PlusArgMatcher; 7 | use once_cell::sync::Lazy; 8 | use rand::prelude::SliceRandom; 9 | use rand::rngs::StdRng; 10 | use rand::{Rng, SeedableRng}; 11 | use std::ffi::*; 12 | use std::sync::{Arc, Mutex}; 13 | use std::time::{SystemTime, UNIX_EPOCH}; 14 | use svdpi::SvScope; 15 | use tracing::{info, trace}; 16 | 17 | pub type SvBitVecVal = u32; 18 | 19 | // -------------------------- 20 | // preparing data structures 21 | // -------------------------- 22 | 23 | static DPI_TARGET: Mutex>> = Mutex::new(None); 24 | static AWID: Mutex = Mutex::new(0); 25 | 26 | pub trait ToBytes { 27 | fn to_bytes(&self) -> Vec; 28 | } 29 | 30 | pub trait ToBytesBe { 31 | fn to_bytes_be(&self) -> Vec; 32 | } 33 | 34 | impl ToBytes for u32 { 35 | fn to_bytes(&self) -> Vec { 36 | self.to_le_bytes().to_vec() 37 | } 38 | } 39 | 40 | impl ToBytesBe for u32 { 41 | fn to_bytes_be(&self) -> Vec { 42 | self.to_be_bytes().to_vec() 43 | } 44 | } 45 | 46 | impl ToBytes for Vec { 47 | fn to_bytes(&self) -> Vec { 48 | self.iter().flat_map(|&value| value.to_bytes()).collect() 49 | } 50 | } 51 | 52 | impl ToBytesBe for Vec { 53 | fn to_bytes_be(&self) -> Vec { 54 | self.iter().flat_map(|&value| value.to_bytes_be()).collect() 55 | } 56 | } 57 | 58 | #[derive(Clone, Debug)] 59 | pub(crate) struct AxiWritePayload { 60 | pub(crate) id: u8, 61 | pub(crate) len: u8, 62 | pub(crate) addr: u32, 63 | pub(crate) data: Vec, 64 | pub(crate) strb: Vec, 65 | pub(crate) wUser: Vec, 66 | pub(crate) awUser: u8, 67 | pub(crate) dataValid: u8, 68 | pub(crate) burst: u8, 69 | pub(crate) cache: u8, 70 | pub(crate) lock: u8, 71 | pub(crate) prot: u8, 72 | pub(crate) qos: u8, 73 | pub(crate) region: u8, 74 | pub(crate) size: u8, 75 | } 76 | 77 | static RNG: Lazy>> = Lazy::new(|| { 78 | let start = SystemTime::now(); 79 | let since_epoch = start 80 | .duration_since(UNIX_EPOCH) 81 | .expect("Clock may have gone backwards"); 82 | let seed = since_epoch.as_secs(); 83 | info!("Using seed: {:#x}", seed); 84 | Arc::new(Mutex::new(StdRng::seed_from_u64(seed))) 85 | }); 86 | 87 | impl AxiWritePayload { 88 | fn generate_random_strb(use_bit: u8, total_bit: u8, rng: &mut StdRng) -> u8 { 89 | let ones_count = 1 << use_bit; 90 | let zeros_count = (1 << total_bit) - ones_count; 91 | 92 | let mut bits: Vec = vec![1; ones_count as usize]; 93 | bits.extend(vec![0; zeros_count as usize]); 94 | bits.shuffle(rng); 95 | 96 | let mut result = 0u8; 97 | for (i, &bit) in bits.iter().enumerate() { 98 | result |= bit << i; 99 | } 100 | 101 | result 102 | } 103 | pub(crate) fn random() -> Self { 104 | let mut rng = RNG.lock().unwrap(); 105 | 106 | let burst_type = 1; 107 | // let burst_type = rng.gen_range(0..=2); 108 | let burst_length = match burst_type { 109 | 0 => rng.gen_range(0..=15), 110 | 1 => rng.gen_range(0..=u8::MAX), 111 | 2 => 1 << rng.gen_range(1..=4), 112 | _ => 0, 113 | }; 114 | let burst_width = AXI_SIZE >> 3; 115 | let MAX_BURST_WIDTH = 7 - burst_width.leading_zeros() as u8; 116 | // let burst_size = 0; 117 | let burst_size = rng.gen_range(0..=MAX_BURST_WIDTH); 118 | let bytes_number = 8 << (1 << burst_size); 119 | let total_bit = 1 << MAX_BURST_WIDTH; 120 | let used_bit = 1 << burst_size; 121 | let strb_sequence = { 122 | let mut vec: Vec = Vec::new(); 123 | let mut start = (1 << used_bit) - 1; 124 | for i in 0..total_bit / used_bit { 125 | vec.push(start); 126 | start <<= used_bit; 127 | } 128 | vec 129 | }; 130 | let payload = AxiWritePayload { 131 | id: *AWID.lock().unwrap() & 0xF, 132 | len: burst_length - 1, 133 | addr: rng.gen_range(0xfc000000..=u32::MAX) / bytes_number * bytes_number, 134 | data: (0..256).map(|_| rng.gen_range(0..=u32::MAX)).collect(), 135 | strb: (0..256) 136 | .map(|i| strb_sequence[i % strb_sequence.len()]) 137 | .collect(), 138 | wUser: (0..256).map(|_| rng.gen_range(0..=u8::MAX)).collect(), 139 | awUser: rng.gen_range(0..=u8::MAX), 140 | dataValid: 1, 141 | burst: burst_type, 142 | cache: 0x77, 143 | lock: 0x88, 144 | prot: 0x99, 145 | qos: 0xaa, 146 | region: 0xbb, 147 | size: burst_size, 148 | }; 149 | *AWID.lock().unwrap() += 1; 150 | payload 151 | } 152 | } 153 | 154 | impl ToBytes for AxiWritePayload { 155 | fn to_bytes(&self) -> Vec { 156 | vec![ 157 | self.size, 158 | self.region, 159 | self.qos, 160 | self.prot, 161 | self.lock, 162 | self.cache, 163 | self.burst, 164 | self.dataValid, 165 | self.awUser, 166 | ] 167 | .into_iter() 168 | .chain(self.wUser.clone()) 169 | .chain(self.strb.clone()) 170 | .chain(self.data.to_bytes()) 171 | .chain(self.addr.to_bytes()) 172 | .chain(vec![self.len, self.id]) 173 | .collect::>() 174 | } 175 | } 176 | 177 | #[derive(Clone, Debug)] 178 | pub(crate) struct AxiReadPayload { 179 | pub(crate) addr: u32, 180 | pub(crate) id: u8, 181 | pub(crate) user: u8, 182 | pub(crate) burst: u8, 183 | pub(crate) cache: u8, 184 | pub(crate) len: u8, 185 | pub(crate) lock: u8, 186 | pub(crate) prot: u8, 187 | pub(crate) qos: u8, 188 | pub(crate) region: u8, 189 | pub(crate) size: u8, 190 | pub(crate) valid: u8, 191 | } 192 | 193 | impl AxiReadPayload { 194 | pub(crate) fn random() -> Self { 195 | let mut rng = rand::thread_rng(); 196 | AxiReadPayload { 197 | addr: rng.gen_range(0..=255), 198 | id: rng.gen_range(0..=255), 199 | user: rng.gen_range(0..=255), 200 | burst: rng.gen_range(0..=15), 201 | cache: rng.gen_range(0..=15), 202 | len: rng.gen_range(0..=255), 203 | lock: rng.gen_range(0..=1), 204 | prot: rng.gen_range(0..=7), 205 | qos: rng.gen_range(0..=15), 206 | region: rng.gen_range(0..=15), 207 | size: rng.gen_range(0..=15), 208 | valid: 1, 209 | } 210 | } 211 | pub(crate) fn from_write_payload(payload: &AxiWritePayload) -> Self { 212 | AxiReadPayload { 213 | addr: payload.addr, 214 | id: payload.id, 215 | user: payload.awUser, 216 | burst: payload.burst, 217 | cache: payload.cache, 218 | len: payload.len, 219 | lock: payload.lock, 220 | prot: payload.prot, 221 | qos: payload.qos, 222 | region: payload.region, 223 | size: payload.size, 224 | valid: 1, 225 | } 226 | } 227 | } 228 | 229 | impl ToBytes for AxiReadPayload { 230 | fn to_bytes(&self) -> Vec { 231 | vec![ 232 | self.valid, 233 | self.size, 234 | self.region, 235 | self.qos, 236 | self.prot, 237 | self.lock, 238 | self.len, 239 | self.cache, 240 | self.burst, 241 | self.user, 242 | self.id, 243 | ] 244 | .into_iter() 245 | .chain(self.addr.to_bytes()) 246 | .collect() 247 | } 248 | } 249 | 250 | unsafe fn write_to_pointer(dst: *mut u8, data: &[u8]) { 251 | std::ptr::copy_nonoverlapping(data.as_ptr(), dst, data.len()); 252 | } 253 | 254 | unsafe fn fill_axi_payload(dst: *mut SvBitVecVal, payload: &T) { 255 | let data = payload.to_bytes(); 256 | // info!("data length: {:?}", data.len()); 257 | write_to_pointer(dst as *mut u8, &data); 258 | } 259 | 260 | //---------------------- 261 | // dpi functions 262 | //---------------------- 263 | 264 | /// evaluate at R fire. 265 | #[no_mangle] 266 | unsafe extern "C" fn axi_read_done_axi4Probe( 267 | rdata: *const u32, 268 | len: u8, 269 | last_data: u32, 270 | rid: u8, 271 | rresp: u8, 272 | ruser: u8, 273 | ) { 274 | let rdata_slice = std::slice::from_raw_parts(rdata, 256); 275 | let mut driver = DPI_TARGET.lock().unwrap(); 276 | let driver = driver.as_mut().unwrap(); 277 | driver.axi_read_done(rdata_slice.to_vec(), len, last_data, rid, rresp, ruser); 278 | } 279 | 280 | /// evaluate at AW ready. 281 | #[no_mangle] 282 | unsafe extern "C" fn axi_write_ready_axi4Probe(payload: *mut SvBitVecVal) { 283 | trace!("axi_write_ready_axi4Probe"); 284 | let mut driver = DPI_TARGET.lock().unwrap(); 285 | let driver = driver.as_mut().unwrap(); 286 | let response = driver.axi_write_ready(); 287 | fill_axi_payload(payload, &response); 288 | } 289 | 290 | /// evaluate at B fire. 291 | #[no_mangle] 292 | unsafe extern "C" fn axi_write_done_axi4Probe(bid: c_uchar, bresp: c_uchar, buser: c_uchar) { 293 | trace!("axi_write_done_axi4Probe (bid={bid}, bresp={bresp}, buser={buser})"); 294 | let mut driver = DPI_TARGET.lock().unwrap(); 295 | let driver = driver.as_mut().unwrap(); 296 | driver.axi_write_done(bid, bresp, buser); 297 | } 298 | 299 | /// evaluate at AR ready. 300 | #[no_mangle] 301 | unsafe extern "C" fn axi_read_ready_axi4Probe(payload: *mut SvBitVecVal) { 302 | trace!("axi_read_ready_axi4Probe"); 303 | let mut driver = DPI_TARGET.lock().unwrap(); 304 | let driver = driver.as_mut().unwrap(); 305 | let response = driver.axi_read_ready(); 306 | fill_axi_payload(payload, &response); 307 | } 308 | 309 | #[no_mangle] 310 | unsafe extern "C" fn cosim_watchdog(reason: *mut c_char) { 311 | let mut driver = DPI_TARGET.lock().unwrap(); 312 | if let Some(driver) = driver.as_mut() { 313 | *reason = driver.watchdog() as c_char; 314 | } 315 | } 316 | 317 | #[no_mangle] 318 | unsafe extern "C" fn cosim_init() { 319 | println!("cosim_init called"); 320 | 321 | let plusargs = PlusArgMatcher::from_args(); 322 | let args = OfflineArgs::from_plusargs(&plusargs); 323 | args.common_args.setup_logger().unwrap(); 324 | 325 | let scope = SvScope::get_current().expect("failed to get scope in cosim_init"); 326 | 327 | let driver = Box::new(Driver::new(scope, &args)); 328 | let mut dpi_target = DPI_TARGET.lock().unwrap(); 329 | assert!( 330 | dpi_target.is_none(), 331 | "cosim_init should be called only once" 332 | ); 333 | *dpi_target = Some(driver); 334 | 335 | if let Some(driver) = dpi_target.as_mut() { 336 | driver.init(); 337 | } 338 | } 339 | 340 | //-------------------------------- 341 | // import functions and wrappers 342 | //-------------------------------- 343 | 344 | mod dpi_export { 345 | use std::ffi::*; 346 | 347 | extern "C" { 348 | #[cfg(feature = "trace")] 349 | /// `export "DPI-C" function dump_wave(input string file)` 350 | pub fn dump_wave(path: *const c_char); 351 | } 352 | } 353 | 354 | #[cfg(feature = "trace")] 355 | pub(crate) fn dump_wave(scope: svdpi::SvScope, path: &str) { 356 | use svdpi; 357 | let path_cstring = CString::new(path).unwrap(); 358 | 359 | svdpi::set_scope(scope); 360 | unsafe { 361 | dpi_export::dump_wave(path_cstring.as_ptr()); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /sdramemu/src/drive.rs: -------------------------------------------------------------------------------- 1 | use svdpi::{get_time, SvScope}; 2 | use tracing::{error, info, trace}; 3 | 4 | use crate::dpi::*; 5 | use crate::driver_assert_eq; 6 | use crate::{OfflineArgs, AXI_SIZE}; 7 | use std::collections::{HashMap, VecDeque}; 8 | 9 | struct ShadowMem { 10 | mem: Vec, 11 | } 12 | 13 | impl ShadowMem { 14 | pub fn new() -> Self { 15 | Self { 16 | mem: vec![0; 0xffff_ffff - 0xfc00_0000], 17 | } 18 | } 19 | 20 | fn is_addr_align(&self, addr: u32, size: u8) -> bool { 21 | let bytes_number = 1 << size; 22 | let aligned_addr = addr / bytes_number * bytes_number; 23 | addr == aligned_addr 24 | } 25 | 26 | // size: 1 << arsize 27 | // return: Vec with len=bus_size 28 | pub fn read_mem_axi(&self, payload: AxiReadPayload) -> Vec { 29 | let bytes_number: u32 = 1 << payload.size; 30 | let transfer_count: u32 = (payload.len + 1) as u32; 31 | 32 | let mut lower_boundary = 0; 33 | let mut upper_boundary = 0; 34 | 35 | let mut data: Vec = vec![]; 36 | 37 | if payload.burst == 2 { 38 | lower_boundary = 39 | payload.addr / (bytes_number * transfer_count) * (bytes_number * transfer_count); 40 | upper_boundary = lower_boundary + bytes_number * transfer_count; 41 | assert!( 42 | transfer_count == 2 43 | || transfer_count == 4 44 | || transfer_count == 8 45 | || transfer_count == 16, 46 | "unsupported burst len" 47 | ); 48 | } 49 | 50 | let mut current_addr = payload.addr - 0xfc000000; 51 | assert!( 52 | self.is_addr_align(payload.addr, payload.size), 53 | "address is unaligned!" 54 | ); 55 | 56 | for _ in 0..transfer_count { 57 | data.extend_from_slice( 58 | &self.mem[current_addr as usize..(current_addr + bytes_number) as usize], 59 | ); 60 | 61 | current_addr = match payload.burst { 62 | 0 => current_addr, // FIXED 63 | 1 => current_addr + bytes_number, // INCR 64 | 2 => { 65 | if current_addr + bytes_number >= upper_boundary { 66 | lower_boundary 67 | } else { 68 | current_addr + bytes_number 69 | } 70 | } // WRAP 71 | _ => { 72 | panic!("unknown burst type: {:?}", payload.burst); 73 | } 74 | } 75 | } 76 | data 77 | } 78 | 79 | // size: 1 << awsize 80 | // bus_size: AXI bus width in bytes 81 | // masks: write strokes, len=bus_size 82 | // data: write data, len=bus_size 83 | pub fn write_mem_axi(&mut self, payload: AxiWritePayload) { 84 | let transfer_count = (payload.len + 1) as usize; 85 | 86 | // assert!( 87 | // transfer_count == payload.data.len() 88 | // && transfer_count == payload.strb.len(), 89 | // "malformed payload: transfer_count = {:?}, payload.data.len = {:?}, payload.strb.len = {:?}", 90 | // transfer_count, payload.data.len(), payload.strb.len(), 91 | // ); 92 | 93 | let bytes_number: u32 = 1 << payload.size; 94 | 95 | let mut lower_boundary = 0; 96 | let mut upper_boundary = 0; 97 | if payload.burst == 2 { 98 | lower_boundary = payload.addr / (bytes_number * transfer_count as u32) 99 | * (bytes_number * transfer_count as u32); 100 | upper_boundary = lower_boundary + bytes_number * transfer_count as u32; 101 | assert!( 102 | transfer_count == 2 103 | || transfer_count == 4 104 | || transfer_count == 8 105 | || transfer_count == 16, 106 | "unsupported burst len: {}", 107 | payload.len 108 | ); 109 | } 110 | 111 | let mut current_addr = payload.addr - 0xfc000000; 112 | assert!( 113 | self.is_addr_align(payload.addr, payload.size), 114 | "address is unaligned!" 115 | ); 116 | 117 | for item_idx in 0..transfer_count { 118 | if payload.strb[item_idx] == 0 { 119 | continue; 120 | } 121 | 122 | assert_eq!( 123 | payload.strb[item_idx].count_ones(), 124 | 1 << payload.size, 125 | "the number of will write bytes is not equal, size = {}", 126 | payload.size 127 | ); 128 | 129 | info!( 130 | "writing(0x{:02x}) 0x{:08x} -> 0x{:08x}/{} with strb:0b{:04b}", 131 | payload.id, 132 | payload.data[item_idx], 133 | current_addr, 134 | match payload.burst { 135 | 0 => "FIX", 136 | 1 => "INCR", 137 | 2 => "WARP", 138 | _ => "UNKNOWN", 139 | }, 140 | payload.strb[item_idx] 141 | ); 142 | 143 | let mut write_count = 0; 144 | for byte_idx in 0..AXI_SIZE / 8 { 145 | let byte_mask: bool = 146 | (payload.strb[item_idx] >> (AXI_SIZE / 8 - (byte_idx + 1))) & 1 != 0; 147 | if byte_mask { 148 | self.mem[(current_addr + write_count as u32) as usize] = 149 | (payload.data[item_idx] >> ((AXI_SIZE / 8 - (byte_idx + 1)) * 8) & 0xff) 150 | as u8; 151 | write_count += 1; 152 | } 153 | } 154 | 155 | current_addr = match payload.burst { 156 | 0 => current_addr, // FIXED 157 | 1 => current_addr + bytes_number, // INCR 158 | 2 => { 159 | if current_addr + bytes_number >= upper_boundary { 160 | lower_boundary 161 | } else { 162 | current_addr + bytes_number 163 | } 164 | } // WRAP 165 | _ => { 166 | panic!("unknown burst type: {:?}", payload.burst); 167 | } 168 | } 169 | } 170 | } 171 | } 172 | 173 | pub(crate) struct Driver { 174 | // SvScope from cosim_init 175 | scope: SvScope, 176 | 177 | #[cfg(feature = "trace")] 178 | wave_path: String, 179 | #[cfg(feature = "trace")] 180 | dump_start: u64, 181 | #[cfg(feature = "trace")] 182 | dump_end: u64, 183 | #[cfg(feature = "trace")] 184 | dump_started: bool, 185 | dump_manual_finish: bool, 186 | timeout: u64, 187 | 188 | clock_flip_time: u64, 189 | 190 | shadow_mem: ShadowMem, 191 | 192 | axi_write_done_fifo: VecDeque, 193 | axi_write_fifo: VecDeque, 194 | axi_read_fifo: VecDeque, 195 | 196 | statistic: HashMap, 197 | } 198 | 199 | #[cfg(feature = "trace")] 200 | fn parse_range(input: &str) -> (u64, u64) { 201 | if input.is_empty() { 202 | return (0, 0); 203 | } 204 | 205 | let parts: Vec<&str> = input.split(",").collect(); 206 | 207 | if parts.len() != 1 && parts.len() != 2 { 208 | error!("invalid dump wave range: `{input}` was given"); 209 | return (0, 0); 210 | } 211 | 212 | const INVALID_NUMBER: &str = "invalid number"; 213 | 214 | if parts.len() == 1 { 215 | return (parts[0].parse().expect(INVALID_NUMBER), 0); 216 | } 217 | 218 | if parts[0].is_empty() { 219 | return (0, parts[1].parse().expect(INVALID_NUMBER)); 220 | } 221 | 222 | let start = parts[0].parse().expect(INVALID_NUMBER); 223 | let end = parts[1].parse().expect(INVALID_NUMBER); 224 | if start > end { 225 | panic!("dump start is larger than end: `{input}`"); 226 | } 227 | 228 | (start, end) 229 | } 230 | 231 | impl Driver { 232 | fn get_tick(&self) -> u64 { 233 | get_time() / self.clock_flip_time 234 | } 235 | 236 | pub(crate) fn new(scope: SvScope, args: &OfflineArgs) -> Self { 237 | #[cfg(feature = "trace")] 238 | let (dump_start, dump_end) = parse_range(&args.dump_range); 239 | Self { 240 | scope, 241 | 242 | #[cfg(feature = "trace")] 243 | wave_path: args.wave_path.to_owned(), 244 | #[cfg(feature = "trace")] 245 | dump_start, 246 | #[cfg(feature = "trace")] 247 | dump_end, 248 | #[cfg(feature = "trace")] 249 | dump_started: false, 250 | dump_manual_finish: false, 251 | timeout: std::env::var("TIMEOUT") 252 | .map(|s| s.parse::().unwrap_or(u64::MAX)) 253 | .unwrap_or(u64::MAX), 254 | clock_flip_time: env!("CLOCK_FLIP_TIME").parse().unwrap(), 255 | shadow_mem: ShadowMem::new(), 256 | axi_read_fifo: VecDeque::new(), 257 | axi_write_done_fifo: VecDeque::new(), 258 | axi_write_fifo: VecDeque::new(), 259 | statistic: HashMap::from([ 260 | ("axi_write".to_string(), 0), 261 | ("axi_write_done".to_string(), 0), 262 | ("axi_read".to_string(), 0), 263 | ("axi_read_done".to_string(), 0), 264 | ]), 265 | } 266 | } 267 | 268 | pub(crate) fn init(&mut self) { 269 | #[cfg(feature = "trace")] 270 | if self.dump_start == 0 { 271 | self.start_dump_wave(); 272 | self.dump_started = true; 273 | } 274 | } 275 | 276 | pub(crate) fn watchdog(&mut self) -> u8 { 277 | const WATCHDOG_CONTINUE: u8 = 0; 278 | const WATCHDOG_TIMEOUT: u8 = 1; 279 | const WATCHDOG_FINISH: u8 = 2; 280 | 281 | let tick = self.get_tick(); 282 | 283 | let mut ret = WATCHDOG_CONTINUE; 284 | 285 | if self.dump_manual_finish { 286 | info!("[{tick}] manual finish, exiting"); 287 | ret = WATCHDOG_FINISH; 288 | } 289 | 290 | #[cfg(feature = "trace")] 291 | if self.dump_end != 0 && tick > self.dump_end { 292 | info!("[{tick}] run to dump end, exiting"); 293 | ret = WATCHDOG_TIMEOUT; 294 | } 295 | 296 | #[cfg(feature = "trace")] 297 | if !self.dump_started && tick >= self.dump_start { 298 | self.start_dump_wave(); 299 | self.dump_started = true; 300 | } 301 | 302 | if tick >= self.timeout { 303 | info!("[{tick}] timeout triggered, exiting"); 304 | ret = WATCHDOG_TIMEOUT; 305 | } 306 | 307 | trace!("[{tick}] watchdog continue"); 308 | 309 | if ret != WATCHDOG_CONTINUE { 310 | info!("statistic:\naxi_write: \n\tdone: {}\n\ttotal: {}\naxi_read:\n\tdone: {}\n\ttotal: {}\n", 311 | self.statistic["axi_write_done"], self.statistic["axi_write"], self.statistic["axi_read_done"], self.statistic["axi_read"]) 312 | } 313 | 314 | ret 315 | } 316 | 317 | pub(crate) fn axi_write_done(&mut self, bid: u8, bresp: u8, buser: u8) { 318 | info!("axi_write_done (bid={bid}, bresp={bresp}, buser={buser})"); 319 | *self 320 | .statistic 321 | .entry("axi_write_done".to_string()) 322 | .or_insert(0) += 1; 323 | let payload = self.axi_write_fifo.pop_front().unwrap(); 324 | driver_assert_eq!( 325 | self, 326 | payload.id, 327 | bid, 328 | "ID is not equal: awid = {}, bid = {}", 329 | payload.id, 330 | bid 331 | ); 332 | self.shadow_mem.write_mem_axi(payload.clone()); 333 | self.axi_write_done_fifo.push_back(payload); 334 | } 335 | 336 | pub(crate) fn axi_write_ready(&mut self) -> AxiWritePayload { 337 | trace!("axi_write_ready"); 338 | *self.statistic.entry("axi_write".to_string()).or_insert(0) += 1; 339 | let payload = AxiWritePayload::random(); 340 | self.axi_write_fifo.push_back(payload.clone()); 341 | payload 342 | } 343 | 344 | pub(crate) fn axi_read_ready(&mut self) -> AxiReadPayload { 345 | trace!("axi_read_ready"); 346 | if self.axi_write_done_fifo.is_empty() || !self.axi_read_fifo.is_empty() { 347 | let mut payload = AxiReadPayload::random(); 348 | payload.valid = 0; 349 | payload 350 | } else { 351 | *self.statistic.entry("axi_read".to_string()).or_insert(0) += 1; 352 | let write_payload = self.axi_write_done_fifo.pop_front().unwrap(); 353 | let payload = AxiReadPayload::from_write_payload(&write_payload); 354 | self.axi_read_fifo.push_back(write_payload); 355 | info!( 356 | "reading(0x{:02x}) <- 0x{:08x}/{:#} with len = 0x{:02x}", 357 | payload.id, 358 | payload.addr, 359 | match payload.burst { 360 | 0 => "FIX", 361 | 1 => "INCR", 362 | 2 => "WARP", 363 | _ => "UNKNOWN", 364 | }, 365 | payload.len, 366 | ); 367 | payload 368 | } 369 | } 370 | 371 | pub(crate) fn axi_read_done( 372 | &mut self, 373 | rdata: Vec, 374 | len: u8, 375 | last_data: u32, 376 | rid: u8, 377 | rresp: u8, 378 | ruser: u8, 379 | ) { 380 | info!( 381 | "axi_read_done (rid=0x{rid:02x}, \ 382 | rresp=0x{rresp:08x}, ruser=0x{ruser:08x})" 383 | ); 384 | *self 385 | .statistic 386 | .entry("axi_read_done".to_string()) 387 | .or_insert(0) += 1; 388 | let payload = self.axi_read_fifo.pop_front().unwrap(); 389 | driver_assert_eq!( 390 | self, 391 | rid, 392 | payload.id, 393 | "id is not equal, current: {}, correct: {}", 394 | rid, 395 | payload.id 396 | ); 397 | driver_assert_eq!( 398 | self, 399 | len, 400 | payload.len + 1, 401 | "len is not equal, current: {}, correct: {}", 402 | len, 403 | payload.len + 1 404 | ); 405 | let compare = self 406 | .shadow_mem 407 | .read_mem_axi(AxiReadPayload::from_write_payload(&payload)); 408 | let mut vec = rdata[..(len - 1) as usize].to_vec(); 409 | vec.push(last_data); 410 | let mut rdata_bytes: Vec = Vec::new(); 411 | for idx in 0..len { 412 | let strb = payload.strb[idx as usize]; 413 | let bytes = vec[idx as usize].to_be_bytes().to_vec(); 414 | let trimed = bytes[bytes.len() - strb.count_ones() as usize..].iter(); 415 | info!( 416 | "trimed: 0x{} -> 0x{}", 417 | hex::encode(&bytes), 418 | hex::encode(&trimed) 419 | ); 420 | rdata_bytes.extend(trimed); 421 | } 422 | driver_assert_eq!( 423 | self, 424 | rdata_bytes, 425 | compare, 426 | "compare failed:\n\tcurrent: {}\n\tcorrect: {}", 427 | hex::encode(&rdata_bytes), 428 | hex::encode(&compare) 429 | ); 430 | } 431 | 432 | #[cfg(feature = "trace")] 433 | fn start_dump_wave(&mut self) { 434 | dump_wave(self.scope, &self.wave_path); 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /sdramemu/src/lib.rs: -------------------------------------------------------------------------------- 1 | use common::{plusarg::PlusArgMatcher, CommonArgs}; 2 | pub mod dpi; 3 | pub mod drive; 4 | 5 | pub(crate) struct OfflineArgs { 6 | pub common_args: CommonArgs, 7 | 8 | #[cfg(feature = "trace")] 9 | pub wave_path: String, 10 | 11 | #[cfg(feature = "trace")] 12 | pub dump_range: String, 13 | } 14 | 15 | pub const AXI_SIZE: u8 = 32; 16 | 17 | impl OfflineArgs { 18 | pub fn from_plusargs(matcher: &PlusArgMatcher) -> Self { 19 | Self { 20 | common_args: CommonArgs::from_plusargs(matcher), 21 | #[cfg(feature = "trace")] 22 | dump_range: matcher.match_("dump-range").into(), 23 | #[cfg(feature = "trace")] 24 | wave_path: matcher.match_("wave-path").into(), 25 | } 26 | } 27 | } 28 | 29 | #[macro_export] 30 | macro_rules! driver_assert_eq { 31 | ($self:expr, $left:expr, $right:expr $(,)?) => {{ 32 | if $left != $right { 33 | $self.dump_manual_finish = true; 34 | error!( 35 | "assertion failed: `(left == right)`\n left: `{:?}`\n right: `{:?}`", 36 | $left, $right 37 | ); 38 | } 39 | }}; 40 | ($self:expr, $left:expr, $right:expr, $($arg:tt)+) => {{ 41 | if $left != $right { 42 | $self.dump_manual_finish = true; 43 | error!($($arg)+); 44 | } 45 | }}; 46 | } 47 | -------------------------------------------------------------------------------- /signal.rc: -------------------------------------------------------------------------------- 1 | Magic 271485 2 | Revision Verdi_V-2023.12 3 | 4 | ; Window Layout 5 | viewPort 0 25 2556 1228 388 134 6 | 7 | ; File list: 8 | ; openDirFile [-d delimiter] [-s time_offset] [-rf auto_bus_rule_file] path_name file_name 9 | openDirFile -d / "" "/home/myyerrol/sdram/sdram-sim-result/all/2024-10-16-11-46-00/trace.fsdb" 10 | 11 | ; file time scale: 12 | ; fileTimeScale ### s|ms|us|ns|ps 13 | 14 | ; signal spacing: 15 | signalSpacing 5 16 | 17 | ; windowTimeUnit is used for zoom, cursor & marker 18 | windowTimeUnit 1ns 19 | 20 | ; waveform viewport range 21 | zoom 496978.230259 497338.118186 1n 22 | cursor 497075.000000 23 | marker 0.000000 24 | 25 | ; user define markers 26 | ; userMarker time_pos marker_name color linestyle 27 | ; visible top row signal index 28 | top 14 29 | ; marker line index 30 | markerPos 37 31 | 32 | ; event list 33 | ; addEvent event_name event_expression 34 | ; curEvent event_name 35 | 36 | 37 | 38 | COMPLEX_EVENT_BEGIN 39 | 40 | 41 | COMPLEX_EVENT_END 42 | 43 | 44 | 45 | ; toolbar current search type 46 | ; curSTATUS search_type 47 | curSTATUS ByChange 48 | 49 | 50 | addGroup "G1" 51 | activeDirFile "" "/home/myyerrol/sdram/sdram-sim-result/all/2024-10-16-11-46-00/trace.fsdb" 52 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 /SDRAMControllerTestBench/dut/clock 53 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -holdScope reset 54 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -ASC -holdScope dbg_state[79:0] 55 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope state_q[3:0] 56 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope next_state_r[3:0] 57 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope next_state_r_w[3:0] 58 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope target_state_q[3:0] 59 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope target_state_r[3:0] 60 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope target_state_r_w[3:0] 61 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope delay_state_q[3:0] 62 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope delay_r[3:0] 63 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope delay_w[3:0] 64 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope refresh_timer_q[16:0] 65 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -holdScope refresh_q 66 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope addr_w[31:0] 67 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope addr_bank_w[1:0] 68 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope addr_row_w[12:0] 69 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope addr_col_w[12:0] 70 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -BIN -holdScope row_open_q[3:0] 71 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope active_row_q_0[12:0] 72 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope active_row_q_1[12:0] 73 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope active_row_q_2[12:0] 74 | addSignal -c ID_ORANGE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope active_row_q_3[12:0] 75 | addSignal -c ID_YELLOW5 -ls solid -lw 1 -h 15 -holdScope ram_req_w 76 | addSignal -c ID_YELLOW5 -ls solid -lw 1 -h 15 -UNSIGNED -BIN -holdScope ram_wr_w[3:0] 77 | addSignal -c ID_YELLOW5 -ls solid -lw 1 -h 15 -holdScope ram_accept_w 78 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -holdScope req_wr_q 79 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -holdScope req_rd_q 80 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope req_len_q[7:0] 81 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope req_id_q[3:0] 82 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -UNSIGNED -BIN -holdScope req_axburst_q[1:0] 83 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope req_axlen_q[7:0] 84 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope req_addr_q[31:0] 85 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -holdScope req_prio_q 86 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -holdScope req_hold_wr_q 87 | addSignal -c ID_GREEN5 -ls solid -lw 1 -h 15 -holdScope req_hold_rd_q 88 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -holdScope clock 89 | addSignal -h 15 -holdScope AXI_AWVALID 90 | addSignal -h 15 -holdScope AXI_AWREADY 91 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_AWADDR[31:0] 92 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_AWBURST[1:0] 93 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_AWLEN[7:0] 94 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_AWSIZE[2:0] 95 | addSignal -h 15 -holdScope AXI_WVALID 96 | addSignal -h 15 -holdScope AXI_WREADY 97 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_WDATA[31:0] 98 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_WSTRB[3:0] 99 | addSignal -h 15 -holdScope AXI_WLAST 100 | addSignal -h 15 -holdScope AXI_BVALID 101 | addSignal -h 15 -holdScope AXI_BREADY 102 | addSignal -h 15 -holdScope AXI_ARVALID 103 | addSignal -h 15 -holdScope AXI_ARREADY 104 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_ARADDR[31:0] 105 | addSignal -h 15 -UNSIGNED -UDEC -holdScope AXI_ARLEN[7:0] 106 | addSignal -h 15 -holdScope AXI_RVALID 107 | addSignal -h 15 -holdScope AXI_RREADY 108 | addSignal -h 15 -holdScope AXI_RLAST 109 | addSignal -h 15 -UNSIGNED -HEX -holdScope AXI_RDATA[31:0] 110 | addSignal -h 15 -UNSIGNED -UDEC -holdScope AXI_ARID[3:0] 111 | addSignal -h 15 -UNSIGNED -UDEC -holdScope AXI_AWID[3:0] 112 | addSignal -h 15 -UNSIGNED -UDEC -holdScope AXI_BID[3:0] 113 | addSignal -h 15 -UNSIGNED -UDEC -holdScope AXI_ARID[3:0] 114 | addSignal -h 15 -UNSIGNED -UDEC -holdScope AXI_RID[3:0] 115 | addSignal -h 15 -holdScope write_active_w 116 | addSignal -h 15 -holdScope read_active_w 117 | addSignal -c ID_CYAN5 -ls solid -lw 1 -h 15 -holdScope write_prio_w 118 | addSignal -c ID_CYAN5 -ls solid -lw 1 -h 15 -holdScope read_prio_w 119 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -UNSIGNED -BIN -holdScope req_in_w[5:0] 120 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope req_push_w 121 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope req_fifo_accept_w 122 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope resp_accept_w 123 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -UNSIGNED -BIN -holdScope req_out_w[5:0] 124 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope req_out_valid_w 125 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope resp_is_write_w 126 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope resp_is_read_w 127 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope resp_id_w[3:0] 128 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope ram_read_data_w[31:0] 129 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope ram_ack_w 130 | addSignal -c ID_BLUE6 -ls solid -lw 1 -h 15 -holdScope resp_valid_w 131 | addSignal -c ID_RED5 -ls solid -lw 1 -h 15 -UNSIGNED -ASC -holdScope dbg_state[79:0] 132 | addSignal -h 15 -holdScope req_wr_q 133 | addSignal -h 15 -holdScope req_wr_q_q 134 | addSignal -h 15 -UNSIGNED -HEX -holdScope data_q[15:0] 135 | addSignal -h 15 -UNSIGNED -HEX -holdScope data_buffer_q[15:0] 136 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -UNSIGNED -ASC -holdScope dbg_cmd[79:0] 137 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -UNSIGNED -BIN -holdScope SDRAM_dqm[1:0] 138 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -UNSIGNED -UDEC -holdScope SDRAM_a[12:0] 139 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope SDRAM_ba[1:0] 140 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope SDRAM_dqi[15:0] 141 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -UNSIGNED -HEX -holdScope SDRAM_dqo[15:0] 142 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -holdScope SDRAM_cke 143 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -holdScope SDRAM_ras 144 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -holdScope SDRAM_cas 145 | addSignal -c ID_PURPLE5 -ls solid -lw 1 -h 15 -holdScope SDRAM_we 146 | addGroup "G2" 147 | 148 | ; getSignalForm Scope Hierarchy Status 149 | ; active file of getSignalForm 150 | 151 | --------------------------------------------------------------------------------