深圳大学-计算机系统(3)-实验三取指和指令译码设计
实验目标
设计完成一个连续取指令并进行指令译码的电路,从而掌握设计简单数据通路的基本方法。
实验内容
本实验分成三周(三次)完成:1)首先完成一个译码器(30分);2)接着实现一个寄存器文件(30分);3)最后添加指令存储器和地址部件等将这些部件组合成一个数据通路原型(40分)。
实验环境
硬件:桌面PC
软件:Linux Chisel开发环境
实验步骤及说明
本次试验分为三个部分:
(1)设计译码电路,输入位32bit的一个机器字,按照课本MIPS 指令格式,完成add、sub、lw、sw指令译码,其他指令一律译码成nop指令。输入信号名为Instr_word,对上述四条指令义译码输出信号名为add_op、sub_op、lw_op和sw_op,其余指令一律译码为nop;
给出Chisel设计代码和仿真测试波形,观察输入Instr_word为add R1,R2,R3; sub R0,R5,R6,lw R5,100(R2), sw R5,104(R2)、JAL RA,100(R2)时,对应的输出波形
思路:
1.定义一个Chisel模块Decoder,表示一个硬件模块,用于译码输入的机器字。
2.创建接口io,其中包含了输入和输出信号。输入信号是Instr_word,代表32位的机器字。从输入信号Instr_word中提取操作码字段(opcode)和功能码字段(func),分别用于后续的匹配。
3.初始化所有的输出信号,将它们都设置为false,并将nop_op设置为true,以表示默认情况下是nop指令。
4.使用条件语句来匹配操作码。当操作码匹配某个特定操作码时,进入相应的条件分支。
5.在每个条件分支中,继续使用条件语句来匹配功能码。如果功能码匹配某个指令的功能码,那么将相应的输出信号设置为true,表示这是一个有效的指令。同时将nop_op设置为false,表示不是nop指令。
Decoder代码:
import chisel3._
import chisel3.util._
import chisel3.stage.ChiselStageclass Decoder extends Module {val io = IO(new Bundle {val Instr_word = Input(UInt(32.W)) // 输入机器指令val add_op = Output(Bool()) // add 操作信号val sub_op = Output(Bool()) // sub 操作信号val lw_op = Output(Bool()) // lw 操作信号val sw_op = Output(Bool()) // sw 操作信号val nop_op = Output(Bool()) // nop 操作信号})// 定义opcodeval ADD_OPCODE = "b100000".U(6.W)val SUB_OPCODE = "b100010".U(6.W)val LW_OPCODE = "b100011".U(6.W)val SW_OPCODE = "b101011".U(6.W)// 提取opcode和func字段val opcode = io.Instr_word(31, 26)val func = io.Instr_word(5, 0)io.add_op := false.Bio.sub_op := false.Bio.lw_op := false.Bio.sw_op := false.Bio.nop_op := true.B// 根据opcode和func判断指令类型when(opcode === "b000000".U(6.W)) { when(func === ADD_OPCODE) {io.add_op := true.Bio.nop_op := false.B}.elsewhen(func === SUB_OPCODE) {io.sub_op := true.Bio.nop_op := false.B}}.elsewhen(opcode === LW_OPCODE) {io.lw_op := true.Bio.nop_op := false.B}.elsewhen(opcode === SW_OPCODE) {io.sw_op := true.Bio.nop_op := false.B}
}object Decoder extends App {(new ChiselStage).emitVerilog(new Decoder(), Array("--target-dir","generated"))
}
测试代码:
使用ChiselTest和ScalaTest对Decoder模块进行单元测试。在测试中,针对不同的指令(ADD、SUB、LW、SW、JAL)模拟输入,并验证Decoder模块的输出是否符合预期,检查各个操作类型的信号是否正确识别。通过逐步模拟时钟步进和检查输出信号的方式,确认Decoder在解码不同指令时的行为是否正确。
DecoderTest.scala:
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpecclass DecoderTest extends AnyFlatSpec with ChiselScalatestTester {behavior of "Decoder"it should "pass" in {test(new Decoder()).withAnnotations(Seq(WriteVcdAnnotation)) { c =>// 定义测试指令val ADD = "b00000000010000110000100000100000".U(32.W) val SUB = "b00000000101001100000000000100010".U(32.W) val LW = "b10001100101000100000000000110010".U(32.W) val SW = "b10101100101000100000000000110100".U(32.W) val JAL = "b00001100001000100000000000110010".U(32.W) c.clock.setTimeout(0)// 测试 ADD 指令c.io.Instr_word.poke(ADD)c.clock.step(1)c.io.add_op.expect(true.B)c.io.sub_op.expect(false.B)c.io.lw_op.expect(false.B)c.io.sw_op.expect(false.B)c.io.nop_op.expect(false.B)// 测试 SUB 指令c.io.Instr_word.poke(SUB)c.clock.step(1)c.io.add_op.expect(false.B)c.io.sub_op.expect(true.B)c.io.lw_op.expect(false.B)c.io.sw_op.expect(false.B)c.io.nop_op.expect(false.B)// 测试 LW 指令c.io.Instr_word.poke(LW)c.clock.step(1)c.io.add_op.expect(false.B)c.io.sub_op.expect(false.B)c.io.lw_op.expect(true.B)c.io.sw_op.expect(false.B)c.io.nop_op.expect(false.B)// 测试 SW 指令c.io.Instr_word.poke(SW)c.clock.step(1)c.io.add_op.expect(false.B)c.io.sub_op.expect(false.B)c.io.lw_op.expect(false.B)c.io.sw_op.expect(true.B)c.io.nop_op.expect(false.B)// 测试 JAL 指令c.io.Instr_word.poke(JAL)c.clock.step(1)c.io.add_op.expect(false.B)c.io.sub_op.expect(false.B)c.io.lw_op.expect(false.B)c.io.sw_op.expect(false.B)c.io.nop_op.expect(true.B)}}
}
(2)设计寄存器文件,共32个32bit寄存器,允许两读一写,且0号寄存器固定读出位0。四个输入信号为RS1、RS2、WB_data、Reg_WB,寄存器输出RS1_out和RS2_out;寄存器内部保存的初始数值等同于寄存器编号
给出Chisel设计代码和仿真测试波形,观察RS1=5,RS2=8,WB_data=0x1234,Reg_WB=1的输出波形和受影响寄存器的值。
思路:
1.定义一个名为 “RegisterFile” 的Chisel模块。使用val io = IO(new Bundle()) 创建模块的输入和输出接口,包括用于指定源寄存器索引、写入数据和写入使能信号,以及用于输出源寄存器数据的输出端口。
2.创建一个包含32个32位寄存器值的寄存器数组,初始值从0到31,代表了模拟的寄存器文件。
3.使用 Mux 操作根据输入的源寄存器索引RS1和RS2的值,从寄存器文件中选择要输出的数据。如果索引为0,就输出0;否则,从寄存器文件中读取对应索引的寄存器的值。
4.当输入信号Reg_WB为真时,表示要进行寄存器写入操作。使用Mux操作根据 RS1 和RS2的值,将输入的WB_data写入寄存器文件的相应索引位置。
RegisterFile代码:
import chisel3._
import chisel3.stage.ChiselStageclass RegisterFile extends Module {val io = IO(new Bundle {val RS1 = Input(UInt(5.W)) // RS1寄存器编号val RS2 = Input(UInt(5.W)) // RS2寄存器编号val WB_data = Input(UInt(32.W)) // 要写入寄存器的值val Reg_WB = Input(Bool()) // 控制是否进行写操作val RS1_out = Output(UInt(32.W)) // RS1寄存器值val RS2_out = Output(UInt(32.W)) // RS2寄存器值})// 定义32个32位寄存器,并将初始值设置为寄存器编号val regs = RegInit(VecInit(Seq.tabulate(32)(i => i.U(32.W))))// 处理RS1和RS2的读取操作io.RS1_out := Mux(io.RS1 === 0.U, 0.U, regs(io.RS1)) io.RS2_out := Mux(io.RS2 === 0.U, 0.U, regs(io.RS2)) // 处理写操作when(io.Reg_WB) { regs(io.RS1) := Mux(io.RS1 === 0.U, 0.U, io.WB_data)regs(io.RS2) := Mux(io.RS2 === 0.U, 0.U, io.WB_data)}
}object RegisterFile extends App {(new ChiselStage).emitVerilog(new RegisterFile(), Array("--target-dir","generated"))
}
测试代码:
使用poke方法,设置RS1为5,RS2为8,设置WB_data为十六进制数0x1234。将 Reg_WB 设置为 true,启用写入。然后执行c.clock.step(1)来推进模拟时钟1个时钟周期。
RegisterFileTest.scala
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpecclass RegisterFileTest extends AnyFlatSpec with ChiselScalatestTester {behavior of "RegisterFile Module"it should "observe the effect on registers" in {test (new RegisterFile).withAnnotations(Seq(WriteVcdAnnotation)) { c =>// 设置输入信号// RS1 = 5c.io.RS1.poke(5.U) // RS2 = 8c.io.RS2.poke(8.U) // WB_data = 0x1234c.io.WB_data.poke(0x1234.U) c.io.Reg_WB.poke(true) c.clock.step(1)}}
}
(3)实现一个32个字的指令存储器,从0地址分别存储4条指令add R1,R2,R3; sub R0,R5,R6,lw R5,100(R2), sw R5,104(R2)。然后组合指令存储器、寄存器文件、译码电路,并结合PC更新电路(PC初值为0)、WB_data和Reg_WB信号产生电路,最终让电路能逐条指令取出、译码(不需要完成指令执行)。
给出Chisel设计代码和仿真测试波形,观察四条指令的执行过程波形,记录并解释其含义。
指令存储器设计思路:
- 定义接口:
rdEna: 读使能信号,用于控制指令读取操作。
rdData: 读取的数据输出,表示从内存读取的 32 位指令。
wrEna: 写使能信号,用于控制指令写入操作。
wrAddr: 写地址,用来指示写入操作的目标地址。
wrData: 写入的数据输入,表示要写入的 32 位指令。 - 内存和程序计数器初始化:
创建了一个名为 pcReg 的程序计数器寄存器,并将其初始化为 0。使用 SyncReadMem 创建一个同步读取的8位宽、128单元的内存,用来存储指令。 - 写内存:
当wrEna为真时,通过写入操作将wrData的不同部分分别存储在指定地址及其后续三个地址中。 - 读内存:
当rdEna为真时,从地址pcReg及其后续三个地址读取数据,分别存储在rdData0至rdData中。使用Cat函数将这四个字节的数据连接成一个32位的数据,以产生完整的指令。程序计数器pcReg每次读取后增加4,以指向下一条指令。 - 默认情况:
当 rdEna 为假时(即没有读取请求),输出设置为0.U,表示没有有效数据。
InstructionMemory代码:
// 指令存储器
class InstructionMemory extends Module {val io = IO(new Bundle {// 读val rdEna = Input(Bool())val rdData = Output(UInt(32.W))// 写val wrEna = Input(Bool())val wrAddr = Input(UInt(10.W))val wrData = Input(UInt(32.W))})// 程序计数器,用于跟踪当前指令的读取位置,初始化为 0val pcReg = RegInit(0.U(32.W))// 创建一个同步读取的 8 位宽、128 单元的内存,用来存储指令val mem = SyncReadMem(128,UInt(8.W))// 写内存when (io.wrEna) {mem(io.wrAddr) := io.wrData(7, 0)mem(io.wrAddr + 1.U) := io.wrData(15, 8)mem(io.wrAddr + 2.U) := io.wrData(23, 16)mem(io.wrAddr + 3.U) := io.wrData(31, 24)}// 读内存when (io.rdEna) {val rdData0 = mem.read(pcReg)val rdData1 = mem.read(pcReg + 1.U)val rdData2 = mem.read(pcReg + 2.U)val rdData3 = mem.read(pcReg + 3.U)io.rdData := Cat(rdData3, rdData2, rdData1, rdData0) pcReg := pcReg + 4.U}.otherwise{io.rdData := 0.U}
}
组合指令存储器、寄存器文件、译码电路后的核心代码:
import chisel3._
import chisel3.util._// 指令存储器
class InstructionMemory extends Module {val io = IO(new Bundle {// 读val rdEna = Input(Bool())val rdData = Output(UInt(32.W))// 写val wrEna = Input(Bool())val wrAddr = Input(UInt(10.W))val wrData = Input(UInt(32.W))})// 程序计数器,用于跟踪当前指令的读取位置,初始化为 0val pcReg = RegInit(0.U(32.W))// 创建一个同步读取的 8 位宽、128 单元的内存,用来存储指令val mem = SyncReadMem(128,UInt(8.W))// 写内存when (io.wrEna) {mem(io.wrAddr) := io.wrData(7, 0)mem(io.wrAddr + 1.U) := io.wrData(15, 8)mem(io.wrAddr + 2.U) := io.wrData(23, 16)mem(io.wrAddr + 3.U) := io.wrData(31, 24)}// 读内存when (io.rdEna) {val rdData0 = mem.read(pcReg)val rdData1 = mem.read(pcReg + 1.U)val rdData2 = mem.read(pcReg + 2.U)val rdData3 = mem.read(pcReg + 3.U)io.rdData := Cat(rdData3, rdData2, rdData1, rdData0) pcReg := pcReg + 4.U}.otherwise{io.rdData := 0.U}
}// 寄存器文件
class RegisterFile extends Module {val io = IO(new Bundle {// 两读val RS1 = Input(UInt(5.W))val RS2 = Input(UInt(5.W))val RS1_out = Output(UInt(32.W))val RS2_out = Output(UInt(32.W))// 一写val Reg_WB = Input(Bool())val WB_data = Input(UInt(32.W))})val registers = RegInit(VecInit((0 until 32).map(i => i.U(32.W))))io.RS1_out := Mux(io.RS1 === 0.U, 0.U, registers(io.RS1))io.RS2_out := Mux(io.RS2 === 0.U, 0.U, registers(io.RS2))// 根据写信号选择要写入的寄存器when (io.Reg_WB) {registers(io.RS1) := Mux(io.RS1 === 0.U, 0.U, io.WB_data)registers(io.RS2) := Mux(io.RS2 === 0.U, 0.U, io.WB_data)}
}
// 译码器
class Decoder extends Module {val io = IO(new Bundle {val Instr_word = Input(UInt(32.W)) // 输入信号// 输出信号val add_op = Output(Bool())val sub_op = Output(Bool())val lw_op = Output(Bool())val sw_op = Output(Bool())val nop_op = Output(Bool())})// opcodeval AandS = "b000000".U(6.W)val ADD_OPCODE = "b100000".U(6.W)val SUB_OPCODE = "b100010".U(6.W)val LW_OPCODE = "b100011".U(6.W)val SW_OPCODE = "b101011".U(6.W)// 取出指令的 opcode 和 func val opcode = io.Instr_word(31, 26)val func = io.Instr_word(5, 0)// 指令默认是 nopio.add_op := false.Bio.sub_op := false.Bio.lw_op := false.Bio.sw_op := false.Bio.nop_op := true.B// 译码when (opcode === AandS) {when (func === ADD_OPCODE){io.add_op := true.Bio.nop_op := false.B}.elsewhen (func === SUB_OPCODE){io.sub_op := true.Bio.nop_op := false.B}}.elsewhen (opcode === LW_OPCODE) {io.lw_op := true.Bio.nop_op := false.B}.elsewhen (opcode === SW_OPCODE) {io.sw_op := true.Bio.nop_op := false.B}
}class Processor extends Module {val io = IO(new Bundle {// Decoderval Instr_word = Output(UInt(32.W))val add_op = Output(Bool())val sub_op = Output(Bool())val lw_op = Output(Bool())val sw_op = Output(Bool())val nop_op = Output(Bool())// RegisterFileval RS1_out = Output(UInt(32.W))val RS2_out = Output(UInt(32.W))// Instructionval rdEna = Input(Bool())val wrAddr = Input(UInt(10.W))val wrData = Input(UInt(32.W))val wrEna = Input(Bool())})// 实例化模块val decoder = Module(new Decoder)val registerFile = Module(new RegisterFile)val instructionMemory = Module(new InstructionMemory)// 连接指令信号io.add_op := decoder.io.add_opio.sub_op := decoder.io.sub_opio.lw_op := decoder.io.lw_opio.sw_op := decoder.io.sw_opio.nop_op := decoder.io.nop_op// 连接控制信号instructionMemory.io.rdEna := io.rdEnainstructionMemory.io.wrEna := io.wrEnainstructionMemory.io.wrAddr := io.wrAddrinstructionMemory.io.wrData := io.wrData// 连接输入数据registerFile.io.RS1 := instructionMemory.io.rdData(25,21)registerFile.io.RS2 := instructionMemory.io.rdData(20, 16)decoder.io.Instr_word := instructionMemory.io.rdDataio.Instr_word := instructionMemory.io.rdData// 初始化寄存器文件的控制信号registerFile.io.Reg_WB := false.BregisterFile.io.WB_data := 0.U// 连接模块输出信号io.RS1_out := registerFile.io.RS1_outio.RS2_out := registerFile.io.RS2_out
}// 生成 Verilog 代码
object Processor extends App {(new chisel3.stage.ChiselStage).emitVerilog(new Processor(), Array("--target-dir", "generated"))
}
实例化解码器、寄存器文件和指令存储器,将各模块的信号进行连接,实现了指令解码、寄存器读写控制以及数据传输功能。同时,对寄存器文件进行了初始化,并将相关输出信号连接至模块的输出端口,构建了一个简单的处理器电路。
测试代码:
测试这四条指令:add R1,R2,R3; sub R0,R5,R6; lw R5,100(R2) ; sw R5,104(R2)
import chiseltest._
import chisel3._
import org.scalatest.flatspec.AnyFlatSpecclass ProcessorTest extends AnyFlatSpec with ChiselScalatestTester {behavior of "Processor"it should "execute instructions in memory correctly" in {test(new Processor).withAnnotations(Seq(WriteVcdAnnotation)) { c =>val instructions = Seq("b00000000010000110000100000100000".U(32.W), // ADD"b00000000101001100000000000100010".U(32.W), // SUB"b10001100101000100000000000110010".U(32.W), // LW"b10101100101000100000000000110100".U(32.W) // SW)c.clock.setTimeout(0)// 写入指令for ((instr, addr) <- instructions.zipWithIndex) {c.io.wrEna.poke(true)c.io.wrAddr.poke((addr * 4).U)c.io.wrData.poke(instr)c.clock.step(1)}// 结束写入c.io.wrEna.poke(false)c.io.rdEna.poke(true)c.clock.step(10)}}
}
实验结果
1.设计译码电路,观察输入Instr_word为add R1,R2,R3; sub R0,R5,R6,lw R5,100(R2), sw R5,104(R2)、JAL RA,100(R2)时,对应的输出波形
(1) add指令(add R1, R2, R3 的十六进制为00430820)
(2) sub指令(sub R0, R5, R6 的十六进制为00A60022)
(3) lw指令(lw R5, 100(R2)的十六进制为8CA20032)
(4) sw指令(sw R5, 104(R2) 的十六进制为ACA20034)
(5) jal指令(jal 100 的十六进制为0C220032)
2. 设计寄存器文件,给出Chisel设计代码和仿真测试波形,观察RS1=5,RS2=8,WB_data=0x1234,Reg_WB=1的输出波形和受影响寄存器的值。
(1) 打开波形图,发现寄存器初值为其编号,RS1 = 5,RS2 = 8,WB_data = 0x1234
(2) 观察到在后面的时钟周期中,0x1234写入R5和R8。
3. 设计指令存储器,然后组合指令存储器、寄存器文件、译码电路, 最终让电路能逐条指令取出、译码。
(1) 第1条指令add R1,R2,R3:
此时,io_Instr_word = 00430820,是add指令对应的16进制表达。io_add_op置为1,表示该操作为为add操作。io_RS1_out的值为2,io_RS2_out的值为3,表示当前操作了R2,R3这2个寄存器。
(2) 第2条指令sub R0,R5,R6:
此时,io_Instr_word = 00A60022,是sub指令对应的16进制表达。io_sub_op置为1,表示该操作为为sub操作。io_RS1_out的值为5,io_RS2_out的值为6,表示当前操作了R5,R6这2个寄存器。
(3) 第3条指令lw R5,100(R2):
此时,io_Instr_word = 8CA20032,是lw指令对应的16进制表达。io_lw_op置为1,表示该操作为为lw操作。io_RS1_out的值为5,io_RS2_out的值为2,表示当前操作了R5,R2这2个寄存器。
(4) 第4条指令sw R5,104(R2):
此时,io_Instr_word =ACA20034,是sw指令对应的16进制表达。io_sw_op置为1,表示该操作为为sw操作。io_RS1_out的值为5,io_RS2_out的值为2,表示当前操作了R5,R2这2个寄存器。
(5) 指令全部执行之后,io_Instr_word为0,io_RS1_out的值为0,io_RS2_out的值为0,表示当前没有操作寄存器。
实验总结与体会
- 译码器的设计
在实验的第一部分,我设计了译码器。译码器的主要作用是根据指令的操作码确定要执行的操作。通过实现一个简单的译码器,我学会了如何将机器指令解析成控制信号,并将这些控制信号进一步用于驱动后续硬件模块。 - 寄存器文件的实现
实验的第二部分是设计寄存器文件,负责存储和读取寄存器数据。通过实现一个多端口的寄存器文件,我掌握了如何通过硬件访问和操作寄存器值。 - 指令存储器的设计与数据通路原型
在最后的阶段,我设计了指令存储器,并将其与前面的译码器和寄存器文件连接,形成了一个简单的数据通路原型。这个阶段不仅是对之前设计的验证,也使我体会到了数据通路中各个模块之间的配合与协调。
总的来说,这个实验为我今后深入学习计算机体系结构打下了良好的基础。
相关文章:

深圳大学-计算机系统(3)-实验三取指和指令译码设计
实验目标 设计完成一个连续取指令并进行指令译码的电路,从而掌握设计简单数据通路的基本方法。 实验内容 本实验分成三周(三次)完成:1)首先完成一个译码器(30分);2)接…...

Java Swing 编程全面解析:从 AWT 到 Swing 的进化之路
目录 前言 一、AWT 简介 1. 什么是 AWT? 2. AWT 的基本组件 3. AWT 编程示例 二、Swing 的诞生与进化 1. Swing 的特点 2. Swing 和 AWT 的主要区别 3. Swing 的基本组件 三、Swing 编程的基础示例 四、Swing 的高级功能 1. 布局管理器 2. 事件监听 3…...

mysql数据库启动出现Plugin ‘FEEDBACK‘ is disabled.问题解决记录
本人出现该问题的环境是xampp,异常关机,再次在xampp控制面板启动mysql出现该问题。出现问题折腾数据库之前,先备份数据,将mysql目录下的data拷贝到其他地方,这很重要。 然后开始折腾。 查资料,会发现很多…...

2025年大模型对智能硬件发展的助力与创新创意
随着人工智能(AI)技术,尤其是大模型的快速进步,智能硬件领域正在经历前所未有的变革。到2025年,大模型不仅能为智能硬件提供强大的算法支持,还能通过数据处理、智能决策和系统集成等方面的创新,推动硬件设备的性能提升和功能拓展。本文将从多个维度分析大模型对智能硬件…...

Tensor 基本操作1 unsqueeze, squeeze, softmax | PyTorch 深度学习实战
本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 目录 创建 Tensor常用操作unsqueezesqueezeSoftmax代码1代码2代码3 argmaxitem 创建 Tensor 使用 Torch 接口创建 Tensor import torch参考:https://pytorch.org/tutorials/beginn…...

Python - itertools- pairwise函数的详解
前言: 最近在leetcode刷题时用到了重叠对pairwise,这里就讲解一下迭代工具函数pairwise,既介绍给大家,同时也提醒一下自己,这个pairwise其实在刷题中十分有用,相信能帮助到你。 参考官方讲解:itertools --- 为高效循…...

Docker可视化管理工具Portainer
Portainer简介 Portainer 是一个轻量级的、开源的容器管理工具,提供了一个直观的 Web 用户界面(UI),用于管理 Docker 和 Kubernetes 环境。它简化了容器的部署、监控和管理,特别适合不熟悉命令行操作的用户或团队。 …...

WPF实战案例 | C# WPF实现大学选课系统
WPF实战案例 | C# WPF实现大学选课系统 一、设计来源1.1 主界面1.2 登录界面1.3 新增课程界面1.4 修改密码界面 二、效果和源码2.1 界面设计(XAML)2.2 代码逻辑(C#) 源码下载更多优质源码分享 作者:xcLeigh 文章地址&a…...

leetcode 面试经典 150 题:有效的括号
链接有效的括号题序号20题型字符串解法栈难度简单熟练度✅✅✅ 题目 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须…...

python学opencv|读取图像(三十九 )阈值处理Otsu方法
【1】引言 前序学习了5种阈值处理方法,包括(反)阈值处理、(反)零值处理和截断处理,还学习了一种自适应处理方法,相关文章链接为: python学opencv|读取图像(三十三)阈值处理-灰度图像-CSDN博客 python学o…...

GBase8c aes_encrypt和aes_decrypt函数
在数据库中,aes_encrypt和aes_decrypt函数进行加解密时使用的块加密模式。 GBase8c 与 MySQL 的aes_encrypt和aes_decrypt函数区别: 1、GBase8c 中的初始化向量init_vector不能为空 2、MySQL的加密模块block_encryption_mode 为aes-128-ecb,…...

【2024年华为OD机试】(B卷,100分)- 数据分类 (Java JS PythonC/C++)
一、问题描述 题目描述 对一个数据a进行分类,分类方法为: 此数据a(四个字节大小)的四个字节相加对一个给定的值b取模,如果得到的结果小于一个给定的值c,则数据a为有效类型,其类型为取模的值;如果得到的结果大于或者等于c,则数据a为无效类型。 比如一个数据a=0x010…...

机器学习 vs 深度学习
目录 一、机器学习 1、实现原理 2、实施方法 二、深度学习 1、与机器学习的联系与区别 2、神经网络的历史发展 3、神经网络的基本概念 一、机器学习 1、实现原理 训练(归纳)和预测(演绎) 归纳: 从具体案例中抽象一般规律…...

flutter_学习记录_00_环境搭建
1.参考文档 Mac端Flutter的环境配置看这一篇就够了 flutter的中文官方文档 2. 本人环境搭建的背景 本人的电脑的是Mac的,iOS开发,所以iOS开发环境本身是可用的;外加Mac电脑本身就会配置Java的环境。所以,后面剩下的就是&#x…...

SpringBoot如何自定义Starter ?
大家好,我是锋哥。今天分享关于【SpringBoot如何自定义Starter ?】面试题。希望对大家有帮助; SpringBoot如何自定义Starter ? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Spring Boot 中,自定义 Starter 是一种将应用程…...

前沿技术对比:大模型技术为什么发展远快于区块链技术,中英对照解释
文章目录 前言1、技术复杂性与成熟度 / Technical Complexity and Maturity2.、应用场景与行业需求 / Application Scenarios and Industry Demand3、监管与法律问题 / Regulatory and Legal Issues4、去中心化与网络效应 / Decentralization and Network Effects5、能源消耗与…...

WordPress果果对象存储插件
将网站上的图片等静态资源文件上传至七牛云对象存储,可以减轻服务器文件存储压力,提升静态文件访问速度,从而加速网站访问速度。 支持:阿里云对象存储、华为云对象存储、百度云对象存储、腾讯云对象存储、七牛云对象存储。 下载…...

elk 安装
创建elk网络 docker network create -d bridge elkelasticsearch 创建目录 mkdir -p /data/elasticsearch/{conf,logs,data,plugins}vim /data/elasticsearch/conf/elasticsearch.ymlcluster.name: "es-cluster" network.host: 0.0.0.0 xpack.security.enabled: tr…...

Python 预训练:打通视觉与大语言模型应用壁垒——Python预训练视觉和大语言模型
大语言模型是一种由包含数百亿甚至更多参数的深度神经网络构建的语言模型,通常使用自监督学习方法通过大量无标签文本进行训练,是深度学习之后的又一大人工智能技术革命。 大语言模型的发展主要经历了基础模型阶段(2018 年到2021年)、能力探索阶段(2019年…...

OpenCV相机标定与3D重建(63)校正图像的畸变函数undistort()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 转换图像以补偿镜头畸变。 该函数通过变换图像来补偿径向和切向镜头畸变。 此函数仅仅是 initUndistortRectifyMap(使用单位矩阵 R…...

用 Java 发送 HTML 内容并带附件的电子邮件
实现思路 首先,设置邮件服务器的相关属性,包括是否需要认证、使用的邮件协议、服务器地址、端口等。 创建一个会话对象,使用 Session.getInstance 方法,并提供邮件服务器的属性和认证信息。 创建一个 MimeMessage 对象作为邮件消…...

【Day24 LeetCode】贪心Ⅱ
一、贪心Ⅱ 1、买卖股票的最佳时机 II 122 这题第一想法是使用动态规划做,每天有两个状态,持有股票和非持有股票,每次计算这两个状态下的最优值。 class Solution { public:int maxProfit(vector<int>& prices) {//表示当前 没有…...

vue3+elementPlus之后台管理系统(从0到1)(day3-管理员管理)
管理员管理 搭建管理员页面 在views中创建一个manager文件夹,并创建ManagerIndexView.vue、MangagerListView.vue、UserList.vue <!-- src/views/manager/ManagerIndexView.vue --> <template><!-- 作为一个占位符,用于渲染与当前 URL…...

上位机知识篇---ROS2命令行命令静态链接库动态链接库
文章目录 前言第一部分:ROS2命令行命令1. 基础命令(1)ros2 run(2)ros2 launch(3)ros2 node(4)ros2 topic(5)ros2 service(6࿰…...

2025/1/21 学习Vue的第四天
睡觉。 --------------------------------------------------------------------------------------------------------------------------------- 11.Object.defineProperty 1.在我们之前学习JS的时候,普通得定义一个对象与属性。 <!DOCTYPE html> <h…...

云计算、AI与国产化浪潮下DBA职业之路风云变幻,如何谋破局启新途?
引言 在近日举办的一场「云和恩墨大讲堂」直播栏目中,云和恩墨联合创始人李轶楠、副总经理熊军和欧冶云商数据库首席薛晓刚共同探讨了DBA的现状与未来发展。三位专家从云计算、人工智能、国产化替代等多个角度进行了深入的分析和探讨,为从业者提供了宝贵…...

Linux内核编程(二十一)USB驱动开发-键盘驱动
一、驱动类型 USB 驱动开发主要分为两种:主机侧的驱动程序和设备侧的驱动程序。一般我们编写的都是主机侧的USB驱动程序。 主机侧驱动程序用于控制插入到主机中的 USB 设备,而设备侧驱动程序则负责控制 USB 设备如何与主机通信。由于设备侧驱动程序通常与…...

模拟算法习题篇
在算法中,模拟是一种通过计算机程序来模拟现实世界中的过程或系统行为的方法。它的核心思想是根据题目给定的规则和逻辑,按照步骤细致地重现事件的发展流程,从而获得最终结果。 解题时如何使用模拟算法: 理解题目规则:…...

蓝桥杯真题 - 翻转 - 题解
题目链接:https://www.lanqiao.cn/problems/3520/learning/ 个人评价:难度 1 星(满星:5) 前置知识:无 整体思路 贪心,除了第一位跟最后一位,其它字符,每当 S [ i ] ≠…...

IP属地与视频定位位置不一致:现象解析与影响探讨
在数字化时代,IP属地和视频定位位置已成为我们获取网络信息、判断内容真实性的重要依据。然而,有时我们会发现,某些视频内容中展示的定位位置与其发布者的IP属地并不一致。这种不一致现象引发了广泛的关注和讨论。本文旨在深入剖析IP属地与视…...