Forum Discussion

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

IOWR and IORD with PIOs

I have a basic question concerning PIOs. Currently, I am sending 4 8-bit integers over 4 ouput PIOs from NIOS to hardware to do a calculation on them and return another 8-bit integer value. This is achieved as below.


alt_u8 val_1 = 10;
alt_u8 val_2 = 15;
alt_u8 val_3 = 20;
alt_u8 val_4 = 25;
alt_u8 result_val;
 
IOWR_ALTERA_AVALON_PIO_DATA(DATA_OUT1_BASE , val_1);
.
.
IOWR_ALTERA_AVALON_PIO_DATA(DATA_OUT4_BASE , val_4);
 
result_val = IORD_ALTERA_AVALON_PIO_DATA(RESULT_IN0_BASE,0);

Now instead of using 4 PIOs of width 8, I want to use 1 PIO of width 32 to send my four integer values. What are the IOWR commands that I should write assuming my new 32-bit PIO base address is DATA_OUT_32_BASE?

Also on the hardware side where the calculation is done, the input port will now be a 32-bit input, i.e. [31:0] data_32_in;. How do I separate that input signal into its 4 component integers to use in the calculation?

15 Replies

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

    Like you already found out, I was going to suggest that you might still have some other problems with pointers. If you pass a pointer, you have to dereference the pointer in the code/macro/firmware before you can get the info that the pointer points to. You were probably getting the results of the addresses of the data, rather than the values of the data.

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

    I assumed your ALT_CI_MYMACRO parameters were pointers and this was wrong.

    From your last post I understand it needs 32bit values.

    Then change the code this way:

    
    alt_u8 small_1= {1,2,3,4};
    alt_u8 small_2= {5,6,7,8};
     
    alt_u32 custom_int_res = 0;
    custom_int_res = ALT_CI_MYMACRO( *((alt_u32 *)small_1), *((alt_u32 *)small_2) );

    The (alt_u32*) forces compiler to interpret small_1 as a pointer to a alt_u32 value instead of the alt_u8 you defined. Then the * references to the pointed value (which is now seen as u32)

    Regards

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

    --- Quote Start ---

    Then change the code this way:

    
    alt_u8 small_1= {1,2,3,4};
    alt_u8 small_2= {5,6,7,8};
     
    alt_u32 custom_int_res = 0;
    custom_int_res = ALT_CI_MYMACRO( *((alt_u32 *)small_1), *((alt_u32 *)small_2) );

    --- Quote End ---

    Thank you so much again Cris and with the very good explanation too. I tried your method and this operation happened with less ticks than when using the '<<'.

    Now I have another problem :) Those small_1 and small_2 arrays have changing values, coming from a bigger array. The 8 values are being collected from as a 'sliding window' as shown in code below.

    
     # define ROW 3# define COL 5
     
    // 2-D array containing unsigned 8-bit integers
    alt_u8 array_image = { /* fill in values */};
     
    alt_u8 small_1;
    alt_u8 small_2;
     
    for(y=0; y<(ROW -2); y++)  {
                   for(x=0; x<(COL-2); x++)  {
     small_1 = array_image; small_1 = array_image;
     small_1 = array_image; small_1 = array_image;
     
     small_2 = array_image; small_2 = array_image;
     small_2 = array_image; small_2 = array_image;
     
     store_result = ALT_CI_MYMACRO( *((alt_u32 *)small_1), *((alt_u32 *)small_2) );
     
                   }
     }
     
    

    But the fact that I am populating the small arrays within the loops requires nios cpu time. Is there instead a smart way again using the pointers to do this? For example, suppose my 3x5 data is as such:

    10 20 30 40 50

    11 21 31 41 51

    12 22 32 42 52

    I want the following values in each small array at each loop iteration.

    at x = 0, small_1 = {10,20,30,11} and small_2 = {31,12,22,32}

    at x = 1, small_1 = {20,30,40,21} and small_2 = {41,22,32,42}

    at x = 2, small_1 = {30,40,50,31} and small_2 = {51,32,42,52}
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Well, conceptually you can something like this:

    alt_u8 array[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };

    Then

    *((alt_u32*)array) returns 0x04030201

    *((alt_u32*)(array+1)) returns 0x05040302

    *((alt_u32*)(array+2)) returns 0x06050403

    ...

    and so on

    For clarity, since you are not used to handle pointers, consider that

    *((alt_u32*)(array+n)) is the same as *((alt_u32*)&(array[n]))

    In practical, I can't remember if Nios requires the 32bit alignment in order to do it as supposed. This depends from the data bus architecture.

    Being this true or not, you'll have very different performance, because in one case the processor can do the bytes to 32bit packing with a single memory access, while in the other it must still handle the single bytes as you do now.

    Since you already measure cpu time, you can simply put this in your code and test if you obtain an improvement.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks for the explanation. Well, I realize that my method is not possible (at least not straighforward), and it is not my final goal anyway to send data this way to hardware for processing. But it got me to understand a bit about Custom Instructions and a lot more about pointers thanks to Cris :)