一、OpenMIPS指令集CPU的ori指令的实现

前言

根据“自己动手写CPU”这本书学习,自己动手实现一个MIPS指令集的CPU。
本文章实现了一个ori指令即“或”操作的五级流水线,后续会持续添加其他指令完善此CPU。

文章作为学习笔记持续更新,源代码也在github上持续更新
项目源码https://github.com/yizhixiaohuihui/OpenMIPS.git

一、设计实现ori指令的OpenMIPS处理器

实现ori指令的OpenMIPS五级流水线结构图
在这里插入图片描述

说明:

1.1、取指阶段:取出指令存储器中的指令,同时PC值递增,准备取下一条指令

  1. PC模块(pc_reg.v):给出指令地址
`include "../rtl/defines.v"module pc_reg(input	wire							clk, input wire								rst,output reg[`InstAddrBus]		pc,	// 要读取的指令地址output reg                    			ce // ָ指令存储器使能信号
);always @ (posedge clk) beginif (rst == `RstEnable) begince <= `ChipDisable;					// 复位的时候指令存储器禁用end else begince <= `ChipEnable;					// 复位结束后指令存储器使能endendalways @ (posedge clk) beginif (ce == `ChipDisable) beginpc <= 32'h00000000;end else beginpc <= pc + 4'h4;					// pc+4指向下一条指令地址(一条指令32位对应4字节)endend
endmodule
  1. IF/ID模块(if_id.v):暂时保存取指阶段取得的指令
`include "../rtl/defines.v"module if_id(input	wire				 		clk,input wire							rst,input wire[`InstAddrBus]	 if_pc,		  // 取指阶段取得的指令对应的地址input wire[`InstBus]       		if_inst,	// 取指阶段取得的指令output reg[`InstAddrBus] 	 id_pc,		// 译码阶段的指令对应的地址output reg[`InstBus] 			id_inst   // 译码阶段的指令
);always @ (posedge clk) beginif (rst == `RstEnable) beginid_pc <= `ZeroWord;id_inst <= `ZeroWord;end else begin	// 其余时刻向下传递取指阶段的值id_pc <= if_pc;id_inst <= if_inst;endend
endmodule

1.2、译码阶段:对取到的指令进行译码 -> 给出要进行的运算类型,以及参与运算的操作数

  1. Regfile模块(regfile.v):实现32个32位通用整数寄存器,可以同时进行两个寄存器的读操作和一个寄存器的写操作
`include "../rtl/defines.v"module regfile(input	wire									clk,input wire										rst,// write portinput wire										we,input wire[`RegAddrBus]					waddr,input wire[`RegBus]						   wdata,// read port 1input wire										re1,input wire[`RegAddrBus]			  		raddr1,output reg[`RegBus]           			  rdata1,// read port 2input wire										re2,input wire[`RegAddrBus]			  		raddr2,output reg[`RegBus]           			  rdata2);// 1. define 32's 32bits registersreg[`RegBus]  regs[0:`RegNum-1];// 2. write operationalways @ (posedge clk) beginif (rst == `RstDisable) begin// we enable and write operation destination register != 0if((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) beginregs[waddr] <= wdata;endendend// Notice: read operation is Combinatorial logic// 3. read port1's read operationalways @ (*) beginif(rst == `RstEnable) beginrdata1 <= `ZeroWord;end else if(raddr1 == `RegNumLog2'h0) beginrdata1 <= `ZeroWord;end // if read port1 want read register is same as the register to writeelse if((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) beginrdata1 <= wdata;end else if(re1 == `ReadEnable) beginrdata1 <= regs[raddr1];end // if read port1 can't be usedelse beginrdata1 <= `ZeroWord;endend// 4. read port2's read operationalways @ (*) beginif(rst == `RstEnable) beginrdata2 <= `ZeroWord;end else if(raddr2 == `RegNumLog2'h0) beginrdata2 <= `ZeroWord;end else if((raddr2 == waddr) && (we == `WriteEnable) && (re2 == `ReadEnable)) beginrdata2 <= wdata;end else if(re2 == `ReadEnable) beginrdata2 <= regs[raddr2];end else beginrdata2 <= `ZeroWord;endendendmodule
  1. ID模块(id.v):对指令进行译码,得到最终运算的类型、子类型、源操作数1、源操作数2、要写入的目的寄存器地址等信息
`include "../rtl/defines.v"module id(input wire								 rst,input wire[`InstAddrBus]		  pc_i,input wire[`InstBus]          		 inst_i,// readed regfile's datainput wire[`RegBus]           		reg1_data_i,input wire[`RegBus]           		reg2_data_i,// ouput to Regfile's messageoutput reg                    			reg1_read_o,	// Regfile reg1's ReadEnableoutput reg                    			reg2_read_o,    // Regfile reg2's ReadEnableoutput reg[`RegAddrBus]       	reg1_addr_o,output reg[`RegAddrBus]       	reg2_addr_o, 	      // sent Execution stage messageoutput reg[`AluOpBus]         	  aluop_o,output reg[`AluSelBus]        	  alusel_o,output reg[`RegBus]           	   reg1_o,output reg[`RegBus]           	   reg2_o,output reg[`RegAddrBus]       	wd_o,output reg                    		    wreg_o
);// instructions codewire[5:0] op = inst_i[31:26]; // ori: judge 26-31bit can judge ori instructionwire[4:0] op2 = inst_i[10:6];wire[5:0] op3 = inst_i[5:0];wire[4:0] op4 = inst_i[20:16];// store immediate num that execute instructions needreg[`RegBus]	imm;// instruction is valid or notreg instvalid;// 1. decode instructionsalways @ (*) begin	if (rst == `RstEnable) beginaluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;wd_o <= `NOPRegAddr;wreg_o <= `WriteDisable;instvalid <= `InstValid;reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;reg1_addr_o <= `NOPRegAddr;reg2_addr_o <= `NOPRegAddr;imm <= 32'h0;			end else beginaluop_o <= `EXE_NOP_OP;alusel_o <= `EXE_RES_NOP;wd_o <= inst_i[15:11];wreg_o <= `WriteDisable;instvalid <= `InstInvalid;	   reg1_read_o <= 1'b0;reg2_read_o <= 1'b0;reg1_addr_o <= inst_i[25:21];	// rs register's addressreg2_addr_o <= inst_i[20:16];	// rt register's addressimm <= `ZeroWord;			case (op)`EXE_ORI:			begin   // judge is ori ins wreg_o <= `WriteEnable;		// ori need write in destination registeraluop_o <= `EXE_OR_OP;	// aiuop is or operationalusel_o <= `EXE_RES_LOGIC; // logic operationreg1_read_o <= 1'b1;	// only need read rsreg2_read_o <= 1'b0;	// immediate num not need read from regimm <= {16'h0, inst_i[15:0]}; // extend immediate num to unsinged 32 bits		wd_o <= inst_i[20:16]; // rt: destination register's address to write instvalid <= `InstValid;	end 							 default:			beginendendcase		  //case op			end       //ifend         //always// 2. choose source num2always @ (*) beginif(rst == `RstEnable) beginreg1_o <= `ZeroWord;end else if(reg1_read_o == 1'b1) beginreg1_o <= reg1_data_i; // rsend else if(reg1_read_o == 1'b0) beginreg1_o <= imm;end else beginreg1_o <= `ZeroWord;endend// 3. choose source num2 always @ (*) beginif(rst == `RstEnable) beginreg2_o <= `ZeroWord;end else if(reg2_read_o == 1'b1) beginreg2_o <= reg2_data_i;	// rtend else if(reg2_read_o == 1'b0) beginreg2_o <= imm;end else beginreg2_o <= `ZeroWord;endendendmodule
  1. ID/EX模块(id_ex.v):将ID模块译码阶段取得的结果在下个时钟传递到流水线执行阶段
