计算机组成原理(计算机系统3)--实验七:新增指令实验
一、实验目标
了解RISC-V mini处理器架构,在其基础之上新增一个指令,完成设计并观察指令执⾏。
二、实验内容
1) 修改数据通路,新增指令comb rs1,rs2,rd采用R型指令格式,实现将rs1高16位和rs2低16位拼接成32位整数,并且保存到rd寄存器。
2) 在处理器上执行该指令,观察仿真波形,验证功能是否正确。
3) 自行设计其他功能指令,并验证设计是否正确
三、实验环境
硬件:桌面PC
软件:Chisel开发环境
四、实验步骤及说明
1) 实验要求
学习Chisel数据通路的Chisel描述,特别是指令译码部分和core核心代码。然后按照下面操作完成指令译码器的修改,以及数据通路的修改,按照参考文档完成comb指令的实现,自行设计新指令实现其功能并验证。
2) 实验过程
(一)COMB指令
分析:添加新指令 comb ,首先需要根据riscv指令格式,设置该指令各个字段的值,并在相应文件中添加该指令的比特模式。然后设置该指令的译码结果,接着在ALU中实现该指令的功能。最后让该指令在处理器上执行,验证功能是否正确。
1. 在Instrutcions.scala文件中添加 comb 指令比特模式串
comb 为R型指令,riscv的R型指令格式如下:
指令功能:comb 是一种 R 型指令,将 rs1 的高 16 位与 rs2 的低 16 位拼接成 32 位数据,结果存储到 rd。
指令格式:基于 RISC-V 的 R 型指令格式,具体字段如下:
opcode(操作码):7位,用于指定指令类型。
rs2(源寄存器2):5位,指定第二个源寄存器。
rs1(源寄存器1):5位,指定第一个源寄存器。
funct3(功能字段3):3位,用于区分具有相同操作码的不同指令。
rd(目标寄存器):5位,指定目标寄存器,用于存放指令执行结果。
opcode/funct7(功能字段7):7位,用于区分具有相同操作码和funct3的不同指令。
为了避免新加指令与riscv-mini已有指令冲突,将 comb 指令的opcode、funct3和funct7部分设置为0110011、111、0000001。然后使用 BitPat() 函数设置 comb 指令的比特模式。
步骤 1.1:定义指令比特模式
在Instructions.scala文件中,添加以下的代码来定义comb指令的比特模式:
- // Instructions.scala
- package min
- import chisel3.util.BitPat
- object Instructions {
- // 省略RISCV-mini已定义的指令
- // 新增指令COMB
- def COMB = BitPat("b0000001??????????111?????0110011")
- }
这里的BitPat()函数用于定义一个位模式,确保与现有指令无冲突,其中?表示不关心的位,可以是0或1。
2. 添加 comb 指令的译码
步骤 2.1:定义 ALU 操作常量
comb 指令需要在ALU中将rs1高16位和rs2低16位拼接成32位整数,因此需要在Alu.scala文件中添加常量 ALU_COMB ,让译码器可以译码出正确的信号。因此,在 Alu.scala 文件中添加新的操作码:
- // Alu.scala
- import chisel3._
- import chisel3.util._
- object Alu {
- val ALU_ADD = 0.U(4.W)
- val ALU_SUB = 1.U(4.W)
- val ALU_AND = 2.U(4.W)
- val ALU_OR = 3.U(4.W)
- val ALU_XOR = 4.U(4.W)
- val ALU_SLT = 5.U(4.W)
- val ALU_SLL = 6.U(4.W)
- val ALU_SLTU = 7.U(4.W)
- val ALU_SRL = 8.U(4.W)
- val ALU_SRA = 9.U(4.W)
- val ALU_COPY_A = 10.U(4.W)
- val ALU_COPY_B = 11.U(4.W)
- // 新加常量
- val ALU_COMB = 12.U(4.W)
- val ALU_XXX = 15.U(4.W)
- }
- //省略RISCV-mini的ALU实现部分
步骤 2.2:设置控制信号映射
接下来为 comb 指令添加对应的译码映射。 comb 指令执行后pc需要加4,并将从寄存器文件中读取的数据rs1和rs2进行拼接操作,然后将ALU输出的拼接结果写回到寄存器文件中。在 Control.scala 文件中为 comb 指令配置控制信号:
- // Control.scala
- import chisel3._
- import chisel3.util._
- object Control {
- //省略常量定义部分
- // format: off
- val default =
- List(PC_4 , A_XXX, B_XXX, IMM_X, ALU_XXX , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, Y)
- val map = Array(
- LUI -> List(PC_4 , A_PC, B_IMM, IMM_U, ALU_COPY_B, BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N),
- AUIPC -> List(PC_4 , A_PC, B_IMM, IMM_U, ALU_ADD , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, Y, CSR.N, N),
- JAL -> List(PC_ALU, A_PC, B_IMM, IMM_J, ALU_ADD , BR_XXX, Y, ST_XXX, LD_XXX, WB_PC4, Y, CSR.N, N),
- //省略部分指令译码映射
- // 这是COMB指令的译码映射
- COMB -> List(PC_4 , A_RS1, B_RS2, IMM_X, ALU_COMB , BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N))
- // format: on
- }
- //省略RISCV-mini的控制实现部分
3. 实现 comb 指令的执行操作
步骤 3.1:实现拼接逻辑
在Alu.scala文件添加将rs1高16位和rs2低16位拼接成32位整数的操作。因此,在 Alu.scala 文件中为 comb 指令添加具体执行逻辑:使用 MuxLookup 多路选择器,根据 alu_op 确定执行操作。Cat() 函数将 io.A(31,16) 与 io.B(15,0) 拼接为 32 位数据。
- // Alu.scala
- import chisel3._
- import chisel3.util._
- //省略Alu常量定义和端口声明部分
- class AluSimple(val width: Int) extends Alu {
- val io = IO(new AluIO(width))
- val shamt = io.B(4, 0).asUInt
- io.out := MuxLookup(
- io.alu_op,
- io.B,
- Seq(
- ALU_ADD -> (io.A + io.B),
- ALU_SUB -> (io.A - io.B),
- ALU_SRA -> (io.A.asSInt >> shamt).asUInt,
- ALU_SRL -> (io.A >> shamt),
- ALU_SLL -> (io.A << shamt),
- ALU_SLT -> (io.A.asSInt < io.B.asSInt),
- ALU_SLTU -> (io.A < io.B),
- ALU_AND -> (io.A & io.B),
- ALU_OR -> (io.A | io.B),
- ALU_XOR -> (io.A ^ io.B),
- ALU_COPY_A -> io.A,
- // COMB指令执行
- ALU_COMB -> Cat(io.A(31,16), io.B(15,0))
- )
- )
- io.sum := io.A + Mux(io.alu_op(0), -io.B, io.B)
- }
- class AluArea(val width: Int) extends Alu {
- val io = IO(new AluIO(width))
- val sum = io.A + Mux(io.alu_op(0), -io.B, io.B)
- val cmp =
- Mux(io.A(width - 1) === io.B(width - 1), sum(width - 1), Mux(io.alu_op(1), io.B(width - 1), io.A(width -1)))
- val shamt = io.B(4, 0).asUInt
- val shin = Mux(io.alu_op(3), io.A, Reverse(io.A))
- val shiftr = (Cat(io.alu_op(0) && shin(width - 1), shin).asSInt >> shamt)(width - 1, 0)
- val shiftl = Reverse(shiftr)
- // 将A(rs1)的高16位与B(rs2)的低16位拼接
- val comb = Cat(io.A(31,16), io.B(15,0))
- val out =
- Mux(
- io.alu_op === ALU_ADD || io.alu_op === ALU_SUB,
- sum,
- Mux(
- io.alu_op === ALU_SLT || io.alu_op === ALU_SLTU,
- cmp,
- Mux(
- io.alu_op === ALU_SRA || io.alu_op === ALU_SRL,
- shiftr,
- Mux(
- io.alu_op === ALU_SLL,
- shiftl,
- Mux(
- io.alu_op === ALU_AND,
- io.A & io.B,
- Mux(
- io.alu_op === ALU_OR,
- io.A | io.B,
- Mux(io.alu_op === ALU_XOR, io.A ^ io.B,
- // COMB指令执行
- Mux(io.alu_op === ALU_COMB, comb, Mux(io.alu_op===ALU_COPY_A, io.A, io.B)))
- )
- )
- )
- )
- )
- )
- io.out := out
- io.sum := sum
- }
对 comb 指令进行测试
步骤 4.1:编写测试程序
编写一个程序加载到处理器中,调用 comb 指令并观察结果。comb.s代码如下:
- .text # Define beginning of text section
- .global _start # Define entry _start
- _start:
- lui x6, 1 # x6 = 0x00001000
- lui x7, 2 # x7 = 0x00002000
- # comb x5, x6, x7
- exit:
- csrw mtohost, 1
- j exit
- .end # End of file
请注意,因为 comb 为自己加入的指令,不能被汇编器汇编,所以这里将其注释掉,到后面生成的comb.hex文件中再将 comb x5, x6, x7 的二进制添加进去。
步骤 4.2:编译测试程序
编写完程序后,使用如下命令进行编译:
$ riscv32-unknown-elf-gcc -nostdlib -Ttext=0x200 -o comb comb.s
然后使用 elf2hx 命令将comb二进制文件转换成十六进制:
$ elf2hex 16 4096 comb > comb.hex
在comb.hex文件中,可以找到 lui x6, 1 和 lui x7, 2 的机器码对应的十六进制形式:
comb x5, x6, x7 转换成机器码的十六机制形式为 027372b3。因此处指令存储为小端模式,故我们需要将十六进制数插入到第一个红线的前面。修改后如下:
步骤 4.3:运行仿真并观察波形
接着需要在主目录下一次执行 make 和 make verilator 命令(若之前已经执行过,则在此次操作之前需要执行 make clean ),执行后会产生VTile可执行文件。然后执行下面命令,使mini处理器执行新建指令并产生波形文件。
$ ./VTile comb.hex comb.vcd
使用GTKWave打开comb.vcd文件,其波形图如下:
指令对应的十六进制形式见下表:
表 1:指令所对应16进制
| 指令 | 十六进制形式 | 说明 |
| lui x6,1 | 00001337 | x6=0x00001000 |
| lui x7,2 | 000023b7 | x7=0x00002000 |
| comb x5,x6,x7 | 027372b3 | x5=cat(x6(31:16),x7(15:0))s |
从波形图中可以看出, comb 指令将拼接后的结果0x00002000写回到了5号寄存器中,故该指令执行正常。
(二)new_inst指令
添加新指令 new_inst ,new_inst 是一个 R 型指令,功能为:将 rs1 和 rs2 的值进行对 rs1 的值取反后与 rs2 进行按位与操作,将结果存储到 rd。
1. 在Instrutcions.scala文件中添加 new_inst 指令比特模式串
指令格式:
基于 R 型指令格式,opcode、funct3 和 funct7 的设置为:
- opcode: 0110011
- funct3: 110
- funct7: 0000001
在 Instructions.scala 文件中添加以下内容:
- // Instructions.scala
- import chisel3.util.BitPat
- object Instructions {
- // 已有指令省略
- def NEW_INST = BitPat("b0000001??????????110?????0110011")
- }
2. 添加 comb 指令的译码
步骤 2.1:定义 ALU 操作常量
在 Alu.scala 文件中为 new_inst 指令添加常量:
- // Alu.scala
- object Alu {
- // 已有常量省略
- val ALU_NEW_INST = 13.U(4.W) // 新指令对应的 ALU 操作常量
- }
步骤 2.2:设置控制信号映射
修改 Control.scala 文件,设置指令控制信号。为 new_inst 指令添加控制信号映射,确保译码后能正确触发对应的 ALU 操作:
- // Control.scala
- val map = Array(
- // 已有映射省略
- NEW_INST -> List(PC_4, A_RS1, B_RS2, IMM_X, ALU_NEW_INST, BR_XXX, N, ST_XXX, LD_XXX, WB_ALU, N, CSR.N, N)
- )
3. 实现 new_inst 指令的执行操作
步骤 3.1:实现指令逻辑
为 new_inst 添加操作(~io.A & io.B 表示对 rs1 的值取反后与 rs2 进行按位与操作):
- // Alu.scala
- class AluSimple(val width: Int) extends Alu {
- val io = IO(new AluIO(width))
- io.out := MuxLookup(
- io.alu_op,
- io.B,
- Seq(
- // 已有操作省略
- ALU_NEW_INST -> (~io.A & io.B) // 新指令逻辑实现
- )
- )
- }
要在 AluArea 中添加对 new_inst 指令的支持,进行以下步骤:
- 定义指令逻辑:new_inst 的功能是对 rs1 取反后与 rs2 按位与,将结果存储到 rd。对应到硬件逻辑,可以直接通过 ~io.A & io.B 实现。
- 在ALU的Mux逻辑中插入新指令处理逻辑:在out的生成逻辑中添加new_inst的逻辑。
- 确保ALU操作码正确映射:在控制逻辑中定义ALU_NEW_INST并在AluArea中使用。
- class AluArea(val width: Int) extends Alu {
- val io = IO(new AluIO(width))
- val sum = io.A + Mux(io.alu_op(0), -io.B, io.B)
- val cmp = Mux(
- io.A(width - 1) === io.B(width - 1),
- sum(width - 1),
- Mux(io.alu_op(1), io.B(width - 1), io.A(width - 1))
- )
- val shamt = io.B(4, 0).asUInt
- val shin = Mux(io.alu_op(3), io.A, Reverse(io.A))
- val shiftr = (Cat(io.alu_op(0) && shin(width - 1), shin).asSInt >> shamt)(width - 1, 0)
- val shiftl = Reverse(shiftr)
- // 新增指令逻辑: rs1取反后与rs2按位与
- val newInst = ~io.A & io.B
- // 其他指令逻辑
- val comb = Cat(io.A(31, 16), io.B(15, 0))
- val out =
- Mux(
- io.alu_op === ALU_ADD || io.alu_op === ALU_SUB,
- sum,
- Mux(
- io.alu_op === ALU_SLT || io.alu_op === ALU_SLTU,
- cmp,
- Mux(
- io.alu_op === ALU_SRA || io.alu_op === ALU_SRL,
- shiftr,
- Mux(
- io.alu_op === ALU_SLL,
- shiftl,
- Mux(
- io.alu_op === ALU_AND,
- io.A & io.B,
- Mux(
- io.alu_op === ALU_OR,
- io.A | io.B,
- Mux(
- io.alu_op === ALU_XOR,
- io.A ^ io.B,
- Mux(
- io.alu_op === ALU_COMB,
- comb,
- Mux(
- io.alu_op === ALU_NEW_INST, // 新增指令的逻辑
- newInst,
- Mux(io.alu_op === ALU_COPY_A, io.A, io.B)
- )
- )
- )
- )
- )
- )
- )
- )
- )
- io.out := out
- io.sum := sum
- }
4. 对 new_inst 指令进行测试
步骤 4.1:编写测试程序
编写一个程序加载到处理器中,调用 new_inst 指令并观察结果。new_inst.s代码如下:
- .text # Define beginning of text section
- .global _start # Define entry _start
- _start:
- lui x6, 1 # x6 = 0x00001000
- lui x7, 2 # x7 = 0x00002000
- # new_inst x5, x6, x7
- exit:
- csrw mtohost, 1
- j exit
- .end # End of file
因为 new_inst 为自己加入的指令,不能被汇编器汇编,所以这里将其注释掉,到后面生成的new_inst.hex文件中再将 new_inst x5, x6, x7 的二进制添加进去。
步骤 4.2:编译测试程序
编写完程序后,使用如下命令进行编译:
$ riscv32-unknown-elf-gcc -nostdlib -Ttext=0x200 -o new_inst new_inst.s
然后使用 elf2hx 命令将new_inst二进制文件转换成十六进制:
$ elf2hex 16 4096 new_inst >new_inst.hex
在new_inst.hex文件中,可以找到 lui x6, 1 和 lui x7, 2 的机器码对应的十六进制形式:
new_inst x5, x6, x7 转换成机器码的十六机制形式为 01070333。因此处指令存储为小端模式,故我们需要将十六进制数插入到第一个红线的前面。修改后如下:
步骤 4.3:运行仿真并观察波形
接着需要在主目录下一次执行 make 和 make verilator 命令(若之前已经执行过,则在此次操作之前需要执行 make clean ),执行后会产生VTile可执行文件。然后执行下面命令,使mini处理器执行新建指令并产生波形文件。
$ ./VTile new_inst.hex new_inst.vcd
使用GTKWave打开new_inst.vcd文件,其波形图如下:
指令对应的十六进制形式见下表:
表 2:指令所对应16进制
| 指令 | 十六进制形式 | 说明 |
| lui x6,1 | 00001337 | x6=0x00001000 |
| lui x7,2 | 000023b7 | x7=0x00002000 |
| new_inst x5,x6,x7 | 01070333 | x5=~(x6)&x7=0x00002000 |
手算验证:
- ~x6 = 0xFFFFEFFF 的二进制表示为:1111 1111 1111 1110 1111 1111 1111 1111。
- x7 = 0x00002000 的二进制表示为:0000 0000 0000 0010 0000 0000 0000 0000。
- x5=(~x6)&x7=0x00002000,即验证正确。
从波形图中可以看出, new_inst 指令将结果0x00002000写回到了5号寄存器中,故该指令执行正常。
五、实验结果
(一)COMB指令
指令对应的十六进制形式见下表:
| 指令 | 十六进制形式 | 说明 |
| lui x6,1 | 00001337 | x6=0x00001000 |
| lui x7,2 | 000023b7 | x7=0x00002000 |
| comb x5,x6,x7 | 027372b3 | x5=cat(x6(31:16),x7(15:0)) |
从波形图中可以看出, comb 指令将拼接后的结果0x00002000写回到了5号寄存器中,故该指令执行正常。
结果验证:comb 指令的功能是将两个寄存器的值拼接成一个 32 位的整数。具体来说,comb 指令将 x6 的高 16 位和 x7 的低 16 位拼接在一起,形成一个新的 32 位值,并将结果写入 x5 寄存器。
- x6 = 0x00001000 的二进制表示为:00000000 00000001 00000000 00000000。
- x7 = 0x00002000 的二进制表示为:00000000 00000010 00000000 00000000。
将 x6 的高 16 位(00000000 00000001)与 x7 的低 16 位(00000000 00000000)拼接,得到的 32 位结果是:
x5 = cat(x6(31:16), x7(15:0)) = 0x00002000
因此,x5 的最终值是 0x00002000,指令执行正确。
(二)new_inst指令
指令对应的十六进制形式见下表:
| 指令 | 十六进制形式 | 说明 |
| lui x6,1 | 00001337 | x6=0x00001000 |
| lui x7,2 | 000023b7 | x7=0x00002000 |
| new_inst x5,x6,x7 | 01070333 | x5=~(x6)&x7=0x00002000 |
从波形图中可以看出, new_inst 指令将结果0x00002000写回到了5号寄存器中,故该指令执行正常。
结果分析:new_inst 是一个 R 型指令,的功能是将 x6 的值按位取反后,与 x7 的值进行按位与操作,并将结果存储到 x5 中。
- x6 = 0x00001000 的二进制表示为:00000000 00000001 00000000 00000000。
- 对 x6 进行按位取反(~x6),得到 0xFFFFEFFF,即二进制表示为:11111111 11111111 11101111 11111111。
- x7 = 0x00002000 的二进制表示为:00000000 00000010 00000000 00000000。
- 按位与操作 ~x6 与 x7:
- 11111111 11111111 11101111 11111111 (x6取反)
- AND
- 00000000 00000010 00000000 00000000 (x7)
- --------------------------------------
- 00000000 00000010 00000000 00000000 (结果)
得到的结果是 0x00002000,所以 x5 的值为 0x00002000,指令执行正确。
相关文章:
计算机组成原理(计算机系统3)--实验七:新增指令实验
一、实验目标 了解RISC-V mini处理器架构,在其基础之上新增一个指令,完成设计并观察指令执⾏。 二、实验内容 1) 修改数据通路,新增指令comb rs1,rs2,rd采用R型指令格式,实现将rs1高16位和rs2低16位拼接成32位整数,…...
LeetCode 0040.组合总和 II:回溯 + 剪枝
【LetMeFly】40.组合总和 II:回溯 剪枝 力扣题目链接:https://leetcode.cn/problems/combination-sum-ii/ 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates…...
解决使用Selenium时ChromeDriver版本不匹配问题
在学习Python爬虫过程中如果使用Selenium的时候遇到报错如下session not created: This version of ChromeDriver only supports Chrome version 99… 这说明当前你的chrome驱动版本和浏览器版本不匹配。 例如 SessionNotCreatedException: Message: session not created: This…...
CAN波特率匹配
STM32 LinuxIMX6ull(Linux)基于can-utils测试...
JVM垃圾回收器的原理和调优详解!
全文目录: 开篇语前言摘要概述垃圾回收器分类及原理1. Serial 垃圾回收器2. Parallel 垃圾回收器3. CMS 垃圾回收器4. G1 垃圾回收器 源码解析示例代码 使用案例分享案例 1:Web 服务的 GC 调优案例 2:大数据任务的 GC 优化 应用场景案例垃圾回…...
与机器学习相关的概率论重要概念的介绍和说明
概率论一些重要概念的介绍和说明 1、 试验 (1)试验是指在特定条件下,对某种方法、技术、设备或产品(即,事物)进行测试或验证的过程。 (2)易混淆的概念是,实验。实验&…...
JavaScript中的相等运算符:`==`与`===`
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
A7. Jenkins Pipeline自动化构建过程,可灵活配置多项目、多模块服务实战
服务容器化构建的环境配置构建前需要解决什么下面我们带着问题分析构建的过程:1. 如何解决jenkins执行环境与shell脚本执行环境不一致问题?2. 构建之前动态修改项目的环境变量3. 在通过容器打包时避免不了会产生比较多的不可用的镜像资源,这些资源要是不及时删除掉时会导致服…...
66-《虞美人》
虞美人 虞美人(学名:Papaver rhoeas L.):一年生草本植物,全体被伸展的刚毛,稀无毛。茎直立,高25-90厘米,具分枝。叶片轮廓披针形或狭卵形,羽状分裂,裂片披针形…...
obsidian插件——Metadata Hider
原本是要找导出图片时显示属性的插件,奈何还没找到,反而找到了可以隐藏属性的插件。唉,人生不如意,十之八九。 说一下功能: 这个插件可以把obsidian的文档属性放在右侧显示,或者决定只显示具体几项属性&a…...
MySQL中InnoDB逻辑存储结构
在MySQL中,InnoDB是最常用的存储引擎之一,它具有高度的事务支持、行级锁、ACID特性以及自动崩溃恢复等特性。InnoDB的逻辑存储结构可以分为多个层次,下面是详细的解析。 1. 表空间 (Tablespace) InnoDB的物理存储结构以表空间为基础。表空间…...
高阶C语言|深入理解字符串函数和内存函数
文章目录 前言1.求字符串长度1.1 字符串长度函数:strlen模拟实现 长度不受限制的字符串函数1.2 字符串拷贝函数:strcpy模拟实现 1.3 字符串连接函数:strcat模拟实现 1.4 字符串比较函数:strcmp模拟实现 长度受限制的字符串函数2.1…...
Pandas DataFrame 拼接、合并和关联
拼接:使用 pd.concat(),可以沿着行或列方向拼接 DataFrame。 合并:使用 pd.merge(),可以根据一个或多个键进行不同类型的合并(左连接、右连接、全连接、内连接)。 关联:使用 join() 方法,通常在设置了索引的 DataFrame 上进行关联操作。 concat拼接 按列拼接 df1 = …...
特种作业操作之低压电工考试真题
1.下面( )属于顺磁性材料。 A. 铜 B. 水 C. 空气 答案:C 2.事故照明一般采用( )。 A. 日光灯 B. 白炽灯 C. 压汞灯 答案:B 3.人体同时接触带电设备或线路中的两相导体时,电流从一相通过人体流…...
“Play around” 在编程领域的含义
“Play around” 的含义 If everything is working correctly we should have a play around in the prompt and verify that functions are actually a new type of value now, not symbols. https://www.buildyourownlisp.com/chapter11_variables 在这段话中,“p…...
[免费]基于Python的Django博客系统【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的基于Python的Django博客系统,分享下哈。 项目视频演示 【免费】基于Python的Django博客系统 Python毕业设计_哔哩哔哩_bilibili 项目介绍 随着互联网技术的飞速发展,信息的传播与…...
通过protoc工具生成proto的pb.go文件以及使用protoc-go-inject-tag工具注入自定义标签
1.ProtoBuf认识,安装以及用法 参考:[golang 微服务] 3. ProtoBuf认识,安装以及golang 中ProtoBuf使用 2. 使用protoc-go-inject-tag工具注入自定义标签 这里有一个案例: syntaxproto3; package test;option go_package ".;test";message MyMessage {int6…...
进程池的制作(linux进程间通信,匿名管道... ...)
目录 一、进程间通信的理解 1.为什么进程间要通信 2.如何进行通信 二、匿名管道 1.管道的理解 2.匿名管道的使用 3.管道的五种特性 4.管道的四种通信情况 5.管道缓冲区容量 三、进程池 1.进程池的理解 2.进程池的制作 四、源码 1.ProcessPool.hpp 2.Task.hpp 3…...
Gurobi 基础语法之 tupledict 和 tuplelist
Python中的字典:dict 我们先来介绍一下Python语法中的 dict 类型, 字典中可以通过任意键值来对数据进行映射,任何无法修改的python对象都可以当作键值来使用,这些无法修改的Python对象包括:整数(比如:1),浮…...
Flutter:搜索页,搜索bar封装
view 使用内置的Chip简化布局 import package:chenyanzhenxuan/common/index.dart; import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import package:get/get.dart; import package:tdesign_flutter/tdesign_flutter.dart;import i…...
IoTDB 2025 春节值班与祝福
2025 春节快乐 瑞蛇迎吉庆,祥光映华年,2025 春节已近在眼前。社区祝福 IoTDB 的所有关注者、支持者、使用者 2025 新年快乐,“蛇”来运转! IoTDB 团队的春节放假时间为 2025 年 1 月 27 日至 2 月 4 日,1 月 25 日、26…...
14、Java 对象关系映射(ORM)框架:简化数据库操作的利器
嘿,Java 开发者们!在我们的编程旅程中,经常会遇到一个重要的任务,那就是将 Java 对象和数据库表进行交互。传统的 JDBC 编程虽然强大,但代码往往会变得繁琐且容易出错。这时候,对象关系映射(ORM…...
鲁滨逊漂流记读后感
前言:学校要求出鲁滨逊漂流记的读后感啊,那么今天我就写着试试叭,好久都没更新了嘤,可能写的不好嗷。真的不是很建议参考,因为我的思想可能会与学校的要求不同,更多的是介入了自己的思考,从鲁滨逊好的地方和…...
【面试】【前端】前端网络面试题总结
一、前端网络面试题总结 网络相关知识是前端开发的核心内容之一,面试中通常会考察协议、网络模型、性能优化及常见网络问题的处理。以下是针对前端网络面试题的总结: (一)协议森林(大话网络协议) 网络协议…...
【MQ】如何保证消息队列的高性能?
零拷贝 Kafka 使用到了 mmap 和 sendfile 的方式来实现零拷贝。分别对应 Java 的 MappedByteBuffer 和 FileChannel.transferTo 顺序写磁盘 Kafka 采用顺序写文件的方式来提高磁盘写入性能。顺序写文件,基本减少了磁盘寻道和旋转的次数完成一次磁盘 IO࿰…...
刀客doc:禁令影响下,TikTok广告业务正在被对手截胡
一、 现如今,TikTok在美国的命运迎来了暂时的反转,根据Adage的报道,广告主的投放在恢复。但短暂的关闭带来的影响依然有余震,一些广告主在重新评估TikTok在自己广告预算中的地位,这些是竞争对手截胡的机会。 长期以…...
中国电信AI大模型发布:评分超o1-preview,近屿智能带您探索AI技术新境界
近日,中国电信人工智能研究院宣布,其自主研发的复杂推理大模型TeleAI-t1-preview即将上线天翼AI开放平台。该模型采用强化学习训练方法,显著提升了逻辑推理和数学推导的准确性,展现了强大的复杂问题解决能力。 在权威评测中&#…...
服务定位器模式
服务定位器模式 引言 服务定位器模式(Service Locator Pattern)是一种设计模式,旨在解决应用程序中服务管理的问题。它通过提供一个中央服务注册中心,将服务提供者与服务消费者解耦,从而简化了服务的查找和依赖管理。…...
开发环境搭建-4:WSL 配置 docker 运行环境
在 WSL 环境中构建:WSL2 (2.3.26.0) Oracle Linux 8.7 官方镜像 基本概念说明 容器技术 利用 Linux 系统的 文件系统(UnionFS)、命名空间(namespace)、权限管理(cgroup),虚拟出一…...
AI代理框架:突破LLMs极限的未来之路
标题:“AI代理框架:突破LLMs极限的未来之路” 文章信息摘要: 大型语言模型(LLMs)已接近通过预训练和数据扩展所能达到的极限,未来的AI进步将依赖于强化学习(RL)和代理框架。代理框架…...
