自己动手写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所示。

指令存储器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/imghw/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/imghw/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所示。

转化为十六进制即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所示。

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

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

(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工具链。
未完待续!

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Terrariaでコマンドを使用してアイテムを取得するにはどうすればよいですか? 1. Terraria でアイテムを与えるコマンドは何ですか? Terraria ゲームでは、アイテムにコマンドを与えることは非常に実用的な機能です。このコマンドにより、プレイヤーはモンスターと戦ったり、特定の場所にテレポートしたりすることなく、必要なアイテムを直接入手できます。これにより、時間が大幅に節約され、ゲームの効率が向上し、プレイヤーは世界の探索と構築により集中できるようになります。全体として、この機能によりゲーム体験がよりスムーズで楽しいものになります。 2. Terraria を使用してアイテム コマンドを与える方法 1. ゲームを開き、ゲーム インターフェイスに入ります。 2. キーボードの「Enter」キーを押してチャットウィンドウを開きます。 3. チャットウィンドウにコマンド形式「/give[プレイヤー名][アイテムID][アイテム数量]」を入力します。

コンピュータの CPU をオーバークロックする方法 テクノロジーの継続的な進歩に伴い、コンピュータのパフォーマンスに対する人々の要求もますます高くなっています。コンピューターのパフォーマンスを向上させる効果的な方法は、オーバークロックによって CPU の動作周波数を上げることです。オーバークロックにより、CPU はデータをより高速に処理できるようになり、より高いコンピューティング能力が提供されます。では、コンピューターの CPU をオーバークロックするにはどうすればよいでしょうか?ここではオーバークロックの基本原理と具体的な操作方法を紹介します。まず、オーバークロックがどのように機能するかを理解しましょう。 CPUの動作周波数はマザーボード上の水晶発振器によって決まります。

1. まず、タスクバーの空白スペースを右クリックして[タスクマネージャー]オプションを選択するか、スタートロゴを右クリックして[タスクマネージャー]オプションを選択します。 2. 開いたタスク マネージャー インターフェイスで、右端の [サービス] タブをクリックします。 3. 開いた[サービス]タブで、下の[サービスを開く]オプションをクリックします。 4. 表示される[サービス]ウィンドウで、[InternetConnectionSharing(ICS)]サービスを右クリックし、[プロパティ]オプションを選択します。 5. 表示されたプロパティ画面で[プログラムから開く]を[無効]に変更し、[適用]をクリックして[OK]をクリックします。 6. スタートロゴをクリックし、シャットダウンボタンをクリックして[再起動]を選択し、コンピュータの再起動を完了します。

7月28日の当サイトのニュースによると、海外メディアTechRaderは、富士通が2027年に出荷予定の「FUJITSU-MONAKA」(以下、MONAKA)プロセッサを詳しく紹介したと報じた。 MONAKACPUは「クラウドネイティブ3Dメニーコア」アーキテクチャをベースとし、Arm命令セットを採用しており、AIコンピューティングに適しており、メインフレームレベルのRAS1を実現できます。富士通は、MONAKAはエネルギー効率と性能の飛躍的な向上を達成すると述べた。超低電圧(ULV)技術などの技術のおかげで、CPUは2027年には競合製品の2倍のエネルギー効率を達成でき、冷却には水冷が必要ない; さらに、プロセッサのアプリケーションパフォーマンスが相手の2倍に達することもあります。命令に関しては、MONAKAにはvectorが搭載されています。

IntelArrowLake は、LunarLake と同じプロセッサ アーキテクチャに基づいていると予想されており、つまり、Intel の新しい Lion Cove パフォーマンス コアが経済的な Skymont 効率コアと組み合わされることになります。

6 月 1 日のこの Web サイトのニュースによると、ソースの @CodeCommando が本日ツイートし、Computex2024 イベントでの AMD の今後のプレゼンテーション資料のスクリーンショットを共有しました。ツイートの内容は「AM4 は決して死ぬことはない」であり、添付の写真には 2 つの新しいものが示されていました。 Ryzen5000XTシリーズプロセッサ。スクリーンショットによると、次の 2 つの製品が示されています。 Ryzen95900XTR Ryzen95900XT は、AMD の Ryzen95950X よりもわずかに遅いクロック速度を持つ、比較的ハイエンドに位置する新しい 16 コア AM4 プロセッサです。 Ryzen75800XT AMD の既存の Ryzen75800X プロセッサの高速バージョンです。両方のプロセッサのクロックは最大 4.8G です。

1. WeChatを開いた後、検索アイコンをクリックし、WeChatチームと入力し、下のサービスをクリックして入力します。 2. 入力後、左下隅にあるセルフサービス ツール オプションをクリックします。 3. をクリックした後、上のオプションで、補助検証のブロック解除/再審査請求のオプションをクリックします。

1. 概要 sar コマンドは、システムアクティビティから収集されたデータを通じてシステム使用状況レポートを表示します。これらのレポートはさまざまなセクションで構成されており、各セクションにはデータの種類とデータが収集された時期が含まれます。 sar コマンドのデフォルト モードでは、CPU にアクセスするさまざまなリソース (ユーザー、システム、I/O スケジューラなど) の CPU 使用率がさまざまな時間増分で表示されます。さらに、特定の期間におけるアイドル状態の CPU の割合も表示されます。各データ ポイントの平均値はレポートの下部にリストされます。 sar レポートはデフォルトで 10 分ごとにデータを収集しますが、さまざまなオプションを使用してこれらのレポートをフィルタリングおよび調整できます。 uptime コマンドと同様に、sar コマンドも CPU 負荷の監視に役立ちます。 sarにより過負荷の発生が把握できる
