CPUとFPGAのバス接続

CPUとFPGAのバス接続

更新日: 2021-03-31

CPU-FPGA間のバス接続 #

CPUからFPGAのレジスタを読み書きする場合を考える。

外部接続バス #

CPUの外部バスタイミングは下記の通り(RA6M3のデータシートから抜粋)。

Parameter Symbol Min Max Unit
Address delay tAD - 12.5 ns
CS delay tCSD - 12.5 ns
RDn delay tRSD - 12.5 ns
Read data setup time tRDS 12.5 - ns
Read data hold time tRDH 0 - ns
WRn delay tWRD - 12.5 ns
Write data delay tWDD - 12.5 ns
Write data hold time tWDH 0 - ns

見ての通り、CPUから出力される信号はクロックの立ち上がりと同期しているので、FPGA側の設計は簡単です。wrがhighになっているときにdataをclkでラッチしてあげれば良い。このタイミングだと2回ラッチすることになるが、問題にならないことが多いだろう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity bus_interface is
    port (
        clk      : in std_logic;
        reset    : in std_logic;
        address  : in std_logic_vector(7 downto 0);
        data_in  : in std_logic_vector(15 downto 0);
        ce       : in std_logic;
        wr       : in std_logic;
        rd       : in std_logic;
        data_out : out std_logic_vector(15 downto 0)
    );
end bus_interface;

architecture rtl of bus_interface is
    signal we        : std_logic;
    signal reg_x00   : std_logic_vector(15 downto 0);
    signal reg_x01   : std_logic_vector(15 downto 0);
    signal read_data : std_logic_vector(15 downto 0);
begin
    we <= ce and wr;
    ---------------------
    -- write processes --
    ---------------------
    process (clk, reset) begin
        if reset = '1' then
            reg_x00 <= (others => '0');
        elsif rising_edge(clk) then
            if we = '1' and address = X"00" then
                reg_x00 <= data_in;
            end if;
        end if;
    end process;
    process (clk, reset) begin
        if reset = '1' then
            reg_x01 <= (others => '0');
        elsif rising_edge(clk) then
            if we = '1' and address = X"01" then
                reg_x01 <= data_in;
            end if;
        end if;
    end process;

    --------------------
    -- read processes --
    --------------------
    with (address) select
    data_out <= reg_x00 when X"00",
        reg_x01 when X"01",
        (others => '0') when others;

end rtl;

タイミング制約は下記の通り。正確にはdata_outも制約する必要があるが、十分余裕があるので通常不要だろう。

#**************************************************************
# Create Clock
#**************************************************************

create_clock -name {clk} -period 16.666 -waveform { 0.000 8.333 } [get_ports clk]
create_clock -name {vclk} -period 16.666 -waveform { 0.000 8.333 }

#**************************************************************
# Set Input Delay
#**************************************************************

set_input_delay -add_delay -max -clock [get_clocks {vclk}]  12.500 [get_ports {address[*]}]
set_input_delay -add_delay -max -clock [get_clocks {vclk}]  12.500 [get_ports {ce}]
set_input_delay -add_delay -max -clock [get_clocks {vclk}]  12.500 [get_ports {data_in[*]}]
set_input_delay -add_delay -max -clock [get_clocks {vclk}]  12.500 [get_ports {rd}]
set_input_delay -add_delay -max -clock [get_clocks {vclk}]  12.500 [get_ports {wr}]

set_input_delay -add_delay -min -clock [get_clocks {vclk}]  0 [get_ports {address[*]}]
set_input_delay -add_delay -min -clock [get_clocks {vclk}]  0 [get_ports {ce}]
set_input_delay -add_delay -min -clock [get_clocks {vclk}]  0 [get_ports {data_in[*]}]
set_input_delay -add_delay -min -clock [get_clocks {vclk}]  0 [get_ports {rd}]
set_input_delay -add_delay -min -clock [get_clocks {vclk}]  0 [get_ports {wr}]

#**************************************************************
# Set False Path
#**************************************************************

set_false_path -from [get_ports {reset}] 
set_false_path -to [get_ports {data_out[*]}] 
comments powered by Disqus