mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-23 13:42:55 +08:00
Merge pull request #314 from madscientist159/master
Add initial FSI protocol decoder
This commit is contained in:
commit
dde9e64ccd
25
libsigrokdecode4DSL/decoders/fsi/__init__.py
Executable file
25
libsigrokdecode4DSL/decoders/fsi/__init__.py
Executable file
@ -0,0 +1,25 @@
|
||||
##
|
||||
## This file is part of the libsigrokdecode project.
|
||||
##
|
||||
## Copyright (C) 2020 Raptor Engineering, LLC <support@raptorengineering.com>
|
||||
##
|
||||
## This program is free software: you can redistribute it and/or modify
|
||||
## it under the terms of the GNU Affero General Public License as
|
||||
## published by the Free Software Foundation, either version 3 of the
|
||||
## License, or (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU Affero General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Affero General Public License
|
||||
## along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
'''
|
||||
FSI is a low level serial protocol used by various devices on OpenPOWER
|
||||
systems such as the Raptor Talos II and Blackbird.
|
||||
'''
|
||||
|
||||
from .pd import Decoder
|
574
libsigrokdecode4DSL/decoders/fsi/pd.py
Executable file
574
libsigrokdecode4DSL/decoders/fsi/pd.py
Executable file
@ -0,0 +1,574 @@
|
||||
##
|
||||
## This file is part of the libsigrokdecode project.
|
||||
##
|
||||
## Copyright (C) 2020 Raptor Engineering, LLC <support@raptorengineering.com>
|
||||
##
|
||||
## This program is free software: you can redistribute it and/or modify
|
||||
## it under the terms of the GNU Affero General Public License as
|
||||
## published by the Free Software Foundation, either version 3 of the
|
||||
## License, or (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU Affero General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Affero General Public License
|
||||
## along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
import sigrokdecode as srd
|
||||
|
||||
# ...
|
||||
fields = {
|
||||
# START field (indicates the start of a transaction)
|
||||
'START': {
|
||||
0b1: 'Start of FSI cycle',
|
||||
},
|
||||
}
|
||||
|
||||
class Decoder(srd.Decoder):
|
||||
api_version = 3
|
||||
id = 'fsi'
|
||||
name = 'FSI'
|
||||
longname = 'Flexible Service Interface'
|
||||
desc = 'Protocol for FSI devices on Raptor OpenPOWER systems.'
|
||||
license = 'agplv3'
|
||||
inputs = ['logic']
|
||||
outputs = []
|
||||
tags = ['PC']
|
||||
channels = (
|
||||
{'id': 'data', 'name': 'DATA', 'desc': 'Frame'},
|
||||
{'id': 'clock', 'name': 'CLOCK', 'desc': 'Clock'},
|
||||
)
|
||||
annotations = (
|
||||
('warnings', 'Warnings'),
|
||||
('start', 'Start'),
|
||||
('cycle-type', 'Cycle type'),
|
||||
('direction', 'Direction'),
|
||||
('addr', 'Address'),
|
||||
('data', 'Data'),
|
||||
('commands', 'Commands'),
|
||||
('crc', 'CRC'),
|
||||
('turn-around', 'TAR'),
|
||||
)
|
||||
annotation_rows = (
|
||||
('data', 'Data', (1, 2, 3, 4, 5, 6, 7, 8,)),
|
||||
('warnings', 'Warnings', (0,)),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.tar_cycles = 3
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.state = 'IDLE'
|
||||
self.break_start_sample_number = 0
|
||||
self.break_counter = 0
|
||||
self.samplenum = 0
|
||||
self.samplenum_prev = 0
|
||||
self.fsi_data_prev = 0
|
||||
self.fsi_data_break_prev = 0
|
||||
self.crc_internal = 0
|
||||
self.response_received = 0
|
||||
self.crc_calculating = 0
|
||||
self.busy_seq_count = 0
|
||||
self.valid_response = 0
|
||||
self.prev_address = {}
|
||||
self.prev_address_valid = {0: False, 1: False, 2: False, 3: False}
|
||||
self.ss_block = None
|
||||
self.es_block = None
|
||||
|
||||
def start(self):
|
||||
self.out_ann = self.register(srd.OUTPUT_ANN)
|
||||
|
||||
def putb(self, data):
|
||||
self.put(self.ss_block, self.es_block, self.out_ann, data)
|
||||
|
||||
def decode(self):
|
||||
while True:
|
||||
# FSI is clocked out on the falling edge and latched in on the rising edge of the clock...according to the specification.
|
||||
# That said, the specification is not clear on what this actually means (and it doesn't follow industry convention).
|
||||
# Real IBM POWER9 hardware is verified to work in the following mode:
|
||||
# FSI data being sent to the master is latched by the master logic at the falling edge of the FSI clock
|
||||
# FSI data being from to the master is strobed by the master logic at the falling edge of the FSI clock
|
||||
# FSI data being sent to the slave is latched by the slave logic at the rising edge of the FSI clock
|
||||
# FSI data being from to the slave is strobed by the slave logic at the rising edge of the FSI clock
|
||||
#
|
||||
# The above means that we have to be able to make a reasonable guess as to who is transmitting (the master or the slave)
|
||||
# in order to know which edge to sample on
|
||||
|
||||
# Wait for either clock edge
|
||||
(data, clk) = self.wait({1: 'e'})
|
||||
|
||||
# FSI data is electrically inverted
|
||||
fsi_data = not data
|
||||
fsi_clk = clk
|
||||
current_sample_number = self.samplenum
|
||||
|
||||
# Detect BREAK commands
|
||||
# Note these can only be sent by the master, so sample on the rising clock edge only
|
||||
if (fsi_clk):
|
||||
if (self.fsi_data_break_prev == 1):
|
||||
self.break_counter = self.break_counter + 1
|
||||
if (self.break_counter == 256):
|
||||
self.ss_block = self.break_start_sample_number
|
||||
self.es_block = current_sample_number
|
||||
self.putb([6, ['BREAK']])
|
||||
self.state = 'BREAK_TAR_QUEUED'
|
||||
self.busy_seq_count = 0
|
||||
self.valid_response = 0
|
||||
self.prev_address = {}
|
||||
self.prev_address_valid = {0: False, 1: False, 2: False, 3: False}
|
||||
self.ss_block = current_sample_number
|
||||
else:
|
||||
if (self.break_counter > 256):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([0, ['BREAK asserted in excess of specification cycles']])
|
||||
self.break_start_sample_number = current_sample_number
|
||||
self.break_counter = 0
|
||||
self.fsi_data_break_prev = fsi_data
|
||||
|
||||
if ((self.state == 'TAR') or (self.state == 'RX_SLAVE_ID') or (self.state == 'RESPONSE') or (self.state == 'RX_DATA')
|
||||
or (self.state == 'RX_IPOLL_INTERRUPT_FIELD') or (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD') or (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD')
|
||||
or ((self.state == 'CRC') and (self.valid_response))):
|
||||
# Slave is / should be transmitting, sample on falling clock edge only
|
||||
if (fsi_clk):
|
||||
continue
|
||||
else:
|
||||
# Master is / should be transmitting, sample on rising clock edge only
|
||||
if (not fsi_clk):
|
||||
continue
|
||||
|
||||
# Transfer state machine
|
||||
if (self.state == 'IDLE'):
|
||||
self.crc_internal = 0
|
||||
self.response_received = 0
|
||||
if (self.fsi_data_prev == 1):
|
||||
self.tx_slave_id = 0
|
||||
self.data_count = 2
|
||||
self.ss_block = self.samplenum_prev
|
||||
self.es_block = current_sample_number
|
||||
self.putb([1, ['START']])
|
||||
self.ss_block = current_sample_number
|
||||
self.crc_calculating = 1
|
||||
self.state = 'TX_SLAVE_ID'
|
||||
|
||||
elif (self.state == 'TX_SLAVE_ID'):
|
||||
self.crc_calculating = 1
|
||||
if (self.data_count > 0):
|
||||
self.tx_slave_id = (self.tx_slave_id >> 1) | (self.fsi_data_prev << 1)
|
||||
self.data_count = self.data_count - 1
|
||||
if (self.data_count == 0):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([5, ['Slave ID: 0x%01x' % self.tx_slave_id]])
|
||||
self.ss_block = current_sample_number
|
||||
self.command_count = 0
|
||||
self.command_code = 0
|
||||
self.command = None
|
||||
self.valid_command = False
|
||||
self.state = 'COMMAND'
|
||||
|
||||
elif (self.state == 'COMMAND'):
|
||||
self.crc_calculating = 1
|
||||
self.command_code = (self.command_code << 1) | self.fsi_data_prev
|
||||
self.command_count = self.command_count + 1
|
||||
if ((self.command_count == 3) and (self.command_code == 0b100)):
|
||||
self.command = 'ABS_ADR'
|
||||
self.valid_command = True
|
||||
elif ((self.command_count == 3) and (self.command_code == 0b101)):
|
||||
self.command = 'REL_ADR'
|
||||
self.valid_command = True
|
||||
elif ((self.command_count == 2) and (self.command_code == 0b11)):
|
||||
self.command = 'SAME_ADR'
|
||||
self.valid_command = True
|
||||
elif ((self.command_count == 3) and (self.command_code == 0b010)):
|
||||
self.command = 'D_POLL'
|
||||
self.valid_command = True
|
||||
elif ((self.command_count == 3) and (self.command_code == 0b011)):
|
||||
self.command = 'E_POLL'
|
||||
self.valid_command = True
|
||||
elif ((self.command_count == 3) and (self.command_code == 0b001)):
|
||||
self.command = 'I_POLL'
|
||||
self.valid_command = True
|
||||
if ((self.command_count > 7) or (self.valid_command == True)):
|
||||
if (self.command_count == 8):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([6, ['Invalid command code: 0x%02x/%d' % (self.command_code, self.command_count)]])
|
||||
self.putb([0, ['%s' % 'Invalid command code']])
|
||||
self.ss_block = current_sample_number
|
||||
self.state = 'IDLE'
|
||||
else:
|
||||
self.es_block = current_sample_number
|
||||
self.putb([6, ['Command: %s (0x%02x/%d)' % (self.command, self.command_code, self.command_count)]])
|
||||
self.ss_block = current_sample_number
|
||||
if (self.command == 'ABS_ADR'):
|
||||
self.address_length = 21
|
||||
self.address_count = 0
|
||||
self.address = 0
|
||||
self.state = 'DIRECTION'
|
||||
elif (self.command == 'REL_ADR'):
|
||||
self.address_length = 8
|
||||
self.address_count = 0
|
||||
self.address = 0
|
||||
self.state = 'DIRECTION'
|
||||
elif (self.command == 'SAME_ADR'):
|
||||
self.address_length = 2
|
||||
self.address_count = 0
|
||||
self.address = 0
|
||||
self.state = 'DIRECTION'
|
||||
elif (self.command == 'D_POLL'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
elif (self.command == 'E_POLL'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
elif (self.command == 'I_POLL'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
else:
|
||||
self.state = 'IDLE'
|
||||
|
||||
elif (self.state == 'DIRECTION'):
|
||||
self.crc_calculating = 1
|
||||
self.direction = self.fsi_data_prev
|
||||
self.es_block = current_sample_number
|
||||
if (self.direction == 1):
|
||||
self.putb([3, ['Direction: %s' % 'Read']])
|
||||
else:
|
||||
self.putb([3, ['Direction: %s' % 'Write']])
|
||||
self.ss_block = current_sample_number
|
||||
if (self.command == 'REL_ADR'):
|
||||
self.state = 'REL_ADDRESS_SIGN'
|
||||
else:
|
||||
self.state = 'ADDRESS'
|
||||
|
||||
elif (self.state == 'REL_ADDRESS_SIGN'):
|
||||
self.crc_calculating = 1
|
||||
self.relative_address_negative = self.fsi_data_prev
|
||||
self.es_block = current_sample_number
|
||||
if (self.relative_address_negative == 1):
|
||||
self.putb([5, ['Relative address sign: %s' % '(-)']])
|
||||
else:
|
||||
self.putb([5, ['Relative address sign: %s' % '(+)']])
|
||||
self.ss_block = current_sample_number
|
||||
self.state = 'ADDRESS'
|
||||
|
||||
elif (self.state == 'ADDRESS'):
|
||||
self.crc_calculating = 1
|
||||
self.address = (self.address << 1) | self.fsi_data_prev
|
||||
self.address_count = self.address_count + 1
|
||||
if (self.address_count >= self.address_length):
|
||||
self.address_raw = self.address
|
||||
if (self.prev_address_valid[self.tx_slave_id]):
|
||||
if (self.command == 'SAME_ADR'):
|
||||
self.address = (self.prev_address[self.tx_slave_id] & ~0b11) | (self.address_raw & 0b11)
|
||||
elif (self.command == 'REL_ADR'):
|
||||
if (self.relative_address_negative):
|
||||
self.address = self.prev_address[self.tx_slave_id] - (0x100 - self.address_raw)
|
||||
else:
|
||||
self.address = self.prev_address[self.tx_slave_id] + self.address_raw
|
||||
self.es_block = current_sample_number
|
||||
if (((self.command == 'SAME_ADR') or (self.command == 'REL_ADR'))):
|
||||
self.putb([5, ['Address: 0x%06x (0x%03x)' % (self.address, self.address_raw)]])
|
||||
if (not self.prev_address_valid[self.tx_slave_id]):
|
||||
self.putb([0, ['%s' % 'Base address for relative address not captured']])
|
||||
else:
|
||||
self.putb([5, ['Address: 0x%06x' % self.address]])
|
||||
self.ss_block = current_sample_number
|
||||
self.state = 'DATA_SIZE'
|
||||
|
||||
elif (self.state == 'DATA_SIZE'):
|
||||
self.crc_calculating = 1
|
||||
if (self.direction and ((self.address_raw & 3) == 3) and self.fsi_data_prev):
|
||||
# OpenFSI suffers from an unfortunate conflict between the SAME_ADR command
|
||||
# and the TERM command. Both start with 2'b11 and since both are variable
|
||||
# length it is impossible to determine if a TERM command was sent until this
|
||||
# point in the receiver process!
|
||||
#
|
||||
# Set correct command code for further processing
|
||||
self.command_code = 0b111111
|
||||
self.command_count = 6
|
||||
self.command = 'TERM'
|
||||
self.es_block = current_sample_number
|
||||
self.putb([6, ['Command: %s (0x%02x/%d)' % (self.command, self.command_code, self.command_count)]])
|
||||
self.ss_block = current_sample_number
|
||||
self.direction = 0
|
||||
self.busy_seq_count = 0
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
else:
|
||||
if (self.fsi_data_prev == 0):
|
||||
self.data_size = 'BYTE'
|
||||
else:
|
||||
if ((self.address_raw & 3) == 1):
|
||||
self.data_size = 'WORD'
|
||||
# Force lowest address bits to specification-mandated values if required
|
||||
self.address = (self.address & ~3) | 1
|
||||
elif ((self.address_raw & 1) == 0):
|
||||
self.data_size = 'HALF_WORD'
|
||||
# Force lowest address bits to specification-mandated values if required
|
||||
self.address = self.address & ~1
|
||||
else:
|
||||
self.data_size = 'UNKNOWN'
|
||||
self.es_block = current_sample_number
|
||||
if (self.data_size == 'UNKNOWN'):
|
||||
self.putb([0, ['Data Size: %s' % 'UNKNOWN']])
|
||||
self.state = 'IDLE'
|
||||
else:
|
||||
self.putb([3, ['Data Size: %s' % self.data_size]])
|
||||
if (self.direction == 1):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
else:
|
||||
self.data = 0
|
||||
self.data_count = 0
|
||||
if (self.data_size == 'BYTE'):
|
||||
self.data_length = 8
|
||||
elif (self.data_size == 'HALF_WORD'):
|
||||
self.data_length = 16
|
||||
elif (self.data_size == 'WORD'):
|
||||
self.data_length = 32
|
||||
else:
|
||||
self.data_size = None
|
||||
self.state = 'TX_DATA'
|
||||
self.ss_block = current_sample_number
|
||||
|
||||
elif (self.state == 'TX_DATA'):
|
||||
self.crc_calculating = 1
|
||||
self.data = (self.data << 1) | self.fsi_data_prev
|
||||
self.data_count = self.data_count + 1
|
||||
if (self.data_count >= self.data_length):
|
||||
self.es_block = current_sample_number
|
||||
if (self.data_size == 'BYTE'):
|
||||
self.putb([5, ['Data: 0x%02x' % self.data]])
|
||||
elif (self.data_size == 'HALF_WORD'):
|
||||
self.putb([5, ['Data: 0x%04x' % self.data]])
|
||||
else:
|
||||
self.putb([5, ['Data: 0x%08x' % self.data]])
|
||||
self.ss_block = current_sample_number
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
|
||||
elif (self.state == 'CRC'):
|
||||
if (self.crc_count == 0):
|
||||
self.computed_crc_tx_end = self.crc_internal
|
||||
self.crc_calculating = 1
|
||||
self.crc = (self.crc << 1) | self.fsi_data_prev
|
||||
self.crc_count = self.crc_count + 1
|
||||
if (self.crc_count >= 4):
|
||||
self.es_block = current_sample_number
|
||||
if (self.crc == self.computed_crc_tx_end):
|
||||
self.putb([7, ['CRC: 0x%01x (GOOD)' % self.crc]])
|
||||
if (self.response_received):
|
||||
if (((self.command == 'ABS_ADR') or (self.command == 'REL_ADR') or (self.command == 'SAME_ADR'))
|
||||
and ((self.response == 'ACK_D') or (self.response == 'ACK'))):
|
||||
self.prev_address[self.tx_slave_id] = self.address
|
||||
self.prev_address_valid[self.tx_slave_id] = True
|
||||
else:
|
||||
self.putb([7, ['CRC: 0x%01x (BAD)' % self.crc]])
|
||||
self.putb([0, ['%s' % 'Bad CRC']])
|
||||
self.ss_block = current_sample_number
|
||||
self.tar_timer = 0
|
||||
self.state = 'TAR'
|
||||
self.timeout_counter = 0
|
||||
|
||||
elif (self.state == 'BREAK_TAR_QUEUED'):
|
||||
# Special case, since break operates outside of the main state machine
|
||||
# This state is a safe entry point into the main state machine
|
||||
self.tar_timer = 0
|
||||
self.state = 'BREAK_TAR'
|
||||
|
||||
elif (self.state == 'BREAK_TAR'):
|
||||
self.tar_timer = self.tar_timer + 1
|
||||
if (self.tar_timer > self.tar_cycles):
|
||||
self.crc_calculating = 0
|
||||
self.crc_internal = 0
|
||||
self.es_block = current_sample_number
|
||||
self.putb([8, ['%s' % 'TAR']])
|
||||
self.ss_block = current_sample_number
|
||||
self.state = 'IDLE'
|
||||
|
||||
elif (self.state == 'TAR'):
|
||||
self.crc_calculating = 0
|
||||
self.crc_internal = 0
|
||||
self.tar_timer = self.tar_timer + 1
|
||||
if (self.tar_timer > self.tar_cycles):
|
||||
if (self.response_received == 1):
|
||||
self.response_received = 0
|
||||
if (self.rx_slave_id == self.tx_slave_id):
|
||||
if (self.response == 'BUSY'):
|
||||
self.busy_seq_count = self.busy_seq_count + 1
|
||||
else:
|
||||
self.busy_seq_count = 0
|
||||
# Sequence complete
|
||||
self.state = 'IDLE'
|
||||
if (self.timeout_counter == 0):
|
||||
self.es_block = self.samplenum_prev
|
||||
self.putb([8, ['%s' % 'TAR']])
|
||||
self.ss_block = current_sample_number
|
||||
if (self.fsi_data_prev == 1):
|
||||
self.crc_calculating = 1
|
||||
self.rx_slave_id = 0
|
||||
self.data_count = 2
|
||||
if (self.state == 'IDLE'):
|
||||
# Already processed response message, was going to IDLE state
|
||||
self.state = 'TX_SLAVE_ID'
|
||||
else:
|
||||
self.state = 'RX_SLAVE_ID'
|
||||
self.ss_block = self.samplenum_prev
|
||||
self.es_block = current_sample_number
|
||||
self.putb([1, ['START']])
|
||||
self.ss_block = current_sample_number
|
||||
else:
|
||||
self.timeout_counter = self.timeout_counter + 1
|
||||
if (self.timeout_counter >= 256):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([8, ['%s' % 'Response timeout']])
|
||||
self.putb([0, ['%s' % 'Response timeout']])
|
||||
self.state = 'IDLE'
|
||||
|
||||
elif (self.state == 'RX_SLAVE_ID'):
|
||||
self.crc_calculating = 1
|
||||
self.response_received = 1
|
||||
if (self.data_count > 0):
|
||||
self.rx_slave_id = (self.rx_slave_id >> 1) | (self.fsi_data_prev << 1)
|
||||
self.data_count = self.data_count - 1
|
||||
if (self.data_count == 0):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([5, ['Slave ID: 0x%01x' % self.rx_slave_id]])
|
||||
if (self.rx_slave_id != self.tx_slave_id):
|
||||
self.putb([0, ['%s' % 'Slave ID does not match active transaction']])
|
||||
self.ss_block = current_sample_number
|
||||
self.response_count = 0
|
||||
self.response_code = 0
|
||||
self.response = None
|
||||
self.valid_response = False
|
||||
self.state = 'RESPONSE'
|
||||
|
||||
elif (self.state == 'RESPONSE'):
|
||||
self.crc_calculating = 1
|
||||
self.response_code = (self.response_code << 1) | self.fsi_data_prev
|
||||
self.response_count = self.response_count + 1
|
||||
if ((self.command == 'I_POLL') and (self.rx_slave_id == self.tx_slave_id) and (self.response_count == 1) and (self.response_code == 0b0)):
|
||||
self.response = 'I_POLL_RSP'
|
||||
self.valid_response = True
|
||||
elif ((self.response_count == 2) and (self.response_code == 0b00)):
|
||||
if (self.direction == 1):
|
||||
self.response = 'ACK_D'
|
||||
else:
|
||||
self.response = 'ACK'
|
||||
self.valid_response = True
|
||||
elif ((self.response_count == 2) and (self.response_code == 0b01)):
|
||||
self.response = 'BUSY'
|
||||
self.valid_response = True
|
||||
elif ((self.response_count == 2) and (self.response_code == 0b10)):
|
||||
self.response = 'ERR_A'
|
||||
self.valid_response = True
|
||||
elif ((self.response_count == 2) and (self.response_code == 0b11)):
|
||||
self.response = 'ERR_C'
|
||||
self.valid_response = True
|
||||
if ((self.response_count > 2) or (self.valid_response == True)):
|
||||
if (self.response_count == 8):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([6, ['Invalid response code: 0x%02x/%d' % (self.response_code, self.response_count)]])
|
||||
self.putb([0, ['%s' % 'Invalid response code']])
|
||||
self.ss_block = current_sample_number
|
||||
self.state = 'IDLE'
|
||||
else:
|
||||
self.es_block = current_sample_number
|
||||
self.putb([6, ['Response: %s (0x%02x/%d)' % (self.response, self.response_code, self.response_count)]])
|
||||
self.ss_block = current_sample_number
|
||||
if (self.response == 'ACK_D'):
|
||||
self.data = 0
|
||||
self.data_count = 0
|
||||
if (self.data_size == 'BYTE'):
|
||||
self.data_length = 8
|
||||
elif (self.data_size == 'HALF_WORD'):
|
||||
self.data_length = 16
|
||||
elif (self.data_size == 'WORD'):
|
||||
self.data_length = 32
|
||||
else:
|
||||
self.data_size = None
|
||||
#self.state = 'DIRECTION'
|
||||
self.state = 'RX_DATA'
|
||||
elif (self.response == 'ACK'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
elif (self.response == 'BUSY'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
elif (self.response == 'ERR_A'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
elif (self.response == 'ERR_C'):
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
elif (self.response == 'I_POLL_RSP'):
|
||||
self.data = 0
|
||||
self.data_count = 0
|
||||
self.data_length = 2
|
||||
self.state = 'RX_IPOLL_INTERRUPT_FIELD'
|
||||
else:
|
||||
self.state = 'IDLE'
|
||||
|
||||
elif (self.state == 'RX_DATA'):
|
||||
self.crc_calculating = 1
|
||||
self.data = (self.data << 1) | self.fsi_data_prev
|
||||
self.data_count = self.data_count + 1
|
||||
if (self.data_count >= self.data_length):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([5, ['Data: 0x%08x' % self.data]])
|
||||
self.ss_block = current_sample_number
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
|
||||
elif (self.state == 'RX_IPOLL_INTERRUPT_FIELD'):
|
||||
self.crc_calculating = 1
|
||||
self.data = (self.data << 1) | self.fsi_data_prev
|
||||
self.data_count = self.data_count + 1
|
||||
if (self.data_count >= self.data_length):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([5, ['Interrupt Field: 0x%01x' % self.data]])
|
||||
self.ss_block = current_sample_number
|
||||
self.data = 0
|
||||
self.data_count = 0
|
||||
self.data_length = 3
|
||||
self.state = 'RX_IPOLL_DMA_CONTROL_FIELD'
|
||||
|
||||
elif (self.state == 'RX_IPOLL_DMA_CONTROL_FIELD'):
|
||||
self.crc_calculating = 1
|
||||
self.data = (self.data << 1) | self.fsi_data_prev
|
||||
self.data_count = self.data_count + 1
|
||||
if (self.data_count >= self.data_length):
|
||||
self.es_block = current_sample_number
|
||||
self.putb([5, ['DMA Control Field: 0x%01x' % self.data]])
|
||||
self.ss_block = current_sample_number
|
||||
self.crc = 0
|
||||
self.crc_count = 0
|
||||
self.state = 'CRC'
|
||||
|
||||
# CRC calculation
|
||||
# Implement Galios-type LFSR for polynomial 0x7 (MSB first)
|
||||
crc_prev = self.crc_internal
|
||||
if (self.crc_calculating):
|
||||
crc_feedback = (((crc_prev >> 3) & 1) ^ self.fsi_data_prev) & 1
|
||||
if (self.crc_calculating):
|
||||
self.crc_internal = (self.crc_internal & ~(1 << 0)) | ((crc_feedback & 1) << 0)
|
||||
self.crc_internal = (self.crc_internal & ~(1 << 1)) | ((((crc_prev & 1) ^ crc_feedback) & 1) << 1)
|
||||
self.crc_internal = (self.crc_internal & ~(1 << 2)) | (((((crc_prev >> 1) & 1) ^ crc_feedback) & 1) << 2)
|
||||
self.crc_internal = (self.crc_internal & ~(1 << 3)) | ((((crc_prev >> 2) & 1) & 1) << 3)
|
||||
|
||||
self.fsi_data_prev = fsi_data
|
||||
self.samplenum_prev = current_sample_number
|
Loading…
x
Reference in New Issue
Block a user