edk/user logic interface

axi_user_logic_4cs_16x1024....

xilinx 2012. 2. 2. 05:27

 

프로세서, USER REGISTER ACCESS

 

일반적으로 FPGA 내부 프로세서를 사용할 경우 FPGA내에 설계하는 사용자 로직과 데이터를 주고받는 경우가 많습니다.

하지만 프로세서가 버스를 통해 user logic 억세스하기 위해서는 버스 신호와 프로토콜을 이해해야 합니다.  정말 지루하고 따분하고 읽어도 읽어도 알아듣지 못할 말로 잔뜩 있는 것이 데이터 시트입니다.

XPS 프로세서를 설계하면 user logic 억세스하는 IP 따로 제공하지 않기 때문에 설계자가 직접 만들어야 합니다.

프로토콜도 알고 있고 프로세서의 동작상황도 알고 있으면 만들 것도 없지만 생소한 프로그램에 낯선 프로세서와 처음 보는 프로토콜에 골탕 먹으면 몹쓸 프로세서로 낙인 찍히기 쉽습니다.

그래서 이번 장에서는 user logic 억세스하기 위한 제가 만든 IP 사용하는 방법에 대해 살펴 보겠습니다.

n 내용 이해하기

일반적으로 임베디드 시스템을 설계하면 일단 프로세서를 기반으로 여러 주변장치들을 버스에 연결하고 동작을 상태를 점검하게 됩니다.

그러면 하나의 FPGA에는 하나의 임베디드 시스템을 구현하게 되는 거지요.

하지만 FPGA 내부에 임베디드 시스템을 하나만 구현하는 경우는 거의 없습니다. 다른 유저로직이 연결 됩니다.

이때 문제는 유저 로직과 임베디드 시스템간에 데이터를 교환해야 하는데 부분이 조금 애매 합니다.

일반적으로 FPGA 설계자라고 한다면 임베디드 시스템과 유저 로직간에 데이터를 주고 받을 필요한 신호 또는 프로토콜은 다음과 같이 생각하는 경우가 많습니다.

자일링스에서 이런 기본적인 IP 만들지 않는지는 모르겠어요.

여러가지 이유가 있겠지만 가장 이유는 같은 사람 고생하라고 하는 것이 아닐까 합니다.

결국에 만들려고 하는 IP 다음 그림과 같이 필요한 신호들을 유저 로직에서 있도록 해주는 입니다.

데이터를 주고 받기 위한 신호들은 정리 했지만 이것을 어떻게 만드느냐?

그리고 실제 읽고 쓰는 타이밍은 어떻게 되는가에 대해서 차례대로 알아보겠습니다.

먼저 신호의 이름을 분석해 보겠습니다.

먼저 데이터 버스는 입력과 출력이 따로 정의된 것을 있습니다. 마스터가 데이터를 출력할 때는 data_to_user 포트를 통해 데이터를 출력하고 데이터 입력은 data_cs[3:0] 따라 data_from_user0 ~ data_from_user3 포트를 통해서 입력된다는 것으로 추정할 있습니다.

어드레스는 모두 10비트 이므로 1024개의 번지를 지정할 있습니다.

User_cs 4비트이고 어드레스가 10비트이고 데이터가 32비트 이므로 4 * 1024 개의 32비트 워드를 디코딩할 있다는 얘기 입니다.

이런 것을 만들기 위해서 어떻게 해야 하는가?

막상 신호 자체는 간단해 보이지만 만들려고 하면 머리가 ~~~ 해지는 것이 사실 입니다.

처음부터 뎀비면 마이 다칩니다.

먼저 자일링스에서 제공하는 기본적인 몇가지 기능을 알아 보도록 하겠습니다.

사실 글을 읽고 있는 분들은 마이크로블레이즈가 어떤 버스에서 어떤 프로토콜을 통해 데이터를 주고 받는지 알지 못할 겁니다.

그러니까 1000 페이지 정도 되는 데이터 쉬트를 읽어 보고 버스와 프로토콜을 이해해 본인 스스로 HDL 코딩하라고 하면 대부분 포기하게 되죠.

