added i80 decoder draft

This commit is contained in:
2025-01-26 18:56:40 +01:00
commit 14b856187d
2 changed files with 233 additions and 0 deletions

22
i80/__init__.py Normal file
View 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
View 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