<mithro>
whitequark: I was looking at one of your tweets with the migen python simulator code and noticed you had a "yield Delay(1e-6)" which made me ponder the bare "yield" to advance the clock -- maybe it should be `yield ClockTick("sys")`-- would make it much easier to do multi-clock domain stuff if you could tell which sync clock you were trying to advance too?
proteusguy has joined #m-labs
proteusguy has quit [Excess Flood]
proteusguy has joined #m-labs
proteusguy has quit [Ping timeout: 245 seconds]
_whitelogger has joined #m-labs
futarisIRCcloud has quit [Quit: Connection closed for inactivity]
proteusguy has joined #m-labs
<whitequark>
mithro: that's alrerady done
<whitequark>
yield Tick() or Yield Tick("clock")
<whitequark>
you just need to use .add_process() instead of .add_sync_process(), which is compatible with migen API
proteusguy has quit [Ping timeout: 250 seconds]
_whitelogger has joined #m-labs
futarisIRCcloud has joined #m-labs
attie has quit [*.net *.split]
forrestv has quit [*.net *.split]
tinyfpga has quit [*.net *.split]
tinyfpga has joined #m-labs
forrestv has joined #m-labs
attie has joined #m-labs
futarisIRCcloud has quit [Quit: Connection closed for inactivity]
cr1901_modern1 has joined #m-labs
cr1901_modern has quit [Ping timeout: 245 seconds]
cr1901_modern1 has quit [Quit: Leaving.]
cr1901_modern has joined #m-labs
proteusguy has joined #m-labs
proteusguy has quit [Remote host closed the connection]
proteusguy has joined #m-labs
d_n|a has joined #m-labs
<d_n|a>
bb-m-labs: force build --branch=pull/1299/head artiq
<bb-m-labs>
build #2976 forced
<bb-m-labs>
I'll give a shout when the build finishes
<d_n|a>
whitequark: The ranges are None, which apparently means that they are not yet resolved - how is this supposed to work?
<whitequark>
hmm
<whitequark>
I don't remember, let me look
<d_n|a>
Thanks
<whitequark>
that's weird, strings live forever
<d_n|a>
The problem seems to be the targets on the left side
<d_n|a>
Target in this case
<d_n|a>
The string is Global()
<d_n|a>
(and ("bar",) is Global() too, which is correct)
<whitequark>
oh
<whitequark>
data = "bar"
<whitequark>
a = data
<whitequark>
this still fails
<whitequark>
i think there needs to be a branch for this case that assigns rhs region to lhs region
<whitequark>
do you think you can implement that? i think it's just a check before that outlives check but i may be missing something
<d_n|a>
whitequark: Hmm... The region for data is also None, though, i.e. both lhs and rhs are None for the second assignment
<whitequark>
hm
<whitequark>
i think the first assignment has the same problem, it's just latent
<whitequark>
because Global outlives anything
<d_n|a>
There is some code which tries to contract the live range at line 307, which looks like it is intended to deal with this case. But it doesn't trigger because Global() is not a Region
<d_n|a>
(there is an instanceof(region, Region) check missing)
<whitequark>
i don't think that's right
<whitequark>
hmmm
<whitequark>
no, it is
<d_n|a>
It definitely seems like this wasn't anticipate during the design (what with Region.contract not being able to set self to Global()), but I'm unsure how else this was supposed to work
<d_n|a>
Might be nicer to fold the update into the RegionOf visitor, though?
<whitequark>
I mean, you can't contract a Region to a Global
<whitequark>
it would be expanding
<whitequark>
but yeah, it's not quite the right design...
<whitequark>
i'm not sure if the visitor is the right place to do it
proteusguy has quit [Remote host closed the connection]
<lkcl>
python introspection that automatically creates pipeline stage names, automatically does the m.d.sync += {newname}.eq(prevname} stuff
<lkcl>
and uses a contextmanager so it looks like nmigen.
<lkcl>
whitequark: hi. attie and i had a really interesting conversation, both of us identified that something akin to a c-style "Union" (basically an object except the name's already taken in python) would be really useful
<whitequark>
mhmm
<whitequark>
how would it translate to RTLIL or Verilog?
<lkcl>
i've already had to create something called "ObjectProxy" which does a dir() walk on its members and identifies (recursively) signals and more ObjectProxies
<lkcl>
as whatever the objects that were in it
<whitequark>
that doesn't work
<lkcl>
i've already done it, and it does.
<lkcl>
the signal names suck, though
<lkcl>
as they're the "leaf" node names, rather than being constructed from the object-hierarchy
<whitequark>
if you have two Records inside of an Union you can't just assign to either record and expect changes to propagate further
<lkcl>
...
<lkcl>
i've created an eq function which takes care of that
<lkcl>
1 sec
<lkcl>
where did i put it... big reorg yesterday :)
<whitequark>
so if you have a Record([("a", 1), ("b", 2)]) and Record([("c", 2), ("d", 1)])
<whitequark>
then you assign to .d, how does that propagate to the bits of .b ?
<lkcl>
then assigning one to the other is a mistake
<whitequark>
that's not how c unions work
<lkcl>
it's not what eq() is for
<whitequark>
so you should start over and coherently explain what behavior do you *actually* need
<lkcl>
ok, sorry... hang on... Structs! sorry! Structs
<whitequark>
oh
<whitequark>
but records are already structs
<lkcl>
sorry, been a while
<lkcl>
they are... except they're static.
<whitequark>
structs in c are static also?..
<lkcl>
you can't do eq on the *Record*, it's necessary to do eq on the *members* of the record
<whitequark>
um
<whitequark>
of courrse you can
<lkcl>
you can??
<lkcl>
the Record itself has an eq method?? moo?? :)
<whitequark>
a Record is a Value.
<whitequark>
so you can pass it anywhere a Value is expected.
<whitequark>
that means on the lhs of .eq()
<whitequark>
or the rhs
<whitequark>
this was one of the major issues with oMigen, which i fixed
<lkcl>
ahh goood.
<lkcl>
so that means that the explicit isinstance detection of Records (and field-walking them) can go in the eq() function. good! thank you!
<whitequark>
you could do this in oMigen too
<whitequark>
using .raw_bits()
<whitequark>
but it was a source of frustration so i made Record first-class
<lkcl>
ok, so the bit that's different between what i need and a Record is: i need to be able to *dynamically* add anything (literally) anything to the not-Record
<lkcl>
attie and i couldn't think of a suitable name.
<whitequark>
what do you mean by dynamically add
<lkcl>
ObjectProxy was what i use at the moment
<lkcl>
x = ObjectProxy()
<whitequark>
migen is a code generator, its output is static by definition
<whitequark>
so you mean something else
<lkcl>
x.signal1 = Signal()
<lkcl>
y.signal = Signal(32)
<lkcl>
s/y/x
<lkcl>
x.signal3 = ObjectProxy()
<lkcl>
x.signal3.x = Signal(55)
<lkcl>
etc
<lkcl>
etc
<whitequark>
i think this is a really bad pattern, because the resulting layout depends on the order in which your code executes
<whitequark>
let's say i want to know in which order the fields are laid out
<whitequark>
the answer is, "fuck you" or alternatively "add a print statement to find out"
<whitequark>
i don't want functionality like this in the core
<lkcl>
then our team have a bit of a problem, as we will have to monkey-patch and/or hard-fork nmigen
<whitequark>
you are free to use an inferior version of nmigen if you want, of course
<lkcl>
i tried deriving ObjectProxy from Value and nmigen barfed in hdl.py
<lkcl>
in the visitor code.
<whitequark>
yeah, the visitors aren't easily extensible
<whitequark>
but you don't need to fork, though
<lkcl>
all i *actually* wanted was to have _lhs_xxxx and _rhs_xxxx work
<whitequark>
what you essentially are doing, is having a record with a layout that keeps changing
<lkcl>
once i'd added _lhs_signals and _rhs_signals it barfed
<whitequark>
you can have your ObjectProxy() wrap a Record() object
<lkcl>
it doesn't "change", it's constructed during the __init__ phase
<whitequark>
yeah it does
<whitequark>
it changes each time you set a new field
<lkcl>
honestly, that's perfectly fine.
<lkcl>
the trade-off is acceptable as the ability to have (and pass) objects is... it's...
<whitequark>
i don't think the trade-off is acceptable, no
<lkcl>
i have over ten classes containing 2-depth nested Signals already
<lkcl>
and may have to go to three levels
<whitequark>
so, there are two approaches to designing a language
<lkcl>
passing those around to pipeline stages is absolutely essential
<whitequark>
one is to add ad-hoc fixes that solve the immediate problem you're encountering without regard to their wider effect
<lkcl>
otherwise we have to pass around dozens of signals as a flat 1D list or something completely unsuitable
<whitequark>
the other is to consider that immediate problem in the context
<lkcl>
appreciated.
<whitequark>
oMigen suffered quite a bit from the first approach
<whitequark>
anyway
<whitequark>
your ObjectProxy doesn't need an nmigen fork
<whitequark>
put a Record inside it and add fields to that record when you want
<lkcl>
that's an interesting approach. i could hide it behind __setattr__ and __getattr__.
<whitequark>
(or even inherit it from Record? that could work)
<lkcl>
yehyeh
<lkcl>
i wonder....
<whitequark>
that's dirty, and i don't like it, but i think you'd be just using public interfaces
<whitequark>
so it's something i essentially have to support regardless
<lkcl>
it means if anyone tries to add an object named "fields", they're hosed...
<whitequark>
correct
<whitequark>
or name or src_loc or layout
<whitequark>
in existing Record you can work around this by doing ["layout"]
<lkcl>
also, even just inheriting from Value is equally problematic
<whitequark>
which will read the field called layout specifically
<lkcl>
i don't like it either
<whitequark>
inheriting from Value is not the same as inheriting from Record
<whitequark>
if your object behaves exactly like Record with respect to Record's interface, it's fine
<whitequark>
like it follows LSP
<lkcl>
understood. ah, yeah, the identification / handling will be different
<whitequark>
following LSP means well-written code elsewhere in nmigen will handle it fine
<lkcl>
i'll give it a shot and see what happens.
<whitequark>
and if not it probably needs to be fixed regardless
<lkcl>
LSP?
<whitequark>
liskov substitution principle
<whitequark>
also known as "Circle is not a subclass of Ellipse"
<lkcl>
hey, first hit on google "LSP definition"! ;)
<lkcl>
ohh yehyehyeh, ha
<lkcl>
i could have done with knowing about that a week ago when describing python OO / abstract base classes to people, oh well :)
<whitequark>
see, i hate OO, and you should know your enemies well, so i had to study it in detail
<whitequark>
that made me hate it more
<lkcl>
very useful conversation
<lkcl>
haha
<lkcl>
ooo don't go near scheme, whatever you do
<whitequark>
dynamic-wind is horrible
<whitequark>
but there are scheme implementations that don't use it
<whitequark>
i think racket doesn't anymore?
<whitequark>
anyway, scheme with delimited continuations is great
<lkcl>
there's things you can do in scheme with a single-character operator which take a few in python, and over *eight* lines in java
<lkcl>
scheme is just one of those rare languages i used to hear people talk about, 10-15 years ago, with awe
<lkcl>
ok - thank you. very useful conversation. will let you know how i get on.