from migen import * from misoc.cores.code_8b10b import SingleEncoder, Decoder class MultiEncoder(Module): # For 4-channel EEM # Thus, no need for words parameter # It is always a 2-wds -> 4-ch conversion # Implement using crossbar, so we don't need to do clock domain conversion # while maintaining proper disparity def __init__(self, lsb_first=False): WORDS = 2 # Keep the link layer interface identical to standard encoders self.d = [Signal(8) for _ in range(WORDS)] self.k = [Signal() for _ in range(WORDS)] # Output interface is simplified because we have custom physical layer self.output = [Signal(10) for _ in range(WORDS)] # Module start signal self.start = Signal() # lsb_first should not be set set # But technically if the same setting is reflected on the decoder # It shouldn't be an issue if lsb_first: raise ValueError("lsb_first must not be set") # Phase of the encoder # Alternate crossbar between encoder and SERDES every cycle phase = Signal() # Intermediate registers for output and disparity # More significant bits are buffered due to channel geometry # Disparity bit is delayed. The same encoder is shared by 2 SERDES output_bufs = [Signal(5) for _ in range(WORDS)] disp_bufs = [Signal() for _ in range(WORDS)] encoders = [SingleEncoder(lsb_first) for _ in range(WORDS)] self.submodules += encoders for d, k, output, output_buf, disp_buf, encoder in \ zip(self.d, self.k, self.output, output_bufs, disp_bufs, encoders): self.comb += [ encoder.d.eq(d), encoder.k.eq(k), encoder.disp_in.eq(disp_buf), # Implementing switching crossbar If(phase, output.eq(Cat(encoder.output[0:5], output_buf)) ).Else( output.eq(Cat(output_buf, encoder.output[0:5])) ), ] # Handle intermediate registers self.sync += [ disp_buf.eq(encoder.disp_out), output_buf.eq(encoder.output[5:10]), ] aligned = Signal() self.sync += [ # Phase switching phase.eq(~phase), If(~aligned & self.start, aligned.eq(1), # Later statements take precedent phase.eq(0), ), ] # Unlike the usual 8b10b decoder, it needs to know which SERDES to decode class CrossbarDecoder(Module): def __init__(self, lsb_first=False): self.raw_input = Signal(10) self.d = Signal(8) self.k = Signal() # Notifier signal when group alignmnet is completed self.start = Signal() aligned = Signal() phase = Signal() # Intermediate register for input buffer = Signal(5) self.submodules.decoder = Decoder(lsb_first) # lsb_first should not be set set # But technically if the same setting is reflected on the decoder # It shouldn't be an issue if lsb_first: raise ValueError("lsb_first must not be set") # Update phase & synchronous elements self.sync += [ phase.eq(~phase), If(~aligned & self.start, aligned.eq(1), phase.eq(0), ), If(phase, buffer.eq(self.raw_input[:5]), ).Else( buffer.eq(self.raw_input[5:]) ), ] # Send appropriate input to decoder self.comb += [ If(phase, self.decoder.input.eq(Cat(buffer, self.raw_input[5:])), ).Else( self.decoder.input.eq(Cat(buffer, self.raw_input[:5])), ), ] self.comb += [ self.d.eq(self.decoder.d), self.k.eq(self.decoder.k), ]