~charles/awk-riscv

42fd79a2b22dd6c42ae21c5095bdc4503ce9ec5f — Charles Daniels 10 months ago fa3c47f
get fibo test case working
3 files changed, 122 insertions(+), 12 deletions(-)

M README.md
M riscv.awk
A tests/simulation/fibo.txt
M README.md => README.md +56 -11
@@ 2,8 2,9 @@

This program is a complete, self-contained simulator for most of the
[RV32I](https://riscv.org//wp-content/uploads/2017/05/riscv-spec-v2.2.pdf)
instruction set. It is implemented entirely in AWK. I have tested it only under
GNU AWK 5.0.1, it may or may not work under other AWKs.
instruction set, as well as a simple assembler for the same. It is implemented
entirely in AWK. I have tested it only under GNU AWK 5.0.1, it may or may not
work under other AWKs.

# Usage



@@ 12,22 13,66 @@ For usage, please see the comments in [riscv.awk](./riscv.awk).
# Demo

Here is the simulator running a RISC-V assembler program which computes the
20th Fibonacci number (6765, 0x1a6d).
20th Fibonacci number (6765, 0x1a6d). [The input
file](./tests/simulation/fibo.txt) includes the assembler program, as well as
several directives that cause `riscv.awk` to assemble and execute it. All but
the last line of output consists of two dumps of the simulation state, one
before the CPU is run, and one after.

```
$ awk -f riscv.awk < fibo.txt
$ awk -f riscv.awk < tests/simulation/fibo.txt
# BEGINNING OF RISCV.AWK DUMP
pcpoke 0x00000000
poke 0x00000000 0x000102b7   # 0x000102b7: LUI x5 0x10000
poke 0x00000004 0x0002a503   # 0x0002a503: LW x10 x5 0
poke 0x00000008 0x00100593   # 0x00100593: ADDI x11 x0 1
poke 0x0000000c 0x00000613   # 0x00000613: ADDI x12 x0 0
poke 0x00000010 0x00100693   # 0x00100693: ADDI x13 x0 1
poke 0x00000014 0x00000713   # 0x00000713: ADDI x14 x0 0
poke 0x00000018 0x00a6c663   # 0x00a6c663: BLT x13 x10 0xc
poke 0x0000001c 0x0000006f   # 0x0000006f: JAL x0 0x0
poke 0x00000020 0x0180006f   # 0x0180006f: JAL x0 0x18
poke 0x00000024 0x00d60733   # 0x00d60733: ADD x14 x12 x13
poke 0x00000028 0x00d00633   # 0x00d00633: ADD x12 x0 x13
poke 0x0000002c 0x00e006b3   # 0x00e006b3: ADD x13 x0 x14
poke 0x00000030 0x00158593   # 0x00158593: ADDI x11 x11 1
poke 0x00000034 0xfea5c8e3   # 0xfea5c8e3: BLT x11 x10 0xfffffff0
poke 0x00000038 0x00d2a223   # 0x00d2a223: SW x5 x13 4
# END OF RISCV.AWK DUMP
# BEGINNING OF RISCV.AWK DUMP
pcpoke 0x000025b0
rpoke 10 0x00000014
rpoke 11 0x00000014
rpoke 12 0x00001055
rpoke 13 0x00001a6d
rpoke 14 0x00001a6d
poke 0x00000000 0x000102b7   # 0x000102b7: LUI x5 0x10000
poke 0x00000004 0x0002a503   # 0x0002a503: LW x10 x5 0
poke 0x00000008 0x00100593   # 0x00100593: ADDI x11 x0 1
poke 0x0000000c 0x00000613   # 0x00000613: ADDI x12 x0 0
poke 0x00000010 0x00100693   # 0x00100693: ADDI x13 x0 1
poke 0x00000014 0x00000713   # 0x00000713: ADDI x14 x0 0
poke 0x00000018 0x00a6c663   # 0x00a6c663: BLT x13 x10 0xc
poke 0x0000001c 0x0000006f   # 0x0000006f: JAL x0 0x0
poke 0x00000020 0x0180006f   # 0x0180006f: JAL x0 0x18
poke 0x00000024 0x00d60733   # 0x00d60733: ADD x14 x12 x13
poke 0x00000028 0x00d00633   # 0x00d00633: ADD x12 x0 x13
poke 0x0000002c 0x00e006b3   # 0x00e006b3: ADD x13 x0 x14
poke 0x00000030 0x00158593   # 0x00158593: ADDI x11 x11 1
poke 0x00000034 0xfea5c8e3   # 0xfea5c8e3: BLT x11 x10 0xfffffff0
poke 0x00000038 0x00d2a223   # 0x00d2a223: SW x5 x13 4
poke 0x00010000 0x00000014   # 0x00000014: UNKNOWN
poke 0x00010004 0x00001a6d   # 0x00001a6d: UNKNOWN
# END OF RISCV.AWK DUMP
0x00001a6d
```

See [`fibo.txt`](./fibo.txt), the input to the simulator, which was produced
using [`fibo.asm`](./fibo.asm). Converting an assembler file into something the
simulator can run is done by hand for now, but with considerable help from
[RARS](https://github.com/TheThirdOne/rars).

```

This program can also be used as a disassembler:

```
$ awk '($1 == "poke" && $2 != "0x10000") {print($3)}' < fibo.txt
$ cat sample.txt
0x000102b7
0x00028293
0x0002a503


@@ 50,7 95,7 @@ $ awk '($1 == "poke" && $2 != "0x10000") {print($3)}' < fibo.txt
0xf0359073
0xfea5c4e3
0x00d2a223
$ awk '($1 == "poke" && $2 != "0x10000") {print($3)}' < fibo.txt  | awk -f riscv.awk -v mode=disasm
$ awk -f riscv.awk -v mode=disasm < sample.txt
0x000102b7: LUI x5 0x10000
0x00028293: ADDI x5 x5 0
0x0002a503: LW x10 x5 0

M riscv.awk => riscv.awk +5 -1
@@ 236,6 236,10 @@
# established which approach is correct, this program will be updated to use
# it.
#
#	UPDATE: it turns out I was incorrect, and the RARS behavior was
#	correct, as documented in the comment thread for the issue. This
#	program needs to be updated to use the correct behavior.
#
# The syntax for lw and sw is changed in order to make them easier to parse.
# The assembled instructions are identical in memory.  The equivalence table is
# shown below:


@@ 875,7 879,7 @@ function assemble() {
			assemble_errors++
			return
		}
		asm_immU = lshift(dec2two($3), 12)
		asm_immU = lshift(dec2two(strtonum($3)), 12)
	} else if (asm_style == "R") {
		asm_rd = parsereg($2)
		if (asm_rd < 0) {

A tests/simulation/fibo.txt => tests/simulation/fibo.txt +61 -0
@@ 0,0 1,61 @@
# keep assembling instructions until we see "mode normal"
mode assemble

# This program computes the value of the nth number in the Fibonacci sequence,
# where n is read from memory address 0x10000. The result is written to memory
# address 0x10004.

lui x5 0x10
lw x10 x5 0        # n <- mem[0x10000]
addi x11 x0 1      # i <- 1
addi x12 x0 0      # F[0] <- 0
addi x13 x0 1      # F[1] <- 1
addi x14 x0 0      # next <- 0

# x12 and x13 will be used to track the previous two elements of the fibonacci
# sequence as we advance through the loop

blt x13 x10 input_is_other      # if n > 1

input_is_zero:
jal x0 end

input_is_one:
jal x0 end

input_is_other:

fibo:
add x14 x12 x13         # next <- F[i] + F[i-1]
add x12 x0 x13          # F[i-1] <- F[i]
add x13 x0 x14          # F[i] <- next
addi x11 x11 1          # i++
blt x11 x10 fibo        # while(i < n)

end:
sw x5 x13 4   # mem[0x10004] <- F[n]

# return to normal mode so we can process other directives
mode normal

# resolve all branch and jump targets
resolve

# dump contents of memory
dump

# write input parameter, we will find the 20th Fibonacci number
poke 0x10000 20

# run the CPU for 2500 steps
step 2500

# dump the memory state again
dump

# view the results written back to this memory location
peek 0x10004

# this is used by the test suite to verify that this program gets the correct
# result
assert mem 0x10004 0x1a6d