搜尋
首頁資料庫mysql教程自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

将陆续上传本人写的新书《自己动手写CPU》(尚未出版),今天是第12篇,我尽量每周四篇 书名又之前的《自己动手写处理器》改为《自己动手写CPU》 4.3 验证OpenMIPS实现效果 4.3.1指令存储器ROM的实现 本节将验证我们的OpenMIPS是否实现正确,包含:流水线是

将陆续上传本人写的新书《自己动手写CPU》(尚未出版),今天是第12篇,我尽量每周四篇

书名又之前的《自己动手写处理器》改为《自己动手写CPU》


4.3 验证OpenMIPS实现效果

4.3.1指令存储器ROM的实现

      本节将验证我们的OpenMIPS是否实现正确,包含:流水线是否正确、ori指令是否实现正确。在验证之前,需要首先实现指令存储器,以便OpenMIPS从中读取指令。

指令存储器模块是只读的,其接口如图4-7所示,还是采用左边是输入接口,右边是输出接口的方式绘制,这样便于理解。接口含义如表4-12所示。

自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

      指令存储器ROM模块在文件inst_rom.v中实现,代码如下,可以在本书附带光盘的Code\Chapter4\目录下找到源文件。

module inst_rom(

	input wire			ce,
	input wire[`InstAddrBus]	addr,
	output reg[`InstBus]		inst
	
);
       // 定义一个数组,大小是InstMemNum,元素宽度是InstBus
	reg[`InstBus]  inst_mem[0:`InstMemNum-1];

       // 使用文件inst_rom.data初始化指令存储器
	initial $readmemh ( "inst_rom.data", inst_mem );

       // 当复位信号无效时,依据输入的地址,给出指令存储器ROM中对应的元素
	always @ (*) begin
	  if (ce == `ChipDisable) begin
	    inst 
<p>      代码很好理解,有以下几点说明。</p>
<p>      (1)在初始化指令存储器时,使用了initial过程语句。initial过程语句只执行一次,通常用于仿真模块中对激励向量的描述,或用于给变量赋初值,是面向模拟仿真的过程语句,通常不能被综合工具支持。所以如果要将本章实现的OpenMIPS处理器使用综合工具进行综合,那么需要修改这里初始化指令存储器的方法。</p>
<p>      (2)在初始化指令存储器时,使用了系统函数$readmemh,表示从inst_rom.data文件中读取数据以初始化inst_mem,而inst_mem正是之前定义的数组。inst_rom.data是一个文本文件,里面存储的是指令,其每行存储一条32位宽度的指令(使用十六进制表示),系统函数$readmemh会将inst_rom.data中的数据依次填写到inst_mem数组中。</p>
<p>      (3)OpenMIPS是按照字节寻址的,而此处定义的指令存储器的每个地址是一个32bit的字,所以要将OpenMIPS给出的指令地址除以4再使用,比如:要读取地址0xC处的指令,那么实际就是对应ROM的inst_mem[3],如图4-8所示。</p>
<p><img  src="/static/imghwm/default1.png" data-src="/inc/test.jsp?url=http%3A%2F%2Fimg.blog.csdn.net%2F20140725125057562%3Fwatermark%2F2%2Ftext%2FaHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4%3D%2Ffont%2F5a6L5L2T%2Ffontsize%2F400%2Ffill%2FI0JBQkFCMA%3D%3D%2Fdissolve%2F70%2Fgravity%2FSouthEast&refer=http%3A%2F%2Fblog.csdn.net%2Fleishangwen%2Farticle%2Fdetails%2F38113933" class="lazy" alt="自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果" ><br>
</p>

<p>      除以4也就是将指令地址右移2位,所以在读取的时候给出的地址是addr[`InstMemNumLog2+1:2],其中InstMemNumLog2是指令存储器的实际地址宽度,比如:如果inst_mem有1024个元素,那么InstMemNum等于1024,InstMemNumLog2等于10,表示实际地址宽度为10。</p>
<h3 id="最小SOPC的实现">4.3.2 最小SOPC的实现 </h3>
<p>      为了验证,需要建立一个SOPC,其中仅包含OpenMIPS、指令存储器ROM,所以是一个最小SOPC。OpenMIPS从指令存储器中读取指令,指令进入OpenMIPS开始执行。最小SOPC的结构如图4-9所示。</p>
<img  src="/static/imghwm/default1.png" data-src="/inc/test.jsp?url=http%3A%2F%2Fimg.blog.csdn.net%2F20140725125417380%3Fwatermark%2F2%2Ftext%2FaHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4%3D%2Ffont%2F5a6L5L2T%2Ffontsize%2F400%2Ffill%2FI0JBQkFCMA%3D%3D%2Fdissolve%2F70%2Fgravity%2FSouthEast&refer=http%3A%2F%2Fblog.csdn.net%2Fleishangwen%2Farticle%2Fdetails%2F38113933" class="lazy" alt="自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果" ><br>

