~charles/awk-riscv

dc120f2d980488a00b78526ce1096cec348334fb — Charles Daniels 10 months ago a4ae14f
assemble I, R, and shift types
3 files changed, 299 insertions(+), 103 deletions(-)

M riscv.awk
M tests/simulation/asm_immediate.txt
A tests/simulation/asm_register.txt
M riscv.awk => riscv.awk +261 -103
@@ 524,6 524,264 @@ function parsereg(r) {
	else {return -1}
}

#### ASSEMBLER ################################################################

# This function operates on the normal AWK field registers and attempts to
# assemble the instruction placed therein. Said instruction is written to
# mem[asmcursor], and asmcursor is incremented by 4.
function assemble() {

	# save the line in case we call fieldshift later
	asm_line=$0

	# handle labels
	if (match($1, /[a-zA-Z][a-zA-Z0-9_]+[:]/)) {
		labels[sub(/[:]/, $1, $1)] = asmcursor
		fieldshift()
	}

	# skip comments and empty lines
	if (match($1, /^[#]/) || NF == 0) { return }


	asm_opcode = 0
	asm_funct3 = 0
	asm_funct7 = 0
	asm_rs2 = 0
	asm_rs1 = 0
	asm_rd = 0
	asm_immI = 0
	asm_immU = 0
	asm_shamt = 0
	asm_arith = 0
	asm_immS = 0
	asm_immB = 0
	asm_immJ = 0

	# valid styles include:
	#
	# I -- assemble like a normal register-immediate instruction
	#
	# shift -- assemble like a shift instruction
	#
	# U -- LUI or AUIPC
	#
	# R -- normal register-register instructions
	#
	# nop -- generate a no-op
	asm_style = "error"

	if (tolower($1) == "addi") {
		asm_opcode = 0x13
		asm_style = "I"

	} else if (tolower($1) == "slti") {
		asm_opcode = 0x13
		asm_funct3 = 0x2
		asm_style = "I"

	} else if (tolower($1) == "sltiu") {
		asm_opcode = 0x13
		asm_funct3 = 0x3
		asm_style = "I"

	} else if (tolower($1) == "andi") {
		asm_opcode = 0x13
		asm_funct3 = 0x7
		asm_style = "I"

	} else if (tolower($1) == "xori") {
		asm_opcode = 0x13
		asm_funct3 = 0x4
		asm_style = "I"

	} else if (tolower($1) == "ori") {
		asm_opcode = 0x13
		asm_funct3 = 0x6
		asm_style = "I"

	} else if (tolower($1) == "slli") {
		asm_opcode = 0x13
		asm_funct3 = 0x1
		asm_style = "shift"

	} else if (tolower($1) == "srli") {
		asm_opcode = 0x13
		asm_funct3 = 0x5
		asm_style = "shift"

	} else if (tolower($1) == "srai") {
		asm_opcode = 0x13
		asm_funct3 = 0x5
		asm_funct7 = 0x20
		asm_arith = 0x1
		asm_style = "shift"

	} else if (tolower($1) == "lui") {
		asm_opcode = 0x37
		asm_style = "U"

	} else if (tolower($1) == "auipc") {
		asm_opcode = 0x17
		asm_style = "U"

	} else if (tolower($1) == "add") {
		asm_opcode = 0x33
		asm_style = "R"

	} else if (tolower($1) == "slt") {
		asm_opcode = 0x33
		asm_funct3 = 0x2
		asm_style = "R"

	} else if (tolower($1) == "sltu") {
		asm_opcode = 0x33
		asm_funct3 = 0x3
		asm_style = "R"

	} else if (tolower($1) == "and") {
		asm_opcode = 0x33
		asm_funct3 = 0x7
		asm_style = "R"

	} else if (tolower($1) == "or") {
		asm_opcode = 0x33
		asm_funct3 = 0x6
		asm_style = "R"

	} else if (tolower($1) == "xor") {
		asm_opcode = 0x33
		asm_funct3 = 0x4
		asm_style = "R"

	} else if (tolower($1) == "sll") {
		asm_opcode = 0x33
		asm_funct3 = 0x1
		asm_style = "R"

	} else if (tolower($1) == "srl") {
		asm_opcode = 0x33
		asm_funct3 = 0x5
		asm_style = "R"

	} else if (tolower($1) == "sub") {
		asm_opcode = 0x33
		asm_funct7 = 0x20
		asm_style = "R"

	} else if (tolower($1) == "sra") {
		asm_opcode = 0x33
		asm_funct7 = 0x20
		asm_funct3 = 0x5
		asm_style = "R"

	} else if (tolower($1) == "nop") {
		asm_style = "nop"
		asm_opcode = 0x13

	} else {
		printf("# ASSEMBLER ERROR: expected opcode, got '%s' (line %d: '%s')\n", $1, NR, asm_line)
		assemble_errors++
		return
	}

	if (asm_style == "I") {
		asm_rd = parsereg($2)
		if (asm_rd < 0) {
			printf("# ASSEMBLER ERROR: expected rd register, got '%s' (line %d: '%s')\n", $2, NR, asm_line)
			assemble_errors++
			return
		}
		asm_rs1 = parsereg($3)
		if (asm_rs1 < 0) {
			printf("# ASSEMBLER ERROR: expected rs1 register, got '%s' (line %d: '%s')\n", $3, NR, asm_line)
			assemble_errors++
			return
		}

		if (strtonum($4) > 2047 || strtonum($4) < -2048) {
			printf("# ASSEMBLER ERROR: expected immediate in range -2048...2047, got '%s' (line %d: '%s')\n", $4, NR, asm_line)
			assemble_errors++
			return
		}
		asm_immI = dec2two($4)

	} else if (asm_style == "shift") {
		asm_rd = parsereg($2)
		if (asm_rd < 0) {
			printf("# ASSEMBLER ERROR: expected rd register, got '%s' (line %d: '%s')\n", $2, NR, asm_line)
			assemble_errors++
			return
		}
		asm_rs1 = parsereg($3)
		if (asm_rs1 < 0) {
			printf("# ASSEMBLER ERROR: expected rs1 register, got '%s' (line %d: '%s')\n", $3, NR, asm_line)
			assemble_errors++
			return
		}

		if (strtonum($4) > 31 || strtonum($4) < 0) {
			printf("# ASSEMBLER ERROR: expected shift amount in range 0...31, got '%s' (line %d: '%s')\n", $4, NR, asm_line)
			assemble_errors++
			return
		}
		asm_immI = or(dec2two($4), lshift(asm_arith, 10))

	} else if (asm_style == "U") {
		asm_rd = parsereg($2)
		if (asm_rd < 0) {
			printf("# ASSEMBLER ERROR: expected rd register, got '%s' (line %d: '%s')\n", $2, NR, asm_line)
			assemble_errors++
			return
		}

		if (strtonum($3) > 1048575 || strtonum($3) < 0) {
			printf("# ASSEMBLER ERROR: expected immedite in range 0...1048575, got '%s' (line %d: '%s')\n", $3, NR, asm_line)
			assemble_errors++
			return
		}
		asm_immU = lshift(dec2two($3), 12)
	} else if (asm_style == "R") {
		asm_rd = parsereg($2)
		if (asm_rd < 0) {
			printf("# ASSEMBLER ERROR: expected rd register, got '%s' (line %d: '%s')\n", $2, NR, asm_line)
			assemble_errors++
			return
		}

		asm_rs1 = parsereg($3)
		if (asm_rs1 < 0) {
			printf("# ASSEMBLER ERROR: expected rs1 register, got '%s' (line %d: '%s')\n", $3, NR, asm_line)
			assemble_errors++
			return
		}

		asm_rs2 = parsereg($4)
		if (asm_rs1 < 0) {
			printf("# ASSEMBLER ERROR: expected rs1 register, got '%s' (line %d: '%s')\n", $4, NR, asm_line)
			assemble_errors++
			return
		}
	} else if (asm_style == "nop") {
		# do nothing
	}


	asm_inst = or( \
		 asm_opcode, \
		 lshift(asm_rd, 7), \
		 lshift(asm_funct3, 12), \
		 lshift(asm_rs1, 15), \
		 lshift(asm_immI, 20), \
		 asm_immU, \
		 lshift(asm_rs2, 20), \
		 lshift(asm_funct7, 25))

	memwrite(asmcursor, asm_inst)

	asmcursor += 4
}

#### STATE MUTATION ###########################################################

# write v to register regaddr


@@ 699,108 957,8 @@ $1 == "mode" { mode=$2 ; next }
		next

	} else if (mode == "assemble") {
		# save the line in case we call fieldshift later
		asm_line=$0

		# handle labels
		if (match($1, /[a-zA-Z][a-zA-Z0-9_]+[:]/)) {
			labels[sub(/[:]/, $1, $1)] = asmcursor
			fieldshift()
		}

		# skip comments and empty lines
		if (match($1, /^[#]/) || NF == 0) { next }


		asm_opcode = 0
		asm_funct3 = 0
		asm_funct7 = 0
		asm_rs2 = 0
		asm_rs1 = 0
		asm_rd = 0
		asm_immI = 0
		asm_immU = 0
		asm_shamt = 0
		asm_arith = 0
		asm_immS = 0
		asm_immB = 0
		asm_immJ = 0

		# style can be any of the instruction types, and will be parsed
		# as they are disassembled
		#
		# TODO: add styles for RARS-style jump targets and lw/sw
		asm_style = "error"

		if (tolower($1) == "addi") {
			asm_opcode = 0x13
			asm_style = "I"

		} else if (tolower($1) == "slti") {
			asm_opcode = 0x13
			asm_funct3= 0x2
			asm_style = "I"

		} else if (tolower($1) == "sltiu") {
			asm_opcode = 0x13
			asm_funct3= 0x3
			asm_style = "I"

		} else if (tolower($1) == "andi") {
			asm_opcode = 0x13
			asm_funct3= 0x7
			asm_style = "I"

		} else if (tolower($1) == "xori") {
			asm_opcode = 0x13
			asm_funct3= 0x4
			asm_style = "I"

		} else if (tolower($1) == "ori") {
			asm_opcode = 0x13
			asm_funct3= 0x6
			asm_style = "I"

		} else {
			printf("# ASSEMBLER ERROR: expected opcode, got '%s' (line %d: '%s')\n", $1, NR, asm_line)
			assemble_errors++
			next
		}

		if (asm_style == "I") {
			asm_rd = parsereg($2)
			if (asm_rd < 0) {
				printf("# ASSEMBLER ERROR: expected rd register, got '%s' (line %d: '%s')\n", $2, NR, asm_line)
				assemble_errors++
				next
			}
			asm_rs1 = parsereg($3)
			if (asm_rs1 < 0) {
				printf("# ASSEMBLER ERROR: expected rs1 register, got '%s' (line %d: '%s')\n", $3, NR, asm_line)
				assemble_errors++
				next
			}

			if (strtonum($4) > 2047 || strtonum($4) < -2048) {
				printf("# ASSEMBLER ERROR: expected immediate in range -2048...2047, got '%s' (line %d: '%s')\n", $4, NR, asm_line)
				assemble_errors++
				next
			}
			asm_immI = dec2two($4)
		}


		asm_inst = or( \
			 asm_opcode, \
			 lshift(asm_rd, 7), \
			 lshift(asm_funct3, 12), \
			 lshift(asm_rs1, 15), \
			 lshift(asm_immI, 20))

		memwrite(asmcursor, asm_inst)

		asmcursor += 4

		assemble()
		next
	}
}



@@ 834,7 992,7 @@ $1 == "assert" && $2 == "reg" {
$1 == "assert" && $2 == "mem" {
	assert_val = dec2two(memread(strtonum($3)))
	if (assert_val  != dec2two(strtonum($4))) {
		printf("# ASSERTION FAILURE: memory at x%d was 0x%08x, should have been 0x%08x\n", strtonum($3), assert_val, strtonum($4))
		printf("# ASSERTION FAILURE: memory at 0x%08x was 0x%08x, should have been 0x%08x\n", strtonum($3), assert_val, strtonum($4))
		assert_errors ++
	}
}

M tests/simulation/asm_immediate.txt => tests/simulation/asm_immediate.txt +10 -0
@@ 7,6 7,11 @@ sltiu x5 x0 123
andi x5 x0 123
ori x5 x0 123
xori x5 x0 123
slli x5 x6 10
srli x5 x6 10
srai x5 x6 10
lui x10 456
auipc x11 789

mode normal
assert mem 0x000 0x07b00293


@@ 15,3 20,8 @@ assert mem 0x008 0x07b03293
assert mem 0x00c 0x07b07293
assert mem 0x010 0x07b06293
assert mem 0x014 0x07b04293
assert mem 0x018 0x00a31293
assert mem 0x01c 0x00a35293
assert mem 0x020 0x40a35293
assert mem 0x024 0x001c8537
assert mem 0x028 0x00315597

A tests/simulation/asm_register.txt => tests/simulation/asm_register.txt +28 -0
@@ 0,0 1,28 @@
tracemem 1

mode assemble
add x1 x2 x3
slt x4 x5 x6
sltu x7 x8 x9
and x10 x11 x12
or x13 x14 x15
xor x16 x17 x18
sll x19 x20 x21
srl x22 x23 x24
sub x25 x26 x27
sra x28 x29 x30
nop


mode normal
assert mem 0x00000000  0x003100b3
assert mem 0x00000004  0x0062a233
assert mem 0x00000008  0x009433b3
assert mem 0x0000000c  0x00c5f533
assert mem 0x00000010  0x00f766b3
assert mem 0x00000014  0x0128c833
assert mem 0x00000018  0x015a19b3
assert mem 0x0000001c  0x018bdb33
assert mem 0x00000020  0x41bd0cb3
assert mem 0x00000024  0x41eede33
assert mem 0x00000028  0x00000013