Debugging Custom AXI IP via UART on Zynq SoC

Hardware Logic Design

First, a Verilog module performing basic bitwisee operations is created to serve as the core logic for the custom IP. This module will be instantiated with in the AXI wrapper.

module bitwise_logic_unit (
    input  wire [31:0] operand_a,
    input  wire [31:0] operand_b,
    output wire [31:0] result_and,
    output wire [31:0] result_or,
    output wire [31:0] result_not
);

    // Perform bitwise AND, OR, and NOT operations
    assign result_and = operand_a & operand_b;
    assign result_or  = operand_a | operand_b;
    assign result_not = ~operand_a;

endmodule

AXI IP Integration

After creating a new custom AXI IP using the wizard, the next step involves modifying the AXI slave module to instantiate the logic unit above. The inputs of the custom logic are connected to the AXI slave registers (slv_reg0 and slv_reg1), allowing the PS to write operands. The outputs are routed to internal wires, which are then mapped to the read registers (slv_reg2, slv_reg3, etc.).

Inside the AXI slave module, declare the wires for the logic outputs and modify the read multiplexer logic:

// Internal wires for logic module outputs
wire [31:0] w_result_and;
wire [31:0] w_result_or;
wire [31:0] w_result_not;

// Instantiate the custom logic
bitwise_logic_unit u_logic_core (
    .operand_a   (slv_reg0),
    .operand_b   (slv_reg1),
    .result_and  (w_result_and),
    .result_or   (w_result_or),
    .result_not  (w_result_not)
);

// Read address decoding logic
always @(*) begin
    case (axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB])
        3'h0   : reg_data_out <= slv_reg0;
        3'h1   : reg_data_out <= slv_reg1;
        3'h2   : reg_data_out <= w_result_and; // Read AND result
        3'h3   : reg_data_out <= w_result_or;  // Read OR result
        3'h4   : reg_data_out <= w_result_not; // Read NOT result
        default: reg_data_out <= 0;
    endcase
end

Once the modifications are complete, package the IP. It is often necessary to re-package the IP if the initial merge fails or if the IP catalog does not update correctly. After packaging, the IP can be added to the Block Design (BD). Since the logic is self-contained within the AXI interface, no external I/O ports are required other than the AXI connection to the Processing System.

Software Application Development

With the hardware exported and the bitstream generated, a software application is developed in the SDK (or Vitis) to drive the IP. A standard "Hello World" template serves as a good starting point, as it includes necessary UART setup. The application writes values to the IP registers and reads back the computed results.

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
#include "xparameters.h"

// Define Base Address and Register Offsets
#define IP_BASE_ADDR   XPAR_MY_LOGIC_IP_0_S00_AXI_BASEADDR
#define REG_IN_A       0x00
#define REG_IN_B       0x04
#define REG_OUT_AND    0x08
#define REG_OUT_OR     0x0C
#define REG_OUT_NOT    0x10

int main() {
    init_platform();

    unsigned int val_a = 150;
    unsigned int val_b = 90;
    unsigned int res_and, res_or, res_not;

    xil_printf("Starting Custom IP Logic Test...\n\r");

    // Write inputs to the custom IP
    Xil_Out32(IP_BASE_ADDR + REG_IN_A, val_a);
    Xil_Out32(IP_BASE_ADDR + REG_IN_B, val_b);

    // Read calculated results from the custom IP
    res_and = Xil_In32(IP_BASE_ADDR + REG_OUT_AND);
    res_or  = Xil_In32(IP_BASE_ADDR + REG_OUT_OR);
    res_not = Xil_In32(IP_BASE_ADDR + REG_OUT_NOT);

    // Print results to UART terminal
    xil_printf("Input A: %d\n\r", val_a);
    xil_printf("Input B: %d\n\r", val_b);
    xil_printf("Result AND: %d\n\r", res_and);
    xil_printf("Result OR : %d\n\r", res_or);
    xil_printf("Result NOT: %d\n\r", res_not);

    cleanup_platform();
    return 0;
}

Terminal Verification

To observe the output, configure the Terminal window in the SDK (or a standalone terminal tool like Putty/TeraTerm) to connect to the appropriate COM port with the correct baud rate (typically 115200 for Zynq). Upon running the application, the calculated values will be displayed, confirming that the custom AXI IP correctly processes data and that the PS can read the results via the AXI interface.

Tags: AXI UART Zynq FPGA Verilog

Posted on Sat, 25 Jul 2026 17:00:16 +0000 by think-digitally