Got back into my SubV ( assembler / machine-code language modelled after @akkartik's SubX) codebase this weekend.

I figured out pretty quickly that what seemed like a terrible problem and caused me to essentially drop it a year ago is actually... not a problem? So that's good news :)

Had to stop for now, but long jumps (absolute/relative with lui/auipc+jalr) can be expressed now.

@s_ol What was the problem?!

Also, just in case you haven't looked at Mu code recently, here's what it looks like now:

I still didn't arrive at Mu, but I'll try to catch up ;)

I was under the impression that the two-instruction relative long-jump aiupc+jalr could only work if SubV would recognize the two-instruction construct and generate the correct offsets in a "smart" way.

I think what I got wrong was that the PC is added in the "auipc" instruction, not when jalr is executed.


Now that I took another look I figure out that it can be expressed very cleanly without grouping opcoded and without any opcode-specific logic in "survey" by allowing offsets in label-references:

# 32-bit relative jump
# load upper 20 bits and add to PC
auipc 5/rd/t0 label[31:12]/off32
# jump, adding lower 12 bits
jalr 0/rd/x0 5/rb/t0 label+4[11:0]/off32

the +4 is to account for the fact that PC was "captured" in the auipc instruction

(typing this blind on my phone, so surely got some details wrong and the opcode instruction bits are missing. Also jalr's immediate argument is actually the [11:1] slice plus a sign bit)

I want to make it so you can optionally specify the exact slices as above, or just write label/off32 and it will get the slices right automatically (including sign extension)

@s_ol Yeah that aiupc construct is a bit strange:

Even outside of our weird notations 🙂 I'm struggling to understand how a compiler would use it. Are they expecting that functions are aligned at 4KB boundaries or something?

Oh, this is only for far jumps. So that alignment constraint might actually be a reasonable choice.

yeah, auipc is only used to "prime" registers for operations that have an immediate argument with limited range and can use a register input to extend that.

My hangup was that in my mind a "relative jump" was always going to be relative to the jump instruction, which is not true in the case of auipc+jalr; jalr by nature is an absolute jump and using auipc you can get the absolute address relative to *that* instruction.

jalr actual also has a 2-byte alignment constraint on the lower immediate, but that is reasonable because instructions are either two or four byte wide.

@akkartik btw it's very interesting to see you and the person who answered in the SO question to also misspell auipc as aiupc, which I have been struggling with a lot also!

I wonder what it is about those three vowels that makes it hard to remember the right way? To my german brain, "aui" should actually be more familiar ("au" is a bigram with a specific sound, and aui is pronouncable) whereas aiu is just letter soup.

@s_ol Oh interesting! I see in my browser history that I actually searched for 'aiupc', which is probably why I got that page.

Thanks for pointing it out. I get annoyed when people spell Gandhi as Ghandi 🙂

@akkartik @s_ol the trick to remember all this gibberish is to read it by their meaning: add upper immediate to program counter.
I force myself to use the whole meaning because instructions like slli or bqez get complicated to read if you don't have it written with fire in your mind.

Sign in to participate in the conversation

Merveilles is a community project aimed at the establishment of new ways of speaking, seeing and organizing information — A culture that seeks augmentation through the arts of engineering and design. A warm welcome to any like-minded people who feel these ideals resonate with them.