From 63626f2f6fc7e8912a349f120e37998cd1a05554 Mon Sep 17 00:00:00 2001 From: jjsuperpower Date: Mon, 5 Sep 2022 20:04:52 -0500 Subject: moveing file around --- .vscode/settings.json | 2 +- ASAP32-ISA.md | 195 ++++++++++++++++++++++ archive/myhdl/.gitignore | 7 + archive/myhdl/Makefile | 13 ++ archive/myhdl/hdl/constants.py | 8 + archive/myhdl/hdl/multiply.py | 205 +++++++++++++++++++++++ archive/myhdl/hdl/myhdl_wrap.py | 47 ++++++ archive/myhdl/hdl/reset_sync.py | 109 +++++++++++++ archive/myhdl/hdl/shift_reg.py | 118 ++++++++++++++ archive/myhdl/myhdl.vpi | Bin 0 -> 32216 bytes archive/myhdl/template.py | 69 ++++++++ archive/testing/async_reset.py | 21 +++ archive/testing/multi_clock.py | 75 +++++++++ archive/testing/up_counter.py | 50 ++++++ archive/testing/up_counter_tb.py | 30 ++++ deprecated/hdl_lab/.gitignore | 7 - deprecated/hdl_lab/Makefile | 13 -- deprecated/hdl_lab/hdl/constants.py | 8 - deprecated/hdl_lab/hdl/multiply.py | 205 ----------------------- deprecated/hdl_lab/hdl/myhdl_wrap.py | 47 ------ deprecated/hdl_lab/hdl/reset_sync.py | 109 ------------- deprecated/hdl_lab/hdl/shift_reg.py | 118 -------------- deprecated/hdl_lab/myhdl.vpi | Bin 32216 -> 0 bytes deprecated/hdl_lab/template.py | 69 -------- doc/ASAP32-ISA.md | 195 ---------------------- hdl/core/reg.py | 304 ----------------------------------- hdl/testing/async_reset.py | 21 --- hdl/testing/multi_clock.py | 75 --------- hdl/testing/up_counter.py | 50 ------ hdl/testing/up_counter_tb.py | 30 ---- hdl/testing/v | 0 requirements.txt | 3 +- 32 files changed, 950 insertions(+), 1253 deletions(-) create mode 100644 ASAP32-ISA.md create mode 100644 archive/myhdl/.gitignore create mode 100644 archive/myhdl/Makefile create mode 100644 archive/myhdl/hdl/constants.py create mode 100644 archive/myhdl/hdl/multiply.py create mode 100644 archive/myhdl/hdl/myhdl_wrap.py create mode 100644 archive/myhdl/hdl/reset_sync.py create mode 100644 archive/myhdl/hdl/shift_reg.py create mode 100755 archive/myhdl/myhdl.vpi create mode 100644 archive/myhdl/template.py create mode 100644 archive/testing/async_reset.py create mode 100644 archive/testing/multi_clock.py create mode 100644 archive/testing/up_counter.py create mode 100644 archive/testing/up_counter_tb.py delete mode 100644 deprecated/hdl_lab/.gitignore delete mode 100644 deprecated/hdl_lab/Makefile delete mode 100644 deprecated/hdl_lab/hdl/constants.py delete mode 100644 deprecated/hdl_lab/hdl/multiply.py delete mode 100644 deprecated/hdl_lab/hdl/myhdl_wrap.py delete mode 100644 deprecated/hdl_lab/hdl/reset_sync.py delete mode 100644 deprecated/hdl_lab/hdl/shift_reg.py delete mode 100755 deprecated/hdl_lab/myhdl.vpi delete mode 100644 deprecated/hdl_lab/template.py delete mode 100644 doc/ASAP32-ISA.md delete mode 100644 hdl/core/reg.py delete mode 100644 hdl/testing/async_reset.py delete mode 100644 hdl/testing/multi_clock.py delete mode 100644 hdl/testing/up_counter.py delete mode 100644 hdl/testing/up_counter_tb.py delete mode 100644 hdl/testing/v diff --git a/.vscode/settings.json b/.vscode/settings.json index 3dc66b5..4b701d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,5 @@ "hdl" ], "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true + "python.testing.pytestEnabled": true, } \ No newline at end of file diff --git a/ASAP32-ISA.md b/ASAP32-ISA.md new file mode 100644 index 0000000..f5fed66 --- /dev/null +++ b/ASAP32-ISA.md @@ -0,0 +1,195 @@ +# Vertex KISS 32 - Machine Code Spec +^ So Vertex is already a name for an FPGA, should we change this? +I propose a different name: + + ASAP Soc 32 a KISS architecture + + As + Simple + As + Possible + +## General Instruction Format + X = HEX + B = BIN + + MAX INSTRUCTIIONS = 256 + ALL INSTRUCTIONS ARE ATOMIC + +### C-Type, Control + XX X X XXXX + Opcode d RS1 IMM + +### I-Type, Immediate + XX X X XXXX + Opcode RD RS1 IMM + +### R-Type, Arithmetic + XX X X X XXX + Opcode RD RS1 RS2 Offset (Load/Store Only) + +### JR-Type, Compare and Jump + XX X X X XXX + Opcode Jump Condition RS1 RS2 ddd + +### JI-Type, Compare and Jump + XX X X XXXX + Opcode Jump Condition RS1 IMM + +## Registers + Maximum registers = 16 + Register width = 32 + All are R/W except 0X + + 0X Always Zero + AX GP-0 + BX GP-1 + CX GP-2 + DX GP-3 + EX GP-4 + FX GP-5 + GX GP-6 + 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) + PDA Page Directory Address + +### FLG Flag Register Bitfield + 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 + FLG[2] Zero + FLG[3] Sign + FLG[4] Odd (parity) + FLG[5-15] RESERVED + FLG[16] Interrupt enable* + FLG[17] User mode* + FLG[18] Paging enabled* + FLG[19-31] RESERVED* + + *Must be in supervisor mode (FLG[17]=0) to set + +## Integer Instructions + +### R-Type + ADD RD, RS1, RS2 RD = RS1 + RS2 + SUB RD, RS1, RS2 RD = RS1 - RS2 + XOR RD, RS1, RS2 RD = RS1 ^ RS2 + OR RD, RS1, RS2 RD = RS1 | RS2 + AND RD, RS1, RS2 RD = RS1 & RS2 + LSL RD, RS1, RS2 RD = RS1 << RS2 (logical) + LSR RD, RS1, RS2 RD = RS1 >> RS2 (logical) + ASR RD, RS1, RS2 RD = RS1 >> RS2 + MUL RD, RS1, RS2 RD = RS1 * RS2 + MULU RD, RS1, RS2 RD = RS1 * RS2 (unsigned) + DIV RD, RS1, RS2 RD = RS1 / RS2 + DIVU RD, RS1, RS2 RD = RS1 / RS2 (unsigned) + + *DIV is based on shift-and-multiply algorithm + *DIV Ex: 8000/192 + (8000/64)/3 + (8000>>6)/3 + (8000>>6)*0x5555>>16=41 + +### I-Type + ADDI RD, RS, IMM RD = RS + IMM + SUBI RD, RS, IMM RD = RS - IMM + XORI RD, RS, IMM RD = RS ^ IMM + ORI RD, RS, IMM RD = RS | IMM + ANDI RD, RS, IMM RD = RS & IMM + LSLI RD, RS, IMM RD = RS << IMM (logical) + LSRI RD, RS, IMM RD = RS >> IMM (logical) + ASRI RD, RS, IMM RD = RS >> IMM + DIVI RD, RS, IMM RD = RS / IMM + DIVIU RD, RS, IMM RD = RS / IMM (unsigned) + +### JR Instructions + JMP 0 if (True) + JMP 1 if (RS1 != RS2) + JMP 2 if (RS1 == RS2) + JMP 3 if (RS1 > RS2) Unsigned + JMP 4 if (RS1 >= RS2) Unsigned + + JMP C if (RS1 > RS2) Signed + JMP D if (RS1 >= RS2) Signed + +### JI Instructions + Compare and then jump (IP = JMP) + + JMPI 0 if (True) + JMPI 1 if (RS1 != IMM) + JMPI 2 if (RS1 == IMM) + JMPI 3 if (RS1 > IMM) Unsigned + JMPI 4 if (RS1 >= IMM) Unsigned + + JMPI C if (RS1 > IMM) Signed + JMPI D if (RS1 >= IMM) Signed + +### Jump Aliases + JEQ + JLT + JGT + JLE + JGE + JLTU + JGTU + JLEU + JGEU + + +### Control Instructions + NOP Do nothing -> opcode = ZERO + HLT Spinlock the CPU* + PUSHR RS SP+=1 ;*SP = RS + POPR RS RS = *SP ;SP-=1 + PUSHI IMM SP+=1 ;*SP = IMM + 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* + CIF Clear interrupt flag* + + *Requires processor to be in supervisor mode (FLG[17]=0) + +## Interrupt Descriptor Table +This will be in a fixed memory location, this will contain pointers to the interupt +function. + + IDT[0] Divide-by-zero exception + IDT[1] Hardware error (NMI) + IDT[2] Overflow + IDT[3] Invalid Opcode + IDT[4] General-protection fault + IDT[5] Page fault + IDT[6] Software interrupt (reserved for OS) + IDT[7-31] RESERVED + IDT[32-255] Platform interrupts (PIC, hard drive, keyboard, etc.) + +## Page Directory + +The page directory contains 1024 page tables that have 1024 entries that are +4096 bytes wide. Optionally, the page table can be 4MB bytes wide with a setting +in the page table. If this bit is set, there is 1024 entries in the page +directory; otherwise, there are 2^20 entries. + +### Page table layout + + PT[0] Present + PT[1] R/W + PT[2] User-mode + PT[3] Accessed + PT[4] Dirty + PT[5] PWT + PT[6] Cache-disable + PT[7] Page size (0=4KB 1=4MB) + PT[8-31] Physical address of page diff --git a/archive/myhdl/.gitignore b/archive/myhdl/.gitignore new file mode 100644 index 0000000..3f63f69 --- /dev/null +++ b/archive/myhdl/.gitignore @@ -0,0 +1,7 @@ +quartus +gen_verilog +simulation +.vscode +__pycache__ +**__pycache__ +.pytest_cache \ No newline at end of file diff --git a/archive/myhdl/Makefile b/archive/myhdl/Makefile new file mode 100644 index 0000000..10ace11 --- /dev/null +++ b/archive/myhdl/Makefile @@ -0,0 +1,13 @@ + +HDL_FOLDER = ./hdl +HDL = $(wildcard $(HDL_FOLDER)/*.py) + + +test: + py.test --disable-pytest-warnings -v $(HDL) + +test-w: + py.test -v $(HDL) + +clean: + $(RM) -rf simulation/* gen_verilog/* hdl/__pycache__ .pytest_cache \ No newline at end of file diff --git a/archive/myhdl/hdl/constants.py b/archive/myhdl/hdl/constants.py new file mode 100644 index 0000000..ca02497 --- /dev/null +++ b/archive/myhdl/hdl/constants.py @@ -0,0 +1,8 @@ +SIM_DIR = './simulation/' +GEN_VERILOG = './gen_verilog/' + +IVERILOG = 'iverilog ' +VVP = 'vvp -M ./ -m myhdl ' + +RESET_ACTIVE = False +RESET_INACTIVE = not RESET_ACTIVE \ No newline at end of file diff --git a/archive/myhdl/hdl/multiply.py b/archive/myhdl/hdl/multiply.py new file mode 100644 index 0000000..015f67a --- /dev/null +++ b/archive/myhdl/hdl/multiply.py @@ -0,0 +1,205 @@ +from turtle import width +from typing import Callable +from myhdl import * +from constants import RESET_ACTIVE +from myhdl_wrap import Myhdl_Wrapper + +import random +from random import randint + +random.seed(63) + +class Multiply(Myhdl_Wrapper): + def __init__(self): + super().__init__() + + # Main code, this is the actual logic + @staticmethod + @block + def Multiply(clk : Signal, reset : Signal, a : Signal, b : Signal, prod : Signal, is_signed : Signal, ready : Signal, valid : Signal): # this must be the same name as the class name + + width_a = len(a) + width_b = len(b) + width_prod = len(a) + len(b) + + a0 = Signal(modbv(0)[width_a:]) + b0 = Signal(modbv(0)[width_b:]) + a1 = Signal(modbv(0)[width_a:]) + b1 = Signal(modbv(0)[width_b:]) + prod_raw = Signal(modbv(0)[width_prod:]) + + @instance + def logic(): + while True: + yield valid.posedge + a0.next = a + b0.next = b + + yield clk.posedge + ready.next = False + + if not is_signed: + a1.next = a0 + b1.next = b0 + else: + if(a0.signed() < 0): + a1.next = -a0.signed() + else: + a1.next = a0 + + if(b0.signed() < 0): + b1.next = -b0.signed() + else: + b1.next = b0 + + prod_raw.next = a1 * b1 + + if is_signed: + if (a0[width_a-1] ^ b0[width_b-1]) == 1: + prod.next = -prod_raw + else: + prod.next = prod_raw + pass + else: + prod.next = prod_raw + + ready.next = True + + return logic + + + @block + def tb(self, func: Callable): + reset = Signal(False) + clk = Signal(bool(0)) + a = Signal(intbv(0)[32:]) + b = Signal(intbv(0)[32:]) + prod = Signal(modbv(0)[64:]) + is_signed = Signal(bool(0)) + ready = Signal(bool(1)) + valid = Signal(bool(0)) + + a_signed = intbv(0, -int(a.max/2), int(a.max/2)-1) + b_signed = intbv(0, -int(b.max/2), int(b.max/2)-1) + + + dut = func(clk=clk, reset=reset, a=a, b=b, prod=prod, is_signed=is_signed, ready=ready, valid=valid) + + @always(delay(2)) + def clock_gen(): + clk.next = not clk + + @instance + def monitor(): + # print(f"ready: {ready}, valid: {valid}") + # print("-"*20) + while True: + yield ready, valid + # print(f"ready: {ready}, valid: {valid}") + + @instance + def stimulus(): + yield clk.negedge + + # unsigned test + for i in range(30): + a_int = randint(a.min, a.max-1) + b_int = randint(b.min, b.max-1) + a.next = a_int + b.next = b_int + + valid.next = True + yield ready.negedge + valid.next = False + + yield ready.posedge + yield delay(1) + assert int(prod) == a_int * b_int, "Unsigned multiplication error random" + + # unsigned extremes test + for a_int in (a.min, a.max-1): + for b_int in (b.min, b.max-1): + a.next = a_int + b.next = b_int + + valid.next = True + yield ready.negedge + valid.next = False + + yield ready.posedge + yield delay(1) + + assert int(prod) == a_int * b_int, "Unsigned multiplication error extreme" + + + is_signed.next = True + yield clk.negedge + + for i in range(30): + a_int = randint(a_signed.min, a_signed.max-1) + b_int = randint(b_signed.min, b_signed.max-1) + + a_signed[:] = a_int + b_signed[:] = b_int + a.next = a_signed.unsigned() + b.next = b_signed.unsigned() + + valid.next = True + yield ready.negedge + valid.next = False + + yield ready.posedge + yield delay(1) + + # print('-'*30) + # print(prod) + # print(a_int * b_int) + + assert int(prod.signed()) == a_int * b_int, "Signed multiplication error random" + + + for a_int in (a_signed.min, 0, a_signed.max-1): + for b_int in (b_signed.min, 0, b_signed.max-1): + + a_signed[:] = a_int + b_signed[:] = b_int + a.next = a_signed.unsigned() + b.next = b_signed.unsigned() + + valid.next = True + yield ready.negedge + valid.next = False + + yield ready.posedge + yield delay(1) + + assert int(prod.signed()) == a_int * b_int, "Signed multiplication error extreme" + + + raise StopSimulation + + + return dut, clock_gen, monitor, stimulus + + def export(self): + reset = Signal(False) + clk = Signal(False) + a = Signal(intbv(0)[32:]) + b = Signal(intbv(0)[32:]) + prod = Signal(modbv(0)[64:]) + is_signed = Signal(False) + ready = Signal(True) + valid = Signal(False) + + # assigning signals, kargs only + self._export(clk=clk, reset=reset, a=a, b=b, prod=prod, is_signed=is_signed, ready=ready, valid=valid) + + +def test_template_sim(): + hdl = Multiply() + hdl.sim() + +def test_template_cosim(): + hdl = Multiply() + hdl.export() + hdl.cosim() diff --git a/archive/myhdl/hdl/myhdl_wrap.py b/archive/myhdl/hdl/myhdl_wrap.py new file mode 100644 index 0000000..56c8c5b --- /dev/null +++ b/archive/myhdl/hdl/myhdl_wrap.py @@ -0,0 +1,47 @@ +import os +from myhdl import * +from constants import * + +class Myhdl_Wrapper(): + def __init__(self): + self.class_name = self.__class__.__name__ + + def _export(self, **kargs): + inst = getattr(self, self.class_name)(**kargs) + inst.convert(hdl='Verilog', path=GEN_VERILOG, name=f"{self.class_name}") + + test_bench_file = GEN_VERILOG + 'tb_' +self.class_name + '.v' + test_bench_tmp_file = GEN_VERILOG + '~tb_' +self.class_name + '.v' + + # this is needed to generate cosim vcd file + with open(test_bench_file) as f_old, open(test_bench_tmp_file, 'w') as f_new: + lines = f_old.readlines() + for line in lines: + f_new.write(line) + if 'initial begin' in line: + f_new.write('\n') + f_new.write(' // Needed to create vcd file\n') + f_new.write(f' $dumpfile ("{SIM_DIR + self.class_name}_cosim.vcd");\n') + f_new.write(f' $dumpvars(0, tb_{self.class_name});\n') + f_new.write('\n') + os.rename(test_bench_tmp_file, test_bench_file) + + + + # This function links myhdl to icarus verilog sim + def _cosim(self, **kargs): #these should have the same signals as logic(), + + iverilog_cmd = IVERILOG + f"-o {SIM_DIR}{self.class_name}.o {GEN_VERILOG}{self.class_name}.v {GEN_VERILOG}tb_{self.class_name}.v" + vvp_cmd = VVP + f"{SIM_DIR}{self.class_name}.o" + + os.system(iverilog_cmd) + return Cosimulation(vvp_cmd, **kargs) + + def sim(self): + tb = self.tb(getattr(self, self.class_name)) + tb.config_sim(trace=True, tracebackup=False, directory=SIM_DIR, filename=f"{self.class_name}_sim") + tb.run_sim() + + def cosim(self): + tb = self.tb(self._cosim) + tb.run_sim() \ No newline at end of file diff --git a/archive/myhdl/hdl/reset_sync.py b/archive/myhdl/hdl/reset_sync.py new file mode 100644 index 0000000..af03075 --- /dev/null +++ b/archive/myhdl/hdl/reset_sync.py @@ -0,0 +1,109 @@ +from typing import Callable +from myhdl import * +from myhdl_wrap import Myhdl_Wrapper + +import random +from random import randint + +random.seed(13) + +class ResetSync(Myhdl_Wrapper): + def __init__(self): + super().__init__() + + # Main code, this is the actual logic + @staticmethod + @block + def ResetSync(clk : Signal, async_reset : Signal, sync_reset : Signal): # this must be the same name as the class name + + sync = Signal(False) + guard = sync_reset + + @instance + def logic(): + while True: + yield clk.posedge, async_reset.negedge + + if not async_reset: + guard.next = False + sync.next = False + else: + guard.next = sync + sync.next = True + + return logic + + + @block + def tb(self, func: Callable): + async_reset = Signal(False) + sync_reset = Signal(False) + clk = Signal(False) + + dut = func(clk=clk, async_reset=async_reset, sync_reset=sync_reset) + + @always(delay(2)) + def clock_gen(): + clk.next = not clk + + @instance + def monitor_async(): + while True: + yield async_reset.negedge + yield delay(1) + assert sync_reset == False, 'Reset not asynchronous on falling edge' + + @instance + def monitor_sync(): + while True: + yield async_reset.posedge + + assert sync_reset == False, 'sync Reset did not wait for first clock positive edge' + + yield clk.posedge, async_reset.negedge + if async_reset == True: + yield delay(0) + assert sync_reset == False, 'sync Reset did not wait for second clock positive edge' + + yield clk.posedge, async_reset.negedge + if async_reset == True: + yield delay(0) + assert sync_reset == True, 'sync Reset did not set' + + + + @instance + def stimulus(): + for _ in range(500): + yield delay(randint(0,20)) + + if (now()+2) % 4 == 0: # do not create rising edge of reset and clk at the same time + yield(delay(1)) + + async_reset.next = True + yield delay(randint(0, 20)) + async_reset.next = False + + raise StopSimulation + + + return dut, clock_gen, monitor_async, monitor_sync, stimulus + + def export(self): + async_reset = Signal(False) + sync_reset = Signal(False) + clk = Signal(bool(0)) + + # assigning signals, kargs only + self._export(clk=clk, async_reset=async_reset, sync_reset=sync_reset) + + +def test_reset_sync_sim(): + hdl = ResetSync() + hdl.sim() + +def test_reset_sync_cosim(): + hdl = ResetSync() + hdl.export() + hdl.cosim() + diff --git a/archive/myhdl/hdl/shift_reg.py b/archive/myhdl/hdl/shift_reg.py new file mode 100644 index 0000000..9c1c6be --- /dev/null +++ b/archive/myhdl/hdl/shift_reg.py @@ -0,0 +1,118 @@ +from myhdl import * +from myhdl_wrap import Myhdl_Wrapper + +import random +from random import randint + +random.seed(63) + +class ShiftReg(Myhdl_Wrapper): + def __init__(self): + super().__init__() + + # Main code, this is the actual logic + @staticmethod + @block + def ShiftReg(reset: Signal, clk: Signal, load: Signal, in0: Signal, out0: Signal, left_right: Signal): + + width = len(out0) + + @instance + def shifter(): + while True: + yield clk.posedge, reset.negedge + + if not reset: + out0.next = load + else: + if not left_right: + out0.next[width:1] = out0[width-1:0] + out0.next[1:0] = in0 + else: + out0.next[width-1:0] = out0[width:1] + out0.next[width:width-1] = in0 + + return shifter + + + @block + def tb(self, func): + reset = Signal(False) + clk = Signal(bool(0)) + load = Signal(intbv(0xA5)[8:]) + in0 = Signal(bool(0)) + out0 = Signal(modbv(int(load))[8:]) + left_right = Signal(bool(0)) + + dut = func(reset=reset, clk=clk, load=load, in0=in0, out0=out0, left_right=left_right) + + @always(delay(2)) + def clock_gen(): + clk.next = not clk + + @instance + def monitor(): + last_val = out0 + + while True: + yield clk.posedge, reset.negedge + yield delay(1) + + if reset == False: + assert out0 == load, "Is output is not zero at reset" + + else: + if not left_right: + assert int(out0) == ((last_val << 1) & 0xFF) | int(in0), "Not shifting left correctly" + else: + assert int(out0) == ((last_val >> 1) & 0xFF) | (int(in0) << 7), "Not shifting rigth correctly" + + last_val = int(out0) + + @instance + def reset_test(): + yield clk.negedge + reset.next = True + while True: + reset.next = True + yield delay(randint(25, 28)) + + reset.next = False + yield delay(randint(1,4)) + + @instance + def stimulus(): + for i in range(20): + yield clk.negedge + left_right.next = 0 + in0.next = randint(0, 1) + + for i in range(20): + yield clk.negedge + left_right.next = 1 + in0.next = randint(0, 1) + + raise StopSimulation + + + return dut, clock_gen, monitor, stimulus, reset_test + + def export(self): + reset = Signal(False) + clk = Signal(bool(0)) + load = Signal(intbv(0xA5)[8:]) + in0 = Signal(bool(0)) + out0 = Signal(modbv(int(load))[8:]) + left_right = Signal(bool(0)) + + self._export(reset=reset, clk=clk, load=load, in0=in0, out0=out0, left_right=left_right) + + +def test_shift_reg_sim(): + hdl = ShiftReg() + hdl.sim() + +def test_shift_reg_cosim(): + hdl = ShiftReg() + hdl.export() + hdl.cosim() diff --git a/archive/myhdl/myhdl.vpi b/archive/myhdl/myhdl.vpi new file mode 100755 index 0000000..1b9d393 Binary files /dev/null and b/archive/myhdl/myhdl.vpi differ diff --git a/archive/myhdl/template.py b/archive/myhdl/template.py new file mode 100644 index 0000000..77eb18c --- /dev/null +++ b/archive/myhdl/template.py @@ -0,0 +1,69 @@ +from typing import Callable +from myhdl import * +from myhdl_wrap import Myhdl_Wrapper + +import random +from random import randint + +random.seed(63) + +class Template(Myhdl_Wrapper): + def __init__(self): + super().__init__() + + # Main code, this is the actual logic + @staticmethod + @block + def Template(args): # this must be the same name as the class name + + @instance + def logic(): + while True: + ... + + return logic + + + @block + def tb(self, func: Callable): + reset = Signal(False) + clk = Signal(False) + ... + + dut = func(..., clk=clk, reset=reset) + + @always(delay(...)) + def clock_gen(): + clk.next = not clk + + @instance + def monitor(): + while True: + ... + + @instance + def stimulus(): + ... + + raise StopSimulation + + + return dut, clock_gen, monitor, stimulus + + def export(self): + reset = Signal(False) + clk = Signal(False) + ... + + # assigning signals, kargs only + self._export(..., clk=clk, reset=reset) + + +def test_template_sim(): + hdl = Template() + hdl.sim() + +def test_template_cosim(): + hdl = Template() + hdl.export() + hdl.cosim() diff --git a/archive/testing/async_reset.py b/archive/testing/async_reset.py new file mode 100644 index 0000000..4760df7 --- /dev/null +++ b/archive/testing/async_reset.py @@ -0,0 +1,21 @@ +from amaranth import * +from amaranth.cli import main + + +class ClockDivisor(Elaboratable): + def __init__(self, factor): + self.v = Signal(factor) + self.o = Signal() + + def elaborate(self, platform): + m = Module() + m.d.sync += self.v.eq(self.v + 1) + m.d.comb += self.o.eq(self.v[-1]) + return m + + +if __name__ == "__main__": + m = Module() + m.domains.sync = sync = ClockDomain("sync", async_reset=True) + m.submodules.ctr = ctr = ClockDivisor(factor=16) + main(m, ports=[ctr.o, sync.clk]) \ No newline at end of file diff --git a/archive/testing/multi_clock.py b/archive/testing/multi_clock.py new file mode 100644 index 0000000..e377156 --- /dev/null +++ b/archive/testing/multi_clock.py @@ -0,0 +1,75 @@ +import sys +from amaranth import * +from amaranth.back import verilog, cxxrtl +from amaranth.cli import main +from amaranth.sim import Simulator, Settle, Delay + +BASENAME = "multi_clock" + +class SubM(Elaboratable): + def __init__(self, domain=None): + self.inv = Signal() + self.domain=domain + + def elaborate(self, platform): + m = Module() + + m.d.sync += self.inv.eq(~self.inv) + + return m + +class top(Elaboratable): + def __init__(self): + self.sig_slow = Signal() + self.sig_fast = Signal() + + self.div = Signal(2) + + def elaborate(self, platform): + m = Module() + + m.domains += ClockDomain('slow') + m.d.sync += [self.div.eq(self.div + 1)] + m.d.comb += ClockSignal('slow').eq(self.div[-1]) + + m.submodules.subm1 = SubM() + m.submodules.subm2 = DomainRenamer("slow")(SubM()) + + m.d.sync += self.sig_fast.eq(m.submodules.subm1.inv) + m.d.slow += self.sig_slow.eq(m.submodules.subm2.inv) + + return m + +def test_shift_reg(): + dut = top() + + def proc1(): + for _ in range(16): + yield + yield Settle() + + sim = Simulator(dut) + sim.add_clock(1e-6) + sim.add_sync_process(proc1) + + with sim.write_vcd(BASENAME + '.vcd'): + sim.run() + + +if __name__ == '__main__': + + if sys.argv[1] == "sim": + test_shift_reg() + exit() + + # m = ShiftReg(8) + + # if sys.argv[1] == "v": + # out = verilog.convert(m, ports=m.ports) + # with open(BASENAME + '.v','w') as f: + # f.write(out) + + # elif sys.argv[1] == "cc": + # out = cxxrtl.convert(m, ports=m.ports) + # with open(BASENAME + '.cc','w') as f: + # f.write(out) diff --git a/archive/testing/up_counter.py b/archive/testing/up_counter.py new file mode 100644 index 0000000..050a6b0 --- /dev/null +++ b/archive/testing/up_counter.py @@ -0,0 +1,50 @@ +from amaranth import * +from amaranth.back import verilog + + +class UpCounter(Elaboratable): + """ + A 16-bit up counter with a fixed limit. + + Parameters + ---------- + limit : int + The value at which the counter overflows. + + Attributes + ---------- + en : Signal, in + The counter is incremented if ``en`` is asserted, and retains + its value otherwise. + ovf : Signal, out + ``ovf`` is asserted when the counter reaches its limit. + """ + + def __init__(self, limit): + self.limit = limit + + # Ports + self.en = Signal() + self.ovf = Signal() + + # State + self.count = Signal(16) + + def elaborate(self, platform): + m = Module() + + m.d.comb += self.ovf.eq(self.count == self.limit) + + with m.If(self.en): + with m.If(self.ovf): + m.d.sync += self.count.eq(0) + with m.Else(): + m.d.sync += self.count.eq(self.count + 1) + + return m + + def to_v(self): + return verilog.convert(self, ports=[self.en, self.ovf]) + +top = UpCounter(25) +print(top.to_v()) \ No newline at end of file diff --git a/archive/testing/up_counter_tb.py b/archive/testing/up_counter_tb.py new file mode 100644 index 0000000..7c2e8d2 --- /dev/null +++ b/archive/testing/up_counter_tb.py @@ -0,0 +1,30 @@ +from amaranth.sim import Simulator +from up_counter import UpCounter + +dut = UpCounter(25) + + +def bench(): + # Disabled counter should not overflow. + yield dut.en.eq(0) + for _ in range(30): + yield + assert not (yield dut.ovf) + + # Once enabled, the counter should overflow in 25 cycles. + yield dut.en.eq(1) + for _ in range(25): + yield + assert not (yield dut.ovf) + yield + assert (yield dut.ovf) + + # The overflow should clear in one cycle. + yield + assert not (yield dut.ovf) + +sim = Simulator(dut) +sim.add_clock(1e-6) # 1 MHz +sim.add_sync_process(bench) +with sim.write_vcd("up_counter.vcd"): + sim.run() \ No newline at end of file diff --git a/deprecated/hdl_lab/.gitignore b/deprecated/hdl_lab/.gitignore deleted file mode 100644 index 3f63f69..0000000 --- a/deprecated/hdl_lab/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -quartus -gen_verilog -simulation -.vscode -__pycache__ -**__pycache__ -.pytest_cache \ No newline at end of file diff --git a/deprecated/hdl_lab/Makefile b/deprecated/hdl_lab/Makefile deleted file mode 100644 index 10ace11..0000000 --- a/deprecated/hdl_lab/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -HDL_FOLDER = ./hdl -HDL = $(wildcard $(HDL_FOLDER)/*.py) - - -test: - py.test --disable-pytest-warnings -v $(HDL) - -test-w: - py.test -v $(HDL) - -clean: - $(RM) -rf simulation/* gen_verilog/* hdl/__pycache__ .pytest_cache \ No newline at end of file diff --git a/deprecated/hdl_lab/hdl/constants.py b/deprecated/hdl_lab/hdl/constants.py deleted file mode 100644 index ca02497..0000000 --- a/deprecated/hdl_lab/hdl/constants.py +++ /dev/null @@ -1,8 +0,0 @@ -SIM_DIR = './simulation/' -GEN_VERILOG = './gen_verilog/' - -IVERILOG = 'iverilog ' -VVP = 'vvp -M ./ -m myhdl ' - -RESET_ACTIVE = False -RESET_INACTIVE = not RESET_ACTIVE \ No newline at end of file diff --git a/deprecated/hdl_lab/hdl/multiply.py b/deprecated/hdl_lab/hdl/multiply.py deleted file mode 100644 index 015f67a..0000000 --- a/deprecated/hdl_lab/hdl/multiply.py +++ /dev/null @@ -1,205 +0,0 @@ -from turtle import width -from typing import Callable -from myhdl import * -from constants import RESET_ACTIVE -from myhdl_wrap import Myhdl_Wrapper - -import random -from random import randint - -random.seed(63) - -class Multiply(Myhdl_Wrapper): - def __init__(self): - super().__init__() - - # Main code, this is the actual logic - @staticmethod - @block - def Multiply(clk : Signal, reset : Signal, a : Signal, b : Signal, prod : Signal, is_signed : Signal, ready : Signal, valid : Signal): # this must be the same name as the class name - - width_a = len(a) - width_b = len(b) - width_prod = len(a) + len(b) - - a0 = Signal(modbv(0)[width_a:]) - b0 = Signal(modbv(0)[width_b:]) - a1 = Signal(modbv(0)[width_a:]) - b1 = Signal(modbv(0)[width_b:]) - prod_raw = Signal(modbv(0)[width_prod:]) - - @instance - def logic(): - while True: - yield valid.posedge - a0.next = a - b0.next = b - - yield clk.posedge - ready.next = False - - if not is_signed: - a1.next = a0 - b1.next = b0 - else: - if(a0.signed() < 0): - a1.next = -a0.signed() - else: - a1.next = a0 - - if(b0.signed() < 0): - b1.next = -b0.signed() - else: - b1.next = b0 - - prod_raw.next = a1 * b1 - - if is_signed: - if (a0[width_a-1] ^ b0[width_b-1]) == 1: - prod.next = -prod_raw - else: - prod.next = prod_raw - pass - else: - prod.next = prod_raw - - ready.next = True - - return logic - - - @block - def tb(self, func: Callable): - reset = Signal(False) - clk = Signal(bool(0)) - a = Signal(intbv(0)[32:]) - b = Signal(intbv(0)[32:]) - prod = Signal(modbv(0)[64:]) - is_signed = Signal(bool(0)) - ready = Signal(bool(1)) - valid = Signal(bool(0)) - - a_signed = intbv(0, -int(a.max/2), int(a.max/2)-1) - b_signed = intbv(0, -int(b.max/2), int(b.max/2)-1) - - - dut = func(clk=clk, reset=reset, a=a, b=b, prod=prod, is_signed=is_signed, ready=ready, valid=valid) - - @always(delay(2)) - def clock_gen(): - clk.next = not clk - - @instance - def monitor(): - # print(f"ready: {ready}, valid: {valid}") - # print("-"*20) - while True: - yield ready, valid - # print(f"ready: {ready}, valid: {valid}") - - @instance - def stimulus(): - yield clk.negedge - - # unsigned test - for i in range(30): - a_int = randint(a.min, a.max-1) - b_int = randint(b.min, b.max-1) - a.next = a_int - b.next = b_int - - valid.next = True - yield ready.negedge - valid.next = False - - yield ready.posedge - yield delay(1) - assert int(prod) == a_int * b_int, "Unsigned multiplication error random" - - # unsigned extremes test - for a_int in (a.min, a.max-1): - for b_int in (b.min, b.max-1): - a.next = a_int - b.next = b_int - - valid.next = True - yield ready.negedge - valid.next = False - - yield ready.posedge - yield delay(1) - - assert int(prod) == a_int * b_int, "Unsigned multiplication error extreme" - - - is_signed.next = True - yield clk.negedge - - for i in range(30): - a_int = randint(a_signed.min, a_signed.max-1) - b_int = randint(b_signed.min, b_signed.max-1) - - a_signed[:] = a_int - b_signed[:] = b_int - a.next = a_signed.unsigned() - b.next = b_signed.unsigned() - - valid.next = True - yield ready.negedge - valid.next = False - - yield ready.posedge - yield delay(1) - - # print('-'*30) - # print(prod) - # print(a_int * b_int) - - assert int(prod.signed()) == a_int * b_int, "Signed multiplication error random" - - - for a_int in (a_signed.min, 0, a_signed.max-1): - for b_int in (b_signed.min, 0, b_signed.max-1): - - a_signed[:] = a_int - b_signed[:] = b_int - a.next = a_signed.unsigned() - b.next = b_signed.unsigned() - - valid.next = True - yield ready.negedge - valid.next = False - - yield ready.posedge - yield delay(1) - - assert int(prod.signed()) == a_int * b_int, "Signed multiplication error extreme" - - - raise StopSimulation - - - return dut, clock_gen, monitor, stimulus - - def export(self): - reset = Signal(False) - clk = Signal(False) - a = Signal(intbv(0)[32:]) - b = Signal(intbv(0)[32:]) - prod = Signal(modbv(0)[64:]) - is_signed = Signal(False) - ready = Signal(True) - valid = Signal(False) - - # assigning signals, kargs only - self._export(clk=clk, reset=reset, a=a, b=b, prod=prod, is_signed=is_signed, ready=ready, valid=valid) - - -def test_template_sim(): - hdl = Multiply() - hdl.sim() - -def test_template_cosim(): - hdl = Multiply() - hdl.export() - hdl.cosim() diff --git a/deprecated/hdl_lab/hdl/myhdl_wrap.py b/deprecated/hdl_lab/hdl/myhdl_wrap.py deleted file mode 100644 index 56c8c5b..0000000 --- a/deprecated/hdl_lab/hdl/myhdl_wrap.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -from myhdl import * -from constants import * - -class Myhdl_Wrapper(): - def __init__(self): - self.class_name = self.__class__.__name__ - - def _export(self, **kargs): - inst = getattr(self, self.class_name)(**kargs) - inst.convert(hdl='Verilog', path=GEN_VERILOG, name=f"{self.class_name}") - - test_bench_file = GEN_VERILOG + 'tb_' +self.class_name + '.v' - test_bench_tmp_file = GEN_VERILOG + '~tb_' +self.class_name + '.v' - - # this is needed to generate cosim vcd file - with open(test_bench_file) as f_old, open(test_bench_tmp_file, 'w') as f_new: - lines = f_old.readlines() - for line in lines: - f_new.write(line) - if 'initial begin' in line: - f_new.write('\n') - f_new.write(' // Needed to create vcd file\n') - f_new.write(f' $dumpfile ("{SIM_DIR + self.class_name}_cosim.vcd");\n') - f_new.write(f' $dumpvars(0, tb_{self.class_name});\n') - f_new.write('\n') - os.rename(test_bench_tmp_file, test_bench_file) - - - - # This function links myhdl to icarus verilog sim - def _cosim(self, **kargs): #these should have the same signals as logic(), - - iverilog_cmd = IVERILOG + f"-o {SIM_DIR}{self.class_name}.o {GEN_VERILOG}{self.class_name}.v {GEN_VERILOG}tb_{self.class_name}.v" - vvp_cmd = VVP + f"{SIM_DIR}{self.class_name}.o" - - os.system(iverilog_cmd) - return Cosimulation(vvp_cmd, **kargs) - - def sim(self): - tb = self.tb(getattr(self, self.class_name)) - tb.config_sim(trace=True, tracebackup=False, directory=SIM_DIR, filename=f"{self.class_name}_sim") - tb.run_sim() - - def cosim(self): - tb = self.tb(self._cosim) - tb.run_sim() \ No newline at end of file diff --git a/deprecated/hdl_lab/hdl/reset_sync.py b/deprecated/hdl_lab/hdl/reset_sync.py deleted file mode 100644 index af03075..0000000 --- a/deprecated/hdl_lab/hdl/reset_sync.py +++ /dev/null @@ -1,109 +0,0 @@ -from typing import Callable -from myhdl import * -from myhdl_wrap import Myhdl_Wrapper - -import random -from random import randint - -random.seed(13) - -class ResetSync(Myhdl_Wrapper): - def __init__(self): - super().__init__() - - # Main code, this is the actual logic - @staticmethod - @block - def ResetSync(clk : Signal, async_reset : Signal, sync_reset : Signal): # this must be the same name as the class name - - sync = Signal(False) - guard = sync_reset - - @instance - def logic(): - while True: - yield clk.posedge, async_reset.negedge - - if not async_reset: - guard.next = False - sync.next = False - else: - guard.next = sync - sync.next = True - - return logic - - - @block - def tb(self, func: Callable): - async_reset = Signal(False) - sync_reset = Signal(False) - clk = Signal(False) - - dut = func(clk=clk, async_reset=async_reset, sync_reset=sync_reset) - - @always(delay(2)) - def clock_gen(): - clk.next = not clk - - @instance - def monitor_async(): - while True: - yield async_reset.negedge - yield delay(1) - assert sync_reset == False, 'Reset not asynchronous on falling edge' - - @instance - def monitor_sync(): - while True: - yield async_reset.posedge - - assert sync_reset == False, 'sync Reset did not wait for first clock positive edge' - - yield clk.posedge, async_reset.negedge - if async_reset == True: - yield delay(0) - assert sync_reset == False, 'sync Reset did not wait for second clock positive edge' - - yield clk.posedge, async_reset.negedge - if async_reset == True: - yield delay(0) - assert sync_reset == True, 'sync Reset did not set' - - - - @instance - def stimulus(): - for _ in range(500): - yield delay(randint(0,20)) - - if (now()+2) % 4 == 0: # do not create rising edge of reset and clk at the same time - yield(delay(1)) - - async_reset.next = True - yield delay(randint(0, 20)) - async_reset.next = False - - raise StopSimulation - - - return dut, clock_gen, monitor_async, monitor_sync, stimulus - - def export(self): - async_reset = Signal(False) - sync_reset = Signal(False) - clk = Signal(bool(0)) - - # assigning signals, kargs only - self._export(clk=clk, async_reset=async_reset, sync_reset=sync_reset) - - -def test_reset_sync_sim(): - hdl = ResetSync() - hdl.sim() - -def test_reset_sync_cosim(): - hdl = ResetSync() - hdl.export() - hdl.cosim() - diff --git a/deprecated/hdl_lab/hdl/shift_reg.py b/deprecated/hdl_lab/hdl/shift_reg.py deleted file mode 100644 index 9c1c6be..0000000 --- a/deprecated/hdl_lab/hdl/shift_reg.py +++ /dev/null @@ -1,118 +0,0 @@ -from myhdl import * -from myhdl_wrap import Myhdl_Wrapper - -import random -from random import randint - -random.seed(63) - -class ShiftReg(Myhdl_Wrapper): - def __init__(self): - super().__init__() - - # Main code, this is the actual logic - @staticmethod - @block - def ShiftReg(reset: Signal, clk: Signal, load: Signal, in0: Signal, out0: Signal, left_right: Signal): - - width = len(out0) - - @instance - def shifter(): - while True: - yield clk.posedge, reset.negedge - - if not reset: - out0.next = load - else: - if not left_right: - out0.next[width:1] = out0[width-1:0] - out0.next[1:0] = in0 - else: - out0.next[width-1:0] = out0[width:1] - out0.next[width:width-1] = in0 - - return shifter - - - @block - def tb(self, func): - reset = Signal(False) - clk = Signal(bool(0)) - load = Signal(intbv(0xA5)[8:]) - in0 = Signal(bool(0)) - out0 = Signal(modbv(int(load))[8:]) - left_right = Signal(bool(0)) - - dut = func(reset=reset, clk=clk, load=load, in0=in0, out0=out0, left_right=left_right) - - @always(delay(2)) - def clock_gen(): - clk.next = not clk - - @instance - def monitor(): - last_val = out0 - - while True: - yield clk.posedge, reset.negedge - yield delay(1) - - if reset == False: - assert out0 == load, "Is output is not zero at reset" - - else: - if not left_right: - assert int(out0) == ((last_val << 1) & 0xFF) | int(in0), "Not shifting left correctly" - else: - assert int(out0) == ((last_val >> 1) & 0xFF) | (int(in0) << 7), "Not shifting rigth correctly" - - last_val = int(out0) - - @instance - def reset_test(): - yield clk.negedge - reset.next = True - while True: - reset.next = True - yield delay(randint(25, 28)) - - reset.next = False - yield delay(randint(1,4)) - - @instance - def stimulus(): - for i in range(20): - yield clk.negedge - left_right.next = 0 - in0.next = randint(0, 1) - - for i in range(20): - yield clk.negedge - left_right.next = 1 - in0.next = randint(0, 1) - - raise StopSimulation - - - return dut, clock_gen, monitor, stimulus, reset_test - - def export(self): - reset = Signal(False) - clk = Signal(bool(0)) - load = Signal(intbv(0xA5)[8:]) - in0 = Signal(bool(0)) - out0 = Signal(modbv(int(load))[8:]) - left_right = Signal(bool(0)) - - self._export(reset=reset, clk=clk, load=load, in0=in0, out0=out0, left_right=left_right) - - -def test_shift_reg_sim(): - hdl = ShiftReg() - hdl.sim() - -def test_shift_reg_cosim(): - hdl = ShiftReg() - hdl.export() - hdl.cosim() diff --git a/deprecated/hdl_lab/myhdl.vpi b/deprecated/hdl_lab/myhdl.vpi deleted file mode 100755 index 1b9d393..0000000 Binary files a/deprecated/hdl_lab/myhdl.vpi and /dev/null differ diff --git a/deprecated/hdl_lab/template.py b/deprecated/hdl_lab/template.py deleted file mode 100644 index 77eb18c..0000000 --- a/deprecated/hdl_lab/template.py +++ /dev/null @@ -1,69 +0,0 @@ -from typing import Callable -from myhdl import * -from myhdl_wrap import Myhdl_Wrapper - -import random -from random import randint - -random.seed(63) - -class Template(Myhdl_Wrapper): - def __init__(self): - super().__init__() - - # Main code, this is the actual logic - @staticmethod - @block - def Template(args): # this must be the same name as the class name - - @instance - def logic(): - while True: - ... - - return logic - - - @block - def tb(self, func: Callable): - reset = Signal(False) - clk = Signal(False) - ... - - dut = func(..., clk=clk, reset=reset) - - @always(delay(...)) - def clock_gen(): - clk.next = not clk - - @instance - def monitor(): - while True: - ... - - @instance - def stimulus(): - ... - - raise StopSimulation - - - return dut, clock_gen, monitor, stimulus - - def export(self): - reset = Signal(False) - clk = Signal(False) - ... - - # assigning signals, kargs only - self._export(..., clk=clk, reset=reset) - - -def test_template_sim(): - hdl = Template() - hdl.sim() - -def test_template_cosim(): - hdl = Template() - hdl.export() - hdl.cosim() diff --git a/doc/ASAP32-ISA.md b/doc/ASAP32-ISA.md deleted file mode 100644 index 3c3c016..0000000 --- a/doc/ASAP32-ISA.md +++ /dev/null @@ -1,195 +0,0 @@ -# Vertex KISS 32 - Machine Code Spec -^ So Vertex is already a name for an FPGA, should we change this? -I propose a different name: - - ASAP Soc 32 a KISS architecture - - As - Simple - As - Possible - -## General Instruction Format - X = HEX - B = BIN - - MAX INSTRUCTIIONS = 256 - ALL INSTRUCTIONS ARE ATOMIC - -### C-Type, Control - XX X X XXXX - Opcode d RS1 IMM - -### I-Type, Immediate - XX X X XXXX - Opcode RD RS1 IMM - -### R-Type, Arithmetic - XX X X X XXX - Opcode RD RS1 RS2 ddd - -### JR-Type, Compare and Jump - XX X X X XXX - Opcode Jump Condition RS1 RS2 ddd - -### JI-Type, Compare and Jump - XX X X XXXX - Opcode Jump Condition RS1 IMM - -## Registers - Maximum registers = 16 - Register width = 32 - All are R/W except 0X - - 0X Always Zero - AX GP-0 - BX GP-1 - CX GP-2 - DX GP-3 - EX GP-4 - FX GP-5 - GX GP-6 - 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) - PDA Page Directory Address - -### FLG Flag Register Bitfield - 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 - FLG[2] Zero - FLG[3] Sign - FLG[4] Odd (parity) - FLG[5-15] RESERVED - FLG[16] Interrupt enable* - FLG[17] User mode* - FLG[18] Paging enabled* - FLG[19-31] RESERVED* - - *Must be in supervisor mode (FLG[17]=0) to set - -## Integer Instructions - -### R-Type - ADD RD, RS1, RS2 RD = RS1 + RS2 - SUB RD, RS1, RS2 RD = RS1 - RS2 - XOR RD, RS1, RS2 RD = RS1 ^ RS2 - OR RD, RS1, RS2 RD = RS1 | RS2 - AND RD, RS1, RS2 RD = RS1 & RS2 - LSL RD, RS1, RS2 RD = RS1 << RS2 (logical) - LSR RD, RS1, RS2 RD = RS1 >> RS2 (logical) - ASR RD, RS1, RS2 RD = RS1 >> RS2 - MUL RD, RS1, RS2 RD = RS1 * RS2 - MULU RD, RS1, RS2 RD = RS1 * RS2 (unsigned) - DIV RD, RS1, RS2 RD = RS1 / RS2 - DIVU RD, RS1, RS2 RD = RS1 / RS2 (unsigned) - - *DIV is based on shift-and-multiply algorithm - *DIV Ex: 8000/192 - (8000/64)/3 - (8000>>6)/3 - (8000>>6)*0x5555>>16=41 - -### I-Type - ADDI RD, RS, IMM RD = RS + IMM - SUBI RD, RS, IMM RD = RS - IMM - XORI RD, RS, IMM RD = RS ^ IMM - ORI RD, RS, IMM RD = RS | IMM - ANDI RD, RS, IMM RD = RS & IMM - LSLI RD, RS, IMM RD = RS << IMM (logical) - LSRI RD, RS, IMM RD = RS >> IMM (logical) - ASRI RD, RS, IMM RD = RS >> IMM - DIVI RD, RS, IMM RD = RS / IMM - DIVIU RD, RS, IMM RD = RS / IMM (unsigned) - -### JR Instructions - JMP 0 if (True) - JMP 1 if (RS1 != RS2) - JMP 2 if (RS1 == RS2) - JMP 3 if (RS1 > RS2) Unsigned - JMP 4 if (RS1 >= RS2) Unsigned - - JMP C if (RS1 > RS2) Signed - JMP D if (RS1 >= RS2) Signed - -### JI Instructions - Compare and then jump (IP = JMP) - - JMPI 0 if (True) - JMPI 1 if (RS1 != IMM) - JMPI 2 if (RS1 == IMM) - JMPI 3 if (RS1 > IMM) Unsigned - JMPI 4 if (RS1 >= IMM) Unsigned - - JMPI C if (RS1 > IMM) Signed - JMPI D if (RS1 >= IMM) Signed - -### Jump Aliases - JEQ - JLT - JGT - JLE - JGE - JLTU - JGTU - JLEU - JGEU - - -### Control Instructions - NOP Do nothing -> opcode = ZERO - HLT Spinlock the CPU* - PUSHR RS SP+=1 ;*SP = RS - POPR RS RS = *SP ;SP-=1 - PUSHI IMM SP+=1 ;*SP = IMM - 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* - CIF Clear interrupt flag* - - *Requires processor to be in supervisor mode (FLG[17]=0) - -## Interrupt Descriptor Table -This will be in a fixed memory location, this will contain pointers to the interupt -function. - - IDT[0] Divide-by-zero exception - IDT[1] Hardware error (NMI) - IDT[2] Overflow - IDT[3] Invalid Opcode - IDT[4] General-protection fault - IDT[5] Page fault - IDT[6] Software interrupt (reserved for OS) - IDT[7-31] RESERVED - IDT[32-255] Platform interrupts (PIC, hard drive, keyboard, etc.) - -## Page Directory - -The page directory contains 1024 page tables that have 1024 entries that are -4096 bytes wide. Optionally, the page table can be 4MB bytes wide with a setting -in the page table. If this bit is set, there is 1024 entries in the page -directory; otherwise, there are 2^20 entries. - -### Page table layout - - PT[0] Present - PT[1] R/W - PT[2] User-mode - PT[3] Accessed - PT[4] Dirty - PT[5] PWT - PT[6] Cache-disable - PT[7] Page size (0=4KB 1=4MB) - PT[8-31] Physical address of page diff --git a/hdl/core/reg.py b/hdl/core/reg.py deleted file mode 100644 index b6aa3c5..0000000 --- a/hdl/core/reg.py +++ /dev/null @@ -1,304 +0,0 @@ -from amaranth import * -from amaranth.sim import Settle - -from hdl.lib.in_out_buff import InOutBuff -from hdl.utils import cmd, step, sim - -class Reg(Elaboratable): - def __init__(self, **kargs): # sim is only for modularity, does nothing for this - - ################ INPUTS ################ - self.wr_en = Signal(1) - self.stall = Signal(1) # stall instruction pointer increment - - self.rd = Signal(32) - self.rd_addr = Signal(4) - self.rs1_addr = Signal(4) - self.rs2_addr = Signal(4) - - self.alu_flgs = Signal(5) # flags from alu - - # these signals should be used one hot only - self.int_sig = Signal(1) # unconditional interrupt - self.iret = Signal(1) # return from interrupt - self.call = Signal(1) # call subroutine, save return address - self.jump = Signal(1) # jump, do not save return address - - - ################ OUTPUTS ################ - - self.rs1 = Signal(32) # read data 1 - self.rs2 = Signal(32) # read data 2 - - self.int_en = Signal(1) #interupt enable output signal to control unit - self.user_mode = Signal(1) # user mode output signal to control unit - - - ################ INTERNAL SIGNALS ################ - self._wr_alu_flg = Signal(1) - self._inc_ip = 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.int_sig, self.iret, self.call, self.jump, self.rd_addr, self.rd, self.rs1_addr, self.rs2_addr] - ports_out = [self.int_en, self.user_mode, self.rs1, self.rs2, self.ip] - self.ports = {'in': ports_in, 'out': ports_out} - - - def elaborate(self, platform=None): - m = Module() - - # output signals to control unit - m.d.comb += self.int_en.eq(self.flg.int) - m.d.comb += self.user_mode.eq(self.flg.user_mode & ~self.int_sig) - - # defualt value of internal signals - m.d.comb += self._wr_alu_flg.eq(1) - 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.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.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.comb += self._inc_ip.eq(0) - m.d.sync += self.ip.eq(self.cs0) - m.d.sync += self.sp.eq(self.cs1) - m.d.sync += self.flg.eq(self.cs2) - - with m.Elif(self.call): - m.d.comb += self._inc_ip.eq(0) - m.d.sync += self.ip.eq(self.rd) - m.d.sync += self.cs0.eq(self.ip) - - with m.Elif(self.jump): - m.d.comb += self._inc_ip.eq(0) - m.d.sync += self.ip.eq(self.cs0) - - with m.Elif(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.flg.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(): - m.d.sync += self.reg_arr[self.rd_addr].eq(self.rd) - - with m.If(self._wr_alu_flg): # alu flags are written only if write enabled and not writing to flags register - m.d.sync += self.flg.eq(Cat(self.alu_flgs, self.flg[len(self.alu_flgs):])) - - - with m.If(self._inc_ip & ~self.stall): # increment ip if not directly writing to ip register - m.d.sync += self.ip.eq(self.ip + 4) - - - ### 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.flg.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.flg.user_mode, 16))) - with m.Case(): - m.d.comb += self.rs2.eq(self.reg_arr[self.rs2_addr]) - - return m - - -#--------------------------------- TEST BENCH BELOW ---------------------------------# - -def _init(dut): - for i in range(16): - yield dut.reg_arr[i].eq(i) - yield Settle() - - -# test combinational output -def test_reg_comb_output(): - dut = Reg() - def proc(): - yield from _init(dut) - 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}' - sim(dut, proc) - -# test writeback with writeback disabled -def test_reg_writeback_dsb(): - dut = Reg() - def proc(): - yield from _init(dut) - 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}' - sim(dut, proc) - -# test writeback with writeback enabled -def test_reg_writeback_en(): - dut = Reg() - def proc(): - for i in range(16): - yield from _init(dut) - 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' - sim(dut, proc) - -# check to make sure alu is writing values -def test_reg_flg_write_aluflg(): - dut = Reg() - def proc(): - 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(dut, proc) - -def test_reg_flg_overwrite(): - dut = Reg() - def proc(): - 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' - sim(dut, proc) - -# test flag register security -def test_reg_flg_read_usermode(): - dut = Reg() - def proc(): - 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' - sim(dut, proc) - -# test flag register security -def test_reg_flg_write_usermode(): - dut = Reg() - def proc(): - 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' - sim(dut, proc) - -def test_reg_flg_read_systemmode(): - dut = Reg() - def proc(): - 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' - sim(dut, proc) - -# make sure not to write alu flags when directly writing to flg register -def test_reg_flg_write_systemmode(): - dut = Reg() - def proc(): - 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' - sim(dut, proc) - - - -if __name__ == '__main__': - reg = InOutBuff(Reg()) - cmd(reg) \ No newline at end of file diff --git a/hdl/testing/async_reset.py b/hdl/testing/async_reset.py deleted file mode 100644 index 4760df7..0000000 --- a/hdl/testing/async_reset.py +++ /dev/null @@ -1,21 +0,0 @@ -from amaranth import * -from amaranth.cli import main - - -class ClockDivisor(Elaboratable): - def __init__(self, factor): - self.v = Signal(factor) - self.o = Signal() - - def elaborate(self, platform): - m = Module() - m.d.sync += self.v.eq(self.v + 1) - m.d.comb += self.o.eq(self.v[-1]) - return m - - -if __name__ == "__main__": - m = Module() - m.domains.sync = sync = ClockDomain("sync", async_reset=True) - m.submodules.ctr = ctr = ClockDivisor(factor=16) - main(m, ports=[ctr.o, sync.clk]) \ No newline at end of file diff --git a/hdl/testing/multi_clock.py b/hdl/testing/multi_clock.py deleted file mode 100644 index e377156..0000000 --- a/hdl/testing/multi_clock.py +++ /dev/null @@ -1,75 +0,0 @@ -import sys -from amaranth import * -from amaranth.back import verilog, cxxrtl -from amaranth.cli import main -from amaranth.sim import Simulator, Settle, Delay - -BASENAME = "multi_clock" - -class SubM(Elaboratable): - def __init__(self, domain=None): - self.inv = Signal() - self.domain=domain - - def elaborate(self, platform): - m = Module() - - m.d.sync += self.inv.eq(~self.inv) - - return m - -class top(Elaboratable): - def __init__(self): - self.sig_slow = Signal() - self.sig_fast = Signal() - - self.div = Signal(2) - - def elaborate(self, platform): - m = Module() - - m.domains += ClockDomain('slow') - m.d.sync += [self.div.eq(self.div + 1)] - m.d.comb += ClockSignal('slow').eq(self.div[-1]) - - m.submodules.subm1 = SubM() - m.submodules.subm2 = DomainRenamer("slow")(SubM()) - - m.d.sync += self.sig_fast.eq(m.submodules.subm1.inv) - m.d.slow += self.sig_slow.eq(m.submodules.subm2.inv) - - return m - -def test_shift_reg(): - dut = top() - - def proc1(): - for _ in range(16): - yield - yield Settle() - - sim = Simulator(dut) - sim.add_clock(1e-6) - sim.add_sync_process(proc1) - - with sim.write_vcd(BASENAME + '.vcd'): - sim.run() - - -if __name__ == '__main__': - - if sys.argv[1] == "sim": - test_shift_reg() - exit() - - # m = ShiftReg(8) - - # if sys.argv[1] == "v": - # out = verilog.convert(m, ports=m.ports) - # with open(BASENAME + '.v','w') as f: - # f.write(out) - - # elif sys.argv[1] == "cc": - # out = cxxrtl.convert(m, ports=m.ports) - # with open(BASENAME + '.cc','w') as f: - # f.write(out) diff --git a/hdl/testing/up_counter.py b/hdl/testing/up_counter.py deleted file mode 100644 index 050a6b0..0000000 --- a/hdl/testing/up_counter.py +++ /dev/null @@ -1,50 +0,0 @@ -from amaranth import * -from amaranth.back import verilog - - -class UpCounter(Elaboratable): - """ - A 16-bit up counter with a fixed limit. - - Parameters - ---------- - limit : int - The value at which the counter overflows. - - Attributes - ---------- - en : Signal, in - The counter is incremented if ``en`` is asserted, and retains - its value otherwise. - ovf : Signal, out - ``ovf`` is asserted when the counter reaches its limit. - """ - - def __init__(self, limit): - self.limit = limit - - # Ports - self.en = Signal() - self.ovf = Signal() - - # State - self.count = Signal(16) - - def elaborate(self, platform): - m = Module() - - m.d.comb += self.ovf.eq(self.count == self.limit) - - with m.If(self.en): - with m.If(self.ovf): - m.d.sync += self.count.eq(0) - with m.Else(): - m.d.sync += self.count.eq(self.count + 1) - - return m - - def to_v(self): - return verilog.convert(self, ports=[self.en, self.ovf]) - -top = UpCounter(25) -print(top.to_v()) \ No newline at end of file diff --git a/hdl/testing/up_counter_tb.py b/hdl/testing/up_counter_tb.py deleted file mode 100644 index 7c2e8d2..0000000 --- a/hdl/testing/up_counter_tb.py +++ /dev/null @@ -1,30 +0,0 @@ -from amaranth.sim import Simulator -from up_counter import UpCounter - -dut = UpCounter(25) - - -def bench(): - # Disabled counter should not overflow. - yield dut.en.eq(0) - for _ in range(30): - yield - assert not (yield dut.ovf) - - # Once enabled, the counter should overflow in 25 cycles. - yield dut.en.eq(1) - for _ in range(25): - yield - assert not (yield dut.ovf) - yield - assert (yield dut.ovf) - - # The overflow should clear in one cycle. - yield - assert not (yield dut.ovf) - -sim = Simulator(dut) -sim.add_clock(1e-6) # 1 MHz -sim.add_sync_process(bench) -with sim.write_vcd("up_counter.vcd"): - sim.run() \ No newline at end of file diff --git a/hdl/testing/v b/hdl/testing/v deleted file mode 100644 index e69de29..0000000 diff --git a/requirements.txt b/requirements.txt index c920901..ee1e958 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -amaranth[builtin-yosys] \ No newline at end of file +amaranth[builtin-yosys] +pytest -- cgit v1.2.3