You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
4.5 KiB

# 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()