Jump to content
  • 0

Cmod A7-35T MICROBLAZE INTERFACING WITH FABRIC LOGIC


BYTEMAN

Question

Dear All,

I'm kindly asking some guidances about the MIcroblaze interfacing with an existing logic described into the FPGA hence internal interconnection other than to external FPGA I/O pin with VIVADO and the Cmod A7-35T board..

I've see many tutorial on the web, also the link (DIGILENT-TUT) but what I'm asking is about interfacing the Microblaze with some logic design written in VHDL language (or Verilog this is not important).

Suppose this scenario:

- some counter and related logic described by a VHDL/Verilog code, hence we have fundamentally a component from an externl point of view

- we need to connect this block described above with the Microblaze.

the key point that I need to understand is how to perform practically this connection between the Microblaze and the entity defined by the VHDL or Verilog code,

All the tutorials I've seen shown how to connect the Microblaze with external I/O and some predefinited modules like UART and so on rather than to internal block not provided by the tool.

Of course, by means of the VIVADO builder feature, I'll able to add e.g. an UART and other peripherals to the Microblaze, but if some parts of the project are described with some VHDL code how I can get all working togheter? I've to generate the Microblaze system and related VHDL wrapper and then use it inside another top.vhd file that make the necessary interconnection between FPGA I/O pin, the custom logic block and the Microblaze component declaration?

I've to create my custom logic as was a custom IP and the add it to the Microblaze design?

Someone can give me some starting point/concept/tutorial specific link on this subject?

Thank you!

Best regards

Link to comment
Share on other sites

18 answers to this question

Recommended Posts

5 minutes ago, xc6lx45 said:

it*s plain Verilog?

If you mean your code posted in this thread I think yes it is, I only know VHDL...

Into the VIVADO Language Templates for the AXI memory mapped interface I can see also a Verilog Template.

Thanks

 

Link to comment
Share on other sites

17 minutes ago, xc6lx45 said:

Hi,

one hint: "regular" AXI is fairly complex and achieves its performance by writing bursts. AXI-Lite is in comparison very simple but limited to writing only a single value at a time (which is usually what I want).

With a 667 MHz Zynq and the simple example I posted earlier, a single write takes about 0.5 microseconds (a for-next loop counting down from 2M writing a constant to the bus takes one second, give or take some). I wonder how a microblaze (at 100 MHz) will perform.

"Polling" is one approach - repeatedly check, whether new data is available. In more complex systems, interrupts would be used, opening up a pretty standard but still XL-size can of worms...

Hi @xc6lx45

thank for reply,

Concerning your code example for the "module axi_lite_slave" could you please let me know how retrieve this one in VIVADO?

Into the Language Templates GUI I've not see such type of template and I don't know how to retrieve it, also if is possible could you let me know this one in VHDL code?

I'll be gratefully.

Thank

Link to comment
Share on other sites

Hi,

one hint: "regular" AXI is fairly complex and achieves its performance by writing bursts. AXI-Lite is in comparison very simple but limited to writing only a single value at a time (which is usually what I want).

With a 667 MHz Zynq and the simple example I posted earlier, a single write takes about 0.5 microseconds (a for-next loop counting down from 2M writing a constant to the bus takes one second, give or take some). I wonder how a microblaze (at 100 MHz) will perform.

"Polling" is one approach - repeatedly check, whether new data is available. In more complex systems, interrupts would be used, opening up a pretty standard but still XL-size can of worms...

Link to comment
Share on other sites

13 hours ago, artvvb said:

@BYTEMAN

My only major concern with the your current flow is that it is still relatively difficult to gain access to any control signals you might want to use. The Language Template GUI (which you can find in the Project Manager section of the Flow Navigator) has some boilerplate code for an AXI port map with customized parameters that you can add to your custom module. THis doesn't come with the actual AXI control template, but combining the syntax for the portmap with the IP you've created, you should be able to create the same design with only a single added module. AFAIK, added modules don't play as nicely with Connection Automation as actual AXI IP, but it may warrant some investigation.

[...]

Thank you Arthur for your time!

About the AXI template you mean that the template present into the Language Templates GUI is different from the template that arise from the Create and Package New IP -> Create a New AXI4 peripheral ? If you mean that I've see many difference in the signal name, also from a practical point of view the AXI4 IP have also the VHDL code used to read and write the register instead of the simple template obtained from the Language Templates GUI hence more simple to integrated in a your own design than using the crude template from Language Templates GUI. I've correctly understand?

