summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjjsuperpower <jjs29356@gmail.com>2022-08-27 01:29:54 -0500
committerjjsuperpower <jjs29356@gmail.com>2022-08-27 01:29:54 -0500
commitd330e0d3da068837684eb51ce1a0e4410440d7a9 (patch)
treeb853883e42ed2ac005b43fda76f9fae37df32934
parent673c7dc0868e8dbbfbc2c327fd78610d7631188f (diff)
coded but not tested Register file
-rw-r--r--doc/ASAP32-ISA.md14
-rw-r--r--hdl/core.py184
2 files changed, 150 insertions, 48 deletions
diff --git a/doc/ASAP32-ISA.md b/doc/ASAP32-ISA.md
index c6a0d54..111dec9 100644
--- a/doc/ASAP32-ISA.md
+++ b/doc/ASAP32-ISA.md
@@ -49,19 +49,18 @@ I propose a different name:
EX GP-4
FX GP-5
GX GP-6
- FX GP-7
- FLG Processor Flags
+ HX GP-7
IP Instruction Pointer
SP Stack Pointer
+ FLG Processor Flags
CS0 Control status 0 (saves IP)
CS1 Control status 1 (saves SP)
CS2 Control status 2 (saves FLG)
- RS0 RESERVED
+ PDA Page Directory Address
### FLG Flag Register Bitfield
- These registers are Read/Write
- They are automaticaly written to by the CPU
- Top-half registers are supervisor only
+ The lower half is read/write
+ The upper half can be read or written to in supervisor mode only
FLG[0] Carry
FLG[1] Overflow
@@ -150,10 +149,11 @@ I propose a different name:
PUSHR RS SP+=1 ;*SP = RS
POPR RS RS = *SP ;SP-=1
PUSHI IMM SP+=1 ;*SP = IMM
- INVP IMM Invalidate entry in TLB
+ INVP IMM Invalidate entry in TLB*
JMP IMM Jump to address IMM
CALL LABEL CS0=IP; IP=LABEL
INT IMM CS0=IP; CS1=SP; CS2=FLG; IP=IDT[IMM]*
+ SCALL Same as call but is used to make calls to the kernel (fixed IDT address)
IRET IP=CS0; SP=CS1; FLG=CS2*
RET IP = CS0
SIF Set interrupt flag*
diff --git a/hdl/core.py b/hdl/core.py
index 655af68..c1e38cc 100644
--- a/hdl/core.py
+++ b/hdl/core.py
@@ -1,4 +1,6 @@
+from curses.ascii import SI
from multiprocessing import dummy
+from tkinter import S
from amaranth import *
from amaranth.sim import Simulator, Settle, Delay
from enum import Enum, unique
@@ -6,49 +8,145 @@ from enum import Enum, unique
from utils import cmd
-# class Reg(Elaboratable):
-# def __init__(self):
-# self.rd_addr = Signal(4)
-# self.rs1_addr = Signal(4)
-# self.rs2_addr = Signal(4)
-
-# self.rd = Signal(32)
-# self.rs1 = Signal(32)
-# self.rs2 = Signal(32)
-
-# self.zx = Signal(32)
-# self.ax = Signal(32)
-# self.bx = Signal(32)
-# self.bx = Signal(32)
-# self.cx = Signal(32)
-# self.dx = Signal(32)
-# self.ex = Signal(32)
-# self.fx = Signal(32)
-# self.gx = Signal(32)
-# self.hx = Signal(32)
-# self.hi = Signal(32)
-# self.lo = Signal(32)
-# self.fg = Signal(32)
-# self.cr = Signal(32)
-# self.ip = Signal(32)
-# self.sp = Signal(32)
-# self.ja = Signal(32)
-
-# self.reg_ar = Array([self.zx, self.ax, self.bx, self.cx, self.dx, self.ex, self.fx, self.gx, self.hx, self.hi, self.lo, self.fg, self.cr, self.ip, self.sp, self.ja])
-
-# # TODO: add support for storing multiplication result
-# self.ports = [self.rd_addr, self.rs1_addr, self.rs2_addr, self.rd, self.rs1, self.rs2, self.ip]
+class Reg(Elaboratable):
+ def __init__(self):
+ # enable write
+ self.wr_en = Signal(1)
-# def elaborate(self, platform=None):
-# m = Module()
+ # input and output addresses
+ self.rd_addr = Signal(4)
+ self.rs1_addr = Signal(4)
+ self.rs2_addr = Signal(4)
-# with m.If(self.rd_addr != 0):
-# m.d.sync += self.reg_ar[self.rd_addr].eq(self.rd)
+ # input and output signals
+ self.rd = Signal(32)
+ self.rs1 = Signal(32)
+ self.rs2 = Signal(32)
-# m.d.comb += self.rs1.eq(self.reg_ar[self.rs1_addr])
-# m.d.comb += self.rs2.eq(self.reg_ar[self.rs2_addr])
+ # alu status signals
+ self.alu_flgs = Signal(5)
-# return m
+ self.stack_instr = Signal(1)
+ self.stack_down_up = Signal(1)
+
+ ##################################################################
+
+ # activated when interupt is triggered
+ self.interupt = 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._interupt = Signal(1)
+ self._sp_write = 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)
+ self.ports = [self.wr_en, self.alu_flgs, self.jump, self.interupt, self.iret, self.stack_instr, self.stack_down_up, self.rd_addr, self.rs1_addr, self.rs2_addr, self.rd, self.rs1, self.rs2, self.ip]
+
+ def elaborate(self, platform=None):
+ m = Module()
+
+ # user mode override
+ m.d.comb += self._interupt.eq(self.flg.int & self.interupt) # if the sw guy don't want to be interupted, don't
+ m.d.comb += self._user_mode.eq(self.flg.user_mode & ~self._interupt)
+
+ # toggle ip and cs0
+ with m.If(self.jump | self._interupt | 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._interupt):
+ 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_write.eq(0)
+
+ # 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
+ m.d.sync += self.flg.eq(self.rd & Cat(Const(0xFFFF, 16), Repl(~self._user_mode, 16)))
+ with m.Case(self.sp.idx):
+ m.d.comb += self._sp_write.eq(1)
+ m.d.sync += self.sp.eq(self.rd)
+ with m.Case():
+ 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
+ m.d.sync += self.reg_arr[self.rd_addr].eq(self.rd)
+
+ with m.If(~self._sp_write & 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
# class ASAP32Core(Elaboratable):
@@ -323,6 +421,10 @@ def test_alu(filename="alu.vcd"):
sim.run()
+
if __name__ == '__main__':
- hdl = ALU()
- cmd(hdl, test_alu)
+ reg = Reg()
+ cmd(reg, None)
+
+ # hdl = ALU()
+ # cmd(hdl, test_alu)