tl;dr - Writing to the base address of lightweight HPS to FPGA bridge works fine at 0xFF200000, but writing to the heavyweight HPS to FPGA bridge at 0xC0000000 causes linux to hang. Any ideas what I’m doing wrong?
I have a very simple design with a single address mapped to LEDs allowing for reading and writing. The verilog file is below along with a screenshot of platform designer (h2f_axi is set to 32 bits same as h2f_lw_axi).
module custom_leds
(
input logic clk, // clock.clk
input logic reset, // reset.reset
// Memory mapped read/write slave interface
input logic avs_s0_address, // avs_s0.address
input logic avs_s0_read, // avs_s0.read
input logic avs_s0_write, // avs_s0.write
output logic [31:0] avs_s0_readdata, // avs_s0.readdata
input logic [31:0] avs_s0_writedata, // avs_s0.writedata
// The LED outputs
output logic [7:0] leds
);
// Read operations performed on the Avalon-MM Slave interface
always_comb begin
if (avs_s0_read) begin
case (avs_s0_address)
1'b0 : avs_s0_readdata = {24'b0, leds};
default : avs_s0_readdata = 'x;
endcase
end else begin
avs_s0_readdata = 'x;
end
end
// Write operations performed on the Avalon-MM Slave interface
always_ff @ (posedge clk) begin
if (reset) begin
leds <= '0;
end else if (avs_s0_write) begin
case (avs_s0_address)
1'b0 : leds <= avs_s0_writedata;
default : leds <= leds;
endcase
end
end
endmodule // custom_leds
When I run the code below, it just hangs and is non-responsive until I restart the device. You can see the values I used for the lightweight bridge which works perfectly without changing anything in the design.
#include "hps_0.h"
/* header includes the following:
#define CUSTOM_LEDS_0_COMPONENT_TYPE custom_leds
#define CUSTOM_LEDS_0_COMPONENT_NAME custom_leds_0
#define CUSTOM_LEDS_0_BASE 0x0
#define CUSTOM_LEDS_0_SPAN 8
#define CUSTOM_LEDS_0_END 0x7
*/
#include <iomanip>
#include <iostream>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
// if (argc != 2) {
// std::cerr << "Missing argument on how many times to blink led."
// << std::endl;
// return -1;
// }
// constexpr uint32_t HPS_TO_FPGA_LW_BASE = 0xFF200000;
// constexpr uint32_t HPS_TO_FPGA_LW_SPAN = 0x0020000;
constexpr uint32_t HPS_TO_FPGA_BASE = 0xC0000000;
constexpr uint32_t HPS_TO_FPGA_SPAN = 0x40000000;
constexpr uint32_t HPS_TO_FPGA_MASK = HPS_TO_FPGA_SPAN - 1;
// int blink_times = std::stoi(argv[1]);
int devmem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (devmem_fd < 0) {
std::cerr << "Couldn't open /dev/mem\n";
return -1;
}
auto bridge_map = static_cast<uint32_t *>(
mmap(nullptr, HPS_TO_FPGA_SPAN, PROT_READ | PROT_WRITE, MAP_SHARED,
devmem_fd, HPS_TO_FPGA_BASE));
if (bridge_map == MAP_FAILED) {
std::cerr << "Couldn't create mmap.\n";
close(devmem_fd);
return -2;
}
uint32_t *custom_led_map =
bridge_map + (static_cast<uint32_t>(0x0 + CUSTOM_LEDS_0_BASE) &
static_cast<uint32_t>(HPS_TO_FPGA_MASK));
//*custom_led_map = 0x55; // Fails
std::cout << *custom_led_map << std::endl; // Also fails
std::cout << "Done.\n";
int result = munmap(bridge_map, HPS_TO_FPGA_SPAN);
if (result < 0) {
std::cerr << "Couldn't unmmap.\n";
close(devmem_fd);
return -3;
}
close(devmem_fd);
return 0;
}
All the bridges are enabled as you can see below.
root@de10-15aug21:~/fat/extlinux# cat /sys/class/fpga_bridge/*/state
enabled
enabled
enabled
enabled
I have also restricted the kernel to use only 512MB ram by adding mem=512M
to the kernel boot options.
What am I doing wrong? Any help will be greatly appreciated!