Example #1
0
    def __init__(s, interface):
        UseInterface(s, interface)
        nreqs = s.interface.nreqs

        s.mask = Register(RegisterInterface(Bits(nreqs)), reset_value=0)
        s.masker = ThermometerMask(ThermometerMaskInterface(nreqs))
        s.raw_arb = PriorityArbiter(ArbiterInterface(nreqs))
        s.masked_arb = PriorityArbiter(ArbiterInterface(nreqs))
        s.final_grant = Wire(nreqs)

        s.connect(s.raw_arb.grant_reqs, s.grant_reqs)
        s.connect(s.masker.mask_in_, s.mask.read_data)

        @s.combinational
        def compute():
            s.masked_arb.grant_reqs.v = s.grant_reqs & s.masker.mask_out
            if s.masked_arb.grant_grant == 0:
                s.final_grant.v = s.raw_arb.grant_grant
            else:
                s.final_grant.v = s.masked_arb.grant_grant

        @s.combinational
        def shift_write():
            s.mask.write_data.v = s.final_grant << 1

        s.connect(s.grant_grant, s.final_grant)
Example #2
0
  def __init__(s):
    UseInterface(s, StageInterface(None, Bits(8)))

    s.counter = Register(RegisterInterface(Bits(8), enable=True), reset_value=0)
    s.connect(s.process_accepted, 1)
    s.connect(s.process_out, s.counter.read_data)
    s.connect(s.counter.write_call, s.process_call)

    @s.combinational
    def count():
      s.counter.write_data.v = s.counter.read_data + 1
Example #3
0
  def __init__(s, interface):
    UseInterface(s, interface)
    s.require(
        MethodSpec(
            'input',
            args=None,
            rets={
                'data': s.interface.Data,
            },
            call=True,
            rdy=True,
        ))

    s.drop_pending = Register(
        RegisterInterface(Bits(1), False, False), reset_value=0)
    s.drop_pending_curr = Wire(1)

    s.connect(s.output_data, s.input_data)

    @s.combinational
    def handle_drop():
      s.drop_pending_curr.v = s.drop_pending.read_data or s.drop_call
      s.drop_status_occurred.v = s.drop_pending_curr and s.input_rdy
      s.drop_rdy.v = not s.drop_pending.read_data

      if s.drop_status_occurred:
        s.input_call.v = 1
        s.output_rdy.v = 0
        s.drop_pending.write_data.v = 0
      elif s.drop_pending_curr:
        s.input_call.v = 0
        s.output_rdy.v = 0
        s.drop_pending.write_data.v = 1
      else:
        s.input_call.v = s.output_call
        s.output_rdy.v = s.input_rdy
        s.drop_pending.write_data.v = 0
Example #4
0
    def __init__(s, mul_interface, nstages):
        UseInterface(s, mul_interface)
        assert nstages > 0
        m = s.interface.DataLen
        n = 2 * m if s.interface.KeepUpper else m

        s.valids_ = [
            Register(RegisterInterface(1), reset_value=0)
            for _ in range(nstages)
        ]
        s.vals_ = [
            Register(RegisterInterface(n, enable=True)) for _ in range(nstages)
        ]

        s.exec_ = [Wire(Bits(1)) for _ in range(nstages)]
        s.rdy_ = [Wire(Bits(1)) for _ in range(nstages)]

        s.value_ = Wire(2 * m)

        # All the inputs get converted to unsigned
        s.src1_usign_ = Wire(Bits(m))
        s.src2_usign_ = Wire(Bits(m))
        s.sign_in_ = Wire(1)

        # Execute call
        s.connect(s.mult_rdy, s.rdy_[0])

        # Result call
        s.connect(s.peek_rdy, s.valids_[nstages - 1].read_data)
        s.connect(s.take_rdy, s.valids_[nstages - 1].read_data)
        s.connect(s.peek_res, s.vals_[nstages - 1].read_data)

        for i in range(nstages):
            s.connect(s.vals_[i].write_call, s.exec_[i])

        # HERE is the actual multiply that will be retimed
        @s.combinational
        def comb_mult():
            s.value_.v = s.src1_usign_ * s.src2_usign_

        @s.combinational
        def unsign_srcs_in():
            s.src1_usign_.v = 0
            s.src2_usign_.v = 0
            s.sign_in_.v = 0
            s.sign_in_.v = (s.mult_src1_signed and s.mult_src1[m - 1]) ^ (
                s.mult_src2_signed and s.mult_src2[m - 1])

            s.src1_usign_.v = (~s.mult_src1 +
                               1) if (s.mult_src1[m - 1]
                                      and s.mult_src1_signed) else s.mult_src1

            s.src2_usign_.v = (~s.mult_src2 +
                               1) if (s.mult_src2[m - 1]
                                      and s.mult_src2_signed) else s.mult_src2

        @s.combinational
        def set_rdy_last():
            # Incoming call:
            s.rdy_[nstages -
                   1].v = s.take_call or not s.valids_[nstages - 1].read_data

        for i in range(nstages - 1):

            @s.combinational
            def set_rdy(i=i):
                # A stage is ready to accept if it is invalid or next stage is ready
                s.rdy_[i].v = not s.valids_[i].read_data or s.rdy_[i + 1]

        @s.combinational
        def set_exec_first():
            s.exec_[0].v = s.rdy_[0] and s.mult_call

        for i in range(1, nstages):

            @s.combinational
            def set_exec(i=i):
                # Will execute if stage ready and current work is valid
                s.exec_[i].v = s.rdy_[i] and s.valids_[i - 1].read_data

        @s.combinational
        def set_valids_last():
            s.valids_[nstages - 1].write_data.v = (
                not s.take_call
                and s.valids_[nstages - 1].read_data) or s.exec_[nstages - 1]

        for i in range(nstages - 1):

            @s.combinational
            def set_valids(i=i):
                # Valid if blocked on next stage, or multuted this cycle
                s.valids_[i].write_data.v = (
                    not s.rdy_[i + 1] and s.valids_[i].read_data) or s.exec_[i]

        @s.combinational
        def mult():
            s.vals_[
                0].write_data.v = ~s.value_[:
                                            n] + 1 if s.sign_in_ else s.value_[:
                                                                               n]
            for i in range(1, nstages):
                s.vals_[i].write_data.v = s.vals_[i - 1].read_data
