Commit 59d224cc authored by Khoi Lam's avatar Khoi Lam 💬
Browse files

Lab 5 Finished

parent c636458e
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/pyriscv.iml" filepath="$PROJECT_DIR$/.idea/pyriscv.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
# filename: fetch_decode.py
import itertools
import sys
from pydigital.memory import readmemh
from pydigital.memory import Memory
from pydigital.memory import MemorySegment
from pydigital.register import Register
from riscv_isa import Instruction
from regfile import RegFile
from mux import make_mux
from riscv_isa.decoder import control
from alu import alu
# the PC register
PC = Register()
# construct a memory segment for instruction memory
# load the contents from the 32-bit fetch_test hex file (big endian)
# imem = readmemh('riscv_isa/programs/fetch_test.hex',
# word_size = 4, byteorder = 'big')
pc_val = PC.out()
def display(pc_val, instr):
if pc_val == None:
return "PC: xxxxxxxx, IR: xxxxxxxx"
else:
return f"PC: {pc_val:08x}, IR: {instr.val:08x}, {instr}" # {instr} just returns the representation of the instruction that we overloaded with __str__ in isa.py
# run cpu
def run_cpu(imem, dmem, debug):
startup = True
# create the regfile
my_reg = RegFile()
my_reg.clock(2 , 0x000effff, 1)
# generate system clocks until we reach a stopping condition
# this is basically the run function from the last lab
for t in itertools.count(): # t represents clock
# sample inputs
pc_val = PC.out()
# access instruction memory
instr = Instruction(imem[pc_val], pc_val)
# RESET the PC register
if startup:
PC.reset(imem.begin_addr)
startup = False
print(f"{t:20d}:", display(pc_val, instr))
continue
# print one line at the end of the clock cycle
print(f"{t:20d}:", display(pc_val, instr))
# clock logic blocks, PC is the only clocked module!
# decide next PC based on what instruction is run
ecall_val = my_reg.read(10) #ecall argument is the value in a0
# Get the values in rs1 rs2 and rd
rs1_value = my_reg.read(int(instr.rs1, 2))
rs2_value = my_reg.read(int(instr.rs2, 2))
# decide if there is a branch instruction and if the branch was taken for that instruction
isTaken = False
if (instr.instr_name == "beq" and (rs1_value == rs2_value) ): isTaken = True
if (instr.instr_name == "bne" and (rs1_value != rs2_value) ): isTaken = True
op1_mux = make_mux(lambda: rs1_value, lambda : None, lambda: instr.immU)
op2_mux = make_mux(lambda : rs2_value, lambda : instr.immI, lambda :instr.immS, lambda: pc_val)
# getting all control signals from the decoder
alu_fun = control[instr.instr_name].ALU_fun
op1_sel = control[instr.instr_name].op1_sel
op2_sel = control[instr.instr_name].op2_sel
rf_wen = control[instr.instr_name].rf_wen
wb_sel = control[instr.instr_name].wb_sel
mem_val = control[instr.instr_name].mask_type
mem_wr = control[instr.instr_name].mem_wr
mem_em = control[instr.instr_name].mem_em
result = alu(op1_mux(op1_sel), op2_mux(op2_sel), alu_fun)
# Data Memory Read
if mem_wr == 0 and mem_em == 1:
rdata = dmem.out(result)
# Data Memory Write
dmem.clock(result, rs2_value, mem_wr, mem_val)
writeback_mux = make_mux(lambda : 4 + pc_val, lambda: result, lambda: rdata, lambda: 0) # replace first None with dmem.out() and 2nd None with csr
my_reg.clock(int(instr.rd,2), writeback_mux(wb_sel), rf_wen)
if instr.instr_name == "jal":
PC.clock(instr.immUJ + pc_val)
elif isTaken:
PC.clock(instr.immSB + pc_val)
else:
PC.clock(pc_val + 4)
rd_value = my_reg.read(int(instr.rd, 2))
if debug != 0:
my_reg.display()
print("------------------------------------------------------------------")
# the default values for instr are strings, if you want them as ints you will need to do int(,2)
if instr.instr_name == "ecall":
if ecall_val == 0:
print('ECALL(' + str(format(ecall_val)) + '): ' + 'HALT')
elif ecall_val == 10:
print('ECALL(' +str(format(ecall_val)) +'): ' + 'EXIT')
else:
print('ECALL(' +str(format(ecall_val)) +'): ' + str(my_reg.read(11)))
# check stopping conditions on NEXT instruction
if PC.out() > 0x1100:
print("STOP -- PC is large! Is something wrong?")
break
if imem[PC.out()] == 0:
print("Done -- end of program.")
break
# display the regfile after all instructions are run
print("--------------------Final register values-----------------------")
my_reg.display()
if __name__ == "__main__":
if len(sys.argv) == 1:
program_file = "riscv_isa/programs/mult3.hex" # default instruction file
else:
program_file = sys.argv[1] # or choose another file
# construct a memory segment for the instruction memory
# load the contents from the 32-bit fetch_test hex file (big endian)
imem = readmemh(program_file, word_size=4, byteorder='big')
dmem = Memory(MemorySegment(0xE0000, count = 0x10000)) #for lab 5
sys.exit(run_cpu(imem, dmem, debug = 0))
......@@ -28,7 +28,7 @@ class Memory:
return self.mem[addr] & 0xffffffffffffffff
else:
raise ValueError("Mem can only access Bytes/Half Words/Words.")
def clock(self, addr, data, mem_rw = 0, byte_count = 4):
def clock(self, addr, data, mem_rw = 0, byte_count = 4): #byte_count = mask_type = mem_val
"synchronous write, mem_rw=1 for write"
if mem_rw == 1:
mask = (2**(byte_count*8))-1
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment