Giter Club home page Giter Club logo

microprobe's Introduction

Getting started

Build Status

GitHub GitHub forks GitHub stars GitHub watchers

PyPI - License PyPI - Implementation PyPI - Python Version PyPI - Wheel

PyPI - Downloads - Day PyPI - Downloads - Week PyPI - Downloads - Month

This is a short description. We refer you to the full documentation that can be found here:

https://ibm.github.io/microprobe/

IBM users can refer to the following extended documentation:

https://pages.github.ibm.com/MicroProbe/microprobe_private/

Required commands

First-time set up

We are assuming a bash environment throughout the process. You might try to use other shell, although some commands might need to be modified accordingly. Execute the following commands the first time:

git clone --recursive [email protected]:IBM/microprobe.git INSTALLDIRECTORY/microprobe
cd INSTALLDIRECTORY/microprobe
bootstrap_environment.sh

Hopefully, the installation is complete. Otherwise, report the error to the development team. The commands above did the following: create a virtual python environment to avoid any dependency issues (which we found quite often...) and activate it. Then, we have checked out the repository and all of its submodules. Finally, we installed the required dependencies.

Using Microprobe

Assuming that all the variables above are set in your environment, you just need to execute the following command to start using Microprobe.

cd INSTALLDIRECTORY
source activate_microprobe

You will see that you command prompt changes. You should be able to execute the Microprobe related commands. This should be the only command you need to execute before using Microprobe related commands.

Updating Microprobe

Since we are in development mode, you just need to go to INSTALLDIRECTORY/microprobe and execute the following command:

git pull --update --recurse-submodules
find . -name \.*.cache -delete
find . -name \.*.lock -delete

Basically, we are pulling the latest copy of the repository and the submodules, and cleaning up any cached files.

Contributing to Microprobe

See CONTRIBUTING for policies on pull-requests to this repo.

Microprobe

Microprobe is a productive microbenchmark generation framework that an user can adapt towards exercising a complex multi-core, multi-threaded computing system in a variety of redundant ways for answering a range of questions related to energy and performance.

The growth in complexity of microprocessor systems today --composed of multi-core, multi-threaded processors with multi-level cache hierarchies and giga-bytes of memory--, hardens the pre-silicon system modeling and the post-silicon system characterizations. We believe that microbenchmarks, generated with particular objectives in mind, hold the key to obtaining accurate characterizations of microprocessor systems. Specially crafted microbenchmarks may be run on simulators (pre-silicon stage) or real machines (post-silicon stage) to help understand, diagnose and fix deficiencies systematically. However, manual generation of such "stress-marks" is tedious, and requires intimate knowledge of the underlying microarchitecture pipeline semantics. Automated microbenchmark generation is therefore crucial in this regard. Microprobe is developed to fulfill that need.

Key features

The automated generation facility must maximize the productivity of the end-user, allowing the generation of different classes of microbenchmarks that are useful in answering a range of different (unknown/future) questions. Therefore, we develop Microprobe with the following features in mind:

  • Adaptive and flexible. We design the microbenchmark synthesizer of Microprobe to work in a compiler-like fashion, i.e. applying a set of passes to a internal representation of the microbenchmark. This allows the users to adapt the microbenchmark generation process to their needs, providing the flexibility and the extensibility required.

  • Microarchitecture semantics aware. Microprobe includes low-level information of the target microarchitectures. This information is crucial to assist the generation of microarchitecture aware microbenchmarks, allowing the definition of microbenchmark generation policies based on them. It provides a white-box solution to the users to define microbenchmarks with very specific microarchitecture properties, avoiding the need to master every detail of the complex underlying architectures.

  • Integrated design space exploration (DSE). Design space explorations have become mandatory to understand the performance of computer architectures due to their increase in complexity. In addition, DSE are required to find microbenchmarks that fulfill a set of dynamic properties that cannot be ensured statically (during code generation). DSE support is therefore a basic functionality that any productive microbenchmark generation framework should have. Microprobe provides generic DSE support to be able to implement different customizable search strategies within the design space defined by the user (feature not yet released)

microprobe's People

Contributors

arnaubigas avatar karthiksv avatar patrick-rivos avatar rbertran avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

microprobe's Issues

Tracking issue: Type hints

Type hints are very helpful when reading/refactoring/debugging code. They can help show issues without running the code, and highlight edge cases before they're ever executed.

