流水账(CPU设计实战)——lab3
Lab3 Rewrite V1.0
版本控制
| 版本 | 描述 |
|---|---|
| V0 | |
| V1.0 | 相对V0变化: 修改了文件名,各阶段以_stage结尾(因为if是关键词,所以module名不能叫if,遂改为if_stage,为了统一命名,将所有module后缀加上_stage) 删除了imm_sign信号(默认对立即数进行有符号数扩展) 由于对sw指令进行了重新理解:无论如何都是需要将rt_data传递给EXE阶段,故将部分译码逻辑进行后移至EXE阶段,避免id_to_exe_data总线过于庞大 将ins_shmat剔除出id_to_exe_data,因为imm包括ins_shamt 对信号进行重命名(例如在ID阶段有个信号叫rf_we,最终要传递给WB阶段,那么在EXE阶段,该信号叫作exe_rf_we,同理mem_rf_we,wb_rf_we),不然都叫rf_we,Debug的时候太痛苦了。 |
Top顶层
接口信号
MYCPU_TOP.v(TOP)
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 取指端访存接口 | |||
| inst_sram_en | 1 | O | 指令RAM使能信号,高电平有效 |
| inst_sram_wen | 4 | O | 指令RAM字节写使能信号,高电平有效 |
| inst_sram_addr | 32 | O | 指令RMA读写地址,字节寻址 |
| inst_sram_wdata | 32 | O | 指令RAM写数据 |
| inst_sram_rdata | 32 | I | 指令RAM读数据 |
| 数据端访存接口 | |||
| data_sram_en | 1 | O | 数据RAM使能信号,高电平有效 |
| data_sram_wen | 4 | O | 数据RAM字节写使能信号,高电平有效 |
| data_sram_addr | 32 | O | 数据RAM读写地址,字节寻址 |
| data_sram_wdata | 32 | O | 数据RAM写数据 |
| data_sram_rdata | 32 | I | 数据RAM读数据 |
| debug信号,供验证平台使用 | |||
| debug_wb_pc | 32 | O | 写回级(多周期最后一级)的PC,需要myCPU里将PC一路传递到写回级 |
| debug_wb_rf_wen | 4 | O | 写回级写寄存器堆(regfiles)的写使能,为字节使能,如果myCPU写regfiles为单字节写使能,则将写使能扩展成4位即可 |
| debug_wb_rf_wnum | 5 | O | 写回级写regfiles的目的寄存器号 |
| debug_wb_rf_wdata | 32 | O | 写回级写regfiles的写数据 |
接口时序
略(MIPS经典五级流水线)
代码结构
MYCPU_TOP.v
|____IF.v
|____ID.v
|____RF.v(2个读端口,1个写端口)
|____EXE.v
|____ALU.v
|____MEM.v
|____WB.v
|____MYCPU.h
DATA_RAM.v
IF.v(修改为IF_STAGE,因为会与关键词if冲突)
接口信号
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 与TOP | |||
| inst_sram_en | 1 | O | RAM使能信号,高电平有效 |
| inst_sram_wen | 4 | O | RAM字节写使能信号,高电平有效 |
| inst_sram_addr | 32 | O | RMA读写地址,字节寻址 |
| inst_sram_wdata | 32 | O | RAM写数据 |
| inst_sram_rdata | 32 | I | RAM读数据 |
| 与ID | |||
| id_to_if_allowin | 1 | I | pipe allowin |
| if_to_id_vld | 1 | O | pipe valid |
| if_to_id_data | 64 | O | pipe data(instruction 32-bits, pc 32-bits) |
| jump_bus | 33 | I | branch instructions(enable 1bit,address 32-bits) |
接口时序


