diff --git a/.gitignore b/.gitignore index 4f00dff4..75c05ad0 100755 --- a/.gitignore +++ b/.gitignore @@ -75,11 +75,13 @@ synlog.tcl /Processor/Src/*.gz /Processor/Src/wlft* +# python +*.pyc +.ropeproject # other files /Work -*.pyc *.log *.o *.bin diff --git a/Processor/Tools/KanataConverter/.vscode/launch.json b/Processor/Tools/KanataConverter/.vscode/launch.json new file mode 100644 index 00000000..0bcaf649 --- /dev/null +++ b/Processor/Tools/KanataConverter/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + // IntelliSense を使用して利用可能な属性を学べます。 + // 既存の属性の説明をホバーして表示します。 + // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python", + "type": "python", + "request": "launch", + "stopOnEntry": false, + "python": "${command:python.interpreterPath}", + "program": "KanataConverter.py", + "cwd": "${workspaceRoot}", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "console": "internalConsole", + "args": [ + "../../Src/RSD.log", + "kanata.log", + ] + } + ] +} + diff --git a/Processor/Tools/KanataConverter/.vscode/settings.json b/Processor/Tools/KanataConverter/.vscode/settings.json new file mode 100644 index 00000000..36c9eaf4 --- /dev/null +++ b/Processor/Tools/KanataConverter/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "RISCV", + "Verilog", + "gids" + ] +} \ No newline at end of file diff --git a/Processor/Tools/KanataConverter/.vscode/tasks.json b/Processor/Tools/KanataConverter/.vscode/tasks.json new file mode 100644 index 00000000..8d337b37 --- /dev/null +++ b/Processor/Tools/KanataConverter/.vscode/tasks.json @@ -0,0 +1,65 @@ +{ + "version": "2.0.0", + + // Configuration for cygwin + "windows": { + "options": { + "env": { + "CHERE_INVOKING": "1", + "LANG": "C" + }, + "shell": { + "executable": "c:/tools/cygwin/bin/bash.exe", + "args": [ + "--login", "-c" + ] + } + } + }, + + "echoCommand": true, + "type": "shell", + "presentation": { + "reveal": "always", + "panel": "dedicated" + }, + "options": { + "cwd": "${workspaceRoot}" + }, + "tasks": [ + { + "label": "make", + "command": "make", + "args": [], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": { + "fileLocation": "absolute", + "pattern": [ + { + "regexp": "^[ ]*.*File \"(.*)\", line (\\d+?), in.*$", + "file": 1, + "line": 2, + "message": 0 + } + ] + } + }, + { + "label": "run", + "command": "make", + "args": ["run"], + "group": { + "kind": "test", + "isDefault": true + } + }, + { + "label": "clean", + "command": "make", + "args": ["clean"] + } + ] +} \ No newline at end of file diff --git a/Processor/Tools/KanataConverter/KanataConverter.py b/Processor/Tools/KanataConverter/KanataConverter.py index 88012591..fdceeabe 100644 --- a/Processor/Tools/KanataConverter/KanataConverter.py +++ b/Processor/Tools/KanataConverter/KanataConverter.py @@ -11,7 +11,7 @@ # # There are several IDs in this script: # -# gid: An unique id for each mico op in this script. +# gid: An unique id for each micro-op in this script. # This is calculated in a RSD_Parser. # cid: An unique id for each 'committed' micro op in a Kanata log. # This is calculated in a RSD_Parser. @@ -24,291 +24,11 @@ import sys import pprint + from RSD_Parser import RSD_Parser, RSD_ParserError +from KanataGenerator import KanataGenerator import RISCV_Disassembler -# -# Global constants -# -KANATA_CONVERTER_STAGE_NAME_TABLE = [ - "Np", "F", "Pd", "Dc", "Rn", "Ds", "Sc", "Is", "Rr", "X", "Ma", "Mt", "Rw", "Wc", "Cm" -] -KANATA_CONVERTER_INITIAL_CYCLE = -1 -KANATA_CONVERTER_RETIREMENT_STAGE_ID = 14 # See constants in RSD_Parser.py - - - -class KanataGenerator( object ): - """ Generate Kanata log data from parsed results. """ - - # - # Constants - # - - # Whether to output flushed ops. - KNT_OUTPUT_FLUSHED_OPS = True - - # Kanata constans related to a file header. - KNT_HEADER = "Kanata\t0004\n" - KNT_THREAD_ID = 0 - - # Kanata lanes - KNT_LANE_DEFAULT = 0 - KNT_LANE_STALL = 1 - - # Kanata command strings. - KNT_CMD_INIT = "I" - KNT_CMD_LABEL = "L" - KNT_CMD_CYCLE = "C" - KNT_CMD_STAGE_BEGIN = "S" - KNT_CMD_STAGE_END = "E" - KNT_CMD_RETIRE = "R" - - # Kanata retirement types. - KNT_CMD_ARG_RETIRE = 0 - KNT_CMD_ARG_FULSH = 1 - - # Label type - KNT_CMD_ARG_LABEL_TYPE_ABSTRACT = 0 # Shown in a left pane. - KNT_CMD_ARG_LABEL_TYPE_DETAIL = 1 # Shown in a tool-tip on a left pane. - KNT_CMD_ARG_LABEL_TYPE_STAGE = 2 # Shown in a tool-tip on each stage. - - KNT_CMD_ARG_STALL = "stl" - - class Op( object ): - """ It has information about an op. """ - - def __init__( self, sid, rid, cid, commit, label ): - self.sid = sid - self.rid = rid - self.cid = cid - self.commit = commit - self.label = label - - def __init__( self ): - self.outputFileName = "" - self.outputFile = None - - self.ops = {} # gid -> op information - self.disassembler = RISCV_Disassembler.RISCV_Disassembler() - - # - # File open/close - # - - def Open( self, fileName ): - self.outputFileName = fileName; - self.outputFile = open( self.outputFileName, "w" ) - - - def Close( self ): - if self.outputFile is not None : - self.outputFile.close() - - - # - # Make and output log data to a file. - # - def Generate( self, parser ): - """ Output Kanata log data to a output file. """ - - - # Extract parsed results. - parserOps = parser.ops - - # sid, rid, label are extracted. - rid = 0; - for sid, gid in enumerate( sorted( parserOps.keys() ) ): - parserOp = parserOps[ gid ] - - if self.KNT_OUTPUT_FLUSHED_OPS: - # Output flushed ops - genOp = KanataGenerator.Op( sid, rid, parserOp.cid, parserOp.commit, parserOp.label ) - self.ops[ gid ] = genOp - if not parserOp.clear: - rid += 1 - else: - # Don't output flushed ops - genOp = KanataGenerator.Op( rid, rid, parserOp.cid, parserOp.commit, parserOp.label ) - if not parserOp.clear: - self.ops[ gid ] = genOp - rid += 1 - - # Emit Kanata file header. - current = KANATA_CONVERTER_INITIAL_CYCLE - self.OutputHeader() - - # Emit Kanata log data. - events = parser.events - for cycle in sorted( events.keys() ): - # Write a cycle updating command. - if cycle > current: - self.Write( "%s\t%s\n" % ( self.KNT_CMD_CYCLE, cycle - current ) ) - current = cycle - - # Extract and process events at a current cycle. - for e in events[ cycle ]: - if e.gid in self.ops: - self.OutputEvent( e ) - - def Write( self, str ): - self.outputFile.write( str ) - - def OutputHeader( self ): - """ Output Kanata log header. """ - self.Write( self.KNT_HEADER ) - self.Write( "C=\t%s\n" % KANATA_CONVERTER_INITIAL_CYCLE ) - - def OutputEvent( self, event ): - """ Output an event to an output file. - This method dispatches events to corresponding handlers. - """ - type = event.type - if( type == RSD_Parser.EVENT_INIT ): - self.OnKNT_Initialize( event ) - elif( type == RSD_Parser.EVENT_STAGE_BEGIN ): - self.OnKNT_StageBegin( event ) - elif( type == RSD_Parser.EVENT_STAGE_END ): - self.OnKNT_StageEnd( event ) - elif( type == RSD_Parser.EVENT_STALL_BEGIN ): - self.OnKNT_StallBegin( event ) - elif( type == RSD_Parser.EVENT_STALL_END ): - self.OnKNT_StallEnd( event ) - elif( type == RSD_Parser.EVENT_RETIRE ): - self.OnKNT_Retire( event ) - elif( type == RSD_Parser.EVENT_FLUSH ): - self.OnKNT_Flush( event ) - - - def GetStageName( self, id ): - return KANATA_CONVERTER_STAGE_NAME_TABLE[ id ] - - def GetSID( self, gid ): - return self.ops[ gid ].sid - - def GetRID( self, gid ): - return self.ops[ gid ].rid - - def GetLabel( self, gid ): - commit = self.ops[ gid ].commit - #cid = self.ops[ gid ].cid - label = self.ops[ gid ].label - pcStr = label.pc - asmStr = self.disassembler.Disassemble( label.code ) - return "%s: %s" % (pcStr, asmStr) - - def OnKNT_Initialize( self, event ): - """ Output an initializing event. """ - gid = event.gid - sid = self.GetSID(gid) - self.Write( - "%s\t%s\t%s\t%s\n" % - (self.KNT_CMD_INIT, sid, gid, self.KNT_THREAD_ID) - ) - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_LABEL, - sid, - self.KNT_CMD_ARG_LABEL_TYPE_ABSTRACT, - self.GetLabel( gid ) - ) - ) - self.Write( - "%s\t%s\t%s\t%s\\n\n" % ( - self.KNT_CMD_LABEL, - sid, - self.KNT_CMD_ARG_LABEL_TYPE_DETAIL, - "(g:%d,c%d)" % (gid, self.ops[gid].cid) - ) - ) - - def OnKNT_StageBegin( self, event ): - """ Output an stage begin event. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_STAGE_BEGIN, - self.GetSID( event.gid ), - self.KNT_LANE_DEFAULT, - self.GetStageName( event.stageID ) - ) - ) - if event.comment != "": - self.OnKNT_Comment( event ) - - def OnKNT_StageEnd( self, event ): - """ Output an stage end event. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_STAGE_END, - self.GetSID( event.gid ), - self.KNT_LANE_DEFAULT, - self.GetStageName( event.stageID ) - ) - ) - - def OnKNT_StallBegin( self, event ): - """ Output an stall begin event. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_STAGE_BEGIN, - self.GetSID( event.gid ), - self.KNT_LANE_STALL, - self.KNT_CMD_ARG_STALL - ) - ) - - def OnKNT_StallEnd( self, event ): - """ Output an stall end event. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_STAGE_END, - self.GetSID( event.gid ), - self.KNT_LANE_STALL, - self.KNT_CMD_ARG_STALL - ) - ) - - def OnKNT_Retire( self, event ): - """ Output a retirement event. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_RETIRE, - self.GetSID( event.gid ), - self.GetRID( event.gid ), - self.KNT_CMD_ARG_RETIRE - ) - ) - - def OnKNT_Flush( self, event ): - """ Output a flush event. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_RETIRE, - self.GetSID( event.gid ), - self.GetRID( event.gid ), - self.KNT_CMD_ARG_FULSH - ) - ) - - def OnKNT_Comment( self, event ): - """ Output a comment event using a label command. """ - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_LABEL, - self.GetSID( event.gid ), - self.KNT_CMD_ARG_LABEL_TYPE_DETAIL, - event.comment - ) - ) - self.Write( - "%s\t%s\t%s\t%s\n" % ( - self.KNT_CMD_LABEL, - self.GetSID( event.gid ), - self.KNT_CMD_ARG_LABEL_TYPE_STAGE, - event.comment - ) - ) - class KanataConverter( object ): @@ -322,16 +42,15 @@ def Main( self, inputFileName, outputFileName ): parser.Open( inputFileName ) generator.Open( outputFileName ) - parser.Parse() - generator.Generate( parser ) - + parser.Parse(generator) + #generator.Generate( parser ) #pprint.pprint( parser.events ); - except IOError, (errno, strerror): - print( "I/O error(%s): %s" % ( errno, strerror ) ) + except IOError as err: + print("I/O error: %s" % err) - except RSD_ParserError, ( strerror ): - print( strerror ) + except RSD_ParserError as err: + print(err) finally: parser.Close() diff --git a/Processor/Tools/KanataConverter/KanataConverter.pyproj b/Processor/Tools/KanataConverter/KanataConverter.pyproj deleted file mode 100644 index 55edf9e8..00000000 --- a/Processor/Tools/KanataConverter/KanataConverter.pyproj +++ /dev/null @@ -1,46 +0,0 @@ - - - - Debug - 2.0 - 544d936d-6ff5-4898-a12b-8fb47549d9c5 - .\ - KanataConverter.py - - - ../../Src - . - {9a7a9026-48c1-4688-9d5d-e5699d47d074} - 2.7 - KanataConverter - KanataConverter - False - Standard Python launcher - RSD.log Kanata.log - - - - - true - false - - - true - false - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets - - - - - - - - - - - - - \ No newline at end of file diff --git a/Processor/Tools/KanataConverter/KanataConverter.sln b/Processor/Tools/KanataConverter/KanataConverter.sln deleted file mode 100644 index 5909b614..00000000 --- a/Processor/Tools/KanataConverter/KanataConverter.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "KanataConverter", "KanataConverter.pyproj", "{544D936D-6FF5-4898-A12B-8FB47549D9C5}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {544D936D-6FF5-4898-A12B-8FB47549D9C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {544D936D-6FF5-4898-A12B-8FB47549D9C5}.Release|Any CPU.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Processor/Tools/KanataConverter/KanataGenerator.py b/Processor/Tools/KanataConverter/KanataGenerator.py new file mode 100644 index 00000000..9a053130 --- /dev/null +++ b/Processor/Tools/KanataConverter/KanataGenerator.py @@ -0,0 +1,297 @@ +# -*- coding: utf-8 -*- + +# +# This script converts a RSD log to a Kanata log. +# +# Source log data is processed as follows: +# 1: RSD_Parser parses source log data, and call +# OnCycle/OnEvent of KanataGenerator. +# 2: KanataGenerator generates Kanata log data. +# +# There are several IDs in this script: +# +# gid: An unique id for each micro-op in this script. +# This id is gerated in a RSD_Parser. +# +# sid: An unique id for each 'fetched' micro op in a Kanata log. +# This id is generated from gid when output. +# rid: An unique id for each 'retired' micro op in a Kanata log. +# This id is generated from gid when output. +# + +import sys +import pprint + +from RSD_Event import RSD_Event + +# +# Global constants +# +KANATA_CONVERTER_STAGE_NAME_TABLE = [ + "Np", "F", "Pd", "Dc", "Rn", "Ds", "Sc", "Is", "Rr", "X", "Ma", "Mt", "Rw", "Wc", "Cm" +] +KANATA_CONVERTER_INITIAL_CYCLE = -1 +KANATA_CONVERTER_RETIREMENT_STAGE_ID = 14 # See constants in RSD_Parser.py + + + +class KanataGenerator(object): + """ Generate Kanata log data from parsed results. """ + + # + # Constants + # + + # Whether to output flushed ops. + KNT_OUTPUT_FLUSHED_OPS = True + + # Kanata constans related to a file header. + KNT_HEADER = "Kanata\t0004\n" + KNT_THREAD_ID = 0 + + # Kanata lanes + KNT_LANE_DEFAULT = 0 + KNT_LANE_STALL = 1 + + # Kanata command strings. + KNT_CMD_INIT = "I" + KNT_CMD_LABEL = "L" + KNT_CMD_CYCLE = "C" + KNT_CMD_STAGE_BEGIN = "S" + KNT_CMD_STAGE_END = "E" + KNT_CMD_RETIRE = "R" + + # Kanata retirement types. + KNT_CMD_ARG_RETIRE = 0 + KNT_CMD_ARG_FLUSH = 1 + + # Label type + KNT_CMD_ARG_LABEL_TYPE_ABSTRACT = 0 # Shown in a left pane. + KNT_CMD_ARG_LABEL_TYPE_DETAIL = 1 # Shown in a tool-tip on a left pane. + KNT_CMD_ARG_LABEL_TYPE_STAGE = 2 # Shown in a tool-tip on each stage. + + KNT_CMD_ARG_STALL = "stl" + + class Op(object): + """ It has information about an op. """ + def __init__(self, sid): + self.sid = sid + + + def __init__(self): + self.outputFileName_ = "" + self.outputFile_ = None + + self.opMap_ = {} # gid -> op information + + self.nextSID_ = 0 + self.lastGID_ = 0 + self.nextRID_ = 0 + + self.currentCycle_ = KANATA_CONVERTER_INITIAL_CYCLE + + # + # File open/close + # + def Open(self, fileName): + self.outputFileName_ = fileName + self.outputFile_ = open(self.outputFileName_, "w") + self.OutputHeader_() + + def Close(self): + if self.outputFile_ is not None : + self.outputFile_.close() + + def Write_(self, str): + self.outputFile_.write(str) + + + def OutputHeader_(self): + """ Output Kanata log header. """ + self.Write_(self.KNT_HEADER) + self.Write_("C=\t%s\n" % KANATA_CONVERTER_INITIAL_CYCLE) + + def OutputEvent_(self, event): + """ Output an event to an output file. + This method dispatches an event to a corresponding handler. + """ + type = event.type + if(type == RSD_Event.INIT): + self.OnKNT_Initialize_(event) + elif(type == RSD_Event.STAGE_BEGIN): + self.OnKNT_StageBegin_(event) + elif(type == RSD_Event.STAGE_END): + self.OnKNT_StageEnd_(event) + elif(type == RSD_Event.STALL_BEGIN): + self.OnKNT_StallBegin_(event) + elif(type == RSD_Event.STALL_END): + self.OnKNT_StallEnd_(event) + elif(type == RSD_Event.RETIRE): + self.OnKNT_Retire_(event) + elif(type == RSD_Event.FLUSH): + self.OnKNT_Flush_(event) + elif(type == RSD_Event.LABEL): + self.OnKNT_Label_(event) + + + def OnCycle(self, cycle): + """ This method is called from RSD_Parser """ + # Write a cycle-update command. + if cycle > self.currentCycle_: + self.Write_("%s\t%s\n" % (self.KNT_CMD_CYCLE, cycle - self.currentCycle_)) + self.currentCycle_ = cycle + + def OnEvent(self, event): + """ This method is called from RSD_Parser """ + if event.gid in self.opMap_ or event.type == RSD_Event.INIT: + self.OutputEvent_(event) + else: + print("Unknown gid:%d is in an event" % event.gid) + + + def GetStageName_(self, id): + return KANATA_CONVERTER_STAGE_NAME_TABLE[id] + + def GetSID_(self, gid): + return self.opMap_[gid].sid + + + def AddNewGID_(self, gid): + """ Register a specified gid and generates a new sid """ + if gid in self.opMap_: + print("gid:%d is re-defined." % (gid)) + else: + genOp = KanataGenerator.Op(self.nextSID_) + self.opMap_[gid] = genOp + self.nextSID_ += 1 + + if self.lastGID_ > gid: + print("lastGID:%d is greater than added gid:%d in AddNewGID" % (self.lastGID_, gid)) + self.lastGID_ = gid + + + def OnKNT_Initialize_(self, event): + """ Output an initializing event. """ + gid = event.gid + self.AddNewGID_(gid) # sid is created in this method + sid = self.GetSID_(gid) + + self.Write_( + "%s\t%s\t%s\t%s\n" % + (self.KNT_CMD_INIT, sid, gid, self.KNT_THREAD_ID) + ) + self.Write_( + "%s\t%s\t%s\t%s\\n\n" % ( + self.KNT_CMD_LABEL, + sid, + self.KNT_CMD_ARG_LABEL_TYPE_DETAIL, + "(g:%d,c0)" % (gid) + ) + ) + + def OnKNT_StageBegin_(self, event): + """ Output a stage begin event. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_STAGE_BEGIN, + self.GetSID_(event.gid), + self.KNT_LANE_DEFAULT, + self.GetStageName_(event.stageID ) + ) + ) + if event.comment != "": + self.OnKNT_Comment(event ) + + def OnKNT_StageEnd_(self, event): + """ Output a stage end event. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_STAGE_END, + self.GetSID_(event.gid), + self.KNT_LANE_DEFAULT, + self.GetStageName_(event.stageID ) + ) + ) + + def OnKNT_StallBegin_(self, event): + """ Output a stall begin event. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_STAGE_BEGIN, + self.GetSID_(event.gid), + self.KNT_LANE_STALL, + self.KNT_CMD_ARG_STALL + ) + ) + + def OnKNT_StallEnd_(self, event): + """ Output a stall end event. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_STAGE_END, + self.GetSID_(event.gid), + self.KNT_LANE_STALL, + self.KNT_CMD_ARG_STALL + ) + ) + + def OnKNT_Retire_(self, event): + """ Output a retirement event. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_RETIRE, + self.GetSID_(event.gid), + self.nextRID_, + self.KNT_CMD_ARG_RETIRE + ) + ) + + self.nextRID_ += 1 + del self.opMap_[event.gid] + + # GC + if event.gid % 64 == 0: + for gid in list(self.opMap_.keys()): + if gid < event.gid: + del self.opMap_[gid] + + def OnKNT_Flush_(self, event): + """ Output a flush event. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_RETIRE, + self.GetSID_(event.gid), + 0, + self.KNT_CMD_ARG_FLUSH + ) + ) + + def OnKNT_Comment(self, event): + """ Output a comment event using a label command. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_LABEL, + self.GetSID_(event.gid), + self.KNT_CMD_ARG_LABEL_TYPE_DETAIL, + event.comment + ) + ) + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_LABEL, + self.GetSID_(event.gid), + self.KNT_CMD_ARG_LABEL_TYPE_STAGE, + event.comment + ) + ) + + def OnKNT_Label_(self, event): + """ Output a label event using a label command. """ + self.Write_( + "%s\t%s\t%s\t%s\n" % ( + self.KNT_CMD_LABEL, + self.GetSID_(event.gid), + self.KNT_CMD_ARG_LABEL_TYPE_ABSTRACT, + event.comment + ) + ) diff --git a/Processor/Tools/KanataConverter/Makefile b/Processor/Tools/KanataConverter/Makefile new file mode 100644 index 00000000..ac1e2814 --- /dev/null +++ b/Processor/Tools/KanataConverter/Makefile @@ -0,0 +1,11 @@ +TARGET = KanataConverter.py +PYTHON = C:/dev/env/python/3.4/python + +all: run + +run: $(TARGET) + $(PYTHON) $(TARGET) ../../Src/RSD.log kanata.log + +clean: + rm kanata.log + diff --git a/Processor/Tools/KanataConverter/RSD_Event.py b/Processor/Tools/KanataConverter/RSD_Event.py new file mode 100644 index 00000000..1987b4aa --- /dev/null +++ b/Processor/Tools/KanataConverter/RSD_Event.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +class RSD_Event(object): + """ Parser event types """ + + INIT = 0 + STAGE_BEGIN = 1 + STAGE_END = 2 + STALL_BEGIN = 3 + STALL_END = 4 + RETIRE = 5 + FLUSH = 6 + LABEL = 7 diff --git a/Processor/Tools/KanataConverter/RSD_Parser.py b/Processor/Tools/KanataConverter/RSD_Parser.py index 9dba97d9..db553b38 100644 --- a/Processor/Tools/KanataConverter/RSD_Parser.py +++ b/Processor/Tools/KanataConverter/RSD_Parser.py @@ -2,23 +2,14 @@ # # Parse a RSD log file. -# -# This class is used by KanataConverter. -# -# There are several IDs in this script: -# -# iid: An unique id for each instruction in a RSD log file. -# This is outputted from SystemVerilog code. -# mid: The index of a micro op in an instruction. -# This is outputted from SystemVerilog code. -# -# gid: An unique id for each mico op in this script. -# This is calculated from iid and mid for internal use. -# cid: An unique id for each 'committed' micro op in a Kanata log. -# This is calculated from gid. +# Please see the comments in KanataGenerator.py # + import re +from KanataGenerator import KanataGenerator +from RSD_Event import RSD_Event +from RISCV_Disassembler import RISCV_Disassembler # # Global constants @@ -27,12 +18,12 @@ RSD_PARSER_RETIREMENT_STAGE_ID = 14 RSD_PARSER_CID_DEFAULT = -1 -class RSD_ParserError( Exception ): +class RSD_ParserError(Exception): """ An exception class for RSD_Parser """ pass -class RSD_Parser( object ): +class RSD_Parser(object): """ Parse RSD log data. """ # Constants @@ -47,158 +38,155 @@ class RSD_Parser( object ): RSD_CMD_COMMENT = "#" # Bit width of OpSerial in SystemVerilog code. - # OpSerial becomes iid in this python script. + # An id stored in OpSerial signal is loaded as "iid" in this python script. + # See the comments in CreateGID() OP_SERIAL_WIDTH = 10 - # Max micro ops per an instruction. + # Max micro-ops per an instruction. MAX_MICRO_OPS_PER_INSN = 4 # Wrap around of gid caused by wrap around of iid. GID_WRAP_AROUND = 2 ** OP_SERIAL_WIDTH * MAX_MICRO_OPS_PER_INSN - def CreateGID( self, iid, mid ): - """ Create unique 'gid' from 'iid' and 'mid'. - """ + # Create unique 'gid' from 'iid' and 'mid'. + # Since 'iid' is stored in a signal with the limited width of OpSerial, + # 'iid' causes wrap around. So this script generats an unique id called 'gid' + # from 'iid' and current state. + def CreateGID_(self, iid, mid): + """ Create unique 'gid' from 'iid' and 'mid'. """ if mid >= RSD_Parser.MAX_MICRO_OPS_PER_INSN: - raise RSD_ParserError( "'mid' exceeds MAX_MICRO_OPS_PER_INSN at iid(%s)" % iid ) + raise RSD_ParserError("'mid' exceeds MAX_MICRO_OPS_PER_INSN at iid(%d)" % iid ) - gid = mid + iid * RSD_Parser.MAX_MICRO_OPS_PER_INSN - - # Convert a gid wrapped around to a unique gid. - # - Search min( n : gid + n * GID_WRAP_AROUND > max-retired-gid - margin ) - # - margin : GID_WRAP_AROUND / 2 - # - Set gid = gid + n * GID_WRAP_AROUND - if len( self.retired ) != 0: - numWrapAround = ( self.maxRetiredOp + RSD_Parser.GID_WRAP_AROUND / 2 - gid ) / RSD_Parser.GID_WRAP_AROUND - gid += RSD_Parser.GID_WRAP_AROUND * numWrapAround + # A B + # |<----W---->|<----W---->| + # |----r---g--|-----------|: n = A + # |----g---r--|-----------|: n = A + # |--------r--|--g--------|: n = B + # |--------g--|--r--------|: n = A + g = mid + iid * RSD_Parser.MAX_MICRO_OPS_PER_INSN + W = RSD_Parser.GID_WRAP_AROUND + M = W / 4 + r = self.maxRetiredOp_ % W + n = self.maxRetiredOp_ - r + + # The maximum difference between g and r must be less than W/2, + # so the maximum number if in-flight ops must be less than GID_WRAP_AROUND/2 + # |--------r--|--g--------|: n = B + if r > M * 3 and g < M: + n = n + W + # |--------g--|--r--------|: n = A + if g > M * 3 and r < M: + n = n - W + + gid = n + g return gid - # Event types - EVENT_INIT = 0 - EVENT_STAGE_BEGIN = 1 - EVENT_STAGE_END = 2 - EVENT_STALL_BEGIN = 3 - EVENT_STALL_END = 4 - EVENT_RETIRE = 5 - EVENT_FLUSH = 6 - # # Internal classes # - - class Label( object ): - """ Label information of an op """ - def __init__( self ): - self.iid = 0 - self.mid = 0 - self.pc = 0 - self.code = "" - - def __repr__( self ): - return "{iid:%d, mid:%d, pc: %s, code: %s}" % ( self.iid, self.mid, self.pc, self.code ) - - class Op( object ): + class Op(object): """ Op class. """ - def __init__( self, iid, mid, gid, stall, clear, stageID, updatedCycle ): + def __init__(self, iid, mid, gid, stall, clear, stageID, updatedCycle): self.iid = iid self.mid = mid self.gid = gid - self.cid = RSD_PARSER_CID_DEFAULT self.stageID = stageID self.stall = stall self.clear = clear self.updatedCycle = updatedCycle - self.commit = False + self.labelOutputted = False - self.label = RSD_Parser.Label() - - def __repr__( self ): + def __repr__(self): return ( - "{gid:%s, cid: %s, stall:%s, clear:%s, stageID:%s, updatedCycle: %s}" % - ( self.gid, self.cid, self.stall, self.clear, self.stageID, self.updatedCycle ) + "{gid:%s, stall:%s, clear:%s, stageID:%s, updatedCycle: %s}" % + (self.gid, self.stall, self.clear, self.stageID, self.updatedCycle) ) - class Event( object ): + class Event(object): """ Event class """ - def __init__( self, gid, type, stageID, comment ): + def __init__(self, gid, type, stageID, comment): self.gid = gid self.type = type self.stageID = stageID self.comment = comment - def __repr__( self ): + def __repr__(self): return ( "{gid:%s, type:%s, stageID:%s, comment:%s}" % - ( self.gid, self.type, self.stageID, self.comment ) + (self.gid, self.type, self.stageID, self.comment) ) - def __init__( self ): + def __init__(self): """ Initializer """ - self.inputFileName = "" - self.inputFile = None + self.inputFileName_ = "" + self.inputFile_ = None # A current processor cycle. - self.currentCycle = RSD_PARSER_INITIAL_CYCLE + self.currentCycle_ = RSD_PARSER_INITIAL_CYCLE + + self.ops_ = {} # gid -> Op map + self.events_ = {} # cycle -> Event map + self.flushedOpGIDs__ = set([]) # retired gids + self.maxRetiredOp_ = 0 # The maximum number in retired ops. + self.committedOpNum_ = 0 # Num of committed ops. - self.ops = {} # gid -> Op map - self.events = {} # cycle -> Event map - self.retired = set( [] ) # retired gids - self.maxRetiredOp = 0; # The maximum number in retired ops. - self.committedOpNum = 0; # Num of committed ops. + self.generator = None + self.lineNum_ = 1 + self.disasm_ = RISCV_Disassembler() + self.wordRe_ = re.compile(r"[\t\n\r]") - def Open( self, inputFileName ): - self.inputFileName = inputFileName - self.inputFile = open( inputFileName, "r" ); - def Close( self ): - if self.inputFile is not None : - self.inputFile.close() + def Open(self, inputFileName): + self.inputFileName_ = inputFileName + self.inputFile_ = open(inputFileName, "r") + + def Close(self): + if self.inputFile_ is not None : + self.inputFile_.close() # # Parsing file # - def ProcessHeader( self, line ): - """ Process a file hedaer """ + def ProcessHeader_(self, line): + """ Process a file header """ - words = re.split( r"[\t\n\r]", line ) + words = self.wordRe_.split(line) header = words[0] if header != self.RSD_HEADER : - raise RSD_ParserError( - "An unknown file format." - ) + raise RSD_ParserError("An unknown file format.") # Check a file version - version = int( words[1] ) + version = int(words[1]) if version != self.RSD_VERSION : - raise RSD_ParserError( - "An unknown file version: %d" % ( version ) - ) + raise RSD_ParserError("An unknown file version: %d" % (version)) - def ProcessLine( self, line ): + def ProcessLine_(self, line): """ Process a line. """ - words = re.split( r"[\t\n\r]", line ) + words = self.wordRe_.split(line) cmd = words[0] if cmd == self.RSD_CMD_STAGE : - self.OnRSD_Stage( words ) + self.OnRSD_Stage_(words) elif cmd == self.RSD_CMD_LABEL : - self.OnRSD_Label( words ) + self.OnRSD_Label_(words ) elif cmd == self.RSD_CMD_CYCLE : - self.OnRSD_Cycle( words ) + self.OnRSD_Cycle_(words ) elif cmd == self.RSD_CMD_COMMENT : pass # A comment is not processed. + elif cmd == "": + pass # A blank line is skipped else: - raise RSD_ParserError( "Unknown command:'%s'" % (cmd) ); + raise RSD_ParserError("Unknown command:'%s'" % cmd) - def OnRSD_Stage( self, words ): + def OnRSD_Stage_(self, words): """ Dump a stage state. Format: 'S', stage, valid, stall, flush, iid, mid, comment @@ -208,152 +196,190 @@ def OnRSD_Stage( self, words ): if words[2] == 'x': valid = False else: - valid = int( words[2] ) - if( not valid ): + valid = int(words[2]) + if(not valid): return - op = self.CreateOpFromString( words ) + op = self.CreateOpFromString_(words) # if both stall and clear signals are asserted, it means send bubble and # it is not pipeline flush. - flush = op.clear and not op.stall; + flush = op.clear and not op.stall - if (op.gid in self.retired): + if (op.gid in self.flushedOpGIDs__): if flush: # Ops in a backend may be flush more than once, because there # are ops in pipeline stages and an active list. return else: - print "A retired op is dumped. op: (%s)" % ( op.__repr__() ) + print("A retired op is dumped. op: (%s)" % op.__repr__()) comment = words[7] - current = self.currentCycle + current = self.currentCycle_ gid = op.gid retire = op.stageID == RSD_PARSER_RETIREMENT_STAGE_ID + if gid < self.maxRetiredOp_: + print("A retired op is dumped. op: (%s)" % op.__repr__()) + # Check whether an event occurs or not. - if gid in self.ops: - prevOp = self.ops[ gid ] - op.label = prevOp.label + if gid in self.ops_: + prevOp = self.ops_[ gid ] + op.labelOutputted = prevOp.labelOutputted # End stalling if prevOp.stall and not op.stall: - self.AddEvent( current, gid, self.EVENT_STALL_END, prevOp.stageID, "" ) + self.AddEvent_(current, gid, RSD_Event.STALL_END, prevOp.stageID, "") # End and begin a current stage For output comment. - self.AddEvent( current, gid, self.EVENT_STAGE_END, prevOp.stageID, "" ) - self.AddEvent( current, gid, self.EVENT_STAGE_BEGIN, op.stageID, comment ) + self.AddEvent_(current, gid, RSD_Event.STAGE_END, prevOp.stageID, "") + self.AddEvent_(current, gid, RSD_Event.STAGE_BEGIN, op.stageID, comment) # Begin stalling if not prevOp.stall and op.stall: - self.AddEvent( current, gid, self.EVENT_STALL_BEGIN, op.stageID, comment ) + self.AddEvent_(current, gid, RSD_Event.STALL_BEGIN, op.stageID, comment) # End/Begin a stage if prevOp.stageID != op.stageID: - self.AddEvent( current, gid, self.EVENT_STAGE_END, prevOp.stageID, "" ) - self.AddEvent( current, gid, self.EVENT_STAGE_BEGIN, op.stageID, comment ) + self.AddEvent_(current, gid, RSD_Event.STAGE_END, prevOp.stageID, "") + self.AddEvent_(current, gid, RSD_Event.STAGE_BEGIN, op.stageID, comment) if retire: - self.AddRetiredGID( gid ) # Count num of committed ops. - op.commit = True - op.cid = self.committedOpNum - self.committedOpNum += 1 + self.RetireOp_(op) + self.committedOpNum_ += 1 # Close a last stage - self.AddEvent( current + 1, gid, self.EVENT_STAGE_END, op.stageID, "" ) - self.AddEvent( current + 1, gid, self.EVENT_RETIRE, op.stageID, "" ) + self.AddEvent_(current + 1, gid, RSD_Event.STAGE_END, op.stageID, "") + self.AddEvent_(current + 1, gid, RSD_Event.RETIRE, op.stageID, "") else: # Initialize/Begin a stage - self.AddEvent( current, gid, self.EVENT_INIT, op.stageID, "" ) - self.AddEvent( current, gid, self.EVENT_STAGE_BEGIN, op.stageID, comment ) - if ( op.stall ): - self.AddEvent( current, gid, self.EVENT_STALL_BEGIN, op.stageID, "" ) + self.AddEvent_(current, gid, RSD_Event.INIT, op.stageID, "") + self.AddEvent_(current, gid, RSD_Event.STAGE_BEGIN, op.stageID, comment) + if (op.stall): + self.AddEvent_(current, gid, RSD_Event.STALL_BEGIN, op.stageID, "") # if both stall and clear signals are asserted, it means send bubble and # it is not pipeline flush. if flush: - self.AddRetiredGID( gid ) - prevOp = self.ops[ gid ] + prevOp = self.ops_[ gid ] if prevOp.stageID == 0: # When an instruction was flushed in NextPCStage, - # delete the op from self.ops so that the instruction is not dumped - del self.ops[ gid ] + # delete the op from self.ops_ so that the instruction is not dumped + del self.ops_[ gid ] return else: # Add events about flush - self.AddEvent( current, gid, self.EVENT_STAGE_END, op.stageID, "" ) - self.AddEvent( current, gid, self.EVENT_FLUSH, op.stageID, comment ) - - self.ops[ gid ] = op + self.AddEvent_(current, gid, RSD_Event.STAGE_END, op.stageID, "") + self.AddEvent_(current, gid, RSD_Event.FLUSH, op.stageID, comment) + self.FlushOp_(op) + + self.ops_[ gid ] = op - def CreateOpFromString( self, words ): + def CreateOpFromString_(self, words): """ Create an op from strings split from a source line text. Format: 'S', stage, stall, valid, clear, iid, mid """ - stageID = int( words[1] ) - stall = int( words[3] ) != 0 - clear = int( words[4] ) != 0 - iid = int( words[5] ) - mid = int( words[6] ) - gid = self.CreateGID( iid, mid ) - return self.Op( iid, mid, gid, stall, clear, stageID, self.currentCycle ) - - - def AddEvent( self, cycle, gid, type, stageID, comment ): + stageID = int(words[1]) + stall = int(words[3]) != 0 + clear = int(words[4]) != 0 + iid = int(words[5]) + mid = int(words[6]) + gid = self.CreateGID_(iid, mid) + return self.Op(iid, mid, gid, stall, clear, stageID, self.currentCycle_) + + def AddEvent_(self, cycle, gid, type, stageID, comment): """ Add an event to an event list. """ - event = self.Event( gid, type, stageID, comment ) - if cycle not in self.events: - self.events[ cycle ] = [] - self.events[ cycle ].append( event ) + event = self.Event(gid, type, stageID, comment) + if cycle not in self.events_: + self.events_[ cycle ] = [] + self.events_[ cycle ].append(event) - def OnRSD_Label( self, words ): + def OnRSD_Label_(self, words): """ Dump information about an op Format: 'L', iid, mid, pc, code """ - iid = int( words[1] ) - mid = int( words[2] ) + iid = int(words[1]) + mid = int(words[2]) pc = words[3] code = words[4] - gid = self.CreateGID( iid, mid ) + gid = self.CreateGID_(iid, mid) - # Add label information to a label database. - label = self.ops[ gid ].label - label.iid = iid; - label.mid = mid; - label.pc = pc - label.code = code + if gid not in self.ops_: + print("Label is outputtted with an unknown gid:%d" % gid) + op = self.ops_[gid] + if not op.labelOutputted: + op.labelOutputted = True + asmStr = self.disasm_.Disassemble(code) + comment = "%s: %s" % (pc, asmStr) + self.AddEvent_(self.currentCycle_, gid, RSD_Event.LABEL, -1, comment) - def OnRSD_Cycle( self, words ): + def OnRSD_Cycle_(self, words): """ Update a processor cycle. Format: 'C', 'incremented value' """ - self.currentCycle += int( words[1] ) + self.currentCycle_ += int(words[1]) + self.ProcessEvents_(dispose=False) + + + def ProcessEvents_(self, dispose): + events = self.events_ + for cycle in sorted(events.keys()): + # イベント投入された後のサイクルで一部取り消されるものがあるためバッファする + # 基本的に Np ステージでの命令取り消しのみのはず + if not dispose and cycle > self.currentCycle_ - 3: + break + self.generator.OnCycle(cycle) + + # Extract and process events at a current cycle. + for e in events[cycle]: + if e.gid in self.ops_: + self.generator.OnEvent(e) + + if e.type == RSD_Event.RETIRE: + del self.ops_[e.gid] + # GC + # リタイアした命令より古いものを削除する + if e.gid % 64 == 0: + for gid in list(self.ops_): + if gid < e.gid: + del self.ops_[gid] + + del events[cycle] - def AddRetiredGID(self, gid): - """ Add a gid to a retired op list. """ - self.retired.add(gid) - self.maxRetiredOp = max(self.maxRetiredOp, gid) + def RetireOp_(self, op): + self.maxRetiredOp_ = max(self.maxRetiredOp_, op.gid) + # リタイアした命令より前のフラッシュされた命令を削除 + for gid in list(self.flushedOpGIDs__): + if gid < self.maxRetiredOp_: + self.flushedOpGIDs__.remove(gid) - def Parse( self ): + def FlushOp_(self, op): + self.flushedOpGIDs__.add(op.gid) + del self.ops_[op.gid] + + def Parse(self, generator): """ Parse an input file. This method includes a main loop that parses a file. """ - - file = self.inputFile + self.generator = generator + file = self.inputFile_ # Process a file header. headerLine = file.readline() - self.ProcessHeader( headerLine ) + self.ProcessHeader_(headerLine) # Parse lines. while True: line = file.readline() if line == "" : break - self.ProcessLine( line ) + self.ProcessLine_(line) + self.lineNum_ = self.lineNum_ + 1 + + self.ProcessEvents_(dispose=True)