All pastes #768962 Raw Edit

Stuff

public text v1 · immutable
#768962 ·published 2007-11-11 00:30 UTC
rendered paste body
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
-------------------------------------------------------------------------------
-- Small 8 bit Harvard Arch accumulator oriented processor ~150 slices: 
-- 1 clk/inst, >120 MHz operation in Spartan3 >60 MHz in Spartan2
-- 8 bit data, 16 bit instruction width
-- 6 JMP instructions: 
-- JMP, JMPNZ, JMPZ, JMPNC, JMPC, JSR
-- 9 basic memory reference instructions:
-- OR, XOR, AND, ADD, ADDC, SUB, SUBB, LDA, STA
-- 13 operate instructions, load immediate, rotate, index load/store: 
-- LDI, RCL, RCR, LDYL, LDXL, STYL, STXL, LDYH, LDXH, STYL, STXH, RTT, TTR  
-- 1K words instruction space
-- 4K words data space
-- 2 index registers for indirect memory access
-- 10 bit offset for indirect addressing (ADD sinetable(6) etc)
-- 11 bit direct memory addressing range
-- 12 bit indirect addressing range with 10 bit offset range
-- 2 levels of subroutine call/return
-- Starts at address 0 from reset
-- THE BAD NEWS: pipelined processor with no locks so --->
-- Instruction hazards: 
--	2 instructions following conditional jumps always executed
--	TTR must precede JSR by at least 2 instructions
--	RTT must precede JSR by at least 2 instructions
--	TTR must precede JMP@R by at least 2 instructions
-- Data hazards:
--	Stored data requires 3 instructions before fetch
-- Address hazards:
--	Fetches via index register require 2 instructions from ST(X,Y)
--	to actual fetch (STA via index takes no extra delay) 
-------------------------------------------------------------------------------

entity DumbAss8 is
	generic(
		width : integer := 8;			-- data width
		iwidth	: integer := 16;		-- instruction width
		maddwidth : integer := 12;	-- memory address width
		paddwidth : integer := 10	-- program counter width
		 );
	port (
		clk   : in  std_logic;
		reset : in  std_logic;
		iabus : out std_logic_vector(paddwidth-1 downto 0);	-- program address bus
		idbus : in  std_logic_vector(iwidth-1 downto 0);  		-- program data bus		 
		mradd	: out std_logic_vector(maddwidth-1  downto 0); 	-- memory read address
		mwadd	: out std_logic_vector(maddwidth-1  downto 0); 	-- memory write address
		mibus	: in  std_logic_vector(width-1 downto 0);			-- memory data in bus	  
		mobus	: out std_logic_vector(width-1 downto 0);			-- memory data out bus
		mwrite: out std_logic;							  				-- memory write signal		  
		carryflg : out std_logic										-- carry flag
		);
end DumbAss8;


architecture Behavioral of DumbAss8 is


  constant carrymask : std_logic_vector := b"0_1111_1111";  -- mask to drop carry bit

-- basic op codes
-- Beware, certain bits are used to simpilfy decoding - dont change without knowing what you are doing...
  constant opr	: std_logic_vector (3 downto 0) := x"0";
  constant jmp	: std_logic_vector (3 downto 0) := x"1";
  constant jmpnz : std_logic_vector (3 downto 0) := x"2";
  constant jmpz : std_logic_vector (3 downto 0) := x"3";
  constant jmpnc : std_logic_vector (3 downto 0) := x"4";
  constant jmpc : std_logic_vector (3 downto 0) := x"5";
  constant jsr	: std_logic_vector (3 downto 0) := x"6";
  constant lda	: std_logic_vector (3 downto 0) := x"7";
  constant lor	: std_logic_vector (3 downto 0) := x"8";
  constant lxor : std_logic_vector (3 downto 0) := x"9";
  constant land : std_logic_vector (3 downto 0) := x"A";
  constant sta	: std_logic_vector (3 downto 0) := x"B";
  constant add	: std_logic_vector (3 downto 0) := x"C";
  constant addc : std_logic_vector (3 downto 0) := x"D";
  constant sub	: std_logic_vector (3 downto 0) := x"E";
  constant subc  : std_logic_vector (3 downto 0) := x"F";

-- operate instructions
  constant nop : std_logic_vector (3 downto 0) := x"0";

-- immediate load type
  constant ldi : std_logic_vector (3 downto 0) := x"1";

-- accumulator operate type

  constant rotcl : std_logic_vector (3 downto 0) := x"2";
  constant rotcr : std_logic_vector (3 downto 0) := x"3";
  
-- index register load/store in address order
  constant ldxl	: std_logic_vector (3 downto 0) := x"4";
  constant ldxh	: std_logic_vector (3 downto 0) := x"5";
  constant stxl	: std_logic_vector (3 downto 0) := x"6";
  constant stxh	: std_logic_vector (3 downto 0) := x"7";
  constant ldyl	: std_logic_vector (3 downto 0) := x"8";
  constant ldyh	: std_logic_vector (3 downto 0) := x"9";
  constant styl	: std_logic_vector (3 downto 0) := x"A";
  constant styh	: std_logic_vector (3 downto 0) := x"B";
