summaryrefslogtreecommitdiff
path: root/hdl/core
diff options
context:
space:
mode:
authorjjsuperpower <jjs29356@gmail.com>2022-08-30 23:05:52 -0500
committerjjsuperpower <jjs29356@gmail.com>2022-08-30 23:05:52 -0500
commitcb5f2d9b12358a943943ed0ce29b3f700db0ba06 (patch)
tree3cefc3e143078b8671da479a61e54c73003d4f81 /hdl/core
parent5a7dedee172dbb30f1053e303a5d984ef96fd001 (diff)
reorganized hdl
Diffstat (limited to 'hdl/core')
-rw-r--r--hdl/core/__init__.py0
-rw-r--r--hdl/core/alu.py269
-rw-r--r--hdl/core/core.py36
-rw-r--r--hdl/core/reg.py289
4 files changed, 594 insertions, 0 deletions
diff --git a/hdl/core/__init__.py b/hdl/core/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hdl/core/__init__.py
diff --git a/hdl/core/alu.py b/hdl/core/alu.py
new file mode 100644
index 0000000..049c8af
--- /dev/null
+++ b/hdl/core/alu.py
@@ -0,0 +1,269 @@
+from amaranth import *
+from amaranth.sim import Simulator, Settle, Delay
+from enum import Enum, unique
+
+from hdl.utils import cmd, DubbleBuff
+
+@unique
+class AluOpCodes(Enum):
+ add = 0
+ addc = 1
+ sub = 2
+ subc = 3
+ bit_and = 4
+ bit_or = 5
+ bit_xor = 6
+ bit_nor = 7
+ lleft = 8
+ lright = 9
+ aright = 10
+ set_bit = 11
+ clear_bit = 12
+ umult = 13
+ smult = 14
+ udiv = 15
+ sdiv = 16
+
+class ALU(Elaboratable):
+ def __init__(self, **kargs):
+ self.in1 = Signal(32, reset_less=True)
+ self.in2 = Signal(32, reset_less=True)
+ self.c_in = Signal(1)
+ self.op = Signal(4, reset_less=True)
+
+ self.tmp = Signal(33, reset_less=True)
+
+ self.c_out = Signal(1, reset_less=True)
+ self.overflow = Signal(1, reset_less=True)
+ self.zero = Signal(1, reset_less=True)
+ self.neg = Signal(1, reset_less=True)
+ self.odd = Signal(1, reset_less=True)
+
+ self.out = Signal(32, reset_less=True)
+
+ self.sim = kargs["sim"] if "sim" in kargs else None
+
+ ports_in = [self.in1, self.in2, self.op, self.c_in]
+ ports_out = [self.c_in, self.out, self.c_out, self.overflow, self.zero, self.neg, self.odd]
+ self.ports = {'in': ports_in, 'out': ports_out}
+
+ def elaborate(self, platform=None):
+ m = Module()
+
+ # dummy sync for simulation only
+ if self.sim == True:
+ dummy = Signal()
+ m.d.sync += dummy.eq(~dummy)
+
+ with m.Switch(self.op):
+ with m.Case(AluOpCodes.add.value):
+ m.d.comb += self.tmp.eq(self.in1 + self.in2)
+
+ with m.Case(AluOpCodes.addc.value):
+ m.d.comb += self.tmp.eq(self.in1 + self.in2 + self.c_in)
+
+ with m.Case(AluOpCodes.sub.value):
+ m.d.comb += self.tmp.eq(self.in1 - self.in2)
+
+ with m.Case(AluOpCodes.subc.value):
+ m.d.comb += self.tmp.eq(self.in1 + (~self.in2 + self.c_in))
+
+ with m.Case(AluOpCodes.bit_and.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 & self.in2, 0))
+
+ with m.Case(AluOpCodes.bit_or.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 | self.in2, 0))
+
+ with m.Case(AluOpCodes.bit_xor.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 ^ self.in2, 0))
+
+ with m.Case(AluOpCodes.bit_nor.value):
+ m.d.comb += self.tmp.eq(Cat(~(self.in1 | self.in2), 0))
+
+ with m.Case(AluOpCodes.lleft.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1, 0) << self.in2[0:5])
+
+ with m.Case(AluOpCodes.lright.value):
+ tmp2 = Signal(33)
+ m.d.comb += tmp2.eq(Cat(0, self.in1) >> self.in2[0:5])
+ m.d.comb += self.tmp.eq(Cat(tmp2[1:33], tmp2[0])) # move shifted bit to carry bit
+
+ with m.Case(AluOpCodes.aright.value):
+ tmp2 = Signal(33)
+ m.d.comb += tmp2.eq(Cat(0, self.in1).as_signed() >> self.in2[0:5])
+ m.d.comb += self.tmp.eq(Cat(tmp2[1:33], tmp2[0])) # move shifted bit to carry bit
+
+ with m.Case(AluOpCodes.set_bit.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 | (1 << self.in2[0:5]), 0))
+
+ with m.Case(AluOpCodes.clear_bit.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 & ~(1 << self.in2[0:5]), 0))
+
+ with m.Case(AluOpCodes.umult.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1[0:16] * self.in2[0:16], 0))
+
+ with m.Case(AluOpCodes.smult.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1[0:16].as_signed() * self.in2[0:16].as_signed(), 0))
+
+
+ # bad juju,
+ # TODO: come back and check this will work
+ # with m.Case(AluOpCodes.udiv.value):
+ # m.d.comb += self.tmp.eq(Cat(self.in1 // self.in2, 0))
+
+ # with m.Case(AluOpCodes.sdiv.value):
+ # m.d.comb += self.tmp.eq(self.in1.as_signed() // self.in2.as_signed()) # for some reason I have not confirmed, signed div can yield a 33 bit number, acording to amaranth
+
+ with m.Case():
+ m.d.comb += self.tmp.eq(0)
+
+ m.d.comb += self.c_out.eq(self.tmp[32])
+ m.d.comb += self.overflow.eq(self.tmp[32] ^ self.tmp[31])
+ m.d.comb += self.out.eq(self.tmp[0:32])
+ m.d.comb += self.neg.eq(self.out[31])
+ m.d.comb += self.zero.eq(self.out == 0)
+ m.d.comb += self.odd.eq(self.out.xor()) # 1 if odd number of bits, 0 if even
+
+ return m
+
+def test_alu(filename="alu.vcd"):
+ dut = ALU(sim=True)
+
+ def proc1():
+ def sub_proc(val1, val2, c_in=0):
+ yield dut.in1.eq(val1)
+ yield dut.in2.eq(val2)
+ yield dut.c_in.eq(c_in)
+ yield
+ yield Settle()
+
+ # test addition
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(27, 13)
+ out = yield dut.out
+ assert 27 + 13 == (out), f'ERROR: {out} != {27 + 13}'
+
+ # test addition with carry
+ yield dut.op.eq(AluOpCodes.addc.value)
+ yield from sub_proc(11, 43, 1)
+ out = yield dut.out.as_signed()
+ assert 11 + 43 + 1 == out, f'ERROR: {out} != {11 + 43 + 1}'
+
+ # test subtraction
+ yield dut.op.eq(AluOpCodes.sub.value)
+ yield from sub_proc(25, 13)
+ out = yield dut.out
+ assert 25 - 13 == out, f'ERROR: {out} != {25 - 13}'
+
+ # test subtraction with carry
+ yield dut.op.eq(AluOpCodes.subc.value)
+ yield from sub_proc(25, -13, 0)
+ out = yield dut.out.as_signed()
+ assert 25 + 13 -1 +0 == out, f'ERROR: {out} != {25 + 13 -1 +0}'
+
+ # test subtraction with carry
+ yield dut.op.eq(AluOpCodes.subc.value)
+ yield from sub_proc(25, -13, 1)
+ out = yield dut.out.as_signed()
+ assert 25 + 13 -1 +1 == out, f'ERROR: {out} != {25 + 13 -1 +1}'
+
+ # test binary and
+ yield dut.op.eq(AluOpCodes.bit_and.value)
+ yield from sub_proc(0b10101011, 0b01010101)
+ out = yield dut.out
+ assert 0b00000001 == out, f'ERROR: {out} != {0b00000001}'
+
+ # test binary or
+ yield dut.op.eq(AluOpCodes.bit_or.value)
+ yield from sub_proc(0b10101011, 0b01000101)
+ out = yield dut.out
+ assert 0b11101111 == out, f'ERROR: {out} != {0b11101111}'
+
+ # test binary nor
+ yield dut.op.eq(AluOpCodes.bit_nor.value)
+ yield from sub_proc(0b10001011, 0b01000101)
+ out = yield dut.out
+ assert 0b11111111111111111111111100110000 == out, f'ERROR: {bin(out)} != {bin(0b11111111111111111111111100110000)}'
+
+ # test binary xor
+ yield dut.op.eq(AluOpCodes.bit_xor.value)
+ yield from sub_proc(0b10001011, 0b01000101)
+ out = yield dut.out
+ assert 0b11001110 == out, f'ERROR: {out} != {0b11001110}'
+
+ # test logical shift left
+ yield dut.op.eq(AluOpCodes.lleft.value)
+ yield from sub_proc(0b10001011, 25) # shift left by 5
+ out = yield dut.out
+ assert 0b00010110000000000000000000000000 == out, f'ERROR: {bin(out)} != {bin(0b00010110000000000000000000000000)}'
+ out = yield dut.c_out
+ assert 1 == out, f'ERROR: {out} != {1}'
+
+ # test logical shift right
+ yield dut.op.eq(AluOpCodes.lright.value)
+ yield from sub_proc(0b10001011, 4) # shift right by 5
+ out = yield dut.out
+ assert 0b1000 == out, f'ERROR: {bin(out)} != {bin(0b1000)}'
+ out = yield dut.c_out
+ assert 1 == out, f'ERROR: {out} != {1}'
+
+ # test aligned shift right
+ yield dut.op.eq(AluOpCodes.aright.value)
+ yield from sub_proc(0x80001234, 4) # shift right by 4
+ out = yield dut.out
+ assert 0xF8000123 == out, f'ERROR: {out} != {0xF8000123}'
+ out = yield dut.c_out
+ assert 0 == out, f'ERROR: {out} != {0}'
+
+ # test unsigned overflow
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0xFFFFFFFF, 1) # add 1 to 0xFFFFFFFF
+ out = yield dut.overflow
+ assert out == 1, f'ERROR: {out} != {1}'
+ out = yield dut.c_out
+ assert out == 1, f'ERROR: {out} != {1}'
+
+ # test unsigned underflow
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, -1) # subtract 1 from 0
+ out = yield dut.overflow
+ assert out == 1, f'ERROR: {out} != {1}'
+ out = yield dut.c_out
+ assert out == 0, f'ERROR: {out} != {0}'
+
+ # test zero
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, 0) # add 0 to 0
+ out = yield dut.zero
+ assert out == 1, f'ERROR: {out} != {1}'
+
+ # test zero
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, 1) # add 0 to 0
+ out = yield dut.zero
+ assert out == 0, f'ERROR: {out} != {0}'
+
+ # test odd
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, 0xAAAAAAAA) # add 0 to 0
+ out = yield dut.odd
+ assert out == 0, f'ERROR: {out} != {0}'
+
+ # test odd
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, 0xAAAAAAAB) # add 0 to 0
+ out = yield dut.odd
+ assert out == 1, f'ERROR: {out} != {1}'
+
+
+ sim = Simulator(dut)
+ sim.add_clock(1e-6)
+ sim.add_sync_process(proc1)
+
+ with sim.write_vcd(filename):
+ sim.run()
+
+
+if __name__ == '__main__':
+ hdl = DubbleBuff(ALU())
+ cmd(hdl, test_alu)
diff --git a/hdl/core/core.py b/hdl/core/core.py
new file mode 100644
index 0000000..a00eab3
--- /dev/null
+++ b/hdl/core/core.py
@@ -0,0 +1,36 @@
+from amaranth import *
+from amaranth.sim import Simulator, Settle, Delay
+from enum import Enum, unique
+
+from hdl.utils import cmd
+
+
+
+
+# class ASAP32Core(Elaboratable):
+# def __init__(self):
+# self.interupt_msk = Signal(32)
+# self.interupt_addr = Signal(32)
+# self.interupt_en = Signal(1)
+# self.interupt_sig = Signal(1)
+
+# self.jump = Signal(1)
+# self.instruction_addr = Signal(32)
+
+# self.ports = []
+
+# def elaborate(self, platform=None):
+# m = Module()
+
+# m.submodules.reg = reg = Reg()
+
+# # interupt setup
+# m.d.comb += self.interupt_en.eq(reg.cr[0])
+
+# # get instruction address, account for jumps and interupts
+# m.d.sync += self.instruction_addr.eq(Mux(self.interupt_en & self.interupt_sig, self.interupt_addr, Mux(self.jump, reg.ja, reg.ip)))
+
+# # update program counter
+# m.d.sync += reg.ip.eq(self.instruction_addr + 1)
+
+# return m \ No newline at end of file
diff --git a/hdl/core/reg.py b/hdl/core/reg.py
new file mode 100644
index 0000000..3859dc5
--- /dev/null
+++ b/hdl/core/reg.py
@@ -0,0 +1,289 @@
+from amaranth import *
+from amaranth.sim import Simulator, Settle, Delay
+
+from hdl.utils import cmd
+
+class Reg(Elaboratable):
+ def __init__(self, **kargs): # sim is only for modularity, does nothing for this
+ # enable write
+ self.wr_en = Signal(1)
+
+ # input and output addresses
+ self.rd_addr = Signal(4)
+ self.rs1_addr = Signal(4)
+ self.rs2_addr = Signal(4)
+
+ # input and output signals
+ self.rd = Signal(32)
+ self.rs1 = Signal(32)
+ self.rs2 = Signal(32)
+
+ #interupt enable output signal
+ self.int_en = Signal(1)
+
+ # alu status signals
+ self.alu_flgs = Signal(5)
+
+ # signals stack operation
+ self.stack_instr = Signal(1)
+ self.stack_down_up = Signal(1)
+
+ ##################################################################
+
+ # this is the singal from the control unit, it not affected by interupt enable
+ self.int_sig = Signal(1)
+ # return from interrupt special
+ self.iret = Signal(1)
+ # jump signal to jump and link (swap ip and cs0)
+ self.jump = Signal(1)
+
+ #################################################################
+ # None of the 3 signals above should ever be set at the same time
+ #################################################################
+
+
+ # internal signals
+ self._user_mode = Signal(1)
+ self._sp_inc_dec = Signal(1)
+ self._wr_alu_flg = Signal(1)
+
+ self.zx = Signal(32) #0
+ self.ax = Signal(32) #1
+ self.bx = Signal(32) #2
+ self.bx = Signal(32) #3
+ self.cx = Signal(32) #4
+ self.dx = Signal(32) #5
+ self.ex = Signal(32) #6
+ self.fx = Signal(32) #7
+ self.gx = Signal(32) #8
+ self.hx = Signal(32) #9
+ self.ip = Signal(32) #10
+ self.sp = Signal(32) #11
+ self.flg = Signal(32) #12
+ self.cs0 = Signal(32) #13
+ self.cs1 = Signal(32) #14
+ self.cs2 = Signal(32) #15
+ self.pda = Signal(32) #16
+
+ # for sake of modularity, make bit locations easily configurable
+ setattr(self.flg, 'c', self.flg[0])
+ setattr(self.flg, 'ov', self.flg[1])
+ setattr(self.flg, 'z', self.flg[2])
+ setattr(self.flg, 'n', self.flg[3])
+ setattr(self.flg, 'od', self.flg[4])
+ setattr(self.flg, 'int', self.flg[16])
+ setattr(self.flg, 'user_mode', self.flg[17])
+ setattr(self.flg, 'page_en', self.flg[18])
+
+
+ reg_list = [self.zx, self.ax, self.bx, self.cx, self.dx, self.ex, self.fx, self.gx, self.hx, self.ip, self.sp, self.flg, self.cs0, self.cs1, self.cs2, self.pda]
+ for idx, reg in enumerate(reg_list):
+ setattr(reg, 'idx', idx) # set idx attribute to each register
+
+ self.reg_arr = Array(reg_list)
+
+ ports_in = [self.wr_en, self.alu_flgs, self.jump, self.int_sig, self.iret, self.stack_instr, self.stack_down_up, self.rd_addr, self.rd, self.rs1_addr, self.rs2_addr]
+ ports_out = [self.int_en, self.rs1, self.rs2, self.ip ]
+ self.ports = {'in': ports_in, 'out': ports_out}
+
+
+ def elaborate(self, platform=None):
+ m = Module()
+
+ # user mode override
+ m.d.comb += self.int_en.eq(self.flg.int)
+ m.d.comb += self._user_mode.eq(self.flg.user_mode & ~self.int_sig)
+
+ # toggle ip and cs0
+ with m.If(self.jump | self.int_sig | self.iret):
+ m.d.sync += self.cs0.eq(self.ip)
+ m.d.sync += self.ip.eq(self.cs0)
+ with m.Else():
+ m.d.sync += self.ip.eq(self.ip + 1) # increment ip only on normal operation
+
+ with m.If(self.int_sig):
+ m.d.sync += self.cs1.eq(self.sp)
+ m.d.sync += self.cs2.eq(self.flg)
+ 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):
+ m.d.sync += self.sp.eq(self.cs1)
+ m.d.sync += self.flg.eq(self.cs2)
+
+ m.d.comb += self._sp_inc_dec.eq(0)
+ m.d.comb += self._wr_alu_flg.eq(1)
+
+ # writeback setup
+ with m.If(self.wr_en):
+ with m.Switch(self.rd_addr):
+ with m.Case(self.zx.idx): # do not write to zero register
+ pass
+
+ with m.Case(self.ip.idx): #do not directly write to ip register
+ pass
+
+ with m.Case(self.flg.idx):
+ # mask top half of register to prevent writing to flags in user mode
+ with m.If(~self._user_mode):
+ m.d.sync += self.flg.eq(self.rd) # system mode, full control
+ with m.Else():
+ m.d.sync += self.flg.eq(Cat(self.rd[:16], self.flg[16:])) # usermode can only effect lower 16 bits
+
+ # don't update flags from alu
+ m.d.comb += self._wr_alu_flg.eq(0)
+
+ with m.Case(self.sp.idx):
+ m.d.comb += self._sp_inc_dec.eq(1)
+ m.d.sync += self.sp.eq(self.rd)
+
+ with m.Case():
+ m.d.sync += self.reg_arr[self.rd_addr].eq(self.rd)
+
+ with m.If(self._wr_alu_flg):
+ m.d.sync += self.flg.eq(Cat(self.alu_flgs, self.flg[len(self.alu_flgs):])) # update flags if register is not being written to
+
+ with m.If(~self._sp_inc_dec & self.stack_instr):
+ with m.If(self.stack_down_up):
+ m.d.sync += self.sp.eq(self.sp - 1)
+ with m.Else():
+ m.d.sync += self.sp.eq(self.sp + 1)
+
+
+ ### Combination signal outputs ###
+ with m.Switch(self.rs1_addr):
+ with m.Case(self.flg.idx):
+ m.d.comb += self.rs1.eq(self.flg & Cat(Const(0xFFFF, 16), Repl(~self._user_mode, 16)))
+ with m.Case():
+ m.d.comb += self.rs1.eq(self.reg_arr[self.rs1_addr])
+
+ with m.Switch(self.rs2_addr):
+ with m.Case(self.flg.idx):
+ m.d.comb += self.rs2.eq(self.flg & Cat(Const(0xFFFF, 16), Repl(~self._user_mode, 16)))
+ with m.Case():
+ m.d.comb += self.rs2.eq(self.reg_arr[self.rs2_addr])
+
+ return m
+
+def test_reg(filename="reg.vcd"):
+ dut = Reg(sim=True)
+
+ def init():
+ for i in range(16):
+ yield dut.reg_arr[i].eq(i)
+ yield Settle()
+
+ def step():
+ yield Settle() # settle comb logic before clock
+ yield # clock edge
+ yield Settle() # settle comb logic after clock
+ yield Delay(5e-7) # used for debugging, change values on neg edge of clock
+
+ def proc1():
+ yield from init()
+
+ # test combinational output
+ for i in range(16):
+ yield dut.rs1_addr.eq(i)
+ yield Settle()
+ assert (yield dut.rs1) == i, f'ERROR reading {dut.reg_arr[i].name} != {i}'
+ for i in range(16):
+ yield dut.rs2_addr.eq(i)
+ yield Settle()
+ assert (yield dut.rs2) == i, f'ERROR reading {dut.reg_arr[i].name} != {i}'
+
+ # test writeback with writeback disabled
+ yield from init()
+ for i in range(16):
+ yield dut.rd_addr.eq(i)
+ yield dut.rd.eq(i + 1)
+ yield from step()
+ if (i != dut.ip.idx) and (i != dut.flg.idx): # flag gets update by the alu
+ assert (yield dut.reg_arr[i]) == i, f'ERROR writing to {dut.reg_arr[i].name} != {i}'
+
+ # test writeback with writeback enabled
+ for i in range(16):
+ yield from init()
+ yield dut.wr_en.eq(1)
+ yield dut.rd_addr.eq(i)
+ yield dut.rd.eq(i - 1)
+ yield from step()
+ if (i != dut.zx.idx) and (i != dut.ip.idx):
+ assert (yield dut.reg_arr[i]) == i-1, f'ERROR writing to {dut.reg_arr[i].name} != {i-1}'
+ elif i == dut.zx.idx:
+ assert (yield dut.zx) == 0, f'ERROR {dut.zx.name} != 0'
+ elif i == dut.ip.idx:
+ # ip should be incremented and not written to
+ assert (yield dut.reg_arr[i]) == i+1, f'ERROR {dut.ip.name} != {i + 1} should not be able to be directly written to'
+
+ yield dut.wr_en.eq(0)
+
+ # test flag register security
+ yield dut.flg.eq(0)
+ yield dut.flg.user_mode.eq(1)
+ yield dut.flg[15].eq(1)
+ yield dut.flg[31].eq(1)
+ yield dut.rs1_addr.eq(dut.flg.idx)
+ yield Settle()
+ assert (yield dut.rs1) == 0x00008000, f'ERROR: able to read upper 16 bits of flg reg in user mode'
+
+ # test flag register security
+ yield dut.flg.eq(0)
+ yield dut.wr_en.eq(1)
+ yield dut.flg.user_mode.eq(1)
+ yield dut.flg[15].eq(1)
+ yield dut.flg[31].eq(1)
+ yield dut.rd_addr.eq(dut.flg.idx)
+ yield dut.rd.eq(0xABCD5789)
+ yield from step()
+ assert (yield dut.flg) == (0x80020000 | 0x5789), f'ERROR: able to write to upper 16 bits of flg reg in user mode'
+
+ yield dut.flg.eq(0)
+ yield dut.flg.user_mode.eq(0)
+ yield dut.flg[15].eq(1)
+ yield dut.flg[31].eq(1)
+ yield dut.rs1_addr.eq(dut.flg.idx)
+ yield Settle()
+ assert (yield dut.rs1) == 0x80008000, f'ERROR: able to read all bits of flg reg in system mode'
+
+ yield dut.flg.eq(0)
+ yield dut.wr_en.eq(1)
+ yield dut.flg.user_mode.eq(0)
+ yield dut.flg[15].eq(1)
+ yield dut.flg[31].eq(1)
+ yield dut.rd_addr.eq(dut.flg.idx)
+ yield dut.rd.eq(0xABCD5789)
+ yield from step()
+ assert (yield dut.flg) == (0xABCD5789), f'ERROR: unamble to write to all bits in supervisor mode'
+
+ # make sure not to write alu flags when directly writing to flg register
+ yield dut.flg.eq(0)
+ yield dut.alu_flgs.eq(Repl(1, dut.alu_flgs.width))
+ yield dut.wr_en.eq(1)
+ yield dut.flg.user_mode.eq(0)
+ yield dut.flg[15].eq(1)
+ yield dut.flg[31].eq(1)
+ yield dut.rd_addr.eq(dut.flg.idx)
+ yield dut.rd.eq(0xFFFF0000)
+ yield from step()
+ assert (yield dut.flg) == (0xFFFF0000), f'ERROR: alu status should not be to flag'
+
+ # check to make sure alu is writing values
+ yield dut.flg.eq(0)
+ yield dut.alu_flgs.eq(Repl(1, dut.alu_flgs.width))
+ yield dut.wr_en.eq(1)
+ yield dut.flg.user_mode.eq(0)
+ yield dut.rd_addr.eq(dut.zx.idx) # can be anything except flg register
+ yield dut.rd.eq(0xFFFF0000) # this does not matter
+ yield from step()
+ assert (yield dut.flg) == (yield dut.alu_flgs), f'ERROR: alu is not writing to flg register'
+
+ sim = Simulator(dut)
+ sim.add_clock(1e-6)
+ sim.add_sync_process(proc1)
+
+ with sim.write_vcd(filename):
+ sim.run()
+
+if __name__ == '__main__':
+ reg = Reg()
+ cmd(reg, test_reg) \ No newline at end of file