- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello everyone.
It's my first approach with addressing custom peripheral in a nios II based system, so I started developing a simple custom hardware that reads a 32 bit input and gives back "input+1". All seemed to work fine, in the C code I used IOWR_32DIRECT(base, 0, input) and IORD_32DIRECT(base, 0) to query the custom logic; I gave 8 as input and I got 9 as output. So I did the next step :) , writing another peripheral which needs a 64-bit transfer. I know Nios only supports 32-bit transfers, so i chunked the single tranfer into two 32-bit ones, using an address bit to distinguish between the two half-words. here is the vhdl code (obtained from the first that worked, with some modifications) , I simulated it with modelsim and seems to work fine:library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
-- define interface
entity des_wrapper64 is
port (
-- inputs:
address : IN STD_LOGIC;
chipselect : IN STD_LOGIC;
clk : IN STD_LOGIC;
reset_n : IN STD_LOGIC;
write_n : IN STD_LOGIC;
read_n : IN STD_LOGIC;
writedata : IN UNSIGNED(0 to 31);
-- outputs:
readdata : OUT UNSIGNED(0 to 31)
--d: OUT UNSIGNED(0 to 63)--
);
end entity;
architecture arch of des_wrapper64 is
begin
process(clk,reset_n)
variable data:UNSIGNED(0 to 63);
begin
if reset_n='0' then
--nop
elsif clk='1' and clk'event then
-- writing
if chipselect='1' and write_n='0' then
case address is
when '0' => data(32 to 63) :=writedata(0 to 31); --write lsb
when '1' => data(0 to 31) :=writedata(0 to 31); --write msb
when others => readdata<=x"FFFFFFFF";
end case;
end if;
-- reading (must send input + 1)
if chipselect='1' and read_n='0' then
data:=data +1;
case address is
when '0' => readdata(0 to 31)<= data(0 to 31); --read lsb
when '1' => readdata(0 to 31)<= data(32 to 63); --read msb
when others => readdata<=x"FFFFFFFF";
end case;
end if;
end if;
--d<=data;
end process;
end arch;
here is the C code: //base address (Custom Peripheral)# define CP_ADDR (0x01001030)
int main()
{
unsigned int data2writelsb=0xAAAAAAAA; // two halves of input
unsigned int data2writemsb=0xBBBBBBBB;
unsigned int data2readlsb=3; // two halves of output initialized to some value
unsigned int data2readmsb=3;
IOWR_32DIRECT(CP_ADDR,0,data2writelsb);
IOWR_32DIRECT(CP_ADDR,1,data2writemsb);
data2readlsb=IORD_32DIRECT(CP_ADDR,0);
data2readmsb=IORD_32DIRECT(CP_ADDR,1);
return 0;
}
The problem is I always have: data2readlsb=0x00000000; data2readmsb=0x00000000; i initialized the two data2read halves to 3 to be sure that IORD works (initializing them to 0 i couldn't see if something is actually read or the IORD doesn't work and the zeroes are simply the initialization value unmodified). I suppose IORD works because modifying randomly the offset I can get values other than zero, so it is actually reading somewhere in the address space! I really don't know how to fix this problem...can anyone help me?:confused: Thanks Anna
- Tags:
- Vhdl
Link Copied
4 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
try using signaltap
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Problem solved, it was my fault, I didn't understand well how avalon bus addressing works :)
Since I've read many questions about register addressing in custom peripheral, but no one had been resolved, i will explain what i learned, in a simplified way: when you define an address width for your logic, you are choosing how much registers you give to your peripheral; for example, a width of 3 bits will lead to a maximum of 8 registers: 000,001,010,011 etc. in the vhdl code of the hw, you decide what to do with every address (i.e. adding a case statement, case address is "000" => do something...etc.) Since Nios address bus is 32 bit wide, avalon bus transforms this addresses into a 32-bit value in this way: as first thing, a range of 32-bit addresses is assigned to your hw starting from the base address, every register is 4 byte wide; for example, with 3 bits address we will have a range given by base address, base+4 bytes, base+8 bytes...etc (up to 8 values in total). Every read operation accesses 4 bytes, so if you want to access the branch of the case statement related to address 001, you must type IORD(base,4) that leads to an address of BASE_ADDR+4 bytes, and to access address 002 you must type IORD(base,8)... writing IORD(base,0), IORD(base,1) , IORD(base,2) will have the same result of calling IORD(base,4), so to access different addresses and so different registers you must jump by multiples of 4 bytes (1 word in nios terminology). Hope it was exausting :)- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, I would always map a C struct onto the device, use an address that bypasses the cache and use normal C struct member operations.
the IORD() etc marcos are designed to cause grief.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your tips! I used IOWR32_DIRECT() and IORD32_DIRECT() that should bypass the cache, and it works :)

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page