summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hdl/core/reg.py23
1 files changed, 16 insertions, 7 deletions
diff --git a/hdl/core/reg.py b/hdl/core/reg.py
index 8dc1281..df7e948 100644
--- a/hdl/core/reg.py
+++ b/hdl/core/reg.py
@@ -90,19 +90,24 @@ class Reg(Elaboratable):
m.d.comb += self._inc_ip.eq(1)
with m.If(self.int_sig):
- m.d.comb += self._inc_ip.eq(0)
- m.d.sync += self.ip.eq(self.rd)
+ m.d.comb += self._inc_ip.eq(0) # do not increment instruction pointer on interrupt
+
+ m.d.sync += self.ip.eq(self.rd) # swap ip and cs0
m.d.sync += self.cs0.eq(self.ip)
- m.d.sync += self.cs1.eq(self.sp)
- m.d.sync += self.cs2.eq(self.flg)
+
+ m.d.sync += self.cs1.eq(self.sp) # swap sp and cs1
+ m.d.sync += self.sp.eq(self.cs1)
+
+ m.d.sync += self.cs2.eq(self.flg) # save old flags to cs2
m.d.sync += self.flg.user_mode.eq(0) # set to system mode or iret cannot be used
m.d.sync += self.flg.int.eq(0) # clear int flag, essential because another interrupt can be triggered without this
- with m.Elif(self.iret):
+ with m.Elif(self.iret & ~self.flg.user_mode): # don't allow iret in user mode, that would be uhhh.... BAD
m.d.comb += self._inc_ip.eq(0)
- m.d.sync += self.ip.eq(self.cs0)
+ m.d.sync += self.ip.eq(self.cs0) #swap back ip and cs0
m.d.sync += self.sp.eq(self.cs1)
- m.d.sync += self.flg.eq(self.cs2)
+ m.d.sync += self.cs1.eq(self.sp) #swap back sp and cs1
+ m.d.sync += self.flg.eq(self.cs2) #restore flags from cs2
with m.Elif(self.call):
m.d.comb += self._inc_ip.eq(0)
@@ -121,6 +126,10 @@ class Reg(Elaboratable):
with m.Case(self.ip.idx): #do not directly write to ip register
pass
+ with m.Case(self.pda.idx): # do not write to pda register in user mode
+ with m.If(~self.flg.user_mode):
+ m.d.sync += self.pda.eq(self.rd)
+
with m.Case(self.flg.idx):
# mask top half of register to prevent writing to flags in user mode
with m.If(~self.flg.user_mode):