Notes:
Q: Why wrap imports in an if TYPE_CHECKING: statement?
A: Otherwise, we get circular dependencies. Since types aren't actually used at runtime, imports can be safely gated so they're only included when type checking.

Q: Why not annotate return types?
A: The derived return types include things like None, which people are often tempted to omit when typing a function. Allowing MyPy to derive the types on its own ensures we are being honest and get warned when a function's output does not match our expectations.

Q: How do you determine the type to annotate with?
A: I use existing comments, search the codebase for call sites, and print(type(x)) when I'm really lost. It's a best guess, so I may need to update some types as more of the codebase is annotated.

Directories to add type hints to:

  • src/microprobe
    • code #38
    • driver
    • model #48
    • passes
    • schemas
    • target #42
    • utils
    • other files in this dir
  • targets
    • generic #49
    • powerpc
    • riscv

[RiscV] "No candidates found for (...)" when reading MPT containing BLT instruction

When I try to run the mp_mpt2c tool on an MPT file which contains a RiscV BLT instruction the program crashes with the following error: No candidates found for 0xfaf740e3

The following options are used: -T riscv_v22-riscv_generic-riscv64_linux_gcc --fix-indirect-branches --fix-branch-next --fix-memory-registers.

If we use objdump to decode the actual instruction in the binary we can see it is as follows:

105d4: faf740e3 blt a4,a5,10574 <intVecSum+0x28>

Attached in this issue there is the debug log output (log.txt). There you will observe how there is some issue regarding the immediate. From the objdump above we can see how the immediate should be -96, but instead in the attached log microprobe is trying to use -3. I suspect there is a bug in the code in charge of decoding an instruction from binary in which the proper formatting of the instruction is not taken into account. Remember that the "B" format in riscv, which is the one used for this instruction, has some weirdly coded immediate which is not only divided in two subfields but also the bits are not ordered. This suggests that this bug could also happen with other branch-related instructions which use the same format.

How to reproduce

  1. Create an MPT file containing the BLT instruction (one is already attached to this issue: vecsum.0.mpt.zip)
  2. Execute the following command: mp_mpt2c.py -t testfile.mpt -O benchmark.c -T riscv_v22-riscv_generic-riscv64_linux_gcc --fix-indirect-branches --fix-branch-next --fix-memory-registers

[RISC-V] Failure to set register value when the upper 32 bits are all ones

The RISC-V isa.py's set_register function fails to set the value 0xFFFFFFFF3C23D70A to a register. The critical code failing is:

if value_high > 2047:
    value_highest = value_highest + 1
    value_high = value_high - (4096)

lui = self.new_instruction("LUI_V0")
lui.set_operands([value_highest, register])
instrs.append(lui)

In this code snippet, value_highest = 0xFFFFF and value_high = 0xFFF. This causes value_highest to become a value out of the 20-bit immediate range of the LUI instruction. I think the code should be revised in greater detail, as I remember encountering a similar problem in the past. This might be a regression caused by ce0ae0d.

Find attached the log.txt and the microbenchmark.zip to reproduce this issue.

Thanks.

Knobs for control flow

Hello @rbertran,

Can you provide some info on how to control the branch taken / not-taken patterns. I see that there is an "InitializeBranchDecorator" pass which deals with T / NT but I'm not sure about what it does, and if its the right one how to use it. Thanks!

How to set up a model for a GenericMemoryStreamsPass?

This is an extension to question #6 .

Could you please provide details (or an example) on how to setup a 'model' for a GenericMemoryStreamsPass (implemented at src/microprobe/passes/memory). My understanding from @rbertran's response in question #6 is that the model should be able to provide information on multiple memory streams. Thanks!

Thanks,
Gokul

Infra: Error in running latest microprobe version

Hi @rbertran

I'm facing some infra issue after syncing to the latest microprobe version:


/research/sgokul/MicroProbe/microprobe/targets/riscv/examples$ ./riscv_ipc.py 
Traceback (most recent call last):
  File "./riscv_ipc.py", line 165, in <module>
    RiscvIpcTest().emit()
  File "./riscv_ipc.py", line 101, in __init__
    self.args.isa, self.args.uarch, self.args.env)
  File "/research/sgokul/MicroProbe/microprobe/src/microprobe/target/__init__.py", line 93, in import_definition
    definition_tuple = _parse_definition_tuple(definition_tuple)
  File "/research/sgokul/MicroProbe/microprobe/src/microprobe/target/__init__.py", line 153, in _parse_definition_tuple
    "Microarchitecture '%s' not available" % architecture_def
