URL
https://opencores.org/ocsvn/openarty/openarty/trunk
Subversion Repositories openarty
[/] [openarty/] [trunk/] [rtl/] [cpu/] [ifastdec.v] - Rev 3
Compare with Previous | Blame | View Log
/////////////////////////////////////////////////////////////////////////////// // // Filename: ifastdec.v // // Project: Zip CPU -- a small, lightweight, RISC CPU soft core // // Purpose: This RTL file specifies how instructions are to be decoded // into their underlying meanings. It is different from the // standard idecode.v file in that this one takes two clocks, and is // pipelined. This one is designed for a 5ns clock cycle, hence it is // a "fast" decoder--even though the old decoder took one cycle in 10ns. // From that standpoint, the two may well be ... comparable in speed. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // /////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2016, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // /////////////////////////////////////////////////////////////////////////////// // // // `define CPU_CC_REG 4'he `define CPU_PC_REG 4'hf // `include "cpudefs.v" // // // module ifastdec(i_clk, i_rst, i_ce, i_stalled, i_instruction, i_gie, i_pc, i_pf_valid, i_illegal, o_phase, o_illegal, o_pc, o_gie, o_R, o_A, o_B, o_I, o_zI, o_cond, o_wF, o_op, o_ALU, o_M, o_DV, o_FP, o_break, o_lock, o_wR, o_rA, o_rB, o_early_branch, o_branch_pc, o_ljmp, o_pipe ); parameter ADDRESS_WIDTH=24, IMPLEMENT_MPY=1, EARLY_BRANCHING=1, IMPLEMENT_DIVIDE=1, IMPLEMENT_FPU=0, AW = ADDRESS_WIDTH; input i_clk, i_rst, i_ce, i_stalled; input [31:0] i_instruction; input i_gie; input [(AW-1):0] i_pc; input i_pf_valid, i_illegal; output reg o_phase; output reg o_illegal; output reg [(AW-1):0] o_pc; output reg o_gie; output reg [6:0] o_R, o_A, o_B; output reg [31:0] o_I; output reg o_zI; output reg [3:0] o_cond; output reg o_wF; output reg [3:0] o_op; output reg o_ALU, o_M, o_DV, o_FP, o_break; output reg o_lock; output reg o_wR, o_rA, o_rB; output reg o_early_branch; output reg [(AW-1):0] o_branch_pc; output reg o_ljmp; output reg o_pipe; ////// // // Path 1: Full size instruction // // Prefix: wf (wire, full) // ////// // The 5-bit opcode, as extracted wire [4:0] wf_op; // Instruction types wire wf_ldi, wf_mov, wf_cmptst, wf_ldilo, wf_brev, wf_noop, wf_break, wf_lock, wf_ljmp, wf_ALU, wf_MEM, wf_DIV, wf_FPU; wire [4:0] wf_R, wf_A, wf_B; // Instruction registers wire [3:0] wf_cond; wire wf_wF; // Write flags? wire wf_wR_n, // Write destination register? or not? wf_rA, // Read register A? wf_rB; // Read register B? wire [22:0] wf_pI; // Partial immediate ... wire wf_Iz; assign wf_op = i_instruction[26:22]; assign wf_brev = (wf_op == 5'hc); assign wf_mov = (wf_op == 5'h0f); assign wf_ldi = (wf_op[4:1] == 4'hb); assign wf_cmptst=(wf_op[4:1] == 4'h8); assign wf_ldilo= (wf_op[4:0] == 5'h9); assign wf_noop = (wf_op[4:0] == 5'h18)&&(wf_R[3:1] == 3'h7); assign wf_break= (wf_op[4:0] == 5'h19)&&(wf_R[3:1] == 3'h7); assign wf_lock = (wf_op[4:0] == 5'h1a)&&(wf_R[3:1] == 3'h7); // assign wf_R = { (wf_mov)&&(i_gie)?i_instruction[18]:i_gie, (i_instruction[30:27]) }; assign wf_A = { (wf_mov)&&(i_gie)?i_instruction[18]:i_gie, (i_instruction[30:27]) }; assign wf_B = { (wf_mov)&&(i_gie)?i_instruction[13]:i_gie, (i_instruction[17:14]) }; // assign wf_ALU = (~wf_op[4]); assign wf_MEM = ( wf_op[4:1] == 4'h9); assign wf_DIV = ( wf_op[4:1] == 4'ha); assign wf_FPU = ( wf_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7); assign wf_ljmp = (i_instruction == 32'h7c87c000); assign wf_pI = (wf_ldi) ? { i_instruction[22:0] } // LDI :((wf_mov) ?{ {(23-13){i_instruction[12]}}, i_instruction[12:0] } // Move :((~i_instruction[18]) ? { {(23-18){i_instruction[17]}}, i_instruction[17:0] } : { {(23-14){i_instruction[13]}}, i_instruction[13:0] } )); assign wf_Iz= (wf_pI == 23'h00); // Will we be writing register R? assign wf_wR_n = ((wf_MEM)&&(wf_op[0])) // Store's dont write regs // Neither do NOOP, BREAK, or LOCKs ||((wf_op[4:3]==2'b11)&&(wf_R[3:1]==3'h7)) // nor CMPs and TSTs ||(wf_cmptst); // Do we read register 'A'? assign wf_rA = (wf_FPU)&&(wf_op[4:1]!=4'he) // FPU, but not CVT or INT ||(wf_DIV) ||(wf_ALU)&&(~wf_mov) ||(wf_MEM)&&(wf_op[0]) ||(wf_cmptst); // Do we need to read register 'B'? assign wf_rB = (wf_mov)||((i_instruction[18])&&(~wf_ldi)); // What are the conditions for this instruction? NOOP, BREAK, and LOCK // are also unconditional, but they'll just ignore this setting assign wf_cond = (wf_ldi) ? 4'h8 // LDI is unconditional : { (i_instruction[21:19]==3'h0), i_instruction[21:19] }; // How about the flags, will we be writing them? assign wf_wF = (wf_cmptst) // Compares always write flags ||((wf_cond[3])&&( // FPU and DIV instructions always write flags (wf_FPU)||(wf_DIV) // So do ALU instructions, UNLESS the ALU // instruction is a MOV, LDILO, or BREV, or // the results are being written into the PC // or CC register--those don't set flags ||((wf_ALU)&&(~wf_mov)&&(~wf_ldilo)&&(~wf_brev) &&(i_instruction[30:28] != 3'h7)))); reg [3:0] rf_op; reg rf_break, rf_lock; reg [4:0] rf_R, rf_A, rf_B; reg rf_ALU, rf_MEM, rf_DIV, rf_FPU, rf_ljmp; reg [3:0] rf_cond; reg rf_rA, rf_rB, rf_wR, rf_wF; reg [22:0] rf_pI; reg rf_Iz; wire [31:0] wf_I; assign wf_I = { {(32-22){rf_pI[22]}}, rf_pI[21:0] }; reg rf_early_branch; reg [(AW-1):0] rf_branch_pc; always @(posedge i_clk) if (i_ce) begin rf_op <= wf_op[3:0]; rf_break<= wf_break; rf_lock <= wf_lock; // rf_R <= (wf_R); rf_A <= (wf_A); rf_B <= (wf_B); // rf_ALU <= (~wf_op[4]); rf_MEM <= ( wf_op[4:1] == 4'h9); rf_DIV <= ( wf_op[4:1] == 4'ha); rf_FPU <= ( wf_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7); rf_ljmp <= (i_instruction == 32'h7c87c000); rf_pI <= wf_pI; rf_Iz<= wf_Iz; // What are the conditions of this instruction? rf_cond <= wf_cond; // Do we read register 'A'? rf_rA <= wf_rA; // Do we need to read register 'B'? rf_rB <= wf_rB; // Will we be writing register 'R'? rf_wR <= ~wf_wR_n; // How about the flags, will we be writing those? rf_wF <= wf_wF; // rf_early_branch <= // PC is the result (wf_R[3:0]==4'hf) // Unconditional instruction &&(i_instruction[21:19]==3'h0) && // Either an ADD #x,PC ((wf_op == 5'h02)&&(~i_instruction[18]) // Or a LOD #x,PC ||(wf_ldi)); rf_branch_pc <= (wf_ldi)?{{(AW-22){wf_pI[22]}},wf_pI[21:0]} :(i_pc + {{(AW-18){i_instruction[17]}}, i_instruction[16:0]}); end ////// // // Path 2: Half size instruction, high half // // Prefix: wh (wire, high-half) // ////// // The 5-bit opcode, as extracted -- same as wf_ // Instruction types -- same as wf_ wire [4:0] wh_R, wh_A, wh_B; // Instruction registers wire [3:0] wh_cond; wire wh_wF; // Write flags? wire wh_wR, wh_wR_n, // Write destination register? or not? wh_rA, // Read register A? wh_rB; // Read register B? wire [4:0] wh_pI; // Partial immediate ... wire wh_Iz; assign wh_R = { i_gie, (i_instruction[30:27]) }; assign wh_A = { i_gie, (i_instruction[30:27]) }; assign wh_B = { i_gie, (i_instruction[17:14]) }; // assign wh_pI = (wf_ldi) ? { i_instruction[18:14] } // LDI :((~i_instruction[18]) ? { i_instruction[17], i_instruction[17:14] } : 5'h0); assign wh_Iz= (wh_pI == 5'h0); // Will we be writing register R? assign wh_wR_n = ((wf_MEM)&&(wf_op[0])) // Store's dont write regs // Neither do NOOP, BREAK, or LOCKs ||((wf_op[4:3]==2'b11)&&(wh_R[3:1]==3'h7)) // nor CMPs and TSTs ||(wf_cmptst); assign wh_cond = (wf_ldi) ? 4'h8 // LDI is unconditional : { (i_instruction[20:19]==2'h0), 1'b0, i_instruction[20:19] }; // How about the flags, will we be writing them? assign wh_wF = (wf_cmptst) // Compares always write flags ||((wh_cond[3])&&( // FPU and DIV instructions always write flags (wf_FPU)||(wf_DIV) // So do ALU instructions, UNLESS the ALU // instruction is a MOV, LDILO, or BREV, or // the results are being written into the PC // or CC register--those don't set flags ||((wf_ALU)&&(~wf_mov)&&(~wf_ldilo)&&(~wf_brev) &&(i_instruction[30:28] != 3'h7)))); reg [3:0] rh_op; reg rh_break, rh_lock; reg [4:0] rh_R, rh_A, rh_B; reg rh_ALU, rh_MEM, rh_DIV, rh_FPU; reg [3:0] rh_cond; reg rh_rA, rh_rB, rh_wR, rh_wF; wire [31:0] wh_I; reg [4:0] rh_pI; reg rh_Iz; assign wh_I = { {(32-4){rh_pI[4]}}, rh_pI[3:0] }; always @(posedge i_clk) if (i_ce) begin rh_op <= wf_op[3:0]; rh_break<= wf_break; rh_lock <= wf_lock; // rh_R <= (wh_R); rh_A <= (wh_A); rh_B <= (wh_B); // rh_ALU <= wf_ALU; rh_MEM <= wf_MEM; rh_DIV <= wf_DIV; rh_FPU <= wf_FPU; rh_pI <= wh_pI; rh_Iz <= wh_Iz; // What are the conditions of this instruction? rh_cond <= wh_cond; // Do we read register 'A'? rh_rA <= (wf_FPU)&&(wf_op[4:1]!=4'he) ||(wf_DIV) ||(wf_ALU)&&(~wf_mov) ||(wf_MEM)&&(wf_op[0]) ||(wf_cmptst); // Do we need to read register 'B'? rh_rB <= (i_instruction[18])&&(~wf_ldi); // Will we be writing register 'R'? rh_wR <= ~wh_wR_n; rh_wF <= wh_wF; end ////// // // Path 3: Half size instruction, low half // ////// // The 5-bit opcode, as extracted wire [4:0] wl_op; // Instruction types wire wl_ldi, wl_mov, wl_cmptst, wl_ldilo, wl_brev, wl_noop, wl_break, wl_lock, wl_ljmp, wl_ALU, wl_MEM, wl_DIV, wl_FPU; wire [4:0] wl_R, wl_A, wl_B; // Instruction registers wire [3:0] wl_cond; wire wl_wF; // Write flags? wire wl_wR, wl_wR_n, // Write destination register? or not? wl_rA, // Read register A? wl_rB; // Read register B? wire [4:0] wl_pI; // Partial immediate ... wire wl_Iz; assign wl_op = i_instruction[9:5]; assign wl_brev = (wl_op == 5'hc); assign wl_mov = (wl_op == 5'h0f); assign wl_ldi = (wl_op[4:1] == 4'hb); assign wl_cmptst=(wl_op[4:1] == 4'h8); assign wl_ldilo= (wl_op[4:0] == 5'h9); assign wl_noop = (wl_op[4:0] == 5'h18)&&(wl_R[3:1] == 3'h7); assign wl_break= (wl_op[4:0] == 5'h19)&&(wl_R[3:1] == 3'h7); assign wl_lock = (wl_op[4:0] == 5'h1a)&&(wl_R[3:1] == 3'h7); // assign wl_R = { i_gie, i_instruction[13:10] }; assign wl_A = { i_gie, i_instruction[13:10] }; assign wl_B = { i_gie, i_instruction[ 3: 0] }; // assign wl_ALU = (~wl_op[4]); assign wl_MEM = ( wl_op[4:1] == 4'h9); assign wl_DIV = ( wl_op[4:1] == 4'ha); assign wl_FPU = ( wl_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7); assign wl_ljmp = ( i_instruction[21:19] == 3'h00) // 1111_10010_1_1111 &&(i_instruction[13:0]==14'h3e5f); assign wl_pI = (wl_ldi) ? { i_instruction[4:0] } // LDI :((~i_instruction[4]) ? { i_instruction[3], i_instruction[3:0] } : 5'h0); assign wl_Iz= (wl_pI == 5'h0); // Will we be writing register R? assign wl_wR_n = ((wl_MEM)&&(wl_op[0])) // Store's dont write regs // Neither do NOOP, BREAK, or LOCKs ||((wl_op[4:3]==2'b11)&&(wl_R[3:1]==3'h7)) // nor CMPs and TSTs ||(wl_cmptst); // What are the conditions for this instruction? NOOP, BREAK, and LOCK // are also unconditional, but they'll just ignore this setting assign wl_cond = (wl_ldi) ? 4'h8 // LDI is unconditional : { (i_instruction[20:19]==2'h0), 1'b0, i_instruction[20:19] }; // How about the flags, will we be writing them? assign wl_wF = (wl_cmptst) // Compares always write flags ||((wl_cond[3])&&( // FPU and DIV instructions always write flags (wl_FPU)||(wl_DIV) // So do ALU instructions, UNLESS the ALU // instruction is a MOV, LDILO, or BREV, or // the results are being written into the PC // or CC register--those don't set flags ||((wl_ALU)&&(~wl_mov)&&(~wl_ldilo)&&(~wl_brev) &&(i_instruction[13:11] != 3'h7)))); reg [3:0] rl_op; reg rl_break, rl_lock; reg [4:0] rl_R, rl_A, rl_B; reg rl_ALU, rl_MEM, rl_DIV, rl_FPU, rl_ljmp; reg [3:0] rl_cond; reg rl_rA, rl_rB, rl_wR, rl_wF; wire [31:0] wl_I; reg [4:0] rl_pI; reg rl_Iz; assign wl_I = { {(32-4){rl_pI[4]}}, rl_pI[3:0] }; always @(posedge i_clk) if (i_ce) begin rl_op <= wl_op[3:0]; rl_break<= wl_break; rl_lock <= wl_lock; // rl_R <= (wl_R); rl_A <= (wl_A); rl_B <= (wl_B); // rl_ALU <= (~wl_op[4]); rl_MEM <= ( wl_op[4:1] == 4'h9); rl_DIV <= ( wl_op[4:1] == 4'ha); rl_FPU <= ( wl_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7); rl_ljmp <= wl_ljmp; rl_pI <= wl_pI; rl_Iz<= wl_Iz; // What are the conditions of this instruction? rl_cond <= wl_cond; // Do we read register 'A'? rl_rA <= (wl_FPU)&&(wl_op[4:1]!=4'he) ||(wl_DIV) ||(wl_ALU)&&(~wf_mov) ||(wl_MEM)&&(wl_op[0]) ||(wl_cmptst); // Do we need to read register 'B'? rl_rB <= (i_instruction[18])&&(~wl_ldi); // Will we be writing register 'R'? rl_wR <= ~wl_wR_n; // How about the flags? rl_wF <= wl_wF; end ////// // // Path 4: triplet instruction: MOV A,B; OP C,B // becomes OP C,A -> B // ////// wire w_triplet; reg r_triplet; assign w_triplet = // Must be a VLIW instruction (i_instruction[31]) // First half must be a move &&(i_instruction[26:22] == 5'h0f) // Move destination must also be register A in 2nd Op &&(i_instruction[30:27]==i_instruction[13:10]) // Only if this is unconditional, or share conditions &&((i_instruction[21])|(i_instruction[20:19]==2'h0)) // Not if the destination is PC or CC regs &&(i_instruction[30:28]!=3'h7); always @(posedge i_clk) if (i_ce) r_triplet <= w_triplet; // Now, let's string our instruction(s) together to create a useful // decoded instruction reg r_singlet, r_gie; reg [(AW-1):0] r_pc; always @(posedge i_clk) if (i_ce) begin r_gie <= i_gie; o_gie<= r_gie; r_singlet <= ~i_instruction[31]; r_pc <= i_pc; if (r_triplet) begin o_phase <= 1'b0; o_pc <= r_pc + {{(AW-1){1'b0}}, 1'b1}; o_lock <= 1'b0; o_break <= 1'b0; o_R<={(rl_R=={r_gie, 4'he }),(rl_R=={r_gie,4'hf}),rl_R}; o_A<={(rh_B=={r_gie, 4'he }),(rh_B=={r_gie,4'hf}),rh_B}; o_B<={(rl_B=={r_gie, 4'he }),(rl_B=={r_gie,4'hf}),rl_B}; o_wR <= rl_wR; o_rA <= 1'b1; o_rB <= rl_rB; o_cond<= rh_cond; o_wF <= rl_wF; o_I <= wl_I; o_zI <= rl_Iz; o_op <= rl_op; o_ALU<= rl_ALU; o_M<= rl_MEM; o_DV<= rl_DIV; o_FP <= rl_FPU; o_ljmp <= 1'b0; o_early_branch <= 1'b0; o_branch_pc <= 0; // o_pipe will never be true for a triplet end else if (r_singlet) begin o_phase <= 1'b0; o_pc <= r_pc + {{(AW-1){1'b0}}, 1'b1}; o_R<={(rf_R=={r_gie, 4'he }),(rf_R=={r_gie,4'hf}),rf_R}; o_A<={(rf_A=={r_gie, 4'he }),(rf_A=={r_gie,4'hf}),rf_A}; o_B<={(rf_B=={r_gie, 4'he }),(rf_B=={r_gie,4'hf}),rf_B}; o_break <= rf_break; o_lock <= rf_lock; o_wR <= rf_wR; o_rA <= rf_rA; o_rB <= rf_rB; o_cond<= rf_cond; o_wF <= rf_wF; o_I <= wf_I; o_zI <= rf_Iz; o_op <= rf_op; o_ALU<= rf_ALU; o_M<= rf_MEM; o_DV<= rf_DIV; o_FP <= rf_FPU; o_ljmp <= rf_ljmp; o_early_branch <= (rf_ljmp); o_branch_pc <= i_instruction[(AW-1):0]; end else if (~o_phase) begin o_phase <= 1'b1; o_pc <= r_pc; o_R<={(rh_R=={r_gie, 4'he }),(rh_R=={r_gie,4'hf}),rh_R}; o_A<={(rh_A=={r_gie, 4'he }),(rh_A=={r_gie,4'hf}),rh_A}; o_B<={(rh_B=={r_gie, 4'he }),(rh_B=={r_gie,4'hf}),rh_B}; o_lock <= rh_lock; o_break <= rh_break; o_wR <= rh_wR; o_rA <= rh_rA; o_rB <= rh_rB; o_cond<= rh_cond; o_wF <= rh_wF; o_I <= wh_I; o_zI <= rh_Iz; o_op <= rh_op; o_ALU<= rh_ALU; o_M<= rh_MEM; o_DV<= rh_DIV; o_FP <= rh_FPU; o_ljmp <= 1'b0; // Can't jump from high-half o_early_branch <= 1'b0; // o_branch_pc <= i_instruction; end else begin o_phase <= 1'b0; o_pc <= r_pc + {{(AW-1){1'b0}}, 1'b1}; o_lock <= rl_lock; o_break <= rl_break; o_R<={(rl_R=={r_gie, 4'he }),(rl_R=={r_gie,4'hf}),rl_R}; o_A<={(rl_A=={r_gie, 4'he }),(rl_A=={r_gie,4'hf}),rl_A}; o_B<={(rl_B=={r_gie, 4'he }),(rl_B=={r_gie,4'hf}),rl_B}; o_wR <= rl_wR; o_rA <= rl_rA; o_rB <= rl_rB; o_cond<= rl_cond; o_wF <= rl_wF; o_I <= wl_I; o_zI <= rl_Iz; o_op <= rl_op; o_ALU<= rl_ALU; o_M<= rl_MEM; o_DV<= rl_DIV; o_FP <= rl_FPU; o_ljmp <= rl_ljmp; o_early_branch <= 1'b0; o_branch_pc <= i_instruction[(AW-1):0]; end o_illegal <= 1'b0; end /* always @(posedge i_clk) begin pipe_M <= { o_M, o_op[0] }; pipe_I <= o_I; pipe_pI <= o_I+1; pipe_B <= o_B[3:0]; pipe_rB<= o_rB; pipe_AB <= ({ o_A[6:5], o_B[6:5] } == 4'h00) // 12 inputs &&(o_A[3:0] != o_B[3:0]); pipe_gie<= o_gie; // 36 bits (18*2) match_sI <= (pipe_I == o_I); // 36 bits match_pI <= (pipe_pI == o_I); // 9 bits match_regs <= (pipe_M[1])&&(pipe_M == { o_M, o_op[0] }) &&((~pipe_rB)||(pipe_B == o_B[3:0])); // 9 inputs match_cnd <= ((pipe_cnd == o_cond)||(o_cond[3])); // 5 inputs match_aux <= (pipe_gie == o_gie)&&(pipeAB)&&(pipe_rB==o_rB) o_pipe <= ((match_sI)||(match_pI))&&(match_regs)&&(match_cnd) &&(match_aux)&&(pipe_AB); end */ /* always @(posedge i_clk) if (i_rst) r_valid <= 1'b0; else if ((i_ce)&&(o_ljmp)) r_valid <= 1'b0; else if ((i_ce)&&(i_pf_valid)) r_valid <= 1'b1; else if (~i_stalled) r_valid <= 1'b0; */ endmodule