-
-
Notifications
You must be signed in to change notification settings - Fork 337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bugfix/wb pipelined #1375
base: dev
Are you sure you want to change the base?
Bugfix/wb pipelined #1375
Conversation
I cleaned up WishboneBusInterface too with additional tests for it. Which of the interfaces is meant to be used more? I made the slave factory variant support proper pipelining, whereas the other one still has classic latencies. Unrelated thing I found: Seems like if you set a field with "#=" in the simulation with the IVerilog backend, it'll never warn you not to do that and then all future retrievals of that value from the simulation of that signal will be what you set it to. The verilator backend doesn't do this. This caused a very confusing bug for me since the simulator disagreed with the fst file. It probably should warn you if you set an OUT signal in the simulation, or make those signals ineligble for the caching layer ( |
…ding asserts that one ack is generated per one request
…erent granularities
Ahhh wishbone is such hell XD I will notify people in gitter for them to know that if they use wishbone, they need to take a look in this issue. |
Looking at it in more detail, I'm not sure we should keep the totally broken version of I know that all behavior can be depended upon - but this is so far broken that we shouldn't keep it in. One general question: do we want |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A mixture of stuff from some small random number stuff in the simulation to a few questions where I'm not sure we're doing the right thing when connecting to bus instances with differing configurations.
I hope I got everything in this round - there was quite a bunch of jumping around.
import spinal.lib._ | ||
|
||
import scala.language.postfixOps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IntelliJ generates a warning that those are needed, but they are not - we should at some point decide whether to use them or not (and e.g. just set the compiler option if we have issues in future versions)
@Dolu1990 what do you think?
tester/src/test/scala/spinal/tester/scalatest/SpinalSimWishboneAdapterTester.scala
Outdated
Show resolved
Hide resolved
lib/src/main/scala/spinal/lib/bus/wishbone/WishboneSlaveFactory.scala
Outdated
Show resolved
Hide resolved
tester/src/test/scala/spinal/tester/scalatest/SpinalSimWishboneBusInterfaceTester.scala
Show resolved
Hide resolved
tester/src/test/scala/spinal/tester/scalatest/SpinalSimWishboneSlaveFactoryTester.scala
Show resolved
Hide resolved
|
||
val dri = new WishboneDriver(dut.io.bus, dut.clockDomain) | ||
dri.drive(scala.collection.immutable.Seq(WishboneTransaction(10*wordInc), WishboneTransaction(0)), we = false) | ||
dri.drive(scala.collection.immutable.Seq(WishboneTransaction(10*wordInc, 200), WishboneTransaction(0, 2)), we = true) | ||
dri.drive(scala.collection.immutable.Seq(WishboneTransaction(10*wordInc), WishboneTransaction(0)), we = false) | ||
dri.drive(scala.collection.immutable.Seq(WishboneTransaction(21*wordInc, 0)), we = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simply having read/write methods would make this a bunch simpler - but I guess not worth it since it works as is...
tester/src/test/scala/spinal/tester/scalatest/SpinalSimWishboneSlaveFactoryTester.scala
Outdated
Show resolved
Hide resolved
And what I forgot to mention in my original reply: thanks for looking into this! |
Co-authored-by: Andreas Wallner <[email protected]>
This reverts commit facaa9d.
We should maybe just map it to isRequestAck. That will keep the behavior for non pipelined usages and I also suspect that there are far fewer people using pipelined mode.
My take on this is that <> / << / >> should do reasonable conversions whenever possible to stay out of users way. It'd be sort of annoying if it detected differences in the configuration and errored out a message saying to map it out one way or another manually. So things I think it should automatically pave over:
I think ERR/RTY does require extra attention though. The standard helpfully notes:
with no real remedy or solution. I think it'd be reasonable to either emit a warning when RTY/ERR are dropped, or disallow it by default, and add a tag that lets you drop it (ie, the same kind of pattern as |
a88d773
to
f50d024
Compare
lib/src/main/scala/spinal/lib/sim/bus/wishbone/WishboneSequencer.scala
Outdated
Show resolved
Hide resolved
tester/src/test/scala/spinal/tester/scalatest/SpinalSimWishboneArbiterTester.scala
Outdated
Show resolved
Hide resolved
As a sidenote: found the reason again why I proposed to drop the |
@@ -7,7 +7,8 @@ import spinal.lib.bus.wishbone._ | |||
import scala.collection.mutable._ | |||
|
|||
object WishboneMonitor{ | |||
def apply(bus : Wishbone, clockdomain: ClockDomain)(callback: (Wishbone) => Unit) = new WishboneMonitor(bus,clockdomain).addCallback(callback) | |||
def apply(bus : Wishbone, clockdomain: ClockDomain = null)(callback: (Wishbone) => Unit) = | |||
new WishboneMonitor(bus, Option(clockdomain).getOrElse(bus.CYC.clockDomain)).addCallback(callback) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand why you put this in, but it's actually not "safe".
Reading the clockDomain of a signal that might not be a register is not really useful, since the property will be set to the clockDomain of the component where the signal was declared, not to the actual clockDomain as you'd want it. For this you'd have to search the driving FF.
Simple (and quite contrived) example - but it shows the issue:
object Blub extends App {
SpinalVerilog {
new Component {
val x = in port Bool()
val xx = RegNext(x)
val myArea = new ClockingArea(ClockDomain.external("myClockName")) {
val y = CombInit(xx)
}
val z = out port Bool()
z.setAsReg()
z := myArea.y
println(xx.clockDomain)
println(myArea.y.clockDomain)
println(z.clockDomain)
}
}
}
Prints:
clk
myClockName_clk
clk
which is not what you'd expect.
IMO we should leave the parameter mandatory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is surprising but makes sense in retrospect. I can change those back, but I think this form is still useful for the tests that don't involve any new clocks / clock areas so this logic will hold?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior is surprising to many and can easily trip someone up - we've had a few question along those lines. That's why I'd keep the parameter mandatory, if it's automatic it should work. And if you have vastly different clocks it might be easy to see in simulation, if it's just a clock enable it's much harder (I actually found out about this because I wanted to make a similar change to AHB and had to debug for a while a week later)
It is super weird they specify:
and then go on to use a slave device without a CYC_I as the example?? The only thing that makes sense to me is there should be some verbiage that STB there is mapped to STB && CYC? Since it's not that much more expensive to keep the check as the && of the two I'd say we keep it like that for now. I've been wanting to write up something like this for the unit tests and my own usages which could check for instances of STB && !CYC. It'd be a weird thing for a driver to do for sure. |
Agreed. For now I'd still keep it in... It shouldn't be that expensive and some interconnects might depend on it.
This is going to be fun if you want to support all the different modes... One doubt that just came up to me (not directly a request for this PR) looking at the WishboneArbiter: |
/** Drive the wishbone bus as master with a transaction. | ||
* @param transaction The transaction to send. | ||
*/ | ||
def sendAsMaster(transaction : WishboneTransaction, we: Boolean): Unit = { | ||
private def sendAsMaster(transaction : WishboneTransaction, we: Boolean): Unit = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't make functions private if we don't want to break users of the standard mode functionality
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can reverse this; but I think the intent of the class is that everything uses send
and it delegates out to the other functions. I'm not sure if anyone should be calling sendAsMaster directly? I guess the bus can be directionless in the sim but I'm not sure I see a use case for that.
But yeah, I guess since it can break existing code I'll reverse it. Maybe tagged as deprecated?
if(bus.config.isPipelined) bus.STALL := False | ||
|
||
val askWrite = bus.isWrite.allowPruning() | ||
val askRead = bus.isRead.allowPruning() | ||
val doWrite = bus.doWrite.allowPruning() | ||
val doRead = bus.doRead.allowPruning() | ||
|
||
val readData = bus.DAT_MISO.clone | ||
readData.assignDontCare() | ||
if(!reg_fedback){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I didn't notice last time - is it actually spec-compliant to have a slave where the bus has bus.config.isPipelined == true
but we configure the WishboneSlaveFactory with reg_feedback == false
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The spec, as far as I can tell, doesn't say much about an asynchronous ACK specific to pipelined mode.
It says this:
RULE 3.59
In pipelined mode the MASTER must accept [ACK_I] signals at any time after a
transaction is initiated.
and then has this:
Even though not initially designed for pipelined mode many simple wishbone slaves
directly support this mode. For this to be true the following characteristics must be true
1. [ACK_O] should be registered
so maybe async isn't in spec for pipelined?
For signalling, it "CYC && STB && !STALL && ACK" is ambiguous but maybe too much to mandate that all master controllers can handle it.
Whether it's in spec or not, it seems prudent to disallow it here. Should it throw an assertion or just make it registered?
STALL - totally agree dropping SEL: has the potential to break a system (CPU does byte write, slave only support word write) - IMO this should need an opt-in address granularity: really not sure on this one - it's hard to predict the impact since it's out-of-spec anyways. It wouldn't have an impact on stuff that comes from one of the generators in SpinalHDL, but dropping parts of the address (lower bits) w/o opt-in seems like a good way to hide a bug. So I see potential issues if the driver is using byte address (as it could e.g. do an unaligned byte write), no issues if the driver is using word. Looking at other bus implementations in lib we have a bit of a mix:
If we require some opt-in then I'd just make a conversion function like we have on some other bits implementations that returns the new bus - the way resize works goes seems overkill for this |
I had a discussion with @Dolu1990: we were wondering if it would make more sense to move this to a This would give us the option to get rid of all the duplicate/deprecated names... Would you be willing to do tackle that? |
After thinking about this some, this might not work. The standard says after an ERR asserts, CYC should be dropped even if there are outstanding requests. The best I can think to do for this is to institute a timeout mechanism to unfreeze the bus but this isn't great. Maybe bridging in this direction requires manual intervention. I think the
If I understand this right -- basically create a new WishboneBusB4/config/etc set of classes in a new package -- I don't know that I like this idea. This would be really confusing to people who just want to pick the right one, and I can't think of a way it wouldn't fragment the existing codebase wrt arbiters/decoders/bus conversions. I think aggressively deprecating foot-guns and being diligent about not breaking existing usages (or existing non-pipelined usages) ends up being better long term. |
The drawback is that deprecation is often either ignored, or right out not seen due to whatever editor is being used. This doesn't mix really well with keeping around functions that are incorrect for both use-cases, but named more logical. |
In any case, you either have to modify / remove those flags or just mark them as deprecated. If the idea is that we preserve the functionality of those fields for non pipelined mode, but are free to modify the behavior for the pipelined flag returns that makes sense to me. This breaks backwards compatibility but in a narrow already broken subset. For creating a WishboneB4 interface, whats the desired strategy to handle all the library tooling for arbiter / decoder / bus conversion / busIf infrastructure? Copy paste seems wrong, retooling to a higher class interface seems like its adding complexity. I have reservations about it still, but don't mind making it happen so long as I understand what the intended end state is. |
Closes #1310
Context, Motivation & Description
Fix wishbone pipelined mode
Impact on code generation
None
Checklist
Fix stall usage in wishboneslavefactory
This fixes the bug. Mainly setting stall to false is the wrong thing; setting stall to the inverse of ack fixs the logic.
Clean up wishbone flags; mark questionable ones for deprecation
Probably needs some discussion. The main thing is that some of the current status checks are not right / meaningful for pipelined mode. I opted to deprecate and make new fields for backwards compatibility reasons. The non pipelined logic makes sense for these but the pipeline path is wrong for some of them: