mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-13 13:32:53 +08:00
1de76d1e05
The FSI protocol is used on OpenPOWER systems such as the Raptor Computing Systems Talos II and Blackbird machines.
575 lines
28 KiB
Python
Executable File
575 lines
28 KiB
Python
Executable File
##
|
|
## 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
|