class Accumulator(SimpleElaboratable): """An accumulator for a Madd4Pipline Public Interface ---------------- add_en: Signal() input When to add the input in_value: Signal(signed(32)) input The input data to add clear: Signal() input Zero accumulator. result: Signal(signed(32)) output Result of the multiply and add """ def __init__(self): super().__init__() self.add_en = Signal() self.in_value = Signal(signed(32)) self.clear = Signal() self.result = Signal(signed(32)) def elab(self, m): accumulator = Signal(signed(32)) m.d.comb += self.result.eq(accumulator) with m.If(self.add_en): m.d.sync += accumulator.eq(accumulator + self.in_value) m.d.comb += self.result.eq(accumulator + self.in_value) # clear always resets accumulator next cycle, even if add_en is high with m.If(self.clear): m.d.sync += accumulator.eq(0)
class ShifterUnit(Elaboratable): def __init__(self): self.src1 = Signal(32, name="shifter_src1") self.src1signed = Signal(signed(32)) self.shift = Signal(5, name="shifter_shift") # 5 lowest imm bits self.res = Signal(32, name="shifter_res") self.funct3 = Signal(Funct3) self.funct7 = Signal(Funct7) def elaborate(self, platform): assert Funct3.SLLI == Funct3.SLL assert Funct3.SRL == Funct3.SRLI assert Funct3.SRA == Funct3.SRAI m = Module() with m.Switch(self.funct3): with m.Case(Funct3.SLL): m.d.comb += self.res.eq(self.src1 << self.shift) with m.Case(Funct3.SRL): assert Funct3.SRL == Funct3.SRA assert Funct7.SRL != Funct7.SRA with m.If(self.funct7 == Funct7.SRL): m.d.comb += self.res.eq(self.src1 >> self.shift) with m.Elif(self.funct7 == Funct7.SRA): m.d.comb += [ self.src1signed.eq(self.src1), self.res.eq(self.src1signed >> self.shift), ] return m
class ByteToWordShifter(SimpleElaboratable): """Shifts bytes into a word. Bytes are shifted from high to low, so that result is little-endian, with the "first" byte occupying the LSBs Public Interface ---------------- shift_en: Signal() input When to shift the input in_value: Signal(8) input The input data to shift result: Signal(32) output Result of the shift """ def __init__(self): super().__init__() self.shift_en = Signal() self.in_value = Signal(8) self.clear = Signal() self.result = Signal(32) def elab(self, m): register = Signal(32) m.d.comb += self.result.eq(register) with m.If(self.shift_en): calc = Signal(32) m.d.comb += [ calc.eq(Cat(register[8:], self.in_value)), self.result.eq(calc), ] m.d.sync += register.eq(calc)
def elab(self, m: Module): buffering = Signal() # True if there is a value being buffered buffered_value = Signal.like(Value.cast(self.input.payload)) # Pipe valid and ready back and forth m.d.comb += [ self.input.ready.eq(~buffering | self.output.ready), self.output.valid.eq(buffering | self.input.valid), self.output.payload.eq( Mux(buffering, buffered_value, self.input.payload)) ] # Buffer when have incoming value but cannot output just now with m.If(~buffering & ~self.output.ready & self.input.valid): m.d.sync += buffering.eq(True) m.d.sync += buffered_value.eq(self.input.payload) # Handle cases when transfering out from buffer with m.If(buffering & self.output.ready): with m.If(self.input.valid): m.d.sync += buffered_value.eq(self.input.payload) with m.Else(): m.d.sync += buffering.eq(False) # Reset all state with m.If(self.reset): m.d.sync += buffering.eq(False) m.d.sync += buffered_value.eq(0)
def elab(self, m): # Unset valid on transfer (may be overrridden below) with m.If(self.output.ready): m.d.sync += self.output.valid.eq(0) # Set flag to remember that value is available flags = Array(Signal(name=f"flag_{i}") for i in range(8)) for i in range(8): with m.If(self.accumulator_new[i]): m.d.sync += flags[i].eq(1) # Calculate index of value to output index = Signal(range(8)) next_index = Signal(range(8)) with m.If(self.half_mode): # counts: 0, 1, 4, 5, 0 ... m.d.comb += next_index[1].eq(0) m.d.comb += Cat(next_index[0], next_index[2] ).eq(Cat(index[0], index[2]) + 1) with m.Else(): m.d.comb += next_index.eq(index + 1) # If value available this cycle, or previously # - output new value # - unset flag # - increment index with m.If(Array(self.accumulator_new)[index] | flags[index]): m.d.sync += [ self.output.payload.eq(Array(self.accumulator)[index]), self.output.valid.eq(1), flags[index].eq(0), index.eq(next_index), ]
def elab(self, m): group = Signal(range(4)) repeat_count = Signal.like(self.repeats) mem = Array([Signal(14, name=f"mem{i}") for i in range(4)]) with m.If(repeat_count == 0): # On first repeat - pass through next and addr and record addresses m.d.comb += self.gen_next.eq(self.next) m.d.comb += self.addr.eq(self.gen_addr) with m.If(self.next): m.d.sync += mem[group].eq(self.gen_addr) with m.Else(): # Subsequently use recorded data m.d.comb += self.addr.eq(mem[group]) # Update group and repeat_count on next with m.If(self.next): m.d.sync += group.eq(group + 1) with m.If(group == 3): m.d.sync += repeat_count.eq(repeat_count + 1) with m.If(repeat_count + 1 == self.repeats): m.d.sync += repeat_count.eq(0) with m.If(self.start): m.d.sync += repeat_count.eq(0) m.d.sync += group.eq(0)
class AdderUnit(Elaboratable): def __init__(self): self.sub = Signal() # add or sub self.src1 = Signal(32, name="adder_src1") self.src2 = Signal(32, name="adder_src2") self.res = Signal(32, name="adder_res") self.overflow = Signal(name="adder_overflow") self.carry = Signal(name="adder_carry") def elaborate(self, platform): m = Module() # neat way of setting carry flag res_and_carry = Cat(self.res, self.carry) m.d.comb += res_and_carry.eq( Mux(self.sub, self.src1 - self.src2, self.src1 + self.src2)) with m.If(self.sub): with m.If((self.src1[-1] != self.src2[-1]) & (self.src1[-1] != self.res[-1])): m.d.comb += self.overflow.eq(1) with m.Else(): # add with m.If((self.src1[-1] == self.src2[-1]) & (self.src1[-1] != self.res[-1])): m.d.comb += self.overflow.eq(1) return m
def elaborate(self, platform): m = Module() with m.If(self.pending.w_stb): m.d.sync += self.pending.r_data.eq(self.pending.r_data & ~self.pending.w_data) with m.If(self.enable.w_stb): m.d.sync += self.enable.r_data.eq(self.enable.w_data) for i, event in enumerate(self._events): m.d.sync += self.status.r_data[i].eq(event.stb) if event.mode in ("rise", "fall"): event_stb_r = Signal.like(event.stb, name_suffix="_r") m.d.sync += event_stb_r.eq(event.stb) event_trigger = Signal(name="{}_trigger".format(event.name)) if event.mode == "level": m.d.comb += event_trigger.eq(event.stb) elif event.mode == "rise": m.d.comb += event_trigger.eq(~event_stb_r & event.stb) elif event.mode == "fall": m.d.comb += event_trigger.eq(event_stb_r & ~event.stb) else: assert False # :nocov: with m.If(event_trigger): m.d.sync += self.pending.r_data[i].eq(1) m.d.comb += self.irq.eq( (self.pending.r_data & self.enable.r_data).any()) return m
def spi_edge_detectors(self, m): """ Generates edge detectors for the sample and output clocks, based on the current SPI mode. Returns: sample_edge, output_edge -- signals that pulse high for a single cycle when we should sample and change our outputs, respectively """ # Select whether we're working with an inverted or un-inverted serial clock. serial_clock = Signal() if self.clock_polarity: m.d.comb += serial_clock.eq(~self.spi.sck) else: m.d.comb += serial_clock.eq(self.spi.sck) # Generate the leading and trailing edge detectors. # Note that we use rising and falling edge detectors, but call these leading and # trailing edges, as our clock here may have been inverted. leading_edge = Rose(serial_clock, domain="sync") trailing_edge = Fell(serial_clock, domain="sync") # Determine the sample and output edges based on the SPI clock phase. sample_edge = trailing_edge if self.clock_phase else leading_edge output_edge = leading_edge if self.clock_phase else trailing_edge return sample_edge, output_edge
class MaccInstruction(InstructionBase): """Multiply accumulate x4 in0 contains 4 signed input values in1 contains 4 signed filter values """ def __init__(self): super().__init__() self.input_offset = Signal(signed(32)) self.accumulator = Signal(signed(32)) self.reset_acc = Signal() def elab(self, m): in_vals = [Signal(signed(8), name=f"in_val_{i}") for i in range(4)] filter_vals = [ Signal( signed(8), name=f"filter_val_{i}") for i in range(4)] mults = [Signal(signed(19), name=f"mult_{i}") for i in range(4)] for i in range(4): m.d.comb += [ in_vals[i].eq(self.in0.word_select(i, 8).as_signed()), filter_vals[i].eq(self.in1.word_select(i, 8).as_signed()), mults[i].eq( (in_vals[i] + self.input_offset) * filter_vals[i]), ] m.d.sync += self.done.eq(0) with m.If(self.start): m.d.sync += self.accumulator.eq(self.accumulator + sum(mults)) # m.d.sync += self.accumulator.eq(self.accumulator + 72) m.d.sync += self.done.eq(1) with m.Elif(self.reset_acc): m.d.sync += self.accumulator.eq(0)
def elab(self, m): was_updated = Signal() m.d.sync += was_updated.eq(self.updated) # Connect sequential memory readers smr_datas = Array([Signal(32, name=f"smr_data_{n}") for n in range(4)]) smr_nexts = Array([Signal(name=f"smr_next_{n}") for n in range(4)]) for n, (smr, mem_addr, mem_data, smr_data, smr_next) in enumerate( zip(self.smrs, self.mem_addrs, self.mem_datas, smr_datas, smr_nexts)): m.submodules[f"smr_{n}"] = smr m.d.comb += [ smr.limit.eq(self.limit >> 2), mem_addr.eq(smr.mem_addr), smr.mem_data.eq(mem_data), smr_data.eq(smr.data), smr.next.eq(smr_next), smr.restart.eq(was_updated), ] curr_bank = Signal(2) m.d.comb += self.data.eq(smr_datas[curr_bank]) with m.If(self.restart): m.d.sync += curr_bank.eq(0) with m.Elif(self.next): m.d.comb += smr_nexts[curr_bank].eq(1) m.d.sync += curr_bank.eq(curr_bank + 1)
class ValueBufferTest(TestBase): def create_dut(self): self.capture = Signal() self.in_signal = Signal(4) return ValueBuffer(self.in_signal, self.capture) def test(self): DATA = [ ((0, 0), 0), ((1, 5), 5), ((0, 3), 5), ((0, 2), 5), ((0, 2), 5), ((1, 2), 2), ((0, 2), 2), ((0, 2), 2), ] def process(): for n, ((capture, in_sig), expected_output) in enumerate(DATA): yield self.in_signal.eq(in_sig) yield self.capture.eq(capture) yield Settle() self.assertEqual((yield self.dut.output), expected_output, f"cycle={n}") yield self.run_sim(process, False)
def elab(self, m): # Track previous restart, next was_restart = Signal() m.d.sync += was_restart.eq(self.restart) was_next = Signal() m.d.sync += was_next.eq(self.next) # Decide address to be output (determines data available next cycle) last_mem_addr = Signal.like(self.mem_addr) m.d.sync += last_mem_addr.eq(self.mem_addr) incremented_addr = Signal.like(self.limit) m.d.comb += incremented_addr.eq( Mux(last_mem_addr == self.limit - 1, 0, last_mem_addr + 1)) with m.If(self.restart): m.d.comb += self.mem_addr.eq(0) with m.Elif(was_next | was_restart): m.d.comb += self.mem_addr.eq(incremented_addr) with m.Else(): m.d.comb += self.mem_addr.eq(last_mem_addr) # Decide data to be output last_data = Signal.like(self.data) m.d.sync += last_data.eq(self.data) with m.If(was_restart | was_next): m.d.comb += self.data.eq(self.mem_data) with m.Else(): m.d.comb += self.data.eq(last_data)
class Counter(Elaboratable): def __init__(self, limit): self.limit = limit # Counter state. # # Using `range(limit)` means the signal will be wide enough to # represent any integer up to but excluding `limit`. # # For example, with limit=128, we'd get a 7-bit signal which can # represent the integers 0 to 127. self.counter = Signal(range(limit)) # Rollover output will be pulsed high for one clock cycle # when the counter reaches `limit-1`. self.rollover = Signal() def elaborate(self, platform): m = Module() # Make the output `rollover` always equal to this comparison, # which will only be 1 for a single cycle every counter period. m.d.comb += self.rollover.eq(self.counter == self.limit - 1) # Conditionally reset the counter to 0 on rollover, otherwise # increment it. We could write the comparison out again here # to the same effect. with m.If(self.rollover): m.d.sync += self.counter.eq(0) with m.Else(): m.d.sync += self.counter.eq(self.counter + 1) return m
def add_composite_register(self, m, address, value, *, reset_value=0): """ Adds a ULPI register that's composed of multiple control signals. Params: address -- The register number in the ULPI register space. value -- An 8-bit signal composing the bits that should be placed in the given register. reset_value -- If provided, the given value will be assumed as the reset value -- of the given register; allowing us to avoid an initial write. """ current_register_value = Signal(8, reset=reset_value, name=f"current_register_value_{address:02x}") # Create internal signals that request register updates. write_requested = Signal(name=f"write_requested_{address:02x}") write_value = Signal(8, name=f"write_value_{address:02x}") write_done = Signal(name=f"write_done_{address:02x}") self._register_signals[address] = { 'write_requested': write_requested, 'write_value': write_value, 'write_done': write_done } # If we've just finished a write, update our current register value. with m.If(write_done): m.d.usb += current_register_value.eq(write_value), # If we have a mismatch between the requested and actual register value, # request a write of the new value. m.d.comb += write_requested.eq(current_register_value != value) with m.If(current_register_value != value): m.d.usb += write_value.eq(value)
def elab(self, m): # number of bytes received already byte_count = Signal(range(4)) # output channel for next byte received pixel_index = Signal(range(self._num_pixels)) # shift registers to buffer 3 incoming values shift_registers = Array( [Signal(24, name=f"sr_{i}") for i in range(self._num_pixels)]) last_pixel_index = Signal.like(pixel_index) m.d.sync += last_pixel_index.eq(Mux(self.half_mode, self._num_pixels // 2 - 1, self._num_pixels - 1)) next_pixel_index = Signal.like(pixel_index) m.d.comb += next_pixel_index.eq(Mux(pixel_index == last_pixel_index, 0, pixel_index + 1)) m.d.comb += self.input.ready.eq(1) with m.If(self.input.is_transferring()): sr = shift_registers[pixel_index] with m.If(byte_count == 3): # Output current value and shift register m.d.comb += self.output.valid.eq(1) payload = Cat(sr, self.input.payload) m.d.comb += self.output.payload.eq(payload) with m.Else(): # Save input to shift register m.d.sync += sr[-8:].eq(self.input.payload) m.d.sync += sr[:-8].eq(sr[8:]) # Increment pixel index m.d.sync += pixel_index.eq(next_pixel_index) with m.If(pixel_index == last_pixel_index): m.d.sync += pixel_index.eq(0) m.d.sync += byte_count.eq(byte_count + 1) # allow rollover
def elab(self, m: Module): num_words = Signal(range(Constants.MAX_INPUT_WORDS + 1)) index = Signal(range(Constants.MAX_INPUT_WORDS)) reset = Signal() m.d.comb += reset.eq(self.num_words_input.valid) memory = WideReadMemory(depth=Constants.MAX_INPUT_WORDS) m.submodules['memory'] = memory with m.FSM(reset="RESET"): with m.State("RESET"): m.d.sync += num_words.eq(0) m.d.sync += index.eq(0) m.d.sync += self.data_output.valid.eq(0) m.next = "NUM_WORDS" with m.State("NUM_WORDS"): m.d.comb += self.num_words_input.ready.eq(1) with m.If(self.num_words_input.is_transferring()): m.d.sync += num_words.eq(self.num_words_input.payload) m.next = "WRITING" with m.State("WRITING"): self.handle_writing(m, memory, num_words, index) with m.If(reset): m.next = "RESET" with m.State("READING"): self.handle_reading(m, memory, num_words, index, reset) with m.If(reset): m.next = "RESET"
class RegisterSetter(Xetter): """A Setter for a value. Sets new value from in0. Return previous value on set. Parameters ---------- width: int Number of bits in the Xetter value (1-32) Public Interface ---------------- value: Signal(width) output The value held by this register. It will be set from in0. set: Signal output This signal is pulsed high for a single cycle when register is set. """ def __init__(self, width=32): super().__init__() self.value = Signal(width) self.set = Signal() def elab(self, m): m.d.sync += self.set.eq(0) with m.If(self.start): m.d.sync += self.value.eq(self.in0), m.d.sync += self.set.eq(1), m.d.comb += self.output.eq(self.value) m.d.comb += self.done.eq(1)
def _elab_write(self, m, dps, r_full): w_curr_buf = Signal() # Address within current buffer w_addr = Signal.like(self.input_depth) # Connect to memory write port for n, dp in enumerate(dps): m.d.comb += [ dp.w_addr.eq(Cat(w_addr[2:], w_curr_buf)), dp.w_data.eq(self.w_data), dp.w_en.eq(self.w_en & self.w_ready & (n == w_addr[:2])), ] # Ready to write current buffer if reading is not allowed m.d.comb += self.w_ready.eq(~r_full[w_curr_buf]) # Write address increment with m.If(self.w_en & self.w_ready): with m.If(w_addr == self.input_depth - 1): # at end of buffer - mark buffer ready for reading and go to # next m.d.sync += [ w_addr.eq(0), r_full[w_curr_buf].eq(1), w_curr_buf.eq(~w_curr_buf), ] with m.Else(): m.d.sync += w_addr.eq(w_addr + 1) with m.If(self.restart): m.d.sync += [ w_addr.eq(0), w_curr_buf.eq(0), ]
def elab(self, m): # Define parameters repeats = Signal(unsigned_upto(self._max_repeats)) count = Signal(unsigned_upto(self._depth)) # Accept new parameters m.d.comb += self.params_input.ready.eq(1) with m.If(self.params_input.valid): m.d.sync += [ repeats.eq(self.params_input.payload.repeats), count.eq(self.params_input.payload.count), ] # Count repeats m.submodules.rc = repeat_counter = LoopingCounter(self._max_repeats) m.d.comb += [ repeat_counter.count.eq(repeats), repeat_counter.reset.eq(self.params_input.valid), repeat_counter.next.eq(self.next), ] # Count addresses m.submodules.ac = addr_counter = LoopingCounter(self._depth) m.d.comb += [ addr_counter.count.eq(count), addr_counter.reset.eq(self.params_input.valid), addr_counter.next.eq(self.next & repeat_counter.last), self.addr.eq(addr_counter.value), ]
def decode_nrzi(self, m: Module, bit_time: Signal, got_edge: Signal, sync_counter: DividingCounter): """Do the actual decoding of the NRZI bitstream""" sync = m.d.sync bit_counter = Signal(7) # this counter is used to detect a dead signal # to determine when to go back to SYNC state dead_counter = Signal(8) output = Signal(reset=1) # recover ADAT clock with m.If(bit_counter <= (bit_time >> 1)): m.d.comb += self.recovered_clock_out.eq(1) with m.Else(): m.d.comb += self.recovered_clock_out.eq(0) # when the frame decoder got garbage # then we need to go back to SYNC state with m.If(self.invalid_frame_in): sync += [ sync_counter.reset_in.eq(1), bit_counter.eq(0), dead_counter.eq(0) ] m.next = "SYNC" sync += bit_counter.eq(bit_counter + 1) with m.If(got_edge): sync += [ # latch 1 until we read it in the middle of the bit output.eq(1), # resynchronize at each bit edge, 1 to compensate # for sync delay bit_counter.eq(1), # when we get an edge, the signal is alive, reset counter dead_counter.eq(0) ] with m.Else(): sync += dead_counter.eq(dead_counter + 1) # wrap the counter with m.If(bit_counter == bit_time): sync += bit_counter.eq(0) # output at the middle of the bit with m.Elif(bit_counter == (bit_time >> 1)): sync += [ self.data_out.eq(output), self.data_out_en.eq(1), # pulse out_en output.eq(0) # edge has been output, wait for new edge ] with m.Else(): sync += self.data_out_en.eq(0) # when we had no edge for 16 bits worth of time # then we go back to sync state with m.If(dead_counter >= bit_time << 4): sync += dead_counter.eq(0) m.next = "SYNC"
def elab(self, m): accumulator = Signal(signed(32)) m.d.comb += self.result.eq(accumulator) with m.If(self.add_en): m.d.sync += accumulator.eq(accumulator + self.in_value) m.d.comb += self.result.eq(accumulator + self.in_value) # clear always resets accumulator next cycle, even if add_en is high with m.If(self.clear): m.d.sync += accumulator.eq(0)
class StreamLimiter(SimpleElaboratable): """Allows only a certain number of elements to apss through stream. Counts a given number of items, then signals that it is done. Parameters ---------- payload_type: The type carried by the stream Attributes ---------- stream_in: Endpoint(payload_type), in The incoming stream. Will always be ready after start and until done. stream_out: Endpoint(payload_type), out The outgoing stream. Does not respect back pressure. num_allowed: Signal(18), in The number of items allowed to pass. start: Signal(), in Pulse high to allow items beginning next cycle. running: Signal(), out Indicates that items are being allowed to pass finished: Signal(), out Indicates that last item has been handled. """ def __init__(self, payload_type=signed(32)): self.stream_in = Endpoint(payload_type) self.stream_out = Endpoint(payload_type) self.num_allowed = Signal(18) self.start = Signal() self.running = Signal() self.finished = Signal() def elab(self, m): m.d.sync += self.finished.eq(0) m.d.comb += [ self.stream_in.ready.eq(self.running), self.stream_out.valid.eq(self.stream_in.is_transferring()), self.stream_out.payload.eq(self.stream_in.payload), ] counter = Signal.like(self.num_allowed) with m.If(self.start): m.d.sync += counter.eq(self.num_allowed) with m.If(self.stream_in.is_transferring()): m.d.sync += counter.eq(counter - 1) with m.If(counter == 1): m.d.sync += self.finished.eq(1) m.d.comb += self.running.eq(counter != 0)
def elab(self, m): running = Signal() with m.If(self.start_run): m.d.sync += running.eq(1) with m.If(self.all_output_finished): m.d.sync += running.eq(0) m.d.comb += self.gate.eq((running | self.start_run) & self.in_store_ready & self.fifo_has_space)
def elab(self, m): x_count = Signal(7) next_row_addr = Signal(14) addr = Signal(14) with m.If(self.start): # Start overrides other behaviors m.d.comb += self.addr_out.eq(self.start_addr) m.d.sync += [ addr.eq(self.start_addr), x_count.eq(1), next_row_addr.eq(self.start_addr + self.num_blocks_y), ] with m.Else(): m.d.comb += self.addr_out.eq(addr) # x_size is the number of cycles to read 4 consecutive pixels x_size = Signal(7) m.d.comb += x_size.eq(self.depth << 4) with m.If(x_count != (x_size - 1)): m.d.sync += x_count.eq(x_count + 1) with m.If(x_count[:2] == 3): m.d.sync += addr.eq(addr + 1) with m.Else(): # x_count == x_size - 1 ==> End of row m.d.sync += [ addr.eq(next_row_addr), next_row_addr.eq(next_row_addr + self.num_blocks_y), x_count.eq(0), ]
def elab(self, m): register = Signal(32) m.d.comb += self.result.eq(register) with m.If(self.shift_en): calc = Signal(32) m.d.comb += [ calc.eq(Cat(register[8:], self.in_value)), self.result.eq(calc), ] m.d.sync += register.eq(calc)
def elab(self, m): waiting = Signal() with m.If(self.ready & (waiting | self.start)): m.d.comb += [ self.output.eq(self.data), self.next.eq(1), self.done.eq(1), ] m.d.sync += waiting.eq(0) with m.Elif(self.start & ~self.ready): m.d.sync += waiting.eq(1)
class StatusRegister(SimpleElaboratable): """A register set by gateware. Allows gateware to provide data to a CPU. Parameters ---------- valid_at_reset: bool Whether payload is valid at reset or register ought to wait to transfer a value from its input stream. ready_when_valid: bool Whether the register should allow overwriting valid values with new values from its input stream. If true, the register is unconditionally ready to accept new values. If false, the register will only accept new values when it is not already holding a valid value. Attributes ---------- input: Endpoint(unsigned(32)), in A stream of new values. invalidate: Signal(), in Causes valid to be deassserted. value: Signal(32), out The value held by the register. Received from sink.payload. valid: Signal(), out Deasserted when clear is asserted. Asserted when new value received at sink. """ def __init__(self, valid_at_reset=True, ready_when_valid=True): super().__init__() self.ready_when_valid = ready_when_valid self.input = Endpoint(unsigned(32)) self.invalidate = Signal() self.valid = Signal(reset=valid_at_reset) self.value = Signal(32) def elab(self, m): if self.ready_when_valid: m.d.comb += self.input.ready.eq(1) else: m.d.comb += self.input.ready.eq(~self.valid) with m.If(self.invalidate): m.d.sync += self.valid.eq(0) with m.If(self.input.is_transferring()): m.d.sync += self.value.eq(self.input.payload) m.d.sync += self.valid.eq(1)
def max_(word0, word1): result = [Signal(8, name=f"result{i}") for i in range(4)] bytes0 = [word0[i:i + 8] for i in range(0, 32, 8)] bytes1 = [word1[i:i + 8] for i in range(0, 32, 8)] for r, b0, b1 in zip(result, bytes0, bytes1): sb0 = Signal(signed(8)) m.d.comb += sb0.eq(b0) sb1 = Signal(signed(8)) m.d.comb += sb1.eq(b1) m.d.comb += r.eq(Mux(sb1 > sb0, b1, b0)) return Cat(*result)
def elab(self, m): waiting = Signal() with m.If(self.start | waiting): m.d.comb += self.r_en.eq(1) with m.If(self.r_rdy): m.d.comb += [ self.output.eq(self.r_data), self.done.eq(1), ] m.d.sync += waiting.eq(0) with m.Else(): m.d.sync += waiting.eq(1)