Nuke
This commit is contained in:
commit
932413bb3d
61 changed files with 7249 additions and 0 deletions
52
src/test/resources/tests/basic/arithmetic/arith.s
Normal file
52
src/test/resources/tests/basic/arithmetic/arith.s
Normal file
|
@ -0,0 +1,52 @@
|
|||
main:
|
||||
addi x1, zero, 1
|
||||
addi x2, zero, -1
|
||||
addi x3, zero, 3
|
||||
addi x4, zero, 7
|
||||
addi x5, zero, 14
|
||||
addi x6, zero, 28
|
||||
addi x7, zero, 56
|
||||
addi x8, zero, 133
|
||||
addi x9, zero, 258
|
||||
addi x10, x1, -231
|
||||
addi x11, x1, -510
|
||||
slt x12, x1, x1
|
||||
slt x12, x1, x2
|
||||
slt x12, x1, x3
|
||||
slt x12, x2, x1
|
||||
slt x12, x2, x2
|
||||
slt x12, x2, x3
|
||||
sltu x12, x1, x1
|
||||
sltu x12, x1, x2
|
||||
sltu x12, x1, x3
|
||||
sltu x12, x2, x1
|
||||
sltu x12, x2, x2
|
||||
sltu x12, x2, x3
|
||||
sll x14, x1, x1
|
||||
sll x14, x1, x2
|
||||
sll x14, x1, x3
|
||||
srl x14, x1, x1
|
||||
srl x14, x1, x2
|
||||
srl x14, x1, x3
|
||||
sra x14, x1, x1
|
||||
sra x14, x1, x2
|
||||
sra x14, x1, x3
|
||||
and x15, x8, x9
|
||||
and x15, x9, x10
|
||||
or x15, x8, x9
|
||||
or x15, x9, x10
|
||||
xor x15, x8, x9
|
||||
xor x15, x9, x10
|
||||
add x16, x1, x5
|
||||
add x16, x2, x7
|
||||
add x16, x3, x6
|
||||
add x16, x4, x10
|
||||
add x16, x5, x14
|
||||
add x16, x6, x15
|
||||
add x16, x7, x7
|
||||
add x16, x8, x9
|
||||
add x16, x9, x1
|
||||
add x16, x10, x8
|
||||
add x16, x11, x9
|
||||
add x16, x12, x10
|
||||
done
|
205
src/test/resources/tests/basic/forward1.s
Normal file
205
src/test/resources/tests/basic/forward1.s
Normal file
|
@ -0,0 +1,205 @@
|
|||
main:
|
||||
ori gp, gp, 0xFFFFFE09
|
||||
and gp, gp, ra
|
||||
xor ra, ra, sp
|
||||
sra ra, sp, sp
|
||||
or sp, ra, ra
|
||||
xori ra, sp, 0x003D
|
||||
srli sp, sp, 0xFFFFFFF2
|
||||
addi ra, sp, 0x0012
|
||||
add ra, gp, sp
|
||||
ori gp, ra, 0xFFFFFFB8
|
||||
sll ra, ra, ra
|
||||
sll sp, gp, ra
|
||||
slt ra, gp, ra
|
||||
srai gp, gp, 0xFFFFFFFB
|
||||
slli ra, ra, 0x0007
|
||||
sub sp, gp, sp
|
||||
andi ra, gp, 0x002D
|
||||
sub gp, gp, sp
|
||||
srai ra, gp, 0x0005
|
||||
or sp, ra, sp
|
||||
xori ra, gp, 0xFFFFFF54
|
||||
sll ra, sp, ra
|
||||
sub gp, gp, sp
|
||||
add ra, sp, sp
|
||||
sll ra, gp, ra
|
||||
add gp, sp, sp
|
||||
ori gp, sp, 0xFFFFFE68
|
||||
srli sp, gp, 0xFFFFFFF1
|
||||
sltui ra, ra, 0xFFFFFE5D
|
||||
srli ra, gp, 0x0006
|
||||
srai sp, sp, 0x0005
|
||||
andi sp, sp, 0x0129
|
||||
and sp, sp, sp
|
||||
slli gp, ra, 0x0001
|
||||
or gp, gp, gp
|
||||
or sp, gp, gp
|
||||
slli gp, gp, 0x0006
|
||||
srl sp, ra, gp
|
||||
sltui gp, ra, 0xFFFFFEC3
|
||||
add sp, gp, sp
|
||||
xori ra, ra, 0xFFFFFFA2
|
||||
or gp, gp, sp
|
||||
and sp, gp, gp
|
||||
srai gp, sp, 0x0008
|
||||
add sp, sp, ra
|
||||
slti sp, ra, 0xFFFFFFF7
|
||||
srli gp, ra, 0xFFFFFFFD
|
||||
sll gp, ra, gp
|
||||
sltu sp, sp, gp
|
||||
srli gp, ra, 0x0002
|
||||
ori gp, sp, 0xFFFFFF28
|
||||
srl ra, gp, ra
|
||||
slti gp, ra, 0x0054
|
||||
or gp, ra, ra
|
||||
ori sp, gp, 0x01D9
|
||||
and sp, ra, ra
|
||||
addi sp, gp, 0x0054
|
||||
slli gp, ra, 0xFFFFFFF2
|
||||
ori sp, sp, 0x0093
|
||||
add gp, gp, gp
|
||||
and gp, gp, gp
|
||||
sltui gp, ra, 0x00DE
|
||||
slli sp, gp, 0x000D
|
||||
slli sp, ra, 0xFFFFFFF5
|
||||
sltui sp, ra, 0xFFFFFF0E
|
||||
and ra, gp, ra
|
||||
add gp, sp, sp
|
||||
slti ra, sp, 0x008C
|
||||
srli ra, sp, 0x0000
|
||||
addi sp, sp, 0x0168
|
||||
slli ra, ra, 0xFFFFFFF3
|
||||
addi ra, gp, 0x012A
|
||||
or sp, gp, ra
|
||||
add ra, sp, gp
|
||||
and gp, ra, ra
|
||||
slli ra, gp, 0xFFFFFFF6
|
||||
or sp, gp, sp
|
||||
or gp, ra, ra
|
||||
ori gp, ra, 0x00EB
|
||||
or sp, gp, ra
|
||||
ori gp, sp, 0x01DA
|
||||
andi ra, ra, 0xFFFFFFE9
|
||||
addi gp, sp, 0x00C9
|
||||
sltui ra, ra, 0xFFFFFF13
|
||||
sltui ra, ra, 0xFFFFFF3A
|
||||
sltui sp, gp, 0xFFFFFE5A
|
||||
ori sp, sp, 0xFFFFFFFE
|
||||
and gp, sp, gp
|
||||
sltui sp, ra, 0x0034
|
||||
srl gp, gp, ra
|
||||
sll gp, sp, ra
|
||||
ori ra, gp, 0xFFFFFEB6
|
||||
sll ra, sp, ra
|
||||
sra ra, gp, sp
|
||||
sub ra, sp, gp
|
||||
xor gp, gp, sp
|
||||
sub ra, ra, sp
|
||||
srl gp, gp, sp
|
||||
andi ra, ra, 0xFFFFFFCB
|
||||
ori ra, ra, 0xFFFFFE1B
|
||||
andi ra, ra, 0xFFFFFEC8
|
||||
sltui sp, gp, 0x0108
|
||||
sub sp, gp, ra
|
||||
slti ra, sp, 0x015D
|
||||
slli sp, sp, 0x0004
|
||||
xor gp, sp, ra
|
||||
srl ra, gp, ra
|
||||
sltui ra, ra, 0xFFFFFF3C
|
||||
add sp, sp, sp
|
||||
add gp, gp, ra
|
||||
andi sp, sp, 0xFFFFFF3A
|
||||
srli ra, sp, 0x0004
|
||||
ori sp, gp, 0xFFFFFEAB
|
||||
ori sp, ra, 0xFFFFFE95
|
||||
slli sp, sp, 0xFFFFFFF2
|
||||
xori gp, sp, 0x0040
|
||||
slti gp, sp, 0xFFFFFED1
|
||||
or sp, sp, sp
|
||||
sltui sp, gp, 0x01B4
|
||||
addi ra, gp, 0x002D
|
||||
and sp, gp, gp
|
||||
or ra, ra, ra
|
||||
or ra, gp, ra
|
||||
or ra, gp, ra
|
||||
sra ra, ra, gp
|
||||
sra gp, ra, sp
|
||||
sub ra, sp, ra
|
||||
srai ra, ra, 0x000F
|
||||
sltu sp, sp, ra
|
||||
slli ra, gp, 0xFFFFFFF5
|
||||
slti gp, gp, 0x00E0
|
||||
addi gp, ra, 0xFFFFFF72
|
||||
srl ra, ra, gp
|
||||
sltui gp, sp, 0xFFFFFEAA
|
||||
xor sp, ra, gp
|
||||
and gp, sp, ra
|
||||
srli gp, gp, 0x0003
|
||||
xori ra, ra, 0x01BD
|
||||
sub ra, gp, sp
|
||||
sll gp, ra, gp
|
||||
xori ra, sp, 0x0065
|
||||
or ra, sp, ra
|
||||
slt sp, gp, ra
|
||||
addi ra, sp, 0xFFFFFE34
|
||||
slli gp, sp, 0x0007
|
||||
sll ra, sp, gp
|
||||
sltui gp, gp, 0xFFFFFE62
|
||||
slti sp, sp, 0x0019
|
||||
xori ra, gp, 0x0092
|
||||
sltui gp, sp, 0xFFFFFF29
|
||||
srl sp, ra, gp
|
||||
xori sp, gp, 0xFFFFFF4C
|
||||
add sp, ra, gp
|
||||
add sp, gp, ra
|
||||
sra sp, sp, gp
|
||||
slli sp, ra, 0x0008
|
||||
srl sp, sp, sp
|
||||
add sp, gp, ra
|
||||
andi sp, sp, 0x0039
|
||||
sll ra, gp, sp
|
||||
andi gp, ra, 0xFFFFFECC
|
||||
sll sp, sp, sp
|
||||
sub sp, sp, ra
|
||||
srai ra, sp, 0x0008
|
||||
xor gp, ra, sp
|
||||
add sp, sp, sp
|
||||
sub gp, ra, gp
|
||||
xori gp, sp, 0x01EE
|
||||
and ra, ra, ra
|
||||
ori gp, ra, 0xFFFFFE96
|
||||
slli ra, gp, 0x0002
|
||||
srli gp, ra, 0x000D
|
||||
add ra, sp, sp
|
||||
andi sp, gp, 0xFFFFFEC0
|
||||
andi sp, gp, 0xFFFFFE7A
|
||||
xori ra, sp, 0x0169
|
||||
xori gp, sp, 0xFFFFFE02
|
||||
andi ra, ra, 0xFFFFFFD1
|
||||
xor ra, sp, gp
|
||||
xori gp, gp, 0x00AB
|
||||
srl ra, ra, gp
|
||||
and ra, ra, sp
|
||||
xori gp, sp, 0x005D
|
||||
srai sp, sp, 0x000A
|
||||
addi ra, sp, 0xFFFFFE19
|
||||
or sp, ra, ra
|
||||
addi ra, gp, 0x0084
|
||||
ori sp, sp, 0xFFFFFF3D
|
||||
xor gp, ra, gp
|
||||
sra ra, ra, gp
|
||||
xori ra, sp, 0x0040
|
||||
srai gp, gp, 0x0002
|
||||
xori ra, ra, 0xFFFFFE9A
|
||||
sra ra, sp, sp
|
||||
ori gp, sp, 0xFFFFFFB8
|
||||
sll sp, ra, ra
|
||||
sll sp, ra, gp
|
||||
sll gp, sp, sp
|
||||
sra gp, ra, ra
|
||||
srli gp, gp, 0x0001
|
||||
done
|
||||
#regset x1, 123
|
||||
#regset x2, -40
|
||||
#regset x3, 0xFFEE
|
205
src/test/resources/tests/basic/forward2.s
Normal file
205
src/test/resources/tests/basic/forward2.s
Normal file
|
@ -0,0 +1,205 @@
|
|||
main:
|
||||
sltui gp, ra, 0x01AE
|
||||
srli sp, sp, 0xFFFFFFFB
|
||||
addi ra, sp, 0x0177
|
||||
sub sp, ra, sp
|
||||
slli sp, ra, 0x000B
|
||||
add sp, gp, ra
|
||||
slli gp, sp, 0x0006
|
||||
ori sp, ra, 0xFFFFFF64
|
||||
and gp, gp, gp
|
||||
andi gp, gp, 0x0084
|
||||
xori ra, ra, 0xFFFFFEB4
|
||||
or sp, ra, ra
|
||||
addi sp, ra, 0x0078
|
||||
srli gp, sp, 0x0000
|
||||
srl sp, gp, sp
|
||||
andi ra, gp, 0xFFFFFFF4
|
||||
srai ra, ra, 0xFFFFFFFF
|
||||
sltu gp, sp, gp
|
||||
or sp, ra, gp
|
||||
sub ra, gp, ra
|
||||
addi sp, gp, 0x017C
|
||||
sltui ra, gp, 0xFFFFFF64
|
||||
xori sp, gp, 0x00A1
|
||||
xor ra, sp, gp
|
||||
ori gp, ra, 0x00B6
|
||||
add ra, ra, sp
|
||||
sltui gp, ra, 0xFFFFFFEC
|
||||
sltu gp, sp, ra
|
||||
sll sp, ra, gp
|
||||
add gp, ra, ra
|
||||
or gp, ra, gp
|
||||
xor sp, ra, sp
|
||||
addi sp, gp, 0xFFFFFF4C
|
||||
xor ra, sp, gp
|
||||
xori ra, sp, 0xFFFFFF72
|
||||
xori gp, sp, 0xFFFFFE95
|
||||
or ra, ra, ra
|
||||
slti ra, gp, 0xFFFFFE75
|
||||
slli sp, sp, 0xFFFFFFFC
|
||||
sltui ra, ra, 0xFFFFFE25
|
||||
add sp, ra, gp
|
||||
sltui gp, gp, 0xFFFFFFDB
|
||||
addi sp, sp, 0x003D
|
||||
sll ra, ra, sp
|
||||
ori ra, ra, 0x012C
|
||||
add gp, ra, gp
|
||||
xori sp, sp, 0x0157
|
||||
slti gp, sp, 0xFFFFFF2A
|
||||
and sp, ra, ra
|
||||
add gp, ra, ra
|
||||
sltui ra, gp, 0xFFFFFE56
|
||||
sra gp, gp, ra
|
||||
xori sp, gp, 0xFFFFFF0D
|
||||
sub sp, gp, ra
|
||||
slti ra, ra, 0x0154
|
||||
slli ra, ra, 0x000A
|
||||
ori ra, gp, 0xFFFFFEC2
|
||||
ori ra, sp, 0x0075
|
||||
addi gp, sp, 0x0079
|
||||
xor gp, ra, sp
|
||||
srli ra, sp, 0xFFFFFFF8
|
||||
slli gp, gp, 0x0006
|
||||
sra sp, gp, gp
|
||||
add sp, sp, sp
|
||||
slli gp, ra, 0xFFFFFFF0
|
||||
add sp, ra, sp
|
||||
srai ra, sp, 0x0005
|
||||
addi ra, gp, 0xFFFFFF83
|
||||
xor gp, sp, ra
|
||||
srli ra, ra, 0x0007
|
||||
sll gp, ra, gp
|
||||
xori gp, gp, 0x0163
|
||||
add ra, gp, gp
|
||||
add sp, ra, ra
|
||||
sltu ra, ra, sp
|
||||
sll sp, ra, ra
|
||||
ori sp, sp, 0xFFFFFF6B
|
||||
slli gp, gp, 0xFFFFFFFA
|
||||
xori sp, ra, 0x00A7
|
||||
add sp, ra, ra
|
||||
add ra, gp, gp
|
||||
addi gp, gp, 0xFFFFFFE9
|
||||
sra sp, ra, gp
|
||||
add gp, ra, ra
|
||||
ori gp, gp, 0x0002
|
||||
addi gp, gp, 0x002F
|
||||
sll sp, sp, ra
|
||||
srli sp, ra, 0xFFFFFFF2
|
||||
ori gp, sp, 0x00EB
|
||||
sra gp, ra, sp
|
||||
sra sp, sp, gp
|
||||
and gp, ra, ra
|
||||
sra ra, ra, gp
|
||||
add sp, gp, ra
|
||||
srl gp, sp, gp
|
||||
add ra, ra, sp
|
||||
srai gp, ra, 0xFFFFFFF2
|
||||
srli sp, ra, 0xFFFFFFFC
|
||||
ori gp, sp, 0xFFFFFE6E
|
||||
and gp, ra, ra
|
||||
ori gp, ra, 0xFFFFFFAF
|
||||
srl ra, ra, ra
|
||||
or sp, ra, ra
|
||||
ori gp, sp, 0x0018
|
||||
and gp, gp, gp
|
||||
slti gp, ra, 0x00C6
|
||||
sll gp, sp, gp
|
||||
srli gp, sp, 0xFFFFFFFA
|
||||
add gp, ra, ra
|
||||
add gp, ra, sp
|
||||
sra sp, ra, ra
|
||||
ori sp, ra, 0x0022
|
||||
and gp, gp, gp
|
||||
add ra, sp, ra
|
||||
sll sp, gp, gp
|
||||
ori gp, sp, 0x008E
|
||||
slti ra, gp, 0x00B5
|
||||
add sp, ra, sp
|
||||
and sp, gp, gp
|
||||
addi ra, sp, 0x0145
|
||||
and sp, gp, gp
|
||||
sll gp, ra, sp
|
||||
addi sp, sp, 0xFFFFFFAF
|
||||
xori sp, ra, 0xFFFFFE2C
|
||||
srl gp, ra, gp
|
||||
sub ra, sp, gp
|
||||
add sp, ra, ra
|
||||
slli sp, sp, 0x0006
|
||||
sub gp, ra, sp
|
||||
sltu sp, ra, gp
|
||||
xori ra, ra, 0xFFFFFF9A
|
||||
addi sp, sp, 0xFFFFFE12
|
||||
slli ra, ra, 0xFFFFFFFD
|
||||
add gp, gp, gp
|
||||
xori ra, ra, 0xFFFFFED7
|
||||
andi gp, gp, 0xFFFFFE05
|
||||
and gp, gp, sp
|
||||
addi gp, gp, 0xFFFFFEE5
|
||||
slli ra, gp, 0xFFFFFFF6
|
||||
sll sp, gp, gp
|
||||
and ra, gp, sp
|
||||
ori ra, gp, 0xFFFFFE22
|
||||
srl sp, sp, gp
|
||||
srli ra, sp, 0x0005
|
||||
slli ra, ra, 0xFFFFFFFB
|
||||
srai ra, ra, 0xFFFFFFF9
|
||||
srli ra, gp, 0xFFFFFFF1
|
||||
andi gp, gp, 0xFFFFFF96
|
||||
sra sp, gp, gp
|
||||
srai gp, gp, 0x000F
|
||||
sub sp, sp, gp
|
||||
sltui ra, ra, 0xFFFFFF41
|
||||
and sp, sp, sp
|
||||
xor gp, sp, ra
|
||||
srai gp, sp, 0xFFFFFFF6
|
||||
xori gp, gp, 0x00D3
|
||||
or gp, sp, sp
|
||||
sltu gp, ra, gp
|
||||
slli ra, gp, 0x0002
|
||||
or sp, gp, ra
|
||||
addi ra, ra, 0x002B
|
||||
addi gp, ra, 0x0035
|
||||
slli sp, gp, 0x0008
|
||||
addi gp, sp, 0x015E
|
||||
xor ra, gp, sp
|
||||
or ra, gp, ra
|
||||
sll ra, gp, ra
|
||||
sll gp, gp, ra
|
||||
srli gp, ra, 0xFFFFFFF4
|
||||
slt sp, ra, sp
|
||||
sltui sp, sp, 0xFFFFFE1C
|
||||
ori sp, ra, 0xFFFFFE83
|
||||
andi sp, sp, 0xFFFFFEFC
|
||||
addi ra, ra, 0xFFFFFF85
|
||||
ori gp, ra, 0x0084
|
||||
sll gp, gp, ra
|
||||
xori gp, sp, 0xFFFFFF6D
|
||||
sll gp, sp, gp
|
||||
sra ra, sp, ra
|
||||
xor ra, gp, sp
|
||||
srl ra, ra, sp
|
||||
srl ra, ra, sp
|
||||
andi gp, ra, 0xFFFFFE7B
|
||||
srai ra, sp, 0xFFFFFFF1
|
||||
sub sp, sp, ra
|
||||
or sp, gp, gp
|
||||
slt ra, ra, gp
|
||||
or gp, gp, sp
|
||||
srli ra, sp, 0xFFFFFFF5
|
||||
andi ra, gp, 0xFFFFFFD4
|
||||
sra sp, sp, sp
|
||||
add sp, ra, sp
|
||||
sub gp, ra, sp
|
||||
xori ra, gp, 0x0131
|
||||
add sp, sp, ra
|
||||
addi sp, gp, 0x0003
|
||||
sll ra, ra, ra
|
||||
slli gp, ra, 0x000E
|
||||
andi ra, gp, 0xFFFFFE88
|
||||
srai ra, gp, 0xFFFFFFFA
|
||||
done
|
||||
#regset x1, 123
|
||||
#regset x2, -40
|
||||
#regset x3, 0xFFEE
|
41
src/test/resources/tests/basic/immediate/addi.s
Normal file
41
src/test/resources/tests/basic/immediate/addi.s
Normal file
|
@ -0,0 +1,41 @@
|
|||
main:
|
||||
addi x0, x1, 1
|
||||
addi x0, x1, 2
|
||||
addi x0, x1, 3
|
||||
addi x0, x1, 7
|
||||
addi x0, x1, 14
|
||||
addi x0, x1, 28
|
||||
addi x0, x1, 56
|
||||
addi x31, x1, 1
|
||||
addi x31, x1, 2
|
||||
addi x31, x1, 3
|
||||
addi x31, x1, 7
|
||||
addi x31, x1, 14
|
||||
addi x31, x1, 28
|
||||
addi x31, x1, 56
|
||||
addi x31, x1, 133
|
||||
addi x31, x1, 258
|
||||
addi x31, x1, 511
|
||||
addi x31, x1, -1
|
||||
addi x31, x1, -3
|
||||
addi x31, x1, -9
|
||||
addi x31, x1, -98
|
||||
addi x31, x1, -231
|
||||
addi x31, x1, -510
|
||||
addi x30, x0, 1
|
||||
addi x30, x30, 2
|
||||
addi x30, x30, 3
|
||||
addi x30, x30, 7
|
||||
addi x30, x30, 14
|
||||
addi x30, x30, 28
|
||||
addi x30, x30, 56
|
||||
addi x30, x30, 133
|
||||
addi x30, x30, 258
|
||||
addi x30, x30, 511
|
||||
addi x30, x30, -1
|
||||
addi x30, x30, -3
|
||||
addi x30, x30, -9
|
||||
addi x30, x30, -98
|
||||
addi x30, x30, -231
|
||||
addi x30, x30, -510
|
||||
done
|
37
src/test/resources/tests/basic/immediate/arithImm.s
Normal file
37
src/test/resources/tests/basic/immediate/arithImm.s
Normal file
|
@ -0,0 +1,37 @@
|
|||
main:
|
||||
addi x1, zero, 1
|
||||
addi x2, zero, -1
|
||||
addi x3, zero, 3
|
||||
addi x4, zero, 7
|
||||
addi x5, zero, 14
|
||||
addi x6, zero, 28
|
||||
addi x7, zero, 56
|
||||
addi x8, zero, 133
|
||||
addi x9, zero, 258
|
||||
addi x10, x1, -231
|
||||
addi x11, x1, -510
|
||||
slti x12, x1, 1
|
||||
slti x12, x1, 10
|
||||
slti x12, x1, -10
|
||||
sltiu x13, x1, 1
|
||||
sltiu x13, x1, 10
|
||||
sltiu x13, x1, -10
|
||||
slti x12, x2, 1
|
||||
slti x12, x2, 10
|
||||
slti x12, x2, -10
|
||||
sltiu x13, x2, 1
|
||||
sltiu x13, x2, 10
|
||||
sltiu x13, x2, -10
|
||||
slli x14, x1, 16
|
||||
slli x14, x2, 16
|
||||
srai x14, x1, 16
|
||||
srai x14, x2, 16
|
||||
srli x14, x1, 16
|
||||
srli x14, x2, 16
|
||||
andi x15, x8, 3
|
||||
andi x15, x9, -1
|
||||
ori x15, x8, 3
|
||||
ori x15, x9, -1
|
||||
xori x15, x8, 3
|
||||
xori x15, x9, -1
|
||||
done
|
0
src/test/resources/tests/basic/immediate/arithmetic.s
Normal file
0
src/test/resources/tests/basic/immediate/arithmetic.s
Normal file
35
src/test/resources/tests/basic/load.s
Normal file
35
src/test/resources/tests/basic/load.s
Normal file
|
@ -0,0 +1,35 @@
|
|||
main:
|
||||
addi x1, zero, 4
|
||||
addi x2, zero, 4
|
||||
addi x3, zero, 4
|
||||
addi x4, zero, 4
|
||||
lw x3, 0(x3)
|
||||
nop
|
||||
nop
|
||||
lw x3, 0(x3)
|
||||
nop
|
||||
nop
|
||||
lw x3, 0(x3)
|
||||
nop
|
||||
nop
|
||||
lw x3, 0(x3)
|
||||
nop
|
||||
nop
|
||||
lw x2, 0(x2)
|
||||
nop
|
||||
lw x2, 0(x2)
|
||||
nop
|
||||
lw x2, 0(x2)
|
||||
nop
|
||||
lw x2, 0(x2)
|
||||
nop
|
||||
lw x1, 0(x1)
|
||||
lw x1, 0(x1)
|
||||
lw x1, 0(x1)
|
||||
lw x1, 0(x1)
|
||||
done
|
||||
#memset 0x0, 4
|
||||
#memset 0x4, 8
|
||||
#memset 0x8, 12
|
||||
#memset 0xc, 16
|
||||
#memset 0x10, 20
|
20
src/test/resources/tests/basic/load2.s
Normal file
20
src/test/resources/tests/basic/load2.s
Normal file
|
@ -0,0 +1,20 @@
|
|||
main:
|
||||
addi x1, zero, 4
|
||||
addi x2, zero, 4
|
||||
addi x3, zero, 4
|
||||
addi x4, zero, 4
|
||||
lw x1, 0(x1)
|
||||
add x1, x1, x1
|
||||
lw x1, 0(x1)
|
||||
sw x1, 4(x1)
|
||||
lw x1, 4(x1)
|
||||
done
|
||||
#memset 0x0, 4
|
||||
#memset 0x4, 8
|
||||
#memset 0x8, 12
|
||||
#memset 0xc, 16
|
||||
#memset 0x10, 20
|
||||
#memset 0x14, 20
|
||||
#memset 0x18, 20
|
||||
#memset 0x1c, 20
|
||||
#memset 0x20, 20
|
180
src/test/resources/tests/programs/BTreeManyO3.s
Normal file
180
src/test/resources/tests/programs/BTreeManyO3.s
Normal file
|
@ -0,0 +1,180 @@
|
|||
main:
|
||||
addi sp,sp,-16
|
||||
sw ra,12(sp)
|
||||
sw s0,8(sp)
|
||||
sw s1,4(sp)
|
||||
sw s2,0(sp)
|
||||
lw s2,0(zero)
|
||||
lw a5,0(s2)
|
||||
blez a5,.L17
|
||||
addi s0,s2,4
|
||||
slli a5,a5,2
|
||||
add s2,a5,s0
|
||||
li s1,0
|
||||
.L16:
|
||||
addi s0,s0,4
|
||||
lw a0,0(s0)
|
||||
call find
|
||||
add s1,s1,a0
|
||||
bne s0,s2,.L16
|
||||
.L14:
|
||||
mv a0,s1
|
||||
lw ra,12(sp)
|
||||
lw s0,8(sp)
|
||||
lw s1,4(sp)
|
||||
lw s2,0(sp)
|
||||
addi sp,sp,16
|
||||
jr ra
|
||||
.L17:
|
||||
li s1,0
|
||||
j .L14
|
||||
find:
|
||||
li a5,4
|
||||
j .L2
|
||||
.L12:
|
||||
mv a0,a5
|
||||
ret
|
||||
.L13:
|
||||
lw a5,0(a5)
|
||||
slli a5,a5,1
|
||||
andi a5,a5,508
|
||||
addi a5,a5,4
|
||||
j .L2
|
||||
.L4:
|
||||
bge a4,a0,.L9
|
||||
lw a4,0(a5)
|
||||
andi a4,a4,256
|
||||
beqz a4,.L10
|
||||
lw a5,0(a5)
|
||||
srli a5,a5,7
|
||||
andi a5,a5,508
|
||||
addi a5,a5,4
|
||||
.L2:
|
||||
lh a4,2(a5)
|
||||
beq a4,a0,.L12
|
||||
ble a4,a0,.L4
|
||||
lw a4,0(a5)
|
||||
andi a4,a4,1
|
||||
bnez a4,.L13
|
||||
li a0,-1
|
||||
ret
|
||||
.L9:
|
||||
li a0,-1
|
||||
ret
|
||||
.L10:
|
||||
li a0,-1
|
||||
ret
|
||||
#memset 0x0, 0x019C
|
||||
#memset 0x0004, 0x02D49D03
|
||||
#memset 0x0008, 0x00912305
|
||||
#memset 0x000C, 0x00301307
|
||||
#memset 0x0010, 0x001B0D09
|
||||
#memset 0x0014, 0x00010B00
|
||||
#memset 0x0018, 0x00090000
|
||||
#memset 0x001C, 0x001E110F
|
||||
#memset 0x0020, 0x001D0000
|
||||
#memset 0x0024, 0x001E0000
|
||||
#memset 0x0028, 0x00782115
|
||||
#memset 0x002C, 0x00661D17
|
||||
#memset 0x0030, 0x003C1B19
|
||||
#memset 0x0034, 0x00300000
|
||||
#memset 0x0038, 0x00430000
|
||||
#memset 0x003C, 0x00701F00
|
||||
#memset 0x0040, 0x00700000
|
||||
#memset 0x0044, 0x007B0000
|
||||
#memset 0x0048, 0x018E5925
|
||||
#memset 0x004C, 0x00A12B27
|
||||
#memset 0x0050, 0x009F0029
|
||||
#memset 0x0054, 0x00910000
|
||||
#memset 0x0058, 0x011D392D
|
||||
#memset 0x005C, 0x00E22F00
|
||||
#memset 0x0060, 0x01190031
|
||||
#memset 0x0064, 0x01090033
|
||||
#memset 0x0068, 0x00E93500
|
||||
#memset 0x006C, 0x00FF3700
|
||||
#memset 0x0070, 0x00FF0000
|
||||
#memset 0x0074, 0x01213F3B
|
||||
#memset 0x0078, 0x0120003D
|
||||
#memset 0x007C, 0x011F0000
|
||||
#memset 0x0080, 0x01835741
|
||||
#memset 0x0084, 0x016A5543
|
||||
#memset 0x0088, 0x012F4745
|
||||
#memset 0x008C, 0x012E0000
|
||||
#memset 0x0090, 0x014B4F49
|
||||
#memset 0x0094, 0x013A4B00
|
||||
#memset 0x0098, 0x01424D00
|
||||
#memset 0x009C, 0x01460000
|
||||
#memset 0x00A0, 0x015C0051
|
||||
#memset 0x00A4, 0x014D5300
|
||||
#memset 0x00A8, 0x01510000
|
||||
#memset 0x00AC, 0x01730000
|
||||
#memset 0x00B0, 0x018B0000
|
||||
#memset 0x00B4, 0x01BF655B
|
||||
#memset 0x00B8, 0x01A2615D
|
||||
#memset 0x00BC, 0x01995F00
|
||||
#memset 0x00C0, 0x019F0000
|
||||
#memset 0x00C4, 0x01A46300
|
||||
#memset 0x00C8, 0x01BD0000
|
||||
#memset 0x00CC, 0x027C8967
|
||||
#memset 0x00D0, 0x026C8569
|
||||
#memset 0x00D4, 0x01CC6D6B
|
||||
#memset 0x00D8, 0x01C60000
|
||||
#memset 0x00DC, 0x021F7D6F
|
||||
#memset 0x00E0, 0x02070071
|
||||
#memset 0x00E4, 0x01D37300
|
||||
#memset 0x00E8, 0x01F67B75
|
||||
#memset 0x00EC, 0x01EF7977
|
||||
#memset 0x00F0, 0x01D70000
|
||||
#memset 0x00F4, 0x01F10000
|
||||
#memset 0x00F8, 0x02060000
|
||||
#memset 0x00FC, 0x0254837F
|
||||
#memset 0x0100, 0x023D0081
|
||||
#memset 0x0104, 0x02200000
|
||||
#memset 0x0108, 0x02640000
|
||||
#memset 0x010C, 0x026D8700
|
||||
#memset 0x0110, 0x026E0000
|
||||
#memset 0x0114, 0x02C0008B
|
||||
#memset 0x0118, 0x0297998D
|
||||
#memset 0x011C, 0x0289978F
|
||||
#memset 0x0120, 0x02839591
|
||||
#memset 0x0124, 0x027C9300
|
||||
#memset 0x0128, 0x027E0000
|
||||
#memset 0x012C, 0x02850000
|
||||
#memset 0x0130, 0x028D0000
|
||||
#memset 0x0134, 0x029E009B
|
||||
#memset 0x0138, 0x02990000
|
||||
#memset 0x013C, 0x03D4C99F
|
||||
#memset 0x0140, 0x0332ADA1
|
||||
#memset 0x0144, 0x02E9A300
|
||||
#memset 0x0148, 0x031AABA5
|
||||
#memset 0x014C, 0x0305A9A7
|
||||
#memset 0x0150, 0x02EC0000
|
||||
#memset 0x0154, 0x03090000
|
||||
#memset 0x0158, 0x032B0000
|
||||
#memset 0x015C, 0x03CC00AF
|
||||
#memset 0x0160, 0x0365B7B1
|
||||
#memset 0x0164, 0x0333B300
|
||||
#memset 0x0168, 0x036200B5
|
||||
#memset 0x016C, 0x033E0000
|
||||
#memset 0x0170, 0x03B6C3B9
|
||||
#memset 0x0174, 0x03AA00BB
|
||||
#memset 0x0178, 0x039700BD
|
||||
#memset 0x017C, 0x037DC1BF
|
||||
#memset 0x0180, 0x03750000
|
||||
#memset 0x0184, 0x03870000
|
||||
#memset 0x0188, 0x03C8C7C5
|
||||
#memset 0x018C, 0x03BB0000
|
||||
#memset 0x0190, 0x03C90000
|
||||
#memset 0x0194, 0x03E0CB00
|
||||
#memset 0x0198, 0x03E40000
|
||||
#memset 0x019C, 0x0010
|
||||
#memset 0x01A0, 0x0264
|
||||
#memset 0x01A4, 0x0C0D
|
||||
#memset 0x01A8, 0x0031
|
||||
#memset 0x01AC, 0x0206
|
||||
#memset 0x01B0, 0x0891
|
||||
#memset 0x01B4, 0x0043
|
||||
#memset 0x01B8, 0x029E
|
||||
#memset 0x01BC, 0x0264
|
||||
#memset 0x01C0, 0x0123
|
||||
#memset 0x01C4, 0x0264
|
142
src/test/resources/tests/programs/BTreeO3.s
Normal file
142
src/test/resources/tests/programs/BTreeO3.s
Normal file
|
@ -0,0 +1,142 @@
|
|||
main:
|
||||
addi sp,sp,-16
|
||||
sw ra,12(sp)
|
||||
lw a0,0(zero)
|
||||
call find
|
||||
lw ra,12(sp)
|
||||
addi sp,sp,16
|
||||
jr ra
|
||||
find:
|
||||
li a5,4
|
||||
.L2:
|
||||
lh a4,2(a5)
|
||||
beq a4,a0,.L13
|
||||
.L11:
|
||||
ble a4,a0,.L4
|
||||
lw a5,0(a5)
|
||||
andi a4,a5,1
|
||||
bnez a4,.L14
|
||||
.L10:
|
||||
li a0,-1
|
||||
ret
|
||||
.L4:
|
||||
bge a4,a0,.L10
|
||||
lw a4,0(a5)
|
||||
srli a5,a4,7
|
||||
andi a4,a4,256
|
||||
andi a5,a5,508
|
||||
beqz a4,.L10
|
||||
addi a5,a5,4
|
||||
lh a4,2(a5)
|
||||
bne a4,a0,.L11
|
||||
.L13:
|
||||
mv a0,a5
|
||||
ret
|
||||
.L14:
|
||||
slli a5,a5,1
|
||||
andi a5,a5,508
|
||||
addi a5,a5,4
|
||||
j .L2
|
||||
#memset 0x0, 0x013A
|
||||
#memset 0x0004, 0x02D49D03
|
||||
#memset 0x0008, 0x00912305
|
||||
#memset 0x000C, 0x00301307
|
||||
#memset 0x0010, 0x001B0D09
|
||||
#memset 0x0014, 0x00010B00
|
||||
#memset 0x0018, 0x00090000
|
||||
#memset 0x001C, 0x001E110F
|
||||
#memset 0x0020, 0x001D0000
|
||||
#memset 0x0024, 0x001E0000
|
||||
#memset 0x0028, 0x00782115
|
||||
#memset 0x002C, 0x00661D17
|
||||
#memset 0x0030, 0x003C1B19
|
||||
#memset 0x0034, 0x00300000
|
||||
#memset 0x0038, 0x00430000
|
||||
#memset 0x003C, 0x00701F00
|
||||
#memset 0x0040, 0x00700000
|
||||
#memset 0x0044, 0x007B0000
|
||||
#memset 0x0048, 0x018E5925
|
||||
#memset 0x004C, 0x00A12B27
|
||||
#memset 0x0050, 0x009F0029
|
||||
#memset 0x0054, 0x00910000
|
||||
#memset 0x0058, 0x011D392D
|
||||
#memset 0x005C, 0x00E22F00
|
||||
#memset 0x0060, 0x01190031
|
||||
#memset 0x0064, 0x01090033
|
||||
#memset 0x0068, 0x00E93500
|
||||
#memset 0x006C, 0x00FF3700
|
||||
#memset 0x0070, 0x00FF0000
|
||||
#memset 0x0074, 0x01213F3B
|
||||
#memset 0x0078, 0x0120003D
|
||||
#memset 0x007C, 0x011F0000
|
||||
#memset 0x0080, 0x01835741
|
||||
#memset 0x0084, 0x016A5543
|
||||
#memset 0x0088, 0x012F4745
|
||||
#memset 0x008C, 0x012E0000
|
||||
#memset 0x0090, 0x014B4F49
|
||||
#memset 0x0094, 0x013A4B00
|
||||
#memset 0x0098, 0x01424D00
|
||||
#memset 0x009C, 0x01460000
|
||||
#memset 0x00A0, 0x015C0051
|
||||
#memset 0x00A4, 0x014D5300
|
||||
#memset 0x00A8, 0x01510000
|
||||
#memset 0x00AC, 0x01730000
|
||||
#memset 0x00B0, 0x018B0000
|
||||
#memset 0x00B4, 0x01BF655B
|
||||
#memset 0x00B8, 0x01A2615D
|
||||
#memset 0x00BC, 0x01995F00
|
||||
#memset 0x00C0, 0x019F0000
|
||||
#memset 0x00C4, 0x01A46300
|
||||
#memset 0x00C8, 0x01BD0000
|
||||
#memset 0x00CC, 0x027C8967
|
||||
#memset 0x00D0, 0x026C8569
|
||||
#memset 0x00D4, 0x01CC6D6B
|
||||
#memset 0x00D8, 0x01C60000
|
||||
#memset 0x00DC, 0x021F7D6F
|
||||
#memset 0x00E0, 0x02070071
|
||||
#memset 0x00E4, 0x01D37300
|
||||
#memset 0x00E8, 0x01F67B75
|
||||
#memset 0x00EC, 0x01EF7977
|
||||
#memset 0x00F0, 0x01D70000
|
||||
#memset 0x00F4, 0x01F10000
|
||||
#memset 0x00F8, 0x02060000
|
||||
#memset 0x00FC, 0x0254837F
|
||||
#memset 0x0100, 0x023D0081
|
||||
#memset 0x0104, 0x02200000
|
||||
#memset 0x0108, 0x02640000
|
||||
#memset 0x010C, 0x026D8700
|
||||
#memset 0x0110, 0x026E0000
|
||||
#memset 0x0114, 0x02C0008B
|
||||
#memset 0x0118, 0x0297998D
|
||||
#memset 0x011C, 0x0289978F
|
||||
#memset 0x0120, 0x02839591
|
||||
#memset 0x0124, 0x027C9300
|
||||
#memset 0x0128, 0x027E0000
|
||||
#memset 0x012C, 0x02850000
|
||||
#memset 0x0130, 0x028D0000
|
||||
#memset 0x0134, 0x029E009B
|
||||
#memset 0x0138, 0x02990000
|
||||
#memset 0x013C, 0x03D4C99F
|
||||
#memset 0x0140, 0x0332ADA1
|
||||
#memset 0x0144, 0x02E9A300
|
||||
#memset 0x0148, 0x031AABA5
|
||||
#memset 0x014C, 0x0305A9A7
|
||||
#memset 0x0150, 0x02EC0000
|
||||
#memset 0x0154, 0x03090000
|
||||
#memset 0x0158, 0x032B0000
|
||||
#memset 0x015C, 0x03CC00AF
|
||||
#memset 0x0160, 0x0365B7B1
|
||||
#memset 0x0164, 0x0333B300
|
||||
#memset 0x0168, 0x036200B5
|
||||
#memset 0x016C, 0x033E0000
|
||||
#memset 0x0170, 0x03B6C3B9
|
||||
#memset 0x0174, 0x03AA00BB
|
||||
#memset 0x0178, 0x039700BD
|
||||
#memset 0x017C, 0x037DC1BF
|
||||
#memset 0x0180, 0x03750000
|
||||
#memset 0x0184, 0x03870000
|
||||
#memset 0x0188, 0x03C8C7C5
|
||||
#memset 0x018C, 0x03BB0000
|
||||
#memset 0x0190, 0x03C90000
|
||||
#memset 0x0194, 0x03E0CB00
|
||||
#memset 0x0198, 0x03E40000
|
14
src/test/resources/tests/programs/add.s
Normal file
14
src/test/resources/tests/programs/add.s
Normal file
|
@ -0,0 +1,14 @@
|
|||
main:
|
||||
add t0, t0, t1
|
||||
add t2, t0, t1
|
||||
add zero, t0, t1
|
||||
add t2, t2, t1
|
||||
add t3, t3, t3
|
||||
add t3, t3, t3
|
||||
add t3, t3, t3
|
||||
nop
|
||||
done
|
||||
#regset t0,10
|
||||
#regset t1,23
|
||||
#regset t2,43
|
||||
#regset t3,-11
|
118
src/test/resources/tests/programs/memoFib.s
Normal file
118
src/test/resources/tests/programs/memoFib.s
Normal file
|
@ -0,0 +1,118 @@
|
|||
main:
|
||||
addi sp,sp,-32
|
||||
sw ra,28(sp)
|
||||
sw s0,24(sp)
|
||||
addi s0,sp,32
|
||||
sw zero,-20(s0)
|
||||
li a5,100
|
||||
sw a5,-24(s0)
|
||||
lw a1,-20(s0)
|
||||
li a0,11
|
||||
call setupmem
|
||||
lw a1,-24(s0)
|
||||
li a0,11
|
||||
call setupmem
|
||||
lw a2,-24(s0)
|
||||
lw a1,-20(s0)
|
||||
li a0,10
|
||||
call f
|
||||
li a5,0
|
||||
mv a0,a5
|
||||
lw ra,28(sp)
|
||||
lw s0,24(sp)
|
||||
addi sp,sp,32
|
||||
jr ra
|
||||
f:
|
||||
addi sp,sp,-48
|
||||
sw ra,44(sp)
|
||||
sw s0,40(sp)
|
||||
sw s1,36(sp)
|
||||
addi s0,sp,48
|
||||
sw a0,-36(s0)
|
||||
sw a1,-40(s0)
|
||||
sw a2,-44(s0)
|
||||
lw a5,-36(s0)
|
||||
slli a5,a5,2
|
||||
lw a4,-40(s0)
|
||||
add a5,a4,a5
|
||||
lw a5,0(a5)
|
||||
beqz a5,.L2
|
||||
lw a5,-36(s0)
|
||||
slli a5,a5,2
|
||||
lw a4,-44(s0)
|
||||
add a5,a4,a5
|
||||
lw a5,0(a5)
|
||||
j .L3
|
||||
.L2:
|
||||
lw a5,-36(s0)
|
||||
bnez a5,.L4
|
||||
li a5,0
|
||||
j .L3
|
||||
.L4:
|
||||
lw a4,-36(s0)
|
||||
li a5,1
|
||||
bne a4,a5,.L5
|
||||
li a5,1
|
||||
j .L3
|
||||
.L5:
|
||||
lw a5,-36(s0)
|
||||
addi a5,a5,-1
|
||||
lw a2,-44(s0)
|
||||
lw a1,-40(s0)
|
||||
mv a0,a5
|
||||
call f
|
||||
mv s1,a0
|
||||
lw a5,-36(s0)
|
||||
addi a5,a5,-2
|
||||
lw a2,-44(s0)
|
||||
lw a1,-40(s0)
|
||||
mv a0,a5
|
||||
call f
|
||||
mv a5,a0
|
||||
add a5,s1,a5
|
||||
sw a5,-20(s0)
|
||||
lw a5,-36(s0)
|
||||
slli a5,a5,2
|
||||
lw a4,-40(s0)
|
||||
add a5,a4,a5
|
||||
li a4,1
|
||||
sw a4,0(a5)
|
||||
lw a5,-36(s0)
|
||||
slli a5,a5,2
|
||||
lw a4,-44(s0)
|
||||
add a5,a4,a5
|
||||
lw a4,-20(s0)
|
||||
sw a4,0(a5)
|
||||
lw a5,-20(s0)
|
||||
.L3:
|
||||
mv a0,a5
|
||||
lw ra,44(sp)
|
||||
lw s0,40(sp)
|
||||
lw s1,36(sp)
|
||||
addi sp,sp,48
|
||||
jr ra
|
||||
setupmem:
|
||||
addi sp,sp,-48
|
||||
sw s0,44(sp)
|
||||
addi s0,sp,48
|
||||
sw a0,-36(s0)
|
||||
sw a1,-40(s0)
|
||||
sw zero,-20(s0)
|
||||
j .L7
|
||||
.L8:
|
||||
lw a5,-20(s0)
|
||||
slli a5,a5,2
|
||||
lw a4,-40(s0)
|
||||
add a5,a4,a5
|
||||
sw zero,0(a5)
|
||||
lw a5,-20(s0)
|
||||
addi a5,a5,1
|
||||
sw a5,-20(s0)
|
||||
.L7:
|
||||
lw a4,-20(s0)
|
||||
lw a5,-36(s0)
|
||||
blt a4,a5,.L8
|
||||
nop
|
||||
lw s0,44(sp)
|
||||
addi sp,sp,48
|
||||
jr ra
|
49
src/test/resources/tests/programs/naiveFib.s
Normal file
49
src/test/resources/tests/programs/naiveFib.s
Normal file
|
@ -0,0 +1,49 @@
|
|||
main:
|
||||
addi sp,sp,-16
|
||||
sw ra,12(sp)
|
||||
sw s0,8(sp)
|
||||
addi s0,sp,16
|
||||
li a0,6
|
||||
call f
|
||||
mv a5,a0
|
||||
mv a0,a5
|
||||
lw ra,12(sp)
|
||||
lw s0,8(sp)
|
||||
addi sp,sp,16
|
||||
jr ra
|
||||
f:
|
||||
addi sp,sp,-32
|
||||
sw ra,28(sp)
|
||||
sw s0,24(sp)
|
||||
sw s1,20(sp)
|
||||
addi s0,sp,32
|
||||
sw a0,-20(s0)
|
||||
lw a5,-20(s0)
|
||||
bnez a5,.L2
|
||||
li a5,0
|
||||
j .L3
|
||||
.L2:
|
||||
lw a4,-20(s0)
|
||||
li a5,1
|
||||
bne a4,a5,.L4
|
||||
li a5,1
|
||||
j .L3
|
||||
.L4:
|
||||
lw a5,-20(s0)
|
||||
addi a5,a5,-1
|
||||
mv a0,a5
|
||||
call f
|
||||
mv s1,a0
|
||||
lw a5,-20(s0)
|
||||
addi a5,a5,-2
|
||||
mv a0,a5
|
||||
call f
|
||||
mv a5,a0
|
||||
add a5,s1,a5
|
||||
.L3:
|
||||
mv a0,a5
|
||||
lw ra,28(sp)
|
||||
lw s0,24(sp)
|
||||
lw s1,20(sp)
|
||||
addi sp,sp,32
|
||||
jr ra
|
112
src/test/resources/tests/programs/palindrome.s
Normal file
112
src/test/resources/tests/programs/palindrome.s
Normal file
|
@ -0,0 +1,112 @@
|
|||
main:
|
||||
addi sp,sp,-32
|
||||
sw ra,28(sp)
|
||||
sw s0,24(sp)
|
||||
addi s0,sp,32
|
||||
sw zero,-20(s0)
|
||||
li a5,32
|
||||
sw a5,-24(s0)
|
||||
li a2,7
|
||||
li a1,0
|
||||
lw a0,-20(s0)
|
||||
call isPalindrome
|
||||
.DEBUG_call1_return:
|
||||
mv a5,a0
|
||||
beqz a5,.L2
|
||||
li a2,15
|
||||
li a1,0
|
||||
lw a0,-24(s0)
|
||||
call isPalindrome
|
||||
.DEBUG_call2_return:
|
||||
mv a5,a0
|
||||
beqz a5,.L2
|
||||
li a5,1
|
||||
j .L4
|
||||
.L2:
|
||||
li a5,0
|
||||
.L4:
|
||||
mv a0,a5
|
||||
lw ra,28(sp)
|
||||
lw s0,24(sp)
|
||||
addi sp,sp,32
|
||||
jr ra
|
||||
isPalindrome:
|
||||
addi sp,sp,-48
|
||||
sw ra,44(sp)
|
||||
sw s0,40(sp)
|
||||
addi s0,sp,48
|
||||
sw a0,-36(s0)
|
||||
sw a1,-40(s0)
|
||||
sw a2,-44(s0)
|
||||
lw a4,-40(s0)
|
||||
lw a5,-44(s0)
|
||||
blt a4,a5,.L6
|
||||
li a5,1
|
||||
j .L7
|
||||
.L6:
|
||||
lw a5,-40(s0)
|
||||
slli a5,a5,2
|
||||
lw a4,-36(s0)
|
||||
add a5,a4,a5
|
||||
lw a4,0(a5)
|
||||
lw a5,-44(s0)
|
||||
slli a5,a5,2
|
||||
lw a3,-36(s0)
|
||||
add a5,a3,a5
|
||||
lw a5,0(a5)
|
||||
sub a5,a4,a5
|
||||
seqz a5,a5
|
||||
andi a5,a5,0xff
|
||||
sw a5,-20(s0)
|
||||
lw a5,-20(s0)
|
||||
beqz a5,.CompareFailed
|
||||
lw a5,-40(s0)
|
||||
addi a4,a5,1
|
||||
lw a5,-44(s0)
|
||||
addi a5,a5,-1
|
||||
mv a2,a5
|
||||
mv a1,a4
|
||||
lw a0,-36(s0)
|
||||
call isPalindrome
|
||||
mv a5,a0
|
||||
beqz a5,.CompareFailed
|
||||
li a5,1
|
||||
j .L7
|
||||
.CompareFailed:
|
||||
li a5,0
|
||||
.L7:
|
||||
mv a0,a5
|
||||
lw ra,44(sp)
|
||||
lw s0,40(sp)
|
||||
addi sp,sp,48
|
||||
jr ra
|
||||
|
||||
#memset 0, 10
|
||||
#memset 4, -3
|
||||
#memset 8, 8
|
||||
#memset 12, 0
|
||||
#memset 16, 0
|
||||
#memset 20, 8
|
||||
#memset 24, -3
|
||||
#memset 28, 10
|
||||
|
||||
|
||||
#memset 32, 10
|
||||
#memset 36, -3
|
||||
#memset 40, 8
|
||||
#memset 44, 0
|
||||
#memset 48, 0
|
||||
#memset 52, 10
|
||||
|
||||
#memset 56, -3
|
||||
#memset 60, 8
|
||||
|
||||
#memset 64, -3
|
||||
#memset 68, 8
|
||||
|
||||
#memset 72, 10
|
||||
#memset 76, 0
|
||||
#memset 80, 0
|
||||
#memset 84, 8
|
||||
#memset 88, -3
|
||||
#memset 92, 10
|
120
src/test/resources/tests/programs/palindromeO3.s
Normal file
120
src/test/resources/tests/programs/palindromeO3.s
Normal file
|
@ -0,0 +1,120 @@
|
|||
main:
|
||||
addi sp,sp,-16
|
||||
li a2,7
|
||||
li a1,0
|
||||
li a0,0
|
||||
sw ra,12(sp)
|
||||
call isPalindrome.part.0
|
||||
.DEBUG_call1_return:
|
||||
bnez a0,.L17
|
||||
isPalindrome.part.0:
|
||||
slli a4,a1,2
|
||||
slli a3,a2,2
|
||||
add a4,a0,a4
|
||||
add a5,a0,a3
|
||||
lw a4,0(a4)
|
||||
lw a5,0(a5)
|
||||
beq a4,a5,.L10
|
||||
li a5,0
|
||||
.L6:
|
||||
mv a0,a5
|
||||
ret
|
||||
.L10:
|
||||
addi a1,a1,1
|
||||
addi a2,a2,-1
|
||||
li a5,1
|
||||
bge a1,a2,.L6
|
||||
addi sp,sp,-16
|
||||
sw ra,12(sp)
|
||||
call isPalindrome.part.0
|
||||
.DEBUG_call2_return:
|
||||
lw ra,12(sp)
|
||||
snez a5,a0
|
||||
mv a0,a5
|
||||
addi sp,sp,16
|
||||
jr ra
|
||||
.L11:
|
||||
lw ra,12(sp)
|
||||
addi sp,sp,16
|
||||
jr ra
|
||||
.L17:
|
||||
li a2,15
|
||||
li a1,0
|
||||
li a0,32
|
||||
call isPalindrome.part.0
|
||||
snez a0,a0
|
||||
j .L11
|
||||
isPalindrome:
|
||||
bge a1,a2,.L20
|
||||
slli a3,a2,2
|
||||
slli a4,a1,2
|
||||
add a5,a0,a3
|
||||
add a4,a0,a4
|
||||
lw a7,0(a4)
|
||||
lw a6,0(a5)
|
||||
li a3,0
|
||||
bne a7,a6,.L28
|
||||
addi a7,a1,1
|
||||
addi a6,a2,-1
|
||||
li a3,1
|
||||
bge a7,a6,.L28
|
||||
lw a7,4(a4)
|
||||
lw a6,-4(a5)
|
||||
li a3,0
|
||||
bne a7,a6,.L28
|
||||
addi a7,a1,2
|
||||
addi a6,a2,-2
|
||||
li a3,1
|
||||
bge a7,a6,.L28
|
||||
lw a4,8(a4)
|
||||
lw a5,-8(a5)
|
||||
li a3,0
|
||||
bne a4,a5,.L28
|
||||
addi a1,a1,3
|
||||
addi a2,a2,-3
|
||||
li a3,1
|
||||
bge a1,a2,.L28
|
||||
addi sp,sp,-16
|
||||
sw ra,12(sp)
|
||||
call isPalindrome.part.0
|
||||
lw ra,12(sp)
|
||||
snez a3,a0
|
||||
mv a0,a3
|
||||
addi sp,sp,16
|
||||
jr ra
|
||||
.L20:
|
||||
li a3,1
|
||||
.L28:
|
||||
mv a0,a3
|
||||
ret
|
||||
|
||||
|
||||
#memset 0, 10
|
||||
#memset 4, -3
|
||||
#memset 8, 8
|
||||
#memset 12, 0
|
||||
#memset 16, 0
|
||||
#memset 20, 8
|
||||
#memset 24, -3
|
||||
#memset 28, 10
|
||||
|
||||
|
||||
#memset 32, 10
|
||||
#memset 36, -3
|
||||
#memset 40, 8
|
||||
#memset 44, 0
|
||||
#memset 48, 0
|
||||
#memset 52, 10
|
||||
|
||||
#memset 56, -3
|
||||
#memset 60, 8
|
||||
|
||||
#memset 64, -3
|
||||
#memset 68, 8
|
||||
|
||||
#memset 72, 10
|
||||
#memset 76, 0
|
||||
#memset 80, 0
|
||||
#memset 84, 8
|
||||
#memset 88, -3
|
||||
#memset 92, 10
|
187
src/test/resources/tests/programs/searchRegularO0.s
Normal file
187
src/test/resources/tests/programs/searchRegularO0.s
Normal file
|
@ -0,0 +1,187 @@
|
|||
main:
|
||||
addi sp,sp,-32
|
||||
sw ra,28(sp)
|
||||
sw s0,24(sp)
|
||||
addi s0,sp,32
|
||||
li a5,0
|
||||
lw a5,0(a5)
|
||||
sw a5,-20(s0)
|
||||
lw a0,-20(s0)
|
||||
call find
|
||||
mv a5,a0
|
||||
mv a0,a5
|
||||
lw ra,28(sp)
|
||||
lw s0,24(sp)
|
||||
addi sp,sp,32
|
||||
jr ra
|
||||
find:
|
||||
addi sp,sp,-64
|
||||
sw s0,60(sp)
|
||||
addi s0,sp,64
|
||||
sw a0,-52(s0)
|
||||
sw zero,-24(s0)
|
||||
li a5,4
|
||||
sw a5,-20(s0)
|
||||
sw zero,-28(s0)
|
||||
j .L2
|
||||
.WHILE:
|
||||
lw a5,-20(s0)
|
||||
lh a5,2(a5)
|
||||
sw a5,-28(s0)
|
||||
lw a4,-28(s0)
|
||||
lw a5,-52(s0)
|
||||
bne a4,a5,.CHECKLEFT
|
||||
lw a5,-20(s0)
|
||||
j .L1
|
||||
.CHECKLEFT:
|
||||
lw a4,-28(s0)
|
||||
lw a5,-52(s0)
|
||||
ble a4,a5,.CHECKRIGHT
|
||||
lw a5,-20(s0)
|
||||
lw a5,0(a5)
|
||||
andi a5,a5,1
|
||||
beqz a5,.CHECKRIGHT
|
||||
lw a5,-20(s0)
|
||||
lw a5,0(a5)
|
||||
srli a5,a5,1
|
||||
andi a5,a5,127
|
||||
andi a5,a5,0xff
|
||||
sw a5,-32(s0)
|
||||
lw a5,-32(s0)
|
||||
slli a5,a5,2
|
||||
addi a5,a5,4
|
||||
sw a5,-20(s0)
|
||||
j .L2
|
||||
.CHECKRIGHT:
|
||||
lw a4,-28(s0)
|
||||
lw a5,-52(s0)
|
||||
bge a4,a5,.L6
|
||||
lw a5,-20(s0)
|
||||
lw a5,0(a5)
|
||||
andi a5,a5,256
|
||||
beqz a5,.L6
|
||||
lw a5,-20(s0)
|
||||
lw a5,0(a5)
|
||||
srli a5,a5,9
|
||||
andi a5,a5,127
|
||||
andi a5,a5,0xff
|
||||
sw a5,-36(s0)
|
||||
lw a5,-36(s0)
|
||||
slli a5,a5,2
|
||||
addi a5,a5,4
|
||||
sw a5,-20(s0)
|
||||
j .L2
|
||||
.L6:
|
||||
li a5,-1
|
||||
j .L1
|
||||
.L2:
|
||||
lw a5,-24(s0)
|
||||
beqz a5,.WHILE
|
||||
.L1:
|
||||
mv a0,a5
|
||||
lw s0,60(sp)
|
||||
addi sp,sp,64
|
||||
jr ra
|
||||
#memset 0x0, 0x013A
|
||||
#memset 0x0004, 0x02D49D03
|
||||
#memset 0x0008, 0x00912305
|
||||
#memset 0x000C, 0x00301307
|
||||
#memset 0x0010, 0x001B0D09
|
||||
#memset 0x0014, 0x00010B00
|
||||
#memset 0x0018, 0x00090000
|
||||
#memset 0x001C, 0x001E110F
|
||||
#memset 0x0020, 0x001D0000
|
||||
#memset 0x0024, 0x001E0000
|
||||
#memset 0x0028, 0x00782115
|
||||
#memset 0x002C, 0x00661D17
|
||||
#memset 0x0030, 0x003C1B19
|
||||
#memset 0x0034, 0x00300000
|
||||
#memset 0x0038, 0x00430000
|
||||
#memset 0x003C, 0x00701F00
|
||||
#memset 0x0040, 0x00700000
|
||||
#memset 0x0044, 0x007B0000
|
||||
#memset 0x0048, 0x018E5925
|
||||
#memset 0x004C, 0x00A12B27
|
||||
#memset 0x0050, 0x009F0029
|
||||
#memset 0x0054, 0x00910000
|
||||
#memset 0x0058, 0x011D392D
|
||||
#memset 0x005C, 0x00E22F00
|
||||
#memset 0x0060, 0x01190031
|
||||
#memset 0x0064, 0x01090033
|
||||
#memset 0x0068, 0x00E93500
|
||||
#memset 0x006C, 0x00FF3700
|
||||
#memset 0x0070, 0x00FF0000
|
||||
#memset 0x0074, 0x01213F3B
|
||||
#memset 0x0078, 0x0120003D
|
||||
#memset 0x007C, 0x011F0000
|
||||
#memset 0x0080, 0x01835741
|
||||
#memset 0x0084, 0x016A5543
|
||||
#memset 0x0088, 0x012F4745
|
||||
#memset 0x008C, 0x012E0000
|
||||
#memset 0x0090, 0x014B4F49
|
||||
#memset 0x0094, 0x013A4B00
|
||||
#memset 0x0098, 0x01424D00
|
||||
#memset 0x009C, 0x01460000
|
||||
#memset 0x00A0, 0x015C0051
|
||||
#memset 0x00A4, 0x014D5300
|
||||
#memset 0x00A8, 0x01510000
|
||||
#memset 0x00AC, 0x01730000
|
||||
#memset 0x00B0, 0x018B0000
|
||||
#memset 0x00B4, 0x01BF655B
|
||||
#memset 0x00B8, 0x01A2615D
|
||||
#memset 0x00BC, 0x01995F00
|
||||
#memset 0x00C0, 0x019F0000
|
||||
#memset 0x00C4, 0x01A46300
|
||||
#memset 0x00C8, 0x01BD0000
|
||||
#memset 0x00CC, 0x027C8967
|
||||
#memset 0x00D0, 0x026C8569
|
||||
#memset 0x00D4, 0x01CC6D6B
|
||||
#memset 0x00D8, 0x01C60000
|
||||
#memset 0x00DC, 0x021F7D6F
|
||||
#memset 0x00E0, 0x02070071
|
||||
#memset 0x00E4, 0x01D37300
|
||||
#memset 0x00E8, 0x01F67B75
|
||||
#memset 0x00EC, 0x01EF7977
|
||||
#memset 0x00F0, 0x01D70000
|
||||
#memset 0x00F4, 0x01F10000
|
||||
#memset 0x00F8, 0x02060000
|
||||
#memset 0x00FC, 0x0254837F
|
||||
#memset 0x0100, 0x023D0081
|
||||
#memset 0x0104, 0x02200000
|
||||
#memset 0x0108, 0x02640000
|
||||
#memset 0x010C, 0x026D8700
|
||||
#memset 0x0110, 0x026E0000
|
||||
#memset 0x0114, 0x02C0008B
|
||||
#memset 0x0118, 0x0297998D
|
||||
#memset 0x011C, 0x0289978F
|
||||
#memset 0x0120, 0x02839591
|
||||
#memset 0x0124, 0x027C9300
|
||||
#memset 0x0128, 0x027E0000
|
||||
#memset 0x012C, 0x02850000
|
||||
#memset 0x0130, 0x028D0000
|
||||
#memset 0x0134, 0x029E009B
|
||||
#memset 0x0138, 0x02990000
|
||||
#memset 0x013C, 0x03D4C99F
|
||||
#memset 0x0140, 0x0332ADA1
|
||||
#memset 0x0144, 0x02E9A300
|
||||
#memset 0x0148, 0x031AABA5
|
||||
#memset 0x014C, 0x0305A9A7
|
||||
#memset 0x0150, 0x02EC0000
|
||||
#memset 0x0154, 0x03090000
|
||||
#memset 0x0158, 0x032B0000
|
||||
#memset 0x015C, 0x03CC00AF
|
||||
#memset 0x0160, 0x0365B7B1
|
||||
#memset 0x0164, 0x0333B300
|
||||
#memset 0x0168, 0x036200B5
|
||||
#memset 0x016C, 0x033E0000
|
||||
#memset 0x0170, 0x03B6C3B9
|
||||
#memset 0x0174, 0x03AA00BB
|
||||
#memset 0x0178, 0x039700BD
|
||||
#memset 0x017C, 0x037DC1BF
|
||||
#memset 0x0180, 0x03750000
|
||||
#memset 0x0184, 0x03870000
|
||||
#memset 0x0188, 0x03C8C7C5
|
||||
#memset 0x018C, 0x03BB0000
|
||||
#memset 0x0190, 0x03C90000
|
||||
#memset 0x0194, 0x03E0CB00
|
||||
#memset 0x0198, 0x03E40000
|
38
src/test/resources/tests/programs/source/memoFib.c
Normal file
38
src/test/resources/tests/programs/source/memoFib.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <stdio.h>
|
||||
|
||||
// C rmsbolt starter file
|
||||
|
||||
// Local Variables:
|
||||
// rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O3"
|
||||
// rmsbolt-disassemble: nil
|
||||
// End:
|
||||
|
||||
|
||||
int f(int x, int* isMemoized, int* memoizedVal){
|
||||
if(isMemoized[x])
|
||||
return memoizedVal[x];
|
||||
|
||||
if (x == 0) return 0;
|
||||
if (x == 1) return 1;
|
||||
|
||||
int next = f(x-1, isMemoized, memoizedVal) + f(x-2, isMemoized, memoizedVal);
|
||||
isMemoized[x] = 1;
|
||||
memoizedVal[x] = next;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
void setupmem(int n, int* m) {
|
||||
for(int ii = 0; ii < n; ii++){
|
||||
m[ii] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int* isMemoized = (int*)0;
|
||||
int* memoizedVal = (int*)100;
|
||||
setupmem(11, isMemoized);
|
||||
setupmem(11, memoizedVal);
|
||||
int r = f(10, isMemoized, memoizedVal);
|
||||
return r;
|
||||
}
|
20
src/test/resources/tests/programs/source/naiveFib.c
Normal file
20
src/test/resources/tests/programs/source/naiveFib.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
// C rmsbolt starter file
|
||||
|
||||
// Local Variables:
|
||||
// rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O0"
|
||||
// rmsbolt-disassemble: nil
|
||||
// End:
|
||||
|
||||
int f(int x){
|
||||
if (x == 0) return 0;
|
||||
if (x == 1) return 1;
|
||||
return f(x-1) + f(x-2);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
return f(4);
|
||||
}
|
28
src/test/resources/tests/programs/source/palindrome.c
Normal file
28
src/test/resources/tests/programs/source/palindrome.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
// C rmsbolt starter file
|
||||
|
||||
// Local Variables:
|
||||
// rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O3"
|
||||
// rmsbolt-disassemble: nil
|
||||
// End:
|
||||
|
||||
int main() {
|
||||
|
||||
/* int palindrome[8]; */
|
||||
/* int notAPalindrome[16]; */
|
||||
|
||||
// Set up "heap" addresses
|
||||
int palindrome = (int*)0;
|
||||
int notAPalindrome = (int*)32;
|
||||
|
||||
return isPalindrome(palindrome, 0, 7) && isPalindrome(notAPalindrome, 0, 15);
|
||||
}
|
||||
|
||||
int isPalindrome(int* word, int start, int stop){
|
||||
if(start >= stop){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
int currentIsPalindrome = (word[start] == word[stop]);
|
||||
return currentIsPalindrome && isPalindrome(word, start + 1, stop - 1);
|
||||
}
|
||||
}
|
50
src/test/resources/tests/programs/source/search.c
Normal file
50
src/test/resources/tests/programs/source/search.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
// C rmsbolt starter file
|
||||
|
||||
// Local Variables:
|
||||
// rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O3"
|
||||
// rmsbolt-disassemble: nil
|
||||
// End:
|
||||
|
||||
/**
|
||||
* Represents a binary tree
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int hasLeft : 1;
|
||||
unsigned int leftIndex : 7;
|
||||
unsigned int hasRight : 1;
|
||||
unsigned int rightIndex : 7;
|
||||
int value : 16;
|
||||
} node;
|
||||
|
||||
|
||||
int find(int findMe){
|
||||
int found = 0;
|
||||
node* currentNodeIdx = (node*)4;
|
||||
int currentValue = 0;
|
||||
|
||||
while(!found){
|
||||
currentValue = currentNodeIdx->value;
|
||||
if(currentValue == findMe){
|
||||
return (int)currentNodeIdx;
|
||||
}
|
||||
|
||||
if((currentValue > findMe) && currentNodeIdx->hasLeft){
|
||||
int nextNodeIdx = currentNodeIdx->leftIndex;
|
||||
currentNodeIdx = (node*)(4 + (nextNodeIdx << 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
if((currentValue < findMe) && currentNodeIdx->hasRight){
|
||||
int nextNodeIdx = currentNodeIdx->rightIndex;
|
||||
currentNodeIdx = (node*)(4 + (nextNodeIdx << 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int needle = *(int*)0;
|
||||
return find(needle);
|
||||
}
|
64
src/test/resources/tests/programs/source/searchMany.c
Normal file
64
src/test/resources/tests/programs/source/searchMany.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
// C rmsbolt starter file
|
||||
|
||||
// Local Variables:
|
||||
// rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O1"
|
||||
// rmsbolt-disassemble: nil
|
||||
// End:
|
||||
|
||||
/**
|
||||
* Represents a binary tree
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int hasLeft : 1;
|
||||
unsigned int leftIndex : 7;
|
||||
unsigned int hasRight : 1;
|
||||
unsigned int rightIndex : 7;
|
||||
int value : 16;
|
||||
} node;
|
||||
|
||||
|
||||
int find(int findMe){
|
||||
int found = 0;
|
||||
node* currentNodeIdx = (node*)4;
|
||||
int currentValue = 0;
|
||||
|
||||
while(!found){
|
||||
currentValue = currentNodeIdx->value;
|
||||
if(currentValue == findMe){
|
||||
return (int)currentNodeIdx;
|
||||
}
|
||||
|
||||
if((currentValue > findMe) && currentNodeIdx->hasLeft){
|
||||
int nextNodeIdx = currentNodeIdx->leftIndex;
|
||||
currentNodeIdx = (node*)(4 + (nextNodeIdx << 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
if((currentValue < findMe) && currentNodeIdx->hasRight){
|
||||
int nextNodeIdx = currentNodeIdx->rightIndex;
|
||||
currentNodeIdx = (node*)(4 + (nextNodeIdx << 2));
|
||||
continue;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Where does the needle list start?
|
||||
int needles = *(int*)0;
|
||||
int sum = 0;
|
||||
|
||||
// How many needles are there?
|
||||
int numNeedles = *(int*)needles;
|
||||
int nextNeedle = (int)needles + 4;
|
||||
|
||||
// Some useless calculations to make gcc O3 happy
|
||||
for(int ii = 0; ii < numNeedles; ii++){
|
||||
nextNeedle += 4;
|
||||
int needle = *(int*)(nextNeedle);
|
||||
sum += find(needle);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
35
src/test/resources/tests/programs/source/square.c
Normal file
35
src/test/resources/tests/programs/source/square.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
// C rmsbolt starter file
|
||||
|
||||
// Local Variables:
|
||||
// rmsbolt-command: "/opt/riscv/bin/riscv32-unknown-elf-gcc -O0"
|
||||
// rmsbolt-disassemble: nil
|
||||
// End:
|
||||
|
||||
|
||||
int mul(int a, int b) {
|
||||
int c = 0;
|
||||
int ii = 0;
|
||||
for(int ii = 0; ii < a; ii++){
|
||||
c += b;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int square(int a){
|
||||
return mul(a, a);
|
||||
}
|
||||
|
||||
int main() {
|
||||
int a = 6;
|
||||
int b = 0xFFFFFFFE; // MAXVAL - 2, (a + b) = -2
|
||||
int c = -1; //-1
|
||||
int d = 7; //0x4D2 (c + d) = 0x4D1
|
||||
|
||||
if(square(a+b) > square(c + d))
|
||||
return a;
|
||||
else
|
||||
return c;
|
||||
}
|
80
src/test/resources/tests/programs/square.s
Normal file
80
src/test/resources/tests/programs/square.s
Normal file
|
@ -0,0 +1,80 @@
|
|||
main:
|
||||
addi sp,sp,-32
|
||||
sw ra,28(sp)
|
||||
sw s0,24(sp)
|
||||
sw s1,20(sp)
|
||||
addi s0,sp,32
|
||||
li a5,6
|
||||
sw a5,-20(s0)
|
||||
li a5,-2
|
||||
sw a5,-24(s0)
|
||||
li a5,-1
|
||||
sw a5,-28(s0)
|
||||
li a5,7
|
||||
sw a5,-32(s0)
|
||||
lw a4,-20(s0)
|
||||
lw a5,-24(s0)
|
||||
add a5,a4,a5
|
||||
mv a0,a5
|
||||
call square
|
||||
mv s1,a0
|
||||
lw a4,-28(s0)
|
||||
lw a5,-32(s0)
|
||||
add a5,a4,a5
|
||||
mv a0,a5
|
||||
call square
|
||||
mv a5,a0
|
||||
ble s1,a5,.L8
|
||||
lw a5,-20(s0)
|
||||
j .L9
|
||||
.L8:
|
||||
lw a5,-28(s0)
|
||||
.L9:
|
||||
mv a0,a5
|
||||
lw ra,28(sp)
|
||||
lw s0,24(sp)
|
||||
lw s1,20(sp)
|
||||
addi sp,sp,32
|
||||
jr ra
|
||||
mul:
|
||||
addi sp,sp,-48
|
||||
sw s0,44(sp)
|
||||
addi s0,sp,48
|
||||
sw a0,-36(s0)
|
||||
sw a1,-40(s0)
|
||||
sw zero,-20(s0)
|
||||
sw zero,-28(s0)
|
||||
sw zero,-24(s0)
|
||||
j .L2
|
||||
.L3:
|
||||
lw a4,-20(s0)
|
||||
lw a5,-40(s0)
|
||||
add a5,a4,a5
|
||||
sw a5,-20(s0)
|
||||
lw a5,-24(s0)
|
||||
addi a5,a5,1
|
||||
sw a5,-24(s0)
|
||||
.L2:
|
||||
lw a4,-24(s0)
|
||||
lw a5,-36(s0)
|
||||
blt a4,a5,.L3
|
||||
lw a5,-20(s0)
|
||||
mv a0,a5
|
||||
lw s0,44(sp)
|
||||
addi sp,sp,48
|
||||
jr ra
|
||||
square:
|
||||
addi sp,sp,-32
|
||||
sw ra,28(sp)
|
||||
sw s0,24(sp)
|
||||
addi s0,sp,32
|
||||
sw a0,-20(s0)
|
||||
lw a1,-20(s0)
|
||||
lw a0,-20(s0)
|
||||
call mul
|
||||
mv a5,a0
|
||||
mv a0,a5
|
||||
lw ra,28(sp)
|
||||
lw s0,24(sp)
|
||||
addi sp,sp,32
|
||||
jr ra
|
78
src/test/scala/Manifest.scala
Normal file
78
src/test/scala/Manifest.scala
Normal file
|
@ -0,0 +1,78 @@
|
|||
package FiveStage
|
||||
import org.scalatest.{Matchers, FlatSpec}
|
||||
import cats._
|
||||
import cats.implicits._
|
||||
import fileUtils._
|
||||
|
||||
import chisel3.iotesters._
|
||||
import scala.collection.mutable.LinkedHashMap
|
||||
|
||||
import fansi.Str
|
||||
|
||||
import Ops._
|
||||
import Data._
|
||||
import VM._
|
||||
|
||||
import PrintUtils._
|
||||
import LogParser._
|
||||
|
||||
object Manifest {
|
||||
|
||||
val singleTest = "forward2.s"
|
||||
|
||||
val nopPadded = false
|
||||
|
||||
val singleTestOptions = TestOptions(
|
||||
printIfSuccessful = true,
|
||||
printErrors = true,
|
||||
printParsedProgram = false,
|
||||
printVMtrace = false,
|
||||
printVMfinal = false,
|
||||
printMergedTrace = true,
|
||||
nopPadded = nopPadded,
|
||||
breakPoints = Nil, // not implemented
|
||||
testName = singleTest)
|
||||
|
||||
|
||||
val allTestOptions: String => TestOptions = name => TestOptions(
|
||||
printIfSuccessful = false,
|
||||
printErrors = false,
|
||||
printParsedProgram = false,
|
||||
printVMtrace = false,
|
||||
printVMfinal = false,
|
||||
printMergedTrace = false,
|
||||
nopPadded = nopPadded,
|
||||
breakPoints = Nil, // not implemented
|
||||
testName = name)
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SingleTest extends FlatSpec with Matchers {
|
||||
it should "just werk" in {
|
||||
TestRunner.run(Manifest.singleTestOptions) should be(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AllTests extends FlatSpec with Matchers {
|
||||
it should "just werk" in {
|
||||
val werks = getAllTestNames.map{testname =>
|
||||
say(s"testing $testname")
|
||||
val opts = Manifest.allTestOptions(testname)
|
||||
(testname, TestRunner.run(opts))
|
||||
}
|
||||
if(werks.foldLeft(true)(_ && _._2))
|
||||
say(Console.GREEN + "All tests successful!" + Console.RESET)
|
||||
else {
|
||||
val success = werks.map(x => if(x._2) 1 else 0).sum
|
||||
val total = werks.size
|
||||
say(s"$success/$total tests successful")
|
||||
werks.foreach{ case(name, success) =>
|
||||
val msg = if(success) Console.GREEN + s"$name successful" + Console.RESET
|
||||
else Console.RED + s"$name failed" + Console.RESET
|
||||
say(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
357
src/test/scala/RISCV/DataTypes.scala
Normal file
357
src/test/scala/RISCV/DataTypes.scala
Normal file
|
@ -0,0 +1,357 @@
|
|||
package FiveStage
|
||||
import cats.data.Writer
|
||||
import cats._
|
||||
import cats.data._
|
||||
import cats.implicits._
|
||||
|
||||
import fansi._
|
||||
import PrintUtils._
|
||||
|
||||
import fileUtils.say
|
||||
|
||||
/**
|
||||
* Types and extension methods go here.
|
||||
* Maybe it's a litte arbitrary to put VM types here, but op types in Ops.scala
|
||||
* Maybe these could be separated to somewhere else.
|
||||
*/
|
||||
object Data {
|
||||
type Label = String
|
||||
|
||||
case class Reg(value: Int)
|
||||
case class Imm(value: Int)
|
||||
case class Addr(value: Int){
|
||||
def +(that: Addr) = Addr(value + that.value)
|
||||
def -(that: Addr) = Addr(value - that.value)
|
||||
def step = Addr(value + 4)
|
||||
}
|
||||
|
||||
object Reg{ def apply(s: String): Reg = Reg(lookupReg(s).get) }
|
||||
|
||||
type SourceInfo[A] = Writer[List[String], A]
|
||||
object SourceInfo { def apply[A](s: String, a: A) = Writer(List(s), a) }
|
||||
|
||||
trait ExecutionEvent
|
||||
import PrintUtils._
|
||||
case class RegUpdate(reg: Reg, word: Int) extends ExecutionEvent
|
||||
case class MemWrite(addr: Addr, word: Int) extends ExecutionEvent
|
||||
case class MemRead(addr: Addr, word: Int) extends ExecutionEvent
|
||||
|
||||
// addr is the target address
|
||||
case class PcUpdateJALR(addr: Addr) extends ExecutionEvent
|
||||
case class PcUpdateJAL(addr: Addr) extends ExecutionEvent
|
||||
case class PcUpdateB(addr: Addr) extends ExecutionEvent
|
||||
case class PcUpdate(addr: Addr) extends ExecutionEvent
|
||||
|
||||
case class ExecutionTraceEvent(pc: Addr, event: ExecutionEvent*){ override def toString(): String = s"$pc: " + event.toList.mkString(", ") }
|
||||
type ExecutionTrace[A] = Writer[List[ExecutionTraceEvent], A]
|
||||
|
||||
object ExecutionTrace {
|
||||
def apply(vm: VM, event: ExecutionTraceEvent*) = Writer(event.toList, vm)
|
||||
}
|
||||
|
||||
|
||||
sealed trait ChiselEvent
|
||||
case class ChiselRegEvent(pcAddr: Addr, reg: Reg, word: Int) extends ChiselEvent
|
||||
case class ChiselMemWriteEvent(pcAddr: Addr, memAddr: Addr, word: Int) extends ChiselEvent
|
||||
|
||||
type CircuitTrace = (Addr, List[ChiselEvent])
|
||||
|
||||
|
||||
/**
|
||||
* Not sure these should be defined here instead of in the VM
|
||||
*/
|
||||
case class Regs(repr: Map[Reg, Int]) {
|
||||
def +(a: (Reg, Int)): (Option[RegUpdate], Regs) =
|
||||
if(a._1.value == 0) (None, this)
|
||||
else (Some(RegUpdate(a._1, a._2)), copy(repr + a))
|
||||
|
||||
def arith(rd: Reg, operand1: Reg, operand2: Reg, op: (Int, Int) => Int): (Option[RegUpdate], Regs) =
|
||||
this + (rd -> op(repr(operand1), repr(operand2)))
|
||||
|
||||
def arithImm(rd: Reg, operand1: Reg, operand2: Imm, op: (Int, Int) => Int): (Option[RegUpdate], Regs) =
|
||||
this + (rd -> op(repr(operand1), operand2.value))
|
||||
|
||||
def compare(operand1: Reg, operand2: Reg, comp: (Int, Int) => Boolean): Boolean =
|
||||
comp(repr(operand1), repr(operand2))
|
||||
|
||||
def apply(setting: TestSetting): Regs = setting match {
|
||||
case setting: REGSET => Regs(repr + (setting.rd -> setting.word))
|
||||
case _ => this
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class DMem(repr: Map[Addr, Int]) {
|
||||
def read(addr: Addr): Either[String, (MemRead, Int)] =
|
||||
if(addr.value >= 4096)
|
||||
Left(s"attempted to read from illegal address ${addr.show}")
|
||||
else {
|
||||
val readResult = repr.lift(addr).getOrElse(0)
|
||||
Right((MemRead(addr, readResult), readResult))
|
||||
}
|
||||
|
||||
def write(addr: Addr, word: Int): Either[String, (MemWrite, DMem)] =
|
||||
if(addr.value >= 4096)
|
||||
Left(s"attempted to write to illegal address ${addr.show}")
|
||||
else {
|
||||
Right((MemWrite(addr, word)), DMem(repr + (addr -> word)))
|
||||
}
|
||||
|
||||
def apply(setting: TestSetting): DMem = setting match {
|
||||
case setting: MEMSET => {
|
||||
DMem(repr + (setting.addr -> setting.word))
|
||||
}
|
||||
case _ => this
|
||||
}
|
||||
}
|
||||
|
||||
object Regs{
|
||||
def empty: Regs = Regs((0 to 31).map(x => (Reg(x) -> 0)).toMap)
|
||||
def apply(settings: List[TestSetting]): Regs = settings.foldLeft(empty){
|
||||
case(acc, setting) => acc(setting)
|
||||
}
|
||||
}
|
||||
object DMem{
|
||||
def empty: DMem = DMem(Map[Addr, Int]())
|
||||
def apply(settings: List[TestSetting]): DMem = settings.foldLeft(empty){
|
||||
case(acc, setting) => acc(setting)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
implicit class IntOps(i: Int) {
|
||||
// Needs backticks to not conflict with xml
|
||||
def `u>`(that: Int): Boolean = {
|
||||
if((i >= 0) && (that >= 0))
|
||||
i > that
|
||||
else if((i < 0) && (that < 0))
|
||||
i > that
|
||||
else if((i < 0))
|
||||
true
|
||||
else
|
||||
false
|
||||
}
|
||||
|
||||
def nBitsS: Int = i match {
|
||||
case i if (i < 0) => (math.log(math.abs(i.toLong))/math.log(2)).ceil.toInt + 1
|
||||
case i if (i == 0) => 0
|
||||
case i if (i > 0) => (math.log((i + 1).toLong)/math.log(2)).ceil.toInt + 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Yes, a negative number technically has a unsigned size, but that depends on integer width,
|
||||
* so it is better left as an option
|
||||
*/
|
||||
def nBitsU: Option[Int] = i match {
|
||||
case i if (i < 0) => None
|
||||
case i if (i == 0) => Some(0)
|
||||
case i if (i > 0) => Some((math.log(i)/math.log(2)).ceil.toInt)
|
||||
}
|
||||
|
||||
def field(firstBit: Int, size: Int): Int = {
|
||||
val bitsLeft = 31 - firstBit
|
||||
val bitsRight = 32 - size
|
||||
val leftShifted = i << bitsLeft
|
||||
val rightShifted = leftShifted >> bitsRight
|
||||
rightShifted
|
||||
}
|
||||
|
||||
def splitLoHi(loBits: Int): (Int, Int) = {
|
||||
val hiBits = 32 - loBits
|
||||
val sep = 31 - loBits
|
||||
val lo = i.field(31, loBits)
|
||||
val hi = i.field(sep, hiBits)
|
||||
(lo, hi)
|
||||
}
|
||||
|
||||
def log2: Int = math.ceil(math.log(i.toDouble)/math.log(2.0)).toInt
|
||||
}
|
||||
|
||||
implicit class StringOps(s: String) {
|
||||
def binary: Int = {
|
||||
s.reverse.foldLeft((0, 0)){
|
||||
case((acc, pow), char) if char == '0' => (acc, pow + 1)
|
||||
case((acc, pow), char) if char == '1' => (acc + (1 << pow), pow + 1)
|
||||
case((acc, pow), char) => assert(false, "malformed binary conversion"); (0, 0)
|
||||
}._1
|
||||
}
|
||||
}
|
||||
|
||||
implicit class ListOps[A](xs: List[A]) {
|
||||
def mkStringN = xs.mkString("\n","\n","\n")
|
||||
def splitAtPred(p: (A, A) => Boolean): List[List[A]] = {
|
||||
val splitPoints = xs.tail.foldLeft((1, List[Int](), xs.head)){
|
||||
case((idx, acc, pA), a) if(p(pA, a)) => (1, idx :: acc, a)
|
||||
case((idx, acc, pA), a) => (idx + 1, acc, a)
|
||||
}._2.reverse
|
||||
|
||||
val (blocks, rem) = splitPoints.foldLeft((List[List[A]](), xs)){
|
||||
case((acc, rem), point) => {
|
||||
val(block, remainder) = rem.splitAt(point)
|
||||
(block :: acc, remainder)
|
||||
}
|
||||
}
|
||||
(rem :: blocks).reverse
|
||||
}
|
||||
def showN(sep: String)(implicit ev: Fancy[A]): fansi.Str =
|
||||
xs.foldLeft(fansi.Str("")){ case(acc, a) => acc ++ a.show ++ fansi.Str(sep) }
|
||||
def showN(sep1: String, sep2: String, sep3: String)(implicit ev: Fancy[A]): fansi.Str =
|
||||
Str(sep1) ++ xs.foldLeft(fansi.Str("")){ case(acc, a) => acc ++ a.show ++ fansi.Str(sep2) } ++ Str(sep3)
|
||||
def shuffle(shuffler: scala.util.Random): List[A] = shuffler.shuffle(xs)
|
||||
}
|
||||
implicit class NestedListOps[A](xs: List[List[A]]) {
|
||||
def zipWithIndexNested: List[List[(A, Int)]] = {
|
||||
val startingPoints = xs.scanLeft(0){ case(acc, xs) => acc + xs.size }
|
||||
(xs.map(_.zipWithIndex) zip startingPoints).map{ case(withIndex, offset) =>
|
||||
withIndex.map{ case(a, idx) => (a, idx + offset) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import Ops._
|
||||
|
||||
sealed trait TestSetting
|
||||
case class REGSET(rd: Reg, word: Int) extends TestSetting
|
||||
case class MEMSET(addr: Addr, word: Int) extends TestSetting
|
||||
|
||||
implicit class ListEitherOps[E,A](es: List[Either[E,A]]) {
|
||||
import cats.data.Validated
|
||||
def separateXOR: Either[List[E], List[A]] = {
|
||||
val (errors, as) = es.map(_.toValidated).separate
|
||||
Either.cond(errors.isEmpty, as, errors)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents the result of parsing a program, with built in convenience methods for running a VM
|
||||
* and assembling the program.
|
||||
*/
|
||||
case class Program(
|
||||
ops : List[SourceInfo[Op]],
|
||||
settings : List[TestSetting],
|
||||
labelMap : Map[Label, Addr],
|
||||
maxSteps : Int = 5000
|
||||
){
|
||||
|
||||
def imem: Map[Addr, Op] =
|
||||
ops.map(_.run._2).zipWithIndex.map{ case(op, idx) => (Addr(idx*4), op) }.toMap
|
||||
|
||||
|
||||
/**
|
||||
* Loads a VM which can be run to get a trace.
|
||||
*/
|
||||
def vm: VM =
|
||||
VM(settings, imem, labelMap)
|
||||
|
||||
|
||||
/**
|
||||
* A convenient lookup for every instruction, allowing the test runner to check what source line
|
||||
* caused an error to happen.
|
||||
*/
|
||||
val sourceMap: Map[Addr, String] =
|
||||
ops.map(_.run._1).zipWithIndex.map{ case(info, idx) => (Addr(idx*4), info.map(_.trim).mkString(", ")) }.toMap
|
||||
|
||||
|
||||
/**
|
||||
* The assembled program
|
||||
*/
|
||||
def machineCode: Either[String, Map[Addr, Int]] =
|
||||
imem.toList
|
||||
.sortBy(_._1.value).map{ case(addr, op) => assembler.assembleOp(op, addr, labelMap).map(x => (addr, x)) }
|
||||
.sequence
|
||||
.map(_.toMap)
|
||||
.left.map{ case(error, addr) => s"Assembler error: $error, corresponding to source:\n${sourceMap(addr)}" }
|
||||
|
||||
|
||||
/**
|
||||
* Returns the binary code and the execution trace or an error for convenient error checking.
|
||||
*/
|
||||
def validate: Either[String, (Map[Addr, Int], ExecutionTrace[VM])] = machineCode.flatMap{ binary =>
|
||||
val uk = "UNKNOWN"
|
||||
val (finish, trace) = VM.run(maxSteps, vm)
|
||||
finish match {
|
||||
case Failed(s, addr) => Left(s"VM failed with error $s at address $addr\nSource line:\n${sourceMap.lift(addr).getOrElse(uk)}")
|
||||
case Timeout => Left(s"VM timed out after $maxSteps steps. This should not happen with the supplied tests")
|
||||
case Success => Right(binary, trace)
|
||||
}
|
||||
}
|
||||
|
||||
def labelMapReverse = labelMap.toList.map(_.swap).toMap
|
||||
}
|
||||
|
||||
|
||||
def lookupReg(s: String): Option[Int] = {
|
||||
val regMap = Map(
|
||||
"x0" -> 0,
|
||||
"x1" -> 1,
|
||||
"x2" -> 2,
|
||||
"x3" -> 3,
|
||||
"x4" -> 4,
|
||||
"x5" -> 5,
|
||||
"x6" -> 6,
|
||||
"x7" -> 7,
|
||||
"x8" -> 8,
|
||||
"x9" -> 9,
|
||||
"x10" -> 10,
|
||||
"x11" -> 11,
|
||||
"x12" -> 12,
|
||||
"x13" -> 13,
|
||||
"x14" -> 14,
|
||||
"x15" -> 15,
|
||||
"x16" -> 16,
|
||||
"x17" -> 17,
|
||||
"x18" -> 18,
|
||||
"x19" -> 19,
|
||||
"x20" -> 20,
|
||||
"x21" -> 21,
|
||||
"x22" -> 22,
|
||||
"x23" -> 23,
|
||||
"x24" -> 24,
|
||||
"x25" -> 25,
|
||||
"x26" -> 26,
|
||||
"x27" -> 27,
|
||||
"x28" -> 28,
|
||||
"x29" -> 29,
|
||||
"x30" -> 30,
|
||||
"x31" -> 31,
|
||||
"zero" -> 0,
|
||||
"ra" -> 1,
|
||||
"sp" -> 2,
|
||||
"gp" -> 3,
|
||||
"tp" -> 4,
|
||||
"t0" -> 5,
|
||||
"t1" -> 6,
|
||||
"t2" -> 7,
|
||||
"s0" -> 8,
|
||||
"fp" -> 8,
|
||||
"s1" -> 9,
|
||||
"a0" -> 10,
|
||||
"a1" -> 11,
|
||||
"a2" -> 12,
|
||||
"a3" -> 13,
|
||||
"a4" -> 14,
|
||||
"a5" -> 15,
|
||||
"a6" -> 16,
|
||||
"a7" -> 17,
|
||||
"s2" -> 18,
|
||||
"s3" -> 19,
|
||||
"s4" -> 20,
|
||||
"s5" -> 21,
|
||||
"s6" -> 22,
|
||||
"s7" -> 23,
|
||||
"s8" -> 24,
|
||||
"s9" -> 25,
|
||||
"s10" -> 26,
|
||||
"s11" -> 27,
|
||||
"t3" -> 28,
|
||||
"t4" -> 29,
|
||||
"t5" -> 30,
|
||||
"t6" -> 31)
|
||||
|
||||
regMap.lift(s)
|
||||
}
|
||||
}
|
184
src/test/scala/RISCV/LogParser.scala
Normal file
184
src/test/scala/RISCV/LogParser.scala
Normal file
|
@ -0,0 +1,184 @@
|
|||
package FiveStage
|
||||
import Data._
|
||||
import fileUtils.say
|
||||
import PrintUtils._
|
||||
|
||||
/**
|
||||
* Helpers for comparing VM and chisel logs
|
||||
*/
|
||||
object LogParser {
|
||||
|
||||
|
||||
/**
|
||||
* Peeks ahead at the chisel log to see if an expected jump is taken.
|
||||
*/
|
||||
def fetchUntilJumpTarget(addr: Addr, chiselLog: List[CircuitTrace]): Option[List[CircuitTrace]] = {
|
||||
val (head, tail) = chiselLog.splitAt(4) // very arbitrary choice
|
||||
val pruned: List[CircuitTrace] = head.dropWhile{ case(myAddr, _) => myAddr != addr }
|
||||
pruned.headOption.map(_ => pruned ::: tail)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fetches a basic block of VM execution trace
|
||||
*/
|
||||
def splitToBlocks(vmTrace: List[ExecutionTraceEvent]): List[List[ExecutionTraceEvent]] =
|
||||
vmTrace.splitAtPred{ case(current, next) =>
|
||||
!(next.pc == current.pc + Addr(4))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches a basic block of chisel execution trace
|
||||
*/
|
||||
def splitToBlocksChisel(chiselTrace: List[CircuitTrace]): List[List[CircuitTrace]] =
|
||||
chiselTrace.splitAtPred{ case((current, _), (next, _)) =>
|
||||
!((next == current + Addr(4)) || (next == current))
|
||||
}
|
||||
|
||||
|
||||
def guessBlockName(trace: List[Addr], labelMap: Map[Addr, Label]): String = trace.headOption.map(x => labelMap.lift(x)
|
||||
.getOrElse(labelMap.lift(trace.head - Addr(4)).getOrElse("UNKNOWN (return jump or misjump)"))).getOrElse("UNKNOWN")
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to merge blocks, patching up when mismatches occur
|
||||
* Fails when branchpredictor misjumps, feel free to send a PR
|
||||
*/
|
||||
type BlockList = List[(List[ExecutionTraceEvent], List[CircuitTrace])]
|
||||
|
||||
def mergeTraces(vmTrace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace]): BlockList = {
|
||||
def helper(acc: BlockList, blocs: (List[List[ExecutionTraceEvent]], List[List[CircuitTrace]])): BlockList = blocs match {
|
||||
|
||||
case (vmBlock :: vmTail, chiselBlock :: chiselTail) if (vmBlock.head.pc == chiselBlock.head._1) =>
|
||||
helper((vmBlock, chiselBlock) :: acc, ((vmTail, chiselTail)))
|
||||
|
||||
case (vmBlock :: vmTail, chiselBlock :: chiselTail) =>
|
||||
helper((Nil, chiselBlock) :: acc, ((vmBlock :: vmTail, chiselTail)))
|
||||
|
||||
case (Nil, chiselBlock :: chiselTail) =>
|
||||
helper((Nil, chiselBlock) :: acc, ((Nil, chiselTail)))
|
||||
|
||||
case (vmBlock :: vmTail, Nil) =>
|
||||
helper((vmBlock, Nil) :: acc, ((vmTail, Nil)))
|
||||
|
||||
case _ => acc.reverse
|
||||
}
|
||||
helper(Nil, (splitToBlocks(vmTrace), splitToBlocksChisel(chiselTrace)))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares register update logs
|
||||
*/
|
||||
def compareRegs(vmTrace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace]): Option[String] = {
|
||||
val vmRegUpdates = vmTrace.zipWithIndex
|
||||
.flatMap{ case (e, step) => e.event.toList.map(y => (step, e.pc, y))}
|
||||
.collect{ case (step: Int, addr: Addr, x: RegUpdate) => (step, addr, x) }
|
||||
|
||||
val chiselRegUpdates = chiselTrace.zipWithIndex
|
||||
.flatMap{ case (e, step) => e._2.map(y => (step, e._1, y))}
|
||||
.collect{ case (step: Int, addr: Addr, x: ChiselRegEvent) => (step, addr, x) }
|
||||
|
||||
val errors = (vmRegUpdates zip chiselRegUpdates).map{
|
||||
case((_, _, vmUpdate), (_, _, chiselUpdate)) if ((vmUpdate.reg == chiselUpdate.reg) && (vmUpdate.word == chiselUpdate.word)) => {
|
||||
None
|
||||
}
|
||||
|
||||
case((vmStep, vmAddr, vmUpdate), (chiselStep, chiselAddr, chiselUpdate)) => {
|
||||
val errorString = s"Register update mismatch.\n" ++
|
||||
s"VM: At step $vmStep, at address ${vmAddr.show}, the VM got ${vmUpdate.show}\n" ++
|
||||
s"Circuit: At step $chiselStep, at address ${chiselAddr.show}, the circuit got ${chiselUpdate.show}"
|
||||
Some(errorString)
|
||||
}
|
||||
}
|
||||
|
||||
val error = errors.collect{ case Some(x) => x }.headOption
|
||||
|
||||
|
||||
val lengthMismatch: Option[String] = (vmRegUpdates, chiselRegUpdates) match {
|
||||
case (h :: t, Nil) => Some(s"Your design performed no reg updates. First expected update was at VM step ${h._1}, PC: ${h._2.show}, ${h._3.show}")
|
||||
case (Nil, h :: t) => Some(s"Your design performed reg updates, but the VM did not. First update was at step ${h._1}, PC: ${h._2.show}, ${h._3.show}")
|
||||
case (hVM :: tVM, hC :: tC) if (tVM.size > tC.size) => {
|
||||
|
||||
val VMremainder = tVM.drop(tC.size)
|
||||
|
||||
val errorString =
|
||||
s"VM performed more reg updates than your design.\n" ++
|
||||
s"Your design performed ${chiselRegUpdates.size} updates before terminating, while the VM performed ${vmRegUpdates.size} updates.\n" ++
|
||||
s"The first update your design missed happened at VM step ${VMremainder.head._1}, PC: ${VMremainder.head._2.show} and was ${VMremainder.head._3.show}"
|
||||
|
||||
Some(errorString)
|
||||
}
|
||||
case (hVM :: tVM, hC :: tC) if (tVM.size < tC.size) => {
|
||||
val ChiselRemainder = tC.drop(tVM.size)
|
||||
|
||||
val errorString =
|
||||
s"Your design performed more reg updates than the VM.\n" ++
|
||||
s"Your design performed ${chiselRegUpdates.size} updates before terminating, while the VM performed ${vmRegUpdates.size} updates.\n" ++
|
||||
s"The first spurious update your design did happened at cycle ${ChiselRemainder.head._1}, PC: ${ChiselRemainder.head._2.show} and was ${ChiselRemainder.head._3.show}"
|
||||
|
||||
Some(errorString)
|
||||
}
|
||||
|
||||
case _ => None
|
||||
}
|
||||
|
||||
|
||||
(error :: lengthMismatch :: Nil).flatten.headOption
|
||||
}
|
||||
|
||||
|
||||
def compareMem(vmTrace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace]): Option[String] = {
|
||||
val vmMemUpdates = vmTrace.zipWithIndex
|
||||
.flatMap{ case (e, step) => e.event.toList.map(y => (step, e.pc, y))}
|
||||
.collect{ case (step: Int, addr: Addr, x: MemWrite) => (step, addr, x) }
|
||||
|
||||
val chiselMemUpdates = chiselTrace.zipWithIndex
|
||||
.flatMap{ case (e, step) => e._2.map(y => (step, e._1, y))}
|
||||
.collect{ case (step: Int, addr: Addr, x: ChiselMemWriteEvent) => (step, addr, x) }
|
||||
|
||||
val error = (vmMemUpdates zip chiselMemUpdates).map{
|
||||
case((_, _, vmUpdate), (_, _, chiselUpdate)) if ((vmUpdate.addr == chiselUpdate.memAddr) && (vmUpdate.word == chiselUpdate.word)) =>
|
||||
None
|
||||
case((vmStep, vmAddr, vmUpdate), (chiselStep, chiselAddr, chiselUpdate)) => {
|
||||
val errorString = s"Mem update mismatch.\n" ++
|
||||
s"VM: At step $vmStep, at address ${vmAddr.show}, the VM got ${vmUpdate.show}\n" ++
|
||||
s"Circuit: At step $chiselStep, at address ${chiselAddr.show}, the circuit got ${chiselUpdate.show}"
|
||||
Some(errorString)
|
||||
}
|
||||
}.collect{ case Some(x) => x }.headOption
|
||||
|
||||
|
||||
val lengthMismatch = (vmMemUpdates, chiselMemUpdates) match {
|
||||
case (h :: t, Nil) => Some(s"Your design performed no mem updates. First expected update was at VM step ${h._1}, PC: ${h._2}, ${h._3}")
|
||||
case (Nil, h :: t) => Some(s"Your design performed mem updates, but the VM did not. First spurious update was at step ${h._1}, PC: ${h._2}, ${h._3}")
|
||||
case (hVM :: tVM, hC :: tC) if (tVM.size > tC.size) => {
|
||||
|
||||
val VMremainder = tVM.drop(tC.size)
|
||||
|
||||
val errorString =
|
||||
s"VM performed more mem updates than your design.\n" ++
|
||||
s"Your design performed ${chiselMemUpdates.size} updates before terminating, while the VM performed ${vmMemUpdates.size} updates.\n" ++
|
||||
s"The first update your design missed happened at VM step ${VMremainder.head._1}, PC: ${VMremainder.head._2} and was ${VMremainder.head._3}"
|
||||
|
||||
Some(errorString)
|
||||
}
|
||||
case (hVM :: tVM, hC :: tC) if (tVM.size < tC.size) => {
|
||||
val ChiselRemainder = tC.drop(tVM.size)
|
||||
|
||||
val errorString =
|
||||
s"Your design performed more mem updates than the VM.\n" ++
|
||||
s"Your design performed ${chiselMemUpdates.size} updates before terminating, while the VM performed ${vmMemUpdates.size} updates.\n" ++
|
||||
s"The first spurious update your design did happened at cycle ${ChiselRemainder.head._1}, PC: ${ChiselRemainder.head._2} and was ${ChiselRemainder.head._3}"
|
||||
|
||||
Some(errorString)
|
||||
}
|
||||
|
||||
case _ => None
|
||||
}
|
||||
|
||||
(error :: lengthMismatch :: Nil).flatten.headOption
|
||||
}
|
||||
}
|
124
src/test/scala/RISCV/Ops.scala
Normal file
124
src/test/scala/RISCV/Ops.scala
Normal file
|
@ -0,0 +1,124 @@
|
|||
package FiveStage
|
||||
import cats.implicits._
|
||||
import fileUtils._
|
||||
|
||||
import Data._
|
||||
import PrintUtils._
|
||||
|
||||
object Ops {
|
||||
|
||||
sealed trait Op extends RegLayout
|
||||
|
||||
sealed trait RegLayout
|
||||
sealed trait RType extends RegLayout { def rd: Reg; def rs1: Reg; def rs2: Reg }
|
||||
sealed trait IType extends RegLayout { def rd: Reg; def rs1: Reg; }
|
||||
sealed trait SType extends RegLayout { def rs1: Reg; def rs2: Reg }
|
||||
sealed trait UType extends RegLayout { def rd: Reg; }
|
||||
|
||||
sealed trait ImmType
|
||||
sealed trait NoImmediate extends ImmType
|
||||
sealed trait IImmediate extends ImmType
|
||||
sealed trait SImmediate extends ImmType
|
||||
sealed trait BImmediate extends ImmType
|
||||
sealed trait UImmediate extends ImmType
|
||||
sealed trait JImmediate extends ImmType
|
||||
sealed trait ShiftImmediate extends ImmType
|
||||
|
||||
|
||||
sealed trait Comparison {
|
||||
def run(rs1Val: Int, rs2Val: Int): Boolean
|
||||
}
|
||||
case object EQ extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val == rs2Val }
|
||||
case object NE extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val != rs2Val }
|
||||
case object GE extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val >= rs2Val }
|
||||
case object LT extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val < rs2Val }
|
||||
case object GEU extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = !(rs1Val `u>` rs2Val) }
|
||||
case object LTU extends Comparison { def run(rs1Val: Int, rs2Val: Int): Boolean = rs1Val `u>` rs2Val }
|
||||
|
||||
case class Branch(rs1: Reg, rs2: Reg, dst: Label, comp: Comparison) extends Op with SType
|
||||
object Branch{
|
||||
def beq( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, EQ)
|
||||
def bne( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, NE)
|
||||
def blt( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, LT)
|
||||
def bge( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, GE)
|
||||
def bltu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, LTU)
|
||||
def bgeu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs1), Reg(rs2), dst, GEU)
|
||||
|
||||
def ble( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, GE)
|
||||
def bgt( rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, LT)
|
||||
def bleu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, GEU)
|
||||
def bgtu(rs1: Int, rs2: Int, dst: Label) = Branch(Reg(rs2), Reg(rs1), dst, LTU)
|
||||
|
||||
def beqz(rs1: Int, dst: Label) = Branch(Reg(rs1), Reg(0), dst, EQ)
|
||||
def bnez(rs1: Int, dst: Label) = Branch(Reg(rs1), Reg(0), dst, NE)
|
||||
def blez(rs1: Int, dst: Label) = Branch(Reg(rs1), Reg(0), dst, LT)
|
||||
}
|
||||
|
||||
sealed trait someDecorator
|
||||
sealed trait ArithOp {
|
||||
def run(operand1: Int, operand2: Int): Int
|
||||
}
|
||||
case object ADD extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 + operand2 }
|
||||
case object SUB extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 - operand2 }
|
||||
case object OR extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 | operand2 }
|
||||
case object XOR extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 ^ operand2 }
|
||||
case object AND extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 & operand2 }
|
||||
case object SLL extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 << operand2 }
|
||||
case object SRL extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 >>> operand2 }
|
||||
case object SRA extends ArithOp { def run(operand1: Int, operand2: Int): Int = operand1 >> operand2 }
|
||||
case object SLT extends ArithOp { def run(operand1: Int, operand2: Int): Int = if(operand2 > operand1) 1 else 0 }
|
||||
case object SLTU extends ArithOp { def run(operand1: Int, operand2: Int): Int = if(operand2 `u>` operand1) 1 else 0 }
|
||||
|
||||
case class Arith(rd: Reg, rs1: Reg, rs2: Reg, op: ArithOp) extends Op with RType
|
||||
object Arith {
|
||||
def add( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), ADD)
|
||||
def sub( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SUB)
|
||||
def or( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), OR)
|
||||
def xor( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), XOR)
|
||||
def and( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), AND)
|
||||
def sll( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SLL)
|
||||
def srl( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SRL)
|
||||
def sra( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SRA)
|
||||
def slt( rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SLT)
|
||||
def sltu(rd: Int, rs1: Int, rs2: Int) = Arith(Reg(rd), Reg(rs1), Reg(rs2), SLTU)
|
||||
}
|
||||
|
||||
def NOP = ArithImm.nop
|
||||
|
||||
|
||||
|
||||
case class ArithImm(rd: Reg, rs1: Reg, imm: Imm, op: ArithOp) extends Op with IType
|
||||
object ArithImm {
|
||||
def add( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), ADD)
|
||||
def or( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), OR)
|
||||
def xor( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), XOR)
|
||||
def and( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), AND)
|
||||
def sll( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SLL)
|
||||
def srl( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SRL)
|
||||
def sra( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SRA)
|
||||
def slt( rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SLT)
|
||||
def sltu(rd: Int, rs1: Int, imm: Int) = ArithImm(Reg(rd), Reg(rs1), Imm(imm), SLTU)
|
||||
def nop = add(0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
case class LUI(rd: Reg, imm: Imm) extends Op with UType
|
||||
case class AUIPC(rd: Reg, imm: Imm) extends Op with UType
|
||||
case class SW(rs2: Reg, rs1: Reg, offset: Imm) extends Op with SType
|
||||
case class LW(rd: Reg, rs1: Reg, offset: Imm) extends Op with IType
|
||||
|
||||
case class JALR(rd: Reg, rs1: Reg, dst: String) extends Op with IType
|
||||
case class JAL(rd: Reg, dst: String) extends Op with UType
|
||||
|
||||
|
||||
object LUI { def apply(rd: Int, imm: Int): LUI = LUI(Reg(rd), Imm(imm)) }
|
||||
object AUIPC { def apply(rd: Int, imm: Int): AUIPC = AUIPC(Reg(rd), Imm(imm)) }
|
||||
object SW { def apply(rs2: Int, rs1: Int, offset: Int): SW = SW(Reg(rs2), Reg(rs1), Imm(offset)) }
|
||||
object LW { def apply(rd: Int, rs1: Int, offset: Int): LW = LW(Reg(rd), Reg(rs1), Imm(offset)) }
|
||||
|
||||
object JAL{ def apply(rd: Int, dst: String): JAL = JAL(Reg(rd), dst) }
|
||||
object JALR{ def apply(rd: Int, rs1: Int, dst: String): JALR = JALR(Reg(rd), Reg(rs1), dst) }
|
||||
|
||||
// This op should not be assembled, but will for the sake of simplicity be rendered as a NOP
|
||||
case object DONE extends Op with IType { val rd = Reg(0); val rs1 = Reg(0) }
|
||||
}
|
357
src/test/scala/RISCV/Parser.scala
Normal file
357
src/test/scala/RISCV/Parser.scala
Normal file
|
@ -0,0 +1,357 @@
|
|||
package FiveStage
|
||||
import atto._, Atto._, syntax.refined._
|
||||
import eu.timepit.refined.numeric._
|
||||
import fileUtils.say
|
||||
|
||||
import Ops._
|
||||
import Data._
|
||||
|
||||
import cats._
|
||||
import cats.data.{ Op => _ }
|
||||
import cats.implicits._
|
||||
|
||||
object Parser {
|
||||
|
||||
def hex : Parser[Int] = string("0x") ~> many1(hexDigit).map{ ds =>
|
||||
val bi = Integer.parseUnsignedInt(new String(ds.toList.toArray), 16)
|
||||
bi.toInt
|
||||
}
|
||||
|
||||
def labelDest : Parser[Label] = (takeWhile(_ != ':') <~ char(':'))
|
||||
def label : Parser[Label] = takeWhile(_ != ' ')
|
||||
def reg : Parser[Int] = takeWhile(x => (x != ',' && x != ')')).map(lookupReg).attempt
|
||||
def sep : Parser[Unit] = many(whitespace) *> char(',') *> many(whitespace).void
|
||||
|
||||
def branch : (Parser[Int], Parser[Int], Parser[String]) = (reg <~ sep, reg <~ sep, label)
|
||||
def branchZ : (Parser[Int], Parser[String]) = (reg <~ sep, label)
|
||||
|
||||
def arith : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, reg)
|
||||
def arithImm : (Parser[Int], Parser[Int], Parser[Int]) = (reg <~ sep, reg <~ sep, hex | int)
|
||||
|
||||
def stringWs(s: String) : Parser[String] = many(whitespace) ~> string(s) <~ many1(whitespace)
|
||||
|
||||
val singleInstruction: Parser[Op] = List(
|
||||
////////////////////////////////////////////
|
||||
//// Branches
|
||||
stringWs("beq") ~> branch.mapN{Branch.beq},
|
||||
stringWs("bne") ~> branch.mapN{Branch.bne},
|
||||
stringWs("blt") ~> branch.mapN{Branch.blt},
|
||||
stringWs("bge") ~> branch.mapN{Branch.bge},
|
||||
stringWs("bltu") ~> branch.mapN{Branch.bltu},
|
||||
stringWs("bgeu") ~> branch.mapN{Branch.bgtu},
|
||||
|
||||
// pseudos:
|
||||
stringWs("ble") ~> branch.mapN{Branch.ble},
|
||||
stringWs("bgt") ~> branch.mapN{Branch.bgt},
|
||||
stringWs("bleu") ~> branch.mapN{Branch.bleu},
|
||||
stringWs("bgtu") ~> branch.mapN{Branch.bgtu},
|
||||
|
||||
// Introduce zero
|
||||
stringWs("bnez") ~> branchZ.mapN{Branch.bnez},
|
||||
stringWs("beqz") ~> branchZ.mapN{Branch.beqz},
|
||||
stringWs("blez") ~> branchZ.mapN{Branch.blez},
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
//// Arith
|
||||
stringWs("add") ~> arith.mapN{Arith.add},
|
||||
stringWs("sub") ~> arith.mapN{Arith.sub},
|
||||
stringWs("or") ~> arith.mapN{Arith.or},
|
||||
stringWs("xor") ~> arith.mapN{Arith.xor},
|
||||
stringWs("and") ~> arith.mapN{Arith.and},
|
||||
|
||||
stringWs("sll") ~> arith.mapN{Arith.sll},
|
||||
stringWs("srl") ~> arith.mapN{Arith.srl},
|
||||
stringWs("sra") ~> arith.mapN{Arith.sra},
|
||||
|
||||
stringWs("slt") ~> arith.mapN{Arith.slt},
|
||||
stringWs("sltu") ~> arith.mapN{Arith.sltu},
|
||||
|
||||
// pseudos
|
||||
stringWs("mv") ~> (reg <~ sep, reg, ok(0)).mapN{Arith.add},
|
||||
stringWs("nop") ~> (ok(0), ok(0), ok(0)).mapN{Arith.add},
|
||||
|
||||
// Check if rs1 is not equal to 0.
|
||||
// snez rd, rs1 => sltu rd, zero, rs1
|
||||
stringWs("snez") ~> (reg <~ sep, ok(0), reg).mapN{Arith.sltu},
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
//// Arith Imm
|
||||
stringWs("addi") ~> arithImm.mapN{ArithImm.add},
|
||||
stringWs("ori") ~> arithImm.mapN{ArithImm.or},
|
||||
stringWs("xori") ~> arithImm.mapN{ArithImm.xor},
|
||||
stringWs("andi") ~> arithImm.mapN{ArithImm.and},
|
||||
|
||||
stringWs("slli") ~> arithImm.mapN{ArithImm.sll},
|
||||
stringWs("srli") ~> arithImm.mapN{ArithImm.srl},
|
||||
stringWs("srai") ~> arithImm.mapN{ArithImm.sra},
|
||||
|
||||
stringWs("slti") ~> arithImm.mapN{ArithImm.slt},
|
||||
stringWs("sltui") ~> arithImm.mapN{ArithImm.sltu},
|
||||
|
||||
// pseudos
|
||||
stringWs("not") ~> (reg <~ sep, reg, ok(-1)).mapN{ArithImm.xor},
|
||||
|
||||
// Check if rs1 is less than 1. Only 0 is less than 1 when using unsigned comparison
|
||||
// seqz rd, rs1 => sltiu rd, rs1, 1
|
||||
stringWs("seqz") ~> (reg <~ sep, reg, ok(1)).mapN{ArithImm.sltu},
|
||||
|
||||
stringWs("li") ~> (reg ~ sep ~ int).collect{
|
||||
case((a, b), c) if (c.nBitsS <= 12) => ArithImm.add(a, 0, c)
|
||||
},
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
//// Jumps
|
||||
stringWs("jalr") ~> (reg <~ sep, reg <~ sep, label).mapN{JALR.apply},
|
||||
stringWs("jal") ~> (reg <~ sep, label).mapN{JAL.apply},
|
||||
|
||||
// pseudos
|
||||
// JAL with ra as rd automatically chosen.
|
||||
stringWs("call") ~> label.map(label => JAL(regNames.ra, label)),
|
||||
|
||||
// For jr we don't care about where we jumped from.
|
||||
stringWs("jr") ~> reg.map(r => JALR(0, r, "zero")),
|
||||
|
||||
// As jr, but with a label rather than a register.
|
||||
stringWs("j") ~> label.map(label => JAL(0, label)),
|
||||
many(whitespace) ~> string("ret") ~> ok(JALR(0, regNames.ra, "zero")),
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
//// load/store
|
||||
stringWs("sw") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{case (rs2, offset, rs1) => SW(rs2, rs1, offset)},
|
||||
stringWs("lw") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{case (rd, offset, rs1) => LW(rd, rs1, offset)},
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
//// others
|
||||
stringWs("auipc") ~> (reg <~ sep, int).mapN{AUIPC.apply},
|
||||
stringWs("lui") ~> (reg <~ sep, int).mapN{LUI.apply},
|
||||
|
||||
many(whitespace) ~> string("nop") ~> ok(Arith.add(0, 0, 0)),
|
||||
many(whitespace) ~> string("done") ~> ok(DONE),
|
||||
// stringWs("done") ~> ok(DONE),
|
||||
|
||||
).map(_.widen[Op]).reduce(_|_)
|
||||
|
||||
|
||||
// def getShiftsHalfWord(offset: Int): (Int, Int) = (offset % 4) match {
|
||||
// case 0 => (16, 16)
|
||||
// case 1 => (
|
||||
// }
|
||||
|
||||
val multipleInstructions: Parser[List[Op]] = List(
|
||||
stringWs("li") ~> (reg <~ sep, int.map(_.splitLoHi(12))).mapN{ case(rd, (lo, hi)) => List(
|
||||
LUI(rd, hi),
|
||||
ArithImm.add(rd, 0, lo)
|
||||
)}.map(_.widen[Op]),
|
||||
|
||||
// NOTE: THESE ARE NOT PSEUDO-OPS IN RISV32I!
|
||||
// NOTE: USES A SPECIAL REGISTER
|
||||
stringWs("lh") ~> (reg <~ sep, int <~ char('('), reg <~ char(')')).mapN{
|
||||
case (rd, offset, rs1) if (offset % 4 == 3) => {
|
||||
val placeHolder = if(rd == Reg("a0").value) Reg("a1").value else Reg("a0").value
|
||||
List(
|
||||
SW(placeHolder, 0, 2048),
|
||||
LW(placeHolder, rs1.value, (offset & 0xFFFFFF1C)),
|
||||
LW(rd.value, rs1.value, (offset & 0xFFFFFF1C) + 4),
|
||||
ArithImm.sra(placeHolder, placeHolder, 24),
|
||||
ArithImm.sll(rd.value, rd.value, 24),
|
||||
ArithImm.sra(rd.value, rd.value, 16),
|
||||
Arith.add(rd, rd, placeHolder),
|
||||
LW(placeHolder, 0, 2048)).reverse
|
||||
}
|
||||
case (rd, offset, rs1) if (offset % 4 == 2) => {
|
||||
List(
|
||||
LW(rd, rs1, (offset & 0xFFFFFF1C)),
|
||||
ArithImm.sra(rd, rd, 16)
|
||||
).reverse
|
||||
}
|
||||
|
||||
case (rd, offset, rs1) => {
|
||||
val leftShift = if((offset % 4) == 0) 16 else 8
|
||||
List(
|
||||
LW(rd, rs1, (offset & 0xFFFFFF1C)),
|
||||
ArithImm.sll(rd, rd, leftShift),
|
||||
ArithImm.sra(rd, rd, 16),
|
||||
).reverse
|
||||
}
|
||||
}.map(_.widen[Op]),
|
||||
).reduce(_|_)
|
||||
|
||||
|
||||
val instruction = singleInstruction.map(List(_)) | multipleInstructions
|
||||
|
||||
val setting = List(
|
||||
char('#') ~> string("regset") ~> many1(whitespace) ~> (reg.map(Reg.apply) <~ sep, hex | int).mapN{REGSET.apply},
|
||||
char('#') ~> string("memset") ~> many1(whitespace) ~> ((hex | int).map(Addr.apply) <~ sep, hex | int).mapN{MEMSET.apply}
|
||||
).map(_.widen[TestSetting]).reduce(_|_)
|
||||
|
||||
|
||||
def parseProgram(p: List[String], testOptions: TestOptions): Either[String, Program] = {
|
||||
|
||||
val all = setting || (instruction || labelDest)
|
||||
|
||||
/**
|
||||
* The foldhelper represents a traversal through a RISC-V program.
|
||||
*
|
||||
* When it sees an op it records the operation and appends the source line and its location.
|
||||
* If it is in nopPad mode it will also insert NOPs between the parsed ops.
|
||||
* After appending ops the address counter is bumbed accordingly
|
||||
*
|
||||
* When it sees a label destination it checks what the current addres counter is at and creates
|
||||
* a link to this address.
|
||||
*
|
||||
* When it sees a parse error it simply stores the error and keeps going, allowing you to get every error
|
||||
* (This works for an ASM program since each line is independent)
|
||||
*
|
||||
* Lastly, when it sees a test setting it appends that test setting.
|
||||
*
|
||||
* The reason everything is treated all-in-one is to make it easier to ensure that everything is parsed.
|
||||
* If there were separate parsers for ops, labels and settings it would be difficult to find out if errors
|
||||
* were simply of the wrong type or a legit error.
|
||||
* This is not set in stone, if you're re-architecturing the code maybe it's better to separate parsers?
|
||||
* Or maybe have multiple passes? Up to you!
|
||||
*/
|
||||
case class FoldHelper(
|
||||
settings : List[TestSetting],
|
||||
ops : List[SourceInfo[Op]],
|
||||
labelMap : Map[Label, Addr],
|
||||
errors : List[String],
|
||||
addrCount : Int){
|
||||
def addSettings (t: TestSetting): FoldHelper = copy(settings = t :: settings)
|
||||
def addErrors (t: String): FoldHelper = copy(errors = t :: errors)
|
||||
def addLabelMap (t: Label): FoldHelper = copy(labelMap = labelMap + (t -> Addr(addrCount)))
|
||||
def addOps (t: List[SourceInfo[Op]]): FoldHelper = {
|
||||
if(testOptions.nopPadded){
|
||||
copy(
|
||||
ops = t.flatMap(x => (x :: List.fill(4)(SourceInfo("inserted NOP", NOP).widen[Op]))).reverse ::: ops,
|
||||
addrCount = addrCount + t.size*4*5)
|
||||
}
|
||||
else {
|
||||
copy(ops = t ::: ops, addrCount = addrCount + t.size*4)
|
||||
}
|
||||
}
|
||||
def program: Either[String, (List[TestSetting], List[SourceInfo[Op]], Map[Label, Addr])] = {
|
||||
/**
|
||||
* There are two possible ways for a program to successfully terminate, either by explicitly executing
|
||||
* a DONE instruction, or by returning from the main method.
|
||||
* In the latter case it is necessary to preload the return address register such that the return instruction
|
||||
* jumps to a predetermined special done address
|
||||
*/
|
||||
val hasDONEinstruction = ops.map(_.run._2).contains(DONE)
|
||||
val done = copy(settings = REGSET(Reg("sp"), 1024) :: settings, ops = ops.reverse, errors = errors.reverse)
|
||||
|
||||
val withReturnAddress = if(hasDONEinstruction){
|
||||
done
|
||||
}
|
||||
else
|
||||
done.copy(settings = REGSET(Reg("ra"), 0xEB1CEB1C) :: done.settings) // now that's what I call EPIC
|
||||
|
||||
Either.cond(errors.isEmpty, (withReturnAddress.settings, done.ops, labelMap), done.errors).left.map(errors =>
|
||||
s"Parser errors in ${testOptions.testName}:\n" + errors.mkString("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def foldHelper(
|
||||
acc: FoldHelper,
|
||||
program: List[(Int, String)]): FoldHelper = program match {
|
||||
case Nil => acc
|
||||
case (lineNo, line) :: t => {
|
||||
if(line.isEmpty)
|
||||
foldHelper(acc, t)
|
||||
else {
|
||||
val next = all.parse(line).done.either match {
|
||||
case Left(parseError) => acc.addErrors(f"$lineNo%3d" +s":$line\t$parseError")
|
||||
case Right(Left(setting)) => acc.addSettings(setting)
|
||||
case Right(Right(Right(label))) => acc.addLabelMap(label)
|
||||
case Right(Right(Left(ops))) => acc.addOps(ops.map(op => SourceInfo(s"${lineNo.toString.padTo(3, ' ')}:\t$line", op)))
|
||||
}
|
||||
foldHelper(next, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val results = foldHelper(FoldHelper(Nil, Nil, Map("zero" -> Addr(0)), Nil, 0), p.zipWithIndex.map(_.swap))
|
||||
|
||||
results.program.map{ case(settings, ops, labelMap) => Program(ops, settings, labelMap) }
|
||||
}
|
||||
|
||||
|
||||
def lookupReg(s: String): Int = {
|
||||
val regMap = Map(
|
||||
"x0" -> 0,
|
||||
"x1" -> 1,
|
||||
"x2" -> 2,
|
||||
"x3" -> 3,
|
||||
"x4" -> 4,
|
||||
"x5" -> 5,
|
||||
"x6" -> 6,
|
||||
"x7" -> 7,
|
||||
"x8" -> 8,
|
||||
"x9" -> 9,
|
||||
"x10" -> 10,
|
||||
"x11" -> 11,
|
||||
"x12" -> 12,
|
||||
"x13" -> 13,
|
||||
"x14" -> 14,
|
||||
"x15" -> 15,
|
||||
"x16" -> 16,
|
||||
"x17" -> 17,
|
||||
"x18" -> 18,
|
||||
"x19" -> 19,
|
||||
"x20" -> 20,
|
||||
"x21" -> 21,
|
||||
"x22" -> 22,
|
||||
"x23" -> 23,
|
||||
"x24" -> 24,
|
||||
"x25" -> 25,
|
||||
"x26" -> 26,
|
||||
"x27" -> 27,
|
||||
"x28" -> 28,
|
||||
"x29" -> 29,
|
||||
"x30" -> 30,
|
||||
"x31" -> 31,
|
||||
"zero" -> 0,
|
||||
"ra" -> 1,
|
||||
"sp" -> 2,
|
||||
"gp" -> 3,
|
||||
"tp" -> 4,
|
||||
"t0" -> 5,
|
||||
"t1" -> 6,
|
||||
"t2" -> 7,
|
||||
"s0" -> 8,
|
||||
"fp" -> 8,
|
||||
"s1" -> 9,
|
||||
"a0" -> 10,
|
||||
"a1" -> 11,
|
||||
"a2" -> 12,
|
||||
"a3" -> 13,
|
||||
"a4" -> 14,
|
||||
"a5" -> 15,
|
||||
"a6" -> 16,
|
||||
"a7" -> 17,
|
||||
"s2" -> 18,
|
||||
"s3" -> 19,
|
||||
"s4" -> 20,
|
||||
"s5" -> 21,
|
||||
"s6" -> 22,
|
||||
"s7" -> 23,
|
||||
"s8" -> 24,
|
||||
"s9" -> 25,
|
||||
"s10" -> 26,
|
||||
"s11" -> 27,
|
||||
"t3" -> 28,
|
||||
"t4" -> 29,
|
||||
"t5" -> 30,
|
||||
"t6" -> 31)
|
||||
|
||||
regMap(s)
|
||||
}
|
||||
}
|
171
src/test/scala/RISCV/VM.scala
Normal file
171
src/test/scala/RISCV/VM.scala
Normal file
|
@ -0,0 +1,171 @@
|
|||
package FiveStage
|
||||
import cats._
|
||||
import cats.data.{ Op => _ }
|
||||
import cats.implicits._
|
||||
import fileUtils._
|
||||
|
||||
import Data._
|
||||
import Ops._
|
||||
|
||||
import PrintUtils._
|
||||
|
||||
sealed trait Finished
|
||||
case object Success extends Finished
|
||||
case object Timeout extends Finished
|
||||
case class Failed(s: String, addr: Addr) extends Finished
|
||||
|
||||
case class VM(
|
||||
dmem : DMem,
|
||||
imem : Map[Addr, Op],
|
||||
regs : Regs,
|
||||
pc : Addr,
|
||||
labelMap : Map[Label, Addr]){
|
||||
def stepInstruction: Either[Finished, ExecutionTrace[VM]] = {
|
||||
if (pc.value == 0xEB1CEB1C) Left(Success)
|
||||
else getOp flatMap {
|
||||
case op: Branch => executeBranch(op)
|
||||
case op: Arith => executeArith(op)
|
||||
case op: ArithImm => executeArithImm(op)
|
||||
case op: AUIPC => executeAUIPC(op)
|
||||
case op: LUI => executeLUI(op)
|
||||
case op: JALR => executeJALR(op)
|
||||
case op: JAL => executeJAL(op)
|
||||
case op: LW => executeLW(op)
|
||||
case op: SW => executeSW(op)
|
||||
case DONE => Left(Success)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private def executeBranch(op: Branch) = {
|
||||
getAddr(op.dst).map{ addr =>
|
||||
val takeBranch = regs.compare(op.rs1, op.rs2, op.comp.run)
|
||||
if(takeBranch){
|
||||
val nextVM = copy(pc = addr)
|
||||
jump(nextVM, PcUpdateB(nextVM.pc))
|
||||
}
|
||||
else {
|
||||
step(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The weird :_* syntax is simply a way to pass a list to a varArgs function.
|
||||
*
|
||||
* To see why, consider def printMany(a: Any*); printMany(List(1,2,3))
|
||||
* It is now ambiguous if it should print "1, 2, 3" or List(1, 2, 3)
|
||||
*
|
||||
* This is disambiguated by appending :_*, thus
|
||||
* printMany(List(1,2,3):_*) == printMany(1, 2, 3)
|
||||
*/
|
||||
private def executeArith(op: Arith) = {
|
||||
val (regUpdate, nextRegs) = regs.arith(op.rd, op.rs1, op.rs2, op.op.run)
|
||||
val nextVM = this.copy(regs = nextRegs)
|
||||
Right(step(nextVM, regUpdate.toList:_*))
|
||||
}
|
||||
|
||||
|
||||
private def executeArithImm(op: ArithImm) = {
|
||||
val (regUpdate, nextRegs) = regs.arithImm(op.rd, op.rs1, op.imm, op.op.run)
|
||||
val nextVM = this.copy(regs = nextRegs)
|
||||
Right(step(nextVM, regUpdate.toList:_*))
|
||||
}
|
||||
|
||||
|
||||
private def executeLUI(op: LUI) = {
|
||||
val (regUpdate, nextRegs) = regs + (op.rd -> (op.imm.value << 12))
|
||||
val nextVM = this.copy(regs = nextRegs)
|
||||
Right(step(nextVM, regUpdate.toList:_*))
|
||||
}
|
||||
|
||||
|
||||
private def executeAUIPC(op: AUIPC) = {
|
||||
val (regUpdate, nextRegs) = regs + (op.rd -> (pc.value << 12))
|
||||
val nextVM = this.copy(regs = nextRegs)
|
||||
Right(step(nextVM, regUpdate.toList:_*))
|
||||
}
|
||||
|
||||
|
||||
|
||||
private def executeJALR(op: JALR) = getAddr(op.dst).map{ targetAddr =>
|
||||
val nextPc = Addr((regs.repr(op.rs1).value + targetAddr.value) & 0xFFFFFFFE)
|
||||
val (regUpdate, nextRegs) = regs + (op.rd -> (pc.step.value))
|
||||
val nextVM = this.copy(regs = nextRegs, pc = nextPc)
|
||||
jump(nextVM, (PcUpdateJALR(nextPc) :: regUpdate.toList):_*)
|
||||
}
|
||||
|
||||
|
||||
private def executeJAL(op: JAL) = getAddr(op.dst).map{ targetAddr =>
|
||||
val nextPc = targetAddr
|
||||
val (regUpdate, nextRegs) = regs + (op.rd -> (pc.step.value))
|
||||
val nextVM = this.copy(regs = nextRegs, pc = nextPc)
|
||||
jump(nextVM, (PcUpdateJAL(nextPc) :: regUpdate.toList):_*)
|
||||
}
|
||||
|
||||
|
||||
private def executeLW(op: LW) = dmem.read(Addr(regs.repr(op.rs1) + op.offset.value)).map{ case(event, result) =>
|
||||
val (regUpdate, nextRegs) = regs + (op.rd -> result)
|
||||
val nextVM = this.copy(regs = nextRegs)
|
||||
step(nextVM, (event :: regUpdate.toList):_*)
|
||||
}.left.map(x => Failed(x, pc))
|
||||
|
||||
private def executeSW(op: SW) = {
|
||||
val writeAddress = Addr(regs.repr(op.rs1) + op.offset.value)
|
||||
val writeData = regs.repr(op.rs2)
|
||||
dmem.write(writeAddress, writeData).map{ case(event, nextDmem) =>
|
||||
val nextVM = this.copy(dmem = nextDmem)
|
||||
step(nextVM, event)
|
||||
}
|
||||
}.left.map(x => Failed(x, pc))
|
||||
|
||||
private def step(nextVM: VM, event: ExecutionEvent*) =
|
||||
ExecutionTrace(nextVM.stepPC, ExecutionTraceEvent(pc, event:_*))
|
||||
|
||||
// Same as above, but no stepping
|
||||
private def jump(nextVM: VM, event: ExecutionEvent*) =
|
||||
ExecutionTrace(nextVM, ExecutionTraceEvent(pc, event:_*))
|
||||
|
||||
|
||||
private def stepPC: VM = copy(pc = this.pc.step)
|
||||
|
||||
private def getAddr(dst: Label): Either[Failed, Addr] =
|
||||
labelMap.lift(dst).toRight(Failed(s"Label $dst missing", pc))
|
||||
|
||||
private def getOp: Either[Failed, Op] =
|
||||
imem.lift(pc).toRight(Failed(s"Attempted to fetch instruction at illegal address ${pc.show}", pc))
|
||||
}
|
||||
|
||||
|
||||
object VM {
|
||||
|
||||
val init = VM(DMem.empty, Map[Addr, Op](), Regs.empty, Addr(0), Map[Label, Addr]())
|
||||
|
||||
def apply(settings: List[TestSetting], imem: Map[Addr, Op], labelMap: Map[Label, Addr]): VM = {
|
||||
val (dmem, regs) = settings.foldLeft((DMem.empty, Regs.empty)){ case((dmem, regs), setting) => setting match {
|
||||
case setting: REGSET => (dmem, regs(setting))
|
||||
case setting: MEMSET => (dmem(setting), regs)
|
||||
}
|
||||
}
|
||||
VM(dmem, imem, regs, Addr(0), labelMap)
|
||||
}
|
||||
|
||||
def run(maxSteps: Int, vm: VM) = {
|
||||
def helper(state: ExecutionTrace[VM], step: Int): (Finished, ExecutionTrace[VM]) = {
|
||||
if(step > 0){
|
||||
val (log, vm) = state.run
|
||||
val next = vm.stepInstruction
|
||||
next match {
|
||||
case Left(stopped) => (stopped, state)
|
||||
case Right(trace) => helper((state >> trace), step - 1)
|
||||
}
|
||||
}
|
||||
else{
|
||||
(Timeout, state)
|
||||
}
|
||||
}
|
||||
helper(ExecutionTrace(vm), maxSteps)
|
||||
}
|
||||
}
|
269
src/test/scala/RISCV/assembler.scala
Normal file
269
src/test/scala/RISCV/assembler.scala
Normal file
|
@ -0,0 +1,269 @@
|
|||
package FiveStage
|
||||
import cats.implicits._
|
||||
|
||||
import Data._
|
||||
import Ops._
|
||||
import fileUtils._
|
||||
import PrintUtils._
|
||||
|
||||
object assembler {
|
||||
|
||||
type InstructionFragment = Either[(String, Addr), Int]
|
||||
|
||||
/**
|
||||
* Will only be called by applyImmedate, thus error propagation is not needed
|
||||
* Kind of a kludge, but it works, don't touch!
|
||||
*/
|
||||
def setField(firstBit: Int, size: Int, field: Int): Int => Int = instruction => {
|
||||
val shiftedField = field << firstBit
|
||||
val mask = (1 << size) - 1
|
||||
val shiftedMask = (mask << firstBit)
|
||||
val masked = ((~instruction) | shiftedMask)
|
||||
val maskedInv = ~(masked)
|
||||
|
||||
val ret = (shiftedField & shiftedMask) | maskedInv
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
|
||||
def getSubField(firstBit: Int, size: Int): Int => Int = word => {
|
||||
val bitsLeft = 32 - firstBit
|
||||
val bitsRight = 32 - size
|
||||
val leftShifted = word << bitsLeft
|
||||
val rightShifted = leftShifted >> bitsRight
|
||||
rightShifted
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Splits the immediate value into fields given by points.
|
||||
The order of points is important!
|
||||
points is of type idx, size
|
||||
*/
|
||||
def applyImmediate(immediateBits: Int, immediate: Int, points: List[(Int, Int)]): Int => Int = instruction => {
|
||||
|
||||
def go(instruction: Int, immediateIndex: Int, points: List[(Int,Int)]): Int = points match {
|
||||
case h :: t => {
|
||||
val (immFirstBit, size) = h
|
||||
val firstBit = (immFirstBit - size) + 1
|
||||
val immSubField = getSubField(immediateIndex, size)(immediate)
|
||||
val nextImmIndex = immediateIndex - size
|
||||
val nextInstruction = setField(firstBit, size, immSubField)(instruction)
|
||||
go(nextInstruction, nextImmIndex, points.tail)
|
||||
}
|
||||
case _ => {
|
||||
instruction
|
||||
}
|
||||
}
|
||||
|
||||
go(instruction, immediateBits, points)
|
||||
}
|
||||
|
||||
|
||||
def applyImmediateU(immediate: Int, points: List[(Int, Int)], addr: Addr): Int => InstructionFragment = instruction => {
|
||||
def totalBits = points.foldLeft(0){ case(acc, (first, size)) => acc + size }
|
||||
totalBits.nBitsU.toRight("Negative number used as unsigned immediate", addr).flatMap { bits =>
|
||||
Either.cond(bits < totalBits, applyImmediate(totalBits, immediate, points)(instruction), ("Immediate unsigned too large", addr))
|
||||
}
|
||||
}
|
||||
|
||||
def applyImmediateS(immediate: Int, points: List[(Int, Int)], addr: Addr): Int => InstructionFragment = instruction => {
|
||||
def totalBits = points.foldLeft(0){ case(acc, (first, size)) => acc + size }
|
||||
if(totalBits < immediate.nBitsS) Left((s"Immediate signed too large. immedate: $immediate, immediate.nBitsS = ${immediate.nBitsS}, total bits: $totalBits", addr))
|
||||
else Right(applyImmediate(totalBits, immediate, points)(instruction))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by JALR, LW and arithmetic immediate ops.
|
||||
* JALR is sort of the odd man out here as it should be unsigned.
|
||||
* This issue should not surface at the very limited address space
|
||||
* for your design. (I hope)
|
||||
*/
|
||||
def setItypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = {
|
||||
val points = List((31, 12))
|
||||
val withField = applyImmediateS(immediate, points, addr)
|
||||
withField
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by SW
|
||||
*/
|
||||
def setStypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = {
|
||||
val points = List((31, 7), (11, 5))
|
||||
val withField = applyImmediateS(immediate, points, addr)
|
||||
withField
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Branches. PC relative jump, thus signed
|
||||
* Last bit is not used, hence the shift
|
||||
*/
|
||||
def setBtypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = {
|
||||
val points = List((31, 1), (7, 1), (30, 6), (11, 4))
|
||||
val withField = applyImmediateS((immediate >> 1), points, addr)
|
||||
withField
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by LUI and AUIPC. Unsigned
|
||||
*/
|
||||
def setUtypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = {
|
||||
val points = List((31, 20))
|
||||
val withField = applyImmediateU(immediate, points, addr)
|
||||
withField
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by JAL. PC relative jump, thus signed
|
||||
* The last bit is not used, hence the shift
|
||||
*/
|
||||
def setJtypeImmediate(immediate: Int, addr: Addr): Int => InstructionFragment = {
|
||||
val points = List((31, 1), (19, 8), (20, 1), (30, 10))
|
||||
applyImmediateU((immediate >> 1), points, addr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently not used, thus we allow too larg shifts.
|
||||
*/
|
||||
def setShiftTypeImmediate(instruction: Int, immediate: Int): Int = {
|
||||
val points = List((24, 5))
|
||||
val withField = applyImmediate(5, immediate, points)(instruction)
|
||||
withField
|
||||
}
|
||||
|
||||
def setOpCode(opcode: Int): Int => Int = setField(0, 7, opcode)
|
||||
def setFunct7(funct7: Int): Int => Int = setField(25, 7, funct7)
|
||||
def setFunct3(funct3: Int): Int => Int = setField(12, 3, funct3)
|
||||
def setRs1(rs1: Int): Int => Int = setField(15, 5, rs1)
|
||||
def setRs2(rs2: Int): Int => Int = setField(20, 5, rs2)
|
||||
def setRd(rd: Int): Int => Int = setField(7, 5, rd)
|
||||
|
||||
|
||||
def setOpCode(op: Op): Int => Int = op match {
|
||||
case x: Branch => setOpCode("1100011".binary)
|
||||
case x: Arith => setOpCode("0110011".binary)
|
||||
case x: ArithImm => setOpCode("0010011".binary)
|
||||
case x: LW => setOpCode("0000011".binary)
|
||||
case x: SW => setOpCode("0100011".binary)
|
||||
case x: JALR => setOpCode("1100111".binary)
|
||||
case x: JAL => setOpCode("1101111".binary)
|
||||
case x: AUIPC => setOpCode("0110111".binary)
|
||||
case x: LUI => setOpCode("0010111".binary)
|
||||
case DONE => setOpCode("0010011".binary) // done is turned into a NOP in the assembler.
|
||||
}
|
||||
|
||||
def setComparisonFunct(cmp: Comparison): Int => Int = cmp match {
|
||||
case EQ => setFunct3("000".binary)
|
||||
case NE => setFunct3("001".binary)
|
||||
case GE => setFunct3("101".binary)
|
||||
case LT => setFunct3("100".binary)
|
||||
case GEU => setFunct3("111".binary)
|
||||
case LTU => setFunct3("110".binary)
|
||||
}
|
||||
|
||||
def setBranchDestination(labelMap: Map[Label, Addr], op: Branch, opAddr: Addr): Int => InstructionFragment = instruction => {
|
||||
labelMap.lift(op.dst).toRight((s"destination ${op.dst} not found", opAddr)).flatMap{ dstAddr =>
|
||||
setBtypeImmediate(dstAddr.value - opAddr.value, opAddr)(instruction)
|
||||
}
|
||||
}
|
||||
|
||||
def setArithFunct(op: ArithOp): Int => Int = op match {
|
||||
case ADD => setFunct7("0000000".binary) andThen setFunct3("000".binary)
|
||||
case SUB => setFunct7("0100000".binary) andThen setFunct3("000".binary)
|
||||
case SLL => setFunct7("0000000".binary) andThen setFunct3("001".binary)
|
||||
case SLT => setFunct7("0000000".binary) andThen setFunct3("010".binary)
|
||||
case SLTU => setFunct7("0000000".binary) andThen setFunct3("011".binary)
|
||||
case XOR => setFunct7("0000000".binary) andThen setFunct3("100".binary)
|
||||
case SRL => setFunct7("0000000".binary) andThen setFunct3("101".binary)
|
||||
case SRA => setFunct7("0100000".binary) andThen setFunct3("101".binary)
|
||||
case OR => setFunct7("0000000".binary) andThen setFunct3("110".binary)
|
||||
case AND => setFunct7("0000000".binary) andThen setFunct3("111".binary)
|
||||
}
|
||||
|
||||
|
||||
def assembleRegLayout(op: RegLayout): Int => Int = {
|
||||
|
||||
def assembleRType(op: RType): Int => Int =
|
||||
setRd(op.rd.value) andThen
|
||||
setRs1(op.rs1.value) andThen
|
||||
setRs2(op.rs2.value)
|
||||
|
||||
def assembleIType(op: IType): Int => Int =
|
||||
setRd(op.rd.value) andThen
|
||||
setRs1(op.rs1.value)
|
||||
|
||||
def assembleSType(op: SType): Int => Int = {
|
||||
// say("stype")
|
||||
instruction =>
|
||||
(setRs1(op.rs1.value) andThen
|
||||
setRs2(op.rs2.value))(instruction)
|
||||
}
|
||||
|
||||
def assembleUType(op: UType): Int => Int =
|
||||
setRd(op.rd.value)
|
||||
|
||||
op match {
|
||||
case op: RType => assembleRType(op)
|
||||
case op: IType => assembleIType(op)
|
||||
case op: SType => assembleSType(op)
|
||||
case op: UType => assembleUType(op)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def assembleImmediate(op: Op, addr: Addr, labelMap: Map[Label, Addr]): Int => Either[(String, Addr), Int] = op match {
|
||||
case DONE => instruction => Right(instruction)
|
||||
case op: Arith => instruction => Right(instruction)
|
||||
case op: ArithImm => setItypeImmediate(op.imm.value, addr)
|
||||
case op: Branch => setBranchDestination(labelMap, op, addr)
|
||||
case op: JALR => instruction => labelMap.lift(op.dst).toRight(s"label ${op.dst} not found", addr).flatMap(addr => setItypeImmediate(addr.value, addr)(instruction))
|
||||
case op: AUIPC => setUtypeImmediate(op.imm.value, addr)
|
||||
case op: LUI => setUtypeImmediate(op.imm.value, addr)
|
||||
case op: LW => setItypeImmediate(op.offset.value, addr)
|
||||
case op: SW => setStypeImmediate(op.offset.value, addr)
|
||||
case op: JAL => instruction => {
|
||||
val addressDistance = labelMap
|
||||
.lift(op.dst).toRight(s"label ${op.dst} not found", addr)
|
||||
.map(absoluteAddr => absoluteAddr - addr)
|
||||
|
||||
import PrintUtils._
|
||||
|
||||
addressDistance.flatMap(distance =>
|
||||
setJtypeImmediate(distance.value, addr)(instruction))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def assembleOp(
|
||||
op : Op with RegLayout,
|
||||
opAddr : Addr,
|
||||
labelMap : Map[Label, Addr]): Either[(String, Addr), Int] = {
|
||||
|
||||
val layout = assembleRegLayout(op)
|
||||
val immediate = assembleImmediate(op, opAddr, labelMap)
|
||||
val opcode = setOpCode(op)
|
||||
|
||||
val extras: Int => Int = (instruction: Int) => op match {
|
||||
case op: Branch => setComparisonFunct(op.comp)(instruction)
|
||||
case op: ArithImm => setArithFunct(op.op)(instruction)
|
||||
case op: Arith => setArithFunct(op.op)(instruction)
|
||||
case op: JALR => setFunct3("000".binary)(instruction)
|
||||
case op: LW => setFunct3("010".binary)(instruction)
|
||||
case op: SW => setFunct3("010".binary)(instruction)
|
||||
case DONE => (setFunct3("000".binary) andThen setFunct7("0000000".binary))(instruction)
|
||||
case _ => instruction
|
||||
}
|
||||
|
||||
val withOp = opcode(0)
|
||||
val withLayout = layout(withOp)
|
||||
val withImmediates = immediate(withLayout)
|
||||
val withExtras = withImmediates.map(extras)
|
||||
|
||||
|
||||
val finalOp = (opcode andThen layout andThen extras andThen immediate)(0)
|
||||
|
||||
finalOp
|
||||
}
|
||||
}
|
178
src/test/scala/RISCV/deleteMe.scala
Normal file
178
src/test/scala/RISCV/deleteMe.scala
Normal file
|
@ -0,0 +1,178 @@
|
|||
package FiveStage
|
||||
import cats.data.Writer
|
||||
import cats._
|
||||
import cats.data.{ Op => _ }
|
||||
import cats.implicits._
|
||||
|
||||
object DTree {
|
||||
|
||||
// opaques WHEN
|
||||
type Feature = String
|
||||
type Value = String
|
||||
type Cls = String
|
||||
|
||||
case class TrainingData(values: Map[Feature, Value], cls: Cls)
|
||||
|
||||
type TestData = Map[Feature, Value]
|
||||
|
||||
// Base
|
||||
// def predict(data: TestData): Cls = "Died"
|
||||
|
||||
// Gendered
|
||||
def predictStatic(data: TestData): Cls =
|
||||
if(data("gender") == "female")
|
||||
"survived"
|
||||
else "died"
|
||||
|
||||
|
||||
sealed trait Tree
|
||||
case class Node(feature: Feature, children: Map[Value, Tree]) extends Tree
|
||||
case class Leaf(cls: Cls) extends Tree
|
||||
|
||||
val genderBased: Tree = Node(
|
||||
"gender", Map(
|
||||
"female" -> Leaf("survived"),
|
||||
"male" -> Leaf("died"),
|
||||
))
|
||||
|
||||
|
||||
def predict(data: TestData)(tree: Tree): Cls =
|
||||
tree match {
|
||||
case Leaf(cls) => cls
|
||||
case Node(feature, children) => predict(data)(children(data(feature)))
|
||||
}
|
||||
|
||||
val data = Map("gender" -> "female", "family size" -> "0", "ticket" -> "1")
|
||||
|
||||
predict(data)(genderBased) // true
|
||||
|
||||
|
||||
def entropy(classes: List[Cls]): Double = {
|
||||
val total = classes.size
|
||||
classes.groupBy(identity)
|
||||
.mapValues { group =>
|
||||
val prop = group.size / total
|
||||
prop * math.log(1.0 / prop)
|
||||
}.values.sum
|
||||
}
|
||||
|
||||
def bucketedEntropy(data: List[TrainingData], feature: Feature): Double = {
|
||||
val total = data.size
|
||||
val bucketed = data.groupBy(_.values(feature))
|
||||
.mapValues(_.map(_.cls))
|
||||
.toMap
|
||||
bucketed.values.map { classes =>
|
||||
val prop = classes.size / total
|
||||
prop * entropy(classes)
|
||||
}.sum
|
||||
}
|
||||
|
||||
def best(data: List[TrainingData], features: Set[Feature]): Feature = features.minBy(bucketedEntropy(data, _))
|
||||
|
||||
def mostCommonCls(data: List[TrainingData]): Cls = ???
|
||||
|
||||
def build(data: List[TrainingData], features: Set[Feature]): Tree = {
|
||||
if(features.nonEmpty) {
|
||||
val feature = best(data, features)
|
||||
val buckets = data.groupBy(_.values(feature))
|
||||
Node(feature, buckets.mapValues(build(_, features - feature)))
|
||||
} else {
|
||||
Leaf(mostCommonCls(data))
|
||||
}
|
||||
}
|
||||
|
||||
def withHKT {
|
||||
|
||||
sealed trait Tree[A]
|
||||
case class Node[A](feature: Feature, children: Map[Value, A]) extends Tree[A]
|
||||
case class Leaf[A](cls: Cls) extends Tree[A]
|
||||
|
||||
// import matryoshka._
|
||||
// import matryoshka.data.Fix
|
||||
// import matryoshka.implicits._
|
||||
|
||||
case class Fix[F[_]](unfix: F[Fix[F]])
|
||||
case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]){
|
||||
def counit: A = head
|
||||
def map[B](f: A => B)(implicit ev: Functor[F]): Cofree[F, B] = Cofree(f(head), tail.map(_.map(f)))
|
||||
|
||||
/**
|
||||
* Coflatmap alters the value of the node based on its context, then recursively
|
||||
* alters its tail independently (which makes sense as it's the only thing Cofree[F, A] => B can do.
|
||||
*/
|
||||
def coflatMap[B](fa: Cofree[F, A] => B)(implicit ev: Functor[F]): Cofree[F, B] = {
|
||||
val b = fa(this)
|
||||
val fb = tail.map(_.coflatMap(fa))
|
||||
Cofree(b, fb)
|
||||
}
|
||||
}
|
||||
|
||||
implicit val treeFunctor: Functor[Tree] = new Functor[Tree] {
|
||||
def map[A, B](fa: Tree[A])(f: A => B): Tree[B] = fa match {
|
||||
case Node(name, children) => Node(name, children.mapValues(f))
|
||||
case Leaf(cls) => Leaf(cls)
|
||||
}
|
||||
}
|
||||
|
||||
val genderBased: Fix[Tree] =
|
||||
Fix(Node(
|
||||
"gender",
|
||||
Map(
|
||||
"female" -> Fix(Leaf[Fix[Tree]]("survived")),
|
||||
"male" -> Fix(Leaf[Fix[Tree]]("died"))
|
||||
)))
|
||||
|
||||
def build: ((List[TrainingData], Set[Feature])) => Tree[(List[TrainingData], Set[Feature])] = {
|
||||
case (data, features) =>
|
||||
if(features.nonEmpty) {
|
||||
val feature = best(data, features)
|
||||
val buckets = data.groupBy(_.values(feature))
|
||||
val next = buckets.mapValues { subset => (subset, features - feature) }
|
||||
Node(feature, next)
|
||||
} else {
|
||||
Leaf(mostCommonCls(data))
|
||||
}
|
||||
}
|
||||
|
||||
def explore(testData: TestData): Fix[Tree] => Cls Either Fix[Tree] =
|
||||
fix => fix.unfix match {
|
||||
case Leaf(cls) => Left(cls)
|
||||
case Node(feature, children) => Right(children.get(testData(feature)).get)
|
||||
}
|
||||
|
||||
// Anamorphism: Generalized unfold, builds structures
|
||||
def ana[F[_]: Functor, A](f: A => F[A])(a: A): Fix[F] =
|
||||
Fix( (f(a)).map(ana(f)) )
|
||||
|
||||
// Catamorphism: Generalized fold, tears structures down.
|
||||
def cata[F[_]: Functor, A](fa: F[A] => A)(f: Fix[F]): A = {
|
||||
fa(f.unfix.map(cata(fa)))
|
||||
}
|
||||
|
||||
// def hyloSimple[F[_] : Functor, A, B](f: F[B] => B)(g: A => F[A]): A => B
|
||||
def hyloSimple[F[_]: Functor, A, B](f: F[B] => B)(g: A => F[A])(a: A): B =
|
||||
cata(f)(ana(g)(a))
|
||||
|
||||
// A more powerful cata
|
||||
def para[F[_]: Functor, A](f: F[(Fix[F], A)] => A)(fa: Fix[F]): A =
|
||||
f(fa.unfix.map(x => (x, para(f)(x))))
|
||||
|
||||
// A more powerful ana
|
||||
def apo[F[_]: Functor, A](f: A => F[Either[Fix[F], A]])(a: A): Fix[F] = {
|
||||
Fix(f(a).map{
|
||||
case Right(a) => apo(f)(a)
|
||||
case Left(fix) => fix
|
||||
})
|
||||
}
|
||||
|
||||
// When we have cofree
|
||||
def histo[F[_]: Functor, A](f: F[Cofree[F, A]] => A)(fix: Fix[F]): A = {
|
||||
def toCofree(fix: Fix[F]): Cofree[F, A] =
|
||||
Cofree(histo(f)(fix), fix.unfix.map(toCofree))
|
||||
|
||||
f(fix.unfix.map(toCofree))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
164
src/test/scala/RISCV/deleteMe2.scala
Normal file
164
src/test/scala/RISCV/deleteMe2.scala
Normal file
|
@ -0,0 +1,164 @@
|
|||
package FiveStage
|
||||
import cats.data.Writer
|
||||
import cats._
|
||||
import cats.data.{ Op => _ }
|
||||
import cats.implicits._
|
||||
|
||||
import fileUtils.say
|
||||
|
||||
object DeletDis {
|
||||
|
||||
def delet = {
|
||||
|
||||
case class Fix[F[_]](unfix: F[Fix[F]])
|
||||
case class Cofree[F[_], A](head: A, tail: F[Cofree[F, A]]){
|
||||
def counit: A = head
|
||||
def map[B](f: A => B)(implicit ev: Functor[F]): Cofree[F, B] = Cofree(f(head), tail.map(_.map(f)))
|
||||
|
||||
/**
|
||||
* Coflatmap alters the value of the node based on its context, then recursively
|
||||
* alters its tail independently (which makes sense as it's the only thing Cofree[F, A] => B can do.
|
||||
*/
|
||||
def coflatMap[B](fa: Cofree[F, A] => B)(implicit ev: Functor[F]): Cofree[F, B] = {
|
||||
val b = fa(this)
|
||||
val fb = tail.map(_.coflatMap(fa))
|
||||
Cofree(b, fb)
|
||||
}
|
||||
}
|
||||
|
||||
// Anamorphism: Generalized unfold, builds structures
|
||||
def ana[F[_]: Functor, A](f: A => F[A])(a: A): Fix[F] =
|
||||
Fix( (f(a)).map(ana(f)) )
|
||||
|
||||
// Catamorphism: Generalized fold, tears structures down.
|
||||
def cata[F[_]: Functor, A](fa: F[A] => A)(f: Fix[F]): A = {
|
||||
fa(f.unfix.map(cata(fa)))
|
||||
}
|
||||
|
||||
// def hyloSimple[F[_] : Functor, A, B](f: F[B] => B)(g: A => F[A]): A => B
|
||||
def hylo[F[_]: Functor, A, B](f: F[B] => B)(g: A => F[A])(a: A): B =
|
||||
cata(f)(ana(g)(a))
|
||||
|
||||
// A more powerful cata
|
||||
def para[F[_]: Functor, A](f: F[(Fix[F], A)] => A)(fa: Fix[F]): A =
|
||||
f(fa.unfix.map(x => (x, para(f)(x))))
|
||||
|
||||
// A more powerful ana
|
||||
def apo[F[_]: Functor, A](f: A => F[Either[Fix[F], A]])(a: A): Fix[F] = {
|
||||
Fix(f(a).map{
|
||||
case Right(a) => apo(f)(a)
|
||||
case Left(fix) => fix
|
||||
})
|
||||
}
|
||||
|
||||
// When we have cofree
|
||||
def histo[F[_]: Functor, A](f: F[Cofree[F, A]] => A)(fix: Fix[F]): A = {
|
||||
def toCofree(fix: Fix[F]): Cofree[F, A] =
|
||||
Cofree(histo(f)(fix), fix.unfix.map(toCofree))
|
||||
|
||||
f(fix.unfix.map(toCofree))
|
||||
}
|
||||
|
||||
sealed trait StackR
|
||||
final case class DoneR(result: Int = 1) extends StackR
|
||||
final case class MoreR(stack: StackR, next: Int) extends StackR
|
||||
|
||||
def unfoldStackR(n: Int): StackR =
|
||||
if(n > 0) MoreR(unfoldStackR(n-1), n) else DoneR()
|
||||
|
||||
say(unfoldStackR(5))
|
||||
|
||||
sealed trait Stack[A]
|
||||
final case class Done[A](result: Int) extends Stack[A]
|
||||
final case class More[A](a: A, next: Int) extends Stack[A]
|
||||
|
||||
object Stack {
|
||||
implicit val stackFunctor: Functor[Stack] = new Functor[Stack] {
|
||||
def map[A, B](fa: Stack[A])(f: A => B): Stack[B] = fa match {
|
||||
case Done(result) => Done(result)
|
||||
case More(a, next) => More(f(a), next)
|
||||
}
|
||||
}
|
||||
|
||||
def done[A](result: Int = 1): Stack[A] = Done(result)
|
||||
def more[A](a: A, next: Int): Stack[A] = More(a, next)
|
||||
}
|
||||
|
||||
import Stack._
|
||||
|
||||
val stackCoalgebra: Int => Stack[Int] =
|
||||
n => if(n > 0) more(n - 1, n) else done()
|
||||
|
||||
say(ana(stackCoalgebra)(5))
|
||||
|
||||
val stackAlgebra: Stack[Int] => Int = {
|
||||
case Done(result) => result
|
||||
case More(acc, next) => acc * next
|
||||
}
|
||||
|
||||
say(cata(stackAlgebra)(ana(stackCoalgebra)(5)))
|
||||
say(hylo(stackAlgebra)(stackCoalgebra)(5))
|
||||
|
||||
|
||||
sealed trait Nat[A]
|
||||
final case class Zero[A]() extends Nat[A]
|
||||
final case class Succ[A](prev: A) extends Nat[A]
|
||||
|
||||
object Nat {
|
||||
implicit val natFunctor: Functor[Nat] = new Functor[Nat] {
|
||||
override def map[A, B](na: Nat[A])(f: A => B): Nat[B] =
|
||||
na match {
|
||||
case Zero() => Zero()
|
||||
case Succ(a) => Succ(f(a))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val natAlgebra: Nat[Int] => Int = {
|
||||
case Zero() => 1
|
||||
case Succ(n) => {
|
||||
say(s"nat alg succ $n")
|
||||
n + 1
|
||||
}
|
||||
}
|
||||
|
||||
val natAlgebraS: Nat[String] => String = {
|
||||
case Zero() => "N"
|
||||
case Succ(n) => n match {
|
||||
case "N" => "NI"
|
||||
case "NI" => "NIG"
|
||||
case "NIG" => "NIGG"
|
||||
case "NIGG" => "NIGGE"
|
||||
case "NIGGE" => "NIGGER :-"
|
||||
case s => s + "D"
|
||||
}
|
||||
}
|
||||
|
||||
val natCoalgebra: Int => Nat[Int] =
|
||||
n => if (n == 0) Zero() else Succ(n - 1)
|
||||
|
||||
val b = ana(natCoalgebra)(9)
|
||||
val c = cata(natAlgebraS)(b)
|
||||
say(c)
|
||||
|
||||
|
||||
val natAlgebraPara: Nat[(Fix[Nat], Int)] => Int = {
|
||||
case Zero() => 1
|
||||
case Succ((fix, acc)) => {
|
||||
say(s"nat para alg succ $fix, $acc")
|
||||
cata(natAlgebra)(fix) * acc
|
||||
}
|
||||
}
|
||||
|
||||
val build = ana(natCoalgebra)(_)
|
||||
say("built")
|
||||
val tear = para(natAlgebraPara)(_)
|
||||
say(tear(build(5)))
|
||||
// say(ana(natCoalgebra)(5))
|
||||
|
||||
val lastThreeSteps: Fix[Stack] = Fix(More(Fix(More(Fix(More(Fix(Done(1)),1)),2)),3))
|
||||
|
||||
val stackCoalgebraApo: Int => Stack[Either[Fix[Stack], Int]] =
|
||||
n => if(n > 3) more(n - 1, n).map(_.asRight) else lastThreeSteps.unfix.map(_.asLeft)
|
||||
}
|
||||
}
|
352
src/test/scala/RISCV/printUtils.scala
Normal file
352
src/test/scala/RISCV/printUtils.scala
Normal file
|
@ -0,0 +1,352 @@
|
|||
package FiveStage
|
||||
import cats.data.Writer
|
||||
import cats._
|
||||
import cats.data.{ Op => _ }
|
||||
import cats.implicits._
|
||||
|
||||
import fansi._
|
||||
|
||||
import Ops._
|
||||
import Data._
|
||||
import VM._
|
||||
import fileUtils._
|
||||
|
||||
object PrintUtils {
|
||||
|
||||
// Minimal typeclass def for being fancy
|
||||
trait Fancy[-A] { def s(a: A): fansi.Str }
|
||||
implicit class FancyOps[-A](a: A)(implicit ev: Fancy[A]){ def show: fansi.Str = ev.s(a) }
|
||||
implicit val DoubleFancy = new Fancy[fansi.Str]{ def s(a: fansi.Str) = a }
|
||||
implicit val FancyMonoid = new Monoid[fansi.Str] {
|
||||
def empty: fansi.Str = fansi.Str("")
|
||||
def combine(self: fansi.Str, that: fansi.Str): fansi.Str = self ++ that
|
||||
}
|
||||
|
||||
implicit class ExtraFancy(a: fansi.Str) {
|
||||
def leftPad(length: Int): fansi.Str = Str((0 until length).map(_ => ' ').mkString) ++ a
|
||||
def replace(from: Char, to: Char): fansi.Str = fansi.Str(a.toString.replace(from, to))
|
||||
def padTo(length: Int, pad: Char = ' '): fansi.Str = a ++ (0 until length - a.length).map(_ => pad).mkString
|
||||
def trim: fansi.Str = fansi.Str(a.toString.trim)
|
||||
}
|
||||
|
||||
implicit val RegFancy = new Fancy[Reg] { def s(r: Reg) = fansi.Str(regNames.canonicalName.lift(r.value).getOrElse("ERROR")) }
|
||||
implicit val ImmFancy = new Fancy[Imm] { def s(r: Imm) = Str(r.value.hs) }
|
||||
implicit val AddrFancy = new Fancy[Addr]{ def s(r: Addr) = Str(r.value.hs) }
|
||||
|
||||
implicit val ExecutionEventFancy = new Fancy[ExecutionEvent]{
|
||||
def s(a: ExecutionEvent): fansi.Str = a match {
|
||||
case RegUpdate(reg, word) => Str(s"R(${reg.show}) <- 0x${word.hs}")
|
||||
case MemWrite(addr, word) => fansi.Color.Blue(s"M[${addr.show}] <- 0x${word.hs}")
|
||||
case MemRead(addr, word) => fansi.Color.Red(f"M[${addr.show}] -> 0x${word.hs}")
|
||||
|
||||
// addr is the target address
|
||||
case PcUpdateJALR(addr) => fansi.Color.Green(s"PC updated to ${addr.show} via JALR")
|
||||
case PcUpdateJAL(addr) => fansi.Color.Magenta(s"PC updated to ${addr.show} via JAL")
|
||||
case PcUpdateB(addr) => fansi.Color.Yellow(s"PC updated to ${addr.show} via Branch")
|
||||
}
|
||||
}
|
||||
|
||||
implicit val ExecutionTraceEventFancy = new Fancy[ExecutionTraceEvent]{
|
||||
def s(a: ExecutionTraceEvent): fansi.Str = a.event.toList match {
|
||||
case (h: ExecutionEvent) :: (t: RegUpdate) :: Nil => t.show.padTo(25) ++ h.show
|
||||
case (h: MemWrite) :: t :: Nil => t.show.padTo(25) ++ h.show
|
||||
case (h: MemRead) :: t :: Nil => t.show.padTo(25) ++ h.show
|
||||
case (h: MemWrite) :: Nil => h.show.leftPad(25)
|
||||
case (h: MemRead) :: Nil => h.show.leftPad(25)
|
||||
case h :: t :: Nil => h.show ++ t.show
|
||||
case (h: RegUpdate) :: Nil => h.show
|
||||
case h :: Nil => h.show.leftPad(25)
|
||||
case _ => Str("")
|
||||
}
|
||||
}
|
||||
|
||||
implicit val ChiselEventFancy = new Fancy[ChiselEvent]{
|
||||
def s(e: ChiselEvent) = e match {
|
||||
case ChiselRegEvent(addr, reg, word) => fansi.Str(s"R(${reg.show}) <- ${word.hs}")
|
||||
case ChiselMemWriteEvent(addr, memAddr, word) => fansi.Str(s"M[${memAddr.show}] <- ${word.hs}")
|
||||
}
|
||||
}
|
||||
|
||||
implicit val RegsFancy = new Fancy[Regs]{
|
||||
def s(e: Regs) = {
|
||||
(0 to 9).map{ idx =>
|
||||
val cols = List.range(idx, 32, 10)
|
||||
cols.map{ reg =>
|
||||
(fansi.Color.Yellow(Reg(reg).show.padTo(5)) ++ Str(e.repr.lift(Reg(reg)).getOrElse(0).hs)).padTo(16)
|
||||
}.showN("| ")
|
||||
}.toList.showN("\n", "\n", "\n")
|
||||
}
|
||||
}
|
||||
|
||||
val UNKNOWN = "UNKNOWN"
|
||||
|
||||
def printInstruction(op: Ops.Op, labelMap: Map[Label, Addr]): fansi.Str = op match {
|
||||
case op: Branch => fansi.Color.Red(s"B${op.comp}\t${op.rs1.show}, ${op.rs2.show}, ${op.dst.show}\t[${labelMap.lift(op.dst).getOrElse(UNKNOWN)}]")
|
||||
case op: Arith => s"${op.op}\t${op.rd.show}, ${op.rs1.show}, ${op.rs2.show}"
|
||||
case op: ArithImm => s"${op.op}I\t${op.rd.show}, ${op.rs1.show}, ${op.imm.show}"
|
||||
case op: JALR => fansi.Color.Green(s"JALR\t${op.rd.show}, ${op.rs1.show}, ${op.dst.show}\t[${labelMap.lift(op.dst).getOrElse(UNKNOWN)}]")
|
||||
case op: JAL => fansi.Color.Magenta(s"JAL\t${op.rd.show}, ${op.dst.show} [${labelMap.lift(op.dst).getOrElse(UNKNOWN)}]")
|
||||
case op: LW => s"LW\t${op.rd.show}, ${op.offset.show}(${op.rs1.show})"
|
||||
case op: SW => s"SW\t${op.rs2.show}, ${op.offset.show}(${op.rs1.show})"
|
||||
case op: LUI => s"LUI\t${op.rd.show}, ${op.imm.show}"
|
||||
case op: AUIPC => s"AUIPC\t${op.rd.show}, ${op.imm.show}"
|
||||
case DONE => s"DONE"
|
||||
}
|
||||
|
||||
|
||||
implicit class IntPrinters(i: Int) {
|
||||
def hs: String = if(i > 65535) f"0x$i%08X" else f"0x$i%04X"
|
||||
def binary: String = String.format("%" + 32 + "s", i.toBinaryString)
|
||||
.replace(' ', '0').grouped(4)
|
||||
.map(x => x + " ").mkString
|
||||
}
|
||||
|
||||
|
||||
|
||||
def printProgram(vm: VM): String = {
|
||||
val withLabels: List[Either[(Addr, Op), (Label, Addr)]] = (vm.imem.toList.map(Left(_)) ::: vm.labelMap.toList.map(Right(_)))
|
||||
.sortBy { case Left(x) => x._1.value.toDouble + 0.1; case Right(x) => x._2.value.toDouble }
|
||||
|
||||
withLabels.map{
|
||||
case Left((addr, op)) => s"$addr:\t\t${printInstruction(op, vm.labelMap)}"
|
||||
case Right((label, addr)) => s"$addr:\t$label:"
|
||||
}.mkString("\n","\n","\n")
|
||||
}
|
||||
|
||||
|
||||
def printProgram(p: Program): String = printProgram(p.vm)
|
||||
|
||||
|
||||
def printBinary(bin: Map[Addr, Int]): String = {
|
||||
bin.toList.sortBy(_._1.value).map{ case(addr, op) => s"$addr: ${op.hs}" }.mkString("\n","\n","\n")
|
||||
}
|
||||
|
||||
|
||||
def printChiselLogEntry(event: (Addr, List[ChiselEvent])): fansi.Str = {
|
||||
val (addr, log) = event
|
||||
val events = log match {
|
||||
case (h: ChiselRegEvent) :: (t: ChiselMemWriteEvent) :: Nil => h.show.padTo(25, ' ') ++ t.show
|
||||
case (h: ChiselMemWriteEvent) :: Nil => h.show.leftPad(25)
|
||||
case (h: ChiselRegEvent) :: Nil => h.show
|
||||
case _ => fansi.Str("")
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
|
||||
def printVMtrace(trace: List[ExecutionTraceEvent], program: Program): String = {
|
||||
val blocks: List[List[(ExecutionTraceEvent, Int)]] = LogParser.splitToBlocks(trace).zipWithIndexNested
|
||||
blocks.map{ block =>
|
||||
val name = LogParser.guessBlockName(block.map(_._1.pc), program.labelMapReverse)
|
||||
val blockString = block.map{ case(event, idx) =>
|
||||
Str(s"Step: $idx,").padTo(12) ++
|
||||
Str("PC: ") ++
|
||||
event.pc.show ++
|
||||
Str("\t") ++
|
||||
event.show.padTo(70) ++
|
||||
printSourceLine(event.pc, program)
|
||||
}
|
||||
fansi.Color.Yellow(name) ++ Str("\n") ++ blockString.showN("\n")
|
||||
}.mkStringN
|
||||
}
|
||||
|
||||
def printSourceLine(addr: Addr, program: Program): fansi.Str = program.sourceMap.lift(addr).map(fansi.Str(_)).getOrElse(fansi.Str("???"))
|
||||
|
||||
def printMergedTraces(
|
||||
mt: (List[ExecutionTraceEvent], List[CircuitTrace]),
|
||||
program: Program
|
||||
): List[String] = {
|
||||
|
||||
|
||||
/**
|
||||
* For branch predicting processors we may end up with a spurious block causing a transient
|
||||
* desynchronization. Therefore it is necessary to have a certain tolerance before calling a divergence.
|
||||
*/
|
||||
// TODO: Implement a synchronization test to pinpoint where a desync happens
|
||||
// This is not straight forward in the case of processors which perform branch prediction.
|
||||
def isSynchronized(desyncs: Int, traces: (List[ExecutionTraceEvent], List[CircuitTrace]) ): Boolean = ???
|
||||
|
||||
|
||||
def helper(mt: (List[ExecutionTraceEvent], List[CircuitTrace])): List[List[fansi.Str]] = mt match {
|
||||
/**
|
||||
* VM trace and execution log synchronized, step both
|
||||
*/
|
||||
case (hVM :: tVM, hC :: tC) if (hVM.pc == hC._1) => {
|
||||
val address = hVM.pc
|
||||
val chiselLogEntry = printChiselLogEntry(hC)
|
||||
val vmEntry = hVM.show
|
||||
val sourceLine = printSourceLine(address, program)
|
||||
|
||||
val line = List(address.show, chiselLogEntry, vmEntry, sourceLine)
|
||||
|
||||
line :: helper((tVM, tC))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* VM trace and execution log unsynchronized, step only chisel trace
|
||||
* Helper is called with (hVM :: tVM) to only step the chisel log.
|
||||
*/
|
||||
case (hVM :: tVM, hC :: tC) => {
|
||||
val address = hC._1
|
||||
val chiselLogEntry = printChiselLogEntry(hC)
|
||||
val vmEntry = Str("")
|
||||
val sourceLine = printSourceLine(address, program)
|
||||
|
||||
val line = List(address.show, chiselLogEntry, vmEntry, sourceLine)
|
||||
|
||||
line :: helper((hVM :: tVM, tC))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The Block contains no more instructions performed by the VM. This
|
||||
* happens naturally since 5-stage pipelines will fetch spurious instructions.
|
||||
*/
|
||||
case (Nil, hC :: tC) => {
|
||||
val address = hC._1
|
||||
val chiselLogEntry = printChiselLogEntry(hC)
|
||||
val vmEntry = fansi.Str("")
|
||||
val sourceLine = printSourceLine(address, program)
|
||||
|
||||
val line = List(fansi.Color.LightBlue(address.show), chiselLogEntry, vmEntry, sourceLine)
|
||||
|
||||
line :: helper((Nil, tC))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The Block contains no more instructions performed by the circuit.
|
||||
* This happens when the circuit takes a jump the VM does not.
|
||||
* This is an error *unless* the circuit has a branch predictor.
|
||||
*
|
||||
* If you want to you can splice the logs when this happens, but it's typically easy to spot.
|
||||
*/
|
||||
case (hVM :: tVM, Nil) => {
|
||||
val address = hVM.pc
|
||||
val chiselLogEntry = fansi.Str("")
|
||||
val vmEntry = hVM.show
|
||||
val sourceLine = printSourceLine(address, program)
|
||||
|
||||
val line = List(fansi.Color.LightRed(address.show), chiselLogEntry, vmEntry, sourceLine)
|
||||
|
||||
line :: helper((tVM, Nil))
|
||||
}
|
||||
|
||||
case (Nil, Nil) => Nil
|
||||
}
|
||||
|
||||
|
||||
def format(triplet: List[fansi.Str]): String = {
|
||||
// Ahh, the GNU toolchain and its tabs
|
||||
val annoyingTabCharacter = ' '
|
||||
triplet match {
|
||||
case address :: ch :: vm :: source :: Nil => {
|
||||
val vmLine: fansi.Str = vm.padTo(60, ' ')
|
||||
val chiselLine: fansi.Str = ch.padTo(50, ' ')
|
||||
val sourceLines: fansi.Str = source
|
||||
((address ++ Str(":")).padTo(14, ' ') ++ vmLine ++ fansi.Str("| ") ++ chiselLine ++ Str("| ") ++ sourceLines).toString
|
||||
}
|
||||
case _ => ""
|
||||
}
|
||||
}
|
||||
|
||||
val blockName = LogParser.guessBlockName(mt._1.map(_.pc), program.labelMapReverse)
|
||||
|
||||
(fansi.Color.Yellow(s"$blockName").padTo(74, ' ').toString ++ "|".padTo(55, ' ') ++ "|") :: helper(mt).map(format)
|
||||
}
|
||||
|
||||
|
||||
def printChiselError(e: Throwable): String = {
|
||||
val rawError = """
|
||||
|This typically occurs when you forget to wrap a module
|
||||
|e.g
|
||||
|
|
||||
|class MyBundle extends Bundle {
|
||||
| val signal = UInt(32.W)
|
||||
|}
|
||||
|val mySignal = new MyBundle
|
||||
| ^^^^ Wrong!
|
||||
|should be
|
||||
|val mySignal = Wire(new MyBundle)
|
||||
""".stripMargin
|
||||
|
||||
def getFiveStageStacktrace(strace: Array[StackTraceElement]): String =
|
||||
strace.map(_.toString).filter(_.contains("FiveStage")).toList.take(5).mkStringN
|
||||
|
||||
e match {
|
||||
case e: firrtl.passes.CheckInitialization.RefNotInitializedException => {
|
||||
s"""
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|Your design has unconnected wires!"
|
||||
|error:\n"
|
||||
|${e.getMessage}
|
||||
|
|
||||
|
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
""".stripMargin
|
||||
}
|
||||
case e: chisel3.core.Binding.ExpectedHardwareException => {
|
||||
s"""
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|Your design is using raw chisel types!
|
||||
|error:\n
|
||||
|${e.getMessage}
|
||||
|
|
||||
|$rawError
|
||||
|The error should be here somewhere:
|
||||
|${getFiveStageStacktrace(e.getStackTrace)}
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
""".stripMargin
|
||||
}
|
||||
case e: firrtl.passes.PassExceptions => {
|
||||
val rawErrorMsg = if(e.getMessage.contains("raw"))
|
||||
s"One of the errors was use of raw chisel types. $rawError"
|
||||
else
|
||||
""
|
||||
|
||||
s"""
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|Your design has multiple errors!
|
||||
|error:
|
||||
|${e.getMessage}
|
||||
|$rawErrorMsg
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
""".stripMargin
|
||||
}
|
||||
case e: Exception => {
|
||||
s"""
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|Unexpected Chisel tester error (could be a chisel error I havent accounted for, or a bug in the tester like index out of bounds.)
|
||||
|error:
|
||||
|${e.getMessage}
|
||||
|reduced stacktrace:
|
||||
|${getFiveStageStacktrace(e.getStackTrace)}
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
|##########################################################
|
||||
""".stripMargin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def printLogSideBySide(trace: List[ExecutionTraceEvent], chiselTrace: List[CircuitTrace], program: Program): String = {
|
||||
import LogParser._
|
||||
val traces = mergeTraces(trace, chiselTrace).map(x => printMergedTraces((x), program))
|
||||
traces.map(_.mkString("\n")).mkString("\n", "\n--------------------------------------------------------------------------+------------------------------------------------------+-------------------------------\n", "\n")
|
||||
}
|
||||
}
|
114
src/test/scala/RISCV/regNames.scala
Normal file
114
src/test/scala/RISCV/regNames.scala
Normal file
|
@ -0,0 +1,114 @@
|
|||
package FiveStage
|
||||
object regNames {
|
||||
val x0 = 0
|
||||
val x1 = 1
|
||||
val x2 = 2
|
||||
val x3 = 3
|
||||
val x4 = 4
|
||||
val x5 = 5
|
||||
val x6 = 6
|
||||
val x7 = 7
|
||||
val x8 = 8
|
||||
val x9 = 9
|
||||
|
||||
val x10 = 10
|
||||
val x11 = 11
|
||||
val x12 = 12
|
||||
val x13 = 13
|
||||
val x14 = 14
|
||||
val x15 = 15
|
||||
val x16 = 16
|
||||
val x17 = 17
|
||||
val x18 = 18
|
||||
val x19 = 19
|
||||
|
||||
val x20 = 20
|
||||
val x21 = 21
|
||||
val x22 = 22
|
||||
val x23 = 23
|
||||
val x24 = 24
|
||||
val x25 = 25
|
||||
val x26 = 26
|
||||
val x27 = 27
|
||||
val x28 = 28
|
||||
val x29 = 29
|
||||
|
||||
val x30 = 30
|
||||
val x31 = 31
|
||||
|
||||
|
||||
val zero = 0
|
||||
val ra = 1
|
||||
val sp = 2
|
||||
val gp = 3
|
||||
val tp = 4
|
||||
val t0 = 5
|
||||
val t1 = 6
|
||||
val t2 = 7
|
||||
val s0 = 8
|
||||
val fp = 8
|
||||
val s1 = 9
|
||||
|
||||
val a0 = 10
|
||||
val a1 = 11
|
||||
val a2 = 12
|
||||
val a3 = 13
|
||||
val a4 = 14
|
||||
val a5 = 15
|
||||
val a6 = 16
|
||||
val a7 = 17
|
||||
val s2 = 18
|
||||
val s3 = 19
|
||||
|
||||
val s4 = 20
|
||||
val s5 = 21
|
||||
val s6 = 22
|
||||
val s7 = 23
|
||||
val s8 = 24
|
||||
val s9 = 25
|
||||
val s10 = 26
|
||||
val s11 = 27
|
||||
val t3 = 28
|
||||
val t4 = 29
|
||||
|
||||
val t5 = 30
|
||||
val t6 = 31
|
||||
|
||||
val canonicalName = Map(
|
||||
0 -> "zero",
|
||||
1 -> "ra",
|
||||
2 -> "sp",
|
||||
3 -> "gp",
|
||||
4 -> "tp",
|
||||
5 -> "t0",
|
||||
6 -> "t1",
|
||||
7 -> "t2",
|
||||
8 -> "s0",
|
||||
8 -> "fp",
|
||||
9 -> "s1",
|
||||
10 -> "a0",
|
||||
11 -> "a1",
|
||||
12 -> "a2",
|
||||
13 -> "a3",
|
||||
14 -> "a4",
|
||||
15 -> "a5",
|
||||
16 -> "a6",
|
||||
17 -> "a7",
|
||||
18 -> "s2",
|
||||
19 -> "s3",
|
||||
20 -> "s4",
|
||||
21 -> "s5",
|
||||
22 -> "s6",
|
||||
23 -> "s7",
|
||||
24 -> "s8",
|
||||
25 -> "s9",
|
||||
26 -> "s10",
|
||||
27 -> "s11",
|
||||
28 -> "t3",
|
||||
29 -> "t4",
|
||||
30 -> "t5",
|
||||
31 -> "t6",
|
||||
)
|
||||
|
||||
}
|
||||
|
103
src/test/scala/RISCV/testRunner.scala
Normal file
103
src/test/scala/RISCV/testRunner.scala
Normal file
|
@ -0,0 +1,103 @@
|
|||
package FiveStage
|
||||
import org.scalatest.{Matchers, FlatSpec}
|
||||
import cats._
|
||||
import cats.implicits._
|
||||
import fileUtils._
|
||||
|
||||
import chisel3.iotesters._
|
||||
import scala.collection.mutable.LinkedHashMap
|
||||
|
||||
import fansi.Str
|
||||
|
||||
import Ops._
|
||||
import Data._
|
||||
import VM._
|
||||
|
||||
import PrintUtils._
|
||||
import LogParser._
|
||||
|
||||
case class TestOptions(
|
||||
printIfSuccessful : Boolean,
|
||||
printErrors : Boolean,
|
||||
printParsedProgram : Boolean,
|
||||
printVMtrace : Boolean,
|
||||
printVMfinal : Boolean,
|
||||
printMergedTrace : Boolean,
|
||||
nopPadded : Boolean,
|
||||
breakPoints : List[Int], // Not implemented
|
||||
testName : String
|
||||
)
|
||||
|
||||
case class TestResult(
|
||||
regError : Option[String],
|
||||
memError : Option[String],
|
||||
program : String,
|
||||
vmTrace : String,
|
||||
vmFinal : String,
|
||||
sideBySide : String
|
||||
)
|
||||
|
||||
object TestRunner {
|
||||
|
||||
def run(testOptions: TestOptions): Boolean = {
|
||||
|
||||
val testResults = for {
|
||||
lines <- fileUtils.readTest(testOptions)
|
||||
program <- FiveStage.Parser.parseProgram(lines, testOptions)
|
||||
(binary, (trace, finalVM)) <- program.validate.map(x => (x._1, x._2.run))
|
||||
(termitationCause, chiselTrace) <- ChiselTestRunner(
|
||||
binary.toList.sortBy(_._1.value).map(_._2),
|
||||
program.settings,
|
||||
finalVM.pc,
|
||||
1500)
|
||||
} yield {
|
||||
val traces = mergeTraces(trace, chiselTrace).map(x => printMergedTraces((x), program))
|
||||
|
||||
val programString = printProgram(program)
|
||||
val vmTraceString = printVMtrace(trace, program)
|
||||
val vmFinalState = finalVM.regs.show
|
||||
val traceString = printLogSideBySide(trace, chiselTrace, program)
|
||||
|
||||
val regError = compareRegs(trace, chiselTrace)
|
||||
val memError = compareMem(trace, chiselTrace)
|
||||
|
||||
TestResult(
|
||||
regError,
|
||||
memError,
|
||||
programString,
|
||||
vmTraceString,
|
||||
vmFinalState.toString,
|
||||
traceString)
|
||||
}
|
||||
|
||||
testResults.left.foreach{ error =>
|
||||
say(s"Test was unable to run due to error: $error")
|
||||
}
|
||||
|
||||
testResults.map{ testResults =>
|
||||
val successful = List(testResults.regError, testResults.memError).flatten.headOption.map(_ => false).getOrElse(true)
|
||||
if(successful)
|
||||
say(s"${testOptions.testName} succesful")
|
||||
else
|
||||
say(s"${testOptions.testName} failed")
|
||||
|
||||
if(testOptions.printIfSuccessful && successful){
|
||||
if(testOptions.printParsedProgram) say(testResults.program)
|
||||
if(testOptions.printVMtrace) say(testResults.vmTrace)
|
||||
if(testOptions.printVMfinal) say(testResults.vmFinal)
|
||||
if(testOptions.printMergedTrace) say(testResults.sideBySide)
|
||||
}
|
||||
else{
|
||||
if(testOptions.printErrors){
|
||||
say(testResults.regError.map(_.show.toString).getOrElse("no reg errors"))
|
||||
say(testResults.memError.map(_.show.toString).getOrElse("no mem errors"))
|
||||
}
|
||||
if(testOptions.printParsedProgram) say(testResults.program)
|
||||
if(testOptions.printVMtrace) say(testResults.vmTrace)
|
||||
if(testOptions.printVMfinal) say(testResults.vmFinal)
|
||||
if(testOptions.printMergedTrace) say(testResults.sideBySide)
|
||||
}
|
||||
successful
|
||||
}.toOption.getOrElse(false)
|
||||
}
|
||||
}
|
166
src/test/scala/TestUtils.scala
Normal file
166
src/test/scala/TestUtils.scala
Normal file
|
@ -0,0 +1,166 @@
|
|||
package FiveStage
|
||||
|
||||
import fileUtils._
|
||||
import Data._
|
||||
import PrintUtils._
|
||||
|
||||
object TestUtils {
|
||||
|
||||
/**
|
||||
* Generate and serialize BTrees for the test runner
|
||||
*/
|
||||
def generateBTree: Unit = {
|
||||
|
||||
import cats._
|
||||
import cats.implicits._
|
||||
|
||||
case class AnnotatedNode(value: Int, index: Int, left: Option[AnnotatedNode], right: Option[AnnotatedNode]){
|
||||
def find(key: Int): Unit = {
|
||||
say(s"at $index (${(4 + (index << 2)).hs})-> ${value.hs}, looking for ${key.hs}")
|
||||
if(value == key)
|
||||
say("found it")
|
||||
else if(key < value)
|
||||
left.map{x => say("going left\n"); x.find(key)}.getOrElse("gave up")
|
||||
else
|
||||
right.map{x => say("going right\n"); x.find(key)}.getOrElse("gave up")
|
||||
}
|
||||
}
|
||||
|
||||
def printAnnoTree(tree: AnnotatedNode, depth: Int): String = {
|
||||
val ls = tree.left.map(n => printAnnoTree(n, depth + 2)).getOrElse("left empty")
|
||||
val rs = tree.right.map(n => printAnnoTree(n, depth + 2)).getOrElse("right empty")
|
||||
val pads = "|".padTo(2, ' ')*depth
|
||||
s"${tree.value.hs} at ${tree.index.hs}\n$pads$ls\n$pads$rs"
|
||||
}
|
||||
|
||||
case class Node(value: Int, left: Option[Node], right: Option[Node]){
|
||||
def append(v: Int): Node = if(v < value)
|
||||
copy(left = left.map(_.append(v)).orElse(Some(Node(v))))
|
||||
else
|
||||
copy(right = right.map(_.append(v)).orElse(Some(Node(v))))
|
||||
}
|
||||
|
||||
object Node {
|
||||
def apply(v: Int): Node = Node(v, None, None)
|
||||
}
|
||||
|
||||
def annotate(n: Int, root: Node): (AnnotatedNode, Int) = {
|
||||
(root.left, root.right) match {
|
||||
case (None, None) => {
|
||||
(AnnotatedNode(root.value, n, None, None), n + 1)
|
||||
}
|
||||
case (Some(node), None) => {
|
||||
val (annotated, next) = annotate(n+1, node)
|
||||
(AnnotatedNode(root.value, n, Some(annotated), None), next)
|
||||
}
|
||||
case (None, Some(node)) => {
|
||||
val (annotated, next) = annotate(n+1, node)
|
||||
(AnnotatedNode(root.value, n, None, Some(annotated)), next)
|
||||
}
|
||||
case (Some(left), Some(right)) => {
|
||||
val (leftAnno, leftNext) = annotate(n+1, left)
|
||||
val (rightAnno, rightNext) = annotate(leftNext, right)
|
||||
(AnnotatedNode(root.value, n, Some(leftAnno), Some(rightAnno)), rightNext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def foldAnno(root: Option[AnnotatedNode]): List[Int] = {
|
||||
root.map{ root =>
|
||||
val leftIndex = root.left.map(_.index).getOrElse(0)
|
||||
val hasLeft = root.left.map(_ => 1).getOrElse(0)
|
||||
|
||||
val rightIndex = root.right.map(_.index).getOrElse(0)
|
||||
val hasRight = root.right.map(_ => 1).getOrElse(0)
|
||||
|
||||
val entry = hasLeft + (leftIndex << 1) + (hasRight << 8) + (rightIndex << 9) + (root.value << 16)
|
||||
|
||||
say(s"with leftIndex: ${leftIndex.hs}, rightIndex: ${rightIndex.hs}, value: ${root.value.hs} we got ${entry.hs}")
|
||||
|
||||
entry :: foldAnno(root.left) ::: foldAnno(root.right)
|
||||
}.getOrElse(Nil)
|
||||
}
|
||||
|
||||
import scala.util.Random
|
||||
val r = new scala.util.Random(0xF01D1EF7)
|
||||
def randInt = r.nextInt(1000)
|
||||
|
||||
val seed = (0 to 100).map(_ => randInt).toList
|
||||
val btree = seed.foldLeft(Node(randInt, None, None)){ case(acc, n) => acc.append(n)}
|
||||
|
||||
val annoTree = annotate(0, btree)
|
||||
say(foldAnno(Some(annoTree._1)).zipWithIndex.map{case(m, idx) => s"#memset ${(4 + (idx*4)).hs}, ${m.hs}"}.mkStringN)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a random program filled with hazards
|
||||
*/
|
||||
def generateHazardsForward(steps: Int) : Unit = {
|
||||
|
||||
// val r = new scala.util.Random(0xF01D1EF7)
|
||||
val r = new scala.util.Random(0xF01D1EF8)
|
||||
import Ops._
|
||||
|
||||
val active = List(1, 2, 3)
|
||||
|
||||
val initVM = {
|
||||
val init = VM.init
|
||||
val init1 = init.copy(regs = (init.regs + (Reg(1) -> 123))._2)
|
||||
val init2 = init.copy(regs = (init1.regs + (Reg(2) -> -40))._2)
|
||||
val init3 = init.copy(regs = (init2.regs + (Reg(3) -> 0xFFEE))._2)
|
||||
init3
|
||||
}
|
||||
|
||||
|
||||
def generateInstruction: (Int, (String, Op)) = {
|
||||
val rd = active.shuffle(r).head
|
||||
val rs1 = active.shuffle(r).head
|
||||
val rs2 = active.shuffle(r).head
|
||||
val imm = r.nextInt(1024) - 512
|
||||
val shift = r.nextInt(32) - 16
|
||||
|
||||
val choices = List(
|
||||
(s"add ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.add(rd, rs1, rs2)),
|
||||
(s"sub ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sub(rd, rs1, rs2)),
|
||||
(s"or ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.or(rd, rs1, rs2)),
|
||||
(s"xor ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.xor(rd, rs1, rs2)),
|
||||
(s"and ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.and(rd, rs1, rs2)),
|
||||
(s"sll ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sll(rd, rs1, rs2)),
|
||||
(s"srl ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.srl(rd, rs1, rs2)),
|
||||
(s"sra ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sra(rd, rs1, rs2)),
|
||||
(s"slt ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.slt(rd, rs1, rs2)),
|
||||
(s"sltu ${Reg(rd).show}, ${Reg(rs1).show}, ${Reg(rs2).show}", Arith.sltu(rd, rs1, rs2)),
|
||||
|
||||
(s"addi ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.add(rd, rs1, imm)),
|
||||
(s"ori ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.or(rd, rs1, imm)),
|
||||
(s"xori ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.xor(rd, rs1, imm)),
|
||||
(s"andi ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.and(rd, rs1, imm)),
|
||||
(s"slli ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(shift).show}", ArithImm.sll(rd, rs1, shift)),
|
||||
(s"srli ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(shift).show}", ArithImm.srl(rd, rs1, shift)),
|
||||
(s"srai ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(shift).show}", ArithImm.sra(rd, rs1, shift)),
|
||||
(s"slti ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.slt(rd, rs1, imm)),
|
||||
(s"sltiu ${Reg(rd).show}, ${Reg(rs1).show}, ${Imm(imm).show}", ArithImm.sltu(rd, rs1, imm)))
|
||||
(rd, choices.shuffle(r).head)
|
||||
}
|
||||
|
||||
def helper(attempts: Int, steps: Int, vm: VM): Unit = {
|
||||
if((attempts > 10) || (steps == 0))
|
||||
()
|
||||
else{
|
||||
val (nextRd, (nS, nextOp)) = generateInstruction
|
||||
val withOp = vm.copy(imem = vm.imem + (vm.pc -> nextOp))
|
||||
val nextVmE = withOp.stepInstruction
|
||||
val nextVm = nextVmE.toOption.get.run._2
|
||||
if(nextVm.regs.repr(Reg(nextRd)) == 0)
|
||||
helper(attempts + 1, steps, vm)
|
||||
else {
|
||||
say(nS)
|
||||
helper(0, steps - 1, nextVm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
helper(0, steps, initVM)
|
||||
}
|
||||
}
|
188
src/test/scala/chiselTestRunner.scala
Normal file
188
src/test/scala/chiselTestRunner.scala
Normal file
|
@ -0,0 +1,188 @@
|
|||
package FiveStage
|
||||
import chisel3.iotesters._
|
||||
import scala.collection.mutable.LinkedHashMap
|
||||
|
||||
import fileUtils.say
|
||||
|
||||
import Data._
|
||||
import PrintUtils._
|
||||
|
||||
private class ChiselTestRunner (
|
||||
instructions : List[Int],
|
||||
settings : List[TestSetting],
|
||||
c : Tile,
|
||||
d : PeekPokeTester[Tile],
|
||||
terminalAddress : Addr,
|
||||
maxSteps : Int) {
|
||||
|
||||
|
||||
/**
|
||||
* Currently unused as it is quite nontrivial to figure out whether read data is actually used.
|
||||
* Still, with the necessary scaffolding these can be correlated with reg writes to figure out
|
||||
* if they are valid or not.
|
||||
*/
|
||||
case class ChiselMemReadEvent(pcAddr: Addr, memAddr: Addr, word: Int)
|
||||
|
||||
private def setup = {
|
||||
|
||||
d.poke(d.dut.io.setup, 1)
|
||||
|
||||
val initDMem = DMem(settings).repr.toList
|
||||
val initRegs = Regs(settings).repr.toList
|
||||
|
||||
setupImem(instructions)
|
||||
setupRegs(initRegs)
|
||||
setupDmem(initDMem)
|
||||
|
||||
// flush
|
||||
d.step(1)
|
||||
disableTestSignals
|
||||
d.step(5)
|
||||
d.poke(d.dut.io.setup, 0)
|
||||
|
||||
def disableTestSignals: Unit = {
|
||||
d.poke(d.dut.io.DMEMWriteData, 0)
|
||||
d.poke(d.dut.io.DMEMAddress, 0)
|
||||
d.poke(d.dut.io.DMEMWriteEnable, 0)
|
||||
d.poke(d.dut.io.regsWriteData, 0)
|
||||
d.poke(d.dut.io.regsAddress, 0)
|
||||
d.poke(d.dut.io.regsWriteEnable, 0)
|
||||
d.poke(d.dut.io.IMEMWriteData, 0)
|
||||
d.poke(d.dut.io.IMEMAddress, 4092)
|
||||
}
|
||||
|
||||
def setupRegs(regs: List[(Reg, Int)]) = {
|
||||
regs.foreach{ case(reg, word) =>
|
||||
d.poke(d.dut.io.setup, 1)
|
||||
d.poke(d.dut.io.regsWriteEnable, 1)
|
||||
d.poke(d.dut.io.regsWriteData, BigInt(word))
|
||||
d.poke(d.dut.io.regsAddress, reg.value)
|
||||
d.step(1)
|
||||
}
|
||||
d.poke(d.dut.io.regsWriteEnable, 0)
|
||||
d.poke(d.dut.io.regsWriteData, 0)
|
||||
d.poke(d.dut.io.regsAddress, 0)
|
||||
}
|
||||
|
||||
def setupDmem(mem: List[(Addr, Int)]) = {
|
||||
mem.foreach { case (addr, word) =>
|
||||
d.poke(d.dut.io.setup, 1)
|
||||
d.poke(d.dut.io.DMEMWriteEnable, 1)
|
||||
d.poke(d.dut.io.DMEMWriteData, word)
|
||||
d.poke(d.dut.io.DMEMAddress, addr.value)
|
||||
d.step(1)
|
||||
}
|
||||
d.poke(d.dut.io.DMEMWriteEnable, 0)
|
||||
d.poke(d.dut.io.DMEMWriteData, 0)
|
||||
d.poke(d.dut.io.DMEMAddress, 0)
|
||||
|
||||
}
|
||||
|
||||
def setupImem(instructions: List[Int]) = {
|
||||
(0 until instructions.length).foreach{ ii =>
|
||||
d.poke(d.dut.io.IMEMAddress, ii*4)
|
||||
d.poke(d.dut.io.IMEMWriteData, instructions(ii).toInt)
|
||||
d.step(1)
|
||||
}
|
||||
d.poke(d.dut.io.IMEMAddress, 4092) // Ensures that we don't overwrite an instruction. Bandaid for lack of IMEM.writeEnable
|
||||
d.poke(d.dut.io.IMEMWriteData, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private def getPC = Addr(d.peek(d.dut.io.currentPC).toInt)
|
||||
private def getDMemWriteAddress = Addr(d.peek(d.dut.io.memDeviceWriteAddress).toInt)
|
||||
private def getRegWriteAddress = Reg(d.peek(d.dut.io.regsDeviceWriteAddress).toInt)
|
||||
|
||||
private def getRegUpdate: Option[ChiselRegEvent] = {
|
||||
if(
|
||||
(d.peek(d.dut.io.regsDeviceWriteEnable) == 1) &&
|
||||
(getRegWriteAddress.value != 0)
|
||||
){
|
||||
val regWriteAddress = getRegWriteAddress
|
||||
val regWriteData = d.peek(d.dut.io.regsDeviceWriteData).toInt
|
||||
val regUpdate = ChiselRegEvent(getPC, regWriteAddress, regWriteData)
|
||||
Some(regUpdate)
|
||||
}
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
private def getMemWrite: Option[ChiselMemWriteEvent] = {
|
||||
if(d.peek(d.dut.io.memDeviceWriteEnable) == 1) {
|
||||
val memWriteAddress = getDMemWriteAddress
|
||||
val memWriteData = d.peek(d.dut.io.memDeviceWriteData).toInt
|
||||
val memUpdate = ChiselMemWriteEvent(getPC, memWriteAddress, memWriteData)
|
||||
Some(memUpdate)
|
||||
}
|
||||
else
|
||||
None
|
||||
}
|
||||
|
||||
private def stepOne: CircuitTrace = {
|
||||
val state = (getPC, List(getRegUpdate, getMemWrite).flatten)
|
||||
// say(d.peek(d.dut.io).toList.mkStringN)
|
||||
d.step(1)
|
||||
state
|
||||
}
|
||||
|
||||
|
||||
private def go(log: List[CircuitTrace], timeOut: Int): (Option[String], List[CircuitTrace]) = {
|
||||
if(timeOut == 0){
|
||||
(Some("Chisel tester timed out before reaching termination address"), log.reverse)
|
||||
}
|
||||
else if(getPC == terminalAddress){
|
||||
(None, (flush ::: log).reverse)
|
||||
}
|
||||
else {
|
||||
val step = stepOne
|
||||
go(step :: log, timeOut - 1)
|
||||
}
|
||||
}
|
||||
|
||||
// After finishing, let the circuit run until all updates can be committed.
|
||||
private def flush: List[CircuitTrace] =
|
||||
(0 to 3).map(_ => stepOne).reverse.toList
|
||||
|
||||
/**
|
||||
* Run the entire shebang
|
||||
*/
|
||||
def run: (Option[String], List[CircuitTrace]) = {
|
||||
setup
|
||||
go(Nil, maxSteps)
|
||||
}
|
||||
}
|
||||
|
||||
object ChiselTestRunner {
|
||||
|
||||
def apply(
|
||||
binary : List[Int],
|
||||
settings : List[TestSetting],
|
||||
terminalAddress : Addr,
|
||||
maxSteps : Int): Either[String, (Option[String], List[CircuitTrace])] = {
|
||||
|
||||
var sideEffectExtravaganza: Option[(Option[String], List[CircuitTrace])] = None
|
||||
|
||||
val error: Either[String, Boolean] = scala.util.Try {
|
||||
chisel3.iotesters.Driver(() => new Tile(), "treadle") { c =>
|
||||
new PeekPokeTester(c) {
|
||||
val testRunner = new ChiselTestRunner(
|
||||
binary,
|
||||
settings,
|
||||
c,
|
||||
this,
|
||||
terminalAddress,
|
||||
maxSteps
|
||||
)
|
||||
|
||||
val log = testRunner.run
|
||||
sideEffectExtravaganza = Some(log)
|
||||
}
|
||||
}
|
||||
}.toEither.left.map{printChiselError}
|
||||
|
||||
error.flatMap{ e =>
|
||||
sideEffectExtravaganza.toRight("Unknown test failure, please let me know")
|
||||
}
|
||||
}
|
||||
}
|
94
src/test/scala/fileUtils.scala
Normal file
94
src/test/scala/fileUtils.scala
Normal file
|
@ -0,0 +1,94 @@
|
|||
package FiveStage
|
||||
import chisel3.iotesters._
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import scala.collection.mutable.LinkedHashMap
|
||||
// import cats.effect.ContextShift
|
||||
|
||||
import cats.implicits._
|
||||
import cats._
|
||||
import cats.syntax._
|
||||
import cats.Applicative._
|
||||
import atto._, Atto._
|
||||
|
||||
object fileUtils {
|
||||
|
||||
def say(word: Any)(implicit filename: sourcecode.File, line: sourcecode.Line): Unit = {
|
||||
val fname = filename.value.split("/").last
|
||||
println(Console.YELLOW + s"[${fname}: ${sourcecode.Line()}]" + Console.RESET + s" - $word")
|
||||
}
|
||||
|
||||
def sayRed(word: Any)(implicit filename: sourcecode.File, line: sourcecode.Line): Unit = {
|
||||
val fname = filename.value.split("/").last
|
||||
println(Console.YELLOW + s"[${fname}: ${sourcecode.Line()}]" + Console.RED + s" - $word")
|
||||
}
|
||||
def sayGreen(word: Any)(implicit filename: sourcecode.File, line: sourcecode.Line): Unit = {
|
||||
val fname = filename.value.split("/").last
|
||||
println(Console.YELLOW + s"[${fname}: ${sourcecode.Line()}]" + Console.GREEN + s" - $word")
|
||||
}
|
||||
|
||||
def getListOfFiles(dir: String): List[File] =
|
||||
(new File(dir)).listFiles.filter(_.isFile).toList
|
||||
|
||||
def getListOfFiles(dir: Path): List[File] =
|
||||
dir.toFile().listFiles.filter(_.isFile).toList
|
||||
|
||||
|
||||
def getListOfFolders(dir: String): List[File] =
|
||||
(new File(dir)).listFiles.filter(_.isDirectory).toList
|
||||
|
||||
def getListOfFolders(dir: Path): List[File] =
|
||||
dir.toFile().listFiles.filter(_.isDirectory).toList
|
||||
|
||||
def getListOfFilesRecursive(dir: String): List[File] = {
|
||||
getListOfFiles(dir) ::: getListOfFolders(dir).flatMap(f =>
|
||||
getListOfFilesRecursive(f.getPath)
|
||||
)
|
||||
}
|
||||
|
||||
import cats.implicits._
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.Executors
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
def relativeFile(name: String) = {
|
||||
new File(getClass.getClassLoader.getResource(name).getPath)
|
||||
}
|
||||
|
||||
def getTestDir: File =
|
||||
new File(getClass.getClassLoader.getResource("tests").getPath)
|
||||
|
||||
def getAllTests: List[File] = getListOfFilesRecursive(getTestDir.getPath)
|
||||
.filter( f => f.getPath.endsWith(".s") )
|
||||
|
||||
def getAllTestNames: List[String] = getAllTests.map(_.toString.split("/").takeRight(1).mkString)
|
||||
|
||||
def clearTestResults = {
|
||||
try {
|
||||
val testResults = relativeFile("/testResults")
|
||||
testResults.delete()
|
||||
}
|
||||
catch {
|
||||
case _:Throwable => ()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an assembly file.
|
||||
*/
|
||||
def readTest(testOptions: TestOptions): Either[String, List[String]] = {
|
||||
|
||||
// Ahh, the GNU toolchain and its tabs
|
||||
val annoyingTabCharacter = ' '
|
||||
|
||||
getAllTests.filter(_.getName.contains(testOptions.testName)).headOption.toRight(s"File not found: ${testOptions.testName}").flatMap{ filename =>
|
||||
import scala.io.Source
|
||||
scala.util.Try(
|
||||
Source.fromFile(filename)
|
||||
.getLines.toList
|
||||
.map(_.replace(annoyingTabCharacter, ' ')))
|
||||
.toOption
|
||||
.toRight(s"Error reading $filename")
|
||||
}
|
||||
}
|
||||
}
|
43
src/test/scala/testConf.scala
Normal file
43
src/test/scala/testConf.scala
Normal file
|
@ -0,0 +1,43 @@
|
|||
// package FiveStage
|
||||
// import chisel3._
|
||||
// import chisel3.iotesters._
|
||||
// import org.scalatest.{Matchers, FlatSpec}
|
||||
// import spire.math.{UInt => Uint}
|
||||
// import fileUtils._
|
||||
// import cats.implicits._
|
||||
|
||||
// import RISCVutils._
|
||||
// import RISCVasm._
|
||||
// import riscala._
|
||||
|
||||
// import utilz._
|
||||
|
||||
// class AllTests extends FlatSpec with Matchers {
|
||||
|
||||
// val results = fileUtils.getAllTests.map{f =>
|
||||
// val result = TestRunner.runTest(f.getPath, false)
|
||||
// (f.getName, result)
|
||||
// }
|
||||
|
||||
// makeReport(results)
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// This is for you to run more verbose testing.
|
||||
// */
|
||||
// class SelectedTests extends FlatSpec with Matchers {
|
||||
|
||||
// val tests = List(
|
||||
// "matMul.s"
|
||||
// )
|
||||
|
||||
// if(!tests.isEmpty){
|
||||
// val results = fileUtils.getAllTests.filter(f => tests.contains(f.getName)).map{ f =>
|
||||
// val result = TestRunner.runTest(f.getPath, true)
|
||||
// (f.getName, result)
|
||||
// }
|
||||
|
||||
// makeReport(results)
|
||||
// }
|
||||
// }
|
Loading…
Add table
Add a link
Reference in a new issue