~charles/awk-riscv

0d5fb3390318d7fba3329ad9b253cad011c883d6 — Charles Daniels 10 months ago 1995754
implement dimp directive
2 files changed, 89 insertions(+), 14 deletions(-)

M riscv.awk
M tests/simulation/ori.txt
M riscv.awk => riscv.awk +88 -14
@@ 85,6 85,19 @@
#	Reads the 32-bit value of a register REG and prints it to standard out.
#	If REG is 0 or greater than 31, this prints 0.
#
# pcpeek
#	
#	Reads the 32-bit PC value.
#
# pcpoke ADDR
#
#	Set the 32-bit PC value to the given address.
#
# dump
#
#	Dump the current state of the simulation in a format that it can be
#	processed as directives for later resumption.
#
# assert reg REG VAL
#
#	Asserts that the register REG contains a value equal to the given


@@ 141,6 154,31 @@
# used as the program's exist code. This can allow a RISC-V program (or the
# simulator) to be tested by monitoring the exit code.
#
#
#                         DIFFERENCES FROM RV32I
#
# For the sake of simplicity, this program implements only a subset of RV32I.
# It could likely be extended to support more of it easily, if someone so
# desired. The following differences are known and deliberate:
#
# * Exception and error handling are not implemented at all.
#
# * CSR-related instructions are not implemented.
#
# * Timers and counters are not implemented.
#
# * ECALL and EBREAK are not implemented.
#
# * Although the memory map is byte-addressable internally, byte and half-word
#   related instructions are not implemented.
#
#
#                               LIMITATIONS
#
# Support for error handling, detecting and recovering from bad inputs, and so
# on is quite limited. In general, if you feed this program garbage, it will
# probably behave in unpredictable and undesirable ways.
#
###############################################################################