ID.v
接口信号
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 与IF | |||
| id_to_if_allowin | 1 | O | pipe allowin |
| if_to_id_vld | 1 | I | pipe valid |
| if_to_id_data | 64 | I | pipe data(instruction 32-bits, pc 32-bits) |
| jump_bus | 33 | O | branch instructions(enable 1bit,address 32-bits) |
| 与EXE | |||
| exe_to_id_allowin | 1 | I | pipe allowin |
| id_to_exe_vld | 1 | O | pipe valid |
| id_to_exe_data | 135 | O | {ins_R:1, ins_I:1, imm:16, alu_op:13, mem_rd:1, mem_we:1, rf_we:1, rf_dst_addr:5, data_1:32, data_2:32, pc:32} |
| 与WB | |||
| wb_to_rf_bus | 38 | I | {rf_we:1, rf_addr:5, rf_data:32} |
接口信号(RF.v)
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| 与ID内部信号 | |||
| rf_r_addr1 | 5 | I | RF读地址1 |
| rf_r_data1 | 32 | O | RF读数据1 |
| rf_r_addr2 | 5 | I | RF读地址2 |
| rf_r_data2 | 32 | O | RF读数据2 |
| rf_wen1 | 1 | I | RF写使能1 |
| rf_w_addr1 | 5 | I | RF写地址1 |
| rf_w_data1 | 32 | O | RF写数据1 |
接口时序

电路设计

图3-4-1 译码电路分组(注:黄线少画了两条)
根据附录——MIPS指令。由于跳转指令不传递给EXE阶段,直接传递给IF阶段,且为纯组合逻辑输出,有可能成为关键路径,故对跳转指令单独处理。除了跳转指令外,涉及加法(减法归为加法)的指令如图3-4-1所示,即ins_addu、ins_addiu、ins_subu、ins_lw、ins_sw。
对于图3-4-1的拼接运算,可以当作移位运算执行。
EXE.v
接口信号
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 与TOP(外接的DATA_RAM) | |||
| data_sram_en | 1 | O | 数据RAM使能信号,高电平有效 |
| data_sram_wen | 4 | O | 数据RAM字节写使能信号,高电平有效(4个比特,应该代表32 = 4 bytes) |
| data_sram_addr | 32 | O | 数据RAM读写地址,字节寻址 |
| data_sram_wdata | 32 | O | 数据RAM写数据 |
| 与ID | |||
| exe_to_id_allowin | 1 | O | pipe allowin |
| id_to_exe_vld | 1 | I | pipe valid |
| id_to_exe_data | 135 | I | {ins_R:1, ins_I:1, imm:16, alu_op:13, mem_rd:1, mem_we:1, rf_we:1, rf_dst_addr:5, data_1:32, data_2:32, pc:32} |
| 与MEM | |||
| mem_to_id_allowin | 1 | I | pipe allowin |
| exe_to_mem_vld | 1 | O | pipe valid |
| exe_to_mem_data | 71 | O | {mem_rd:1, rf_we:1, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32 |
接口信号(ALU.v)
暂时不需要时钟和复位,纯组合逻辑
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 与ID内部信号 | |||
| alu_shamt | 6 | I | ALU移位(R-指令的shamt部分) |
| alu_op | 13 | I | ALU操作(加、减、乘除、位运算) |
| alu_din1 | 32 | I | ALU输入1 |
| alu_din2 | 32 | I | ALU输入2 |
| alu_out | 32 | O | ALU输出 |
接口时序


MEM.v
接口信号
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 与TOP(外接的DATA_RAM) | |||
| data_sram_rdata | 32 | I | 数据RAM读数据 |
| 与EXE | |||
| mem_to_exe_allowin | 1 | O | pipe allowin |
| exe_to_mem_vld | 1 | I | pipe valid |
| exe_to_mem_data | 71 | I | {mem_rd:1, rf_we:1, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32} |
| 与WB | |||
| wb_to_mem_allowin | 1 | I | pipe allowin |
| mem_to_wb_vld | 1 | O | pipe valid |
| mem_to_wb_data | 70 | O | { rf_we:1, rf_dst_addr:5, mem_result:32, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc)} |
WB.v
接口信号
| 名称 | 宽度 | 方向 | 描述 |
|---|---|---|---|
| 时钟与复位 | |||
| clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
| resetn | 1 | I | 复位信号,低电平同步复位 |
| 与TOP | |||
| debug_wb_pc | 32 | O | 写回级(多周期最后一级)的PC,需要myCPU里将PC一路传递到写回级(与原书保持一致) |
| debug_wb_rf_wen | 4 | O | 写回级写寄存器堆(regfiles)的写使能,为字节使能,如果myCPU写regfiles为单字节写使能,则将写使能扩展成4位即可(与原书保持一致) |
| debug_wb_rf_wnum | 5 | O | 写回级写regfiles的目的寄存器号(与原书保持一致) |
| debug_wb_rf_wdata | 32 | O | 写回级写regfiles的写数据(与原书保持一致) |
| 与MEM | |||
| wb_to_mem_allowin | 1 | O | pipe allowin |
| mem_to_wb_vld | 1 | I | pipe valid |
| mem_to_wb_data | 70 | I | { rf_we:1, rf_dst_addr:5, mem_result:32, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc)} |
| 与ID | |||
| wb_to_rf_bus | 38 | O | {rf_we:1, rf_addr:5, rf_data:32} |
接口时序