Also I'm starting to read the cited document about the AXI stream Interface, about this I've a question concerning the difference between a End-Point IP and a infrastructure IP, could you please let me know something about this stuff?

Always about the AXI stream interface then I can read and write single packet of data e.g. 32 bit and then use it throught reading and writing suitable register (memory mapped like the standard AXI) or this work in order to expose directly the data on a std_logic_vector and then I can read and write by looking for specific synchronization signals that advice when the data is ready to be readed? In a similar way it works in order to put my signal on the AXI bus and the assert some data ready to be read from the Microblaze core? Are these ones the Events listed on page 53 (UG761)? This point is not clear to me, may be I've missed something...

Do you have some link/tutorial that can give me some insight from a practical point of view?

For a design that I've to start I'm thinking to interface a Microblaze core with some counter and other logic that is described by VHDL source and that will reside into the FPGA fabric. I've to do a high performance digital tacho then after reading the encoder interface (a FSM on a VHDL) and some counter (coded in VHDL) I've to send data to the Microblaze for the speed calculation and then retrieve the calculation results and send these ones to the FPGA in order to drive a external DAC through a SPI interface (also coded in VHDL code). About this work then I think to need transfer only some small bounchs of data from my logic to the Microblaze and then back to logic into the fastest way (my full cycle will be within 100 micro seconds due to the industrial control constraints that I must satisfied, actually the system was implemented on a ds PIC with a refresh time of 5 milli seconds  but the motor has a high torque ripple instability due to, in my opinion, about the large amount of time into the speed response (closed loop instability), then to shorten the cycle time I'm thinking to built the whole measurement system inside the FPGA, from the microblaze point of view I only need to perform some simple rescaling operations, mul and div, no others stuff).

Thanks!

 

 

Link to comment
Share on other sites

@BYTEMAN

My only major concern with the your current flow is that it is still relatively difficult to gain access to any control signals you might want to use. The Language Template GUI (which you can find in the Project Manager section of the Flow Navigator) has some boilerplate code for an AXI port map with customized parameters that you can add to your custom module. THis doesn't come with the actual AXI control template, but combining the syntax for the portmap with the IP you've created, you should be able to create the same design with only a single added module. AFAIK, added modules don't play as nicely with Connection Automation as actual AXI IP, but it may warrant some investigation.

I am currently away from a PC with Vivado installed, so I am unfortunately unable to be more specific on where in the Language Templates you can find this...

 

I'd suggest you try the above, but another method that can be useful to move data between Microblaze and HDL would be to use an AXI Stream interface (which is MUCH simpler than full AXI, there's some info in Xilinx UG761, starting at page 45) in your HDL module that connects to the transmit stream of an AXI4-Stream FIFO Controller (Xilinx PG080). I've been playing around with this a bit recently, and it seems like it works pretty well. This method is more useful for "bursty" data streams (Xilinx uses this for Ethernet communications), rather than "set and forget" registers (like LEDs or something), either on the processor or module side, but it's worth pointing out.

Thanks,

-Arthur

Link to comment
Share on other sites

I've did a little step after reading this tutorial:

Creating AXI4 Lite peripheral in VIVADO

the IP building flow is clear, after creating the AXI Slave I've to add my port(s) and functionality to the IP and then write and read registers to send data or receive it from the Microblaze. Inside the IP I can also get out of the IP signals that I can use to interface with custom RTL logic, in this way I will use the IP as a sort of bridge between the Microblaze and my RTL external logic.

With this idea I've managed the solution shown here below:

image.thumb.png.9e60943e58a87f924925147e55c23f9b.png

inside the IP I've put a myioport signal, a std_logic_vector with 4 lines, these lines are driven from the Microblaze thorugh the AXI interface and slave register 0 (open the IP from the attached project to see it), after that this lines was connected to a RTL logic that will perform customs operations on the data and finally from the RTL some data are put on external pin of the FPGA (by the way I'll also take some data and return results to the IP by changing this one and adding some input lines).

In this way, as my first attempt, I think to have found a way (is efficient or not from your perspective?) to get in communication the Microblaze with RTL code.

Then the flow I've followed was:

- Create IP as simple AXI slave interface and customize the code inside the IP in order to port out the contents of some register

- Create a RTL logic block that have to perform operation on the signal that came from the IP above mentioned

- Now we can go out to the FPGA or connect to others internals logic block

