URL
https://opencores.org/ocsvn/tinycpu/tinycpu/trunk
Subversion Repositories tinycpu
Compare Revisions
- This comparison shows the changes necessary to convert path
/tinycpu/trunk
- from Rev 20 to Rev 21
- ↔ Reverse comparison
Rev 20 → Rev 21
/testbench/carryover_tb.vhd
17,10 → 17,19
SegmentIn: in std_logic_vector(7 downto 0); |
Addend: in std_logic_vector(7 downto 0); --How much to increase DataIn by (as a signed number). Believe it or not, that's the actual word for what we need. |
DataOut: out std_logic_vector(7 downto 0); |
SegmentOut: out std_logic_vector(7 downto 0) |
SegmentOut: out std_logic_vector(7 downto 0); |
Clock: in std_logic |
-- Debug: out std_logic_vector(8 downto 0) |
); |
end component; |
component registerfile is |
port( |
WriteEnable: in regwritetype; |
DataIn: in regdatatype; |
Clock: in std_logic; |
DataOut: out regdatatype |
); |
end component; |
|
|
--Inputs |
32,6 → 41,10
signal DataOut: std_logic_vector(7 downto 0); |
signal SegmentOut: std_logic_vector(7 downto 0); |
-- signal Debug: std_logic_vector(8 downto 0); |
|
signal regwe: regwritetype; |
signal regin: regdatatype; |
signal regout: regdatatype; |
|
signal Clock: std_logic; |
constant clock_period : time := 10 ns; |
45,9 → 58,16
Addend => Addend, |
SegmentIn => SegmentIn, |
DataOut => DataOut, |
SegmentOut => SegmentOut |
SegmentOut => SegmentOut, |
Clock => Clock |
-- Debug => Debug |
); |
regfile: registerfile port map( |
WriteEnable => regwe, |
DataIn => regin, |
Clock => Clock, |
DataOut => regout |
); |
|
-- Clock process definitions |
clock_process :process |
98,6 → 118,25
SegmentIn <= x"00"; |
wait for 10 ns; |
assert (SegmentOut=x"00" and DataOut = x"FE") report "Carryover when not appropriate case 1" severity error; |
|
--practical register test |
regin(0) <= x"10"; |
regwe(0) <= '1'; |
wait for 10 ns; |
regwe(0) <= '0'; |
wait for 10 ns; |
regwe(0) <= '1'; |
DataIn <= regout(0); |
Addend <= x"02"; |
SegmentIn <= x"00"; |
wait for 10 ns; |
regin(0) <= DataOut; |
wait for 10 ns; |
assert(DataOut = x"12") report "practical fail 1" severity error; |
DataIn <= regout(0); |
regin(0) <= DataOut; |
wait for 10 ns; |
assert(DataOut = x"14") report "practical fail 2" severity error; |
|
-- summary of testbench |
assert false |
/testbench/core_tb.vhd
41,11 → 41,11
signal MemWW: std_logic; --memory writeword |
signal MemWE: std_logic; --memory writeenable |
signal MemOut: std_logic_vector(15 downto 0); |
signal MemIn: std_logic_vector(15 downto 0); |
signal MemIn: std_logic_vector(15 downto 0):=x"0000"; |
--general interface |
signal Reset: std_logic; --When this is high, CPU will reset within 1 clock cycles. |
signal Reset: std_logic:='0'; --When this is high, CPU will reset within 1 clock cycles. |
--Enable: in std_logic; --When this is high, the CPU executes as normal, when low the CPU stops at the next clock cycle(maintaining all state) |
signal Hold: std_logic; --when high, CPU pauses execution and places Memory interfaces into high impendance state so the memory can be used by other components |
signal Hold: std_logic:='0'; --when high, CPU pauses execution and places Memory interfaces into high impendance state so the memory can be used by other components |
signal HoldAck: std_logic; --when high, CPU acknowledged hold and buses are in high Z |
--todo: port interface |
|
111,7 → 111,7
|
Reset <= '0'; |
MemIn <= x"0012"; --mov r0, 0xFF |
wait for 10 ns; |
wait for 30 ns; --fetcher needs two clock cycles to catch up |
assert(MemAddr = x"0100") report "Not fetching from correct start address" severity error; |
MemIn <= x"00F1"; --mov r0, 0xF1 |
wait for 10 ns; |
/testbench/fetch_tb.vhd
69,7 → 69,7
Enable <= '1'; |
AddressIn <= x"1234"; |
DataIn <= x"5321"; |
wait for 10 ns; |
wait for 10 ns; |
assert (IROut = x"5321" and AddressOut = x"1234") report "basic operation failure" severity error; |
|
AddressIn <= x"5121"; |
/src/core.vhd
60,7 → 60,8
SegmentIn: in std_logic_vector(7 downto 0); |
Addend: in std_logic_vector(7 downto 0); --How much to increase DataIn by (as a signed number). Believe it or not, that's the actual word for what we need. |
DataOut: out std_logic_vector(7 downto 0); |
SegmentOut: out std_logic_vector(7 downto 0) |
SegmentOut: out std_logic_vector(7 downto 0); |
Clock: in std_logic |
); |
end component; |
component registerfile is |
81,7 → 82,8
|
type ProcessorState is ( |
ResetProcessor, |
FirstFetch, |
FirstFetch1, --the fetcher needs two clock cycles to catch up |
FirstFetch2, |
Execute, |
WaitForMemory, |
HoldMemory |
127,11 → 129,12
); |
carryovercs: carryover port map( |
EnableCarry => CarryCS, |
DataIn => regOut(REGIP), |
SegmentIn => regOut(REGCS), |
DataIn => regIn(REGIP), |
SegmentIn => regIn(REGCS), |
Addend => IPAddend, |
DataOut => IPCarryOut, |
SegmentOut => CSCarryOut |
SegmentOut => CSCarryOut, |
Clock => Clock |
); |
fetcher: fetch port map( |
Enable => fetchEN, |
141,7 → 144,7
IROut => IR, |
AddressOut => MemAddr --this component supports tristate, so no worries about an intermediate signal |
); |
fetcheraddress <= regOut(REGCS) & regOut(REGIP); |
fetcheraddress <= regIn(REGCS) & regIn(REGIP); |
|
|
--opcode shortcuts |
160,23 → 163,37
DebugIR <= IR; |
|
|
|
|
states: process(Clock, reset, hold, state) |
|
decode: process(Clock, Hold, state, IR, inreset, reset, regin, regout, IPCarryOut, CSCarryOut) |
begin |
if rising_edge(Clock) then |
|
--states |
if reset='1' and hold='0' then |
InReset <= '1'; |
state <= ResetProcessor; |
HoldAck <= '0'; |
CarryCS <= '1'; |
CarrySS <= '0'; |
regWE <= (others => '1'); |
regIn <= (others => "00000000"); |
regIn(REGCS) <= x"01"; |
IPAddend <= x"00"; |
fetchEN <= '1'; |
--finish up |
elsif InReset='1' and reset='0' and Hold='0' then --reset is done, start executing |
InReset <= '0'; |
state <= FirstFetch; |
fetchEN <= '1'; |
state <= FirstFetch1; |
elsif Hold = '1' and (state=HoldMemory or state=Execute or state=ResetProcessor) then |
--do not hold immediately if waiting on memory or if waiting on the first fetch of an instruction after reset |
state <= HoldMemory; |
HoldAck <= '1'; |
FetchEN <= '0'; |
MemAddr <= "ZZZZZZZZZZZZZZZZ"; |
MemOut <= "ZZZZZZZZZZZZZZZZ"; |
MemWE <= 'Z'; |
MemWW <= 'Z'; |
elsif Hold='0' and state=HoldMemory then |
if reset='1' or InReset='1' then |
state <= ResetProcessor; |
183,25 → 200,35
else |
state <= Execute; |
end if; |
elsif state=FirstFetch then --we have to let IR get loaded before we can execute. |
FetchEN <= '1'; |
elsif state=FirstFetch1 then --we have to let IR get loaded before we can execute. |
--regWE <= (others => '0'); |
state <= Execute; |
fetchEN <= '1'; --already enabled, but anyway |
regWE <= (others => '0'); |
state <= FirstFetch2; |
elsif state=FirstFetch2 then |
state <= Execute; |
IPAddend <= x"02"; |
SPAddend <= x"00"; --no addend unless pushing or popping |
RegWE <= (others => '0'); |
regIn(REGIP) <= IPCarryOut; |
regWE(REGIP) <= '1'; |
regWE(REGCS) <= '1'; |
regIn(REGCS) <= CSCarryOut; |
end if; |
|
end if; |
end process; |
|
decode: process(Clock, Hold, state, IR, inreset) |
begin |
if rising_edge(Clock) then |
|
|
if state=Execute then |
fetchEN <= '1'; |
--reset to "usual" |
RegIn(REGIP) <= IPCarryOut; |
IPAddend <= x"02"; |
SPAddend <= x"00"; --no addend unless pushing or popping |
RegIn(REGCS) <= CSCarryOut; |
RegWE <= (others => '0'); |
regIn(REGIP) <= IPCarryOut; |
regWE(REGIP) <= '1'; |
regWE(REGCS) <= '1'; |
regIn(REGCS) <= CSCarryOut; |
|
MemWE <= '0'; |
MemWW <= '0'; |
|
215,26 → 242,11
report "Not implemented" severity error; |
--synthesis on |
end case; |
elsif state=ResetProcessor then |
CarryCS <= '1'; |
CarrySS <= '0'; |
regWE <= (others => '1'); |
regIn <= (others => "00000000"); |
regIn(REGCS) <= x"01"; |
fetchEN <= '1'; |
elsif InReset='1' and hold='0' then |
fetchEN <= '1'; |
elsif state=HoldMemory then |
FetchEN <= '0'; |
MemAddr <= "ZZZZZZZZZZZZZZZZ"; |
MemOut <= "ZZZZZZZZZZZZZZZZ"; |
MemWE <= 'Z'; |
MemWW <= 'Z'; |
elsif state=FirstFetch then |
fetchEN <= '1'; --already enabled, but anyway |
elsif state=HoldMemory and hold='0' then |
fetchEN <= '1'; |
end if; |
|
|
|
|
end if; |
end process; |
|
/src/fetch.vhd
29,7 → 29,7
begin |
process(Clock, AddressIn, DataIn) |
begin |
if(rising_edge(Clock)) then |
--if(rising_edge(Clock)) then |
if(Enable='1') then |
IR <= DataIn; |
AddressOut <= AddressIn; |
36,7 → 36,8
else |
AddressOut <= "ZZZZZZZZZZZZZZZZ"; |
end if; |
end if; |
--end if; |
end process; |
--AddressOut <= AddressIn when Enable='1' else "ZZZZZZZZZZZZZZZZ"; |
IROut <= IR; |
end Behavioral; |
/src/carryover.vhd
10,26 → 10,31
SegmentIn: in std_logic_vector(7 downto 0); |
Addend: in std_logic_vector(7 downto 0); --How much to increase DataIn by (as a signed number). Believe it or not, that's the actual word for what we need. |
DataOut: out std_logic_vector(7 downto 0); |
SegmentOut: out std_logic_vector(7 downto 0) |
SegmentOut: out std_logic_vector(7 downto 0); |
Clock: in std_logic |
-- Debug: out std_logic_vector(8 downto 0) |
); |
end carryover; |
|
architecture Behavioral of carryover is |
signal temp: std_logic_vector(8 downto 0); |
signal temp: std_logic_vector(8 downto 0) := "000000000"; |
signal temp2: std_logic_vector(7 downto 0); |
begin |
--treat as unsigned because it doesn't actually matter for addition and just make carry and borrow correct |
process(DataIn, SegmentIn,Addend, EnableCarry) |
|
begin |
temp <= std_logic_vector(unsigned('0' & DataIn) + unsigned( Addend)); |
-- if ('1' and ((not Addend(7)) and DataIn(7) and temp(8)))='1' then |
if (EnableCarry and ((not Addend(7)) and DataIn(7) and not temp(8)))='1' then |
SegmentOut <= std_logic_vector(unsigned(SegmentIn)+1); |
elsif (EnableCarry and (Addend(7) and not DataIn(7) and temp(8)))='1' then |
SegmentOut <= std_logic_vector(unsigned(SegmentIn)-1); |
else |
SegmentOut <= SegmentIn; |
end if; |
--if rising_edge(Clock) then |
temp <= std_logic_vector(unsigned('0' & DataIn) + unsigned( Addend)); |
-- if ('1' and ((not Addend(7)) and DataIn(7) and temp(8)))='1' then |
if (EnableCarry and ((not Addend(7)) and DataIn(7) and not temp(8)))='1' then |
SegmentOut <= std_logic_vector(unsigned(SegmentIn)+1); |
elsif (EnableCarry and (Addend(7) and not DataIn(7) and temp(8)))='1' then |
SegmentOut <= std_logic_vector(unsigned(SegmentIn)-1); |
else |
SegmentOut <= SegmentIn; |
end if; |
--end if; |
end process; |
--Debug <= Temp; |
DataOut <= temp(7 downto 0); |
/docs/design.md.txt
273,9 → 273,16
Carryover is set on CS and not set on SS. DS and ES is 0. TR is false. |
Register bank 0 is selected. |
|
Electrical operation: |
On power-on, RESET should be high for at least 2 clock cycles. HOLD can optionally be high as well after these two clock cycles. |
When HOLD is no longer needed, it should just be turned low and an extra clock cycle should be waited on for it to return to RESET state |
When RESET is held low, the processor will execute. It takes 3 clock cycles for the processor to "catch up" to actually executing instructions |
|
|
|
|
|
|
Implemented opcode list: |
legend: |
r = register choice |