【计算机系统设计】实践笔记(4)改进数据通路:第一类I型指令分析与实现
0 回顧
之前,我們完成了17條R型指令的設(shè)計(jì),接下來(lái),我們逐步完成I型指令的設(shè)計(jì)。
1 核心思想:增量思維 & 復(fù)用思維 & 學(xué)會(huì)選擇 & 分治思想
增量思維
我們從無(wú)到有,構(gòu)建了支持R型指令的CPU,接下來(lái)還會(huì)完成I型指令,J型指令,這樣,單周期CPU就完成了,之后,我們會(huì)將其改進(jìn)為多周期CPU,也會(huì)改進(jìn)為五級(jí)流水線CPU,之后可能需要提升性能,增加串口;將內(nèi)存移出去,增加內(nèi)存控制器;增加指令Cache和數(shù)據(jù)Cache……讓我們慢慢啟程吧!
復(fù)用思維 & 學(xué)會(huì)選擇
人生皆選擇,CPU也一樣,同樣的一個(gè)功能,復(fù)用同一個(gè)器件,輸入?yún)s可能不同,而控制器就幫其做出選擇,配合多路選擇器完成這個(gè)選擇!
分治思想
我們每一次,都是完成一類指令,我們將一類具備共同特征的指令抽出來(lái),一起來(lái)完成它,提高效率!
2 第一類I型指令
這些指令,是R型指令的立即數(shù)操作。
| addi | 001000 | rs | rt | immediate |
| addiu | 001001 | rs | rt | immediate |
| andi | 001100 | rs | rt | immediate |
| ori | 001101 | rs | rt | immediate |
| xori | 001110 | rs | rt | immediate |
| lui | 001111 | 00000 | rt | immediate |
| slti | 001010 | rs | rt | immediate |
| sltiu | 001011 | rs | rt | immediate |
它們共同的操作都是 rt <- rs op imm
特別的,lui比較特殊,直接將imm移動(dòng)到32位高16位,低16位補(bǔ)0.
另外,16位的imm需要擴(kuò)展,可能是0擴(kuò)展也可能是符號(hào)擴(kuò)展,根據(jù)不同的指令進(jìn)行不同判斷即可。
然后,我們看看這些操作需要增加的器件和控制信號(hào),再進(jìn)行設(shè)計(jì)即可,這個(gè)過(guò)程已經(jīng)做了好多遍了,這里可以直接加速完成,不再細(xì)說(shuō)了。
這里,還需要一個(gè)額外的控制信號(hào),表明是0擴(kuò)展還是符號(hào)擴(kuò)展,我們使用Zero_sign_ex
- 0:0擴(kuò)展
- 1:符號(hào)擴(kuò)展
還有Lui信號(hào),表明是lui指令,輸入到ALU。
這是新的數(shù)據(jù)通路,我們?cè)谠O(shè)計(jì)的時(shí)候
3 設(shè)計(jì)
3.1 控制器
特別注意RegDst 信號(hào)
- 0:rt I類指令
- 1:rd R類指令
| addi | 001000 | 0000 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
| addiu | 001001 | 0001 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
| andi | 001100 | 0100 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
| ori | 001101 | 0101 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
| xori | 001110 | 0110 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
| lui | 001111 | 1101 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
| slti | 001010 | 1000 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
| sltiu | 001011 | 1001 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
3.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 control/*** I-type ***/input [15:0] imm, // data// controlinput Lui, // 1:lui instructioninput ALUSrc, // 1:imm calculateinput Zero_sign_ex, // 0:zero extension; 1:sign extensionoutput reg [31:0] ALUresult);// convert A and B to signed numbers wire signed [31:0] A_signed = A; wire signed [31:0] B_signed; wire signed [31:0] B_signed_origin = B; // for sra instruction// 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};/*** I-type: data select ***/// immediate data extension and select wire [31:0] zero_imm_ex = {16'b0,imm}; wire [31:0] sign_imm_ex = (imm[15] == 1)? {16'hffff,imm}: {16'b0,imm}; // NOTE: 16'b1 is incorrect wire [31:0] imm_input = (Zero_sign_ex == 0)? zero_imm_ex: sign_imm_ex;// R[rt] or imm extension wire [31:0] B_select = (ALUSrc == 0)? B: imm_input; assign B_signed = B_select;/* calculate */ always @(*) begincase (ALUop)4'b0000: // add addibeginALUresult <= A + B_select;end4'b0001: // addu addiubeginALUresult <= A + B_select;end4'b0010: // subbeginALUresult <= A - B;end4'b0011: // sububeginALUresult <= A - B;end4'b0100: // and andibeginALUresult <= A & B_select;end4'b0101: // or oribeginALUresult <= A | B_select;end4'b0110: // xor xoribeginALUresult <= A ^ B_select;end4'b0111: // nor noribeginALUresult <= ~(A | B_select);end4'b1000: // slt slti // note:********signed********//beginif(A_signed < B_signed)ALUresult <= 1;elseALUresult <= 0;end4'b1001: // sltu sltiubeginif(A < B_select)ALUresult <= 1;elseALUresult <= 0;end4'b1010: // sllv 10 /*** note: not B_select ***/beginALUresult <= 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_origin >>> A_or_Shift; // NOTE: not A_signed >> B!end4'b1101: // luibeginALUresult <= (Lui == 1)? {imm,16'b0}: 0;enddefault:beginALUresult <= 0;endendcase endendmodule3.3 Reg Files
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2020/11/14 22:31:09 // Design Name: // Module Name: reg_files_1 // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // //module reg_files_1(input clk,input rst_n,/*** read port 1 ***/input [4:0] rA, // rs fieldoutput reg [31:0] A,/*** read port 2 ***/input [4:0] rB, // rtoutput reg [31:0] B,/*** write port ***/input [4:0] rW, // rdinput [31:0] writeData, // datainput RegWrite, // if RegWrite == 1,you can write data to reg files/*** I-type input control ***/input RegDst // 1: R-type destination is rd; 0: I-type dst is rt);// reg files reg [31:0] register [0:31]; integer i; initial beginfor (i = 0;i < 32;i = i + 1)begin// 為了方便初步測(cè)試 ///register[i] <= i;// register[i] <= 0;end end/******* write operation *******/ wire [4:0] rW_select; assign rW_select = (RegDst == 1)? rW: rB;always @(posedge clk) // sequential logic beginif(rst_n == 0) // reset is invalidbeginif((RegWrite == 1'b1) && (rW_select != 5'b0)) // write is valid and address is not equal zerobeginregister[rW_select] <= writeData;endelse;endelse; end/******* rA read operation *******/ always @(*) // combinational logic beginif(rst_n == 1)beginA <= 32'b0;endelse if(rA == 5'b0)beginA <= 32'b0;endelsebeginA <= register[rA];end end/******* rB read operation *******/ always @(*) // combinational logic beginif(rst_n == 1)beginB <= 32'b0;endelse if(rB == 5'b0) // $zerobeginB <= 32'b0;endelsebeginB <= register[rB];end endendmodule注意事項(xiàng):需要16位1的寫法是16'h_FFFF,不是16'b1,缺少的項(xiàng)會(huì)被自動(dòng)補(bǔ)0!如果需要16位0,只需要16'b0即可。
3.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: 僅僅實(shí)現(xiàn)了幾個(gè)簡(jiǎn)單的R類指令的最簡(jiǎn)單的數(shù)據(jù)通路,不與外界交互 // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // //module datapath_1(input clk,input rst_n,output [31:0] result // 測(cè)試syntheses,沒(méi)有輸出的模塊是恐怖的);/******** PC ********/// pc_1 Inputs wire Jrn; wire [31:0] JrPC;// pc_1 Outputs wire [31:0] pcOld;pc_1 u_pc_1 (.clk ( clk ),.rst_n ( rst_n ),.pcOrigin ( pcOld ),.JrPC ( JrPC ),.Jrn ( Jrn ),.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; wire RegDst_in;// reg_files_1 Outputs wire [31:0] A; // rs wire [31:0] B; // rt assign JrPC = A;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 ),.RegDst ( RegDst_in ),.A ( A ),.B ( B ));/// /******** ALU ********/ ///// ALU_1 Inputs // wire [31:0] A; // wire [31:0] B; wire [3:0] ALUop; wire Sftmd;wire [15:0] imm = instruction[15:0]; wire Lui_in; wire ALUSrc_in; wire Zero_sign_ex_in;// ALU_1 Outputs // wire [31:0] ALUresult = writeData; // Note:Error!ALU_1 u_ALU_1 (.A ( A ),.B ( B ),.shamt ( instruction[10:6]),.ALUop ( ALUop ),.Sftmd ( Sftmd ),/** I-type **/.imm ( imm ),.Lui ( Lui_in ),.ALUSrc ( ALUSrc_in ),.Zero_sign_ex ( Zero_sign_ex_in ),.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; wire Lui; wire RegDst; wire ALUSrc; wire Zero_sign_ex;assign RegDst_in = RegDst; // Send to Reg Files // send to ALU assign Lui_in = Lui; assign ALUSrc_in = ALUSrc; assign Zero_sign_ex_in = Zero_sign_ex;control_1 u_control_1 (.op ( instruction[31:26] ),.func ( instruction[5:0] ),.RegWrite ( RegWrite ),.Sftmd ( Sftmd ),.ALUop ( ALUop ),.Jrn ( Jrn ),// I type.Lui ( Lui ),.RegDst ( RegDst ),.ALUSrc ( ALUSrc ),.Zero_sign_ex ( Zero_sign_ex ));assign result = ALUresult;endmodule4 測(cè)試
注意,以前完成的指令依然要測(cè)試,因?yàn)槟悴恢滥愀耐曛?#xff0c;是不是把以前對(duì)的改錯(cuò)了。
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 # 應(yīng)該用負(fù)數(shù)驗(yàn)證,以后再說(shuō) sltu $10,$12,$11 # $10 = 12 > 11 = 0# sllv $12,$5,$13 # $12 = 1101 << 1 = 1101_0 = 1A 【注意此處的倒置問(wèn)題! sllv rd,rt,rs】 # srlv $12,$5,$13 # $12 = 1101 >> 1 = 110 = 6 # srav $14,$5,$15 # $14 = 1111 >>> 1 = 111 = 7 應(yīng)該用負(fù)數(shù)驗(yàn)證,以后再說(shuō)# 上面3條是錯(cuò)誤的!我們應(yīng)該改的不是使用,而是內(nèi)部運(yùn)算邏輯 # 對(duì)于使用者來(lái)說(shuō),邏輯就是 $13 << $5 # 而實(shí)際的編碼是 rt = $13,rs = $5,這與一般的指令不一樣 # 因此,我們?cè)贏LU運(yùn)算中 rt--B,rs--A,應(yīng)該是 【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 應(yīng)該用負(fù)數(shù)驗(yàn)證,以后再說(shuō)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 # 應(yīng)該用負(fù)數(shù)驗(yàn)證,以后再說(shuō) $16 = 4################ I type test ################# addi $17,$7,-1 # $17 = 8 - 1 = 7 測(cè)試符號(hào)擴(kuò)展 addiu $17,$7,-2 # $17 = 8 - 2 = 6 andi $17,$8,1 # $17 = 1 測(cè)試zero extension ori $17,$8,0 # $17 = ffff_fff7 = ffff_fff7 xori $17,$8,15 # $17 = ffff_fff7 xor 0000_000f = ffff_fff8 lui $17,100 # $17 = 前16位是64_后16位是0jr $16 # PC = 4編碼
memory_initialization_radix = 16; memory_initialization_vector = 00000000, 00430820, 00811021, 00412022, 00832823, 00e83024, 00c83825, 00c83826, 00e64027, 016c502a, 018b502b, 00ad6004, 00ad6006, 00af7007, 00118080, 00128082, 00138083, 20f1ffff, 24f1fffe, 31110001, 35110000, 3911000f, 3c110064, 02000008;行為仿真測(cè)試成功。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的【计算机系统设计】实践笔记(4)改进数据通路:第一类I型指令分析与实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【计算机系统设计】实践笔记(3)改进数据
- 下一篇: 成都欢乐谷夜场和白天有什么区别