Example #5
0
    def __init__(s, mul_interface, nstages, use_mul=True):
        UseInterface(s, mul_interface)

        # For now must be evenly divisible
        assert nstages > 0
        assert s.interface.DataLen % nstages == 0

        m = s.interface.DataLen
        n = 2 * m if s.interface.KeepUpper else m
        k = s.interface.DataLen // nstages
        last = nstages - 1

        # All the inputs get converted to unsigned
        s.src1_usign_ = Wire(Bits(m))
        s.src2_usign_ = Wire(Bits(m))

        # At step i, i = [0, nstages), product needs at most m + k(i+1) bits
        s.valids_ = [
            Register(RegisterInterface(1), reset_value=0)
            for _ in range(nstages)
        ]
        if s.interface.KeepUpper:
            s.vals_ = [
                # nbits = m + k * (i + 1)
                Register(RegisterInterface(2 * m, enable=True))
                for i in range(nstages)
            ]
            s.units_ = [
                MulCombinational(
                    # input nbits = m,k, output = k+m
                    MulCombinationalInterface(m, k, 2 * m),
                    use_mul) for i in range(nstages)
            ]
            s.src2_ = [
                # nbits = m - k * i
                Register(RegisterInterface(m, enable=True))
                for i in range(nstages - 1)
            ]
        else:
            s.vals_ = [
                Register(RegisterInterface(m, enable=True))
                for _ in range(nstages)
            ]
            s.units_ = [
                MulCombinational(MulCombinationalInterface(m, k, m), use_mul)
                for _ in range(nstages)
            ]
            s.src2_ = [
                Register(RegisterInterface(m, enable=True))
                for _ in range(nstages - 1)
            ]

        s.src1_ = [
            Register(RegisterInterface(m, enable=True))
            for _ in range(nstages - 1)
        ]

        s.signs_ = [
            Register(RegisterInterface(1, enable=True))
            for _ in range(nstages - 1)
        ]
        s.exec_ = [Wire(Bits(1)) for _ in range(nstages)]
        s.rdy_ = [Wire(Bits(1)) for _ in range(nstages)]

        s.sign_out_ = Wire(Bits(1))
        s.sign_in_ = Wire(Bits(1))

        # Connect the sign bit in the last stage
        if nstages == 1:
            s.connect_wire(s.sign_out_, s.sign_in_)
        else:
            s.connect(s.sign_out_, s.signs_[last - 1].read_data)

        # Execute call rdy
        s.connect(s.mult_rdy, s.rdy_[0])
        # Result call rdy
        s.connect(s.peek_rdy, s.valids_[last].read_data)
        s.connect(s.take_rdy, s.valids_[last].read_data)
        s.connect(s.peek_res, s.vals_[last].read_data)

        for i in range(nstages):
            s.connect(s.vals_[i].write_call, s.exec_[i])
            s.connect(s.units_[i].mult_call, s.exec_[i])
            # Last stage does not have these
            if i < nstages - 1:
                s.connect(s.src1_[i].write_call, s.exec_[i])
                s.connect(s.src2_[i].write_call, s.exec_[i])
                s.connect(s.signs_[i].write_call, s.exec_[i])

        # Take twos compliment
        @s.combinational
        def unsign_srcs_in():
            s.src1_usign_.v = 0
            s.src2_usign_.v = 0
            s.sign_in_.v = 0
            s.sign_in_.v = (s.mult_src1_signed and s.mult_src1[m - 1]) ^ (
                s.mult_src2_signed and s.mult_src2[m - 1])

            s.src1_usign_.v = (~s.mult_src1 +
                               1) if (s.mult_src1[m - 1]
                                      and s.mult_src1_signed) else s.mult_src1

            s.src2_usign_.v = (~s.mult_src2 +
                               1) if (s.mult_src2[m - 1]
                                      and s.mult_src2_signed) else s.mult_src2

        @s.combinational
        def connect_unit0():
            s.units_[0].mult_src1.v = s.src1_usign_
            s.units_[0].mult_src2.v = s.src2_usign_[:k]

        for i in range(1, nstages):

            @s.combinational
            def connect_unitk(i=i):
                s.units_[i].mult_src1.v = s.src1_[i - 1].read_data
                s.units_[i].mult_src2.v = s.src2_[i - 1].read_data[:k]

        @s.combinational
        def set_rdy_last():
            s.rdy_[last].v = s.take_call or not s.valids_[last].read_data

        for i in range(nstages - 1):

            @s.combinational
            def set_rdy(i=i):
                # A stage is ready to accept if it is invalid or next stage is ready
                s.rdy_[i].v = not s.valids_[i].read_data or s.rdy_[i + 1]

        @s.combinational
        def set_exec_first():
            s.exec_[0].v = s.rdy_[0] and s.mult_call

        for i in range(1, nstages):

            @s.combinational
            def set_exec(i=i):
                # Will execute if stage ready and current work is valid
                s.exec_[i].v = s.rdy_[i] and s.valids_[i - 1].read_data

        @s.combinational
        def set_valids_last():
            s.valids_[last].write_data.v = (
                not s.take_call and s.valids_[last].read_data) or s.exec_[last]

        for i in range(nstages - 1):

            @s.combinational
            def set_valids(i=i):
                # Valid if blocked on next stage, or multuted this cycle
                s.valids_[i].write_data.v = (
                    not s.rdy_[i + 1] and s.valids_[i].read_data) or s.exec_[i]

        # Hook up the pipeline stages
        if nstages == 1:

            @s.combinational
            def connect_stage():
                s.vals_[0].write_data.v = ~s.units_[
                    0].mult_res + 1 if s.sign_out_ else s.units_[0].mult_res
        else:

            @s.combinational
            def connect_first_stage():
                s.vals_[0].write_data.v = s.units_[0].mult_res
                s.src1_[0].write_data.v = s.src1_usign_
                s.src2_[0].write_data.v = s.src2_usign_ >> k
                s.signs_[0].write_data.v = s.sign_in_

            for i in range(1, nstages - 1):

                @s.combinational
                def connect_stage(i=i):
                    s.vals_[i].write_data.v = s.vals_[i - 1].read_data + (
                        s.units_[i].mult_res << (k * i))
                    s.src1_[i].write_data.v = s.src1_[i - 1].read_data
                    s.src2_[i].write_data.v = s.src2_[i - 1].read_data >> k
                    s.signs_[i].write_data.v = s.signs_[i - 1].read_data

            @s.combinational
            def connect_last_stage():
                if s.sign_out_:
                    s.vals_[last].write_data.v = ~(
                        s.vals_[last - 1].read_data +
                        (s.units_[last].mult_res << (k * last))) + 1
                else:
                    s.vals_[last].write_data.v = s.vals_[
                        last - 1].read_data + (s.units_[last].mult_res <<
                                               (k * last))
