【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析
0 回顧
前面的內容中,第一類R型指令分析,我們完成了一類R型指令的設計,完成了其數(shù)據(jù)通路,構建了相應的部件,并且完成了從ROM中取指,成功進行了基本的功能仿真,進行了綜合和實現(xiàn),但是沒有完成綜合和實現(xiàn)的時序仿真。
下面,我們要繼續(xù)進行其他R型指令的分析,這次我們只分析三個移位指令,也就是sll srl sra,然后改進我們已有的數(shù)據(jù)通路,完成對應的設計。
1 移位指令分析
我們先看看指令編碼
| sll | 000000 | 00000 | rt | rd | shamt | 000000 |
| srl | 000000 | 00000 | rt | rd | shamt | 000010 |
| sra | 000000 | 00000 | rt | rd | shamt | 000011 |
再看看其功能邏輯
三個指令的邏輯都是一樣的
- rd <- (rt op shamt)
- op:
- srl: >>
- sll: <<
- sra: >>>
指令的使用:instruction rd,rs,shamt
值得注意的是,shamt是5位,范圍是0~31.
需要的器件和信號
我們依次分析一下,完成操作,需要改進哪些部件和信號。
很容易知道,我們只需要改進一下ALU的輸入數(shù)據(jù)和控制即可,同時控制器要識別出這三個指令,增加一些相關信號。
我們原來的數(shù)據(jù)通路就變成了
3 ALU和控制器設計改進
3.1 控制器設計
我們把之前的也拿出來,同時標出新增內容。
- 輸入信號:op func
- 輸出信號:RegWrite ALUop,新增Sftmd
| add | 000000 | 100000 | 0000 | 1 | 0 |
| addu | 000000 | 100001 | 0001 | 1 | 0 |
| sub | 000000 | 100010 | 0010 | 1 | 0 |
| subu | 000000 | 100011 | 0011 | 1 | 0 |
| and | 000000 | 100100 | 0100 | 1 | 0 |
| or | 000000 | 100101 | 0101 | 1 | 0 |
| xor | 000000 | 100110 | 0110 | 1 | 0 |
| nor | 000000 | 100111 | 0111 | 1 | 0 |
| slt | 000000 | 101010 | 1000 | 1 | 0 |
| sltu | 000000 | 101011 | 1001 | 1 | 0 |
| sllv | 000000 | 101010 | 1010 | 1 | 0 |
| srlv | 000000 | 000110 | 1011 | 1 | 0 |
| srav | 000000 | 000111 | 1100 | 1 | 0 |
| 新增 | |||||
| sll | 000000 | 000000 | 1010 | 1 | 1 |
| srl | 000000 | 000010 | 1011 | 1 | 1 |
| sra | 000000 | 000011 | 1100 | 1 | 1 |
3.2 ALU設計
- 數(shù)據(jù)輸入:R[rs] R[rd],新增shamt
- 控制輸入:ALUop,新增Sftmd
- 數(shù)據(jù)輸出:R[rd]
特別的,當Sftmd == 1(表明是移位指令)的時候,ALU增加了多路選擇器,將sllv等指令的輸入由rt和rs變成了rt和shamt。
也就是在rs和shamt之間增加了選擇器,當Shtmd == 1使用shamt作為輸入,注意需要0擴展為32位進行運算。
注意:改了輸入輸出端口,相應的實例也要改。
4 Verilog實現(xiàn)
我們下面改進代碼!
4.1 Bug修復:sllv等指令的ALU錯誤
設計中發(fā)現(xiàn),之前的設計有錯誤!是在移位指令的時候!我們先來改正它,并且改進我們的測試實例。
以sllv舉例,它是使用方法是sllv rd,rt,rs,邏輯是rd <- rt << rs。
匯編程序員視角
是正常指令的使用,邏輯也是正常的,但是,內部邏輯卻不一樣了。
內部邏輯
例如sllv $5,$10,$9,功能操作是$5 = $10 << $9,而內部是
- rt = $10 對應ALU的B
- rs = $9 對應ALU的A
- ALU操作是B << A,而不是A << B
這里之前犯的錯誤是,改變了程序員視角的指令……,將上層和底層搞混了……
4.2 新的ALU
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2020/11/14 22:30:23 // Design Name: // Module Name: ALU_1 // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // //module ALU_1(// datainput [31:0] A,input [31:0] B,input [4:0] shamt,// controlinput [3:0] ALUop,input Sftmd, // shift instruction controloutput reg [31:0] ALUresult);// convert A and B to signed numbers wire signed [31:0] A_signed = A; wire signed [31:0] B_signed = B;// for shift instructions // select data: if (Sftmd == 1) input shamt else input rs wire [31:0] A_or_Shift = (Sftmd == 0) ? A : {27'b0,shamt};/* calculate */ always @(*) begincase (ALUop)4'b0000: // addbeginALUresult <= A + B;end4'b0001: // addubeginALUresult <= A + B;end4'b0010: // subbeginALUresult <= A - B;end4'b0011: // sububeginALUresult <= A - B;end4'b0100: // andbeginALUresult <= A & B;end4'b0101: // orbeginALUresult <= A | B;end4'b0110: // xorbeginALUresult <= A ^ B;end4'b0111: // norbeginALUresult <= ~(A | B);end4'b1000: // slt // note:********signed********//beginif(A_signed < B_signed)ALUresult <= 1;elseALUresult <= 0;end4'b1001: // sltubeginif(A < B)ALUresult <= 1;elseALUresult <= 0;end4'b1010: // sllv 10beginALUresult <= B << A_or_Shift; // NOTE: not A << B!end4'b1011: // srlvbeginALUresult <= B >> A_or_Shift; // NOTE: not A >> B!end4'b1100: // srav // note: ******signed*******//beginALUresult <= B_signed >>> A_or_Shift; // NOTE: not A_signed >> B!enddefault:beginALUresult <= 0;endendcase endendmodule關注移位指令的部分即可,同時注意最開始的多路選擇器。
4.3 新的control
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2020/11/14 22:30:48 // Design Name: // Module Name: control_1 // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // //module control_1(input [5:0] op,input [5:0] func,output reg RegWrite,output reg Sftmd, // indicate the instruction is sll/srl/sraoutput reg [3:0] ALUop);always @(*) beginif(op == 6'b0)begincase (func)6'b100000: // addbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0000;end6'b100001: // addubeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0001;end6'b100010: // subbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0010;end6'b100011: // sububeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0011;end6'b100100: // andbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0100;end6'b100101: // orbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0101;end6'b100110: // xorbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0110;end6'b100111: // norbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b0111;end6'b101010: // sltbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b1000;end6'b101011: // sltubeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b1001;end6'b000100: // sllvbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b1010;end6'b000110: // srlvbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b1011;end6'b000111: // sravbeginRegWrite <= 1;Sftmd <= 0;ALUop <= 4'b1100;end6'b000000: // sllbeginRegWrite <= 1;Sftmd <= 1;ALUop <= 4'b1010;end6'b000010: // srlbeginRegWrite <= 1;Sftmd <= 1;ALUop <= 4'b1011;end6'b000011: // srabeginRegWrite <= 1;Sftmd <= 1;ALUop <= 4'b1100;enddefault:beginRegWrite <= 0;Sftmd <= 0;ALUop <= 4'b1111;endendcaseendelsebeginRegWrite <= 0;Sftmd <= 0;ALUop <= 4'b1111;end endendmodule注意新增的信號。
4.4 新的datapath
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2020/11/27 11:41:34 // Design Name: // Module Name: datapath_1 // Project Name: // Target Devices: // Tool Versions: // Description: 僅僅實現(xiàn)了幾個簡單的R類指令的最簡單的數(shù)據(jù)通路,不與外界交互 // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // //module datapath_1(input clk,input rst_n,output [31:0] result // 測試syntheses,沒有輸出的模塊是恐怖的);/******** PC ********/// pc_1 Outputs wire [31:0] pcOld;pc_1 u_pc_1 (.clk ( clk ),.rst_n ( rst_n ),.pcNew ( pcOld ), // pcNew = pcOld + 4; no selection.pcOld ( pcOld ));/******** Instruction ROM ********/// blk_mem_gen_0 Inputs // wire [13:0] addra = pcOld[15:2];// blk_mem_gen_0 Outputs // instructions wire [31:0] instruction;blk_mem_gen_0 u_blk_mem_gen_0 (.clka ( clk ),.addra ( pcOld[15:2] ),.douta ( instruction ));/******** Reg Files ********/// reg_files_1 Inputs wire [31:0] ALUresult;/// wire [4:0] rA = instruction[25:21]; /// wire [4:0] rB = instruction[20:16]; /// wire [4:0] rW = instruction[15:11]; /// wire [31:0] writeData = ALUresult; wire RegWrite;// reg_files_1 Outputs wire [31:0] A; wire [31:0] B;reg_files_1 u_reg_files_1 (.clk ( clk ),.rst_n ( rst_n ),.rA ( instruction[25:21] ),.rB ( instruction[20:16] ),.rW ( instruction[15:11] ),.writeData ( ALUresult ),.RegWrite ( RegWrite ),.A ( A ),.B ( B ));/******** ALU ********/// ALU_1 Inputs // wire [31:0] A; // wire [31:0] B; wire [3:0] ALUop; wire Sftmd;// ALU_1 OutputsALU_1 u_ALU_1 (.A ( A ),.B ( B ),.shamt ( instruction[10:6]),.ALUop ( ALUop ),.Sftmd ( Sftmd ),.ALUresult ( ALUresult ));/******** controler ********/// control_1 Inputs // wire [5:0] op = instruction[31:26]; // wire [5:0] func = instruction[5:0];// control_1 Outputs // wire RegWrite // wire [3:0] ALUop;control_1 u_control_1 (.op ( instruction[31:26] ),.func ( instruction[5:0] ),.RegWrite ( RegWrite ),.Sftmd ( Sftmd ),.ALUop ( ALUop ));assign result = ALUresult;endmodule注意實例化的時候,信號不要弄錯。
4.5 舊的測試:tb_datapath
激勵塊內容不變。
4.6 新的測試用例
nop add $1,$2,$3 # $1 = 2 + 3 = 5 addu $2,$4,$1 # $2 = 4 + 5 = 9 sub $4,$2,$1 # $4 = 9 - 5 = 4 subu $5,$4,$3 # $5 = 4 - 3 = 1and $6,$7,$8 # $6 = 0111 and 1000 = 0 or $7,$6,$8 # $7 = 0 or 1000 = 8 xor $7,$6,$8 # $7 = 0000 xor 1000 = 1000 = 8 nor $8,$7,$6 # $8 = not (1000 or 0) = 11111111111110111slt $10,$11,$12 # $10 = 11 < 12 = 1 # 應該用負數(shù)驗證,以后再說 sltu $10,$12,$11 # $10 = 12 > 11 = 0# sllv $12,$5,$13 # $12 = 1101 << 1 = 1101_0 = 1A 【注意此處的倒置問題! sllv rd,rt,rs】 # srlv $12,$5,$13 # $12 = 1101 >> 1 = 110 = 6 # srav $14,$5,$15 # $14 = 1111 >>> 1 = 111 = 7 應該用負數(shù)驗證,以后再說# 上面3條是錯誤的!我們應該改的不是使用,而是內部運算邏輯 # 對于使用者來說,邏輯就是 $13 << $5 # 而實際的編碼是 rt = $13,rs = $5,這與一般的指令不一樣 # 因此,我們在ALU運算中 rt--B,rs--A,應該是 【B << A】,而不是 A >> B。 sllv $12,$13,$5 # $12 = 1101 << 1 = 1101_0 = 1A srlv $12,$13,$5 # $12 = 1101 >> 1 = 110 = 6 srav $14,$15,$5 # $14 = 1111 >>> 1 = 111 = 7 應該用負數(shù)驗證,以后再說sll $16,$17,2 # $16 = 1_0001 << 2 = 100_0100 = 44 srl $16,$18,2 # $16 = 1_0010 >> 2 = 0100 = 4 sra $16,$19,2 # 應該用負數(shù)驗證,以后再說 $16 = 4特別注意最后移位指令,注意注釋內容。
指令編碼的coe文件:
memory_initialization_radix = 16; memory_initialization_vector = 00000000, 00430820, 00811021, 00412022, 00832823, 00e83024, 00c83825, 00c83826, 00e64027, 016c502a, 018b502b, 00ad6004, 00ad6006, 00af7007, 00118080, 00128082, 00138083;最終測試
經過了每個模塊的RTL優(yōu)化和最終的仿真測試,結果沒有問題!我們又為之前的數(shù)據(jù)通路增加了新的3個指令!Fighting!
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 神角技巧手游滑翔伞怎么飞,神角技巧手游滑
- 下一篇: 神角技巧手游光头强坐骑怎么获得