299 lines
7.2 KiB
Python
299 lines
7.2 KiB
Python
import sys
|
|
import struct
|
|
from opcodes import opcodes
|
|
import types
|
|
|
|
with open(sys.argv[1], 'rb') as f:
|
|
buf = f.read()
|
|
rom = memoryview(buf)
|
|
|
|
def u8(offset):
|
|
global rom
|
|
value, = struct.unpack("<B", rom[offset:offset+1])
|
|
return value
|
|
|
|
def u16(offset):
|
|
global rom
|
|
value, = struct.unpack("<H", rom[offset:offset+2])
|
|
return value
|
|
|
|
def u32(offset):
|
|
global rom
|
|
value, = struct.unpack("<I", rom[offset:offset+4])
|
|
return value
|
|
|
|
def rstr(offset, length):
|
|
global rom
|
|
return bytes(rom[offset:offset + length])
|
|
|
|
ATOM_BIOS_MAGIC = 0xaa55
|
|
ATOM_ATI_MAGIC_OFFSET = 0x30
|
|
ATOM_ATI_MAGIC = b" 761295520"
|
|
ATOM_ROM_TABLE_OFFSET = 0x48
|
|
ATOM_ROM_MAGIC = b"ATOM"
|
|
|
|
ATOM_ROM_MAGIC_OFFSET = 0x04
|
|
ATOM_ROM_MSG_OFFSET = 0x10
|
|
ATOM_ROM_CMD_OFFSET = 0x1e
|
|
ATOM_ROM_DATA_OFFSET = 0x20
|
|
|
|
_command_table_names = [
|
|
"ASIC_Init",
|
|
"GetDisplaySurfaceSize",
|
|
"ASIC_RegistersInit",
|
|
"VRAM_BlockVenderDetection",
|
|
"DIGxEncoderControl",
|
|
"MemoryControllerInit",
|
|
"EnableCRTCMemReq",
|
|
"MemoryParamAdjust",
|
|
"DVOEncoderControl",
|
|
"GPIOPinControl",
|
|
"SetEngineClock",
|
|
"SetMemoryClock",
|
|
"SetPixelClock",
|
|
"DynamicClockGating",
|
|
"ResetMemoryDLL",
|
|
"ResetMemoryDevice",
|
|
"MemoryPLLInit",
|
|
"AdjustDisplayPll",
|
|
"AdjustMemoryController",
|
|
"EnableASIC_StaticPwrMgt",
|
|
"ASIC_StaticPwrMgtStatusChange",
|
|
"DAC_LoadDetection",
|
|
"LVTMAEncoderControl",
|
|
"LCD1OutputControl",
|
|
"DAC1EncoderControl",
|
|
"DAC2EncoderControl",
|
|
"DVOOutputControl",
|
|
"CV1OutputControl",
|
|
"GetConditionalGoldenSetting",
|
|
"TVEncoderControl",
|
|
"TMDSAEncoderControl",
|
|
"LVDSEncoderControl",
|
|
"TV1OutputControl",
|
|
"EnableScaler",
|
|
"BlankCRTC",
|
|
"EnableCRTC",
|
|
"GetPixelClock",
|
|
"EnableVGA_Render",
|
|
"GetSCLKOverMCLKRatio",
|
|
"SetCRTC_Timing",
|
|
"SetCRTC_OverScan",
|
|
"SetCRTC_Replication",
|
|
"SelectCRTC_Source",
|
|
"EnableGraphSurfaces",
|
|
"UpdateCRTC_DoubleBufferRegisters",
|
|
"LUT_AutoFill",
|
|
"EnableHW_IconCursor",
|
|
"GetMemoryClock",
|
|
"GetEngineClock",
|
|
"SetCRTC_UsingDTDTiming",
|
|
"ExternalEncoderControl",
|
|
"LVTMAOutputControl",
|
|
"VRAM_BlockDetectionByStrap",
|
|
"MemoryCleanUp",
|
|
"ProcessI2cChannelTransaction",
|
|
"WriteOneByteToHWAssistedI2C",
|
|
"ReadHWAssistedI2CStatus",
|
|
"SpeedFanControl",
|
|
"PowerConnectorDetection",
|
|
"MC_Synchronization",
|
|
"ComputeMemoryEnginePLL",
|
|
"MemoryRefreshConversion",
|
|
"VRAM_GetCurrentInfoBlock",
|
|
"DynamicMemorySettings",
|
|
"MemoryTraining",
|
|
"EnableSpreadSpectrumOnPPLL",
|
|
"TMDSAOutputControl",
|
|
"SetVoltage",
|
|
"DAC1OutputControl",
|
|
"DAC2OutputControl",
|
|
"SetupHWAssistedI2CStatus",
|
|
"ClockSource",
|
|
"MemoryDeviceInit",
|
|
"EnableYUV",
|
|
"DIG1EncoderControl",
|
|
"DIG2EncoderControl",
|
|
"DIG1TransmitterControl",
|
|
"DIG2TransmitterControl",
|
|
"ProcessAuxChannelTransaction",
|
|
"DPEncoderService",
|
|
]
|
|
|
|
# attr
|
|
|
|
# 2:0 - ATOM_ARG_
|
|
# 5:3 - ATOM_SRC_
|
|
# 7:6 - dest align
|
|
# long: 0 [31-0]
|
|
# word: 0 [15-0]
|
|
# 1 [23-8]
|
|
# 2 [31-16]
|
|
# byte 0 [7-0]
|
|
# 1 [15-8]
|
|
# 2 [23-16]
|
|
# 3 [31-24]
|
|
|
|
def opcode_type_setport(offset, dest_type):
|
|
if dest_type == "ati":
|
|
return 2
|
|
elif dest_type == "pci":
|
|
return 1
|
|
elif dest_type == "sysio":
|
|
return 1
|
|
else:
|
|
assert False, dest_type
|
|
|
|
def src_size(src):
|
|
return [
|
|
4, # DWORD
|
|
2, # WORD0
|
|
2, # WORD8
|
|
2, # WORD16
|
|
1, # BYTE0
|
|
1, # BYTE8
|
|
1, # BYTE16
|
|
1, # BYTE24
|
|
][src]
|
|
|
|
SRC = types.SimpleNamespace()
|
|
SRC.REG = 0
|
|
SRC.PS = 1
|
|
SRC.WS = 2
|
|
SRC.FB = 3
|
|
SRC.ID = 4
|
|
SRC.IMM = 5
|
|
SRC.PLL = 6
|
|
SRC.MC = 7
|
|
|
|
def dest_arg_size(dest_type):
|
|
assert type(dest_type) == int
|
|
match dest_type:
|
|
case SRC.REG:
|
|
return 2
|
|
case SRC.IMM:
|
|
assert False, dest_type
|
|
case SRC.ID:
|
|
assert False, dest_type
|
|
case _:
|
|
return 1
|
|
|
|
def dest_src_size(arg, src):
|
|
assert type(arg) == int
|
|
match arg:
|
|
case SRC.IMM:
|
|
return src_size(src)
|
|
case SRC.REG:
|
|
return 2
|
|
case SRC.ID:
|
|
return 2
|
|
case _:
|
|
return 1
|
|
|
|
def opcode_type_dest_src(offset, dest_type):
|
|
attr = u8(offset)
|
|
arg = (attr >> 0) & 0b111
|
|
src = (attr >> 3) & 0b111
|
|
return (
|
|
1
|
|
+ dest_arg_size(dest_type)
|
|
+ dest_src_size(arg, src)
|
|
)
|
|
|
|
def opcode_type_1x16(offset, dest_type):
|
|
return 2
|
|
|
|
def opcode_type_setregblock(offset, dest_type):
|
|
return 2
|
|
|
|
def opcode_type_dest(offset, dest_type):
|
|
attr = u8(offset)
|
|
src = (attr >> 3) & 0b111
|
|
return 1 + dest_src_size(dest_type, src)
|
|
|
|
def opcode_type_shift(offset, dest_type):
|
|
attr = u8(offset)
|
|
src = (attr >> 3) & 0b111
|
|
return 1 + dest_src_size(dest_type, src)
|
|
|
|
def opcode_0(offset, dest_type):
|
|
return 0
|
|
|
|
argument_handlers = {
|
|
"setport": opcode_type_setport,
|
|
"dest_src": opcode_type_dest_src,
|
|
"1x16": opcode_type_1x16,
|
|
"setregblock": opcode_type_1x16,
|
|
"shift": opcode_type_shift,
|
|
"dest": opcode_type_dest,
|
|
"0": opcode_0,
|
|
}
|
|
|
|
def disassemble(start, length):
|
|
offset = start
|
|
offset_end = start + length - 6
|
|
|
|
while offset < offset_end:
|
|
opcode = u8(offset)
|
|
arg_type, name, dest_type = opcodes[opcode]
|
|
pc = (offset - start) + 6
|
|
print(f"{pc:04x} opcode {opcode:02x} {name}:{dest_type}")
|
|
offset += 1
|
|
handler = argument_handlers[arg_type]
|
|
offset += handler(offset, dest_type)
|
|
|
|
def parse_table(names, table):
|
|
structure_size = u16(table + 0)
|
|
format_revision = u8(table + 2)
|
|
content_revision = u8(table + 3)
|
|
print("structure size", structure_size)
|
|
print("format revision", format_revision)
|
|
print("content revision", content_revision)
|
|
table_entries = (structure_size - 4) // 2
|
|
for i in range(table_entries):
|
|
offset = u16(table + 4 + i * 2)
|
|
if offset == 0:
|
|
print(f"{i:02x} offset {offset:04x} : ({names[i]})")
|
|
continue
|
|
length = u16(offset + 0)
|
|
format_rev = u8(offset + 2)
|
|
content_rev = u8(offset + 3)
|
|
print(f"{i:02x} offset {offset:04x} length {length:04x} format {format_rev:02x} content {content_rev:02x} : ({names[i]})")
|
|
if i == 0x22:
|
|
disassemble(offset + 6, length)
|
|
break
|
|
|
|
def parse_header():
|
|
bios_magic = u16(0)
|
|
assert bios_magic == ATOM_BIOS_MAGIC, bios_magic
|
|
ati_magic = rstr(ATOM_ATI_MAGIC_OFFSET, len(ATOM_ATI_MAGIC))
|
|
assert ati_magic == ATOM_ATI_MAGIC, ati_magic
|
|
|
|
base = u16(ATOM_ROM_TABLE_OFFSET)
|
|
rom_magic = rstr(base + ATOM_ROM_MAGIC_OFFSET, len(ATOM_ROM_MAGIC))
|
|
assert rom_magic == ATOM_ROM_MAGIC, rom_magic
|
|
|
|
print("structure size", u16(0))
|
|
|
|
cmd_table = u16(base + ATOM_ROM_CMD_OFFSET)
|
|
data_table = u16(base + ATOM_ROM_DATA_OFFSET)
|
|
|
|
str = rom[u16(base + ATOM_ROM_MSG_OFFSET):]
|
|
while str[0] == ord(b'\n') or str[0] == ord(b'\r'):
|
|
str = str[1:]
|
|
message = []
|
|
for i in range(511):
|
|
if str[i] == 0:
|
|
break
|
|
message.append(str[i])
|
|
message = bytes(message).strip()
|
|
print(message)
|
|
|
|
print("command table:")
|
|
parse_table(_command_table_names, cmd_table)
|
|
print("\n\n")
|
|
#print("data table:")
|
|
#parse_table(data_table)
|
|
|
|
parse_header()
|