VHDL
Source Code for Simple 8-bit CPU
Taken
from http://instruct1.cit.cornell.edu/ee475/
--
Design for lab 4 of ee475 for spring 1998
-- The mica cpu + ken's shell
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY shell IS
PORT (
rxdat : IN
std_logic;
xclk : IN
std_logic;
rxstb
: IN std_logic;
txstb : IN std_logic;
txdat
: OUT std_logic;
clk
: IN std_logic;
addr
: BUFFER std_logic_vector(15 DOWNTO 0);
data : INOUT std_logic_vector(7 DOWNTO 0);
rd
: BUFFER std_logic;
wr : BUFFER std_logic;
ramcs : OUT std_logic;
sevseg:
OUT std_logic_vector(6 DOWNTO
0)
);
END shell;
ARCHITECTURE one OF shell IS
COMPONENT cpu PORT (
clk : IN std_logic;
addr : BUFFER std_logic_vector(15 DOWNTO
0);
data : INOUT
std_logic_vector(7 DOWNTO 0);
rd :
BUFFER std_logic;
wr : BUFFER std_logic;
--ramcs : OUT std_logic;
sevseg: OUT
std_logic_vector(6 DOWNTO 0);
din :
IN std_logic_vector(15 DOWNTO
0);
dout : OUT
std_logic_vector(7 DOWNTO 0);
dsel :
IN std_logic_vector(1 DOWNTO
0)
);
END COMPONENT;
SIGNAL din : std_logic_vector(15 DOWNTO 0);
SIGNAL clksel : std_logic_vector(4 DOWNTO 0);
SIGNAL dsel : std_logic_vector(1 DOWNTO 0);
SIGNAL dout : std_logic_vector(7 DOWNTO 0);
SIGNAL txshift : std_logic_vector(7 DOWNTO 0);
SIGNAL txshiftnext:
std_logic_vector(7 DOWNTO 0);
SIGNAL rxshift :
std_logic_vector(22 DOWNTO 0);
SIGNAL clkdiv :
std_logic_vector(23 DOWNTO 0);
SIGNAL cpuclk :
std_logic;
BEGIN
u1:
cpu PORT MAP (
clk => cpuclk,
addr
=> addr,
data => data,
rd => rd,
wr
=> wr,
--ramcs => ramcs,
sevseg => sevseg,
din => din,
dout => dout,
dsel
=> dsel
);
-- select ram
ramcs
<='0';
-- Drive serial interface
WITH
txstb SELECT
txshiftnext
<= txshift(6 DOWNTO 0)&'0' WHEN '0',
dout WHEN OTHERS;
txrx:
PROCESS
BEGIN
WAIT
UNTIL (xclk'event AND xclk='0');
rxshift
<= rxshift(21 DOWNTO 0)&(NOT rxdat);
txshift <= txshiftnext;
END PROCESS txrx;
rx:
PROCESS
BEGIN
WAIT
UNTIL (rxstb'event AND rxstb='1');
din <= rxshift(15
DOWNTO 0);
dsel <= rxshift(17 DOWNTO 16);
clksel <= rxshift(22 DOWNTO 18);
END
PROCESS rx;
txdat <= txshift(7);
-- Run clock divider
PROCESS
BEGIN
WAIT UNTIL (clk'event AND clk='1');
clkdiv <= clkdiv + 1;
END
PROCESS;
WITH clksel SELECT
cpuclk
<= clk WHEN "00000",
clkdiv(0) WHEN "00001",
clkdiv(1) WHEN
"00010",
clkdiv(2) WHEN "00011",
clkdiv(3) WHEN
"00100",
clkdiv(4) WHEN "00101",
clkdiv(5) WHEN
"00110",
clkdiv(6) WHEN "00111",
clkdiv(7) WHEN
"01000",
clkdiv(8) WHEN "01001",
clkdiv(9) WHEN
"01010",
clkdiv(10) WHEN "01011",
clkdiv(11) WHEN
"01100",
clkdiv(12) WHEN "01101",
clkdiv(13) WHEN
"01110",
clkdiv(14) WHEN "01111",
clkdiv(15) WHEN
"10000",
clkdiv(16) WHEN
"10001",
clkdiv(17) WHEN "10010",
clkdiv(18) WHEN
"10011",
clkdiv(19) WHEN "10100",
clkdiv(20) WHEN
"10101",
clkdiv(21) WHEN "10110",
clkdiv(22) WHEN "10111",
clkdiv(23) WHEN
"11000",
'0' WHEN
"11110",
'1' WHEN
"11111",
'0' WHEN
OTHERS;
END one;
---------------------------------------------------------------------------
-- Design based on
the MICA architecture from Notre Dame.
-- CPU is a four register, 8 bit data/instruction, load/store
machine.
LIBRARY ieee;
USE ieee.std_logic_1164.all; -- standard logic
USE ieee.std_logic_unsigned.all; --
arithmetic stuff
ENTITY cpu IS
PORT(
clk: IN std_logic; -- 50% duty cycle clock
rd: BUFFER std_logic; -- mem read cntl
wr:
BUFFER std_logic; -- mem write
cntl
addr: BUFFER
std_logic_vector(15 downto 0);-- the address bus
data: INOUT std_logic_vector(7 downto 0); --
the data bus
sevseg: OUT std_logic_vector(6 downto 0); -- segven segment
display
din
: IN std_logic_vector(15
DOWNTO 0); -- shell data in
dout : OUT std_logic_vector(7 DOWNTO 0); -- shell
data out
dsel : IN
std_logic_vector(1 DOWNTO 0) --
shell data out select
);
END cpu;
ARCHITECTURE one OF cpu IS
-- reset signal
SIGNAL
reset: std_logic;
-- cpu state
SIGNAL
fetch, exec: std_logic;
--opcodes
SIGNAL
ld, st, addi, add, inand, isll, inot: std_logic;
SIGNAL
clr, jal, skipn, skipz, br: std_logic;
-- IR, PC
SIGNAL ir: std_logic_vector(7 downto 0);
--instruction
register
SIGNAL pc:
std_logic_vector(7 downto 0);
--program counter
SIGNAL
PCinSel: std_logic;
--selects
PC load source 0=PC_incrementer 1=Aout
SIGNAL PCload: std_logic;
--gates the PC
load
SIGNAL PCaddSel:
std_logic_vector(1 downto 0);
--selects PC increment
0=1 1=2 3=displacement
SIGNAL PCinc: std_logic_vector(7 downto 0);
--increment value
SIGNAL
PCin: std_logic_vector(7 downto
0);
--PC update
SIGNAL PCnew: std_logic_vector(7 downto 0);
--incrmented PC
--
DATA from IR
SIGNAL DataImm: std_logic_vector(7 downto 0);
-- 4 bits from IR
extended
SIGNAL disp: std_logic_vector(2
downto 0);
--offset for reg indirect data addr from IR
so addr<= disp+Bout
SIGNAL displacement: std_logic_vector(7 downto 0);
--offset
for PC jump from IR so PC <= PC+displacement
-- MEMORY interface
SIGNAL
MASel: std_logic;
--memory address select: 0=PC,
1=disp+(B)
SIGNAL dataAddr:
std_logic_vector(7 downto 0);
--memory
data address 1=disp+(B)
SIGNAL
AtoBus: std_logic;
--gates
the A bus output onto the memory data bus
-- DATA registers
SIGNAL
r0, r1, r2, r3: std_logic_vector(7 downto 0);
SIGNAL rdata: std_logic_vector(7 downto 0);
--
register outputs
SIGNAL Aout, Bout: std_logic_vector(7
downto 0);
--register input bus
SIGNAL RegDSel: std_logic_vector(1 downto 0);
--data
source for rdata reg write: 0=0 1=PC 2=ALUout 3=data
SIGNAL
ALUBSel: std_logic_vector(1 downto
0);
--data source for ALU b input: 0=Bout 1=0 2=1 3=DataImm
SIGNAL
ASel: std_logic_vector(1 downto
0);
--selects A register output
SIGNAL BSel: std_logic_vector(1 downto 0);
--selects
B register output
SIGNAL we:
std_logic;
--enables a register load
-- ALU
SIGNAL
Bin: std_logic_vector(7 downto 0);
SIGNAL ALUop: std_logic_vector(1 downto 0);
--selects
ALU function
SIGNAL ALUout: std_logic_vector(7 downto 0);
--ALU result
SIGNAL
zne: std_logic;
--gates
the Z and N register loads
SIGNAL z, n: std_logic;
--the Z and N registers
BEGIN
--
***********************************
--debugger shell interface
reset <= din(0);
WITH dsel SELECT
dout <= addr(7 downto 0) WHEN "00" ,
data WHEN
"01",
pc WHEN "10",
ir WHEN "11" ,
"11111111" WHEN OTHERS ;
--
***********************************
--
7-seg decoder
WITH
r3(3 downto 0) SELECT
sevseg
<= "0111111" WHEN "0000",
"0000110" WHEN "0001",
"1011011" WHEN "0010",
"1001111" WHEN "0011",
"1100110" WHEN "0100",
"1101101" WHEN "0101",
"1111101" WHEN "0110",
"0000111" WHEN "0111",
"1111111" WHEN "1000",
"1101111" WHEN "1001",
"1110111" WHEN "1010",
"1111100" WHEN "1011",
"0111001" WHEN "1100",
"1011110" WHEN "1101",
"1111001" WHEN "1110",
"1110001" WHEN OTHERS;
-- ***********************************
-- OPcode decoder
ld <= '1' WHEN ir(7 downto
6)="00" ELSE '0'; -- load
st <= '1' WHEN ir(7 downto
6)="01" ELSE '0'; --store
addi <= '1' WHEN ir(7 downto
6)="10" ELSE '0'; --add immediate
add <= '1' WHEN (ir(7 downto
6)="11"
AND ir(1 downto 0)="00") ELSE
'0'; --add
inand <= '1' WHEN
(ir(7 downto 6)="11"
AND
ir(1 downto 0)="01") ELSE '0'; -- nand
isll <= '1' WHEN
(ir(7 downto 6)="11"
AND
ir(3 downto 0)="0010") ELSE '0'; -- shift left
inot <= '1' WHEN
(ir(7 downto 6)="11"
AND
ir(3 downto 0)="0110") ELSE '0'; -- not
clr <= '1' WHEN
(ir(7 downto 6)="11"
AND
ir(3 downto 0)="1010") ELSE '0'; -- clear reg
jal <= '1' WHEN ir(7 downto 0)="11011110" ELSE
'0'; -- jump and link
skipn <= '1' WHEN ir(7 downto
0)="11101110" ELSE '0'; --skip on neg
skipz <= '1' WHEN ir(7 downto 0)="11111110" ELSE
'0'; -- skip on zero
br <= '1'
WHEN (ir(7 downto 6)="11"
AND
ir(1 downto 0)="11") ELSE '0'; -- branch
-- ***********************************
-- compute memory address
disp <= ir(2 downto 0);
dataAddr <= "00000"&disp
+ Bout;
MASel
<= '1' WHEN exec='1' ELSE '0';
WITH
MASel SELECT
addr
<= "00000000" & pc
WHEN '0', -- during fetch phase
"00000000" & dataAddr WHEN '1', -- during exec phase
"00000000"
& pc WHEN OTHERS;
--
***********************************
-- memory read/write control
rd <= '0' WHEN (ld='1' AND exec='1' AND clk='0' ) -- load
data
OR (fetch='1' AND clk='0')
-- fetch inst
ELSE '1';
wr <= '0' WHEN (st='1' AND exec='1' AND
clk='0') -- store data
ELSE '1';
--
A bus to memory
data
<= Aout WHEN wr='0' ELSE "ZZZZZZZZ"; -- floats the bus
-- ***********************************
-- Program Counter control
PCaddSel <= '0'&n WHEN skipn='1'
ELSE -- add 2
'0'&z WHEN skipz='1' ELSE -- add
2
"10" WHEN br='1' ELSE -- add displacment
"00"; -- increment when
not a branch or skip
-- sign extend the displacement field
displacement <= ir(5) & ir(5) &
ir(5) & ir(5) & ir(5 downto 2);
WITH
PCaddSel SELECT
PCinc
<= "00000001" WHEN
"00",
"00000010" WHEN "01",
displacement WHEN "10",
"00000001" WHEN
OTHERS;
PCnew
<= pc + PCinc; -- the updated verion of the PC
PCinSel
<= '1' WHEN jal='1' ELSE '0';
WITH PCinSel SELECT
PCin <= PCnew WHEN '0',
Aout
WHEN '1',
Aout
WHEN OTHERS;
--
***********************************
-- register controls
-- set up register data select
RegDSel <= "11" WHEN
ld='1' ELSE
"01" WHEN jal='1' ELSE
"00" WHEN clr='1' ELSE
"10" ; -- feedback
from alu
-- route the input data
WITH RegDSel SELECT
rdata <= "00000000" WHEN
"00",
pcnew WHEN "01",
ALUout WHEN
"10",
data WHEN "11",
"00000000" WHEN OTHERS;
-- choose a register for output A, jal
always loads r2
ASel
<= "10" WHEN jal='1' ELSE ir(5 downto 4) ;
-- choose a register for output B, r2 or r3 used for ld/st
disp
BSel <=
'1'&ir(3) WHEN (ld='1' OR st='1') ELSE ir(3 downto 2) ;
-- write enable for registers disable for
4 opcodes
we <= '0'
WHEN st='1' OR br='1' OR skipn='1' OR
skipz='1' ELSE '1' ;
-- A output
WITH ASel SELECT
Aout <= r0 WHEN "00",
r1 WHEN "01",
r2 WHEN
"10",
r3 WHEN OTHERS;
-- B output
WITH
BSel SELECT
Bout
<= r0 WHEN "00",
r1 WHEN "01",
r2 WHEN "10",
r3 WHEN
OTHERS;
--
***********************************
-- ALU controls
--
control the B input to the ALU
ALUbSel
<= "11" WHEN addi='1' ELSE -- DataImm
"10" WHEN inot='1' ELSE -- const=1
"00" ; --Bout
DataImm <= "0000"&ir(3 downto 0);
-- ALU B input
WITH
ALUbSel SELECT
Bin <= Bout WHEN "00",
"00000000" WHEN "01",
"11111111" WHEN "10",
DataImm WHEN
OTHERS;
--
ALU function control
ALUop
<= "00" WHEN addi='1' OR
add='1' ELSE
"01" WHEN inand='1' OR inot='1'
ELSE
"10" ;-- shift left
-- ALU
WITH
ALUop SELECT
ALUout
<= Aout + Bin WHEN
"00", -- add and addi
NOT (Aout AND Bin) WHEN "01", -- nand and not
Aout(6 downto 0)&'0' WHEN OTHERS; --shift
-- zero and neg flag control
zne <= '1' WHEN addi='1' OR add='1' OR inand='1'
OR isll='1' OR inot='1' ELSE
'0' ;
--
***********************************
-- Timing, reset, and register updates
PROCESS (clk, reset) BEGIN
IF reset='1' THEN
pc
<= "00000000"; -- reset to address zero
ir
<= "00000000"; -- inst is equiv to clear reg 0
r3
<= "11111111"; -- for testing
fetch
<= '1';
exec <= '0';
ELSIF (clk='1' AND clk'event) THEN
IF
fetch='1' THEN
ir <= data;
fetch
<= '0';
exec <= '1';
ELSE
pc
<= PCin;
fetch <= '1';
exec
<= '0';
IF we='1' THEN
CASE ASel IS
WHEN "00" => r0 <=
rdata;
WHEN
"01" => r1 <= rdata;
WHEN "10" => r2 <=
rdata;
WHEN
"11" => r3 <= rdata;
WHEN OTHERS => NULL;
END CASE;
END
IF;
IF
zne='1' THEN
n
<= aluout(7);
IF aluout=0 THEN
z <= '1';
ELSE
z <= '0';
END IF;
END
IF;
END IF;
END IF;
END PROCESS;
END one;