Skip to content

Commit 623482d

Browse files
committed
Fix privileged instructions... all coming back to me now
1 parent e3e6bd9 commit 623482d

2 files changed

Lines changed: 136 additions & 42 deletions

File tree

bronzebeard/asm.py

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def r_type(rd, rs1, rs2, *, opcode, funct3, funct7):
163163

164164
return code
165165

166+
166167
# r-type variation for privileged instructions
167168
def rp_type(rs1, rs2, *, rd, opcode, funct3, funct7):
168169
rd = lookup_register(rd)
@@ -832,15 +833,15 @@ def cj_type(imm, *, opcode, funct3, cs=None):
832833
C_SWSP = partial(css_type, opcode=0b10, funct3=0b110)
833834

834835
# RV32 Priv: Trap-Return Instructions
835-
SRET = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=0b00010, funct7=0b0001000) # special syntax
836-
MRET = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=0b00010, funct7=0b0011000) # special syntax
837-
MNRET = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=0b00010, funct7=0b0111000) # special syntax
836+
SRET = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b000100000010) # special syntax
837+
MRET = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b001100000010) # special syntax
838+
MNRET = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b011100000010) # special syntax
838839

839840
# RV32 Priv: Interrupt-Management Instructions
840-
WFI = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=0b00101, funct7=0b0001000) # special syntax
841+
WFI = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b000100000101) # special syntax
841842

842843
# RV32 Priv: Control Transfer Records Management Instructions
843-
SCTRCLR = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=0b00100, funct7=0b0001000) # special syntax
844+
SCTRCLR = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b000100000100) # special syntax
844845

845846
# RV32 Priv: Supervisor Memory-Management Instructions
846847
SFENCE_VMA = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000,funct7=0b0001001) # special syntax
@@ -863,8 +864,8 @@ def cj_type(imm, *, opcode, funct3, cs=None):
863864

864865
# RV32 Priv: Svinval Memory-Management Extension
865866
SINVAL_VMA = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, funct7=0b0001011) # special syntax
866-
SFENCE_W_INVAL = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=0, funct7=0b0001100) # special syntax
867-
SFENCE_INVAL_IR = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, rs2=1, funct7=0b0001100) # special syntax
867+
SFENCE_W_INVAL = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b000110000000) # special syntax
868+
SFENCE_INVAL_IR = partial(i_type, opcode=0b1110011, rd=0, funct3=0b000, rs1=0, imm=0b000110000001) # special syntax
868869
HINVAL_VVMA = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, funct7=0b0010011) # special syntax
869870
HINVAL_GVMA = partial(rp_type, opcode=0b1110011, rd=0, funct3=0b000, funct7=0b0110011) # special syntax
870871

@@ -892,6 +893,19 @@ def cj_type(imm, *, opcode, funct3, cs=None):
892893
'remu': REMU,
893894
}
894895

896+
RP_TYPE_INSTRUCTIONS = {
897+
# Privileged Instructions
898+
'sfence.vma': SFENCE_VMA,
899+
'hfence.vvma': HFENCE_VVMA,
900+
'hfence.gvma': HFENCE_GVMA,
901+
'hsv.b': HSV_B,
902+
'hsv.h': HSV_H,
903+
'hsv.w': HSV_W,
904+
'sinval.vma': SINVAL_VMA,
905+
'hinval.vvma': HINVAL_VVMA,
906+
'hinval.gvma': HINVAL_GVMA,
907+
}
908+
895909
I_TYPE_INSTRUCTIONS = {
896910
'jalr': JALR,
897911
'lb': LB,
@@ -913,10 +927,30 @@ def cj_type(imm, *, opcode, funct3, cs=None):
913927
'csrrci': CSRRCI,
914928
}
915929

930+
IP_TYPE_INSTRUCTIONS = {
931+
# Privileged Instructions
932+
'hlv.b': HLV_B,
933+
'hlv.bu': HLV_BU,
934+
'hlv.h': HLV_H,
935+
'hlv.hu': HLV_HU,
936+
'hlv.w': HLV_W,
937+
'hlvx.hu': HLVX_HU,
938+
'hlvx.wu': HLVX_WU,
939+
}
940+
916941
IE_TYPE_INSTRUCTIONS = {
917942
'ecall': ECALL,
918943
'ebreak': EBREAK,
919944
'fence.i': FENCE_I,
945+
946+
# Privileged Instructions
947+
'sret': SRET,
948+
'mret': MRET,
949+
'mnret': MNRET,
950+
'wfi': WFI,
951+
'sctrclr': SCTRCLR,
952+
'sfence.w.inval': SFENCE_W_INVAL,
953+
'sfence.inval.ir': SFENCE_INVAL_IR,
920954
}
921955

