Adding an intrinsic to Vortex

An intrinsic is a form of inline assembly that can be invoked from software like a function, while being defined in hardware. The process of using an intrinsic generally involves three main steps: writing the inline assembly code, modifying the decode and execute stages, and calling the intrinsic from the source code. This explanation is largely based on the Vortex crypto branch.

Example chosen: Rotate right shift Simulator chosen: SimX

Step 1: Inline asm

Add inline assembly to vx_intrinsic.h

inline uint32_t __intrin_rotr(uint32_t word, uint32_t n) {
    uint32_t ret;
    asm volatile (
        ".insn r 0x33, 5, 0x30, %[ret], %[word], %[n]\n"
        : [ret] "=r" (ret)
        : [word] "r" (word), [n] "r" (n)
		);
    return ret;
}

inline uint32_t __intrin_rotr_imm(uint32_t word, int32_t n) {
    uint32_t ret;
    asm volatile (
        ".insn i 0x13, 5, %[ret], %[word], %[n]\n"
        : [ret] "=r" (ret)
        : [word] "r" (word), [n] "i" ((0x30 << 5) | (n & 0x1f))
		);
    return ret;
}

Step 2: Modify decode and execute stages

Modify simx/decode.cpp and simx/execute.cpp

Step 3: Invoke intrinsic

Example code that invokes intrinsic:

//this code tests the ROR intrinsic we added
#include <stdio.h>
#include "vx_intrinsics.h"
#include <stdint.h>
int main(void)
{
        printf("Hello World!\n");
        uint32_t result;
        int x = 8, n=2; 
        int y = (int)((unsigned)x >> n);
        int z = x << (32 - n);
        int g = y | z;
        result = __intrin_rotr_imm(8, 2);
        printf("Result = %ld and verif = %ld\n", result, g);
        return 0;
}