附录——参考
- 参考:处理机流水线------经典五段流水线-CSDN博客
附录——原书指令
| 指令 | sel_nextpc | inst_ram_wen | inst_ram_wen | sel_alu_src1 | sel_alu_src2 | alu_op | data_ram_en | data_ram_wen | rf_we | sel_rf_dst | sel_rf_res |
|---|---|---|---|---|---|---|---|---|---|---|---|
| ADDU | 0001 | 1 | 0 | 001 | 001 | 000000000001 | 0 | 0 | 1 | 001 | 0 |
| ADDIU | 0001 | 1 | 0 | 001 | 010 | 000000000001 | 0 | 0 | 1 | 010 | 0 |
| SUBU | 0001 | 1 | 0 | 001 | 001 | 000000000010 | 0 | 0 | 1 | 001 | 0 |
| LW | 0001 | 1 | 0 | 001 | 010 | 000000000001 | 1 | 0 | 1 | 010 | 1 |
| SW | 0001 | 1 | 0 | 001 | 010 | 000000000001 | 1 | 1 | 0 | 000 | 0 |
| BEQ | 0010 | 1 | 0 | 000 | 000 | 000000000000 | 0 | 0 | 0 | 000 | 0 |
| BNE | 0010 | 1 | 0 | 000 | 000 | 000000000000 | 0 | 0 | 0 | 000 | 0 |
| JAL | 0100 | 1 | 0 | 010 | 100 | 000000000001 | 0 | 0 | 1 | 100 | 0 |
| JR | 1000 | 1 | 0 | 000 | 000 | 000000000000 | 0 | 0 | 0 | 000 | 0 |
| SLT | 0001 | 1 | 0 | 001 | 001 | 000000000100 | 0 | 0 | 1 | 001 | 0 |
| SLTU | 0001 | 1 | 0 | 001 | 001 | 000000001000 | 0 | 0 | 1 | 001 | 0 |
| SLL | 0001 | 1 | 0 | 100 | 001 | 000100000000 | 0 | 0 | 1 | 001 | 0 |
| SRL | 0001 | 1 | 0 | 100 | 001 | 001000000000 | 0 | 0 | 1 | 001 | 0 |
| SRA | 0001 | 1 | 0 | 100 | 001 | 010000000000 | 0 | 0 | 1 | 001 | 0 |
| LUI | 0001 | 1 | 0 | 000 | 010 | 100000000000 | 0 | 0 | 1 | 010 | 0 |
| AND | 0001 | 1 | 0 | 001 | 001 | 000000010000 | 0 | 0 | 1 | 001 | 0 |
| OR | 0001 | 1 | 0 | 001 | 001 | 000001000000 | 0 | 0 | 1 | 001 | 0 |
| XOR | 0001 | 1 | 0 | 001 | 001 | 000010000000 | 0 | 0 | 1 | 001 | 0 |
| NOR | 0001 | 1 | 0 | 001 | 001 | 000000100000 | 0 | 0 | 1 | 001 | 0 |
附录——Debug
PC复位问题