Example #6
0
    def __init__(s, interface, MemMsg):
        UseInterface(s, interface)

        s.require(
            MethodSpec(
                'mb_send',
                args={'msg': MemMsg.req},
                rets=None,
                call=True,
                rdy=True,
            ),
            MethodSpec(
                'mb_recv',
                args=None,
                rets={'msg': MemMsg.resp},
                call=True,
                rdy=True,
            ),
        )

        s.store_in_flight = Register(RegisterInterface(Bits(1)))
        s.store_in_flight_after_recv = Wire(1)

        @s.combinational
        def handle_recv():
            s.recv_load_data.v = s.mb_recv_msg.data
            if s.mb_recv_rdy:
                if s.store_in_flight.read_data:
                    s.mb_recv_call.v = 1
                    s.recv_load_rdy.v = 0
                    s.store_in_flight_after_recv.v = 0
                else:
                    s.mb_recv_call.v = s.recv_load_call
                    s.recv_load_rdy.v = 1
                    s.store_in_flight_after_recv.v = 0
            else:
                s.mb_recv_call.v = 0
                s.recv_load_rdy.v = 0
                s.store_in_flight_after_recv.v = s.store_in_flight.read_data

        @s.combinational
        def handle_send_rdy():
            if s.mb_send_rdy:
                s.send_store_rdy.v = 1
                s.send_load_rdy.v = not s.send_store_call
            else:
                s.send_store_rdy.v = 0
                s.send_load_rdy.v = 0

        @s.combinational
        def handle_send(size=s.interface.Size.nbits - 1):
            s.mb_send_msg.v = 0
            if s.send_store_call:
                s.mb_send_call.v = 1
                s.mb_send_msg.type_.v = MemMsgType.WRITE
                s.mb_send_msg.opaque.v = 0
                s.mb_send_msg.addr.v = s.send_store_addr
                # This size will have to be truncated by 1 bit because full for a mem msg
                # is 0. The length field must always be a power of 2 so this works
                s.mb_send_msg.len_.v = s.send_store_size[0:size]
                s.mb_send_msg.data.v = s.send_store_data
                s.store_in_flight.write_data.v = 1
            elif s.send_load_call:
                s.mb_send_call.v = 1
                s.mb_send_msg.type_.v = MemMsgType.READ
                s.mb_send_msg.opaque.v = 0
                s.mb_send_msg.addr.v = s.send_load_addr
                s.mb_send_msg.len_.v = s.send_load_size[0:size]
                s.mb_send_msg.data.v = 0
                s.store_in_flight.write_data.v = 0
            else:
                s.mb_send_call.v = 0
                s.store_in_flight.write_data.v = s.store_in_flight_after_recv

        s.connect(s.store_acks_outstanding_ret, s.store_in_flight_after_recv)
Example #7
0
  def __init__(s, interface, nregs):
    UseInterface(s, interface)

    Addr = Bits(clog2nz(nregs))
    Key = s.interface.Key
    Value = s.interface.Value

    s.Entry = Entry(Key, Value)
    s.entries = [
        Register(RegisterInterface(s.Entry(), enable=True), reset_value=0)
        for _ in range(nregs)
    ]
    s.overwrite_counter = Register(
        RegisterInterface(Addr, enable=True), reset_value=0)
    s.read_addr_chain = [Wire(Addr) for _ in range(nregs)]
    s.read_addr_valid = [Wire(1) for _ in range(nregs)]

    # PYMTL_BROKEN
    s.entries_read_data_key = [Wire(Key) for _ in range(nregs)]
    s.entries_read_data_value = [Wire(Value) for _ in range(nregs)]
    s.entries_read_data_valid = [Wire(1) for _ in range(nregs)]
    s.entries_write_data_key = [Wire(Key) for _ in range(nregs)]
    s.entries_write_data_value = [Wire(Value) for _ in range(nregs)]
    s.entries_write_data_valid = [Wire(1) for _ in range(nregs)]
    for i in range(nregs):
      s.connect(s.entries_read_data_key[i], s.entries[i].read_data.key)
      s.connect(s.entries_read_data_value[i], s.entries[i].read_data.value)
      s.connect(s.entries_read_data_valid[i], s.entries[i].read_data.valid)
      s.connect(s.entries[i].write_data.key, s.entries_write_data_key[i])
      s.connect(s.entries[i].write_data.value, s.entries_write_data_value[i])
      s.connect(s.entries[i].write_data.valid, s.entries_write_data_valid[i])

    for i in range(nregs):
      if i == 0:

        @s.combinational
        def handle_read_addr_0(i=i):
          s.read_addr_chain[i].v = i
          s.read_addr_valid[i].v = s.entries_read_data_key[
              i] == s.read_key and s.entries_read_data_valid[i]
      else:

        @s.combinational
        def handle_read_addr(i=i, j=i - 1):
          if s.entries_read_data_key[
              i] == s.read_key and s.entries_read_data_valid[i]:
            s.read_addr_chain[i].v = i
            s.read_addr_valid[i].v = 1
          else:
            s.read_addr_chain[i].v = s.read_addr_chain[j]
            s.read_addr_valid[i].v = s.read_addr_valid[j]

    @s.combinational
    def handle_read():
      s.read_value.v = s.entries_read_data_value[s.read_addr_chain[nregs - 1]]
      s.read_valid.v = s.read_addr_valid[nregs - 1]

    s.write_addr_chain = [Wire(Addr) for _ in range(nregs)]
    s.write_addr_valid = [Wire(1) for _ in range(nregs)]
    s.invalid_addr_chain = [Wire(Addr) for _ in range(nregs)]
    s.invalid_addr_valid = [Wire(1) for _ in range(nregs)]

    for i in range(nregs):
      if i == 0:

        @s.combinational
        def handle_write_addr_0(i=i):
          s.write_addr_chain[i].v = i
          s.write_addr_valid[i].v = s.entries_read_data_key[
              i] == s.write_key and s.entries_read_data_valid[i]
          s.invalid_addr_chain[i].v = i
          s.invalid_addr_valid[i].v = not s.entries_read_data_valid[i]
      else:

        @s.combinational
        def handle_write_addr(i=i, j=i - 1):
          if s.entries_read_data_key[
              i] == s.write_key and s.entries_read_data_valid[i]:
            s.write_addr_chain[i].v = i
            s.write_addr_valid[i].v = 1
          else:
            s.write_addr_chain[i].v = s.write_addr_chain[j]
            s.write_addr_valid[i].v = s.write_addr_valid[j]

          if not s.entries_read_data_valid[i]:
            s.invalid_addr_chain[i].v = i
            s.invalid_addr_valid[i].v = 1
          else:
            s.invalid_addr_chain[i].v = s.invalid_addr_chain[j]
            s.invalid_addr_valid[i].v = s.invalid_addr_valid[j]

    s.overwrite = Wire(1)

    @s.combinational
    def compute_overwrite():
      s.overwrite.v = not s.write_remove and not s.write_addr_valid[
          nregs - 1] and not s.invalid_addr_valid[nregs - 1]

    for i in range(nregs):

      @s.combinational
      def handle_write(i=i):
        if not s.clear_call:
          s.entries[i].write_call.v = s.write_call and (
              (s.overwrite and s.overwrite_counter.read_data == i) or
              (s.write_addr_chain[nregs - 1] == i and
               s.write_addr_valid[nregs - 1]) or
              (not s.write_addr_valid[nregs - 1] and
               s.invalid_addr_chain[nregs - 1] == i and
               s.invalid_addr_valid[nregs - 1] and not s.write_remove))
          s.entries_write_data_key[i].v = s.write_key
          s.entries_write_data_value[i].v = s.write_value
          s.entries_write_data_valid[i].v = not s.write_remove
        else:
          s.entries[i].write_call.v = 1
          s.entries_write_data_key[i].v = 0
          s.entries_write_data_value[i].v = 0
          s.entries_write_data_valid[i].v = 0

    @s.combinational
    def update_overwrite_counter(nregsm1=nregs - 1):
      if s.write_call and s.overwrite:
        s.overwrite_counter.write_call.v = 1
        if s.overwrite_counter.read_data == nregsm1:
          s.overwrite_counter.write_data.v = 0
        else:
          s.overwrite_counter.write_data.v = s.overwrite_counter.read_data + 1
      else:
        s.overwrite_counter.write_call.v = 0
        s.overwrite_counter.write_data.v = 0