microprobe.exceptions.MicroprobeTargetDefinitionError: Microarchitecture 'riscv_generic' not available


Am I missing something? - I think I followed the same steps I was using before but it's been a while. I did the following before running:

/research/sgokul/MicroProbe/microprobe$ git pull --update --recurse-submodules

Thank you!

-Gokul

[RiscV] Microbenchmark generated through mpt2c crashes (segfault)

Using the attached mpt file (generated via chopstix), I correctly created a microbenchmark using the mpt2c tool. However there seems to be some sort of issue regarding the fixing of memory addresses. The .c source code is the same which microprobe generates given the scenario above (benchmark.c). The crash (segfault) happens at the last of the following lines (the SD instruction at line 378):

367 __asm__(" MEMACCESS_FIX_0_pcrel_1:AUIPC x2, %pcrel_hi(MEMACCESS_FIX_0) ");      
368 __asm__(" ADDI x2, x2, %pcrel_lo(MEMACCESS_FIX_0_pcrel_1) ");                   
369 __asm__(" MEMACCESS_FIX_1_pcrel_2:AUIPC x8, %pcrel_hi(MEMACCESS_FIX_1) ");      
370 __asm__(" ADDI x8, x8, %pcrel_lo(MEMACCESS_FIX_1_pcrel_2) ");                   
371 __asm__(" MEMACCESS_FIX_2_pcrel_3:AUIPC x15, %pcrel_hi(MEMACCESS_FIX_2) ");     
372 __asm__(" ADDI x15, x15, %pcrel_lo(MEMACCESS_FIX_2_pcrel_3) ");                 
373 __asm__(" ADDI x3, x0, 0x0 ");                                                  
374 __asm__(" first:ADDI x0, x2, -0x40 ");                                          
375 __asm__(" ADDI x1, x2, -0x40 ");                                                
376 __asm__(" ADDI x10, x2, -0x40 ");                                               
377 __asm__(" ADDI x11, x2, -0x40 ");                                               
378 __asm__(" SD x8, 0x38(x2) "); 

When debugging the execution, one would expect that the x2 register would point to a region of memory within MEMACCESS_FIX_0 (as is set above in the code), however this is not the case (you can check this by reading the value of x2 and comparing it to the position of MEMACCES_FIX_0 symbol which can be found by using the nm utility). This suggests that maybe the instructions being generated for memory fixing is not right? I'm not sure.

Aside from this, I also noticed some weird code involving writing to the x0 register, or using "protected" registers such as the stack pointer (which is, precisely, x2), etc. I'm not sure if that's intended behavior or not.

If you need any additional information, files, whatever else to solve this issue, please don't hesitate to ask me.

Tracking issue: Seeded Randomess

The current code base uses a few unseeded random.Random() calls. This causes the generated asm to be non-reproducable. Ideally we would have the user provide a seed to generate random values

Beyond the benefit of reproducible tests, this change also allows developers to see at a glance if a function uses a random value (since it will have rand: random.Random in it's function signature).

Directories with random.* calls

  • /passes #40
  • /target/isa
  • /utils
  • /wrappers
  • /policies

There might be other directories I missed, but I'll revise this issue when I discover them.

Race conditions:

  • Global variable in riscv-common/isa.py
    • This causes a race condition that manifests in label name when generating in multi-processing mode. Doesn't really matter from a correctness standpoint, but prevents comparing hashes of generated tests.

Implementation of the "safe" binary decoding

Hello,

I was wondering if the implementation of the "safe" binary decoding is complete or not, because I've had some problems with it. The implementation is mainly in src/microprobe/utils/bin.py:139 and src/microprobe/target/isa/instruction.py:150. To begin with, the accesses to the instruction definition cache are not checked, and due to some reason (which I suspect is RiscV's variable length instructions or maybe the byte swapping due to endianess) it often crashes with the MicroprobeDuplicatedValueError exception.