Make sense? There are some others aspect that I've to consider to keep a better design and if yes what can be?

Attached the whole design for your considerations and suggestions.

hello_world.xpr.zip

My VIVADO suite release is 2016.1

Thanks to all for any help!

 

 

Link to comment
Share on other sites

9 hours ago, jpeyron said:

Hi @BYTEMAN,

The portion dealing with the axi gpio block, the pmodad1 test block should be the same in regards to how you will connect these IP blocks.

cheers,

Jon

I've see the design, unfortunately the structure of the file are different, for the custom RTL module into the example design you provided is made by three file, but the not so clear things to me is why in this design we have a verilog wrapper that I can see and in my design this wrapper can not be opened, I'm surprised that a so simple concept "how to connect a RTL block to Microblaze" into the graphical design should be so complicated, the idea is simple (make a wrapper to expose the interface to the design) but get in practice is not so simple and after reading many tutorial and user guide I've to admit that a lack of information is present, XILINX tutorial not cover every particular case although many people need clarification on this subject, this is a very time expesive activity and time is very precious :)

Looking at the template for the AXI (is this the right one to choose?):

image.png.965ec1c9bbd1f32b1fad57005273fdd7.png

I can see:


-- Normally AXI is automatically inferred.  However, if the names of your ports do not match, you can force the
-- the creation of an interface and map the physical ports to the logical ports by using the X_INTERFACE_INFO
-- attribute before each physical port
-- Typical parameters the user might specify: PROTOCOL {AXI4, AXI4LITE, AXI3}, SUPPORTS_NARROW_BURST {0, 1}, NUM_READ_OUTSTANDING, NUM_WRITE_OUTSTANDING, MAX_BURST_LENGTH
-- The PROTOCOL can be typically be inferred from the set of signals.
-- aximm - AMBA AXI Interface (slave directions)
-- 
-- Allowed parameters:
--  CLK_DOMAIN                - Clk Domain                (string default: <blank>) 
--  PHASE                     - Phase                     (float) 
--  MAX_BURST_LENGTH          - Max Burst Length          (long default: 256) [1, 256]
--  NUM_WRITE_OUTSTANDING     - Num Write Outstanding     (long default: 1) [0, 32]
--  NUM_READ_OUTSTANDING      - Num Read Outstanding      (long default: 1) [0, 32]
--  SUPPORTS_NARROW_BURST     - Supports Narrow Burst     (long default: 1) [0, 1]
--  READ_WRITE_MODE           - Read Write Mode           (string default: READ_WRITE) {READ_WRITE,READ_ONLY,WRITE_ONLY}
--  BUSER_WIDTH               - Buser Width               (long) 
--  RUSER_WIDTH               - Ruser Width               (long) 
--  WUSER_WIDTH               - Wuser Width               (long) 
--  ARUSER_WIDTH              - Aruser Width              (long) 
--  AWUSER_WIDTH              - Awuser Width              (long) 
--  ADDR_WIDTH                - Addr Width                (long default: 32) [1, 64]
--  ID_WIDTH                  - Id Width                  (long) 
--  FREQ_HZ                   - Frequency                 (float default: 100000000) 
--  PROTOCOL                  - Protocol                  (string default: AXI4) {AXI4,AXI4LITE,AXI3}
--  DATA_WIDTH                - Data Width                (long default: 32) {32,64,128,256,512,1024}
--  HAS_BURST                 - Has BURST                 (long default: 1) {0,1}
--  HAS_CACHE                 - Has CACHE                 (long default: 1) {0,1}
--  HAS_LOCK                  - Has LOCK                  (long default: 1) {0,1}
--  HAS_PROT                  - Has PROT                  (long default: 1) {0,1}
--  HAS_QOS                   - Has QOS                   (long default: 1) {0,1}
--  HAS_REGION                - Has REGION                (long default: 1) {0,1}
--  HAS_WSTRB                 - Has WSTRB                 (long default: 1) {0,1}
--  HAS_BRESP                 - Has BRESP                 (long default: 1) {0,1}
--  HAS_RRESP                 - Has RRESP                 (long default: 1) {0,1}

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity my_module is
  port (

  <s_awid> : in std_logic_vector(<left_bound> downto 0); -- Write address ID (optional)
  <s_awaddr> : in std_logic_vector(<left_bound> downto 0); -- Write address (optional)
  <s_awlen> : in std_logic_vector(<left_bound> downto 0); -- Burst length (optional)
  <s_awsize> : in std_logic_vector(2 downto 0); -- Burst size (optional)
  <s_awburst> : in std_logic_vector(1 downto 0); -- Burst type (optional)
  <s_awlock> : in std_logic_vector(<left_bound> downto 0); -- Lock type (optional)
  <s_awcache> : in std_logic_vector(3 downto 0); -- Cache type (optional)
  <s_awprot> : in std_logic_vector(2 downto 0); -- Protection type (optional)
  <s_awregion> : in std_logic_vector(3 downto 0); -- Write address slave region (optional)
  <s_awqos> : in std_logic_vector(3 downto 0); -- Transaction Quality of Service token (optional)
  <s_awuser> : in std_logic_vector(<left_bound> downto 0); -- Write address user sideband (optional)
  <s_awvalid> : in std_logic; -- Write address valid (optional)
  <s_awready> : out std_logic; -- Write address ready (optional)
  <s_wid> : in std_logic_vector(<left_bound> downto 0); -- Write ID tag (optional)
  <s_wdata> : in std_logic_vector(<left_bound> downto 0); -- Write data (optional)
  <s_wstrb> : in std_logic_vector(<left_bound> downto 0); -- Write strobes (optional)
  <s_wlast> : in std_logic; -- Write last beat (optional)
  <s_wuser> : in std_logic_vector(<left_bound> downto 0); -- Write data user sideband (optional)
  <s_wvalid> : in std_logic; -- Write valid (optional)
  <s_wready> : out std_logic; -- Write ready (optional)
  <s_bid> : out std_logic_vector(<left_bound> downto 0); -- Response ID (optional)
  <s_bresp> : out std_logic_vector(1 downto 0); -- Write response (optional)
  <s_buser> : out std_logic_vector(<left_bound> downto 0); -- Write response user sideband (optional)
  <s_bvalid> : out std_logic; -- Write response valid (optional)
  <s_bready> : in std_logic; -- Write response ready (optional)
  <s_arid> : in std_logic_vector(<left_bound> downto 0); -- Read address ID (optional)
  <s_araddr> : in std_logic_vector(<left_bound> downto 0); -- Read address (optional)
  <s_arlen> : in std_logic_vector(<left_bound> downto 0); -- Burst length (optional)
  <s_arsize> : in std_logic_vector(2 downto 0); -- Burst size (optional)
  <s_arburst> : in std_logic_vector(1 downto 0); -- Burst type (optional)
  <s_arlock> : in std_logic_vector(<left_bound> downto 0); -- Lock type (optional)
  <s_arcache> : in std_logic_vector(3 downto 0); -- Cache type (optional)
  <s_arprot> : in std_logic_vector(2 downto 0); -- Protection type (optional)
  <s_arregion> : in std_logic_vector(3 downto 0); -- Read address slave region (optional)
  <s_arqos> : in std_logic_vector(3 downto 0); -- Quality of service token (optional)
  <s_aruser> : in std_logic_vector(<left_bound> downto 0); -- Read address user sideband (optional)
  <s_arvalid> : in std_logic; -- Read address valid (optional)
  <s_arready> : out std_logic; -- Read address ready (optional)
  <s_rid> : out std_logic_vector(<left_bound> downto 0); -- Read ID tag (optional)
  <s_rdata> : out std_logic_vector(<left_bound> downto 0); -- Read data (optional)
  <s_rresp> : out std_logic_vector(1 downto 0); -- Read response (optional)
  <s_rlast> : out std_logic; -- Read last beat (optional)
  <s_ruser> : out std_logic_vector(<left_bound> downto 0); -- Read user sideband (optional)
  <s_rvalid> : out std_logic; -- Read valid (optional)
  <s_rready> : in std_logic; -- Read ready (optional)
  --  additional ports here

  );
