#! /usr/bin/python3 import sys, fileinput, re # Ross Thompson # July 27, 2021 # Rewrite of the linux trace parser. InstrStartDelim = '=>' InstrEndDelim = '-----' #InputFile = 'noparse.txt' #InputFile = sys.stdin #InputFile = 'temp.txt' #OutputFile = 'parsedAll.txt' HUMAN_READABLE = False def toDict(lst): 'Converts the list of register values to a dictionary' dct= {} for item in lst: regTup = item.split() dct[regTup[0]] = int(regTup[2], 10) del dct['pc'] return dct def whichClass(text, Regs): 'Which instruction class?' #print(text, Regs) if text[0:2] == 'ld' or text[0:2] == 'lw' or text[0:2] == 'lh' or text[0:2] == 'lb': return ('load', WhatAddr(text, Regs), None, WhatMemDestSource(text)) elif text[0:2] == 'sd' or text[0:2] == 'sw' or text[0:2] == 'sh' or text[0:2] == 'sb': return ('store', WhatAddr(text, Regs), WhatMemDestSource(text), None) elif text[0:3] == 'amo': return ('amo', WhatAddrAMO(text, Regs), WhatMemDestSource(text), WhatMemDestSource(text)) elif text[0:2] == 'lr': return ('lr', WhatAddrLR(text, Regs), None, WhatMemDestSource(text)) elif text[0:2] == 'sc': return ('sc', WhatAddrSC(text, Regs), WhatMemDestSource(text), None) else: return ('other', None, None, None) def whatChanged(dct0, dct1): 'Compares two dictionaries of instrution registers and indicates which registers changed' dct = {} for key in dct0: if (dct1[key] != dct0[key]): dct[key] = dct1[key] return dct def WhatMemDestSource(text): ''''What is the destination register. Used to compute where the read data is on a load or the write data on a store.''' return text.split()[1].split(',')[0] def WhatAddr(text, Regs): 'What is the data memory address?' Imm = text.split(',')[1] (Imm, Src) = Imm.split('(') Imm = int(Imm.strip(), 10) Src = Src.strip(')').strip() RegVal = Regs[Src] return Imm + RegVal def WhatAddrAMO(text, Regs): 'What is the data memory address?' Src = text.split('(')[1] Src = Src.strip(')').strip() return Regs[Src] def WhatAddrLR(text, Regs): 'What is the data memory address?' Src = text.split('(')[1] Src = Src.strip(')').strip() return Regs[Src] def WhatAddrSC(text, Regs): 'What is the data memory address?' Src = text.split('(')[1] Src = Src.strip(')').strip() return Regs[Src] def PrintInstr(instr): if instr[2] == None: return ChangedRegisters = instr[4] GPR = '' CSR = [] for key in ChangedRegisters: # filter out csr which are not checked. if(key in RegNumber): if(RegNumber[key] < 32): # GPR if(HUMAN_READABLE): GPR = '{:-2d} {:016x}'.format(RegNumber[key], ChangedRegisters[key]) else: GPR = '{:d} {:x}'.format(RegNumber[key], ChangedRegisters[key]) else: if(HUMAN_READABLE): CSR.extend([key, '{:016x}'.format(ChangedRegisters[key])]) else: CSR.extend([key, '{:x}'.format(ChangedRegisters[key])]) CSRStr = ' '.join(CSR) #print(instr) if (HUMAN_READABLE == True): outString='{:016x} {:08x} {:25s}'.format(instr[0], instr[1], instr[2]) if(len(GPR) != 0): outString+=' GPR {}'.format(GPR) if(instr[3] == 'load' or instr[3] == 'lr'): outString+=' MemR {:016x} {:016x} {:016x}'.format(instr[5], 0, instr[7]) if(instr[3] == 'store'): outString+='\t\t\t MemW {:016x} {:016x} {:016x}'.format(instr[5], instr[6], 0) if(len(CSR) != 0): outString+=' CSR {}'.format(CSRStr) else: outString='{:x} {:x} {:s}'.format(instr[0], instr[1], instr[2].replace(' ', '_')) if(len(GPR) != 0): outString+=' GPR {}'.format(GPR) if(instr[3] == 'load' or instr[3] == 'lr'): outString+=' MemR {:x} {:x} {:x}'.format(instr[5], 0, instr[7]) if(instr[3] == 'store'): outString+=' MemW {:x} {:x} {:x}'.format(instr[5], instr[6], 0) if(len(CSR) != 0): outString+=' CSR {}'.format(CSRStr) outString+='\n' return outString # ========= # Main Code # ========= # Parse argument for interrupt file if len(sys.argv) != 2: sys.exit('Error parseGDBtoTrace.py expects 1 arg:\n >') interruptFname = sys.argv[1] # reg number RegNumber = {'zero': 0, 'ra': 1, 'sp': 2, 'gp': 3, 'tp': 4, 't0': 5, 't1': 6, 't2': 7, 's0': 8, 's1': 9, 'a0': 10, 'a1': 11, 'a2': 12, 'a3': 13, 'a4': 14, 'a5': 15, 'a6': 16, 'a7': 17, 's2': 18, 's3': 19, 's4': 20, 's5': 21, 's6': 22, 's7': 23, 's8': 24, 's9': 25, 's10': 26, 's11': 27, 't3': 28, 't4': 29, 't5': 30, 't6': 31, 'mhartid': 32, 'mstatus': 33, 'mip': 34, 'mie': 35, 'mideleg': 36, 'medeleg': 37, 'mtvec': 38, 'stvec': 39, 'mepc': 40, 'sepc': 41, 'mcause': 42, 'scause': 43, 'mtval': 44, 'stval': 45, 'mscratch': 46, 'sscratch': 47, 'satp': 48} # initial state CurrentInstr = ['0', '0', None, 'other', {'zero': 0, 'ra': 0, 'sp': 0, 'gp': 0, 'tp': 0, 't0': 0, 't1': 0, 't2': 0, 's0': 0, 's1': 0, 'a0': 0, 'a1': 0, 'a2': 0, 'a3': 0, 'a4': 0, 'a5': 0, 'a6': 0, 'a7': 0, 's2': 0, 's3': 0, 's4': 0, 's5': 0, 's6': 0, 's7': 0, 's8': 0, 's9': 0, 's10': 0, 's11': 0, 't3': 0, 't4': 0, 't5': 0, 't6': 0, 'mhartid': 0, 'mstatus': 0, 'mip': 0, 'mie': 0, 'mideleg': 0, 'medeleg': 0, 'mtvec': 0, 'stvec': 0, 'mepc': 0, 'sepc': 0, 'mcause': 0, 'scause': 0, 'mtval': 0, 'stval': 0, 'mscratch': 0, 'sscratch': 0, 'satp': 0}, {}, None, None, None] #with open (InputFile, 'r') as InputFileFP: #lines = InputFileFP.readlines() lineNum = 0 StartLine = 0 EndLine = 0 numInstrs = 0 #instructions = [] MemAdr = 0 lines = [] interrupts=open(interruptFname,'w') interrupts.close() prevInstrOutString='' currInstrOutString='' for line in fileinput.input('-'): if line.startswith('riscv_cpu_do_interrupt'): with open(interruptFname,'a') as interrupts: # Write line # Example line: hart:0, async:0, cause:0000000000000002, epc:0x0000000080008548, tval:0x0000000000000000, desc=illegal_instruction interrupts.write(line) # Write instruction count interrupts.write(str(numInstrs)+'\n') # Convert line to rows of info for easier Verilog parsing vals=line.strip('riscv_cpu_do_interrupt: ').strip('\n').split(',') vals=[val.split(':')[-1].strip(' ') for val in vals] vals=[val.split('=')[-1].strip(' ') for val in vals] for val in vals: interrupts.write(val+'\n') continue lines.insert(lineNum, line) if InstrStartDelim in line: lineNum = 0 StartLine = lineNum elif InstrEndDelim in line: EndLine = lineNum (InstrBits, text) = lines[StartLine].split(':') InstrBits = int(InstrBits.strip('=> '), 16) text = text.strip() PC = int(lines[StartLine+1].split(':')[0][2:], 16) Regs = toDict(lines[StartLine+2:EndLine]) (Class, Addr, WriteReg, ReadReg) = whichClass(text, Regs) #print("CWR", Class, WriteReg, ReadReg) PreviousInstr = CurrentInstr Changed = whatChanged(PreviousInstr[4], Regs) if (ReadReg !=None): ReadData = ReadReg else: ReadData = None if (WriteReg !=None): WriteData = WriteReg else: WriteData = None CurrentInstr = [PC, InstrBits, text, Class, Regs, Changed, Addr, WriteData, ReadData] #print(CurrentInstr[0:4], PreviousInstr[5], CurrentInstr[6:7], PreviousInstr[8]) # pc, instrbits, text and class come from the last line. MoveInstrToRegWriteLst = PreviousInstr[0:4] # updated registers come from the current line. MoveInstrToRegWriteLst.append(CurrentInstr[5]) # destination regs # memory address if present comes from the last line. MoveInstrToRegWriteLst.append(PreviousInstr[6]) # MemAdrM # write data from the previous line #MoveInstrToRegWriteLst.append(PreviousInstr[7]) # WriteDataM if (PreviousInstr[7] != None): MoveInstrToRegWriteLst.append(Regs[PreviousInstr[7]]) # WriteDataM else: MoveInstrToRegWriteLst.append(None) # read data from the current line #MoveInstrToRegWriteLst.append(PreviousInstr[8]) # ReadDataM if (PreviousInstr[8] != None): MoveInstrToRegWriteLst.append(Regs[PreviousInstr[8]]) # ReadDataM else: MoveInstrToRegWriteLst.append(None) lines.clear() #instructions.append(MoveInstrToRegWriteLst) prevInstrOutString = currInstrOutString currInstrOutString = PrintInstr(MoveInstrToRegWriteLst) # Remove duplicates if (PreviousInstr[0] != CurrentInstr[0]) and (currInstrOutString != None): sys.stdout.write(currInstrOutString) numInstrs += 1 if (numInstrs % 1e5 == 0): sys.stderr.write('GDB trace parser reached '+str(numInstrs/1.0e6)+' million instrs.\n') sys.stderr.flush() lineNum += 1 #for instruction in instructions[1::]: #with open(OutputFile, 'w') as OutputFileFP: # print('opened file')