`include "../rtl/defines.v"module id_ex(input	wire						clk,input wire							rst,// message from decodeStageinput wire[`AluOpBus]        id_aluop,input wire[`AluSelBus]       id_alusel,input wire[`RegBus]           id_reg1,input wire[`RegBus]           id_reg2,input wire[`RegAddrBus]     id_wd,input wire                    		id_wreg,	// message sent to executeStageoutput reg[`AluOpBus]        ex_aluop,output reg[`AluSelBus]       ex_alusel,output reg[`RegBus]           ex_reg1,output reg[`RegBus]           ex_reg2,output reg[`RegAddrBus]     ex_wd,output reg                    		ex_wreg);always @ (posedge clk) beginif (rst == `RstEnable) beginex_aluop <= `EXE_NOP_OP;ex_alusel <= `EXE_RES_NOP;ex_reg1 <= `ZeroWord;ex_reg2 <= `ZeroWord;ex_wd <= `NOPRegAddr;ex_wreg <= `WriteDisable;end else begin		ex_aluop <= id_aluop;ex_alusel <= id_alusel;ex_reg1 <= id_reg1;ex_reg2 <= id_reg2;ex_wd <= id_wd;ex_wreg <= id_wreg;		endendendmodule

1.3、执行阶段:依据译码阶段的结果,对源操作数1、源操作数2、进行指定的运算

  1. EX模块(ex.v):从ID/EX模块得到运算的类型、子类型、源操作数1、源操作数2、要写入的目的寄存器地址,并依据这些数据进行计算
