mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-13 13:32:53 +08:00
575 lines
28 KiB
Python
575 lines
28 KiB
Python
|
##
|
||
|
## 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
|