Skip to content

Assembler

陳鍾誠 edited this page Dec 28, 2018 · 5 revisions

RISCV 組譯器

範例

ADD : R-type

add x9, x20, x21

0 21 20 0 9 15

Func7   rs2   rs1    func3 rd    opcode
7bits   5bits 5bits  3bits 5bits 7bits
0000000 10101 10100  000   01001 0110011

LD : S-Type load double words

ld x9, 64(x22) 


Immediate[11:5]   rs2   rs1    func3 Immediate[4:0] opcode
7bits             5bits 5bits  3bits 5bits          7bits
0000000           10101 10100  000   01001          0000011

SLLI :

SLLI:  slli x11, x19, 4  // reg x11 = reg x19 << 4 bits

0000000 shamt rs1   001   rd   0010011 
0       4     19      1   11   19
0000000 0100  10011 001 01101  0010011  

方法

func InstToBin(inst []string) ([]byte, elf.R_RISCV) {

	t := mnem2type[inst[0]]
	var op RV_OPCODE_TYPE
	if t != RV_INST_PSEUDO {
		op = mnem2opcode[inst[0]]
	}

	var bits uint32
	switch t {
	case RV_INST_R_TYPE:
		rd := reg2bits[inst[1]]
		rs1 := reg2bits[inst[2]]
		rs2 := reg2bits[inst[3]]
		f3 := funct3[inst[0]]

		var f7 uint32
		if inst[0] == "sub" || inst[0] == "sra" || inst[0] == "sraw" {
			f7 = 0x20
		}

		bits = f7<<25 | rs2<<20 | rs1<<15 | f3<<12 | rd<<7 | uint32(op)

	case RV_INST_I_TYPE:
		var isop int
		if (op == RV_OPCODE_OP_IMM) || (op == RV_OPCODE_OP_IMM_32) {
			isop = 1
		}

		f3 := funct3[inst[0]]
		var issh bool
		if f3 == 0x01 || f3 == 0x05 {
			issh = true
		}

		rd := reg2bits[inst[1]]
		rs1 := reg2bits[inst[3-isop]]
		if issh {
			shamt, _ := strconv.ParseUint(inst[2+isop], 16, 6)

			var f6 uint32
			if inst[0] == "srai" || inst[0] == "sraiw" {
				f6 = 0x10
			} else {
				f6 = 0
			}

			bits = f6<<26 | uint32(shamt)<<20 | rs1<<15 | f3<<12 | rd<<7 | uint32(op)
		} else {
			imm, _ := strconv.ParseInt(inst[2+isop], 10, 12)
			bits = uint32(imm)<<20 | rs1<<15 | f3<<12 | rd<<7 | uint32(op)
		}

	case RV_INST_S_TYPE:
		f3 := funct3[inst[0]]
		rs1 := reg2bits[inst[3]]
		imm, _ := strconv.ParseInt(inst[2], 10, 12)
		rs2 := reg2bits[inst[1]]

		bits = uint32(imm) << 20
		bits &= 0xfe000000
		bits |= (rs2<<20 | rs1<<15 | f3<<12 | (uint32(imm)&0x1f)<<7 | uint32(op))

	case RV_INST_B_TYPE:
		f3 := funct3[inst[0]]
		rs1 := reg2bits[inst[1]]
		rs2 := reg2bits[inst[2]]
		imm, _ := strconv.ParseUint(inst[3], 16, 12)

		fmt.Println(imm)
		fmt.Println(imm & 0x800)
		imm12 := uint32((imm & 0x800) >> 11)
		imm11 := uint32((imm & 0x400) >> 10)
		imm10_5 := uint32((imm & 0x3f0) >> 4)
		imm4_1 := uint32(imm & 0x00f)
		fmt.Println(imm12, imm11, imm10_5, imm4_1)

		bits = imm12<<31 | imm10_5<<25 | rs2<<20 | rs1<<15 | f3<<12 | imm4_1<<8 | imm11<<7 | uint32(op)

	case RV_INST_U_TYPE:
		rd := reg2bits[inst[1]]
		imm, _ := strconv.ParseUint(inst[2], 16, 20)
		bits = uint32(imm)<<12 | rd<<7 | uint32(op)

	case RV_INST_J_TYPE:
	case RV_INST_NONE:
		bits |= uint32(op)
	case RV_INST_PSEUDO:
		if inst[0] == "call" {
			ra, _ := InstToBin([]string{"auipc", "ra", "0"})
			rb, _ := InstToBin([]string{"jalr", "ra", "0", "ra"})
			return append(ra, rb...), elf.R_RISCV_CALL
		}
	}

	ret := make([]byte, 4)
	binary.LittleEndian.PutUint32(ret, bits)
	return ret, elf.R_RISCV_NONE
}

參考文獻

Clone this wiki locally