R
Rafal Pietrak
Guest
Hi,
I'm playing with Tim BĂśscke "Minimal 8 Bit CPU" code some time ago found
at: http://www.tu-harburg.de/~setb0209/cpu/ (currently unaccesable, but
may be google can reveal other repositories).
My code is now significantly different from the original, but the basic
functionality remains: The CPU has 2-bits for instruction code and 6-bits
of address space.
And all was well until I tried to change instruction encoding (the
complete source of the CPU is at the tail of the post). The CPU
synthesizes to 35 macrocells of xc9536xl CPLD.
But when encoding changes to "new instruction encoding" listed below in
source header, Xilinx WebPack is not able to put it in fewer then 45
macrocells!
The instruction encoding values are used solely in a few comparations at
the end of the source (marked by "HERE" comment) - this should be easily
implemented within product terms block. But it isn't!! And that encoding
changes synthesize result dramatically!
Can someone shred some light on possible reasons? I've just started to use
enumerated type variable wherever 'state decoding' apply, but this example
shows, that synthesizer may not be entirely trusted with optimal
synthesize of arbitrary 'codes' encoding/decoding logic.
So:
1. Is there an explanation on why the synthesizer runs away with so slight
(and unimportant) source changes?
2. Is there a way to know, that synthesizer 'fell into disoptimization'?
(this is *very* simple design - the problem is easily spotted, yet I would
have have problems seeing it existed if I wasn't so lucky to choose the
*correct* encoding in the first run.
3. Is there a way to hint synthesizer (like VHDL statements) on 'proper'
encoding - leading to optimized synthesize? How would I know which
encoding is 'fine' for synthesizer, and which isn't.
Any comments appreciated!
-R
---------------------------------------------------------------
--
-- Minimal 8 Bit CPU
--
-- new instruction encoding (for OPCODE):
-- 00 - JCC (branch if carry clear, clear carry)
-- 01 - ADD
-- 10 - NOR
-- 11 - STA
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity CPU8BIT2 is
port ( data: inout std_logic_vector(7 downto 0);
adress: out std_logic_vector(5 downto 0);
oe, we: out std_logic; -- Asynchronous memory interface
clk, rst: in std_logic);
end;
architecture CPU_ARCH of CPU8BIT2 is
signal akku, state: std_logic_vector(8 downto 0); -- akku(8) is carry !
signal pc: std_logic_vector(5 downto 0);
alias execute: std_logic is state(8);
alias opcode: std_logic_vector(1 downto 0) is state(7 downto 6);
alias adreg: std_logic_vector(5 downto 0) is state(5 downto 0);
begin
process(clk,rst)
begin
if (rst = '0') then
state <= (others => '0');
akku <= (others => '0');
pc <= (others => '0'); -- start execution at memory location 0
elsif rising_edge(clk) then
if (execute = '0') then -- instruction fetch
pc <= adreg + 1;
state <= '1' & data; -- fetch the instruction/address
else -- instruction execution
state <= "000" & pc;
if (opcode = "00") then
if (akku(8) = '1') then
akku(8) <= '0'; -- ... branch NOT taken, just clear CARRY
else
pc <= adreg + 1; -- branch taken... fetch instruction there
state <= '1' & data;
end if;
elsif (opcode = "10") then -- HERE!!
akku <= ("0" & akku(7 downto 0)) + data + akku(8);
elsif (opcode = "11") then -- HERE!!
akku(7 downto 0) <= akku(7 downto 0) nor data;
end if;
end if;
end if;
end process;
-- combinational logic (.... HERE!! ... changes to OPCODE encoding)
adress <= adreg;
data <= "ZZZZZZZZ" when opcode /= "01" else akku(7 downto 0);
we <= '1' when (clk='1' or opcode /= "01" or rst='0') else '0'; -- state "101" (branch not taken)
oe <= '1' when (clk='1' or opcode = "01" or rst='0') else '0'; -- no memory access during reset and
end CPU_ARCH;
I'm playing with Tim BĂśscke "Minimal 8 Bit CPU" code some time ago found
at: http://www.tu-harburg.de/~setb0209/cpu/ (currently unaccesable, but
may be google can reveal other repositories).
My code is now significantly different from the original, but the basic
functionality remains: The CPU has 2-bits for instruction code and 6-bits
of address space.
And all was well until I tried to change instruction encoding (the
complete source of the CPU is at the tail of the post). The CPU
synthesizes to 35 macrocells of xc9536xl CPLD.
But when encoding changes to "new instruction encoding" listed below in
source header, Xilinx WebPack is not able to put it in fewer then 45
macrocells!
The instruction encoding values are used solely in a few comparations at
the end of the source (marked by "HERE" comment) - this should be easily
implemented within product terms block. But it isn't!! And that encoding
changes synthesize result dramatically!
Can someone shred some light on possible reasons? I've just started to use
enumerated type variable wherever 'state decoding' apply, but this example
shows, that synthesizer may not be entirely trusted with optimal
synthesize of arbitrary 'codes' encoding/decoding logic.
So:
1. Is there an explanation on why the synthesizer runs away with so slight
(and unimportant) source changes?
2. Is there a way to know, that synthesizer 'fell into disoptimization'?
(this is *very* simple design - the problem is easily spotted, yet I would
have have problems seeing it existed if I wasn't so lucky to choose the
*correct* encoding in the first run.
3. Is there a way to hint synthesizer (like VHDL statements) on 'proper'
encoding - leading to optimized synthesize? How would I know which
encoding is 'fine' for synthesizer, and which isn't.
Any comments appreciated!
-R
---------------------------------------------------------------
--
-- Minimal 8 Bit CPU
--
-- new instruction encoding (for OPCODE):
-- 00 - JCC (branch if carry clear, clear carry)
-- 01 - ADD
-- 10 - NOR
-- 11 - STA
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity CPU8BIT2 is
port ( data: inout std_logic_vector(7 downto 0);
adress: out std_logic_vector(5 downto 0);
oe, we: out std_logic; -- Asynchronous memory interface
clk, rst: in std_logic);
end;
architecture CPU_ARCH of CPU8BIT2 is
signal akku, state: std_logic_vector(8 downto 0); -- akku(8) is carry !
signal pc: std_logic_vector(5 downto 0);
alias execute: std_logic is state(8);
alias opcode: std_logic_vector(1 downto 0) is state(7 downto 6);
alias adreg: std_logic_vector(5 downto 0) is state(5 downto 0);
begin
process(clk,rst)
begin
if (rst = '0') then
state <= (others => '0');
akku <= (others => '0');
pc <= (others => '0'); -- start execution at memory location 0
elsif rising_edge(clk) then
if (execute = '0') then -- instruction fetch
pc <= adreg + 1;
state <= '1' & data; -- fetch the instruction/address
else -- instruction execution
state <= "000" & pc;
if (opcode = "00") then
if (akku(8) = '1') then
akku(8) <= '0'; -- ... branch NOT taken, just clear CARRY
else
pc <= adreg + 1; -- branch taken... fetch instruction there
state <= '1' & data;
end if;
elsif (opcode = "10") then -- HERE!!
akku <= ("0" & akku(7 downto 0)) + data + akku(8);
elsif (opcode = "11") then -- HERE!!
akku(7 downto 0) <= akku(7 downto 0) nor data;
end if;
end if;
end if;
end process;
-- combinational logic (.... HERE!! ... changes to OPCODE encoding)
adress <= adreg;
data <= "ZZZZZZZZ" when opcode /= "01" else akku(7 downto 0);
we <= '1' when (clk='1' or opcode /= "01" or rst='0') else '0'; -- state "101" (branch not taken)
oe <= '1' when (clk='1' or opcode = "01" or rst='0') else '0'; -- no memory access during reset and
end CPU_ARCH;