Mercurial > repos > blastem
view analyze_olp.py @ 2069:8e51c0c3f2e3 segacd
Initial attempt at implementing the Sega CD graphics hardware
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 30 Jan 2022 19:55:33 -0800 |
parents | b1ad6339de4f |
children |
line wrap: on
line source
#!/usr/bin/env python from zipfile import ZipFile from sys import exit, argv def detect_rise(last, sample, bit): mask = 1 << bit return (not last & mask) and (sample & mask) def detect_fall(last, sample, bit): mask = 1 << bit return (last & mask) and (not sample & mask) def detect_high(sample, bit): mask = 1 << bit return sample & mask def detect_low(sample, bit): mask = 1 << bit return not sample & mask def get_value(sample, bits): value = 0 for i in xrange(0, len(bits)): bit = bits[i] value |= (sample >> bit & 1) << i return value def swizzle_mode4(row, col): return (col & 1) | (row << 1) | (col << 8 & 0xFE00) def analyze_delays(chanmap, datafile): if 'M68K_CLK' in chanmap: m68k_clk = chanmap['M68K CLK'] elif 'CLK' in chanmap: m68k_clk = chanmap['CLK'] m_as = chanmap['!AS'] ram_oe = chanmap['RAM !LOE/!RFSH'] ram_ce = chanmap['RAM !CE'] last = False prev = False prevRefresh = False clks = 0 as_start = 0 for line in datafile.readlines(): line = line.strip() if line and not line.startswith(';'): sample,_,num = line.partition('@') sample = int(sample, 16) if not (last is False): if detect_rise(last, sample, m68k_clk): clks = clks + 1 if detect_rise(last, sample, m_as): as_clks = clks - as_start if as_clks > 2: if not (prev is False): 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 else: print '!AS held for', as_clks, 'cycles starting (delay of ' + str(as_clks - 2) + ') at', as_start, 'and ending at', clks prev = as_start elif detect_fall(last, sample, m_as): as_start = clks if detect_fall(last, sample, ram_oe) and detect_high( sample, ram_ce): if prevRefresh is False: print 'RAM refresh at ', clks else: print 'RAM refresh at', clks, 'delta since last:', clks-prevRefresh prevRefresh = clks last = sample def analyze_refresh(chanmap, datafile): if 'M68K_CLK' in chanmap: m68k_clk = chanmap['M68K CLK'] elif 'CLK' in chanmap: m68k_clk = chanmap['CLK'] ram_oe = chanmap['RAM !LOE/!RFSH'] ram_ce = chanmap['RAM !CE'] clks = 0 last = False prevRefresh = False for line in datafile.readlines(): line = line.strip() if line and not line.startswith(';'): sample,_,num = line.partition('@') sample = int(sample, 16) if not (last is False): if detect_rise(last, sample, m68k_clk): clks = clks + 1 if detect_fall(last, sample, ram_oe) and detect_high( sample, ram_ce): if prevRefresh is False: print 'RAM refresh at ', clks else: print 'RAM refresh at', clks, 'delta since last:', clks-prevRefresh prevRefresh = clks last = sample table_start = 0x3800 table_end = table_start + 0x600 sat_start = 0x3E00 #0x3F00 sat_xname = sat_start + 0x80 sat_end = sat_start + 0x100 def analyze_vram(chanmap, datafile): address_bits = [chanmap['AD{0}'.format(i)] for i in xrange(0, 8)] ras = chanmap['!RAS'] cas = chanmap['!CAS'] hsync = chanmap['!HSYNC'] state = 'begin' last = False for line in datafile.readlines(): line = line.strip() if line and not line.startswith(';'): sample,_,num = line.partition('@') sample = int(sample, 16) if not (last is False): if detect_fall(last, sample, hsync): print 'HSYNC low @ {0}'.format(num) elif detect_rise(last, sample, hsync): print 'HSYNC high @ {0}'.format(num) if state == 'begin': if detect_fall(last, sample, ras): state = 'ras' row = get_value(sample, address_bits) elif detect_fall(last, sample, cas): state = 'cas' elif state == 'ras': if detect_fall(last, sample, cas): col = get_value(sample, address_bits) address = swizzle_mode4(row, col) if address < table_end and address >= table_start: offset = (address - table_start)/2 desc = 'Map Row {0} Col {1}'.format(offset / 32, offset & 31) elif address >= sat_start and address < sat_xname: offset = address - sat_start desc = 'Sprite {0} Y Read'.format(offset) elif address >= sat_xname and address < sat_end: offset = address - sat_xname desc = 'Sprite {0} X/Name Read'.format(offset / 2) else: desc = 'Tile {0} Row {1}'.format(address / 32, ((address / 4) & 7) + (0.5 if address & 2 else 0)) print '{0:02X}:{1:02X} - {2:04X} @ {3} - {4}'.format(row, col, address, num, desc) state = 'begin' elif state == 'cas': if detect_fall(last, sample, ras): print 'refresh @ {0}'.format(num) state = 'begin' last = sample def analyze_z80_mreq(chanmap, datafile): m1 = chanmap['!M1'] mreq = chanmap['!MREQ'] addressMask = 0x3FF last = None lastWasM1 = False for line in datafile.readlines(): line = line.strip() if line and not line.startswith(';'): sample,_,num = line.partition('@') sample = int(sample, 16) if not (last is None): if detect_rise(last, sample, mreq): address = last & addressMask if detect_low(last, m1): print 'M1 read {0:02X} @ {1}'.format(address, num) lastWasM1 = True elif lastWasM1: print 'Refresh {0:02X} @ {1}'.format(address, num) lastWasM1 = False else: print 'Access {0:02X} @ {1}'.format(address, num) last = sample def main(args): if len(args) < 2: print 'Usage: analyze_olp.py filename' exit(1) olpfile = ZipFile(args[1], "r") channelfile = olpfile.open('channel.labels') channels = [line.strip() for line in channelfile.readlines()] channelfile.close() print channels chanmap = {} for i in xrange(0, len(channels)): chanmap[channels[i]] = i datafile = olpfile.open('data.ols') #analyze_delays(chanmap, datafile) #analyze_vram(chanmap, datafile) #analyze_refresh(chanmap, datafile) analyze_z80_mreq(chanmap, datafile) datafile.close() if __name__ == '__main__': main(argv)