C Header files for User Design Logic in the Nios.

Hello Guys,

I am using the SOPC builder to design a simple system that integrates a couple of UARTS, a soft processor and a VHDL blackbox (Connected internally in user design logic). I export a 8-bit wide signal which are connected to LEDs on-board from the blackbox. I am using the Nios Development Board Pro Edition. My VHDL code is as follows: Libraries blah blah... entity count is port( clk: in std_logic; write_con: in std_logic; chipsel: in std_logic; write_data: in std_logic_vector(1 downto 0); export dataout: out std_logic_vector(7 downto 0)); end count;

architecture RTL of count is

signal counter: std_logic_vector(7 downto 0); signal write_data_d: std_logic_vector(1 downto 0); signal resetn_d: std_logic; signal control: std_logic;

begin

control

Reply to
Ted
Loading thread data ...

Hi Ted,

A couple of potential issues:

  1. point1 is declared a pointer, when you assign it something "point1 = something", what you're doing is changing the address it points to. Use * to dereference the pointer (standard C code stuff)... so the first thing I'd do is change point1 = 1; to *point1 = 1;

  1. If you're using Nios I with a data cache, you should declare point1 to be "volatile int*(blah)"... this isn't critical as the Nios I data cache was write-through, but it is good practice and will prevent cache-coherency issues down the road. If you're using Nios II (without the legacy SDK) we have some I/O macros which direct the CPU to bypass the cache.

Obviously your C code above is pretty simple, but in a more complex situation its advisable to use the debugger to see what is happening (at least with the pointers & variables declared in your C code).... the debugger would probably catch, for example, that the pointer's address was being written, rather than the actual address off in memory.

Another general suggestion: when designing a peripheral as you are, consider (at least for bring-up purposes), include registers that allow you to read back the data... some HDL pseudo code would look like this (I am a Verilog guy :) --

at posedge clock handle reset if (chipselect and write) case addressbus: 00: reg0 = writedata 01: reg1 = writedata ... ... if (chipselect and read) case addressbus: 00: readdata = reg0 01: readdata = reg1

...and so forth. You'll burn some logic in the registers, but again, this is a fine idea for prototyping as it allows you to debug your hardware straight from the C code (then you can dereference the pointer and call printf() to display what is going on in your peripheral), which is kind of nice depending on what you're used to. Once you're up and running and want to shave off LEs, remove the registers and read logic as appropriate. This is just one idea, of course.. Additional debug options include using signal tap and triggering on the chipselect to your peripheral, or simulating in ModelSim (see the app note on simulating Nios systems) -- you can have an RTL view of what happens when your C code executes.

Hope this helps.

Jesse Kempa Altera Corp. jkempa at altera dot com

Reply to
Jesse Kempa

Good suggestion. Often you can do it with almost no additional hardware.

Sometimes a CSR type register has enough bits for this purpose. You just have to readback the C bits while reading the S bits. If there are any unused bits, you can make them R/W but not connected to anything (else).

Sometimes you can make a write only data register read/write with the read path being used only for this purpose.

--
The suespammers.org mail server is located in California.  So are all my
other mailboxes.  Please do not send unsolicited bulk e-mail or unsolicited
commercial e-mail to my suespammers.org address or any of my other addresses.
These are my opinions, not necessarily my employer's.  I hate spam.
Reply to
Hal Murray

Another question: Referring to

formatting link
where the PWM is used as an example for a Verilog Blackbox, The lowest-level of the C headers contains the following:

#ifndef __ALTERA_AVALON_PWM00_H #define __ALTERA_AVALON_PWM00_H

#define ALTERA_AVALON_PWM_CLOCK_DIVIDER(base_addr) (ALTERA_AVALON_PWM_TYPE (base_addr + 0x0 )) #define ALTERA_AVALON_PWM_CLOCK_DIVIDER_MSK (0xFFFFFFFF) #define ALTERA_AVALON_PWM_CLOCK_DIVIDER_OFST (0)

#define ALTERA_AVALON_PWM_DUTY_CYCLE(base_addr) (ALTERA_AVALON_PWM_TYPE (base_addr + 0x4 )) #define ALTERA_AVALON_PWM_DUTY_CYCLE_MSK (0xFFFFFFFF) #define ALTERA_AVALON_PWM_DUTY_CYCLE_OFST (0)

#define ALTERA_AVALON_PWM_ENABLE(base_addr) (ALTERA_AVALON_PWM_TYPE (base_addr + 0x8 )) #define ALTERA_AVALON_PWM_ENABLE_MSK (0x1) #define ALTERA_AVALON_PWM_ENABLE_OFST (0)