`include "../rtl/defines.v"module ex(input wire										rst,// message rom decodeStageinput wire[`AluOpBus]        aluop_i,input wire[`AluSelBus]       alusel_i,input wire[`RegBus]           reg1_i,input wire[`RegBus]           reg2_i,input wire[`RegAddrBus]     wd_i,input wire                    		wreg_i,// execute resultoutput reg[`RegAddrBus]     wd_o,output reg                    		wreg_o,output reg[`RegBus]			   wdata_o);// save logic op resultreg[`RegBus] logicout;// 1. according aluop_i to operatealways @ (*) beginif(rst == `RstEnable) beginlogicout <= `ZeroWord;end else begincase (aluop_i)`EXE_OR_OP:			beginlogicout <= reg1_i | reg2_i;enddefault:				beginlogicout <= `ZeroWord;endendcaseend    end      // 2. according alusel_i to choose an op result as last resultalways @ (*) beginwd_o <= wd_i;	// detinationReg's address need write wreg_o <= wreg_i; // write reg enablecase ( alusel_i ) `EXE_RES_LOGIC:		beginwdata_o <= logicout; // save op resultenddefault:					beginwdata_o <= `ZeroWord;endendcaseend	endmodule
  1. EX/MEM模块(ex_mem.v):将执行阶段取得的运算结果在下个时钟传递到流水线访存阶段