@@ 346,7 384,7 @@ function disasm(v) {
# write v to register regaddr
function regwrite(regaddr, v) {
	if (traceregs) {
		printf("regwrite(x%d, 0x%08x)\n", regaddr, v)
		printf("# regwrite(x%d, 0x%08x)\n", regaddr, v)
	}

	if (regaddr == 0 || regaddr > 31) {


@@ 360,14 398,14 @@ function regwrite(regaddr, v) {
function regread(regaddr ) {
	if (regaddr == 0 || regaddr > 31) {
		if (traceregs) {
			printf("regread(x%d) -> 0x%08x\n", regaddr, 0)
			printf("# regread(x%d) -> 0x%08x\n", regaddr, 0)
		}

		return 0
	}

	if (traceregs) {
		printf("regread(x%d) -> 0x%08x\n", regaddr, and(regs[regaddr], 0xffffffff))
		printf("# regread(x%d) -> 0x%08x\n", regaddr, and(regs[regaddr], 0xffffffff))
	}

	return and(regs[regaddr], 0xffffffff)


@@ 377,7 415,7 @@ function regread(regaddr ) {
# be split into 4 individual bytes and written to memaddr ... memaddr+3
function memwrite(memaddr, v) {
	if (tracemem) {
		printf("memwrite(0x%08x, 0x%08x)\n", memaddr, v)
		printf("# memwrite(0x%08x, 0x%08x)\n", memaddr, v)
	}

	mem[memaddr] = and(v, 0xff)


@@ 391,7 429,7 @@ function memwrite(memaddr, v) {
function memread(memaddr,      res) {
	res = or(lshift(and(mem[memaddr], 0xff), 0), lshift(and(mem[memaddr+1], 0xff), 8), lshift(and(mem[memaddr+2], 0xff), 16), lshift(and(mem[memaddr+3], 0xff), 24))
	if (tracemem) {
		printf("memread(0x%08x) -> 0x%08x\n", memaddr, res)
		printf("# memread(0x%08x) -> 0x%08x\n", memaddr, res)
	}
	return res
}


@@ 402,7 440,7 @@ function nextstate(    inst, branchtarget) {
	inst = memread(PC)

	if (traceinst) {
		printf("PC=0x%08x, inst=0x%08x, type=%s, disasm='%s', funct7=0x%02x, funct3=0x%1x, rs1=0x%02x, rs2=0x%02x, rd=0x%02x, opcode=0x%02x", PC, inst, type(inst), disasm(inst), funct7(inst), funct3(inst), rs1(inst), rs2(inst), rd(inst), opcode(inst))
		printf("# PC=0x%08x, inst=0x%08x, type=%s, disasm='%s', funct7=0x%02x, funct3=0x%1x, rs1=0x%02x, rs2=0x%02x, rd=0x%02x, opcode=0x%02x", PC, inst, type(inst), disasm(inst), funct7(inst), funct3(inst), rs1(inst), rs2(inst), rd(inst), opcode(inst))

		if (type(inst) == "R") {
			printf("\n")


@@ 531,6 569,10 @@ $1 == "rpoke" { regwrite(strtonum($2), strtonum($3)) ; next }

$1 == "rpeek" { printf("0x%08x\n", regread(strtonum($2))) ; next }

$1 == "pcpeek" { printf("0x%08x\n", PC) ; next }

$1 == "pcpoke" { PC = strtonum($2) ; next }

$1 == "assert" && $2 == "reg" {
	assert_val = dec2two(regread(strtonum($3)))
	if (assert_val  != dec2two(strtonum($4))) {


@@ 556,38 598,38 @@ $1 == "step" {
}

$1 == "showregs" {
	printf("register: ")
	printf("# register: ")
	for (i = 0 ; i < 8 ; i ++) {
		printf("  x%-8d ", i)
	}
	printf("\n        = ")
	printf("\n#         = ")
	for (i = 0 ; i < 8 ; i ++) {
		printf(" 0x%08x ", regs[i])
	}

	printf("\nregister: ")
	printf("\n# register: ")
	for (i = 8 ; i < 16 ; i ++) {
		printf("  x%-8d ", i)
	}
	printf("\n        = ")
	printf("\n#         = ")
	for (i = 8 ; i < 16 ; i ++) {
		printf(" 0x%08x ", regs[i])
	}

	printf("\nregister: ")
	printf("\n# register: ")
	for (i = 16 ; i < 24; i ++) {
		printf("  x%-8d ", i)
	}
	printf("\n        = ")
	printf("\n#         = ")
	for (i = 16 ; i < 24 ; i ++) {
		printf(" 0x%08x ", regs[i])
	}

	printf("\nregister: ")
	printf("\n# register: ")
	for (i = 24; i < 32; i ++) {
		printf("  x%-8d ", i)
	}
	printf("\n        = ")
	printf("\n#         = ")
	for (i = 24; i < 32 ; i ++) {
		printf(" 0x%08x ", regs[i])
	}


@@ 597,6 639,38 @@ $1 == "showregs" {
	next
}

$1 == "dump" {
	printf("# BEGINNING OF RISCV.AWK DUMP\n")

	printf("pcpoke 0x%08x\n", PC)

	savtraceregs = traceregs
	savtracemem = tracemem
	traceregs = 0
	tracemem = 0

	for (addr in regs) {
		if (regread(addr) != 0 ) {
			printf("rpoke %d 0x%08x\n", addr, regread(addr))
		}
	}

	for (addr in mem) {
		if (addr % 4 == 0) {
			if (memread(addr) != 0) {
				printf("poke 0x%08x 0x%08x   # %s\n", addr, memread(addr), disasm(memread(addr)))
			}
		}
	}

	printf("# END OF RISCV.AWK DUMP\n")

	traceregs = savtraceregs
	tracemem = savtracemem

	next
}

# these operations expose some of our internal functions to assist in debugging
# and automated testing
$1 == "debug" && $2 == "funct7" { printf("0x%08x\n", funct7(strtonum($3))); next }

M tests/simulation/ori.txt => tests/simulation/ori.txt +1 -0
@@ 23,3 23,4 @@ assert reg 14 0xff
assert reg 15 0xff

showregs
dump