diff --git a/CHANGELOG.md b/CHANGELOG.md index bf6456b..6f36a97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.11.0] - 2022-04-03 +- Added plugins to use new rvopcode format +- Added CLI option to setup rvopcode plugin + ## [0.10.2] - 2022-03-15 - Added method to generate data patterns for bitmanip instructions - diff --git a/MANIFEST.in b/MANIFEST.in index 7cbf7d0..b888a5a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ include LICENSE.incore include README.rst include riscv_isac/requirements.txt +recursive-include riscv_isac/data/* recursive-exclude * __pycache__ recursive-exclude * *.py[co] diff --git a/docs/source/add_instr.rst b/docs/source/add_instr.rst index ee6948e..f4781a7 100644 --- a/docs/source/add_instr.rst +++ b/docs/source/add_instr.rst @@ -4,7 +4,10 @@ Adding Support for new Instructions ################################### -This section details the steps for adding support for new instructions in RISCV-ISAC. +This section details the steps for adding support for new instructions in the native python plugins +of RISCV-ISAC. + +.. note:: An alternative is to add support for the new instructions using the ``riscv/riscv-opcodes`` repository. Refer :here:`rvopcodes` for further information. Update the Parser-Module ======================== diff --git a/docs/source/index.rst b/docs/source/index.rst index 94b91a3..65e30f0 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,9 +18,10 @@ please refer to the :ref:`Revisions ` documentation. overview quickstart cgf + rvopcodesdecoder add_instr - code contributing revisions licensing python_plugins + code diff --git a/docs/source/rvopcodesdecoder.rst b/docs/source/rvopcodesdecoder.rst new file mode 100644 index 0000000..cb87497 --- /dev/null +++ b/docs/source/rvopcodesdecoder.rst @@ -0,0 +1,39 @@ +.. _rvopcodes: + +Using the encodings from riscv-opcodes +====================================== + +The `rvopcodesdecoder` is a decoder plugin for RISCV-ISAC, dependent on the official `riscv-opcodes `_ repository. The `rvopcodesdecoder` plugin automatically builds the decode tree and decodes instructions based on the encodings specified in the repository. The plugin will support any instruction/extension as long as it is specified in the format adhereing to the official repository. + +Usage +~~~~~ + +Initial Setup +************* +- **Standard version**: This use case is intended for users who want to use the rvopcodes repo as + is from `riscv/riscv-opcodes `_. The command generates a + ``rvop-plugin`` folder with all the necessary files needed for the plugin. This path will have to + be passed via the CLI while running coverage. :: + + riscv_isac setup --plugin-path ./rvop-plugin + +- **Custom Version**: This use case is intended for users who have a custom/modified version of the + rvopcodes encodings locally. The ```` in the following command should point to + the path on the system where the custom/modified ``riscv-opcodes`` repository contents are located. + The command generates a symlink to the path inside the plugin folder and hence all changes to + the encodings are picked up automatically. To add an extension, the user has to create a file + with the ``rv`` prefix followed by the extension name. The file can then be populated with + the instruction encodings in the appropriate format. Similar steps can be followed for updating + existing extensions too. :: + + riscv_isac setup --plugin-path ./rvop-plugin --rvop-path + +Using the decoder with ISAC for coverage +**************************************** + +To use `rvopcodesdecoder` as the decoder in RISCV-ISAC, ``rvopcodesdecoder`` should be supplied as argument for ``--decoder-name`` option with the ``--decoder-path`` set to the path of ``rvop-plugin`` generated in the previous step.. For example, :: + + riscv_isac --verbose info coverage --decoder-name rvopcodesdecoder --decoder-path ./rvop-plugin -t trace.log --parser-name spike -o coverage.rpt -e add-01.out -c rv64i.cgf -x 64 + +.. note:: Pseudo instructions are always decoded into the mnemonics of the base instruction in this plugin. For example, `zext.h` is always decoded as `pack` only. + diff --git a/riscv_isac/__init__.py b/riscv_isac/__init__.py index 5e8f937..77fcb97 100644 --- a/riscv_isac/__init__.py +++ b/riscv_isac/__init__.py @@ -4,4 +4,4 @@ __author__ = """InCore Semiconductors Pvt Ltd""" __email__ = 'info@incoresemi.com' -__version__ = '0.10.2' +__version__ = '0.11.0' diff --git a/riscv_isac/coverage.py b/riscv_isac/coverage.py index c071da0..6bdc6b5 100644 --- a/riscv_isac/coverage.py +++ b/riscv_isac/coverage.py @@ -922,8 +922,9 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle parser_pm.add_hookspecs(ParserSpec) try: parserfile = importlib.import_module(parser_name) - except ImportError: - logger.error('Parser name invalid!') + except ImportError as e: + logger.error('Error while importing Parser!') + logger.error(e) raise SystemExit parserclass = getattr(parserfile, parser_name) parser_pm.register(parserclass()) @@ -934,8 +935,9 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle decoder_pm.add_hookspecs(DecoderSpec) try: instructionObjectfile = importlib.import_module(decoder_name) - except ImportError: - logger.error('Decoder name invalid!') + except ImportError as e: + logger.error('Error while importing Decoder!') + logger.error(e) raise SystemExit decoderclass = getattr(instructionObjectfile, "disassembler") decoder_pm.register(decoderclass()) diff --git a/riscv_isac/data/__init__.py b/riscv_isac/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/riscv_isac/data/constants.py b/riscv_isac/data/constants.py new file mode 100644 index 0000000..b6a4351 --- /dev/null +++ b/riscv_isac/data/constants.py @@ -0,0 +1,597 @@ +import re + + +isa_regex = \ +re.compile("^RV(32|64|128)[IE]+[ABCDEFGHJKLMNPQSTUVX]*(Zicsr|Zifencei|Zihintpause|Zam|Ztso|Zkne|Zknd|Zknh|Zkse|Zksh|Zkg|Zkb|Zkr|Zks|Zkn|Zba|Zbc|Zbb|Zbp|Zbr|Zbm|Zbs|Zbe|Zbf|Zbt|Zmmul|Zbpbo){,1}(_Zicsr){,1}(_Zifencei){,1}(_Zihintpause){,1}(_Zmmul){,1}(_Zam){,1}(_Zba){,1}(_Zbb){,1}(_Zbc){,1}(_Zbe){,1}(_Zbf){,1}(_Zbm){,1}(_Zbp){,1}(_Zbpbo){,1}(_Zbr){,1}(_Zbs){,1}(_Zbt){,1}(_Zkb){,1}(_Zkg){,1}(_Zkr){,1}(_Zks){,1}(_Zkn){,1}(_Zknd){,1}(_Zkne){,1}(_Zknh){,1}(_Zkse){,1}(_Zksh){,1}(_Ztso){,1}$") + +# regex to find ..= patterns in instruction +fixed_ranges = re.compile( + '\s*(?P\d+.?)\.\.(?P\d+.?)\s*=\s*(?P\d[\w]*)[\s$]*', re.M) + +# regex to find = patterns in instructions +#single_fixed = re.compile('\s+(?P\d+)=(?P[\w\d]*)[\s$]*', re.M) +single_fixed = re.compile('(?:^|[\s])(?P\d+)=(?P[\w]*)((?=\s|$))', re.M) + +# regex to find the overloading condition variable +var_regex = re.compile('(?P[a-zA-Z][\w\d]*)\s*=\s*.*?[\s$]*', re.M) + +# regex for pseudo op instructions returns the dependent filename, dependent +# instruction, the pseudo op name and the encoding string +pseudo_regex = re.compile( + '^\$pseudo_op\s+(?Prv[\d]*_[\w].*)::\s*(?P.*?)\s+(?P.*?)\s+(?P.*)$' +, re.M) + +imported_regex = re.compile('^\s*\$import\s*(?P.*)\s*::\s*(?P.*)', re.M) + +# +# Trap cause codes +causes = [ + (0x00, 'misaligned fetch'), + (0x01, 'fetch access'), + (0x02, 'illegal instruction'), + (0x03, 'breakpoint'), + (0x04, 'misaligned load'), + (0x05, 'load access'), + (0x06, 'misaligned store'), + (0x07, 'store access'), + (0x08, 'user_ecall'), + (0x09, 'supervisor_ecall'), + (0x0A, 'virtual_supervisor_ecall'), + (0x0B, 'machine_ecall'), + (0x0C, 'fetch page fault'), + (0x0D, 'load page fault'), + (0x0F, 'store page fault'), + (0x14, 'fetch guest page fault'), + (0x15, 'load guest page fault'), + (0x16, 'virtual instruction'), + (0x17, 'store guest page fault'), +] + +csrs = [ + # Standard User R/W + (0x001, 'fflags'), + (0x002, 'frm'), + (0x003, 'fcsr'), + (0x008, 'vstart'), + (0x009, 'vxsat'), + (0x00A, 'vxrm'), + (0x00F, 'vcsr'), + (0x015, 'seed'), # Zkr + + # Standard User RO + (0xC00, 'cycle'), + (0xC01, 'time'), + (0xC02, 'instret'), + (0xC03, 'hpmcounter3'), + (0xC04, 'hpmcounter4'), + (0xC05, 'hpmcounter5'), + (0xC06, 'hpmcounter6'), + (0xC07, 'hpmcounter7'), + (0xC08, 'hpmcounter8'), + (0xC09, 'hpmcounter9'), + (0xC0A, 'hpmcounter10'), + (0xC0B, 'hpmcounter11'), + (0xC0C, 'hpmcounter12'), + (0xC0D, 'hpmcounter13'), + (0xC0E, 'hpmcounter14'), + (0xC0F, 'hpmcounter15'), + (0xC10, 'hpmcounter16'), + (0xC11, 'hpmcounter17'), + (0xC12, 'hpmcounter18'), + (0xC13, 'hpmcounter19'), + (0xC14, 'hpmcounter20'), + (0xC15, 'hpmcounter21'), + (0xC16, 'hpmcounter22'), + (0xC17, 'hpmcounter23'), + (0xC18, 'hpmcounter24'), + (0xC19, 'hpmcounter25'), + (0xC1A, 'hpmcounter26'), + (0xC1B, 'hpmcounter27'), + (0xC1C, 'hpmcounter28'), + (0xC1D, 'hpmcounter29'), + (0xC1E, 'hpmcounter30'), + (0xC1F, 'hpmcounter31'), + (0xC20, 'vl'), + (0xC21, 'vtype'), + (0xC22, 'vlenb'), + + # Standard Supervisor R/W + (0x100, 'sstatus'), + (0x102, 'sedeleg'), + (0x103, 'sideleg'), + (0x104, 'sie'), + (0x105, 'stvec'), + (0x106, 'scounteren'), + (0x10A, 'senvcfg'), + (0x140, 'sscratch'), + (0x141, 'sepc'), + (0x142, 'scause'), + (0x143, 'stval'), + (0x144, 'sip'), + (0x180, 'satp'), + (0x5A8, 'scontext'), + + # Standard Hypervisor R/w + (0x200, 'vsstatus'), + (0x204, 'vsie'), + (0x205, 'vstvec'), + (0x240, 'vsscratch'), + (0x241, 'vsepc'), + (0x242, 'vscause'), + (0x243, 'vstval'), + (0x244, 'vsip'), + (0x280, 'vsatp'), + (0x600, 'hstatus'), + (0x602, 'hedeleg'), + (0x603, 'hideleg'), + (0x604, 'hie'), + (0x605, 'htimedelta'), + (0x606, 'hcounteren'), + (0x607, 'hgeie'), + (0x60A, 'henvcfg'), + (0x643, 'htval'), + (0x644, 'hip'), + (0x645, 'hvip'), + (0x64A, 'htinst'), + (0x680, 'hgatp'), + (0x6A8, 'hcontext'), + (0xE12, 'hgeip'), + + # Tentative CSR assignment for CLIC + (0x007, 'utvt'), + (0x045, 'unxti'), + (0x046, 'uintstatus'), + (0x048, 'uscratchcsw'), + (0x049, 'uscratchcswl'), + (0x107, 'stvt'), + (0x145, 'snxti'), + (0x146, 'sintstatus'), + (0x148, 'sscratchcsw'), + (0x149, 'sscratchcswl'), + (0x307, 'mtvt'), + (0x345, 'mnxti'), + (0x346, 'mintstatus'), + (0x348, 'mscratchcsw'), + (0x349, 'mscratchcswl'), + + # Standard Machine R/W + (0x300, 'mstatus'), + (0x301, 'misa'), + (0x302, 'medeleg'), + (0x303, 'mideleg'), + (0x304, 'mie'), + (0x305, 'mtvec'), + (0x306, 'mcounteren'), + (0x30a, 'menvcfg'), + (0x320, 'mcountinhibit'), + (0x340, 'mscratch'), + (0x341, 'mepc'), + (0x342, 'mcause'), + (0x343, 'mtval'), + (0x344, 'mip'), + (0x34a, 'mtinst'), + (0x34b, 'mtval2'), + (0x3a0, 'pmpcfg0'), + (0x3a1, 'pmpcfg1'), + (0x3a2, 'pmpcfg2'), + (0x3a3, 'pmpcfg3'), + (0x3a4, 'pmpcfg4'), + (0x3a5, 'pmpcfg5'), + (0x3a6, 'pmpcfg6'), + (0x3a7, 'pmpcfg7'), + (0x3a8, 'pmpcfg8'), + (0x3a9, 'pmpcfg9'), + (0x3aa, 'pmpcfg10'), + (0x3ab, 'pmpcfg11'), + (0x3ac, 'pmpcfg12'), + (0x3ad, 'pmpcfg13'), + (0x3ae, 'pmpcfg14'), + (0x3af, 'pmpcfg15'), + (0x3b0, 'pmpaddr0'), + (0x3b1, 'pmpaddr1'), + (0x3b2, 'pmpaddr2'), + (0x3b3, 'pmpaddr3'), + (0x3b4, 'pmpaddr4'), + (0x3b5, 'pmpaddr5'), + (0x3b6, 'pmpaddr6'), + (0x3b7, 'pmpaddr7'), + (0x3b8, 'pmpaddr8'), + (0x3b9, 'pmpaddr9'), + (0x3ba, 'pmpaddr10'), + (0x3bb, 'pmpaddr11'), + (0x3bc, 'pmpaddr12'), + (0x3bd, 'pmpaddr13'), + (0x3be, 'pmpaddr14'), + (0x3bf, 'pmpaddr15'), + (0x3c0, 'pmpaddr16'), + (0x3c1, 'pmpaddr17'), + (0x3c2, 'pmpaddr18'), + (0x3c3, 'pmpaddr19'), + (0x3c4, 'pmpaddr20'), + (0x3c5, 'pmpaddr21'), + (0x3c6, 'pmpaddr22'), + (0x3c7, 'pmpaddr23'), + (0x3c8, 'pmpaddr24'), + (0x3c9, 'pmpaddr25'), + (0x3ca, 'pmpaddr26'), + (0x3cb, 'pmpaddr27'), + (0x3cc, 'pmpaddr28'), + (0x3cd, 'pmpaddr29'), + (0x3ce, 'pmpaddr30'), + (0x3cf, 'pmpaddr31'), + (0x3d0, 'pmpaddr32'), + (0x3d1, 'pmpaddr33'), + (0x3d2, 'pmpaddr34'), + (0x3d3, 'pmpaddr35'), + (0x3d4, 'pmpaddr36'), + (0x3d5, 'pmpaddr37'), + (0x3d6, 'pmpaddr38'), + (0x3d7, 'pmpaddr39'), + (0x3d8, 'pmpaddr40'), + (0x3d9, 'pmpaddr41'), + (0x3da, 'pmpaddr42'), + (0x3db, 'pmpaddr43'), + (0x3dc, 'pmpaddr44'), + (0x3dd, 'pmpaddr45'), + (0x3de, 'pmpaddr46'), + (0x3df, 'pmpaddr47'), + (0x3e0, 'pmpaddr48'), + (0x3e1, 'pmpaddr49'), + (0x3e2, 'pmpaddr50'), + (0x3e3, 'pmpaddr51'), + (0x3e4, 'pmpaddr52'), + (0x3e5, 'pmpaddr53'), + (0x3e6, 'pmpaddr54'), + (0x3e7, 'pmpaddr55'), + (0x3e8, 'pmpaddr56'), + (0x3e9, 'pmpaddr57'), + (0x3ea, 'pmpaddr58'), + (0x3eb, 'pmpaddr59'), + (0x3ec, 'pmpaddr60'), + (0x3ed, 'pmpaddr61'), + (0x3ee, 'pmpaddr62'), + (0x3ef, 'pmpaddr63'), + (0x747, 'mseccfg'), + (0x7a0, 'tselect'), + (0x7a1, 'tdata1'), + (0x7a2, 'tdata2'), + (0x7a3, 'tdata3'), + (0x7a4, 'tinfo'), + (0x7a5, 'tcontrol'), + (0x7a8, 'mcontext'), + (0x7aa, 'mscontext'), + (0x7b0, 'dcsr'), + (0x7b1, 'dpc'), + (0x7b2, 'dscratch0'), + (0x7b3, 'dscratch1'), + (0xB00, 'mcycle'), + (0xB02, 'minstret'), + (0xB03, 'mhpmcounter3'), + (0xB04, 'mhpmcounter4'), + (0xB05, 'mhpmcounter5'), + (0xB06, 'mhpmcounter6'), + (0xB07, 'mhpmcounter7'), + (0xB08, 'mhpmcounter8'), + (0xB09, 'mhpmcounter9'), + (0xB0A, 'mhpmcounter10'), + (0xB0B, 'mhpmcounter11'), + (0xB0C, 'mhpmcounter12'), + (0xB0D, 'mhpmcounter13'), + (0xB0E, 'mhpmcounter14'), + (0xB0F, 'mhpmcounter15'), + (0xB10, 'mhpmcounter16'), + (0xB11, 'mhpmcounter17'), + (0xB12, 'mhpmcounter18'), + (0xB13, 'mhpmcounter19'), + (0xB14, 'mhpmcounter20'), + (0xB15, 'mhpmcounter21'), + (0xB16, 'mhpmcounter22'), + (0xB17, 'mhpmcounter23'), + (0xB18, 'mhpmcounter24'), + (0xB19, 'mhpmcounter25'), + (0xB1A, 'mhpmcounter26'), + (0xB1B, 'mhpmcounter27'), + (0xB1C, 'mhpmcounter28'), + (0xB1D, 'mhpmcounter29'), + (0xB1E, 'mhpmcounter30'), + (0xB1F, 'mhpmcounter31'), + (0x323, 'mhpmevent3'), + (0x324, 'mhpmevent4'), + (0x325, 'mhpmevent5'), + (0x326, 'mhpmevent6'), + (0x327, 'mhpmevent7'), + (0x328, 'mhpmevent8'), + (0x329, 'mhpmevent9'), + (0x32A, 'mhpmevent10'), + (0x32B, 'mhpmevent11'), + (0x32C, 'mhpmevent12'), + (0x32D, 'mhpmevent13'), + (0x32E, 'mhpmevent14'), + (0x32F, 'mhpmevent15'), + (0x330, 'mhpmevent16'), + (0x331, 'mhpmevent17'), + (0x332, 'mhpmevent18'), + (0x333, 'mhpmevent19'), + (0x334, 'mhpmevent20'), + (0x335, 'mhpmevent21'), + (0x336, 'mhpmevent22'), + (0x337, 'mhpmevent23'), + (0x338, 'mhpmevent24'), + (0x339, 'mhpmevent25'), + (0x33A, 'mhpmevent26'), + (0x33B, 'mhpmevent27'), + (0x33C, 'mhpmevent28'), + (0x33D, 'mhpmevent29'), + (0x33E, 'mhpmevent30'), + (0x33F, 'mhpmevent31'), + + # Standard Machine RO + (0xF11, 'mvendorid'), + (0xF12, 'marchid'), + (0xF13, 'mimpid'), + (0xF14, 'mhartid'), + (0xF15, 'mconfigptr'), +] + +csrs32 = [ + # Standard Hypervisor R/w + (0x615, 'htimedeltah'), + (0x61A, 'henvcfgh'), + + # Standard User RO + (0xC80, 'cycleh'), + (0xC81, 'timeh'), + (0xC82, 'instreth'), + (0xC83, 'hpmcounter3h'), + (0xC84, 'hpmcounter4h'), + (0xC85, 'hpmcounter5h'), + (0xC86, 'hpmcounter6h'), + (0xC87, 'hpmcounter7h'), + (0xC88, 'hpmcounter8h'), + (0xC89, 'hpmcounter9h'), + (0xC8A, 'hpmcounter10h'), + (0xC8B, 'hpmcounter11h'), + (0xC8C, 'hpmcounter12h'), + (0xC8D, 'hpmcounter13h'), + (0xC8E, 'hpmcounter14h'), + (0xC8F, 'hpmcounter15h'), + (0xC90, 'hpmcounter16h'), + (0xC91, 'hpmcounter17h'), + (0xC92, 'hpmcounter18h'), + (0xC93, 'hpmcounter19h'), + (0xC94, 'hpmcounter20h'), + (0xC95, 'hpmcounter21h'), + (0xC96, 'hpmcounter22h'), + (0xC97, 'hpmcounter23h'), + (0xC98, 'hpmcounter24h'), + (0xC99, 'hpmcounter25h'), + (0xC9A, 'hpmcounter26h'), + (0xC9B, 'hpmcounter27h'), + (0xC9C, 'hpmcounter28h'), + (0xC9D, 'hpmcounter29h'), + (0xC9E, 'hpmcounter30h'), + (0xC9F, 'hpmcounter31h'), + + # Standard Machine RW + (0x310, 'mstatush'), + (0x31A, 'menvcfgh'), + (0x757, 'mseccfgh'), + (0xB80, 'mcycleh'), + (0xB82, 'minstreth'), + (0xB83, 'mhpmcounter3h'), + (0xB84, 'mhpmcounter4h'), + (0xB85, 'mhpmcounter5h'), + (0xB86, 'mhpmcounter6h'), + (0xB87, 'mhpmcounter7h'), + (0xB88, 'mhpmcounter8h'), + (0xB89, 'mhpmcounter9h'), + (0xB8A, 'mhpmcounter10h'), + (0xB8B, 'mhpmcounter11h'), + (0xB8C, 'mhpmcounter12h'), + (0xB8D, 'mhpmcounter13h'), + (0xB8E, 'mhpmcounter14h'), + (0xB8F, 'mhpmcounter15h'), + (0xB90, 'mhpmcounter16h'), + (0xB91, 'mhpmcounter17h'), + (0xB92, 'mhpmcounter18h'), + (0xB93, 'mhpmcounter19h'), + (0xB94, 'mhpmcounter20h'), + (0xB95, 'mhpmcounter21h'), + (0xB96, 'mhpmcounter22h'), + (0xB97, 'mhpmcounter23h'), + (0xB98, 'mhpmcounter24h'), + (0xB99, 'mhpmcounter25h'), + (0xB9A, 'mhpmcounter26h'), + (0xB9B, 'mhpmcounter27h'), + (0xB9C, 'mhpmcounter28h'), + (0xB9D, 'mhpmcounter29h'), + (0xB9E, 'mhpmcounter30h'), + (0xB9F, 'mhpmcounter31h'), +] + +# look up table of position of various arguments that are used by the +# instructions in the encoding files. +arg_lut = {} +arg_lut['rd'] = (11, 7) +arg_lut['rt'] = (19, 15) # source+dest register address. Overlaps rs1. +arg_lut['rs1'] = (19, 15) +arg_lut['rs2'] = (24, 20) +arg_lut['rs3'] = (31, 27) +arg_lut['aqrl'] = (26, 25) +arg_lut['aq'] = (26, 26) +arg_lut['rl'] = (25, 25) +arg_lut['fm'] = (31, 28) +arg_lut['pred'] = (27, 24) +arg_lut['succ'] = (23, 20) +arg_lut['rm'] = (14, 12) +arg_lut['funct3'] = (14, 12) +arg_lut['funct2'] = (26, 25) +arg_lut['imm20'] = (31, 12) +arg_lut['jimm20'] = (31, 12) +arg_lut['imm12'] = (31, 20) +arg_lut['csr'] = (31, 20) +arg_lut['imm12hi'] = (31, 25) +arg_lut['bimm12hi'] = (31, 25) +arg_lut['imm12lo'] = (11, 7) +arg_lut['bimm12lo'] = (11, 7) +arg_lut['zimm'] = (19, 15) +arg_lut['shamt'] = (25, 20) +arg_lut['shamtw'] = (24, 20) +arg_lut['shamtw4'] = (23, 20) +arg_lut['bs'] = (31, 30) # byte select for RV32K AES +arg_lut['rnum'] = (23, 20) # round constant for RV64 AES +arg_lut['rc'] = (29, 25) +arg_lut['imm2'] = (21, 20) +arg_lut['imm3'] = (22, 20) +arg_lut['imm4'] = (23, 20) +arg_lut['imm5'] = (24, 20) +arg_lut['imm6'] = (25, 20) +arg_lut['zimm'] = (19, 15) +arg_lut['opcode'] = (6,0) +arg_lut['funct7'] = (31,25) + +# for vectors +arg_lut['vd'] = (11, 7) +arg_lut['vs3'] = (11, 7) +arg_lut['vs1'] = (19, 15) +arg_lut['vs2'] = (24, 20) +arg_lut['vm'] = (25, 25) +arg_lut['wd'] = (26, 26) +arg_lut['amoop'] = (31, 27) +arg_lut['nf'] = (31, 29) +arg_lut['simm5'] = (19, 15) +arg_lut['zimm10'] = (29, 20) +arg_lut['zimm11'] = (30, 20) + + +#compressed immediates and fields +arg_lut['c_nzuimm10'] = (12,5) +arg_lut['c_uimm7lo'] = (6,5) +arg_lut['c_uimm7hi'] = (12,10) +arg_lut['c_uimm8lo'] = (6,5) +arg_lut['c_uimm8hi'] = (12,10) +arg_lut['c_uimm9lo'] = (6,5) +arg_lut['c_uimm9hi'] = (12,10) +arg_lut['c_nzimm6lo'] = (6,2) +arg_lut['c_nzimm6hi'] = (12,12) +arg_lut['c_imm6lo'] = (6,2) +arg_lut['c_imm6hi'] = (12,12) +arg_lut['c_nzimm10hi'] = (12,12) +arg_lut['c_nzimm10lo'] = (6,2) +arg_lut['c_nzimm18hi'] = (12,12) +arg_lut['c_nzimm18lo'] = (6,2) +arg_lut['c_imm12'] = (12,2) +arg_lut['c_bimm9lo'] = (6,2) +arg_lut['c_bimm9hi'] = (12,10) +arg_lut['c_nzuimm5'] = (6,2) +arg_lut['c_nzuimm6lo'] = (6,2) +arg_lut['c_nzuimm6hi'] = (12, 12) +arg_lut['c_uimm8splo'] = (6,2) +arg_lut['c_uimm8sphi'] = (12, 12) +arg_lut['c_uimm8sp_s'] = (12,7) +arg_lut['c_uimm10splo'] = (6,2) +arg_lut['c_uimm10sphi'] = (12, 12) +arg_lut['c_uimm9splo'] = (6,2) +arg_lut['c_uimm9sphi'] = (12, 12) +arg_lut['c_uimm10sp_s'] = (12,7) +arg_lut['c_uimm9sp_s'] = (12,7) + +arg_lut['rs1_p'] = (9,7) +arg_lut['rs2_p'] = (4,2) +arg_lut['rd_p'] = (4,2) +arg_lut['rd_rs1_n0'] = (11,7) +arg_lut['rd_rs1_p'] = (9,7) +arg_lut['rd_rs1'] = (11,7) +arg_lut['rd_n2'] = (11,7) +arg_lut['rd_n0'] = (11,7) +arg_lut['rs1_n0'] = (11,7) +arg_lut['c_rs2_n0'] = (6,2) +arg_lut['c_rs1_n0'] = (11,7) +arg_lut['c_rs2'] = (6,2) + +# dictionary containing the mapping of the argument to the what the fields in +# the latex table should be +latex_mapping = {} +latex_mapping['imm12'] = 'imm[11:0]' +latex_mapping['rs1'] = 'rs1' +latex_mapping['rs2'] = 'rs2' +latex_mapping['rd'] = 'rd' +latex_mapping['imm20'] = 'imm[31:12]' +latex_mapping['bimm12hi'] = 'imm[12$\\vert$10:5]' +latex_mapping['bimm12lo'] = 'imm[4:1$\\vert$11]' +latex_mapping['imm12hi'] = 'imm[11:5]' +latex_mapping['imm12lo'] = 'imm[4:0]' +latex_mapping['jimm20'] = 'imm[20$\\vert$10:1$\\vert$11$\\vert$19:12]' +latex_mapping['zimm'] = 'uimm' +latex_mapping['shamtw'] = 'shamt' +latex_mapping['rd_p'] = "rd\\,$'$" +latex_mapping['rs1_p'] = "rs1\\,$'$" +latex_mapping['rs2_p'] = "rs2\\,$'$" +latex_mapping['rd_rs1_n0'] = 'rd/rs$\\neq$0' +latex_mapping['rd_rs1_p'] = "rs1\\,$'$/rs2\\,$'$" +latex_mapping['c_rs2'] = 'rs2' +latex_mapping['c_rs2_n0'] = 'rs2$\\neq$0' +latex_mapping['rd_n0'] = 'rd$\\neq$0' +latex_mapping['rs1_n0'] = 'rs1$\\neq$0' +latex_mapping['c_rs1_n0'] = 'rs1$\\neq$0' +latex_mapping['rd_rs1'] = 'rd/rs1' +latex_mapping['c_nzuimm10'] = "nzuimm[5:4$\\vert$9:6$\\vert$2$\\vert$3]" +latex_mapping['c_uimm7lo'] = 'uimm[2$\\vert$6]' +latex_mapping['c_uimm7hi'] = 'uimm[5:3]' +latex_mapping['c_uimm8lo'] = 'uimm[7:6]' +latex_mapping['c_uimm8hi'] = 'uimm[5:3]' +latex_mapping['c_uimm9lo'] = 'uimm[7:6]' +latex_mapping['c_uimm9hi'] = 'uimm[5:4$\\vert$8]' +latex_mapping['c_nzimm6lo'] = 'nzimm[4:0]' +latex_mapping['c_nzimm6hi'] = 'nzimm[5]' +latex_mapping['c_imm6lo'] = 'imm[4:0]' +latex_mapping['c_imm6hi'] = 'imm[5]' +latex_mapping['c_nzimm10hi'] = 'nzimm[9]' +latex_mapping['c_nzimm10lo'] = 'nzimm[4$\\vert$6$\\vert$8:7$\\vert$5]' +latex_mapping['c_nzimm18hi'] = 'nzimm[17]' +latex_mapping['c_nzimm18lo'] = 'nzimm[16:12]' +latex_mapping['c_imm12'] = 'imm[11$\\vert$4$\\vert$9:8$\\vert$10$\\vert$6$\\vert$7$\\vert$3:1$\\vert$5]' +latex_mapping['c_bimm9lo'] = 'imm[7:6$\\vert$2:1$\\vert$5]' +latex_mapping['c_bimm9hi'] = 'imm[8$\\vert$4:3]' +latex_mapping['c_nzuimm5'] = 'nzuimm[4:0]' +latex_mapping['c_nzuimm6lo'] = 'nzuimm[4:0]' +latex_mapping['c_nzuimm6hi'] = 'nzuimm[5]' +latex_mapping['c_uimm8splo'] = 'uimm[4:2$\\vert$7:6]' +latex_mapping['c_uimm8sphi'] = 'uimm[5]' +latex_mapping['c_uimm8sp_s'] = 'uimm[5:2$\\vert$7:6]' +latex_mapping['c_uimm10splo'] = 'uimm[4$\\vert$9:6]' +latex_mapping['c_uimm10sphi'] = 'uimm[5]' +latex_mapping['c_uimm9splo'] = 'uimm[4:3$\\vert$8:6]' +latex_mapping['c_uimm9sphi'] = 'uimm[5]' +latex_mapping['c_uimm10sp_s'] = 'uimm[5:4$\\vert$9:6]' +latex_mapping['c_uimm9sp_s'] = 'uimm[5:3$\\vert$8:6]' + +# created a dummy instruction-dictionary like dictionary for all the instruction +# types so that the same logic can be used to create their tables +latex_inst_type = {} +latex_inst_type['R-type'] = {} +latex_inst_type['R-type']['variable_fields'] = ['opcode', 'rd', 'funct3', \ + 'rs1', 'rs2', 'funct7'] +latex_inst_type['R4-type'] = {} +latex_inst_type['R4-type']['variable_fields'] = ['opcode', 'rd', 'funct3', \ + 'rs1', 'rs2', 'funct2', 'rs3'] +latex_inst_type['I-type'] = {} +latex_inst_type['I-type']['variable_fields'] = ['opcode', 'rd', 'funct3', \ + 'rs1', 'imm12'] +latex_inst_type['S-type'] = {} +latex_inst_type['S-type']['variable_fields'] = ['opcode', 'imm12lo', 'funct3', \ + 'rs1', 'rs2', 'imm12hi'] +latex_inst_type['B-type'] = {} +latex_inst_type['B-type']['variable_fields'] = ['opcode', 'bimm12lo', 'funct3', \ + 'rs1', 'rs2', 'bimm12hi'] +latex_inst_type['U-type'] = {} +latex_inst_type['U-type']['variable_fields'] = ['opcode', 'rd', 'imm20'] +latex_inst_type['J-type'] = {} +latex_inst_type['J-type']['variable_fields'] = ['opcode', 'rd', 'jimm20'] +latex_fixed_fields = [] +latex_fixed_fields.append((31,25)) +latex_fixed_fields.append((24,20)) +latex_fixed_fields.append((19,15)) +latex_fixed_fields.append((14,12)) +latex_fixed_fields.append((11,7)) +latex_fixed_fields.append((6,0)) diff --git a/riscv_isac/data/rvopcodesdecoder.py b/riscv_isac/data/rvopcodesdecoder.py new file mode 100644 index 0000000..22bf061 --- /dev/null +++ b/riscv_isac/data/rvopcodesdecoder.py @@ -0,0 +1,457 @@ +import glob +from operator import itemgetter +from collections import defaultdict +import pprint +import os + +from constants import * +import riscv_isac.plugins as plugins +from riscv_isac.log import logger + +from riscv_isac.InstructionObject import instructionObject + +# Closure to get argument value +def get_arg_val(arg: str): + (msb, lsb) = arg_lut[arg] + len = msb - lsb + 1 + mask = int(''.join('1' * (len)), 2) << lsb + def mcode_in(mcode: int): + val = (mask & mcode) >> lsb + return f'{val:0{len}b}' + return mcode_in + +# Functs handler +def get_funct(pos_tuple: tuple, mcode: int): + msb = pos_tuple[0] + lsb = pos_tuple[1] + mask = int(''.join('1' * (msb - lsb + 1)), 2) << lsb + val = (mask & mcode) >> lsb + + return val + +class disassembler(): + + FIRST_TWO = 0x00000003 + OPCODE_MASK = 0x0000007f + + INST_LIST = [] + + @plugins.decoderHookImpl + def setup(self, arch: str): + self.arch = arch + + # Create nested dictionary + nested_dict = lambda: defaultdict(nested_dict) + disassembler.INST_DICT = nested_dict() + disassembler.create_inst_dict('*') + + def process_enc_line(line: str): + + functs = [] + args = [] + + # get the name of instruction by splitting based on the first space + [name, remaining] = line.split(' ', 1) + + # replace dots with underscores as dot doesn't work with C/Sverilog, etc + name = name + + # remove leading whitespaces + remaining = remaining.lstrip() + + # extract bit pattern assignments of the form hi..lo=val. fixed_ranges is a + # regex expression present in constants.py. The extracted patterns are + # captured as a list in args where each entry is a tuple (msb, lsb, value) + + opcode_parsed = fixed_ranges.findall(remaining) + opcode_functs = [] + for func in opcode_parsed: + opcode_functs.append([int(a, 0) for a in func]) + + # Sort in ascending order of lsb + opcode_functs = sorted(opcode_functs, key=itemgetter(1)) + for (msb, lsb, value) in opcode_functs: + flen = msb - lsb + 1 + value = f"{value:0{flen}b}" + value = int(value, 2) + funct = (msb, lsb) + + functs.append((funct, value)) + + # parse through the args + args_list = fixed_ranges.sub(' ', remaining) + args_list = single_fixed.sub(' ', args_list).split() + for arg in args_list: + args.append(arg) + + # do the same as above but for = pattern. single_fixed is a regex + # expression present in constants.py + for (lsb, value, drop) in single_fixed.findall(remaining): + lsb = int(lsb, 0) + value = int(value, 0) + functs.append(((lsb, lsb), value)) + + return (functs, (name, args)) + + def create_inst_dict(file_filter): + ''' + Gathers files and generates instruciton list from the filter given + + Input: + file_filter: (string) A file filter + ''' + + # Default riscv-opcodes directory + opcodes_dir = os.path.join(os.path.dirname(__file__),"riscv_opcodes/") + + # file_names contains all files to be parsed in the riscv-opcodes directory + file_names = glob.glob(f'{opcodes_dir}/rv{file_filter}') + file_names += glob.glob(f'{opcodes_dir}/unratified/rv{file_filter}') + + # first pass for standard/original instructions + for f in file_names: + with open(f) as fp: + lines = (line.rstrip() + for line in fp) # All lines including the blank ones + lines = list(line for line in lines if line) # Non-blank lines + lines = list( + line for line in lines + if not line.startswith("#")) # Remove comment lines + + # go through each line of the file + for line in lines: + + # ignore all lines starting with $import and $pseudo + if '$import' in line or '$pseudo' in line: + continue + + (functs, (name, args)) = disassembler.process_enc_line(line) + args.append(os.path.basename(f)) + + # [ [(funct, val)], name, [args] ] + disassembler.INST_LIST.append([functs, name, args]) + + # second pass for pseudo-ops + for f in file_names: + with open(f) as fp: + lines = (line.rstrip() + for line in fp) # All lines including the blank ones + lines = list(line for line in lines if line) # Non-blank lines + lines = list( + line for line in lines + if not line.startswith("#")) # Remove comment lines + + # go through each line of the file + for line in lines: + # ignore all lines not starting with $pseudo + if '$pseudo' not in line: + continue + + # use the regex pseudo_regex from constants.py to find the dependent + # extension, dependent instruction, the pseudo_op in question and + # its encoding + (ext, orig_inst, pseudo_inst, line) = pseudo_regex.findall(line)[0] + + # call process_enc_line to get the data about the current + # instruction + (functs, (name, args)) = disassembler.process_enc_line(pseudo_inst + ' ' + line) + args.append(os.path.basename(f)) + + # [ [(funct, val)], name, [args] ] + disassembler.INST_LIST.append([functs, name, args]) + + # third pass for imports + for f in file_names: + with open(f) as fp: + lines = (line.rstrip() + for line in fp) # All lines including the blank ones + lines = list(line for line in lines if line) # Non-blank lines + lines = list( + line for line in lines + if not line.startswith("#")) # remove comment lines + + for line in lines: + # if the an instruction needs to be imported then go to the + # respective file and pick the line that has the instruction. + # The variable 'line' will now point to the new line from the + # imported file + + # ignore all lines starting with $import and $pseudo + if '$import' not in line : + continue + + (import_ext, reg_instr) = imported_regex.findall(line)[0] + + path = opcodes_dir + import_ext + # Find the file where the dependent extension exist. + if not os.path.exists(path): + ext1 = f'{opcodes_dir}unratified/{import_ext}' + if not os.path.exists(ext1): + raise SystemExit(1) + else: + ext = ext1 + else: + ext = path + + # Fetch the dependent instruction + for oline in open(ext): + if not re.findall(f'^\s*{reg_instr}',oline): + continue + else: + break + + (functs, (name, args)) = disassembler.process_enc_line(oline) + args.append(os.path.basename(f)) + + # [ [(funct, val)], name, [args] ] + disassembler.INST_LIST.append([functs, name, args]) + + if not disassembler.INST_LIST: + logger.error("No instruction encodings found.") + raise SystemExit + + # Insert all instructions to the root of the dictionary + disassembler.INST_DICT['root'] = disassembler.INST_LIST + + # Generate dictionary + disassembler.build_instr_dict(disassembler.INST_DICT) + + def build_instr_dict(inst_dict): + ''' + This function recursively generates the dictionary based on + highest occurrence of functs in a particular path + ''' + + # Get all instructions in the level + val = inst_dict['root'] + + # Gather all functs + funct_list = [item[0] for item in val] + funct_occ = [funct[0] for ins in funct_list for funct in ins] + + # Path recoder + funct_path = set() + # Check if there are functions remaining + while funct_occ: + if (1, 0) in funct_occ: + max_funct = (1, 0) + else: + max_funct = max(set(funct_occ),key=funct_occ.count) + + funct_occ = list(filter(lambda a: a != max_funct, funct_occ)) + + i = 0 + # For each instruciton... + while i < len(val): + # For each funct of each instruction... + for funct in val[i][0]: + if funct[0] == max_funct: + # Max funct found! + + # Push into path recorder + funct_path.add(funct) + + # Push funct and its value into the dict + temp_dict = inst_dict[funct[0]][funct[1]] + + # Create empty list in the path + if not temp_dict: + inst_dict[funct[0]][funct[1]]['root'] = [] + + # Delete appended funct + temp = val[i] + temp[0].remove(funct) + + if temp[0]: + # Add to the path + inst_dict[funct[0]][funct[1]]['root'].append(temp) + + # Remove the copied instruction from previous list + inst_dict['root'].remove(val[i]) + else: + # Append name and args + temp_dict[temp[1]] = temp[2] + i = i - 1 + i = i + 1 + else: + # Remove previous root + del inst_dict['root'] + + for funct in funct_path: + + new_path = inst_dict[funct[0]][funct[1]] + a = disassembler.build_instr_dict(new_path) + if a == None: + continue + else: + return a + return + + def get_instr(func_dict, mcode: int): + ''' + Recursively extracts the instruction from the dictionary + ''' + global instr + # Get list of functions + keys = func_dict.keys() + num_keys = len(keys) + for key in keys: + if type(key) == str and num_keys == 1: + return (key, func_dict[key]) + elif type(key) == tuple: + val = get_funct(key, mcode) + else: # There must be pseudo-ops + instr = (key, func_dict[key]) + continue + temp_func_dict = func_dict[key][val] + if temp_func_dict.keys(): + a = disassembler.get_instr(temp_func_dict, mcode) + if a == None: + continue + else: + return a + else: + continue + + @plugins.decoderHookImpl + def decode(self, instrObj_temp): + ''' + Take an instruction object with just machine code and fill + the instruction name and argument fields + + Input: + temp_instrobj: (instructionObject) + Returns: + (instructionObject) : Instruction object with names and arguments filled + None : When the dissassembler fails to decode the machine code + ''' + global instr + instr = None + + temp_instrobj = instrObj_temp + + mcode = temp_instrobj.instr + + name_args = disassembler.get_instr(disassembler.INST_DICT, mcode) + if not name_args: + name_args = instr + + # Fill out the partially filled instructionObject + if name_args: + instr_name = name_args[0] + + # Fill instruction name + temp_instrobj.instr_name = instr_name + # Fill arguments + args = name_args[1] + imm = '' + # Get extension + file_name = args[-1] + # If instruction from P extension + if file_name in ['rv_p', 'rv32_p', 'rv64_p']: + temp_instrobj.is_rvp = True + # Register type assignment + reg_type = 'x' + if file_name in ['rv_f', 'rv64_f', 'rv_d','rv64_d']: + reg_type = 'f' + for arg in args[:-1]: + if arg == 'rd': + treg = reg_type + if any([instr_name.startswith(x) for x in [ + 'fcvt.w','fcvt.l','fmv.s','fmv.d','flt','feq','fle','fclass']]): + treg = 'x' + temp_instrobj.rd = (int(get_arg_val(arg)(mcode), 2), treg) + if arg == 'rs1': + treg = reg_type + if any([instr_name.startswith(x) for x in [ + 'fsw','fsd','fcvt.s','fcvt.d','fmv.w','fmv.l']]): + treg = 'x' + temp_instrobj.rs1 = (int(get_arg_val(arg)(mcode), 2), treg) + if arg == 'rs2': + treg = reg_type + temp_instrobj.rs2 = (int(get_arg_val(arg)(mcode), 2), treg) + if arg == 'rs3': + treg = reg_type + temp_instrobj.rs3 = (int(get_arg_val(arg)(mcode), 2), treg) + if arg == 'csr': + temp_instrobj.csr = int(get_arg_val(arg)(mcode), 2) + if arg == 'shamt': + temp_instrobj.shamt = int(get_arg_val(arg)(mcode), 2) + if arg == 'shamt': + temp_instrobj.shamt = int(get_arg_val(arg)(mcode), 2) + if arg == 'shamtw': + temp_instrobj.shamt = int(get_arg_val(arg)(mcode), 2) + if arg == 'shamtw4': + temp_instrobj.shamt = int(get_arg_val(arg)(mcode), 2) + if arg == 'succ': + temp_instrobj.succ = int(get_arg_val(arg)(mcode), 2) + if arg == 'pred': + temp_instrobj.pred = int(get_arg_val(arg)(mcode), 2) + if arg == 'rl': + temp_instrobj.rl = int(get_arg_val(arg)(mcode), 2) + if arg == 'aq': + temp_instrobj.aq = int(get_arg_val(arg)(mcode), 2) + if arg == 'rm': + temp_instrobj.rm = int(get_arg_val(arg)(mcode), 2) + if arg == 'csr': + temp_instrobj.imm = int(get_arg_val(arg)(mcode), 2) + if arg.find('imm') != -1: + if arg in ['imm12', 'imm20', 'zimm', 'imm2', 'imm3', 'imm4', 'imm5']: + imm = get_arg_val(arg)(mcode) + # Reoder immediates + if arg == 'jimm20': + imm_temp = get_arg_val(arg)(mcode) + imm = imm_temp[0] + imm_temp[12:21] + imm_temp[11] + imm_temp[1:11] + '0' + if arg == 'imm12hi': + imm_temp = get_arg_val(arg)(mcode) + imm = imm_temp + imm + if arg == 'imm12lo': + imm_temp = get_arg_val(arg)(mcode) + imm = imm + imm_temp + if arg == 'bimm12hi': + imm_temp = get_arg_val(arg)(mcode) + if imm: + imm = imm_temp[0] + imm[-1] + imm_temp[1:] + imm[0:4] + '0' + else: + imm = imm_temp + imm + if arg == 'bimm12lo': + imm_temp = get_arg_val(arg)(mcode) + if imm: + imm = imm[0] + imm_temp[-1] + imm[1:] + imm_temp[0:4] + '0' + else: + imm = imm + imm_temp + if imm: + numbits = len(imm) + temp_instrobj.imm = disassembler.twos_comp(int(imm, 2), numbits) + return temp_instrobj + else: + return None + + # Utility functions + def twos_comp(val, bits): + ''' + Get the two_complement value + ''' + if (val & (1 << (bits - 1))) != 0: + val = val - (1 << bits) + return val + + def default_to_regular(d): + ''' + Utility function to convert nested defaultdict to regular dict + ''' + if isinstance(d, defaultdict): + d = {k: disassembler.default_to_regular(v) for k, v in d.items()} + return d + + def print_instr_dict(): + ''' + Print out the dictionary map to a file + ''' + printer = pprint.PrettyPrinter(indent=1, width=800, depth=None, stream=None, + compact=False, sort_dicts=False) + + s = printer.pformat(disassembler.default_to_regular(disassembler.INST_DICT)) + f = open('dict_tree.txt', 'w+') + f.write(s) + f.close() diff --git a/riscv_isac/main.py b/riscv_isac/main.py index 74bc205..1b6ada6 100644 --- a/riscv_isac/main.py +++ b/riscv_isac/main.py @@ -1,7 +1,10 @@ # See LICENSE.incore for details """Console script for riscv_isac.""" +import os import click +import shutil +from git import Repo from riscv_isac.isac import isac from riscv_isac.__init__ import __version__ @@ -74,7 +77,8 @@ def cli(verbose): @click.option( '--output-file','-o', type=click.Path(writable=True,resolve_path=True), - help="Coverage Group File" + help="Coverage Group File", + required=True ) @click.option( '--test-label', @@ -171,3 +175,49 @@ def normalize(cgf_file,output_file,xlen): utils.dump_yaml(expand_cgf(cgf_file,int(xlen)),outfile) + +@cli.command(help = 'Setup the plugin which uses the information from RISCV Opcodes repository to decode.') +@click.option('--url', + type = str, + default='https://github.com/riscv/riscv-opcodes', + required=False, + help='URL to the riscv-opcodes repo') +@click.option('--branch',type=str,default='master') +@click.option('--plugin-path', + type=click.Path(resolve_path=True,writable=True), + help="Target folder to setup the plugin files in. [./]", + default="./rvop_decoder") +@click.option("--rvop-path", + type=click.Path(resolve_path=True,writable=True), + help="Path to RVOpcodes directory.") +# Clone repo +def setup(url,branch, plugin_path, rvop_path): + # path = os.getcwd() + '/plugins/riscv_opcodes/' + if not os.path.exists(plugin_path): + logger.debug("Creating directory: "+str(plugin_path)) + os.mkdir(plugin_path) + target_dir = os.path.join(plugin_path,"riscv_opcodes/") + repo = None + if rvop_path is not None: + if not os.path.exists(rvop_path): + logger.warning("RISCV Opcodes folder not found at: "+rvop_path) + clone = click.prompt("Do you wish to clone from git?", + default='Y',type=click.Choice(['Y','n','y','N']),show_choices=True) + if clone == 'Y' or clone == 'y': + logger.debug("Cloning from Git.") + repo = Repo.clone_from(url, rvop_path) + repo.git.checkout(branch) + else: + logger.error("Exiting Setup.") + raise SystemExit + os.symlink(rvop_path,target_dir[:-1]) + else: + logger.debug("Cloning from Git.") + repo = Repo.clone_from(url, target_dir) + repo.git.checkout(branch) + plugin_file = os.path.join(os.path.dirname(__file__), "data/rvopcodesdecoder.py") + constants_file = os.path.join(os.path.dirname(__file__), "data/constants.py") + logger.debug("Copying plugin files.") + shutil.copy(plugin_file,plugin_path) + shutil.copy(constants_file,plugin_path) + diff --git a/riscv_isac/plugins/internaldecoder.py b/riscv_isac/plugins/internaldecoder.py index 7b2a43b..d9cb288 100644 --- a/riscv_isac/plugins/internaldecoder.py +++ b/riscv_isac/plugins/internaldecoder.py @@ -1363,7 +1363,7 @@ def priviledged_ops(self, instrObj): instrObj.instr_name = 'csrrsi' instrObj.rs1 = None instrObj.zimm = rs1[0] - if funct3 == 0b101: + if funct3 == 0b111: instrObj.instr_name = 'csrrci' instrObj.rs1 = None instrObj.zimm = rs1[0] diff --git a/riscv_isac/requirements.txt b/riscv_isac/requirements.txt index bf3e7cc..11b143e 100644 --- a/riscv_isac/requirements.txt +++ b/riscv_isac/requirements.txt @@ -1,4 +1,5 @@ click +gitpython ruamel.yaml>=0.16.0 pyyaml pyelftools==0.26 diff --git a/setup.cfg b/setup.cfg index 1e6d57f..6159946 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.10.2 +current_version = 0.11.0 commit = True tag = True diff --git a/setup.py b/setup.py index aeebd08..ef986dd 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ def read_requires(): setup( name='riscv_isac', - version='0.10.2', + version='0.11.0', description="RISC-V ISAC", long_description=readme + '\n\n', classifiers=[