chisel快速入门(三)
前一篇見此:
chisel快速入門(二)_滄海一升的博客-CSDN博客簡單介紹了chisel,使硬件開發者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121418806
十四、模塊的功能創建
????????制造用于模塊構造的功能接口也是有用的。例如,我們可以構建一個構造函數,它將多路復用器輸入作為參數,并返回多路復用器輸出:
object Mux2 {def apply (sel: UInt, in0: UInt, in1: UInt) = {val m = new Mux2() m.io.in0 := in0 m.io.in1 := in1 m.io.sel := sel m.io.out} }????????其中對象Mux2在Mux2模塊類中創建一個Scala單例對象,并且apply定義了創建Mux2實例的方法。有了這個Mux2創建功能,Mux4的規格現在明顯更簡單。
class Mux4 extends Module { val io = new Bundle {val in0 = UInt(INPUT, 1)val in1 = UInt(INPUT, 1) val in2 = UInt(INPUT, 1) val in3 = UInt(INPUT, 1) val sel = UInt(INPUT, 2) val out = UInt(OUTPUT, 1)}io.out := Mux2(io.sel(1), Mux2(io.sel(0), io.in0, io.in1), Mux2(io.sel(0), io.in2, io.in3)) }????????選擇輸入非常有用,以至于 Chisel 將其內置并稱之為 Mux。 然而,與上面定義的 Mux2 不同,內置版本允許 in0 和 in1 上的任何數據類型,只要它們有一個共同的超類。
????????Chisel提供MuxCase,其本質上是一個n-way Mux。
MuxCase(default, Array(c1 -> a, c2 -> b, ...))十五、多態性和參數化
????????Scala是一種強類型語言,使用參數化類型來指定通用函數和類。 在本節中,我們展示了Chisel用戶如何使用參數化類來定義自己的可重用函數和類。
1、參數化函數
????????前面我們在Bool上定義了Mux2,但現在我們展示如何定義一個通用的多路復用器功能。我們使用一個布爾條件和con和alt參數(對應于then和else表達式)來定義一個T類型的函數:
def Mux[T <: Bits](c: Bool, con: T, alt: T): T { ... }????????其中T需要是Bits的子類。Scala確保在Mux的每個使用中,它可以找到實際的con和alt參數類型的公共超類,否則會導致Scala編譯類型錯誤。
2、參數化類
????????與參數化函數一樣,我們也可以參數化類,使它們可重用程度更高。例如,我們可以將Filter類概括為可以使用任何類型的鏈接。
????????我們可以通過參數化FilterIO類和定義構造函數采取零參數類型構造函數來做到這點,如下所示:
class FilterIO[T <: Data](type: T) extends Bundle { val x = type.asInput.flipval y = type.asOutput }????????我們現在可以通過定義一個模塊類來定義Filter,該模塊類也接收一個鏈接類型構造函數參數,并將其傳遞給FilterIO接口構造器:
class Filter[T <: Data](type: T) extends Module { val io = new FilterIO(type)... }? ? ? ? 另一個例子,通用FIFO可以這樣定義,并使用如下:
class DataBundle extends Bundle { val A = UInt(width = 32)val B = UInt(width = 32) } object FifoDemo {def apply () = new Fifo(new DataBundle, 32) }class Fifo[T <: Data] (type: T, n: Int) extends Module {val io = new Bundle {val enq_val = Bool(INPUT) val enq_rdy = Bool(OUTPUT) val deq_val = Bool(OUTPUT) val deq_rdy = Bool(INPUT) val enq_dat = type.asInput val deq_dat = type.asOutput}val enq_ptr = Reg(init = UInt(0, sizeof(n)))val deq_ptr = Reg(init = UInt(0, sizeof(n)))val is_full = Reg(init = Bool(false))val do_enq = io.enq_rdy && io.enq_valval do_deq = io.enq_rdy && io.deq_val val is_empty = !is_full && (enq_ptr === deq_ptr)val deq_ptr_inc = deq_ptr + UInt(1)val enq_ptr_inc = enq_ptr + UInt(1)val is_full_next = Mux(do_enq && ~do_deq && (enq_ptr_inc === deq_ptr), Bool(true), Mux(do_deq && is_full, Bool(false), is_full)) enq_ptr := Mux(do_enq, enq_ptr_inc, enq_ptr) deq_ptr := Mux(do_deq, deq_ptr_inc, deq_ptr) is_full := is_full_nextval ram = Mem(n) when (do_enq) {ram(enq_ptr) := io.enq_dat }io.enq_rdy := !is_full io.deq_val := !is_empty ram(deq_ptr) <> io.deq_dat }? ? ? ? 對FIFO定義通用解耦接口,可以簡化IO:
class DecoupledIO[T <: Data](data: T) extends Bundle {val ready = Bool(INPUT)val valid = Bool(OUTPUT)val bits = data.clone.asOutput }class DecoupledDemo extends DecoupledIO()( new DataBundle )class Fifo[T <: Data] (data: T, n: Int) extends Module {val io = new Bundle {val enq = new DecoupledIO( data ).flip() val deq = new DecoupledIO( data )}... }十六、多時鐘域
1、創建時鐘域
????????為了使用多個時鐘域,用戶必須創建多個時鐘。 在Chisel中,時鐘是使用復位信號參數創建的第一級節點,定義如下:
class Clock (reset: Bool) extends Node { def reset: Bool // returns reset pin }????????在Chisel中有一個內置的隱式時鐘,狀態元素默認使用:
var implicitClock = new Clock( implicitReset )????????狀態元素和模塊的時鐘可以使用名為clock的附加命名參數來定義:
Reg(... clock: Clock = implicitClock) Mem(... clock: Clock = implicitClock) Module(... clock: Clock = implicitClock)2、跨時鐘域
????????有兩種方式可以定義電路在時鐘域之間發送數據。第一種也是最原始的方式就是使用由兩個寄存器組成的同步器電路,如下所示:?
// signalA is in clock domain clockA, // want a version in clockB as signalB val s1 = Reg(init = UInt(0), clock = clockB) val s2 = Reg(init = UInt(0), clock = clockB) s1 := signalA s2 := s1; signalB := s2????????由于亞穩性問題,該技術只限于在域之間傳遞一位數據。
????????在域之間發送數據的第二種和更一般的方式是通過使用異步fifo:
class AsyncFifo[T<:Data](gen: T, entries: Int, enq_clk: Clock, deq_clock:Clock) extends Module????????當通過指定標準fifo參數和兩個時鐘,然后使用標準解耦ready/valid信號從時鐘域clockA到clockB獲取一個版本的signalA時:
val fifo = new AsyncFifo(Uint(width = 32), 2, clockA, clockB) fifo.io.enq.bits := signalA signalB := fifo.io.deq.bits fifo.io.enq.valid := condA fifo.io.deq.ready := condB3、后端多時鐘處理
????????每個 Chisel 后端都需要用戶以后端特定的方式設置和控制多個時鐘。 為了展示如何驅動多時鐘設計,我們以具有兩個模塊的硬件為例進行說明,該例子使用 AsyncFifo 與不同時鐘的每個模塊進行通信:fastClock 和 slowClock。
????????在Verilog中:
- Chisel為每個時鐘/復位創建一個新端口,
- Chisel將所有的時鐘連到頂層模塊
- 用戶必須要為每個時鐘i創建一個always塊時鐘驅動
總結
以上是生活随笔為你收集整理的chisel快速入门(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gcc 4.9编译
- 下一篇: CMOS图像传感器——2021产品选谈