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 |
|
|
|