Decoder Update: QSPI add flash mode

This commit is contained in:
yunyaobaihong 2024-04-15 15:10:05 +08:00
parent 6a6f1c11a8
commit b8b17b6361

View File

@ -1,7 +1,9 @@
###
##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2020 DreamSourceLab <support@dreamsourcelab.com>
## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
## Copyright (C) 2012-2014 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2024 DreamSourceLab <support@dreamsourcelab.com>
##
## 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
@ -19,9 +21,13 @@
import sigrokdecode as srd
from collections import namedtuple
from math import floor, ceil
from enum import Enum
Data = namedtuple('Data', ['ss', 'es', 'val'])
##
## 2023/4/8 DreamSourceLab : add flash module
##
# Key: (CPOL, CPHA). Value: SPI mode.
# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
@ -33,22 +39,155 @@ spi_mode = {
(1, 1): 3, # Mode 3
}
class process_enum(Enum):
COMMAND = 0
WRITE_BYTE = 1
READ_BYTE = 2
READ_BYTE_CONTINUOUS = 3
CONTINUOUS_READ_MODE_BITS = 4
ADDRESS_BY_MODE = 5
ADDRESS_24BIT = 6
ADDRESS_32BIT = 7
DUMMY_BY_MODE = 8
DUMMY_8BIT = 9
DUMMY_32BIT = 10
DUMMY_40BIT = 11
process_text = {
process_enum.COMMAND : ['Command' , 'CMD'] ,
process_enum.WRITE_BYTE : ['Write Data' , 'WD'] ,
process_enum.READ_BYTE : ['Read Data' , 'RD'] ,
process_enum.READ_BYTE_CONTINUOUS : ['Read Data' , 'RD'] ,
process_enum.ADDRESS_24BIT : ['24-Bit Address' , 'AD'] ,
process_enum.ADDRESS_32BIT : ['32-Bit Address' , 'AD'] ,
process_enum.CONTINUOUS_READ_MODE_BITS : ['Continuous Read Mode bits' , 'M'] ,
}
class process_mode(Enum):
SINGLE = 0
DUAL = 1
QUAD = 2
class process_info:
def __init__(self, enum, mode):
self.enum = enum
self.mode = mode
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.enum == other.enum and self.mode == other.mode
return False
#read adressaddress mode、24BIT,32BIT
READ_ADDRESS = process_info(process_enum.ADDRESS_BY_MODE , process_mode.SINGLE)
READ_3B_ADDRESS = process_info(process_enum.ADDRESS_24BIT , process_mode.SINGLE)
READ_4B_ADDRESS = process_info(process_enum.ADDRESS_32BIT , process_mode.SINGLE)
#read DUAL Adress
READ_ADDRESS_DUAL = process_info(process_enum.ADDRESS_BY_MODE , process_mode.DUAL)
READ_3B_ADDRESS_DUAL = process_info(process_enum.ADDRESS_24BIT , process_mode.DUAL)
READ_4B_ADDRESS_DUAL = process_info(process_enum.ADDRESS_32BIT , process_mode.DUAL)
#read QUAD Adress
READ_ADDRESS_QUAD = process_info(process_enum.ADDRESS_BY_MODE , process_mode.QUAD)
READ_3B_ADDRESS_QUAD = process_info(process_enum.ADDRESS_24BIT , process_mode.DUAL)
READ_4B_ADDRESS_QUAD = process_info(process_enum.ADDRESS_32BIT , process_mode.QUAD)
#Read ByteIO1, DUAL,QUAD
READ_BYTE_SINGLE = process_info(process_enum.READ_BYTE , process_mode.SINGLE)
READ_BYTE_DUAL = process_info(process_enum.READ_BYTE , process_mode.DUAL)
READ_BYTE_QUAD = process_info(process_enum.READ_BYTE , process_mode.QUAD)
READ_BYTE_SINGLE_CONTINUOUS = process_info(process_enum.READ_BYTE_CONTINUOUS , process_mode.SINGLE)
READ_BYTE_DUAL_CONTINUOUS = process_info(process_enum.READ_BYTE_CONTINUOUS , process_mode.DUAL)
READ_BYTE_QUAD_CONTINUOUS = process_info(process_enum.READ_BYTE_CONTINUOUS , process_mode.QUAD)
#read m7-m0(DUAL,QUAD)
READ_MODE_BITS_DUAL = process_info(process_enum.CONTINUOUS_READ_MODE_BITS , process_mode.DUAL)
READ_MODE_BITS_QUAD = process_info(process_enum.CONTINUOUS_READ_MODE_BITS , process_mode.QUAD)
#write (io0)
WRITE_BYTE_SINGLE = process_info(process_enum.WRITE_BYTE , process_mode.SINGLE)
#DUMMY
DUMMY_CYCLE = process_info(process_enum.DUMMY_BY_MODE , process_mode.SINGLE)
DUMMY_CYCLE_8BIT = process_info(process_enum.DUMMY_8BIT , process_mode.SINGLE)
DUMMY_CYCLE_8BIT_QUAD = process_info(process_enum.DUMMY_8BIT , process_mode.QUAD)
#Command listcommand、name、abb、data after command
command = {
0x06 : ['Write Enable' , 'WREN' , []],
0x04 : ['Write Disable' , 'WRDI' , []],
0x50 : ['Write Enable for Volatile Status Register' , 'WRENFVSR' , []],
0x05 : ['Read Status Register' , 'RDSR' , [READ_BYTE_SINGLE]],
0x35 : ['Read Status Register' , 'RDSR' , [READ_BYTE_SINGLE]],
0x15 : ['Read Status Register' , 'RDSR' , [READ_BYTE_SINGLE]],
0x01 : ['Write Status Register' , 'WRSR' , [WRITE_BYTE_SINGLE]],
0x31 : ['Write Status Register' , 'WRSR' , [WRITE_BYTE_SINGLE]],
0x11 : ['Write Status Register' , 'WRSR' , [WRITE_BYTE_SINGLE]],
0xC8 : ['Read Extended Register' , 'RER' , [READ_BYTE_SINGLE]],
0xC5 : ['Write Extended Register' , 'WER' , [WRITE_BYTE_SINGLE]],
0x03 : ['Read Data Bytes' , 'READ' , [READ_ADDRESS , READ_BYTE_SINGLE_CONTINUOUS]],
0x13 : ['Read Data Bytes' , '4READ' , [READ_4B_ADDRESS , READ_BYTE_SINGLE_CONTINUOUS]],
0x0B : ['Read Data Bytes at Higher Speed' , 'Fast Read' , [READ_ADDRESS , DUMMY_CYCLE_8BIT , READ_BYTE_SINGLE_CONTINUOUS]],
0x0C : ['Read Data Bytes at Higher Speed' , '4Fast Read', [READ_4B_ADDRESS , DUMMY_CYCLE_8BIT , READ_BYTE_SINGLE_CONTINUOUS]],
0x3B : ['Dual Output Fast Read' , 'DOFR' , [READ_ADDRESS ,DUMMY_CYCLE_8BIT , READ_BYTE_DUAL_CONTINUOUS]],
0x3C : ['Dual Output Fast Read' , '4DOFR' , [READ_4B_ADDRESS ,DUMMY_CYCLE_8BIT , READ_BYTE_DUAL_CONTINUOUS]],
0x6B : ['Quad Output Fast Read' , 'QOFR' , [READ_ADDRESS ,DUMMY_CYCLE_8BIT , READ_BYTE_QUAD_CONTINUOUS]],
0x6C : ['Quad Output Fast Read' , '4QOFR' , [READ_4B_ADDRESS ,DUMMY_CYCLE_8BIT , READ_BYTE_QUAD_CONTINUOUS]],
0xBB : ['Dual I/O Fast Read' , 'DIOFR' , [READ_ADDRESS_DUAL ,READ_MODE_BITS_DUAL , READ_BYTE_DUAL_CONTINUOUS]],
0xBC : ['Dual I/O Fast Read' , '4DIOFR' , [READ_4B_ADDRESS_DUAL , READ_MODE_BITS_DUAL , READ_BYTE_DUAL_CONTINUOUS]],
0xEB : ['Quad I/O Fast Read' , 'QIOFR' , [READ_ADDRESS_QUAD , READ_MODE_BITS_QUAD , DUMMY_CYCLE_8BIT_QUAD , DUMMY_CYCLE_8BIT_QUAD , READ_BYTE_QUAD_CONTINUOUS]],
0xEC : ['Quad I/O Fast Read' , '4QIOFR' , [READ_4B_ADDRESS_QUAD , READ_MODE_BITS_QUAD , DUMMY_CYCLE_8BIT_QUAD , DUMMY_CYCLE_8BIT_QUAD , READ_BYTE_QUAD_CONTINUOUS]],
0x77 : ['Set Burst with Wrap' , 'SBWW' , [DUMMY_CYCLE_8BIT_QUAD , DUMMY_CYCLE_8BIT_QUAD , DUMMY_CYCLE_8BIT_QUAD , READ_BYTE_QUAD_CONTINUOUS]],
0x02 : ['Page Program' , 'PP' , [READ_ADDRESS] + [WRITE_BYTE_SINGLE] * 256],
0x12 : ['Page Program' , '4PP' , [READ_4B_ADDRESS] + [WRITE_BYTE_SINGLE] * 256],
0x32 : ['Quad Page Program' , 'QPP' , [READ_ADDRESS] + [READ_BYTE_QUAD_CONTINUOUS]],
0x34 : ['Quad Page Program' , '4QPP' , [READ_4B_ADDRESS] + [READ_BYTE_QUAD_CONTINUOUS]],
0x20 : ['Sector Erase' , 'SE' , [READ_ADDRESS]],
0x21 : ['Sector Erase' , '4SE', [READ_4B_ADDRESS]],
0x52 : ['32KB Block Erase' , 'BE32' , [READ_ADDRESS]],
0x5C : ['32KB Block Erase' , '4BE32' , [READ_4B_ADDRESS]],
0xD8 : ['64KB Block Erase' , 'BE64', [READ_ADDRESS]],
0xDC : ['64KB Block Erase' , '4BE64', [READ_4B_ADDRESS]],
0x60 : ['Chip Erase' , 'CE' , []],
0xC7 : ['Chip Erase' , 'CE' , []],
0xB9 : ['Deep Power-Down' , 'DP' , []],
0x4B : ['Read Unique ID' , 'RUID', [DUMMY_CYCLE , READ_BYTE_SINGLE_CONTINUOUS]],
0xB7 : ['Enter 4-Byte Address Mode' , 'EN4BADM' , []],
0xE9 : ['Exit 4-Byte Address Mode' , 'EX4BADM' , []],
0x30 : ['Clear SR Flags' , 'CLSRF' , []],
0xAB : ['Release from Deep Power-Down and Read Device ID' , 'RDI' , []],
0x90 : ['Read Manufacture ID/ Device ID' , 'REMS' , [READ_3B_ADDRESS , READ_BYTE_SINGLE , READ_BYTE_SINGLE]],
0x92 : ['Read Manufacture ID/ Device ID Dual I/O' , 'REMS' , [READ_3B_ADDRESS_DUAL , READ_MODE_BITS_DUAL ,READ_BYTE_DUAL_CONTINUOUS]],
0x94 : ['Read Manufacture ID/ Device ID Quad I/O' , 'REMS' , [READ_3B_ADDRESS_QUAD , READ_MODE_BITS_QUAD , DUMMY_CYCLE_8BIT_QUAD , DUMMY_CYCLE_8BIT_QUAD , READ_BYTE_QUAD_CONTINUOUS]],
0x9F : ['Read Identification' , 'RDID', [READ_BYTE_SINGLE_CONTINUOUS]],
0x75 : ['Program/Erase Suspend' , 'PES' , []],
0x7A : ['Program/Erase Resume' , 'PER' , []],
0x44 : ['Erase Security Registers' , 'ESR' , [READ_ADDRESS]],
0x42 : ['Program Security Registers' , 'PSR' , [READ_ADDRESS] + [WRITE_BYTE_SINGLE] * 256],
0x48 : ['Read Security Registers' , 'RSR' , [READ_ADDRESS , DUMMY_CYCLE_8BIT , READ_BYTE_SINGLE_CONTINUOUS]],
0x66 : ['Enable Reset' , 'ENRE' , []],
0x99 : ['Reset' , 'RE' , []],
0x5A : ['Read Serial Flash Discoverable Parameter' , 'RSFDP', [READ_3B_ADDRESS , DUMMY_CYCLE_8BIT , READ_BYTE_SINGLE_CONTINUOUS]],
}
class ChannelError(Exception):
pass
class Decoder(srd.Decoder):
api_version = 3
id = 'qspi'
name = 'QSPI'
id = 'smart_qspi'
name = 'Smart QSPI'
longname = 'Quad Serial Peripheral Interface'
desc = 'Full-duplex, synchronous, serial bus.'
desc = 'Full-duplex, synchronous, serial bus.compatible with Dual SPI and Quad SPI interfaces.'
license = 'gplv2+'
inputs = ['logic']
outputs = ['spi']
tags = ['Embedded/industrial']
channels = (
{'id': 'clk', 'type': 0, 'name': 'CLK', 'desc': 'Clock', 'idn':'dec_qspi_chan_clk'},
{'id': 'io0', 'type': 107, 'name': 'IO0', 'desc': 'Data i/o 0', 'idn':'dec_qspi_chan_io0'},
{'id': 'io0', 'type': 109, 'name': 'IO0', 'desc': 'Data i/o 0', 'idn':'dec_qspi_chan_io0'},
)
optional_channels = (
{'id': 'io1', 'type': 107, 'name': 'IO1', 'desc': 'Data i/o 1', 'idn':'dec_qspi_opt_chan_io1'},
@ -65,13 +204,35 @@ class Decoder(srd.Decoder):
'values': (0, 1), 'idn':'dec_qspi_opt_cpha'},
{'id': 'bitorder', 'desc': 'Bit order',
'default': 'msb-first', 'values': ('msb-first', 'lsb-first'), 'idn':'dec_qspi_opt_bitorder'},
{'id': 'wordsize', 'desc': 'Word size', 'default': 8, 'idn':'dec_qspi_opt_wordsize'},
{'id': 'ads', 'desc': 'Adress Mode', 'default': '24-Bit Address',
'values': ('32-Bit Address', '24-Bit Address'), 'idn':'dec_qspi_adress_mode'},
{'id': 'frame', 'desc': 'Frame Decoder', 'default': 'no',
'values': ('yes', 'no'), 'idn':'dec_qspi_opt_frame'},
{'id': 'twolinesmode', 'desc': 'TwoLinesMode', 'default':'spi',
'values':('spi','dspi','qspi'), 'idn':'dec_qspi_two_lines_mode'},
{'id': 'invalidlevel', 'desc': 'Keep high or low as invalid', 'default':'both',
'values':('both','low','high'), 'idn':'dec_qspi_invalidlevel'},
)
annotations = (
('106', 'data', 'data'),
('6', 'data-transfer', 'data transfer'),
('108', 'Quad data', 'Q-Data'),
('108', 'Dual data', 'D-Data'),
('106', 'd0', 'IO0 data'),
('106', 'd1', 'IO1 data'),
('106', 'd2', 'IO2 data'),
('106', 'd3', 'IO3 data'),
('1000', 'other', 'Human-readable warnings'),
)
annotation_rows = (
('data', 'data', (0,)),
('data-transfer', 'data transfer', (0,)),
('Quad data', 'Q-Data', (1,)),
('Dual data', 'D-Data', (2,)),
('d0', 'D0', (3,)),
('d1', 'D1', (4,)),
('d2', 'D2', (5,)),
('d3', 'D3', (6,)),
('Other', 'Other',(7,)),
)
def __init__(self):
@ -82,6 +243,29 @@ class Decoder(srd.Decoder):
self.bitcount = 0
self.data = 0
self.bits = []
self.io0bits=[]
self.io1bits=[]
self.io2bits=[]
self.io3bits=[]
self.io0bytes=[]
self.io1bytes=[]
self.io2bytes=[]
self.io3bytes=[]
self.io0data=0
self.io1data=0
self.io2data=0
self.io3data=0
self.command = 0
self.state_count = 0
self.ads = False
self.diagram = []
self.ss = 0
self.count = 0
self.bits_data = 0
self.ss_block = -1
self.samplenum = -1
self.ss_transfer = -1
@ -89,93 +273,332 @@ class Decoder(srd.Decoder):
self.have_cs = self.have_io1 = self.have_io3 = None
def start(self):
self.out_python = self.register(srd.OUTPUT_PYTHON)
self.out_ann = self.register(srd.OUTPUT_ANN)
self.bw = (self.options['wordsize'] + 7) // 8
self.out_binary = self.register(srd.OUTPUT_BINARY)
self.out_bitrate = self.register(srd.OUTPUT_META,
meta=(int, 'Bitrate', 'Bitrate during transfers'))
self.bw = (8 + 7) // 8
self.spiModeSet=self.options['twolinesmode'].lower()
self.invalidlevelSet = 0XFF if self.options['invalidlevel'] == 'high' else 0
self.ads = False if self.options['ads'] == '24-Bit Address' else True
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
self.samplerate = value
self.bit_width = float(self.samplerate) / float(115200)
def putw(self, data):
self.put(self.ss_block, self.samplenum, self.out_ann, data)
def putdata(self):
# Pass bits and then data to the next PD up the stack.
ss, es = self.bits[-1][1], self.bits[0][2]
def putgse(self, ss, es, data):
self.put(ss, es, self.out_ann, data)
# Dataword annotations.
self.put(ss, es, self.out_ann, [0, ['%02X' % self.data]])
def putg(self, data):
s, halfbit = self.samplenum, self.bit_width / 2.0
self.put(s - floor(halfbit), s + ceil(halfbit), self.out_ann, data)
def puttext(self, ss, es, state, data):
self.put(ss, es, self.out_ann, [0, ['%s : 0x%02x' % (process_text[state][0] , data),
'%s : 0x%02x' % (process_text[state][1] , data),
'0x%02X' % data]])
def putdummy(self, ss, es):
self.put(ss, es, self.out_ann, [0, ['Dummy Cycles','Dummy','D']])
def putcmd(self, ss, es):
self.put(ss, es, self.out_ann, [0, ['%s : %s' % (process_text[process_enum.COMMAND][0] , command[self.io0data][0]),
'%s : %s' % (process_text[process_enum.COMMAND][1] , command[self.io0data][1]),
'%s' % command[self.io0data][1]]])
def checkinvalidlevel(self,data): # if data line is keep high or keep low,data is invalid then return true
if self.options['invalidlevel']=='both' :
return data==0xff or data ==0
elif self.options['invalidlevel']=='high':
return data==0xff
else :
return data==0
def putdata(self, frame):
data0 = self.io0data
data1 = self.io1data
data2 = self.io2data if self.have_io3 else None
data3 = self.io3data if self.have_io3 else None
ss,es = self.io0bits[-1][1], self.io0bits[0][2]
if frame:
if self.have_io3:
self.io2bytes.append(Data(ss = ss, es = es, val = data2))
self.io3bytes.append(Data(ss = ss, es = es, val = data3))
if self.have_io1:
self.io1bytes.append(Data(ss = ss, es = es, val = data1))
self.io0bytes.append(Data(ss = ss, es = es, val = data0))
bo = self.options['bitorder']
if(((self.checkinvalidlevel(data2) or self.checkinvalidlevel(data3)) and self.have_io3) or (self.checkinvalidlevel(data1) and self.have_io1)):
spiMode = self.spiModeSet
elif self.have_io3:
spiMode='qspi'
else :
spiMode='spi'
self.putgse(ss,es,[7, ['%s' %spiMode.upper()]])
self.put(ss, es, self.out_ann, [3, ['@%02X' % self.io0data]])
if self.have_io1:
self.put(ss, es, self.out_ann, [4, ['@%02X' % self.io1data]])
if self.have_io3:
self.put(ss, es, self.out_ann, [5, ['@%02X' % self.io2data]])
self.put(ss, es, self.out_ann, [6, ['@%02X' % self.io3data]])
if spiMode == 'qspi' or spiMode == 'dspi':
qdata = []
ddata = []
if self.have_io1 and self.have_io3:
for i in range(4):
self.data = 0
for j in range(2):
self.data |= self.io3bits[-1 - i * 2 - j][0]
self.data = self.data << 1
self.data |= self.io2bits[-1 - i * 2 - j][0]
self.data = self.data << 1
self.data |= self.io1bits[-1 - i * 2 - j][0]
self.data = self.data << 1
self.data |= self.io0bits[-1 - i * 2 - j][0]
if j < 1:
self.data = self.data << 1
qss,qes = self.io0bits[-1 - i * 2][1], self.io0bits[-2 - i * 2][2]
if not bo == 'msb-first':
dataTemp = (0xF0 & self.data) >> 4|(0x0f & self.data) << 4
self.data = dataTemp
qdata.append([self.data, qss, qes])
self.put(qss, qes, self.out_ann, [1, ['@%02X' % self.data]])
if self.have_io1:
for i in range(2):
self.data = 0
for j in range(4):
self.data |= self.io1bits[-1 - i * 4 - j][0]
self.data = self.data << 1
self.data |= self.io0bits[-1 - i * 4 - j][0]
if j < 3:
self.data = self.data << 1
dss,des = self.io0bits[-1 - i * 4][1], self.io0bits[-4 - i * 4][2]
if not bo == 'msb-first':
dataTemp = (0xF0 & self.data) >> 4|(0x0f & self.data) << 4
self.data = dataTemp
ddata.append([self.data, dss, des])
self.put(dss, des, self.out_ann, [2, ['@%02X' % self.data]])
if self.command == 0 and self.io0data in command:
self.putcmd(ss, es)
#update adress mode
if self.io0data == 0xB7:
self.ads = True
elif self.io0data == 0xE9:
self.ads = False
if len(command[self.io0data][2]) != 0:
self.command = self.io0data
self.diagram = command[self.command][2]
elif self.command != 0:
cur_state = self.diagram[self.state_count]
i, size = 0, 1
if cur_state.mode == process_mode.DUAL:
size = 2
elif cur_state.mode == process_mode.QUAD:
size = 4
while i < size:
if size == 1:
if cur_state.enum == process_enum.READ_BYTE and self.have_io1:
origin_data = [self.io1data & 0xFF , ss, es]
else:
origin_data = [self.io0data & 0xFF , ss, es]
elif size == 2:
origin_data = ddata[i]
origin_data[0] = origin_data[0] & 0xFF
elif size == 4:
origin_data = qdata[i]
origin_data[0] = origin_data[0] & 0xFF
i = i + 1
if cur_state.enum == process_enum.ADDRESS_BY_MODE or \
cur_state.enum == process_enum.ADDRESS_24BIT or \
cur_state.enum == process_enum.ADDRESS_32BIT or \
cur_state.enum == process_enum.DUMMY_BY_MODE or \
cur_state.enum == process_enum.DUMMY_8BIT:
if cur_state.enum == process_enum.ADDRESS_BY_MODE:
cur_state.enum = process_enum.ADDRESS_24BIT if self.ads == False else process_enum.ADDRESS_32BIT
elif cur_state.enum == process_enum.DUMMY_BY_MODE:
cur_state.enum = process_enum.DUMMY_32BIT if self.ads == False else process_enum.DUMMY_40BIT
if self.count == 0:
self.ss = ss
self.bits_data |= origin_data[0]
self.count = self.count + 1
if (cur_state.enum == process_enum.ADDRESS_24BIT and self.count == 3) or \
(cur_state.enum == process_enum.ADDRESS_32BIT and self.count == 4) or \
(cur_state.enum == process_enum.DUMMY_8BIT and self.count == 1) or \
(cur_state.enum == process_enum.DUMMY_32BIT and self.count == 4) or \
(cur_state.enum == process_enum.DUMMY_40BIT and self.count == 5):
if cur_state.enum == process_enum.ADDRESS_24BIT or \
cur_state.enum == process_enum.ADDRESS_32BIT:
self.puttext(self.ss , origin_data[2] , cur_state.enum , self.bits_data)
else:
self.putdummy(self.ss, origin_data[2])
self.ss = 0
self.count = 0
self.bits_data = 0
self.state_count += 1
if self.state_count < len(self.diagram):
cur_state = self.diagram[self.state_count]
else:
self.bits_data = self.bits_data << 8
elif cur_state.enum == process_enum.WRITE_BYTE or \
cur_state.enum == process_enum.READ_BYTE or \
cur_state.enum == process_enum.READ_BYTE_CONTINUOUS or \
cur_state.enum == process_enum.CONTINUOUS_READ_MODE_BITS:
self.puttext(origin_data[1] , origin_data[2] , cur_state.enum , origin_data[0])
if cur_state.enum != process_enum.READ_BYTE_CONTINUOUS:
self.state_count += 1
if self.state_count < len(self.diagram):
cur_state = self.diagram[self.state_count]
if self.state_count >= len(self.diagram):
self.command = 0
self.diagram = []
self.state_count = 0
break
def reset_decoder_state(self):
self.data = 0
self.bits = []
self.io0data = 0
self.io1data = 0 if self.have_io1 else None
self.io2data=0 if self.have_io3 else None
self.io3data=0 if self.have_io3 else None
self.io0bits=[]
self.io1bits=[] if self.have_io1 else None
self.io2bits=[] if self.have_io3 else None
self.io3bits=[] if self.have_io3 else None
self.bitcount = 0
def cs_asserted(self, cs):
active_low = (self.options['cs_polarity'] == 'active-low')
return (cs == 0) if active_low else (cs == 1)
def handle_bit(self, datapins, clk, cs):
def handle_bit(self, datapins, clk, cs, frame):
# If this is the first bit of a dataword, save its sample number.
if self.bitcount == 0:
self.ss_block = self.samplenum
self.cs_was_deasserted = \
not self.cs_asserted(cs) if self.have_cs else False
ws = 8
bo = self.options['bitorder']
ws = self.options['wordsize']
if self.have_io3:
nibws = ws >> 2
elif self.have_io1:
nibws = ws >> 1
else:
nibws = ws
# Receive bit into our shift register.
if self.have_io3:
for i in range(4):
if bo == 'msb-first':
self.data |= datapins[i] << (ws - 1 - self.bitcount*4 - i)
else:
self.data |= datapins[3-i] << (self.bitcount*4 + i)
elif self.have_io1:
for i in range(2):
if bo == 'msb-first':
self.data |= datapins[i+2] << (ws - 1 - self.bitcount*2 - i)
else:
self.data |= datapins[3-i] << (self.bitcount*2 + i)
if bo == 'msb-first':
self.io0data |= datapins[3] << (ws - 1 - self.bitcount)
else:
self.io0data |= datapins[3] << self.bitcount
if self.have_io1:
if bo == 'msb-first':
self.data |= datapins[3] << (ws - 1 - self.bitcount)
self.io1data |= datapins[2] << (ws - 1 - self.bitcount)
else:
self.data |= datapins[3] << self.bitcount
self.io1data |= datapins[2] << self.bitcount
if self.have_io3:
if bo == 'msb-first':
self.io2data |= datapins[1] << (ws - 1 - self.bitcount)
self.io3data |= datapins[0] << (ws - 1 - self.bitcount)
else:
self.io2data |= datapins[1] << self.bitcount
self.io3data |= datapins[0] << self.bitcount
# Guesstimate the endsample for this bit (can be overridden below).
es = self.samplenum
if self.bitcount > 0:
es += self.samplenum - self.bits[0][1]
es += self.samplenum - self.io0bits[0][1]
self.bits.insert(0, [datapins[3], self.samplenum, es])
self.io0bits.insert(0, [datapins[3], self.samplenum, es])
if self.have_io1:
self.io1bits.insert(0, [datapins[2], self.samplenum, es])
if self.have_io3:
self.io2bits.insert(0, [datapins[1], self.samplenum, es])
self.io3bits.insert(0, [datapins[0], self.samplenum, es])
if self.bitcount > 0:
self.bits[1][2] = self.samplenum
self.io0bits[1][2] = self.samplenum
if self.have_io1:
self.io1bits[1][2] = self.samplenum
if self.have_io3:
self.io2bits[1][2] = self.samplenum
self.io3bits[1][2] = self.samplenum
self.bitcount += 1
# Continue to receive if not enough bits were received, yet.
if self.bitcount != nibws:
if self.bitcount != ws:
return
self.putdata()
self.putdata(frame)
if self.samplerate:
elapsed = 1 / float(self.samplerate)
elapsed *= (self.samplenum - self.ss_block + 1)
bitrate = int(1 / elapsed * ws)
self.put(self.ss_block, self.samplenum, self.out_bitrate, bitrate)
if self.have_cs and self.cs_was_deasserted:
self.putw([6, ['CS# was deasserted during this data word!']])
self.reset_decoder_state()
def find_clk_edge(self, datapins, clk, cs, first):
def find_clk_edge(self, datapins, clk, cs, first,frame):
if self.have_cs and (first or (self.matched & (0b1 << self.have_cs))):
# Send all CS# pin value changes.
oldcs = None if first else 1 - cs
self.put(self.samplenum, self.samplenum, self.out_python,
['CS-CHANGE', oldcs, cs])
if frame:
if self.cs_asserted(cs):
self.ss_transfer = self.samplenum
self.io0bytes = []
self.io1bytes = []
self.io2bytes = []
self.io3bytes = []
elif self.ss_transfer != -1:
self.put(self.ss_transfer, self.samplenum, self.out_python,
['TRANSFER', self.io0bytes, self.io1bytes, self.io2bytes,self.io3bytes])
# Reset decoder state when CS# changes (and the CS# pin is used).
self.command = 0
self.diagram = []
self.state_count = 0
self.ss = 0
self.count = 0
self.bits_data = 0
self.reset_decoder_state()
# We only care about samples if CS# is asserted.
@ -187,17 +610,25 @@ class Decoder(srd.Decoder):
return
# Found the correct clock edge, now get the SPI bit(s).
self.handle_bit(datapins, clk, cs)
self.handle_bit(datapins, clk, cs,frame)
def decode(self):
# The CLK & IO0 input is mandatory. Other signals are (individually)
# optional. Tell stacked decoders when we don't have a CS# signal.
if not self.has_channel(0):
raise ChannelError('CLK pin required.')
if not self.has_channel(1):
raise ChannelError('io0 pin required.')
self.have_io1 = self.has_channel(2)
self.have_io3 = self.has_channel(3) & self.has_channel(4)
self.have_cs = self.has_channel(5)
if not self.have_cs:
self.put(0, 0, self.out_python, ['CS-CHANGE', None, None])
frame = self.options['frame'] == 'yes'
# We want all CLK changes. We want all CS changes if CS is used.
# Map 'have_cs' from boolean to an integer index. This simplifies
# evaluation in other locations.
@ -217,10 +648,12 @@ class Decoder(srd.Decoder):
# previous implementation did this by seeding old values with
# None, which led to an immediate "change" in comparison.
(clk, d0, d1, d2, d3, cs) = self.wait({})
d = (d3, d2, d1, d0);
self.find_clk_edge(d, clk, cs, True)
d = (d3, d2, d1, d0)
self.find_clk_edge(d, clk, cs, True ,frame)
while True:
(clk, d0, d1, d2, d3, cs) = self.wait(wait_cond)
d = (d3, d2, d1, d0);
self.find_clk_edge(d, clk, cs, False)#
d = (d3, d2, d1, d0)
self.find_clk_edge(d, clk, cs, False,frame)#