版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1.新型敏捷硬件开发语言——Chisel和Scala
全套可编辑PPT课件
一、什么是Scala二、什么是Chisel三、Scala安装与运行四、总结目
录2一、什么是Scala3
什么是Scala1.1Scala与Java运行环境:Scala是一门基于JVM运行的语言。语法特性:
直接访问java字段,调用java方法等。实用性:比java更简洁,语法功能也更强大。4什么是Scala1.2Scala特点面向对象,函数式编程:
函数式编程(functional):what,how。
命令式编程(Imperative):how,what。强大伸缩性:
自定义Scala类库,快速开发出“新”语言。Chisel就是以Scala为宿主语言构建的。5二、什么是Chisel6什么是Chisel2.1Verilog发展出现:
1983年由GDA公司的PhilMoorby首创。突破:
PhilMoorby提出了用于快速门级仿真的XL算法。快速发展:
1989年,Cadence公司收购GDA公司,随后对VerilogHDL进行了公开。标准化:
1995年,
VerilogHDL的IEEE标准诞生。7什么是Chisel
Chisel全称:
ConstructingHardwareinScalaEmbeddedLanguage开发团队:
加州大学伯克利分校团队开发的新型硬件描述语言。特性:
操作符即方法,纯粹的面向对象等。不包含Verilog的不可综合语法。效果:
极大地提高硬件开发的效率。转换形式:
2.2Chisel由来Chisel文件firrtl文件Verilog文件8三、Scala安装9Scala安装3.1ubuntu下安装查看系统Java版本:下载对应安装包并安装:Scala版本应该与Java版本一致Linux系统应选择deb或者rpm文件10xjtu-chisel@ubuntu:~$java-version
openjdkversion"11.0.11"2021-04-20Scala安装使用Scala解释器:退出Scala解释器:
3.1ubuntu下安装11xjtu_chisel@ubuntu:~$scala
WelcometoScala2.11.12(OpenJDK64-BitServerVM,Java11.0.11).
Typeinexpressionsforevaluation.ortry:help.
scala>1+2
valres0:Int=3
scala>println("Hello,world!")
Hello,world!scala>:q
xjtu_chisel@ubuntu:~$键入:q或者:quit可退出Scala解释器Scala安装3.1ubuntu下安装运行脚本文件:编译非脚本文件://hello.scala
println("Hello,world!")classHello{
valhw="Hello,world!"
defdisplay()=println(hw)
}使用scala命令使用scalac或者fsc命令12Scala安装3.2IDEA工具开发下载安装软件并配置好开发环境:JDK版本选择1.813Scala安装3.2IDEA工具开发运行调试:objecttest{
defmain(args:Array[String]):Unit={
vara=0;
for(a<-1until6){
println("Valueofa:"+a);
}
}
}Valueofa:1Valueofa:2Valueofa:3Valueofa:4Valueofa:5控制台输出14四、总结15总结16
本章主要介绍了Scala与Chisel的背景以及开发环境安装。
在开发环境安装这一块,可以使用命令行的形式直接运行Scala脚本文件和编译非脚本文件,也可以使用集成开发环境IDEA,本书推荐使用IDEA进行Scala开发。参考资料基础知识
在学习Chisel前,初学者应该掌握一定的面向对象的思想。建议初学者先学习第二篇的Scala部分。参考资料1Chisel3官网/2Chisel3开源github网址/chipsalliance/chisel33伯克利Chisel开源项目chisel-tutorial、chiseltest、chipyard等/ucb-bar4课题组维护的博客/qq_34291505/article/details/86744581?utm_source=app5chisel-template网址/freechipsproject/chisel-template6Chisel官方bootcamp/v2/gh/freechipsproject/chisel-bootcamp/master7RocketChip网址/chipsalliance/rocket-chip8chipyard文档https://chipyard.readthedocs.io/17谢谢大家2.Chisel入门及数据类型
一、Chisel开发环境安装二、Chisel的常见问题三、Chisel的变量与数据类型四、总结目
录20一、Chisel开发环境安装21Chisel开发环境安装1.1安装步骤安装SBT:安装Git:
Scala的构建工具方便后续项目开发xjtu-chisel@ubuntu:~$sbtsbtVersion
[info]welcometosbt1.4.6(PrivateBuildJava1.8.0_275)
[info]loadingprojectdefinitionfrom/home/xjtu-chisel/project
[info]setcurrentprojecttoxjtu-chisel(inbuildfile:/home/xjtu-chisel/)
[info]1.4.6xjtu-chisel@ubuntu:~$sudoapt-getinstallgit
xjtu-chisel@ubuntu:~$git–version
gitversion2.25.122Chisel开发环境安装1.1安装步骤安装Verilator:安装g++:
开源高性能VerilogHDL仿真器C++编译器,Verilator会用到xjtu-chisel@ubuntu:~$sudoapt-getinstallverilator
xjtu-chisel@ubuntu:~$verilator-version
Verilator4.0282020-02-06revv4.026-92-g890cecc1xjtu-chisel@ubuntu:~$sudoapt-getinstallg++
xjtu-chisel@ubuntu:~$g++-v
gccversion7.5.0(Ubuntu7.5.0-3ubuntu1~18.04)23Chisel开发环境安装1.1安装步骤安装GTKWave:安装Chisel:
波形查看器从github上克隆chisel-template,其自带了Chisel3.4.3,后续项目都是基于这个工程开发xjtu-chisel@ubuntu:~$sudoapt-getinstallgtkwavexjtu-chisel@ubuntu:~$gitclonehttps:///freechipsproject/chisel-template24Chisel开发环境安装1.2工程文件目录Chisel的设计部分文件测试文件和生成电路的主函数自定义工程文件与Chisel互动的外部文件25Chisel开发环境安装1.2环境测试主工程文件:
packagetest
importchisel3._
classANDextendsRawModule{
valio=IO(newBundle{
vala=Input(UInt(1.W))
valb=Input(UInt(1.W))
valc=Output(UInt(1.W))
})
io.c:=io.a&io.b}端口定义二输入与门逻辑26Chisel开发环境安装1.2环境测试生成电路的主函数:
//ANDtest.scala
packagetest
importchisel3.stage.ChiselGeneratorAnnotation
objecttestMainextendsApp{
(newchisel3.stage.ChiselStage).execute(Array("--target-dir","generated/and"),Seq(ChiselGeneratorAnnotation(()=>newAND)))
}27Chisel实现简单电路1.2环境测试moduleAND(
inputio_a,
inputio_b,
outputio_c
);
assignio_c=io_a&io_b;//@[and.scala11:16]
endmodule生成Verilog文件:对于大规模电路,用生成的Verilog文件在专业EDA工具里仿真。28二、Chisel常见问题29Chisel常见问题2.1常见问题寄宿在Scala里面。转变成Verilog时不会采用不可综合语法。只支持0,1逻辑。自动检测未被驱动的输出型线网或端口。代码包不会被隐式导入。Chisel仍在更新中。30三、Chisel的变量与数据类型31Chisel的变量与数据类型3.1数据类型长方形是trait,三角形是object,椭圆形是class。32Chisel的变量与数据类型3.2数据字面量构造UInt对象:1.U//字面值为“1”的UInt对象0xd.U//字面值为“14”的UInt对象构造SInt对象:-8.S//字面值为“-8”的SInt对象构造Bool对象:true.B//字面值为“true”的Bool对象构造UInt,SInt对象,其实调用了fromtIntToLiteral(1).U的方法,Bool则是fromBooleanToLiteral33Chisel的变量与数据类型3.3数据宽度默认情况,数据宽度按字面值取最小:1.U字面值为“1”、宽度为1bit的UInt对象构造指定宽度的对象:1.U(32.W)字面值为“1”、宽度为32bit的UInt对象-8.S(32.W)字面值为“-8”、宽度为32bit的SInt对象取数据的某一位:1.U(31)字面值为“0”、宽度为1bit的UInt对象1.U(0)字面值为“1”、宽度为1bit的UInt对象34Chisel的变量与数据类型3.4类型转换类型转换包括asUInt、asSInt、asBool和asBools:"ha".asUInt(8.W)-1.S(3.W).asUInt、辅助完成子字赋值:
classTestModuleextendsModule{
valio=IO(newBundle{
valin=Input(UInt(10.W))
valbit=Output(Bool())
valout=Output(UInt(10.W))
})
valbools=VecInit(io.in.asBools)
bools(0):=io.bit
io.out:=bools.asUInt}35Chisel的变量与数据类型3.5向量定义:参数:
第一个参数:元素的个数
第二个参数:元素的类型与位宽提取向量中某个元素:
valmyVec=Wire(Vec(3,UInt(32.W)))valmyReg_0=myVec(0)
valmyReg_1=myVec(1.U)36Chisel的变量与数据类型3.5向量高级用法一
37Chisel的变量与数据类型3.5向量38Chisel的变量与数据类型3.5向量高级用法二
39Chisel的变量与数据类型3.5向量40Chisel的变量与数据类型3.5包裹构建端口列表可以包含向量classMyModuleextendsModule{
valio=IO(newBundle{
valin=Input(UInt(32.W))
valout=Output(UInt(32.W))
})classMyBundleextendsBundle{
valfoo=UInt(4.W)
valbar=Vec(2,UInt(4.W))
}41Chisel的变量与数据类型3.5包裹字段拼接classMyBundleextendsBundle{
valfoo=UInt(4.W)//高位
valbar=UInt(4.W)//低位
}
valbundle=Wire(newMyBundle)
bundle.foo:=0xc.U
bundle.bar:=0x3.U
valuint=bundle.asUInt//12*16+3=195wire[7:0]uint;
reg[3:0]foo=4’hc;reg
[3:0]bar=4’h3;
assignuint={
foo,
bar};//把foo和bar拼接成uint。42Chisel的变量与数据类型3.5包裹完成拼接变量的赋值wire[1:0]a;
wire[3:0]b;
wire[2:0]c;
wire[8:0]z=[...];
assign{a,b,c}=z;classMyBundleextendsBundle{
vala=UInt(2.W)
valb=UInt(4.W)
valc=UInt(3.W)
}
valz=Wire(UInt(9.W))
z:=...
valunpacked=z.asTypeOf(newMyBundle)
unpacked.a
unpacked.b
unpacked.c43Chisel的变量与数据类型3.5内建操作符Chisel的内建操作符操作符释义位操作符作用类型:
SInt,UInt,BoolvalinvertedX=~x位取反valhiBits=x&"h_ffff_0000".U位与valflagsOut=flagsIn|overflow位或valflagsOut=flagsIn^toggle位异或缩减位操作符作用类型:
SInt,UInt
返回类型:BoolvalallSet=x.andR缩减与valanySet=x.orR缩减或44Chisel的变量与数据类型3.6位宽推断Chisel的位宽推断操作符位宽z=x+y
or
z=x+%yw(z)=max(w(x),w(y))z=x+&yw(z)=max(w(x),w(y))+1z=x-y
or
z=x-%yw(z)=max(w(x),w(y))z=x-&yw(z)=max(w(x),w(y))+1z=x&yw(z)=min(w(x),w(y))z=Mux(c,x,y)w(z)=max(w(x),w(y))z=w*yw(z)=w(x)+w(y)z=x<<nw(z)=w(x)+maxNum(n)45四、总结46总结
本章主要是Chisel开发环境的安装以及Chisel的变量和数据类型的介绍。
对于Chisel开发环境安装部分,要能够搭建起开发环境并实现由Chisel生成Verilog的流程。此外本章还应掌握数据字面量,数据位宽定义,包裹,向量等基本数据类型及其常见用法。47谢谢大家
3.模块与硬件类型一、硬件类型二、赋值三、端口四、模块五、线网六、寄存器(组)七、补充与总结50目
录一、硬件类型51
硬件类型
Chisel的数据类型是无法独立工作的,实际的电路应该是由硬件类型的对象构成的硬件类型完成:信号的声明、用赋值进行信号传递valx=Wire(UInt(4.W))数据类型对象作为参数定义:位宽是多少、按无符号数还是有符号数解释、是不是向量valx=Wire(UInt(4.W))52二、赋值53赋值首次创建变量时用赋值运算符“=”初始化valx=Wire(UInt(4.W))
valy=Wire(UInt(4.W))
x:="b1010".U
//向4bit的线网x赋予了无符号数10
y:=~x
//把x按位取反,传递给y
驱动该端口时,就需要通过变量名来进行赋值操作,使用方法“:=”作为赋值运算符“=”的代替“:=”优先级与“=”一致,是最低的54三、端口55端口3.1定义端口列表端口列表是由方法“IO[T<:Data](iodef:T)”定义参数通常是一个Bundle类型的对象而且引用的字段名称必须是“io”(继承自Module的模块)56端口通过“io.xxx”来使用端口从性质上来说它仍然属于组合逻辑的线网3.2端口方向classMyIOextendsBundle{
valin=Input(Vec(5,UInt(32.W)))
valout=Output(UInt(32.W))
}
classMyModuleextendsModule{
valio=IO(newMyIO)
//模块的端口列表
......
}端口存在方向,需要方法“Input[T<:Data](source:T)”和“Output[T<:Data](source:T)”来为每个端口表明具体方向57端口3.3翻转端口列表的方向使用情况:
对于两个相连的模块,可能存在大量同名但方向相反的端口方法:Flipped[T<:Data](source:T)实现细节
其把参数里所有的输入端口转为输出端口,输出端口转为输入端口
58端口classMyIOextendsBundle{
valin=Input(Vec(5,UInt(32.W)))
valout=Output(UInt(32.W))
}
classMyModule_1extendsModule{
valio=IO(newMyIO)
//in是输入,out是输出
......
}
classMyModule_2extendsModule{
valio=IO(Flipped(newMyIO))
//in是输出,out是输入
......
}59MyModule_1inoutMyModule_2inout端口3.4端口整体连接使用整体连接符号“<>”该操作符会把符号左右两边的端口列表里所有同名的端口进行连接
同一级的模块的端口方向必须是输入连输出、输出连输入;父级模块和子级模块的端口方向则是输入连输入、输出连输出不能存在端口名字、数量、类型不同的情况classMyIOextendsBundle{
valin=Input(Vec(5,UInt(32.W)))
valout=Output(UInt(32.W))
}
classMyModuleextendsModule{
valio=IO(newBundle{
valx=newMyIO
valy=Flipped(newMyIO)
})
io.x<>io.y
//相当于io.y.in:=io.x.in;
//io.x.out:=io.y.out
}60四、模块614.1模块的分类Module/LegacyModuleChisel的模块分为三类,继承关系如下(箭头指向父类)MultiIOModuleRawModule必须实现抽象成员io有隐式时钟(称为clock)和隐式复位(称为reset)123模块根据需要定义IO无抽象成员io不提供隐式时钟和复位根据需要定义IO无抽象成员io有隐式时钟和复位624.2定义模块模块继承自Module类包含一个用于接口的抽象字段“io”在类的主构造器里进行内部电路连线//mux2.scala
packagetest
importchisel3._
classMux2extendsModule{
valio=IO(newBundle{
valsel=Input(UInt(1.W))
valin0=Input(UInt(1.W))
valin1=Input(UInt(1.W))
valout=Output(UInt(1.W))
})
io.out:=(io.sel&io.in1)|(~io.sel&io.in0)
}“newBundle{...}”是声明一个继承自Bundle的匿名类,然后实例化该匿名类。定义一个二选一多路选择器:63模块4.3例化模块//mux4.scala
packagetest
importchisel3._
classMux4extendsModule{
valio=IO(newBundle{
valin0=Input(UInt(1.W))
valin1=Input(UInt(1.W))
valin2=Input(UInt(1.W))
valin3=Input(UInt(1.W))
valsel=Input(UInt(2.W))
valout=Output(UInt(1.W))
})
valm0=Module(newMux2)
m0.io.sel:=io.sel(0)
m0.io.in0:=io.in0
m0.io.in1:=io.in1
valm1=Module(newMux2)
m1.io.sel:=io.sel(0)
m1.io.in0:=io.in2
m1.io.in1:=io.in3
valm2=Module(newMux2)
m2.io.sel:=io.sel(1)
m2.io.in0:=m0.io.out
m2.io.in1:=m1.io.out
io.out:=m2.io.out
}例化一个模块,要把实例对象传递给单例对象Module的apply方法通过例化刚才的双输入多路选择器构建四输入多路选择器:64模块4.4例化多个模块对于要多次例化的重复模块,可以利用向量的工厂方法VecInit[T<:Data]通常使用待例化模块的io字段组成的序列作为参数://mux4_2.scala
packagetest
importchisel3._
classMux4_2extendsModule{
valio=IO(newBundle{
valin0=Input(UInt(1.W))
valin1=Input(UInt(1.W))
valin2=Input(UInt(1.W))
valin3=Input(UInt(1.W))
valsel=Input(UInt(2.W))
valout=Output(UInt(1.W))
})65模块生成序列的方法:
调用单例对象Seq里的方法fill,该方法的一个重载版本有两个单参数列表,第一个参数接收Int类型的对象,表示序列的元素个数,第二个是传名参数,接收序列的元素。
valm=VecInit(Seq.fill(3)(Module(newMux2).io))
//例化了三个Mux2,并且参数是端口字段io
m(0).sel:=io.sel(0)//模块的端口通过下标索引,并且路径里没有“io”
m(0).in0:=io.in0
m(0).in1:=io.in1
m(1).sel:=io.sel(0)
m(1).in0:=io.in2
m(1).in1:=io.in3
m(2).sel:=io.sel(1)
m(2).in0:=m(0).out
m(2).in1:=m(1).out
io.out:=m(2).out
}66五、线网67线网classMyModuleextendsModule{
valio=IO(newBundle{
valin=Input(UInt(8.W))
})
valmyNode=Wire(UInt(8.W))
myNode:=0.U;//无效
myNode:=io.in+1.U;
}通过工厂方法“Wire[T<:Data](t:T)”来定义线网可以对线网进行赋值,也可以把线网连接到其他电路节点,线网是组成组合逻辑的基本硬件类型。定义具有覆盖性,对同一个线网多次赋值,则只有最后一次赋值是有效的5.1Wire68Wire不提供位宽参数将启用自动推断。官方源代码注释:valw0=Wire(UInt())//widthisinferred
valw1=Wire(UInt(8.W))//widthissetto8
valw2=Wire(Vec(4,UInt()))//widthisinferred
valw3=Wire(Vec(4,UInt(8.W)))//widthofeachelementissetto8
classMyBundle{
valunknown=UInt()
valknown=UInt(8.W)
}
valw4=Wire(newMyBundle)
//Widthofw4.unknownisinferred
//Widthofw4.knownissetto869WireDefault例1:Non-LiteralElementinitializer-widthwillbeinferred对于non-literalchisel3.Bits,导线的宽度将被推断。WireDefault用于构建具有默认连接的硬件线路有单参数和多参数两种形式。
单参数使用参数来指定类型和默认连接:valx=Wire(UInt())
valy=Wire(UInt(8.W))
valw1=WireDefault(x)//widthwillbeinferred
valw2=WireDefault(y)//widthwillbeinferred5.2WireDefault70WireDefault例3:Aggregateinitializer:widthwillbesettomatchtheaggregate例2:Literalchisel3.Bitsinitializer:widthwillbesettomatch对于literalchisel3.Bits和所有非Bits参数,类型将从参数复制。valw1=WireDefault(1.U)//widthwillbeinferredtobe1
valw2=WireDefault(1.U(8.W))//widthissetto8classMyBundle{
valunknown=UInt()
valknown=UInt(8.W)
}
valw1=Wire(newMyBundle)
valw2=WireDefault(w1)
//Widthofw2.unknownisinferred
//Widthofw2.knownissetto871WireDefault带有两个参数的WireDefault的宽度推断语义与Wire的相匹配。WireDefault的第一个参数是类型模板,它定义了Wire的宽度,其方式与Wire的参数完全相同。其定义类似于:
双参数形式允许独立指定Wire的类型和默认连接。defWireDefault[T<:Data](t:T,init:T):T={
valx=Wire(t)
x:=init
x
}vala=Wire(UInt(8.W))
valb=WireDefault(UInt(10.W),a)wire[7:0]a;
wire[9:0]b={{2'd0},a};72六、寄存器(组)73寄存器6.1RegChisel有五种内建的寄存器,Reg、RegNext、RegInit、util包里的RegEnable和ShiftRegister普通的寄存器“Reg[T<:Data](t:T):T”可以在when语句里用全局reset信号进行同步复位(asBool),也可以进行条件赋值或无条件跟随入参必须是数据类型的对象74寄存器和Wire的构造方式非常类似valr0=Reg(UInt())//widthisinferred
valr1=Reg(UInt(8.W))
//widthissetto8
valr2=Reg(Vec(4,UInt()))
//widthisinferred
valr3=Reg(Vec(4,UInt(8.W)))
//widthofeachelementissetto8
classMyBundle{
valunknown=UInt()
valknown=UInt(8.W)
}
valr4=Reg(newMyBundle)
//Widthofr4.unknownisinferred
//Widthofr4.knownissetto875寄存器6.2RegNextvalfoo=Reg(UInt(4.W))//widthis4
valbar=RegNext(foo)//widthisunset
valfoo=Reg(UInt(4.W))//widthis4
valbar=Reg(chiselTypeOf(foo))
//widthis4
bar:=foo
classMyBundleextendsBundle{
valx=UInt(4.W)
}
valfoo=Wire(newMyBundle)
//thewidthoffoo.xis4
valbar=RegNext(foo)
//thewidthofbar.xis4“RegNext[T<:Data](next:T)”,没有复位信号另一个版本的apply工厂方法是“RegNext[T<:Data](next:T,init:T)”,是由复位信号控制RegNext经常用于构造延迟一个周期的信号。76寄存器例1:Non-LiteralElementinitializer-widthwillbeinferred对于non-literalchisel3.Bits、Reg的宽度将被推断6.3RegInit
复位到指定值的寄存器RegInit,也有两种构造方式:“RegInit[T<:Data](init:T)”“RegInit[T<:Data](t:T,init:T)”
单参数形式使用参数来指定类型和重置值valx=Wire(UInt())
valy=Wire(UInt(8.W))
valr1=RegInit(x)//widthwillbeinferred
valr2=RegInit(y)//widthwillbeinferred77寄存器例3:Aggregateinitializer:widthwillbesettomatchtheaggregate例2:Literalchisel3.Bitsinitializer:widthwillbesettomatch对于literalchisel3.Bits和所有非Bits参数,类型将从参数复制。valr1=RegInit(1.U)//widthwillbeinferredtobe1
valr2=RegInit(1.U(8.W))//widthissetto8classMyBundleextendsBundle{
valunknown=UInt()
valknown=UInt(8.W)
}
valw1=Reg(newMyBundle)
valw2=RegInit(w1)
//Widthofw2.unknownisinferred
//Widthofw2.knownissetto878寄存器带有两个参数的RegInit的宽度推断语义与Reg的宽度推断语义相匹配。RegInit的第一个参数是类型模板,它定义Reg的宽度的方式与Wire的完全相同。其定义类似于:defRegInit[T<:Data](t:T,init:T):T={
valx=Reg(t)
x:=init
x
}
双参数形式允许独立指定Reg的类型和默认连接。79第一个apply方法,不进行复位初始化。例:寄存器6.4RegEnableobjectRegEnable{
defapply[T<:Data]
(next:T,enable:Bool):T=
{
valr=Reg(chiselTypeOf(next))
when(enable){r:=next}
r
}
defapply[T<:Data]
(next:T,init:T,enable:Bool):T=
{
valr=RegInit(init)
when(enable){r:=next}
r
}
}valregWithEnableAndReset=RegEnable(nextVal,ena)valregWithEnableAndReset=RegEnable(nextVal,0.U,ena)第二个apply方法,进行复位初始化。例:80寄存器6.5ShiftRegister“ShiftRegister[T<:Data](in:T,n:Int,resetData:T,en:Bool)”第一个参数in是待移位的数据,第二个参数n是需要延迟的周期数,第三个参数resetData是指定的复位值,可以省略,第四个参数en是移位的使能信号,默认为true.B,也是通过两个apply方法实现的valregDelayTwo=ShiftRegister(nextVal,2,ena)valregDelayTwoReset=ShiftRegister(nextVal,2,0.U,ena)81寄存器使用withClockAndReset来构造异步时钟和异步复位信号,也可以用withClock和withReset单独控制异步时钟或异步复位信号classasyncRegextendsModule{
valio=IO(newBundle{
valasyncClk=Input(UInt(1.W))
valasyncRst=Input(UInt(1.W))
valout=Output(UInt(8.W))
})
valasyncRegInit=withClockAndReset(io.asyncClk.asBool().asClock(),
io.asyncRst.asBool().asAsyncReset())(RegInit(0.U(8.W)))
asyncRegInit:=asyncRegInit+1.U
io.out:=asyncRegInit
}6.6异步寄存器82寄存器如果把子类型Vec[T]作为参数传递进去,就会生成多个位宽相同、行为相同、名字前缀相同的寄存器。同样,寄存器组在Chisel代码里可以通过下标索引。
valreg0=RegNext(VecInit(io.a,io.a))
valreg1=RegNext(VecInit(io.a,io.a),VecInit(0.U,0.U))
valreg2=RegInit(VecInit(0.U(8.W),0.U(8.W)))
valreg3=Reg(Vec(2,UInt(8.W)))
valreg4=Reg(Vec(2,UInt(8.W)))
valreg5=RegEnable(VecInit(io.a+1.U,io.a+1.U),VecInit(0.U(8.W),0.U(8.W)),io.en)
valreg6=RegEnable(VecInit(io.a-1.U,io.a-1.U),io.en)6.7寄存器组83寄存器valreg7=ShiftRegister(VecInit(io.a,io.a),3,VecInit(0.U(8.W),0.U(8.W)),io.en)
valreg8=ShiftRegister(VecInit(io.a,io.a),3,io.en)
reg2(0):=io.a.andR
reg2(1):=io.a.andR
reg3(0):=io.a.orR
reg3(1):=io.a.orR
when(reset.asBool){
reg4(0):=0.U
reg4(1):=0.U
}.otherwise{
reg4(0):=1.U
reg4(1):=1.U
}84七、补充与总结85补充与总结7.1when条件赋值由于Scala已经占用了“if…elseif…else”语法,所以相应的Chisel控制结构改成了when语句,其语法如下:所有的判断条件都是返回Bool类型的传名参数,不要和Scala的Boolean类型混淆,也不存在Boolean和Bool之间的相互转换。对于UInt、SInt和Reset类型,可以用方法asBool转换成Bool类型来作为判断条件。when(condition1){definition1}
.elsewhen(condition2){definition2}
...
.elsewhen(conditionN){definitionN}
.otherwise{defaultbehavior}86补充与总结//mux2_when.scala
packagetest
importchisel3._
classMux2extendsModule{
valio=IO(newBundle{
valsel=Input(UInt(1.W))
valin0=Input(UInt(1.W))
valin1=Input(UInt(1.W))
valout=Output(UInt(1.W))
})
when(io.sel===1.U){
io.out:=io.in1
}.otherwise{
io.out:=io.in0
}
}通常,when用于给带使能信号的寄存器更新数据,组合逻辑不常用。对于有复位信号的寄存器,推荐使用RegInit来声明用when实现一个二选一多路选择器:87unlessimportchisel3.util._
unless(condition){definition}除了when结构,util包里还有一个与之对偶的结构“unless”,如果unless的判定条件为false.B,则一直执行,否则不执行7.2unless88总结数据类型必须配合硬件类型才能使用,它不能独立存在,因为编译器只会把硬件类型生成对应的Verilog代码。这是因为方法Vec期望第二个参数是数据类型,这样它才能推断出返回的Vec[T]是数据类型。但实际的“io.a”是经过Input封装过的硬件类型,导致Vec[T]变成了硬件类型,所以发生了类型匹配错误。valreg0=RegNext(VecInit(io.a,io.a))//正确
valreg0=RegNext(Vec(2,io.a))//错误,报错如下
//[error]chisel3.core.Binding$ExpectedChiselTypeException:vectype'chisel3.core.UInt@6147b2fd'mustbeaChiseltype,nothardware
89总结Chisel提供了一个用户API——chiselTypeOf[T<:Data](target:T):T,其作用就是把硬件类型的“封皮”去掉,变成纯粹的数据类型。这次是RegNext出错了。RegNext需要根据入参来推断返回结果的类型,所以传入一个数据类型Vec[T]就引发了错误。VecInit专门接收硬件类型的参数来构造硬件向量,给VecInit传入数据类型反而会报错,尽管它的返回类型也是Vec[T]。
valreg0=RegNext(Vec(2,chiselTypeOf(io.a)))//依然错误,错误信息如下
//[error]chisel3.core.Binding$ExpectedHardwareException:regnext'Vec(chisel3.core.UInt@65b0972a,chisel3.core.UInt@25155aa4)'mustbehardware,notabareChiseltype.PerhapsyouforgottowrapitinWire(_)orIO(_)?90总结
寄存器组部分例子:valreg1=RegNext(VecInit(io.a,io.a),VecInit(0.U,0.U))
valreg2=RegInit(VecInit(0.U(8.W),0.U(8.W)))
valreg3=Reg(Vec(2,UInt(8.W)))
valreg5=RegEnable(VecInit(io.a+1.U,io.a+1.U),VecInit(0.U(8.W),0.U(8.W)),io.en)
valreg7=ShiftRegister(VecInit(io.a,io.a),3,VecInit(0.U(8.W),0.U(8.W)),io.en)甚至是带有字面量的数据类型,比如“0.U(8.W)”这样的对象,也被当作是硬件类型。另外,Reg(_)的参数是数据类型,不是硬件类型,所以示例代码中它的参数是Vec,而别的参数都是VecInit。91谢谢大家
4.Chisel常用的硬件原语一、多路选择器二、优先编码器三、仲裁器四、队列五、ROM六、RAM七、计数器八、线性反馈移位寄存器九、状态机94目
录一、多路选择器95多路选择器二输入多路选择器”Mux(sel,in1,in2)”sel是Bool类型;in1和in2的类型相同,都是Data的任意子类型。当sel为true.B时,返回in1,否则返回in2可内嵌Mux,构成n输入,例:
“Mux(c1,a,Mux(c2,b,Mux(...,default)))”1.1Mux96多路选择器1.2MuxCasen输入多路选择器”MuxCase(default,Array(c1->a,c2->b,...))”第一个参数是默认情况下返回的结果;第二个参数是一个数组,数组的元素是对偶“(成立条件,被选择的输入)”。97多路选择器MuxCase的变体,类似查找表“MuxLookup(idx,default,Array(0.U->a,1.U->b,...))”相当于把MuxCase的成立条件依次换成从0开始的索引值它的展开相当于:“MuxCase(default,Array((idx===0.U)->a,(idx===1.U)->b,...))”1.3MuxLookup98多路选择器1.4Mux1H独热码多路选择器如果零个或多个选择信号有效,则行为变为多个被选择数字之和Mux1H三种常用的定义形式(等价):valhotValue=Mux1H(io.selector,Seq(2.U,4.U,8.U,11.U))
valhotValue=Mux1H(Seq(io.selector(0),io.selector(1),
io.selector(2),io.selector(3)),Seq(2.U,4.U,8.U,11.U))
valhotValue=Mux1H(Seq(
io.selector(0)->2.U,
io.selector(1)->4.U,
io.selector(2)->8.U,
io.selector(3)->11.U
))io.selectorSeq(2.U,4.U,8.U,11.U)00012.U00104.U01008.U100011.U99多路选择器1.5PriorityMux当多个选择信号有效时,按照定义时的顺序,返回更靠前的被选数据。有以下三种定义形式(等价):valpriorityValue=PriorityMux(io.selector,Seq(2.U,4.U,8.U,11.U))
valpriorityValue=PriorityMux(Seq(io.selector(0),io.selector(1),
io.selector(2),io.selector(3)),
Seq(2.U,4.U,8.U,11.U))
valpriorityValue=PriorityMux(Seq(
io.selector(0)->2.U,
io.selector(1)->4.U,
io.selector(2)->8.U,
io.selector(3)->11.U,
))io.selectorSeq(2.U,4.U,8.U,11.U)xxx12.Uxx104.Ux1008.U100011.U100二、优先编码器101优先编码器2.1PriorityEncoderPriorityEncoder("b1010".U)
PriorityEncoder(Seq(false.B,true.B,false.B,true.B))作用是对多个输入信号中优先级最高的一个信号进行编码。有以下两种定义形式:以上两种形式是等价的,返回值类型都是UInt,值为1.U。入参:Bits返回值:UIntxxx10.Uxx101.Ux1002.U10003.U102优先编码器2.2PriorityEncoderOH有以下两种定义形式:PriorityEncoderOH("b1010".U)
PriorityEncoderOH(Seq(false.B,true.B,true.B,false.B))它和第一种编码器的区别在于该编码器会把编码结果转换成独热码。第一种形式返回一个UInt的数据2.U,第二种形式返回一个Seq:Seq(false.B,true.B,false.B,false.B)。入参:Bits返回值:Uintxxx10001xx100010x100010010001000103三、仲裁器104仲裁器3.1ready-valid接口Arbiter使用的是标准的ready-valid接口,该类型的端口在单一数据信号的基础上又添加了ready和valid信号以使用ready-valid握手协议。它包含3个信号:ready:高有效时表示数据接收者consumer已经准备好接收信号,由consumer驱动。valid:高有效时表示数据生产者producer已经准备好待发送的数据了,由producer驱动。bits:是要在producer与consumer之间传输的数据。105仲裁器使用单例对象Decoupled可创建ready-valid接口,有以下两种形式:
Decoupled(...):可以传入任意的数据类型,然后返回一个ready-valid接口,此时ready是input信号,valid和bits都是output信号。因此它是属于数据生产者producer的端口。
Flipped(Decoupled(...)):Flipped()会将ready-valid接口的信号方向进行取反,因此此时ready是output信号,valid和bits都是input信号。因此它是属于数据接收者consumer的端口。106仲裁器producerDecoupled(...)readyvalidbitsconsumerFlipped(Decoupled(...))readyvalidbits107仲裁器3.2优先仲裁器优先仲裁器的输入通道的优先级是固定的,每次都是选择多个有效通道中优先级最高的。创建Arbiter对象的方式为newArbiter(gen:T,n:Int)gen是传输的数据的类型,n是待仲裁对象的个数,也即数据发送者producer的个数。数据接收者consumer的个数为默认为1。108仲裁器Arbiter内部使用ArbiterIO定义端口,而ArbiterIO内部又使用Decoupled()创建最终所需的ready-valid接口,定义如下:classArbiterIO[T<:Data](privatevalgen:T,valn:Int)extendsBundle{
valin=Flipped(Vec(n,Decoupled(gen)))
valout=Decoupled(gen)
valchosen=Output(UInt(log2Ceil(n).W))
}”log2Ceil(n)”是实现的是以2为底的对数函数的计算,把结果向上取整返回109仲裁器producer0readyvalidbitsconsumerreadyvalidbitsArbiterin(0).validin(0).bitsin(0).readyin(1).validin(1).bitsin(1).readyout.bitsout.readyout.validchosenproducer1readyvalidbitschosen110仲裁器例:
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 部门内控自评报告
- KTV服务员培训内容ktv服务员培训方案
- 5个政治素质自查自评报告
- 违法责任追究制度3篇
- 搬运设备合同模板(3篇)
- 美容服务话术指南
- 幼儿园班级管理制度
- 采购订单管理工具简化订单流程提升效率
- 幼儿园集体活动安全管理制度
- 企业运营成本分析与节约方案参考
- 音乐疗法对焦虑缓解作用-洞察及研究
- 2023年广东省深圳市中考适应性数学试卷(原卷版)
- 建筑工程钢筋质量验收报告模板
- 《海南自由贸易港建设总体方案》解读
- 仓库安全管理台账模板
- GB/T 6730.46-2025铁矿石砷含量的测定蒸馏分离-砷钼蓝分光光度法
- 河南省省直辖县级行政区划济源市2024-2025学年八年级(上)期末物理试卷(含解析)
- 四川省医疗护理员考试题库及答案
- 食品现场品鉴活动方案
- 护理管理学课程教学大纲
- 2026届天津市和平区物理八上期末调研模拟试题含解析
评论
0/150
提交评论