From ef6972275125b23e9d874400742ab665d489980d Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 24 Mar 2020 13:51:11 -0500 Subject: [PATCH 1/4] Fix LPC write cycle decoding --- libsigrokdecode4DSL/decoders/lpc/pd.py | 32 +++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/libsigrokdecode4DSL/decoders/lpc/pd.py index 6eda49be..ed844cc8 100755 --- a/libsigrokdecode4DSL/decoders/lpc/pd.py +++ b/libsigrokdecode4DSL/decoders/lpc/pd.py @@ -3,6 +3,7 @@ ## ## Copyright (C) 2012-2013 Uwe Hermann ## Copyright (C) 2019 DreamSourceLab +## Copyright (C) 2020 Raptor Engineering, LLC ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -62,6 +63,26 @@ fields = { 0b1110: 'Reserved / not allowed', 0b1111: 'Reserved / not allowed', }, + # Cycle type / direction field + # False for read cycle, True for write cycle + 'CT_DR_WR': { + 0b0000: False, + 0b0001: False, + 0b0010: True, + 0b0011: True, + 0b0100: False, + 0b0101: False, + 0b0110: True, + 0b0111: True, + 0b1000: False, + 0b1001: False, + 0b1010: True, + 0b1011: True, + 0b1100: False, + 0b1101: False, + 0b1110: False, + 0b1111: False, + }, # SIZE field (determines how many bytes are to be transferred) # Bits[3:2] are reserved, must be driven to 0b00. # Neither host nor peripheral are allowed to drive 0b0010. @@ -155,6 +176,7 @@ class Decoder(srd.Decoder): self.samplenum = 0 self.lad = -1 self.addr = 0 + self.direction = 0 self.cur_nibble = 0 self.cycle_type = -1 self.databyte = 0 @@ -196,6 +218,7 @@ class Decoder(srd.Decoder): # LAD[3:0]: Cycle type / direction field (1 clock cycle). self.cycle_type = fields['CT_DR'][self.oldlad] + self.direction = fields['CT_DR_WR'][self.oldlad] # TODO: Warning/error on invalid cycle types. if self.cycle_type == 'Reserved': @@ -235,8 +258,12 @@ class Decoder(srd.Decoder): self.putb([3, [s % self.addr]]) self.ss_block = self.samplenum - self.state = 'GET TAR' - self.tar_count = 0 + if self.direction == 1: + self.state = 'GET DATA' + self.cycle_count = 0 + else: + self.state = 'GET TAR' + self.tar_count = 0 def handle_get_tar(self): # LAD[3:0]: First TAR (turn-around) field (2 clock cycles). @@ -277,7 +304,6 @@ class Decoder(srd.Decoder): self.ss_block = self.samplenum # TODO - self.cycle_count = 0 if (lframe == 0): self.state = 'GET TIMEOUT' From 6fbe3d3a57b462b4499a6ffb9487b85c612fd1de Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 29 Mar 2020 01:31:55 -0500 Subject: [PATCH 2/4] Fix decode failure on host driven abort --- libsigrokdecode4DSL/decoders/lpc/pd.py | 1 + 1 file changed, 1 insertion(+) diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/libsigrokdecode4DSL/decoders/lpc/pd.py index ed844cc8..49ccb96f 100755 --- a/libsigrokdecode4DSL/decoders/lpc/pd.py +++ b/libsigrokdecode4DSL/decoders/lpc/pd.py @@ -182,6 +182,7 @@ class Decoder(srd.Decoder): self.databyte = 0 self.tarcount = 0 self.synccount = 0 + self.timeoutcount = 0 self.oldpins = None self.ss_block = self.es_block = None From 51acdf0d8491091fdb6bfbac5de0e4834def4b39 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 29 Mar 2020 16:17:23 -0500 Subject: [PATCH 3/4] Add initial firmware cycle decode support --- libsigrokdecode4DSL/decoders/lpc/pd.py | 135 +++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 6 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/libsigrokdecode4DSL/decoders/lpc/pd.py index 49ccb96f..21310e64 100755 --- a/libsigrokdecode4DSL/decoders/lpc/pd.py +++ b/libsigrokdecode4DSL/decoders/lpc/pd.py @@ -212,6 +212,13 @@ class Decoder(srd.Decoder): if (self.oldlad == 0b0000 or self.oldlad == 0b0101): self.start_field = self.oldlad self.state = 'GET CT/DR' + elif (self.oldlad == 0b1101 or self.oldlad == 0b1110): + self.start_field = self.oldlad + if (self.oldlad == 0b1110): + self.direction = True + else: + self.direction = False + self.state = 'GET FW IDSEL' else: self.state = 'IDLE' @@ -233,6 +240,58 @@ class Decoder(srd.Decoder): self.addr = 0 self.cur_nibble = 0 + def handle_get_fw_idsel(self): + # LAD[3:0]: IDSEL field (1 clock cycle). + self.es_block = self.samplenum + s = 'IDSEL: 0x%%0%dx' % self.oldlad + self.putb([3, [s % self.oldlad]]) + self.ss_block = self.samplenum + + self.state = 'GET FW ADDR' + self.addr = 0 + self.cur_nibble = 0 + + def handle_get_fw_addr(self): + # LAD[3:0]: ADDR field (7 clock cycles). + addr_nibbles = 7 # Address is 28bits. + + # Addresses are driven MSN-first. + offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 + if (offset < 0): + self.putb([0, ['Warning: Invalid address shift: %d' % offset]]) + self.state = 'IDLE' + return + self.addr |= (self.oldlad << offset) + + # Continue if we haven't seen all ADDR cycles, yet. + if (self.cur_nibble < addr_nibbles - 1): + self.cur_nibble += 1 + return + + self.es_block = self.samplenum + s = 'Address: 0x%%0%dx' % addr_nibbles + self.putb([3, [s % self.addr]]) + self.ss_block = self.samplenum + + self.state = 'GET FW MSIZE' + + def handle_get_fw_msize(self): + # LAD[3:0]: MSIZE field (1 clock cycle). + self.es_block = self.samplenum + s = 'MSIZE: 0x%%0%dx' % self.oldlad + self.putb([3, [s % self.oldlad]]) + self.ss_block = self.samplenum + self.msize = self.oldlad + + if self.direction == 1: + self.state = 'GET FW DATA' + self.cycle_count = 0 + self.dataword = 0 + self.cur_nibble = 0 + else: + self.state = 'GET TAR' + self.tar_count = 0 + def handle_get_addr(self): # LAD[3:0]: ADDR field (4/8/0 clock cycles). @@ -247,6 +306,10 @@ class Decoder(srd.Decoder): # Addresses are driven MSN-first. offset = ((addr_nibbles - 1) - self.cur_nibble) * 4 + if (offset < 0): + self.putb([0, ['Warning: Invalid address shift: %d' % offset]]) + self.state = 'IDLE' + return self.addr |= (self.oldlad << offset) # Continue if we haven't seen all ADDR cycles, yet. @@ -305,11 +368,17 @@ class Decoder(srd.Decoder): self.ss_block = self.samplenum # TODO - self.cycle_count = 0 - if (lframe == 0): - self.state = 'GET TIMEOUT' - else: - self.state = 'GET DATA' + if (self.cycle_type != 'Short wait' and self.cycle_type != 'Long wait'): + self.cycle_count = 0 + if (lframe == 0): + self.state = 'GET TIMEOUT' + elif (self.start_field == 0b1101 or self.start_field == 0b1110): + self.state = 'GET FW DATA' + self.cycle_count = 0 + self.dataword = 0 + self.cur_nibble = 0 + else: + self.state = 'GET DATA' def handle_get_timeout(self): # LFRAME#: tie low (4 clock cycles). @@ -330,6 +399,50 @@ class Decoder(srd.Decoder): self.timeoutcount = 0 self.state = 'IDLE' + + def handle_get_fw_data(self): + # LAD[3:0]: DATA field + if (self.msize == 0b0000): + data_nibbles = 2 # Data is 8bits. + elif (self.msize == 0b0001): + data_nibbles = 4 # Data is 16bits. + elif (self.msize == 0b0010): + data_nibbles = 8 # Data is 32bits. + elif (self.msize == 0b0100): + data_nibbles = 32 # Data is 128bits. + elif (self.msize == 0b0111): + data_nibbles = 256 # Data is 1024bits. + else: + self.putb([0, ['Warning: Invalid MSIZE: %d' % self.msize]]) + self.state = 'IDLE' + return + + # Data is driven LSN-first. + nibble_swap = self.cur_nibble % 2 + offset = ((data_nibbles - 1) - self.cur_nibble) * 4 + if (nibble_swap): + offset += 4 + else: + offset -= 4 + if (offset < 0): + self.putb([0, ['Warning: Invalid data shift: %d' % offset]]) + self.state = 'IDLE' + return + self.dataword |= (self.oldlad << offset) + + # Continue if we haven't seen all DATA cycles, yet. + if (self.cur_nibble < data_nibbles - 1): + self.cur_nibble += 1 + return + + self.es_block = self.samplenum + s = 'DATA: 0x%%0%dx' % data_nibbles + self.putb([3, [s % self.dataword]]) + self.ss_block = self.samplenum + + self.cycle_count = 0 + self.state = 'GET TAR2' + def handle_get_data(self): # LAD[3:0]: DATA field (2 clock cycles). @@ -339,7 +452,9 @@ class Decoder(srd.Decoder): elif (self.cycle_count == 1): self.databyte |= (self.oldlad << 4) else: - raise Exception('Invalid cycle_count: %d' % self.cycle_count) + self.putb([0, ['Warning: Invalid cycle_count: %d' % self.cycle_count]]) + self.state = 'IDLE' + return if (self.cycle_count != 1): self.cycle_count += 1 @@ -404,12 +519,20 @@ class Decoder(srd.Decoder): self.handle_get_ct_dr() elif self.state == 'GET ADDR': self.handle_get_addr() + elif self.state == 'GET FW IDSEL': + self.handle_get_fw_idsel() + elif self.state == 'GET FW ADDR': + self.handle_get_fw_addr() + elif self.state == 'GET FW MSIZE': + self.handle_get_fw_msize() elif self.state == 'GET TAR': self.handle_get_tar() elif self.state == 'GET SYNC': self.handle_get_sync(lframe) elif self.state == 'GET TIMEOUT': self.handle_get_timeout() + elif self.state == 'GET FW DATA': + self.handle_get_fw_data() elif self.state == 'GET DATA': self.handle_get_data() elif self.state == 'GET TAR2': From 14a7c1d6bbc18543d0c21c888b0693478e14aba9 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 5 Apr 2020 22:31:25 -0500 Subject: [PATCH 4/4] Correctly detect LPC timeouts / aborts LPC timeouts and aborts can occur anywhere and at any time during or after a cycle, not just during the SYNC/TAR periods. --- libsigrokdecode4DSL/decoders/lpc/pd.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsigrokdecode4DSL/decoders/lpc/pd.py b/libsigrokdecode4DSL/decoders/lpc/pd.py index 21310e64..6ae13f4a 100755 --- a/libsigrokdecode4DSL/decoders/lpc/pd.py +++ b/libsigrokdecode4DSL/decoders/lpc/pd.py @@ -504,6 +504,10 @@ class Decoder(srd.Decoder): # TODO: Only memory read/write is currently supported/tested. + # Detect host cycle abort requests + if (lframe == 0) and (self.oldlframe == 0): + self.state = 'GET TIMEOUT' + # State machine if self.state == 'IDLE': # A valid LPC cycle starts with LFRAME# being asserted (low).