jchdl Module类在概念上对应Verilog的module,作为所有用户自定义模块的父类。
所有用户创建的节点,必须继承Module类。Module为用户创建模块提供了很多支持方法,但把logic()方法留给子类自行定义。
如同Verilog一样,Module的logic()中,只包含Assign和Always这两种块的构建。
一. 类结构
主要属性
- parent: 父模块;
- children:子模块;
- blocks:包含的Assign和Always Block;
主要方法
- 构造方法
Module(Module parent): 声明本模块的父模块,并把本模块作为父模块的子模块。如此即可构建模块层次结构(hierarchy)。
用户自定义模块的构造方法,需要把parent参数作为第一个参数,并调用这个构造方法(参考下面实例)。
- 模块构建方法: construct()
当前实现比较简单,直接调用logic()方法;
- 模块内部逻辑构建方法:logic()
该方法为抽象方法,留给子类自行实现。即用户覆盖这个方法,实现自己的模块内部逻辑。
- 支持构建Assign Block的方法
assign(Bit): 对Bit赋值,返回一个Assign Block,方便后续使用。
assign(Bits): 对Bits赋值,返回一个Assign Block,方便后续使用。
示例:
assign(bitA).from(bitB, bitC...).with(() -> bitA.assign(bitB.and(bitC)))
即Verilog的:assign bitA = bitB & bitC;
- 支持构建Always Block的方法
when(Event...): 返回一个依赖于参数里的事件的Always Block,方便后续使用。即如果发生参数里的事件,则执行Always Block中的runnable。
示例:
always(PosEdgeEvent.of(clk)).run(() -> regA.set(regB))
即Verilog的:
always @(posedge clk)
regA <= regB;
- 转换为Verilog的方法:toVerilog()
把Module转换为Verilog的RTL实现。
二. 用户自定义逻辑
- 添加构造方法
构造方法第一个参数为父模块的对象,如果本身为顶层模块,则实例化时可以传入null;
构造方法后续的参数,是与模块的输入和输出对接的线或寄存器;
最后调用construct()方法,构造模块的子模块和blocks;
- 声明模块输入和输出
模块的输入和输出,是模块的一个组成部分,作为类的属性声明;
模块的输入和输出,使用@Input和@Output注解;位数可以使用@Width(8)注解。
- 声明内部使用的线和寄存器
模块内部使用的线和寄存器,也是模块的一个组成部分,作为类的属性声明:
- 实现logic()方法
在logic()方法内部构建模块内部的子模块和逻辑块:
三. 实例Mux
- 构造方法
- 输入和输出
Bit全部为1位;
- 其他内部线和寄存器
Mux没有。
- 自定义逻辑
这也是一种lambda写法。
assign(out)意为要对out赋值,返回一个对out赋值的Assign Block;
.from(a, b, sel)意为赋值时需要使用a, b, sel。即如果a, b, sel的值发生变化,则会对out进行赋值;
.with(): 提供对out赋值的方法,即如果值变化事件发生,则使用this::assign0方法对out进行赋值;
assign0()方法,根据sel的值把a或者b赋值给out。
- 创建Mux模块
- 验证
结果:
- 转换为Verilog