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 --- MicSim/components/__init__.py | 0 MicSim/components/caretaker.py | 34 +++++++ MicSim/components/ijvm.py | 30 ++++++ MicSim/components/microprogram.py | 204 ++++++++++++++++++++++++++++++++++++++ MicSim/components/ram.py | 83 ++++++++++++++++ MicSim/micsim.py | 18 ++++ MicSim/ram.txt | 2 + MicSim/test/__init__.py | 0 MicSim/test/test_ram.py | 34 +++++++ README.md | 3 +- components/__init__.py | 0 components/caretaker.py | 34 ------- components/ijvm.py | 30 ------ components/microprogram.py | 202 ------------------------------------- components/ram.py | 94 ------------------ micsim.py | 15 --- ram.txt | 9 -- 17 files changed, 407 insertions(+), 385 deletions(-) create mode 100644 MicSim/components/__init__.py create mode 100644 MicSim/components/caretaker.py create mode 100644 MicSim/components/ijvm.py create mode 100644 MicSim/components/microprogram.py create mode 100644 MicSim/components/ram.py create mode 100755 MicSim/micsim.py create mode 100644 MicSim/ram.txt create mode 100644 MicSim/test/__init__.py create mode 100644 MicSim/test/test_ram.py 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 delete mode 100755 micsim.py delete mode 100644 ram.txt diff --git a/MicSim/components/__init__.py b/MicSim/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/MicSim/components/caretaker.py b/MicSim/components/caretaker.py new file mode 100644 index 0000000..ab20fba --- /dev/null +++ b/MicSim/components/caretaker.py @@ -0,0 +1,34 @@ +#!/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/MicSim/components/ijvm.py b/MicSim/components/ijvm.py new file mode 100644 index 0000000..86f5f63 --- /dev/null +++ b/MicSim/components/ijvm.py @@ -0,0 +1,30 @@ + +# 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/MicSim/components/microprogram.py b/MicSim/components/microprogram.py new file mode 100644 index 0000000..ec84886 --- /dev/null +++ b/MicSim/components/microprogram.py @@ -0,0 +1,204 @@ + +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 + """ + little_endian=self.c["RAM"].read() + ##### Build little endian version of MDR #### + big_endian=(little_endian&0xFF)<<24 + big_endian=big_endian|(((little_endian>>8)&0xFF)<<16) + big_endian=big_endian|(((little_endian>>16)&0xFF)<<8) + big_endian=big_endian|((little_endian>>24)&0xFF) + ############################################## + self.c["MDR"]=big_endian + + def wr(self): + """ + Write data into memory + """ + ##### Build little endian version of MDR #### + little_endian=(self.c["MDR"]&0xFF)<<24 + little_endian=little_endian|(((self.c["MDR"]>>8)&0xFF)<<16) + little_endian=little_endian|(((self.c["MDR"]>>16)&0xFF)<<8) + little_endian=little_endian|((self.c["MDR"]>>24)&0xFF) + ############################################## + big_endian=self.c["MDR"] # Backup MDR before change it to little endian + self.c["MDR"]=little_endian # Load little endian value + self.c["RAM"].write() # Write little endian value into memory + self.c["MDR"]=big_endian # Restore big endian + + 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 + diff --git a/MicSim/components/ram.py b/MicSim/components/ram.py new file mode 100644 index 0000000..6a5b02e --- /dev/null +++ b/MicSim/components/ram.py @@ -0,0 +1,83 @@ +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)) + #### Split bytes and write #### + self.data[addr+3]=self.c["MDR"] & 0xFF + self.data[addr+2]=self.c["MDR"]>>8 & 0xFF + self.data[addr+1]=self.c["MDR"]>>16 & 0xFF + self.data[addr]=self.c["MDR"]>>24 & 0xFF + + + 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: + #### Combine bytes #### + value=self.data[addr]<<24|(self.data[addr+1]<<16)|(self.data[addr+2]<<8)|(self.data[addr+3]) + 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): + """ + Fetch RAM data (usefull for unit tests) + """ + return(self.data) + diff --git a/MicSim/micsim.py b/MicSim/micsim.py new file mode 100755 index 0000000..a45311f --- /dev/null +++ b/MicSim/micsim.py @@ -0,0 +1,18 @@ +#!/usr/bin/python + +from components.microprogram import Microprogram +from components.ram import Ram +from components.caretaker import Caretaker + +c=Caretaker() # Init components +RAM=Ram(c,5000) # Init ram +RAM.loadRamFile("./ram.txt") # Load Ram from file +c["RAM"]=RAM # Add ram to components + + +mic=Microprogram(c) # Create micro program +mic.run() # Run the micro program + +mic.rd() +print(bin(c["MDR"])) +print(RAM.dump()) diff --git a/MicSim/ram.txt b/MicSim/ram.txt new file mode 100644 index 0000000..660c3c6 --- /dev/null +++ b/MicSim/ram.txt @@ -0,0 +1,2 @@ +BIPUSH +9 diff --git a/MicSim/test/__init__.py b/MicSim/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/MicSim/test/test_ram.py b/MicSim/test/test_ram.py new file mode 100644 index 0000000..1570e0d --- /dev/null +++ b/MicSim/test/test_ram.py @@ -0,0 +1,34 @@ + +from components.ram import Ram +import unittest +from random import randint + + +class RamTest(unittest.TestCase): + + def setUp(self): + """ + Init test + """ + self.caretaker=dict({"MDR":0,"MAR":0,"MBR":0,"PC":0}) + + def test_write(self): + """ + Test write method + """ + toWrite=randint(0,2**32) # Pick a random number to write + self.caretaker["MDR"]=toWrite + ram=Ram(self.caretaker,10000) + ram.write() # Write a random number at address 0 + + data=ram.dump() # Dump ram + ##### Test if everything is written using big endian model ##### + self.assertEqual((toWrite>>24)&0xFF,data[self.caretaker["MAR"]]) + self.assertEqual((toWrite>>16)&0xFF,data[self.caretaker["MAR"]+1]) + self.assertEqual((toWrite>>8)&0xFF,data[self.caretaker["MAR"]+2]) + self.assertEqual(toWrite&0xFF,data[self.caretaker["MAR"]+3]) + + + +if __name__ == "__main__": + unittest.main() diff --git a/README.md b/README.md index 50ddb63..2fa18f1 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ It is simple, you have to: 3. Enjoy ! ### I want to know more about it.... -All the architecture components are located in _components_ folder: +Source code is located in MicSim folder. All the components used for the Mic-1 architecture are +located in _MicSim/components_ folder: - **ijvm.py** Contains standard IJVM constant - **microprogram.py** Contains IJVM implementation that use Mic-1 architecture - **caretaker.py** Hold all the Mic-1 architecture components (registers, ram etc..) 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)) diff --git a/micsim.py b/micsim.py deleted file mode 100755 index 46df648..0000000 --- a/micsim.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python - -from components.microprogram import Microprogram -from components.ram import Ram -from components.caretaker import Caretaker - -c=Caretaker() # Init components -RAM=Ram(c,5000) # Init ram -RAM.loadRamFile("./ram.txt") # Load Ram from file -c["RAM"]=RAM # Add ram to components - - -mic=Microprogram(c) # Create micro program -mic.run() # Run the micro program -mic.dump() # Dump ram diff --git a/ram.txt b/ram.txt deleted file mode 100644 index 9cfc244..0000000 --- a/ram.txt +++ /dev/null @@ -1,9 +0,0 @@ -BIPUSH --4 -IFLT -0 -4 -BIPUSH -6 -BIPUSH -7 -- cgit v1.2.3