main analyze_olp.py
  1#!/usr/bin/env python
  2
  3from zipfile import ZipFile
  4from sys import exit, argv
  5
  6def detect_rise(last, sample, bit):
  7	mask = 1 << bit
  8	return (not last & mask) and (sample & mask)
  9
 10def detect_fall(last, sample, bit):
 11	mask = 1 << bit
 12	return (last & mask) and (not sample & mask)
 13
 14def detect_high(sample, bit):
 15	mask = 1 << bit
 16	return sample & mask
 17
 18def detect_low(sample, bit):
 19	mask = 1 << bit
 20	return not sample & mask
 21	
 22def get_value(sample, bits):
 23	value = 0
 24	for i in xrange(0, len(bits)):
 25		bit = bits[i]
 26		value |= (sample >> bit & 1) << i
 27	return value
 28	
 29def swizzle_mode4(row, col):
 30	return (col & 1) | (row << 1) | (col << 8 & 0xFE00)
 31
 32def analyze_delays(chanmap, datafile):
 33	if 'M68K_CLK' in chanmap:
 34		m68k_clk = chanmap['M68K CLK']
 35	elif 'CLK' in chanmap:
 36		m68k_clk = chanmap['CLK']
 37	m_as = chanmap['!AS']
 38	ram_oe = chanmap['RAM !LOE/!RFSH']
 39	ram_ce = chanmap['RAM !CE']
 40	last = False
 41	prev = False
 42	prevRefresh = False
 43	clks = 0
 44	as_start = 0
 45	for line in datafile.readlines():
 46		line = line.strip()
 47		if line and not line.startswith(';'):
 48			sample,_,num = line.partition('@')
 49			sample = int(sample, 16)
 50			if not (last is False):
 51				if detect_rise(last, sample, m68k_clk):
 52					clks = clks + 1
 53				if detect_rise(last, sample, m_as):
 54					as_clks  = clks - as_start
 55					if as_clks > 2:
 56						if not (prev is False):
 57							print '!AS held for', as_clks, 'cycles starting (delay of ' + str(as_clks - 2) + ') at', as_start, 'and ending at', clks, 'delta since last delay:', as_start - prev
 58						else:
 59							print '!AS held for', as_clks, 'cycles starting (delay of ' + str(as_clks - 2) + ') at', as_start, 'and ending at', clks
 60						prev = as_start
 61				elif detect_fall(last, sample, m_as):
 62					as_start = clks
 63				if detect_fall(last, sample, ram_oe) and detect_high( sample, ram_ce):
 64					if prevRefresh is False:
 65						print 'RAM refresh at ', clks
 66					else:
 67						print 'RAM refresh at', clks, 'delta since last:', clks-prevRefresh
 68					prevRefresh = clks
 69			last = sample
 70			
 71def analyze_refresh(chanmap, datafile):
 72	if 'M68K_CLK' in chanmap:
 73		m68k_clk = chanmap['M68K CLK']
 74	elif 'CLK' in chanmap:
 75		m68k_clk = chanmap['CLK']
 76	ram_oe = chanmap['RAM !LOE/!RFSH']
 77	ram_ce = chanmap['RAM !CE']
 78	clks = 0
 79	last = False
 80	prevRefresh = False
 81	for line in datafile.readlines():
 82		line = line.strip()
 83		if line and not line.startswith(';'):
 84			sample,_,num = line.partition('@')
 85			sample = int(sample, 16)
 86			if not (last is False):
 87				if detect_rise(last, sample, m68k_clk):
 88					clks = clks + 1
 89				if detect_fall(last, sample, ram_oe) and detect_high( sample, ram_ce):
 90					if prevRefresh is False:
 91						print 'RAM refresh at ', clks
 92					else:
 93						print 'RAM refresh at', clks, 'delta since last:', clks-prevRefresh
 94					prevRefresh = clks
 95			last = sample
 96			
 97			
 98table_start = 0x3800
 99table_end = table_start + 0x600
