计算机组成实验-第7章_单时钟数据通路设计

本文详细介绍了基于Verilog HDL的嵌入式CPU设计过程,包括各个模块如存储器、寄存器、运算器及控制器的设计与实现,并探讨了在Xilinx平台上的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结:
1. 定义各个模块:
存储器部分:指令存储器和数据存储器,利用Xilinx生成,均采用板载时钟作为时钟输入。
寄存器:包括PC和寄存器堆,均采用按键时钟作为时钟输入。注意PC寄存器的写入控制(按键按下时写入)以及+4操作。
运算器:ALU模块(需要根据控制信号进行加法输入)和加法器,
控制器:control模块和ALUControl模块(就是一个组合电路)。
选择器:包括各种多路选择器以及对应的控制信号。
显示器:负责显示数字,要点在于将32位二进制转化成8个十六进制并利用分时复用显示出来,分时的信号是将板载时钟频率降低得到。
2. 在top模块中综合(生成各个模块的实例),相当于产生了真正的组件。
3. 利用线性变量(wire类型)作为输入输出,相当于把各个组件用线连接起来。
问题:
1. 时钟信号
clk:对应的是按键。
按键clk:用于控制PC寄存器、寄存器堆、
disp_clk,即板载时钟t9。
用于控制数码管的显示、指令存储器、数据存储器。

2. PC不需要初始化,因为rst(reset)信号。

3.unexpected token
语法问题,括号,全角、半角问题。

4. 单周期中,PC以及地址的运算用的是单独的ALU

5. project clean up:解决找不到数据存储器模块的问题

6. 
http://stackoverflow.com/questions/7589443/xilinx-error-place-1018-message
NET "clk"   CLOCK_DEDICATED_ROUTE = FALSE;
7. 
在xilinx12.4版本中,使用block memory generator代替10.1中的Single Port Block Memory

instr_block_instr_block.coe为什么有十一条指令?
MEMORY_INITIALIZATION_RADIX=2;
MEMORY_INITIALIZATION_VECTOR=
100011 00000 00001 00000 00000 000000,
10001100000000100000000000000100,
10001100000001000000000000000001,
000000 00001 00010 00011 00000 100000,
00000000011000100001000000100000,
00000000011000010001100000100000,
00010000011001000000000000000001,
00001000000000000000000000000100,
10101100000000100000000000000010,
000000 00001 00100 00110 00000 101010,//slt #4 #
000000 00100 00001 00110 00000 101010,//slt