PC的跳转有误,直接看IF_STAGE.v
修改代码为:

RegFile的零寄存器问题

修改如下:

RF数据高阻

发现数据有错,应当为63:32

跳转指令的PC值
跳转指令的PC,本人使用的都是ID阶段的pc,经过vivado调试,发现有误,隧改为如下,即使用IF阶段的pc:

lui译码错误
在ID阶段,lui指令译码错误,具体如下:
assign ins_lui = op_ext[6’h15] & rs_ext[5’h00];//错误
改为如下:
assign ins_lui = op_ext[6’h0f] & rs_ext[5’h00];
addiu执行错误
经排查,发现在ID阶段,忘了声明rs_data和rt_data这两个变量,导致被默认为1 bit(实际都是32 bit的变量)
addiu执行错误
(影响Debug了)
经排查,发现rs数据读取为高阻,向前追溯,发现是写寄存器的时候,写入的是高阻,最终发现在WB阶段的,rf_we始终为高,更改如下:
assign rf_we = wb_data[69] ;
assign debug_wb_rf_wen = {4{rf_we}} ;
assign wb_to_rf_bus[37] = rf_we & wb_vld;
改为:
assign rf_we = wb_data[69] & wb_vld;
assign debug_wb_rf_wen = {4{rf_we}} ;
assign wb_to_rf_bus[37] = rf_we ;
然而还是有错,遂向前回溯,发现RF.v中的rf_group声明有误:
reg [31:0] rf_group [4:0];
改为:
reg [31:0] rf_group [31:0];
lw错误
发现电路设计本身就有问题,原因为:从CSDN上的一个MIPS指令集设计的电路,但是该CSDN上的内容是错的!!!
电路设计错误:发现rf_we漏掉了ins_lw

更改如下:
assign rf_we = ins_addu
|ins_addiu
|ins_subu
|ins_lw
|ins_jal
|ins_slt xxxxxx ;
subu错误

assign alu_din2_two_cmpl[31] = 1’b1;
assign alu_din2_two_cmpl[30:0] = (~alu_din2) + 1’b1;
上面两句,修改为下:
assign alu_din2_two_cmpl[31:0] = (~alu_din2) + 1’b1;
在MIPS指令中有subu和sub两种指令,(lab3只要求实现subu,不要求实现sub指令)而在代码中本人将subu简写为sub是不合适的,已全部修改为subu
slt报错

原始代码:
assign result_slt = ($signed(alu_din1) < $signed(alu_din2)) ? 32’h1: 32’h0;
学习了下原书上的源码,发现可以将比较运算合并至减法运算,于是修改了slt(同时也修改了sltu)如下:
- assign add_din2 = (alu_subu | alu_slt | alu_sltu) ? alu_din2_two_cmpl
- alu_din2;
另外,我发现单独进行求补码运算,可能会浪费加法器,不利于vivado优化,遂修改

修改为:

nor报错
assign result_nor = ~result_xor ;
更改为:
assign result_nor = ~ result_or ;
srl报错

发现ID阶段的译码错误:
assign ins_srl = op_ext[6’h00] & sa_ext[5’h00] & fun_ext[6’h06];
更改为:
assign ins_srl = op_ext[6’h00] & rs_ext[5’h00] & fun_ext[6’h02];
sra报错

assign result_sra = alu_din2 >>> alu_shamt ;
更改为:
assign result_sra = $signed(alu_din2) >>> alu_shamt ;
sw/lw报错
lw报错,经排查是因为sw命令有误
本人设计的时候没有认真分析sw指令,导致EXE阶段的sram_wdata数据有误。
具体地讲,由于本人设计阶段欠缺,误认为加法结果给到sram_wdata(实际上加法结果是给sram_addr),导致出错。
由于欠思考导致总线也需要更改,需要将rt_data从ID阶段传递给exe阶段,因为sw指令执行中需要将rt_data赋给sram_wdata。
bne出错