Example #8
0
    def __init__(s, interface):
        UseInterface(s, interface)
        seqidx_nbits = s.interface.SeqIdxNbits
        max_entries = 1 << seqidx_nbits

        # ROB stuff: Dealloc from head, alloc at tail
        s.tail = Register(RegisterInterface(Bits(seqidx_nbits), enable=True),
                          reset_value=0)
        s.head = Register(RegisterInterface(Bits(seqidx_nbits), enable=True),
                          reset_value=0)
        s.num = Register(RegisterInterface(Bits(seqidx_nbits + 1),
                                           enable=True),
                         reset_value=0)

        s.head_next = Wire(seqidx_nbits)
        s.tail_next = Wire(seqidx_nbits)

        s.empty_ = Wire(1)
        s.full_ = Wire(1)

        # Connect methods
        s.connect(s.allocate_idx, s.tail.read_data)
        s.connect(s.get_head_idx, s.head.read_data)

        # All the following comb blocks are for ROB stuff:
        @s.combinational
        def set_method_rdy():
            s.allocate_rdy.v = not s.full_
            s.get_head_rdy.v = not s.empty_
            s.free_rdy.v = not s.empty_

        @s.combinational
        def set_flags():
            s.full_.v = s.num.read_data == max_entries
            s.empty_.v = s.num.read_data == 0

        @s.combinational
        def update_tail():
            s.tail.write_call.v = s.allocate_call or s.rollback_call
            s.tail_next.v = s.tail.read_data + 1
            if s.rollback_call:
                s.tail_next.v = s.rollback_idx + 1
            s.tail.write_data.v = s.tail_next.v

        @s.combinational
        def update_head():
            s.head_next.v = s.head.read_data + 1 if s.free_call else s.head.read_data
            s.head.write_call.v = s.free_call
            s.head.write_data.v = s.head_next

        s.head_tail_delta = Wire(seqidx_nbits)

        @s.combinational
        def update_num(seqp1=seqidx_nbits + 1):
            s.head_tail_delta.v = s.tail_next - s.head_next
            s.num.write_call.v = s.tail.write_call or s.head.write_call
            s.num.write_data.v = s.num.read_data
            if s.rollback_call:
                # If it is going to be full (head=tail and not rolling back to head)
                if s.head_tail_delta == 0 and (s.rollback_idx !=
                                               s.head.read_data):
                    s.num.write_data.v = max_entries
                else:
                    s.num.write_data.v = zext(
                        s.head_tail_delta,
                        seqp1)  # An exception clears everything
            elif s.allocate_call ^ s.free_call:
                if s.allocate_call:
                    s.num.write_data.v = s.num.read_data + 1
                elif s.free_call:
                    s.num.write_data.v = s.num.read_data - 1