-- return register save/restore
  constant rtt	: std_logic_vector (3 downto 0) := x"C";
  constant ttr	: std_logic_vector (3 downto 0) := x"D";  
-- basic signals

  signal accumcar  : std_logic_vector (width downto 0);  -- accumulator+carry
  alias accum		: std_logic_vector (width-1 downto 0) is accumcar(width-1 downto 0);
  alias carrybit	: std_logic is accumcar(width);

  signal pc		  : std_logic_vector (paddwidth -1 downto 0); -- program counter - 10 bits = 1k
  signal mra		 : std_logic_vector (maddwidth -1 downto 0);  -- memory read address - 11 bits = 2k
  signal mwa		 : std_logic_vector (maddwidth -1 downto 0);  -- memory write address - 11 bits = 2k
  signal id1		 : std_logic_vector (iwidth -1 downto 0);  -- instruction pipeline 1		 
  signal id2		 : std_logic_vector (iwidth -1 downto 0);  -- instruction pipeline 2			  
  alias opcode0	 : std_logic_vector (3 downto 0) is idbus (iwidth-1 downto iwidth-4);	-- main opcode at pipe0
  alias opcode2	 : std_logic_vector (3 downto 0) is id2 (iwidth-1 downto iwidth-4);	  -- main opcode at pipe2
  alias Arith		 : std_logic_vector (1 downto 0) is id2 (iwidth-1 downto iwidth-2);
  alias WithCarry  : std_logic is id2(iwidth-4);		-- indicates add with carry or subtract with borrow
  alias Minus		: std_logic is id2(iwidth-3);		-- indicates subtract
  alias opradd0	 : std_logic_vector (maddwidth -1 downto 0) is idbus (maddwidth -1 downto 0);					-- operand address at pipe0
  alias opradd2	 : std_logic_vector (maddwidth -1 downto 0) is id2 (maddwidth -1 downto 0);					  -- operand address at pipe2
  alias ind0		 : std_logic is idbus(iwidth -5); 
  alias ind2		 : std_logic is id2(iwidth -5);
  alias ireg0		: std_logic is idbus(iwidth -6);
  alias ireg2		: std_logic is id2(iwidth -6); 
  alias offset0	 : std_logic_vector (maddwidth-2  downto 0) is idbus(maddwidth-2 downto 0);
  alias offset2	 : std_logic_vector (maddwidth-2  downto 0) is	id2(maddwidth-2 downto 0);
  alias opropcode2 : std_logic_vector (3 downto 0) is id2 (iwidth-5 downto iwidth-8);	 -- operate opcode at pipe2  alias iopr2		: std_logic_vector (7 downto 0) is id2 (7 downto 0);					  -- immediate operand at pipe2
  alias iopr2		: std_logic_vector (7 downto 0) is id2 (7 downto 0);					  -- immediate operand at pipe2
  signal oprr		: std_logic_vector (width -1 downto 0);										-- operand register
  signal idx		 : std_logic_vector (maddwidth -1 downto 0);
  signal idy		 : std_logic_vector (maddwidth -1 downto 0);
  signal idn0		 : std_logic_vector (maddwidth -1 downto 0);
  signal idn2		 : std_logic_vector (maddwidth -1 downto 0);
  signal idr		 : std_logic_vector (paddwidth -1 downto 0);
  signal idt		 : std_logic_vector (paddwidth -1 downto 0);
  signal nextpc	 : std_logic_vector (paddwidth -1 downto 0);
  signal pcplus1	: std_logic_vector (paddwidth -1 downto 0);
  signal zero		: std_logic;

  function rotcleft(v : std_logic_vector ) return std_logic_vector is
	 variable result	: std_logic_vector(width downto 0);
  begin
	 result(width downto 1) := v(width-1 downto 0);
	 result(0)				  := v(width);
	 return result;
  end rotcleft;

  function rotcright(v : std_logic_vector ) return std_logic_vector is
	 variable result	 : std_logic_vector(width downto 0);
  begin
	 result(width -1 downto 0) := v(width downto 1);
	 result(width)				 := v(0);
	 return result;
  end rotcright;

