[ChAI] Initial commit - ChAI is a "Standalone Kelvin" system - It contains a Kelvin core, a UART, and a 4MB SRAM, tied together via a TL-UL crossbar. Change-Id: I278e721831eef2a452d050c2973d6a7ec9bf69a7
diff --git a/hdl/chisel/src/chai/BUILD b/hdl/chisel/src/chai/BUILD new file mode 100644 index 0000000..b4e1c48 --- /dev/null +++ b/hdl/chisel/src/chai/BUILD
@@ -0,0 +1,45 @@ +# Copyright 2024 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. + +load("@kelvin_hw//rules:chisel.bzl", "chisel_cc_library", "chisel_library") + +package(default_visibility = ["//visibility:public"]) + +chisel_library( + name = "chai", + srcs = [ + "ChAI.scala", + "KelvinToTlul.scala", + "TlulAdapterSram.scala", + "Uart.scala", + ], + deps = [ + "//hdl/chisel/src/matcha:matcha", + "//hdl/chisel/src/kelvin:kelvin", + ], +) + +chisel_cc_library( + name = "chai_cc_library", + chisel_lib = ":chai", + emit_class = "chai.EmitChAI", + module_name = "ChAI", + verilog_deps = [ + "//hdl/verilog:clock_gate", + "//hdl/verilog:sram_1rw_256x256", + "//hdl/verilog:sram_1rw_256x288", + "//hdl/verilog:tlul_adapter_sram", + "//hdl/verilog:uart", + ], +)
diff --git a/hdl/chisel/src/chai/ChAI.scala b/hdl/chisel/src/chai/ChAI.scala new file mode 100644 index 0000000..97ce896 --- /dev/null +++ b/hdl/chisel/src/chai/ChAI.scala
@@ -0,0 +1,119 @@ +// Copyright 2024 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 chai + +import chisel3._ +import chisel3.util._ +import _root_.circt.stage.ChiselStage + +case class Parameters() { + val sramReadPorts = 1 + val sramWritePorts = 1 + val sramReadWritePorts = 0 + val sramDataBits = 256 + val sramBytes = 4 * 1024 * 1024 + def sramDataEntries(): Int = { + ((sramBytes * 8) / sramDataBits) + } + def sramAddrBits(): Int = { + log2Ceil(sramDataEntries()) + } +} + +object ChAI { + def apply(p: Parameters): ChAI = { + return Module(new ChAI(p)) + } +} + +class ChAI(p: Parameters) extends RawModule { + val io = IO(new Bundle { + val clk_i = Input(Clock()) + val rst_ni = Input(AsyncReset()) + val sram = new Bundle { + val write_address = Input(UInt(p.sramAddrBits().W)) + val write_enable = Input(Bool()) + val write_data = Input(UInt(p.sramDataBits.W)) + } + val finish = Output(Bool()) + val fault = Output(Bool()) + val freeze = Input(Bool()) + + val uart_rx = Input(Bool()) + val uart_tx = Output(Bool()) + }) + + // TODO(atv): Compute that we don't have any overlaps in regions. + val memoryRegions = Seq( + new kelvin.MemoryRegion(0, 4 * 1024 * 1024, true, 256), // SRAM + new kelvin.MemoryRegion(4 * 1024 * 1024, 4 * 1024 * 1024, false, 256) // UART + ) + val kelvin_p = kelvin.Parameters(memoryRegions) + val rst_i = (!io.rst_ni.asBool).asAsyncReset + + val u_kelvin = matcha.Kelvin(kelvin_p) + u_kelvin.clk_i := io.clk_i + u_kelvin.rst_ni := io.rst_ni + u_kelvin.clk_freeze := io.freeze + u_kelvin.ml_reset := 0.U + u_kelvin.pc_start := 0.U + u_kelvin.volt_sel := 0.U + + io.finish := u_kelvin.finish + io.fault := u_kelvin.fault + + withClockAndReset(io.clk_i, rst_i) { + val tlul_p = new kelvin.TLULParameters() + val kelvin_to_tlul = chai.KelvinToTlul(tlul_p, kelvin_p) + kelvin_to_tlul.io.kelvin <> u_kelvin.mem + + val tlul_sram = + SRAM(p.sramDataEntries(), UInt(p.sramDataBits.W), p.sramReadPorts, p.sramWritePorts, p.sramReadWritePorts) + val tlul_adapter_sram = Module(new chai.TlulAdapterSram()) + tlul_adapter_sram.io.clk_i := io.clk_i + tlul_adapter_sram.io.rst_ni := io.rst_ni + tlul_adapter_sram.io.en_ifetch_i := 9.U // MuBi4False + tlul_sram.readPorts(0).enable := tlul_adapter_sram.io.req_o + tlul_sram.readPorts(0).address := tlul_adapter_sram.io.addr_o + tlul_sram.writePorts(0).enable := Mux(io.freeze, io.sram.write_enable, tlul_adapter_sram.io.we_o) + tlul_sram.writePorts(0).address := Mux(io.freeze, io.sram.write_address, tlul_adapter_sram.io.addr_o) + tlul_sram.writePorts(0).data := Mux(io.freeze, io.sram.write_data, tlul_adapter_sram.io.wdata_o) + tlul_adapter_sram.io.gnt_i := 1.U + tlul_adapter_sram.io.rdata_i := tlul_sram.readPorts(0).data + tlul_adapter_sram.io.rvalid_i := 1.U + tlul_adapter_sram.io.rerror_i := 0.U + + val uart = Module(new chai.Uart(tlul_p)) + uart.io.clk_i := io.clk_i + uart.io.rst_ni := io.rst_ni + uart.io.alert_rx_i := 0.U + uart.io.cio_rx_i := io.uart_rx + io.uart_tx := uart.io.cio_tx_o + + val crossbar = + Module(new kelvin.TileLinkUL(tlul_p, kelvin_p.m, /* hosts= */ 1)) + crossbar.io.hosts_a(0) <> kelvin_to_tlul.io.tl_o + crossbar.io.hosts_d(0) <> kelvin_to_tlul.io.tl_i + crossbar.io.devices_a(0) <> tlul_adapter_sram.io.tl_i + crossbar.io.devices_d(0) <> tlul_adapter_sram.io.tl_o + crossbar.io.devices_a(1) <> uart.io.tl_i + crossbar.io.devices_d(1) <> uart.io.tl_o + } +} + +object EmitChAI extends App { + val p = new Parameters() + ChiselStage.emitSystemVerilogFile(new ChAI(p), args) +}
diff --git a/hdl/chisel/src/chai/KelvinToTlul.scala b/hdl/chisel/src/chai/KelvinToTlul.scala new file mode 100644 index 0000000..c8573c2 --- /dev/null +++ b/hdl/chisel/src/chai/KelvinToTlul.scala
@@ -0,0 +1,114 @@ +// Copyright 2024 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 chai + +import chisel3._ +import chisel3.util._ + +object KelvinToTlul { + object State extends ChiselEnum { + val sIdle, sWaitForReady, sWaitForResponse = Value + } + + def apply(tlul_p: kelvin.TLULParameters, kelvin_p: kelvin.Parameters): KelvinToTlul = { + return Module(new KelvinToTlul(tlul_p, kelvin_p)) + } +} + +class KelvinToTlul(tlul_p: kelvin.TLULParameters, kelvin_p: kelvin.Parameters) extends Module { + import KelvinToTlul.State + import KelvinToTlul.State._ + + val io = IO(new Bundle { + val tl_i = Input(new _root_.kelvin.TileLinkULIO_D2H(tlul_p)) + val tl_o = Output(new _root_.kelvin.TileLinkULIO_H2D(tlul_p)) + val kelvin = Flipped(new matcha.KelvinMemIO(kelvin_p)) + }) + val state = RegInit(sIdle) + + val wmask_width = io.kelvin.wmask.getWidth + val wmask_bits = (0 until wmask_width) + .map(x => Mux(io.kelvin.wmask(x), 0xff.U(wmask_width.W) << (x * 8).U, 0.U(wmask_width.W))) + .reduce(_ | _) + + io.tl_o := 0.U.asTypeOf(new kelvin.TileLinkULIO_H2D(tlul_p)) + io.tl_o.a_user.instr_type := 9.U + io.tl_o.a_source := 0.U + io.tl_o.d_ready := true.B + io.kelvin.rid := 0.U + io.kelvin.cready := true.B + io.kelvin.rvalid := false.B + io.kelvin.rdata := 0.U + io.tl_o.a_mask := -1.S(io.tl_o.a_mask.getWidth.W).asUInt + io.tl_o.a_param := 0.U + io.tl_o.a_size := 5.U + + // state | transition | next state + // sIdle | valid & a_ready | sWaitForResponse + // sIdle | valid & !a_ready | sWaitForReady + // sWaitForReady | a_ready | sWaitForResponse + // sWaitForResponse | d_valid | sIdle + switch(state) { + is(sIdle) { + io.kelvin.cready := true.B + when(io.kelvin.cvalid) { + io.kelvin.cready := false.B + io.tl_o.a_valid := true.B + io.tl_o.a_address := io.kelvin.caddr + val cwrite = io.kelvin.cwrite + io.tl_o.a_opcode := Mux(cwrite, kelvin.TLULOpcodesA.PutFullData.asUInt, kelvin.TLULOpcodesA.Get.asUInt) + io.tl_o.a_data := Mux(cwrite, io.kelvin.wdata & wmask_bits, 0.U) + state := Mux(io.tl_i.a_ready, sWaitForResponse, sWaitForReady) + } + } + is(sWaitForReady) { + when(io.tl_i.a_ready) { + state := sWaitForResponse + } + } + is(sWaitForResponse) { + io.tl_o.a_valid := false.B + when(io.tl_i.d_valid) { + val (value, valid) = kelvin.TLULOpcodesD.safe(io.tl_i.d_opcode) + val valid2 = valid && (value =/= kelvin.TLULOpcodesD.End) + assert(valid2, "Received invalid TLUL-D opcode\n") + + val rdata = chisel3.util.MuxLookup(value, 0.U(32.W))( + Array( + kelvin.TLULOpcodesD.AccessAck -> 0.U, + kelvin.TLULOpcodesD.AccessAckData -> io.tl_i.d_data + ) + ) + val rvalid = chisel3.util.MuxLookup(value, false.B)( + Array( + kelvin.TLULOpcodesD.AccessAck -> false.B, + kelvin.TLULOpcodesD.AccessAckData -> true.B + ) + ) + val rid = chisel3.util.MuxLookup(value, 0.U)( + Array( + kelvin.TLULOpcodesD.AccessAck -> 0.U, + kelvin.TLULOpcodesD.AccessAckData -> io.kelvin.cid + ) + ) + io.kelvin.rvalid := rvalid + io.kelvin.rdata := rdata + io.kelvin.cready := true.B + io.kelvin.rid := rid + state := sIdle + } + } + } +}
diff --git a/hdl/chisel/src/chai/TlulAdapterSram.scala b/hdl/chisel/src/chai/TlulAdapterSram.scala new file mode 100644 index 0000000..345db11 --- /dev/null +++ b/hdl/chisel/src/chai/TlulAdapterSram.scala
@@ -0,0 +1,55 @@ +// Copyright 2024 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 chai + +import chisel3._ +import chisel3.util._ + +package object sram_params { + val SramAw = 17 + val SramDw = 256 + val Outstanding = 1 + val ByteAccess = 1 + val ErrOnRead = 0 + val EnableDataIntgPt = 0 +} + +class TlulAdapterSram extends BlackBox { + val tlul_p = new kelvin.TLULParameters() + val io = IO(new Bundle { + val clk_i = Input(Clock()) + val rst_ni = Input(AsyncReset()) + + // TL-UL + val tl_i = Input(new kelvin.TileLinkULIO_H2D(tlul_p)) + val tl_o = Output(new kelvin.TileLinkULIO_D2H(tlul_p)) + + // control + val en_ifetch_i = Input(UInt(4.W)) // mubi4_t + + // SRAM interface + val req_o = Output(Bool()) + val req_type_o = Output(UInt(4.W)) // mubi4_t + val gnt_i = Input(Bool()) + val we_o = Output(Bool()) + val addr_o = Output(UInt(sram_params.SramAw.W)) + val wdata_o = Output(UInt(sram_params.SramDw.W)) + val wmask_o = Output(UInt(sram_params.SramDw.W)) + val intg_error_o = Output(Bool()) + val rdata_i = Input(UInt(sram_params.SramDw.W)) + val rvalid_i = Input(Bool()) + val rerror_i = Input(UInt(2.W)) + }) +}
diff --git a/hdl/chisel/src/chai/Uart.scala b/hdl/chisel/src/chai/Uart.scala new file mode 100644 index 0000000..4fa3090 --- /dev/null +++ b/hdl/chisel/src/chai/Uart.scala
@@ -0,0 +1,45 @@ +// Copyright 2024 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 chai + +import chisel3._ +import chisel3.util._ + +class Uart(tlul_p: kelvin.TLULParameters) extends BlackBox { + val io = IO(new Bundle { + val clk_i = Input(Clock()) + val rst_ni = Input(AsyncReset()) + + val tl_i = Input(new kelvin.TileLinkULIO_H2D(tlul_p)) + val tl_o = Output(new kelvin.TileLinkULIO_D2H(tlul_p)) + + // These have some alert_{rx|tx}_t types. + val alert_rx_i = Input(UInt(4.W)) + val alert_tx_o = Output(UInt(2.W)) + + val cio_rx_i = Input(Bool()) + val cio_tx_o = Output(Bool()) + val cio_tx_en_o = Output(Bool()) + + val intr_tx_watermark_o = Output(Bool()) + val intr_rx_watermark_o = Output(Bool()) + val intr_tx_empty_o = Output(Bool()) + val intr_rx_overflow_o = Output(Bool()) + val intr_rx_frame_err_o = Output(Bool()) + val intr_rx_break_err_o = Output(Bool()) + val intr_rx_timeout_o = Output(Bool()) + val intr_rx_parity_err_o = Output(Bool()) + }) +}
diff --git a/hdl/chisel/src/kelvin/BUILD b/hdl/chisel/src/kelvin/BUILD index b206de7..76d2cda 100644 --- a/hdl/chisel/src/kelvin/BUILD +++ b/hdl/chisel/src/kelvin/BUILD
@@ -28,6 +28,7 @@ "L1ICache.scala", "Library.scala", "Parameters.scala", + "TileLinkUL.scala", "scalar/Alu.scala", "scalar/Bru.scala", "scalar/Csr.scala", @@ -191,4 +192,4 @@ chisel_lib = ":kelvin", emit_class = "kelvin.EmitVSt", module_name = "VSt", -) \ No newline at end of file +)
diff --git a/hdl/chisel/src/kelvin/Parameters.scala b/hdl/chisel/src/kelvin/Parameters.scala index bb8a149..7c4b983 100644 --- a/hdl/chisel/src/kelvin/Parameters.scala +++ b/hdl/chisel/src/kelvin/Parameters.scala
@@ -17,7 +17,21 @@ import chisel3._ import chisel3.util._ -case class Parameters() { +class MemoryRegion( + val memStart: Int, + val memSize: Int, + val cacheable: Boolean, + val dataWidthBits: Int, +) { + +def contains(addr: UInt): Bool = { + val addrWidth = addr.getWidth.W + (addr >= memStart.U(addrWidth)) && (addr < memStart.U(addrWidth) + memSize.U(addrWidth)) +} + +} + +case class Parameters(m: Seq[MemoryRegion] = Seq()) { case object Core { val tiny = 0 val little = 1
diff --git a/hdl/chisel/src/kelvin/TileLinkUL.scala b/hdl/chisel/src/kelvin/TileLinkUL.scala new file mode 100644 index 0000000..155fa3d --- /dev/null +++ b/hdl/chisel/src/kelvin/TileLinkUL.scala
@@ -0,0 +1,127 @@ +// Copyright 2024 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 kelvin + +import chisel3._ +import chisel3.util._ +import _root_.circt.stage.ChiselStage + +case class TLULParameters() { + val w = 32 + val a = 32 + val z = 6 + val o = 10 + val i = 1 +} + +object TLULOpcodesA extends ChiselEnum { + val PutFullData = Value(0.U(3.W)) + val PutPartialData = Value(1.U(3.W)) + val Get = Value(4.U(3.W)) + val End = Value(7.U(3.W)) +} + +object TLULOpcodesD extends ChiselEnum { + val AccessAck = Value(0.U(3.W)) + val AccessAckData = Value(1.U(3.W)) + val End = Value(7.U(3.W)) +} + +class TileLinkULIO_H2D(p: TLULParameters) extends Bundle { + val a_valid = (Bool()) + val a_opcode = (UInt(3.W)) + val a_param = (UInt(3.W)) + val a_size = (UInt(p.z.W)) + val a_source = (UInt(p.o.W)) + val a_address = (UInt(p.a.W)) + val a_mask = (UInt(p.w.W)) + val a_data = (UInt((8 * p.w).W)) + val a_user = new Bundle { + val rsvd = UInt(5.W) + val instr_type = UInt(4.W) // mubi4_t + val cmd_intg = UInt(7.W) + val data_intg = UInt(7.W) + } + val d_ready = (Bool()) +} + +class TileLinkULIO_D2H(p: TLULParameters) extends Bundle { + val d_valid = (Bool()) + val d_opcode = (UInt(3.W)) + val d_param = (UInt(3.W)) + val d_size = (UInt(p.z.W)) + val d_source = (UInt(p.o.W)) + val d_sink = (UInt(p.i.W)) + val d_data = (UInt((8 * p.w).W)) + val d_user = new Bundle { + val rsp_intg = UInt(7.W) + val data_intg = UInt(7.W) + } + val d_error = (Bool()) + val a_ready = (Bool()) +} + +class TileLinkUL(p: TLULParameters, m: Seq[MemoryRegion], hosts: Int) extends Module { + val devices = m.length + val io = IO(new Bundle { + val hosts_a = Vec(hosts, Input(new TileLinkULIO_H2D(p))) + val hosts_d = Vec(hosts, Output(new TileLinkULIO_D2H(p))) + val devices_a = Vec(devices, Output(new TileLinkULIO_H2D(p))) + val devices_d = Vec(devices, Input(new TileLinkULIO_D2H(p))) + }) + + + for (i <- 0 until hosts) { + io.hosts_d(i) := 0.U.asTypeOf(new TileLinkULIO_D2H(p)) + } + for (i <- 0 until devices) { + io.devices_a(i) := 0.U.asTypeOf(new TileLinkULIO_H2D(p)) + } + + val aValids = io.hosts_a.map(x => x.a_valid) + val anyAValid = PopCount(aValids) > 0.U + when(anyAValid) { + val aValidIndex = PriorityEncoder(aValids) + val host_a = io.hosts_a(aValidIndex) + val host_d = io.hosts_d(aValidIndex) + val address = host_a.a_address + + val addressOk = (0 until devices).map(x => m(x).contains(address)) + val startAddresses = VecInit(m.map(x => x.memStart.U(p.a.W))) + assert(PopCount(addressOk) === 1.U) + val deviceIndex = PriorityEncoder(addressOk) + val device_a = io.devices_a(deviceIndex) + val device_d = io.devices_d(deviceIndex) + + device_a :<>= host_a + device_a.a_address := host_a.a_address - startAddresses(deviceIndex) + host_d :<>= device_d + } + + val dValids = io.devices_d.map(x => x.d_valid) + val anyDValid = dValids.reduce(_ || _) + when(anyDValid) { + val dValidIndex = PriorityEncoder(dValids) + val device_d = io.devices_d(dValidIndex) + val device_a = io.devices_a(dValidIndex) + val source = device_d.d_source + val sink = device_d.d_sink + val host_d = io.hosts_d(source) + val host_a = io.hosts_a(source) + + host_d :<>= device_d + device_a :<>= host_a + } +}
diff --git a/hdl/chisel/src/kelvin/scalar/Lsu.scala b/hdl/chisel/src/kelvin/scalar/Lsu.scala index 520693b..60aa158 100644 --- a/hdl/chisel/src/kelvin/scalar/Lsu.scala +++ b/hdl/chisel/src/kelvin/scalar/Lsu.scala
@@ -136,8 +136,10 @@ // Control Port Inputs. ctrl.io.in.valid := io.req.map(_.valid).reduce(_||_) + val uncacheable = p.m.filter(x => !x.cacheable) for (i <- 0 until 4) { - val uncached = io.busPort.addr(i)(31) + val uncached = io.busPort.addr(i)(31) || + (if (uncacheable.length > 0) uncacheable.map(x => (io.busPort.addr(i) >= x.memStart.U) && (io.busPort.addr(i) < (x.memStart + x.memSize).U)).reduce(_||_) else false.B) val opstore = io.req(i).op(lsu.SW) || io.req(i).op(lsu.SH) || io.req(i).op(lsu.SB) val opiload = io.req(i).op(lsu.LW) || io.req(i).op(lsu.LH) || io.req(i).op(lsu.LB) || io.req(i).op(lsu.LHU) || io.req(i).op(lsu.LBU) @@ -218,7 +220,6 @@ io.ubus.size := ctrl.io.out.bits.size io.ubus.wdata := wdata io.ubus.wmask := wmask - assert(!(io.ubus.valid && !ctrl.io.out.bits.addr(31))) assert(!(io.ubus.valid && io.dbus.addr(31))) assert(!(io.ubus.valid && io.dbus.adrx(31)))
diff --git a/hdl/chisel/src/matcha/Kelvin.scala b/hdl/chisel/src/matcha/Kelvin.scala index 31efda2..b8ed6cf 100644 --- a/hdl/chisel/src/matcha/Kelvin.scala +++ b/hdl/chisel/src/matcha/Kelvin.scala
@@ -144,6 +144,6 @@ } object EmitKelvin extends App { - val p = new kelvin.Parameters() + val p = new kelvin.Parameters(Seq()) ChiselStage.emitSystemVerilogFile(new Kelvin(p), args) }
diff --git a/hdl/verilog/BUILD b/hdl/verilog/BUILD index 63f4925..440262a 100644 --- a/hdl/verilog/BUILD +++ b/hdl/verilog/BUILD
@@ -19,6 +19,8 @@ "ClockGate.sv", "Sram_1rw_256x256.v", "Sram_1rwm_256x288.v", + "TlulAdapterSram.sv", + "Uart.sv", ], visibility = ["//visibility:public"], ) @@ -43,3 +45,22 @@ srcs = ["Sram_1rwm_256x288.v"], visibility = ["//visibility:public"], ) + +verilog_library( + name = "tlul_adapter_sram", + srcs = ["TlulAdapterSram.sv"], + deps = [ + "//third_party/ip/lowrisc:prim", + "//third_party/ip/lowrisc:tlul_adapter_sram", + ], + visibility = ["//visibility:public"], +) + +verilog_library( + name = "uart", + srcs = ["Uart.sv"], + deps = [ + "//third_party/ip/lowrisc:uart", + ], + visibility = ["//visibility:public"], +)
diff --git a/hdl/verilog/TlulAdapterSram.sv b/hdl/verilog/TlulAdapterSram.sv new file mode 100644 index 0000000..e1a295c --- /dev/null +++ b/hdl/verilog/TlulAdapterSram.sv
@@ -0,0 +1,113 @@ +// Copyright 2024 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. + +module TlulAdapterSram +import prim_mubi_pkg::mubi4_t; +( + input clk_i, + input rst_ni, + input tl_i_a_valid, + input [2:0] tl_i_a_opcode, + input [2:0] tl_i_a_param, + input [5:0] tl_i_a_size, + input [9:0] tl_i_a_source, + input [31:0] tl_i_a_address, + input [31:0] tl_i_a_mask, + input [255:0] tl_i_a_data, + input [4:0] tl_i_a_user_rsvd, + input [3:0] tl_i_a_user_instr_type, + input [6:0] tl_i_a_user_cmd_intg, + input [6:0] tl_i_a_user_data_intg, + input tl_i_d_ready, + input [3:0] en_ifetch_i, + input gnt_i, + input [255:0] rdata_i, + input rvalid_i, + input [1:0] rerror_i, + output tl_o_d_valid, + output [2:0] tl_o_d_opcode, + output [2:0] tl_o_d_param, + output [5:0] tl_o_d_size, + output [9:0] tl_o_d_source, + output tl_o_d_sink, + output [255:0] tl_o_d_data, + output [6:0] tl_o_d_user_rsp_intg, + output [6:0] tl_o_d_user_data_intg, + output tl_o_d_error, + output tl_o_a_ready, + output req_o, + output [3:0] req_type_o, + output we_o, + output [16:0] addr_o, + output [255:0] wdata_o, + output [255:0] wmask_o, + output intg_error_o +); + +mubi4_t en_ifetch_i_ = mubi4_t'(en_ifetch_i); + +tlul_adapter_sram #( + .SramAw(17), + .SramDw(256), + .Outstanding(1), + .ByteAccess(1), + .ErrOnRead(0), + .EnableDataIntgPt(0) +) u_tlul_adapter_sram ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .tl_i( + { + tl_i_a_valid, + tl_i_a_opcode, + tl_i_a_param, + tl_i_a_size, + tl_i_a_source, + tl_i_a_address, + tl_i_a_mask, + tl_i_a_data, + tl_i_a_user_rsvd, + tl_i_a_user_instr_type, + tl_i_a_user_cmd_intg, + tl_i_a_user_data_intg, + tl_i_d_ready + }), + .tl_o({ + tl_o_d_valid, + tl_o_d_opcode, + tl_o_d_param, + tl_o_d_size, + tl_o_d_source, + tl_o_d_sink, + tl_o_d_data, + tl_o_d_user_rsp_intg, + tl_o_d_user_data_intg, + tl_o_d_error, + tl_o_a_ready + }), + .en_ifetch_i(en_ifetch_i_), + .req_o(req_o), + .req_type_o(req_type_o), + .gnt_i(gnt_i), + .we_o(we_o), + .addr_o(addr_o), + .wdata_o(wdata_o), + .wmask_o(wmask_o), + .intg_error_o(intg_error_o), + .rdata_i(rdata_i), + .rvalid_i(rvalid_i), + .rerror_i(rerror_i) +); + +endmodule \ No newline at end of file
diff --git a/hdl/verilog/Uart.sv b/hdl/verilog/Uart.sv new file mode 100644 index 0000000..b00a4b4 --- /dev/null +++ b/hdl/verilog/Uart.sv
@@ -0,0 +1,109 @@ +// Copyright 2024 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. + +module Uart( + input clk_i, + input rst_ni, + input tl_i_a_valid, + input [2:0] tl_i_a_opcode, + input [2:0] tl_i_a_param, + input [5:0] tl_i_a_size, + input [9:0] tl_i_a_source, + input [31:0] tl_i_a_address, + input [31:0] tl_i_a_mask, + input [255:0] tl_i_a_data, + input [4:0] tl_i_a_user_rsvd, + input [3:0] tl_i_a_user_instr_type, + input [6:0] tl_i_a_user_cmd_intg, + input [6:0] tl_i_a_user_data_intg, + input tl_i_d_ready, + output tl_o_d_valid, + output [2:0] tl_o_d_opcode, + output [2:0] tl_o_d_param, + output [5:0] tl_o_d_size, + output [9:0] tl_o_d_source, + output tl_o_d_sink, + output [255:0] tl_o_d_data, + output [6:0] tl_o_d_user_rsp_intg, + output [6:0] tl_o_d_user_data_intg, + output tl_o_d_error, + output tl_o_a_ready, + + input [3:0] alert_rx_i, + output [1:0] alert_tx_o, + + input cio_rx_i, + output cio_tx_o, + output cio_tx_en_o, + + output intr_tx_watermark_o, + output intr_rx_watermark_o, + output intr_tx_empty_o, + output intr_rx_overflow_o, + output intr_rx_frame_err_o, + output intr_rx_break_err_o, + output intr_rx_timeout_o, + output intr_rx_parity_err_o +); + +uart #() u_uart ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .tl_i( + { + tl_i_a_valid, + tl_i_a_opcode, + tl_i_a_param, + tl_i_a_size, + tl_i_a_source, + tl_i_a_address, + tl_i_a_mask, + tl_i_a_data, + tl_i_a_user_rsvd, + tl_i_a_user_instr_type, + tl_i_a_user_cmd_intg, + tl_i_a_user_data_intg, + tl_i_d_ready + }), + .tl_o({ + tl_o_d_valid, + tl_o_d_opcode, + tl_o_d_param, + tl_o_d_size, + tl_o_d_source, + tl_o_d_sink, + tl_o_d_data, + tl_o_d_user_rsp_intg, + tl_o_d_user_data_intg, + tl_o_d_error, + tl_o_a_ready + }), + .alert_rx_i(alert_rx_i), + .alert_tx_o(alert_tx_o), + + .cio_rx_i(cio_rx_i), + .cio_tx_o(cio_tx_o), + .cio_tx_en_o(cio_tx_en_o), + + .intr_tx_watermark_o(intr_tx_watermark_o), + .intr_rx_watermark_o(intr_rx_watermark_o), + .intr_tx_empty_o(intr_tx_empty_o), + .intr_rx_overflow_o(intr_rx_overflow_o), + .intr_rx_frame_err_o(intr_rx_frame_err_o), + .intr_rx_break_err_o(intr_rx_break_err_o), + .intr_rx_timeout_o(intr_rx_timeout_o), + .intr_rx_parity_err_o(intr_rx_parity_err_o) +); + +endmodule \ No newline at end of file
diff --git a/rules/repos.bzl b/rules/repos.bzl index e57dc73..6a70d75 100644 --- a/rules/repos.bzl +++ b/rules/repos.bzl
@@ -88,6 +88,8 @@ urls = ["https://github.com/lowrisc/opentitan/archive/f243e6802143374741739d2c164c4f2f61697669.zip"], patches = [ "@kelvin_hw//third_party/ip/lowrisc:0001-Add-BUILD.bazel.patch", + "@kelvin_hw//third_party/ip/lowrisc:0002-Modify-TLUL-and-SRAM-adapter-for-ChAI.patch", + "@kelvin_hw//third_party/ip/lowrisc:0003-Modify-UART-for-ChAI.patch", ], patch_args = ["-p1"], )
diff --git a/rules/verilator.bzl b/rules/verilator.bzl index c00bad3..2f8fdd9 100644 --- a/rules/verilator.bzl +++ b/rules/verilator.bzl
@@ -140,10 +140,16 @@ args.add("--Mdir", verilator_output.path) args.add("--top-module", ctx.attr.module_top) args.add("--prefix", prefix) + verilog_dirs = dict() + for file in verilog_files: + verilog_dirs[file.dirname] = None + for vdir in verilog_dirs: + args.add("-I" + vdir) if ctx.attr.trace: args.add("--trace") for verilog_file in verilog_files: args.add(verilog_file.path) + args.add("-Wno-UNOPTFLAT") args.add_all(ctx.attr.vopts, expand_directories = False) ctx.actions.run(
diff --git a/tests/verilator_sim/BUILD b/tests/verilator_sim/BUILD index 681096f..10c126e 100644 --- a/tests/verilator_sim/BUILD +++ b/tests/verilator_sim/BUILD
@@ -66,6 +66,25 @@ ], ) +cc_binary( + name = "chai_sim", + srcs = [ + "chai/chai_if.h", + "chai/chai_tb.cc", + ], + deps = [ + ":kelvin_if", + ":sim_libs", + "//hdl/chisel/src/chai:chai_cc_library", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/flags:usage", + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:check", + ], +) + + cc_test( name = "dbus2axi_tb", size = "small",
diff --git a/tests/verilator_sim/chai/chai_if.h b/tests/verilator_sim/chai/chai_if.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/verilator_sim/chai/chai_if.h
diff --git a/tests/verilator_sim/chai/chai_tb.cc b/tests/verilator_sim/chai/chai_tb.cc new file mode 100644 index 0000000..74fa133 --- /dev/null +++ b/tests/verilator_sim/chai/chai_tb.cc
@@ -0,0 +1,245 @@ +// Copyright 2024 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. + +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include <algorithm> + +#include "VChAI.h" // Generated +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" +#include "absl/log/check.h" +#include "absl/log/log.h" +#include "tests/verilator_sim/sysc_module.h" +#include "tests/verilator_sim/sysc_tb.h" + +ABSL_FLAG(int, cycles, 10'000'000, "Simulation cycles"); +ABSL_FLAG(bool, trace, false, "Enable tracing"); + +namespace { + +struct ChAI_tb : Sysc_tb { + sc_in<bool> io_halted; + sc_in<bool> io_fault; + using Sysc_tb::Sysc_tb; // constructor + + void posedge() { + check(!io_fault, "io_fault"); + if (io_halted) sc_stop(); + } +}; + +struct Memory : Sysc_module { + sc_out<sc_bv<17> > write_address; + sc_out<bool> write_enable; + sc_out<sc_bv<256> > write_data; + sc_out<bool> loadedn; + + sc_bv<256> wdata = 0; + + Memory(sc_module_name n, const char* path) + : Sysc_module(n), path_(path), offset_(0) { + int fd = open(path, 0); + CHECK(fd > 0); + struct stat sb; + CHECK(fstat(fd, &sb) == 0); + LOG(INFO) << "Input file size: " << sb.st_size; + size_ = sb.st_size; + if (size_ % 256 != 0) { + LOG(FATAL) << "Please align your file size to 256 bytes."; + } + void* data = mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + CHECK(data != MAP_FAILED); + close(fd); + data_ = reinterpret_cast<uint8_t*>(data); + data32_ = reinterpret_cast<uint32_t*>(data_); + } + + ~Memory() { + LOG(INFO) << "Cycles at teardown: " << cycle_; + munmap(data_, size_); + data_ = nullptr; + data32_ = nullptr; + } + + void eval() { + if (reset) { + cycle_ = 0; + loadedn = true; + write_address = 0; + write_enable = false; + write_data = 0; + } + if (clock->posedge()) { + cycle_++; + if (offset_ == size_) { + static bool logged = false; + if (!logged) { + LOG(INFO) << "[" << cycle_ << "] setting loadedn to false"; + logged = true; + } + loadedn = false; + write_enable = false; + } + if (offset_ < size_) { + const size_t wordsPerWrite = 32 / sizeof(uint32_t); // 32B / 4B + for (size_t i = 0; i < wordsPerWrite; i++) { + uint32_t val = data32_[(offset_ / sizeof(uint32_t)) + i]; + wdata.set_word(i, val); + } + write_data.write(wdata); + write_enable = true; + write_address = offset_ >> 5; + offset_ += 32; // 32 bytes == 8 words + } + } + if (cycle_ % 10000 == 0) { + LOG(INFO) << "Cycle " << cycle_; + } + } + + private: + uint32_t cycle_ = 0; + const char* path_; + size_t offset_; // bytes + size_t size_; // bytes + uint8_t* data_; // bytes + uint32_t* data32_; // words +}; + +struct Uart : Sysc_module { + sc_in<bool> rx; + sc_out<bool> tx; + Uart(sc_module_name n) : Sysc_module(n) {} + uint64_t kBaudrate = 115200; + uint64_t kFrequencyHz = 10000000; // 10MHz + uint32_t nco_rx = static_cast<uint32_t>((kBaudrate << 20) / kFrequencyHz); + void eval() { + if (reset) { + last_rx_val_ = true; + uart_baud_ctr_ = 0; + baud_cnt_ = 0; + s_ = State::sIdle; + bit_in_pkt_ = 0; + rx_data_ = 0; + } + if (clock->posedge()) { + if (uart_baud_ctr_ & 0x10000) { + baud_cnt_++; + } + if (baud_cnt_ == 16) { + bool rx_val = rx; + bool edge = rx_val != last_rx_val_; + switch (s_) { + case State::sIdle: { + if (edge) { + s_ = State::sStarted; + bit_in_pkt_ = 0; + } + break; + } + case State::sStarted: { + if (bit_in_pkt_ == 8) { + LOG(INFO) << "UART val: " << (char)rx_data_; + rx_data_ = 0; + s_ = State::sIdle; + } + rx_data_ = (rx_data_ >> 1) | ((uint8_t)rx_val << 7); + bit_in_pkt_++; + break; + } + } + last_rx_val_ = rx_val; + baud_cnt_ = 0; + } + uart_baud_ctr_ = (uart_baud_ctr_ & 0xFFFF) + nco_rx; + } + } + + private: + enum class State { sIdle, sStarted }; + bool last_rx_val_ = true; + size_t uart_baud_ctr_ = 0; + size_t baud_cnt_ = 0; + State s_ = State::sIdle; + size_t bit_in_pkt_ = 0; + uint8_t rx_data_ = 0; +}; + +void ChAI_run(const char* name, const char* path, const int cycles, + const bool trace) { + VChAI chai(name); + ChAI_tb tb("ChAI_tb", cycles, /* random= */ false); + Memory mem("ChAI_mem", path); + Uart uart("ChAI_uart"); + + sc_signal<bool> io_halted, io_fault; + sc_signal<sc_bv<17> > io_sram_write_address; + sc_signal<bool> io_sram_write_enable; + sc_signal<sc_bv<256> > io_sram_write_data; + sc_signal<bool> mem_loadedn; + sc_signal<bool> uart_tx; // Output from ChAI + sc_signal<bool> uart_rx; // Input to ChAI + + tb.io_halted(io_halted); + tb.io_fault(io_fault); + + chai.io_clk_i(tb.clock); + chai.io_rst_ni(tb.resetn); + chai.io_sram_write_address(io_sram_write_address); + chai.io_sram_write_enable(io_sram_write_enable); + chai.io_sram_write_data(io_sram_write_data); + chai.io_finish(io_halted); + chai.io_fault(io_fault); + chai.io_freeze(mem_loadedn); + chai.io_uart_tx(uart_tx); + chai.io_uart_rx(uart_rx); + + mem.clock(tb.clock); + mem.reset(tb.reset); + mem.write_address(io_sram_write_address); + mem.write_enable(io_sram_write_enable); + mem.write_data(io_sram_write_data); + mem.loadedn(mem_loadedn); + + uart.clock(tb.clock); + uart.reset(tb.reset); + uart.rx(uart_tx); + uart.tx(uart_rx); + + if (trace) { + tb.trace(chai); + } + + tb.start(); +} + +} // namespace + +extern "C" int sc_main(int argc, char** argv) { + absl::SetProgramUsageMessage("ChAI sim"); + auto out_args = absl::ParseCommandLine(argc, argv); + argc = out_args.size(); + argv = &out_args[0]; + if (argc < 2) { + LOG(FATAL) << "Need an input file"; + } + const char* path = argv[1]; + ChAI_run(Sysc_tb::get_name(argv[0]), path, absl::GetFlag(FLAGS_cycles), + absl::GetFlag(FLAGS_trace)); + return 0; +} \ No newline at end of file
diff --git a/third_party/ip/lowrisc/0002-Modify-TLUL-and-SRAM-adapter-for-ChAI.patch b/third_party/ip/lowrisc/0002-Modify-TLUL-and-SRAM-adapter-for-ChAI.patch new file mode 100644 index 0000000..3d104a1 --- /dev/null +++ b/third_party/ip/lowrisc/0002-Modify-TLUL-and-SRAM-adapter-for-ChAI.patch
@@ -0,0 +1,180 @@ +From 617fc52a30d18725e50080e64bc6459fa24ca709 Mon Sep 17 00:00:00 2001 +From: Alex Van Damme <atv@google.com> +Date: Thu, 15 Feb 2024 11:24:49 -0800 +Subject: [PATCH 2/3] Modify TLUL and SRAM adapter for ChAI + +--- + hw/ip/tlul/rtl/tlul_adapter_reg.sv | 12 +++++------- + hw/ip/tlul/rtl/tlul_adapter_sram.sv | 21 +++------------------ + hw/ip/tlul/rtl/tlul_err.sv | 15 ++++++++++----- + hw/ip/tlul/rtl/tlul_pkg.sv | 18 ------------------ + 4 files changed, 18 insertions(+), 48 deletions(-) + +diff --git a/hw/ip/tlul/rtl/tlul_adapter_reg.sv b/hw/ip/tlul/rtl/tlul_adapter_reg.sv +index ac48750129..85e89d63f4 100644 +--- a/hw/ip/tlul/rtl/tlul_adapter_reg.sv ++++ b/hw/ip/tlul/rtl/tlul_adapter_reg.sv +@@ -82,8 +82,8 @@ module tlul_adapter_reg + + assign we_o = wr_req & ~err_internal; + assign re_o = rd_req & ~err_internal; +- assign wdata_o = tl_i.a_data; +- assign be_o = tl_i.a_mask; ++ assign wdata_o = tl_i.a_data[RegDw-1:0]; ++ assign be_o = tl_i.a_mask[RegBw-1:0]; + + if (RegAw <= 2) begin : gen_only_one_reg + assign addr_o = '0; +@@ -161,7 +161,7 @@ module tlul_adapter_reg + d_size: reqsz_q, + d_source: reqid_q, + d_sink: '0, +- d_data: rdata, ++ d_data: {224'b0, rdata}, + d_user: '0, + d_error: error + }; +@@ -201,14 +201,12 @@ module tlul_adapter_reg + + // An instruction type transaction is only valid if en_ifetch is enabled + // If the instruction type is completely invalid, also considered an instruction error +- assign instr_error = prim_mubi_pkg::mubi4_test_invalid(tl_i.a_user.instr_type) | +- (prim_mubi_pkg::mubi4_test_true_strict(tl_i.a_user.instr_type) & +- prim_mubi_pkg::mubi4_test_false_loose(en_ifetch_i)); ++ assign instr_error = '0; + + assign err_internal = addr_align_err | malformed_meta_err | tl_err | instr_error | intg_error; + + // Don't allow unsupported values. +- assign malformed_meta_err = tl_a_user_chk(tl_i.a_user); ++ assign malformed_meta_err = '0; + + // addr_align_err + // Raised if addr isn't aligned with the size +diff --git a/hw/ip/tlul/rtl/tlul_adapter_sram.sv b/hw/ip/tlul/rtl/tlul_adapter_sram.sv +index ec764cbefa..8f41f38581 100644 +--- a/hw/ip/tlul/rtl/tlul_adapter_sram.sv ++++ b/hw/ip/tlul/rtl/tlul_adapter_sram.sv +@@ -106,7 +106,7 @@ module tlul_adapter_sram + // Here it checks any partial write if ByteAccess isn't allowed. + assign wr_attr_error = (tl_i.a_opcode == PutFullData || tl_i.a_opcode == PutPartialData) + ? ((ByteAccess == 0) ? +- (tl_i.a_mask != '1 || tl_i.a_size != 2'h2) : 1'b0) ++ (tl_i.a_mask != '1 || tl_i.a_size != 6'h2) : 1'b0) + : 1'b0; + + // An instruction type transaction is only valid if en_ifetch is enabled +@@ -268,24 +268,9 @@ module tlul_adapter_sram + DataWhenInstrError : + DataWhenError; + +- // Since DataWhenInstrError and DataWhenError can be arbitrary parameters +- // we statically calculate the correct integrity values for these parameters here so that +- // they do not have to be supplied externally. +- logic [top_pkg::TL_DW-1:0] unused_instr, unused_data; +- logic [DataIntgWidth-1:0] error_instr_integ, error_data_integ; +- tlul_data_integ_enc u_tlul_data_integ_enc_instr ( +- .data_i(DataMaxWidth'(DataWhenInstrError)), +- .data_intg_o({error_instr_integ, unused_instr}) +- ); +- tlul_data_integ_enc u_tlul_data_integ_enc_data ( +- .data_i(DataMaxWidth'(DataWhenError)), +- .data_intg_o({error_data_integ, unused_data}) +- ); + + logic [DataIntgWidth-1:0] error_blanking_integ; +- assign error_blanking_integ = (prim_mubi_pkg::mubi4_test_true_strict(reqfifo_rdata.instr_type)) ? +- error_instr_integ : +- error_data_integ; ++ assign error_blanking_integ = '0; + + logic [top_pkg::TL_DW-1:0] d_data; + assign d_data = (vld_rd_rsp & ~d_error) ? rspfifo_rdata.data // valid read +@@ -445,7 +430,7 @@ module tlul_adapter_sram + error : rerror_i[1] // Only care for Uncorrectable error + }; + assign rspfifo_rready = (reqfifo_rdata.op == OpRead & ~reqfifo_rdata.error) +- ? reqfifo_rready : 1'b0 ; ++ ? reqfifo_rready : 1'b1 ; + + // This module only cares about uncorrectable errors. + logic unused_rerror; +diff --git a/hw/ip/tlul/rtl/tlul_err.sv b/hw/ip/tlul/rtl/tlul_err.sv +index c887cc387b..6cb3ea380a 100644 +--- a/hw/ip/tlul/rtl/tlul_err.sv ++++ b/hw/ip/tlul/rtl/tlul_err.sv +@@ -29,11 +29,10 @@ module tlul_err import tlul_pkg::*; ( + + // An instruction type transaction cannot be write + logic instr_wr_err; +- assign instr_wr_err = prim_mubi_pkg::mubi4_test_true_strict(tl_i.a_user.instr_type) & +- (op_full | op_partial); ++ assign instr_wr_err = '0; + + logic instr_type_err; +- assign instr_type_err = prim_mubi_pkg::mubi4_test_invalid(tl_i.a_user.instr_type); ++ assign instr_type_err = '0; + + // Anything that doesn't fall into the permitted category, it raises an error + assign err_o = ~(opcode_allowed & a_config_allowed) | instr_wr_err | instr_type_err; +@@ -68,8 +67,8 @@ module tlul_err import tlul_pkg::*; ( + 'h1: begin // 2 Byte + addr_sz_chk = ~tl_i.a_address[0]; + // check inactive lanes if lower 2B, check a_mask[3:2], if uppwer 2B, a_mask[1:0] +- mask_chk = (tl_i.a_address[1]) ? ~|(tl_i.a_mask & 4'b0011) +- : ~|(tl_i.a_mask & 4'b1100); ++ mask_chk = (tl_i.a_address[1]) ? ~|(tl_i.a_mask & 32'b0011) ++ : ~|(tl_i.a_mask & 32'b1100); + fulldata_chk = (tl_i.a_address[1]) ? &tl_i.a_mask[3:2] : &tl_i.a_mask[1:0] ; + end + +@@ -79,6 +78,12 @@ module tlul_err import tlul_pkg::*; ( + fulldata_chk = &tl_i.a_mask[3:0]; + end + ++ 'h5: begin // 32 Byte ++ addr_sz_chk = 1'b1; ++ mask_chk = 1'b1; ++ fulldata_chk = 1'b1; ++ end ++ + default: begin // else + addr_sz_chk = 1'b0; + mask_chk = 1'b0; +diff --git a/hw/ip/tlul/rtl/tlul_pkg.sv b/hw/ip/tlul/rtl/tlul_pkg.sv +index 4e9401fdf9..dae9671f25 100644 +--- a/hw/ip/tlul/rtl/tlul_pkg.sv ++++ b/hw/ip/tlul/rtl/tlul_pkg.sv +@@ -179,17 +179,6 @@ package tlul_pkg; + return cmd_intg; + endfunction // get_cmd_intg + +- // calculate ecc for data checking +- function automatic logic [DataIntgWidth-1:0] get_data_intg(logic [top_pkg::TL_DW-1:0] data); +- logic [DataIntgWidth-1:0] data_intg; +- logic [top_pkg::TL_DW-1:0] unused_data; +- logic [DataIntgWidth + top_pkg::TL_DW - 1 : 0] enc_data; +- enc_data = prim_secded_pkg::prim_secded_inv_39_32_enc(data); +- data_intg = enc_data[DataIntgWidth + top_pkg::TL_DW - 1 : top_pkg::TL_DW]; +- unused_data = enc_data[top_pkg::TL_DW - 1 : 0]; +- return data_intg; +- endfunction // get_data_intg +- + // return inverted integrity for command payload + function automatic logic [H2DCmdIntgWidth-1:0] get_bad_cmd_intg(tl_h2d_t tl); + logic [H2DCmdIntgWidth-1:0] cmd_intg; +@@ -197,11 +186,4 @@ package tlul_pkg; + return ~cmd_intg; + endfunction // get_bad_cmd_intg + +- // return inverted integrity for data payload +- function automatic logic [H2DCmdIntgWidth-1:0] get_bad_data_intg(logic [top_pkg::TL_DW-1:0] data); +- logic [H2DCmdIntgWidth-1:0] data_intg; +- data_intg = get_data_intg(data); +- return ~data_intg; +- endfunction // get_bad_data_intg +- + endpackage +-- +2.43.0.687.g38aa6559b0-goog +
diff --git a/third_party/ip/lowrisc/0003-Modify-UART-for-ChAI.patch b/third_party/ip/lowrisc/0003-Modify-UART-for-ChAI.patch new file mode 100644 index 0000000..a68a3e7 --- /dev/null +++ b/third_party/ip/lowrisc/0003-Modify-UART-for-ChAI.patch
@@ -0,0 +1,84 @@ +From 37adcc443c2d7879079ca6e634f2992dbc9bfac8 Mon Sep 17 00:00:00 2001 +From: Alex Van Damme <atv@google.com> +Date: Wed, 14 Feb 2024 15:29:54 -0800 +Subject: [PATCH 3/3] Modify UART for ChAI + +--- + hw/ip/uart/rtl/uart_reg_pkg.sv | 28 ++++++++++++++-------------- + hw/ip/uart/rtl/uart_reg_top.sv | 7 ++----- + 2 files changed, 16 insertions(+), 19 deletions(-) + +diff --git a/hw/ip/uart/rtl/uart_reg_pkg.sv b/hw/ip/uart/rtl/uart_reg_pkg.sv +index 355afaff1b..8a44cd5af8 100644 +--- a/hw/ip/uart/rtl/uart_reg_pkg.sv ++++ b/hw/ip/uart/rtl/uart_reg_pkg.sv +@@ -10,7 +10,7 @@ package uart_reg_pkg; + parameter int NumAlerts = 1; + + // Address widths within the block +- parameter int BlockAw = 6; ++ parameter int BlockAw = 9; + + //////////////////////////// + // Typedefs for registers // +@@ -324,19 +324,19 @@ package uart_reg_pkg; + } uart_hw2reg_t; + + // Register offsets +- parameter logic [BlockAw-1:0] UART_INTR_STATE_OFFSET = 6'h 0; +- parameter logic [BlockAw-1:0] UART_INTR_ENABLE_OFFSET = 6'h 4; +- parameter logic [BlockAw-1:0] UART_INTR_TEST_OFFSET = 6'h 8; +- parameter logic [BlockAw-1:0] UART_ALERT_TEST_OFFSET = 6'h c; +- parameter logic [BlockAw-1:0] UART_CTRL_OFFSET = 6'h 10; +- parameter logic [BlockAw-1:0] UART_STATUS_OFFSET = 6'h 14; +- parameter logic [BlockAw-1:0] UART_RDATA_OFFSET = 6'h 18; +- parameter logic [BlockAw-1:0] UART_WDATA_OFFSET = 6'h 1c; +- parameter logic [BlockAw-1:0] UART_FIFO_CTRL_OFFSET = 6'h 20; +- parameter logic [BlockAw-1:0] UART_FIFO_STATUS_OFFSET = 6'h 24; +- parameter logic [BlockAw-1:0] UART_OVRD_OFFSET = 6'h 28; +- parameter logic [BlockAw-1:0] UART_VAL_OFFSET = 6'h 2c; +- parameter logic [BlockAw-1:0] UART_TIMEOUT_CTRL_OFFSET = 6'h 30; ++ parameter logic [BlockAw-1:0] UART_INTR_STATE_OFFSET = 9'h 0; ++ parameter logic [BlockAw-1:0] UART_INTR_ENABLE_OFFSET = 9'h 20; ++ parameter logic [BlockAw-1:0] UART_INTR_TEST_OFFSET = 9'h 40; ++ parameter logic [BlockAw-1:0] UART_ALERT_TEST_OFFSET = 9'h 60; ++ parameter logic [BlockAw-1:0] UART_CTRL_OFFSET = 9'h 80; ++ parameter logic [BlockAw-1:0] UART_STATUS_OFFSET = 9'h a0; ++ parameter logic [BlockAw-1:0] UART_RDATA_OFFSET = 9'h c0; ++ parameter logic [BlockAw-1:0] UART_WDATA_OFFSET = 9'h e0; ++ parameter logic [BlockAw-1:0] UART_FIFO_CTRL_OFFSET = 9'h 100; ++ parameter logic [BlockAw-1:0] UART_FIFO_STATUS_OFFSET = 9'h120 ; ++ parameter logic [BlockAw-1:0] UART_OVRD_OFFSET = 9'h 140; ++ parameter logic [BlockAw-1:0] UART_VAL_OFFSET = 9'h 160; ++ parameter logic [BlockAw-1:0] UART_TIMEOUT_CTRL_OFFSET = 9'h180; + + // Reset values for hwext registers and their fields + parameter logic [7:0] UART_INTR_TEST_RESVAL = 8'h 0; +diff --git a/hw/ip/uart/rtl/uart_reg_top.sv b/hw/ip/uart/rtl/uart_reg_top.sv +index 6b6952f5d8..b105550cc4 100644 +--- a/hw/ip/uart/rtl/uart_reg_top.sv ++++ b/hw/ip/uart/rtl/uart_reg_top.sv +@@ -24,7 +24,7 @@ module uart_reg_top ( + + import uart_reg_pkg::* ; + +- localparam int AW = 6; ++ localparam int AW = 9; + localparam int DW = 32; + localparam int DBW = DW/8; // Byte Width + +@@ -48,10 +48,7 @@ module uart_reg_top ( + + // incoming payload check + logic intg_err; +- tlul_cmd_intg_chk u_chk ( +- .tl_i(tl_i), +- .err_o(intg_err) +- ); ++ assign intg_err = '0; + + // also check for spurious write enables + logic reg_we_err; +-- +2.43.0.687.g38aa6559b0-goog +
diff --git a/third_party/ip/lowrisc/BUILD b/third_party/ip/lowrisc/BUILD index 8eb1241..0a97a9c 100644 --- a/third_party/ip/lowrisc/BUILD +++ b/third_party/ip/lowrisc/BUILD
@@ -17,7 +17,9 @@ verilog_library( name = "prim_generic", srcs = [ + "@lowrisc_opentitan//hw/ip/prim_generic:rtl/prim_generic_buf.sv", "@lowrisc_opentitan//hw/ip/prim_generic:rtl/prim_generic_clock_gating.sv", + "@lowrisc_opentitan//hw/ip/prim_generic:rtl/prim_generic_flop.sv", ], visibility = ["//visibility:public"], ) @@ -35,7 +37,39 @@ # Do not sort: "*_pkg" comes first. srcs = [ "@lowrisc_opentitan//hw:vendor/lowrisc_ibex/dv/uvm/core_ibex/common/prim/prim_pkg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_alert_pkg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_mubi_pkg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_secded_pkg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_subreg_pkg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_util_pkg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_alert_sender.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_assert.sv", + # Verilator + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_assert_dummy_macros.svh", + # Synth + # "@lowrisc_opentitan//hw/ip/prim:rtl/prim_assert_standard_macros.svh", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_assert_sec_cm.svh", + "@lowrisc_opentitan//hw:vendor/lowrisc_ibex/dv/uvm/core_ibex/common/prim/prim_buf.sv", "@lowrisc_opentitan//hw:vendor/lowrisc_ibex/dv/uvm/core_ibex/common/prim/prim_clock_gating.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_count.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_diff_decode.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_fifo_sync.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_fifo_sync_cnt.sv", + "@lowrisc_opentitan//hw:vendor/lowrisc_ibex/dv/uvm/core_ibex/common/prim/prim_flop.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_flop_2sync.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_flop_macros.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_intr_hw.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_onehot_check.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_reg_we_check.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_sec_anchor_buf.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_sec_anchor_flop.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_secded_inv_64_57_dec.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_secded_inv_39_32_dec.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_secded_inv_39_32_enc.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_secded_inv_64_57_enc.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_subreg.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_subreg_arb.sv", + "@lowrisc_opentitan//hw/ip/prim:rtl/prim_subreg_ext.sv", ], deps = [ ":prim_generic", @@ -43,3 +77,60 @@ ], visibility = ["//visibility:public"], ) + +verilog_library( + name = "top", + srcs = [ + "top_pkg.sv", + ], + visibility = ["//visibility:public"], +) + +verilog_library( + name = "tlul", + # Do not sort: "tlul_pkg" comes first. + srcs = [ + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_pkg.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_adapter_reg.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_cmd_intg_chk.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_data_integ_dec.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_data_integ_enc.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_err.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_rsp_intg_gen.sv", + ], + deps = [ + ":top", + ":prim", + ], + visibility = ["//visibility:public"], +) + +verilog_library( + name = "tlul_adapter_sram", + srcs = [ + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_adapter_sram.sv", + "@lowrisc_opentitan//hw/ip/tlul:rtl/tlul_sram_byte.sv", + ], + deps = [ + ":prim", + ":tlul", + ], + visibility = ["//visibility:public"], +) + +verilog_library( + name = "uart", + srcs = [ + "@lowrisc_opentitan//hw/ip/uart:rtl/uart_reg_pkg.sv", + "@lowrisc_opentitan//hw/ip/uart:rtl/uart_core.sv", + "@lowrisc_opentitan//hw/ip/uart:rtl/uart_reg_top.sv", + "@lowrisc_opentitan//hw/ip/uart:rtl/uart_rx.sv", + "@lowrisc_opentitan//hw/ip/uart:rtl/uart_tx.sv", + "@lowrisc_opentitan//hw/ip/uart:rtl/uart.sv", + ], + deps = [ + ":prim", + ":tlul", + ], + visibility = ["//visibility:public"], +)
diff --git a/third_party/ip/lowrisc/top_pkg.sv b/third_party/ip/lowrisc/top_pkg.sv new file mode 100644 index 0000000..0af4c75 --- /dev/null +++ b/third_party/ip/lowrisc/top_pkg.sv
@@ -0,0 +1,27 @@ +// Copyright 2024 Google LLC +// Copyright lowRISC contributors +// +// 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 top_pkg; + +localparam int TL_AW=32; +localparam int TL_DW=256; // = TL_DBW * 8; TL_DBW must be a power-of-two +localparam int TL_AIW=10; // a_source, d_source +localparam int TL_DIW=1; // d_sink +localparam int TL_AUW=21; // a_user +localparam int TL_DUW=14; // d_user +localparam int TL_DBW=(TL_DW>>3); +localparam int TL_SZW=6; + +endpackage