그래서 자일링스는 유저 로직을 억세스할 있는 기본 플랫폼을 제시해 줍니다.

이제 기본 플랫폼을 만들어 봅시다.

부분은 비디오 클립으로 보는 것이 좋을 같습니다.

설치된 폴더를 보니까 아래와 같습니다.

$ISE_INSTALL$\ISE_DS\edk_user_repository\MyProcessorIPLib\pcores

폴더 이름은 axi_user_logic_4096x32_4cs_10clk_v1_00_a 입니다.

axi_user_logic_4096x32_4cs_10clk_v1_00_a 폴더 밑에는 3개의 폴더가 기본적으로 있습니다.

Data

Dev

Hdl

여기서 저는 먼저 hdl 폴더에 먼저 관심을 가져 봅니다.

Hdl 폴더 , VHDL 폴더 밑에 보면 axi_user_logic_4096x32_4cs_10clk.vhd 파일과 user_logic.vhd 파일 2개가 있습니다.

먼저 user_logic.vhd 보면 다음과 같습니다.

굳이 코드를 설명하려고 덤비는 이유는 다음과 같습니다. 먼저 버스 트랜잭션, 버스를 통해 데이터를 주고 받을 언제 시작해서 언제 끝냐느냐를 알아야 하는데 이것 땜시 전체 소스를 가져다 붙였습니다.

1   ------------------------------------------------------------------------------

2   -- user_logic.vhd - entity/architecture pair

3   ------------------------------------------------------------------------------

4   --

5   -- ***************************************************************************

6   -- ** Copyright (c) 1995-2011 Xilinx, Inc.  All rights reserved.            **

7   -- **                                                                       **

8   -- ** Xilinx, Inc.                                                          **

9   -- ** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"         **

10  -- ** AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND       **

11  -- ** SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,        **

12  -- ** OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,        **

13  -- ** APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION           **

14  -- ** THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,     **

15  -- ** AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE      **

16  -- ** FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY              **

17  -- ** WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE               **

18  -- ** IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR        **

19  -- ** REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF       **

20  -- ** INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS       **

21  -- ** FOR A PARTICULAR PURPOSE.                                             **

22  -- **                                                                       **

23  -- ***************************************************************************

24  --

25  ------------------------------------------------------------------------------

26  -- Filename:          user_logic.vhd

27  -- Version:           1.00.a

28  -- Description:       User logic.

29  -- Date:              Sat Dec 24 17:14:44 2011 (by Create and Import Peripheral Wizard)

30  -- VHDL Standard:     VHDL'93

31  ------------------------------------------------------------------------------

32  -- Naming Conventions:

33  --   active low signals:                    "*_n"

34  --   clock signals:                         "clk", "clk_div#", "clk_#x"

35  --   reset signals:                         "rst", "rst_n"

36  --   generics:                              "C_*"

37  --   user defined types:                    "*_TYPE"

38  --   state machine next state:              "*_ns"

39  --   state machine current state:           "*_cs"

40  --   combinatorial signals:                 "*_com"

41  --   pipelined or register delay signals:   "*_d#"

42  --   counter signals:                       "*cnt*"

43  --   clock enable signals:                  "*_ce"

44  --   internal version of output port:       "*_i"

45  --   device pins:                           "*_pin"

46  --   ports:                                 "- Names begin with Uppercase"

47  --   processes:                             "*_PROCESS"

48  --   component instantiations:              "<ENTITY_>I_<#|FUNC>"

49  ------------------------------------------------------------------------------

50 

51  -- DO NOT EDIT BELOW THIS LINE --------------------

52  library ieee;

53  use ieee.std_logic_1164.all;

54  use ieee.std_logic_arith.all;

55  use ieee.std_logic_unsigned.all;

56 

57  library proc_common_v3_00_a;

58  use proc_common_v3_00_a.proc_common_pkg.all;

59 

60  -- DO NOT EDIT ABOVE THIS LINE --------------------

61 

62  --USER libraries added here

63 

64  ------------------------------------------------------------------------------

65  -- Entity section

