Hi, I'm trying desperately to experience the AVALON MM interface on a Cyclone V SoC FPGA board.
For my interface implementation I have written a control, an input and an output verilog file, as also some C code running on the HPS. Control, Input and Output are joined by QSYS together with a clock, and an HPS component. A top level verilog file connects the .qip to an algorithm verilog file. The actual algorithm will come later (some ready-made IP core). Currently instead of an algorithm, I'm just lighting LEDs: Initially, in state WAITING, led1. When "input" and a "start" signal come from the control verilog file inside the .qip, it should do the transition to WORKING and light another led2. My problem now, is that it does not work - it stays at lighting led1. I tried another example using AVALON MM and it works, so there should not be anything basic such as MSEL setting, etc.
Here are Control, Input and Output, as below the C code I wrote. I left out the toplevel file as also the.. what I call "algorithm" so far.
Code:
module avalonmm_control (
input clk,
input reset,
output reg debug_led, // DEBUG
input [7:0] avs_writedata,
output reg [7:0] avs_readdata,
input [1:0] avs_address,
input avs_read,
input avs_write,
output algostart,
output algoreset,
input algodone
);
// TODO check out, why we use "reg" here?
reg start_reg;
reg reset_reg;
assign algostart = start_reg;
assign algoreset = reset_reg;
always @(posedge clk) begin
if(avs_write)begin
case (avs_address)
2'b00: begin
reset_reg <= avs_writedata[0];
start_reg <= 1'd0;
end
2'b01: begin
debug_led = 1'b1; // TODO rm, DEBUGGING
reset_reg <= 1'd0;
start_reg <= avs_writedata[0];
end
default: begin
reset_reg <= 1'd0;
start_reg <= 1'd0;
end
endcase
end else if (avs_read) begin
reset_reg <= 1'd0;
start_reg <= 1'd0;
case (avs_address)
2'b00: avs_readdata[0] <= reset_reg;
2'b01: avs_readdata[0] <= start_reg;
2'b10: avs_readdata[0] <= algodone;
default: avs_readdata[0] <= 1'd0;
endcase
end else begin
reset_reg <= 1'd0;
start_reg <= 1'd0;
end
end
endmodule
Code:
module avalonmm_input (
input clk,
input reset,
input avs_write,
input [31:0] avs_writedata,
input [3:0] avs_address,
output alg_write,
output [31:0] alg_writedata,
output [3:0] alg_writeaddr
);
assign alg_write = avs_write;
assign alg_writedata = avs_writedata;
assign alg_writeaddr = avs_address;
endmodule
Code:
module avalonmm_output (
input clk,
input reset,
input avs_read,
output [31:0] avs_readdata,
input [3:0] avs_address,
input [31:0] alg_readdata,
output [3:0] alg_readaddr
);
assign avs_readdata = alg_readdata;
assign alg_readaddr = avs_address;
endmodule
I'm currently trying to light an additional debugging led, on any input, and leave it light - without any success. Either it stays always on or is always off. It seems as if "avs_write" is always true, already in the beginning. As C code, I wrote the following..
Code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> // memset()
#include <stdint.h> // uint8_t, etc.
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
/*******************************************************************************/
#define INPUT_OFFSET 0x0
#define OUTPUT_OFFSET 0x800
#define CONTROL_OFFSET 0xa00
#define INPUT_SIZE 16
#define OUTPUT_SIZE 16
#define PAGE_SIZE sysconf(_SC_PAGESIZE)
#define LWHPS2FPGA_BASE 0xff200000
#define SEQUENCE_SIZE 16
/*******************************************************************************/
typedef struct fpgactrl{
void *mem;
volatile uint32_t *input;
volatile uint32_t *output;
volatile uint32_t *control;
/*
control states / orders configured in FPGA:
2'b00 - reset
2'b01 - start
2'b10 - done
*/
int fd;
} fpgactrl_t;
typedef fpgactrl_t* fpgactrl_p;
typedef struct sequence{
int size;
uint8_t sequence[SEQUENCE_SIZE];
} sequence_t;
typedef sequence_t* sequence_p;
/*******************************************************************************/
int fpga_init(struct fpgactrl* fpga)
{
if (0 > (fpga->fd = open("/dev/mem", O_RDWR))) {
fprintf(stderr, "FAILED, %s [%d]: fpga->fd < 0\n", __FILE__, __LINE__);
return -1; // FAIL
}
if (MAP_FAILED == (fpga->mem = mmap(NULL, PAGE_SIZE
, PROT_READ | PROT_WRITE, MAP_SHARED
, fpga->fd, LWHPS2FPGA_BASE))) {
perror("FAILED");
fprintf(stderr, "%s [%d]: MAP_FAILED == (fpga->mem = mmap(...))\n", __FILE__, __LINE__);
close(fpga->fd);
return -1; // FAIL
}
fpga->input = fpga->mem + INPUT_OFFSET;
fpga->output = fpga->mem + OUTPUT_OFFSET;
fpga->control = fpga->mem + CONTROL_OFFSET;
return 0; // OK
}
void fpga_reset(struct fpgactrl* fpga)
{
fpga->control[0] |= 0x1;
while (fpga->control[0] & 0x1) ;
}
void fpga_start(struct fpgactrl* fpga)
{
fpga->control[1] |= 0x1;
while (fpga->control[1] & 0x1) ;
fprintf(stderr, "XXX: fpga started\n"); // the message comes
}
void fpga_done(struct fpgactrl* fpga)
{
while ((fpga->control[2]) & 0x1) ;
}
void fpga_copy_input(struct fpgactrl* fpga, uint8_t* input)
{
int idx;
for (idx=0; idx<INPUT_SIZE; ++idx) {
fpga->input[idx] = (uint32_t*) input[idx];
}
}
void fpga_copy_output(struct fpgactrl* fpga, uint8_t* output)
{
int idx;
for( idx=0; idx < OUTPUT_SIZE; ++idx){
output[idx] = (uint8_t*) fpga->output[idx];
}
}
void fpga_release(struct fpgactrl* fpga)
{
munmap(fpga->mem, PAGE_SIZE);
close(fpga->fd);
}
void sequence_init(struct sequence* seq)
{
seq->size = 0;
seq->size = SEQUENCE_SIZE; // static array!
memset(seq->sequence, '\0', seq->size);
}
void sequence_init_text(struct sequence* seq)
{
sequence_init(seq);
memset(seq->sequence, '1', SEQUENCE_SIZE);
}
/*******************************************************************************/
int main(int argc, char* argv[]){
fpgactrl_t fpga;
fpgactrl_p ptr_fpga = &fpga;
sequence_t seq_input, seq_output;
sequence_p input = &seq_input;
sequence_p output = &seq_output;
fprintf(stderr, "init fpga\n");
if (fpga_init(ptr_fpga)) {
fprintf(stderr, "FAILED: initialization of fpga controller\n");
exit(EXIT_FAILURE);
}
fprintf(stderr, "set up input\n");
sequence_init(output);
sequence_init_text(input);
fprintf(stderr, "reset fpga\n");
fpga_reset(ptr_fpga);
fprintf(stderr, "copy input to fpga\n");
fpga_copy_input(ptr_fpga, input->sequence);
fprintf(stderr, "start fpga process\n");
fpga_start(ptr_fpga);
fprintf(stderr, "wait for done\n");
fpga_done(ptr_fpga);
fprintf(stderr, "copy output from fpga\n");
fpga_copy_output(ptr_fpga, output->sequence);
fprintf(stderr, "results: '%s'\n", output->sequence);
fpga_release(ptr_fpga);
fprintf(stderr, "READY.\n");
exit(EXIT_SUCCESS);
}
I kept away the top level and the "algorithm" verilog. The already printed should be boring enough. Anyway, I'm not very positive that anyone really will have the patience to understand my post and read up till here. If YOU did so - I already thank you a lot!!!
Questions:
1. Where can I check by setting an LED if the FPGA is receiving any input, and then that it has input and has received the "start"?
2. Is there any obvious error?
3. What techniques I may use in quartus to debug this? I'm using quartus II web edition, I don't have any license, and no experience in working with oscilloscopes :(
ANY help is appreciated!