Skip to content

Commit 8090120

Browse files
Avoid ambiguity for Word expressions (#97)
Co-authored-by: devops <devops@runtimeverification.com>
1 parent 0c40c65 commit 8090120

4 files changed

Lines changed: 36 additions & 29 deletions

File tree

package/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.73
1+
0.1.74

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "kriscv"
7-
version = "0.1.73"
7+
version = "0.1.74"
88
description = "K tooling for the RISC-V architecture"
99
authors = [
1010
"Runtime Verification, Inc. <contact@runtimeverification.com>",

src/kriscv/kdist/riscv-semantics/riscv.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,15 @@ We then provide rules to consume and execute each instruction from the top of th
197197
`SLLI`, `SRLI`, and `SRAI` perform logical left, logical right, and arithmetic right shifts respectively.
198198
```k
199199
rule <instrs> SLLI RD , RS , SHAMT => .K ...</instrs>
200-
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS) <<Word SHAMT) </regs>
200+
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS) <<Word W(SHAMT)) </regs>
201201
requires 0 <=Int SHAMT
202202
203203
rule <instrs> SRLI RD , RS , SHAMT => .K ...</instrs>
204-
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS) >>lWord SHAMT) </regs>
204+
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS) >>lWord W(SHAMT)) </regs>
205205
requires 0 <=Int SHAMT
206206
207207
rule <instrs> SRAI RD , RS , SHAMT => .K ...</instrs>
208-
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS) >>aWord SHAMT) </regs>
208+
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS) >>aWord W(SHAMT)) </regs>
209209
requires 0 <=Int SHAMT
210210
```
211211
`LUI` builds a 32-bit constant from the 20-bit immediate by setting the 12 least-significant bits to `0`, then sign extends to `XLEN` bits and places the result in register `RD`.
@@ -261,13 +261,13 @@ The following instructions behave analogously to their `I`-suffixed counterparts
261261
`SLL`, `SRL`, and `SRA` read their shift amount fom the lowest `log_2(XLEN)` bits of `RS2`.
262262
```k
263263
rule <instrs> SLL RD , RS1 , RS2 => .K ...</instrs>
264-
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS1) <<Word Word2UInt(readReg(REGS, RS2) &Word W(XLEN -Int 1))) </regs>
264+
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS1) <<Word (readReg(REGS, RS2) &Word W(XLEN -Int 1))) </regs>
265265
266266
rule <instrs> SRL RD , RS1 , RS2 => .K ...</instrs>
267-
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS1) >>lWord Word2UInt(readReg(REGS, RS2) &Word W(XLEN -Int 1))) </regs>
267+
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS1) >>lWord (readReg(REGS, RS2) &Word W(XLEN -Int 1))) </regs>
268268
269269
rule <instrs> SRA RD , RS1 , RS2 => .K ...</instrs>
270-
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS1) >>aWord Word2UInt(readReg(REGS, RS2) &Word W(XLEN -Int 1))) </regs>
270+
<regs> REGS => writeReg(REGS, RD, readReg(REGS, RS1) >>aWord (readReg(REGS, RS2) &Word W(XLEN -Int 1))) </regs>
271271
```
272272
`JAL` stores `PC + 4` in `RD`, then increments `PC` by `OFFSET`.
273273
```k

src/kriscv/kdist/riscv-semantics/word.md

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,28 +61,41 @@ The `s` prefix denotes a signed operation while `u` denotes an unsigned operatio
6161
syntax Bool ::= Word ">=uWord" Word [function, total]
6262
rule W(I1) >=uWord W(I2) => I1 >=Int I2
6363
```
64+
To avoid syntax conflicts, we define the following syntax with `left` associativity and clear precedence over the bitwise operations.
65+
```k
66+
syntax Word ::= left:
67+
Word "*Word" Word [function, total, symbol(mulWord)]
68+
| Word "*hWord" Word [function, total, symbol(mulhWord)]
69+
| Word "*huWord" Word [function, total, symbol(mulhuWord)]
70+
| Word "*hsuWord" Word [function, total, symbol(mulhsuWord)]
71+
> left:
72+
Word "+Word" Word [function, total, symbol(addWord)]
73+
| Word "-Word" Word [function, total, symbol(subWord)]
74+
> left:
75+
Word ">>lWord" Word [function, total, symbol(rshWord)]
76+
| Word ">>aWord" Word [function, total, symbol(ashWord)]
77+
| Word "<<Word" Word [function, total, symbol(lshWord)]
78+
> left:
79+
Word "&Word" Word [function, total, symbol(andWord)]
80+
> left:
81+
Word "xorWord" Word [function, total, symbol(xorWord)]
82+
> left:
83+
Word "|Word" Word [function, total, symbol(orWord)]
84+
```
85+
6486
Note that two's complement enables us to use a single addition or subtraction operation for both signed and unsigned values.
6587
```k
66-
syntax Word ::= Word "+Word" Word [function, total]
6788
rule W(I1) +Word W(I2) => chop(I1 +Int I2)
68-
69-
syntax Word ::= Word "-Word" Word [function, total]
7089
rule W(I1) -Word W(I2) => chop(I1 -Int I2)
7190
```
7291
The same is true for the `XLEN` least-significant bits of the result of multiplication.
7392
```k
74-
syntax Word ::= Word "*Word" Word [function, total, symbol(mulWord)]
7593
rule W(I1) *Word W(I2) => chop(I1 *Int I2)
7694
```
7795
The value of the upper `XLEN` bits however depends on signedness of the operands, as reflected by the followig functions.
7896
```k
79-
syntax Word ::= Word "*hWord" Word [function, total, symbol(mulhWord)]
8097
rule W1 *hWord W2 => chop((Word2SInt(W1) *Int Word2SInt(W2)) >>Int XLEN)
81-
82-
syntax Word ::= Word "*huWord" Word [function, total, symbol(mulhuWord)]
8398
rule W(I1) *huWord W(I2) => chop((I1 *Int I2) >>Int XLEN)
84-
85-
syntax Word ::= Word "*hsuWord" Word [function, total, symbol(mulhsuWord)]
8699
rule W1 *hsuWord W(I2) => chop((Word2SInt(W1) *Int I2) >>Int XLEN)
87100
```
88101
Above, the `chop` utility function
@@ -92,18 +105,14 @@ Above, the `chop` utility function
92105
```
93106
is used to zero-out all but the least-significant `XLEN`-bits in case of overflow.
94107
```k
95-
syntax Word ::= Word "&Word" Word [function, total]
96108
rule W(I1) &Word W(I2) => W(I1 &Int I2)
97109
98-
syntax Word ::= Word "|Word" Word [function, total]
99110
rule W(I1) |Word W(I2) => W(I1 |Int I2)
100111
101-
syntax Word ::= Word "xorWord" Word [function, total]
102112
rule W(I1) xorWord W(I2) => W(I1 xorInt I2)
103113
104-
syntax Word ::= Word "<<Word" Int [function, total]
105-
rule W(I1) <<Word I2 => chop(I1 <<Int I2) requires 0 <=Int I2
106-
rule _ <<Word I2 => W(0) requires I2 <Int 0
114+
rule W(I1) <<Word W(I2) => chop(I1 <<Int I2) requires 0 <=Int I2
115+
rule _ <<Word W(I2) => W(0) requires I2 <Int 0
107116
```
108117
For right shifts, we provide both arithmetic and logical variants.
109118

@@ -114,14 +123,12 @@ Counterintuitively, we use the arithmetic right shift operator `>>Int` for `Int`
114123

115124
That is, for any `I:Int` underlying some `W(I):Word`, applying `>>Int` will always pad with `0`s, correctly implementing a logical right shift.
116125
```k
117-
syntax Word ::= Word ">>lWord" Int [function, total]
118-
rule W(I1) >>lWord I2 => W(I1 >>Int I2) requires 0 <=Int I2
119-
rule _ >>lWord I2 => W(0) requires I2 <Int 0
126+
rule W(I1) >>lWord W(I2) => W(I1 >>Int I2) requires 0 <=Int I2
127+
rule _ >>lWord W(I2) => W(0) requires I2 <Int 0
120128
```
121129
To actually perform an arithmetic shift over `Word`, we first convert to an infinitely sign-extended `Int` of equal value using `Word2SInt`, ensuring `>>Int` will pad with `1`s for a negative `Word`. The final result will still be infinitely sign-extended, so we must `chop` it back to a `Word`.
122130
```k
123-
syntax Word ::= Word ">>aWord" Int [function, total]
124-
rule W1 >>aWord I2 => chop(Word2SInt(W1) >>Int I2) requires 0 <=Int I2
125-
rule _ >>aWord I2 => W(0) requires I2 <Int 0
131+
rule W1 >>aWord W(I2) => chop(Word2SInt(W1) >>Int I2) requires 0 <=Int I2
132+
rule _ >>aWord W(I2) => W(0) requires I2 <Int 0
126133
endmodule
127134
```

0 commit comments

Comments
 (0)