begin  -- the CPU

  idproc : process (clk)					 -- instruction data pipeline
  begin
	 
	 if clk'event and clk = '1' then
		id1  <= idbus;	
		id2  <= id1;	  
		if reset = '1' then
		  id1  <= x"0000";					 -- fill pipeline with 0 (nop)
		end if;
	 end if;  -- if clk
  end process idproc;

  nextpcproc : process (clk, reset, pc, zero, nextpc, id2,
								ind0, ind2,idr, idbus, opcode0,
								opcode2, carrybit)  -- next pc calculation - jump decode
  begin
	 pcplus1 <= pc + '1';	 
	 iabus <= nextpc;							 -- program memory address from combinatorial	 
	 if reset = '1' then						 -- nextpc since blockram has built in addr register
		nextpc <= (others => '0');
	 else
		if (opcode0 = jmp) or (opcode0 = jsr) then
		  if ind0 = '1' then					  -- indirect
			 nextpc <= idr;
		  else										 -- direct
			 nextpc <= idbus(paddwidth -1 downto 0);
		  end if;
		elsif
		  ((opcode2 = jmpnz) and (zero = '0')) or
		  ((opcode2 = jmpz) and (zero = '1')) or
		  ((opcode2 = jmpnc) and (carrybit = '0')) or
		  ((opcode2 = jmpc) and (carrybit = '1')) then
		  if ind2 = '1' then				  -- indirect
			 nextpc <= idr;
		  else									 -- direct
			 nextpc <= id2(paddwidth -1 downto 0);
		  end if;
		else
		  nextpc <= pcplus1;
		end if;  -- opcode = jmp
	 end if;  -- no reset

	 if clk'event and clk = '1' then
		pc <= nextpc;

	 end if;

  end process nextpcproc;

  mraproc : process (idbus, idx, idy, mra, ind0,
							ireg0,
							offset0, opcode0, opradd0, clk)  -- memory read address generation
  begin
	 mradd <= mra;
	 case ireg0 is
		when '0' => idn0 <= idx;
		when '1' => idn0 <= idy;
		when others => null;
	  end case;
	 if opcode0 /= opr and ind0 = '1' then
		mra <= idn0 + ('0'&offset0);
	 else
		mra	<= opradd0;
	 end if;
  end process mraproc;

	mwaproc : process (clk, mwa)			 -- memory write address generation
	begin
		mwadd	  <= mwa;
		case ireg2 is
			when '0' => idn2 <= idx;
			when '1' => idn2 <= idy;
			when others => null;
		end case;	 
		if clk'event and clk = '1' then
			if ind2 = '1' then
				mwa <= idn2 + ('0'&offset2);
			else
				mwa	<= opradd2;
			end if;
		end if;
	end process mwaproc;

  oprrproc : process (clk)			  -- memory operand register  -- could remove to
  begin									  -- reduce pipelining depth but would impact I/O read
	 if clk'event and clk = '1' then	-- access time  --> not good for larger systems
		oprr <= mibus;
	 end if;
  end process oprrproc;

  accumproc : process (clk, accum, carrybit)  -- accumulator instruction decode - operate
  begin
	 carryflg <= carrybit;
	 if accum = x"00" then
		zero <= '1';
	 else
		zero <= '0';
	end if;
	
	if clk'event and clk = '1' then
		case opcode2 is -- memory reference first
			when land			=> accum	 <= accum and oprr;
			when lor			 => accum	 <= accum or oprr;
			when lxor			=> accum	 <= accum xor oprr;
			when lda			 => accum	 <= oprr;
					
			when opr				=>												  -- operate
				case opropcode2 is
					when ldi		  => accum	 <= iopr2;						-- load immediate byte	  
					when rotcl		=> accumcar <= rotcleft(accumcar);		-- rotate left through carry
					when rotcr		=> accumcar <= rotcright(accumcar);	 -- rotate right through carry				  

					when ldxl		  => accum	 <= idx(width-1 downto 0);
					when ldyl		  => accum	 <= idy(width-1 downto 0);
					when stxl		  => idx(width-1 downto 0) <= accum;
					when styl		  => idy(width-1 downto 0) <= accum;

					when ldxh		  => accum((maddwidth-width)-1 downto 0) <= idx(maddwidth-1 downto width);
										  accum(width-1 downto maddwidth-width) <= (others => '0'); 
					when ldyh		  => accum((maddwidth-width)-1 downto 0) <= idy(maddwidth-1 downto width);
											  accum(width-1 downto maddwidth-width) <= (others => '0');  
					when stxh		  => idx(maddwidth-1 downto width) <= accum((maddwidth-width)-1 downto 0);
					when styh		  => idy(maddwidth-1 downto width) <= accum((maddwidth-width)-1 downto 0);
					when rtt			  => idt <= idr;
					when ttr			=> idr <= idt;
					when others	  => null;
			  end case;
			when others		 => null;
		end case;
		
		if Arith = "11" then
			if Minus = '0' then
				accumcar <= (accumcar and carrymask) + oprr + (carrybit and WithCarry); -- add/addc
			else
				accumcar <= (accumcar and carrymask) - oprr - (carrybit and WithCarry); -- sub/subc
			end if;
		end  if;					
		if (opcode0 = jsr) then			 -- save return address -- note priority over ttr!	  
			idr  <= pcplus1;  
		end if;	
	end if;  -- clk
end process accumproc;

  staproc : process (clk, accum)  -- sta decode  -- not much to do but enable mwrite
  begin
	 mobus <= accum;
	 if clk'event and clk = '1' then
		if opcode2 = sta then
		  mwrite <= '1';
		else
		  mwrite <= '0';
		end if;
	 end if;
  end process staproc;

end Behavioral;