whitequark changed the topic of #amaranth-lang to: Amaranth hardware definition language · code https://github.com/amaranth-lang · logs https://libera.irclog.whitequark.org/amaranth-lang
<_whitenotifier-e> [YoWASP/nextpnr] whitequark pushed 1 commit to develop [+0/-0/±1] https://github.com/YoWASP/nextpnr/compare/a7cc51bf9661...b2e354f4dbbf
<_whitenotifier-e> [YoWASP/nextpnr] whitequark b2e354f - Update dependencies.
<d1b2> <Gabriel> Is there a "light-weight" way to specify a function? Something like a macro that doesn't require a submodule
<whitequark> not currently; it may be introduced in the future
<d1b2> <Gabriel> It would be nice if this sort of thing would synthesize:py class Color: def __init__(self, r : Signal, g : Signal, b : Signal): self.r = r self.g = g self.b = b self.rgb = Cat(self.r, self.g, self.b)
<d1b2> <Gabriel> Is there another way to do that (preferably as a reusable datatype rather than a module)?
<d1b2> <Gabriel> it works except for the .rgb
<_whitenotifier-e> [YoWASP/yosys] whitequark pushed 1 commit to develop [+0/-0/±1] https://github.com/YoWASP/yosys/compare/f6fb958b82d4...7ade1a295f97
<_whitenotifier-e> [YoWASP/yosys] whitequark 7ade1a2 - Update dependencies.
Degi_ has joined #amaranth-lang
Degi has quit [Ping timeout: 240 seconds]
Degi_ is now known as Degi
<d1b2> <Gabriel> Is there a way to check if a multiplication overflows?
<d1b2> <emeb> If the multiplier is built correctly (result bits = multiplier bits + multiplicand bits) then it shouldn't overflow.
<d1b2> <emeb> If you're reducing the bitwidth at the top end then you should use a saturation function to ensure the result doesn't wrap.
<d1b2> <Gabriel> I'm running into the limit of timing violations so I can't actually make the multiplier big enough. However, I don't care about large numbers since they'll be discarded later in the calculation anyway. If I see the multiplication is going to overflow, I think I can just invalidate it early
<d1b2> <emeb> So you build a mutiplier without enough msbits?
<d1b2> <emeb> I suppose you could look for a carry/borrow on the last adder
<d1b2> <Gabriel> Actually I think I should just step back and take a different approach alltogether. I'm just trying to draw a line without a framebuffer...
<d1b2> <Gabriel> But I think I'll want a framebuffer at some point anyway, so I'll just do that
<d1b2> <Gabriel> oh, the iCE40 doesn't have enough BRAM for a framebuffer of any reasonable size. Gross.
<d1b2> <emeb> Depends on which part - the UP5k has 128kB SPRAM which is enough for a modest frame buffer.
<d1b2> <Gabriel> I was hoping to capitalize on the dual-port RAM to not worry about how drawing to the fb will impact the part that sends the fb to the screen
<d1b2> <Gabriel> But I'm not sure how that would've worked anyway with drawing a partially-updated framebuffer. And I don't think there will be enough room for multiple framebuffers but lemme do some math I guess
<d1b2> <emeb> When I did something like that I designed it with interleaved access - video system and CPU get control on alternate clock cycles.
<d1b2> <Gabriel> Oh wait I'm missing something obvious
<d1b2> <Gabriel> I don't need to calculate each pixel separately. I know they'll come up in a certain order, so I can use that to follow normal line-drawing algorithms, just with the constraint of left-to-right top-to-bottom
<d1b2> <Gabriel> Should only take a handful of registers and luts for each line then, so I can just instantiate a bunch of them to draw multiple lines
<d1b2> <Gabriel> Where can I find an example of using BRAM in Amaranth?
<d1b2> <emeb> Here's both read-only and read/write BRAM: https://github.com/emeb/orangecrab_adc/blob/master/gateware/nmigen/fir8dec.py
<d1b2> <emeb> yup
<d1b2> <Gabriel> Thanks!
<d1b2> <dragonmux> @Gabriel for the future, it might be worth you looking at the Karatsuba method as this allows the multiplication to be expressed in parts, including multiplying just the upper bits to find out if it'd overflow
<d1b2> <dragonmux> We'll get you an example shortly, but it should ease your timing pains
indy_ has joined #amaranth-lang
indy has quit [Ping timeout: 248 seconds]
indy_ has quit [Ping timeout: 240 seconds]
kaucasus has joined #amaranth-lang
indy has joined #amaranth-lang
Guest59 has joined #amaranth-lang
Guest59 has quit [Quit: Client closed]
Guest59 has joined #amaranth-lang
<Guest59> Is there some way to specify a default/catchall state with FSM? Suppose I have 5 states in my FSM, requiring a 3-bit state register with the remaining three states undefined. I would like to all the remaining states transition to one of the well defined states in the case that the state register randomly takes a value corresponding to an undefined
<Guest59> state at device startup. Is this possible with the FSM construct?
<Degi> I think at device startup the FSM is initialized to the default state or the first state, or is there something different that it might take a random state?
<Guest59> I'm trying to keep the design technology independent, i.e. not assuming that it's initialized to a known value like in an FPGA
<kaucasus> Normally the verilog code Amaranth generates in the end will explicitly start with an assignment to the first/default state of the FSM
<Guest59> Seems like the next next state is assigned to the current state by default:
<Guest59>   reg [1:0] fsm_state = 2'h0;
<Guest59>   reg [1:0] \fsm_state$next ;
<Guest59>   // ...
<Guest59>   always @(posedge clk)
<Guest59>     fsm_state <= \fsm_state$next ;
<Guest59>   always @* begin
<Guest59>     \fsm_state$next = fsm_state;
<Guest59>     casez (fsm_state)
<Guest59>       2'h0:
<Guest59>           \fsm_state$next = 2'h1;
<Guest59>       2'h1:
<Guest59>           casez (\$1 )
<Guest59>             1'h1:
<Guest59>                 \fsm_state$next = 2'h2;
<Guest59>           endcase
<Guest59>       2'h2:
<Guest59>           \fsm_state$next = 2'h1;
<Guest59> Is there a way to format code nicely here?
<Degi> Maybe put it on paste.debian.net/
<Guest59> Maybe this is more readable: https://paste.debian.net/hidden/985b926a/
<kaucasus> Interesting, me trying to generate the basic FSM example, found here: https://github.com/amaranth-lang/amaranth/blob/main/examples/basic/fsm.py generates the boilerplate of
<kaucasus> `if (\initial ) begin end`, but as you can see it doesn't actually put anything there
<kaucasus> Nonetheless, it *does* initialize it the normal way by putting the register as
<kaucasus> reg [2:0] fsm_state = 3'h0;
<kaucasus> I'm not entirely familiar with different technologies, but I assume the synthesis tool you use should see that and correctly imply that it's a standard value?
<kaucasus> *initial value
<Guest59> I think ASIC implementations rely on explicit reset lines which are in fact present in the generated verilog:
<Guest59>     casez (rst)
<Guest59>       1'h1:
<Guest59>           \fsm_state$next = 2'h0;
<Guest59>     endcase
<kaucasus> yeah indeed, that is always the case, so it should be fine?
<kaucasus> (I think?)
<Guest59> Should be fine for most circuits. I'm just experimenting with the idea of FSM that naturally navitate to a well known state without an explicit reset. In any case I think I can just implement it hand with a Switch if it's not supported by FSM natively.
<Degi> Hmm, I think you can somehow directly write the state
Guest59 has quit [Quit: Client closed]
<kaucasus> Hmm, I'm going over the RFC for the Aggregate data structure library, and I'm not quite grokking the difference between e.g. a Struct and a StructLayout.
<kaucasus> Where exactly do they differ? I'm assuming the Layout is also slightly different than the Layout used in 0.3 to basically layout a record.
<d1b2> <dragonmux> Your best bet Guest59 is to have explicit state assignments in all states of the FSM that take you back toward the initial state if things aren't right for the state it finds itself in.. an example of how it can be achieved is the JTAG TAP state machine
<d1b2> <dragonmux> Even in raw Verilog that's your best bet
nak has quit [Ping timeout: 256 seconds]
<d1b2> <dragonmux> Gabriel: https://gist.github.com/dragonmux/c2c19abc1aa36d3b4227d1279c7d2ade this is what you were looking for regarding multiplying and figuring out overflow without having it cripple f(max)
<d1b2> <dragonmux> translated and cleaned up some old code for you and added plenty of comments
<d1b2> <dragonmux> hopefully it'll make sense
<d1b2> <Gabriel> Thanks a bunch!
<d1b2> <dragonmux> The important part is that B^m from the method formulae in the article is 2^8 in our example, as we're handling 8 bits at a time for 4 16-bit multiplies to complete a 32-bit multiply - if you need it further explained then do just ping us and we'll do our best to make the abstract maths more concrete
dfhg has joined #amaranth-lang
dfhg has quit [Client Quit]
kaucasus has quit [Quit: kaucasus]
Wolfvak has quit [Ping timeout: 276 seconds]
Wolfvak has joined #amaranth-lang
peepsalot has quit [Ping timeout: 244 seconds]
lf_ has quit [Ping timeout: 240 seconds]
lf has joined #amaranth-lang