<p>      最小SOPC对应的模块是openmips_min_sopc,位于文件openmips_min_sopc.v中,读者可以在本书附带光盘的Code\Chapter4\目录下找到该文件,主要内容如下。在其中例化了处理器OpenMIPS、指令存储器ROM,并将两者按照图4-9的方式连接。</p>
<pre class="brush:php;toolbar:false">module openmips_min_sopc(

	input	wire		clk,
	input  wire		rst
	
);

  	// 连接指令存储器
  	wire[`InstAddrBus] inst_addr;
  	wire[`InstBus]     inst;
       wire               rom_ce;
 
       // 例化处理器OpenMIPS
 	openmips openmips0(
                 .clk(clk),			.rst(rst),
                 .rom_addr_o(inst_addr),	.rom_data_i(inst),
                 .rom_ce(rom_ce)
	);
	
       // 例化指令存储器ROM
	inst_rom inst_rom0(
		.ce(rom_ce),
		.addr(inst_addr),		.inst(inst)
	);

endmodule

4.3.3 编写测试程序

      我们需要写一段测试程序,并将其存储到指令存储器ROM,这样当上一节建立的最小SOPC开始运行的时候,就会从ROM中取出我们的程序,送入OpenMIPS处理器执行。由于目前的OpenMIPS只实现了一条ori指令,所以测试程序很简单,如下,对应本书附带光盘Code\Chapter4\TestAsm目录下的inst_rom.S文件。

  ori $1,$0,0x1100        # $1 = $0 | 0x1100 = 0x1100
  ori $2,$0,0x0020        # $2 = $0 | 0x0020 = 0x0020
  ori $3,$0,0xff00        # $3 = $0 | 0xff00 = 0xff00
  ori $4,$0,0xffff        # $4 = $0 | 0xffff = 0xffff

      共有4条指令,都是ori指令。

      第1条指令将0x1100进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$1中。

      第2条指令将0x0020进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$2中。

      第3条指令将0xff00进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$3中。

      第4条指令将0xffff进行零扩展后与寄存器$0进行逻辑“或”运算,结果保存在寄存器$4中。

      指令的注释说明了指令的执行结果。接下来,按照正常的顺序应该是使用编译器编译我们的测试程序,但由于GCC编译器的安装、使用、Makefile文件的制作等内容还需要不少篇幅讲解,而想必各位读者和笔者一样,急切地想知道OpenMIPS是否实现正确,所以本节采用手工编译的方式编译测试程序,4.4节将专题介绍GCC编译器的使用。

      手工编译只需按照指令内容填充进图4-1所示的ori指令格式中,即可得到对应的二进制字,比如:对于指令ori $1,$0,0x1100,对应的二进制字如图4-10所示。

自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

      转化为十六进制即0x34011100,其余3条指令按照同样的方式可以得到对应的二进制字,按照$readmemh函数的要求,一行放一条指令,得到测试程序对应的isnt_rom.data文件如下,可在本书附带光盘的Code\Chapter4\TestAsm目录下找到同名文件。

34011100
34020020
3403ff00
3404ffff

4.3.4 建立Test Bench文件

      本小节将建立Test Bench文件,其中给出最小SOPC运行所需的时钟信号、复位信号。代码如下,对应本书附带光盘Code\Chapter4\目录下的openmips_min_sopc_tb.v文件。

