OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [branches/] [mp3_stable/] [or1200/] [rtl/] [verilog/] [id.v] - Rev 170

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  OR1200's Instruction decode                                 ////
////                                                              ////
////  This file is part of the OpenRISC 1200 project              ////
////  http://www.opencores.org/cores/or1k/                        ////
////                                                              ////
////  Description                                                 ////
////  Majority of instruction decoding is performed here.         ////
////                                                              ////
////  To Do:                                                      ////
////   - make it smaller and faster                               ////
////                                                              ////
////  Author(s):                                                  ////
////      - Damjan Lampret, lampret@opencores.org                 ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
//
// CVS Revision History
//
// $Log: not supported by cvs2svn $
// Revision 1.1  2001/08/09 13:39:33  lampret
// Major clean-up.
//
//
 
`include "timescale.v"
`include "defines.v"
 
module id(
	// Clock and reset
	clk, rst,
 
	// Internal i/f
	pipeline_freeze, except_flushpipe, if_insn, branch_op,
	rf_addra, rf_addrb, alu_op, shrot_op, comp_op, rf_addrw, rfwb_op,
	wb_insn, simm, branch_addrofs, lsu_addrofs, sel_a, sel_b, lsu_op,
	multicycle, branch_stall, spr_addrimm, wbforw_valid, sig_syscall
);
 
//
// I/O
//
input					clk;
input					rst;
input					pipeline_freeze;
input					except_flushpipe;
input	[31:0]				if_insn;
output	[`BRANCHOP_WIDTH-1:0]		branch_op;
output	[`REGFILE_ADDR_WIDTH-1:0]	rf_addrw;
output	[`REGFILE_ADDR_WIDTH-1:0]	rf_addra;
output	[`REGFILE_ADDR_WIDTH-1:0]	rf_addrb;
output	[`ALUOP_WIDTH-1:0]		alu_op;
output	[`SHROTOP_WIDTH-1:0]		shrot_op;
output	[`RFWBOP_WIDTH-1:0]		rfwb_op;
output	[31:0]				wb_insn;
output	[31:0]				simm;
output	[31:2]				branch_addrofs;
output	[31:0]				lsu_addrofs;
output	[`SEL_WIDTH-1:0]		sel_a;
output	[`SEL_WIDTH-1:0]		sel_b;
output	[`LSUOP_WIDTH-1:0]		lsu_op;
output	[`COMPOP_WIDTH-1:0]		comp_op;
output	[`MULTICYCLE_WIDTH-1:0]		multicycle;
output					branch_stall;
output	[15:0]				spr_addrimm;
input					wbforw_valid;
output					sig_syscall;
 
//
// Internal wires and regs
//
reg	[`BRANCHOP_WIDTH-1:0]		pre_branch_op;
reg	[`BRANCHOP_WIDTH-1:0]		branch_op;
reg	[`ALUOP_WIDTH-1:0]		alu_op;
reg	[`SHROTOP_WIDTH-1:0]		shrot_op;
reg	[31:0]				id_insn;
reg	[31:0]				ex_insn;
reg	[31:0]				wb_insn;
reg	[`REGFILE_ADDR_WIDTH-1:0]	rf_addrw;
reg	[`REGFILE_ADDR_WIDTH-1:0]	wb_rfaddrw;
reg	[`RFWBOP_WIDTH-1:0]		rfwb_op;
reg	[31:0]				lsu_addrofs;
reg	[`SEL_WIDTH-1:0]		sel_a;
reg	[`SEL_WIDTH-1:0]		sel_b;
reg					sel_imm;
reg	[`LSUOP_WIDTH-1:0]		lsu_op;
reg	[`COMPOP_WIDTH-1:0]		comp_op;
reg	[`MULTICYCLE_WIDTH-1:0]		multicycle;
reg					imm_signextend;
reg	[15:0]				spr_addrimm;
reg					sig_syscall;
wire					rst_or_except_flushpipe;
 
//
// Register file read addresses
//
assign rf_addra = if_insn[20:16];
assign rf_addrb = if_insn[15:11];
 