66  ------------------------------------------------------------------------------

67  -- Definition of Generics:

68  --   C_SLV_AWIDTH                 -- Slave interface address bus width

69  --   C_SLV_DWIDTH                 -- Slave interface data bus width

70  --   C_NUM_MEM                    -- Number of memory spaces

71  --

72  -- Definition of Ports:

73  --   Bus2IP_Clk                   -- Bus to IP clock

74  --   Bus2IP_Resetn                -- Bus to IP reset

75  --   Bus2IP_Addr                  -- Bus to IP address bus

76  --   Bus2IP_CS                    -- Bus to IP chip select for user logic memory selection

77  --   Bus2IP_RNW                   -- Bus to IP read/not write

78  --   Bus2IP_Data                  -- Bus to IP data bus

79  --   Bus2IP_BE                    -- Bus to IP byte enables

80  --   Bus2IP_RdCE                  -- Bus to IP read chip enable

81  --   Bus2IP_WrCE                  -- Bus to IP write chip enable

82  --   Bus2IP_Burst                 -- Bus to IP burst-mode qualifier

83  --   Bus2IP_BurstLength           -- Bus to IP burst length

84  --   Bus2IP_RdReq                 -- Bus to IP read request

85  --   Bus2IP_WrReq                 -- Bus to IP write request

86  --   IP2Bus_AddrAck               -- IP to Bus address acknowledgement

87  --   IP2Bus_Data                  -- IP to Bus data bus

88  --   IP2Bus_RdAck                 -- IP to Bus read transfer acknowledgement

89  --   IP2Bus_WrAck                 -- IP to Bus write transfer acknowledgement

90  --   IP2Bus_Error                 -- IP to Bus error response

91  --   Type_of_xfer                 -- Transfer Type

92  ------------------------------------------------------------------------------

93 

94  entity user_logic is

95    generic

96    (

97      -- ADD USER GENERICS BELOW THIS LINE ---------------

98      --USER generics added here

99      -- ADD USER GENERICS ABOVE THIS LINE ---------------

100

101     -- DO NOT EDIT BELOW THIS LINE ---------------------

102     -- Bus protocol parameters, do not add to or delete

103     C_SLV_AWIDTH                   : integer              := 32;

104     C_SLV_DWIDTH                   : integer              := 32;

105     C_NUM_MEM                      : integer              := 4

106     -- DO NOT EDIT ABOVE THIS LINE ---------------------

107   );

108   port

109   (

110     -- ADD USER PORTS BELOW THIS LINE ------------------

111     --USER ports added here

112     -- ADD USER PORTS ABOVE THIS LINE ------------------

113

114     -- DO NOT EDIT BELOW THIS LINE ---------------------

115     -- Bus protocol ports, do not add to or delete

116     Bus2IP_Clk                     : in  std_logic;

117     Bus2IP_Resetn                  : in  std_logic;

118     Bus2IP_Addr                    : in  std_logic_vector(C_SLV_AWIDTH-1 downto 0);

119     Bus2IP_CS                      : in  std_logic_vector(C_NUM_MEM-1 downto 0);

120     Bus2IP_RNW                     : in  std_logic;

121     Bus2IP_Data                    : in  std_logic_vector(C_SLV_DWIDTH-1 downto 0);

122     Bus2IP_BE                      : in  std_logic_vector(C_SLV_DWIDTH/8-1 downto 0);

123     Bus2IP_RdCE                    : in  std_logic_vector(C_NUM_MEM-1 downto 0);

124     Bus2IP_WrCE                    : in  std_logic_vector(C_NUM_MEM-1 downto 0);

125     Bus2IP_Burst                   : in  std_logic;

126     Bus2IP_BurstLength             : in  std_logic_vector(7 downto 0);

127     Bus2IP_RdReq                   : in  std_logic;

128     Bus2IP_WrReq                   : in  std_logic;

129     IP2Bus_AddrAck                 : out std_logic;

130     IP2Bus_Data                    : out std_logic_vector(C_SLV_DWIDTH-1 downto 0);

131     IP2Bus_RdAck                   : out std_logic;

132     IP2Bus_WrAck                   : out std_logic;

133     IP2Bus_Error                   : out std_logic;

134     Type_of_xfer                   : out std_logic

135     -- DO NOT EDIT ABOVE THIS LINE ---------------------

136   );

