This commit is contained in:
peteraa 2019-06-07 17:43:33 +02:00
commit 932413bb3d
61 changed files with 7249 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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);
}

View 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);
}
}

View 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);
}

View 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;
}

View 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;
}

View 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

View 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)
}
}
}
}

View 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)
}
}

View 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
}
}

View 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) }
}

View 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)
}
}

View 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)
}
}

View 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
}
}

View 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))
}
}
}

View 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)
}
}

View 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")
}
}

View 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",
)
}

View 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)
}
}

View 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)
}
}

View 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")
}
}
}

View 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")
}
}
}

View 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)
// }
// }