文章目錄
- 介紹
- Chisel的Valid和Ready流控
- build.sbt
- RRArbiter代碼示例
介紹
仲裁器在NoC路由器中是重要的組成部分,虛通道仲裁和交叉開關仲裁都需要使用仲裁器。
Chisel提供了Arbiter和RRArbiter仲裁器
Arbiter是基礎的低位優先仲裁器,
RRArbiter初始情況下也是低位優先仲裁,但在某個通道仲裁勝出后,該通道的優先級將置為最低。
舉例:
假設有3個通道,0 1 2,初始情況下0優先級最高,1其次,2最低,假設1和2同時請求資源,那么根據低位優先的原則,
通道1獲勝,然后優先級從高到低位0 2 1,然后0和2同時請求資源,那么通道0獲勝,優先級變為2 1 0
Chisel的Valid和Ready流控
Ready-Valid接口是一種簡單的控制流接口,包含:
- data:發送端向接收端發送的數據;
- valid:發送端到接收端的信號,用于指示發送端是否準備好發送數據;
- ready:接收端到發送端的信號,用于指示接收端是否準備好接收數據;
發送端在data準備好之后就會設置valid信號,接收端在準備好接收一個字的數據的時候就會設置ready信號。數據的傳輸會在兩個信號,valid信號和ready信號,都被設置時才會進行。如果兩個信號有任何一個沒被設置,那就不會進行數據傳輸。
更詳細的內容參考該博客
在對RRArbiter進行測試過程中,由于仲裁器是接收數據的設備,因此valid和data是輸入信號,ready是接收信號,需要對valid和data信號設置激勵,并查看輸出端獲勝的數據。
build.sbt
程序的build.sbt配置如下:
ThisBuild / scalaVersion := "2.13.8"
ThisBuild / version := "0.1.0"
ThisBuild / organization := "BATHTUB"val chiselVersion = "3.6.0"lazy val root = (project in file(".")).settings(name := "noc-router-main",libraryDependencies ++= Seq("edu.berkeley.cs" %% "chisel3" % chiselVersion,"edu.berkeley.cs" %% "chiseltest" % "0.6.0" % "test",//包含ChiselTest會自動包含對應版本的ScalaTest//導入scalatest的庫//"org.scalatest" %% "scalatest" % "3.1.4" % "test"),scalacOptions ++= Seq("-language:reflectiveCalls","-deprecation","-feature","-Xcheckinit","-P:chiselplugin:genBundleElements",),addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full),)
RRArbiter代碼示例
以下代碼可以直接運行,并給出了詳細注釋。
輸出結果:
//3個輸入的RRArbiter官方API測試
//依次測試001~111請求下的輸出數據
//初始情況下默認低位優先,在每次仲裁后,將仲裁勝利的通道置為優先級最低,進行下次仲裁
class OfficialRRArbTest extends AnyFreeSpec with ChiselScalatestTester{"OfficialRRArbiter should pass" in {test(new RRArbiter(UInt(8.W), 3)).withAnnotations(Seq(WriteVcdAnnotation)) { c =>//第一次測試 此時從高到低優先級為0 1 2 通道0發起請求c.io.in(0).valid.poke(true.B)c.io.in(1).valid.poke(false.B)c.io.in(2).valid.poke(false.B)//假設在全部測試中通道0的數據為0 通道1的數據為1 通道2的數據為2c.io.in(0).bits.poke(0)c.io.in(1).bits.poke(1)c.io.in(2).bits.poke(2)c.io.out.ready.poke(true.B)c.clock.step(2)//初始狀態下接收端已準備好接受in(0),in(1),in(2) 因此ready均為1//println(s"${c.io.in(0).ready.peek().litValue},${c.io.in(1).ready.peek().litValue},${c.io.in(2).ready.peek().litValue}")//通道0獲勝,輸出0println(s"1\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")//第二次測試 此時優先級從高到低為1 2 0 通道1發起請求c.io.in(0).valid.poke(false.B)c.io.in(1).valid.poke(true.B)c.io.in(2).valid.poke(false.B)c.clock.step(2)//通道1獲勝,輸出1println(s"2\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")//第三次測試 此時優先級從高到低為2 0 1 通道0和1發起請求c.io.in(0).valid.poke(true.B)c.io.in(1).valid.poke(true.B)c.io.in(2).valid.poke(false.B)c.clock.step(2)//通道0獲勝,輸出0println(s"3\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")//第四次測試 此時優先級從高到低為2 1 0 通道2發起請求c.io.in(0).valid.poke(false.B)c.io.in(1).valid.poke(false.B)c.io.in(2).valid.poke(true.B)c.clock.step(2)//通道2獲勝,輸出2println(s"4\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")//第五次測試 此時優先級從高到低為1 0 2 通道0和2發起請求c.io.in(0).valid.poke(true.B)c.io.in(1).valid.poke(false.B)c.io.in(2).valid.poke(true.B)c.clock.step(2)//通道0獲勝,輸出0println(s"5\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")//第六次測試 此時優先級從高到低為1 2 0 通道1和2發起請求c.io.in(0).valid.poke(false.B)c.io.in(1).valid.poke(true.B)c.io.in(2).valid.poke(true.B)c.clock.step(2)//通道1獲勝,輸出1println(s"6\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")//第七次測試 此時優先級從高到低為2 0 1 通道2、0、1發起請求c.io.in(0).valid.poke(true.B)c.io.in(1).valid.poke(true.B)c.io.in(2).valid.poke(true.B)c.clock.step(2)//通道2獲勝,輸出2println(s"7\t out.valid=${c.io.out.valid.peek().litValue}, out.bits=${c.io.out.bits.peek().litValue}\n")}}
}