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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [bench/] [formal/] [f_idecode.v] - Rev 209

Compare with Previous | Blame | View Log

////////////////////////////////////////////////////////////////////////////////
//
// Filename:	f_idecode.v
//
// Project:	Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:	This RTL file is meant to shadow the idecode.v file, but yet
//		to require no clocks for decoding at all.  The purpose is to
//	help to verify instructions as they go through the ZipCPU pipeline,
//	and so to know what instructions are supposed to do what when.
//
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018-2019, 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.
//
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype	none
//
`define	CPU_SP_REG	4'hd
`define	CPU_CC_REG	4'he
`define	CPU_PC_REG	4'hf
//
`define	CISBIT		31
`define	CISIMMSEL	23
`define	IMMSEL		18
//
//
//
module	f_idecode(i_instruction, i_phase, i_gie,
		o_illegal,
		o_dcdR, o_dcdA, o_dcdB, o_I, 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_prepipe, o_sim, o_sim_immv
		);
	parameter		ADDRESS_WIDTH=24;
	parameter	[0:0]	OPT_MPY    = 1'b1;
	parameter	[0:0]	OPT_EARLY_BRANCHING = 1'b1;
	parameter	[0:0]	OPT_DIVIDE = 1'b1;
	parameter	[0:0]	OPT_FPU    = 1'b0;
	parameter	[0:0]	OPT_CIS    = 1'b1;
	parameter	[0:0]	OPT_LOCK   = 1'b1;
	parameter	[0:0]	OPT_OPIPE  = 1'b1;
	parameter	[0:0]	OPT_SIM    = 1'b0;
	localparam		AW = ADDRESS_WIDTH;
	//
	input	wire [31:0]	i_instruction;
	input	wire		i_phase, i_gie;
	output	reg		o_illegal;
	output	wire	[6:0]	o_dcdR, o_dcdA, o_dcdB;
	output	wire	[31:0]	o_I;
	output	wire	[3:0]	o_cond;
	output	wire		o_wF;
	output	wire	[3:0]	o_op;
	output	wire		o_ALU, o_M, o_DV, o_FP, o_break;
	output	wire		o_lock;
	output	wire		o_wR, o_rA, o_rB;
	output	wire		o_prepipe;
	output	wire		o_sim;
	output	wire	[22:0]	o_sim_immv;
 
 
	wire	[4:0]	w_op;
	wire		w_ldi, w_mov, w_cmptst, w_ldilo, w_ALU, w_brev,
			w_noop, w_lock, w_sim, w_break, w_special, w_add,
			w_mpy;
	wire	[4:0]	w_dcdR, w_dcdB, w_dcdA;
	wire		w_dcdR_pc, w_dcdR_cc;
	wire		w_dcdA_pc, w_dcdA_cc;
	wire		w_dcdB_pc, w_dcdB_cc;
	wire	[3:0]	w_cond;
	wire		w_wF, w_mem, w_sto, w_div, w_fpu;
	wire		w_wR, w_rA, w_rB, w_wR_n;
	wire		w_ljmp, w_ljmp_dly, w_cis_ljmp;
	wire	[31:0]	iword;
	wire		pf_valid;
 
 
	reg	[15:0]	r_nxt_half;
 
	generate if (OPT_CIS)
	begin : SET_IWORD
 
		assign	iword = ((!i_instruction[`CISBIT])||(i_phase))
			? i_instruction
			: { 1'b1, i_instruction[14:0], i_instruction[15:0] };
 
	end else begin : CLR_IWORD
 
		assign	iword = { 1'b0, i_instruction[30:0] };
 
	end endgenerate
 
	generate
	if (OPT_EARLY_BRANCHING)
	begin
		if (OPT_CIS)
		begin : CIS_EARLY_BRANCHING
 
			assign	w_cis_ljmp = (iword[31:16] == 16'hfcf8);
 
		end else begin : NOCIS_EARLY_BRANCH
 
			assign	w_cis_ljmp = 1'b0;
 
		end
 
		assign	w_ljmp = (iword == 32'h7c87c000);
 
	end else begin : NO_EARLY_BRANCHING
 
		assign	w_cis_ljmp = 1'b0;
		assign	w_ljmp = 1'b0;
	end endgenerate
 
	reg	[4:0]	w_cis_op;
 
	generate if (OPT_CIS)
	begin : GEN_CIS_OP
 
		always @(*)
		if (!iword[`CISBIT])
			w_cis_op = iword[26:22];
		else case(iword[26:24])
		3'h0: w_cis_op = 5'h00;
		3'h1: w_cis_op = 5'h01;
		3'h2: w_cis_op = 5'h02;
		3'h3: w_cis_op = 5'h10;
		3'h4: w_cis_op = 5'h12;
		3'h5: w_cis_op = 5'h13;
		3'h6: w_cis_op = 5'h18;
		3'h7: w_cis_op = 5'h0d;
		endcase
 
	end else begin : GEN_NOCIS_OP
 
		always @(*)
			w_cis_op = w_op;
 
	end endgenerate
 
	// Decode instructions
	assign	w_op= iword[26:22];
	assign	w_mov    = (w_cis_op      == 5'h0d);
	assign	w_ldi    = (w_cis_op[4:1] == 4'hc);
	assign	w_brev   = (w_cis_op      == 5'h08);
	assign	w_mpy    = (w_cis_op[4:1] == 4'h5)||(w_cis_op[4:0]==5'h0c);
	assign	w_cmptst = (w_cis_op[4:1] == 4'h8);
	assign	w_ldilo  = (w_cis_op[4:0] == 5'h09);
	assign	w_ALU    = (!w_cis_op[4]) // anything with [4]==0, but ...
				&&(w_cis_op[3:1] != 3'h7); // not the divide
	assign	w_add    = (w_cis_op[4:0] == 5'h02);
	assign	w_mem    = (w_cis_op[4:3] == 2'b10)&&(w_cis_op[2:1] !=2'b00);
	assign	w_sto    = (w_mem)&&( w_cis_op[0]);
	assign	w_div    = (!iword[`CISBIT])&&(w_op[4:1] == 4'h7);
	assign	w_fpu    = (!iword[`CISBIT])&&(w_op[4:3] == 2'b11)
				&&(w_dcdR[3:1] != 3'h7)&&(w_op[2:1] != 2'b00);
	// If the result register is either CC or PC, and this would otherwise
	// be a floating point instruction with floating point opcode of 0,
	// then this is a NOOP.
	assign	w_special= (!iword[`CISBIT])&&((!OPT_FPU)||(w_dcdR[3:1]==3'h7))
			&&(w_op[4:2] == 3'b111);
	assign	w_break = (w_special)&&(w_op[4:0]==5'h1c);
	assign	w_lock  = (w_special)&&(w_op[4:0]==5'h1d);
	assign	w_sim   = (w_special)&&(w_op[4:0]==5'h1e);
	assign	w_noop  = (w_special)&&(w_op[4:0]==5'h1f);
 
 
	// w_dcdR (4 LUTs)
	//
	// What register will we be placing results into (if at all)?
	//
	// Two parts to the result register: the register set, given for
	// moves in iword[18] but only for the supervisor, and the other
	// four bits encoded in the instruction.
	//
	assign	w_dcdR = { ((!iword[`CISBIT])&&(w_mov)&&(!i_gie))?iword[`IMMSEL]:i_gie,
				iword[30:27] };
 
	// dcdB - What register is used in the opB?
	//
	assign w_dcdB[4] = ((!iword[`CISBIT])&&(w_mov)&&(!i_gie))?iword[13]:i_gie;
	assign w_dcdB[3:0]= (iword[`CISBIT])
				? (((!iword[`CISIMMSEL])&&(iword[26:25]==2'b10))
					? `CPU_SP_REG : iword[22:19])
				: iword[17:14];
 
	// 0 LUTs
	assign	w_dcdA = w_dcdR;	// on ZipCPU, A is always result reg
	// 2 LUTs, 1 delay each
	assign	w_dcdR_pc = (w_dcdR == {i_gie, `CPU_PC_REG});
	assign	w_dcdR_cc = (w_dcdR == {i_gie, `CPU_CC_REG});
	// 0 LUTs
	assign	w_dcdA_pc = w_dcdR_pc;
	assign	w_dcdA_cc = w_dcdR_cc;
	// 2 LUTs, 1 delays each
	assign	w_dcdB_pc = (w_rB)&&(w_dcdB[3:0] == `CPU_PC_REG);
	assign	w_dcdB_cc = (w_rB)&&(w_dcdB[3:0] == `CPU_CC_REG);
 
	//
	// Under what condition will we execute this instruction?  Only the
	// load immediate instruction and the CIS instructions are completely
	// unconditional.  Well ... not quite.  The BREAK, LOCK, and SIM/NOOP
	// instructions are also unconditional.
	//
	assign	w_cond = ((w_ldi)||(w_special)||(iword[`CISBIT])) ? 4'h8 :
			{ (iword[21:19]==3'h0), iword[21:19] };
 
	// rA - do we need to read register A?
	assign	w_rA = // Floating point reads reg A
			((w_fpu)&&(OPT_FPU))
			// Divide's read A
			||(w_div)
			// ALU ops read A,
			//	except for MOV's and BREV's which don't
			||((w_ALU)&&(!w_brev)&&(!w_mov))
			// STO's read A
			||(w_sto)
			// Test/compares
			||(w_cmptst);
	// rB -- do we read a register for operand B?  Specifically, do we
	// add the registers value to the immediate to create opB?
	assign	w_rB     = (w_mov)
				||((!iword[`CISBIT])&&(iword[`IMMSEL])&&(!w_ldi)&&(!w_special))
				||(( iword[`CISBIT])&&(iword[`CISIMMSEL])&&(!w_ldi))
				// If using compressed instruction sets,
				// we *always* read on memory operands.
				||(( iword[`CISBIT])&&(w_mem));
 
	// wR -- will we be writing our result back?
	// wR_n = !wR
	// All but STO, NOOP/BREAK/LOCK, and CMP/TST write back to w_dcdR
	assign	w_wR_n   = (w_sto)
				||(w_special)
				||(w_cmptst);
	assign	w_wR     = !w_wR_n;
	//
	// wF -- do we write flags when we are done?
	//
	assign	w_wF     = (w_cmptst)
			||((w_cond[3])&&(((w_fpu)&&(OPT_FPU))||(w_div)
				||((w_ALU)&&(!w_mov)&&(!w_ldilo)&&(!w_brev)
					&&(w_dcdR[3:1] != 3'h7))));
 
	// Bottom 13 bits: no LUT's
	// w_dcd[12: 0] -- no LUTs
	// w_dcd[   13] -- 2 LUTs
	// w_dcd[17:14] -- (5+i0+i1) = 3 LUTs, 1 delay
	// w_dcd[22:18] : 5 LUTs, 1 delay (assuming high bit is o/w determined)
	wire	[22:0]	w_I, w_fullI;
	wire		w_Iz;
 
	assign	w_fullI = (w_ldi) ? { iword[22:0] } // LDI
			// MOVE immediates have one less bit
			:((w_mov) ?{ {(23-13){iword[12]}}, iword[12:0] }
			// Normal Op-B immediate ... 18 or 14 bits
			:((!iword[`IMMSEL]) ? { {(23-18){iword[17]}}, iword[17:0] }
			: { {(23-14){iword[13]}}, iword[13:0] }
			));
 
	generate if (OPT_CIS)
	begin : GEN_CIS_IMMEDIATE
		wire	[7:0]	w_halfbits;
		assign	w_halfbits = iword[`CISIMMSEL:16];
 
		wire	[7:0]	w_halfI;
		assign	w_halfI = (iword[26:24]==3'h6) ? w_halfbits[7:0] // 8'b for LDI
				:(w_halfbits[7])?
					{ {(6){w_halfbits[2]}}, w_halfbits[1:0]}
					:{ w_halfbits[6], w_halfbits[6:0] };
		assign	w_I  = (iword[`CISBIT])
				? {{(23-8){w_halfI[7]}}, w_halfI }
				: w_fullI;
 
	end else begin : GEN_NOCIS_IMMEDIATE
 
		assign	w_I  = w_fullI;
 
	end endgenerate
 
	assign	w_Iz = (w_I == 0);
 
 
	initial	o_illegal = 1'b0;
	always @(*)
	begin
		o_illegal <= 1'b0;
		if ((!OPT_CIS)&&(i_instruction[`CISBIT]))
			o_illegal <= 1'b1;
		if ((!OPT_MPY)&&(w_mpy))
			o_illegal <= 1'b1;
 
		if ((!OPT_DIVIDE)&&(w_div))
			o_illegal <= 1'b1;
		else if ((OPT_DIVIDE)&&(w_div)&&(w_dcdR[3:1]==3'h7))
			o_illegal <= 1'b1;
 
 
		if ((!OPT_FPU)&&(w_fpu))
			o_illegal <= 1'b1;
 
		if ((!OPT_SIM)&&(w_sim))
			// Simulation instructions on real hardware should
			// always cause an illegal instruction error
			o_illegal <= 1'b1;
 
		// There are two (missing) special instructions
		// These should cause an illegal instruction error
		if ((w_dcdR[3:1]==3'h7)&&(w_cis_op[4:1]==4'b1101))
			o_illegal <= 1'b1;
 
		// If the lock function isn't implemented, this should
		// also cause an illegal instruction error
		if ((!OPT_LOCK)&&(w_lock))
			o_illegal <= 1'b1;
	end
 
	generate if (OPT_OPIPE)
	begin
		// o_prepipe is true if a pipelined memory instruction
		// might follow this one
		assign	o_prepipe =
				((OPT_CIS)||(!i_instruction[`CISBIT]))
				&&(o_M)&&(o_rB)
				&&(o_dcdB[3:1] != 3'h7)
				&&(o_dcdR[3:1] != 3'h7)
				&&((!o_wR)||(o_dcdR != o_dcdB));
	end else begin
		assign	o_prepipe = 1'b0;
	end endgenerate
 
	assign	o_dcdR = { w_dcdR_cc, w_dcdR_pc, w_dcdR};
	assign	o_dcdA = { w_dcdA_cc, w_dcdA_pc, w_dcdA};
	assign	o_dcdB = { w_dcdB_cc, w_dcdB_pc, w_dcdB};
	assign	o_I = { {(32-22){w_I[22]}}, w_I[21:0] };
	assign	o_cond = w_cond;
	assign	o_wF   = w_wF;
	assign	o_op   = ((w_ldi)||(w_noop))? 4'hd : w_cis_op[3:0];
	assign	o_ALU  =  (w_ALU)||(w_ldi)||(w_cmptst)||(w_noop);
	assign	o_M    = w_mem;
	assign	o_DV   = (OPT_DIVIDE)&&(w_div);
	assign	o_FP   = (OPT_FPU)&&(w_fpu);
	assign	o_break= w_break;
	assign	o_lock = (OPT_LOCK)&&(w_lock);
	assign	o_wR   = w_wR;
	assign	o_rA   = w_rA;
	assign	o_rB   = w_rB;
	assign	o_sim      = (OPT_SIM) ? ((w_sim)||(w_noop)) : 1'b0;
	assign	o_sim_immv = (OPT_SIM) ? iword[22:0] : 0;
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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