From a110465a4261e582025b6344facb7fa65c0acd56 Mon Sep 17 00:00:00 2001 From: Loic GUEGAN Date: Sun, 2 Sep 2018 16:31:49 +0200 Subject: Add unit tests, refactoring --- components/__init__.py | 0 components/caretaker.py | 34 -------- components/ijvm.py | 30 ------- components/microprogram.py | 202 --------------------------------------------- components/ram.py | 94 --------------------- 5 files changed, 360 deletions(-) delete mode 100644 components/__init__.py delete mode 100644 components/caretaker.py delete mode 100644 components/ijvm.py delete mode 100644 components/microprogram.py delete mode 100644 components/ram.py (limited to 'components') diff --git a/components/__init__.py b/components/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/components/caretaker.py b/components/caretaker.py deleted file mode 100644 index ab20fba..0000000 --- a/components/caretaker.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python - -class Caretaker: - - def __init__(self): - self.objects=dict() # Create empty objects pool - # Add registers to pool - for reg in ["MAR","MDR", "PC", "MBR", "SP","LV","CPP","TOS","OPC","H"]: - self.objects[reg]=0 - self.objects["RAM"]=None - - def __getitem__(self,key): - if key=="MBRU": # If we ask for unsigned - return(abs(self.objects["MBR"])) - elif key== "MBR": - if (self.objects[key]>>7)==1: # If it a negative number (2 complement) - return(-((self.objects[key]-1)^0xFF)) # transforme bin negative number to python negative number - else: - return(self.objects[key]) - return(self.objects[key]) - - def __setitem__(self,key,value): - if key!="RAM": - if value > (2**32) and key!="MBR" and key!="MBRU": # Check value fit in word - print("Warning word overflow: value {} on register {}".format(value,key)) - value=value%(2**32) # Force to fit in word - elif value > (2**8) and key=="MBR" and key=="MBRU": # Check value fit in byte - print("Warning byte overflow: value {} on register {}".format(value,key)) - value=value%256 # Force to fit in byte - self.objects[key]=value - - def items(self): - return(self.objects.items()) - diff --git a/components/ijvm.py b/components/ijvm.py deleted file mode 100644 index 86f5f63..0000000 --- a/components/ijvm.py +++ /dev/null @@ -1,30 +0,0 @@ - -# Quick link about opcode: https://users-cs.au.dk/bouvin/dComArk/2015/noter/Note_2/#Instructions - -# Build IJVM -ijvm=dict({ - "BIPUSH":0x10, - "DUP":0x59, - "GOTO":0xA7, - "IADD":0x60, - "IAND":0x7E, - "IFEQ":0x99, - "IFLT":0x9B, - "IF_ICMPEQ":0x9F, - "IINC":0x84, - "ILOAD":0x15, - "INVOKEVIRTUAL":0xB6, - "IOR":0x80, - "IRETURN":0xAC, - "ISTORE":0x36, - "ISUB":0x64, - "LDC_W":0x13, - "NOP":0x00, - "POP":0x57, - "SWAP":0x5F, - "WIDE":0xC4 -}) - -# Add extras instructions -ijvm["OUT"]=0x23 # Print next byte as char -ijvm["HALT"]=0x2F # Stop simulator diff --git a/components/microprogram.py b/components/microprogram.py deleted file mode 100644 index 6147921..0000000 --- a/components/microprogram.py +++ /dev/null @@ -1,202 +0,0 @@ - -from components.ijvm import ijvm - -class Microprogram: - - def __init__(self,components): - self.c=components # Link components to microprogram - if self.c["RAM"]==None: # Check if RAM is initialize - raise RuntimeError("Microprogram initialization fail, RAM is not initialized") - - def run(self): - """ - Start microprogram - """ - self.c["LV"]=(1024)# Place stack to 1024 - self.c["SP"]=(1024-1) # Init SP to LV-1 (because otherwise first element of the stack will be enty because of BIPUSH impl - - for i in range(1,30): # Launche first 30 insctructions - self.fetch() # Fetch - self.c["PC"]+=1 # INC PC after fetch - if self.exec()==1: # Execute opcode and halt if return code is 1 - break; - - def fetch(self): - """ - Fetch next byte from memory into MBR - """ - opcode=self.c["RAM"].fetch() - self.c["MBR"]=opcode # Opcode to MBR - - def rd(self): - """ - Read data into memory - """ - data=self.c["RAM"].read() - self.c["MDR"]=data - - def wr(self): - """ - Write data into memory - """ - self.c["RAM"].write() - - def exec(self): # TODO: Implement opcode - """ - Execute next opcode - """ - opcode=self.c["MBRU"] # Get loaded OpCode (/!\ We used MBRU not MBR because MBR is signed) - if opcode==ijvm["NOP"]: # NOP - pass - elif opcode==ijvm["BIPUSH"]: # BIPUSH - self.fetch();self.c["PC"]+=1 # Fetch byte to push in MBR - self.c["SP"]+=1 # Increment stack pointer - self.c["MAR"]=self.c["SP"] # Copy SP to MAR - self.c["MDR"]=self.c["MBR"] # Set MDR to MBR - self.c["TOS"]=self.c["MBR"] # Set MDR to MBR - self.wr() # Write data to stack - elif opcode==ijvm["IADD"]: - self.c["SP"]-=1 - self.c["MAR"]=self.c["SP"] - self.c["H"]=self.c["TOS"] - self.rd() - self.c["TOS"]=self.c["MDR"]+self.c["H"] - self.c["MDR"]=self.c["TOS"] - self.wr() - elif opcode==ijvm["ISUB"]: - self.c["SP"]-=1 - self.c["MAR"]=self.c["SP"] - self.c["H"]=self.c["TOS"] - self.rd() - self.c["TOS"]=self.c["MDR"]-self.c["H"] - self.c["MDR"]=self.c["TOS"] - self.wr() - elif opcode==ijvm["POP"]: - self.c["SP"]-=1 - self.c["MAR"]=self.c["SP"] - self.rd() - self.c["TOS"]=self.c["MDR"] - elif opcode==ijvm["DUP"]: - self.c["SP"]+=1 - self.c["MAR"]=self.c["SP"] - self.c["MDR"]=self.c["TOS"] - self.wr() - elif opcode==ijvm["IAND"]: - self.c["SP"]-=1 - self.c["MAR"]=self.c["SP"] - self.c["H"]=self.c["TOS"] - self.rd() - self.c["TOS"]=(self.c["MDR"] & self.c["H"]) - self.c["MDR"]=self.c["TOS"] - self.wr() - elif opcode==ijvm["IOR"]: - self.c["SP"]-=1 - self.c["MAR"]=self.c["SP"] - self.c["H"]=self.c["TOS"] - self.rd() - self.c["TOS"]=(self.c["MDR"] | self.c["H"]) - self.c["MDR"]=self.c["TOS"] - self.wr() - elif opcode==ijvm["SWAP"]: - self.c["MAR"]=self.c["SP"]-1 - self.rd() - self.c["MAR"]=self.c["SP"] - self.c["H"]=self.c["MDR"] - self.wr() - self.c["MDR"]=self.c["TOS"] - self.c["MAR"]=self.c["SP"]-1 - self.wr() - self.c["TOS"]=self.c["H"] - elif opcode==ijvm["ILOAD"]: - self.fetch();self.c["PC"]+=1 # Fetch local variable to push onto the stack - self.c["H"]=self.c["LV"] - self.c["MAR"]=self.c["MBRU"]+self.c["H"] - self.rd() - self.c["SP"]+=1 - self.c["MAR"]=self.c["SP"] - self.wr() - self.c["TOS"]=self.c["MDR"] - elif opcode==ijvm["ISTORE"]: - self.fetch();self.c["PC"]+=1 # Fetch local variable offset where to store - self.c["H"]=self.c["LV"] - self.c["MAR"]=self.c["MBRU"]+self.c["H"] - self.c["MDR"]=self.c["TOS"] - self.wr() - self.c["SP"]-=1 - self.c["MAR"]=self.c["SP"] - self.rd() - self.c["TOS"]=self.c["MDR"] - elif opcode==ijvm["IINC"]: - self.fetch();self.c["PC"]+=1 # Fetch local variable offset to inc - self.c["H"]=self.c["LV"] - self.c["MAR"]=self.c["MBRU"]+self.c["H"] - self.rd() - self.fetch();self.c["PC"]+=1 # Fetch inc value - self.c["H"]=self.c["MDR"] - self.c["MDR"]=self.c["MBR"]+self.c["H"] - self.wr() - elif opcode==ijvm["GOTO"]: - self.fetch();self.c["PC"]+=1 # Fetch first byte - self.c["OPC"]=self.c["PC"]-1 - self.c["H"]=self.c["MBR"]<<8 - self.fetch();self.c["PC"]+=1 # Fetch second byte - self.c["H"]=self.c["MBRU"]|self.c["H"] - self.c["PC"]=self.c["OPC"]+self.c["H"] - elif opcode==ijvm["OUT"]: - self.fetch();self.c["PC"]+=1 # Fetch byte to push in MBR - print(str(chr(self.c["MBRU"])),end="") # MBRU because no char which are negative - elif opcode==ijvm["IFEQ"]: - self.c["SP"]=self.c["SP"]-1 - self.c["MAR"]=self.c["SP"] - self.c["OPC"]=self.c["TOS"] - self.rd() - self.c["TOS"]=self.c["MDR"] - if self.c["OPC"]==0: - self.T() - else: - self.F() - elif opcode==ijvm["IFLT"]: - self.c["SP"]=self.c["SP"]-1 - self.c["MAR"]=self.c["SP"] - self.c["OPC"]=self.c["TOS"] - self.rd() - self.c["TOS"]=self.c["MDR"] - if self.c["OPC"]<0: - self.T() - else: - self.F() - elif opcode==ijvm["HALT"]: - return(1) - else: - if opcode in ijvm: - print("Instruction {} not yet implemented.".format(ijvm[opcode])) - else: - raise RuntimeError("Instruction {} not found on address {}".format(opcode,self.c["PC"]-1)) - return(0) - - def T(self): # This function is here just to follow ijvm implementation of "Structured Computer Organization" - self.fetch();self.c["PC"]+=1 # exactly like GOTO implementation - self.c["OPC"]=self.c["PC"]-1 # exactly like GOTO implementation - ###### GOTO2 ##### - self.c["H"]=self.c["MBR"]<<8 - self.fetch();self.c["PC"]+=1 # Fetch second byte - self.c["H"]=self.c["MBRU"]|self.c["H"] - self.c["PC"]=self.c["OPC"]+self.c["H"] - ################## - def F(self): # This function is here just to follow ijvm implementation of "Structured Computer Organization" - self.fetch();self.c["PC"]+=1 # Needed because memory access take 1 cycle in simulation - self.c["PC"]=self.c["PC"]+1 - - def dump(self): - """ - Print RAM, stack and registers - """ - print("-------------- RAM --------------") - self.c["RAM"].dump() - print("------------- Stack -------------") - self.c["RAM"].dumpRange(self.c["LV"]*4,self.c["SP"]*4,4) # Convert address to 32bits value - print("----------- Registers -----------") - for key,value in self.c.items(): - if key!="RAM": - print("{}={}".format(key,value)) - print("---------------------------------") diff --git a/components/ram.py b/components/ram.py deleted file mode 100644 index dd99ada..0000000 --- a/components/ram.py +++ /dev/null @@ -1,94 +0,0 @@ -from components.ijvm import ijvm - -class Ram: - - def __init__(self,components,size): - self.data=dict() - self.lastAddr=size-1 - self.c=components - - def loadRamFile(self,filepath): - """ - Load a Ram file into self.data - """ - data=dict() - addr=0 - f=open(filepath,"r") - for line in f.readlines(): - line=line.rstrip() # remove \n - if line in ijvm: - data[addr]=int(ijvm[line]) - else: - try: - value=int(line,0) - except: - raise ValueError("Invalide RAM entry: Address {} value {}".format(addr,line)) - if value>255: - raise ValueError("Ram contain values that does not fit in a byte: value {} at address {}".format(value,addr)) - data[addr]=value - addr+=1 - f.close() - self.data=data - - def write(self): - """ - Write data to memory based Mic-1 architecture - """ - addr=self.c["MAR"]*4 # Don't forget MAR address 32bits block of memory - if addr>self.lastAddr: - raise ValueError("You get out of the ram by trying to set a value at address {}, max address is {}".format(addr,self.lastAddr)) - #### Little endian #### - self.data[addr]=self.c["MDR"] & 0xFF - self.data[addr+1]=self.c["MDR"] & 0xFF00 - self.data[addr+2]=self.c["MDR"] & 0xFF0000 - self.data[addr+3]=self.c["MDR"] & 0xFF000000 - - - def read(self): - """ - Read data from memory based Mic-1 architecture - """ - addr=self.c["MAR"]*4 # Don't forget MAR address 32bits block of memory - value=None - try: - #### Little endian #### - value=(self.data[addr+3]<<24)|(self.data[addr+2]<<16)|(self.data[addr+1]<<8)|self.data[addr] - except: - if addr>self.lastAddr: - raise ValueError("You get out of the ram by trying to get value at address {}, max address is {}".format(addr,self.lastAddr)) - if(value==None): - return(0) - return(value) - - def fetch(self): - """ - Fetch next byte from memory based Mic-1 architecture - """ - addr=self.c["PC"] - value=None - try: - value=self.data[addr] - except: - if addr>self.lastAddr: - raise ValueError("You get out of the ram by trying to get value at address {}, max address is {}".format(addr,self.lastAddr)) - if(value==None): - return(0) - return(value) - - def dump(self): - """ - Simple dump helper - """ - for key,value in self.data.items(): - #print("{}:{}".format(key,bin(value)[2:])) - print("{}:{}".format(key,value)) - - def dumpRange(self,start,end,step): - """ - Another dump helper - """ - for i in range(start,end+1,step): - try: - print("{}:{}".format(i,self.data[i])) - except: - print("{}:0".format(i)) -- cgit v1.2.3