Using custom asm instructions

I'm writing bare-metal code for MicroBlaze V, AMD's soft-core RISC-V processor, using the target riscv32im-unknown-none-elf.

In addition to the standard RISC-V instructions, the MicroBlaze V defines some custom instructions. Is there a way of using these from Rust using inline assembly?


For example, I'd like to use the custom instruction PUT to write data to an AXI4-Stream link, but the following code does not compile because the instruction is not recognized:

fn axi_write(word: u32) {
    unsafe {
        // write to M0_AXIS_TDATA using custom instruction PUT
        asm!("put {}, 0", in(reg) word);
    }
}
error: unrecognized instruction mnemonic
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     put a0, 0
  |     ^

error: could not compile `xxx` (bin "xxx") due to 1 previous error

Is there a way of using custom instructions in inline assembly? If not, is there some workaround?

1 Like

RISC-V has .insn to solve that problem, but it looks as if rustc just ignores it — but clang accepts it as expected. Bug?

1 Like

It doesn't. What happens here is that godbolt by default filters out directives when printing the assembly. And .insn happens to be a directive. If you enable printing of directives you will see that the .insn is present in the output.

2 Likes

Thanks, that does it:

fn axi_write(word: u32) {
    unsafe {
        // write to M0_AXIS_TDATA using custom instruction PUT
        core::arch::asm!(".insn s 0x2b, 0x3, x0, 0({})", in(reg) word);
    }
}

Indeed! Showing directives, I get for both rustc and clang (abridged):

axi_write:
    .insn s 43, 3, zero, 0(a0)
    ret