├── 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 
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 |
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 |
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 |
--------------------------------------------------------------------------------