added i80 decoder draft
This commit is contained in:
22
i80/__init__.py
Normal file
22
i80/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
##
|
||||||
|
## Copyright (C) 2024 Timo Schneider
|
||||||
|
##
|
||||||
|
## 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
|
||||||
|
## the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
'''
|
||||||
|
This protocol decoder can decode an i80 bus.
|
||||||
|
'''
|
||||||
|
|
||||||
|
from .pd import Decoder
|
||||||
211
i80/pd.py
Normal file
211
i80/pd.py
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
##
|
||||||
|
## This file is part of the libsigrokdecode project.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2013-2016 Uwe Hermann <uwe@hermann-uwe.de>
|
||||||
|
##
|
||||||
|
## 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
|
||||||
|
## the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
import sigrokdecode as srd
|
||||||
|
from common.srdhelper import bitpack
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
NUM_CHANNELS = 32
|
||||||
|
|
||||||
|
class Decoder(srd.Decoder):
|
||||||
|
api_version = 3
|
||||||
|
id = 'i80'
|
||||||
|
name = 'Intel 8080'
|
||||||
|
longname = 'Intel 8080 like bus'
|
||||||
|
desc = 'Parallel asynchronous 8/16 bit bus.'
|
||||||
|
license = 'gplv2+'
|
||||||
|
inputs = ['logic']
|
||||||
|
outputs = ['i80']
|
||||||
|
tags = ['Util']
|
||||||
|
channels = (
|
||||||
|
{'id': 'cs', 'name': 'CS', 'desc': 'Chip select line', 'idn':'dec_i80_chan_cs'},
|
||||||
|
{'id': 'cmd', 'name': 'CMD', 'desc': 'Command line', 'idn':'dec_i80_chan_cmd'},
|
||||||
|
{'id': 'rst', 'name': 'RST', 'desc': 'Reset line', 'idn':'dec_i80_chan_rst'},
|
||||||
|
{'id': 'hrdy', 'name': 'HRDY', 'desc': 'Ready line', 'idn':'dec_i80_chan_hrdy'},
|
||||||
|
{'id': 'd0', 'name': 'D0', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d0'},
|
||||||
|
{'id': 'd1', 'name': 'D1', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d1'},
|
||||||
|
{'id': 'd2', 'name': 'D2', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d2'},
|
||||||
|
{'id': 'd3', 'name': 'D3', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d3'},
|
||||||
|
{'id': 'd4', 'name': 'D4', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d4'},
|
||||||
|
{'id': 'd5', 'name': 'D5', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d5'},
|
||||||
|
{'id': 'd6', 'name': 'D6', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d6'},
|
||||||
|
{'id': 'd7', 'name': 'D7', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d7'},
|
||||||
|
)
|
||||||
|
optional_channels = (
|
||||||
|
{'id': 'd8', 'name': 'D8', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d8'},
|
||||||
|
{'id': 'd9', 'name': 'D9', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d9'},
|
||||||
|
{'id': 'd10', 'name': 'D10', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d10'},
|
||||||
|
{'id': 'd11', 'name': 'D11', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d11'},
|
||||||
|
{'id': 'd12', 'name': 'D12', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d12'},
|
||||||
|
{'id': 'd13', 'name': 'D13', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d13'},
|
||||||
|
{'id': 'd14', 'name': 'D14', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d14'},
|
||||||
|
{'id': 'd15', 'name': 'D15', 'desc': 'Serial data line', 'idn':'dec_i80_chan_d15'},
|
||||||
|
{'id': 'hwe', 'name': 'HWE', 'desc': 'Write enable line', 'idn':'dec_i80_chan_hwe'},
|
||||||
|
{'id': 'hre', 'name': 'HRE', 'desc': 'Read enable line', 'idn':'dec_i80_chan_hre'},
|
||||||
|
)
|
||||||
|
options = (
|
||||||
|
{'id': 'cs_polarity', 'desc': 'Chip select active state',
|
||||||
|
'default': 'low', 'values': ('low', 'high'), 'idn':'dec_i80_opt_cs_polarity'},
|
||||||
|
{'id': 'cmd_polarity', 'desc': 'Command active state',
|
||||||
|
'default': 'low', 'values': ('low', 'high'), 'idn':'dec_i80_opt_cmd_polarity'},
|
||||||
|
{'id': 'hwe_polarity', 'desc': 'Write enable active state',
|
||||||
|
'default': 'low', 'values': ('low', 'high'), 'idn':'dec_i80_opt_hwe_polarity'},
|
||||||
|
{'id': 'hre_polarity', 'desc': 'Read enable active state',
|
||||||
|
'default': 'low', 'values': ('low', 'high'), 'idn':'dec_i80_opt_hre_polarity'},
|
||||||
|
{'id': 'rst_polarity', 'desc': 'Reset polarity',
|
||||||
|
'default': 'low', 'values': ('low', 'high'), 'idn':'dec_i80_opt_rst_polarity'},
|
||||||
|
{'id': 'hrdy_polarity', 'desc': 'HRDY polarity',
|
||||||
|
'default': 'high', 'values': ('low', 'high'), 'idn':'dec_i80_opt_cs_polarity'},
|
||||||
|
{'id': 'endianness', 'desc': 'Data endianness',
|
||||||
|
'default': 'little', 'values': ('little', 'big'), 'idn':'dec_i80_opt_endianess'},
|
||||||
|
)
|
||||||
|
annotations = (
|
||||||
|
('command', 'Command'),
|
||||||
|
('write_data', 'Write'),
|
||||||
|
('read_data', 'Read'),
|
||||||
|
('reset', 'Reset'),
|
||||||
|
('warnings', 'Warnings'),
|
||||||
|
)
|
||||||
|
annotation_rows = (
|
||||||
|
('data', 'Data', (0,1,2)),
|
||||||
|
('events', 'Events', (3,)),
|
||||||
|
('warnings', 'Warnings', (4,)),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.items = []
|
||||||
|
self.saved_item = None
|
||||||
|
self.saved_word = None
|
||||||
|
self.ss_word = self.es_word = None
|
||||||
|
self.first = True
|
||||||
|
self.have_clock = True
|
||||||
|
self.prv_dex = 0
|
||||||
|
self.num_item_bits = None
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.out_python = self.register(srd.OUTPUT_PYTHON)
|
||||||
|
self.out_ann = self.register(srd.OUTPUT_ANN)
|
||||||
|
|
||||||
|
def putd(self, s, e, data):
|
||||||
|
self.put(s, e, self.out_ann, data)
|
||||||
|
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
#the last annotation
|
||||||
|
#self.put_py(self._data_begin, self.samplenum, ['ITEM', self._data])
|
||||||
|
#self.put_ann(self._data_begin, self.samplenum, [0, [self.format.format(self._data)]])
|
||||||
|
...
|
||||||
|
|
||||||
|
def decode(self):
|
||||||
|
# Determine which (optional) channels have input data. Insist in
|
||||||
|
# a non-empty input data set. Cope with sparse connection maps.
|
||||||
|
# Store enough state to later "compress" sampled input data.
|
||||||
|
bus_width_8_bit = all(not self.has_channel(chan) for chan in range(12, 20))
|
||||||
|
bus_width_16_bit = all(self.has_channel(chan) for chan in range(12, 20))
|
||||||
|
|
||||||
|
if not bus_width_8_bit and not bus_width_16_bit:
|
||||||
|
raise ChannelError('Can\'t determine bus width. Define only 8 or 16 bits!')
|
||||||
|
|
||||||
|
self.format = "@{{:0{}X}}".format(2 if bus_width_8_bit else 4)
|
||||||
|
|
||||||
|
have_hwe = self.has_channel(20)
|
||||||
|
hwe_active_low = self.options['hwe_polarity'] == 'low'
|
||||||
|
|
||||||
|
have_hre = self.has_channel(21)
|
||||||
|
hre_active_low = self.options['hre_polarity'] == 'low'
|
||||||
|
|
||||||
|
cs_active_low = self.options['cs_polarity'] == 'low'
|
||||||
|
cmd_active_low = self.options['cmd_polarity'] == 'low'
|
||||||
|
rst_active_low = self.options['rst_polarity'] == 'low'
|
||||||
|
|
||||||
|
trigger_conds = [
|
||||||
|
{0: 'e'}, # CS
|
||||||
|
{2: 'e'}, # RST
|
||||||
|
{20: 'r' if hwe_active_low else 'f'}, # HWE
|
||||||
|
{21: 'r' if hre_active_low else 'f'}, # HRE
|
||||||
|
]
|
||||||
|
|
||||||
|
# Keep processing the input stream. Assume "always zero" for
|
||||||
|
# not-connected input lines.
|
||||||
|
|
||||||
|
is_first = True
|
||||||
|
self._last_samplenum = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
(cs, cmd, rst, hrdy, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10 ,d11 ,d12 ,d13 ,d14 ,d15, hwe, hre) = self.wait(trigger_conds)
|
||||||
|
|
||||||
|
operation = (cs, cmd, hwe, hre, rst, hrdy)
|
||||||
|
if bus_width_8_bit:
|
||||||
|
data = bitpack([d0, d1, d2, d3, d4, d5, d6, d7])
|
||||||
|
elif bus_width_16_bit:
|
||||||
|
data = bitpack([d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15])
|
||||||
|
|
||||||
|
if is_first:
|
||||||
|
is_first = False
|
||||||
|
self._last_operation = operation
|
||||||
|
self._data_begin = 0
|
||||||
|
self._rst_begin = 0
|
||||||
|
self._data = data
|
||||||
|
self._data_is_cmd = operation[1]
|
||||||
|
self._data_dir = 1
|
||||||
|
self._last_samplenum = self.samplenum
|
||||||
|
continue
|
||||||
|
|
||||||
|
# check edge on hwe
|
||||||
|
if have_hwe and ((not self._last_operation[2] and operation[2] and hwe_active_low) or (self._last_operation[2] and not operation[2] and not hwe_active_low)):
|
||||||
|
self._data = data
|
||||||
|
self._data_is_cmd = operation[1] if cmd_active_low else not operation[1]
|
||||||
|
self._data_dir = 1
|
||||||
|
|
||||||
|
# check edge on hre
|
||||||
|
elif have_hre and ((not self._last_operation[3] and operation[3] and hre_active_low) or (self._last_operation[3] and not operation[3] and not hre_active_low)):
|
||||||
|
self._data = data
|
||||||
|
self._data_is_cmd = operation[1] if cmd_active_low else not operation[1]
|
||||||
|
self._data_dir = 0
|
||||||
|
|
||||||
|
# check cs switch
|
||||||
|
if operation[0] != self._last_operation[0]:
|
||||||
|
# cs on
|
||||||
|
if cs_active_low != operation[0]:
|
||||||
|
self._data_begin = self.samplenum
|
||||||
|
|
||||||
|
#cs off
|
||||||
|
elif self._data_is_cmd:
|
||||||
|
#self.putd(self._data_begin, self.samplenum, [0, [self.format.format(self._data)]])
|
||||||
|
self.putd(self._data_begin, self.samplenum, [1, [self.format.format(data)]])
|
||||||
|
else:
|
||||||
|
#self.putd(self._data_begin, self.samplenum, [1 if self._data_dir else 2, [self.format.format(self._data)]])
|
||||||
|
self.putd(self._data_begin, self.samplenum, [0, [self.format.format(data)]])
|
||||||
|
|
||||||
|
# check rst switch
|
||||||
|
if operation[4] != self._last_operation[4]:
|
||||||
|
if rst_active_low != operation[4]:
|
||||||
|
self._rst_begin = self.samplenum
|
||||||
|
else:
|
||||||
|
self.putd(self._rst_begin, self.samplenum, [3, ['Reset']])
|
||||||
|
|
||||||
|
self._last_operation = operation
|
||||||
|
self._last_samplenum = self.samplenum
|
||||||
Reference in New Issue
Block a user