Example #9
0
  def __init__(s, interface, make_kill, bypass_ready=True):
    """ This model implements a generic issue slot, an issue queue has an instance
      of this for each slot in the queue

      SlotType: Should subclass AbstractSlotType and add any additional fields
    """
    UseInterface(s, interface)

    # The storage for everything
    #s.valid_ = Register(RegisterInterface(Bits(1)), reset_value=0)

    # Make the valid manager from the DropControllerInterface passed in
    s.val_manager_ = gen_valid_value_manager(make_kill)()

    s.opaque_ = Register(RegisterInterface(s.interface.Opaque, enable=True))
    s.src0_ = Register(RegisterInterface(s.interface.SrcTag, enable=True))
    s.src0_val_ = Register(RegisterInterface(Bits(1), enable=True))
    s.src0_rdy_ = Register(RegisterInterface(Bits(1), enable=True))
    s.src1_ = Register(RegisterInterface(s.interface.SrcTag, enable=True))
    s.src1_val_ = Register(RegisterInterface(Bits(1), enable=True))
    s.src1_rdy_ = Register(RegisterInterface(Bits(1), enable=True))
    if s.interface.WithOrder:
      s.ordered_ = Register(RegisterInterface(Bits(1), enable=True))
      s.connect(s.peek_value.ordered, s.ordered_.read_data)
      s.connect(s.status_ordered, s.ordered_.read_data)
      s.connect(s.ordered_.write_data, s.input_value.ordered)
      s.connect(s.ordered_.write_call, s.input_call)

    s.srcs_ready_ = Wire(1)
    s.kill_ = Wire(1)

    # Does it match this cycle?
    s.src0_match_ = Wire(1)
    s.src1_match_ = Wire(1)

    # Connect the output method
    s.connect(s.peek_value.opaque, s.opaque_.read_data)
    s.connect(s.peek_value.src0, s.src0_.read_data)
    s.connect(s.peek_value.src0_val, s.src0_val_.read_data)
    s.connect(s.peek_value.src1, s.src1_.read_data)
    s.connect(s.peek_value.src1_val, s.src1_val_.read_data)

    # Connect inputs into registers
    s.connect(s.opaque_.write_data, s.input_value.opaque)
    s.connect(s.src0_.write_data, s.input_value.src0)
    s.connect(s.src0_val_.write_data, s.input_value.src0_val)
    s.connect(s.src1_.write_data, s.input_value.src1)
    s.connect(s.src1_val_.write_data, s.input_value.src1_val)

    # Connect all the enables
    s.connect(s.opaque_.write_call, s.input_call)
    s.connect(s.src0_.write_call, s.input_call)
    s.connect(s.src0_val_.write_call, s.input_call)
    s.connect(s.src1_.write_call, s.input_call)
    s.connect(s.src1_val_.write_call, s.input_call)

    # Connect up val manager
    s.connect(s.val_manager_.add_msg, s.input_value.kill_opaque)
    s.connect(s.peek_value.kill_opaque, s.val_manager_.peek_msg)
    s.connect(s.val_manager_.add_call, s.input_call)
    s.connect(s.status_valid, s.val_manager_.peek_rdy)
    s.connect(s.val_manager_.take_call, s.take_call)
    # Lift the global kill notify signal
    s.connect_m(s.val_manager_.kill_notify, s.kill_notify)

    s.src0_notify_match = Wire(s.interface.NumNotify)
    s.src1_notify_match = Wire(s.interface.NumNotify)

    @s.combinational
    def match_src():
      for i in range(s.interface.NumNotify):
        s.src0_notify_match[i].v = s.src0_val_.read_data and s.notify_call[
            i] and (s.src0_.read_data == s.notify_tag[i])
        s.src1_notify_match[i].v = s.src1_val_.read_data and s.notify_call[
            i] and (s.src1_.read_data == s.notify_tag[i])

      s.src0_match_.v = reduce_or(s.src0_notify_match)
      s.src1_match_.v = reduce_or(s.src1_notify_match)

    @s.combinational
    def handle_ready():
      s.peek_value.src0_rdy.v = s.src0_rdy_.read_data or s.src0_match_
      s.peek_value.src1_rdy.v = s.src1_rdy_.read_data or s.src1_match_
      s.status_ready.v = s.status_valid and s.srcs_ready_

    if bypass_ready:

      @s.combinational
      def handle_srcs_ready():
        s.srcs_ready_.v = s.peek_value.src0_rdy and s.peek_value.src1_rdy
    else:

      @s.combinational
      def handle_srcs_ready():
        s.srcs_ready_.v = s.src0_rdy_.read_data and s.src1_rdy_.read_data

    @s.combinational
    def set_reg_rdy():
      s.src0_rdy_.write_call.v = s.input_call or (s.src0_match_ and
                                                  s.status_valid)
      s.src1_rdy_.write_call.v = s.input_call or (s.src1_match_ and
                                                  s.status_valid)

      if s.input_call:
        s.src0_rdy_.write_data.v = s.input_value.src0_rdy or not s.input_value.src0_val
        s.src1_rdy_.write_data.v = s.input_value.src1_rdy or not s.input_value.src1_val
      else:
        s.src0_rdy_.write_data.v = s.src0_match_
        s.src1_rdy_.write_data.v = s.src1_match_
Example #10
0
    def __init__(s, interface):
        UseInterface(s, interface)
        tracking = s.interface.tracking

        s.require(
            DropControllerInterface(s.interface.DataIn, s.interface.DataOut,
                                    s.interface.KillArgType)['check'])

        s.val_reg = Register(RegisterInterface(Bits(1)), reset_value=0)
        s.out_reg = Register(RegisterInterface(s.interface.DataIn))
        if tracking:
            s.dead_reg = Register(RegisterInterface(Bits(1)))
        s.output_rdy = Wire(1)
        s.output_clear = Wire(1)

        if s.interface.KillArgType is not None:
            s.connect(s.check_msg, s.kill_notify_msg)
        s.connect(s.check_in_, s.out_reg.read_data)
        s.connect(s.peek_msg, s.check_out)

        s.should_keep = Wire(1)
        # If tracking we always keep it, but just mark it dead
        if tracking:
            s.connect(s.should_keep, 1)
        else:
            s.connect(s.should_keep, s.check_keep)

        @s.combinational
        def handle_rdy():
            if s.val_reg.read_data:
                s.output_rdy.v = s.should_keep
                s.dropping_out.v = not s.should_keep
            else:
                s.output_rdy.v = 0
                s.dropping_out.v = 0

        s.connect(s.peek_rdy, s.output_rdy)

        @s.combinational
        def handle_clear():
            s.output_clear.v = not s.output_rdy or s.take_call

        s.connect(s.add_rdy, s.output_clear)

        @s.combinational
        def handle_val_reg_in():
            if s.add_call:
                s.val_reg.write_data.v = 1
            else:
                s.val_reg.write_data.v = not s.output_clear

        @s.combinational
        def handle_out_reg():
            if s.add_call:
                s.out_reg.write_data.v = s.add_msg
            else:
                s.out_reg.write_data.v = s.check_out

        if tracking:

            @s.combinational
            def handle_dead_reg():
                # It is dead if it is already dead or we are not keeping it
                s.peek_dead.v = s.dead_reg.read_data or not s.check_keep
                if s.add_call:
                    s.dead_reg.write_data.v = s.add_dead
                else:
                    s.dead_reg.write_data.v = s.peek_dead
