- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm just having a play with a basic (very basic!) peripheral (1 bit output, a few registers etc), but I can't get it to behave correctly.
module my_pwm (address, chipselect, clk, reset_n, write_n, writedata, readdata, pwm_out);
output pwm_out;
input address;
input chipselect;
input clk;
input reset_n;
input write_n;
input writedata;
output readdata;
reg readregister;
reg divider;
reg counter;
reg width;
reg period;
always @(posedge clk or negedge reset_n)
begin
if (reset_n==0)
begin
counter <= 0;
width <= 0;
period <= 0;
divider <= 0;
end
else
begin
if (chipselect && ~write_n)
begin
case(address)
3'b000 : width <= writedata;
3'b001 : period <= writedata;
3'b010 : divider <= writedata;
default :;
endcase
end
if (chipselect && write_n)
begin
case(address)
3'b000 : readregister = width;
3'b001 : readregister = period;
3'b010 : readregister = divider;
3'b011 : readregister = ~width;
default : readregister = 32'b10001111000010100000000000001010;
endcase
end
end
end
assign readdata = readregister;
endmodule
I added this as a user logic peripheral in SOPC builder. I created a small program using the IDE which basically did: IOWR(base, 0, 123456) reg = IORD(base, 0) <- reads back as 0 reg = IORD(base, 0) <- reads back as 123456 What exactly have I missed here, I can't see anything wrong with the logic, I've looked at the led & button peripherals and cant see anything wrong, wiggling the appropriate lines up & down in modelsim (just with my verilog source, not simulating the cpu) looks like it should work. I thought maybe it was some sort of cache issue, but the programmers manual says that the IOWR & IORD macro's specifically prevent cache issues from occuring. Can anybody see what I'm doing wrong here? Thanks. Adrian
Link Copied
6 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Adrian,
Without loading your system and trying it myself it difficult to say for sure what the problem is. Your assumption on the IO<Write and Read> macros is correct. So you may want to take the approach of ruling out hardware first. Taking quick look at your hdl, because you are having problems there looks like there are somethings you might want to consider modifing in the spirit of being cautious. 1. In your always block for the write case and the read case logic you are using a mix of both non-blocking and blocking assignments. In general, for sync logic, you proably want to use a non-blocking assignment( <= ). For example: Rather than thiscase(address)
3'b000 : readregister = width;
3'b001 : readregister = period;
3'b010 : readregister = divider;
3'b011 : readregister = ~width;
default : readregister = 32'b10001111000010100000000000001010;
Try this: case(address)
3'b000 : readregister <= width;
3'b001 : readregister <= period;
3'b010 : readregister <= divider;
3'b011 : readregister <= ~width;
default : readregister <= 32'b10001111000010100000000000001010;
It would be interesting to know if this changes your behavior. In addition, for your case statements you are not filling out all the cases. For example in the write case you don't give a default case and in addition for every possible case, you do not assign a value to every register. Again being cautious, rather than this: case(address)
3'b000 : width <= writedata;
3'b001 : period <= writedata;
3'b010 : divider <= writedata;
default :;
endcase
Try this: case(address)
3'b000 : width <= writedata;
period <= period;
divider <= divider;
3'b001 : period <= writedata;
width <= width;
divider <= divider;
.............etc........
default :
Do something here;
endcase
Good Luck, Altera hbutler97
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for taking the time to reply.
I didn't bother with the default case in the write because it was only a meant as a quick test to check read/write functionality before I added anything else. I *think* I originally used blocking assignments in both read & write, but I'll certainly go back and have another look to see if that makes any difference. I made changes to my original code after looking at the altera peripherals, so I made changes from my *99% working* code to alteras presumably *100%* code - and it still didn't work. I'll have another try over the weekend, and hopefully will get it to work and I can continue with my uClinux drivers. This is probably a good idea why software engineers should stay away from hardware! (can't resist though!) Adrian- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
With SOPC Builder and Nios, I'm sure there will be a lot more softies taking on hardware projects.
In general with hdls you want to be as specific as possible. Frequently if you don't explicitly state exactly what you want to have happen, synthesis tools will basically make a guess (for lack of better terms). Guess is probably better stated as it has to remember what the prior state was which usually means the inference of latches or extra logic that you don't need. In software we frequently try to minimize the number of lines of code we are able do something. A lot of times with hardware that same concept isn't true. Depending on how you write things, smaller logic can frequently be more lines of code. My personal feeling on hardware is to be specific when you can, meaning that you should always have a good idea as to what the synthesis tool is going to generate based on your hdl. In a lot of cases that means being explicit. Altera hbutler97- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Did you get your problem solved?
If not tell us.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, it still does it. Have to read twice after a write, couldn't see a problem.
I've not touched it for a couple of weeks though. Adrian- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Adrian,
Saying "have to read twice" is a hint to your problem. Here's what's going on: You are only updating the readdata bus on positive clock edges. Internal to the Avalon bus the chipselect signal is driven by combinational logic driven by the readaddress, such that CS is asserted after a clock edge. By default, your user peripheral will have zero for read latency. Avalon will sample readdata on the first clock edge after CS, but you update readdata AFTER the clock edge. If you read twice, you are actually reading what you drove on readdata for the previous read. You'll notice that everything will be delayed by one read. See the Avalon bus manual for descriptions of the bus cycle timings. You can fix by 1) setting read latency to one in your .PTF (or maybe in SOPC Builder, can't remember) or making your read logic asynchronous: (I'm a VHDL guy so pardon any syntax errors) Note that readdata only depends on address, not write_n!always @(address)
begin
case(address)
3'b000 : readregister = width;
3'b001 : readregister = period;
3'b010 : readregister = divider;
3'b011 : readregister = ~width;
default : readregister = 32'b10001111000010100000000000001010;
endcase
end
-Tim

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