RISC-V source class riscv_asm_program_gen, the brain behind assembly instruction generator

By Shailesh Vasekar, VeriFast

Abstract

CHIPS Alliance has developed an open-source riscv-dv random instruction generator for RISC-V processor verification. This article focuses on the class riscv_asm_program_gen.sv and its various functions, which generate the complete RISC-V assembly program, which is then used to verify RISC-V IP. This class can also address any customization to RISC-V GPR or instruction.

Introduction

The open source https://github.com/chipsalliance/riscv-dv/tree/master defines the SV UVM-based class structure very helpful in the verification of RISC-V IP. The generated random test can be added directly to run with the design IP. The various sections of the ASM program, such as initialization routine, instruction section, data section, stack section, page table, interrupt and exception handling, etc., are generated with different functions in the riscv_asm_program_gen class itself.

First Thing First

First, the class riscv_instr_gen_config is randomized from the test riscv_instr_base_test.sv. This randomization decides the RISC-V extension we are running with, the privilege mode supported, the instruction count in the main and subprogram, whether the program must generate break instructions using variable no_ebreak, similarly no_dret, no_fence, no_wfi, and such configurations.

Many other such variables can be set to true or false based on DUT features and testbench stimulus generation requirements. The above snapshot lists very few of them.

Kick Start Function gen_program()

The function gen_program() is the main function to generate all sections of the program. Once it’s called from upper layer, it calls other function from the riscv_asm_program_gen one by one.

Then it calls function call get_directed_instr_stream(), selects the ratio of instruction generation from another function called add_directed_instr_stream().

riscv_asm_program_gen.sv(1552) @ 0: reporter [asm_gen] Adding directed instruction stream:riscv_jal_instr ratio: 30/1000

Next function call is to  gen_program_header() and uses string array  instr_stream to fill it up with header.

str[0] =.include “user_init.s”    //example output

  • The gen_program_header()   function calls another function gen_section(“_start”, str); which inserts header instruction in the  instr_stream.

  • gen_program() then it calls init_gpr() function whose functionality to initialize general purpose registers with random value.

  • Next generate_directed_instr_stream() functions get call which decides the ratio and insert directed instruction stream and randomizes the instruction as well. The function randomizes and selects which rs1, rs2 and rd to use based on instruction type. This will generate the asm program which has the instructions with various GPRs x0 to x31 used in all instructions the post_random() function of riscv_instr helps here.
  • Then sequence riscv_instr_sequence which has function generate_instr_stream which has now all the stream of instruction available and uses convert2asm() function.
  • There are also check for any illegal or HINT instructions ration is defined, if they are 0 then no illegal or HINT instruction is generated.
  • From riscv_asm_program_gen  main_program[hart].generate_instr_stream() is called which convert the instruction stream to the string format.
  • There is any sub_program instruction to generate then function call to function insert_sub_program(sub_program[hart], instr_stream);
  • Once the main and sub_program generation is done then host interface related instruction are added by gen_section function
    str=write_tohost:
    str= sw gp, tohost, t1
    instr[0]=sw gp, tohost, t1
    str=_exit:
  • Then function push_gpr_to_kernel_stack() which pushes general purpose register to stack for trap handling. The riscv_asm_program uses gen_section() selects string for instruction str=mtvec_handler which has exception_hander and interrupt_handler defined.

Generated Program

The function gen_program() and group of functions defined in the same class together with riscv_ instruction_sequence and base test and other helper class generates full assembly language RISC-V program with random instructions, random GPR for each instruction with different patterns of instructions.

Summary of Generated Output

The `gen_program()` function and associated helpers work in concert with the `riscv_instruction_sequence`, base test classes, and various configuration helpers to produce a complete RISC-V assembly program. These programs feature randomized instructions and register selections suitable for robust IP verification.

Conclusion

The `riscv_asm_program_gen` class serves as a comprehensive utility to automate the generation of RISC-V assembly programs. Its modular function calls and rich configuration support make it a crucial component in the `riscv-dv` verification ecosystem.

×
Semiconductor IP