922956
S_TYPE_INSTRUCTIONS = {
@@ -1030,41 +1064,11 @@ def cj_type(imm, *, opcode, funct3, cs=None):
10301064
'c.j': C_J,
10311065
}
10321066

1033-
PRIV_INSTRUCTIONS = {
1034-
'sret': SRET,
1035-
'mret': MRET,
1036-
'mnret': MNRET,
1037-
1038-
'wfi': WFI,
1039-
1040-
'sctrclr': SCTRCLR,
1041-
1042-
'sfence.vma': SFENCE_VMA,
1043-
1044-
'hfence.vvma': HFENCE_VVMA,
1045-
'hfence.gvma': HFENCE_GVMA,
1046-
1047-
'hlv.b': HLV_B,
1048-
'hlv.bu': HLV_BU,
1049-
'hlv.h': HLV_H,
1050-
'hlv.hu': HLV_HU,
1051-
'hlv.w': HLV_W,
1052-
'hlvx.hu': HLVX_HU,
1053-
'hlvx.wu': HLVX_WU,
1054-
'hsv.b': HSV_B,
1055-
'hsv.h': HSV_H,
1056-
'hsv.w': HSV_W,
1057-
1058-
'sinval.vma': SINVAL_VMA,
1059-
'sfence.w.inval': SFENCE_W_INVAL,
1060-
'sfence.inval.ir': SFENCE_INVAL_IR,
1061-
'hinval.vvma': HINVAL_VVMA,
1062-
'hinval.gvma': HINVAL_GVMA,
1063-
}
1064-
10651067
INSTRUCTIONS = {}
10661068
INSTRUCTIONS.update(R_TYPE_INSTRUCTIONS)
1069+
INSTRUCTIONS.update(RP_TYPE_INSTRUCTIONS)
10671070
INSTRUCTIONS.update(I_TYPE_INSTRUCTIONS)
1071+
INSTRUCTIONS.update(IP_TYPE_INSTRUCTIONS)
10681072
INSTRUCTIONS.update(IE_TYPE_INSTRUCTIONS)
10691073
INSTRUCTIONS.update(S_TYPE_INSTRUCTIONS)
10701074
INSTRUCTIONS.update(B_TYPE_INSTRUCTIONS)
@@ -1086,7 +1090,6 @@ def cj_type(imm, *, opcode, funct3, cs=None):
10861090
INSTRUCTIONS.update(CA_TYPE_INSTRUCTIONS)
10871091
INSTRUCTIONS.update(CB_TYPE_INSTRUCTIONS)
10881092
INSTRUCTIONS.update(CJ_TYPE_INSTRUCTIONS)
1089-
INSTRUCTIONS.update(PRIV_INSTRUCTIONS)
10901093

