当前位置:网站首页>Chisel tutorial - 05 Sequential logic in chisel (including explicit multi clock, explicit synchronous reset and explicit asynchronous reset)
Chisel tutorial - 05 Sequential logic in chisel (including explicit multi clock, explicit synchronous reset and explicit asynchronous reset)
2022-07-07 23:41:00 【github-3rr0r】
Sequential logic
motivation
It is impossible for us to write a meaningful digital logic circuit without States !
It is impossible for us to write a meaningful digital logic circuit without States !
It is impossible for us to write a meaningful digital logic circuit without States !
Say the important thing three times !
Because nothing can be done without storing intermediate results .
This section describes how to use Chisel Express general temporal logic , At the end of this section , You should have a spare Chisel Implement and test the ability of a shift register .
It should be emphasized that this section may not be too shocking , because Chisel The power of is not reflected in the temporal logic pattern , But in the parameterization of design . This ability has been demonstrated before , Now we have to learn about the temporal patterns . therefore , This section will show Chisel Than Verilog Well done place , Just learn some grammar .
register (Register)
Chisel The basic stateful element in is a register , The symbol is Reg
.Reg
It will keep its output value until the rising edge of its clock , At the rising edge, new data is accepted as input . By default , Every Chisel Each module has an implicit clock , Used by each register in the design . This saves the time of specifying the same clock signal in the code every time .
Use of registers
The following code implements a module , It takes an input , Then add 1 And connected to the input of a register .
Be careful : Implicit clock can be covered by multi clock design , See the examples in the appendix below .
// MyModule.scala
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(12.W))
val out = Output(UInt(12.W))
})
val register = Reg(UInt(12.W))
register := io.in + 1.U
io.out := register
}
object MyModule extends App {
println(getVerilogString(new MyModule))
}
// MyModuleTest.scala
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "MyModule"
it should "get right results" in {
test(new MyModule) {
c =>
for (i <- 0 until 100) {
c.io.in.poke(i.U)
c.clock.step(1)
c.io.out.expect((i + 1).U)
}
}
println("SUCCESS!!")
}
}
Register by calling Reg(tpe)
, here tpe
It refers to variables that encode register types , Here is a 12bit Of UInt
.
Then look at what's done in the tester . Calling poke
and expect
Between , There is one step(1)
Call to . This tells the tester to push (tick) Primary clock , This will cause the register to pass its input to the output . call step(n)
will tick The clock n Time .
If you are scheming 0, Then you can notice that there is no call in the tester of combinatorial logic step()
Of . This is because calling on an input poke()
The value will be immediately passed and updated through combinatorial logic . Only in temporal logic ,step()
Is necessary .
Generated Verilog The code is as follows ( It can be seen that it is very complicated !):
module MyModule(
input clock,
input reset,
input [11:0] io_in,
output [11:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [11:0] register; // @[MyModule.scala 10:21]
assign io_out = register; // @[MyModule.scala 12:10]
always @(posedge clock) begin
register <= io_in + 12'h1; // @[MyModule.scala 11:21]
end
// Register and memory initialization
... // Omit
endmodule
Observe this generated Verilog Code , It can be noted that :
- This module has a clock input and a reset input , This is not explicitly added by myself ;
- Variable
register
As expected, it becamereg [11:0]
; - There is a long code block , With ``ifdef RANDOMIZE` start , Used to initialize the register value to a random number before the simulation starts ;
register
On the rising edge of the clock (@(posedge clock)
) to update .
Another thing to note is ,Chisel In type ( Such as UInt
) And hardware nodes ( Such as literal value 2.U
or myReg
Output ) There is a distinction between :
val myReg = Reg(UInt(2.W))
It's legal. , because Reg
Need a data type as a model ;
val myReg = Reg(2.U)
This will lead to errors , because 2.U
It's a node , It cannot be used as a model .
RegNext
Use
Chisel There is a useful register object , Register for simple input connection . The previous module can be shortened to the following code :
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(12.W))
val out = Output(UInt(12.W))
})
io.out := RegNext(io.in + 1.U)
}
object MyModule extends App {
println(getVerilogString(new MyModule))
}
Here are two points to note :
RegNext
The value will be updated to the output on the rising edge of the next clock ;- The width of the register is not specified here , But it can be achieved by Output The connection of infers , Here is the
io.out
Width ;
Generated Verilog The code is as follows :
module MyModule(
input clock,
input reset,
input [11:0] io_in,
output [11:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [11:0] io_out_REG; // @[MyModule.scala 10:20]
assign io_out = io_out_REG; // @[MyModule.scala 10:10]
always @(posedge clock) begin
io_out_REG <= io_in + 12'h1; // @[MyModule.scala 10:27]
end
// Register and memory initialization
... // Omit
endmodule
It is very similar to the previous code , Only the name of the register is automatically generated (io_out_REG
) Not explicitly defined .
The test passed .
RegInit
Use
In the module above , Registers are initialized to a random value during simulation . Unless specified , The register has no reset value .
Can pass RegInit
To create registers and specify reset values .
such as , Will a 12bit The register of is initialized to 0 It can be written like this :
val myReg = RegInit(UInt(12.W), 0.U)
perhaps :
val myReg = RegInit(0.U(12.W))
The first method has two parameters , The first parameter is the type node , Specify the width and type of register , The second parameter is a hardware node , Specify the reset value of the register , Here is the 0.
The second method has only one parameter , The parameter is a hardware node , It's usually 0.U
,0.U(12.W)
Is the use of mandatory width .
Now add initialization to the previous code :
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(12.W))
val out = Output(UInt(12.W))
})
val register = RegInit(0.U(12.W))
register := io.in + 1.U
io.out := register
}
object MyModule extends App {
println(getVerilogString(new MyModule))
}
Output is as follows :
module MyModule(
input clock,
input reset,
input [11:0] io_in,
output [11:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [11:0] register; // @[MyModule.scala 10:25]
wire [11:0] _register_T_1 = io_in + 12'h1; // @[MyModule.scala 11:21]
assign io_out = register; // @[MyModule.scala 12:10]
always @(posedge clock) begin
if (reset) begin // @[MyModule.scala 10:25]
register <= 12'h0; // @[MyModule.scala 10:25]
end else begin
register <= _register_T_1; // @[MyModule.scala 11:12]
end
end
// Register and memory initialization
... // Omit
endmodule
It can be observed that Verilog There are already pairs in the code reset
Check the signal , Used to reset the register to 0. And this reset operation is in always @(posedge clock)
In the code block .
Chisel The implicit reset of is active at high level (active high) And synchronized (synchronous) Of .
Before the reset , The register will still be initialized to a random number .
PeekPokeTesters
Always call reset before running the test , But you can also use reset(n)
Manually call the reset function , The reset signal will remain n High level of clock cycles .
Combine the control flow of the register
And use wire The control flow of is similar , Both have final connection semantics and support when
,elsewhen
and otherwise
structure .
The following code uses the control flow to find the maximum value in a sequence :
// MyModule.scala
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(10.W))
val max = Output(UInt(10.W))
})
val max = RegInit(0.U(10.W))
when(io.in > max) {
max := io.in
}
io.max := max
}
object MyModule extends App {
println(getVerilogString(new MyModule))
}
// MyModuleTest.scala
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "MyModule"
it should "get right results" in {
test(new MyModule) {
c =>
c.io.max.expect(0.U)
c.io.in.poke(1.U)
c.clock.step(1)
c.io.max.expect(1.U)
c.io.in.poke(3.U)
c.clock.step(1)
c.io.max.expect(3.U)
c.io.in.poke(2.U)
c.clock.step(1)
c.io.max.expect(3.U)
c.io.in.poke(24.U)
c.clock.step(1)
c.io.max.expect(24.U)
}
println("SUCCESS!!")
}
}
Output Verilog The code is as follows :
module MyModule(
input clock,
input reset,
input [9:0] io_in,
output [9:0] io_max
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [9:0] max; // @[MyModule.scala 10:20]
assign io_max = max; // @[MyModule.scala 14:10]
always @(posedge clock) begin
if (reset) begin // @[MyModule.scala 10:20]
max <= 10'h0; // @[MyModule.scala 10:20]
end else if (io_in > max) begin // @[MyModule.scala 11:21]
max <= io_in; // @[MyModule.scala 12:9]
end
end
// Register and memory initialization
... // Omit
endmodule
Another example of register
The operation on the register is on the register Output Performed on , And the type of operation is based on the type of register , This means that it can be written like this :
val reg: UInt = Reg(UInt(4.W))
This means reg
It's a UInt
Type value , So it can be executed UInt
The operating , Such as addition and subtraction .
whatever chisel.Data
You can do this for all data types in , Include SInt
etc. .
Here is a comb filter (Comb Filter, This means that the output of each clock cycle is equal to the input of this round minus the input of the previous round ) The implementation of the :
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(SInt(12.W))
val out = Output(SInt(12.W))
})
val delay: SInt = Reg(SInt(12.W))
delay := io.in
io.out := io.in - delay
}
object MyModule extends App {
println(getVerilogString(new MyModule))
}
The meaning is as follows :
val delay: SInt = Reg(SInt(12.W))
Expressdelay
It's a register ,delay
The following designation of types can be omitted ;delay := io.in
Indicates that the input of the register is connected toio.in
, The register will be updated on the rising edge of the next clock ;io.out := io.in - delay
It means that you willio.in
And the value of the current register ( Input of last cycle ) The difference is connected toio.out
On .
Generated Verilog The code is as follows :
module MyModule(
input clock,
input reset,
input [11:0] io_in,
output [11:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [11:0] delay; // @[MyModule.scala 10:18]
assign io_out = $signed(io_in) - $signed(delay); // @[MyModule.scala 12:19]
always @(posedge clock) begin
delay <= io_in; // @[MyModule.scala 11:9]
end
// Register and memory initialization
... // Omit
endmodule
practice
Implementation of shift register
For now LFSR( Linear feedback shift register ) Implement a shift register , requirement :
- Every element is 1bit wide ;
- Yes 4bit The signal output of ;
- Accept one 1bit Input , This input is the next value to enter the shift register ;
- Parallel output of output shift register , May need to use
Cat
; - The output is initialized to
b0001
; - Every clock cycle shifts ( No enable signal );
- Be careful : stay Chisel in , The assignment of subwords is illegal , such as
out(0) := in
No way. .
A brief analysis of , You need a register to store the current value , Connect to output , The current value is shifted one bit to the left, and the input 1bit, Use or to calculate , Then as the state of the next clock cycle . therefore , The code implementation is as follows :
// MyModule.scala
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(Bool())
val out = Output(UInt(4.W))
})
val state = RegInit(UInt(4.W), 1.U)
val nextState = state << 1 | io.in
state := nextState
io.out := state
}
object MyModule extends App {
println(getVerilogString(new MyModule))
}
// MyModuleTest.scala
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "MyModule"
it should "get right results" in {
test(new MyModule) {
c =>
var state = 1
for (i <- 0 until 10) {
// poke in LSB of i (i % 2)
c.io.in.poke(((i % 2) != 0).B)
// update expected state
state = ((state * 2) + (i % 2)) & 0xf
c.clock.step(1)
c.io.out.expect(state.U)
}
}
println("SUCCESS!!")
}
}
Generated Verilog The code is as follows :
module MyModule(
input clock,
input reset,
input io_in,
output [3:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [3:0] state; // @[MyModule.scala 10:22]
wire [4:0] _nextState_T = {state, 1'h0}; // @[MyModule.scala 12:25]
wire [4:0] _GEN_0 = {
{4'd0}, io_in}; // @[MyModule.scala 12:30]
wire [4:0] nextState = _nextState_T | _GEN_0; // @[MyModule.scala 12:30]
wire [4:0] _GEN_1 = reset ? 5'h1 : nextState; // @[MyModule.scala 10:{22,22} 13:9]
assign io_out = state; // @[MyModule.scala 14:10]
always @(posedge clock) begin
state <= _GEN_1[3:0]; // @[MyModule.scala 10:{22,22} 13:9]
end
// Register and memory initialization
... // Omit
endmodule
The test passed .
Parameterized shift register
Now write another parameterized shift register , Through it delay(n
) And the initial value (init
) To parameterize , There is also an enable signal input .(delay It means that the input will delay several clock cycles before output , That is, the width of the shift register )
The code is as follows :
// MyModule.scala
import chisel3._
import chisel3.util._
class MyModule(val n: Int, val init: BigInt = 1) extends Module {
val io = IO(new Bundle {
val en = Input(Bool())
val in = Input(Bool())
val out = Output(UInt(n.W))
})
val state = RegInit(UInt(n.W), init.U)
val nextState = state << 1 | io.in
when (io.en) {
state := nextState
}
io.out := state
}
object MyModule extends App {
println(getVerilogString(new MyModule(10, 2)))
}
// MyModuleTest.scala
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "MyModule"
it should "get right results" in {
for (i <- Seq(3, 4, 8, 24, 65)) {
println(s"Testing n=$i")
test(new MyModule(n = i)) {
c =>
val inSeq = Seq(0, 1, 1, 1, 0, 1, 1, 0, 0, 1)
var state = c.init
var i = 0
c.io.en.poke(true.B)
while (i < 10 * c.n) {
// poke in repeated inSeq
val toPoke = inSeq(i % inSeq.length)
c.io.in.poke((toPoke != 0).B)
// update expected state
state = ((state * 2) + toPoke) & BigInt("1"*c.n, 2)
c.clock.step(1)
c.io.out.expect(state.U)
i += 1
}
}
}
println("SUCCESS!!")
}
}
Verilog Output is as follows :
module MyModule(
input clock,
input reset,
input io_en,
input io_in,
output [9:0] io_out
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
reg [9:0] state; // @[MyModule.scala 11:22]
wire [10:0] _nextState_T = {state, 1'h0}; // @[MyModule.scala 12:25]
wire [10:0] _GEN_1 = {
{10'd0}, io_in}; // @[MyModule.scala 12:30]
wire [10:0] nextState = _nextState_T | _GEN_1; // @[MyModule.scala 12:30]
wire [10:0] _GEN_0 = io_en ? nextState : {
{1'd0}, state}; // @[MyModule.scala 13:16 14:11 11:22]
wire [10:0] _GEN_2 = reset ? 11'h2 : _GEN_0; // @[MyModule.scala 11:{22,22}]
assign io_out = state; // @[MyModule.scala 16:10]
always @(posedge clock) begin
state <= _GEN_2[9:0]; // @[MyModule.scala 11:{22,22}]
end
// Register and memory initialization
... // Omit
endmodule
The test passed .
Explicit clock and reset
Chisel The module has a default clock and reset signal , Each register created in the module implicitly uses them .
If you want to override this default behavior , Maybe there is a black box that can generate a clock or reset signal , Maybe there is a multi clock design .
Synchronous multi clock and synchronous reset
Chisel Provides a structure to handle this situation , The clock and reset signal pass withClock() {}
,withReset() {}
and withClockAndReset() {}
Cover separately or together . The following code gives examples of using these functions , It is a module with multiple clock signals and reset signals :
// MyModule.scala
import chisel3._
import chisel3.util._
// In the old version, this is an experimental feature , And the tester does not support ( The tester does not support it now )
// import chisel3.experimental.{withClock, withReset, withClockAndReset}
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(10.W))
val alternateReset = Input(Bool())
val alternateClock = Input(Clock())
val outImplicit = Output(UInt())
val outAlternateReset = Output(UInt())
val outAlternateClock = Output(UInt())
val outAlternateBoth = Output(UInt())
})
val imp = RegInit(0.U(10.W))
imp := io.in
io.outImplicit := imp
withReset(io.alternateReset) {
val altRst = RegInit(0.U(10.W))
altRst := io.in
io.outAlternateReset := altRst
}
withClock(io.alternateClock) {
val altClk = RegInit(0.U(10.W))
altClk := io.in
io.outAlternateClock := altClk
}
withClockAndReset(io.alternateClock, io.alternateReset) {
val alt = RegInit(0.U(10.W))
alt := io.in
io.outAlternateBoth := alt
}
}
object MyModule extends App {
println(getVerilogString(new MyModule()))
}
// MyModuleTest.scala
// current version Chisel(3.5) The multi clock feature on the tester is not supported
Note that there reset
The signal is synchronous and of type Bool
,Reset
Type cannot be used in top-level input .
Chisel 3.2 Start to support asynchronous reset 了 , The type is AsyncReset()
.
The clock is Chisel Has its own type (Clock
) And it must be stated .
Bool
Can pass asClock()
Convert to Clock
, But don't do stupid things when you use it .
Output Verilog The code is as follows :
module MyModule(
input clock,
input reset,
input [9:0] io_in,
input io_alternateReset,
input io_alternateClock,
output [9:0] io_outImplicit,
output [9:0] io_outAlternateReset,
output [9:0] io_outAlternateClock,
output [9:0] io_outAlternateBoth
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
reg [31:0] _RAND_1;
reg [31:0] _RAND_2;
reg [31:0] _RAND_3;
`endif // RANDOMIZE_REG_INIT
reg [9:0] imp; // @[MyModule.scala 17:20]
reg [9:0] altRst; // @[MyModule.scala 22:25]
reg [9:0] altClk; // @[MyModule.scala 28:25]
reg [9:0] alt; // @[MyModule.scala 34:22]
assign io_outImplicit = imp; // @[MyModule.scala 19:18]
assign io_outAlternateReset = altRst; // @[MyModule.scala 24:26]
assign io_outAlternateClock = altClk; // @[MyModule.scala 30:26]
assign io_outAlternateBoth = alt; // @[MyModule.scala 36:25]
always @(posedge clock) begin
if (reset) begin // @[MyModule.scala 17:20]
imp <= 10'h0; // @[MyModule.scala 17:20]
end else begin
imp <= io_in; // @[MyModule.scala 18:7]
end
if (io_alternateReset) begin // @[MyModule.scala 22:25]
altRst <= 10'h0; // @[MyModule.scala 22:25]
end else begin
altRst <= io_in; // @[MyModule.scala 23:12]
end
end
always @(posedge io_alternateClock) begin
if (reset) begin // @[MyModule.scala 28:25]
altClk <= 10'h0; // @[MyModule.scala 28:25]
end else begin
altClk <= io_in; // @[MyModule.scala 29:12]
end
if (io_alternateReset) begin // @[MyModule.scala 34:22]
alt <= 10'h0; // @[MyModule.scala 34:22]
end else begin
alt <= io_in; // @[MyModule.scala 35:9]
end
end
// Register and memory initialization
... // Omit
endmodule
It does not support multiple clocks, so it is impossible to test , I won't test it .
But the reset signal can still be tested :
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "MyModule"
it should "get right results" in {
test(new MyModule) {
c =>
c.io.in.poke(111.U)
c.io.alternateReset.poke(false.B)
c.clock.step(1)
c.io.outImplicit.expect(111.U)
c.io.outAlternateReset.expect(111.U)
c.reset.poke(true.B)
c.clock.step(1)
c.io.outImplicit.expect(0.U)
c.io.outAlternateReset.expect(111.U)
c.io.alternateReset.poke(true.B)
c.clock.step(1)
c.io.outAlternateReset.expect(0.U)
}
println("SUCCESS!!")
}
}
The test passed .
Asynchronous reset
Then there is the asynchronous reset signal , The code is as follows :
// MyModule.scala
import chisel3._
import chisel3.util._
class MyModule extends Module {
val io = IO(new Bundle {
val in = Input(UInt(10.W))
val alternateAsyncReset = Input(Bool()) // Synchronous reset signal
val outImplicit = Output(UInt())
val outAlternateAsyncReset = Output(UInt())
})
val imp = RegInit(0.U(10.W))
imp := io.in
io.outImplicit := imp
withReset(io.alternateAsyncReset.asAsyncReset()) {
// Convert to asynchronous reset signal using
val altRst = RegInit(0.U(10.W))
altRst := io.in
io.outAlternateAsyncReset := altRst
}
}
object MyModule extends App {
println(getVerilogString(new MyModule()))
}
// MyModuleTest.scala
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
class MyModuleTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "MyModule"
it should "get right results" in {
test(new MyModule) {
c =>
c.io.in.poke(111.U)
c.io.alternateAsyncReset.poke(false.B)
c.clock.step(1)
c.io.outImplicit.expect(111.U)
c.io.outAlternateAsyncReset.expect(111.U)
c.reset.poke(true.B)
c.clock.step(1)
c.io.outImplicit.expect(0.U)
c.io.outAlternateAsyncReset.expect(111.U)
c.io.alternateAsyncReset.poke(true.B)
// c.clock.step(1) // Here, direct asynchronous reset , Instead of waiting for the next clock cycle
c.io.outAlternateAsyncReset.expect(0.U)
}
println("SUCCESS!!")
}
}
Output Verilog The code is as follows :
module MyModule(
input clock,
input reset,
input [9:0] io_in,
input io_alternateAsyncReset,
output [9:0] io_outImplicit,
output [9:0] io_outAlternateAsyncReset
);
`ifdef RANDOMIZE_REG_INIT
reg [31:0] _RAND_0;
reg [31:0] _RAND_1;
`endif // RANDOMIZE_REG_INIT
reg [9:0] imp; // @[MyModule.scala 14:20]
reg [9:0] altRst; // @[MyModule.scala 19:25]
assign io_outImplicit = imp; // @[MyModule.scala 16:18]
assign io_outAlternateAsyncReset = altRst; // @[MyModule.scala 21:31]
always @(posedge clock) begin
if (reset) begin // @[MyModule.scala 14:20]
imp <= 10'h0; // @[MyModule.scala 14:20]
end else begin
imp <= io_in; // @[MyModule.scala 15:7]
end
end
always @(posedge clock or posedge io_alternateAsyncReset) begin
if (io_alternateAsyncReset) begin // @[MyModule.scala 19:25]
altRst <= 10'h0; // @[MyModule.scala 19:25]
end else begin
altRst <= io_in; // @[MyModule.scala 20:12]
end
end
// Register and memory initialization
... // Omit
endmodule
The test passed .
边栏推荐
猜你喜欢
SAP memory parameter tuning process
SAP 内存参数调优过程
Learn about scratch
archery安装测试
Wechat applet development beginner 1
Benchmarking Detection Transfer Learning with Vision Transformers(2021-11)
激光slam学习(2D/3D、偏实践)
二叉排序树【BST】——创建、查找、删除、输出
Ora-01741 and ora-01704
Solution of intelligent supply chain collaboration platform in electronic equipment industry: solve inefficiency and enable digital upgrading of industry
随机推荐
go time包常用函数
Anti climbing means cracking the second
ping报错:未知的名称或服务
[untitled]
Given an array, such as [7864, 284, 347, 7732, 8498], now you need to splice the numbers in the array to return the "largest possible number."
P1055 [noip2008 popularization group] ISBN number
C语言学习
Pycharm essential plug-in, change the background (self use, continuous update) | CSDN creation punch in
Map operation execution process
May day d-light
c—线性表
Jisuan Ke - t3104
Take you hand in hand to build Eureka client with idea
SAP HR 家庭成员信息
Anxin can internally test offline voice module vb-01 to communicate with esp-c3-12f
[stm32+esp8266 connect Tencent cloud IOT development platform 2] stm32+esp8266-01s connect Tencent cloud
SAP HR social work experience 0023
Enumeration, simulation, and sorting
【汇总】看过的一些Panel与视频
Anxin vb01 offline voice module access intelligent curtain guidance