`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:    14:27:50 04/16/2013
// Design Name:
// Module Name:    top
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1 ps / 1 ps
//顶层模块
module top(
 clk, rst,
 disp_sel, disp_clk,
 o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp,
 o_sel,
 o_instr);
 
 input clk, rst, disp_clk;//disp_clk对应板载时钟,用来控制寄存器的写入。
 input [6:0] disp_sel;
 output o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp;
 output [3:0] o_sel;
 output [5:0] o_instr;
 wire clk_clk;//去抖动之后的按键输出
 wire [8:0] pc_out, pc_in, pc_plus_4;
 wire [4:0] reg3_out,
      tmp_sel;
 wire [31:0] wdata_out,
     instr_out,
     reg1_dat, reg2_dat,
     signext_out,
     mux_to_alu,
     alu_out,
     mem_dat_out,
     branch_addr_out,
     branch_mux_out,
     gpr_disp_out;
 wire [1:0] aluop;
 wire [2:0] alu_ctrl;
 wire regwrite, alusrc, memwrite, memtoreg, memread, branch, jump, regdst, alu_zero, and_out;
 reg [15:0] clk_cnt, tmp_cnt;
 reg [1:0] disp_clk_cnt;
 always @ (posedge clk_clk or posedge rst) begin
  if (rst == 1)
   clk_cnt = 16'h0000;
  else begin
   clk_cnt = clk_cnt + 1;
  end
 end
 always @ (posedge disp_clk or posedge rst) begin
  if (rst == 1) begin
   disp_clk_cnt = 2'b00;
   tmp_cnt = 0;
  end
  else begin
   tmp_cnt = tmp_cnt + 1;
   if (tmp_cnt == 16'h0000)
   disp_clk_cnt = disp_clk_cnt + 1;
  end
 end
 assign o_instr = instr_out[31:26];
 assign tmp_sel[4:0] = disp_sel[4:0];
 //防抖动模块
 anti_jitter x_anti_jitter(disp_clk, clk, clk_clk);
 //debug display module
 debug_out x_debug_out(
  disp_clk_cnt,
  clk_cnt,
  gpr_disp_out,
  pc_out,
  disp_sel,o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp, o_sel);
 //PC register
 single_pc x_single_pc(clk_clk, rst, pc_in, pc_out);
 //PC plus 4
 single_pc_plus4 x_single_pc_plus4(pc_out, pc_plus_4);
 //intruction memory, read only. read address from PC's output
 c_instr_mem x_c_instr_mem(pc_out, disp_clk, instr_out);
 //mux5, select from [20:16] or [15:11], to register file's write port
 single_mux5 x_single_mux5(instr_out[20:16],instr_out[15:11],
 regdst, reg3_out);
 //register files, read from 3 ports, write to 1 port
 single_gpr x_single_gpr(
  clk_clk, rst,
  instr_out[25:21], instr_out[20:16],
  tmp_sel,
  reg3_out, wdata_out,
  regwrite,
  reg1_dat, reg2_dat,
  gpr_disp_out);
 //ALU ctrl
 single_alu_ctrl x_single_alu_ctrl(aluop,  instr_out[5:0],alu_ctrl);
 //16 to 32 extension
 single_signext x_single_signext(instr_out[15:0], signext_out);
 //mux32,to ALU B-port input(mux to alu)
 single_mux32 x_single_mux32(reg2_dat, signext_out, alusrc, mux_to_alu);
 //ALU
 single_alu x_single_alu(reg1_dat, mux_to_alu, alu_ctrl, alu_zero, alu_out);
 //data memory, r/w
 c_dat_mem x_c_dat_mem(
  alu_out[8:0],
  disp_clk,
  reg2_dat,
  mem_dat_out,
  memwrite);
 //mux32, select from ALU or Memory 's output, to Register files' write  port
 single_mux32 x_single_mux32_2(alu_out, mem_dat_out, memtoreg, wdata_out);
 //and gate, zero and branch signal for BEQ
 and x_and(and_out, alu_zero, branch);
 //ADD, add PC+4 and immediate number for BEQ's address transition
 single_add  x_single_add(signext_out, {{23'b000_0000_0000_0000_0000_0000},pc_plus_4},branch_addr_out);//why not shifit left 2 bits?
 //mux32,ctrl is the output of and gate, determine whether use the BEQ transition address,(branch mux out)
 single_mux32 x_single_mux_32_3({23'b000_0000_0000_0000_0000_0000,pc_plus_4}, branch_addr_out, and_out, branch_mux_out);
 //mux9, jump selection, to pc_in
 single_mux9 x_single_mux9(branch_mux_out[8:0], instr_out[8:0], jump, pc_in);
 //CPU controllor
 single_ctrl x_single_ctrl(rst, instr_out[31:26], regdst, alusrc,memtoreg, regwrite, memread, memwrite, branch, jump, aluop);
endmodule
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
/////
//按键去抖动模块,和我写的有差别
module anti_jitter(clk, button, button_out);
 input wire clk;
 input wire button;
 output reg button_out;
 reg [31:0] counter;
 always @(posedge clk) begin
 if(counter>0) begin
  if(counter<100000)
   counter<=counter+1;
  else begin
   counter<=32'b0;
   button_out<=button;
  end
 end
 else
 if(button>0)
  counter<=counter+1;
 end
endmodule
//N 路多路复用器模块
module single_mux5(A, B, Ctrl, S);//2to1MUX
 parameter N = 5;//N=5
 input wire [N-1:0] A, B;
 input Ctrl;
 output wire [N-1:0] S;
 assign S = (Ctrl == 1'b0) ? (A) : (B);
endmodule
module single_mux9(A, B, Ctrl, S);//2to1MUX
 parameter N = 9;//N=9
 input wire [N-1:0] A, B;
 input Ctrl;
 output wire [N-1:0] S;
 assign S = (Ctrl == 1'b0) ? (A) : (B);
endmodule
module single_mux32(A, B, Ctrl, S);//2to1MUX
 parameter N = 32;//N=32
 input wire [N-1:0] A, B;
 input Ctrl;
 output wire [N-1:0] S;
 assign S = (Ctrl == 1'b0) ? (A) : (B);
endmodule
//PC+4 模块
module single_pc_plus4(i_pc, o_pc);//PC+4
 parameter N = 9;//N
 input wire [N-1:0] i_pc;
 output wire [N-1:0] o_pc;
 assign o_pc[N-1:0] = i_pc[N-1:0] + 1;
endmodule
//PC 模块
module single_pc(clk, rst, i_pc, o_pc);//PC
 parameter N = 9;//N
 input wire clk, rst;
 input wire [N-1:0] i_pc;
 output wire [N-1:0] o_pc;
 reg [N-1:0] t_pc;
 assign o_pc = rst ? {N{1'b1}} : t_pc;
 always@(posedge clk) begin
  t_pc <= i_pc;
 end
endmodule
//符号扩展模块
module single_signext(i_16, o_32);//sign extent
 input wire [15:0] i_16;
 output reg [31:0] o_32;
 always@(i_16) begin
  o_32 <= {{16{i_16[15]}}, i_16[15:0]};
 end
endmodule
//加法器模块
module single_add(i_op1, i_op2, o_out);//single adder
 parameter N = 32;//N
 input wire [N-1:0] i_op1;
 input wire [N-1:0] i_op2;
 output wire [N-1:0] o_out;
 assign o_out = i_op1 + i_op2;
endmodule
//指令控制模块
module single_ctrl(rst, OP, RegDst, ALUsrc, MemtoReg, RegWrite,MemRead,
 MemWrite, Branch, Jump, ALUop);//single ctrl
 input wire rst;
 input wire [5:0] OP;
 output wire RegDst, RegWrite,  ALUsrc, MemtoReg, MemRead, MemWrite,
 Branch, Jump;
 output wire [1:0] ALUop;
 wire R, LW, SW, BEQ;
 assign R = ~OP[5]&~OP[4]&~OP[3]&~OP[2]&~OP[1]&~OP[0];//000000=0
 assign LW = OP[5]&~OP[4]&~OP[3]&~OP[2]&OP[1]&OP[0];//100011=35
 assign SW = OP[5]&~OP[4]&OP[3]&~OP[2]&OP[1]&OP[0];//101011=43
 assign BEQ = ~OP[5]&~OP[4]&~OP[3]&OP[2]&~OP[1]&~OP[0];//000100=4
 assign RegDst = ~rst & R;
 assign MemtoReg = ~rst & LW;
 assign RegWrite = ~rst & (R | LW);//? not or?
 assign ALUsrc = ~rst & (LW | SW);//? not or?
 assign ALUop = ~rst & {R, BEQ};
 assign MemRead = ~rst & LW;
 assign MemWrite = ~rst & SW;
 assign Branch = ~rst & BEQ;
 assign Jump = (~OP[5]&~OP[4]&~OP[3]&~OP[2]&OP[1]&~OP[0]);//000010=2
endmodule
//ALUop 控制模块
module single_alu_ctrl(aluop, func, alu_ctrl);//single ALU ctrl
 input [1:0] aluop;
 input [5:0] func;
 output reg [2:0] alu_ctrl;
 always @(aluop or func) begin
  case(aluop)
   2'b00: begin
    alu_ctrl = 3'b010;//ADD
   end
   2'b01: begin
    alu_ctrl = 3'b110;//SUB
   end
   2'b10: begin
    case(func)
     6'b100000: alu_ctrl = 3'b010;//ADD
     6'b100010: alu_ctrl = 3'b110;//SUB
     6'b101010: alu_ctrl = 3'b111;//SLT
     6'b100100: alu_ctrl = 3'b000;//AND
     6'b100101: alu_ctrl = 3'b001;//OR
     default: alu_ctrl = 3'b000;//ADD
    endcase
   end
   default: begin
    alu_ctrl = 3'b000;//ADD
   end
  endcase
 end
endmodule
//ALU 计算模块
module single_alu(i_r, i_s, i_aluc, o_zf, o_alu);//single ALU
 input [31:0] i_r;
 input [31:0] i_s;
 input [2:0] i_aluc;
 output reg o_zf;
 output reg [31:0] o_alu;
 always @(i_aluc or i_r or i_s) begin
  case (i_aluc)
   3'b000: begin//AND
    o_zf = 0;
    o_alu = i_r & i_s;
   end
   3'b001: begin//OR
    o_zf = 0;
    o_alu = i_r | i_s;
   end
   3'b010: begin//ADD
    o_zf = 0;
    o_alu = i_r + i_s;
   end
   3'b110: begin//SUB
    o_alu = i_r - i_s;
    o_zf = (o_alu == 0);
   end
   3'b111: begin//SLT
    o_zf = 0;
    if (i_r < i_s)
     o_alu = 1;
    else
     o_alu = 0;
   end
   default: begin//reset
    o_alu = 0;
    o_zf = 0;
   end
  endcase
 end
endmodule
//寄存器读写模块
module single_gpr(//general purpose registers
 clk, rst,//clock and reset
 i_adr1, i_adr2,//read register 1 2
 i_adr3,//read register 3, for test
 i_wreg, i_wdata,//register to be written and the data
 i_wen,//RegWrite Enable
 o_op1,o_op2,//read data output 1 2
 o_op3//read data output 3, for test
 );
 input wire clk, rst, i_wen;
 input wire [4:0] i_adr1, i_adr2, i_adr3, i_wreg;
 input wire [31:0] i_wdata;
 output wire [31:0] o_op1, o_op2, o_op3;
 reg [31:0] mem[31:0];//32 local registers
 assign o_op1 = mem[i_adr1];
 assign o_op2 = mem[i_adr2];
 assign o_op3 = mem[i_adr3];
 always @(posedge clk or posedge rst) begin//both on positive pulse written
  if (rst == 1) begin
   mem[0] <= 32'h0000_0000;
  end
  else if (i_wen) begin
   mem[i_wreg] <= (i_wreg == 5'b00000) ? 32'h0000_0000 :
   i_wdata;//zero can't be written
  end
 end
endmodule
//测试模块
module debug_out(//debug led display
 clk,//decides which digit to display
 i_clk_cnt,//clock number to display
 i_reg_dat,//register to display
 i_pc,//PC to display
 i_disp_sel,//display selection
 o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp,//8 digit display
 o_sel);
 input [1:0] clk;
 input [15:0] i_clk_cnt;
 input [31:0] i_reg_dat;
 input [8:0] i_pc;
 input [6:0] i_disp_sel;
 output o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp;
 output [3:0] o_sel;
 single_leds x_single_leds(clk,
  (i_disp_sel[6:5]==2'b10)?{{5'b00000},i_pc}:
  ((i_disp_sel[6:5]==2'b11)?i_clk_cnt:
  ((i_disp_sel[6:5]==2'b00)?i_reg_dat[15:0]:i_reg_dat[31:16])),
  o_a,o_b,o_c,o_d,o_e,o_f,o_g,o_dp,o_sel);
endmodule
//display 模块
module single_leds(clk_cnt, i_number, o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp, o_sel);
 input [1:0] clk_cnt;
 input [15:0] i_number;
 output o_a, o_b, o_c, o_d, o_e, o_f, o_g, o_dp;
 output [3:0] o_sel;
 reg o_a, o_b, o_c, o_d, o_e, o_f, o_g;
 reg [3:0] o_sel;
 reg [3:0] t_num;
 assign o_dp = 1;
 always @ (clk_cnt or i_number or t_num) begin
  case (clk_cnt)
   2'b00:begin
   o_sel <= 4'b0111;
   t_num <= i_number[15:12];
   end
   2'b01:begin
   o_sel <= 4'b1011;
   t_num <= i_number[11:8];
   end
   2'b10:begin
   o_sel <= 4'b1101;
   t_num <= i_number[7:4];
   end
   2'b11:begin
   o_sel <= 4'b1110;
   t_num <= i_number[3:0];
   end
   default:;
  endcase
  case (t_num)
   4'b0000:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 0;
    o_d <= 0;
    o_e <= 0;
    o_f <= 0;
    o_g <= 1;
   end
   4'b0001:begin
    o_a <= 1;
    o_b <= 0;
    o_c <= 0;
    o_d <= 1;
    o_e <= 1;
    o_f <= 1;
    o_g <= 1;
   end
   4'b0010:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 1;
    o_d <= 0;
    o_e <= 0;
    o_f <= 1;
    o_g <= 0;
   end
   4'b0011:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 0;
    o_d <= 0;
    o_e <= 1;
    o_f <= 1;
    o_g <= 0;
   end
   4'b0100:begin
    o_a <= 1;
    o_b <= 0;
    o_c <= 0;
    o_d <= 1;
    o_e <= 1;
    o_f <= 0;
    o_g <= 0;
   end
   4'b0101:begin
    o_a <= 0;
    o_b <= 1;
    o_c <= 0;
    o_d <= 0;
    o_e <= 1;
    o_f <= 0;
    o_g <= 0;
   end
   4'b0110:begin
    o_a <= 0;
    o_b <= 1;
    o_c <= 0;
    o_d <= 0;
    o_e <= 0;
    o_f <= 0;
    o_g <= 0;
   end
   4'b0111:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 0;
    o_d <= 1;
    o_e <= 1;
    o_f <= 1;
    o_g <= 1;
   end
   4'b1000:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 0;
    o_d <= 0;
    o_e <= 0;
    o_f <= 0;
    o_g <= 0;
   end
   4'b1001:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 0;
    o_d <= 0;
    o_e <= 1;
    o_f <= 0;
    o_g <= 0;
   end
   4'b1010:begin
    o_a <= 0;
    o_b <= 0;
    o_c <= 0;
    o_d <= 1;
    o_e <= 0;
    o_f <= 0;
    o_g <= 0;
   end
   4'b1011:begin
    o_a <= 1;
    o_b <= 1;
    o_c <= 0;
    o_d <= 0;
    o_e <= 0;
    o_f <= 0;
    o_g <= 0;
   end
   4'b1100:begin
    o_a <= 0;
    o_b <= 1;
    o_c <= 1;
    o_d <= 0;
    o_e <= 0;
    o_f <= 0;
    o_g <= 1;
   end
   4'b1101:begin
    o_a <= 1;
    o_b <= 0;
    o_c <= 0;
    o_d <= 0;
    o_e <= 0;
    o_f <= 1;
    o_g <= 0;
   end
   4'b1110:begin
    o_a <= 0;
    o_b <= 1;
    o_c <= 1;
    o_d <= 0;
    o_e <= 0;
    o_f <= 0;
    o_g <= 0;
   end
   4'b1111:begin
    o_a <= 0;
    o_b <= 1;
    o_c <= 1;
    o_d <= 1;
    o_e <= 0;
    o_f <= 0;
    o_g <= 0;
   end
   default:;
  endcase
 end
endmodule





ucf文件
NET"clk"          LOC="L13";
NET"rst"          LOC="L14";
NET"disp_clk"  LOC="T9";
NET"disp_sel[0]" LOC="F12";
NET"disp_sel[1]" LOC="G12";
NET"disp_sel[2]" LOC="H14";
NET"disp_sel[3]" LOC="H13";
NET"disp_sel[4]" LOC="J14";
NET"disp_sel[5]" LOC="J13";
NET"o_a"          LOC="E14";
NET"o_b"          LOC="G13";
NET"o_c"          LOC="N15";
NET"o_d"          LOC="P15";
NET"o_e"          LOC="R16";
NET"o_f"          LOC="F13";
NET"o_g"          LOC="N16";
NET"o_dp"          LOC="P16";
NET"o_instr[0]"  LOC="K12";
NET"o_instr[1]"  LOC="P14";
NET"o_instr[2]"  LOC="L12";
NET"o_instr[3]"  LOC="N14";
NET"o_instr[4]"  LOC="P13";
NET"o_instr[5]"  LOC="N12";
NET"o_sel[0]"  LOC="D14";
NET"o_sel[1]"  LOC="G14";
NET"o_sel[2]"  LOC="F14";
NET"o_sel[3]"  LOC="E13";
NET "clk" CLOCK_DEDICATED_ROUTE = FALSE;#占用了ckl信号




                
<think>我们正在设计一个周期MIPSCPU。根据计算机组成原理,周期CPU是指所有指令都在一个时钟周期内完成。由于不同指令的执行时间不同,因此时钟周期必须满足最慢指令的要求。同时,周期CPU中,数据通路的资源不能在一个周期内被重复使用,因此需要为每个需要多次使用的资源(如加法器)设置多个副本。此外,由于取指令执行指令都需要访问存储器,因此必须采用哈佛结构(即指令存储器数据存储器分离)。设计步骤:1.确定支持的指令集:首先需要确定CPU要支持哪些MIPS指令。常见的指令包括算术运算指令(如add, sub, and, or等)、逻辑运算指令、数据传送指令(如lw, sw)、分支指令(如beq,bne)跳转指令(如j)等。2.设计数据通路数据通路是CPU中执行指令的路径。它包括以下主要部件:-程序计数器(PC):存放当前指令的地址。-指令存储器(IM):存放指令。-寄存器堆(RegisterFile):包含32个32位寄存器。-算术逻辑元(ALU):执行算术逻辑运算。-数据存储器(DM):用于存储数据(读写内存)。-符号扩展元(SignExtend):将16位立即数扩展为32位。-多路选择器(Mux):用于选择不同的数据来源。-控制元(ControlUnit):根据指令生成控制信号。3.设计控制元:控制元根据指令的操作码(opcode)功能码(funct)生成控制信号,以控制数据通路中的多路选择器各功能部件的操作。控制信号包括:- RegDst:选择写入寄存器堆的目标寄存器(rt或rd)。-ALUSrc:选择ALU的第二个操作数(来自寄存器或立即数)。- MemtoReg:选择写入寄存器堆的数据来源(ALU结果或内存读取数据)。- RegWrite:控制是否写入寄存器堆。-MemRead:控制是否读取数据存储器。- MemWrite:控制是否写入数据存储器。-Branch:控制是否进行分支(与零标志一起决定是否跳转)。- ALUOp:指示ALU执行的操作类型(例如加法、减法等),通常需要结合功能码(funct)进一步确定。-Jump:控制是否进行跳转。4.连接数据通路:将上述部件按照指令执行流程连接起来。指令执行流程包括:-取指令(IF):从PC指向的指令存储器地址读取指令。-指令译码(ID):解析指令,读取寄存器堆,同时控制元生成控制信号。-执行(EX):ALU根据控制信号执行运算。-存储器访问(MEM):如果需要访问数据存储器(如lw,sw),则在此阶段进行。-写回(WB):将结果写回寄存器堆(如果需要)。由于是周期设计,所有步骤在一个时钟周期内完成。5.处理时钟周期:时钟周期必须足够长,以完成最慢指令(通常是lw指令)的执行。lw指令需要依次完成:取指令、读寄存器、ALU计算地址、访问数据存储器、写回寄存器。6.设计中的注意事项:-资源冲突:由于周期内不能重复使用同一个功能部件,因此需要为每个需要多次使用的资源设置多个实例。例如,在同一个周期内,PC更新ALU计算都需要加法器,因此需要两个加法器:一个用于PC+4,另一个用于ALU计算。-控制信号:控制元需要根据指令生成正确的控制信号,这些信号将控制多路选择器的选择功能部件的使能。下面是一个简化的周期MIPSCPU数据通路图(文字描述):-PC:当前指令地址-指令存储器:输入来自PC,输出指令(32位)-指令分解:指令[31:26]为opcode,[25:21]为rs,[20:16]为rt,[15:11]为rd,[15:0]为立即数,[25:0]为跳转地址-控制元:输入opcode,输出控制信号-寄存器堆:输入rs,rt,rd(或rt,取决于RegDst),写数据(来自多路选择器,选择ALU结果或内存数据),RegWrite信号控制写使能-符号扩展:将16位立即数扩展为32位-两个多路选择器(Mux):*第一个Mux(在寄存器堆的写寄存器地址前):选择rt或rd(由RegDst控制)*第二个Mux(在ALU的第二个操作数前):选择寄存器rt的数据或立即数(由ALUSrc控制)-ALU:输入两个操作数(第一个来自寄存器rs,第二个来自上述Mux),ALU控制信号(由ALUOpfunct决定),输出运算结果Zero标志-数据存储器:地址来自ALU结果,写数据来自寄存器rt的数据,读数据输出(由MemReadMemWrite控制)-第三个Mux(在写回寄存器堆的数据前):选择ALU结果或数据存储器读出的数据(由MemtoReg控制)-分支处理:Branch信号Zero标志一起决定是否分支。分支地址计算:PC+4 +符号扩展后的立即数左移2位(因为立即数是字偏移,而PC是字节地址,左移2位相当于乘以4)。这里需要另一个加法器。-跳转处理:Jump信号为1时,跳转地址由指令中的26位地址左移2位(形成28位)与PC+4的高4位拼接而成。-PC更新:下一个PC可能是PC+4、分支目标地址或跳转目标地址,因此需要一个多路选择器(通常先由BranchZero决定是否选择分支地址,然后再由Jump决定是否选择跳转地址)。7.控制设计:根据指令的操作码(opcode)生成控制信号。例如:- R型指令:opcode=000000,控制信号:RegDst=1, ALUSrc=0, MemtoReg=0, RegWrite=1,MemRead=0, MemWrite=0,Branch=0,ALUOp=10(表示需要根据funct确定操作),Jump=0- lw指令:opcode=100011,控制信号:RegDst=0,ALUSrc=1,MemtoReg=1,RegWrite=1, MemRead=1,MemWrite=0, Branch=0, ALUOp=00(加法),Jump=0- sw指令:opcode=101011,控制信号:RegDst=X(无关),ALUSrc=1, MemtoReg=X,RegWrite=0, MemRead=0,MemWrite=1, Branch=0, ALUOp=00(加法),Jump=0-beq指令:opcode=000100,控制信号:RegDst=X,ALUSrc=0,MemtoReg=X, RegWrite=0,MemRead=0, MemWrite=0,Branch=1,ALUOp=01(减法),Jump=0-j指令:opcode=000010,控制信号:RegDst=X,ALUSrc=X, MemtoReg=X,RegWrite=0, MemRead=0,MemWrite=0, Branch=0, Jump=18.ALU控制:控制元输出的ALUOp是2位的信号,用于指示ALU的操作类型。但ALU需要4位的控制信号(如加、减、与、或等)。因此,需要一个小型译码器,根据ALUOpfunct(对于R型指令)生成ALU的控制信号。例如:-ALUOp=00:ALU执行加法(用于lw, sw)- ALUOp=01:ALU执行减法(用于beq)- ALUOp=10:根据funct确定操作(R型指令):*funct=100000(add):加法* funct=100010(sub):减法*funct=100100(and):与* funct=100101(or):或*...等等9.测试:设计完成后,需要编写测试程序(汇编指令),通过模拟器(如Logisim或Educoder)进行测试,确保每条指令都能正确执行。以上是周期MIPSCPU设计的基本步骤原理。具体实现时,可以使用硬件描述语言(如Verilog)或数字电路仿真工具(如Logisim)来搭建电路。参考文献: [^1]:计算机组成原理周期MIPSCPU设计实验[^2]:华科计算机组成原理周期 MIPS CPU设计24条指令(Logisim&Educoder) [^3]: 【计算机组成原理】周期MIPSCPU的设计[^4]:计算机组成原理周期mips,计算机组成原理CPU周期数据通路(MIPS)相关问题:1.周期MIPS CPU中为什么需要两个加法器?2.在周期MIPS CPU中,控制元如何根据指令生成控制信号?3.周期MIPS CPU的缺点是什么?如何改进?4.如何设计支持更多指令(如24条)的周期MIPSCPU?5.周期MIPSCPU的数据通路中,多路选择器的作用是什么?</think>### 周期MIPS CPU设计指南 #### 一、核心设计原理 周期MIPS CPU的所有指令在一个时钟周期内完成,时钟周期长度由执行时间最长的指令(通常是`lw`)决定。设计需满足: 1. **哈佛架构**:指令存储器数据存储器分离(避免访问冲突)[^3] 2. **资源独占**:功能部件不能复用(如需要多个加法器) 3. **控制信号集中生成**:由指令操作码统一产生控制信号 #### 二、数据通路设计(关键部件) ```mermaid graph LR PC[程序计数器] --> IM[指令存储器] IM --> CU[控制元] IM --> RF[寄存器堆] RF --> ALU[算术逻辑元] SignExt[符号扩展] --> ALU ALU --> DM[数据存储器] DM --> RF CU -.控制信号.-> 所有部件 ``` 1. **程序计数器(PC)** - 存储当前指令地址 - 更新方式: $$ PC_{next} = \begin{cases} PC+4 & \text{默认} \\ PC+4 + \text{SignExt}(imm16)\times4 & \text{分支} \\ \text{Jump目标} & \text{跳转} \end{cases} $$ [^4] 2. **寄存器堆** - 32个32位寄存器 - 读写控制: `RegWrite=1`时,在时钟上升沿写入目标寄存器 3. **ALU核心功能** | 操作 | 控制信号 | 用途示例 | |------------|----------|----------------| | 加法 | 0010 | `add`, `lw` | | 减法 | 0110 | `sub`, `beq` | | 按位与 | 0000 | `and` | | 按位或 | 0001 | `or` | - 零标志位:`beq`指令判断依据[^4] 4. **存储器设计** - 指令存储器(ROM):只读,地址由PC提供 - 数据存储器(RAM):`MemWrite``MemRead`控制访问 #### 三、控制设计 控制信号生成逻辑: ```mermaid flowchart LR opcode[指令31-26位] --> CU CU --> RegDst[目标寄存器选择] CU --> ALUSrc[ALU操作数选择] CU --> MemtoReg[写回数据选择] CU --> RegWrite[寄存器写使能] CU --> MemRead[存储器读] CU --> MemWrite[存储器写] CU --> Branch[分支使能] CU --> ALUOp[ALU操作类型] CU --> Jump[跳转使能] ``` 典型指令控制信号示例: | 指令 | RegDst | ALUSrc | MemtoReg | RegWrite | MemRead | MemWrite | Branch | ALUOp | Jump | |------|--------|--------|----------|----------|---------|----------|--------|-------|------| | R型 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 10 | 0 | | lw | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 00 | 0 | | sw | X | 1 | X | 0 | 0 | 1 | 0 | 00 | 0 | | beq | X | 0 | X | 0 | 0 | 0 | 1 | 01 | 0 | | j | X | X | X | 0 | 0 | 0 | 0 | XX | 1 | > 注:X表示无关项,1/0为有效信号[^2][^4] #### 四、关键问题解决方案 1. **资源冲突** - PC更新ALU计算需独立加法器 - 例:PC+4专用加法器 vs ALU计算地址用加法器 2. **立即数处理** - 符号扩展元:16位→32位(`lw/sw/beq`) - 零扩展:逻辑指令(如`ori`) 3. **分支逻辑** ```verilog assign PCSrc = Branch & Zero; // 分支条件满足 assign BranchTarget = (SignExt(imm16) << 2) + PC + 4; ``` 4. **跳转实现** $$ JumpAddr = \{ PC[31:28], instr[25:0] << 2 \} $$ #### 五、设计验证步骤 1. 搭建基础数据通路(Logisim/Verilog) 2. 实现控制信号生成逻辑 3. 逐指令测试: - R型指令(`add`, `sub`) - 访存指令(`lw`, `sw`) - 控制指令(`beq`, `j`) 4. 关键测试点: - 数据冲突检测 - 存储器访问时序 - 边界条件(如零寄存器写入) > 参考实现:华科24条指令周期CPU[^2]支持指令包括`add`, `sub`, `lw`, `sw`, `beq`, `j`, `andi`, `ori`等,采用硬布线控制器设计。 #### 六、优化方向 1. **关键路径优化**:减少最长路径门级延迟 2. **资源复用**:在面积允许时复用加法器 3. **控制信号简化**:合并相似指令控制逻辑 --- ### 相关问题 1. 周期CPU为什么必须采用哈佛架构?冯·诺依曼架构会导致什么问题? 2. 在MIPS周期设计中,如何处理`beq`指令的立即数偏移量计算? 3. 控制元中的`ALUOp`信号为什么要设计为2位?其如何与ALU控制信号配合? 4. 若需新增`addi`指令,数据通路控制元需要哪些修改? 5. 周期CPU的主要性能瓶颈是什么?如何定量分析最长路径延迟? [^1]: 计算机组成原理 周期MIPS CPU设计实验 [^2]: 华科计算机组成原理 周期 MIPS CPU设计 24条指令 [^3]: 【计算机组成原理】周期MIPS CPU的设计 [^4]: 计算机组成原理CPU周期数据通路(MIPS)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值