mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #! /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 <interrupt filename>>')
 | |
| 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')
 | |
| 
 | |
| 
 | |
| 
 |