`include "../rtl/defines.v"module ex_mem(input wire						  	  clk,input wire							  rst,// message from executeStageinput wire[`RegAddrBus]       ex_wd,input wire                    		  ex_wreg,input wire[`RegBus]				ex_wdata, 	// message sent to accessStageoutput reg[`RegAddrBus]      mem_wd,output reg                   		 mem_wreg,output reg[`RegBus]				mem_wdata);always @ (posedge clk) beginif(rst == `RstEnable) beginmem_wd <= `NOPRegAddr;mem_wreg <= `WriteDisable;mem_wdata <= `ZeroWord;	end else beginmem_wd <= ex_wd;mem_wreg <= ex_wreg;mem_wdata <= ex_wdata;			end    end      endmodule

1.4、访存阶段:由于ori指令不需要访问数据存储器,所以在访存阶段不做任何事,只是简单地将执行阶段的结果向写回阶段传递

  1. MEM模块(mem.v):将输入的执行阶段的结果直接作为输出
`include "../rtl/defines.v"module mem(input wire							rst,// message from executeStageinput wire[`RegAddrBus]     wd_i,input wire                    		wreg_i,input wire[`RegBus]			   wdata_i,// result in accessStageoutput reg[`RegAddrBus]     wd_o,output reg                   		wreg_o,output reg[`RegBus]			   wdata_o);always @ (*) beginif(rst == `RstEnable) beginwd_o <= `NOPRegAddr;wreg_o <= `WriteDisable;wdata_o <= `ZeroWord;end else beginwd_o <= wd_i;wreg_o <= wreg_i;wdata_o <= wdata_i;end   end      endmodule
  1. MEM/WB模块(mem_wb.v):将访存阶段的运算结果,在下一个时钟传递到回写阶段
`include "../rtl/defines.v"module mem_wb(input	wire						clk,input wire							rst,// accessStage result input wire[`RegAddrBus]     mem_wd,input wire                    		mem_wreg,input wire[`RegBus]			   mem_wdata,// message sent to writeBackStageoutput reg[`RegAddrBus]    wb_wd,output reg                   	   wb_wreg,output reg[`RegBus]			  wb_wdata	       );always @ (posedge clk) beginif(rst == `RstEnable) beginwb_wd <= `NOPRegAddr;wb_wreg <= `WriteDisable;wb_wdata <= `ZeroWord;	end else beginwb_wd <= mem_wd;wb_wreg <= mem_wreg;wb_wdata <= mem_wdata;end    //ifend      //alwaysendmodule

1.5、回写阶段:将指令的运算结果写入目的寄存器

  1. Regfile模块(regfile.v):将指令的运算结果写入目的寄存器

ori指令格式
在这里插入图片描述

地址为rs的寄存器的值 = 立即数 or 地址为rt的寄存器的值
目的操作数 = 源操作数1 || 源操作数2

1.6、顶层模块

在这里插入图片描述

`include "../rtl/defines.v"module openmips(input wire clk,input wire rst,input wire[`RegBus] rom_data_i, // instruction get from instructionRomemaryoutput wire[`RegBus] rom_addr_o, // address ouput to instructionRomemaryoutput wire rom_ce_o // instructionRomemary enable);// PC -> IF/IDwire[`InstAddrBus] pc;// IF/ID -> IDwire[`InstAddrBus] id_pc_i;wire[`InstBus] id_inst_i;// ID -> ID/EXwire[`AluOpBus] id_aluop_o;wire[`AluSelBus] id_alusel_o;wire[`RegBus] id_reg1_o;wire[`RegBus] id_reg2_o;wire id_wreg_o;wire[`RegAddrBus] id_wd_o;// ID/EX -> EXwire[`AluOpBus] ex_aluop_i;wire[`AluSelBus] ex_alusel_i;wire[`RegBus] ex_reg1_i;wire[`RegBus] ex_reg2_i;wire ex_wreg_i;wire[`RegAddrBus] ex_wd_i;// EX -> EX/MEMwire ex_wreg_o;wire[`RegAddrBus] ex_wd_o;wire[`RegBus] ex_wdata_o;// Ex/MEM -> MEMwire mem_wreg_i;wire[`RegAddrBus] mem_wd_i;wire[`RegBus] mem_wdata_i;// MEM -> MEM/WB wire mem_wreg_o;wire[`RegAddrBus] mem_wd_o;wire[`RegBus] mem_wdata_o;// MEM/WB -> WBwire wb_wreg_i;wire[`RegAddrBus] wb_wd_i;wire[`RegBus] wb_wdata_i;// ID <-> Regfilewire reg1_read;wire reg2_read;wire[`RegBus] reg1_data;wire[`RegBus] reg2_data;wire[`RegAddrBus] reg1_addr;wire[`RegAddrBus] reg2_addr;pc_reg pc_reg0(.clk(clk),.rst(rst),.pc(pc),.ce(rom_ce_o)	);assign rom_addr_o = pc;if_id if_id0(.clk(clk),.rst(rst),.if_pc(pc),.if_inst(rom_data_i),.id_pc(id_pc_i),.id_inst(id_inst_i)      	);id id0(.rst(rst),.pc_i(id_pc_i),.inst_i(id_inst_i),.reg1_data_i(reg1_data),.reg2_data_i(reg2_data),.reg1_read_o(reg1_read),.reg2_read_o(reg2_read), 	  .reg1_addr_o(reg1_addr),.reg2_addr_o(reg2_addr), .aluop_o(id_aluop_o),.alusel_o(id_alusel_o),.reg1_o(id_reg1_o),.reg2_o(id_reg2_o),.wd_o(id_wd_o),.wreg_o(id_wreg_o));regfile regfile1(.clk (clk),.rst (rst),.we	(wb_wreg_i),.waddr (wb_wd_i),.wdata (wb_wdata_i),.re1 (reg1_read),.raddr1 (reg1_addr),.rdata1 (reg1_data),.re2 (reg2_read),.raddr2 (reg2_addr),.rdata2 (reg2_data));id_ex id_ex0(.clk(clk),.rst(rst),.id_aluop(id_aluop_o),.id_alusel(id_alusel_o),.id_reg1(id_reg1_o),.id_reg2(id_reg2_o),.id_wd(id_wd_o),.id_wreg(id_wreg_o),.ex_aluop(ex_aluop_i),.ex_alusel(ex_alusel_i),.ex_reg1(ex_reg1_i),.ex_reg2(ex_reg2_i),.ex_wd(ex_wd_i),.ex_wreg(ex_wreg_i));		ex ex0(.rst(rst),.aluop_i(ex_aluop_i),.alusel_i(ex_alusel_i),.reg1_i(ex_reg1_i),.reg2_i(ex_reg2_i),.wd_i(ex_wd_i),.wreg_i(ex_wreg_i),.wd_o(ex_wd_o),.wreg_o(ex_wreg_o),.wdata_o(ex_wdata_o));ex_mem ex_mem0(.clk(clk),.rst(rst),.ex_wd(ex_wd_o),.ex_wreg(ex_wreg_o),.ex_wdata(ex_wdata_o),.mem_wd(mem_wd_i),.mem_wreg(mem_wreg_i),.mem_wdata(mem_wdata_i));mem mem0(.rst(rst),.wd_i(mem_wd_i),.wreg_i(mem_wreg_i),.wdata_i(mem_wdata_i),.wd_o(mem_wd_o),.wreg_o(mem_wreg_o),.wdata_o(mem_wdata_o));mem_wb mem_wb0(.clk(clk),.rst(rst),.mem_wd(mem_wd_o),.mem_wreg(mem_wreg_o),.mem_wdata(mem_wdata_o),.wb_wd(wb_wd_i),.wb_wreg(wb_wreg_i),.wb_wdata(wb_wdata_i));endmodule

二、验证设计正确性

2.1 指令存储器ROM

在这里插入图片描述

  1. 在初始化指令存储器时使用了initial过程语句,不能被综合工具支持,若想被综合修改初始化指令存储器的方法
  2. $readmemh读取数据的系统函数,表示从inst_rom.data文件中读取数据以初始化inst_mem
  3. OpenMIPS是按字节寻址的,而此处定义的指令存储器的每个地址是一个32bit的字,所以要将OpenMIPS给出的地址除以4再使用
    在这里插入图片描述

2.2最小SOPC

为了验证建立一个SOPC:OpenMIPS从指令存储器读取指令,指令进入OpenMIPS开始执行
在这里插入图片描述

`include "../rtl/defines.v"module openmips_min_sopc(input wire clk,input wire rst);//openmips <-> ROMwire[`InstAddrBus] inst_addr;wire[`InstBus] inst;wire rom_ce;openmips openmips0(.clk(clk),.rst(rst),.rom_addr_o(inst_addr),.rom_data_i(inst),.rom_ce_o(rom_ce));inst_rom inst_rom0(.addr(inst_addr),.inst(inst),.ce(rom_ce)	);endmodule

2.3使用VCS和verdi联合仿真

“自己动手写CPU”这本书是在windows环境下用modelsim软件进行仿真验证,而众所周知工业界都是在Linux环境下使用VCSverdi进行仿真验证,因此本文使用Linux环境进行验证并可以学习一些VCSverdi软件的使用。

如何得到inst_rom.data文件参考文章https://blog.csdn.net/yvbycf/article/details/128359374

testbench文件


`include "../rtl/defines.v"
`timescale 1ns/1psmodule openmips_min_sopc_tb();reg CLOCK_50;reg rst;initial beginCLOCK_50 = 1'b0;// cycle is 20ns: 50Mhzforever #10 CLOCK_50 = ~CLOCK_50;endinitial beginrst = `RstEnable;// min sopc start run#195 rst= `RstDisable;#1000 $stop;endopenmips_min_sopc openmips_min_sopc0(.clk(CLOCK_50),.rst(rst)	);initial	begin$fsdbDumpfile("tb.fsdb"); // generate "tb.fsdb"// $fsdbDumpvars(0, openmips_min_sopc_tb,  "+mda"); // dump tb and dut ports, "+mda"->dump mem$fsdbDumpvars(0, openmips_min_sopc_tb); // dump tb and dut ports$fsdbDumpMDA( ); // dump memendendmodule

注意:

  • 要在vedi中显示波形需要使用 $fsdbDumpfile( )函数指定波形文件名
  • 要使用函数$fsdbDumpvars( )去dump tb和dut的端口加载波形
  • 要加载寄存器数组的波形,需要使用$fsdbDumpMDA( )函数

我们使用Makefile文件控制VCS和verdi联合仿真
Makfile文件


all  : vcs verdivcs   :vcs  \-f filelist.f  \-timescale=1ns/1ps \-debug_acc+dmptf -debug_region+cell+encrypt  -full64  -R  +vc  +v2k  -sverilog  -debug_all  \-P ${LD_LIBRARY_PATH}/novas.tab  ${LD_LIBRARY_PATH}/pli.a  \|  tee  vcs.log  verdi  :verdi -f filelist.f -ssf tb.fsdb clean  :rm  -rf  *~  core  csrc  simv*  vc_hdrs.h  ucli.key  urg* *.log  novas.* *.fsdb* verdiLog  64* DVEfiles *.vpd

在文件夹sim/下使用命令

make vcs
make verdi

即可仿真及打开verdi查看波形
如何编写Makefile进行vcs+verdi联合仿真可参考本人的另一篇博客VCS + verdi + Makefile

仿真波形图
在这里插入图片描述

  1. if_inst是取到的指令,从仿真可知,依次取出inst_rom.data中的指令
  2. 观察regs[1]、regs[2]、regs[3]、regs[4]的最终值,可知OpenMIPS正确执行了程序

三、链接汇总

项目源码https://github.com/yizhixiaohuihui/OpenMIPS.git
如何得到inst_rom.data文件参考文章https://blog.csdn.net/yvbycf/article/details/128359374
如何编写Makefile进行vcs+verdi联合仿真可参考本人的另一篇博客VCS + verdi + Makefile

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/807749.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

头歌-机器学习 第1次实验 Python机器学习软件包Scikit-Learn的学习与运用

第1关&#xff1a;使用scikit-learn导入数据集 scikit-learn包括一些标准数据集&#xff0c;不需要从外部下载&#xff0c;可直接导入使用&#xff0c;比如与分类问题相关的Iris数据集和digits手写图像数据集&#xff0c;与回归问题相关的波士顿房价数据集。 以下列举一些简单…

JAVA面试八股文之数据库

MySQL面试题 MySQL 存储引擎架构了解吗&#xff1f;CHAR 和 VARCHAR 的区别是什么&#xff1f;索引是越多越好嘛&#xff1f;MySQL数据库中空值&#xff08;null&#xff09;和空字符串&#xff08;&#xff09;的区别&#xff1f;SQL 中 on 条件与 where 条件的区别&#xff1…

面试算法-171-翻转二叉树

题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 解 class Solution {public TreeNode invertTree(TreeNode root) {if (root n…

腾讯云4核8G服务器多少钱?4核8G能干啥?

腾讯云4核8G服务器多少钱&#xff1f;腾讯云4核8G轻量应用服务器12M带宽租用价格646元15个月&#xff0c;活动页面 txybk.com/go/txy 活动链接打开如下图所示&#xff1a; 腾讯云4核8G服务器优惠价格 这台4核8G服务器是轻量应用服务器&#xff0c;详细配置为&#xff1a;轻量4核…

前端代码优化--computed

随便记录一下 主要是通过计算属性来简化和优化代码。在 Vue 中&#xff0c;计算属性是一种方便的工具&#xff0c;可以让你根据依赖状态的变化来动态计算衍生值。在这个例子中&#xff0c;我们使用计算属性 formattedCommunicationType 来根据 workDetail.realTimeItemDeviceDT…

openlayer实现webgis端绘制制图及编辑

在WebGIS端制图是指通过Web浏览器界面实现地理信息数据的可视化、编辑、分析以及地图产品的制作。这一过程通常涉及以下几个关键环节&#xff1a; **1. 前端技术栈&#xff1a; •HTML/CSS/JavaScript&#xff1a;作为Web开发的基础&#xff0c;用于构建用户界面布局、样式设…

Win11又来「重大」更新!

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站ai人工智能工具 更多资源欢迎关注 Windows 11预览通道的22635.3420版本迎来了几个比较大的改进&#xff0c;主要有三个方面&#xff1a; …

一种快速移植 OpenHarmony Linux 内核的方法

移植概述 本文面向希望将 OpenHarmony 移植到三方芯片平台硬件的开发者&#xff0c;介绍一种借助三方芯片平台自带 Linux 内核的现有能力&#xff0c;快速移植 OpenHarmony 到三方芯片平台的方法。 移植到三方芯片平台的整体思路 内核态层和用户态层 为了更好的解释整个内核…

python-study-day1-(病人管理系统-带sql)

MainWindow代码 from tkinter import * from tkinter import messagebox from tkinter.ttk import Comboboxclass MianWindow(Frame):def __init__(self, masterNone):super().__init__(master, padx30, pady20)self.flag 0self.pack(expandTrue, fillBOTH)self.id StringVa…

深入OceanBase内部机制:系统架构与组件精讲

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 1️⃣OceanBase 整体架构1.1 分区1.2 分片1.3 日志流1.4 对等节点1.5 多租户 2️⃣OceanBase 架构与组件详解2.1 存储层2.2 …

Disk Drill Enterprise for Mac v5.5.1515数据恢复软件中文版

Disk Drill 是 Mac 操作系统固有的Mac数据恢复软件&#xff1a;使用 Recovery Vault 轻松保护文件免遭意外删除&#xff0c;并从 Mac 磁盘恢复丢失的数据。支持大多数存储设备&#xff0c;文件类型和文件系统。 软件下载&#xff1a;Disk Drill Enterprise for Mac v5.5.1515激…

keepalived2.2.8+drbd9+nfs高可用存储部署

目录 一.本文基于上一篇文章keepalived环境来做的&#xff0c;主机信息如下 二.为两台虚拟机准备添加一块新硬盘设备 三.安装drbd9 1.使用扩展源的rpm包来下载 2.创建资源并挂载到新增的硬盘 3.主设备升级身份 4.主备两个设备手动切换身份演示 四.安装配置nfs 五.安装…

【YOLOv8】Yolov5和Yolov8网络结构的分析与对比

目录 一 YOLOv5 二 YOLOv8 yolo通常采用backbone-neck-head的网络结构。 Backbone 主要负责从输入图像中提取高层次的语义特征,常包含多个卷积层和池化层&#xff0c;构建了一个深层次的特征提取器。Neck通常用来进一步整合与调整backbone提取的特征&#xff0c;有利于将不同…

大话设计模式——24.迭代器模式(Iterator Pattern)

简介 提供一种方法顺序访问一个聚合对象中各个元素&#xff0c;而又不暴露该对象的内部实现。&#xff08;Java中使用最多的设计模式之一&#xff09; UML图 应用场景 Java的集合对象&#xff1a;Collection、List、Map、Set等都有迭代器Java ArrayList的迭代器源码 示例 简…

uniapp的h5项目 用命令起这个项目(vue-cli)

这里其实就相当于给uniapp h5套了一个vue-cli的壳&#xff08;纯属个人感觉&#xff09; 首先需要安装vue-cli 脚手架 npm install -g vue/cli然后创建项目&#xff08;这里需要在hbuilder创建&#xff09; vue create -p dcloudio/uni-preset-vue uniapp安装成功后它的结构…

OSCP靶场--Dibble

OSCP靶场–Dibble 考点(前端鉴权参数修改node.js代码注入 suid cp提权 ) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.173.110 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-09 06:36 EDT Nmap scan repor…

Jackson配置处理LocalDateTime、LocalDate等java8时间类型失效的问题解决

目录 前言 一、问题排查过程 1.1 SpringMvc是如何处理请求报文和响应报文 1.2 JacksonConfig配置排查 二、导致Jackson配置失效的原因 2.1 没有addSerializer 2.2 添加了EnableMvc注解 2.3 另外有地方配置了Jacksonhttpconver覆盖了配置 总结 前言 上一篇文章《使用Ja…

C/C++的内存管理

栈帧最主要的作用就是存储局部数据 C语言中动态内存管理方式 C语言动态内存管理 该篇详细的讲述了C语言动态内存管理的使用&#xff0c;不太懂的小伙伴可以去了解一下 C中动态内存管理方式 首先&#xff0c;C语言内存管理的方式在C中可以继续使用。但有些地方就无能为力而且使用…

Volatility-内存取证案例1-writeup--xx大赛

题目提示&#xff1a;flag{中文} 按部就班 &#xff08;1&#xff09;获取内存镜像版本信息 volatility -f 文件名 imageinfo 通过上述可知&#xff0c;镜像版本为Win7SP1X64。 &#xff08;2&#xff09;获取进程信息&#xff1a; volatility -f 镜像名 --profile第一步获取…

关于AI Agent、RAG技术揭秘:如何让人工智能更懂你?

人工智能技术正以前所未有的速度改变着我们的世界。从深度学习算法的突破到自动化和机器学习技术的进步。在这个变革的时代&#xff0c;几种前沿技术尤其引人注目&#xff0c;其中包括RAG&#xff08;Retrieval-Augmented Generation&#xff09;、AI Agent以及多模态技术。 近…