DigitalJS
这是一个用JavaScript实现的数字电路模拟器项目。
它旨在模拟由硬件设计工具(如Yosys,GitHub仓库在这里)合成的电路,并有一个配套项目yosys2digitaljs,用于将Yosys的输出文件转换为DigitalJS格式。该项目也意在成为一个教学工具,因此可读性和易于检查是项目的首要考虑因素之一。
你可以在线试用。这个网页应用是一个单独的GitHub项目。
使用方法
你可以通过从NPM安装来在你的项目中使用DigitalJS:
npm install digitaljs
或者你可以直接使用Webpack打包文件。
要模拟使用JSON输入格式(稍后描述)表示的电路,并将其显示在名为#paper
的div
上,你需要运行以下JavaScript代码(查看运行示例):
// 创建模拟对象
const circuit = new digitaljs.Circuit(input_goes_here);
// 在#paper上显示
const paper = circuit.displayOn($('#paper'));
// 激活实时模拟
circuit.start();
输入格式
电路使用JSON表示。顶层对象有三个键:devices
、connectors
和subcircuits
。devices
下是构成电路的所有设备列表,以对象形式表示,其中键是(唯一的内部)设备名称。每个设备都有若干属性,以对象形式表示。一个必需的属性是type
,用于指定设备类型。设备示例:
"dev1": {
"type": "And",
"label": "AND1"
}
connectors
下是设备端口之间的连接列表,以对象数组形式表示,每个对象有两个键:from
和to
。这两个键都映射到一个包含id
和port
两个键的对象;前者对应设备名称,后者对应该设备的有效端口名称。连接必须从输出端口连接到输入端口,且两个端口的位宽必须相等。连接示例:
{
"from": {
"id": "dev1",
"port": "out"
},
"to": {
"id": "dev2",
"port": "in"
}
}
subcircuits
下是子电路定义列表,以对象形式表示,其中键是唯一的子电路名称。子电路名称可以用作类型为Subcircuit
的设备的celltype
;这会实例化该子电路。子电路定义遵循整个电路的表示方式,但子电路(目前)不能定义自己的子电路。子电路可以包含Input
和Output
设备,这些设备会映射到子电路实例的端口。
器件类型
- 一元门:
Not
(非门)、Repeater
(中继器) - 属性:
bits
(自然数) - 输入:
in
(bits
位) - 输出:
out
(bits
位) - N元门:
And
(与门)、Nand
(与非门)、Or
(或门)、Nor
(或非门)、Xor
(异或门)、Xnor
(同或门) - 属性:
bits
(自然数)、inputs
(自然数,默认为2) - 输入:
in1
、in2
...inN
(bits
位,N
=inputs
) - 输出:
out
(bits
位) - 归约门:
AndReduce
、NandReduce
、OrReduce
、NorReduce
、XorReduce
、XnorReduce
- 属性:
bits
(自然数) - 输入:
in
(bits
位) - 输出:
out
(1位) - 位移:
ShiftLeft
(左移)、ShiftRight
(右移) - 属性:
bits.in1
、bits.in2
和bits.out
(自然数),signed.in1
、signed.in2
、signed.out
和fillx
(布尔值) - 输入:
in1
(bits.in1
位)、in2
(bits.in2
位) - 输出:
out
(bits.out
位) - 比较器:
Eq
(等于)、Ne
(不等于)、Lt
(小于)、Le
(小于等于)、Gt
(大于)、Ge
(大于等于) - 属性:
bits.in1
和bits.in2
(自然数),signed.in1
和signed.in2
(布尔值) - 输入:
in1
(bits.in1
位)、in2
(bits.in2
位) - 输出:
out
(1位) - 数字常量:
Constant
- 属性:
constant
(二进制字符串) - 输出:
out
(constant.length
位) - 一元算术运算:
Negation
(取反)、UnaryPlus
(正号) - 属性:
bits.in
和bits.out
(自然数),signed
(布尔值) - 输入:
in
(bits.in
位) - 输出:
out
(bits.out
位) - 二元算术运算:
Addition
(加法)、Subtraction
(减法)、Multiplication
(乘法)、Division
(除法)、Modulo
(取模)、Power
(幂运算) - 属性:
bits.in1
、bits.in2
和bits.out
(自然数),signed.in1
和signed.in2
(布尔值) - 输入:
in1
(bits.in1
位)、in2
(bits.in2
位) - 输出:
out
(bits.out
位) - 多路复用器:
Mux
- 属性:
bits.in
、bits.sel
(自然数) - 输入:
in0
...inN
(bits.in
位,N
= 2**bits.sel
-1),sel
(bits.sel
位) - 输出:
out
(bits.in
位) - 独热码多路复用器:
Mux1Hot
- 属性:
bits.in
、bits.sel
(自然数) - 输入:
in0
...inN
(bits.in
位,N
=bits.sel
),sel
(bits.sel
位) - 输出:
out
(bits.in
位) - 稀疏多路复用器:
MuxSparse
- 属性:
bits.in
、bits.sel
(自然数),inputs
(自然数列表),default_input
(可选布尔值) - 输入:
in0
...inN
(bits.in
位,N
=inputs.length
,如果default_input
为真则+1) - 输出:
out
(bits.in
位) - D触发器:
Dff
- 属性:
bits
(自然数),polarity.clock
、polarity.arst
、polarity.srst
、polarity.aload
、polarity.set
、polarity.clr
、polarity.enable
、enable_srst
(可选布尔值),initial
(可选二进制字符串),arst_value
、srst_value
(可选二进制字符串),no_data
(可选布尔值) - 输入:
in
(bits
位),clk
(1位,如果存在polarity.clock
),arst
(1位,如果存在polarity.arst
),srst
(1位,如果存在polarity.srst
),en
(1位,如果存在polarity.enable
),set
(1位,如果存在polarity.set
),clr
(1位,如果存在polarity.clr
),ain
(bits
位,如果存在polarity.aload
),aload
(1位,如果存在polarity.aload
) - 输出:
out
(bits
位) - 内存:
Memory
- 属性:
bits
、abits
、words
、offset
(自然数),rdports
(读端口描述符数组),wrports
(写端口描述符数组),memdata
(内存内容描述) - 读端口描述符属性:
enable_polarity
、clock_polarity
、arst_polarity
、srst_polarity
(可选布尔值),init_value
、arst_value
、srst_value
(可选二进制字符串),transparent
、collision
(可选布尔值或布尔值数组) - 写端口描述符属性:
enable_polarity
、clock_polarity
、no_bit_enable
(可选布尔值) - 输入(每个读端口):
rdKaddr
(abits
位),rdKen
(1位,如果存在enable_polarity
),rdKclk
(1位,如果存在clock_polarity
),rdKarst
(1位,如果存在arst_polarity
),rdKsrst
(1位,如果存在srst_polarity
) - 输出(每个读端口):
rdKdata
(bits
位) - 输入(每个写端口):
wrKaddr
(abits
位),wrKdata
(bits
位),wrKen
(当no_bit_enable
为真时为1位,否则为bits
位,如果存在enable_polarity
),wrKclk
(1位,如果存在clock_polarity
) - 时钟源:
Clock
- 输出:
out
(1位) - 按钮输入:
Button
- 输出:
out
(1位) - 指示灯输出:
Lamp
- 输入:
in
(1位) - 数字输入:
NumEntry
- 属性:
bits
(自然数),numbase
(字符串) - 输出:
out
(bits
位) - 数字输出:
NumDisplay
- 属性:
bits
(自然数),numbase
(字符串) - 输入:
in
(bits
位) - 子电路输入:
Input
- 属性:
bits
(自然数) - 输出:
out
(bits
位) - 子电路输出:
Output
- 属性:
bits
(自然数) - 输入:
in
(bits
位) - 七段显示器输出:
Display7
- 输入:
bits
(仅8位 - 最高有效位控制小数点LED) - 总线分组:
BusGroup
- 属性:
groups
(自然数数组) - 输入:
in0
(groups[0]
位) ...inN
(groups[N]
位) - 输出:
out
(groups
总和位) - 总线解组:
BusUngroup
- 属性:
groups
(自然数数组) - 输入:
in
(groups
总和位) - 输出:
out0
(groups[0]
位) ...outN
(groups[N]
位) - 总线切片:
BusSlice
- 属性:
slice.first
、slice.count
、slice.total
(自然数) - 输入:
in
(slice.total
位) - 输出:
out
(slice.count
位) - 零扩展和符号扩展:
ZeroExtend
、SignExtend
- 属性:
extend.input
、extend.output
(自然数) - 输入:
in
(extend.input
位) - 输出:
out
(extend.output
位) - 有限状态机:
FSM
- 属性:
bits.in
、bits.out
、states
、init_state
、current_state
(自然数)、trans_table
(转换描述符数组) - 转换描述符属性:
ctrl_in
、ctrl_out
(二进制字符串)、state_in
、state_out
(自然数) - 输入:
clk
(1位)、arst
(1位)、in
(bits.in
位) - 输出:
out
(bits.out
位)
待办事项
进一步开发模拟器的一些想法:
- 使用JointJS elementTools来配置/移除门电路。
- 支持Verilog格式和Intel HEX的RAM/ROM导入/导出。
- 添加带字符/位图显示的帧缓冲区元素。
- 增加更多编辑功能:添加和删除模块,修改部分模块属性。
- 添加撤销-重做功能。
- 保存和加载电路,包括布局和状态。
- 为单目/二目门电路通用处理否定(输入/输出上的否定),以提高清晰度。
- SVG导出功能。
- Verilog导出功能。
- 适配智能手机和平板电脑的用户界面。