Matching a signal against a bitvector

@theller
Here is a block that does what you want :

class MatchPattern():
    def __init__(self, pattern="----"):
        self.pattern = pattern
    
        self.hdl = self.hdl1
        
        
    @block
    def hdl1(self, 
             
            i_Clk,
 
            i_DataEn,
            i_Data,
             
            o_Match) :
         
        assert len(i_Data) == len(self.pattern)
         
        data_length = len(i_Data)
        
        xor_init = 0
        and_init = 0
        for i,c in enumerate(reversed(self.pattern)) :
            if c == '1' :
                xor_init |= 1 << i
                and_init |= 1 << i
            elif c == '0' :
                and_init |= 1 << i
            elif c == '-' :
                pass
            else :
                raise ValueError("Value should be '1', '0' or '-'")
        
        xor_vect = Signal(intbv(xor_init)[data_length:])
        xor_vect.read   = True
        xor_vect.driven = True
        
        and_vect = Signal(intbv(and_init)[data_length:])
        and_vect.read   = True
        and_vect.driven = True
         
        @always_seq(i_Clk.posedge, reset=None)
        def compare() :
            if i_DataEn :
                cmp = True
                for i in range(data_length) :
                    if bool((i_Data[i] ^ xor_vect[i]) & and_vect[i]) :
                        cmp = False
                o_Match.next = cmp

        return compare

You can use it this way :

match_inst = MatchPattern("01-10--").hdl(clk, data_en, data, match)

During elaboration, we can do everything we want. Here, we create masking vectors.
xor_vect and and_vect should be constants but we don’t have this in MyHDL for now.

Another version of the compare() function is this one :

        @always_seq(i_Clk.posedge, reset=None)
        def compare() :
            if i_DataEn :
                cmp_vect = intbv(0)[data_length:]
                for i in range(data_length) :
                    cmp_vect[i] = bool((i_Data[i] ^ xor_vect[i]) & and_vect[i])
                
                if cmp_vect == 0 :
                    o_Match.next = True
                else :
                    o_Match.next = False

Here we create a vector which content is compared to 0 to get the result.
I don’t know which version is best. I believe it will depend on the toolchain synthesiser.

This is not an optimised design since all bits are computed while they should not. With the following pattern “01–0--”, only 3 bits need to be computed.

This can be done in the following way :

        @always_seq(i_Clk.posedge, reset=None)
        def compare() :
            if i_DataEn :
                cmp_vect = intbv(0)[nb_bits_to_cmp:]
                cmp_index = 0
                for i in range(data_length) :
                    if and_vect[i] :
                        cmp_vect[cmp_index] = bool(i_Data[i] ^ xor_vect[i])
                        cmp_index += 1
                
                if cmp_vect == 0 :
                    o_Match.next = True
                else :
                    o_Match.next = False

This works in simulation but I think it will not synthesise (I have not tried).