#endif /* __ALTERA_AVALON_PWM00_H */

What exactly does ALTERA_AVALON_PWM_TYPE do? What does ALTERA_AVALON_PWM_ENABLE_MSK and ALTERA_AVALON_PWM_ENABLE_OFST mean? If the former is a subroutine, I can't seem to find it in any of the files.

In the exacalibur.h file, there is a line:

#define na_user_logic_altera_avalon_pwm_0 ((void *)

0x00020020) // user_logic_altera_avalon_pwm

Since the base address is always pointing to void, then can I say that ALTERA_AVALON_PWM_CLOCK_DIVIDER always has the input 0?

What exactly is np_usersocket and why is it set to point to void?

Reply to
Ted

Another question: Referring to

formatting link
where the PWM is used as an example for a Verilog Blackbox, The lowest-level of the C headers contains the following:

#ifndef __ALTERA_AVALON_PWM00_H #define __ALTERA_AVALON_PWM00_H

#define ALTERA_AVALON_PWM_CLOCK_DIVIDER(base_addr) (ALTERA_AVALON_PWM_TYPE (base_addr + 0x0 )) #define ALTERA_AVALON_PWM_CLOCK_DIVIDER_MSK (0xFFFFFFFF) #define ALTERA_AVALON_PWM_CLOCK_DIVIDER_OFST (0)

#define ALTERA_AVALON_PWM_DUTY_CYCLE(base_addr) (ALTERA_AVALON_PWM_TYPE (base_addr + 0x4 )) #define ALTERA_AVALON_PWM_DUTY_CYCLE_MSK (0xFFFFFFFF) #define ALTERA_AVALON_PWM_DUTY_CYCLE_OFST (0)

#define ALTERA_AVALON_PWM_ENABLE(base_addr) (ALTERA_AVALON_PWM_TYPE (base_addr + 0x8 )) #define ALTERA_AVALON_PWM_ENABLE_MSK (0x1) #define ALTERA_AVALON_PWM_ENABLE_OFST (0)

#endif /* __ALTERA_AVALON_PWM00_H */

What exactly does ALTERA_AVALON_PWM_TYPE do? What does ALTERA_AVALON_PWM_ENABLE_MSK and ALTERA_AVALON_PWM_ENABLE_OFST mean? If the former is a subroutine, I can't seem to find it in any of the files.

In the exacalibur.h file, there is a line:

#define na_user_logic_altera_avalon_pwm_0 ((void *)

0x00020020) // user_logic_altera_avalon_pwm

Since the base address is always pointing to void, then can I say that ALTERA_AVALON_PWM_CLOCK_DIVIDER always has the input 0?

What exactly is np_usersocket and why is it set to point to void?

Reply to
Ted

Hello,

A more direct question, for the above VHDL code, how do I access the write_data port in C i.e. in cmd mode? I tried changing the contents of the base address of the VHDL blackbox but the else condition ALWAYS occurs. In my excalibur.h file, I get the blackbox base address as

0x00020020. No end address is specified.

Is it required to have a register file? Must I include the byte_enable, reset signals to get it to work? When I do something like i=*point1, then it goes into the else condition. Probably something to do with exception handling.

Is it a problem with the VHDL coding (Checked seperately in ModelSim) or something to do with the C?

Perplexed...

Reply to
Ted

Ted, I think you have a bug in your VHDL. The reason you always see two bright LEDs is that on every clock cycle _except_ the one in which you access your peripheral, your else clause (counter if ((write_data="00") and control='1') then

Reply to
Aaron Ferrucci

Hi Aaron,

Thanks for your reply. Through a process of trial and error, I managed to find the write port at base_address+3. I was just wondering if the compiler treats data-bitwidth as 32 bits and therefore assign the LSB at base_address+3. Since relevant data is only 8-bits wide, the upper bits would be always 0.

But SOPC builder is supposed to have a dynamic bitwidth right so this shouldn't happen. Like u said, the *point1=1 should work (*point4=1 works in this instance) but it doesn't. Might it be something to do with the settings i.e. how the compiler or device and pins settings are made etc. affecting the optimisation process or affecting how data is communicated to the device?

My design works but it is at best erratic. I am inserting a multiplier into the blackbox now with 32-bits and it is not working.

Ed

Reply to
Ted

Ted, void* just means a generic pointer. In your code, you're casting it to int*, which should work fine. Since your component has no address input, it spans only a single int* location. I'm not sure I understand what you mean when you say you found the write port at base_address+3.

Just to reiterate, I think you have a bug in your HDL which makes it look like you aren't able to access your hardware at the device base address.

Reply to
Aaron Ferrucci

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.