记录编写的负二分之一次方生成器从chisel代码到上板测试全过程
chisel代码及测试
本次设计中需要计算两个8bit输入的负二分之一次方乘积,并输出其8bit量化的输出结果。
O
u
t
p
u
t
=
i
n
p
u
t
0
−
1
/
2
∗
i
n
p
u
t
1
−
1
/
2
∗
256
Output= input0^{-1/2}*input1^{-1/2} * 256
Output=input0−1/2∗input1−1/2∗256
设计chisel代码及测试如下。
chisel代码
整体思想是用Python预先计算了一下,生成了部分查找表,由于当input0, input1较大时,输出均被量化为1,2等较小的数字,故不需要生成全部的查找表,使用条件判断加查找表相结合的方式即可。
package FAM
import chisel3._
import chisel3.util._
import os.read
import chisel3._
/* 输入起始节点和目的节点的度,计算得到他们乘积的-1/2次方
// 假设节点度最高256位,8bit
// 这里为实现整数的运算,将起始节点度与目的节点度的-1/2次方的乘积 * 256再取整
// 使用查找表完成乘法后的计算
*/
class SqrtInv(val Degree_Data_width: Int = 8) extends Module {
val io = IO(new Bundle {
val start_point_degree = Input(UInt(Degree_Data_width.W))
val end_point_degree = Input(UInt(Degree_Data_width.W))
val start = Input(Bool())
val done = Output(Bool())
val out = Output(UInt((Degree_Data_width).W))
})
// 初始化状态机。共四个状态:空闲状态、输入节点乘法计算,查找表,输出
val state = RegInit(0.U(2.W))
val idle :: multiply :: lut :: done :: Nil = Enum(4)
// 计算乘积
val mulResult = RegInit(0.U((2*Degree_Data_width).W))
val result = RegInit(0.U(8.W))
// 初始化LUT
val LUT_array = Array(
1.U -> 255.U(8.W),
2.U -> 181.U(8.W),
3.U -> 148.U(8.W),
4.U -> 128.U(8.W),
5.U -> 114.U(8.W),
6.U -> 105.U(8.W),
7.U -> 97.U(8.W),
8.U -> 91.U(8.W),
9.U -> 85.U(8.W),
10.U -> 81.U(8.W),
11.U -> 77.U(8.W),
12.U -> 74.U(8.W),
13.U -> 71.U(8.W),
14.U -> 68.U(8.W),
15.U -> 66.U(8.W),
16.U -> 64.U(8.W),
17.U -> 62.U(8.W),
18.U -> 60.U(8.W),
19.U -> 59.U(8.W),
20.U -> 57.U(8.W),
21.U -> 56.U(8.W),
22.U -> 55.U(8.W),
23.U -> 53.U(8.W),
24.U -> 52.U(8.W),
25.U -> 51.U(8.W),
26.U -> 50.U(8.W),
27.U -> 49.U(8.W),
28.U -> 48.U(8.W),
29.U -> 48.U(8.W),
30.U -> 47.U(8.W),
31.U -> 46.U(8.W),
32.U -> 45.U(8.W),
33.U -> 45.U(8.W),
34.U -> 44.U(8.W),
35.U -> 43.U(8.W),
36.U -> 43.U(8.W),
37.U -> 42.U(8.W),
38.U -> 42.U(8.W),
39.U -> 41.U(8.W),
40.U -> 40.U(8.W),
41.U -> 40.U(8.W),
42.U -> 40.U(8.W),
43.U -> 39.U(8.W),
44.U -> 39.U(8.W),
45.U -> 38.U(8.W),
46.U -> 38.U(8.W),
47.U -> 37.U(8.W),
48.U -> 37.U(8.W),
49.U -> 37.U(8.W),
50.U -> 36.U(8.W),
51.U -> 36.U(8.W),
52.U -> 36.U(8.W),
53.U -> 35.U(8.W),
54.U -> 35.U(8.W),
55.U -> 35.U(8.W),
56.U -> 34.U(8.W),
57.U -> 34.U(8.W),
58.U -> 34.U(8.W),
59.U -> 33.U(8.W),
60.U -> 33.U(8.W),
61.U -> 33.U(8.W),
62.U -> 33.U(8.W),
63.U -> 32.U(8.W),
64.U -> 32.U(8.W),
65.U -> 32.U(8.W),
66.U -> 32.U(8.W),
67.U -> 31.U(8.W),
68.U -> 31.U(8.W),
69.U -> 31.U(8.W),
70.U -> 31.U(8.W),
71.U -> 30.U(8.W),
72.U -> 30.U(8.W),
73.U -> 30.U(8.W),
74.U -> 30.U(8.W),
75.U -> 30.U(8.W),
76.U -> 29.U(8.W),
77.U -> 29.U(8.W),
78.U -> 29.U(8.W),
79.U -> 29.U(8.W),
80.U -> 29.U(8.W),
81.U -> 28.U(8.W),
82.U -> 28.U(8.W),
83.U -> 28.U(8.W),
84.U -> 28.U(8.W),
85.U -> 28.U(8.W),
86.U -> 28.U(8.W),
87.U -> 27.U(8.W),
88.U -> 27.U(8.W),
89.U -> 27.U(8.W),
90.U -> 27.U(8.W),
91.U -> 27.U(8.W),
92.U -> 27.U(8.W),
93.U -> 27.U(8.W),
94.U -> 26.U(8.W),
95.U -> 26.U(8.W),
96.U -> 26.U(8.W),
97.U -> 26.U(8.W),
98.U -> 26.U(8.W),
99.U -> 26.U(8.W),
100.U -> 26.U(8.W),
101.U -> 25.U(8.W),
102.U -> 25.U(8.W),
103.U -> 25.U(8.W),
104.U -> 25.U(8.W),
105.U -> 25.U(8.W),
106.U -> 25.U(8.W),
107.U -> 25.U(8.W),
108.U -> 25.U(8.W),
109.U -> 25.U(8.W),
110.U -> 24.U(8.W),
111.U -> 24.U(8.W),
112.U -> 24.U(8.W),
113.U -> 24.U(8.W),
114.U -> 24.U(8.W),
115.U -> 24.U(8.W),
116.U -> 24.U(8.W),
117.U -> 24.U(8.W),
118.U -> 24.U(8.W),
119.U -> 23.U(8.W),
120.U -> 23.U(8.W),
121.U -> 23.U(8.W),
122.U -> 23.U(8.W),
123.U -> 23.U(8.W),
124.U -> 23.U(8.W),
125.U -> 23.U(8.W),
126.U -> 23.U(8.W),
127.U -> 23.U(8.W),
128.U -> 23.U(8.W),
129.U -> 23.U(8.W),
130.U -> 22.U(8.W),
131.U -> 22.U(8.W),
132.U -> 22.U(8.W),
133.U -> 22.U(8.W),
134.U -> 22.U(8.W),
135.U -> 22.U(8.W),
136.U -> 22.U(8.W),
137.U -> 22.U(8.W),
138.U -> 22.U(8.W),
139.U -> 22.U(8.W),
140.U -> 22.U(8.W),
141.U -> 22.U(8.W),
142.U -> 21.U(8.W),
143.U -> 21.U(8.W),
144.U -> 21.U(8.W),
145.U -> 21.U(8.W),
146.U -> 21.U(8.W),
147.U -> 21.U(8.W),
148.U -> 21.U(8.W),
149.U -> 21.U(8.W),
150.U -> 21.U(8.W),
151.U -> 21.U(8.W),
152.U -> 21.U(8.W),
153.U -> 21.U(8.W),
154.U -> 21.U(8.W),
155.U -> 21.U(8.W),
156.U -> 20.U(8.W),
157.U -> 20.U(8.W),
158.U -> 20.U(8.W),
159.U -> 20.U(8.W),
160.U -> 20.U(8.W),
161.U -> 20.U(8.W),
162.U -> 20.U(8.W),
163.U -> 20.U(8.W),
164.U -> 20.U(8.W),
165.U -> 20.U(8.W),
166.U -> 20.U(8.W),
167.U -> 20.U(8.W),
168.U -> 20.U(8.W),
169.U -> 20.U(8.W),
170.U -> 20.U(8.W),
171.U -> 20.U(8.W),
172.U -> 20.U(8.W),
173.U -> 19.U(8.W),
174.U -> 19.U(8.W),
175.U -> 19.U(8.W),
176.U -> 19.U(8.W),
177.U -> 19.U(8.W),
178.U -> 19.U(8.W),
179.U -> 19.U(8.W),
180.U -> 19.U(8.W),
181.U -> 19.U(8.W),
182.U -> 19.U(8.W),
183.U -> 19.U(8.W),
184.U -> 19.U(8.W),
185.U -> 19.U(8.W),
186.U -> 19.U(8.W),
187.U -> 19.U(8.W),
188.U -> 19.U(8.W),
189.U -> 19.U(8.W),
190.U -> 19.U(8.W),
191.U -> 19.U(8.W),
192.U -> 18.U(8.W),
193.U -> 18.U(8.W),
194.U -> 18.U(8.W),
195.U -> 18.U(8.W),
196.U -> 18.U(8.W),
197.U -> 18.U(8.W),
198.U -> 18.U(8.W),
199.U -> 18.U(8.W),
200.U -> 18.U(8.W),
201.U -> 18.U(8.W),
202.U -> 18.U(8.W),
203.U -> 18.U(8.W),
204.U -> 18.U(8.W),
205.U -> 18.U(8.W),
206.U -> 18.U(8.W),
207.U -> 18.U(8.W),
208.U -> 18.U(8.W),
209.U -> 18.U(8.W),
210.U -> 18.U(8.W),
211.U -> 18.U(8.W),
212.U -> 18.U(8.W),
213.U -> 18.U(8.W),
214.U -> 17.U(8.W),
215.U -> 17.U(8.W),
216.U -> 17.U(8.W),
217.U -> 17.U(8.W),
218.U -> 17.U(8.W),
219.U -> 17.U(8.W),
220.U -> 17.U(8.W),
221.U -> 17.U(8.W),
222.U -> 17.U(8.W),
223.U -> 17.U(8.W),
224.U -> 17.U(8.W),
225.U -> 17.U(8.W),
226.U -> 17.U(8.W),
227.U -> 17.U(8.W),
228.U -> 17.U(8.W),
229.U -> 17.U(8.W),
230.U -> 17.U(8.W),
231.U -> 17.U(8.W),
232.U -> 17.U(8.W),
233.U -> 17.U(8.W),
234.U -> 17.U(8.W),
235.U -> 17.U(8.W),
236.U -> 17.U(8.W),
237.U -> 17.U(8.W),
238.U -> 17.U(8.W),
239.U -> 17.U(8.W),
240.U -> 17.U(8.W),
241.U -> 16.U(8.W),
242.U -> 16.U(8.W),
243.U -> 16.U(8.W),
244.U -> 16.U(8.W),
245.U -> 16.U(8.W),
246.U -> 16.U(8.W),
247.U -> 16.U(8.W),
248.U -> 16.U(8.W),
249.U -> 16.U(8.W),
250.U -> 16.U(8.W),
251.U -> 16.U(8.W),
252.U -> 16.U(8.W),
253.U -> 16.U(8.W),
254.U -> 16.U(8.W),
255.U -> 16.U(8.W),
256.U -> 16.U(8.W),
257.U -> 16.U(8.W),
258.U -> 16.U(8.W),
259.U -> 16.U(8.W),
260.U -> 16.U(8.W),
261.U -> 16.U(8.W),
262.U -> 16.U(8.W),
263.U -> 16.U(8.W),
264.U -> 16.U(8.W),
265.U -> 16.U(8.W),
266.U -> 16.U(8.W),
267.U -> 16.U(8.W),
268.U -> 16.U(8.W),
269.U -> 16.U(8.W),
270.U -> 16.U(8.W),
271.U -> 16.U(8.W),
272.U -> 16.U(8.W)
)
// 状态机执行
switch(state) {
is(idle) {
when(io.start) {
state := multiply
}
}
is(multiply) {
mulResult := io.start_point_degree * io.end_point_degree
state := lut
}
is(lut) {
// 使用输入值作为索引来查找结果
// 接受选择信号、一个默认值,一个选择表。如果匹配成功,则按照匹配值输出,否则按默认值输出
// 观察计算结果,前面数值变化相对频繁,而后面数值变化不大,这里将整个过程进行分类。变化相对频繁的地方使用查找表进行查找,
// 而没那么频繁的使用条件判断所属区间进行处理
when(mulResult < 273.U) { // 查找表所属区间,即LUT_depth
result := MuxLookup(mulResult, 0.U, LUT_array)
}
.elsewhen(mulResult < 312.U) { // 15
result := 15.U
}
.elsewhen(mulResult < 360.U) { // 14
result := 14.U
}
.elsewhen(mulResult < 420.U) { // 13
result := 13.U
}
.elsewhen(mulResult < 496.U) { // 12
result := 12.U
}
.elsewhen(mulResult < 595.U) { // 11
result := 11.U
}
.elsewhen(mulResult < 727.U) { // 10
result := 10.U
}
.elsewhen(mulResult < 908.U) { // 9
result := 9.U
}
.elsewhen(mulResult < 1166.U) { // 8
result := 8.U
}
.elsewhen(mulResult < 1552.U) { // 7
result := 7.U
}
.elsewhen(mulResult < 2167.U) { // 6
result := 6.U
}
.elsewhen(mulResult < 3237.U) { // 5
result := 5.U
}
.elsewhen(mulResult < 5350.U) { // 4
result := 4.U
}
.elsewhen(mulResult < 10487.U) { // 3
result := 3.U
}
.elsewhen(mulResult < 29128.U) { // 2
result := 2.U
}
.otherwise { // 1
result := 1.U
}
state := done
}
is(done) {
state := idle
}
}
io.done := (state === done)
io.out := result
}
// 实例化模块并运行测试,同时生成Verilog代码
object SqrtInv extends App {
(new chisel3.stage.ChiselStage).emitVerilog(new SqrtInv(), Array("--target-dir", "./verilog/FAM"))
}
chisel测试代码
类似UVM那套验证方法,软件做一套,硬件做一套,然后用断言来验证。
import scala.util.Random
import org.scalatest._
import chiseltest._
import chisel3._
import FAM.SqrtInv
// 乘累加器的测试类
class SqrtInvTest extends FreeSpec with ChiselScalatestTester {
"SqrtInv should pass" in {
test(new SqrtInv)
.withAnnotations(Seq(WriteVcdAnnotation)) // generate the .vcd waveform file as output
{ c =>
println("Start Testing")
for (i <- 0 until 10) {
val a = Random.nextInt(256) // 生成0到255之间的随机数
val b = Random.nextInt(256)
c.io.start_point_degree.poke(a.U) // 将随机数a作为无符号数输入
c.io.end_point_degree.poke(b.U) // 将随机数b作为无符号数输入
c.io.start.poke(true.B)
c.clock.step(2)
while (c.io.done.peekBoolean() === false) {
c.clock.step(1)
}
val expectedResult = math.round(256/math.sqrt(a * b)) // 计算预期乘积
val actualResult = c.io.out.peek().litValue.toLong // 获取实际乘积
/*
c: 这是测试环境中MAC模块的实例。
c.io.result: 这是指向模块输出端口result的引用。
peek(): 这是一个Chisel测试方法,用于在不推进时钟的情况下读取端口的当前值。
litValue: 这是一个方法,用于从Chisel的Data类型中提取实际的Scala值(在这个例子中是BigInt)
*/
println(s"Iteration: $i, A: $a, B: $b, Expected Result: $expectedResult, Actual Result: $actualResult")
assert(actualResult === expectedResult, s"Product is incorrect at iteration $i!\n Start_point_degree is $a, end point degree is $b.\n Expected: $expectedResult, Actual: $actualResult")
}
}
}
}
chisel测试结果
运行命令行sbt "testOnly SqrtInvTest"
测试结果如下
(base) wzm@wzm-Predator-PHN16-71:~/Graduation_Design/task/main/GCN try/chisel-examples/hello-world$ sbt "testOnly SqrtInvTest"
[info] welcome to sbt 1.9.7 (Ubuntu Java 17.0.13)
[info] loading settings for project hello-world-build-build from metals.sbt ...
[info] loading project definition from /home/wzm/Graduation_Design/task/main/GCN try/chisel-examples/hello-world/project/project
[info] loading settings for project hello-world-build from metals.sbt ...
[info] loading project definition from /home/wzm/Graduation_Design/task/main/GCN try/chisel-examples/hello-world/project
[success] Generated .bloop/hello-world-build.json
[success] Total time: 1 s, completed 2025年1月4日 下午5:09:53
[info] loading settings for project hello-world from build.sbt ...
[info] set current project to hello-world (in build file:/home/wzm/Graduation_Design/task/main/GCN%20try/chisel-examples/hello-world/)
Start Testing
Iteration: 0, A: 211, B: 169, Expected Result: 1, Actual Result: 1
Iteration: 1, A: 92, B: 242, Expected Result: 2, Actual Result: 2
Iteration: 2, A: 65, B: 251, Expected Result: 2, Actual Result: 2
Iteration: 3, A: 38, B: 87, Expected Result: 4, Actual Result: 4
Iteration: 4, A: 129, B: 204, Expected Result: 2, Actual Result: 2
Iteration: 5, A: 156, B: 201, Expected Result: 1, Actual Result: 1
Iteration: 6, A: 172, B: 210, Expected Result: 1, Actual Result: 1
Iteration: 7, A: 194, B: 22, Expected Result: 4, Actual Result: 4
Iteration: 8, A: 97, B: 189, Expected Result: 2, Actual Result: 2
Iteration: 9, A: 47, B: 23, Expected Result: 8, Actual Result: 8
[info] SqrtInvTest:
[info] - SqrtInv should pass
[info] Run completed in 1 second, 497 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 2 s, completed 2025年1月4日 下午5:09:55
测试通过
生成Verilog文件
运行命令行sbt run
得到Verilog代码(非常长,可以不看)
module SqrtInv(
input clock,
input reset,
input [7:0] io_start_point_degree,
input [7:0] io_end_point_degree,
input io_start,
output io_done,
output [7:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
reg [31:0] _RAND_1;
reg [31:0] _RAND_2;
`endif // RANDOMIZE_REG_INIT
reg [1:0] state; // @[SqrtInv.scala 24:24]
reg [15:0] mulResult; // @[SqrtInv.scala 28:28]
reg [7:0] result; // @[SqrtInv.scala 29:25]
wire [15:0] _mulResult_T = io_start_point_degree * io_end_point_degree; // @[SqrtInv.scala 317:48]
wire [7:0] _result_T_1 = 16'h1 == mulResult ? 8'hff : 8'h0; // @[Mux.scala 81:58]
wire [7:0] _result_T_3 = 16'h2 == mulResult ? 8'hb5 : _result_T_1; // @[Mux.scala 81:58]
wire [7:0] _result_T_5 = 16'h3 == mulResult ? 8'h94 : _result_T_3; // @[Mux.scala 81:58]
wire [7:0] _result_T_7 = 16'h4 == mulResult ? 8'h80 : _result_T_5; // @[Mux.scala 81:58]
wire [7:0] _result_T_9 = 16'h5 == mulResult ? 8'h72 : _result_T_7; // @[Mux.scala 81:58]
wire [7:0] _result_T_11 = 16'h6 == mulResult ? 8'h69 : _result_T_9; // @[Mux.scala 81:58]
wire [7:0] _result_T_13 = 16'h7 == mulResult ? 8'h61 : _result_T_11; // @[Mux.scala 81:58]
wire [7:0] _result_T_15 = 16'h8 == mulResult ? 8'h5b : _result_T_13; // @[Mux.scala 81:58]
wire [7:0] _result_T_17 = 16'h9 == mulResult ? 8'h55 : _result_T_15; // @[Mux.scala 81:58]
wire [7:0] _result_T_19 = 16'ha == mulResult ? 8'h51 : _result_T_17; // @[Mux.scala 81:58]
wire [7:0] _result_T_21 = 16'hb == mulResult ? 8'h4d : _result_T_19; // @[Mux.scala 81:58]
wire [7:0] _result_T_23 = 16'hc == mulResult ? 8'h4a : _result_T_21; // @[Mux.scala 81:58]
wire [7:0] _result_T_25 = 16'hd == mulResult ? 8'h47 : _result_T_23; // @[Mux.scala 81:58]
wire [7:0] _result_T_27 = 16'he == mulResult ? 8'h44 : _result_T_25; // @[Mux.scala 81:58]
wire [7:0] _result_T_29 = 16'hf == mulResult ? 8'h42 : _result_T_27; // @[Mux.scala 81:58]
wire [7:0] _result_T_31 = 16'h10 == mulResult ? 8'h40 : _result_T_29; // @[Mux.scala 81:58]
wire [7:0] _result_T_33 = 16'h11 == mulResult ? 8'h3e : _result_T_31; // @[Mux.scala 81:58]
wire [7:0] _result_T_35 = 16'h12 == mulResult ? 8'h3c : _result_T_33; // @[Mux.scala 81:58]
wire [7:0] _result_T_37 = 16'h13 == mulResult ? 8'h3b : _result_T_35; // @[Mux.scala 81:58]
wire [7:0] _result_T_39 = 16'h14 == mulResult ? 8'h39 : _result_T_37; // @[Mux.scala 81:58]
wire [7:0] _result_T_41 = 16'h15 == mulResult ? 8'h38 : _result_T_39; // @[Mux.scala 81:58]
wire [7:0] _result_T_43 = 16'h16 == mulResult ? 8'h37 : _result_T_41; // @[Mux.scala 81:58]
wire [7:0] _result_T_45 = 16'h17 == mulResult ? 8'h35 : _result_T_43; // @[Mux.scala 81:58]
wire [7:0] _result_T_47 = 16'h18 == mulResult ? 8'h34 : _result_T_45; // @[Mux.scala 81:58]
wire [7:0] _result_T_49 = 16'h19 == mulResult ? 8'h33 : _result_T_47; // @[Mux.scala 81:58]
wire [7:0] _result_T_51 = 16'h1a == mulResult ? 8'h32 : _result_T_49; // @[Mux.scala 81:58]
wire [7:0] _result_T_53 = 16'h1b == mulResult ? 8'h31 : _result_T_51; // @[Mux.scala 81:58]
wire [7:0] _result_T_55 = 16'h1c == mulResult ? 8'h30 : _result_T_53; // @[Mux.scala 81:58]
wire [7:0] _result_T_57 = 16'h1d == mulResult ? 8'h30 : _result_T_55; // @[Mux.scala 81:58]
wire [7:0] _result_T_59 = 16'h1e == mulResult ? 8'h2f : _result_T_57; // @[Mux.scala 81:58]
wire [7:0] _result_T_61 = 16'h1f == mulResult ? 8'h2e : _result_T_59; // @[Mux.scala 81:58]
wire [7:0] _result_T_63 = 16'h20 == mulResult ? 8'h2d : _result_T_61; // @[Mux.scala 81:58]
wire [7:0] _result_T_65 = 16'h21 == mulResult ? 8'h2d : _result_T_63; // @[Mux.scala 81:58]
wire [7:0] _result_T_67 = 16'h22 == mulResult ? 8'h2c : _result_T_65; // @[Mux.scala 81:58]
wire [7:0] _result_T_69 = 16'h23 == mulResult ? 8'h2b : _result_T_67; // @[Mux.scala 81:58]
wire [7:0] _result_T_71 = 16'h24 == mulResult ? 8'h2b : _result_T_69; // @[Mux.scala 81:58]
wire [7:0] _result_T_73 = 16'h25 == mulResult ? 8'h2a : _result_T_71; // @[Mux.scala 81:58]
wire [7:0] _result_T_75 = 16'h26 == mulResult ? 8'h2a : _result_T_73; // @[Mux.scala 81:58]
wire [7:0] _result_T_77 = 16'h27 == mulResult ? 8'h29 : _result_T_75; // @[Mux.scala 81:58]
wire [7:0] _result_T_79 = 16'h28 == mulResult ? 8'h28 : _result_T_77; // @[Mux.scala 81:58]
wire [7:0] _result_T_81 = 16'h29 == mulResult ? 8'h28 : _result_T_79; // @[Mux.scala 81:58]
wire [7:0] _result_T_83 = 16'h2a == mulResult ? 8'h28 : _result_T_81; // @[Mux.scala 81:58]
wire [7:0] _result_T_85 = 16'h2b == mulResult ? 8'h27 : _result_T_83; // @[Mux.scala 81:58]
wire [7:0] _result_T_87 = 16'h2c == mulResult ? 8'h27 : _result_T_85; // @[Mux.scala 81:58]
wire [7:0] _result_T_89 = 16'h2d == mulResult ? 8'h26 : _result_T_87; // @[Mux.scala 81:58]
wire [7:0] _result_T_91 = 16'h2e == mulResult ? 8'h26 : _result_T_89; // @[Mux.scala 81:58]
wire [7:0] _result_T_93 = 16'h2f == mulResult ? 8'h25 : _result_T_91; // @[Mux.scala 81:58]
wire [7:0] _result_T_95 = 16'h30 == mulResult ? 8'h25 : _result_T_93; // @[Mux.scala 81:58]
wire [7:0] _result_T_97 = 16'h31 == mulResult ? 8'h25 : _result_T_95; // @[Mux.scala 81:58]
wire [7:0] _result_T_99 = 16'h32 == mulResult ? 8'h24 : _result_T_97; // @[Mux.scala 81:58]
wire [7:0] _result_T_101 = 16'h33 == mulResult ? 8'h24 : _result_T_99; // @[Mux.scala 81:58]
wire [7:0] _result_T_103 = 16'h34 == mulResult ? 8'h24 : _result_T_101; // @[Mux.scala 81:58]
wire [7:0] _result_T_105 = 16'h35 == mulResult ? 8'h23 : _result_T_103; // @[Mux.scala 81:58]
wire [7:0] _result_T_107 = 16'h36 == mulResult ? 8'h23 : _result_T_105; // @[Mux.scala 81:58]
wire [7:0] _result_T_109 = 16'h37 == mulResult ? 8'h23 : _result_T_107; // @[Mux.scala 81:58]
wire [7:0] _result_T_111 = 16'h38 == mulResult ? 8'h22 : _result_T_109; // @[Mux.scala 81:58]
wire [7:0] _result_T_113 = 16'h39 == mulResult ? 8'h22 : _result_T_111; // @[Mux.scala 81:58]
wire [7:0] _result_T_115 = 16'h3a == mulResult ? 8'h22 : _result_T_113; // @[Mux.scala 81:58]
wire [7:0] _result_T_117 = 16'h3b == mulResult ? 8'h21 : _result_T_115; // @[Mux.scala 81:58]
wire [7:0] _result_T_119 = 16'h3c == mulResult ? 8'h21 : _result_T_117; // @[Mux.scala 81:58]
wire [7:0] _result_T_121 = 16'h3d == mulResult ? 8'h21 : _result_T_119; // @[Mux.scala 81:58]
wire [7:0] _result_T_123 = 16'h3e == mulResult ? 8'h21 : _result_T_121; // @[Mux.scala 81:58]
wire [7:0] _result_T_125 = 16'h3f == mulResult ? 8'h20 : _result_T_123; // @[Mux.scala 81:58]
wire [7:0] _result_T_127 = 16'h40 == mulResult ? 8'h20 : _result_T_125; // @[Mux.scala 81:58]
wire [7:0] _result_T_129 = 16'h41 == mulResult ? 8'h20 : _result_T_127; // @[Mux.scala 81:58]
wire [7:0] _result_T_131 = 16'h42 == mulResult ? 8'h20 : _result_T_129; // @[Mux.scala 81:58]
wire [7:0] _result_T_133 = 16'h43 == mulResult ? 8'h1f : _result_T_131; // @[Mux.scala 81:58]
wire [7:0] _result_T_135 = 16'h44 == mulResult ? 8'h1f : _result_T_133; // @[Mux.scala 81:58]
wire [7:0] _result_T_137 = 16'h45 == mulResult ? 8'h1f : _result_T_135; // @[Mux.scala 81:58]
wire [7:0] _result_T_139 = 16'h46 == mulResult ? 8'h1f : _result_T_137; // @[Mux.scala 81:58]
wire [7:0] _result_T_141 = 16'h47 == mulResult ? 8'h1e : _result_T_139; // @[Mux.scala 81:58]
wire [7:0] _result_T_143 = 16'h48 == mulResult ? 8'h1e : _result_T_141; // @[Mux.scala 81:58]
wire [7:0] _result_T_145 = 16'h49 == mulResult ? 8'h1e : _result_T_143; // @[Mux.scala 81:58]
wire [7:0] _result_T_147 = 16'h4a == mulResult ? 8'h1e : _result_T_145; // @[Mux.scala 81:58]
wire [7:0] _result_T_149 = 16'h4b == mulResult ? 8'h1e : _result_T_147; // @[Mux.scala 81:58]
wire [7:0] _result_T_151 = 16'h4c == mulResult ? 8'h1d : _result_T_149; // @[Mux.scala 81:58]
wire [7:0] _result_T_153 = 16'h4d == mulResult ? 8'h1d : _result_T_151; // @[Mux.scala 81:58]
wire [7:0] _result_T_155 = 16'h4e == mulResult ? 8'h1d : _result_T_153; // @[Mux.scala 81:58]
wire [7:0] _result_T_157 = 16'h4f == mulResult ? 8'h1d : _result_T_155; // @[Mux.scala 81:58]
wire [7:0] _result_T_159 = 16'h50 == mulResult ? 8'h1d : _result_T_157; // @[Mux.scala 81:58]
wire [7:0] _result_T_161 = 16'h51 == mulResult ? 8'h1c : _result_T_159; // @[Mux.scala 81:58]
wire [7:0] _result_T_163 = 16'h52 == mulResult ? 8'h1c : _result_T_161; // @[Mux.scala 81:58]
wire [7:0] _result_T_165 = 16'h53 == mulResult ? 8'h1c : _result_T_163; // @[Mux.scala 81:58]
wire [7:0] _result_T_167 = 16'h54 == mulResult ? 8'h1c : _result_T_165; // @[Mux.scala 81:58]
wire [7:0] _result_T_169 = 16'h55 == mulResult ? 8'h1c : _result_T_167; // @[Mux.scala 81:58]
wire [7:0] _result_T_171 = 16'h56 == mulResult ? 8'h1c : _result_T_169; // @[Mux.scala 81:58]
wire [7:0] _result_T_173 = 16'h57 == mulResult ? 8'h1b : _result_T_171; // @[Mux.scala 81:58]
wire [7:0] _result_T_175 = 16'h58 == mulResult ? 8'h1b : _result_T_173; // @[Mux.scala 81:58]
wire [7:0] _result_T_177 = 16'h59 == mulResult ? 8'h1b : _result_T_175; // @[Mux.scala 81:58]
wire [7:0] _result_T_179 = 16'h5a == mulResult ? 8'h1b : _result_T_177; // @[Mux.scala 81:58]
wire [7:0] _result_T_181 = 16'h5b == mulResult ? 8'h1b : _result_T_179; // @[Mux.scala 81:58]
wire [7:0] _result_T_183 = 16'h5c == mulResult ? 8'h1b : _result_T_181; // @[Mux.scala 81:58]
wire [7:0] _result_T_185 = 16'h5d == mulResult ? 8'h1b : _result_T_183; // @[Mux.scala 81:58]
wire [7:0] _result_T_187 = 16'h5e == mulResult ? 8'h1a : _result_T_185; // @[Mux.scala 81:58]
wire [7:0] _result_T_189 = 16'h5f == mulResult ? 8'h1a : _result_T_187; // @[Mux.scala 81:58]
wire [7:0] _result_T_191 = 16'h60 == mulResult ? 8'h1a : _result_T_189; // @[Mux.scala 81:58]
wire [7:0] _result_T_193 = 16'h61 == mulResult ? 8'h1a : _result_T_191; // @[Mux.scala 81:58]
wire [7:0] _result_T_195 = 16'h62 == mulResult ? 8'h1a : _result_T_193; // @[Mux.scala 81:58]
wire [7:0] _result_T_197 = 16'h63 == mulResult ? 8'h1a : _result_T_195; // @[Mux.scala 81:58]
wire [7:0] _result_T_199 = 16'h64 == mulResult ? 8'h1a : _result_T_197; // @[Mux.scala 81:58]
wire [7:0] _result_T_201 = 16'h65 == mulResult ? 8'h19 : _result_T_199; // @[Mux.scala 81:58]
wire [7:0] _result_T_203 = 16'h66 == mulResult ? 8'h19 : _result_T_201; // @[Mux.scala 81:58]
wire [7:0] _result_T_205 = 16'h67 == mulResult ? 8'h19 : _result_T_203; // @[Mux.scala 81:58]
wire [7:0] _result_T_207 = 16'h68 == mulResult ? 8'h19 : _result_T_205; // @[Mux.scala 81:58]
wire [7:0] _result_T_209 = 16'h69 == mulResult ? 8'h19 : _result_T_207; // @[Mux.scala 81:58]
wire [7:0] _result_T_211 = 16'h6a == mulResult ? 8'h19 : _result_T_209; // @[Mux.scala 81:58]
wire [7:0] _result_T_213 = 16'h6b == mulResult ? 8'h19 : _result_T_211; // @[Mux.scala 81:58]
wire [7:0] _result_T_215 = 16'h6c == mulResult ? 8'h19 : _result_T_213; // @[Mux.scala 81:58]
wire [7:0] _result_T_217 = 16'h6d == mulResult ? 8'h19 : _result_T_215; // @[Mux.scala 81:58]
wire [7:0] _result_T_219 = 16'h6e == mulResult ? 8'h18 : _result_T_217; // @[Mux.scala 81:58]
wire [7:0] _result_T_221 = 16'h6f == mulResult ? 8'h18 : _result_T_219; // @[Mux.scala 81:58]
wire [7:0] _result_T_223 = 16'h70 == mulResult ? 8'h18 : _result_T_221; // @[Mux.scala 81:58]
wire [7:0] _result_T_225 = 16'h71 == mulResult ? 8'h18 : _result_T_223; // @[Mux.scala 81:58]
wire [7:0] _result_T_227 = 16'h72 == mulResult ? 8'h18 : _result_T_225; // @[Mux.scala 81:58]
wire [7:0] _result_T_229 = 16'h73 == mulResult ? 8'h18 : _result_T_227; // @[Mux.scala 81:58]
wire [7:0] _result_T_231 = 16'h74 == mulResult ? 8'h18 : _result_T_229; // @[Mux.scala 81:58]
wire [7:0] _result_T_233 = 16'h75 == mulResult ? 8'h18 : _result_T_231; // @[Mux.scala 81:58]
wire [7:0] _result_T_235 = 16'h76 == mulResult ? 8'h18 : _result_T_233; // @[Mux.scala 81:58]
wire [7:0] _result_T_237 = 16'h77 == mulResult ? 8'h17 : _result_T_235; // @[Mux.scala 81:58]
wire [7:0] _result_T_239 = 16'h78 == mulResult ? 8'h17 : _result_T_237; // @[Mux.scala 81:58]
wire [7:0] _result_T_241 = 16'h79 == mulResult ? 8'h17 : _result_T_239; // @[Mux.scala 81:58]
wire [7:0] _result_T_243 = 16'h7a == mulResult ? 8'h17 : _result_T_241; // @[Mux.scala 81:58]
wire [7:0] _result_T_245 = 16'h7b == mulResult ? 8'h17 : _result_T_243; // @[Mux.scala 81:58]
wire [7:0] _result_T_247 = 16'h7c == mulResult ? 8'h17 : _result_T_245; // @[Mux.scala 81:58]
wire [7:0] _result_T_249 = 16'h7d == mulResult ? 8'h17 : _result_T_247; // @[Mux.scala 81:58]
wire [7:0] _result_T_251 = 16'h7e == mulResult ? 8'h17 : _result_T_249; // @[Mux.scala 81:58]
wire [7:0] _result_T_253 = 16'h7f == mulResult ? 8'h17 : _result_T_251; // @[Mux.scala 81:58]
wire [7:0] _result_T_255 = 16'h80 == mulResult ? 8'h17 : _result_T_253; // @[Mux.scala 81:58]
wire [7:0] _result_T_257 = 16'h81 == mulResult ? 8'h17 : _result_T_255; // @[Mux.scala 81:58]
wire [7:0] _result_T_259 = 16'h82 == mulResult ? 8'h16 : _result_T_257; // @[Mux.scala 81:58]
wire [7:0] _result_T_261 = 16'h83 == mulResult ? 8'h16 : _result_T_259; // @[Mux.scala 81:58]
wire [7:0] _result_T_263 = 16'h84 == mulResult ? 8'h16 : _result_T_261; // @[Mux.scala 81:58]
wire [7:0] _result_T_265 = 16'h85 == mulResult ? 8'h16 : _result_T_263; // @[Mux.scala 81:58]
wire [7:0] _result_T_267 = 16'h86 == mulResult ? 8'h16 : _result_T_265; // @[Mux.scala 81:58]
wire [7:0] _result_T_269 = 16'h87 == mulResult ? 8'h16 : _result_T_267; // @[Mux.scala 81:58]
wire [7:0] _result_T_271 = 16'h88 == mulResult ? 8'h16 : _result_T_269; // @[Mux.scala 81:58]
wire [7:0] _result_T_273 = 16'h89 == mulResult ? 8'h16 : _result_T_271; // @[Mux.scala 81:58]
wire [7:0] _result_T_275 = 16'h8a == mulResult ? 8'h16 : _result_T_273; // @[Mux.scala 81:58]
wire [7:0] _result_T_277 = 16'h8b == mulResult ? 8'h16 : _result_T_275; // @[Mux.scala 81:58]
wire [7:0] _result_T_279 = 16'h8c == mulResult ? 8'h16 : _result_T_277; // @[Mux.scala 81:58]
wire [7:0] _result_T_281 = 16'h8d == mulResult ? 8'h16 : _result_T_279; // @[Mux.scala 81:58]
wire [7:0] _result_T_283 = 16'h8e == mulResult ? 8'h15 : _result_T_281; // @[Mux.scala 81:58]
wire [7:0] _result_T_285 = 16'h8f == mulResult ? 8'h15 : _result_T_283; // @[Mux.scala 81:58]
wire [7:0] _result_T_287 = 16'h90 == mulResult ? 8'h15 : _result_T_285; // @[Mux.scala 81:58]
wire [7:0] _result_T_289 = 16'h91 == mulResult ? 8'h15 : _result_T_287; // @[Mux.scala 81:58]
wire [7:0] _result_T_291 = 16'h92 == mulResult ? 8'h15 : _result_T_289; // @[Mux.scala 81:58]
wire [7:0] _result_T_293 = 16'h93 == mulResult ? 8'h15 : _result_T_291; // @[Mux.scala 81:58]
wire [7:0] _result_T_295 = 16'h94 == mulResult ? 8'h15 : _result_T_293; // @[Mux.scala 81:58]
wire [7:0] _result_T_297 = 16'h95 == mulResult ? 8'h15 : _result_T_295; // @[Mux.scala 81:58]
wire [7:0] _result_T_299 = 16'h96 == mulResult ? 8'h15 : _result_T_297; // @[Mux.scala 81:58]
wire [7:0] _result_T_301 = 16'h97 == mulResult ? 8'h15 : _result_T_299; // @[Mux.scala 81:58]
wire [7:0] _result_T_303 = 16'h98 == mulResult ? 8'h15 : _result_T_301; // @[Mux.scala 81:58]
wire [7:0] _result_T_305 = 16'h99 == mulResult ? 8'h15 : _result_T_303; // @[Mux.scala 81:58]
wire [7:0] _result_T_307 = 16'h9a == mulResult ? 8'h15 : _result_T_305; // @[Mux.scala 81:58]
wire [7:0] _result_T_309 = 16'h9b == mulResult ? 8'h15 : _result_T_307; // @[Mux.scala 81:58]
wire [7:0] _result_T_311 = 16'h9c == mulResult ? 8'h14 : _result_T_309; // @[Mux.scala 81:58]
wire [7:0] _result_T_313 = 16'h9d == mulResult ? 8'h14 : _result_T_311; // @[Mux.scala 81:58]
wire [7:0] _result_T_315 = 16'h9e == mulResult ? 8'h14 : _result_T_313; // @[Mux.scala 81:58]
wire [7:0] _result_T_317 = 16'h9f == mulResult ? 8'h14 : _result_T_315; // @[Mux.scala 81:58]
wire [7:0] _result_T_319 = 16'ha0 == mulResult ? 8'h14 : _result_T_317; // @[Mux.scala 81:58]
wire [7:0] _result_T_321 = 16'ha1 == mulResult ? 8'h14 : _result_T_319; // @[Mux.scala 81:58]
wire [7:0] _result_T_323 = 16'ha2 == mulResult ? 8'h14 : _result_T_321; // @[Mux.scala 81:58]
wire [7:0] _result_T_325 = 16'ha3 == mulResult ? 8'h14 : _result_T_323; // @[Mux.scala 81:58]
wire [7:0] _result_T_327 = 16'ha4 == mulResult ? 8'h14 : _result_T_325; // @[Mux.scala 81:58]
wire [7:0] _result_T_329 = 16'ha5 == mulResult ? 8'h14 : _result_T_327; // @[Mux.scala 81:58]
wire [7:0] _result_T_331 = 16'ha6 == mulResult ? 8'h14 : _result_T_329; // @[Mux.scala 81:58]
wire [7:0] _result_T_333 = 16'ha7 == mulResult ? 8'h14 : _result_T_331; // @[Mux.scala 81:58]
wire [7:0] _result_T_335 = 16'ha8 == mulResult ? 8'h14 : _result_T_333; // @[Mux.scala 81:58]
wire [7:0] _result_T_337 = 16'ha9 == mulResult ? 8'h14 : _result_T_335; // @[Mux.scala 81:58]
wire [7:0] _result_T_339 = 16'haa == mulResult ? 8'h14 : _result_T_337; // @[Mux.scala 81:58]
wire [7:0] _result_T_341 = 16'hab == mulResult ? 8'h14 : _result_T_339; // @[Mux.scala 81:58]
wire [7:0] _result_T_343 = 16'hac == mulResult ? 8'h14 : _result_T_341; // @[Mux.scala 81:58]
wire [7:0] _result_T_345 = 16'had == mulResult ? 8'h13 : _result_T_343; // @[Mux.scala 81:58]
wire [7:0] _result_T_347 = 16'hae == mulResult ? 8'h13 : _result_T_345; // @[Mux.scala 81:58]
wire [7:0] _result_T_349 = 16'haf == mulResult ? 8'h13 : _result_T_347; // @[Mux.scala 81:58]
wire [7:0] _result_T_351 = 16'hb0 == mulResult ? 8'h13 : _result_T_349; // @[Mux.scala 81:58]
wire [7:0] _result_T_353 = 16'hb1 == mulResult ? 8'h13 : _result_T_351; // @[Mux.scala 81:58]
wire [7:0] _result_T_355 = 16'hb2 == mulResult ? 8'h13 : _result_T_353; // @[Mux.scala 81:58]
wire [7:0] _result_T_357 = 16'hb3 == mulResult ? 8'h13 : _result_T_355; // @[Mux.scala 81:58]
wire [7:0] _result_T_359 = 16'hb4 == mulResult ? 8'h13 : _result_T_357; // @[Mux.scala 81:58]
wire [7:0] _result_T_361 = 16'hb5 == mulResult ? 8'h13 : _result_T_359; // @[Mux.scala 81:58]
wire [7:0] _result_T_363 = 16'hb6 == mulResult ? 8'h13 : _result_T_361; // @[Mux.scala 81:58]
wire [7:0] _result_T_365 = 16'hb7 == mulResult ? 8'h13 : _result_T_363; // @[Mux.scala 81:58]
wire [7:0] _result_T_367 = 16'hb8 == mulResult ? 8'h13 : _result_T_365; // @[Mux.scala 81:58]
wire [7:0] _result_T_369 = 16'hb9 == mulResult ? 8'h13 : _result_T_367; // @[Mux.scala 81:58]
wire [7:0] _result_T_371 = 16'hba == mulResult ? 8'h13 : _result_T_369; // @[Mux.scala 81:58]
wire [7:0] _result_T_373 = 16'hbb == mulResult ? 8'h13 : _result_T_371; // @[Mux.scala 81:58]
wire [7:0] _result_T_375 = 16'hbc == mulResult ? 8'h13 : _result_T_373; // @[Mux.scala 81:58]
wire [7:0] _result_T_377 = 16'hbd == mulResult ? 8'h13 : _result_T_375; // @[Mux.scala 81:58]
wire [7:0] _result_T_379 = 16'hbe == mulResult ? 8'h13 : _result_T_377; // @[Mux.scala 81:58]
wire [7:0] _result_T_381 = 16'hbf == mulResult ? 8'h13 : _result_T_379; // @[Mux.scala 81:58]
wire [7:0] _result_T_383 = 16'hc0 == mulResult ? 8'h12 : _result_T_381; // @[Mux.scala 81:58]
wire [7:0] _result_T_385 = 16'hc1 == mulResult ? 8'h12 : _result_T_383; // @[Mux.scala 81:58]
wire [7:0] _result_T_387 = 16'hc2 == mulResult ? 8'h12 : _result_T_385; // @[Mux.scala 81:58]
wire [7:0] _result_T_389 = 16'hc3 == mulResult ? 8'h12 : _result_T_387; // @[Mux.scala 81:58]
wire [7:0] _result_T_391 = 16'hc4 == mulResult ? 8'h12 : _result_T_389; // @[Mux.scala 81:58]
wire [7:0] _result_T_393 = 16'hc5 == mulResult ? 8'h12 : _result_T_391; // @[Mux.scala 81:58]
wire [7:0] _result_T_395 = 16'hc6 == mulResult ? 8'h12 : _result_T_393; // @[Mux.scala 81:58]
wire [7:0] _result_T_397 = 16'hc7 == mulResult ? 8'h12 : _result_T_395; // @[Mux.scala 81:58]
wire [7:0] _result_T_399 = 16'hc8 == mulResult ? 8'h12 : _result_T_397; // @[Mux.scala 81:58]
wire [7:0] _result_T_401 = 16'hc9 == mulResult ? 8'h12 : _result_T_399; // @[Mux.scala 81:58]
wire [7:0] _result_T_403 = 16'hca == mulResult ? 8'h12 : _result_T_401; // @[Mux.scala 81:58]
wire [7:0] _result_T_405 = 16'hcb == mulResult ? 8'h12 : _result_T_403; // @[Mux.scala 81:58]
wire [7:0] _result_T_407 = 16'hcc == mulResult ? 8'h12 : _result_T_405; // @[Mux.scala 81:58]
wire [7:0] _result_T_409 = 16'hcd == mulResult ? 8'h12 : _result_T_407; // @[Mux.scala 81:58]
wire [7:0] _result_T_411 = 16'hce == mulResult ? 8'h12 : _result_T_409; // @[Mux.scala 81:58]
wire [7:0] _result_T_413 = 16'hcf == mulResult ? 8'h12 : _result_T_411; // @[Mux.scala 81:58]
wire [7:0] _result_T_415 = 16'hd0 == mulResult ? 8'h12 : _result_T_413; // @[Mux.scala 81:58]
wire [7:0] _result_T_417 = 16'hd1 == mulResult ? 8'h12 : _result_T_415; // @[Mux.scala 81:58]
wire [7:0] _result_T_419 = 16'hd2 == mulResult ? 8'h12 : _result_T_417; // @[Mux.scala 81:58]
wire [7:0] _result_T_421 = 16'hd3 == mulResult ? 8'h12 : _result_T_419; // @[Mux.scala 81:58]
wire [7:0] _result_T_423 = 16'hd4 == mulResult ? 8'h12 : _result_T_421; // @[Mux.scala 81:58]
wire [7:0] _result_T_425 = 16'hd5 == mulResult ? 8'h12 : _result_T_423; // @[Mux.scala 81:58]
wire [7:0] _result_T_427 = 16'hd6 == mulResult ? 8'h11 : _result_T_425; // @[Mux.scala 81:58]
wire [7:0] _result_T_429 = 16'hd7 == mulResult ? 8'h11 : _result_T_427; // @[Mux.scala 81:58]
wire [7:0] _result_T_431 = 16'hd8 == mulResult ? 8'h11 : _result_T_429; // @[Mux.scala 81:58]
wire [7:0] _result_T_433 = 16'hd9 == mulResult ? 8'h11 : _result_T_431; // @[Mux.scala 81:58]
wire [7:0] _result_T_435 = 16'hda == mulResult ? 8'h11 : _result_T_433; // @[Mux.scala 81:58]
wire [7:0] _result_T_437 = 16'hdb == mulResult ? 8'h11 : _result_T_435; // @[Mux.scala 81:58]
wire [7:0] _result_T_439 = 16'hdc == mulResult ? 8'h11 : _result_T_437; // @[Mux.scala 81:58]
wire [7:0] _result_T_441 = 16'hdd == mulResult ? 8'h11 : _result_T_439; // @[Mux.scala 81:58]
wire [7:0] _result_T_443 = 16'hde == mulResult ? 8'h11 : _result_T_441; // @[Mux.scala 81:58]
wire [7:0] _result_T_445 = 16'hdf == mulResult ? 8'h11 : _result_T_443; // @[Mux.scala 81:58]
wire [7:0] _result_T_447 = 16'he0 == mulResult ? 8'h11 : _result_T_445; // @[Mux.scala 81:58]
wire [7:0] _result_T_449 = 16'he1 == mulResult ? 8'h11 : _result_T_447; // @[Mux.scala 81:58]
wire [7:0] _result_T_451 = 16'he2 == mulResult ? 8'h11 : _result_T_449; // @[Mux.scala 81:58]
wire [7:0] _result_T_453 = 16'he3 == mulResult ? 8'h11 : _result_T_451; // @[Mux.scala 81:58]
wire [7:0] _result_T_455 = 16'he4 == mulResult ? 8'h11 : _result_T_453; // @[Mux.scala 81:58]
wire [7:0] _result_T_457 = 16'he5 == mulResult ? 8'h11 : _result_T_455; // @[Mux.scala 81:58]
wire [7:0] _result_T_459 = 16'he6 == mulResult ? 8'h11 : _result_T_457; // @[Mux.scala 81:58]
wire [7:0] _result_T_461 = 16'he7 == mulResult ? 8'h11 : _result_T_459; // @[Mux.scala 81:58]
wire [7:0] _result_T_463 = 16'he8 == mulResult ? 8'h11 : _result_T_461; // @[Mux.scala 81:58]
wire [7:0] _result_T_465 = 16'he9 == mulResult ? 8'h11 : _result_T_463; // @[Mux.scala 81:58]
wire [7:0] _result_T_467 = 16'hea == mulResult ? 8'h11 : _result_T_465; // @[Mux.scala 81:58]
wire [7:0] _result_T_469 = 16'heb == mulResult ? 8'h11 : _result_T_467; // @[Mux.scala 81:58]
wire [7:0] _result_T_471 = 16'hec == mulResult ? 8'h11 : _result_T_469; // @[Mux.scala 81:58]
wire [7:0] _result_T_473 = 16'hed == mulResult ? 8'h11 : _result_T_471; // @[Mux.scala 81:58]
wire [7:0] _result_T_475 = 16'hee == mulResult ? 8'h11 : _result_T_473; // @[Mux.scala 81:58]
wire [7:0] _result_T_477 = 16'hef == mulResult ? 8'h11 : _result_T_475; // @[Mux.scala 81:58]
wire [7:0] _result_T_479 = 16'hf0 == mulResult ? 8'h11 : _result_T_477; // @[Mux.scala 81:58]
wire [7:0] _result_T_481 = 16'hf1 == mulResult ? 8'h10 : _result_T_479; // @[Mux.scala 81:58]
wire [7:0] _result_T_483 = 16'hf2 == mulResult ? 8'h10 : _result_T_481; // @[Mux.scala 81:58]
wire [7:0] _result_T_485 = 16'hf3 == mulResult ? 8'h10 : _result_T_483; // @[Mux.scala 81:58]
wire [7:0] _result_T_487 = 16'hf4 == mulResult ? 8'h10 : _result_T_485; // @[Mux.scala 81:58]
wire [7:0] _result_T_489 = 16'hf5 == mulResult ? 8'h10 : _result_T_487; // @[Mux.scala 81:58]
wire [7:0] _result_T_491 = 16'hf6 == mulResult ? 8'h10 : _result_T_489; // @[Mux.scala 81:58]
wire [7:0] _result_T_493 = 16'hf7 == mulResult ? 8'h10 : _result_T_491; // @[Mux.scala 81:58]
wire [7:0] _result_T_495 = 16'hf8 == mulResult ? 8'h10 : _result_T_493; // @[Mux.scala 81:58]
wire [7:0] _result_T_497 = 16'hf9 == mulResult ? 8'h10 : _result_T_495; // @[Mux.scala 81:58]
wire [7:0] _result_T_499 = 16'hfa == mulResult ? 8'h10 : _result_T_497; // @[Mux.scala 81:58]
wire [7:0] _result_T_501 = 16'hfb == mulResult ? 8'h10 : _result_T_499; // @[Mux.scala 81:58]
wire [7:0] _result_T_503 = 16'hfc == mulResult ? 8'h10 : _result_T_501; // @[Mux.scala 81:58]
wire [7:0] _result_T_505 = 16'hfd == mulResult ? 8'h10 : _result_T_503; // @[Mux.scala 81:58]
wire [7:0] _result_T_507 = 16'hfe == mulResult ? 8'h10 : _result_T_505; // @[Mux.scala 81:58]
wire [7:0] _result_T_509 = 16'hff == mulResult ? 8'h10 : _result_T_507; // @[Mux.scala 81:58]
wire [7:0] _result_T_511 = 16'h100 == mulResult ? 8'h10 : _result_T_509; // @[Mux.scala 81:58]
wire [7:0] _result_T_513 = 16'h101 == mulResult ? 8'h10 : _result_T_511; // @[Mux.scala 81:58]
wire [7:0] _result_T_515 = 16'h102 == mulResult ? 8'h10 : _result_T_513; // @[Mux.scala 81:58]
wire [7:0] _result_T_517 = 16'h103 == mulResult ? 8'h10 : _result_T_515; // @[Mux.scala 81:58]
wire [7:0] _result_T_519 = 16'h104 == mulResult ? 8'h10 : _result_T_517; // @[Mux.scala 81:58]
wire [7:0] _result_T_521 = 16'h105 == mulResult ? 8'h10 : _result_T_519; // @[Mux.scala 81:58]
wire [7:0] _result_T_523 = 16'h106 == mulResult ? 8'h10 : _result_T_521; // @[Mux.scala 81:58]
wire [7:0] _result_T_525 = 16'h107 == mulResult ? 8'h10 : _result_T_523; // @[Mux.scala 81:58]
wire [7:0] _result_T_527 = 16'h108 == mulResult ? 8'h10 : _result_T_525; // @[Mux.scala 81:58]
wire [7:0] _result_T_529 = 16'h109 == mulResult ? 8'h10 : _result_T_527; // @[Mux.scala 81:58]
wire [7:0] _result_T_531 = 16'h10a == mulResult ? 8'h10 : _result_T_529; // @[Mux.scala 81:58]
wire [7:0] _result_T_533 = 16'h10b == mulResult ? 8'h10 : _result_T_531; // @[Mux.scala 81:58]
wire [7:0] _result_T_535 = 16'h10c == mulResult ? 8'h10 : _result_T_533; // @[Mux.scala 81:58]
wire [7:0] _result_T_537 = 16'h10d == mulResult ? 8'h10 : _result_T_535; // @[Mux.scala 81:58]
wire [7:0] _result_T_539 = 16'h10e == mulResult ? 8'h10 : _result_T_537; // @[Mux.scala 81:58]
wire [7:0] _result_T_541 = 16'h10f == mulResult ? 8'h10 : _result_T_539; // @[Mux.scala 81:58]
wire [7:0] _result_T_543 = 16'h110 == mulResult ? 8'h10 : _result_T_541; // @[Mux.scala 81:58]
wire [1:0] _GEN_1 = mulResult < 16'h71c8 ? 2'h2 : 2'h1; // @[SqrtInv.scala 368:44 369:24 372:24]
wire [1:0] _GEN_2 = mulResult < 16'h28f7 ? 2'h3 : _GEN_1; // @[SqrtInv.scala 365:44 366:24]
wire [2:0] _GEN_3 = mulResult < 16'h14e6 ? 3'h4 : {{1'd0}, _GEN_2}; // @[SqrtInv.scala 362:43 363:24]
wire [2:0] _GEN_4 = mulResult < 16'hca5 ? 3'h5 : _GEN_3; // @[SqrtInv.scala 359:43 360:24]
wire [2:0] _GEN_5 = mulResult < 16'h877 ? 3'h6 : _GEN_4; // @[SqrtInv.scala 356:43 357:24]
wire [2:0] _GEN_6 = mulResult < 16'h610 ? 3'h7 : _GEN_5; // @[SqrtInv.scala 353:43 354:24]
wire [3:0] _GEN_7 = mulResult < 16'h48e ? 4'h8 : {{1'd0}, _GEN_6}; // @[SqrtInv.scala 350:43 351:24]
wire [3:0] _GEN_8 = mulResult < 16'h38c ? 4'h9 : _GEN_7; // @[SqrtInv.scala 347:42 348:24]
wire [3:0] _GEN_9 = mulResult < 16'h2d7 ? 4'ha : _GEN_8; // @[SqrtInv.scala 344:42 345:24]
wire [3:0] _GEN_10 = mulResult < 16'h253 ? 4'hb : _GEN_9; // @[SqrtInv.scala 341:42 342:24]
wire [3:0] _GEN_11 = mulResult < 16'h1f0 ? 4'hc : _GEN_10; // @[SqrtInv.scala 338:42 339:24]
wire [3:0] _GEN_12 = mulResult < 16'h1a4 ? 4'hd : _GEN_11; // @[SqrtInv.scala 335:42 336:24]
wire [3:0] _GEN_13 = mulResult < 16'h168 ? 4'he : _GEN_12; // @[SqrtInv.scala 332:42 333:24]
wire [3:0] _GEN_14 = mulResult < 16'h138 ? 4'hf : _GEN_13; // @[SqrtInv.scala 329:42 330:24]
wire [7:0] _GEN_15 = mulResult < 16'h111 ? _result_T_543 : {{4'd0}, _GEN_14}; // @[SqrtInv.scala 326:37 327:24]
wire [1:0] _GEN_16 = 2'h3 == state ? 2'h0 : state; // @[SqrtInv.scala 309:19 380:19 24:24]
assign io_done = state == 2'h3; // @[SqrtInv.scala 384:23]
assign io_out = result; // @[SqrtInv.scala 385:12]
always @(posedge clock) begin
if (reset) begin // @[SqrtInv.scala 24:24]
state <= 2'h0; // @[SqrtInv.scala 24:24]
end else if (2'h0 == state) begin // @[SqrtInv.scala 309:19]
if (io_start) begin // @[SqrtInv.scala 311:28]
state <= 2'h1; // @[SqrtInv.scala 312:23]
end
end else if (2'h1 == state) begin // @[SqrtInv.scala 309:19]
state <= 2'h2; // @[SqrtInv.scala 318:19]
end else if (2'h2 == state) begin // @[SqrtInv.scala 309:19]
state <= 2'h3; // @[SqrtInv.scala 376:19]
end else begin
state <= _GEN_16;
end
if (reset) begin // @[SqrtInv.scala 28:28]
mulResult <= 16'h0; // @[SqrtInv.scala 28:28]
end else if (!(2'h0 == state)) begin // @[SqrtInv.scala 309:19]
if (2'h1 == state) begin // @[SqrtInv.scala 309:19]
mulResult <= _mulResult_T; // @[SqrtInv.scala 317:23]
end
end
if (reset) begin // @[SqrtInv.scala 29:25]
result <= 8'h0; // @[SqrtInv.scala 29:25]
end else if (!(2'h0 == state)) begin // @[SqrtInv.scala 309:19]
if (!(2'h1 == state)) begin // @[SqrtInv.scala 309:19]
if (2'h2 == state) begin // @[SqrtInv.scala 309:19]
result <= _GEN_15;
end
end
end
end
// Register and memory initialization
`ifdef RANDOMIZE_GARBAGE_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_INVALID_ASSIGN
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_REG_INIT
`define RANDOMIZE
`endif
`ifdef RANDOMIZE_MEM_INIT
`define RANDOMIZE
`endif
`ifndef RANDOM
`define RANDOM $random
`endif
`ifdef RANDOMIZE_MEM_INIT
integer initvar;
`endif
`ifndef SYNTHESIS
`ifdef FIRRTL_BEFORE_INITIAL
`FIRRTL_BEFORE_INITIAL
`endif
initial begin
`ifdef RANDOMIZE
`ifdef INIT_RANDOM
`INIT_RANDOM
`endif
`ifndef VERILATOR
`ifdef RANDOMIZE_DELAY
#`RANDOMIZE_DELAY begin end
`else
#0.002 begin end
`endif
`endif
`ifdef RANDOMIZE_REG_INIT
_RAND_0 = {1{`RANDOM}};
state = _RAND_0[1:0];
_RAND_1 = {1{`RANDOM}};
mulResult = _RAND_1[15:0];
_RAND_2 = {1{`RANDOM}};
result = _RAND_2[7:0];
`endif // RANDOMIZE_REG_INIT
`endif // RANDOMIZE
end // initial
`ifdef FIRRTL_AFTER_INITIAL
`FIRRTL_AFTER_INITIAL
`endif
`endif // SYNTHESIS
endmodule
使用vivado上板测试
这里使用的vivado版本为2023.2,使用系统为Ubuntu22.04,开发板型号为芯驰科技AXU3EGB开发版,该板采用XILINX Zynq UltraScale+ EG芯片型号与双核 ARM Cortex-A53集成方案,其中FPGA型号为XCZU3EG-1SFVC784I。
本次测试均采用其中的PL差分系统时钟源,并将该时钟使用IBUFDS原语转为单端时钟作为系统时钟。配置启动模式为JTAG调试模式。
本文针对各个关键技术优化内容,分模块进行仿真及上板测试。为检测其输入输出逻辑是否符合预期,本文将采用仿真与上板向结合的方式进行,其中仿真生成随机的输入与并判定是否与期望的输出相符合,上板测试将采用仿真阶段生成的输入输出结果,通过嵌入的VIO(Virtual Input/Output)IP核模拟输入,并通过JTAG接口传至FPGA中,并同时监测输出结果。
项目创建过程
略
verilog仿真代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 01/02/2025 09:07:49 PM
// Design Name:
// Module Name: SqrtInvTest
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module SqrtInvTest;
// 输入信号
reg clock;
reg reset;
reg [7:0] start_point_degree;
reg [7:0] end_point_degree;
reg start;
// 输出信号
wire done;
wire [7:0] out;
// 声明变量
integer expected_result;
// real sqrt_input;
integer sqrt_input;
// 仿真测试时去掉注释
SqrtInv sqrtInv_inst (
.clock(clock),
.reset(reset),
.io_start_point_degree(start_point_degree),
.io_end_point_degree(end_point_degree),
.io_start(start),
.io_done(done),
.io_out(out)
);
// 时钟生成
initial begin
clock = 0;
forever #5 clock = ~clock; // 10ns 周期时钟
end
// 测试逻辑
initial begin
// 初始化信号
reset = 1;
start_point_degree = 0;
end_point_degree = 0;
start = 0;
// 复位模块
#20;
reset = 0;
// 开始测试
$display("Start Testing");
// 测试 10 次随机输入
for (integer i = 0; i < 10; i = i + 1) begin
// 生成随机输入
start_point_degree = $urandom % 256;
end_point_degree = $urandom % 256;
start = 1;
// 等待模块完成计算
#10;
start = 0;
while (done == 0) begin
#10; // 每个时钟周期检查一次 done 信号
end
// 计算预期结果
sqrt_input = (start_point_degree) * (end_point_degree); // 将输入转换为 real 类型
$display("Sqrt input: %d", sqrt_input);
expected_result = 256 / ($sqrt(sqrt_input));
// 打印结果
$display("Iteration: %0d, A: %0d, B: %0d, Expected Result: %0d, Actual Result: %0d",
i, start_point_degree, end_point_degree, expected_result, out);
// 断言验证
if (out !== expected_result) begin
$error("Test failed at iteration %0d! Start_point_degree: %0d, End_point_degree: %0d, Expected: %0d, Actual: %0d",
i, start_point_degree, end_point_degree, expected_result, out);
end
#10;
end
// 测试完成
$display("Testing completed");
$finish;
end
endmodule
verilog仿真结果
测试思路同chisel
# run 1000ns
Start Testing
Sqrt input: 33201
Iteration: 0, A: 217, B: 153, Expected Result: 1, Actual Result: 1
Sqrt input: 33300
Iteration: 1, A: 150, B: 222, Expected Result: 1, Actual Result: 1
Sqrt input: 34160
Iteration: 2, A: 140, B: 244, Expected Result: 1, Actual Result: 1
Sqrt input: 14746
Iteration: 3, A: 146, B: 101, Expected Result: 2, Actual Result: 2
Sqrt input: 5680
Iteration: 4, A: 142, B: 40, Expected Result: 3, Actual Result: 3
Sqrt input: 1742
Iteration: 5, A: 67, B: 26, Expected Result: 6, Actual Result: 6
Sqrt input: 6206
Iteration: 6, A: 29, B: 214, Expected Result: 3, Actual Result: 3
Sqrt input: 21888
Iteration: 7, A: 128, B: 171, Expected Result: 2, Actual Result: 2
Sqrt input: 49530
Iteration: 8, A: 254, B: 195, Expected Result: 1, Actual Result: 1
Sqrt input: 5319
Iteration: 9, A: 197, B: 27, Expected Result: 4, Actual Result: 4
Testing completed
$finish called at time : 420 ns : File "/home/wzm/Graduate_project/Graduate_project.srcs/sim_1/new/SqrtInvTest.v" Line 112
INFO: [USF-XSim-96] XSim completed. Design snapshot 'SqrtInvTest_behav' loaded.
INFO: [USF-XSim-97] XSim simulation ran for 1000ns
launch_simulation: Time (s): cpu = 00:00:08 ; elapsed = 00:00:06 . Memory (MB): peak = 8106.234 ; gain = 7.246 ; free physical = 1565 ; free virtual = 9052
设计SqrtInv并将VIO IP核嵌入
点击创建IP核,并在界面中点击“+”,输入VIO,创建VIO IP核
双击VIO IP核,他的输出设计为模块所需的输入,输入设计为模块所需的输出,包括个数和位宽
VIO模拟输出信号,即待测模块输入信号为:
vio_0_probe_out0为start_point_degree,
vio_0_probe_out1为end_point_degree,
vio_0_probe_out2为io_start
VIO模拟输入信号,即待测模块输出信号为:
vio_0_probe_in0为io_done,
vio_0_probe_in1为io_out
上述配置完成后,右键点击对应端口,点击make external,创建端口如下,完成后点击保存,创建对应的IP及VIO.v文件
至此,VIO IP创建完成。
顶层设计与连接
设计顶层文件如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 01/03/2025 03:51:53 PM
// Design Name:
// Module Name: SqurtInv_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module SqrtInv_top(
// 输入信号
input sys_clk_p,
input sys_clk_n,
input reset,
output io_done,
output [7:0] io_out
);
// 差分时钟缓冲器
wire clock;
IBUFDS ibufds_inst (
.I(sys_clk_p), // 差分时钟正端
.IB(sys_clk_n), // 差分时钟负端
.O(clock) // 单端时钟输出
);
// 输出信号
wire io_start;
wire [7:0] start_point_degree;
wire [7:0] end_point_degree;
VIO vio_inst (
.clk_0(clock),
.probe_out0_0(start_point_degree),
.probe_out1_0(end_point_degree),
.probe_out2_0(io_start),
.probe_in0_0(io_out),
.probe_in1_0(io_done)
);
SqrtInv sqrtInv_inst (
.clock(clock),
.reset(reset),
.io_start_point_degree(start_point_degree),
.io_end_point_degree(end_point_degree),
.io_start(io_start),
.io_done(io_done),
.io_out(io_out)
);
endmodule
其中, IBUFDS为内置原语,将开发板上的差分时钟转为单端时钟。
运行综合(SYNTHESIS)
略
配置I/O
点击Open Synthesis Design,打开后点击Windows -> I/O Ports
参考手册对其中的管脚进行分配,完成后点击保存生成xdc文件。
xdc文件如下:
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_SSTL12 [get_ports sys_clk_p]
set_property IOSTANDARD LVCMOS33 [get_ports reset]
set_property IOSTANDARD LVCMOS12 [get_ports io_done]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[7]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[6]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[5]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[4]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[3]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[2]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[1]}]
set_property IOSTANDARD LVCMOS12 [get_ports {io_out[0]}]
set_property PACKAGE_PIN AF2 [get_ports {io_out[7]}]
set_property PACKAGE_PIN AD2 [get_ports {io_out[6]}]
set_property PACKAGE_PIN AD1 [get_ports {io_out[5]}]
set_property PACKAGE_PIN AG1 [get_ports {io_out[4]}]
set_property PACKAGE_PIN AF1 [get_ports {io_out[3]}]
set_property PACKAGE_PIN AH1 [get_ports {io_out[2]}]
set_property PACKAGE_PIN AH2 [get_ports {io_out[1]}]
set_property PACKAGE_PIN AF3 [get_ports {io_out[0]}]
set_property PACKAGE_PIN AE2 [get_ports io_done]
set_property PACKAGE_PIN AF12 [get_ports reset]
create_clock -period 5.000 -name sys_clk_p -waveform {0.000 2.500} [get_ports sys_clk_p]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets clock_BUFG]
时序约束
打开Constraints Wizard,点击Next,在Primary Clocks中点击Recommended Constraints中的时钟,设定频率为200MHz,然后直接点击Skip to Finish保存约束。
综合、布局布线、生成bit流文件
略
上板测试
将开发板调成JTAG模式后接入电脑,在Auto Connect后Program device,写入开发板中。
vio界面弹出,可以模拟输入并检查输出。由于之前先将reset信号绑定在PL_key按键上,这里修改输入的值,设置probe_out2为1(io_start),按下按键,可以看到下面两个模块输出产生一闪而过的变化,如下所示。(如果未能捕获,多按几次按键即可)。至此成功完成验证。