又是码错了
assign jump_bne = (rt_equ_rs == 1’b0) & ins_beq ;
更改为:
assign jump_bne = (rt_equ_rs == 1’b0) & ins_bne ;
完结
还有一些小bug没有记录,终于pass了,完结。

后记
-
原书是将regfile.v当作ID_stage的一个子模块,WB_stage写回时,也是通过ID_stage的顶层将信号传递到regfile模块。本设计将regfile.v置于与ID、WB的同一hierarchy
-
原书将跳转指令(如JAL)的译码放在ID_stage模块中(没有问题,因为译码就是在ID_stage阶段),并以组合逻辑的形式传递给IF_stage(必须用组合逻辑,否则会影响流水)。本设计将跳转指令放在IF模块中,避免组合逻辑穿越模块边界。(还是不要合并,因为R、I、J型指令均含有跳转指令,合并至IF模块,会增加大量的额外译码逻辑。)
-
原书的译码方式值得学习:


若是按我之前的写法,大概率会写成如下形式:
always@(*)begin
case(xxxx)
…
endcase
end
always-case的形式容易写错,而且不够清晰。使用原书的写法,避免写成:
inst_addu = (op == 6’h0 ) & (func == 6’h21) & (sa == 5’h00);
- 小括号太多,看着就乱
- 等号也影响纠错
- 原书将0写成00,格式上是对齐的,更舒服
- 另外我猜测将判断逻辑写成generate—endgenerate的形式,也更容易让编译器进行优化
-
在自己设计译码的时候,本人遇到一个问题,译码到什么程度才算“译码”。是译码出R\I\J型指令(每种类型用1bit标志位表示),还是译码至具体的加减乘除?
我的思想:EXE除了负责寄存一些必要数据外(比如WB需要的数据),其核心执行内容应当只有:加、减、乘、除、移位、与、或、非、异或。也就是说,ID阶段负责输入的数据给准备好级EXE。然后我就在想Regfile怎么搞,因为Regfile读是不需要周期的(即本周期给出地址,本周就可以得到数据),但是WB写Regfile的时候,如果同时读Regfile的同一地址,怎么办呢?这个读写冲突应当放在Regfile中处理吗?
另一方面,EXE的执行时,输入可以是寄存器(比如and指令),也可以是pc(比如跳转指令)。当输入是寄存器时,需要读Regfile,当输入是pc时,不需要读Regfile,将Regfile置于与ID、EXE同一hierarchy,意味着需要在EXE阶段判断输入是pc还是来自Regfile,这样增加了复杂性。(我现在理解了原书为什么要把Regfile当作ID的子模块,还是有道理的)
-
原lab3中的ID_stage.v中的ds_to_es_bus是136bits,但是在EXE阶段还存在少量的译码,我认为译码这种东西应当在ID阶段全部完成,不应当在EXE阶段还进行译码。
-
译码逻辑我写的是:assign {ins_op, ins_rs, ins_rt, ins_rd, ins_sa, ins_fun} = ins;
原书代码给的是:
assign ins_op = ins[31:26];
assign ins_rs = ins[25:21];
assign ins_rt = ins[20:16];
assign ins_rd = ins[15:11];
assign ins_sa = ins[10:6] ;
assign ins_fun = ins[5:0] ;
assign ins_index = ins[25:0] ;
assign ins_imm = ins[15:0] ;
感觉还是书上写的比较易读,隧写成书上的这种形式
- 实例化,我写的是:
decoder_6_64 U_decoder_6_64(
.din ( ins ),
.dout( ins_ext )
);
原书上写的是:
decoder_6_64 U_decoder_6_64(.din ( ins ),.dout( ins_ext ) );
感觉还是差不多,我还是按我自己的写
-
在译码过程中对于5bits转32bits,和6bits转64bits。本人可以理解opcode和function需要转换成64bits、32bits,但是不明白rs、rt、rd、sa为何还需要转换。我现在是怀疑,后续指令会扩展,然后译码的时候将rt、rd、sa也加进去,可以确保指令译码的唯一性。
-
我原本想将ID阶段中的译码中的rf_dst_addr按下图进行Coding:

