├── project ├── plugins.sbt ├── build.properties └── metals.sbt ├── docs ├── assets │ ├── memory.png │ ├── putfulldata.gif │ ├── tilelink-M_1.png │ ├── tilelink1:N.png │ ├── tilelinkM_1.png │ ├── tl-arbiter.png │ ├── memory-a_size=1.png │ ├── tilelink-a_size=2.png │ ├── errResp_ctrlSignals.png │ └── tilelink-putfulldata.png └── index.md ├── src ├── main │ └── scala │ │ └── merl │ │ └── uit │ │ └── tilelink │ │ ├── TL_D_Opcode.scala │ │ ├── TL_A_Opcode.scala │ │ ├── TL_D2H.scala │ │ ├── TL_H2D.scala │ │ ├── TL_Decoder.scala │ │ ├── Config.scala │ │ ├── Arbiter.scala │ │ ├── TL_HostAdapter.scala │ │ ├── TL_ErrResp.scala │ │ ├── TL_Err.scala │ │ ├── TL_RegAdapter.scala │ │ ├── TLSocketM_1.scala │ │ ├── TLSocket1_N.scala │ │ └── TL_SramAdapter.scala └── test │ └── scala │ ├── TLHostAdapterTest.scala │ ├── TLDecoderTest.scala │ ├── ArbiterTest.scala │ ├── TLSocket1toNTest.scala │ └── TLSocketMto1Test.scala ├── .github └── workflows │ └── test.yml ├── README.md ├── scalastyle-config.xml ├── .gitignore └── scalastyle-test-config.xml /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn 2 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.3.10 2 | -------------------------------------------------------------------------------- /docs/assets/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/memory.png -------------------------------------------------------------------------------- /docs/assets/putfulldata.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/putfulldata.gif -------------------------------------------------------------------------------- /docs/assets/tilelink-M_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/tilelink-M_1.png -------------------------------------------------------------------------------- /docs/assets/tilelink1:N.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/tilelink1:N.png -------------------------------------------------------------------------------- /docs/assets/tilelinkM_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/tilelinkM_1.png -------------------------------------------------------------------------------- /docs/assets/tl-arbiter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/tl-arbiter.png -------------------------------------------------------------------------------- /docs/assets/memory-a_size=1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/memory-a_size=1.png -------------------------------------------------------------------------------- /docs/assets/tilelink-a_size=2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/tilelink-a_size=2.png -------------------------------------------------------------------------------- /docs/assets/errResp_ctrlSignals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/errResp_ctrlSignals.png -------------------------------------------------------------------------------- /docs/assets/tilelink-putfulldata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merledu/TileLink/HEAD/docs/assets/tilelink-putfulldata.png -------------------------------------------------------------------------------- /project/metals.sbt: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT! This file is auto-generated. 2 | // This file enables sbt-bloop to create bloop config files. 3 | 4 | addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.3") 5 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_D_Opcode.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | 5 | object TL_D_Opcode { 6 | val accessAck = 0.U(3.W) 7 | val accessAckData = 1.U(3.W) 8 | } -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_A_Opcode.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | object TL_A_Opcode { 5 | val get = 4.U(3.W) 6 | val putFullData = 0.U(3.W) 7 | val putPartialData = 1.U(3.W) 8 | } -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up JDK 1.8 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 1.8 20 | - name: Run tests 21 | run: sbt test -------------------------------------------------------------------------------- /src/test/scala/TLHostAdapterTest.scala: -------------------------------------------------------------------------------- 1 | package tilelink 2 | import org.scalatest._ 3 | import chiseltest._ 4 | import chisel3._ 5 | import merl.uit.tilelink.{TLConfiguration, TL_HostAdapter} 6 | 7 | class TLHostAdapterTest extends FlatSpec with ChiselScalatestTester with Matchers { 8 | implicit val tl_conf = TLConfiguration() 9 | behavior of "TL-UL Host Adapter" 10 | 11 | it should "Pass data to the device" in { 12 | test(new TL_HostAdapter) { c => 13 | c.io.req_i.poke(true.B) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_D2H.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | 5 | // TileLink Device To Host (Channel D ports) TL_D2H 6 | class TL_D2H(implicit val conf: TLConfiguration) extends Bundle { 7 | val d_valid = Output(Bool()) 8 | val d_opcode = Output(UInt(3.W)) 9 | val d_param = Output(UInt(3.W)) 10 | val d_size = Output(UInt(conf.TL_SZW.W)) 11 | val d_source = Output(UInt(conf.TL_AIW.W)) 12 | val d_sink = Output(UInt(conf.TL_DIW.W)) 13 | val d_data = Output(UInt(conf.TL_DW.W)) 14 | val d_error = Output(Bool()) 15 | val a_ready = Output(Bool()) 16 | } -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_H2D.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | 5 | // TileLink Host to Device (Channel A ports) TL_H2D 6 | class TL_H2D(implicit val conf: TLConfiguration) extends Bundle { 7 | val a_valid = Output(Bool()) 8 | val a_opcode = Output(UInt(3.W)) 9 | val a_param = Output(UInt(3.W)) 10 | val a_size = Output(UInt(conf.TL_SZW.W)) 11 | val a_source = Output(UInt(conf.TL_AIW.W)) 12 | val a_address = Output(UInt(conf.TL_AW.W)) 13 | val a_mask = Output(UInt(conf.TL_DBW.W)) 14 | val a_data = Output(UInt(conf.TL_DW.W)) 15 | val d_ready = Output(Bool()) 16 | } -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_Decoder.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | 5 | class TL_Decoder(N: Int, addrMap: AddressMap)(implicit val conf: TLConfiguration) extends Module { 6 | val io = IO(new Bundle { 7 | val addr_i = Input(UInt(32.W)) 8 | val dev_sel = Output(UInt(N.W)) 9 | }) 10 | 11 | io.dev_sel := N.asUInt 12 | when((io.addr_i & ~addrMap.ADDR_MASK_GPIO) === addrMap.ADDR_SPACE_GPIO) { 13 | io.dev_sel := TL_Peripherals.deviceMap("gpio") 14 | } .elsewhen((io.addr_i & ~addrMap.ADDR_MASK_UART) === addrMap.ADDR_SPACE_UART) { 15 | io.dev_sel := TL_Peripherals.deviceMap("uart") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/scala/TLDecoderTest.scala: -------------------------------------------------------------------------------- 1 | package tilelink 2 | import org.scalatest._ 3 | import chiseltest._ 4 | import chisel3._ 5 | import merl.uit.tilelink.{AddressMap, TLConfiguration, TL_Decoder, TL_Peripherals} 6 | 7 | class TLDecoderTest extends FlatSpec with ChiselScalatestTester with Matchers { 8 | behavior of "TL Decoder" 9 | implicit val conf = TLConfiguration() 10 | val addrMap = AddressMap() 11 | it should "set the dev_sel to point to gpio" in { 12 | test(new TL_Decoder(2, addrMap)) {c => 13 | c.io.addr_i.poke("h40010000".U) 14 | c.io.dev_sel.expect(TL_Peripherals.deviceMap("gpio")) 15 | } 16 | } 17 | 18 | it should "set the dev_sel to point to uart" in { 19 | test(new TL_Decoder(2, addrMap)) {c => 20 | c.io.addr_i.poke("h40000000".U) 21 | c.io.dev_sel.expect(TL_Peripherals.deviceMap("uart")) 22 | } 23 | } 24 | 25 | it should "set the dev_sel to point to error responder" in { 26 | test(new TL_Decoder(2, addrMap)) {c => 27 | c.io.addr_i.poke("h4fffffff".U) 28 | c.io.dev_sel.expect(2.U) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/Config.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import scala.collection.immutable._ 6 | 7 | case class TLConfiguration() { 8 | val TL_AW = 32 // AW -> the default width of address bus 9 | val TL_DW = 32 // DW -> the default width of data bus 10 | val TL_AIW = 4 // AIW -> Address source identifier bus width 11 | val TL_DIW = 1 // DIW -> Sink bits width 12 | val TL_DBW = (TL_DW >> 3) // Number of data bytes generated (DW/8) 13 | val TL_SZW = log2Ceil(TL_DBW) // The size width of operation in power of 2 represented in bytes 14 | } 15 | 16 | case class AddressMap() { 17 | val ADDR_SPACE_UART = "h40000000".U(32.W) 18 | val ADDR_MASK_UART = "h00000fff".U(32.W) 19 | val ADDR_SPACE_GPIO = "h40010000".U(32.W) 20 | val ADDR_MASK_GPIO = "h00000fff".U(32.W) 21 | } 22 | 23 | object TL_Peripherals { 24 | // The device map will have N-1 devices data for the 1:N socket. 25 | // So if we have a 1:4 socket then the device map should have 4 devices from 0 to 3. 26 | val deviceMap: Map[String, UInt] = Map("gpio" -> 0.U, "uart" -> 1.U) 27 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TileLink ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/hadirkhan10/TileLink/test) 2 | This project deals with creating TileLink bus protocol API with Chisel and generating the RTL for synthesis 3 | 4 | 5 | ## Description 6 | TileLink is a protocol developed at SiFive which is used for On-Chip communication. This project implements the TileLink Uncached Lightweight (TL-UL) protocol as described in the specification. This project conforms to the [1.7.1 specification](https://sifive.cdn.prismic.io/sifive%2F57f93ecf-2c42-46f7-9818-bcdd7d39400a_tilelink-spec-1.7.1.pdf). 7 | 8 | ## Purpose 9 | TileLink has been implemented in `rocketchip` but it takes use of _diplomacy_ which is a little advanced stuff to understand. In this project we implement the specification with only the logic provided by the specification and hope to keep it simple enough for other Chisel users to use it in their projects without the need of LazyModules and complex diplomacy negotiation. 10 | 11 | ## Contributors 12 |
13 | 14 | 15 | 16 |
17 |
Hadir Khan
18 |
19 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/Arbiter.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} 5 | 6 | object Arbiter extends App { 7 | implicit val conf: TLConfiguration = TLConfiguration() 8 | (new ChiselStage).execute(args, Seq(ChiselGeneratorAnnotation(() => new Arbiter(3)))) 9 | } 10 | 11 | class Arbiter(M: Int)(implicit val conf: TLConfiguration) extends Module { 12 | val io = IO(new Bundle { 13 | val req_i = Input(Vec(M, Bool())) // a_valid signals coming from all the hosts 14 | val data_i = Vec(M, Flipped(new TL_H2D)) // Channel A data coming from all the hosts 15 | val gnt_o = Output(Vec(M, Bool())) // The grant output used for indicating the host that the device is ready to accept the request 16 | val valid_o = Output(Bool()) // The valid signal from the host to the device 17 | val data_o = new TL_H2D // The Channel A data of selected host forwarded to the device 18 | val ready_i = Input(Bool()) // The ready signal coming from the device 19 | }) 20 | // by default setting the arbiter to pass the request of last host 21 | io.data_o <> io.data_i(M-1) 22 | io.valid_o := io.req_i(M-1) 23 | io.gnt_o(M-1) := Mux(io.ready_i, Mux(io.req_i(M-1), true.B, false.B), false.B) 24 | for(i <- M-2 to 0 by -1) { 25 | when(io.req_i(i)) { 26 | io.gnt_o(i) := Mux(io.ready_i, true.B, false.B) 27 | io.data_o := io.data_i(i) 28 | io.valid_o := io.req_i(i) 29 | } .otherwise { 30 | io.gnt_o(i) := false.B 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/scala/ArbiterTest.scala: -------------------------------------------------------------------------------- 1 | package tilelink 2 | import org.scalatest._ 3 | import chiseltest._ 4 | import chisel3._ 5 | import merl.uit.tilelink.{Arbiter, TLConfiguration} 6 | 7 | class ArbiterTest extends FlatSpec with ChiselScalatestTester with Matchers { 8 | implicit val tl_conf = TLConfiguration() 9 | behavior of "Arbiter connecting multiple hosts to single device" 10 | 11 | it should "connect host 0 with device" in { 12 | test(new Arbiter(2)) { c => 13 | c.io.req_i(0).poke(false.B) 14 | c.io.req_i(1).poke(true.B) 15 | 16 | // Host 1 data 17 | c.io.data_i(0).a_data.poke(0.U) 18 | c.io.data_i(0).a_mask.poke("b1111".U) 19 | c.io.data_i(0).a_address.poke(0.U) 20 | c.io.data_i(0).a_source.poke(0.U) 21 | c.io.data_i(0).a_size.poke(2.U) 22 | c.io.data_i(0).a_param.poke(0.U) 23 | c.io.data_i(0).a_opcode.poke(4.U) 24 | c.io.data_i(0).a_valid.poke(true.B) 25 | c.io.data_i(0).d_ready.poke(true.B) 26 | 27 | // Host 2 data 28 | c.io.data_i(1).a_data.poke(10.U) 29 | c.io.data_i(1).a_mask.poke("b1111".U) 30 | c.io.data_i(1).a_address.poke(4.U) 31 | c.io.data_i(1).a_source.poke(0.U) 32 | c.io.data_i(1).a_size.poke(2.U) 33 | c.io.data_i(1).a_param.poke(0.U) 34 | c.io.data_i(1).a_opcode.poke(1.U) 35 | c.io.data_i(1).a_valid.poke(true.B) 36 | c.io.data_i(1).d_ready.poke(true.B) 37 | 38 | // the slave is ready to accept the data 39 | c.io.ready_i.poke(true.B) 40 | 41 | c.io.gnt_o(0).expect(false.B) 42 | c.io.gnt_o(1).expect(true.B) 43 | c.io.valid_o.expect(true.B) 44 | c.io.data_o.a_opcode.expect(1.U) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_HostAdapter.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class TL_HostAdapter(implicit val conf: TLConfiguration) extends Module { 7 | val io = IO(new Bundle { 8 | val req_i = Input(Bool()) 9 | val gnt_o = Output(Bool()) 10 | val addr_i = Input(UInt(conf.TL_AW.W)) 11 | val we_i = Input(Bool()) 12 | val wdata_i = Input(UInt(conf.TL_DW.W)) 13 | val be_i = Input(UInt(conf.TL_DBW.W)) 14 | val valid_o = Output(Bool()) 15 | val rdata_o = Output(UInt(conf.TL_DW.W)) 16 | val err_o = Output(Bool()) 17 | 18 | val tl_o = new TL_H2D() 19 | val tl_i = Flipped(new TL_D2H()) 20 | }) 21 | 22 | 23 | when(reset.asBool()) { 24 | io.tl_o.a_valid := false.B // spec pg 11 during RESET the a_valid from master must be low 25 | } 26 | 27 | val wordSize = log2Ceil(conf.TL_DBW) 28 | val tl_source = Wire(UInt(conf.TL_AIW.W)) 29 | val tl_be = Wire(UInt(conf.TL_DBW.W)) 30 | 31 | tl_source := 0.U // providing source identifier id => 0 32 | tl_be := Mux(io.we_i, io.be_i, Fill(conf.TL_DBW, 1.U)) // Using a mux to conditionally assign value to byte enable wire (tl_be) 33 | 34 | io.tl_o.a_valid := io.req_i 35 | io.tl_o.a_opcode := Mux(io.we_i, Mux(io.be_i.andR, TL_A_Opcode.putFullData, TL_A_Opcode.putPartialData), TL_A_Opcode.get) // .andR is AND reduction that return true if all bits are set. 36 | io.tl_o.a_param := 0.U 37 | io.tl_o.a_size := wordSize.asUInt(conf.TL_SZW.W) 38 | io.tl_o.a_mask := tl_be 39 | io.tl_o.a_source := tl_source 40 | io.tl_o.a_address := Cat(io.addr_i(31, wordSize), 0.U(wordSize.W)) // word aligned addressing. 0, 4, 8, 12 ... 41 | io.tl_o.a_data := io.wdata_i 42 | io.tl_o.d_ready := true.B 43 | 44 | io.gnt_o := io.tl_i.a_ready 45 | io.valid_o := io.tl_i.d_valid 46 | io.rdata_o := io.tl_i.d_data 47 | io.err_o := io.tl_i.d_error 48 | 49 | } -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_ErrResp.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | 6 | class TL_ErrResp(implicit val conf: TLConfiguration) extends Module { 7 | val io = IO(new Bundle { 8 | val tl_h_i = Flipped(new TL_H2D) 9 | val tl_d_o = new TL_D2H 10 | }) 11 | 12 | val err_opcode = RegInit(TL_A_Opcode.get) 13 | val err_source = RegInit(0.U) 14 | val err_size = RegInit(0.U) 15 | val err_reqPending = RegInit(false.B) 16 | val err_rspPending = RegInit(false.B) 17 | 18 | when(io.tl_h_i.a_valid && io.tl_d_o.a_ready) { 19 | // the host sends a valid request and the device is ready to accept it 20 | // which means the request is accepted and is pending now if there is another response pending 21 | err_reqPending := true.B 22 | err_source := io.tl_h_i.a_source 23 | err_opcode := io.tl_h_i.a_opcode 24 | err_size := io.tl_h_i.a_size 25 | } .elsewhen(!err_rspPending) { 26 | // if no response is pending then the request pending is set to false which means no request is pending 27 | err_reqPending := false.B 28 | } 29 | 30 | when((err_reqPending || err_rspPending) && !io.tl_h_i.d_ready) { 31 | // if any req is accepted then err_reqPending = true which means if the host is not ready to receive it 32 | // then err_rspPending will get true. 33 | err_rspPending := true.B 34 | } .otherwise { 35 | err_rspPending := false.B 36 | } 37 | 38 | io.tl_d_o.a_ready := ~err_rspPending & ~(err_reqPending & ~io.tl_h_i.d_ready) 39 | io.tl_d_o.d_valid := err_reqPending || err_rspPending 40 | io.tl_d_o.d_data := Fill(conf.TL_DW/4, "hf".U) //Return all F. If dw = 32 then 32/4 = 8 characters all 0xf 41 | io.tl_d_o.d_source := err_source 42 | io.tl_d_o.d_sink := 0.U 43 | io.tl_d_o.d_param := 0.U 44 | io.tl_d_o.d_size := err_size 45 | io.tl_d_o.d_opcode := Mux(err_opcode === TL_A_Opcode.get, TL_D_Opcode.accessAckData, TL_D_Opcode.accessAck) 46 | io.tl_d_o.d_error := true.B 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_Err.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | 5 | class TL_Err(implicit val conf: TLConfiguration) extends Module { 6 | val io = IO(new Bundle { 7 | val tl_i = Flipped(new TL_H2D) 8 | val err_o = Output(Bool()) 9 | }) 10 | 11 | val opcode_allowed = Wire(Bool()) 12 | val op_get = Wire(Bool()) 13 | val op_partial = Wire(Bool()) 14 | val op_full = Wire(Bool()) 15 | val a_config_allowed = Wire(Bool()) 16 | 17 | io.err_o := !(opcode_allowed && a_config_allowed) 18 | 19 | op_get := io.tl_i.a_opcode === TL_A_Opcode.get 20 | op_partial := io.tl_i.a_opcode === TL_A_Opcode.putPartialData 21 | op_full := io.tl_i.a_opcode === TL_A_Opcode.putFullData 22 | 23 | opcode_allowed := op_get || op_partial || op_full 24 | 25 | 26 | 27 | // channel A configuration check 28 | val addr_size_chk = Wire(Bool()) // address and size alignment check 29 | val mask_chk = Wire(Bool()) // inactive lane a_mask check 30 | val fulldata_chk = Wire(Bool()) // PutFullData should have size match to mask 31 | 32 | val mask = Wire(UInt(conf.TL_DBW.W)) 33 | mask := (1.U << io.tl_i.a_address(conf.TL_SZW-1,0)) 34 | addr_size_chk := false.B 35 | mask_chk := false.B 36 | fulldata_chk := false.B 37 | 38 | when(io.tl_i.a_valid) { 39 | when(io.tl_i.a_size === 0.U) { // 1 byte 40 | addr_size_chk := true.B 41 | mask_chk := ~((io.tl_i.a_mask & (~mask).asUInt).orR) 42 | fulldata_chk := (io.tl_i.a_mask & mask).orR 43 | } .elsewhen(io.tl_i.a_size === 1.U) { // 2 bytes 44 | addr_size_chk := ~(io.tl_i.a_address(0)) 45 | mask_chk := Mux(io.tl_i.a_address(1), ~((io.tl_i.a_mask & "b0011".U).orR), ~((io.tl_i.a_mask & "b1100".U).orR)) 46 | fulldata_chk := Mux(io.tl_i.a_address(1), io.tl_i.a_mask(3,2).andR, io.tl_i.a_mask(1,0).andR) 47 | } .elsewhen(io.tl_i.a_size === 2.U) { // 4 bytes 48 | addr_size_chk := ~(io.tl_i.a_address(conf.TL_SZW-1,0).orR) 49 | mask_chk := true.B 50 | fulldata_chk := io.tl_i.a_mask(3,0).andR 51 | } .otherwise { 52 | addr_size_chk := false.B 53 | mask_chk := false.B 54 | fulldata_chk := false.B 55 | } 56 | } 57 | 58 | a_config_allowed := addr_size_chk && mask_chk && (op_get || op_partial || fulldata_chk) 59 | 60 | io.err_o := ~(opcode_allowed && a_config_allowed) 61 | } -------------------------------------------------------------------------------- /src/test/scala/TLSocket1toNTest.scala: -------------------------------------------------------------------------------- 1 | package tilelink 2 | import org.scalatest._ 3 | import chiseltest._ 4 | import chisel3._ 5 | import merl.uit.tilelink.{TLConfiguration, TLSocket1_N, TL_A_Opcode} 6 | 7 | class TLSocket1toNTest extends FlatSpec with ChiselScalatestTester with Matchers { 8 | behavior of "TL-UL 1:N socket connecting single host with N devices" 9 | implicit val tl_conf = TLConfiguration() 10 | 11 | // Test Case: 1 (Devices = 2) 12 | it should "Connect host with device(0) when dev_sel = 0" in { 13 | test(new TLSocket1_N(2)) {c => { 14 | // Host sending a GET request 15 | c.io.tl_h_i.a_valid.poke(true.B) 16 | c.io.tl_h_i.a_opcode.poke(TL_A_Opcode.get) 17 | c.io.tl_h_i.a_data.poke(0.U) 18 | c.io.tl_h_i.a_mask.poke("b1111".U) 19 | c.io.tl_h_i.a_address.poke(0.U) 20 | c.io.tl_h_i.a_source.poke(0.U) 21 | c.io.tl_h_i.a_size.poke(2.U) 22 | c.io.tl_h_i.a_param.poke(0.U) 23 | // Address Decoder selecting device 0 24 | c.io.dev_sel.poke(0.U) 25 | 26 | c.io.tl_d_o(0).a_valid.expect(true.B) 27 | c.io.tl_d_o(0).a_opcode.expect(TL_A_Opcode.get) 28 | c.io.tl_d_o(1).a_valid.expect(false.B) 29 | c.io.tl_h_o.d_error.expect(false.B) 30 | }} 31 | } 32 | 33 | // Test Case: 2 (Devices = 2) 34 | it should "Connect host with device(1) when dev_sel = 1" in { 35 | test(new TLSocket1_N(2)) {c => { 36 | // Host sending a GET request 37 | c.io.tl_h_i.a_valid.poke(true.B) 38 | c.io.tl_h_i.a_opcode.poke(TL_A_Opcode.get) 39 | c.io.tl_h_i.a_data.poke(0.U) 40 | c.io.tl_h_i.a_mask.poke("b1111".U) 41 | c.io.tl_h_i.a_address.poke(0.U) 42 | c.io.tl_h_i.a_source.poke(0.U) 43 | c.io.tl_h_i.a_size.poke(2.U) 44 | c.io.tl_h_i.a_param.poke(0.U) 45 | // Address Decoder selecting device 1 46 | c.io.dev_sel.poke(1.U) 47 | 48 | c.io.tl_d_o(1).a_valid.expect(true.B) 49 | c.io.tl_d_o(1).a_opcode.expect(TL_A_Opcode.get) 50 | c.io.tl_d_o(0).a_valid.expect(false.B) 51 | c.io.tl_h_o.d_error.expect(false.B) 52 | }} 53 | } 54 | 55 | // Test Case: 3 (Devices = 2) 56 | it should "Connect host with error responder when dev_sel = 2" in { 57 | test(new TLSocket1_N(2)) {c => { 58 | // Host sending a GET request 59 | c.io.tl_h_i.a_valid.poke(true.B) 60 | c.io.tl_h_i.a_opcode.poke(TL_A_Opcode.get) 61 | c.io.tl_h_i.a_data.poke(0.U) 62 | c.io.tl_h_i.a_mask.poke("b1111".U) 63 | c.io.tl_h_i.a_address.poke(0.U) 64 | c.io.tl_h_i.a_source.poke(0.U) 65 | c.io.tl_h_i.a_size.poke(2.U) 66 | c.io.tl_h_i.a_param.poke(0.U) 67 | // Address Decoder selecting device 0 68 | c.io.dev_sel.poke(2.U) 69 | 70 | c.io.tl_d_o(0).a_valid.expect(false.B) 71 | c.io.tl_d_o(1).a_valid.expect(false.B) 72 | c.io.tl_h_o.d_error.expect(true.B) 73 | }} 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_RegAdapter.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.util.{Cat, Fill} 5 | 6 | /** 7 | TL-UL adapter for the register interface used by peripherals 8 | */ 9 | 10 | class TL_RegAdapter(regAw: Int = 8, regDw: Int = 32)(regBw: Int = regDw/8)(implicit val conf: TLConfiguration) extends Module { 11 | val io = IO(new Bundle { 12 | // TL-UL interface 13 | val tl_i = Flipped(new TL_H2D()) 14 | val tl_o = new TL_D2H() 15 | 16 | // Register interface 17 | val re_o = Output(Bool()) 18 | val we_o = Output(Bool()) 19 | val addr_o = Output(UInt(regAw.W)) 20 | val wdata_o = Output(UInt(regDw.W)) 21 | val be_o = Output(UInt(regBw.W)) 22 | val rdata_i = Input(UInt(regDw.W)) 23 | val error_i = Input(Bool()) 24 | }) 25 | 26 | val a_ack = Wire(Bool()) 27 | val d_ack = Wire(Bool()) 28 | 29 | val rdata_q = RegInit(0.U(regDw.W)) 30 | val error = RegInit(0.U(1.W)) 31 | 32 | val err_internal = Wire(Bool()) 33 | val addr_align_err = Wire(Bool()) 34 | val tl_err = Wire(Bool()) 35 | 36 | val reqId = RegInit(0.U(conf.TL_AIW.W)) 37 | val reqSz = RegInit(0.U(conf.TL_SZW.W)) 38 | val respOp = RegInit(TL_D_Opcode.accessAck) 39 | 40 | val rd_req = Wire(Bool()) 41 | val wr_req = Wire(Bool()) 42 | 43 | val outstanding = RegInit(0.U(1.W)) 44 | 45 | 46 | a_ack := io.tl_i.a_valid && io.tl_o.a_ready 47 | d_ack := io.tl_o.d_valid && io.tl_i.d_ready 48 | 49 | // Request signals coming from Host 50 | wr_req := a_ack && ((io.tl_i.a_opcode === TL_A_Opcode.putFullData) || (io.tl_i.a_opcode === TL_A_Opcode.putPartialData)) 51 | rd_req := a_ack && (io.tl_i.a_opcode === TL_A_Opcode.get) 52 | 53 | io.we_o := wr_req && !err_internal 54 | io.re_o := rd_req && !err_internal 55 | io.addr_o := Cat(io.tl_i.a_address(regAw-1, 2), 0.U(2.W)) // word aligned address 56 | io.wdata_o := io.tl_i.a_data 57 | io.be_o := io.tl_i.a_mask 58 | 59 | 60 | when(a_ack) { 61 | outstanding := 1.U 62 | reqId := io.tl_i.a_source 63 | reqSz := io.tl_i.a_size 64 | respOp := Mux(rd_req, TL_D_Opcode.accessAckData, TL_D_Opcode.accessAck) 65 | rdata_q := Mux(err_internal, Fill(regDw, 1.U), io.rdata_i) // return all 1111s if err_internal = true 66 | error := io.error_i || err_internal 67 | } .elsewhen(d_ack) { 68 | outstanding := 0.U 69 | } 70 | 71 | io.tl_o.a_ready := !outstanding 72 | io.tl_o.d_valid := outstanding 73 | io.tl_o.d_opcode := respOp 74 | io.tl_o.d_param := 0.U 75 | io.tl_o.d_size := reqSz 76 | io.tl_o.d_source := reqId 77 | io.tl_o.d_sink := 0.U 78 | io.tl_o.d_data := rdata_q 79 | io.tl_o.d_error := error 80 | 81 | err_internal := addr_align_err | tl_err 82 | 83 | when(wr_req) { 84 | addr_align_err := io.tl_i.a_address(1,0).orR 85 | } .otherwise { 86 | addr_align_err := false.B 87 | } 88 | 89 | // separate tl_err checker which checks the address, size and mask correspondence according to the spec. 90 | val tlErr = Module(new TL_Err) 91 | tlErr.io.tl_i := io.tl_i 92 | tl_err := tlErr.io.err_o 93 | } -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TLSocketM_1.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.util.{Cat, log2Ceil} 5 | 6 | class TLSocketM_1(M: Int)(implicit val conf:TLConfiguration) extends Module { 7 | val io = IO(new Bundle { 8 | val tl_h_i = Vec(M, Flipped(new TL_H2D)) 9 | val tl_h_o = Vec(M, new TL_D2H) 10 | val tl_d_o = new TL_H2D 11 | val tl_d_i = Flipped(new TL_D2H) 12 | }) 13 | val STIDW = log2Ceil(M) // the bits required for identifying hosts. 14 | val tl_h2d = Wire(Vec(M, Flipped(new TL_H2D))) // create an intermediate bundles of wire for capturing the host request 15 | val hRequest = Wire(Vec(M, Bool())) // this bundle of wires is used to have the valid signals of all hosts. 16 | val respReady = Wire(Vec(M, Bool())) 17 | val respValid = Wire(Vec(M, Bool())) 18 | 19 | for(i <- 0 until M) { 20 | val reqid_sub = Wire(UInt(STIDW.W)) 21 | val shifted_id = Wire(UInt(conf.TL_AIW.W)) 22 | 23 | reqid_sub := i.asUInt // this will be used to identify hosts connected with the socket 24 | shifted_id := Cat(io.tl_h_i(i).a_source((conf.TL_AIW-STIDW)-1,0), reqid_sub) 25 | tl_h2d(i).a_valid := io.tl_h_i(i).a_valid 26 | tl_h2d(i).a_opcode := io.tl_h_i(i).a_opcode 27 | tl_h2d(i).a_param := io.tl_h_i(i).a_param 28 | tl_h2d(i).a_size := io.tl_h_i(i).a_size 29 | tl_h2d(i).a_source := shifted_id 30 | tl_h2d(i).a_address := io.tl_h_i(i).a_address 31 | tl_h2d(i).a_mask := io.tl_h_i(i).a_mask 32 | tl_h2d(i).a_data := io.tl_h_i(i).a_data 33 | tl_h2d(i).d_ready := io.tl_h_i(i).d_ready 34 | } 35 | 36 | for(i <- 0 until M) { 37 | hRequest(i) := tl_h2d(i).a_valid 38 | } 39 | 40 | for(i <- 0 until M) { 41 | respValid(i) := io.tl_d_i.d_valid && (io.tl_d_i.d_source(STIDW-1,0) === i.asUInt) 42 | respReady(i) := tl_h2d(i).d_ready && (io.tl_d_i.d_source(STIDW-1,0) === i.asUInt) && io.tl_d_i.d_valid 43 | } 44 | 45 | val arb = Module(new Arbiter(M)) 46 | arb.io.req_i := hRequest 47 | arb.io.ready_i := io.tl_d_i.a_ready 48 | arb.io.data_i <> tl_h2d 49 | 50 | io.tl_d_o.a_valid := arb.io.valid_o 51 | io.tl_d_o.a_opcode := arb.io.data_o.a_opcode 52 | io.tl_d_o.a_param := arb.io.data_o.a_param 53 | io.tl_d_o.a_size := arb.io.data_o.a_size 54 | io.tl_d_o.a_source := arb.io.data_o.a_source 55 | io.tl_d_o.a_address := arb.io.data_o.a_address 56 | io.tl_d_o.a_mask := arb.io.data_o.a_mask 57 | io.tl_d_o.a_data := arb.io.data_o.a_data 58 | io.tl_d_o.d_ready := respReady.contains(true.B) // this is to check if any wire inside the respReady bundle is true. 59 | 60 | 61 | for(i <- 0 until M) { 62 | io.tl_h_o(i).d_valid := respValid(i) 63 | io.tl_h_o(i).d_opcode := io.tl_d_i.d_opcode 64 | io.tl_h_o(i).d_param := io.tl_d_i.d_param 65 | io.tl_h_o(i).d_size := io.tl_d_i.d_size 66 | io.tl_h_o(i).d_source := Cat(0.U,io.tl_d_i.d_source(conf.TL_AIW-1,STIDW)) // making sure we pass the same a_source in d_source. 67 | io.tl_h_o(i).d_sink := io.tl_d_i.d_sink 68 | io.tl_h_o(i).d_data := io.tl_d_i.d_data 69 | io.tl_h_o(i).d_error := io.tl_d_i.d_error 70 | io.tl_h_o(i).a_ready := arb.io.gnt_o(i) 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TLSocket1_N.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | 3 | import chisel3._ 4 | import chisel3.util.{log2Ceil} 5 | 6 | class TLSocket1_N(N: Int)(implicit val conf: TLConfiguration) extends Module { 7 | val io = IO(new Bundle { 8 | val tl_h_i = Flipped(new TL_H2D) 9 | val tl_h_o = new TL_D2H 10 | 11 | val tl_d_o = Vec(N, new TL_H2D) 12 | val tl_d_i = Flipped(Vec(N, new TL_D2H)) 13 | 14 | val dev_sel = Input(UInt(log2Ceil(N+1).W)) 15 | }) 16 | 17 | // An intermediate bundle of wires for error responder 18 | // the tl_err_h_o takes the host input from tl_h_i and then will eventually send it to error responder 19 | val tl_err_h_o = Wire(new TL_H2D) 20 | // the tl_err_d_i takes the input from the error responder and sends it to the host output tl_h_o 21 | val tl_err_d_i = Wire(Flipped(new TL_D2H)) 22 | 23 | // by default connecting the response with the error bundle 24 | // this would be connected with the correct device according to dev_sel 25 | // if dev_sel does not match any device than it will remain connected with this error bundle. 26 | io.tl_h_o <> tl_err_d_i 27 | 28 | for(i <- 0 until N) { 29 | io.tl_d_o(i).a_valid := io.tl_h_i.a_valid && (io.dev_sel === i.asUInt) 30 | io.tl_d_o(i).a_opcode := io.tl_h_i.a_opcode 31 | io.tl_d_o(i).a_param := io.tl_h_i.a_param 32 | io.tl_d_o(i).a_size := io.tl_h_i.a_size 33 | io.tl_d_o(i).a_source := io.tl_h_i.a_source 34 | io.tl_d_o(i).a_address := io.tl_h_i.a_address 35 | io.tl_d_o(i).a_mask := io.tl_h_i.a_mask 36 | io.tl_d_o(i).a_data := io.tl_h_i.a_data 37 | io.tl_d_o(i).d_ready := io.tl_h_i.d_ready 38 | 39 | } 40 | 41 | // looping over all the devices and seeing if dev_sel matches the device number 42 | for(id <- 0 until N) { 43 | // routing the ready signal of the device we are addressing with dev_sel 44 | // if dev_sel matches no devices then it means the dev_sel is out of range and 45 | // we connect it with the error responder device which will route an error 46 | when(io.dev_sel === id.asUInt) { 47 | // io.tl_h_o.a_ready := io.tl_h_i.a_valid && io.tl_d_i(id).a_ready 48 | io.tl_h_o.a_ready := io.tl_d_i(id).a_ready 49 | io.tl_h_o.d_valid := io.tl_d_i(id).d_valid 50 | io.tl_h_o.d_opcode := io.tl_d_i(id).d_opcode 51 | io.tl_h_o.d_param := io.tl_d_i(id).d_param 52 | io.tl_h_o.d_size := io.tl_d_i(id).d_size 53 | io.tl_h_o.d_source := io.tl_d_i(id).d_source 54 | io.tl_h_o.d_sink := io.tl_d_i(id).d_sink 55 | io.tl_h_o.d_data := io.tl_d_i(id).d_data 56 | io.tl_h_o.d_error := io.tl_d_i(id).d_error 57 | } 58 | } 59 | 60 | 61 | 62 | tl_err_h_o.a_valid := io.tl_h_i.a_valid && (io.dev_sel === N.asUInt) 63 | tl_err_h_o.a_opcode := io.tl_h_i.a_opcode 64 | tl_err_h_o.a_param := io.tl_h_i.a_param 65 | tl_err_h_o.a_size := io.tl_h_i.a_size 66 | tl_err_h_o.a_source := io.tl_h_i.a_source 67 | tl_err_h_o.a_address := io.tl_h_i.a_address 68 | tl_err_h_o.a_mask := io.tl_h_i.a_mask 69 | tl_err_h_o.a_data := io.tl_h_i.a_data 70 | tl_err_h_o.d_ready := io.tl_h_i.d_ready 71 | 72 | val tl_errResp = Module(new TL_ErrResp) 73 | tl_errResp.io.tl_h_i <> tl_err_h_o 74 | tl_err_d_i <> tl_errResp.io.tl_d_o 75 | } 76 | -------------------------------------------------------------------------------- /src/main/scala/merl/uit/tilelink/TL_SramAdapter.scala: -------------------------------------------------------------------------------- 1 | package merl.uit.tilelink 2 | import chisel3._ 3 | import chisel3.util.{Cat, Enum, Fill, log2Ceil} 4 | 5 | class TL_SramAdapter(sramAw: Int, sramDw: Int, forFetch: Bool = false.B)(implicit val conf: TLConfiguration) extends Module { 6 | val io = IO(new Bundle { 7 | // TL-UL interface 8 | val tl_i = Flipped(new TL_H2D()) 9 | val tl_o = new TL_D2H() 10 | // SRAM interface 11 | val we_o = Output(Bool()) 12 | val addr_o = Output(UInt(sramAw.W)) 13 | val wdata_o = Output(UInt(sramDw.W)) 14 | val wmask_o = Output(Vec(conf.TL_DBW, Bool())) 15 | val rdata_i = Input(UInt(sramDw.W)) 16 | //val rerror_i = Input(UInt(2.W)) 17 | }) 18 | 19 | val a_ack = Wire(Bool()) 20 | val d_ack = Wire(Bool()) 21 | // reading data received from DCCM 22 | val rdata = Wire(UInt(sramDw.W)) 23 | // reading data received from ICCM 24 | // separate wires because for fetch we cannot wait for valid 25 | // and stall the pipeline so we directly receive the data and 26 | // pass it to the tilelink response bus. 27 | val rdata_fetch = Wire(UInt(sramDw.W)) 28 | rdata_fetch := io.rdata_i 29 | val error = RegInit(0.U(1.W)) 30 | 31 | val err_internal = Wire(Bool()) 32 | val addr_align_err = Wire(Bool()) 33 | val tl_err = Wire(Bool()) 34 | 35 | val reqId = RegInit(0.U(conf.TL_AIW.W)) 36 | val reqSz = RegInit(0.U(conf.TL_SZW.W)) 37 | val respOp = RegInit(TL_D_Opcode.accessAck) 38 | 39 | val rd_req = Wire(Bool()) 40 | val wr_req = Wire(Bool()) 41 | 42 | val outstanding = RegInit(0.U(1.W)) 43 | 44 | 45 | a_ack := io.tl_i.a_valid && io.tl_o.a_ready 46 | d_ack := io.tl_o.d_valid && io.tl_i.d_ready 47 | 48 | wr_req := a_ack && ((io.tl_i.a_opcode === TL_A_Opcode.putFullData) || (io.tl_i.a_opcode === TL_A_Opcode.putPartialData)) 49 | rd_req := a_ack && (io.tl_i.a_opcode === TL_A_Opcode.get) 50 | 51 | io.we_o := wr_req && !err_internal 52 | io.addr_o := Cat(io.tl_i.a_address(sramAw-1, 2), 0.U(2.W)) // word aligned address 53 | io.wdata_o := io.tl_i.a_data 54 | for(i <- 0 until conf.TL_DBW) { 55 | io.wmask_o(i) := io.tl_i.a_mask(i).asBool() 56 | } 57 | 58 | when(a_ack) { 59 | outstanding := 1.U 60 | reqId := io.tl_i.a_source 61 | reqSz := io.tl_i.a_size 62 | respOp := Mux(rd_req, TL_D_Opcode.accessAckData, TL_D_Opcode.accessAck) 63 | error := err_internal 64 | } .elsewhen(d_ack) { 65 | outstanding := 0.U 66 | } 67 | 68 | when(outstanding.asBool()) { 69 | rdata := Mux(error.asBool(), Fill(sramDw, 1.U), io.rdata_i) // return all 1111s if err_internal = true 70 | } .otherwise { 71 | rdata := 0.U 72 | } 73 | 74 | io.tl_o.a_ready := Mux(forFetch, true.B, !outstanding) 75 | io.tl_o.d_valid := outstanding 76 | io.tl_o.d_opcode := respOp 77 | io.tl_o.d_param := 0.U 78 | io.tl_o.d_size := reqSz 79 | io.tl_o.d_source := reqId 80 | io.tl_o.d_sink := 0.U 81 | io.tl_o.d_data := Mux(forFetch, rdata_fetch, rdata) 82 | io.tl_o.d_error := error 83 | 84 | err_internal := addr_align_err | tl_err 85 | 86 | when(wr_req) { 87 | addr_align_err := io.tl_i.a_address(1,0).orR 88 | } .otherwise { 89 | addr_align_err := false.B 90 | } 91 | 92 | // separate tl_err checker which checks the address, size and mask correspondence according to the spec. 93 | val tlErr = Module(new TL_Err) 94 | tlErr.io.tl_i := io.tl_i 95 | tl_err := tlErr.io.err_o 96 | 97 | } 98 | -------------------------------------------------------------------------------- /scalastyle-config.xml: -------------------------------------------------------------------------------- 1 | 2 | Scalastyle standard configuration 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | No lines ending with a ; 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Project Specific stuff 2 | test_run_dir/* 3 | ### XilinxISE template 4 | # intermediate build files 5 | *.bgn 6 | *.bit 7 | *.bld 8 | *.cmd_log 9 | *.drc 10 | *.ll 11 | *.lso 12 | *.msd 13 | *.msk 14 | *.ncd 15 | *.ngc 16 | *.ngd 17 | *.ngr 18 | *.pad 19 | *.par 20 | *.pcf 21 | *.prj 22 | *.ptwx 23 | *.rbb 24 | *.rbd 25 | *.stx 26 | *.syr 27 | *.twr 28 | *.twx 29 | *.unroutes 30 | *.ut 31 | *.xpi 32 | *.xst 33 | *_bitgen.xwbt 34 | *_envsettings.html 35 | *_map.map 36 | *_map.mrp 37 | *_map.ngm 38 | *_map.xrpt 39 | *_ngdbuild.xrpt 40 | *_pad.csv 41 | *_pad.txt 42 | *_par.xrpt 43 | *_summary.html 44 | *_summary.xml 45 | *_usage.xml 46 | *_xst.xrpt 47 | 48 | # project-wide generated files 49 | *.gise 50 | par_usage_statistics.html 51 | usage_statistics_webtalk.html 52 | webtalk.log 53 | webtalk_pn.xml 54 | 55 | # generated folders 56 | iseconfig/ 57 | xlnx_auto_0_xdb/ 58 | xst/ 59 | _ngo/ 60 | _xmsgs/ 61 | .bloop/ 62 | .metals/ 63 | ### Eclipse template 64 | *.pydevproject 65 | .metadata 66 | .gradle 67 | bin/ 68 | tmp/ 69 | *.tmp 70 | *.bak 71 | *.swp 72 | *~.nib 73 | local.properties 74 | .settings/ 75 | .loadpath 76 | 77 | # Eclipse Core 78 | .project 79 | 80 | # External tool builders 81 | .externalToolBuilders/ 82 | 83 | # Locally stored "Eclipse launch configurations" 84 | *.launch 85 | 86 | # CDT-specific 87 | .cproject 88 | 89 | # JDT-specific (Eclipse Java Development Tools) 90 | .classpath 91 | 92 | # Java annotation processor (APT) 93 | .factorypath 94 | 95 | # PDT-specific 96 | .buildpath 97 | 98 | # sbteclipse plugin 99 | .target 100 | 101 | # TeXlipse plugin 102 | .texlipse 103 | ### C template 104 | # Object files 105 | *.o 106 | *.ko 107 | *.obj 108 | *.elf 109 | 110 | # Precompiled Headers 111 | *.gch 112 | *.pch 113 | 114 | # Libraries 115 | *.lib 116 | *.a 117 | *.la 118 | *.lo 119 | 120 | # Shared objects (inc. Windows DLLs) 121 | *.dll 122 | *.so 123 | *.so.* 124 | *.dylib 125 | 126 | # Executables 127 | *.exe 128 | *.out 129 | *.app 130 | *.i*86 131 | *.x86_64 132 | *.hex 133 | 134 | # Debug files 135 | *.dSYM/ 136 | ### SBT template 137 | # Simple Build Tool 138 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control 139 | 140 | target/ 141 | lib_managed/ 142 | src_managed/ 143 | project/boot/ 144 | .history 145 | .cache 146 | ### Emacs template 147 | # -*- mode: gitignore; -*- 148 | *~ 149 | \#*\# 150 | /.emacs.desktop 151 | /.emacs.desktop.lock 152 | *.elc 153 | auto-save-list 154 | tramp 155 | .\#* 156 | 157 | # Org-mode 158 | .org-id-locations 159 | *_archive 160 | 161 | # flymake-mode 162 | *_flymake.* 163 | 164 | # eshell files 165 | /eshell/history 166 | /eshell/lastdir 167 | 168 | # elpa packages 169 | /elpa/ 170 | 171 | # reftex files 172 | *.rel 173 | 174 | # AUCTeX auto folder 175 | /auto/ 176 | 177 | # cask packages 178 | .cask/ 179 | ### Vim template 180 | [._]*.s[a-w][a-z] 181 | [._]s[a-w][a-z] 182 | *.un~ 183 | Session.vim 184 | .netrwhist 185 | *~ 186 | ### JetBrains template 187 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 188 | 189 | *.iml 190 | 191 | ## Directory-based project format: 192 | .idea/ 193 | # if you remove the above rule, at least ignore the following: 194 | 195 | # User-specific stuff: 196 | # .idea/workspace.xml 197 | # .idea/tasks.xml 198 | # .idea/dictionaries 199 | 200 | # Sensitive or high-churn files: 201 | # .idea/dataSources.ids 202 | # .idea/dataSources.xml 203 | # .idea/sqlDataSources.xml 204 | # .idea/dynamic.xml 205 | # .idea/uiDesigner.xml 206 | 207 | # Gradle: 208 | # .idea/gradle.xml 209 | # .idea/libraries 210 | 211 | # Mongo Explorer plugin: 212 | # .idea/mongoSettings.xml 213 | 214 | ## File-based project format: 215 | *.ipr 216 | *.iws 217 | 218 | ## Plugin-specific files: 219 | 220 | # IntelliJ 221 | /out/ 222 | 223 | # mpeltonen/sbt-idea plugin 224 | .idea_modules/ 225 | 226 | # JIRA plugin 227 | atlassian-ide-plugin.xml 228 | 229 | # Crashlytics plugin (for Android Studio and IntelliJ) 230 | com_crashlytics_export_strings.xml 231 | crashlytics.properties 232 | crashlytics-build.properties 233 | ### C++ template 234 | # Compiled Object files 235 | *.slo 236 | *.lo 237 | *.o 238 | *.obj 239 | 240 | # Precompiled Headers 241 | *.gch 242 | *.pch 243 | 244 | # Compiled Dynamic libraries 245 | *.so 246 | *.dylib 247 | *.dll 248 | 249 | # Fortran module files 250 | *.mod 251 | 252 | # Compiled Static libraries 253 | *.lai 254 | *.la 255 | *.a 256 | *.lib 257 | 258 | # Executables 259 | *.exe 260 | *.out 261 | *.app 262 | ### OSX template 263 | .DS_Store 264 | .AppleDouble 265 | .LSOverride 266 | 267 | # Icon must end with two \r 268 | Icon 269 | 270 | # Thumbnails 271 | ._* 272 | 273 | # Files that might appear in the root of a volume 274 | .DocumentRevisions-V100 275 | .fseventsd 276 | .Spotlight-V100 277 | .TemporaryItems 278 | .Trashes 279 | .VolumeIcon.icns 280 | 281 | # Directories potentially created on remote AFP share 282 | .AppleDB 283 | .AppleDesktop 284 | Network Trash Folder 285 | Temporary Items 286 | .apdisk 287 | ### Xcode template 288 | # Xcode 289 | # 290 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 291 | 292 | ## Build generated 293 | build/ 294 | DerivedData 295 | 296 | ## Various settings 297 | *.pbxuser 298 | !default.pbxuser 299 | *.mode1v3 300 | !default.mode1v3 301 | *.mode2v3 302 | !default.mode2v3 303 | *.perspectivev3 304 | !default.perspectivev3 305 | xcuserdata 306 | 307 | ## Other 308 | *.xccheckout 309 | *.moved-aside 310 | *.xcuserstate 311 | ### Scala template 312 | *.class 313 | *.log 314 | 315 | # sbt specific 316 | .cache 317 | .history 318 | .lib/ 319 | dist/* 320 | target/ 321 | lib_managed/ 322 | src_managed/ 323 | project/boot/ 324 | project/plugins/project/ 325 | 326 | # Scala-IDE specific 327 | .scala_dependencies 328 | .worksheet 329 | ### Java template 330 | *.class 331 | 332 | # Mobile Tools for Java (J2ME) 333 | .mtj.tmp/ 334 | 335 | # Package Files # 336 | *.jar 337 | *.war 338 | *.ear 339 | 340 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 341 | hs_err_pid* 342 | 343 | -------------------------------------------------------------------------------- /scalastyle-test-config.xml: -------------------------------------------------------------------------------- 1 | 2 | Scalastyle configuration for Chisel3 unit tests 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | No lines ending with a ; 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Welcome to the TL-UL Implementation Specification 2 | 3 | This page is dedicated for the implementation specification of the TileLink Uncached Lightweight (TL-UL) protocol. 4 | 5 | The TL-UL protocol conforms to the [Tilelink 1.7.1 specification](https://sifive.cdn.prismic.io/sifive%2F57f93ecf-2c42-46f7-9818-bcdd7d39400a_tilelink-spec-1.7.1.pdf) provided by SiFive. 6 | 7 | ### a_size functionality 8 | For all the Host (Master) messages listed below (Get, PutPartialData, PutFullData) the `a_size` in terms of log2(bytes) cannot be greater than the physical data bus width in TL-UL. For example, if the physical data bus width is 32 bits then `a_size <= 2` since 2^a_size -> 2^2 -> 4 bytes. 9 | 10 | #### Get 11 | `a_size` indicates the total amount of data the requesting agent wishes to read in terms of _log2(bytes)_. `a_size` represents the size of the resulting `AccessAckData` response. 12 | 13 | #### Possbilities of a_size in Get 14 | 15 | | a_size | Interpretation (2^a_size) bytes | 16 | |-------|--------| 17 | | 0 | Slave returns (2^0 = 1 byte) in AccessAckData | 18 | | 1 | Slave returns (2^1 = 2 bytes) in AccessAckData | 19 | | 2 | Slave returns (2^2 = 4 bytes) in AccessAckData | 20 | 21 | #### PutFullData 22 | `a_size` indicates the total amount of data the requesting agent wishes to write in terms of _log2(bytes)_. Although, the specification allows `a_size` to represent any value but `PutFullData` should always set `a_size = 2` for a 32-bit wide data bus or `a_size = 3` for a 64-bit wide data bus. 23 | 24 | #### Possbilities of a_size in PutFullData 25 | 26 | | a_size | Interpretation (2^a_size) bytes | 27 | | ------ | --------- | 28 | | 2 | Host intends to write (2^2 = 4 bytes) of data on the data bus 29 | 30 | 31 | #### PutPartialData 32 | `a_size` indicates how many bytes are transmitted in terms of _log2(bytes)_. As compared to `PutFullData`, the `PutPartialData` can write data at byte granuality using the `a_size` and `a_mask` properties. The `a_size` can indicate a byte, two bytes, three bytes as well as four bytes. 33 | 34 | #### Possbilities of a_size in PutPartialData 35 | 36 | | a_size | Interpretation (2^a_size) bytes | 37 | | ------ | --------- | 38 | | 0 | Host intends to write (2^0 = 1 byte) of data on the data bus 39 | | 1 | Host intends to write (2^1 = 2 bytes) of data on the data bus 40 | | 2 | Host intends to write (2^2 = 4 bytes) of data on the data bus 41 | 42 | ### d_size functionality 43 | For all the Device (Slave) messages listed below (AccessAck, AccessAckData) the `d_size` in terms of log2(bytes) cannot be greater than the physical data bus width in TL-UL and must always be in correspondence with `a_size`. 44 | 45 | #### AccessAck 46 | `d_size` indicates the size of the data written by the slave device. This should always correspond to the `a_size` that was received when the Host initiated the request. 47 | 48 | 49 | #### Possbilities of d_size in AccessAck 50 | 51 | | d_size | Interpretation (2^d_size) bytes | 52 | | ------ | --------- | 53 | | 0 | Device wrote (2^0 = 1 byte) of data 54 | | 1 | Device wrote (2^1 = 2 bytes) of data 55 | | 2 | Device wrote (2^2 = 4 bytes) of data 56 | 57 | #### AccessAckData 58 | `d_size` indicates the size of the data accessed by the device and is included in the response message along with `d_data` which contains the actual data payload, and other d channel properties. `d_size` must always correspond with the `a_size` which the host sets while sending a request to the device. 59 | 60 | #### Possbilities of d_size in AccessAckData 61 | 62 | | d_size | Interpretation (2^d_size) bytes | 63 | | ------ | --------- | 64 | | 0 | Device accessed (2^0 = 1 byte) of data 65 | | 1 | Device accessed (2^1 = 2 bytes) of data 66 | | 2 | Device accessed (2^2 = 4 bytes) of data 67 | 68 | ### a_mask functionality 69 | `a_mask`indicates the byte lanes that are active for the current operation. The `a_mask` signal bit width is identified by Data Bus Width (DBW)/8 which gives 4 bit width for a 32 bit Data Bus. If all the `a_mask` bits are set `1111` it means that all byte lanes are active. 70 | 71 | #### Get 72 | `a_mask` selects the byte lanes to read from the data that is received in `AccessAckData`. The `a_size` describes the size of the data received (1 Byte, 2 Bytes, 3 Bytes, 4 Bytes) and the `a_mask` selects from which byte lane to read the data. 73 | 74 | #### Possbilities of a_mask in Get 75 | 76 | | a_size[1:0] | Size in Bytes (2^a_size) | a_mask[3:0] | Description 77 | | :------: | :-----: | :------: | ----------- | 78 | | 'd0 | 1 byte | 'b0001 | Read zeroth byte lane from the received data. 79 | | 'd0 | 1 byte | 'b0010 | Read first byte lane from the received data. 80 | | 'd0 | 1 byte | 'b0100 | Read second byte lane from the received data. 81 | | 'd0 | 1 byte | 'b1000 | Read third byte lane from the received data. 82 | | 'd1 | 2 bytes |'b0011 | Read the zeroth and first byte lane from the received data. 83 | | 'd1 | 2 bytes |'b0110 | Read the first and second byte lane from the received data. 84 | | 'd1 | 2 bytes |'b1100 | Read the second and third byte lane from the received data. 85 | | 'd2 | 4 bytes |'b0111 | Read the zeroth, first and second byte lane from the received data. 86 | | 'd2 | 4 bytes |'b1110 | Read the first, second and third byte lane from the received data. 87 | | 'd2 | 4 bytes |'b1111 | Read all byte lanes from the received data. 88 | 89 | **Note**: The 'd represents decimal representation and 'b represents the binary representation in the table above. The `a_mask` bits are contiguous i.e they are side by side an not like `b1001` and so on. This is not allowed by the specification. 90 | 91 | #### PutFullData 92 | `a_mask` selects the byte lanes to be written. One HIGH bit of `a_mask` indicates one byte written. Whenever `PutFullData` is active then `a_size = 2` and all the bits of `a_mask` must be set `a_mask = 1111` in order to write all byte lanes. 93 | 94 | #### Possbilities of a_mask in PutFullData 95 | 96 | | a_size[1:0] | Size in Bytes (2^a_size) | a_mask[3:0] | Description 97 | | :------: | :-----: | :------: | ----------- | 98 | | 'd2 | 4 byte | 'b1111 | Write all byte lanes of the data. 99 | 100 | **Note**: The 'd represents decimal representation and 'b represents the binary representation in the table above. The `a_mask` bits are contiguous i.e they are side by side an not like `b1001` and so on. This is not allowed by the specification. 101 | 102 | #### PutPartialData 103 | `a_mask` selects the byte lanes to be written. During `PutPartialData` the `a_size` can be either 0, 1 or 2 and `a_mask` will select the corresponding byte lane to write. 104 | 105 | | a_size[1:0] | Size in Bytes (2^a_size) | a_mask[3:0] | Description 106 | | :------: | :-----: | :------: | ----------- | 107 | | 'd0 | 1 byte | 'b0001 | Write zeroth byte lane of the data. 108 | | 'd0 | 1 byte | 'b0010 | Write first byte lane of the data. 109 | | 'd0 | 1 byte | 'b0100 | Write second byte lane of the data. 110 | | 'd0 | 1 byte | 'b1000 | Write third byte lane of the data. 111 | | 'd1 | 2 bytes |'b0011 | Write the zeroth and first byte lane of the data. 112 | | 'd1 | 2 bytes |'b0110 | Write the first and second byte lane of the data. 113 | | 'd1 | 2 bytes |'b1100 | Write the second and third byte lane of the data. 114 | | 'd1 | 2 bytes |'b1001 | Write the zeroth and third byte lane of the data. 115 | | 'd1 | 2 bytes |'b1010 | Write the first and third byte lane of the data. 116 | | ... | ... |... | Other non contiguous possibilities 117 | | 'd2 | 4 bytes |'b0111 | Write the zeroth, first and second byte lane of the data. 118 | | 'd2 | 4 bytes |'b1110 | Write the first, second and third byte lane of the data. 119 | | 'd2 | 4 bytes |'b1101 | Write the zeroth, second and third byte lane of the data. 120 | | ... | ... |... | Other non contiguous possibilities 121 | | 'd2 | 4 bytes |'b1111 | Write all byte lanes of the data. 122 | 123 | **Note**: The 'd represents decimal representation and 'b represents the binary representation in the table above. The `a_mask` bits can be non-contiguous for `PutPartialData`. This is allowed by the specification. See [Section 6.2.3 PutPartialData](https://sifive.cdn.prismic.io/sifive%2F57f93ecf-2c42-46f7-9818-bcdd7d39400a_tilelink-spec-1.7.1.pdf) 124 | 125 | 126 | 127 | ### Support or Contact 128 | 129 | Having trouble with the documentation? Please open an issue [here](https://github.com/hadirkhan10/TileLink/issues) defining the problem you are facing or any question you have. 130 | -------------------------------------------------------------------------------- /src/test/scala/TLSocketMto1Test.scala: -------------------------------------------------------------------------------- 1 | package tilelink 2 | import org.scalatest._ 3 | import chiseltest._ 4 | import chisel3._ 5 | import merl.uit.tilelink.{TLConfiguration, TLSocketM_1, TL_A_Opcode} 6 | 7 | class TLSocketMto1Test extends FlatSpec with ChiselScalatestTester with Matchers { 8 | behavior of "TL-UL M:1 socket connecting M hosts with a single device" 9 | implicit val tl_conf = TLConfiguration() 10 | // Test Case: 1 11 | it should "Connect host(0) with the device when host(1) is not accessing bus" in { 12 | test(new TLSocketM_1(2)) {c => { 13 | // Host 1 sending a GET 14 | c.io.tl_h_i(0).a_opcode.poke(TL_A_Opcode.get) 15 | c.io.tl_h_i(0).a_valid.poke(true.B) 16 | c.io.tl_h_i(0).a_param.poke(0.U) 17 | c.io.tl_h_i(0).a_size.poke(2.U) 18 | c.io.tl_h_i(0).a_source.poke(0.U) 19 | c.io.tl_h_i(0).a_address.poke(0.U) 20 | c.io.tl_h_i(0).a_mask.poke("b1111".U) 21 | c.io.tl_h_i(0).a_data.poke(0.U) 22 | 23 | // Host 2 sending a PUT 24 | c.io.tl_h_i(1).a_opcode.poke(TL_A_Opcode.putFullData) 25 | c.io.tl_h_i(1).a_valid.poke(false.B) 26 | c.io.tl_h_i(1).a_param.poke(0.U) 27 | c.io.tl_h_i(1).a_size.poke(2.U) 28 | c.io.tl_h_i(1).a_source.poke(0.U) 29 | c.io.tl_h_i(1).a_address.poke(0.U) 30 | c.io.tl_h_i(1).a_mask.poke("b1111".U) 31 | c.io.tl_h_i(1).a_data.poke(10.U) 32 | 33 | c.io.tl_d_o.a_opcode.expect(TL_A_Opcode.get) 34 | c.io.tl_d_o.a_data.expect(0.U) 35 | }} 36 | } 37 | // Test Case: 2 38 | it should "Connect host(1) with the device when host(0) is not accessing bus" in { 39 | test(new TLSocketM_1(2)) {c => { 40 | // Host 1 sending a GET 41 | c.io.tl_h_i(0).a_opcode.poke(TL_A_Opcode.get) 42 | c.io.tl_h_i(0).a_valid.poke(false.B) 43 | c.io.tl_h_i(0).a_param.poke(0.U) 44 | c.io.tl_h_i(0).a_size.poke(2.U) 45 | c.io.tl_h_i(0).a_source.poke(0.U) 46 | c.io.tl_h_i(0).a_address.poke(0.U) 47 | c.io.tl_h_i(0).a_mask.poke("b1111".U) 48 | c.io.tl_h_i(0).a_data.poke(0.U) 49 | 50 | // Host 2 sending a PUT 51 | c.io.tl_h_i(1).a_opcode.poke(TL_A_Opcode.putFullData) 52 | c.io.tl_h_i(1).a_valid.poke(true.B) 53 | c.io.tl_h_i(1).a_param.poke(0.U) 54 | c.io.tl_h_i(1).a_size.poke(2.U) 55 | c.io.tl_h_i(1).a_source.poke(0.U) 56 | c.io.tl_h_i(1).a_address.poke(0.U) 57 | c.io.tl_h_i(1).a_mask.poke("b1111".U) 58 | c.io.tl_h_i(1).a_data.poke(10.U) 59 | 60 | c.io.tl_d_o.a_opcode.expect(TL_A_Opcode.putFullData) 61 | c.io.tl_d_o.a_data.expect(10.U) 62 | }} 63 | } 64 | // Test Case: 3 65 | it should "Connect host(0) with the device even when host(1) is accessing bus" in { 66 | test(new TLSocketM_1(2)) {c => { 67 | // Host 1 sending a GET 68 | c.io.tl_h_i(0).a_opcode.poke(TL_A_Opcode.get) 69 | c.io.tl_h_i(0).a_valid.poke(true.B) 70 | c.io.tl_h_i(0).a_param.poke(0.U) 71 | c.io.tl_h_i(0).a_size.poke(2.U) 72 | c.io.tl_h_i(0).a_source.poke(0.U) 73 | c.io.tl_h_i(0).a_address.poke(0.U) 74 | c.io.tl_h_i(0).a_mask.poke("b1111".U) 75 | c.io.tl_h_i(0).a_data.poke(0.U) 76 | 77 | // Host 2 sending a PUT 78 | c.io.tl_h_i(1).a_opcode.poke(TL_A_Opcode.putFullData) 79 | c.io.tl_h_i(1).a_valid.poke(true.B) 80 | c.io.tl_h_i(1).a_param.poke(0.U) 81 | c.io.tl_h_i(1).a_size.poke(2.U) 82 | c.io.tl_h_i(1).a_source.poke(0.U) 83 | c.io.tl_h_i(1).a_address.poke(0.U) 84 | c.io.tl_h_i(1).a_mask.poke("b1111".U) 85 | c.io.tl_h_i(1).a_data.poke(10.U) 86 | 87 | c.io.tl_d_o.a_opcode.expect(TL_A_Opcode.get) 88 | c.io.tl_d_o.a_data.expect(0.U) 89 | }} 90 | } 91 | // Test Case: 4 (Hosts = 3) 92 | it should "Connect host(2) with the device when host(0) and host(1) both are not accessing bus" in { 93 | test(new TLSocketM_1(3)) {c => { 94 | // Host 1 sending a GET 95 | c.io.tl_h_i(0).a_opcode.poke(TL_A_Opcode.get) 96 | c.io.tl_h_i(0).a_valid.poke(false.B) 97 | c.io.tl_h_i(0).a_param.poke(0.U) 98 | c.io.tl_h_i(0).a_size.poke(2.U) 99 | c.io.tl_h_i(0).a_source.poke(0.U) 100 | c.io.tl_h_i(0).a_address.poke(0.U) 101 | c.io.tl_h_i(0).a_mask.poke("b1111".U) 102 | c.io.tl_h_i(0).a_data.poke(0.U) 103 | 104 | // Host 2 sending a PUT 105 | c.io.tl_h_i(1).a_opcode.poke(TL_A_Opcode.putFullData) 106 | c.io.tl_h_i(1).a_valid.poke(false.B) 107 | c.io.tl_h_i(1).a_param.poke(0.U) 108 | c.io.tl_h_i(1).a_size.poke(2.U) 109 | c.io.tl_h_i(1).a_source.poke(0.U) 110 | c.io.tl_h_i(1).a_address.poke(0.U) 111 | c.io.tl_h_i(1).a_mask.poke("b1111".U) 112 | c.io.tl_h_i(1).a_data.poke(10.U) 113 | 114 | // Host 3 sending a PutPartial 115 | c.io.tl_h_i(2).a_opcode.poke(TL_A_Opcode.putPartialData) 116 | c.io.tl_h_i(2).a_valid.poke(true.B) 117 | c.io.tl_h_i(2).a_param.poke(0.U) 118 | c.io.tl_h_i(2).a_size.poke(0.U) 119 | c.io.tl_h_i(2).a_source.poke(0.U) 120 | c.io.tl_h_i(2).a_address.poke(1.U) 121 | c.io.tl_h_i(2).a_mask.poke("b0001".U) 122 | c.io.tl_h_i(2).a_data.poke(2.U) 123 | 124 | c.io.tl_d_o.a_opcode.expect(TL_A_Opcode.putPartialData) 125 | c.io.tl_d_o.a_data.expect(2.U) 126 | }} 127 | } 128 | // Test Case: 5 (Hosts = 3) 129 | it should "Connect host(0) with the device when all three hosts are accessing the bus" in { 130 | test(new TLSocketM_1(3)) {c => { 131 | // Host 1 sending a GET 132 | c.io.tl_h_i(0).a_opcode.poke(TL_A_Opcode.get) 133 | c.io.tl_h_i(0).a_valid.poke(true.B) 134 | c.io.tl_h_i(0).a_param.poke(0.U) 135 | c.io.tl_h_i(0).a_size.poke(2.U) 136 | c.io.tl_h_i(0).a_source.poke(0.U) 137 | c.io.tl_h_i(0).a_address.poke(0.U) 138 | c.io.tl_h_i(0).a_mask.poke("b1111".U) 139 | c.io.tl_h_i(0).a_data.poke(0.U) 140 | 141 | // Host 2 sending a PUT 142 | c.io.tl_h_i(1).a_opcode.poke(TL_A_Opcode.putFullData) 143 | c.io.tl_h_i(1).a_valid.poke(true.B) 144 | c.io.tl_h_i(1).a_param.poke(0.U) 145 | c.io.tl_h_i(1).a_size.poke(2.U) 146 | c.io.tl_h_i(1).a_source.poke(0.U) 147 | c.io.tl_h_i(1).a_address.poke(0.U) 148 | c.io.tl_h_i(1).a_mask.poke("b1111".U) 149 | c.io.tl_h_i(1).a_data.poke(10.U) 150 | 151 | // Host 3 sending a PutPartial 152 | c.io.tl_h_i(2).a_opcode.poke(TL_A_Opcode.putPartialData) 153 | c.io.tl_h_i(2).a_valid.poke(true.B) 154 | c.io.tl_h_i(2).a_param.poke(0.U) 155 | c.io.tl_h_i(2).a_size.poke(0.U) 156 | c.io.tl_h_i(2).a_source.poke(0.U) 157 | c.io.tl_h_i(2).a_address.poke(1.U) 158 | c.io.tl_h_i(2).a_mask.poke("b0001".U) 159 | c.io.tl_h_i(2).a_data.poke(2.U) 160 | 161 | c.io.tl_d_o.a_opcode.expect(TL_A_Opcode.get) 162 | c.io.tl_d_o.a_data.expect(0.U) 163 | }} 164 | } 165 | 166 | // Test Case: 6 (Hosts = 3) 167 | it should "Connect host(1) with the device when host(0) does not access bus but host(2) is accessing the bus" in { 168 | test(new TLSocketM_1(3)) {c => { 169 | // Host 1 sending a GET 170 | c.io.tl_h_i(0).a_opcode.poke(TL_A_Opcode.get) 171 | c.io.tl_h_i(0).a_valid.poke(false.B) 172 | c.io.tl_h_i(0).a_param.poke(0.U) 173 | c.io.tl_h_i(0).a_size.poke(2.U) 174 | c.io.tl_h_i(0).a_source.poke(0.U) 175 | c.io.tl_h_i(0).a_address.poke(0.U) 176 | c.io.tl_h_i(0).a_mask.poke("b1111".U) 177 | c.io.tl_h_i(0).a_data.poke(0.U) 178 | 179 | // Host 2 sending a PUT 180 | c.io.tl_h_i(1).a_opcode.poke(TL_A_Opcode.putFullData) 181 | c.io.tl_h_i(1).a_valid.poke(true.B) 182 | c.io.tl_h_i(1).a_param.poke(0.U) 183 | c.io.tl_h_i(1).a_size.poke(2.U) 184 | c.io.tl_h_i(1).a_source.poke(0.U) 185 | c.io.tl_h_i(1).a_address.poke(0.U) 186 | c.io.tl_h_i(1).a_mask.poke("b1111".U) 187 | c.io.tl_h_i(1).a_data.poke(10.U) 188 | 189 | // Host 3 sending a PutPartial 190 | c.io.tl_h_i(2).a_opcode.poke(TL_A_Opcode.putPartialData) 191 | c.io.tl_h_i(2).a_valid.poke(true.B) 192 | c.io.tl_h_i(2).a_param.poke(0.U) 193 | c.io.tl_h_i(2).a_size.poke(0.U) 194 | c.io.tl_h_i(2).a_source.poke(0.U) 195 | c.io.tl_h_i(2).a_address.poke(1.U) 196 | c.io.tl_h_i(2).a_mask.poke("b0001".U) 197 | c.io.tl_h_i(2).a_data.poke(2.U) 198 | 199 | c.io.tl_d_o.a_opcode.expect(TL_A_Opcode.putFullData) 200 | c.io.tl_d_o.a_data.expect(10.U) 201 | }} 202 | } 203 | } 204 | --------------------------------------------------------------------------------