#include "../../../../../runtime/textflag.h"
TEXT asmtest(SB),DUPOK|NOSPLIT,$0
-
+start:
// Unprivileged ISA
// 2.4: Integer Computational Instructions
SRA $1, X5, X6 // 13d31240
SRA $1, X5 // 93d21240
+ // 2.5: Control Transfer Instructions
+
+ // These jumps and branches get printed as a jump or branch
+ // to 2 because they transfer control to the second instruction
+ // in the function (the first instruction being an invisible
+ // stack pointer adjustment).
+ JAL X5, start // JAL X5, 2 // eff2dff0
+ JALR X6, (X5) // 67830200
+ JALR X6, 4(X5) // 67834200
+ BEQ X5, X6, start // BEQ X5, X6, 2 // e38062f0
+ BNE X5, X6, start // BNE X5, X6, 2 // e39e62ee
+ BLT X5, X6, start // BLT X5, X6, 2 // e3cc62ee
+ BLTU X5, X6, start // BLTU X5, X6, 2 // e3ea62ee
+ BGE X5, X6, start // BGE X5, X6, 2 // e3d862ee
+ BGEU X5, X6, start // BGEU X5, X6, 2 // e3f662ee
+
// 2.6: Load and Store Instructions
LW $0, X5, X6 // 03a30200
LW $4, X5, X6 // 03a34200
func buildop(ctxt *obj.Link) {}
+// lowerJALR normalizes a JALR instruction.
+func lowerJALR(p *obj.Prog) {
+ if p.As != AJALR {
+ panic("lowerJALR: not a JALR")
+ }
+
+ // JALR gets parsed like JAL - the linkage pointer goes in From,
+ // and the target is in To. However, we need to assemble it as an
+ // I-type instruction, so place the linkage pointer in To, the
+ // target register in Reg, and the offset in From.
+ p.Reg = p.To.Reg
+ p.From, p.To = p.To, p.From
+
+ // Reset Reg so the string looks correct.
+ p.From.Type = obj.TYPE_CONST
+ p.From.Reg = obj.REG_NONE
+}
+
// progedit is called individually for each *obj.Prog. It normalizes instruction
// formats and eliminates as many pseudo-instructions as possible.
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
switch p.As {
+ case AJALR:
+ lowerJALR(p)
+
case obj.AUNDEF, AECALL, AEBREAK, ASCALL, ASBREAK, ARDCYCLE, ARDTIME, ARDINSTRET:
switch p.As {
case obj.AUNDEF:
setPCs(cursym.Func.Text, 0)
+ // Resolve branch and jump targets.
+ for p := cursym.Func.Text; p != nil; p = p.Link {
+ switch p.As {
+ case AJAL, ABEQ, ABNE, ABLT, ABLTU, ABGE, ABGEU:
+ switch p.To.Type {
+ case obj.TYPE_BRANCH:
+ p.To.Type, p.To.Offset = obj.TYPE_CONST, p.Pcond.Pc-p.Pc
+ case obj.TYPE_MEM:
+ panic("unhandled type")
+ }
+ }
+ }
+
// Validate all instructions - this provides nice error messages.
for p := cursym.Func.Text; p != nil; p = p.Link {
encodingForProg(p).validate(p)
wantRegAddr(p, pos, a, "float", REG_F0, REG_F31)
}
+// wantEvenJumpOffset checks that the jump offset is a multiple of two.
+func wantEvenJumpOffset(p *obj.Prog) {
+ if p.To.Offset%1 != 0 {
+ p.Ctxt.Diag("%v\tjump offset %v must be even", p, obj.Dconv(p, &p.To))
+ }
+}
+
func validateRIII(p *obj.Prog) {
wantIntRegAddr(p, "from", &p.From)
wantIntReg(p, "reg", p.Reg)
wantIntRegAddr(p, "to", &p.To)
}
+func validateB(p *obj.Prog) {
+ // Offsets are multiples of two, so accept 13 bit immediates for the
+ // 12 bit slot. We implicitly drop the least significant bit in encodeB.
+ wantEvenJumpOffset(p)
+ wantImmI(p, "to", p.To, 13)
+ wantIntReg(p, "reg", p.Reg)
+ wantIntRegAddr(p, "from", &p.From)
+}
+
func validateU(p *obj.Prog) {
wantImmU(p, "from", p.From, 20)
wantIntRegAddr(p, "to", &p.To)
}
+func validateJ(p *obj.Prog) {
+ // Offsets are multiples of two, so accept 21 bit immediates for the
+ // 20 bit slot. We implicitly drop the least significant bit in encodeJ.
+ wantEvenJumpOffset(p)
+ wantImmI(p, "to", p.To, 21)
+ wantIntRegAddr(p, "from", &p.From)
+}
+
func validateRaw(p *obj.Prog) {
// Treat the raw value specially as a 32-bit unsigned integer.
// Nobody wants to enter negative machine code.
return encodeS(p, regF(p.Reg))
}
+// encodeB encodes a B-type RISC-V instruction.
+func encodeB(p *obj.Prog) uint32 {
+ imm := immI(p.To, 13)
+ rs2 := regI(p.Reg)
+ rs1 := regIAddr(p.From)
+ ins := encode(p.As)
+ if ins == nil {
+ panic("encodeB: could not encode instruction")
+ }
+ return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | rs2<<20 | rs1<<15 | ins.funct3<<12 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7 | ins.opcode
+}
+
// encodeU encodes a U-type RISC-V instruction.
func encodeU(p *obj.Prog) uint32 {
// The immediates for encodeU are the upper 20 bits of a 32 bit value.
return imm<<12 | rd<<7 | ins.opcode
}
+// encodeJ encodes a J-type RISC-V instruction.
+func encodeJ(p *obj.Prog) uint32 {
+ imm := immI(p.To, 21)
+ rd := regIAddr(p.From)
+ ins := encode(p.As)
+ if ins == nil {
+ panic("encodeJ: could not encode instruction")
+ }
+ return (imm>>20)<<31 | ((imm>>1)&0x3ff)<<21 | ((imm>>11)&0x1)<<20 | ((imm>>12)&0xff)<<12 | rd<<7 | ins.opcode
+}
+
// encodeRaw encodes a raw instruction value.
func encodeRaw(p *obj.Prog) uint32 {
// Treat the raw value specially as a 32-bit unsigned integer.
var (
// Encodings have the following naming convention:
//
- // 1. the instruction encoding (R/I/S/SB/U/UJ), in lowercase
+ // 1. the instruction encoding (R/I/S/B/U/J), in lowercase
// 2. zero or more register operand identifiers (I = integer
// register, F = float register), in uppercase
// 3. the word "Encoding"
sIEncoding = encoding{encode: encodeSI, validate: validateSI, length: 4}
sFEncoding = encoding{encode: encodeSF, validate: validateSF, length: 4}
+ bEncoding = encoding{encode: encodeB, validate: validateB, length: 4}
uEncoding = encoding{encode: encodeU, validate: validateU, length: 4}
+ jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4}
// rawEncoding encodes a raw instruction byte sequence.
rawEncoding = encoding{encode: encodeRaw, validate: validateRaw, length: 4}
// encodingForAs contains the encoding for a RISC-V instruction.
// Instructions are masked with obj.AMask to keep indices small.
var encodingForAs = [ALAST & obj.AMask]encoding{
- // TODO(jsing): Implement remaining instructions.
// Unprivileged ISA
ASUB & obj.AMask: rIIIEncoding,
ASRA & obj.AMask: rIIIEncoding,
+ // 2.5: Control Transfer Instructions
+ AJAL & obj.AMask: jEncoding,
+ AJALR & obj.AMask: iIEncoding,
+ ABEQ & obj.AMask: bEncoding,
+ ABNE & obj.AMask: bEncoding,
+ ABLT & obj.AMask: bEncoding,
+ ABLTU & obj.AMask: bEncoding,
+ ABGE & obj.AMask: bEncoding,
+ ABGEU & obj.AMask: bEncoding,
+
// 2.6: Load and Store Instructions
ALW & obj.AMask: iIEncoding,
ALWU & obj.AMask: iIEncoding,