📅  最后修改于: 2023-12-03 14:51:40.535000             🧑  作者: Mango
在计算机组成原理中,数据路径的设计可以采用多周期和流水线两种方式。虽然二者都是完成相同的任务,但是它们在实现方式和性能方面存在显著的差异。下面详细介绍多周期数据路径和流水线数据路径之间的差异。
多周期数据路径将指令执行划分为多个时钟周期,每个时钟周期执行不同的功能,如取指、译码、执行、访存和写回等。经典的多周期数据路径通常由以下部分组成:
多周期数据路径的性能相对较低,因为每个指令执行需要多个时钟周期。此外,在多周期数据路径中,不同指令的时钟周期数量可能是不同的,其执行过程受到了指令类型和数据冲突等因素的影响。
流水线数据路径采用流水线的方式将指令执行划分为多个阶段,每个阶段在同一时钟周期内执行不同的指令。经典的流水线数据路径通常由以下级别组成:
与多周期数据路径相比,流水线数据路径的性能更高,因为每个阶段的执行时间比多周期数据路径的时钟周期短。此外,在流水线数据路径中,不同指令的执行时间相同,具有更一致的性能。
虽然多周期数据路径和流水线数据路径实现相同的功能,但它们的设计方式、性能和特点存在明显的差异。多周期数据路径适用于较简单的处理器,其实现简单,容易理解和设计;流水线数据路径用于更复杂的处理器,具有更高的性能和更好的适应性,但其设计和调试都更为困难。
// 多周期数据路径实现
module multi_cycle_data_path
(
input clk,
input reset,
input [31:0] inst,
input [4:0] rs,
input [4:0] rt,
input [4:0] rd,
output reg [31:0] out_data
);
// 时钟周期 1
wire [31:0] pc_next;
wire [31:0] inst_out;
wire [4:0] rs_out;
wire [4:0] rt_out;
assign pc_next = reset ? 32'h00000000 : pc + 4;
instruction_fetcher inst_fetcher(
.clk(clk),
.reset(reset),
.pc(pc),
.inst(inst_out)
);
instruction_decoder inst_decoder(
.rs(rs_out),
.rt(rt_out),
.inst(inst_out)
);
assign inst_out = inst[pc[9:2]];
assign rs_out = inst[25:21];
assign rt_out = inst[20:16];
// 时钟周期 2
wire [31:0] alu_in1;
wire [31:0] alu_in2;
wire [31:0] alu_out;
assign alu_in1 = register_file[rs_out];
assign alu_in2 = register_file[rt_out];
alu alu_unit(
.in1(alu_in1),
.in2(alu_in2),
.op(inst_out[5:2]),
.out(alu_out)
);
// 时钟周期 3
wire [31:0] mem_in;
wire [31:0] mem_out;
assign mem_in = alu_out;
memory_access mem_access(
.clk(clk),
.write(inst_out[0]),
.addr(alu_out),
.in(mem_in),
.out(mem_out)
);
// 时钟周期 4
wire [4:0] wb_reg;
wire [31:0] wb_data;
assign wb_reg = rd;
assign wb_data = mem_out;
write_back wb(
.clk(clk),
.enable(inst_out[1]),
.data(wb_data),
.reg(wb_reg),
.out(out_data)
);
register_file reg(
.read_a(rs_out),
.read_b(rt_out),
.write_data(wb_data)
);
assign register_file[0] = 32'h0;
endmodule
// 流水线数据路径实现
module pipeline_data_path
(
input clk,
input reset,
input [31:0] inst,
input [4:0] rs,
input [4:0] rt,
input [4:0] rd,
output reg [31:0] out_data
);
// 取指阶段
wire [31:0] pc_next;
wire [31:0] inst_out;
assign pc_next = reset ? 32'h00000000 : pc + 4;
instruction_fetcher inst_fetcher(
.clk(clk),
.reset(reset),
.pc(pc),
.inst(inst_out)
);
pipeline_register if_id_reg(
.in(inst_out),
.out(id_inst),
.clk(clk)
);
// 译码阶段
wire [31:0] id_inst;
wire [4:0] rs_out;
wire [4:0] rt_out;
instruction_decoder inst_decoder(
.rs(rs_out),
.rt(rt_out),
.inst(id_inst)
);
register_file reg(
.read_a(rs_out),
.read_b(rt_out),
.write_data(wb_data)
);
pipeline_register id_exe_reg(
.in({rs_out, rt_out, imm_ext}),
.out(exe_info),
.clk(clk)
);
// 执行阶段
wire [31:0] exe_op1;
wire [31:0] exe_op2;
wire [31:0] alu_out;
wire [31:0] imm_ext;
assign exe_op1 = register_file[exe_info[0]];
assign exe_op2 = register_file[exe_info[1]];
assign imm_ext = sign_ext(exe_info[2]);
alu alu_unit(
.in1(exe_op1),
.in2(exe_op2),
.op(id_inst[5:2]),
.out(alu_out)
);
pipeline_register exe_mem_reg(
.in(alu_out),
.out(mem_op),
.clk(clk)
);
// 访存阶段
wire [31:0] mem_op_out;
memory_access mem_access(
.clk(clk),
.write(id_inst[0]),
.addr(alu_out),
.in(mem_op),
.out(mem_op_out)
);
pipeline_register mem_wb_reg(
.in(mem_op_out),
.out(wb_data),
.clk(clk)
);
write_back wb(
.clk(clk),
.enable(id_inst[1]),
.data(wb_data),
.reg(id_inst[4:0])
.out(out_data)
);
endmodule