10911094
PSEUDO_INSTRUCTIONS = {
10921095
'nop',
@@ -1638,6 +1641,29 @@ def args(self):
16381641
return [self.rd, self.rs1, self.rs2]
16391642

16401643

1644+
# custom syntax for privileged instructions
1645+
class RPTypeInstruction(Instruction):
1646+
1647+
def __init__(self, line, name, rs1, rs2):
1648+
super().__init__(line)
1649+
self.name = name
1650+
self.rs1 = rs1
1651+
self.rs2 = rs2
1652+
1653+
def __repr__(self):
1654+
s = '{}({!r}, rs1={!r}, rs2={!r})'
1655+
s = s.format(type(self).__name__, self.name, self.rs1, self.rs2)
1656+
return s
1657+
1658+
def __str__(self):
1659+
s = '{} {}, {}'
1660+
s = s.format(self.name, self.rs1, self.rs2)
1661+
return s
1662+
1663+
def args(self):
1664+
return [self.rs1, self.rs2]
1665+
1666+
16411667
class ITypeInstruction(Instruction):
16421668

16431669
def __init__(self, line, name, rd, rs1, imm, is_auipc_jump=False):
@@ -1662,6 +1688,29 @@ def args(self):
16621688
return [self.rd, self.rs1, self.imm]
16631689

16641690

1691+
# custom syntax for privileged instructions
1692+
class IPTypeInstruction(Instruction):
1693+
1694+
def __init__(self, line, name, rd, rs1):
1695+
super().__init__(line)
1696+
self.name = name
1697+
self.rd = rd
1698+
self.rs1 = rs1
1699+
1700+
def __repr__(self):
1701+
s = '{}({!r}, rd={!r}, rs1={!r})'
1702+
s = s.format(type(self).__name__, self.name, self.rd, self.rs1)
1703+
return s
1704+
1705+
def __str__(self):
1706+
s = '{} {}, {}'
1707+
s = s.format(self.name, self.rd, self.rs1)
1708+
return s
1709+
1710+
def args(self):
1711+
return [self.rd, self.rs1]
1712+
1713+
16651714
# custom syntax for: ecall, ebreak, fence.i
16661715
class IETypeInstruction(Instruction):
16671716

@@ -2361,6 +2410,13 @@ def parse_item(line_tokens):
23612410
name, rd, rs1, rs2 = tokens
23622411
name = name.lower()
23632412
return RTypeInstruction(line, name, rd, rs1, rs2)
2413+
# rp-type instructions
2414+
elif head in RP_TYPE_INSTRUCTIONS:
2415+
if len(tokens) != 3:
2416+
raise AssemblerError('rp-type instructions require exactly 2 args', line)
2417+
name, rs1, rs2 = tokens
2418+
name = name.lower()
2419+
return RPTypeInstruction(line, name, rs1, rs2)
23642420
# i-type instructions
23652421
elif head in I_TYPE_INSTRUCTIONS:
23662422
# check for jalr PI
@@ -2376,6 +2432,13 @@ def parse_item(line_tokens):
23762432
name = name.lower()
23772433
imm = parse_immediate(imm, line)
23782434
return ITypeInstruction(line, name, rd, rs1, imm)
2435+
# ip-type instructions
2436+
elif head in IP_TYPE_INSTRUCTIONS:
2437+
if len(tokens) != 3:
2438+
raise AssemblerError('ip-type instructions require exactly 2 args', line)
2439+
name, rd, rs1 = tokens
2440+
name = name.lower()
2441+
return IPTypeInstruction(line, name, rd, rs1)
23792442
# ie-type instructions
23802443
elif head in IE_TYPE_INSTRUCTIONS:
23812444
name, = tokens
@@ -2567,7 +2630,6 @@ def parse_item(line_tokens):
25672630
imm = ['%offset', reference]
25682631
imm = parse_immediate(imm, line)
25692632
return CJTypeInstruction(line, name, imm)
2570-
25712633
# pseudo instructions
25722634
elif head in PSEUDO_INSTRUCTIONS:
25732635
name, *args = tokens

tests/test_isa_priv.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import struct
2+
13
import pytest
24

35
from bronzebeard import asm
@@ -204,4 +206,34 @@ def test_hinval_vvma(rs1, rs2, code):
204206
(31, 31, 0b01100111111111111000000001110011),
205207
])
206208
def test_hinval_gvma(rs1, rs2, code):
207-
assert asm.HINVAL_GVMA(rs1, rs2) == code
209+
assert asm.HINVAL_GVMA(rs1, rs2) == code
210+
211+
212+
@pytest.mark.parametrize(
213+
'source, expected', [
214+
('sret', asm.SRET()),
215+
('mret', asm.MRET()),
216+
('mnret', asm.MNRET()),
217+
('wfi', asm.WFI()),
218+
('sctrclr', asm.SCTRCLR()),
219+
('sfence.vma x0 x1', asm.SFENCE_VMA('x0', 'x1')),
220+
('hfence.vvma x0 x1', asm.HFENCE_VVMA('x0', 'x1')),
221+
('hfence.gvma x0 x1', asm.HFENCE_GVMA('x0', 'x1')),
222+
('hlv.b x0 x1', asm.HLV_B('x0', 'x1')),
223+
('hlv.bu x0 x1', asm.HLV_BU('x0', 'x1')),
224+
('hlv.h x0 x1', asm.HLV_H('x0', 'x1')),
225+
('hlv.hu x0 x1', asm.HLV_HU('x0', 'x1')),
226+
('hlv.w x0 x1', asm.HLV_W('x0', 'x1')),
227+
('hlvx.hu x0 x1', asm.HLVX_HU('x0', 'x1')),
228+
('hlvx.wu x0 x1', asm.HLVX_WU('x0', 'x1')),
229+
('hsv.b x0 x1', asm.HSV_B('x0', 'x1')),
230+
('hsv.h x0 x1', asm.HSV_H('x0', 'x1')),
231+
('hsv.w x0 x1', asm.HSV_W('x0', 'x1')),
232+
('sinval.vma x0 x1', asm.SINVAL_VMA('x0', 'x1')),
233+
('sfence.w.inval', asm.SFENCE_W_INVAL()),
234+
('sfence.inval.ir', asm.SFENCE_INVAL_IR()),
235+
])
236+
def test_assemble_priv(source, expected):
237+
binary = asm.assemble(source)
238+
target = struct.pack('<I', expected)
239+
assert binary == target

0 commit comments

Comments
 (0)