end my_module;
architecture arch_impl of my_module is

  ATTRIBUTE X_INTERFACE_INFO : STRING;
  ATTRIBUTE X_INTERFACE_INFO of <s_awid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWID";
  ATTRIBUTE X_INTERFACE_INFO of <s_awaddr>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWADDR";
  ATTRIBUTE X_INTERFACE_INFO of <s_awlen>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWLEN";
  ATTRIBUTE X_INTERFACE_INFO of <s_awsize>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWSIZE";
  ATTRIBUTE X_INTERFACE_INFO of <s_awburst>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWBURST";
  ATTRIBUTE X_INTERFACE_INFO of <s_awlock>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWLOCK";
  ATTRIBUTE X_INTERFACE_INFO of <s_awcache>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWCACHE";
  ATTRIBUTE X_INTERFACE_INFO of <s_awprot>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWPROT";
  ATTRIBUTE X_INTERFACE_INFO of <s_awregion>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWREGION";
  ATTRIBUTE X_INTERFACE_INFO of <s_awqos>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWQOS";
  ATTRIBUTE X_INTERFACE_INFO of <s_awuser>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWUSER";
  ATTRIBUTE X_INTERFACE_INFO of <s_awvalid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWVALID";
  ATTRIBUTE X_INTERFACE_INFO of <s_awready>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> AWREADY";
  ATTRIBUTE X_INTERFACE_INFO of <s_wid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WID";
  ATTRIBUTE X_INTERFACE_INFO of <s_wdata>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WDATA";
  ATTRIBUTE X_INTERFACE_INFO of <s_wstrb>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WSTRB";
  ATTRIBUTE X_INTERFACE_INFO of <s_wlast>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WLAST";
  ATTRIBUTE X_INTERFACE_INFO of <s_wuser>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WUSER";
  ATTRIBUTE X_INTERFACE_INFO of <s_wvalid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WVALID";
  ATTRIBUTE X_INTERFACE_INFO of <s_wready>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> WREADY";
  ATTRIBUTE X_INTERFACE_INFO of <s_bid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> BID";
  ATTRIBUTE X_INTERFACE_INFO of <s_bresp>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> BRESP";
  ATTRIBUTE X_INTERFACE_INFO of <s_buser>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> BUSER";
  ATTRIBUTE X_INTERFACE_INFO of <s_bvalid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> BVALID";
  ATTRIBUTE X_INTERFACE_INFO of <s_bready>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> BREADY";
  ATTRIBUTE X_INTERFACE_INFO of <s_arid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARID";
  ATTRIBUTE X_INTERFACE_INFO of <s_araddr>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARADDR";
  ATTRIBUTE X_INTERFACE_INFO of <s_arlen>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARLEN";
  ATTRIBUTE X_INTERFACE_INFO of <s_arsize>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARSIZE";
  ATTRIBUTE X_INTERFACE_INFO of <s_arburst>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARBURST";
  ATTRIBUTE X_INTERFACE_INFO of <s_arlock>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARLOCK";
  ATTRIBUTE X_INTERFACE_INFO of <s_arcache>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARCACHE";
  ATTRIBUTE X_INTERFACE_INFO of <s_arprot>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARPROT";
  ATTRIBUTE X_INTERFACE_INFO of <s_arregion>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARREGION";
  ATTRIBUTE X_INTERFACE_INFO of <s_arqos>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARQOS";
  ATTRIBUTE X_INTERFACE_INFO of <s_aruser>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARUSER";
  ATTRIBUTE X_INTERFACE_INFO of <s_arvalid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARVALID";
  ATTRIBUTE X_INTERFACE_INFO of <s_arready>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> ARREADY";
  ATTRIBUTE X_INTERFACE_INFO of <s_rid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RID";
  ATTRIBUTE X_INTERFACE_INFO of <s_rdata>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RDATA";
  ATTRIBUTE X_INTERFACE_INFO of <s_rresp>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RRESP";
  ATTRIBUTE X_INTERFACE_INFO of <s_rlast>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RLAST";
  ATTRIBUTE X_INTERFACE_INFO of <s_ruser>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RUSER";
  ATTRIBUTE X_INTERFACE_INFO of <s_rvalid>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RVALID";
  ATTRIBUTE X_INTERFACE_INFO of <s_rready>: SIGNAL is "xilinx.com:interface:aximm:1.0 <interface_name> RREADY";
  -- Uncomment the following to set interface specific parameter on the bus interface.
  --  ATTRIBUTE X_INTERFACE_PARAMETER : STRING;
  --  ATTRIBUTE X_INTERFACE_PARAMETER of <port_name>: SIGNAL is "CLK_DOMAIN <value>,PHASE <value>,MAX_BURST_LENGTH <value>,NUM_WRITE_OUTSTANDING <value>,NUM_READ_OUTSTANDING <value>,SUPPORTS_NARROW_BURST <value>,READ_WRITE_MODE <value>,BUSER_WIDTH <value>,RUSER_WIDTH <value>,WUSER_WIDTH <value>,ARUSER_WIDTH <value>,AWUSER_WIDTH <value>,ADDR_WIDTH <value>,ID_WIDTH <value>,FREQ_HZ <value>,PROTOCOL <value>,DATA_WIDTH <value>,HAS_BURST <value>,HAS_CACHE <value>,HAS_LOCK <value>,HAS_PROT <value>,HAS_QOS <value>,HAS_REGION <value>,HAS_WSTRB <value>,HAS_BRESP <value>,HAS_RRESP <value>";

