# An RV32IM assembler: assembly text in, the bytes of a memory image out.
#
# Two passes over the statements. The first gives every statement its
# section and offset, which fixes the address of every label; the second
# encodes each instruction now that every label it names has an address.
#
# The text is GNU-assembler style: `label:`, `op arg, arg`, `#` comments,
# `;` between statements on a line, numeric local labels (`1:` named as
# `1b` backward or `1f` forward), `.text` and `.data`, data directives and
# the pseudo-instructions li, la, mv, j, call, ret and a few more. The
# encodings are those of the RISC-V unprivileged manual (version
# 20191213), figure 2.3 and chapter 24.
from rv32.bits import WORD, pow2, wrap, signed, bits, sext, fits_signed
from rv32.sim import INSTR_BYTES, OPC_LOAD, OPC_MISC_MEM, OPC_OP_IMM, OPC_AUIPC, OPC_STORE, OPC_OP, OPC_LUI, OPC_BRANCH, OPC_JALR, OPC_JAL, OPC_SYSTEM, F7_ALT, F7_MULDIV
IMM_BITS: Int = 12 # an I or S immediate: -2048 .. 2047
BRANCH_BITS: Int = 13 # a branch offset: -4096 .. 4094, even
JUMP_BITS: Int = 21 # a jal offset: -1 MiB .. 1 MiB - 2, even
UPPER_SHIFT: Int = 12 # lui and auipc fill bits 31..12
DATA_ALIGN: Int = 4096 # the data section starts at the next multiple of this after the code
SECTION_TEXT: Int = 0
SECTION_DATA: Int = 1
#| How an instruction's operands are written and encoded.
enum Fmt {
R # op rd, rs1, rs2
I # op rd, rs1, imm
Shift # op rd, rs1, shamt (funct7 in the immediate's top bits)
Load # op rd, imm(rs1)
Store # op rs2, imm(rs1)
Branch # op rs1, rs2, label
U # op rd, imm20
J # jal rd, label
Jalr # jalr rd, rs1, imm or jalr rd, imm(rs1)
Sys # ecall, ebreak: funct12 in the immediate
Fence # fence: no operands that matter here
}
#| One machine instruction's encoding fields.
record Spec {
name: Str
fmt: Fmt
opcode: Int
f3: Int
f7: Int
}
#| One statement of the source: its labels, its operation and its arguments.
record Stmt {
labels: [Str]
op: Str
args: [Str]
text: Str
line: Int
}
#| The assembled program: the memory image (code from address 0, then the
#| data), the address of every label, and for each code word the statement
#| it came from.