Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

Avalon MM slave custom component: register reading/writing issue

Hi all!

I'm having some trouble designing an Avalon MM slave component. I’m new with FPGA and probably is something really easy to fix. I’m using Quartus prime (15.1) and a Max10 FPGA development kit.

I’d like to understand the right way to implement a custom Avalon MM salve component and to integrate it into Qsys to read/write registers from NIOS processor.

At moment I can write and read the registers from the processor but something strange is happening into the memory. The component is using 8 bits address and 4 test registers LED0, LED1, LED2, LED3. When I try to write the registers with 4 different values it seems that the values are shifted by 1 location (a word) and the last value is written in all the rest of the memory space allocated to the component.

The component address assigned in Qsys is 0x9400 and the picture attached shows the content of the memory in debug mode in Eclipse. Verilog code and C code are also attached.

Does anybody have a good idea about a solution?

Thanks

Verilog component code:

// testSlave.v

`timescale 1 ps / 1 ps

module testSlave (

input [7:0] avs_testSlave_address, // testslave.address

input avs_testSlave_read, // .read

output [31:0] avs_testSlave_readdata, // .readdata

input avs_testSlave_write, // .write

input [31:0] avs_testSlave_writedata, // .writedata

output avs_testSlave_waitrequest, // .waitrequest

input clock_testSlave_clk, // clock_testSlave.clk

input reset_testSlave_reset // reset_testSlave.reset

);

reg [31:0] LED0,LED1,LED2,LED3;

reg [31:0] avs_testSlave_readdata_;

assign avs_testSlave_readdata = avs_testSlave_readdata_;

always @(posedge clock_testSlave_clk or posedge reset_testSlave_reset)

begin //write

if(reset_testSlave_reset == 1) //if(!reset_testSlave_reset)

begin

LED0 <= 0;

LED1 <= 0;

LED2 <= 0;

LED3 <= 0;

end

else if(avs_testSlave_write)

begin

case(avs_testSlave_address)

0: begin LED0 <= avs_testSlave_writedata; end

1: begin LED1 <= avs_testSlave_writedata; end

2: begin LED2 <= avs_testSlave_writedata; end

3: begin LED3 <= avs_testSlave_writedata; end

endcase

end

end

always @(posedge clock_testSlave_clk or posedge reset_testSlave_reset)

begin //read

if (reset_testSlave_reset == 1)

begin

avs_testSlave_readdata_ <= 0;

end

else if(avs_testSlave_read)

begin

case(avs_testSlave_address)

0: begin avs_testSlave_readdata_ <= LED0; end

1: begin avs_testSlave_readdata_ <= LED1; end

2: begin avs_testSlave_readdata_ <= LED2; end

3: begin avs_testSlave_readdata_ <= LED3; end

endcase

end

end

endmodule

Nios C code:

while(1)

{

if(alt_timestamp() > 50000000)

{

printf("* %u \n", alt_timestamp());

printf("* %u \n", counter);

counter++;

alt_timestamp_start();

if(counter %2 == 0)

{

testValue = 0x0A;

IOWR(TESTSLAVE_0_BASE, 0, testValue);

printf("\n write0 %u \n", testValue);

testValue = 0x0B;

IOWR(TESTSLAVE_0_BASE, 1, testValue);

printf("\n write1 %u \n", testValue);

testValue = 0x0C;

IOWR(TESTSLAVE_0_BASE, 2, testValue);

printf("\n write2 %u \n", testValue);

testValue = 0x0D;

IOWR(TESTSLAVE_0_BASE, 3, testValue);

printf("\n write3 %u \n", testValue);

}

else

{

ledRegValue0 = IORD(TESTSLAVE_0_BASE, 0);

printf("\n read led0 %u \n", (ledRegValue0));

ledRegValue1 = IORD(TESTSLAVE_0_BASE, 1);

printf("\n read led1 %u \n", (ledRegValue1));

ledRegValue2 = IORD(TESTSLAVE_0_BASE, 2);

printf("\n read led2 %u \n", (ledRegValue2));

ledRegValue3 = IORD(TESTSLAVE_0_BASE, 3);

printf("\n read led3 %u \n", (ledRegValue3));

}

}

}

http://www.alteraforum.com/forum/attachment.php?attachmentid=11459&stc=1

14 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Try it like this:

    h2p_lw_pio_d_dirn = virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_D_BASE + 4 ) & ( unsigned long)( HW_REGS_MASK ) );

    The gpio_swporta_ddr (data direction) register offset is 0x4, not 0x1, according to cv_5_hps_trm.pdf manual.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Try it like this:

    h2p_lw_pio_d_dirn = virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_D_BASE + 4 ) & ( unsigned long)( HW_REGS_MASK ) );

    The gpio_swporta_ddr (data direction) register offset is 0x4, not 0x1, according to cv_5_hps_trm.pdf manual.

    --- Quote End ---

    Yes indeed you are quite correct, that works fine, thank you very much.

    I can now read and write the registers in my firmware.

    I understand the 4 vs 1 is a matter of byte vs word addressing.

    I now have 4 of the "instruments" from my Cyclone II firmware installed in the DE0-Nano-SoC fabric, and under test.

    Sorry to be a pain, but can you give me a link to the cv_5_hps_trm.pdf manual ? I have searched the Altera site and not yet found it.

    .
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Oh thanks indeed.

    I am using the DE0-Nano-SoC board, which has a Cyclone V :

    Programmable Logic IC Development Tools Cyclone V SE 5CSEMA4U23C6N + 800MHz Dual-core ARM Cortex-A9 processor

    http://www.terasic.com.tw/cgi-bin/page/archive.pl?language=english&categoryno=205&no=941

    https://www.mouser.co.uk/new/terasic-technologies/terasic-atlas-soc-kit/

    Except for the point that you have helped me over I have found it a very easy and flexible system to work with.

    The two rows of GPIO connectors map well to similar double rows of connectors on my Cyclone II modules, and is allowing me to port hardware as well as the firmware.