Signals change during the rising edge of the LPC clock and are stable during its falling edge. So we sample the data signals on LCLK falling edge, but use its rising edge times to delimit the fields. --- decoders/lpc/pd.py | 117 +++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 63 deletions(-)
diff --git a/decoders/lpc/pd.py b/decoders/lpc/pd.py index 2a88e30..8ab2faf 100644 --- a/decoders/lpc/pd.py +++ b/decoders/lpc/pd.py @@ -141,15 +141,15 @@ def __init__(self): def reset(self): self.state = 'IDLE' - self.oldlclk = -1 self.lad = -1 + self.lad_bits = None + self.lframe = -1 self.addr = 0 self.cur_nibble = 0 self.cycle_type = -1 self.databyte = 0 self.tarcount = 0 self.synccount = 0 - self.oldpins = None self.ss_block = self.es_block = None def start(self): @@ -158,38 +158,32 @@ def start(self): def putb(self, data): self.put(self.ss_block, self.es_block, self.out_ann, data) - def handle_get_start(self, lad, lad_bits, lframe): + def handle_get_start(self): # LAD[3:0]: START field (1 clock cycle). + # LFRAME# is de-asserted (high). Last START field was last clock cycle, + # we are now reading the CYCTYPE + DIR field. + if self.lframe == 1: + self.state = 'GET CT/DR' + return + # The last value of LAD[3:0] before LFRAME# gets de-asserted is what # the peripherals must use. However, the host can keep LFRAME# asserted # multiple clocks, and we output all START fields that occur, even # though the peripherals are supposed to ignore all but the last one. self.es_block = self.samplenum - self.putb([1, [fields['START'][lad], 'START', 'St', 'S']]) - self.ss_block = self.samplenum - - # Output a warning if LAD[3:0] changes while LFRAME# is low. - # TODO - if (self.lad != -1 and self.lad != lad): - self.putb([0, ['LAD[3:0] changed while LFRAME# was asserted']]) - - # LFRAME# is asserted (low). Wait until it gets de-asserted again - # (the host is allowed to keep it asserted multiple clocks). - if lframe != 1: - return - + self.putb([1, [fields['START'][self.lad], 'START', 'St', 'S']]) self.start_field = self.lad - self.state = 'GET CT/DR' + self.ss_block = self.samplenum - def handle_get_ct_dr(self, lad, lad_bits): + def handle_get_ct_dr(self): # LAD[3:0]: Cycle type / direction field (1 clock cycle). - self.cycle_type = fields['CT_DR'].get(lad, 'Reserved / unknown') + self.cycle_type = fields['CT_DR'].get(self.lad, 'Reserved / unknown') # TODO: Warning/error on invalid cycle types. if 'Reserved' in self.cycle_type: - self.putb([0, ['Invalid cycle type (%s)' % lad_bits]]) + self.putb([0, ['Invalid cycle type (%s)' % self.lad_bits]]) self.es_block = self.samplenum self.putb([2, ['Cycle type: %s' % self.cycle_type]]) @@ -199,7 +193,7 @@ def handle_get_ct_dr(self, lad, lad_bits): self.addr = 0 self.cur_nibble = 0 - def handle_get_addr(self, lad, lad_bits): + def handle_get_addr(self): # LAD[3:0]: ADDR field (4/8/0 clock cycles). # I/O cycles: 4 ADDR clocks. Memory cycles: 8 ADDR clocks. @@ -213,7 +207,7 @@ def handle_get_addr(self, lad, lad_bits): # Addresses are driven MSN-first. offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 - self.addr |= (lad << offset) + self.addr |= (self.lad << offset) # Continue if we haven't seen all ADDR cycles, yet. if (self.cur_nibble < addr_nibbles - 1): @@ -228,20 +222,20 @@ def handle_get_addr(self, lad, lad_bits): self.state = 'GET TAR' self.tar_count = 0 - def handle_get_tar(self, lad, lad_bits): + def handle_get_tar(self): # LAD[3:0]: First TAR (turn-around) field (2 clock cycles). self.es_block = self.samplenum - self.putb([4, ['TAR, cycle %d: %s' % (self.tarcount, lad_bits)]]) + self.putb([4, ['TAR, cycle %d: %s' % (self.tarcount, self.lad_bits)]]) self.ss_block = self.samplenum # On the first TAR clock cycle LAD[3:0] is driven to 1111 by # either the host or peripheral. On the second clock cycle, # the host or peripheral tri-states LAD[3:0], but its value # should still be 1111, due to pull-ups on the LAD lines. - if lad_bits != '1111': + if self.lad_bits != '1111': self.putb([0, ['TAR, cycle %d: %s (expected 1111)' % \ - (self.tarcount, lad_bits)]]) + (self.tarcount, self.lad_bits)]]) if (self.tarcount != 1): self.tarcount += 1 @@ -250,11 +244,11 @@ def handle_get_tar(self, lad, lad_bits): self.tarcount = 0 self.state = 'GET SYNC' - def handle_get_sync(self, lad, lad_bits): + def handle_get_sync(self): # LAD[3:0]: SYNC field (1-n clock cycles). - self.sync_val = lad_bits - self.cycle_type = fields['SYNC'].get(lad, 'Reserved / unknown') + self.sync_val = self.lad_bits + self.cycle_type = fields['SYNC'].get(self.lad, 'Reserved / unknown') # TODO: Warnings if reserved value are seen? if 'Reserved' in self.cycle_type: @@ -270,14 +264,14 @@ def handle_get_sync(self, lad, lad_bits): self.cycle_count = 0 self.state = 'GET DATA' - def handle_get_data(self, lad, lad_bits): + def handle_get_data(self): # LAD[3:0]: DATA field (2 clock cycles). # Data is driven LSN-first. if (self.cycle_count == 0): - self.databyte = lad + self.databyte = self.lad elif (self.cycle_count == 1): - self.databyte |= (lad << 4) + self.databyte |= (self.lad << 4) else: raise Exception('Invalid cycle_count: %d' % self.cycle_count) @@ -292,20 +286,20 @@ def handle_get_data(self, lad, lad_bits): self.cycle_count = 0 self.state = 'GET TAR2' - def handle_get_tar2(self, lad, lad_bits): + def handle_get_tar2(self): # LAD[3:0]: Second TAR field (2 clock cycles). self.es_block = self.samplenum - self.putb([7, ['TAR, cycle %d: %s' % (self.tarcount, lad_bits)]]) + self.putb([7, ['TAR, cycle %d: %s' % (self.tarcount, self.lad_bits)]]) self.ss_block = self.samplenum # On the first TAR clock cycle LAD[3:0] is driven to 1111 by # either the host or peripheral. On the second clock cycle, # the host or peripheral tri-states LAD[3:0], but its value # should still be 1111, due to pull-ups on the LAD lines. - if lad_bits != '1111': + if self.lad_bits != '1111': self.putb([0, ['Warning: TAR, cycle %d: %s (expected 1111)' - % (self.tarcount, lad_bits)]]) + % (self.tarcount, self.lad_bits)]]) if (self.tarcount != 1): self.tarcount += 1 @@ -315,51 +309,48 @@ def handle_get_tar2(self, lad, lad_bits): self.state = 'IDLE' def decode(self): - conditions = [{i: 'e'} for i in range(6)] + conditions = {1: 'e'} # LCLK edge while True: pins = self.wait(conditions) - # Store current pin values for the next round. - self.oldpins = pins - # Get individual pin values into local variables. (lframe, lclk, lad0, lad1, lad2, lad3) = pins[:6] (lreset, ldrq, serirq, clkrun, lpme, lpcpd, lsmi) = pins[6:] - # Only look at the signals upon rising LCLK edges. The LPC clock - # is the same as the PCI clock (which is sampled at rising edges). - if not (self.oldlclk == 0 and lclk == 1): - self.oldlclk = lclk + # Signals change during the rising edge of the LPC clock and are + # stable during its falling edge. So we sample the LAD[3:0] data + # and LFRAME# on the falling edge, but use the rising edges time + # to delimit the fields. + if lclk == 0: + # Store LAD and LFRAME# to use them on next LCLK rising edge + self.lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0 + self.lad_bits = '{:04b}'.format(self.lad) + self.lframe = lframe + # self.putb([0, ['LAD: %s' % self.lad_bits]]) continue - # Store LAD[3:0] bit values (one nibble) in local variables. - # Most (but not all) states need this. - if self.state != 'IDLE': - lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0 - lad_bits = '{:04b}'.format(lad) - # self.putb([0, ['LAD: %s' % lad_bits]]) - # TODO: Only memory read/write is currently supported/tested. # State machine if self.state == 'IDLE': # A valid LPC cycle starts with LFRAME# being asserted (low). - if lframe != 0: + if self.lframe != 0: + self.ss_block = self.samplenum continue - self.ss_block = self.samplenum self.state = 'GET START' - self.lad = -1 - elif self.state == 'GET START': - self.handle_get_start(lad, lad_bits, lframe) - elif self.state == 'GET CT/DR': - self.handle_get_ct_dr(lad, lad_bits) + # FALLTHROUGH + if self.state == 'GET START': + self.handle_get_start() + # FALLTHROUGH + if self.state == 'GET CT/DR': + self.handle_get_ct_dr() elif self.state == 'GET ADDR': - self.handle_get_addr(lad, lad_bits) + self.handle_get_addr() elif self.state == 'GET TAR': - self.handle_get_tar(lad, lad_bits) + self.handle_get_tar() elif self.state == 'GET SYNC': - self.handle_get_sync(lad, lad_bits) + self.handle_get_sync() elif self.state == 'GET DATA': - self.handle_get_data(lad, lad_bits) + self.handle_get_data() elif self.state == 'GET TAR2': - self.handle_get_tar2(lad, lad_bits) + self.handle_get_tar2() -- 2.30.2 _______________________________________________ sigrok-devel mailing list sigrok-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sigrok-devel