|
|
|
# Memory
|
|
|
|
# 32-bit address
|
|
|
|
# 8-bit cell
|
|
|
|
# Register File
|
|
|
|
# ·32 32-bit registers, with 2 read ports and 1 write portTest bench
|
|
|
|
# / Add the number in memory address 0 and 1 to address 3
|
|
|
|
# Load r1, #0
|
|
|
|
# Load r2,#1
|
|
|
|
# Add r3, r1, r2
|
|
|
|
# Store r3, #3
|
|
|
|
import numpy as np
|
|
|
|
import re
|
|
|
|
import random
|
|
|
|
class register_file:
|
|
|
|
|
|
|
|
def __init__(self , size) -> None:
|
|
|
|
self.regs = np.array([0] * size , dtype=np.int32)
|
|
|
|
self.size = size
|
|
|
|
|
|
|
|
def read(self , idx1 : int , idx2 : int) -> tuple:# 2 read port
|
|
|
|
if idx1 < 0 or idx1 >= self.size or idx2 < 0 or idx2 >= self.size:
|
|
|
|
raise IndexError(f"The index is out of range")
|
|
|
|
|
|
|
|
return (self.regs[idx1] , self.regs[idx2])
|
|
|
|
|
|
|
|
def write(self , idx : int , value : np.int32) -> None:# 1 write port
|
|
|
|
if idx < 0 or idx >= self.size:
|
|
|
|
raise IndexError("The index is out of range")
|
|
|
|
|
|
|
|
if value < -2**31 or value > 2**31 - 1:
|
|
|
|
raise ValueError("The value is out of range")
|
|
|
|
|
|
|
|
self.regs[idx] = value
|
|
|
|
|
|
|
|
def info(self) -> None:
|
|
|
|
print(f"register file : {self.regs}")
|
|
|
|
|
|
|
|
class memory:
|
|
|
|
def __init__(self , size):
|
|
|
|
self.size = size
|
|
|
|
self.mem = {key : np.int8(0) for key in range(10)}#8-bit cell
|
|
|
|
# use dictionary to simulate 2**32 byte-memory
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self.mem = {key : np.int8(0) for key in self.mem}
|
|
|
|
|
|
|
|
def info(self) -> None:
|
|
|
|
print(f"memory : {self.mem}")
|
|
|
|
|
|
|
|
def read(self , idx : int) -> np.int8:
|
|
|
|
if idx < 0 or idx >= self.size:
|
|
|
|
raise IndexError("The index is out of range")
|
|
|
|
|
|
|
|
if idx not in self.mem:
|
|
|
|
self.mem[idx] = np.int8(0)
|
|
|
|
return self.mem[idx]
|
|
|
|
|
|
|
|
def write(self , idx , value : np.int8) -> None:
|
|
|
|
if idx < 0 or idx >= self.size:
|
|
|
|
raise IndexError("The index is out of range")
|
|
|
|
|
|
|
|
if(value < -128 or value > 127):
|
|
|
|
raise ValueError("The value is out of range")
|
|
|
|
|
|
|
|
self.mem[idx] = value
|
|
|
|
|
|
|
|
|
|
|
|
class instruction:
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def Load(ins : list , immediate: bool = False) -> None:
|
|
|
|
mem_val : np.int32 = np.int32(mem.read(ins[2])) | np.int32(mem.read(ins[2] + 1)) << 8 + np.int32(mem.read(ins[2] + 2)) << 16 + np.int32(mem.read(ins[2] + 3)) << 24
|
|
|
|
regfile.write(ins[1] , mem_val)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def Loadi(ins : list):#load immediate to register , just for test , style of instruction : Loadi r1 , i100
|
|
|
|
regfile.write(ins[1] , ins[2]) #to fix : merge into Load instruction by adding flag immediate , maybe
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def Store(ins : list) -> None:
|
|
|
|
reg_val : np.int32 = regfile.read(ins[1] , 0)[0]#just use one read port of regfile
|
|
|
|
mem.write(ins[2] , np.int8(reg_val & 0xff))
|
|
|
|
mem.write(ins[2] + 1 , np.int8((reg_val >> 8) & 0xff))
|
|
|
|
mem.write(ins[2] + 2 , np.int8((reg_val >> 16) & 0xff))
|
|
|
|
mem.write(ins[2] + 3 , np.int8((reg_val >> 24) & 0xff))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def Add(ins : list) -> None:
|
|
|
|
r1 , r2 = regfile.read(ins[2] , ins[3])
|
|
|
|
regfile.write(ins[1] , r1 + r2)
|
|
|
|
|
|
|
|
def exec_ins(self , ins : list) -> None:
|
|
|
|
target_ins = getattr(type(self) , ins[0])
|
|
|
|
if target_ins is None:
|
|
|
|
raise RuntimeError("the error instruction {}".format(ins[0]))
|
|
|
|
target_ins(ins)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def parse_instruction(instruc : str) -> list:
|
|
|
|
#parse the instruction
|
|
|
|
_ins = re.split(r'[ ,]+' , instruc)# split the string by space and comma
|
|
|
|
ins = [_ins[0]]
|
|
|
|
for elem in _ins:
|
|
|
|
if elem[0] == 'r' or elem[0] == '#' or elem[0] == 'i':#get the bias of address
|
|
|
|
ins.append(int(elem[1:]))
|
|
|
|
|
|
|
|
return ins
|
|
|
|
|
|
|
|
class testbench:
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def memory_random_flip():
|
|
|
|
mem.mem = {key : random.randint(-10,10) for key in mem.mem}
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def test():
|
|
|
|
testbench.memory_random_flip()
|
|
|
|
mem.info()
|
|
|
|
test_instr = ['Load r1, #0' , 'Load r2,#1' , 'Add r3, r1, r2' , 'Store r3, #3']
|
|
|
|
for ins in test_instr:
|
|
|
|
_ins = instruction.parse_instruction(ins)
|
|
|
|
instruc.exec_ins(_ins)
|
|
|
|
|
|
|
|
mem.info()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
|
|
global regfile , mem , instruc
|
|
|
|
regfile = register_file(32)#32 32-bit registers
|
|
|
|
mem = memory(2 ** 32)# 32-bit address memory
|
|
|
|
instruc = instruction()
|
|
|
|
|
|
|
|
testbench.test()
|
|
|
|
while True:
|
|
|
|
_inst = input('>')
|
|
|
|
inst = instruc.parse_instruction(_inst)
|
|
|
|
instruc.exec_ins(inst)
|
|
|
|
mem.info()
|
|
|
|
regfile.info()
|