//
// Sign/Zero extension of immediates
//
assign simm = (imm_signextend == `on) ? {{16{id_insn[15]}}, id_insn[15:0]} : {{16'b0}, id_insn[15:0]};
 
//
// Sign extension of branch offset
//
assign branch_addrofs = {{4{ex_insn[25]}}, ex_insn[25:0]};
 
//
// Assert branch_stall if pre_branch_op is a branch operation
//
assign branch_stall = pre_branch_op ? 1'b1 : 1'b0;
 
//
// Async reset for most of pipeline flops
//
assign rst_or_except_flushpipe = rst | except_flushpipe;
 
//
// Generation of sel_a
//
always @(rf_addrw or wb_insn or id_insn or rfwb_op or wbforw_valid or wb_rfaddrw)
	if ((id_insn[20:16] == rf_addrw) && rfwb_op[0])
		sel_a <= #1 `SEL_EX_FORW;
	else if ((id_insn[20:16] == wb_rfaddrw) && wbforw_valid)
		sel_a <= #1 `SEL_WB_FORW;
	else
		sel_a <= #1 `SEL_RF;
 
//
// Generation of sel_b
//
always @(rf_addrw or wb_insn or sel_imm or id_insn or rfwb_op or wbforw_valid or wb_rfaddrw)
	if (sel_imm)
		sel_b <= #1 `SEL_IMM;
	else if ((id_insn[15:11] == rf_addrw) && rfwb_op[0])
		sel_b <= #1 `SEL_EX_FORW;
	else if ((id_insn[15:11] == wb_rfaddrw) && wbforw_valid)
		sel_b <= #1 `SEL_WB_FORW;
	else
		sel_b <= #1 `SEL_RF;
 
//
// Decode of spr_addrimm
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		spr_addrimm <= #1 16'h0000;
	else if (!pipeline_freeze) begin
		case (id_insn[31:26])	// synopsys full_case parallel_case
			// l.mtspr
			`OR32_MTSPR: 
				spr_addrimm <= #1 id_insn[15:0];
			// l.mfspr
			default:
				spr_addrimm <= #1 {id_insn[25:21], id_insn[10:0]};
		endcase
	end
end
 
//
// Decode of multicycle
//
always @(id_insn) begin
  case (id_insn[31:26])		// synopsys full_case parallel_case
 
    // l.lwz
    `OR32_LWZ:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.lbz
    `OR32_LBZ:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.lbs
    `OR32_LBS:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.lhz
    `OR32_LHZ:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.lhs
    `OR32_LHS:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.sw
    `OR32_SW:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.sb
    `OR32_SB:
      multicycle <= #1 `TWO_CYCLES;
 
    // l.sh
    `OR32_SH:
      multicycle <= #1 `TWO_CYCLES;
 
    // ALU instructions except the one with immediate
    `OR32_ALU:
      multicycle <= #1 id_insn[`ALUMCYC_POS];
 
    // Single cycle instructions
    default: begin
      multicycle <= #1 `ONE_CYCLE;
    end
 
  endcase
 
end
 
//
// Decode of imm_signextend
//
always @(id_insn) begin
  case (id_insn[31:26])		// synopsys full_case parallel_case
 
	// l.addi
	`OR32_ADDI:
		imm_signextend <= #1 `on;
 
	// l.addic
	`OR32_ADDIC:
		imm_signextend <= #1 `on;
 
	// l.xori
	`OR32_XORI:
		imm_signextend <= #1 `on;
 
	// l.muli
	`OR32_MULI:
		imm_signextend <= #1 `on;
 
	// l.maci
	`OR32_MACI:
		imm_signextend <= #1 `on;
 
	// SFXX insns with immediate
	`OR32_SFXXI:
		imm_signextend <= #1 `on;
 
	// Instructions with no or zero extended immediate
	default: begin
		imm_signextend <= #1 `off;
	end
 
endcase
 
end
 