// 时间单位是1ns,精度是1ps
`timescale 1ns/1ps

module openmips_min_sopc_tb();

  reg     CLOCK_50;
  reg     rst;
  
  // 每隔10ns,CLOCK_50信号翻转一次,所以一个周期是20ns,对应50MHz
  initial begin
    CLOCK_50 = 1'b0;
    forever #10 CLOCK_50 = ~CLOCK_50;
  end
      
  // 最初时刻,复位信号有效,在第195ns,复位信号无效,最小SOPC开始运行
  // 运行1000ns后,暂停仿真
  initial begin
    rst = `RstEnable;
    #195 rst= `RstDisable;
    #1000 $stop;
  end
  
  // 例化最小SOPC
  openmips_min_sopc openmips_min_sopc0(
		.clk(CLOCK_50),
		.rst(rst)	
	);

endmodule

4.3.5使用ModelSim检验OpenMIPS实现效果

      万事俱备,只欠东风了,本节是验证前的最后一步——建立ModelSim工程,进行仿真。参考第2章的介绍,新建一个ModelSim工程,工程名可以为openmips_min_sopc,将上文创建的OpenMIPS所有源文件、Test Bench文件、指令存储器的源文件等(也就是本书附带光盘Code\Chapter4目录下所有.v文件)添加到工程中,然后编译。

      注意:还需要将上一小节制作的inst_rom.data文件复制到工程目录下。

      编译通过后,将workspace切换到Library选项卡,打开work这个library,选中openmips_min_sopc_tb,右键点击,选择Simulate,如图4-11所示。

自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

      在出现的波形显示界面中,添加要观察的信号,即可开始仿真。此处我们选择寄存器$1-$4作为观察对象,如图4-12所示,通过观察寄存器$1-$4的最终值,可知OpenMIPS正确执行了测试程序,也就是正确实现了ori指令。

自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

      添加更多要观察的信号,可以了解流水线执行情况,如图4-13所示。为了使流水线情况显示的更加直观,此处以第一条指令在流水线中的执行过程为例,并且图中去掉了其它指令执行时引起的信号变化。

自己动手写CPU之第四阶段(2)验证第一条指令ori的实现效果

      (1)在复位结束后的第一个时钟周期上升沿,rom_ce_o变为ChipEnable,表示指令存储器使能,开始取指,进入取指阶段,从指令存储器中取出第一条指令0x34011100,赋给IF/ID模块的输入端口if_inst。下一个时钟周期,第一条指令进入译码阶段。

      (2)观察译码阶段。

  •  此时译码阶段的指令id_inst正是第一条指令0x34011100
  •  指令地址id_pc是0x00000000
  •  在ID模块对指令进行译码,得到指令运算类型alusel_o是3'b001,查询defines.h文件中的宏定义可知,对应宏EXE_RES_LOGIC,表示是逻辑运算
  •  得到运算子类型aluop_o是8'b00100101,查询defines.h文件中的宏定义可知,对应宏EXE_OR_OP,表示逻辑“或”运算
  •  译码得到参与运算的源操作数1是0x00000000,正是$0寄存器的值
  •  译码得到参与运算的源操作数2是0x00001100,正是指令中立即数零扩展后的值
  •  译码得到wreg_o的值为1,表示要写目的寄存器
  •  译码得到要写入的目的寄存器wd_o是5'b00001,正是$1寄存器

      (3)观察执行阶段。

  •  进行指定的运算,得到wdata_o为0x00001100,就是要写到目的寄存器的数据
  •  传递译码阶段wreg_o的值,为1,表示要写目的寄存器
  •  传递译码阶段wd_o的值,为5'b00001,表示要写入的目的寄存器是$1寄存器

      (4)观察访存阶段

  •  传递执行阶段wdata_o的值,为0x00001100,表示要写到目的寄存器的数据
  •  传递执行阶段wreg_o的值,为1,表示要写目的寄存器
  •  传递执行阶段wd_o的值,为5'b00001,表示要写入的目的寄存器是$1寄存器

      (5)观察回写阶段

  •  得到访存阶段wdata_o的值,为0x00001100,表示要写到目的寄存器的数据
  •  得到访存阶段wreg_o的值,为1,表示要写目的寄存器
  •  得到访存阶段wd_o的值,为5'b00001,表示要写入的目的寄存器是$1寄存器

      在回写阶段的最后,将按照要求写目的寄存器$1,使得$1的值为0x00001100。通过上面的观察,可知原始的OpenMIPS五级流水线实现正确。接下来,我们就可以以此为基础,不断充实,添加实现更多的MIPS指令,不过,在此之前,我们要先学习使用GNU工具链,本节的例子只有4条指令,可以手工编译,以后会遇到比较复杂,拥有较多指令的程序,届时,手工编译就显得效率低下了,所以要使用GNU工具链。


