chisel快速入门(三)
前一篇見此:
chisel快速入門(二)_滄海一升的博客-CSDN博客簡單介紹了chisel,使硬件開發(fā)者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121418806
十四、模塊的功能創(chuàng)建
????????制造用于模塊構(gòu)造的功能接口也是有用的。例如,我們可以構(gòu)建一個構(gòu)造函數(shù),它將多路復(fù)用器輸入作為參數(shù),并返回多路復(fù)用器輸出:
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模塊類中創(chuàng)建一個Scala單例對象,并且apply定義了創(chuàng)建Mux2實例的方法。有了這個Mux2創(chuàng)建功能,Mux4的規(guī)格現(xiàn)在明顯更簡單。
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 將其內(nèi)置并稱之為 Mux。 然而,與上面定義的 Mux2 不同,內(nèi)置版本允許 in0 和 in1 上的任何數(shù)據(jù)類型,只要它們有一個共同的超類。
????????Chisel提供MuxCase,其本質(zhì)上是一個n-way Mux。
MuxCase(default, Array(c1 -> a, c2 -> b, ...))十五、多態(tài)性和參數(shù)化
????????Scala是一種強類型語言,使用參數(shù)化類型來指定通用函數(shù)和類。 在本節(jié)中,我們展示了Chisel用戶如何使用參數(shù)化類來定義自己的可重用函數(shù)和類。
1、參數(shù)化函數(shù)
????????前面我們在Bool上定義了Mux2,但現(xiàn)在我們展示如何定義一個通用的多路復(fù)用器功能。我們使用一個布爾條件和con和alt參數(shù)(對應(yīng)于then和else表達(dá)式)來定義一個T類型的函數(shù):
def Mux[T <: Bits](c: Bool, con: T, alt: T): T { ... }????????其中T需要是Bits的子類。Scala確保在Mux的每個使用中,它可以找到實際的con和alt參數(shù)類型的公共超類,否則會導(dǎo)致Scala編譯類型錯誤。
2、參數(shù)化類
????????與參數(shù)化函數(shù)一樣,我們也可以參數(shù)化類,使它們可重用程度更高。例如,我們可以將Filter類概括為可以使用任何類型的鏈接。
????????我們可以通過參數(shù)化FilterIO類和定義構(gòu)造函數(shù)采取零參數(shù)類型構(gòu)造函數(shù)來做到這點,如下所示:
class FilterIO[T <: Data](type: T) extends Bundle { val x = type.asInput.flipval y = type.asOutput }????????我們現(xiàn)在可以通過定義一個模塊類來定義Filter,該模塊類也接收一個鏈接類型構(gòu)造函數(shù)參數(shù),并將其傳遞給FilterIO接口構(gòu)造器:
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、創(chuàng)建時鐘域
????????為了使用多個時鐘域,用戶必須創(chuàng)建多個時鐘。 在Chisel中,時鐘是使用復(fù)位信號參數(shù)創(chuàng)建的第一級節(jié)點,定義如下:
class Clock (reset: Bool) extends Node { def reset: Bool // returns reset pin }????????在Chisel中有一個內(nèi)置的隱式時鐘,狀態(tài)元素默認(rèn)使用:
var implicitClock = new Clock( implicitReset )????????狀態(tài)元素和模塊的時鐘可以使用名為clock的附加命名參數(shù)來定義:
Reg(... clock: Clock = implicitClock) Mem(... clock: Clock = implicitClock) Module(... clock: Clock = implicitClock)2、跨時鐘域
????????有兩種方式可以定義電路在時鐘域之間發(fā)送數(shù)據(jù)。第一種也是最原始的方式就是使用由兩個寄存器組成的同步器電路,如下所示:?
// 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????????由于亞穩(wěn)性問題,該技術(shù)只限于在域之間傳遞一位數(shù)據(jù)。
????????在域之間發(fā)送數(shù)據(jù)的第二種和更一般的方式是通過使用異步fifo:
class AsyncFifo[T<:Data](gen: T, entries: Int, enq_clk: Clock, deq_clock:Clock) extends Module????????當(dāng)通過指定標(biāo)準(zhǔn)fifo參數(shù)和兩個時鐘,然后使用標(biāo)準(zhǔn)解耦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 后端都需要用戶以后端特定的方式設(shè)置和控制多個時鐘。 為了展示如何驅(qū)動多時鐘設(shè)計,我們以具有兩個模塊的硬件為例進(jìn)行說明,該例子使用 AsyncFifo 與不同時鐘的每個模塊進(jìn)行通信:fastClock 和 slowClock。
????????在Verilog中:
- Chisel為每個時鐘/復(fù)位創(chuàng)建一個新端口,
- Chisel將所有的時鐘連到頂層模塊
- 用戶必須要為每個時鐘i創(chuàng)建一個always塊時鐘驅(qū)動
總結(jié)
以上是生活随笔為你收集整理的chisel快速入门(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gcc 4.9编译
- 下一篇: CMOS图像传感器——2021产品选谈