0

I am writing an emulator of a subset of the RISCV specification, intending to use the compressed ISA as a baseline for my customized 16-bit instruction set. However, riscv32-unknown-elf-as refuses to assemble the C.SW and C.LW instructions with a label acting as the immediate value.

I am aware that RV-C is only an extension of the base ISA and is not intended for standalone execution, but I would like to use the riscv32-unknown-elf-as assembler utility as an easy way to assemble small programs for my simulator/emulator.

According to the RISC-V ISA spec (as of the time of writing), the C.SW instruction takes a 7-bit immediate value, and the value is left shifted twice (multiplied by 4) as the loads/stores are assumed to be 4-byte aligned anyway.

As a result, the following assembly is deemed legal by riscv32-unknown-elf-as and successfully assembles:

C.SW x12, 64(x13)

One would think that if a label was correctly 4-byte aligned, representing the address 0x64, you would be able to write the equivalent assembly:

C.SW x12, my_label(x13)

However, riscv32-unknown-elf-as refuses to assemble this line, stating:

test_asm.S: Assembler messages:
test_asm.S:4: Error: illegal operands `c.sw x12,my_label(x13)'

I have tried many combinations of this syntax, along with all kinds of alignment directives w.r.t. the label. For reference, this is the assembly file itself:

main:
    .option rvc
    c.sw x12, my_label(x13)

my_label:
    .word 1

Is there an additional compiler directive I need to add? According the ISA spec, I would expect this to be valid assembly.

Zee2
  • 163
  • 8

1 Answers1

1

The assembler cannot know what value you might have in x13, so cannot guess what offset my_label would need to have.  These instructions have such small immediates that you want to use a relative value not an absolute address.

It appears though that if you use the form target-base, and, define them ahead of their usage, that the assembler will accept the compact instructions and compute proper offset / immediate.

Try this:

my_label = 64

main:
    .option rvc
    c.sw x12, my_label(x13)

Here's a larger example of lablings that work:

label =  32
    .data
lab1:
    .word 0
lab2:
    .word 1
lab3 = lab2 - lab1
    .text
lab5:
    .word 0
lab6:
    .word 2
lab4 = lab6-lab5
main:
    .option rvc
    c.sw x12,64(x14)
    c.sw x12,label(x13)
    c.sw x12,lab3(x12)
    c.sw x12,lab4(x11)

The only restriction seems to be that the assembler wants to see these short reach labels defined before their usage.

Because these compact instructions have such short offset (reach), the above labels defined with equality and subtraction are probably the most useful.  (In the examples, we would presume then that the address of lab1 was in x12 and lab5 in x11..)

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • So, the direct assumption from this would be that there would be no way to coerce the assembler into placing the labels (I guess we could call it a "data section") close enough to the code that the short immediate offset could fit the label, and perform this sort of arithmetic statically for us? This for sure would not work in real code, but for my tiny use case, perhaps? – Zee2 Sep 17 '19 at 02:59
  • Not sure what you're asking. My examples include data in code. I guess you want to use this in a (short displacement) pc-relative addressing mode, though as I answered it might be made to work if the data precedes the code and you define labels just right. Though the embedded systems that RISC V is targeting probably won't mix (read-only) code and mutable data (but who knows). – Erik Eidt Sep 17 '19 at 03:36