| // Copyright 2023 Google LLC | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package matcha | 
 |  | 
 | import chisel3._ | 
 |  | 
 | import bus.KelvinMemIO | 
 | import java.nio.file.{Paths, Files, StandardOpenOption} | 
 | import java.nio.charset.{StandardCharsets} | 
 | import _root_.circt.stage.{ChiselStage} | 
 |  | 
 | object Kelvin { | 
 |   def apply(p: kelvin.Parameters): Kelvin = { | 
 |     return Module(new Kelvin(p, moduleName = "Kelvin")) | 
 |   } | 
 | } | 
 |  | 
 | class Kelvin(p: kelvin.Parameters, moduleName: String) extends RawModule { | 
 |   override val desiredName = moduleName | 
 |   // IO ports. (RawModule removes default[clock, reset]) | 
 |   val clk_i  = IO(Input(Clock())) | 
 |   val rst_ni = IO(Input(AsyncReset())) | 
 |  | 
 |   val mem = IO(new KelvinMemIO(p)) | 
 |  | 
 |   val clk_freeze = IO(Input(Bool())) | 
 |   val ml_reset   = IO(Input(Bool())) | 
 |   val pc_start   = IO(Input(UInt(32.W))) | 
 |   val volt_sel   = IO(Input(Bool())) | 
 |   val debug_req  = IO(Input(Bool())) | 
 |  | 
 |   val finish   = IO(Output(Bool())) | 
 |   val host_req = IO(Output(Bool())) | 
 |   val fault    = IO(Output(Bool())) | 
 |  | 
 |   val slog = IO(new kelvin.SLogIO(p)) | 
 |  | 
 |   // --------------------------------------------------------------------------- | 
 |   // Gated Clock. | 
 |   val cg = Module(new kelvin.ClockGate) | 
 |   cg.io.clk_i  := clk_i | 
 |   cg.io.enable := !clk_freeze | 
 |   cg.io.te := false.B | 
 |   val clk_g = cg.io.clk_o | 
 |  | 
 |   // --------------------------------------------------------------------------- | 
 |   // Reset inverter and synchronizer. | 
 |   // | 
 |   // Most registers in the design are loaded by literals and it is safe to use | 
 |   // rst_i directly. However some registers {fetch.instAddr} load from io ports | 
 |   // or use "reset.asBool" to initialize state which infers synchronous resets. | 
 |   // This hybrid design allows for interfaces to reset immediately on reset | 
 |   // assertion while ensuring all internal state will eventually be reset | 
 |   // correctly before usage. | 
 |   val rst_i = (!rst_ni.asBool || ml_reset).asAsyncReset | 
 |   val rst_core = Wire(Bool()) | 
 |  | 
 |   withClockAndReset(clk_i, rst_i) { | 
 |     val rst_q1 = RegInit(true.B) | 
 |     val rst_q2 = RegInit(true.B) | 
 |     rst_q1 := false.B | 
 |     rst_q2 := rst_q1 | 
 |     rst_core := rst_q2 | 
 |   } | 
 |  | 
 |   // --------------------------------------------------------------------------- | 
 |   // Connect clock and reset. | 
 |   withClockAndReset(clk_g, rst_core.asAsyncReset) { | 
 |     assert(p.vectorBits == 256) | 
 |  | 
 |     val core = kelvin.Core(p) | 
 |     val l1d = kelvin.L1DCache(p) | 
 |     val l1i = kelvin.L1ICache(p) | 
 |     val bus = Axi2Sram(p) | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // Control interface. | 
 |     finish   := core.io.halted | 
 |     host_req := false.B | 
 |     fault    := core.io.fault | 
 |     core.io.irq := false.B | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // Scalar Core logging. | 
 |     slog   := core.io.slog | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // Debug Interface. | 
 |     core.io.debug_req   := debug_req | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // L1Cache. | 
 |     l1d.io.dbus     <> core.io.dbus | 
 |     l1d.io.flush    <> core.io.dflush | 
 |     l1d.io.volt_sel := volt_sel | 
 |  | 
 |     l1i.io.ibus     <> core.io.ibus | 
 |     l1i.io.flush    <> core.io.iflush | 
 |     l1i.io.volt_sel := volt_sel | 
 |  | 
 |     // core.io.ebus <> 0.U.asTypeOf(core.io.ebus) | 
 |     core.io.ebus.dbus.ready := false.B | 
 |     core.io.ebus.dbus.rdata := 0.U.asTypeOf(core.io.ebus.dbus.rdata) | 
 |     core.io.ebus.fault.valid := false.B | 
 |     core.io.ebus.fault.bits := 0.U.asTypeOf(core.io.ebus.fault.bits) | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // Bus Mux. | 
 |     bus.io.l1d <> l1d.io.axi | 
 |     bus.io.l1i.read <> l1i.io.axi.read | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // SRAM bridge. | 
 |     mem.cvalid := bus.io.out.cvalid | 
 |     bus.io.out.cready := mem.cready | 
 |     mem.cwrite := bus.io.out.cwrite | 
 |     mem.caddr  := bus.io.out.caddr | 
 |     mem.cid    := bus.io.out.cid | 
 |     mem.wdata  := bus.io.out.wdata | 
 |     mem.wmask  := bus.io.out.wmask | 
 |     bus.io.out.rvalid := mem.rvalid | 
 |     bus.io.out.rid := mem.rid | 
 |     bus.io.out.rdata := mem.rdata | 
 |  | 
 |     // ------------------------------------------------------------------------- | 
 |     // Command interface. | 
 |     for (i <- 0 until p.csrInCount) { | 
 |       core.io.csr.in.value(i) := 0.U | 
 |     } | 
 |  | 
 |     core.io.csr.in.value(0) := pc_start | 
 |   } | 
 | } | 
 |  | 
 | object EmitKelvin extends App { | 
 |   val p = new kelvin.MatchaParameters | 
 |   val core_p = new kelvin.Parameters | 
 |   var moduleName = "Kelvin" | 
 |   var chiselArgs = List[String]() | 
 |   var targetDir: Option[String] = None | 
 |   for (arg <- args) { | 
 |     if (arg.startsWith("--enableFetchL0")) { | 
 |       val argval = arg.split("=")(1).toBoolean | 
 |       p.enableFetchL0 = argval | 
 |       core_p.enableFetchL0 = argval | 
 |     } else if (arg.startsWith("--moduleName")) { | 
 |       moduleName = arg.split("=")(1) | 
 |     } else if (arg.startsWith("--enableVector")) { | 
 |       val argval = arg.split("=")(1).toBoolean | 
 |       p.enableVector = argval | 
 |       core_p.enableVector = argval | 
 |     } else if (arg.startsWith("--fetchDataBits")) { | 
 |       val argval = arg.split("=")(1).toInt | 
 |       p.fetchDataBits = argval | 
 |       core_p.fetchDataBits = argval | 
 |     } else if (arg.startsWith("--lsuDataBits")) { | 
 |       val argval = arg.split("=")(1).toInt | 
 |       p.lsuDataBits = argval | 
 |       core_p.lsuDataBits = argval | 
 |     } else if (arg.startsWith("--target-dir")) { | 
 |       targetDir = Some(arg.split("=")(1)) | 
 |     } else { | 
 |       chiselArgs = chiselArgs :+ arg | 
 |     } | 
 |   } | 
 |   // The core module must be created in the ChiselStage context. Use lazy here | 
 |   // so it's created in ChiselStage, but referencable afterwards. | 
 |   lazy val core = new Kelvin(p, moduleName) | 
 |   val firtoolOpts = Array( | 
 |       "-enable-layers=Verification", | 
 |   ) | 
 |   val systemVerilogSource = ChiselStage.emitSystemVerilog( | 
 |     core, chiselArgs.toArray, firtoolOpts) | 
 |   // CIRCT adds a little extra data to the sv file at the end. Remove it as we | 
 |   // don't want it (it prevents the sv from being verilated). | 
 |   val resourcesSeparator = | 
 |       "// ----- 8< ----- FILE \"firrtl_black_box_resource_files.f\" ----- 8< -----" | 
 |   val strippedVerilogSource = systemVerilogSource.split(resourcesSeparator)(0) | 
 |  | 
 |  | 
 |   val header_str = kelvin.EmitParametersHeader(core_p) | 
 |   targetDir match { | 
 |     case Some(targetDir) => { | 
 |       Files.write( | 
 |           Paths.get(targetDir + "/V" + moduleName + "_parameters.h"), | 
 |           header_str.getBytes(StandardCharsets.UTF_8), | 
 |           StandardOpenOption.CREATE) | 
 |       Files.write( | 
 |           Paths.get(targetDir + "/" + core.name + ".sv"), | 
 |           strippedVerilogSource.getBytes(StandardCharsets.UTF_8), | 
 |           StandardOpenOption.CREATE) | 
 |       () | 
 |     } | 
 |     case None => () | 
 |   } | 
 | } |