未完待续!
陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
在MySQL中使用視圖的局限性是什麼?在MySQL中使用視圖的局限性是什麼?May 14, 2025 am 12:10 AM

mysqlviewshavelimitations:1)他們不使用Supportallsqloperations,限制DatamanipulationThroughViewSwithJoinsOrsubqueries.2)他們canimpactperformance,尤其是withcomplexcomplexclexeriesorlargedatasets.3)

確保您的MySQL數據庫:添加用戶並授予特權確保您的MySQL數據庫:添加用戶並授予特權May 14, 2025 am 12:09 AM

porthusermanagementinmysqliscialforenhancingsEcurityAndsingsmenting效率databaseoperation.1)usecReateusertoAddusers,指定connectionsourcewith@'localhost'or@'%'。

哪些因素會影響我可以在MySQL中使用的觸發器數量?哪些因素會影響我可以在MySQL中使用的觸發器數量?May 14, 2025 am 12:08 AM

mysqldoes notimposeahardlimitontriggers,butacticalfactorsdeterminetheireffactective:1)serverConfiguration impactactStriggerGermanagement; 2)複雜的TriggerSincreaseSySystemsystem load; 3)largertablesslowtriggerperfermance; 4)highConconcConcrencerCancancancancanceTigrignecentign; 5); 5)

mysql:存儲斑點安全嗎?mysql:存儲斑點安全嗎?May 14, 2025 am 12:07 AM

Yes,it'ssafetostoreBLOBdatainMySQL,butconsiderthesefactors:1)StorageSpace:BLOBscanconsumesignificantspace,potentiallyincreasingcostsandslowingperformance.2)Performance:LargerrowsizesduetoBLOBsmayslowdownqueries.3)BackupandRecovery:Theseprocessescanbe

mySQL:通過PHP Web界面添加用戶mySQL:通過PHP Web界面添加用戶May 14, 2025 am 12:04 AM

通過PHP網頁界面添加MySQL用戶可以使用MySQLi擴展。步驟如下:1.連接MySQL數據庫,使用MySQLi擴展。 2.創建用戶,使用CREATEUSER語句,並使用PASSWORD()函數加密密碼。 3.防止SQL注入,使用mysqli_real_escape_string()函數處理用戶輸入。 4.為新用戶分配權限,使用GRANT語句。

mysql:blob和其他無-SQL存儲,有什麼區別?mysql:blob和其他無-SQL存儲,有什麼區別?May 13, 2025 am 12:14 AM

mysql'sblobissuitableForStoringBinaryDataWithInareLationalDatabase,而ilenosqloptionslikemongodb,redis和calablesolutionsolutionsolutionsoluntionsoluntionsolundortionsolunsonstructureddata.blobobobissimplobisslowdeperformberbutslowderformandperformancewithlararengedata;

mySQL添加用戶:語法,選項和安全性最佳實踐mySQL添加用戶:語法,選項和安全性最佳實踐May 13, 2025 am 12:12 AM

toaddauserinmysql,使用:createUser'username'@'host'Indessify'password'; there'showtodoitsecurely:1)choosethehostcarecarefullytocon trolaccess.2)setResourcelimitswithoptionslikemax_queries_per_hour.3)usestrong,iniquepasswords.4)Enforcessl/tlsconnectionswith

MySQL:如何避免字符串數據類型常見錯誤?MySQL:如何避免字符串數據類型常見錯誤?May 13, 2025 am 12:09 AM

toAvoidCommonMistakeswithStringDatatatPesInMysQl,CloseStringTypenuances,chosethirtightType,andManageEngencodingAndCollat​​ionsEttingSefectery.1)usecharforfixed lengengtrings,varchar forvariable-varchar forbariaible length,andtext/blobforlargerdataa.2 seterters seterters seterters

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具