//
// LSU addr offset
//
always @(lsu_op or ex_insn) begin
	lsu_addrofs[10:0] <= #1 ex_insn[10:0];
	case(lsu_op)	// synopsys parallel_case full_case
		`LSUOP_SW, `LSUOP_SH, `LSUOP_SB : 
			lsu_addrofs[31:11] <= #1 {{16{ex_insn[25]}}, ex_insn[25:21]};
		default : 
			lsu_addrofs[31:11] <= #1 {{16{ex_insn[15]}}, ex_insn[15:11]};
	endcase
end
 
//
// Register file write address
//
always @(posedge clk or posedge rst) begin
	if (rst)
		rf_addrw <= #1 5'd0;
	else if (!pipeline_freeze)
		case (pre_branch_op)	// synopsys parallel_case full_case
			`BRANCHOP_JR, `BRANCHOP_BAL:
				rf_addrw <= #1 5'd09;	// link register r9
			default:
				rf_addrw <= #1 id_insn[25:21];
		endcase
end
 
//
// rf_addrw in wb stage (used in forwarding logic)
//
always @(posedge clk or posedge rst) begin
	if (rst)
		wb_rfaddrw <= #1 5'd0;
	else if (!pipeline_freeze)
		wb_rfaddrw <= #1 rf_addrw;
end
 
//
// Instruction latch in id_insn
//
always @(posedge clk or posedge rst) begin
	if (rst) begin
		id_insn[31:26] <= #1 `OR32_NOP;
		id_insn[25:0] <= #1 26'd0;
	end
	else if (!pipeline_freeze) begin
		id_insn <= #1 if_insn;
		$display("%t: id_insn <= %h", $time, if_insn);
	end
end
 
//
// Instruction latch in ex_insn
//
always @(posedge clk or posedge rst) begin
	if (rst) begin
		ex_insn[31:26] <= #1 `OR32_NOP;
		ex_insn[25:0] <= #1 26'd0;
	end
	else if (!pipeline_freeze) begin
		ex_insn <= #1 id_insn;
		$display("%t: ex_insn <= %h", $time, id_insn);
	end
end
 
//
// Instruction latch in wb_insn
//
always @(posedge clk or posedge rst) begin
	if (rst) begin
		wb_insn[31:26] <= #1 `OR32_NOP;
		wb_insn[25:0] <= #1 26'd0;
	end
	else if (!pipeline_freeze) begin
		wb_insn <= #1 ex_insn;
	end
end
 
//
// Decode of sel_imm
//
always @(posedge clk or posedge rst) begin
	if (rst)
		sel_imm <= #1 1'b0;
	else if (!pipeline_freeze) begin
	  case (if_insn[31:26])		// synopsys full_case parallel_case
 
	    // j.jalr
	    `OR32_JALR:
	      sel_imm <= #1 `off;
 
	    // l.jr
	    `OR32_JR:
	      sel_imm <= #1 `off;
 
	    // l.rfe
	    `OR32_RFE:
	      sel_imm <= #1 `off;
 
	    // l.mfspr
	    `OR32_MFSPR:
	      sel_imm <= #1 `off;
 
	    // l.mtspr
	    `OR32_MTSPR:
	      sel_imm <= #1 `off;
 
	    // l.sys, l.brk and all three sync insns
	    `OR32_XSYNC:
	      sel_imm <= #1 `off;
 
	    // l.sw
	    `OR32_SW:
	      sel_imm <= #1 `off;
 
	    // l.sb
	    `OR32_SB:
	      sel_imm <= #1 `off;
 
	    // l.sh
	    `OR32_SH:
	      sel_imm <= #1 `off;
 
	    // ALU instructions except the one with immediate
	    `OR32_ALU:
	      sel_imm <= #1 `off;
 
	    // SFXX instructions
	    `OR32_SFXX:
	      sel_imm <= #1 `off;
 
	    // l.nop
	    `OR32_NOP:
	      sel_imm <= #1 `off;
 
	    // All instructions with immediates
	    default: begin
	      sel_imm <= #1 `on;
	    end
 
	  endcase
 
	end