100sat_start = 0x3E00 #0x3F00 
101sat_xname = sat_start + 0x80
102sat_end = sat_start + 0x100
103
104
105def analyze_vram(chanmap, datafile):
106	address_bits = [chanmap['AD{0}'.format(i)] for i in xrange(0, 8)]
107	ras = chanmap['!RAS']
108	cas = chanmap['!CAS']
109	hsync = chanmap['!HSYNC']
110	state = 'begin'
111	last = False
112	for line in datafile.readlines():
113		line = line.strip()
114		if line and not line.startswith(';'):
115			sample,_,num = line.partition('@')
116			sample = int(sample, 16)
117			if not (last is False):
118				if detect_fall(last, sample, hsync):
119					print 'HSYNC low @ {0}'.format(num)
120				elif detect_rise(last, sample, hsync):
121					print 'HSYNC high @ {0}'.format(num)
122				if state == 'begin':
123					if detect_fall(last, sample, ras):
124						state = 'ras'
125						row = get_value(sample, address_bits)
126					elif detect_fall(last, sample, cas):
127						state = 'cas'
128				elif state == 'ras':
129					if detect_fall(last, sample, cas):
130						col = get_value(sample, address_bits)
131						address = swizzle_mode4(row, col)
132						
133						if address < table_end and address >= table_start:
134							offset = (address - table_start)/2
135							desc = 'Map Row {0} Col {1}'.format(offset / 32, offset & 31)
136						elif address >= sat_start and address < sat_xname:
137							offset = address - sat_start
138							desc = 'Sprite {0} Y Read'.format(offset)
139						elif address >= sat_xname and address < sat_end:
140							offset = address - sat_xname
141							desc = 'Sprite {0} X/Name Read'.format(offset / 2)
142						else:
143							desc = 'Tile {0} Row {1}'.format(address / 32, ((address / 4) & 7) + (0.5 if address & 2 else 0))
144						print '{0:02X}:{1:02X} - {2:04X} @ {3} - {4}'.format(row, col, address, num, desc)
145						state = 'begin'
146				elif state == 'cas':
147					if detect_fall(last, sample, ras):
148						print 'refresh @ {0}'.format(num)
149						state = 'begin'
150			last = sample
151			
152def analyze_z80_mreq(chanmap, datafile):
153	m1 = chanmap['!M1']
154	mreq = chanmap['!MREQ']
155	addressMask = 0x3FF
156	last = None
157	lastWasM1 = False
158	for line in datafile.readlines():
159		line = line.strip()
160		if line and not line.startswith(';'):
161			sample,_,num = line.partition('@')
162			sample = int(sample, 16)
163			if not (last is None):
164				if detect_rise(last, sample, mreq):
165					address = last & addressMask
166					if detect_low(last, m1):
167						print 'M1 read {0:02X} @ {1}'.format(address, num)
168						lastWasM1 = True
169					elif lastWasM1:
170						print 'Refresh {0:02X} @ {1}'.format(address, num)
171						lastWasM1 = False
172					else:
173						print 'Access {0:02X} @ {1}'.format(address, num)
174			last = sample
175
176def main(args):
177	if len(args) < 2:
178		print 'Usage: analyze_olp.py filename'
179		exit(1)
180	olpfile = ZipFile(args[1], "r")
181	channelfile = olpfile.open('channel.labels')
182	channels = [line.strip() for line in channelfile.readlines()]
183	channelfile.close()
184	print channels
185	chanmap = {}
186	for i in xrange(0, len(channels)):
187		chanmap[channels[i]] = i
188	datafile = olpfile.open('data.ols')
189	#analyze_delays(chanmap, datafile)
190	#analyze_vram(chanmap, datafile)
191	#analyze_refresh(chanmap, datafile)
192	analyze_z80_mreq(chanmap, datafile)
193	datafile.close()
194	
195
196if __name__ == '__main__':
197	main(argv)