Example #11
0
    def __init__(s, interface, ncycles):
        UseInterface(s, interface)
        assert s.interface.DataLen % ncycles == 0
        nsteps = s.interface.DataLen // ncycles
        END = s.interface.DataLen - 1
        AEND = s.interface.DataLen
        iface = NonRestoringDividerStepInterface(s.interface.DataLen)
        s.unit = NonRestoringDividerStep(iface, nsteps)

        s.acc = Register(
            RegisterInterface(s.interface.DataLen + 1, enable=True))
        s.divisor = Register(
            RegisterInterface(s.interface.DataLen, enable=True))
        s.dividend = Register(
            RegisterInterface(s.interface.DataLen, enable=True))
        # Set if we need to take twos compliment at end
        s.negate = Register(RegisterInterface(1, enable=True))
        s.negate_rem = Register(RegisterInterface(1, enable=True))
        s.connect(s.negate.write_call, s.div_call)
        s.connect(s.negate_rem.write_call, s.div_call)
        s.connect(s.divisor.write_call, s.div_call)

        # Connect up the unit
        s.connect(s.unit.div_acc, s.acc.read_data)
        s.connect(s.unit.div_divisor, s.divisor.read_data)
        s.connect(s.unit.div_dividend, s.dividend.read_data)

        s.counter = Register(RegisterInterface(clog2(ncycles + 1),
                                               enable=True))
        s.busy = Register(RegisterInterface(1, enable=True), reset_value=0)

        @s.combinational
        def handle_calls():
            # Arguments
            s.div_rdy.v = not s.busy.read_data or s.result_call
            # Results
            s.result_rdy.v = s.busy.read_data and s.counter.read_data == 0
            s.result_quotient.v = s.dividend.read_data
            s.result_rem.v = s.acc.read_data[:s.interface.DataLen]
            # Figure out if we need to negative
            s.negate.write_data.v = s.div_signed and (s.div_divisor[END]
                                                      ^ s.div_dividend[END])
            s.negate_rem.write_data.v = s.div_signed and s.div_dividend[END]

        @s.combinational
        def handle_counter():
            s.counter.write_call.v = s.counter.read_data != 0 or s.div_call
            s.counter.write_data.v = 0
            if s.div_call:
                s.counter.write_data.v = ncycles
            else:
                s.counter.write_data.v = s.counter.read_data - 1

        @s.combinational
        def set_div_regs():
            s.acc.write_call.v = s.div_call or s.counter.read_data > 0
            s.dividend.write_call.v = s.div_call or s.counter.read_data > 0

            # Load the values
            s.acc.write_data.v = 0
            s.divisor.write_data.v = 0
            s.divisor.write_data.v = ~s.div_divisor + 1 if (
                s.div_signed and s.div_divisor[END]) else s.div_divisor
            s.dividend.write_data.v = ~s.div_dividend + 1 if (
                s.div_signed and s.div_dividend[END]) else s.div_dividend

            if not s.div_call:
                s.dividend.write_data.v = s.unit.div_dividend_next
                s.acc.write_data.v = s.unit.div_acc_next
                # Special case last cycle
                if s.counter.read_data == 1:
                    if s.unit.div_acc_next[AEND]:
                        s.acc.write_data.v += s.divisor.read_data
                    if s.negate_rem.read_data:  # Last cycle, compliment
                        s.acc.write_data.v = ~s.acc.write_data + 1
                    # Only if not divided by zero
                    if s.negate.read_data and s.divisor.read_data != 0:
                        s.dividend.write_data.v = ~s.dividend.write_data + 1

        @s.combinational
        def handle_busy():
            s.busy.write_call.v = s.div_call or s.result_call or s.preempt_call
            s.busy.write_data.v = s.div_call
Example #12
0
    def __init__(s, fetch_interface, MemMsg, enable_btb):
        UseInterface(s, fetch_interface)
        s.MemMsg = MemMsg
        xlen = XLEN
        ilen = ILEN
        ilen_bytes = ilen / 8
        s.require(
            MethodSpec(
                'mem_recv',
                args=None,
                rets={'msg': s.MemMsg.resp},
                call=True,
                rdy=True,
            ),
            MethodSpec(
                'mem_send',
                args={'msg': s.MemMsg.req},
                rets=None,
                call=True,
                rdy=True,
            ),
            MethodSpec(
                'check_redirect',
                args={},
                rets={
                    'redirect': Bits(1),
                    'target': Bits(xlen),
                },
                call=False,
                rdy=False,
            ),
            MethodSpec(
                'btb_read',
                args={
                    'key': XLEN,
                },
                rets={
                    'value': XLEN,
                    'valid': Bits(1)
                },
                call=False,
                rdy=False,
            ),
        )

        s.drop_unit = DropUnit(DropUnitInterface(s.MemMsg.resp))
        s.connect_m(s.drop_unit.input, s.mem_recv, {
            'msg': 'data',
        })
        # PYMTL_BROKEN
        s.drop_unit_output_data_data = Wire(s.drop_unit.output_data.data.nbits)
        s.connect(s.drop_unit_output_data_data, s.drop_unit.output_data.data)
        s.inst_from_mem = Wire(ILEN)
        # PYMTL_BROKEN
        @s.combinational
        def pymtl_is_broken_connect_does_not_work():
            s.inst_from_mem.v = s.drop_unit_output_data_data[0:ilen]

        s.fetch_val = Register(RegisterInterface(Bits(1), True, False),
                               reset_value=0)
        s.fetch_msg = Register(RegisterInterface(FetchMsg(), True, False))

        s.in_flight = Register(RegisterInterface(Bits(1), True, False),
                               reset_value=0)
        s.pc = Register(RegisterInterface(Bits(xlen), True, False),
                        reset_value=0)

        s.advance_f1 = Wire(1)
        s.advance_f0 = Wire(1)

        @s.combinational
        def handle_advance():
            s.advance_f1.v = s.drop_unit.output_rdy and (
                not s.fetch_val.read_data or s.take_call)
            s.advance_f0.v = not s.in_flight.read_data or s.drop_unit.drop_status_occurred or s.advance_f1

        @s.combinational
        def handle_redirect():
            # Insert BTB here!
            s.btb_read_key.v = s.pc.read_data
            if s.check_redirect_redirect:
                # drop if in flight
                s.drop_unit.drop_call.v = s.in_flight.read_data
                # the new PC is the target
                s.pc.write_data.v = s.check_redirect_target
                s.pc.write_call.v = 1
            else:
                s.drop_unit.drop_call.v = 0
                # if we are issuing now, the new PC is just ilen_bytes more than the last one
                if s.btb_read_valid and enable_btb:
                    s.pc.write_data.v = s.btb_read_value
                else:
                    s.pc.write_data.v = s.pc.read_data + ilen_bytes
                s.pc.write_call.v = s.advance_f0

        s.connect(s.in_flight.write_data, 1)
        s.connect(s.in_flight.write_call, s.advance_f0)
        s.connect(s.peek_msg, s.fetch_msg.read_data)

        @s.combinational
        def handle_f1():
            s.fetch_val.write_call.v = 0
            s.fetch_val.write_data.v = 0
            s.fetch_msg.write_call.v = 0
            s.fetch_msg.write_data.v = 0
            s.drop_unit.output_call.v = 0

            if s.check_redirect_redirect:
                # invalidate the output
                s.peek_rdy.v = 0
                # write a 0 into the valid register
                s.fetch_val.write_call.v = 1
            else:
                s.peek_rdy.v = s.fetch_val.read_data

                if s.drop_unit.output_rdy and (not s.fetch_val.read_data
                                               or s.take_call):
                    s.fetch_val.write_call.v = 1
                    s.fetch_val.write_data.v = 1
                    s.fetch_msg.write_call.v = 1
                    s.drop_unit.output_call.v = 1

                    s.fetch_msg.write_data.hdr_pc.v = s.pc.read_data
                    if s.drop_unit.output_data.stat != MemMsgStatus.OK:
                        s.fetch_msg.write_data.hdr_status.v = PipelineMsgStatus.PIPELINE_MSG_STATUS_EXCEPTION_RAISED
                        if s.drop_unit.output_data.stat == MemMsgStatus.ADDRESS_MISALIGNED:
                            s.fetch_msg.write_data.exception_info_mcause.v = ExceptionCode.INSTRUCTION_ADDRESS_MISALIGNED
                        elif s.drop_unit.output_data.stat == MemMsgStatus.ACCESS_FAULT:
                            s.fetch_msg.write_data.exception_info_mcause.v = ExceptionCode.INSTRUCTION_ACCESS_FAULT
                        # save the faulting PC as mtval
                        s.fetch_msg.write_data.exception_info_mtval.v = s.pc.read_data
                    else:
                        s.fetch_msg.write_data.hdr_status.v = PipelineMsgStatus.PIPELINE_MSG_STATUS_VALID
                        s.fetch_msg.write_data.inst.v = s.inst_from_mem
                        s.fetch_msg.write_data.pc_succ.v = s.pc.write_data
                elif s.take_call:
                    # someone is calling, but we are stalled, so give them output but
                    # unset valid
                    s.fetch_val.write_call.v = 1
                    s.fetch_val.write_data.v = 0

        # handle_f0
        s.connect(s.mem_send_msg.type_, int(MemMsgType.READ))

        @s.combinational
        def write_addr():
            s.mem_send_msg.addr.v = s.pc.write_data

        s.connect(s.mem_send_msg.len_, ilen_bytes)
        # can only send it if advancing
        s.connect(s.mem_send_call, s.advance_f0)