begin
--  user logic here

end arch_impl;

I can also see the two comment:

-- additional port here

and

--- user logic here comment

hence I suppose that these ones are the right place were I've to put my port declarations and code respectively to describe my function, the I think that I've to upgrade my RTL code:with the above reported statements to build the AXI around my logic but are all the options really needed and how to translate it in a practical way?
 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity andexample is
    Port (   A : in STD_LOGIC;
             B : in STD_LOGIC;
             C : in STD_LOGIC;
             OUTY : out STD_LOGIC
         );
end andexample;

architecture Behavioral of andexample is

begin

    OUTY <= A and B and C;

end Behavioral;

with the one provided by the template, but what are the correct definition to use?

Somebody have some idea about this point I'll be gratefully.

Best regards

 

Link to comment
Share on other sites

Hi @BYTEMAN,

 Here is a  forum thread that has a good add a  module reference project done by one of our community members attached called notarobot_ad1 done in vivado 2016.4 that uses an altered version of hamsters vhdl code and the add a module function to connect the hdl to the axi. I have also attached a screen shot of their block design.

thank you,

Jon

ADD_A_Module.jpg

 

Link to comment
Share on other sites

I can see that If I choose the add module option I can insert the logic block into the microblaze design.

image.thumb.png.f69efbe53104a85d153b8f2b667c06df.png