137

138   attribute MAX_FANOUT : string;

139   attribute SIGIS : string;

140

141   attribute SIGIS of Bus2IP_Clk    : signal is "CLK";

142   attribute SIGIS of Bus2IP_Resetn : signal is "RST";

143

144 end entity user_logic;

145

146 ------------------------------------------------------------------------------

147 -- Architecture section

148 ------------------------------------------------------------------------------

149

150 architecture IMP of user_logic is

151

152   --USER signal declarations added here, as needed for user logic

153

154   ------------------------------------------

155   -- Signals for user logic memory space example

156   ------------------------------------------

157   type BYTE_RAM_TYPE is array (0 to 255) of std_logic_vector(7 downto 0);

158   type DO_TYPE is array (0 to C_NUM_MEM-1) of std_logic_vector(C_SLV_DWIDTH-1 downto 0);

159   signal mem_data_out                   : DO_TYPE;

160   signal mem_address                    : std_logic_vector(7 downto 0);

161   signal mem_select                     : std_logic_vector(0 to 3);

162   signal mem_read_enable                : std_logic;

163   signal mem_ip2bus_data                : std_logic_vector(C_SLV_DWIDTH-1 downto 0);

164   signal mem_read_ack_dly1              : std_logic;

165   signal mem_read_ack_dly2              : std_logic;

166   signal mem_read_ack                   : std_logic;

167   signal mem_write_ack                  : std_logic;

168

169 begin

170

171   --USER logic implementation added here

172

173   ------------------------------------------

174   -- Example code to access user logic memory region

175   --

176   -- Note:

177   -- The example code presented here is to show you one way of using

178   -- the user logic memory space features. The Bus2IP_Addr, Bus2IP_CS,

179   -- and Bus2IP_RNW IPIC signals are dedicated to these user logic

180   -- memory spaces. Each user logic memory space has its own address

181   -- range and is allocated one bit on the Bus2IP_CS signal to indicated

182   -- selection of that memory space. Typically these user logic memory

183   -- spaces are used to implement memory controller type cores, but it

184   -- can also be used in cores that need to access additional address space

185   -- (non C_BASEADDR based), s.t. bridges. This code snippet infers

186   -- 4 256x32-bit (byte accessible) single-port Block RAM by XST.

187   ------------------------------------------

188   mem_select      <= Bus2IP_CS;

189   mem_read_enable <= ( Bus2IP_RdCE(0) or Bus2IP_RdCE(1) or Bus2IP_RdCE(2) or Bus2IP_RdCE(3) );

190   mem_read_ack    <= mem_read_ack_dly1 and (not mem_read_ack_dly2);

191   mem_write_ack   <= ( Bus2IP_WrCE(0) or Bus2IP_WrCE(1) or Bus2IP_WrCE(2) or Bus2IP_WrCE(3) );

192   mem_address     <= Bus2IP_Addr(9 downto 2);

193

194   -- this process generates the read acknowledge 1 clock after read enable

195   -- is presented to the BRAM block. The BRAM block has a 1 clock delay

196   -- from read enable to data out.

197   BRAM_RD_ACK_PROC : process( Bus2IP_Clk ) is

198   begin

199