end
 
 
//
// Decode of alu_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		alu_op <= #1 `ALUOP_NOP;
	else if (!pipeline_freeze) begin
	  case (id_insn[31:26])		// synopsys full_case parallel_case
 
	    // l.j
	    `OR32_J:
	      alu_op <= #1 `ALUOP_IMM;
 
	    // j.jal
	    `OR32_JAL:
	      alu_op <= #1 `ALUOP_IMM;
 
	    // j.jalr
	    `OR32_JALR:
	      alu_op <= #1 `ALUOP_OR;
 
	    // l.jr
	    `OR32_JR:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.bnf
	    `OR32_BNF:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.bf
	    `OR32_BF:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.rfe
	    `OR32_RFE:
	      alu_op <= #1 `ALUOP_NOP;
 
	    // l.movhi
	    `OR32_MOVHI:
	      alu_op <= #1 `ALUOP_MOVHI;
 
	    // l.mfspr
	    `OR32_MFSPR:
	      alu_op <= #1 `ALUOP_MFSR;
 
	    // l.mtspr
	    `OR32_MTSPR:
	      alu_op <= #1 `ALUOP_MTSR;
 
	    // l.sys, l.brk and all three sync insns
	    `OR32_XSYNC:
	      alu_op <= #1 `ALUOP_NOP;
 
	    // l.lwz
	    `OR32_LWZ:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.lbz
	    `OR32_LBZ:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.lbs
	    `OR32_LBS:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.lhz
	    `OR32_LHZ:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.lhs
	    `OR32_LHS:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.addi
	    `OR32_ADDI:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.addic
	    `OR32_ADDIC:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.andi
	    `OR32_ANDI:
	      alu_op <= #1 `ALUOP_AND;
 
	    // l.ori
	    `OR32_ORI:
	      alu_op <= #1 `ALUOP_OR;
 
	    // l.xori
	    `OR32_XORI:
	      alu_op <= #1 `ALUOP_XOR;
 
	    // l.muli
	    `OR32_MULI:
	      alu_op <= #1 `ALUOP_MUL;
 
	    // l.maci
	    `OR32_MACI:
	      alu_op <= #1 `ALUOP_MAC;
 
	    // Shift and rotate insns with immediate
	    `OR32_SH_ROTI:
	      alu_op <= #1 `ALUOP_SHROT;
 
	    // SFXX insns with immediate
	    `OR32_SFXXI:
	      alu_op <= #1 `ALUOP_COMP;
 
	    // l.sw
	    `OR32_SW:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.sb
	    `OR32_SB:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // l.sh
	    `OR32_SH:
	      alu_op <= #1 `ALUOP_ADD;
 
	    // ALU instructions except the one with immediate
	    `OR32_ALU:
	      alu_op <= #1 id_insn[3:0];
 
	    // SFXX instructions
	    `OR32_SFXX:
	      alu_op <= #1 `ALUOP_COMP;
 
	    // l.nop
	    `OR32_NOP:
	      alu_op <= #1 `ALUOP_NOP;
 
	    // Illegal and OR1200 unsupported instructions
	    default: begin
	      alu_op <= #1 `ALUOP_NOP;
	      $display("%t: Illegal insn.... insn %h", $time, id_insn);
	    end
 
	  endcase
 
	end
end
 
//
// Decode of shrot_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		shrot_op <= #1 `SHROTOP_NOP;
	else if (!pipeline_freeze) begin
		shrot_op <= #1 id_insn[`SHROTOP_POS];
	end
end
 
//
// Decode of rfwb_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		rfwb_op <= #1 `RFWBOP_NOP;
	else  if (!pipeline_freeze) begin
		case (id_insn[31:26])		// synopsys full_case parallel_case
 
		  // j.jal
		  `OR32_JAL:
		    rfwb_op <= #1 `RFWBOP_LR;
 
		  // j.jalr
		  `OR32_JALR:
		    rfwb_op <= #1 `RFWBOP_LR;
 
		  // l.movhi
		  `OR32_MOVHI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.mfspr
		  `OR32_MFSPR:
		    rfwb_op <= #1 `RFWBOP_SPRS;
 
		  // l.lwz
		  `OR32_LWZ:
		    rfwb_op <= #1 `RFWBOP_LSU;
 
		  // l.lbz
		  `OR32_LBZ:
		    rfwb_op <= #1 `RFWBOP_LSU;
 
		  // l.lbs
		  `OR32_LBS:
		    rfwb_op <= #1 `RFWBOP_LSU;
 
		  // l.lhz
		  `OR32_LHZ:
		    rfwb_op <= #1 `RFWBOP_LSU;
 
		  // l.lhs
		  `OR32_LHS:
		    rfwb_op <= #1 `RFWBOP_LSU;
 
		  // l.addi
		  `OR32_ADDI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.addic
		  `OR32_ADDIC:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.andi
		  `OR32_ANDI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.ori
		  `OR32_ORI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.xori
		  `OR32_XORI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.muli
		  `OR32_MULI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // l.maci
		  `OR32_MACI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // Shift and rotate insns with immediate
		  `OR32_SH_ROTI:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // ALU instructions except the one with immediate
		  `OR32_ALU:
		    rfwb_op <= #1 `RFWBOP_ALU;
 
		  // Instructions w/o register-file write-back
		  default: begin
		    rfwb_op <= #1 `RFWBOP_NOP;
		  end
 
		endcase
	end
