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)