但是看了原书的代码后,认为,没默认ins_R选项即可,只需要判断其他写寄存器地址,遂改为如下:
assign rf_dst_addr = ins_jal ? 5’d31 : ins_I ? ins_rt : ins_rd ;
同理,也对data_2的生成进行了类似的修改。
- 原书源码中每个阶段的pc值叫作fs_pc、ds_pc等,而我写的代码中都叫作pc,导致使用vivado调试时,都叫作pc不好定位
- 在跑通了全程后(共两周,包括Debug两天),感觉自己的Coding水平还是不如原书,而且控制信号和数据通路结构层次不好,级与级之间的bus编码(信号的放置位置等)也不够完美,数据的命名相同不利于debug(比如都叫pc,分不清是if的pc,还是exe的pc)。数据的耦合严重,尤其是ID与EXE阶段,两个阶段的信号耦合过于严重。除此之外还有资源上的复用也有所欠缺。还有一点就是出现了许多Coding的问题,比如wire信号忘记声明就使用,bne却使用了beq的信号。最后一点就是9.14节的sw/lw报错问题,这个bug,本人解决了一个晚上加一个上午,因为在设计阶段,是按照CSDN上的一篇博客上给出的MIPS指令设计的,所以一直没意识到博客本身就有问题,这种先入为主的指令加上本人设计的代码结构在sw/lw指令上耦合严重,导致后来阅读龙芯给的PDF时也没意识的问题,最后阅读了lab3原书上的源码才发现问题。
相关文章:
流水账(CPU设计实战)——lab3
Lab3 Rewrite V1.0 版本控制 版本描述V0V1.0相对V0变化: 修改了文件名,各阶段以_stage结尾(因为if是关键词,所以module名不能叫if,遂改为if_stage,为了统一命名,将所有module后缀加上_stage&a…...
k8s集群配置普通用户权限
集群管理员:负责管理 Kubernetes 集群的用户,拥有最高权限,可以对集群中的资源进行任何操作。 开发者:在 Kubernetes 集群中部署和管理自己的应用,可能有限制的权限,仅能管理特定的命名空间或资源。 第三…...
clickhouse——clickhouse单节点部署及基础命令介绍
clickhouse支持运行在主流的64位CPU架构的linux操作系统之上,可以通过源码编译,预编译压缩包,docker镜像和rpm等多种方式进行安装。 一、单节点部署 1、安装curl工具 yum install -y curl 2、添加clickhouse的yum镜像 curl -s https://pack…...
MATLAB基础应用精讲-【数模应用】价格敏感度PSM分析(附python代码实现)
目录 前言 算法原理 什么是价格敏感度分析? 原理 示例 PSM用途...
数据驱动的UI艺术:智能设计的视觉盛宴
数据驱动的UI艺术:智能设计的视觉盛宴 引言 在当今这个数据泛滥的时代,大数据不仅仅是一种技术手段,它更是一种艺术形式。当大数据遇上UI设计,两者的结合便催生了一种全新的艺术形式——数据驱动的UI艺术。本文将探讨如何将数据…...
栈的特性及代码实现(C语言)
目录 栈的定义 栈的结构选取 链式储存结构和顺序栈储存结构的差异 栈的代码实现 "stack.h" "stack.c" 总结 栈的定义 栈:栈是限定仅在表尾进行插入和删除操作的线性表。 我们把运行插入的和删除的一段叫做栈顶(TOPÿ…...
防火墙如何端口映射?
防火墙端口映射(Firewall Port Mapping)是一种网络技术,通过对防火墙配置进行调整,允许外部网络用户访问内部网络中的指定端口。该技术使得外部用户可以通过公共网络访问内部网络中的特定服务或应用程序,从而实现远程访…...
咖啡看书休闲时光404错误页面源码
源码介绍 咖啡看书休闲时光404错误页面源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,重定向这个界面 源码效果 源码下载 咖啡看书…...
中央事件bus
中央事件bus的使用 使用场景:当需要传递给多个组件的时候例如父组件->子组件->孙组件,甚至还得传递到更深的组件的时候中央事件就起到了作用,不需要一直传递。bus其实就是一个发布订阅模式,利用vue的自定义事件机制 // 事…...
中国上市企业行业异质性数据分析
数据简介:企业行业异质性数据是指不同行业的企业在运营、管理、财务等方面的差异性数据。这些数据可以反映不同行业企业的特点、优势和劣势,以及行业间的异质性对企业经营和投资的影响。通过对企业行业异质性数据的分析,投资者可以更好地了解…...
【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP和Uniapp)
一款基于FastAdminThinkPHP和Uniapp进行开发的多平台(微信小程序、H5网页)溯源、防伪、管理一体化独立系统,拥有强大的防伪码和溯源码双码生成功能(内置多种生成规则)、批量大量导出防伪和溯源码码数据、支持代理商管理…...
鸿蒙ArkUI-X跨语言调用说明:【平台桥接(@arkui-x.bridge)】
平台桥接(arkui-x.bridge) 简介 平台桥接用于客户端(ArkUI)和平台(Android或iOS)之间传递消息,即用于ArkUI与平台双向数据传递、ArkUI侧调用平台的方法、平台调用ArkUI侧的方法。 以Android平台为例,Ark…...
ts面试题: 面试题2
31. 计算字符串长度 // 计算字符串的长度,类似于 String#length 。答案 type test Str1<"abc123">; type Str1<T extends string, L extends any[] []> T extends ${infer f}${infer b} ? Str1<b, [...L, f]> : L[length];32. 接…...
.NET 某和OA办公系统全局绕过漏洞分析
转自先知社区 作者:dot.Net安全矩阵 原文链接:.NET 某和OA办公系统全局绕过漏洞分析 - 先知社区 0x01 前言 某和OA协同办公管理系统C6软件共有20多个应用模块,160多个应用子模块,从功能型的协同办公平台上升到管理型协同管理平…...
Git-01
Git是一个免费且开源的分布式版本控制系统,它可以跟踪文件的修改、记录变更的历史,并且在多人协作开发中提供了强大的工具和功能。 Git最初是由Linus Torvalds开发的,用于Linux内核的开发,现在已经成为了广泛使用的版本控制系统&a…...
GitLab的原理及应用详解(七)
本系列文章简介: 随着软件开发的不断进步和发展,版本控制系统成为了现代软件开发过程中不可或缺的一部分。而GitLab作为其中一种流行的版本控制工具,在软件开发领域享有广泛的应用。GitLab不仅提供了强大的版本控制功能,还集成了项目管理、持续集成和部署、代码审查等多个功…...
Vue中使用Vue-scroll做表格使得在x轴滑动
页面效果 首先 npm i vuescroll 在main.js中挂载到全局 页面代码 <template><div class"app-container"><Header :titletitle gobackgoBack><template v-slot:icon><van-icon clickgoHome classicon namewap-home-o /></templat…...
【高频】从输入URL到页面展示到底发生了什么?
一、相关衍生面试问题: 浏览器输入美团网站,从回车到浏览器展示经历了哪些过程 ? http输入网页之后的流程? 百度搜索页面,从点开搜索框,到显示搜索页面经历了什么? 二、探究各个过程&#x…...
【CSharp】ushort[]的IntPtr快速转换为ushort[]无符号短整型数组
【CSharp】ushort[]的IntPtr快速转换为ushort[]无符号短整型数组 1.背景2.代码1.背景 参考博客: 【CSharp】无符号短整型数组ushort[]转化为IntPtr https://blog.csdn.net/jn10010537/article/details/139278321?spm=1001.2014.3001.5501探测器/相机SDK获得是InPtr指针,它…...
释放 OSINT 的力量:在线调查综合指南
开源情报 (OSINT) 是从公开信息中提取有价值见解的艺术。无论您是网络安全专业人士、道德黑客还是情报分析师,OSINT 都能为您提供先进的技术,帮助您筛选海量的数字数据,发现隐藏的真相。 在本文中,我们将深入研究大量的OSINT 资源…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
