aboutsummaryrefslogtreecommitdiffstats
path: root/riscv.py
diff options
context:
space:
mode:
Diffstat (limited to 'riscv.py')
-rw-r--r--riscv.py229
1 files changed, 192 insertions, 37 deletions
diff --git a/riscv.py b/riscv.py
index c0d5a15..245d60d 100644
--- a/riscv.py
+++ b/riscv.py
@@ -1,44 +1,199 @@
+def u(num, bits):
+ if num < 0:
+ raise ValueError("negative value not allowed: {}".format(num))
+
+ if num.bit_length() > bits:
+ raise ValueError("value too large for u{} field: {} ({} bits)",
+ bits, num, num.bit_length())
+
+ return (num, bits)
+
+def i(num, bits):
+ if num < 0:
+ num = (1 << bits) + num
+
+ return u(num, bits)
+
+def bit_concat(*parts):
+ val, size = 0, 0
+ for (pval, psize) in parts:
+ val = val | pval << size
+ size += psize
+ return (val, size)
+
+def bit_slice(bits, top, bottom):
+ (val, size) = bits
+
+ if top < bottom:
+ raise ValueError("cant slice reverse range")
+ elif bottom < 0:
+ raise ValueError("negative slice index")
+ elif top >= size:
+ raise ValueError("cant slice [{}:{}] from {} bit value".format(top, bottom, size))
+
+ width = top - bottom + 1
+ val = (val >> bottom) & ((1 << width) - 1)
+ return (val, width)
+
+def byteify(word):
+ (val, size) = word
+ if size != 32:
+ raise ValueError("Expected 32-bit word")
+
+ b0 = bit_slice(word, 7, 0)
+ b1 = bit_slice(word, 15, 8)
+ b2 = bit_slice(word, 23, 16)
+ b3 = bit_slice(word, 31, 24)
+ return [b0[:1], b1[:1], b2[:1], b3[:1]]
+
def format_r(op, rd, r1, r2, funct3, funct7):
- # opcode[7] rd[5] funct3[3] rs1[5] rs2[5] funct7[7]
- b0 = (rd & 0x1) << 7 | op
- b1 = (r1 & 0x1) << 7 | funct3 << 4 | rd >> 1
- b2 = (r2 & 0xf) << 4 | r1 >> 1
- b3 = funct7 << 1 | r2 >> 4
- return [(b0,), (b1,), (b2,), (b3,)]
+ # HH funct7 rs2 rs1 funct3 rd opcode LL
+ return byteify(bit_concat(
+ u(op, 7),
+ u(rd, 5),
+ u(funct3, 3),
+ u(r1, 5),
+ u(r2, 5),
+ u(funct7, 7),
+ ))
def format_i(op, rd, r1, imm12, funct3):
- # opcode[7] rd[5] funct3[3] rs1[5] imm[12]
- b0 = (rd & 0x1) << 7 | op
- b1 = (r1 & 0x1) << 7 | funct3 << 4 | rd >> 1
- b2 = (imm12 & 0xf) << 4 | r1 >> 1
- b3 = imm12 >> 4
- return [(b0,), (b1,), (b2,), (b3,)]
+ # HH imm[11:0] rs1 funct3 rd opcode LL
+ return byteify(bit_concat(
+ u(op, 7),
+ u(rd, 5),
+ u(funct3, 3),
+ u(r1, 5),
+ i(imm12, 12),
+ ))
def format_s(op, r1, r2, imm12, funct3):
- # opcode[7] rd[5] funct3[3] rs1[5] rs2[5] funct7[7]
- b0 = (imm12 & 0x1) << 7 | op
- b1 = (r1 & 0x1) << 7 | funct3 << 4 | (imm12 & 0x1f) >> 1
- b2 = (r2 & 0xf) << 4 | r1 >> 1
- b3 = (imm12 & 0xf0) | r2 >> 4
- return [(b0,), (b1,), (b2,), (b3,)]
+ # HH imm[11:5] rs2 rs1 funct3 imm[4:0] opcode LL
+ imm = i(imm12, 12)
+ imm_lo = bit_slice(imm, 4, 0)
+ imm_hi = bit_slice(imm, 11, 5)
+ return byteify(bit_concat(
+ u(op, 7),
+ imm_lo,
+ u(funct3, 3),
+ u(r1, 5),
+ u(r2, 5),
+ imm_hi
+ ))
+
+ # imm12 = i(imm12, 12)
+ # r1 = i(r1, 5, neg=False)
+ # r2 = i(r2, 5, neg=False)
+ #
+ # b0 = (imm12 & 0x1) << 7 | op
+ # b1 = (r1 & 0x1) << 7 | funct3 << 4 | (imm12 & 0x1f) >> 1
+ # b2 = (r2 & 0xf) << 4 | r1 >> 1
+ # b3 = (imm12 & 0xf0) | r2 >> 4
+ # return [(b0,), (b1,), (b2,), (b3,)]
def format_u(op, rd, imm20):
- # opcode[7] rd[5] imm31:12[20]
- b0 = (rd & 0x1) << 7 | op
- b1 = (imm20 & 0xf) << 4 | rd >> 1
- b2 = (imm20 >> 4) & 0xff
- b3 = imm20 >> 12
- return [(b0,), (b1,), (b2,), (b3,)]
-
-def format_j(op, rd, imm):
- # opcode[7] rd[5] imm19:12[8] imm11[1] imm10:1[10] imm20[1]
- imm12 = (imm >> 11) & 0xff
- imm11 = (imm >> 12) & 0x1
- imm1 = imm & 0x3ff
- imm20 = imm >> 19
-
- b0 = (rd & 0x1) << 7 | op # rd[1] op[7:0]
- b1 = (imm12 & 0xf) << 4 | rd >> 1 # imm[15:12] rd[5:2]
- b2 = (imm1 << 5) & 0xe0 | imm11 << 4 | (imm12 >> 4) # imm[3:1] imm[11] imm[19:16]
- b3 = imm20 << 7 | imm1 >> 3
- return [(b0,), (b1,), (b2,), (b3,)]
+ # HH imm[31:12] rd opcode LL
+ return byteify(bit_concat(
+ u(op, 7),
+ u(rd, 5),
+ i(imm20, 20)
+ ))
+
+def format_j(op, rd, imm20):
+ # HH imm[20] imm[10:1] imm[11] imm[19:12] rd opcode LL
+ imm = i(imm20, 20)
+ imm_lo = bit_slice(imm, 9, 0)
+ imm_10 = bit_slice(imm, 10, 10)
+ imm_hi = bit_slice(imm, 18, 11)
+ imm_19 = bit_slice(imm, 19, 19)
+ return byteify(bit_concat(
+ u(op, 7),
+ u(rd, 5),
+ imm_hi,
+ imm_10,
+ imm_lo,
+ imm_19
+ ))
+
+import unittest
+class TestHelpers(unittest.TestCase):
+ def test_bit_concat(self):
+ self.assertEqual(
+ bit_concat((0b10, 2), (0b00, 2)),
+ (0b0010, 4)
+ )
+ self.assertEqual(
+ bit_concat((0b1, 1), (0b0110, 4), (0b110, 3)),
+ (0b11001101, 8)
+ )
+
+ def test_bit_slice(self):
+ self.assertEqual(
+ bit_slice((0x7f, 8), 7, 4),
+ (0x7, 4)
+ )
+ self.assertEqual(
+ bit_slice((0b100, 3), 2, 2),
+ (0b1, 1)
+ )
+ with self.assertRaises(ValueError):
+ bit_slice((0xf, 4), 4, 0)
+ with self.assertRaises(ValueError):
+ bit_slice((0xf, 4), 2, 3)
+ with self.assertRaises(ValueError):
+ bit_slice((0xf, 4), 3, -1)
+ self.assertEqual(
+ bit_slice((0x12345678, 32), 7, 0),
+ (0x78, 8)
+ )
+ self.assertEqual(
+ bit_slice((0x12345678, 32), 15, 8),
+ (0x56, 8)
+ )
+ self.assertEqual(
+ bit_slice((0x12345678, 32), 23, 16),
+ (0x34, 8)
+ )
+
+ def test_byteify(self):
+ self.assertEqual(
+ byteify((0x12345678, 32)),
+ [(0x78,), (0x56,), (0x34,), (0x12,)]
+ )
+
+class TestFormats(unittest.TestCase):
+ def test_format_u(self):
+ self.assertEqual(
+ format_u(0x37, 0x5, 0x10010),
+ [(183,), (2,), (1,), (16,)]
+ )
+
+ def test_format_i(self):
+ self.assertEqual(
+ format_i(0x13, 5, 0, 72, 0x0),
+ [(147,), (2,), (128,), (4,)]
+ )
+ self.assertEqual(
+ format_i(0x13, 9, 2, 72, 0x3),
+ [(147,), (52,), (129,), (4,)]
+ )
+
+ def test_format_s(self):
+ self.assertEqual(
+ format_s(0x23, 3, 4, 0, 0x2),
+ [(35,), (160,), (65,), (0,)]
+ )
+ self.assertEqual(
+ format_s(0x23, 2, 0, -4, 0x2),
+ [(35,), (46,), (1,), (254,)]
+ )
+
+ def test_format_j(self):
+ self.assertEqual(
+ format_j(0x6f, 0, -26),
+ [(111,), (240,), (223,), (252,)]
+ )
+ self.assertEqual(
+ format_j(0x6f, 9, 0),
+ [(239,), (4,), (0,), (0,)]
+ )