Skip to content

Commit

Permalink
dialects: add all rv32i/rv64i CSR instructions (#852)
Browse files Browse the repository at this point in the history
This PR adds all the instructions in the RV32I/RV64I Section 2.8
(Control and Status Register Instructions) of the spec.

WIP: this section of the spec defines instructions with weird behavior,
like:

> Atomically swaps values in the CSRs and integer registers. CSRRW reads
the old value of the CSR, zero-extends the value to XLEN bits, then
writes it to integer register rd. The initial value in rs1 is written to
the CSR. The initial value in rs1 is written to the CSR. **If rd=x0,
then the instruction shall not read the CSR and shall not cause any of
the side-effects that might occur on a CSR read.**

In order to expose this *full* (e.g.: *read/write*) VS *limited* (e.g.:
*write only*) behavior the idea is to treat instructions like regular
ones by taking into account their *full* behaviour and then use an
attribute to switch on the *limited* mode. When, for example, we have a
`riscv.csrrw` in *limited mode*, rd **must be allocated to x0**.

---------

Co-authored-by: Sasha Lopoukhine <superlopuh@gmail.com>
  • Loading branch information
nazavode and superlopuh committed May 3, 2023
1 parent dd178f3 commit 8e051e5
Show file tree
Hide file tree
Showing 3 changed files with 398 additions and 2 deletions.
42 changes: 42 additions & 0 deletions tests/dialects/test_riscv.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from xdsl.utils.test_value import TestSSAValue
from xdsl.dialects import riscv

from xdsl.dialects.builtin import IntegerAttr, i32

from xdsl.utils.exceptions import VerifyException

import pytest


def test_add_op():
a1 = TestSSAValue(riscv.RegisterType(riscv.Register("a1")))
Expand All @@ -16,3 +22,39 @@ def test_add_op():
assert a0.typ.data.name == "a0"
assert a1.typ.data.name == "a1"
assert a2.typ.data.name == "a2"


def test_csr_op():
a1 = TestSSAValue(riscv.RegisterType(riscv.Register("a1")))
zero = TestSSAValue(riscv.RegisterType(riscv.Register("zero")))
csr = IntegerAttr(16, i32)
# CsrrwOp
riscv.CsrrwOp(rs1=a1, csr=csr, rd="a2").verify()
riscv.CsrrwOp(rs1=a1, csr=csr, rd="zero").verify()
riscv.CsrrwOp(rs1=a1, csr=csr, writeonly=True, rd="zero").verify()
with pytest.raises(VerifyException):
riscv.CsrrwOp(rs1=a1, csr=csr, writeonly=True, rd="a2").verify()
# CsrrsOp
riscv.CsrrsOp(rs1=a1, csr=csr, rd="a2").verify()
riscv.CsrrsOp(rs1=zero, csr=csr, rd="a2").verify()
riscv.CsrrsOp(rs1=zero, csr=csr, readonly=True, rd="a2").verify()
with pytest.raises(VerifyException):
riscv.CsrrsOp(rs1=a1, csr=csr, readonly=True, rd="a2").verify()
# CsrrcOp
riscv.CsrrcOp(rs1=a1, csr=csr, rd="a2").verify()
riscv.CsrrcOp(rs1=zero, csr=csr, rd="a2").verify()
riscv.CsrrcOp(rs1=zero, csr=csr, readonly=True, rd="a2").verify()
with pytest.raises(VerifyException):
riscv.CsrrcOp(rs1=a1, csr=csr, readonly=True, rd="a2").verify()
# CsrrwiOp
riscv.CsrrwiOp(csr=csr, rd="a2").verify()
riscv.CsrrwiOp(csr=csr, rd="zero").verify()
riscv.CsrrwiOp(csr=csr, writeonly=True, rd="zero").verify()
with pytest.raises(VerifyException):
riscv.CsrrwiOp(csr=csr, writeonly=True, rd="a2").verify()
# CsrrsiOp
riscv.CsrrsiOp(csr=csr, immediate=IntegerAttr(0, i32), rd="a2").verify()
riscv.CsrrsiOp(csr=csr, immediate=IntegerAttr(1, i32), rd="a2").verify()
# CsrrciOp
riscv.CsrrciOp(csr=csr, immediate=IntegerAttr(0, i32), rd="a2").verify()
riscv.CsrrsiOp(csr=csr, immediate=IntegerAttr(1, i32), rd="a2").verify()
27 changes: 26 additions & 1 deletion tests/filecheck/dialects/riscv/riscv_ops.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,32 @@
// CHECK-NEXT: "riscv.sh"(%0, %1) {"immediate" = 1 : i32} : (!riscv.reg<>, !riscv.reg<>) -> ()
"riscv.sw"(%0, %1) {"immediate" = 1 : i32}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: "riscv.sw"(%0, %1) {"immediate" = 1 : i32} : (!riscv.reg<>, !riscv.reg<>) -> ()
// Assembler pseudo-insgtructions
// RV32I/RV64I: Control and Status Register Instructions (Section 2.8)
%csrrw_rw = "riscv.csrrw"(%0) {"csr" = 1024 : i32}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrw"(%0) {"csr" = 1024 : i32} : (!riscv.reg<>) -> !riscv.reg<>
%csrrw_w = "riscv.csrrw"(%0) {"csr" = 1024 : i32, "writeonly"}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrw"(%0) {"csr" = 1024 : i32, "writeonly"} : (!riscv.reg<>) -> !riscv.reg<>
%csrrs_rw = "riscv.csrrs"(%0) {"csr" = 1024 : i32}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrs"(%0) {"csr" = 1024 : i32} : (!riscv.reg<>) -> !riscv.reg<>
%csrrs_r = "riscv.csrrs"(%0) {"csr" = 1024 : i32, "readonly"}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrs"(%0) {"csr" = 1024 : i32, "readonly"} : (!riscv.reg<>) -> !riscv.reg<>
%csrrc_rw = "riscv.csrrc"(%0) {"csr" = 1024 : i32}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrc"(%0) {"csr" = 1024 : i32} : (!riscv.reg<>) -> !riscv.reg<>
%csrrc_r = "riscv.csrrc"(%0) {"csr" = 1024 : i32, "readonly"}: (!riscv.reg<>) -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrc"(%0) {"csr" = 1024 : i32, "readonly"} : (!riscv.reg<>) -> !riscv.reg<>
%csrrsi_rw = "riscv.csrrsi"() {"csr" = 1024 : i32, "immediate" = 8 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrsi"() {"csr" = 1024 : i32, "immediate" = 8 : i32} : () -> !riscv.reg<>
%csrrsi_r = "riscv.csrrsi"() {"csr" = 1024 : i32, "immediate" = 0 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrsi"() {"csr" = 1024 : i32, "immediate" = 0 : i32} : () -> !riscv.reg<>
%csrrci_rw = "riscv.csrrci"() {"csr" = 1024 : i32, "immediate" = 8 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrci"() {"csr" = 1024 : i32, "immediate" = 8 : i32} : () -> !riscv.reg<>
%csrrci_r = "riscv.csrrci"() {"csr" = 1024 : i32, "immediate" = 0 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrci"() {"csr" = 1024 : i32, "immediate" = 0 : i32} : () -> !riscv.reg<>
%csrrwi_rw = "riscv.csrrwi"() {"csr" = 1024 : i32, "immediate" = 1 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrwi"() {"csr" = 1024 : i32, "immediate" = 1 : i32} : () -> !riscv.reg<>
%csrrwi_w = "riscv.csrrwi"() {"csr" = 1024 : i32, "writeonly", "immediate" = 1 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.csrrwi"() {"csr" = 1024 : i32, "writeonly", "immediate" = 1 : i32} : () -> !riscv.reg<>
// Assembler pseudo-instructions
%li = "riscv.li"() {"immediate" = 1 : i32}: () -> !riscv.reg<>
// CHECK-NEXT: %{{.*}} = "riscv.li"() {"immediate" = 1 : i32} : () -> !riscv.reg<>
// Environment Call and Breakpoints
Expand Down

0 comments on commit 8e051e5

Please sign in to comment.