Forum Discussion

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

Custom Component Help

Hi all, I'm sorry if this question if too broad, but I'm a beginner to custom components and I need some help. My final goal is to have a custom component in SOPC builder, that performs the SHA-256 hashing algorithm (takes a message in, outputs the hash of the message). I have a VHDL entity that functions as an FSM that computes the SHA hash in 20us (not optimized at all), that I want to make into a custom component. I want the Nios to set the input to the component, wait 20us, and then receive the output.

I have been doing a lot of reading on custom components and the avalon fabric, but I still find it very confusing to define my component in terms of all the signals necessary for avalon master/slave communication.

Without any of those, my entity declaration is as follows:

entity SHA_Unit is
    port(
        clk: in std_logic;
        rst: in std_logic;
        message: in std_logic_vector(255 downto 0);
        hash: out std_logic_vector(255 downto 0)
        );
end SHA_Unit;

Could anyone help me turn this entity into an avalon MM slave peripheral with the nios acting as the master? I can't find any VHDL examples for creating a custom component both in the VHDL and in the C parts. Does anyone know of an example, something as simple as an adder or something?

Also, I don't know how to address the fact that my component requires 256 bits of data, while the nios seems only to output up to 32 bits (in pio form anyway).

Sorry for the overly general nature of this question,

Max

15 Replies

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

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    Just make your readdata and writedata signals 32 bits. It doesn&#39;t matter if you are only using bits 0-7. You can then ignore the byteenable and avoid the 3 "extra" non-functional read/writes.[/b]

    --- Quote End ---

    That makes sense on the hardware side, but in the Nios IDE I don&#39;t see how it would work. When I call the IOWR macro for example, doesn&#39;t the input data need to match up to the bit width of the component data bus? How would I use the IOWR/IORD functions to use only the lowest byte of the 4 byte value?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    If you have defined your custom component as a register slave it will use native addressing. That means that if your slave is only 8 bits wide it should ignore the upper 24 bits of the data written by IOWR. Likewise, IORD will return your slave data in the lower 8 bits of a 32 bit word, with the upper 24 bits set to zero.

    For the issue of byte enables to arise, I&#39;d guess you must have defined your component as a memory slave so it will use dynamic addressing. To read/write a single byte, you&#39;d have to use IOWR_8DIRECT and IORD_8DIRECT. Have a look in the file io.h if you want to understand what these macros do. Also, the Avalon spec. document explains the difference between native and dynamic addressing and how different data bus widths are handled.

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

    You wrote:

    "That makes sense on the hardware side, but in the Nios IDE I don&#39;t see how it would work. When I call the IOWR macro for example, doesn&#39;t the input data need to match up to the bit width of the component data bus? How would I use the IOWR/IORD functions to use only the lowest byte of the 4 byte value? "

    It is not a matter of figuring out how to restrict IOWR/IORD to manage the lowest byte of the 4 byte value. It always passes and receives 32 bits. It is your custom logic that manages using only the lowest byte of the 4 byte values by utilizing only writedata[7:0], and setting readdata[7:0] bits only. If you desire, you can explicitly set readdata[31:8] to zeros in your module, but it probably is not necessary.

    Perhaps you don&#39;t like the inconsistency of passing a char/byte variable to the IOWR macro, which in turn writes to a 32-bit port. If that is the case, cast your variable to an unsigned int which will be 32 bits wide with the low order 8 bits equal to your variable. I haven&#39;t looked at it, but the macro may already do this. The alternative is to assign a temp 32-bit unsigned int variable equal to your char/byte variable, and passing the temp variable to IOWR and using IORD with your temp variable and assign your 8-bit variable to (temp_var && 0xFF), or something like eight_bit_var = (unsigned char) (IORD(base,offset) & 0xff);

    I suggest looking at the macro, or the dissassembly of the code while debugging to see what is going on to satisfy your concerns.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    @ Max

    ignore this warning about unused byteeables.

    Your datasize is 8 bit so you cannot add a single bit byteenable. i tried that and earned an error from sopc. this message is a bug as MySupport said and should be ignored.

    your chipselect is your 1 bit byteenable here ...

    This story about additional avalon access to a slave with less bits data width than the master is old and still present. (maybe a compatibility feature like the A20 gate of x86 cores :lol: )

    use signaltap and monitor your interface between avalon and your ip or memory ...

    even when you use IORD there will always be that number of accesses that are needed to get the summ of 32 bits.

    when the slave has 8 bit then it will be 4.

    only when you use IOWR there will be only these accesses you think.

    there is a workaround possible.

    if you have a look at the signaltap of your interface then you can see that the byteenables tells you how many valid accesses there will be.

    as nails already said, nios is a 32 bit cpu so all data accesses are 32 bit even when only 8 bit of them are valid.

    you might loose performace when you think in 8 bit

    if i understand your application right then you need 256bit that are written by the nios cpu and you get 256 bits as a result.

    you could go for an avalon slave that has 2 avs (avalon valid slave) ports.

    1 port for status and control, the other one for data

    tha avs for data is a 256 bit memory the nios will see 8 32bit portions of it.

    it is very easy to implement the nios read write access to that memory with byteenable control.

    now inside your sopc module you have 256 bit that feed your HASH

    if you need help, let me know.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Hello again! So everything was working perfectly, but I ended up needing to change over to 32x1 byte read/writes instead of 8x4 byte read/writes. I changed my C code to reflect this in IOWR/IORD calls, but the results are not promising. SOPC builder gives this warning:

    "Warning: cpu_0.data_master/SHA_Unit_0.s0: SHA_Unit_0.s0 does not have byteenables. Narrow (less than 32-bit) writes from cpu_0.data_master will result in spurious writes to SHA_Unit_0.s0".

    I have changed my read and write signals to be only 8-bits instead of 32-bits. Since those signals are only one byte, I don't understand how to use a byteenable to make the results more accurate.

    Any thoughts?

    --- Quote End ---

    Have you solve this problem?

    "Warning: cpu_0.data_master/SHA_Unit_0.s0: SHA_Unit_0.s0 does not have byteenables. Narrow (less than 32-bit) writes from cpu_0.data_master will result in spurious writes to SHA_Unit_0.s0".

    I have got a similar problem,when I change the "writedata" width to 8.

    If you have any idea,can you tell me?

    Thank you!

    This is my email:

    adream307@gmail.com