| 1 |
6 |
root |
-- Tiny Instruction Set (TISC) VHDL CPU Core
|
| 2 |
|
|
-- Copyright Vincent Crabtree, 15th Nov 2001
|
| 3 |
|
|
--
|
| 4 |
|
|
-- My first attempt at processor design, thanks to :-
|
| 5 |
|
|
-- Tim Boscke - CPU8BIT2, Rockwell - 6502, Microchip - Pic
|
| 6 |
|
|
-- Jien Chung Lo - EL405 , Steve Scott - Tisc,
|
| 7 |
|
|
-- Giovanni Moretti - Intro to Asm
|
| 8 |
|
|
-- Uses 12 bit program word, and 8 bit data memory
|
| 9 |
|
|
|
| 10 |
|
|
-- 2 reg machine,accumulator based, with akku and index regs
|
| 11 |
|
|
-- Harvard architecture, uses return x so as to eliminate need of pmem
|
| 12 |
|
|
-- indirect instructions like 8051.
|
| 13 |
|
|
-- pc is 10 bits, akku and idx are 8 bit.
|
| 14 |
|
|
|
| 15 |
|
|
-- Has carry and zero flags,
|
| 16 |
|
|
-- three addressing modes:- immediate, indirect and reg.
|
| 17 |
|
|
-- seperate program and data memory for pipelining later...
|
| 18 |
|
|
|
| 19 |
|
|
-- Instructions coded as thus:-
|
| 20 |
|
|
|
| 21 |
|
|
|
| 22 |
|
|
-- Long instructions first - program jump.
|
| 23 |
|
|
-- Both store return address for subroutine calls, 1 deep stack.
|
| 24 |
|
|
-- 0 0 xxxxxxxxxx jc pmem10 ; if c==1, stack = pc, pc <- pmem10, fi
|
| 25 |
|
|
-- 0 1 xxxxxxxxxx jz pmem10 ; if z==1, stack = pc, pc <- pmem10, fi
|
| 26 |
|
|
|
| 27 |
|
|
-- Immediate ops
|
| 28 |
|
|
-- bits 9 and 8 select what to do
|
| 29 |
|
|
-- 1 00 0 xxxxxxxx lda #imm8 ; a= imm8, c=0,
|
| 30 |
|
|
-- 1 00 1 xxxxxxxx ret #imm8 ; a= imm8, pc = stack
|
| 31 |
|
|
|
| 32 |
|
|
-- 1 01 0 xxxxxxxx adc #imm8 ; add with carry imm8, cy and z set
|
| 33 |
|
|
-- 1 01 1 xxxxxxxx adx #imm8 ; add imm8 to idx reg, z=(a==0)
|
| 34 |
|
|
|
| 35 |
|
|
-- Indirect and alu ops
|
| 36 |
|
|
-- bit 9 selects indirect or alu ops
|
| 37 |
|
|
|
| 38 |
|
|
-- Indirect - bits 7 and 8 select what to do
|
| 39 |
|
|
-- 1 10 0 0 xxxxxxx lda [ix] ; load a indirect data mem
|
| 40 |
|
|
-- 1 10 0 1 xxxxxxx sta [ix] ; store a indirect data mem
|
| 41 |
|
|
|
| 42 |
|
|
-- register register
|
| 43 |
|
|
-- 1 10 1 0 xxxxxxx tax ; x = a,
|
| 44 |
|
|
-- 1 10 1 1 xxxxxxx txa ; a = x
|
| 45 |
|
|
|
| 46 |
|
|
-- Arithmetic ops use indirect addressing
|
| 47 |
|
|
-- all alu ops indirect, bits 7 and 8 select alu op.
|
| 48 |
|
|
-- 1 11 00 xxxxxxx add a,[ix] ; add with carry
|
| 49 |
|
|
-- 1 11 01 xxxxxxx sub a,[ix] ; a = a + ~[idx], inc a after for proper subtract
|
| 50 |
|
|
-- 1 11 10 xxxxxxx and a,[ix] ; and mem contents into a
|
| 51 |
|
|
-- 1 11 11 xxxxxxx nor a,[ix] ; nor
|
| 52 |
|
|
|
| 53 |
|
|
-- States.
|
| 54 |
|
|
-- 000 instruction decode
|
| 55 |
|
|
-- 010 load a indirect - lda [ix]
|
| 56 |
|
|
-- 011 stor a indirect - sta [ix]
|
| 57 |
|
|
-- 100 add a,[ix]
|
| 58 |
|
|
-- 101 sub a,[ix[
|
| 59 |
|
|
-- 110 and a,[ix]
|
| 60 |
|
|
-- 111 nor a,[ix]
|
| 61 |
|
|
|
| 62 |
|
|
library ieee;
|
| 63 |
|
|
use ieee.std_logic_1164.all;
|
| 64 |
|
|
use ieee.std_logic_unsigned.all; -- has adder built in
|
| 65 |
|
|
|
| 66 |
|
|
entity tisc is
|
| 67 |
|
|
port(
|
| 68 |
|
|
-- bus
|
| 69 |
|
|
-- db only 8 bits wide on dmem side, 12 on pmem side.
|
| 70 |
|
|
data : inout std_logic_vector(11 downto 0);
|
| 71 |
|
|
address : out std_logic_vector(9 downto 0);
|
| 72 |
|
|
|
| 73 |
|
|
-- control - active low
|
| 74 |
|
|
rd : out std_logic; -- dram
|
| 75 |
|
|
wr : out std_logic; -- dram
|
| 76 |
|
|
psen : out std_logic; -- pmem
|
| 77 |
|
|
|
| 78 |
|
|
-- machine control
|
| 79 |
|
|
clock : in std_logic;
|
| 80 |
|
|
reset : in std_logic);
|
| 81 |
|
|
end;
|
| 82 |
|
|
|
| 83 |
|
|
architecture cpu_arch of tisc is
|
| 84 |
|
|
-- Program control
|
| 85 |
|
|
signal stack : std_logic_vector(9 downto 0); -- stack, 1 deep
|
| 86 |
|
|
signal pc : std_logic_vector(9 downto 0); -- program counter
|
| 87 |
|
|
|
| 88 |
|
|
-- Registers
|
| 89 |
|
|
signal akku : std_logic_vector(8 downto 0); -- accumulator, cy is bit 8
|
| 90 |
|
|
signal idx : std_logic_vector(7 downto 0); -- index reg
|
| 91 |
|
|
signal z : std_logic; -- zero flag
|
| 92 |
|
|
|
| 93 |
|
|
-- ALU controls
|
| 94 |
|
|
signal aluout : std_logic_vector(9 downto 0); -- alu result
|
| 95 |
|
|
signal temp : std_logic_vector(8 downto 0); -- temp storage for alu
|
| 96 |
|
|
signal aludest : std_logic_vector(1 downto 0); -- output mux alu
|
| 97 |
|
|
signal aluop : std_logic_vector(1 downto 0); -- alu operation
|
| 98 |
|
|
signal aluinput : std_logic_vector(9 downto 0); -- input to alu
|
| 99 |
|
|
|
| 100 |
|
|
-- machine control
|
| 101 |
|
|
signal states : std_logic_vector(2 downto 0); -- state controller
|
| 102 |
|
|
|
| 103 |
|
|
begin -- start logic decleration
|
| 104 |
|
|
|
| 105 |
|
|
process(clock,reset) -- sequential section
|
| 106 |
|
|
begin
|
| 107 |
|
|
-- check if reset or not
|
| 108 |
|
|
if(reset = '0' ) then -- async reset parameters
|
| 109 |
|
|
-- how do I stop the annoying async error?
|
| 110 |
|
|
pc <= (others => '0');-- reset
|
| 111 |
|
|
states <= (others => '0'); -- decode sub state
|
| 112 |
|
|
aludest <= "01"; -- reset destination dest
|
| 113 |
|
|
|
| 114 |
|
|
elsif rising_edge(clock) then -- actual machine
|
| 115 |
|
|
|
| 116 |
|
|
-- check state machine for indirect alu ops
|
| 117 |
|
|
if( states(2) = '1') then
|
| 118 |
|
|
|
| 119 |
|
|
if( states(1 downto 0) = "01") then --sub add ind
|
| 120 |
|
|
temp <= "0" & (Not data(7 downto 0));
|
| 121 |
|
|
else
|
| 122 |
|
|
temp <= "0" & data(7 downto 0);
|
| 123 |
|
|
end if;
|
| 124 |
|
|
|
| 125 |
|
|
aluop <= states(1 downto 0); -- 00 adc indirect
|
| 126 |
|
|
-- 01 not add ind
|
| 127 |
|
|
-- 10 and indirect
|
| 128 |
|
|
-- 11 nor indirect
|
| 129 |
|
|
-- sort out muxers for alu
|
| 130 |
|
|
aludest <= "00"; -- akku destination
|
| 131 |
|
|
states <= "000"; -- decode
|
| 132 |
|
|
|
| 133 |
|
|
else
|
| 134 |
|
|
|
| 135 |
|
|
-- States decode
|
| 136 |
|
|
case states(1 downto 0) is -- action dependent on states
|
| 137 |
|
|
when "00" => -- instruction decode
|
| 138 |
|
|
|
| 139 |
|
|
-- increment pc first
|
| 140 |
|
|
temp <= "000000001"; -- inc
|
| 141 |
|
|
aludest <= "10"; -- pc and increment and idle
|
| 142 |
|
|
pc <= aluout; -- get result
|
| 143 |
|
|
|
| 144 |
|
|
-- Now decode instr on data bus
|
| 145 |
|
|
-- sort out jz or jc
|
| 146 |
|
|
if( (data(11) = '0') and -- top bit nought, sio a jump...
|
| 147 |
|
|
( ((akku(8) = '1') and (data(10) = '0')) or -- JC
|
| 148 |
|
|
((z='1') and (data(10)='1'))) ) then -- Jz
|
| 149 |
|
|
stack <= pc; --return stack
|
| 150 |
|
|
pc <= data(9 downto 0);
|
| 151 |
|
|
-- states already at decode
|
| 152 |
|
|
|
| 153 |
|
|
else -- top bit is one, so not a jump instruction...
|
| 154 |
|
|
case data(10 downto 9) is
|
| 155 |
|
|
when "01" => -- adc #imm/adx #imm
|
| 156 |
|
|
temp <= "0" & data(7 downto 0);
|
| 157 |
|
|
aluop <= "01"; -- add
|
| 158 |
|
|
aludest <= data(8) & data(8) ; --00 is akku, 11 is idx
|
| 159 |
|
|
-- states already at decode
|
| 160 |
|
|
|
| 161 |
|
|
when "00" => -- lda #imm/ret #imm clear cy
|
| 162 |
|
|
if( data(8) = '1' ) then -- ret ##imm
|
| 163 |
|
|
pc <= stack;
|
| 164 |
|
|
end if;
|
| 165 |
|
|
akku <= "0" & data(7 downto 0);
|
| 166 |
|
|
-- states already at decode
|
| 167 |
|
|
|
| 168 |
|
|
when "10" => -- lda/store or reg/reg
|
| 169 |
|
|
if( data(8) = '1') then -- ld ind /store ind
|
| 170 |
|
|
states <= "01" & data(7);-- "010";
|
| 171 |
|
|
-- reg/reg
|
| 172 |
|
|
elsif( data(7) = '0') then -- tax
|
| 173 |
|
|
idx <= akku(7 downto 0);
|
| 174 |
|
|
else -- txa
|
| 175 |
|
|
akku <= "0" & idx(7 downto 0);
|
| 176 |
|
|
end if;
|
| 177 |
|
|
-- states already at decode
|
| 178 |
|
|
|
| 179 |
|
|
when "11" => -- add ind, and
|
| 180 |
|
|
states <= "1" & data(8 downto 7); -- "100"; -- add/sub ind
|
| 181 |
|
|
-- "110"; -- and/nor ind
|
| 182 |
|
|
when others =>
|
| 183 |
|
|
states <= "000"; -- if non of above, decode/nop
|
| 184 |
|
|
end case; -- end of instruction decode
|
| 185 |
|
|
|
| 186 |
|
|
end if; -- jump if
|
| 187 |
|
|
|
| 188 |
|
|
when "10" => -- lda [ix] - buses should be setup
|
| 189 |
|
|
akku <= "0" & data(7 downto 0);
|
| 190 |
|
|
states <= "000"; -- decode
|
| 191 |
|
|
|
| 192 |
|
|
when "11" => -- sta [ix]
|
| 193 |
|
|
-- akku placed on data bus now
|
| 194 |
|
|
states <= "000"; -- decode
|
| 195 |
|
|
|
| 196 |
|
|
when others =>
|
| 197 |
|
|
states <= "000"; -- decode
|
| 198 |
|
|
|
| 199 |
|
|
end case; -- end of state decode
|
| 200 |
|
|
end if; -- end of alu indirect if
|
| 201 |
|
|
end if; -- rising edge if
|
| 202 |
|
|
|
| 203 |
|
|
|
| 204 |
|
|
-- Sort out alu ops and source/destination regs
|
| 205 |
|
|
case aludest is
|
| 206 |
|
|
when "00" => -- destination is alu
|
| 207 |
|
|
akku <= aluout(8 downto 0);
|
| 208 |
|
|
when "11" => -- alu destination is idx
|
| 209 |
|
|
idx <= aluout(7 downto 0);
|
| 210 |
|
|
when others => null;
|
| 211 |
|
|
end case; -- end of dest decode
|
| 212 |
|
|
|
| 213 |
|
|
end process; -- end sequential section
|
| 214 |
|
|
|
| 215 |
|
|
-- concurrent section
|
| 216 |
|
|
z <= '1' when akku = "000000000" and reset='1' else '0'; -- nice nand here
|
| 217 |
|
|
|
| 218 |
|
|
-- alu input muxer
|
| 219 |
|
|
with aludest select
|
| 220 |
|
|
aluinput <= ("0" & akku) when "00",
|
| 221 |
|
|
("00" & idx) when "11",
|
| 222 |
|
|
pc when "10",
|
| 223 |
|
|
("0" & temp) when others;
|
| 224 |
|
|
|
| 225 |
|
|
-- Decode and perform arithmetic ops
|
| 226 |
|
|
with aluop select
|
| 227 |
|
|
aluout <= aluinput + ("0" & temp) when "01", -- add
|
| 228 |
|
|
aluinput and ("0" & temp) when "10", -- and
|
| 229 |
|
|
aluinput nor ("0" & temp) when "11", -- nor
|
| 230 |
|
|
not ("0" & temp) when others; -- any use?
|
| 231 |
|
|
|
| 232 |
|
|
-- assign pins
|
| 233 |
|
|
address <= pc when states = "000" else "00"&idx;
|
| 234 |
|
|
|
| 235 |
|
|
data <= ("000" & akku) when states = "011" else "ZZZZZZZZZZZZ";
|
| 236 |
|
|
|
| 237 |
|
|
psen <= '0' when states="000" else '1'; -- pmem read
|
| 238 |
|
|
|
| 239 |
|
|
rd <= '0' when (states(2)='1') or (states="010") else '1'; -- dmem read
|
| 240 |
|
|
wr <= '0' when states="011" else '1'; -- dmem write
|
| 241 |
|
|
|
| 242 |
|
|
end cpu_arch;
|
| 243 |
|
|
|
| 244 |
|
|
|