aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Bikovsky <bsv.serg@gmail.com>2015-09-17 02:13:38 +0300
committerSergey Bikovsky <bsv.serg@gmail.com>2015-09-17 02:13:38 +0300
commitb3d9beada656bce070e8aeb2d74a859a29a54b56 (patch)
treea08f6563de32c4751461549d34e80a0f764b8f67
downloadMIPSLabs-b3d9beada656bce070e8aeb2d74a859a29a54b56.zip
MIPSLabs-b3d9beada656bce070e8aeb2d74a859a29a54b56.tar.gz
MIPSLabs-b3d9beada656bce070e8aeb2d74a859a29a54b56.tar.bz2
init repo
-rw-r--r--README.md0
-rw-r--r--hdl/alu.v29
-rw-r--r--hdl/alu_ctrl.v31
-rw-r--r--hdl/control.v114
-rw-r--r--hdl/dp_memory.v37
-rw-r--r--hdl/ex_stage.v120
-rw-r--r--hdl/forwarding_unit.v138
-rw-r--r--hdl/hazard_unit.v66
-rw-r--r--hdl/id_stage.v188
-rw-r--r--hdl/if_stage.v77
-rw-r--r--hdl/mem_stage.v59
-rw-r--r--hdl/mips_system.v55
-rw-r--r--hdl/pipeline.v250
-rw-r--r--hdl/regfile.v40
-rw-r--r--hdl/testbench.v73
-rw-r--r--hdl/wb_stage.v11
-rw-r--r--sw/Makefile22
-rw-r--r--sw/test.asm19
18 files changed, 1329 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README.md
diff --git a/hdl/alu.v b/hdl/alu.v
new file mode 100644
index 0000000..17008a9
--- /dev/null
+++ b/hdl/alu.v
@@ -0,0 +1,29 @@
+`timescale 1ns / 1ps
+
+/**
+ ALU Unit
+ */
+module alu (
+ input wire [4:0] alu_ctl,
+ input wire [31:0] a_in, b_in,
+ output reg [31:0] result,
+ output wire zero_flag
+ );
+
+ assign zero_flag = (result == 0);
+
+ always @(alu_ctl, a_in, b_in) begin // reevaluate if these change
+ case (alu_ctl)
+ 0: result = a_in & b_in; // bitwise and
+ 1: result = a_in | b_in; // bitwise or
+ 2: result = a_in + b_in; // addition
+ 6: result = a_in - b_in; // substraction
+ 7: result = a_in < b_in ? 1 : 0; // set on less than
+ 8: result = ~(a_in | b_in); // bitwise nor
+ 9: result = a_in ^ b_in; // bitwise xor
+
+ default: result = 0;
+ endcase
+ end
+
+endmodule
diff --git a/hdl/alu_ctrl.v b/hdl/alu_ctrl.v
new file mode 100644
index 0000000..881c2c7
--- /dev/null
+++ b/hdl/alu_ctrl.v
@@ -0,0 +1,31 @@
+`timescale 1ns / 1ps
+
+/**
+ALU Control unit
+ */
+module alu_ctrl(
+ input wire [1:0] alu_op,
+ input wire [5:0] func_code,
+ output reg [4:0] alu_ctl
+ );
+
+always @*
+ begin
+ if(alu_op == 0)
+ alu_ctl = 2; // add
+ else if(alu_op == 1)
+ alu_ctl = 6;
+ else case( func_code )
+ 32: alu_ctl = 2; // add
+ 34: alu_ctl = 6; // subtract
+ 36: alu_ctl = 0; // and
+ 37: alu_ctl = 1; // or
+ 38: alu_ctl = 9; // xor
+ 39: alu_ctl = 8; // nor
+ 42: alu_ctl = 7; // slt
+ default: alu_ctl = 15; // should not happen
+ endcase
+ end
+
+endmodule
+
diff --git a/hdl/control.v b/hdl/control.v
new file mode 100644
index 0000000..58f273f
--- /dev/null
+++ b/hdl/control.v
@@ -0,0 +1,114 @@
+`timescale 1ns / 1ps
+
+module control(
+ input [5:0] opcode,
+ input branch_eq, // result of comparison for conditional branch
+
+ output reg [1:0] if_pc_source,
+ output id_rt_is_source, // rt is source
+
+ output ex_imm_command,
+ output reg ex_alu_src_b,
+ output reg ex_dst_reg_sel,
+ output reg [1:0] ex_alu_op,
+ output reg mem_read,
+ output reg mem_write,
+ output reg wb_mem_to_reg,
+ output reg wb_reg_write
+ );
+
+
+ localparam
+ LW = 6'b100011,
+ SW = 6'b101011,
+ BEQ=6'b000100,
+ RTYPE = 6'b0,
+ J=6'd2,
+ JAL=6'd3,
+ ADDI = 6'b001000,
+ ANDI = 6'b001100,
+ ORI = 6'b001101,
+ XORI = 6'b001110,
+ SLTI = 6'b001010; // opcodes
+
+ reg memory_op;
+ reg r_type_op;
+ reg immediate_op;
+ reg branch_op;
+ reg jump_op;
+
+
+ assign ex_imm_command = immediate_op;
+ assign id_rt_is_source = (r_type_op | branch_op | opcode == SW);
+
+
+ always @*
+ begin
+ // default values
+ if_pc_source = 0;
+ ex_alu_src_b = 0;
+ ex_dst_reg_sel = 0;
+ ex_alu_op = 0;
+ mem_read = 0;
+ mem_write = 0;
+ wb_mem_to_reg = 0;
+ wb_reg_write = 0;
+
+ memory_op = ( (opcode == LW) | (opcode == SW) );
+ r_type_op = ( opcode == RTYPE );
+ branch_op = ( opcode == BEQ );
+ immediate_op = ( (opcode == ADDI) | (opcode == ANDI) | (opcode == ORI) | (opcode == XORI) | (opcode == SLTI) );
+ jump_op = ( opcode == J);
+
+ if (memory_op) begin
+ ex_alu_src_b = 1'b1; // select sign_extend_offset input
+ ex_dst_reg_sel = 1'b0; // rt
+ ex_alu_op = 2'b00; // add op
+ wb_mem_to_reg = 1'b1; // select mem_out
+
+ if ( opcode == LW ) begin
+ mem_read = 1'b1;
+ wb_reg_write = 1'b1;
+ end
+ else
+ mem_write = 1'b1; // opcode == SW
+
+ end
+
+ else if (r_type_op) begin
+ ex_alu_src_b = 1'b0; // select B input
+ ex_dst_reg_sel = 1'b1; // rd
+ ex_alu_op = 2'b10; // operaction defined by func code
+
+ wb_mem_to_reg = 1'b0; // alu_out
+ wb_reg_write = 1'b1; // write result to regfile
+ end
+
+ else if (immediate_op) begin
+ ex_alu_src_b = 1'b1; // select sign_extend_offset input
+ ex_dst_reg_sel = 1'b0; // rt
+ ex_alu_op = 2'b10; // operation defined by function code
+
+ wb_mem_to_reg = 1'b0; // alu_out
+ wb_reg_write = 1'b01;
+ end
+
+ else if (branch_op) begin
+ if (branch_eq) if_pc_source = 2'b01; // PC <= branch_addr
+ else if_pc_source = 2'b00;
+
+ end
+
+ else if (jump_op) begin
+ if_pc_source = 2'b10; // PC <= jump_addr
+ end
+
+ else begin
+ // NOP
+ end
+
+
+ end
+
+
+endmodule
diff --git a/hdl/dp_memory.v b/hdl/dp_memory.v
new file mode 100644
index 0000000..fa7db30
--- /dev/null
+++ b/hdl/dp_memory.v
@@ -0,0 +1,37 @@
+`timescale 1ns / 1ps
+
+/**
+ Dual-port Instrcution/Data memory
+ */
+
+module dp_memory(
+ input wire clk,
+
+ input wire i_read_en,
+ input wire [31:0] i_addr,
+ output wire [31:0] i_instr_out,
+
+ input wire d_read_en,
+ input wire d_write_en,
+ input wire [31:0] d_addr,
+ input wire [31:0] d_write_data,
+ output wire [31:0] d_data_out
+ );
+
+ reg [31:0] mem[0:1023];
+
+ initial begin
+ $readmemh("./sw/test.rom", mem);
+ end
+
+
+ always @(posedge clk) begin
+ if (d_write_en)
+ mem [d_addr] <= d_write_data;
+ end
+
+ assign i_instr_out = i_read_en ? mem[i_addr] : 0;
+ assign d_data_out = d_read_en ? mem[d_addr] : 0;
+
+endmodule
+
diff --git a/hdl/ex_stage.v b/hdl/ex_stage.v
new file mode 100644
index 0000000..cca87e9
--- /dev/null
+++ b/hdl/ex_stage.v
@@ -0,0 +1,120 @@
+module ex_stage(
+ input clk,
+ input rst,
+
+ input wb_reg_write,
+ input wb_mem_to_reg,
+
+ input mem_read,
+ input mem_write,
+
+ input ex_imm_command,
+ input ex_alu_src_b,
+ input ex_dst_reg_sel,
+ input [1:0] ex_alu_op,
+
+ input [31:0] A,
+ input [31:0] B,
+ input [31:0] sign_extend_offset,
+ input [4:0] rt, // target register
+ input [4:0] rd, // destination register
+ input [5:0] opcode,
+ input [1:0] rs_fwd_sel, // forwarding muxes control
+ input [1:0] rt_fwd_sel, // forwarding muxes control
+ input [31:0] mem_fwd_val, // forwarding from EX_MEM
+ input [31:0] wb_fwd_val, // forwarding from WB
+
+ // outputs
+ output [4:0] ex_dst_reg,
+ output [5:0] ex_opcode,
+
+ output reg [31:0] EX_MEM_alu_result,
+ output reg [31:0] EX_MEM_B_value,
+ output reg [4:0] EX_MEM_dst_reg,
+ output reg [5:0] EX_MEM_opcode,
+ output reg EX_MEM_mem_read,
+ output reg EX_MEM_mem_write,
+ output reg EX_MEM_wb_reg_write,
+ output reg EX_MEM_wb_mem_to_reg
+);
+
+
+ wire [5:0] func_field; // func code field in instruction
+ wire [5:0] func_code; // func code for ALU control
+ wire [4:0] alu_ctl; // ALU control lines
+
+ reg [31:0] alu_a_in;
+ wire [31:0] alu_b_in;
+ reg[31:0] b_value;
+
+ wire [31:0] alu_result;
+ wire zero;
+
+
+ always @*
+ begin
+ case(rs_fwd_sel)
+ 0: alu_a_in = A;
+ 1: alu_a_in = mem_fwd_val;
+ 2: alu_a_in = wb_fwd_val;
+ endcase
+ end
+
+ always @*
+ begin
+ case(rt_fwd_sel)
+ 0: b_value = B;
+ 1: b_value = mem_fwd_val;
+ 2: b_value = wb_fwd_val;
+ endcase
+ end
+
+ assign alu_b_in = ex_alu_src_b ? sign_extend_offset : b_value;
+ assign func_field = sign_extend_offset [5:0]; // looks wierd, but func code is encoded there
+ assign func_code = ex_imm_command ? {{2'b10},{~opcode[2] & opcode[1] & ~opcode[0]},opcode[2:0]} : func_field;
+ assign ex_opcode = opcode;
+ assign ex_dst_reg = ex_dst_reg_sel ? rd : rt;
+
+
+
+ alu_ctrl aluctl_inst(
+ .alu_op (ex_alu_op),
+ .func_code (func_code),
+ .alu_ctl (alu_ctl)
+ );
+
+ alu alu_inst (
+ .alu_ctl (alu_ctl),
+ .a_in (alu_a_in),
+ .b_in (alu_b_in),
+ .result (alu_result),
+ .zero_flag (zero)
+ );
+
+ // EX/MEM Pipeline register
+ always @(posedge clk) begin
+ if (rst)
+ begin
+ EX_MEM_alu_result <= 0;
+ EX_MEM_B_value <= 0;
+ EX_MEM_dst_reg <= 0;
+ EX_MEM_mem_read <= 0;
+ EX_MEM_mem_write <= 0;
+ EX_MEM_wb_reg_write <= 0;
+ EX_MEM_wb_mem_to_reg <= 0;
+ end
+ else
+ begin
+ EX_MEM_alu_result <= alu_result;
+ EX_MEM_B_value <= b_value;
+ EX_MEM_dst_reg <= ex_dst_reg;
+ EX_MEM_opcode <= opcode;
+ EX_MEM_mem_read <= mem_read;
+ EX_MEM_mem_write <= mem_write;
+ EX_MEM_wb_reg_write <= wb_reg_write;
+ EX_MEM_wb_mem_to_reg <= wb_mem_to_reg;
+ end
+ end
+
+
+endmodule
diff --git a/hdl/forwarding_unit.v b/hdl/forwarding_unit.v
new file mode 100644
index 0000000..ab98219
--- /dev/null
+++ b/hdl/forwarding_unit.v
@@ -0,0 +1,138 @@
+`timescale 1ns / 1ps
+
+module forwarding_unit
+ (
+ input ex_mem_reg_write,
+ input mem_wb_reg_write,
+ input [4:0] ex_mem_dst_reg,
+ input [4:0] mem_wb_dst_reg,
+ input [4:0] id_ex_rs,
+ input [4:0] id_ex_rt,
+ input [4:0] if_id_rs,
+ input [4:0] if_id_rt,
+
+ output [1:0] if_rs_forward_control,
+ output [1:0] id_rt_forward_control,
+ output [1:0] ex_rs_forward_control,
+ output [1:0] ex_rt_forward_control
+ );
+
+ // tmp signals
+ wire [3:0] id_fwd_ctrl, ex_fwd_ctrl;
+
+ // encoding for muxes control signals
+ // general for both forwarding muxes
+ // 2'b01 - from EX_MEM pipe reg
+ // 2'b10 - from MEM_WB pipe reg
+ // 2'b00 - no forwarding
+
+ assign if_rs_forward_control = id_fwd_ctrl[0] ? 2'b01 : id_fwd_ctrl[2] ? 2'b10 : 2'b00;
+ assign id_rt_forward_control = id_fwd_ctrl[1] ? 2'b01 : id_fwd_ctrl[3] ? 2'b10 : 2'b00;
+ assign ex_rs_forward_control = ex_fwd_ctrl[0] ? 2'b01 : ex_fwd_ctrl[2] ? 2'b10 : 2'b00;
+ assign ex_rt_forward_control = ex_fwd_ctrl[1] ? 2'b01 : ex_fwd_ctrl[3] ? 2'b10 : 2'b00;
+
+ base_forwarding_unit ex_forwarding_inst(
+ .ex_mem_reg_write(ex_mem_reg_write),
+ .mem_wb_reg_write(mem_wb_reg_write),
+ .ex_mem_dst_reg(ex_mem_dst_reg),
+ .mem_wb_dst_reg(mem_wb_dst_reg),
+ .rs(id_ex_rs),
+ .rt(id_ex_rt),
+ .forward_control(ex_fwd_ctrl)
+ );
+
+ base_forwarding_unit id_forwarding_inst(
+ .ex_mem_reg_write(ex_mem_reg_write),
+ .mem_wb_reg_write(mem_wb_reg_write),
+ .ex_mem_dst_reg(ex_mem_dst_reg),
+ .mem_wb_dst_reg(mem_wb_dst_reg),
+ .rs(if_id_rs),
+ .rt(if_id_rt),
+ .forward_control(id_fwd_ctrl)
+ );
+
+
+endmodule
+
+
+
+/* Generic base logic module to implement forwarding
+
+ Description of forward_control signal:
+0000 - no forwarding
+0001 - forwarding value from EX_MEM for replace rs value on destination stage.
+ EX_MEM[Value] -> PIPE_STAGE[rs]
+
+0010 - forwarding value from EX_MEM for replace rt value on destination stage.
+ EX_MEM[Value] -> PIPE_STAGE[rt]
+
+0100 - forwarding value from WB for replace rs value on destination stage.
+ WB[Value] -> PIPE_STAGE[rs]
+
+1000 - forwarding value from WB for replace rt value on destination stage.
+ WB[Value] -> PIPE_STAGE[rt]
+
+0011 - forwarding value from EX_MEM for replace rs and rt value on destination stage
+ EX_MEM[Value] -> PIPE_STAGE[rs]; EX_MEM[Value] -> PIPE_STAGE[rt]
+
+1100 - forwarding value from WB for replace Rs and Rt value on destination stage
+ WB[Value] -> PIPE_STAGE[rs]; WB[Value] -> PIPE_STAGE[rt]
+
+
+0110 - forwarding value from EX_MEM for replace rt value on destination stage.
+ EX_MEM[Value] -> PIPE_STAGE[rt]
+ forwarding value from WB for replace rs value on destination stage.
+ WB[Value] -> PIPE_STAGE[rs]
+
+1001 - forwarding value from EX_MEM for replace rs value on destination stage.
+ EX_MEM[Value] -> PIPE_STAGE[rs]
+ forwarding value from WB for replace rt value on destination stage.
+ WB[Value] -> PIPE_STAGE[rt]
+ */
+
+module base_forwarding_unit (
+ input ex_mem_reg_write,
+ input mem_wb_reg_write,
+ input [4:0] ex_mem_dst_reg,
+ input [4:0] mem_wb_dst_reg,
+ input [4:0] rs,
+ input [4:0] rt,
+
+ output reg [3:0] forward_control
+);
+
+ // service signals
+ reg ex_mem_dst_reg_is_not_zero;
+ reg mem_wb_dst_reg_is_not_zero;
+
+ always @*
+ begin
+
+ ex_mem_dst_reg_is_not_zero = |ex_mem_dst_reg;
+ mem_wb_dst_reg_is_not_zero = |mem_wb_dst_reg;
+ forward_control = 4'h0;
+
+ if (ex_mem_reg_write & ex_mem_dst_reg_is_not_zero)
+ begin
+ if (ex_mem_dst_reg == rs) forward_control[0] = 1'b1;
+ else forward_control[0] = 1'b0;
+
+ if (ex_mem_dst_reg == rt) forward_control[1] = 1'b1;
+ else forward_control[1] = 1'b0;
+ end
+ else forward_control[1:0] = 2'b00;
+
+ if (mem_wb_reg_write & mem_wb_dst_reg_is_not_zero)
+ begin
+ if ((mem_wb_dst_reg == rs) & (ex_mem_dst_reg != rs)) forward_control[2] = 1'b1;
+ else forward_control[2] = 1'b0;
+
+ if ((mem_wb_dst_reg == rt) & (ex_mem_dst_reg != rt)) forward_control[3] = 1'b1;
+ else forward_control[3] = 1'b0;
+ end
+ else forward_control[3:2] = 2'b00;
+
+ end
+
+
+endmodule
diff --git a/hdl/hazard_unit.v b/hdl/hazard_unit.v
new file mode 100644
index 0000000..627c162
--- /dev/null
+++ b/hdl/hazard_unit.v
@@ -0,0 +1,66 @@
+`timescale 1ns / 1ps
+
+module hazard_unit(
+ input clk,
+ input rst,
+ input [4:0] ex_dst_reg,
+ input [4:0] mem_dst_reg,
+ input [4:0] id_rs,
+ input [4:0] id_rt,
+
+ input [5:0] mem_opcode,
+ input [5:0] ex_opcode,
+ input [5:0] id_opcode,
+
+ input id_rt_is_source,
+ input ex_reg_write,
+ input mem_reg_write,
+
+ output pc_write,
+ output if_id_write_en,
+ output reg hazard_detected
+);
+
+ localparam
+ LW = 6'b100011,
+ BEQ=6'b000100;
+
+
+ assign pc_write = ~hazard_detected;
+ assign if_id_write_en = ~hazard_detected;
+
+ reg [1:0] coincidence;
+
+ always @*
+ begin
+ coincidence = 0;
+
+ if (ex_reg_write && ( (id_rs == ex_dst_reg) | ( (id_rt == ex_dst_reg) && id_rt_is_source)))
+ coincidence[0] = 1'b1;
+ else if (mem_reg_write && ( (id_rs == mem_dst_reg) | ( (id_rt == mem_dst_reg) && id_rt_is_source)))
+ coincidence[1] = 1'b1;
+ end
+
+
+ always @*
+ begin
+ hazard_detected = 0;
+
+ if (coincidence [0])
+ begin
+ if ( id_opcode == BEQ && ex_opcode == LW )
+ hazard_detected = 1;
+ else if ( id_opcode == BEQ && ex_opcode != LW)
+ hazard_detected = 1;
+ else if ( id_opcode != BEQ && ex_opcode == LW)
+ hazard_detected = 1;
+ end
+ else if (coincidence [1])
+ begin
+ if (id_opcode == BEQ && mem_opcode == LW)
+ hazard_detected = 1;
+ end
+ end
+
+
+endmodule
diff --git a/hdl/id_stage.v b/hdl/id_stage.v
new file mode 100644
index 0000000..387c420
--- /dev/null
+++ b/hdl/id_stage.v
@@ -0,0 +1,188 @@
+`timescale 1ns / 1ps
+/*
+ Instruction decode pipeline stage
+ */
+
+module id_stage(
+ input clk, rst,
+ input reg_write,
+ input [4:0] wreg_addr, // write register number
+ input [31:0] wreg_data, // data to write into regfile
+ input [31:0] instruction, next_i_addr, // instruction fetched, next instruction address
+
+ // inputs to support forwarding
+ input [1:0] rs_fwd_sel, rt_fwd_sel, // forwarding control signals
+ input [31:0] mem_fwd_val, wb_fwd_val, // forwarded data values
+
+ input hazard,
+ // outputs
+ output wire [4:0] id_rs,
+ output wire [4:0] id_rt,
+ output wire [5:0] id_opcode,
+
+
+ output reg [31:0] ID_EX_A,
+ output reg [31:0] ID_EX_B,
+ output reg [4:0] ID_EX_rt,
+ output reg [4:0] ID_EX_rs,
+ output reg [4:0] ID_EX_rd,
+ output reg [5:0] ID_EX_opcode,
+ output reg [31:0] ID_EX_sign_extend_offset,
+ output reg ID_EX_wb_reg_write,
+ output reg ID_EX_wb_mem_to_reg,
+ output reg ID_EX_mem_read,
+ output reg ID_EX_mem_write,
+ output reg ID_EX_ex_imm_command,
+ output reg ID_EX_ex_alu_src_b,
+ output reg ID_EX_ex_dst_reg_sel,
+ output reg [1:0] ID_EX_ex_alu_op,
+
+ output [31:0] branch_addr, jump_addr, // branch and jump adresses
+ output id_rt_is_source,
+ output [1:0] if_pc_source
+ );
+
+
+
+
+ reg [31:0] A, B;
+ wire [31:0] a_out;
+ wire [31:0] b_out;
+ wire [31:0] sign_extend_offset;
+
+ wire ex_imm_command;
+ wire ex_alu_src_b;
+ wire ex_dst_reg_sel;
+ wire [1:0] ex_alu_op;
+ wire mem_read;
+ wire mem_write;
+ wire wb_mem_to_reg;
+ wire wb_reg_write;
+ wire is_nop;
+ wire branch_eq;
+
+
+
+ regfile regfile_inst
+ (
+ .clk( clk ),
+ .rst( rst ),
+ .raddr1( instruction[25:21] ),
+ .raddr2( instruction[20:16] ),
+ .waddr( wreg_addr ),
+ .wdata( wreg_data ),
+ .w_en( reg_write ),
+ .rdata1( a_out ),
+ .rdata2( b_out )
+ );
+
+
+
+ // Forwarding muxes
+
+ always @*
+ begin
+ A = 0;
+ case (rs_fwd_sel)
+ 0: A = a_out;
+ 1: A = mem_fwd_val;
+ 2: A = wb_fwd_val;
+ endcase
+ end
+
+ always @*
+ begin
+ B = 0;
+ case (rt_fwd_sel)
+ 0: B = b_out;
+ 1: B = mem_fwd_val;
+ 2: B = wb_fwd_val;
+ endcase
+ end
+
+
+ assign sign_extend_offset = { { 16{instruction[15]} }, instruction [15:0]};
+ assign branch_addr = next_i_addr + ( sign_extend_offset << 2 );
+ assign jump_addr = {next_i_addr[31:28], instruction[25:0], 2'b00 };
+ assign branch_eq = ( A == B);
+
+ assign id_rs = instruction[25:21];
+ assign id_rt = instruction[20:16];
+ assign id_opcode = instruction[31:26];
+
+ assign is_nop = ~|instruction;
+
+ // Control Unit -- Opcode Decoder
+
+ control cunit_instance (
+ .opcode( instruction [31:26] ),
+ .branch_eq( branch_eq ),
+ .id_rt_is_source(id_rt_is_source),
+ .if_pc_source(if_pc_source),
+ .ex_imm_command(ex_imm_command),
+ .ex_alu_src_b(ex_alu_src_b),
+ .ex_dst_reg_sel(ex_dst_reg_sel),
+ .ex_alu_op(ex_alu_op),
+ .mem_read(mem_read),
+ .mem_write(mem_write),
+ .wb_mem_to_reg(wb_mem_to_reg),
+ .wb_reg_write(wb_reg_write)
+ );
+
+
+ // ID/EX Pipeline register
+
+
+ always @(posedge clk) begin
+ if (rst)
+ begin
+ ID_EX_A <= 0;
+ ID_EX_B <= 0;
+ ID_EX_rt <= 0;
+ ID_EX_rs <= 0;
+ ID_EX_rd <= 0;
+ ID_EX_opcode <= 0;
+ ID_EX_sign_extend_offset <= 0;
+ ID_EX_wb_reg_write <= 0;
+ ID_EX_wb_mem_to_reg <= 0;
+ ID_EX_mem_read <= 0;
+ ID_EX_mem_write <= 0;
+ ID_EX_ex_imm_command <= 0;
+ ID_EX_ex_alu_src_b <= 0;
+ ID_EX_ex_dst_reg_sel <= 0;
+ ID_EX_ex_alu_op <= 0;
+ end
+ else
+ begin
+ ID_EX_A <= A;
+ ID_EX_B <= B;
+ ID_EX_rt <= id_rt;
+ ID_EX_rs <= id_rs;
+ ID_EX_rd <= instruction[15:11];
+ ID_EX_opcode <= id_opcode;
+ ID_EX_sign_extend_offset <= sign_extend_offset;
+ if (is_nop || hazard) begin
+ ID_EX_wb_reg_write <= 0;
+ ID_EX_wb_mem_to_reg <= 0;
+ ID_EX_mem_read <= 0;
+ ID_EX_mem_write <= 0;
+ ID_EX_ex_imm_command <= 0;
+ ID_EX_ex_alu_src_b <= 0;
+ ID_EX_ex_dst_reg_sel <= 0;
+ ID_EX_ex_alu_op <= 0;
+ end
+ else begin
+ ID_EX_wb_reg_write <= wb_reg_write;
+ ID_EX_wb_mem_to_reg <= wb_mem_to_reg;
+ ID_EX_mem_read <= mem_read;
+ ID_EX_mem_write <= mem_write;
+ ID_EX_ex_imm_command <= ex_imm_command;
+ ID_EX_ex_alu_src_b <= ex_alu_src_b;
+ ID_EX_ex_dst_reg_sel <= ex_dst_reg_sel;
+ ID_EX_ex_alu_op <= ex_alu_op;
+ end
+ end
+ end
+
+
+endmodule
diff --git a/hdl/if_stage.v b/hdl/if_stage.v
new file mode 100644
index 0000000..eda165d
--- /dev/null
+++ b/hdl/if_stage.v
@@ -0,0 +1,77 @@
+`timescale 1ns / 1ps
+
+/*
+ Instruction Fetch pipeline stage
+ */
+
+module if_stage(
+ input clk, rst,
+
+ input if_id_write_en,
+ input pc_write,
+ input [1:0] pc_source,
+
+ output i_read_en,
+ output [31:0] i_addr,
+
+ input [31:0] i_instr_in,
+ input [31:0] jump_addr, branch_addr,
+
+ output reg [31:0] IF_ID_next_i_addr,
+ output reg [31:0] IF_ID_instruction
+ );
+
+
+ reg [31:0] pc_reg, pc_next; // Program counter (PC)
+ wire [31:0] next_i_addr;
+
+ // logic
+ assign next_i_addr = pc_reg + 4;
+ assign i_read_en = 1;
+ assign i_addr = pc_reg >> 2;
+
+ always @*
+ begin
+ pc_next = pc_reg;
+
+ case (pc_source)
+ 2'b00: pc_next = next_i_addr;
+ 2'b01: pc_next = branch_addr;
+ 2'b10: pc_next = jump_addr;
+ endcase
+
+ end
+
+ always @(posedge clk)
+ begin
+ if (rst)
+ pc_reg <= 0;
+ else
+ begin
+ if (pc_write)
+ pc_reg <= pc_next;
+ end
+ end
+
+
+ /*
+ IF/ID Pipeline register
+ */
+
+ always @(posedge clk) begin
+ if (rst)
+ begin
+ IF_ID_next_i_addr <= 0;
+ IF_ID_instruction <= 0;
+ end
+ else
+ begin
+ if ( if_id_write_en ) begin
+ IF_ID_next_i_addr <= pc_reg + 4;
+ IF_ID_instruction <= i_instr_in;
+ end
+ end
+ end
+
+
+endmodule
diff --git a/hdl/mem_stage.v b/hdl/mem_stage.v
new file mode 100644
index 0000000..79a211d
--- /dev/null
+++ b/hdl/mem_stage.v
@@ -0,0 +1,59 @@
+`timescale 1ns / 1ps
+
+
+module mem_stage (
+ input clk,
+ input rst,
+ input mem_read,
+ input mem_write,
+ input [31:0] alu_result,
+ input [31:0] B,
+ input [4:0] dst_reg,
+ input wb_reg_write,
+ input wb_mem_to_reg,
+
+ output reg [4:0] MEM_WB_dst_reg,
+ output reg MEM_WB_reg_write,
+ output reg MEM_WB_mem_to_reg,
+ output reg [31:0] MEM_WB_mem_out,
+ output reg [31:0] MEM_WB_alu_out,
+
+ // Memory Interface
+ output d_read_en,
+ output d_write_en,
+ output [31:0] d_addr,
+ output [31:0] d_write_data,
+ input [31:0] d_data_in
+ );
+
+ assign d_read_en = mem_read;
+ assign d_write_en = mem_write;
+ assign d_addr = alu_result;
+ assign d_write_data = B;
+
+
+ /*
+ MEM/WB Pipeline register
+ */
+
+ always @(posedge clk) begin
+ if (rst)
+ begin
+ MEM_WB_dst_reg <= 0;
+ MEM_WB_reg_write <= 0;
+ MEM_WB_mem_to_reg <= 0;
+ MEM_WB_mem_out <= 0;
+ MEM_WB_alu_out <= 0;
+ end
+ else
+ begin
+ MEM_WB_dst_reg <= dst_reg;
+ MEM_WB_reg_write <= wb_reg_write;
+ MEM_WB_mem_to_reg <= wb_mem_to_reg;
+ MEM_WB_mem_out <= d_data_in;
+ MEM_WB_alu_out <= alu_result;
+ end
+ end
+
+
+endmodule
diff --git a/hdl/mips_system.v b/hdl/mips_system.v
new file mode 100644
index 0000000..fa01da1
--- /dev/null
+++ b/hdl/mips_system.v
@@ -0,0 +1,55 @@
+/*
+ MIPS System: CPU Core + Memory
+ */
+
+module mips_system
+ (
+ input wire clk,
+ input wire rst,
+
+ output ext_write_en,
+ output ext_read_en,
+ output [31:0] ext_addr,
+ output [31:0] ext_write_data,
+ input [31:0] ext_data_in
+ ) ;
+
+ wire i_read_en;
+ wire [31:0] i_addr;
+ wire [31:0] i_instr;
+ wire d_read_en;
+ wire d_write_en;
+ wire [31:0] d_addr;
+ wire [31:0] d_write_data;
+ wire [31:0] d_read_data;
+
+ pipeline pipeline_inst
+ (
+ .clk(clk),
+ .rst(rst),
+ .i_read_en(i_read_en),
+ .i_addr(i_addr),
+ .i_instr_in(i_instr),
+ .d_read_en(d_read_en),
+ .d_write_en(d_write_en),
+ .d_addr(d_addr),
+ .d_write_data(d_write_data),
+ .d_data_in(d_read_data)
+ );
+
+
+ dp_memory memory_inst
+ (
+ .clk(clk),
+ .i_read_en(i_read_en),
+ .i_addr(i_addr),
+ .i_instr_out(i_instr),
+ .d_read_en(d_read_en),
+ .d_write_en(d_write_en),
+ .d_addr(d_addr),
+ .d_write_data(d_write_data),
+ .d_data_out(d_read_data)
+ );
+
+
+endmodule // mips_system
diff --git a/hdl/pipeline.v b/hdl/pipeline.v
new file mode 100644
index 0000000..01f94da
--- /dev/null
+++ b/hdl/pipeline.v
@@ -0,0 +1,250 @@
+`timescale 1ns / 1ps
+
+/**
+ Pipelined CPU
+ */
+
+module pipeline(
+ input wire clk,
+ input wire rst,
+
+ output i_read_en,
+ output [31:0] i_addr,
+
+ input [31:0] i_instr_in,
+
+ output wire d_read_en,
+ output wire d_write_en,
+ output wire [31:0] d_addr,
+ output wire [31:0] d_write_data,
+ input wire [31:0] d_data_in
+ );
+
+
+/* Interconnect wires*/
+ wire [1:0] pc_source;
+ wire pc_write;
+ wire [31:0] jump_addr;
+ wire [31:0] branch_addr;
+ wire [31:0] next_i_addr;
+ wire [31:0] i_fetched; // fetched instrcution from if
+ wire if_id_write_en; // write enable for IF/ID pipe reg
+
+ wire [31:0] wreg_data; // data to write into regfile
+
+ wire [4:0] ex_dst_reg;
+ wire [5:0] ex_opcode;
+
+ wire [4:0] id_rs;
+ wire [4:0] id_rt;
+ wire [5:0] id_opcode;
+
+ wire ID_EX_wb_reg_write;
+ wire ID_EX_wb_mem_to_reg;
+ wire ID_EX_mem_read;
+ wire ID_EX_mem_write;
+ wire ID_EX_ex_imm_command;
+ wire ID_EX_ex_alu_src_b;
+ wire ID_EX_ex_dst_reg_sel;
+ wire [1:0] ID_EX_ex_alu_op;
+ wire [31:0] ID_EX_A;
+ wire [31:0] ID_EX_B;
+ wire [31:0] ID_EX_sign_extend_offset;
+ wire [4:0] ID_EX_rt; // target register
+ wire [4:0] ID_EX_rd; // destination register
+ wire [4:0] ID_EX_rs; // source register
+ wire [5:0] ID_EX_opcode;
+
+ wire [31:0] EX_MEM_alu_result;
+ wire [31:0] EX_MEM_B_value;
+ wire [4:0] EX_MEM_dst_reg;
+ wire [5:0] EX_MEM_opcode;
+ wire EX_MEM_mem_read;
+ wire EX_MEM_mem_write;
+ wire EX_MEM_wb_reg_write;
+ wire EX_MEM_wb_mem_to_reg;
+
+ wire [4:0] MEM_WB_dst_reg;
+ wire MEM_WB_reg_write;
+ wire MEM_WB_mem_to_reg;
+ wire [31:0] MEM_WB_mem_out;
+ wire [31:0] MEM_WB_alu_out;
+
+ wire id_rt_is_source;
+ wire hazard_detected;
+
+
+ // forwarding control signals for muxes
+ wire [1:0] if_rs_forward_control;
+ wire [1:0] id_rt_forward_control;
+ wire [1:0] ex_rs_forward_control;
+ wire [1:0] ex_rt_forward_control;
+
+
+
+ if_stage ifetch_inst
+ (
+ .clk ( clk ),
+ .rst ( rst ),
+ .if_id_write_en ( if_id_write_en ),
+ .pc_write ( pc_write ),
+ .pc_source ( pc_source ),
+ .i_read_en ( i_read_en ),
+ .i_addr ( i_addr ),
+ .i_instr_in ( i_instr_in),
+ .jump_addr ( jump_addr ),
+ .branch_addr ( branch_addr ),
+ .IF_ID_instruction ( i_fetched ),
+ .IF_ID_next_i_addr ( next_i_addr )
+ );
+
+
+ hazard_unit hazard_inst
+ (
+ .clk ( clk ),
+ .rst ( rst ),
+ .ex_dst_reg ( ex_dst_reg ),
+ .mem_dst_reg ( EX_MEM_dst_reg ),
+ .id_rs ( id_rs ),
+ .id_rt ( id_rt ),
+ .mem_opcode ( EX_MEM_opcode ),
+ .ex_opcode ( ex_opcode ),
+ .id_opcode ( id_opcode ),
+ .id_rt_is_source ( id_rt_is_source ),
+ .ex_reg_write ( ID_EX_wb_reg_write ),
+ .mem_reg_write ( EX_MEM_wb_reg_write ),
+ .pc_write ( pc_write ),
+ .if_id_write_en ( if_id_write_en ),
+ .hazard_detected ( hazard_detected )
+ );
+
+ forwarding_unit forwarding_inst
+ (
+ .ex_mem_reg_write (EX_MEM_wb_reg_write),
+ .mem_wb_reg_write (MEM_WB_reg_write),
+ .ex_mem_dst_reg (EX_MEM_dst_reg),
+ .mem_wb_dst_reg (MEM_WB_dst_reg),
+ .id_ex_rs (ID_EX_rs),
+ .id_ex_rt (ID_EX_rt),
+ .if_id_rs (id_rs),
+ .if_id_rt (id_rt),
+ .if_rs_forward_control ( if_rs_forward_control ),
+ .id_rt_forward_control ( id_rt_forward_control ),
+ .ex_rs_forward_control ( ex_rs_forward_control ),
+ .ex_rt_forward_control ( ex_rt_forward_control )
+ );
+
+
+
+ id_stage idecode_inst
+ (
+ .clk ( clk ),
+ .rst ( rst ),
+ .reg_write ( MEM_WB_reg_write ),
+ .wreg_addr ( MEM_WB_dst_reg ), // write register number
+ .wreg_data ( wreg_data ), // data to write into regfile
+ .instruction ( i_fetched ),
+ .next_i_addr ( next_i_addr ), // instruction fetched, next instruction address
+
+ .rs_fwd_sel ( if_rs_forward_control ), // forwarding control signals
+ .rt_fwd_sel ( id_rt_forward_control ), // forwarding control signals
+ .mem_fwd_val ( EX_MEM_alu_result ), // forwarded data values from MEM
+ .wb_fwd_val ( wreg_data ), // forwarded data values from WB
+
+ .hazard ( hazard_detected ),
+ .id_rs( id_rs ),
+ .id_rt( id_rt ),
+ .id_opcode( id_opcode ),
+
+ .ID_EX_A ( ID_EX_A ),
+ .ID_EX_B ( ID_EX_B ),
+ .ID_EX_rt ( ID_EX_rt ),
+ .ID_EX_rs ( ID_EX_rs ),
+ .ID_EX_rd ( ID_EX_rd ),
+ .ID_EX_opcode ( ID_EX_opcode ),
+ .ID_EX_sign_extend_offset ( ID_EX_sign_extend_offset ),
+ .ID_EX_wb_reg_write ( ID_EX_wb_reg_write ),
+ .ID_EX_wb_mem_to_reg ( ID_EX_wb_mem_to_reg ),
+ .ID_EX_mem_read ( ID_EX_mem_read ),
+ .ID_EX_mem_write ( ID_EX_mem_write ),
+ .ID_EX_ex_imm_command ( ID_EX_ex_imm_command ),
+ .ID_EX_ex_alu_src_b ( ID_EX_ex_alu_src_b ),
+ .ID_EX_ex_dst_reg_sel ( ID_EX_ex_dst_reg_sel ),
+ .ID_EX_ex_alu_op ( ID_EX_ex_alu_op ),
+
+ .branch_addr ( branch_addr ),
+ .jump_addr ( jump_addr ),
+ .id_rt_is_source ( id_rt_is_source ),
+ .if_pc_source ( pc_source )
+ );
+
+
+ ex_stage execute_inst
+ (
+ .clk ( clk ),
+ .rst ( rst ),
+ .wb_reg_write ( ID_EX_wb_reg_write ),
+ .wb_mem_to_reg ( ID_EX_wb_mem_to_reg ),
+ .mem_read ( ID_EX_mem_read ),
+ .mem_write ( ID_EX_mem_write ),
+ .ex_imm_command ( ID_EX_ex_imm_command ),
+ .ex_alu_src_b ( ID_EX_ex_alu_src_b ),
+ .ex_dst_reg_sel ( ID_EX_ex_dst_reg_sel ),
+ .ex_alu_op ( ID_EX_ex_alu_op ),
+ .A ( ID_EX_A ),
+ .B ( ID_EX_B ),
+ .sign_extend_offset ( ID_EX_sign_extend_offset ),
+ .rt ( ID_EX_rt ), // target register
+ .rd ( ID_EX_rd ), // destination register
+ .opcode ( ID_EX_opcode ),
+ .rs_fwd_sel ( ex_rs_forward_control ), // forwarding muxes control
+ .rt_fwd_sel ( ex_rt_forward_control ), // forwarding muxes control
+ .mem_fwd_val ( EX_MEM_alu_result ), // forwarding from MEM
+ .wb_fwd_val ( wreg_data ), // forwarding from WB
+ .ex_dst_reg ( ex_dst_reg ),
+ .ex_opcode ( ex_opcode ),
+ .EX_MEM_alu_result ( EX_MEM_alu_result ),
+ .EX_MEM_B_value ( EX_MEM_B_value ),
+ .EX_MEM_dst_reg ( EX_MEM_dst_reg ),
+ .EX_MEM_opcode ( EX_MEM_opcode ),
+ .EX_MEM_mem_read ( EX_MEM_mem_read ),
+ .EX_MEM_mem_write ( EX_MEM_mem_write ),
+ .EX_MEM_wb_reg_write ( EX_MEM_wb_reg_write ),
+ .EX_MEM_wb_mem_to_reg ( EX_MEM_wb_mem_to_reg )
+ );
+
+
+ mem_stage memstage_inst
+ (
+ .clk ( clk ),
+ .rst ( rst ),
+ .mem_read ( EX_MEM_mem_read ),
+ .mem_write ( EX_MEM_mem_write ),
+ .alu_result ( EX_MEM_alu_result ),
+ .B ( EX_MEM_B_value ),
+ .dst_reg ( EX_MEM_dst_reg ),
+ .wb_reg_write ( EX_MEM_wb_reg_write ),
+ .wb_mem_to_reg ( EX_MEM_wb_mem_to_reg ),
+ .MEM_WB_dst_reg ( MEM_WB_dst_reg ),
+ .MEM_WB_reg_write ( MEM_WB_reg_write ),
+ .MEM_WB_mem_to_reg ( MEM_WB_mem_to_reg ),
+ .MEM_WB_mem_out ( MEM_WB_mem_out ),
+ .MEM_WB_alu_out ( MEM_WB_alu_out ),
+ .d_read_en ( d_read_en ),
+ .d_write_en ( d_write_en ),
+ .d_addr ( d_addr ),
+ .d_write_data ( d_write_data ),
+ .d_data_in ( d_data_in )
+ );
+
+
+ wb_stage wb_inst
+ (
+ .mem_to_reg ( MEM_WB_mem_to_reg ),
+ .mem_out ( MEM_WB_mem_out ),
+ .alu_out ( MEM_WB_alu_out ),
+ .write_data ( wreg_data )
+ );
+
+
+endmodule
diff --git a/hdl/regfile.v b/hdl/regfile.v
new file mode 100644
index 0000000..01219f9
--- /dev/null
+++ b/hdl/regfile.v
@@ -0,0 +1,40 @@
+`timescale 1ns / 1ps
+
+/**
+ Register file:
+ * 2 asyncrhonous read ports
+ * 1 synchronous write port
+ */
+module regfile(
+ input wire clk, // clock to trigger write
+ input wire rst, // reset
+ input wire [4:0] raddr1, raddr2, waddr, // the registers numbers to read or write
+ input wire [31:0] wdata, // data to write
+ input wire w_en, // write enable
+ output wire [31:0] rdata1, rdata2 // the register values read
+ );
+
+
+ reg [31:0] rf [31:0]; // 32 registers each 32 bits long
+
+ assign rdata1 = rf [raddr1];
+ assign rdata2 = rf [raddr2];
+
+ integer ii;
+
+ initial
+ begin
+ for ( ii = 0; ii < 32; ii= ii + 1 )
+ rf[ii] = 0;
+ end
+
+ always @(posedge clk)
+ begin
+ if (rst)
+ rf[0] <= 0;
+ else
+ if(w_en)
+ rf [waddr] <= wdata;
+ end
+
+endmodule
diff --git a/hdl/testbench.v b/hdl/testbench.v
new file mode 100644
index 0000000..6100226
--- /dev/null
+++ b/hdl/testbench.v
@@ -0,0 +1,73 @@
+`timescale 1ns / 1ps
+
+
+module testbench;
+
+ // Inputs
+ reg clk;
+ reg rst;
+ reg [31:0] ext_data_in;
+
+ // Outputs
+ wire ext_write_en;
+ wire ext_read_en;
+ wire [31:0] ext_addr;
+ wire [31:0] ext_write_data;
+
+ // Instantiate the Unit Under Test (UUT)
+ mips_system uut (
+ .clk(clk),
+ .rst(rst),
+ .ext_write_en(ext_write_en),
+ .ext_read_en(ext_read_en),
+ .ext_addr(ext_addr),
+ .ext_write_data(ext_write_data),
+ .ext_data_in(ext_data_in)
+ );
+
+ initial begin
+ rst = 1;
+ ext_data_in = 0;
+
+ // Wait 100 ns for global reset to finish
+ #100;
+ rst = 0;
+
+ end // initial begin
+
+
+ initial begin
+ clk = 0;
+ forever
+ #10 clk = !clk;
+ end
+
+
+ integer i;
+ initial begin
+
+ for (i = 0; i < 1000; i=i+1)
+ @(posedge clk);
+
+
+ $stop();
+ end
+
+ initial
+ begin
+ $display("Trace register $t0");
+ @(negedge rst);
+
+ forever
+ begin
+ @(posedge clk);
+ $display("$t0 (REG8) = %x",uut.pipeline_inst.idecode_inst.regfile_inst.rf[8]);
+ end
+
+
+
+ end
+
+
+endmodule
+
diff --git a/hdl/wb_stage.v b/hdl/wb_stage.v
new file mode 100644
index 0000000..37cfc38
--- /dev/null
+++ b/hdl/wb_stage.v
@@ -0,0 +1,11 @@
+`timescale 1ns / 1ps
+
+module wb_stage(
+ input mem_to_reg,
+ input [31:0] mem_out, alu_out,
+ output [31:0] write_data
+ );
+
+ assign write_data = mem_to_reg ? mem_out : alu_out;
+
+endmodule
diff --git a/sw/Makefile b/sw/Makefile
new file mode 100644
index 0000000..2207685
--- /dev/null
+++ b/sw/Makefile
@@ -0,0 +1,22 @@
+CFLAGS = -O2 -Wall -c -s
+
+GCC_MIPS = mips-sde-elf-gcc $(CFLAGS)
+AS_MIPS = mips-sde-elf-as
+LD_MIPS = mips-sde-elf-ld
+DUMP_MIPS = mips-sde-elf-objdump
+COPY_MIPS = mips-sde-elf-objcopy
+CONVERT = cat test.vh | perl -pe 's/([\dA-F]{2})\s+([\dA-F]{2})\s+([\dA-F]{2})\s+([\dA-F]{2})/$$1$$2$$3$$4/g;' > test.rom
+
+
+LIBS =
+
+
+all:
+ $(AS_MIPS) -o test.o test.asm
+ $(LD_MIPS) -Ttext 0x0 -Tdata 0x200 -eentry -o test.axf test.o
+ $(DUMP_MIPS) --disassemble test.axf > test.lst
+ $(COPY_MIPS) -O verilog test.axf test.vh
+ $(CONVERT)
+
+clean:
+ rm -f *.o
diff --git a/sw/test.asm b/sw/test.asm
new file mode 100644
index 0000000..7712165
--- /dev/null
+++ b/sw/test.asm
@@ -0,0 +1,19 @@
+.global entry
+
+.data /* data section*/
+ .word 0x0001
+ .word 0xFFFF
+.text /* code goes to text section*/
+.ent entry
+entry:
+ lw $t0, 0x200 /* t0 = 1*/
+ lw $t1, 0x200 /* t1 = 1*/
+ add $t0, $t0, $t1 /* t0 = t0 + t1 = 2*/
+ add $t0, $t0, 0xB /* t0 = t0 + 0xB == 0xD*/
+ sub $t0, $t0, $t1 /* t0 = t0 - $t1 == 0xC*/
+ or $t0, $t0, 0x10 /* t0 = t0 | 0x10 == 0x1C*/
+ xor $t0, $t0, $t1 /* t0 = t0 ^ t1 == 0x1D*/
+ slt $t0, $t0, $t1 /* t0 = t0 < t1 == 0*/
+ add $t0, $t0, $t1 /* t0 = t0 + t1 == 1*/
+ beq $t0, $t1, entry /* PC = entry if t0 == t1*/
+.end entry