Example #13
0
    def __init__(s, cflow_interface, reset_vector):
        UseInterface(s, cflow_interface)
        xlen = s.interface.DataLen
        seqidx_nbits = s.interface.SeqIdxNbits
        specidx_nbits = s.interface.SpecIdxNbits
        specmask_nbits = s.interface.SpecMaskNbits
        store_id_nbits = s.interface.StoreIdNbits
        max_entries = 1 << seqidx_nbits

        s.require(
            MethodSpec(
                'dflow_get_store_id',
                args=None,
                rets={
                    'store_id': store_id_nbits,
                },
                call=True,
                rdy=True,
            ),
            # Snapshot call on dataflow
            MethodSpec(
                'dflow_snapshot',
                args=None,
                rets={
                    'id_': specidx_nbits,
                },
                call=True,
                rdy=True,
            ),
            MethodSpec(
                'dflow_restore',
                args={
                    'source_id': specidx_nbits,
                },
                rets=None,
                call=True,
                rdy=False,
            ),
            MethodSpec(
                'dflow_free_snapshot',
                args={
                    'id_': specidx_nbits,
                },
                rets=None,
                call=True,
                rdy=False,
            ),
            MethodSpec(
                'dflow_rollback',
                args=None,
                rets=None,
                call=True,
                rdy=False,
            ),
        )

        # The speculative predicted PC table
        s.pc_pred = AsynchronousRAM(
            AsynchronousRAMInterface(xlen, specmask_nbits, 1, 1, False))

        s.seq = SequenceAllocator(SequenceAllocatorInterface(seqidx_nbits))
        # The redirect registers (needed for sync reset)
        s.reset_redirect_valid_ = Wire(1)

        # The OR of all the redirect signals
        s.is_redirect_ = Wire(1)

        # Redirects caused by branches
        s.branch_redirect_ = Wire(1)
        s.redirect_target_ = Wire(xlen)
        # Redirects caused by exceptions, traps, etc...
        s.commit_redirect_ = Wire(1)
        s.commit_redirect_target_ = Wire(xlen)

        # Note that these signals are guaranteed to be zero if register_call = 0
        s.register_success_ = Wire(1)
        s.spec_register_success_ = Wire(1)
        s.store_register_success_ = Wire(1)

        # Branch mask stuff:
        s.kill_mask_ = Wire(specmask_nbits)
        s.clear_mask_ = Wire(specmask_nbits)
        s.bmask_curr_ = Wire(specmask_nbits)
        s.bmask_next_ = Wire(specmask_nbits)

        # The kill and clear signals are registered
        s.update_kills_ = Wire(1)
        s.kill_pend = Register(RegisterInterface(Bits(1), enable=True),
                               reset_value=0)
        s.reg_force = Register(RegisterInterface(Bits(1), enable=True),
                               reset_value=0)
        s.reg_kill = Register(RegisterInterface(Bits(specmask_nbits),
                                                enable=True),
                              reset_value=0)
        s.reg_clear = Register(RegisterInterface(Bits(specmask_nbits),
                                                 enable=True),
                               reset_value=0)
        s.connect(s.kill_pend.write_call, s.update_kills_)
        s.connect(s.reg_force.write_call, s.update_kills_)
        s.connect(s.reg_kill.write_call, s.update_kills_)
        s.connect(s.reg_clear.write_call, s.update_kills_)

        # Every instruction is registered under a branch mask
        s.bmask = Register(RegisterInterface(Bits(specmask_nbits),
                                             enable=True),
                           reset_value=0)
        s.bmask_alloc = OneHotEncoder(specmask_nbits, enable=True)
        s.redirect_mask = OneHotEncoder(specmask_nbits)
        # Are we currently in a serialized instruction
        s.serial = Register(RegisterInterface(Bits(1), enable=True),
                            reset_value=0)

        # connect bmask related signals
        s.connect(s.bmask.write_data, s.bmask_next_)
        # This will create the alloc mask
        s.connect(s.bmask_alloc.encode_number, s.dflow_snapshot_id_)
        s.connect(s.bmask_alloc.encode_call, s.spec_register_success_)
        # This will create the reidrection mask
        s.connect(s.redirect_mask.encode_number, s.redirect_spec_idx)
        # Things that need to be called on a successful speculative register
        s.connect(s.dflow_snapshot_call, s.spec_register_success_)
        # Connect up the dflow restore signals
        s.connect(s.dflow_restore_source_id, s.redirect_spec_idx)
        s.connect(s.dflow_restore_call, s.branch_redirect_)
        # Connect up free snapshot val
        s.connect(s.dflow_free_snapshot_id_, s.redirect_spec_idx)

        # Alloc the store ID if needed
        s.connect(s.dflow_get_store_id_call, s.store_register_success_)
        s.connect(s.register_store_id, s.dflow_get_store_id_store_id)

        # Save the speculative PC
        s.connect(s.pc_pred.write_call[0], s.spec_register_success_)
        s.connect(s.pc_pred.write_addr[0], s.dflow_snapshot_id_)
        s.connect(s.pc_pred.write_data[0], s.register_pc_succ)
        s.connect(s.pc_pred.read_addr[0], s.redirect_spec_idx)

        # Connect up check_kill method
        s.connect(s.check_kill_kill.force, s.reg_force.read_data)
        s.connect(s.check_kill_kill.kill_mask, s.reg_kill.read_data)
        s.connect(s.check_kill_kill.clear_mask, s.reg_clear.read_data)

        # Connect up register method rets
        s.connect(s.register_seq, s.seq.allocate_idx)
        s.connect(s.register_spec_idx, s.dflow_snapshot_id_)
        s.connect(s.register_branch_mask, s.bmask_curr_)
        s.connect(s.seq.allocate_call, s.register_success_)

        # Connect get head method
        s.connect(s.get_head_seq, s.seq.get_head_idx)
        s.connect(s.get_head_rdy, s.seq.get_head_rdy)

        # Connect commit
        s.connect(s.seq.free_call, s.commit_call)

        # All the backend kill signals are registered to avoid comb. loops
        @s.combinational
        def set_kill_pend():
            # We need to update this if there is a redirect even if  branch resolved correctly
            s.update_kills_.v = s.kill_pend.read_data or s.is_redirect_ or s.redirect_call
            s.kill_pend.write_data.v = s.is_redirect_ or s.redirect_call

            s.reg_force.write_data.v = (s.branch_redirect_ and s.redirect_force
                                        ) or (s.commit_redirect_)
            s.reg_kill.write_data.v = s.kill_mask_
            s.reg_clear.write_data.v = s.clear_mask_

        # This prioritizes reset redirection, then exceptions, then a branch reidrect call
        @s.combinational
        def handle_check_redirect():
            s.is_redirect_.v = s.reset_redirect_valid_ or s.commit_redirect_ or s.branch_redirect_
            s.check_redirect_redirect.v = s.is_redirect_
            s.check_redirect_target.v = 0
            if s.reset_redirect_valid_:
                s.check_redirect_target.v = reset_vector
            elif s.commit_redirect_:
                s.check_redirect_target.v = s.commit_redirect_target_
            else:  # s.branch_redirect_
                s.check_redirect_target.v = s.redirect_target_

        @s.combinational
        def set_serial():
            s.serial.write_call.v = ((s.register_success_
                                      and s.register_serialize)
                                     or (s.serial.read_data and s.commit_call))
            s.serial.write_data.v = not s.serial.read_data  #  we are always inverting it

        # This is only for a redirect call
        @s.combinational
        def handle_branch_redirection():
            # These are set after a redirect call
            s.kill_mask_.v = 0
            s.clear_mask_.v = 0
            s.redirect_target_.v = s.redirect_target
            # Free the snapshot
            s.dflow_free_snapshot_call.v = s.redirect_call
            # Look up if the predicted PC saved during register is correct
            s.branch_redirect_.v = s.redirect_call and (
                s.redirect_target != s.pc_pred.read_data[0]
                or s.redirect_force)

            if s.branch_redirect_:
                # Kill everything except preceeding branches
                s.kill_mask_.v = s.redirect_mask.encode_onehot | ~s.redirect_branch_mask
            elif s.redirect_call:
                s.clear_mask_.v = s.redirect_mask.encode_onehot

        @s.combinational
        def handle_bmask():
            s.bmask.write_call.v = s.spec_register_success_ or s.redirect_call or s.commit_redirect_
            # Update the current branch mask
            s.bmask_curr_.v = s.bmask.read_data.v & (
                ~(s.kill_mask_ | s.clear_mask_))
            s.bmask_next_.v = s.bmask_curr_
            if s.commit_redirect_:
                s.bmask_next_.v = 0
            elif s.register_speculative:
                s.bmask_next_.v = s.bmask_curr_ | s.bmask_alloc.encode_onehot

        @s.combinational
        def handle_register():
            s.register_success.v = (
                s.seq.allocate_rdy and  # ROB slot availible
                (not s.register_speculative or s.dflow_snapshot_rdy) and
                (not s.register_store
                 or s.dflow_get_store_id_rdy) and  # RT snapshot
                (not s.register_serialize or not s.seq.free_rdy)
                and  # Serialized inst
                not s.serial.read_data)

            s.register_success_.v = s.register_call and s.register_success
            s.spec_register_success_.v = s.register_success_.v and s.register_speculative
            s.store_register_success_.v = s.register_success_.v and s.register_store

        @s.combinational
        def handle_commit():
            s.commit_redirect_.v = 0
            s.commit_redirect_target_.v = s.commit_redirect_target
            # If we are committing there are a couple cases
            s.commit_redirect_.v = s.commit_call and s.commit_redirect
            s.dflow_rollback_call.v = s.commit_call and s.commit_redirect

        @s.combinational
        def update_seq():
            s.seq.rollback_call.v = s.commit_redirect_ or s.branch_redirect_
            s.seq.rollback_idx.v = s.redirect_seq
            if s.commit_redirect_:
                # On an exception, the tail = head + 1, since head will be incremented
                s.seq.rollback_idx.v = s.seq.get_head_idx

        @s.tick_rtl
        def handle_reset():
            s.reset_redirect_valid_.n = s.reset