forked from Ivasoft/DSView
Merge branch 'master' of https://github.com/DreamSourceLab/DSView
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
##
|
||||
## Copyright (C) 2012-2013 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
## Copyright (C) 2019 DreamSourceLab <support@dreamsourcelab.com>
|
||||
## 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 General Public License as published by
|
||||
@@ -62,6 +63,26 @@ fields = {
|
||||
0b1110: 'Reserved / not allowed',
|
||||
0b1111: 'Reserved / not allowed',
|
||||
},
|
||||
# Cycle type / direction field
|
||||
# False for read cycle, True for write cycle
|
||||
'CT_DR_WR': {
|
||||
0b0000: False,
|
||||
0b0001: False,
|
||||
0b0010: True,
|
||||
0b0011: True,
|
||||
0b0100: False,
|
||||
0b0101: False,
|
||||
0b0110: True,
|
||||
0b0111: True,
|
||||
0b1000: False,
|
||||
0b1001: False,
|
||||
0b1010: True,
|
||||
0b1011: True,
|
||||
0b1100: False,
|
||||
0b1101: False,
|
||||
0b1110: False,
|
||||
0b1111: False,
|
||||
},
|
||||
# SIZE field (determines how many bytes are to be transferred)
|
||||
# Bits[3:2] are reserved, must be driven to 0b00.
|
||||
# Neither host nor peripheral are allowed to drive 0b0010.
|
||||
@@ -155,11 +176,13 @@ class Decoder(srd.Decoder):
|
||||
self.samplenum = 0
|
||||
self.lad = -1
|
||||
self.addr = 0
|
||||
self.direction = 0
|
||||
self.cur_nibble = 0
|
||||
self.cycle_type = -1
|
||||
self.databyte = 0
|
||||
self.tarcount = 0
|
||||
self.synccount = 0
|
||||
self.timeoutcount = 0
|
||||
self.oldpins = None
|
||||
self.ss_block = self.es_block = None
|
||||
|
||||
@@ -189,6 +212,13 @@ class Decoder(srd.Decoder):
|
||||
if (self.oldlad == 0b0000 or self.oldlad == 0b0101):
|
||||
self.start_field = self.oldlad
|
||||
self.state = 'GET CT/DR'
|
||||
elif (self.oldlad == 0b1101 or self.oldlad == 0b1110):
|
||||
self.start_field = self.oldlad
|
||||
if (self.oldlad == 0b1110):
|
||||
self.direction = True
|
||||
else:
|
||||
self.direction = False
|
||||
self.state = 'GET FW IDSEL'
|
||||
else:
|
||||
self.state = 'IDLE'
|
||||
|
||||
@@ -196,6 +226,7 @@ class Decoder(srd.Decoder):
|
||||
# LAD[3:0]: Cycle type / direction field (1 clock cycle).
|
||||
|
||||
self.cycle_type = fields['CT_DR'][self.oldlad]
|
||||
self.direction = fields['CT_DR_WR'][self.oldlad]
|
||||
|
||||
# TODO: Warning/error on invalid cycle types.
|
||||
if self.cycle_type == 'Reserved':
|
||||
@@ -209,6 +240,58 @@ class Decoder(srd.Decoder):
|
||||
self.addr = 0
|
||||
self.cur_nibble = 0
|
||||
|
||||
def handle_get_fw_idsel(self):
|
||||
# LAD[3:0]: IDSEL field (1 clock cycle).
|
||||
self.es_block = self.samplenum
|
||||
s = 'IDSEL: 0x%%0%dx' % self.oldlad
|
||||
self.putb([3, [s % self.oldlad]])
|
||||
self.ss_block = self.samplenum
|
||||
|
||||
self.state = 'GET FW ADDR'
|
||||
self.addr = 0
|
||||
self.cur_nibble = 0
|
||||
|
||||
def handle_get_fw_addr(self):
|
||||
# LAD[3:0]: ADDR field (7 clock cycles).
|
||||
addr_nibbles = 7 # Address is 28bits.
|
||||
|
||||
# Addresses are driven MSN-first.
|
||||
offset = ((addr_nibbles - 1) - self.cur_nibble) * 4
|
||||
if (offset < 0):
|
||||
self.putb([0, ['Warning: Invalid address shift: %d' % offset]])
|
||||
self.state = 'IDLE'
|
||||
return
|
||||
self.addr |= (self.oldlad << offset)
|
||||
|
||||
# Continue if we haven't seen all ADDR cycles, yet.
|
||||
if (self.cur_nibble < addr_nibbles - 1):
|
||||
self.cur_nibble += 1
|
||||
return
|
||||
|
||||
self.es_block = self.samplenum
|
||||
s = 'Address: 0x%%0%dx' % addr_nibbles
|
||||
self.putb([3, [s % self.addr]])
|
||||
self.ss_block = self.samplenum
|
||||
|
||||
self.state = 'GET FW MSIZE'
|
||||
|
||||
def handle_get_fw_msize(self):
|
||||
# LAD[3:0]: MSIZE field (1 clock cycle).
|
||||
self.es_block = self.samplenum
|
||||
s = 'MSIZE: 0x%%0%dx' % self.oldlad
|
||||
self.putb([3, [s % self.oldlad]])
|
||||
self.ss_block = self.samplenum
|
||||
self.msize = self.oldlad
|
||||
|
||||
if self.direction == 1:
|
||||
self.state = 'GET FW DATA'
|
||||
self.cycle_count = 0
|
||||
self.dataword = 0
|
||||
self.cur_nibble = 0
|
||||
else:
|
||||
self.state = 'GET TAR'
|
||||
self.tar_count = 0
|
||||
|
||||
def handle_get_addr(self):
|
||||
# LAD[3:0]: ADDR field (4/8/0 clock cycles).
|
||||
|
||||
@@ -223,6 +306,10 @@ class Decoder(srd.Decoder):
|
||||
|
||||
# Addresses are driven MSN-first.
|
||||
offset = ((addr_nibbles - 1) - self.cur_nibble) * 4
|
||||
if (offset < 0):
|
||||
self.putb([0, ['Warning: Invalid address shift: %d' % offset]])
|
||||
self.state = 'IDLE'
|
||||
return
|
||||
self.addr |= (self.oldlad << offset)
|
||||
|
||||
# Continue if we haven't seen all ADDR cycles, yet.
|
||||
@@ -235,8 +322,12 @@ class Decoder(srd.Decoder):
|
||||
self.putb([3, [s % self.addr]])
|
||||
self.ss_block = self.samplenum
|
||||
|
||||
self.state = 'GET TAR'
|
||||
self.tar_count = 0
|
||||
if self.direction == 1:
|
||||
self.state = 'GET DATA'
|
||||
self.cycle_count = 0
|
||||
else:
|
||||
self.state = 'GET TAR'
|
||||
self.tar_count = 0
|
||||
|
||||
def handle_get_tar(self):
|
||||
# LAD[3:0]: First TAR (turn-around) field (2 clock cycles).
|
||||
@@ -277,12 +368,17 @@ class Decoder(srd.Decoder):
|
||||
self.ss_block = self.samplenum
|
||||
|
||||
# TODO
|
||||
|
||||
self.cycle_count = 0
|
||||
if (lframe == 0):
|
||||
self.state = 'GET TIMEOUT'
|
||||
else:
|
||||
self.state = 'GET DATA'
|
||||
if (self.cycle_type != 'Short wait' and self.cycle_type != 'Long wait'):
|
||||
self.cycle_count = 0
|
||||
if (lframe == 0):
|
||||
self.state = 'GET TIMEOUT'
|
||||
elif (self.start_field == 0b1101 or self.start_field == 0b1110):
|
||||
self.state = 'GET FW DATA'
|
||||
self.cycle_count = 0
|
||||
self.dataword = 0
|
||||
self.cur_nibble = 0
|
||||
else:
|
||||
self.state = 'GET DATA'
|
||||
|
||||
def handle_get_timeout(self):
|
||||
# LFRAME#: tie low (4 clock cycles).
|
||||
@@ -303,6 +399,50 @@ class Decoder(srd.Decoder):
|
||||
|
||||
self.timeoutcount = 0
|
||||
self.state = 'IDLE'
|
||||
|
||||
def handle_get_fw_data(self):
|
||||
# LAD[3:0]: DATA field
|
||||
if (self.msize == 0b0000):
|
||||
data_nibbles = 2 # Data is 8bits.
|
||||
elif (self.msize == 0b0001):
|
||||
data_nibbles = 4 # Data is 16bits.
|
||||
elif (self.msize == 0b0010):
|
||||
data_nibbles = 8 # Data is 32bits.
|
||||
elif (self.msize == 0b0100):
|
||||
data_nibbles = 32 # Data is 128bits.
|
||||
elif (self.msize == 0b0111):
|
||||
data_nibbles = 256 # Data is 1024bits.
|
||||
else:
|
||||
self.putb([0, ['Warning: Invalid MSIZE: %d' % self.msize]])
|
||||
self.state = 'IDLE'
|
||||
return
|
||||
|
||||
# Data is driven LSN-first.
|
||||
nibble_swap = self.cur_nibble % 2
|
||||
offset = ((data_nibbles - 1) - self.cur_nibble) * 4
|
||||
if (nibble_swap):
|
||||
offset += 4
|
||||
else:
|
||||
offset -= 4
|
||||
if (offset < 0):
|
||||
self.putb([0, ['Warning: Invalid data shift: %d' % offset]])
|
||||
self.state = 'IDLE'
|
||||
return
|
||||
self.dataword |= (self.oldlad << offset)
|
||||
|
||||
# Continue if we haven't seen all DATA cycles, yet.
|
||||
if (self.cur_nibble < data_nibbles - 1):
|
||||
self.cur_nibble += 1
|
||||
return
|
||||
|
||||
self.es_block = self.samplenum
|
||||
s = 'DATA: 0x%%0%dx' % data_nibbles
|
||||
self.putb([3, [s % self.dataword]])
|
||||
self.ss_block = self.samplenum
|
||||
|
||||
self.cycle_count = 0
|
||||
self.state = 'GET TAR2'
|
||||
|
||||
def handle_get_data(self):
|
||||
# LAD[3:0]: DATA field (2 clock cycles).
|
||||
|
||||
@@ -312,7 +452,9 @@ class Decoder(srd.Decoder):
|
||||
elif (self.cycle_count == 1):
|
||||
self.databyte |= (self.oldlad << 4)
|
||||
else:
|
||||
raise Exception('Invalid cycle_count: %d' % self.cycle_count)
|
||||
self.putb([0, ['Warning: Invalid cycle_count: %d' % self.cycle_count]])
|
||||
self.state = 'IDLE'
|
||||
return
|
||||
|
||||
if (self.cycle_count != 1):
|
||||
self.cycle_count += 1
|
||||
@@ -362,6 +504,10 @@ class Decoder(srd.Decoder):
|
||||
|
||||
# TODO: Only memory read/write is currently supported/tested.
|
||||
|
||||
# Detect host cycle abort requests
|
||||
if (lframe == 0) and (self.oldlframe == 0):
|
||||
self.state = 'GET TIMEOUT'
|
||||
|
||||
# State machine
|
||||
if self.state == 'IDLE':
|
||||
# A valid LPC cycle starts with LFRAME# being asserted (low).
|
||||
@@ -377,12 +523,20 @@ class Decoder(srd.Decoder):
|
||||
self.handle_get_ct_dr()
|
||||
elif self.state == 'GET ADDR':
|
||||
self.handle_get_addr()
|
||||
elif self.state == 'GET FW IDSEL':
|
||||
self.handle_get_fw_idsel()
|
||||
elif self.state == 'GET FW ADDR':
|
||||
self.handle_get_fw_addr()
|
||||
elif self.state == 'GET FW MSIZE':
|
||||
self.handle_get_fw_msize()
|
||||
elif self.state == 'GET TAR':
|
||||
self.handle_get_tar()
|
||||
elif self.state == 'GET SYNC':
|
||||
self.handle_get_sync(lframe)
|
||||
elif self.state == 'GET TIMEOUT':
|
||||
self.handle_get_timeout()
|
||||
elif self.state == 'GET FW DATA':
|
||||
self.handle_get_fw_data()
|
||||
elif self.state == 'GET DATA':
|
||||
self.handle_get_data()
|
||||
elif self.state == 'GET TAR2':
|
||||
|
||||
Reference in New Issue
Block a user