200     if ( Bus2IP_Clk'event and Bus2IP_Clk = '1' ) then

201       if ( Bus2IP_Resetn = '0' ) then

202         mem_read_ack_dly1 <= '0';

203         mem_read_ack_dly2 <= '0';

204       else

205         mem_read_ack_dly1 <= mem_read_enable;

206         mem_read_ack_dly2 <= mem_read_ack_dly1;

207       end if;

208     end if;

209

210   end process BRAM_RD_ACK_PROC;

211

212   -- implement Block RAM(s)

213   BRAM_GEN : for i in 0 to C_NUM_MEM-1 generate

214     constant NUM_BYTE_LANES : integer := (C_SLV_DWIDTH+7)/8;

215   begin

216

217     BYTE_BRAM_GEN : for byte_index in 0 to NUM_BYTE_LANES-1 generate

218       signal ram           : BYTE_RAM_TYPE;

219       signal write_enable  : std_logic;

220       signal data_in       : std_logic_vector(7 downto 0);

221       signal data_out      : std_logic_vector(7 downto 0);

222       signal read_address  : std_logic_vector(7 downto 0);

223     begin

224

225       write_enable <= Bus2IP_WrCE(i) and Bus2IP_BE(byte_index);

226

227       data_in <= Bus2IP_Data(byte_index*8+7 downto byte_index*8);

228       BYTE_RAM_PROC : process( Bus2IP_Clk ) is

229       begin

230

231         if ( Bus2IP_Clk'event and Bus2IP_Clk = '1' ) then

232           if ( write_enable = '1' ) then

233             ram(CONV_INTEGER(mem_address)) <= data_in;

234           end if;

235           read_address <= mem_address;

236         end if;

237

238       end process BYTE_RAM_PROC;

239

240       data_out <= ram(CONV_INTEGER(read_address));

241

242       mem_data_out(i)(byte_index*8+7 downto byte_index*8) <= data_out;

243

244     end generate BYTE_BRAM_GEN;

245

246   end generate BRAM_GEN;

247

248   -- implement Block RAM read mux

249   MEM_IP2BUS_DATA_PROC : process( mem_data_out, mem_select ) is

250   begin

251

252     case mem_select is

253       when "0001" => mem_ip2bus_data <= mem_data_out(0);

254       when "0010" => mem_ip2bus_data <= mem_data_out(1);

255       when "0100" => mem_ip2bus_data <= mem_data_out(2);

256       when "1000" => mem_ip2bus_data <= mem_data_out(3);

257       when others => mem_ip2bus_data <= (others => '0');

258     end case;

259

260   end process MEM_IP2BUS_DATA_PROC;

261

262   ------------------------------------------

263   -- Example code to drive IP to Bus signals

264   ------------------------------------------

265   IP2Bus_Data  <= mem_ip2bus_data when mem_read_ack = '1' else

266                   (others => '0');

267

268   IP2Bus_AddrAck <= mem_write_ack or (mem_read_enable and mem_read_ack);

269   IP2Bus_WrAck <= mem_write_ack;

270   IP2Bus_RdAck <= mem_read_ack;

271   IP2Bus_Error <= '0';

272

273 end IMP;

전체 entity 이름은 user logic이고요108라인부터 보면 포트를 정의했는데 111라인을 보면 “user port 여기에다 정의해라라는 친절한 주석문이 있습니다.

116라인부터 134라인까지는 아마도 프로세서로에서 사용하는 버스의 신호라고 예상할 있습니다. 슬슬 읽어보면 대충 감을 때릴 있는데 조금 햇갈리는 것은 burst라든지 burst length 라는 것이 여기는 설명하지 않을 테니까 넘어가고요.

AddrAck, RaAck, WrAck같은 신호를 보니 버스가 정해진 클럭에 트랜잭션이 끝나는 것이 아니고 슬레이브 쪽에서 응답을 해줘야 하나보다이렇게 추측할 있습니다.

신호이름들의 특성을 보면 Bus è IP, IP è Bus 왔다 갔다 하는 방향이 정확힐 설정되어 있습니다. 다른 말로 입출력 포트가 아니고 입력이나 출력으로 단방향으로 정해졌다는 얘기 입니다.

당연한 얘기겠죠. FPGA 내부에서는 BUFT 없으니까요.

                

108   port

109   (

110     -- ADD USER PORTS BELOW THIS LINE ------------------

111     --USER ports added here

112     -- ADD USER PORTS ABOVE THIS LINE ------------------

113

114     -- DO NOT EDIT BELOW THIS LINE ---------------------

115     -- Bus protocol ports, do not add to or delete

116     Bus2IP_Clk                     : in  std_logic;

117     Bus2IP_Resetn                  : in  std_logic;

118     Bus2IP_Addr                    : in  std_logic_vector(C_SLV_AWIDTH-1 downto 0);

119     Bus2IP_CS                      : in  std_logic_vector(C_NUM_MEM-1 downto 0);

120     Bus2IP_RNW                     : in  std_logic;

121     Bus2IP_Data                    : in  std_logic_vector(C_SLV_DWIDTH-1 downto 0);

122     Bus2IP_BE                      : in  std_logic_vector(C_SLV_DWIDTH/8-1 downto 0);

123     Bus2IP_RdCE                    : in  std_logic_vector(C_NUM_MEM-1 downto 0);

124     Bus2IP_WrCE                    : in  std_logic_vector(C_NUM_MEM-1 downto 0);

125     Bus2IP_Burst                   : in  std_logic;

126     Bus2IP_BurstLength             : in  std_logic_vector(7 downto 0);

127     Bus2IP_RdReq                   : in  std_logic;

128     Bus2IP_WrReq                   : in  std_logic;

129     IP2Bus_AddrAck                 : out std_logic;

130     IP2Bus_Data                    : out std_logic_vector(C_SLV_DWIDTH-1 downto 0);

131     IP2Bus_RdAck                   : out std_logic;

132     IP2Bus_WrAck                   : out std_logic;

133     IP2Bus_Error                   : out std_logic;

134     Type_of_xfer                   : out std_logic

135     -- DO NOT EDIT ABOVE THIS LINE ---------------------

136   );

 그래서 FPGA 내부에서는 IO라는 포트를 사용하지 않고요 실제 FPGA IO 만나는 부분에서만 사용하는 것이 좋습니다.

이제 entity 내부는 어떻게 구현되어 있는지 살펴보죠.

다음 코드는 메모리를 구현하는 VHDL 코드 입니다.

먼저 157, 158 라인에서 메모리 타입을 선언하고 8비트짜리 256개를 모두 4 선언했네요.  그리고 나서 212라인부터 246 라인까지 BRAM ~~~~ 했습니다.

인퍼런싱이라는 것은 코드를 보면 내가 BRAM 쓰지는 않았지만 합성툴이 가만보고 ~~ 이놈의 레지스터 집합의 동작 특성을 보니 메모리구만그러면 BRAM으로 합성해야지라고 자동으로 판단해서 BRAM 사용하도록 해주는 코딩 스타일 입니다.

조금 자세히 애기하자면 합성툴은 레지스터의 크기와 동작특성을 보고 그냥 레지스터로 합성할지, Distributed Ram으로 합성할지 BRAM으로 합성할지 자동적으로 판단 합니다.

여기서는 입력과 출력이 모두 클럭에 동기가 되고 레지스터의 크기가 비교적 크다고 판단했기 때문에 합성툴은 자동으로 BRAM으로 합니다.

 그렇게 수도 있고 아닐 수도 있지만 인퍼런싱의 장점은 FPGA 패밀리에 영향을 받지 않는 다는 것과 심지어는 다른 벤더의 제품을 써도 (~~이런거 알려주면 안돼는데) 합성을 해준다는거이게 중요합니다.

프로젝트가 바꿔도 디바이스 벤더가 바꿔도 (제발 그러지는 말아 주세요 흑흑) 같은 코드를 있다는 겁니다.

실제로 프로젝트할 때마다 바꿔보세요내가 개고생인가 라는 생각이 저절로 납니다.

코드자체에서 어려운 점은 없어요.

어려우면 VHDL 공부부터 다시 하세요.

157   type BYTE_RAM_TYPE is array (0 to 255) of std_logic_vector(7 downto 0);

158   type DO_TYPE is array (0 to C_NUM_MEM-1) of std_logic_vector(C_SLV_DWIDTH-1 downto 0);

 

212   -- implement Block RAM(s)

213   BRAM_GEN : for i in 0 to C_NUM_MEM-1 generate

214     constant NUM_BYTE_LANES : integer := (C_SLV_DWIDTH+7)/8;

215   begin

216

217     BYTE_BRAM_GEN : for byte_index in 0 to NUM_BYTE_LANES-1 generate

218       signal ram           : BYTE_RAM_TYPE;

219       signal write_enable  : std_logic;

220       signal data_in       : std_logic_vector(7 downto 0);

221       signal data_out      : std_logic_vector(7 downto 0);

222       signal read_address  : std_logic_vector(7 downto 0);

223     begin

224

225       write_enable <= Bus2IP_WrCE(i) and Bus2IP_BE(byte_index);

226

227       data_in <= Bus2IP_Data(byte_index*8+7 downto byte_index*8);

228       BYTE_RAM_PROC : process( Bus2IP_Clk ) is

229       begin

230

231         if ( Bus2IP_Clk'event and Bus2IP_Clk = '1' ) then

232           if ( write_enable = '1' ) then

233             ram(CONV_INTEGER(mem_address)) <= data_in;

234           end if;

235           read_address <= mem_address;

236         end if;

237

238       end process BYTE_RAM_PROC;

239

240       data_out <= ram(CONV_INTEGER(read_address));

241

242       mem_data_out(i)(byte_index*8+7 downto byte_index*8) <= data_out;

243

244     end generate BYTE_BRAM_GEN;

245

246   end generate BRAM_GEN

 

다음은 2가지를 한꺼번에 보겠습니다. 먼저 249라인을 보면 MUX 하나 구현되어 있습니다.

CASE  ~ WHEN 보면 이런 회로도가 당연히 올라야 해요

안떠오르면

VHDL 공부부터 다시 하세요.

간단하네요 mem_select 따라서 mem_ip2bus_data 연결되는 포트가 4개중 하나로 결정되네요.

두번째가 중요 합니다.

이렇게 mux에서 선택된 최정 출력은 다시 265라인에서 IP2Bus_data 연결되는데 시점이 언제냐 하면 mem_read_ack ‘1 입니다. 그렇지 않으면 ‘0’ 입니다.

 FPGA 내부에는 ‘Z’ 신호를 만들어주는 BUFT 없어요. 그러니까 FPGA 내부에는 OR 버스를 쓴다고 생각할 있습니다. OR 연산에서는 0 DON’T CARE이니까국산 말로 라고 있습니다.

그러면 언제 mem_read_ack ‘1’ 만드느냐는 조금 있다가 설명하고 나머지 268, 269, 270 라인의 IP2Bus_*Ack 신호 삼총사는 일단 슬레이브에서 만드는 것을 확인할 있습니다.

 어떻게 만들까 삼총사도 조금있다가 설명 합니다.

271라인의 IP2Bus_Error 그냥 ‘0’으로 묶어 둡니다.

248   -- implement Block RAM read mux

249   MEM_IP2BUS_DATA_PROC : process( mem_data_out, mem_select ) is

250   begin

251

252     case mem_select is

253       when "0001" => mem_ip2bus_data <= mem_data_out(0);

254       when "0010" => mem_ip2bus_data <= mem_data_out(1);

255       when "0100" => mem_ip2bus_data <= mem_data_out(2);

256       when "1000" => mem_ip2bus_data <= mem_data_out(3);

257       when others => mem_ip2bus_data <= (others => '0');

258     end case;

259

260   end process MEM_IP2BUS_DATA_PROC;

261

262   ------------------------------------------

263   -- Example code to drive IP to Bus signals

264   ------------------------------------------

265   IP2Bus_Data  <= mem_ip2bus_data when mem_read_ack = '1' else

266                   (others => '0');

267

268   IP2Bus_AddrAck <= mem_write_ack or (mem_read_enable and mem_read_ack);

269   IP2Bus_WrAck <= mem_write_ack;

270   IP2Bus_RdAck <= mem_read_ack;

271   IP2Bus_Error <= '0';

272

이제 ACK 삼총사를 설명하려고 합니다.

먼저 188라인에서 두개의 신호는 서로 연결되었고요 189라인을 보면 4개의 RdCE OR연산을 하네요. 4개중 어느 하나라도 ‘1이면 mem_read_enable ‘1’ 되죠.