当前位置:网站首页>Understand chisel language thoroughly 16. Detailed explanation of chisel module (III) -- bulk connection of chisel, taking pipeline processor as an example
Understand chisel language thoroughly 16. Detailed explanation of chisel module (III) -- bulk connection of chisel, taking pipeline processor as an example
2022-07-20 16:09:00 【github-3rr0r】
Chisel Module details ( 3、 ... and )——Chisel Overall connection of (Bulk Connection), Take pipeline processor as an example
Generally speaking , One Chisel Modules will have many ports , To connect multi port modules , It would be troublesome to connect one line by one . and Chisel Provided in The whole connection (Bulk Connection) The operator <>
, Can be bundle The part of is connected in two directions , In this way, we can use an operator when connecting components , A lot of convenient . Let's talk about this in this article <>
Usage of operators . But notice :
This <>
stay Chisel3 It can't be used in this way !!!
This <>
stay Chisel3 It can't be used in this way !!!
This <>
stay Chisel3 It can't be used in this way !!!
But here I still want to say , Besides, where has changed , Let's start with .
Chisel2 Integral connection in
<>
The operator is used to connect two bundle, When connecting, connect through the naming of sub fields , If there is no corresponding name , Then don't connect .
for instance , Now suppose we want to write a Pipelined processors , Instruction fetching stage Fetch
The interface of is as follows :
class Fetch extends Module {
val io = IO(new Bundle {
val instr = Output(UInt(32.W))
val pc = Output(UInt(32.W))
})
// fetch The implementation of the phase is omitted
}
The next stage is decoding Decode
:
class Decode extends Module {
val io = IO(new Bundle {
val instr = Input(UInt(32.W))
val pc = Input(UInt(32.W))
val aluOp = Output(UInt(32.W))
val regA = Output(UInt(5.W))
val regB = Output(UInt(5.W))
})
// decode The implementation of the phase is omitted
}
Finally, the implementation stage Execute
:
class Execute extends Module {
val io = IO(new Bundle {
val aluOp = Input(UInt(5.W))
val regA = Input(UInt(32.W))
val regB = Input(UInt(32.W))
val result = Output(UInt(32.W))
})
// execute The implementation of the phase is omitted
}
Now let's go through <>
Operator connects these three stages :
class Top extends Module {
val io = IO(new Bundle {
val result = Input((UInt(32.W)))
val out = Output(Bool())
})
val fetch = Module(new Fetch())
val decode = Module(new Decode())
val execute = Module(new Execute())
fetch.io <> decode.io
decode.io <> execute.io
io <> execute.io
}
Be careful , final io <> execute.io
Connect the port of the parent module with the port of the child module , That's ok .
If everything comes as expected , It should compile and output smoothly Verilog, The news is so exhilarating that everyone is celebrating and spreading it to the rest of the world , But the terminal outputs an error message :
[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-FMTbAKKu-1657687380858)(16.Chisel Module details ( 3、 ... and )——Chisel Overall connection of (Bulk Connection)/image-20220712141526240.png)]
mean ,<>
The module on the right has interfaces , The module on the left must also have ? It seems that this operator has changed according to the version , So I went to Chisel-book Of Github The warehouse issue I looked inside , If someone really encountered this problem :What do we do if we still want partial bulk connection · Issue #18 · schoeberl/chisel-book (github.com)
Turned out to be Chisel3 in <>
I can't use it anymore ! It's a shame !
Official website Chisel/FIRRTL: Chisel3 vs. Chisel2 (chisel-lang.org) Given in Chisel3 and Chisel2 The difference between , There is a passage in it :
in Chisel2, bulk-connects
<>
with unconnected source components do not update connections from the unconnected components. ** In Chisel3, bulk-connects strictly adhere to last connection semantics and unconnected OUTPUTs will be connected to INPUTs resulting in the assignment of random values to those inputs.
Translate :
Chisel2 in , There is an overall connection of unconnected source components <>
Connections of unconnected components will not be updated ; And in the Chisel3 in , The whole connection strictly follows the last connection semantics , Unconnected outputs are connected to inputs , This will cause these inputs to be assigned random values .
Do you understand ? Anyway, I didn't understand . You might as well listen to the one who is issue Next reply to my friend's words :
I’m sorry that I have not understanded how to use <> in Chisel3.In my opinion, you should avoid to use <> in Chisel3.
I agree with , It's over without this overall connection .
Chisel3 Integral connection in
But that doesn't solve the problem , Let's change the solution .
We can encapsulate all interfaces between each two modules into one Bundle
, Then define the module IO The use of interfaces uses these Bundle
, such as :
// Fetch Phase and Decode Phase of the connection bundle
class FetchDecodeIO extends Bundle {
val instr = Output(UInt(32.W))
val pc = Output(UInt(32.W))
}
class Fetch extends Module {
val io = IO(new Bundle {
val fetchdecodeIO = new FetchDecodeIO()
})
// fetch The implementation of the phase is omitted
}
class Decode extends Module {
val io = IO(new Bundle {
val fetchdecodeIO = Flipped(new FetchDecodeIO())
})
// decode The implementation of the phase is omitted
}
Be careful , Because of the definition Bundle It's always Output
, and Decode
Stages are input , So we need to Flipped()
once , Flip the input and output . So for this three-stage assembly line , We could write it this way :
import chisel3._
import chisel3.util._
class FetchDecodeIO extends Bundle {
val instr = Output(UInt(32.W))
val pc = Output(UInt(32.W))
}
class Fetch extends Module {
val io = IO(new Bundle {
val fetchdecodeIO = new FetchDecodeIO()
val a = Input(UInt(32.W))
val b = Input(UInt(32.W))
})
// fetch The implementation of the phase is omitted
io.fetchdecodeIO.instr := io.a
io.fetchdecodeIO.pc := io.b
}
class DecodeExecuteIO extends Bundle {
val aluOp = Output(UInt(5.W))
val regA = Output(UInt(32.W))
val regB = Output(UInt(32.W))
}
class Decode extends Module {
val io = IO(new Bundle {
val fetchdecodeIO = Flipped(new FetchDecodeIO())
val decodeexecuteIO = new DecodeExecuteIO()
})
// decode The implementation of the phase is omitted
io.decodeexecuteIO.aluOp := io.fetchdecodeIO.instr(5, 0)
io.decodeexecuteIO.regA := io.fetchdecodeIO.instr
io.decodeexecuteIO.regB := io.fetchdecodeIO.pc
}
class ExecuteTopIO extends Bundle {
val result1 = Output(UInt(32.W))
val result2 = Output(UInt(32.W))
}
class Execute extends Module {
val io = IO(new Bundle {
val decodeexecuteIO = Flipped(new DecodeExecuteIO())
val executetopIO = new ExecuteTopIO()
})
// execute The implementation of the phase is omitted
io.executetopIO.result1 := io.decodeexecuteIO.regA
io.executetopIO.result2 := io.decodeexecuteIO.regB
}
class Top extends Module {
val io = IO(new Bundle {
val a = Input(UInt(32.W))
val b = Input(UInt(32.W))
val executetopIO = new ExecuteTopIO()
})
val fetch = Module(new Fetch())
val decode = Module(new Decode())
val execute = Module(new Execute())
fetch.io.a := io.a
fetch.io.b := io.b
fetch.io.fetchdecodeIO <> decode.io.fetchdecodeIO
decode.io.decodeexecuteIO <> execute.io.decodeexecuteIO
io.executetopIO <> execute.io.executetopIO
}
object MyModule extends App {
// emitVerilog(new Count10(), Array("--target-dir", "generated"))
println(getVerilogString(new Top()))
}
Be careful , We are Top
Use... In the module executetopIO
There is no flipping when , This is because Execute
The module is in Top
Inside , It should be understood as Execute
The output of the module is used as Top
The output of the module is right . And some of them io.a
and io.b
It's to generate Verilog Random signals added by code , No practical significance . Finally generated Verilog The code is as follows :
module Fetch(
output [31:0] io_fetchdecodeIO_instr,
output [31:0] io_fetchdecodeIO_pc,
input [31:0] io_a,
input [31:0] io_b
);
assign io_fetchdecodeIO_instr = io_a; // @[hello.scala 18:28]
assign io_fetchdecodeIO_pc = io_b; // @[hello.scala 19:25]
endmodule
module Decode(
input [31:0] io_fetchdecodeIO_instr,
input [31:0] io_fetchdecodeIO_pc,
output [31:0] io_decodeexecuteIO_regA,
output [31:0] io_decodeexecuteIO_regB
);
assign io_decodeexecuteIO_regA = io_fetchdecodeIO_instr; // @[hello.scala 35:29]
assign io_decodeexecuteIO_regB = io_fetchdecodeIO_pc; // @[hello.scala 36:29]
endmodule
module Execute(
input [31:0] io_decodeexecuteIO_regA,
input [31:0] io_decodeexecuteIO_regB,
output [31:0] io_executetopIO_result1,
output [31:0] io_executetopIO_result2
);
assign io_executetopIO_result1 = io_decodeexecuteIO_regA; // @[hello.scala 50:29]
assign io_executetopIO_result2 = io_decodeexecuteIO_regB; // @[hello.scala 51:29]
endmodule
module Top(
input clock,
input reset,
input [31:0] io_a,
input [31:0] io_b,
output [31:0] io_executetopIO_result1,
output [31:0] io_executetopIO_result2
);
wire [31:0] fetch_io_fetchdecodeIO_instr; // @[hello.scala 61:23]
wire [31:0] fetch_io_fetchdecodeIO_pc; // @[hello.scala 61:23]
wire [31:0] fetch_io_a; // @[hello.scala 61:23]
wire [31:0] fetch_io_b; // @[hello.scala 61:23]
wire [31:0] decode_io_fetchdecodeIO_instr; // @[hello.scala 62:24]
wire [31:0] decode_io_fetchdecodeIO_pc; // @[hello.scala 62:24]
wire [31:0] decode_io_decodeexecuteIO_regA; // @[hello.scala 62:24]
wire [31:0] decode_io_decodeexecuteIO_regB; // @[hello.scala 62:24]
wire [31:0] execute_io_decodeexecuteIO_regA; // @[hello.scala 63:25]
wire [31:0] execute_io_decodeexecuteIO_regB; // @[hello.scala 63:25]
wire [31:0] execute_io_executetopIO_result1; // @[hello.scala 63:25]
wire [31:0] execute_io_executetopIO_result2; // @[hello.scala 63:25]
Fetch fetch ( // @[hello.scala 61:23]
.io_fetchdecodeIO_instr(fetch_io_fetchdecodeIO_instr),
.io_fetchdecodeIO_pc(fetch_io_fetchdecodeIO_pc),
.io_a(fetch_io_a),
.io_b(fetch_io_b)
);
Decode decode ( // @[hello.scala 62:24]
.io_fetchdecodeIO_instr(decode_io_fetchdecodeIO_instr),
.io_fetchdecodeIO_pc(decode_io_fetchdecodeIO_pc),
.io_decodeexecuteIO_regA(decode_io_decodeexecuteIO_regA),
.io_decodeexecuteIO_regB(decode_io_decodeexecuteIO_regB)
);
Execute execute ( // @[hello.scala 63:25]
.io_decodeexecuteIO_regA(execute_io_decodeexecuteIO_regA),
.io_decodeexecuteIO_regB(execute_io_decodeexecuteIO_regB),
.io_executetopIO_result1(execute_io_executetopIO_result1),
.io_executetopIO_result2(execute_io_executetopIO_result2)
);
assign io_executetopIO_result1 = execute_io_executetopIO_result1; // @[hello.scala 69:21]
assign io_executetopIO_result2 = execute_io_executetopIO_result2; // @[hello.scala 69:21]
assign fetch_io_a = io_a; // @[hello.scala 65:16]
assign fetch_io_b = io_b; // @[hello.scala 66:16]
assign decode_io_fetchdecodeIO_instr = fetch_io_fetchdecodeIO_instr; // @[hello.scala 67:28]
assign decode_io_fetchdecodeIO_pc = fetch_io_fetchdecodeIO_pc; // @[hello.scala 67:28]
assign execute_io_decodeexecuteIO_regA = decode_io_decodeexecuteIO_regA; // @[hello.scala 68:31]
assign execute_io_decodeexecuteIO_regB = decode_io_decodeexecuteIO_regB; // @[hello.scala 68:31]
endmodule
You can see ,Verilog Number of lines of code and Chisel The number of lines of code is basically the same , But exclude the parentheses 、 Empty these ,Chisel The amount of code is much less , And readability is better than Verilog The code is much better , The most important time to write is much clearer !
Conclusion
Having a whole connection can make code writing more efficient , Readability is better , But notice Chisel2 To Chisel3 The change of , Right in Chisel3 Use integral connection in .
边栏推荐
猜你喜欢
Phase mechanism in UVM
Which is the best test management tool?
深入了解JUC并发(八)线程池
【redis入门系列】初识 redis以及redis的安装
Don't understand MySQL database? Alibaba P8 architects will show you MySQL and Optimization in simple terms
En savoir plus sur le pool de Threads simultanés juc (VIII)
Bi skills - same month on month calculation
[matlab project practice] Research on UAV image compression technology based on region of interest
Fiddler设置断点(一)
走进首个通用无代码开发平台—iVX
随机推荐
kubeadm介绍
Notes in October 2020
详解redis 中Pipeline流水线机制
Go printf how to format output, structure format output, one-stop solution to all troubles
IMX8M RTL8201F以太网调试
数据中台、商业智能BI业务访谈(一):行业和业务研究的准备
Wechat applet (login, sharing, payment)
“还是太年轻”,实习生花2分钟解决bug,老程序员的反应耐人寻味
【redis入门系列】初识 redis以及redis的安装
【SCADA案例】mySCADA助力Vib公司实现产线现代化升级
In depth understanding of JUC concurrent (VIII) thread pool
DS(LineLinkStorStruct)
Preparation Notes: opencv learning: color recognition
MongoDB和Redis的区别是什么
DS(ArrayStructure)
Deep understanding of JUC concurrency (IX) deep understanding of CAS
广州深入开展经营性自建房安全整治“百日行动” 两个月排查房屋逾两百万栋
How does markdown draw a sequence diagram? One is enough
C language simulation to realize character function and memory function
走进首个通用无代码开发平台—iVX