Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
ram_adr_i
ram_data_o
ram_data_i
clk
reset
ram_wr_i
ram_en_i
Ram (Read)
architecture sim of mc8051_ram is
type ram_type is array (127 downto 0) of unsigned(7 downto 0);
signal gpram: ram_type; -- general purpose RAM
begin
---------- ram_read ----------
p_read : process (clk, reset)
begin
if reset='1' then
ram_data_o <= "00000000";
else
if Rising_Edge(clk) then
ram_data_o <= std_logic_vector(gpram(conv_integer(unsigned(ram_adr_i))));
end if;
end if;
end process p_read;
Ram (Write)
---------- ram_write ----------
p_write : process (clk, reset, ram_en_i)
begin
if reset='1' then
gpram <= (others => (others =>'0')); -- reset every bit
else
if Rising_Edge(clk) then
if ((ram_en_i='1') and (ram_wr_i='1')) then
gpram(conv_integer(unsigned(ram_adr_i))) <= unsigned(ram_data_i);
end if;
end if;
end if;
end process p_write;
end sim;
Ramx (Entity)
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
------------------------ ENTITY DECLARATION -------------------------
entity mc8051_ramx is
port (clk : in std_logic; -- clock signal
reset : in std_logic; -- reset signal
ram_data_i : in std_logic_vector(7 downto 0); -- data input
ram_data_o : out std_logic_vector(7 downto 0); -- data output
ram_adr_i : in std_logic_vector(15 downto 0); -- adresses
ram_wr_i : in std_logic); -- read=0, write=1
end mc8051_ramx;
Ramx (Architecture)
architecture sim of mc8051_ramx is
type ram_type is array (65535 downto 0) of bit_vector(7 downto 0);
begin
p_readwrite : process (clk, reset)
variable gpram: ram_type; -- general purpose RAM
begin
if reset='1' then
ram_data_o <= "00000000";
gpram := (others => (others =>'0')); -- reset every bit
else
if Rising_Edge(clk) then
ram_data_o <= to_stdlogicvector(gpram(conv_integer(unsigned(ram_adr_i))));
if ram_wr_i='1' then
gpram(conv_integer(unsigned(ram_adr_i))) := to_bitvector(ram_data_i);
end if;
end if;
end if;
end process p_readwrite;
end sim;
Rom (Entity)
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_textio.all;
library STD;
use STD.textio.all;
------------------------ ENTITY DECLARATION -------------------------
entity mc8051_rom is
generic (c_init_file : string := "mc8051_rom.dua");
port (clk : in std_logic; -- clock signal
reset : in std_logic; -- reset signal
rom_data_o : out std_logic_vector(7 downto 0); -- data output
rom_adr_i : in std_logic_vector(15 downto 0)); -- adresses
end mc8051_rom;
Ram Block Diagram
rom_adr_i integer
rom_adr_i
rom_data_o clk
reset
rom_en_i
Rom (Architecture)
architecture sim of mc8051_rom is
type rom_type is array (65535 downto 0) of bit_vector(7 downto 0);
signal s_init : boolean := false;
Begin
---------- rom_read ----------
p_read : process (clk, reset, rom_adr_i)
variable v_loop : integer;
variable v_line : line;
variable v_rom_data : rom_type;
file f_initfile : text is in c_init_file;
begin
if (not s_init) then
v_loop := 0;
while ((not endfile(f_initfile) and (v_loop < 65535))) loop
readline(f_initfile,v_line);
read(v_line,v_rom_data(v_loop));
v_loop := v_loop + 1;
end loop;
s_init <= true;
end if;
if (clk'event and (clk = '1')) then -- rising clock edge
rom_data_o <= to_stdlogicvector(v_rom_data(conv_integer(unsigned(rom_adr_i))));
end if;
end process p_read;
end sim;
Testbench
architecture sim of tb_mc8051_top is
function FUNC_PULLUP (signal s_bidir_line : in std_logic) return
std_logic is
end FUNC_PULLUP;
begin
i_mc8051_top : mc8051_top
port map ();
gen_portmodel : for i in 0 to 7 generate
end generate;
p_run : process
begin
reset <= '1';
wait for one_period + one_period/2 + 5 ns;
reset <= '0';
wait for one_period * 5000;
wait for one_period / 2;
assert false report "END OF SIMULATION" severity failure;
end process p_run;
-- system clock definition
p_clock : process
variable v_loop1 : integer;
begin
clk <= '0';
wait for one_period/2;
while true loop
clk <= not clk;
wait for one_period/2;
end loop;
end process p_clock;
--------------------------------------
end sim;
Test
Bench
CPU
ROM
RAM
Reset
Clock
Configurable Mudules
-----------------------------------------------------------------------------
-- Select how many timer/counter units should be implemented
-- Default: 1
constant C_IMPL_N_TMR : integer := 1;
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Select how many serial interface units should be implemented
-- Default: C_IMPL_N_TMR ---(DO NOT CHANGE!)---
constant C_IMPL_N_SIU : integer := C_IMPL_N_TMR;
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Select how many external interrupt-inputs should be
implemented
-- Default: C_IMPL_N_TMR ---(DO NOT CHANGE!)---
constant C_IMPL_N_EXT : integer := C_IMPL_N_TMR;
-----------------------------------------------------------------------------
mc8051_p.vhd
Configurable Modules (contd.)
entity control_mem is
port {
all_tcon_tr0_o : out std_logic_vector(C_IMPL_N_TMR-1
downto 0);
};
architecture rtl of control_mem is
for_tmr:
for i in 0 to C_IMPL_N_TMR-1 generate
end generate for_tmr;
end rtl;
Use constant
instead of
Generic
Configurable Modules
(contd.)
for i in 0 to C_IMPL_N_TMR-1 loop
end loop;
type t_tmr_lv is
array(C_IMPL_N_TMR-1 downto 0) of
std_logic_vector(7 downto 0);
Select
Timer /
Counter
Using TSEL to
select which
module to use
mc8051_alu_struc.vhd
ADDSUB_CORE
Half carry bit, so the 8-bit
adder will e implemented
by 2 4-bit adder
one carry, one
auxiliary-carry
Addsub_cy &
addsub_ovcy
Module addsub_cy
architecture rtl of addsub_cy is
begin
p_addsub: process (opa_i, opb_i, addsub_i, cy_i)
variable v_a : unsigned(DWIDTH downto 0);
variable v_b : unsigned(DWIDTH downto 0);
variable v_result : std_logic_vector(DWIDTH+1 downto 0);
begin -- process p_addsub
v_a(DWIDTH downto 1) := unsigned(opa_i);
v_b(DWIDTH downto 1) := unsigned(opb_i);
if addsub_i = '1' then -- add or sub
v_a(0) := '1';
v_b(0) := cy_i;
v_result := conv_unsigned(v_a,DWIDTH+2) + v_b; -- add operation
else
v_a(0) := '0';
v_b(0) := cy_i;
v_result := conv_unsigned(v_a,DWIDTH+2) - v_b; -- sub operation
end if;
cy_o <= v_result(DWIDTH+1);
rslt_o <= v_result(DWIDTH downto 1);
end process p_addsub;
end rtl;
So that the + function
will get a sum 1 bit longer
opa_i
opb_i
cy_i
0/1
cy_o
rslt_o
Append an extra
bit to handle carry
else
v_a(0) := '0';
v_b(0) := cy_i;
v_result := conv_unsigned(v_a,DWIDTH+1) - unsigned(v_b);
v_la(0) := '0';
v_lb(0) := v_result(DWIDTH);
v_lresult := conv_unsigned(v_la,3) - unsigned(v_lb);
end if;
cy_o <= v_lresult(2);
ov_o <= (v_result(DWIDTH) and not(v_lresult(2))) or
(v_lresult(2) and not(v_result(DWIDTH)));
rslt_o(DWIDTH-2 downto 0) <= v_result(DWIDTH-1 downto 1);
rslt_o(DWIDTH-1) <= v_lresult(1);
end process p_addsub_ov;
end generate gen_greater_one;
end rtl;
Module sddsub_ovcy
architecture rtl of addsub_ovcy is
begin
gen_greater_one: if (DWIDTH > 1) generate
p_addsub_ov: process (opa_i, opb_i, addsub_i, cy_i)
variable v_a : unsigned(DWIDTH-1 downto 0);
variable v_b : unsigned(DWIDTH-1 downto 0);
variable v_result : std_logic_vector(DWIDTH downto 0);
variable v_la : unsigned(1 downto 0);
variable v_lb : unsigned(1 downto 0);
variable v_lresult : std_logic_vector(2 downto 0);
begin -- process p_addsub
v_a(DWIDTH-1 downto 1) := unsigned(opa_i(DWIDTH-2 downto 0));
v_b(DWIDTH-1 downto 1) := unsigned(opb_i(DWIDTH-2 downto 0));
v_la(1) := opa_i(DWIDTH-1);
v_lb(1) := opb_i(DWIDTH-1);
if addsub_i = '1' then
v_a(0) := '1';
v_b(0) := cy_i;
v_result := conv_unsigned(v_a,DWIDTH+1) + unsigned(v_b);
v_la(0) := '1';
v_lb(0) := v_result(DWIDTH);
v_lresult := conv_unsigned(v_la,3) + unsigned(v_lb);
opa_i(2:0)
opb_i (2:0)
opa_i(3)
opb_i (3)
0/1
cy_i
Carry out
from bit 7
Carry out
from bit 6
The add operation is separate
into 2, add of bit2~0 and add
of bit 3. The separation of
add operation help find
overflow
ALU
Module
architecture rtl of alucore is
constant LAND : std_logic_vector(3 downto 0) := "0011";
constant LOR : std_logic_vector(3 downto 0) := "0101";
constant LXOR : std_logic_vector(3 downto 0) := "0110";
constant RL : std_logic_vector(3 downto 0) := "0111";
begin -- architecture structural
p_alu: process (alu_cmd_i, op_a_i, op_b_i, cy_i)
begin
case alu_cmd_i is
-----------------------------------------------------------
when LAND => -- op_a_i and op_b_i
result_o <= op_a_i and op_b_i;
cy_o <= cy_i;
-----------------------------------------------------------
when LOR => -- op_a_i or op_b_i
result_o <= op_a_i or op_b_i;
cy_o <= cy_i;
-----------------------------------------------------------
when LXOR => -- op_a_i xor op_b_i
result_o <= op_a_i xor op_b_i;
cy_o <= cy_i;
-----------------------------------------------------------
end case;
end process p_alu;
end rtl;
ALUMUX
Module
ALUMUX
addsub_core
alucore
dcml_adjust
comb_divider
comb_mltplr
Connect
wires
according to
different
input
instruction
ALUMUX
Module
(VHDL)
architecture rtl of alumux is
constant DA : std_logic_vector(5 downto 0) := "100000";
constant ADD_ACC_RAM : std_logic_vector(5 downto 0) := "100001";
constant AND_ACC_RAM : std_logic_vector(5 downto 0) := "100101";
...
Begin
process ()
begin
case cmd_i is
when AND_ACC_RAM =>
alu_cmd_o <= LAND;
op_a_o <= acc_i;
op_b_o <= ram_data_i;
when AND_ACC_ROM =>
...;
end case;
end process;
end rtl;
Timer /
Counter
Mc8051_tmrctr_rtl.vhd
Code structure
Clk/16
Falling Edge Detection
& Synchronize
Timer/Counter 0
Mode 0
Timer/Counter 0
Mode 0
Timer/Counter 1
Mode 1
Timer/Counter 0
Mode 1
Timer/Counter 1
Mode 2
Timer/Counter 0
Mode 2
Timer/Counter 1
Mode 3
Timer/Counter 0
Mode 3
Timer/Counter 1
Falling Edge Detection
& Synchronize
Timer/Counter 1
Timer / Counter (clock)
s_count_enable <= '1' when s_pre_count =
conv_unsigned(15,4) else '0';
p_divide_clk: process (clk, reset)
begin
if reset = '1' then
s_pre_count <= conv_unsigned(0,4);
else
if clk'event and clk='1' then
s_pre_count <= s_pre_count + conv_unsigned(1,1);
end if;
end if;
end process p_divide_clk;
Clk16
Conv_unsigned(value, bit_length)
Timer / Counter
(edge detection)
s_ext_edge0 <= '1' when (s_t0ff1 = '0' and s_t0ff2 = '1') else '0';
p_sample_t0: process (clk, reset)
begin
if reset = '1' then
s_t0ff0 <= '0';
s_t0ff1 <= '0';
s_t0ff2 <= '0';
else
if clk'event and clk = '1' then
if s_pre_count = conv_unsigned(6,3) then
if s_c_t0 = '1' then
s_t0ff0 <= t0_i;
s_t0ff1 <= s_t0ff0;
s_t0ff2 <= s_t0ff1;
end if;
end if;
end if;
end if;
end process p_sample_t0;
D Q
CLK
D Q
CLK
D Q
CLK
t0_i s_t0ff0 s_t0ff1 s_t0ff2
s_ext_edge0
Timer / Counter (VHDL
Structure)
case s_mode0 is
when "00" =>
...;
when "01" =>
...;
when "10" =>
...;
when "11" =>
...;
when others => null;
end case;
Mode 0
Mode 1
Mode 2
Mode 3
Timer / Counter (TCON)
Timer / Counter (TMOD)
Mode 0, 13-bit Timer
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' or (s_ext_edge0 = '1' and s_c_t0 = '1') then
if s_count0 = conv_unsigned(8191,16) then
s_tf0 <= '1';
else
s_tf0 <= '0';
end if;
end if;
end if;
end if;
8191 = 2
13
- 1
Clock/16
Mode 0, 13-bit Timer (contd.)
if wt_i = "00" and wt_en_i = '1' then
s_countl0 <= unsigned(reload_i);
else
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' then
if s_count0 = conv_unsigned(8191,16) then
s_countl0 <= conv_unsigned(0,8);
else
s_countl0 <= s_countl0 + conv_unsigned(1,1);
end if;
else
if s_ext_edge0 = '1' then
if s_count0 = conv_unsigned(8191,16) then
s_countl0 <= conv_unsigned(0,8);
else
s_countl0 <= s_countl0 + conv_unsigned(1,1);
end if;
end if;
end if;
end if;
end if;
end if;
if wt_i = "10" and wt_en_i = '1' then
s_counth0 <= unsigned(reload_i);
else
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' then
if s_count0 = conv_unsigned(8191,16) then
s_counth0 <= conv_unsigned(0,8);
else
if s_countl0 = conv_unsigned(255,8) then
s_counth0 <= s_counth0 + conv_unsigned(1,1);
end if;
end if;
else
if s_ext_edge0 = '1' then
if s_count0 = conv_unsigned(8191,16) then
s_counth0 <= conv_unsigned(0,8);
else
if s_countl0 = conv_unsigned(255,8) then
s_counth0 <= s_counth0 + conv_unsigned(1,1);
end if;
end if;
end if;
end if;
end if;
end if;
end if;
Clock/16
Timer mode or Counter mode?
Higher bits
counts when
low bits
count to 255
Reload low 8 bit Reload low bits
Mode 1, 16-bit Timer
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' or (s_ext_edge0 = '1' and s_c_t0 = '1') then
if s_count0 = conv_unsigned(65535,16) then
s_tf0 <= '1';
else
s_tf0 <= '0';
end if;
end if;
end if;
end if;
2
15
-1=65535
Clock/16
Mode 1, 16-bit Timer (contd.)
if wt_i = "00" and wt_en_i = '1' then
s_countl0 <= unsigned(reload_i);
else
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' then
if s_count0 = conv_unsigned(65535,16) then
s_countl0 <= conv_unsigned(0,8);
else
s_countl0 <= s_countl0+ conv_unsigned(1,1);
end if;
else
if s_ext_edge0 = '1' then
if s_count0 = conv_unsigned(65535,16) then
s_countl0 <= conv_unsigned(0,8);
else
s_countl0 <= s_countl0+conv_unsigned(1,1);
end if;
end if;
end if;
end if;
end if;
end if;
if wt_i = "10" and wt_en_i = '1' then
s_counth0 <= unsigned(reload_i);
else
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' then
if s_count0 = conv_unsigned(65535,16) then
s_counth0 <= conv_unsigned(0,8);
else
if s_countl0 = conv_unsigned(255,8) then
s_counth0 <= s_counth0 + conv_unsigned(1,1);
end if;
end if;
else
if s_ext_edge0 = '1' then
if s_count0 = conv_unsigned(65535,16) then
s_counth0 <= conv_unsigned(0,8);
else
if s_countl0 = conv_unsigned(255,8) then
s_counth0 <= s_counth0 + conv_unsigned(1,1);
end if;
end if;
end if;
end if;
end if;
end if;
end if;
Higher bits
counts when
low bits
count to 255
Clock/16
Timer mode or Counter mode?
Reload high 8 bit Reload low 8 bit
Mode 2, 8-bit, auto-reload
if wt_i = "00" and wt_en_i = '1' then
s_countl0 <= unsigned(reload_i);
else
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' then
if s_countl0 = conv_unsigned(255,8) then
s_countl0 <= s_counth0;
else
s_countl0 <= s_countl0 + conv_unsigned(1,1);
end if;
else
if s_ext_edge0 = '1' then
if s_countl0 = conv_unsigned(255,8) then
s_countl0 <= s_counth0;
else
s_countl0 <= s_countl0 + conv_unsigned(1,1);
end if;
end if;
end if;
end if;
end if;
end if;
if wt_i = "10" and wt_en_i = '1' then
s_counth0 <= unsigned(reload_i);
end if;
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' or (s_ext_edge0 = '1' and s_c_t0 = '1') then
if s_count0(7 downto 0) = conv_unsigned(255,16) then
s_tf0 <= '1';
else
s_tf0 <= '0';
end if;
end if;
end if;
end if;
Clock/16
Timer mode or Counter mode?
Reload low 8-bit
count with high 8-bit
User write high 8-bit
of the counter
Clock/16
Mode 3, 2 8-bit timer/counter
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' or (s_ext_edge0 = '1' and s_c_t0 = '1') then
if s_count0(7 downto 0) = conv_unsigned(255,16) then
s_tf0 <= '1';
else
s_tf0 <= '0';
end if;
end if;
end if;
end if;
Clock/16
Mode 3, 2 8-bit timer/Counter
if wt_i = "00" and wt_en_i = '1' then
s_countl0 <= unsigned(reload_i);
else
if s_tmr_ctr0_en = '1' then
if s_count_enable = '1' then
if s_c_t0 = '0' then
if s_countl0 = conv_unsigned(255,8) then
s_countl0 <= conv_unsigned(0,8);
else
s_countl0 <= s_countl0 + conv_unsigned(1,1);
end if;
else
if s_ext_edge0 = '1' then
if s_countl0 = conv_unsigned(255,8) then
s_countl0 <= conv_unsigned(0,8);
else
s_countl0 <= s_countl0 + conv_unsigned(1,1);
end if;
end if;
end if;
end if;
end if;
end if;
if tcon_tr1_i = '1' then
if s_count_enable = '1' then
if s_count0(15 downto 8) = conv_unsigned(255,8) then
s_tf1 <= '1';
else
s_tf1 <= '0';
end if;
end if;
end if;
if wt_i = "10" and wt_en_i = '1' then
s_counth0 <= unsigned(reload_i);
else
if tcon_tr1_i = '1' then
if s_count_enable = '1' then
if s_counth0 = conv_unsigned(255,8) then
s_counth0 <= conv_unsigned(0,8);
else
s_counth0 <= s_counth0 + conv_unsigned(1,1);
end if;
end if;
end if;
end if;
Reload low 8 bit
Note that the high 8-bit
counter is controlled by
Timer 1 register bit
instead of timer 0
Reload high 8 bit
Mc8051_control
Control_fsm &
Control_mem
Control_fsm
Main state machine
Set command signals for Control_mem
Control_mem
Fulfill command from command signals of
Control_fsm
Control_fsm & Control_mem
(Block Diagram)
FETCH
EXEC1
EXEC2
EXEC1
EXEC2
EXEC1
Control_FSM
I nternal
register &
memory
operation
command
Control_MEM
Internal
Memory
Internal
Registers
Control_fsm
architecture rtl of control_fsm is
...
Begin
...
s_instr_category <= - - Analysis instruction
IC_ACALL when s_command(4 downto 0) = ACALL else
IC_ADD_A_RR when s_command(7 downto 3) = ADD_A_RR else
...
p_state: process (...)
begin
...
if (...) then -- startup
NULL;
else
if (...) then -- Execute interrupt operation
...
Else
... -- Execute normal instruction
end if;
end if;
end process p_state;
end rtl;
Find category
of the
instruction
Process
Interrupt
If Interrupt
Process
Instruction
Find Catalog of The
Instruction
s_instr_category <=
IC_ACALL when s_command(4 downto 0) = ACALL else
IC_ADD_A_RR when s_command(7 downto 3) = ADD_A_RR else
IC_ADD_A_D when s_command = ADD_A_D else
IC_ADD_A_ATRI when s_command(7 downto 1)= ADD_A_ATRI else
IC_XRL_D_DATA when s_command = XRL_D_DATA else
IC_NOP;
Interrupt Operation
if state=FETCH then
...
s_nextstate <= EXEC1;
elsif state=EXEC1 then
...
s_nextstate <= EXEC2;
elsif state=EXEC2 then
...
s_nextstate <= EXEC3;
elsif state=EXEC3 then
...
s_nextstate <= FETCH;
else
s_nextstate <= FETCH;
end if;
Increase SP
Reset
interrupt
flag
Save
PC(7~0)
Save
PC(15~8) &
Reload PC
with interrupt
vector
Execute Instruction
case s_instr_category is
when IC_ACALL => -- ACALL addr11
if state=FETCH then
...
s_nextstate <= EXEC1;
elsif state=EXEC1 then
...
s_nextstate <= FETCH;
end if;
when IC_ADD_A_RR => -- ADD A,Rr
if state=FETCH then
...
s_nextstate <= EXEC1;
elsif state=EXEC1 then
...
s_nextstate <= FETCH;
end if;
when ...
...
when others =>
nextstate <= FETCH;
end case;
FETCH
EXEC1
EXEC2
-- update state machine
if rising_edge(clk) then
state <= s_nextstate;
Execute Instruction
(IC_ACCAL)
when IC_ACALL => -- ACALL addr11
if state=FETCH then
s_adr_mux <= "1111"; -- adress = sp + 1
s_data_mux <= "1110"; -- data = (pc+2)(7 downto 0)
s_regs_wr_en <= "101"; -- write one byte and increment SP
s_help16_en <= "10"; -- s_help16 = pc+2
s_pc_inc_en <= "0001"; -- increment program-counter
s_nextstate <= EXEC1;
elsif state=EXEC1 then
s_adr_mux <= "1111"; -- adress = sp + 1
s_data_mux <= "1101"; -- data = s_help16(15 downto 8)
s_regs_wr_en <= "101"; -- write one byte and increment SP
s_pc_inc_en <= "0100"; -- load PC with 11 bits (2k block)
s_nextstate <= FETCH;
end if;
Operation
command to
control_mem
module
Control_mem
Internal RAM Address
Internal RAM Data
Internal Register
Internal Memory
OperationCommand
Internal
Registers
Internal
RAM