end
 
//
// Decode of pre_branch_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		pre_branch_op <= #1 `BRANCHOP_NOP;
	else if (!pipeline_freeze) begin
		case (if_insn[31:26])		// synopsys full_case parallel_case
 
		  // l.j
		  `OR32_J:
		    pre_branch_op <= #1 `BRANCHOP_BAL;
 
		  // j.jal
		  `OR32_JAL:
		    pre_branch_op <= #1 `BRANCHOP_BAL;
 
		  // j.jalr
		  `OR32_JALR:
		    pre_branch_op <= #1 `BRANCHOP_JR;
 
		  // l.jr
		  `OR32_JR:
		    pre_branch_op <= #1 `BRANCHOP_JR;
 
		  // l.bnf
		  `OR32_BNF:
		    pre_branch_op <= #1 `BRANCHOP_BNF;
 
		  // l.bf
		  `OR32_BF:
		    pre_branch_op <= #1 `BRANCHOP_BF;
 
		  // l.rfe
		  `OR32_RFE:
		    pre_branch_op <= #1 `BRANCHOP_RFE;
 
		  // Non branch instructions
		  default: begin
		    pre_branch_op <= #1 `BRANCHOP_NOP;
		  end
		endcase
	end
end
 
//
// Generation of branch_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		branch_op <= #1 `BRANCHOP_NOP;
	else if (!pipeline_freeze) begin
		branch_op <= #1 pre_branch_op;
	end
end
 
//
// Decode of lsu_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		lsu_op <= #1 `LSUOP_NOP;
	else if (!pipeline_freeze)  begin
	  case (id_insn[31:26])		// synopsys full_case parallel_case
 
	    // l.lwz
	    `OR32_LWZ:
	      lsu_op <= #1 `LSUOP_LWZ;
 
	    // l.lbz
	    `OR32_LBZ:
	      lsu_op <= #1 `LSUOP_LBZ;
 
	    // l.lbs
	    `OR32_LBS:
	      lsu_op <= #1 `LSUOP_LBS;
 
	    // l.lhz
	    `OR32_LHZ:
	      lsu_op <= #1 `LSUOP_LHZ;
 
	    // l.lhs
	    `OR32_LHS:
	      lsu_op <= #1 `LSUOP_LHS;
 
	    // l.sw
	    `OR32_SW:
	      lsu_op <= #1 `LSUOP_SW;
 
	    // l.sb
	    `OR32_SB:
	      lsu_op <= #1 `LSUOP_SB;
 
	    // l.sh
	    `OR32_SH:
	      lsu_op <= #1 `LSUOP_SH;
 
	    // Non load/store instructions
	    default: begin
	      lsu_op <= #1 `LSUOP_NOP;
	    end
	  endcase
	end
end
 
//
// Decode of comp_op
//
always @(posedge clk or posedge rst_or_except_flushpipe) begin
	if (rst_or_except_flushpipe)
		comp_op <= #1 4'd0;
	else if (!pipeline_freeze) begin
		comp_op <= #1 id_insn[24:21];
	end
end
 
//
// Decode of l.sys
//
always @(posedge clk or posedge rst) begin
	if (rst)
		sig_syscall <= #1 1'b0;
	else if (!pipeline_freeze) begin
// synopsys translate_off
		if (wb_insn[31:24] == {`OR32_XSYNC, 2'b00})
			$display("Generating sig_syscall");
// synopsys translate_on
//		sig_syscall <= #1 (wb_insn[31:24] == {`OR32_XSYNC, 2'b00});
	end
end
 
endmodule
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.