If I disable the use of the cache, then the program fails later in the execution, during the codification stage. At that moment, it tries to apply some bit shifts to the operands, which seem to be hardcoded to strings and so generate python errors (can't bit shift a string). These strings appear to originate from the method in the instruction.py file mentioned earlier.

My current workaround is to simply not emit any new instructions when there is an error, but continue the decoding. But I understand this could possibly cause problems when reconstructing the instruction sequence, specially with relative jumps and such. I wonder if a better, and simpler, solution would be to just emit NOP instructions of the appropriate length?

Just in case, I am also providing an mpt.tar.gz compressed archive containing an MPT with invalid (RiscV) instructions to test with.

Generate multiple iterations of the stress test code block as a loop

Hello,

I am generating micro-benchmarks for risc-v (based on risv_ipc) with the parameter --loop-size L which, in my understanding, sets the size of the building block (with SimpleBuildingBlockPass). After this the various passes act on this block.

I am interested in having the final generated code to loop over this instruction block multiple (i.e. a configurable N-times outer loop) times, so that the total instructions I would execute would be N*L i.e. so that I can have a longer stress test to run on the simulator.

Not sure if I can just add/edit a simple pass to enable this.

The current code I use:
passes = [
structure.SimpleBuildingBlockPass(self.args.loop_size),
initialization.InitializeRegistersPass(),
initialization.InitializeRegistersPass(v_value=(1.000000000000001, 64)),
instruction.SetInstructionTypeByProfilePass(thisdict),
address.UpdateInstructionAddressesPass(),
branch.BranchNextPass(),
register.DefaultRegisterAllocationPass(dd=GOK_REG_DIST),
address.UpdateInstructionAddressesPass()
]
for p in passes:
synth.add_pass(p)

            bench = synth.synthesize()

Thanks,
Gokul

Adding new features memory access pattern - Randomness + Temporal locality

Hello @rbertran,

Is there some existing way for me to get randomized memory access patterns? (may it could take only the memory footprint as parameter).

Best case scenario would be if a stream in the GenericMemoryStreamsPass could be random access, similar to:

GenericMemoryStreamsPass([[0, 4 * 1024 * 1024, 10, 128, 1], [1, 256, 5, 64, 1]])

And the random pattern could also be used with some probability, similar to the 10:5 ratio above.

As we discussed at some point, this might provide some more control for cache miss rates etc.

Thanks!!

Memory pattern configurability

From @rgokulsm comment on issue #5 :

I think it might be a useful feature if each loop iteration had some configurability. For example, if the memory addresses could be changed from one iteration to another (say, as some function of the iteration number), this might be useful in stressing the prefetcher. If you think this would be a useful usecase then maybe adding a pass to enable this might be a better option than directly doing so from the wrapper?

There are already various passes that control the memory access pattern, all of them rely on an endless loop behavior so that the requested access pattern can be generated over time. The two main passes are the following (there are others for more specific use cases):

  • GenericMemoryModelPass: Given the definition of the uarch details (e.g. associativity, sets, cache size, hierarchy, etc...) one can specify that 20% of accesses go to L1, 30% of accesses go to L2 and 50% of accesses go to L3. The pass generates the required addresses to guarantee that behavior (or similar).
  • GenericMemoryStreamsPass: Given a list of memory access streams (each of them with their size, stride access pattern, and weight) , the pass generates the addresses according to the streams defined. E.g. 1 stream of length 10K of stride 256bytes, and 2 streams of length 4MB of stride 16bytes, each stream same weight. The code generated will traverse/access tree different memory regions using those strides patterns, and whenever the end of a stream is reached, the access stream starts from the beginning.

Not sure the level of support for these passes for the RISCV-port, but if you let me know which type of patterns you'd like to generate, I can prioritize that effort.

Memory address check does not account for loop iterations

Hello @rbertran ,

There seems to be an issue with the memory addresses when the memory size exceeds the values reached within 1 iteration of the code loop.

This scenario has a small memory (uses memory.GenericMemoryStreamsPass([[1, 1024, 1, 64, 1]])) works correctly and has the following memory access pattern:

 533500: system.cpu T0 : @rel_branch_3+4    : fsd ft1, 640(ra)           : FloatMemWrite :  D=0x0000000000000000 A=0x80003280
 533500: system.cpu T0 : @rel_branch_3+8    : sd t2, 704(ra)             : MemWrite :  D=0x0000000000000000 A=0x800032c0
 620500: system.cpu T0 : @rel_branch_3+12    : mul a0, s1, s0             : IntMult :  D=0x0000000000000000
 620500: system.cpu T0 : @rel_branch_3+16    : fld fa1, 768(ra)           : FloatMemRead :  D=0x0000000000000000 A=0x80003300
 620500: system.cpu T0 : @rel_branch_3+20    : lb a1, 832(ra)             : MemRead :  D=0x0000000000000000 A=0x80003340
 620500: system.cpu T0 : @rel_branch_3+24    : fld fa2, 896(ra)           : FloatMemRead :  D=0x0000000000000000 A=0x80003380
 620500: system.cpu T0 : @rel_branch_3+28    : mul a2, a5, a3             : IntMult :  D=0x0000000000000000
 620500: system.cpu T0 : @rel_branch_3+32    : beq a7, a6, 4              : IntAlu :
 620500: system.cpu T0 : @rel_branch_4    : sb a0, 960(ra)             : MemWrite :  D=0x0000000000000000 A=0x800033c0
 620500: system.cpu T0 : @rel_branch_4+4    : mul a4, s3, s2             : IntMult :  D=0x0000000000000000
 621000: system.cpu T0 : @rel_branch_4+8    : bne s4, a1, 4              : IntAlu :
 621000: system.cpu T0 : @rel_branch_5    : flw fa3, 0(ra)             : FloatMemRead :  D=0x0000000000000000 A=0x80003000

You will notice that the memory addresses loops back to 0x80003000 after 0x800033c0, since the size of the memory is 1024 bytes.

The next scenario errors outs with incorrect memory address. It uses the following: memory.GenericMemoryStreamsPass([[1, 1024*1024, 1, 64, 1]])

At the end of the first iteration of execution, the memory address limit is not reached which itself is fine. The last few addresses are shown below (note: the starting address was 80003000, so this has covered an address range of 4800, which is less than the total available) :

4747500: system.cpu T0 : @rel_branch_44+24    : sd s8, 1920(ra)            : MemWrite :  D=0x0000000000000000 A=0x80007780
4747500: system.cpu T0 : @rel_branch_44+28    : fadd_s fs8, fs4, fa0       : FloatAdd :  D=0x0000000000000000
4747500: system.cpu T0 : @rel_branch_44+32    : sb zero, 1984(ra)          : MemWrite :  D=0x0000000000000000 A=0x800077c0
4755500: system.cpu T0 : @rel_branch_44+36    : addi ra, ra, 2047          : IntAlu :  D=0x00000000800077ff
4755500: system.cpu T0 : @rel_branch_44+40    : c_addi ra, ra, 1           : IntAlu :  D=0x0000000080007800
4756000: system.cpu T0 : @rel_branch_44+42    : fmul_s fa7, fs0, fs10      : FloatMult :  D=0x0000000000000000
4833000: system.cpu T0 : @rel_branch_44+46    : sd t1, 0(ra)               : MemWrite :  D=0x0000000000000000 A=0x80007800

This is followed by:

4833500: system.cpu T0 : @rel_branch_44+56    : addi ra, ra, 2047          : IntAlu :  D=0x0000000080007fff
4833500: system.cpu T0 : @rel_branch_44+60    : addi ra, ra, 2047          : IntAlu :  D=0x00000000800087fe
4833500: system.cpu T0 : @rel_branch_44+64    : addi ra, ra, 2047          : IntAlu :  D=0x0000000080008ffd
4833500: system.cpu T0 : @rel_branch_44+68    : addi ra, ra, 2047          : IntAlu :  D=0x00000000800097fc
4833500: system.cpu T0 : @rel_branch_44+72    : addi ra, ra, 2047          : IntAlu :  D=0x0000000080009ffb
4833500: system.cpu T0 : @rel_branch_44+76    : addi ra, ra, 2047          : IntAlu :  D=0x000000008000a7fa
4833500: system.cpu T0 : @rel_branch_44+80    : addi ra, ra, 2047          : IntAlu :  D=0x000000008000aff9
4833500: system.cpu T0 : @rel_branch_44+84    : addi ra, ra, 2047          : IntAlu :  D=0x000000008000b7f8
4834000: system.cpu T0 : @rel_branch_44+88    : addi ra, ra, 2047          : IntAlu :  D=0x000000008000bff7
4834000: system.cpu T0 : @rel_branch_44+92    : c_addi ra, ra, 9           : IntAlu :  D=0x000000008000c000


which is increasing the addresses by a huge chunk and thus wasting some space. Not sure if this is for alignment (to 4096 which is default).

After this in the next iteration we start from address 8000c000, which is okay. But now the check for address less than max size seems to go haywire. This check does not seem to account for the loop iteration, so it always seems to be within the address range.

This leads to a point (in some Nth iteration) when address hits the maximum and does not loop back:

163481500: system.cpu T0 : @rel_branch_39+12    : c_addi ra, ra, 1           : IntAlu :  D=0x0000000080103000

And this results in a fault.

Please let me know if i can provide more details - I'm not sure if my details convey the problem completely. In short I believe that the problem is that the memory address check, which should loop the memory address back to 0 when it crosses the max value, does not seem to take the iteration number multiplicative factor into account, thus it does not realize that the actual memory address has crossed the max bound.

Thanks!

Memory addressing

This might be more of a general/riscv question than a microprobe specific one - can you provide some insight on what is happening in the code below with respect to the x_i and the 0x7ff... More specifically what is the difference between x2, x3 etc and why are they used. The reason I'm asking is because I hit a page fault (on gem5 syscall emulation mode) when my program has to use multiple x_i for the memory addressing:

.comm ST_1024_64_0, 65600
.comm riscv_v22_scratch_var, 256

/* Start Main */
RVTEST_RV64UF
RVTEST_CODE_BEGIN

reset:ADDI x0, x1, 0x0
ST_1024_64_0_pcrel:AUIPC x2, %pcrel_hi(ST_1024_64_0)
ADDI x2, x2, %pcrel_lo(ST_1024_64_0_pcrel)
OR x2, x2, x3
ADDI x3, x3, 0x7ff
ADDI x3, x3, 0x1
OR x3, x3, x4

ADDI x4, x4, 0x7ff
ADDI x4, x4, 0x1
OR x4, x4, x5
ADDI x5, x5, 0x7ff
ADDI x5, x5, 0x1
OR x5, x5, x6
ADDI x6, x6, 0x7ff
ADDI x6, x6, 0x1
OR x6, x6, x7
..................................
..................................
..................................
And later:
LD x20, 0x7c0(x2) /* Address: Address((char) ST_1024_64_0[65600]+0x00000000000007c0) /
MUL x22, x21, x0
SD x28, 0x0(x3) /
Address: Address((char) ST_1024_64_0[65600]+0x0000000000000800) */
MUL x27, x25, x23

[RISCV] NotImplementedError when using mpt2c with branch fixing

When trying to use the mpt2c tool to generate a C source file from an MPT file (generated using chopstix) a NotImplementedError exception is thrown, corresponding to the line 838 of src/microprobe/passes/branch/__init__.py

The MPT file in question is this one. The command to generate the C source file is as follows: mp_mpt2c.py -T riscv_v22-riscv_generic-riscv64_linux_gcc --fix-indirect-branches --fix-branch-next --fix-memory-registers --endless -t bt.mpt -O /tmp/temp.c

The last instruction in the BBL is JALR (JALR_V0) Description: Jump and Link Register: Jump to rs1 plus the 12-bit signed immediate while saving PC+4 into rd.

New "enum" operand needed for some RiscV instructions

For some architectures such as RiscV some instructions (e.g. floating point instructions) have what could be described as an enum constant field, which the compiler then translates into the appropiate bitwise value to be encoded inside the instruction itself. Here is an example for RiscV, which involves multiple rounding modes for floating point operations: Floating-point rounding modes.

At the moment instructions which use this field are implemented using a hard-coded value which might not always be the one used in the binary, resulting in a crash. There is a similar operand available, but it only works with integers. Maybe it could be adapted, although I'm not sure if it would work because enums have a key-value relation.

I propose the following interface for an ideal implementation, as an example I used the RiscV floating point instruction format with rounding mode field.

For the instruction format it should look as follows:

- Name: "r-m+rf2"
  Fields:
  - funct5
  - funct2
  - rs2c
  - frs1
  - rm
  - rd
  - opcode
  Assembly: OPC rd, frs1, rm

And, for the rm field:

- Name: "rm"
  Size: 3
  Description: "rm"
  Show: False
  IO: "?"
  Operand: "rm"

Finally, for the operand:

- Name: rm
  Description: 3-bit immediate
  Enum:
  - [0, 'rne']
  - [1, 'rtz']
  - [2, 'rdn']
  - [3, 'rup']
  - [4, 'rmm']
  - [7, 'dyn']

As can be probably guessed, the first field in the array is the number the enum can be translated to, and the string is the enum's name to be used in the assembly language. Note the gap between the last two enums! The implementation should also take that into account.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.