then now I've to connect the A to a button input pin (I think the button 1 into the Cmod A7-35T board) and also to the microblaze,

The Y to an output available pin, like the led0 or led1 and the B and C to the microblaze.

Any help?

 

Link to comment
Share on other sites

In order to start I've followed the DIGILENT tutorial at this link:

Cmod A7 - Getting Started with Microblaze

now I stopped at pass number 8 "Exporting Hardware Design to SDK".

My suite release is VIVADO 2016.1.

All the step until this point is straight and clear, at this point I think to have to put some AXI interface in order to get in connection to my logic that will be described by my VHDL file.

In order to start simply suppose to have a simple combinatorial logic made of a three AND function.

----------------------------------------------------------------------------------
-- filename: andxample.vhd
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity andexample is
    Port (   A : in STD_LOGIC;
             B : in STD_LOGIC;
             C : in STD_LOGIC;
             Y : out STD_LOGIC
         );
end andexample;

architecture Behavioral of andexample is

begin

    Y <= A and B and C;

end Behavioral;

  for each input of this simple logic block suppose to connect these ones respectively:

A : to one button board and to one input of the microblaze

B: to one ouput port of the microblaze

C: to one output port of the microbaze

Y = to an output pin of the FPGA

At this point of the design I've a VHDL wrapper for the whole design that involve the microblaze and the others peripherals (UART) and the VHDL code reported above for the simple logic that has to be interfaced with the microblaze.

The next step should be link together the andexample.vhd file and the system.vhd file with a top.vhd wrapper, I'm correct?

Before doing that from previous posts I know that I've to connect my logic to a interface able to communicate with the AXI bus and from the microblaze side we need also to put a so called slave GPIO module attached to the AXI bus controller, but if in theory this sounds correct I'm little confused how to put all in practice.

I've attached my project file, if someone can take a look and give some hint I will be gratefully!

Thank

Best regards

hello_world.xpr.zip

Link to comment
Share on other sites

Check out the AXI GPIO. For simple designs, it may be all you need.

On the other hand, putting my own logic on the bus allows some elegant solutions like read-sensitive registers that may simplify the software greatly. Digitop design has its own little team in larger projects (at least on ASIC), don't expect this to just fall into place.

Maybe someone else can comment on "standard way", those are just paths I figured out for myself.

Link to comment
Share on other sites

3 hours ago, xc6lx45 said:

...
What I'd do is make my own design an "axi_lite_slave" (based on Xilinx' template) and include via "add module" to the diagram editor. Connect via axi_interconnect to convert AXI to AXI-lite. Then connect IOs from the module by making the signals "external" (right-click", "make external").
...

Hi @xc6lx45 thank for your answer.

From what I can understand then I've to interface my design to the AXI bus that is the standard way to pass information between IP hence also from and to the Microblaze soft core, correct?

To do that I've to put into my design a component that will act as a bridge between my design and the design that include the Microblaze, a solution for that is use your suggested axi_lite_slave", if I've got the point could you please let me know if there is a axi_lite_slave in VHDL (I don't know Verilog...)?

Also I kindly request if there is some simple example or tutorial to follow in order to set a simple working design based on:

- some simple logic (may be a simple counter that will be read from the Microblaze then a line to latch the count and then read it into the microblaze)

- the microblaze + UART section

Thank

Best regards

Link to comment
Share on other sites

Hi,

disclaimer: I'm not an expert on the topic. What I'd do is make my own design an "axi_lite_slave" (based on Xilinx' template) and include via "add module" to the diagram editor. Connect via axi_interconnect to convert AXI to AXI-lite. Then connect IOs from the module by making the signals "external" (right-click", "make external").

I could also include the HDL wrapper for the processor in my own top level design, but then I'd have to bridge the connectivity for e.g. DDR in a more complex design, which would be a mess.

Below a very simple AXI-lite slave (single-register read/write, no address decoding). I guess it worked with Zynq.

A completely different approach I've tried is to instantiate microblaze_mcs as regular IP block (no use of graphical design entry) and enable GPI/GPO to control custom logic.

module axi_lite_slave 
  #(parameter integer C_S_AXI_ADDR_WIDTH = 32,
    parameter integer C_S_AXI_DATA_WIDTH = 32)
   (// System Signals
    input wire 				  ACLK,
    input wire 				  ARESETN,
    
    // Slave Interface Write Address Ports
    input wire [C_S_AXI_ADDR_WIDTH-1:0]   S_AXI_AWADDR,
    input wire [2:0] 			  S_AXI_AWPROT,
    input wire 				  S_AXI_AWVALID,
    output wire 			  S_AXI_AWREADY,

    // Slave Interface Write Data Ports
    input wire [C_S_AXI_DATA_WIDTH-1:0]   S_AXI_WDATA,
    input wire [C_S_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
    input wire 				  S_AXI_WVALID,
    output wire 			  S_AXI_WREADY,

   // Slave Interface Write Response Ports
    output wire [1:0] 		  S_AXI_BRESP,
    output wire 			  S_AXI_BVALID,
    input wire 				  S_AXI_BREADY,
    
    // Slave Interface Read Address Ports
    input wire [C_S_AXI_ADDR_WIDTH-1:0]   S_AXI_ARADDR,
    input wire [2:0] 			  S_AXI_ARPROT,
    input wire 				  S_AXI_ARVALID,
    output wire 			  S_AXI_ARREADY,
    
    // Slave Interface Read Data Ports
    output wire [C_S_AXI_DATA_WIDTH-1:0]  S_AXI_RDATA,
    output wire [1:0] 		  S_AXI_RRESP,
    output wire 			  S_AXI_RVALID,
    input wire 				  S_AXI_RREADY,
    );

   // slave is ready to accept address
   assign S_AXI_AWREADY = 1'b1;

   // slave can accept the write data
   assign S_AXI_WREADY = 1'b1;

   // data is valid
   reg 					  rvalid = 1'b0;   
   assign S_AXI_RVALID = rvalid;

   // read status is OK
   assign S_AXI_RRESP = 2'd0;   

   // write status is OK
   assign S_AXI_BRESP = 2'd0;   
   
   // write status is valid
   reg 					  bvalid = 1'b0;   
   assign S_AXI_BVALID = bvalid;

   // slave is ready to accept address
   assign S_AXI_ARREADY = 1'b1;   
   
   reg [31:0] 			       myData = 32'hDEADBEEF;  

   // output data
   assign S_AXI_RDATA = myData;
   always @(posedge ACLK) begin
      if (S_AXI_WVALID)
	myData <= S_AXI_WDATA;
      // Figure A3-5 in AXI4-specification.pdf:
      // the slave must wait ... for ARVALID before it asserts RVALID
      rvalid <= S_AXI_ARVALID;
      // Figure A3-6
      bvalid <= S_AXI_AWVALID;
   end
endmodule

 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...