diff --git a/README.md b/README.md index 9c5db86..80d425a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ -# architecture-2022 - +# 2022秋 高级计算机体系结构 diff --git a/hw3/addiuTest.py b/hw3/addiuTest.py new file mode 100644 index 0000000..e92e650 --- /dev/null +++ b/hw3/addiuTest.py @@ -0,0 +1,26 @@ +from hardware.hardware import Hardware +from execute.controller import Controller +from execute.debugger import Debugger + +hw = Hardware() +ctrl = Controller(hw) +dbg = Debugger(hw) +prog = 'program/addiuTest.txt' + +dbg.loadProgram(prog) + +print('running...') +ctrl.run() +ctrl.run() +ctrl.run() +dbg.dumpGenReg() + +print('running...') +ctrl.run() +ctrl.run() +ctrl.run() +dbg.dumpGenReg() + +print('running...') +ctrl.run() +dbg.dumpGenReg() diff --git a/hw3/execute/controller.py b/hw3/execute/controller.py new file mode 100644 index 0000000..7b3dc4a --- /dev/null +++ b/hw3/execute/controller.py @@ -0,0 +1,72 @@ +from hardware.hardware import Hardware +from instruction.nop import Nop +from instruction.ri.addiu import Addiu +from instruction.ldst.load import Load +from instruction.ldst.store import Store +from instruction.br.BEQ import Beq +from instruction.rr.addu import Addu +from instruction.j.j import J + +class Controller: + opMap = { + 0x09: Addiu, + 0x20: Load, + 0x28: Store, + 0x04: Beq, + 0x02: J, + } + funcMap = { + 0x00: Nop, + 0x21: Addu, + } + + def __init__(self, hw): + self.hw = hw + + #获取指令对象 + #输入: + # instr为指令编码 + #输出: + # instr表示的指令类型的对象 + def getInstrObj(self, instr): + mask = (1 << 6) - 1 + op = (instr >> 26) & mask + func = instr & mask + + if op == 0x00: + if func in Controller.funcMap.keys(): + return Controller.funcMap[func](self.hw) + else: + raise Exception('instruction does not exist') + else: + if op in Controller.opMap.keys(): + return Controller.opMap[op](self.hw) + else: + raise Exception('instruction does not exist') + + #取指令阶段 + #效果: + # 将即将执行的指令编码写入instr寄存器,pc+4 + def instrFetch(self): + #从指令存储器中取指令 + pc = self.hw.pc.read() + instr = self.hw.instrMem.read(pc) + self.hw.pplReg[1][0].write(instr) + + #pc+4 + self.hw.pc.write(pc + 4) + + return instr + + #无流水线的执行 + #效果: + # 完整执行一条指令 + def run(self): + #取指令,获取指令对象 + instr = self.instrFetch() + instrObj = self.getInstrObj(instr) + self.hw.globalSync() + + for i in range(len(instrObj.stages)): + instrObj.stages[i]() + self.hw.globalSync() diff --git a/hw3/execute/debugger.py b/hw3/execute/debugger.py new file mode 100644 index 0000000..a652e71 --- /dev/null +++ b/hw3/execute/debugger.py @@ -0,0 +1,80 @@ +from hardware.hardware import Hardware + +class Debugger: + def __init__(self, hw): + self.hw = hw + + #打印程序计数器 + #效果: + # 打印当前pc寄存器的值 + def dumpPC(self): + pc = self.hw.pc.read() + print('pc: {:08x}'.format(pc)) + + #打印通用寄存器 + #效果: + # 打印当前所有通用寄存器的值 + def dumpGenReg(self): + for i in range(self.hw.genRegCnt): + data = self.hw.genReg[i].read() + print('GR{:02}: {:08x}'.format(i, data)) + + #打印流水线寄存器 + #效果: + # 打印当前所有流水线寄存器的值 + def dumpPplReg(self): + for i in range(self.hw.stageCnt): + print('stage{}:'.format(i)) + + for j in range(self.hw.pplRegCnt): + data = self.hw.pplReg[i][j].read() + print('PR{}: {:08x}'.format(j, data)) + + #打印指令存储器 + #输入: + # addr为地址 + #效果: + # 打印当前指令存储器地址addr所在的一个字 + def dumpInstrMem(self, addr): + data = self.hw.instrMem.read(addr) + print('IM{:08x}: {:08x}'.format(addr, data)) + + #打印数据存储器 + #输入: + # addr为地址 + #效果: + # 打印当前数据存储器地址addr所在的一个字 + def dumpDataMem(self, addr): + data = self.hw.dataMem.read(addr) + print('DM{:08x}: {:08x}'.format(addr, data)) + + #获取指令列表 + #输入: + # fileName为程序文件名 + #输出: + # 程序中指令的列表 + #约束: + # 程序文件的每一行是一个8位16进制数,表示一条指令 + def getListFromFile(fileName): + instrList = [] + program = open(fileName, 'r') + for line in program: + instrList.append(int(line, 16)) + + return instrList + + #加载程序 + #输入: + # fileName为程序文件名 + #效果: + # 将程序写入指令存储器,地址从0开始,并将pc置为0 + def loadProgram(self, fileName): + instrList = Debugger.getListFromFile(fileName) + addr = 0 + for instr in instrList: + self.hw.instrMem.write(addr, instr) + self.hw.globalSync() + addr = addr + 4 + + self.hw.pc.write(0) + self.hw.globalSync() diff --git a/hw3/hardware/hardware.py b/hw3/hardware/hardware.py new file mode 100644 index 0000000..9cc199d --- /dev/null +++ b/hw3/hardware/hardware.py @@ -0,0 +1,51 @@ +from hardware.util import Register, Memory + +#硬件资源 +class Hardware: + def __init__(self): + #寄存器 + self.pc = Register() #程序计数器 + + #通用寄存器 + self.genRegCnt = 32 #通用寄存器数 + self.genReg = [] #通用寄存器组 + for i in range(self.genRegCnt): + self.genReg.append(Register()) + + #流水线寄存器 + # 约定:指令在第i个阶段可以读pplReg[i]中的寄存器、写pplReg[i+1]中的寄存器 + self.pplRegCnt = 5 #流水线上每个阶段的寄存器数 + self.stageCnt = 5 #流水线阶段数 + self.pplReg = [] #流水线寄存器 + for i in range(self.stageCnt): + stage = [] + for j in range(self.pplRegCnt): + stage.append(Register()) + self.pplReg.append(stage) + + #存储器 + self.instrMemSize = 1 << 32 #指令存储器字节数 + self.dataMemSize = 1 << 32 #数据存储器字节数 + + self.instrMem = Memory(self.instrMemSize) #指令存储器 + self.dataMem = Memory(self.dataMemSize) #数据存储器 + + #全局同步 + #效果: + # 对所有寄存器和存储器进行同步 + def globalSync(self): + #程序计数器同步 + self.pc.sync() + + #通用寄存器同步 + for reg in self.genReg: + reg.sync() + + #流水线寄存器同步 + for stage in self.pplReg: + for reg in stage: + reg.sync() + + #存储器同步 + self.instrMem.sync() + self.dataMem.sync() diff --git a/hw3/hardware/util.py b/hw3/hardware/util.py new file mode 100644 index 0000000..7fb4dca --- /dev/null +++ b/hw3/hardware/util.py @@ -0,0 +1,84 @@ +#寄存器 +# 约定:寄存器为1word=32bit +class Register: + def __init__(self): + self.data = 0 + self.buff = None + + #读数据 + #输出: + # 寄存器中的数据 + def read(self): + return self.data + + #写数据 + #输入: + # data为写入的数据 + #效果: + # 将data写入缓冲区 + def write(self, data): + self.buff = data + + #同步 + #效果: + # 将缓冲区中的数据写入寄存器 + def sync(self): + if self.buff is not None: + self.data = self.buff + self.buff = None + +#存储器 +# 约定:每个存储单元为1byte=8bit,但存取时需要按字对齐 +class Memory: + def __init__(self, size): + self.size = size >> 2 + self.dict = {} + self.addr = None + self.buff = None + + #读数据 + #输入: + # addr为读取的地址 + #输出: + # 地址addr所在的一个字,若addr不是4的整数倍,将向下取整 + def read(self, addr): + addr = addr >> 2 + + #检查地址是否越界 + if addr < 0 or addr >= self.size: + raise Exception("memory address out of bounds") + + if addr in self.dict.keys(): + #该地址被访问过 + return self.dict[addr] + else: + #该地址未被访问过 + self.dict[addr] = 0 + return 0 + + #写数据 + #输入: + # addr为写入的地址 + # data为写入的数据 + #效果: + # 将data写入地址addr所在的一个字的缓冲区 + # + #一个周期内只能写入一个数据 + def write(self, addr, data): + addr = addr >> 2 + + #检查地址是否越界 + if addr < 0 or addr >= self.size: + raise Exception("memory address out of bounds") + + self.addr = addr + self.buff = data + + #同步 + #效果: + # 将缓冲区中的数据写入存储器 + def sync(self): + if self.addr is not None: + self.dict[self.addr] = self.buff + self.addr = None + self.buff = None diff --git a/hw3/instruction.md b/hw3/instruction.md new file mode 100644 index 0000000..2603d8b --- /dev/null +++ b/hw3/instruction.md @@ -0,0 +1,27 @@ +## 已实现的指令 +### 1 br型 +#### 1.1 beq 相等时跳转 +TODO + +### 2 j型 +#### 2.1 j 跳转 +TODO + +### 3 rr型 +#### 3.1 addu 无符号加 +TODO + +### 4 ri型 +#### 4.1 addiu 无符号加立即数 +TODO + +### 5 ldst型 +#### 5.1 load 加载字节 +TODO + +#### 5.2 store 存储字节 +TODO + +### 6 其他 +#### 6.1 nop 空指令 +TODO diff --git a/hw3/instruction/br/BEQ.py b/hw3/instruction/br/BEQ.py new file mode 100644 index 0000000..4d3e7bb --- /dev/null +++ b/hw3/instruction/br/BEQ.py @@ -0,0 +1,37 @@ +from instruction.instruction import Instruction +from hardware.hardware import Hardware +class Beq(Instruction): + def __init__(self, hw): + super().__init__(hw) + + def instrDecode(self): + super().instrDecode() + instr = self.hw.pplReg[1][0].read() + mask1 = (1 << 5) - 1 + rs = (instr >> 21) & mask1 # 这里的rs为base + rsData = self.hw.genReg[rs].read() + rt = (instr >> 16) & mask1 + rtData = self.hw.genReg[rt].read() + mask2 = (1 << 16) - 1 + offset = instr & mask2 + + self.hw.pplReg[2][0].write(rsData) # A <= Reg[base] + self.hw.pplReg[2][1].write(rtData) # B <= rt + self.hw.pplReg[2][2].write(offset) # C <= offset + def execute(self): + super().execute() + pc=self.hw.pc.read() + if self.hw.pplReg[2][0].read==self.hw.pplReg[2][1].read: + jpc=pc+4+self.hw.pplReg[2][2].read*4#offest后补两个0 + else: + jpc=pc+4 + self.hw.pplReg[3][0].write(jpc) + + def memAccess(self): + super().memAccess() + + Hardware.pc.write(self.hw.pplReg[3][0].read()) + + def writeBack(self): + super().writeBack() + diff --git a/hw3/instruction/instruction.py b/hw3/instruction/instruction.py new file mode 100644 index 0000000..4468562 --- /dev/null +++ b/hw3/instruction/instruction.py @@ -0,0 +1,27 @@ +#指令抽象类 +# 一条指令的实现应当继承这个类,并重写四个方法 +class Instruction: + #指令译码阶段 + def instrDecode(self): + pass + + #运算阶段 + def execute(self): + pass + + #访问存储器阶段 + def memAccess(self): + pass + + #写回寄存器阶段 + def writeBack(self): + pass + + def __init__(self, hw): + self.hw = hw #指令关联的硬件结构 + self.stages = [ + self.instrDecode, + self.execute, + self.memAccess, + self.writeBack + ] #每条指令包含四个阶段 diff --git a/hw3/instruction/j/j.py b/hw3/instruction/j/j.py new file mode 100644 index 0000000..17ac170 --- /dev/null +++ b/hw3/instruction/j/j.py @@ -0,0 +1,28 @@ +from instruction.instruction import Instruction +from hardware.hardware import Hardware + +class J(Instruction): + def instrDecode(self): + super().instrDecode() + + instr = self.hw.pplReg[1][0].read() + nextPC = str(bin(Hardware.pc.read() + 4))[2:6] # PC+4,再取高4位 + instr_index = str(bin(instr))[8:34] # instruction转换为字符串类型时,有‘0b’需要去除,然后取出其中的[25:0] + + self.hw.pplReg[2][0].write(nextPC) + self.hw.pplReg[2][1].write(instr_index) + + def execute(self): + super().execute() + + jPC = int(self.hw.pplReg[2][0].read + self.hw.pplReg[2][1].read + 2*'0') # PC <-- PC[31:28] || instr_index || 00. (||为拼接操作) + + self.hw.pplReg[3][0].write(jPC) + + def memAccess(self): + super().memAccess() + + Hardware.pc.write(self.hw.pplReg[3][0].read()) + + def writeBack(self): + super().writeBack() \ No newline at end of file diff --git a/hw3/instruction/ldst/ldst.py b/hw3/instruction/ldst/ldst.py new file mode 100644 index 0000000..41cc8fc --- /dev/null +++ b/hw3/instruction/ldst/ldst.py @@ -0,0 +1,28 @@ +from instruction.instruction import Instruction + + +# 存取类指令 +class Ldst(Instruction): + def __init__(self, hw): + super().__init__(hw) + + def instrDecode(self): + super().instrDecode() + instr = self.hw.pplReg[1][0].read() + mask1 = (1 << 5) - 1 + base = (instr >> 21) & mask1 # 这里的rs为base + baseData = self.hw.genReg[base].read() + rt = (instr >> 16) & mask1 + mask2 = (1 << 16) - 1 + offset = instr & mask2 + + self.hw.pplReg[2][0].write(baseData) # A <= Reg[base] + self.hw.pplReg[2][1].write(rt) # B <= rt + self.hw.pplReg[2][2].write(offset) # C <= offset + + def execute(self): + super().execute() + rt = self.hw.pplReg[2][1].read() + addr = self.hw.pplReg[2][0].read() + self.hw.pplReg[2][2].read() # 计算地址 = baseData+offset + self.hw.pplReg[3][0].write(addr) + self.hw.pplReg[3][1].write(rt) diff --git a/hw3/instruction/ldst/load.py b/hw3/instruction/ldst/load.py new file mode 100644 index 0000000..ef60366 --- /dev/null +++ b/hw3/instruction/ldst/load.py @@ -0,0 +1,20 @@ +from instruction.ldst.ldst import Ldst + + +class Load(Ldst): + def __init__(self, hw): + super().__init__(hw) + + def memAccess(self): + super().memAccess() + addr = self.hw.pplReg[3][0].read() + memData = self.hw.dataMem.read(addr) + rt = self.hw.pplReg[3][1].read() + self.hw.pplReg[4][0].write(memData) # 取内存数据 + self.hw.pplReg[4][1].write(rt) + + def writeBack(self): + super().writeBack() + rt = self.hw.pplReg[4][1].read() + memData = self.hw.pplReg[4][0].read() + self.hw.genReg[rt].write(memData) # 数据写回目标寄存器 diff --git a/hw3/instruction/ldst/store.py b/hw3/instruction/ldst/store.py new file mode 100644 index 0000000..dc012e0 --- /dev/null +++ b/hw3/instruction/ldst/store.py @@ -0,0 +1,15 @@ +from instruction.ldst.ldst import Ldst + + +class Store(Ldst): + def __init__(self, hw): + super().__init__(hw) + + def memAccess(self): + super().memAccess() + addr = self.hw.pplReg[3][0].read() + rt = self.hw.pplReg[3][1].read() + regData = self.hw.genReg[rt].read() # 取寄存器数据 + self.hw.dataMem.write(addr, regData) # 写入存储器 + + diff --git a/hw3/instruction/nop.py b/hw3/instruction/nop.py new file mode 100644 index 0000000..53dcda0 --- /dev/null +++ b/hw3/instruction/nop.py @@ -0,0 +1,16 @@ +from instruction.instruction import Instruction + +#空指令 +class Nop(Instruction): + #什么都不做 + def instrDecode(self): + super().instrDecode() + + def execute(self): + super().execute() + + def memAccess(self): + super().memAccess() + + def writeBack(self): + super().writeBack() diff --git a/hw3/instruction/ri/addiu.py b/hw3/instruction/ri/addiu.py new file mode 100644 index 0000000..b7502c1 --- /dev/null +++ b/hw3/instruction/ri/addiu.py @@ -0,0 +1,16 @@ +from instruction.ri.riInstr import SignExtRegImmInstr + +#无符号加立即数 +class Addiu(SignExtRegImmInstr): + def execute(self): + super().execute() + + op1 = self.hw.pplReg[2][0].read() + op2 = self.hw.pplReg[2][1].read() + rt = self.hw.pplReg[2][2].read() + + mask = (1 << 32) - 1 + res = (op1 + op2) & mask + + self.hw.pplReg[3][0].write(res) + self.hw.pplReg[3][1].write(rt) diff --git a/hw3/instruction/ri/riInstr.py b/hw3/instruction/ri/riInstr.py new file mode 100644 index 0000000..9746d9f --- /dev/null +++ b/hw3/instruction/ri/riInstr.py @@ -0,0 +1,59 @@ +from instruction.instruction import Instruction + +#RI类指令 +class RegImmInstr(Instruction): + def instrDecode(self): + super().instrDecode() + + instr = self.hw.pplReg[1][0].read() + mask = (1 << 5) - 1 + + rs = (instr >> 21) & mask + rsData = self.hw.genReg[rs].read() + rt = (instr >> 16) & mask + + self.hw.pplReg[2][0].write(rsData) + self.hw.pplReg[2][2].write(rt) + + def memAccess(self): + super().memAccess() + + res = self.hw.pplReg[3][0].read() + rt = self.hw.pplReg[3][1].read() + + self.hw.genReg[rt].write(res) + +#进行零扩展的RI类指令 +class ZeroExtRegImmInstr(RegImmInstr): + def instrDecode(self): + super().instrDecode() + + instr = self.hw.pplReg[1][0].read() + mask = (1 << 16) - 1 + + imm = instr & mask + self.hw.pplReg[2][1].write(imm) + +#进行符号扩展的RI类指令 +class SignExtRegImmInstr(RegImmInstr): + #符号扩展 + #输入: + # imm为16bit数据 + #输出: + # imm的32bit符号扩展 + def signedExtend(imm): + mask = (1 << 16) - 1 << 16 + if (imm >> 15) & 1: + return imm | mask + else: + return imm + + def instrDecode(self): + super().instrDecode() + + instr = self.hw.pplReg[1][0].read() + mask = (1 << 16) - 1 + + imm = instr & mask + imm = SignExtRegImmInstr.signedExtend(imm) + self.hw.pplReg[2][1].write(imm) diff --git a/hw3/instruction/rr/addu.py b/hw3/instruction/rr/addu.py new file mode 100644 index 0000000..6f1192c --- /dev/null +++ b/hw3/instruction/rr/addu.py @@ -0,0 +1,50 @@ +from instruction.instruction import Instruction +#from hardware.hardware import Hardware + +#RR类指令 +class Addu(Instruction): + def __init__(self, hw): + super().__init__(hw) + + def instrDecode(self): + super().instrDecode() + instr = self.hw.pplReg[1][0].read() + mask = (1 << 5) - 1 + rs = (instr >> 21) & mask + rsData = self.hw.genReg[rs].read() + rt = (instr >> 16) & mask + rtData = self.hw.genReg[rs].read() + rd = (instr >> 11) & mask + + self.hw.pplReg[2][0].write(rsData) + self.hw.pplReg[2][1].write(rtData) + self.hw.pplReg[2][3].write(rd) + + def execute(self): + super().execute() + + op1 = self.hw.pplReg[2][0].read() + op2 = self.hw.pplReg[2][1].read() + rd = self.hw.pplReg[2][3].read() + + mask = (1 << 32) - 1 + res = (op1 + op2) & mask + + self.hw.pplReg[3][0].write(res) + self.hw.pplReg[3][1].write(rd) + + def memAccess(self): + super().memAccess() + + addr = self.hw.pplReg[3][0].read() + memData = self.hw.dataMem.read(addr) + rd = self.hw.pplReg[3][1].read() + + self.hw.pplReg[4][0].write(memData) # 取内存数据 + self.hw.pplReg[4][1].write(rd) + + def writeBack(self): + super().writeBack() + rd = self.hw.pplReg[4][1].read() + memData = self.hw.pplReg[4][0].read() + self.hw.genReg[rd].write(memData) # 数据写回目标寄存器 \ No newline at end of file diff --git a/hw3/ldstTest.py b/hw3/ldstTest.py new file mode 100644 index 0000000..3c258db --- /dev/null +++ b/hw3/ldstTest.py @@ -0,0 +1,20 @@ +from hardware.hardware import Hardware +from execute.controller import Controller +from execute.debugger import Debugger + +hw = Hardware() +ctrl = Controller(hw) +dbg = Debugger(hw) +prog = 'program/ldstTest.txt' +# Addiu r1,r1,3 +# Store r1, 10(r0) +# Load r2, 10(r0) + +dbg.loadProgram(prog) + +ctrl.run() +ctrl.run() +ctrl.run() +dbg.dumpGenReg() +# dbg.dumpPplReg() +dbg.dumpDataMem(10) diff --git a/hw3/program/addiuTest.txt b/hw3/program/addiuTest.txt new file mode 100644 index 0000000..d81888b --- /dev/null +++ b/hw3/program/addiuTest.txt @@ -0,0 +1,7 @@ +24210001 +24210001 +24210001 +2421ffff +2421ffff +2421ffff +2421ffff diff --git a/hw3/program/ldstTest.txt b/hw3/program/ldstTest.txt new file mode 100644 index 0000000..acc3c34 --- /dev/null +++ b/hw3/program/ldstTest.txt @@ -0,0 +1,3 @@ +24210003 +A001000A +8002000A \ No newline at end of file diff --git a/hw3/program/test.txt b/hw3/program/test.txt new file mode 100644 index 0000000..9981ed0 --- /dev/null +++ b/hw3/program/test.txt @@ -0,0 +1,3 @@ +00001000 +00002000 +00003000 diff --git a/hw4/ir/ir.py b/hw4/ir/ir.py new file mode 100644 index 0000000..ebde27b --- /dev/null +++ b/hw4/ir/ir.py @@ -0,0 +1,168 @@ +#程序类 +class Program: + def __init__(self): + self.instrList = [] #指令列表,其中的元素或者是Instruction,或者是Loop + + #将中间表示转化为代码并输出到文件 + def emit(self, stream, cnt): + for instr in self.instrList: + instr.emit(stream, cnt) + + return cnt + +#循环类 +class Loop: + def __init__(self, iterator, times): + self.iter = iterator #循环变量,是一个寄存器 + self.times = times #循环次数,是一个寄存器 + self.instrList = [] #指令列表,其中的元素是Instruction或Loop,应该有如下的形式 + ''' + beq i, n, out + loop: + [loop body] + addi i, i, 1 + bne i, n, loop + out: + ''' + + def emit(self, stream, cnt): + cnt = cnt + 1 + for i in range(len(self.instrList)): + if i == 0: + self.instrList[0].emit(stream, cnt) + stream.write('loop' + str(cnt) + ':\n') + else: + self.instrList[i].emit(stream, cnt) + + stream.write('out' + str(cnt) + ':\n') + return cnt + +#指令类 +class Instruction: + def __init__(self): + self.rs = [] #源寄存器,是一个列表,其中的元素是该指令读取的所有寄存器号 + #注意这个列表里去掉了重复的元素 + self.rt = None #目的寄存器,是该指令写入的寄存器号 + self.instrStr = None #指令字符串 + + def emit(self, stream, cnt): + pass + +#存储访问指令类 +class MemInstr(Instruction): + def emit(self, stream, cnt): + stream.write(self.instrStr + '\n') + return cnt + +#Load +class Load(MemInstr): + #load reg1, offset(reg2) + def __init__(self, reg1, offset, reg2): + super().__init__() + self.rt = reg1 + self.rs.append(reg2) + self.offset = offset + self.instrStr = 'load r' + str(reg1) + ', ' + str(offset) + '(r' + str(reg2) + ')' + +#Store +class Store(MemInstr): + #store reg1, imm(reg2) + def __init__(self, reg1, offset, reg2): + super().__init__() + + #去掉重复的元素 + self.rs.append(reg1) + if reg1 != reg2: + self.rs.append(reg2) + + self.offset = offset + self.instrStr = 'store r' + str(reg1) + ', ' + str(offset) + '(r' + str(reg2) + ')' + +#ALU型指令类 +class AluInstr(Instruction): + def emit(self, stream, cnt): + stream.write(self.instrStr + '\n') + return cnt + +#Nop +class Nop(AluInstr): + #nop + def __init__(self): + super().__init__() + self.instrStr = 'nop' + +#Add +class Add(AluInstr): + #add reg1, reg2, reg3 + def __init__(self, reg1, reg2, reg3): + super().__init__() + self.rt = reg1 + + #去掉重复的元素 + self.rs.append(reg2) + if reg2 != reg3: + self.rs.append(reg3) + + self.instrStr = 'add r' + str(reg1) + ', r' + str(reg2) + ', ' + str(reg3) + +#Move +class Move(AluInstr): + #move reg1, reg2 + def __init__(self, reg1, reg2): + super().__init__() + self.rt = reg1 + self.rs.append(reg2) + self.instrStr = 'move r' + str(reg1) + ', r' + str(reg2) + +#Addi +class Addi(AluInstr): + #addi reg1, reg2, imm + def __init__(self, reg1, reg2, imm): + super().__init__() + self.rt = reg1 + self.rs.append(reg2) + self.imm = imm + self.instrStr = 'addi r' + str(reg1) + ', r' + str(reg2) + ', ' + str(imm) + +#条件跳转指令类 +class Condition(Instruction): + pass + +#Bne +class Bne(Condition): + #bne reg1, reg2, label + def __init__(self, reg1, reg2): + #Bne对象的属性中不需要包含label,它应该在将中间表示转化为代码时被加上 + super().__init__() + + #去掉重复的元素 + self.rs.append(reg1) + if reg1 != reg2: + self.rs.append(reg2) + + self.instrStr = 'bne r' + str(reg1) + ', r' + str(reg2) + + def emit(self, stream, cnt): + instrStr = self.instrStr + ', out' + str(cnt) + stream.write(instrStr + '\n') + + return cnt + +#Beq +class Beq(Condition): + #beq reg1, reg2, label + def __init__(self, reg1, reg2): + super().__init__() + + #去掉重复的元素 + self.rs.append(reg1) + if reg1 != reg2: + self.rs.append(reg2) + + self.instrStr = 'beq r' + str(reg1) + ', r' + str(reg2) + + def emit(self, stream, cnt): + instrStr = self.instrStr + ', loop' + str(cnt) + stream.write(instrStr + '\n') + + return cnt diff --git a/hw4/ir/trans.py b/hw4/ir/trans.py new file mode 100644 index 0000000..4c8088f --- /dev/null +++ b/hw4/ir/trans.py @@ -0,0 +1,11 @@ +from ir.ir import * + +#中间表示转化为代码 +#输入: +# ir为中间表示 +# fileName为目的代码的文件名 +#效果: +# 将ir对应的汇编代码写入fileName文件,若文件不存在则创建 +def ir2code(ir, fileName): + fileStream = open(fileName, 'w') + ir.emit(fileStream, 0) diff --git a/hw4/irTest.py b/hw4/irTest.py new file mode 100644 index 0000000..4e4c96c --- /dev/null +++ b/hw4/irTest.py @@ -0,0 +1,28 @@ +from ir.ir import * +from ir.trans import ir2code + +''' +beq r1, r2, out (1) +loop: +load r10, 0(r1) (2) +add r14, r10, r12 (3) +store r14, 0(r1) (4) +addi r1, r1, 1 (5) +bne r1, r2, loop (6) +out: +''' + +prog = Program() +loop = Loop(1, 2) + +loop.instrList.append(Beq(1, 2)) +loop.instrList.append(Load(10, 0, 1)) +loop.instrList.append(Add(14, 10, 12)) +loop.instrList.append(Store(14, 0, 1)) +loop.instrList.append(Addi(1, 1, 1)) +loop.instrList.append(Bne(1, 2)) + +prog.instrList.append(loop) + +fileName = 'program/irTest.txt' +ir2code(prog, fileName) diff --git a/hw4/loop_unrolling.md b/hw4/loop_unrolling.md new file mode 100644 index 0000000..fca034d --- /dev/null +++ b/hw4/loop_unrolling.md @@ -0,0 +1,85 @@ +# 循环展开 +## 1 假设 +关于源代码的形式,做如下的假设: +- 除了循环外,源代码中不含其他分支或跳转指令(比如if语句、goto语句、函数调用等) +- 不区分浮点运算和整数运算 +- 仅包含形如`for i = 0 to n - 1`的循环,其中循环变量`i`在循环体内不会被修改,`n`是变量 + +进一步假设源代码中仅包含以下要素: +- 标签:形如`label: [instruction]`,其中`label`是标签,`[instruction]`是某条指令 +- 功能型指令: + - 加载:形如`load reg1, offset(reg2)`,其中`reg`是寄存器,`offset`是某个整数 + - 存储:形如`store reg1, offset(reg2)`,其中`reg`是寄存器,`offset`是某个整数 + - 加法:形如`add reg1, reg2, reg3`,其中`reg1`、`reg2`、`reg3`是寄存器 + - 移动:形如`move reg1, reg2`,其中`reg1`、`reg2`是寄存器 + - 加立即数:形如`addi reg1, reg2, imm`,其中`reg1`、`reg2`是寄存器,`imm`是某个整数 + - 空指令:形如`nop` +- 条件跳转指令: + - 不相等时跳转:形如`bne reg1, reg2, label`,其中`reg1`、`reg2`是寄存器,`label`是标签 + - 相等时跳转:形如`beq reg1, reg2, label`,其中`reg1`、`reg2`是寄存器,`label`是标签 + +关于寄存器的使用,做如下假设: +- 物理寄存器有32个 +- 存储器中有一块专用区域作为虚拟寄存器的交换空间: + - 交换空间是一块起始地址为0的连续存储空间 + - 交换空间足够大 + +关于指令排序的约束,做如下假设: +- 5阶段流水线 +- 分支延迟1周期,延迟槽中的指令无条件执行 +- (其他假设由实现者自行补充在这里) + +## 2 程序结构 +整个程序的描述如下: +- 输入:源代码的中间表示 +- 输出:经过循环展开和指令重排后的汇编代码 +- 约束:输出代码应当能够直接被CPU执行,并且与输入代码等效 + +我们将整个程序划分为四个模块: +- 循环展开:将代码中的循环展开若干次,展开的次数应当作为参数输入 +- 寄存器管理:将代码中使用的虚拟寄存器号转化为物理寄存器号,适当加入与存储器交换的指令 +- 指令重排:将指令重新排列,以消除指令之间的冲突,并**尽可能地**提高执行效率 +- 代码生成:将经过处理的中间表示转化为输出代码 + +### 2.1 中间表示的形式 +- 一个程序是一个列表,其中每一项或者是一个功能型指令、或者是一个循环 +- 仅考虑特定形式的for循环,因此一个循环可以用如下结构表示: + - 循环变量:一个寄存器 + - 循环次数:一个寄存器 + - 循环体:一个程序,即一列功能型指令或循环(允许循环的嵌套) + +形式化的表达是这样的: +``` +program ::= [item, item, ..., item] +item ::= function | loop +loop ::= [iterator, times, program] +``` + +具体的实现在`ir/ir.py`中,可以阅读一下 + +### 2.2 循环展开模块 +循环展开模块的作用是将一个中间表示中的循环展开指定次数,输出也是一个中间表示 + +实现时注意边界条件,展开后的循环在跳出前的最后一次循环体可能有不一样的形式 + +实现者可以自行决定嵌套的循环如何展开: +- 展开最内层的循环 +- 从内向外展开所有循环 +- 将嵌套的循环展开成单层的循环 + +### 2.3 寄存器管理模块 +在循环展开模块中,通常需要使用更多的寄存器,我们允许指令访问的寄存器号可以是任意的,虚拟寄存器模块负责将这些虚拟寄存器号转化为物理寄存器号 + +当物理寄存器不够用时,需要将寄存器中的数据移到存储器中,在适当的时候调回(参考虚拟内存中的调页) + +寄存器管理模块的输入输出都是一个中间表示,输入中允许访问任意的虚拟寄存器号,输出中仅允许访问有限的物理寄存器号 + +### 2.4 指令重排 +指令重排模块的作用是将指令重新排列,使其成为满足假设的程序,输入输出都是一个中间表示 + +在正确的基础上,实现者可以自行决定优化到什么程度(可以先无脑插入nop) + +### 2.5 代码生成模块 +代码生成模块的作用是将一个中间表示转化为对应的汇编代码,并输出到指定文件 + +## 2 其他事项 diff --git a/hw4/program/irTest.txt b/hw4/program/irTest.txt new file mode 100644 index 0000000..8d257d7 --- /dev/null +++ b/hw4/program/irTest.txt @@ -0,0 +1,8 @@ +beq r1, r2, loop1 +loop1: +load r10, 0(r1) +add r14, r10, 12 +store r14, 0(r1) +addi r1, r1, 1 +bne r1, r2, out1 +out1: diff --git a/hw4/reorder/reorder.py b/hw4/reorder/reorder.py new file mode 100644 index 0000000..56b12cf --- /dev/null +++ b/hw4/reorder/reorder.py @@ -0,0 +1,62 @@ +from ir.ir import * + +#指令重排 +#输入: +# ir为源代码对应的中间表示 +#输出: +# ir中指令按约束重排后的中间表示 +def reorder(ir): + + # reorder list,在列表中重排指令 + ROL = ir + n = len(ROL) + i = 0 + + # 根据相关性插入stall + while i < n: + if i < n - 1: + if (ROL[i][0] == 'l') & (ROL[i+1][0] == 'a'): + if (ROL[i][6] == ROL[i+1][9]) or (ROL[i][6] == ROL[i+1][12]): + ROL.insert(i+1, 'Stall') + i = i + 2 + n = n + 1 + + elif (ROL[i][0] == 'a') & (ROL[i+1][0] == 'a'): + if (ROL[i][5] == ROL[i+1][9]) or (ROL[i][5] == ROL[i+1].instrStr[12]): + j = i + 1 + while j < i + 4: + ROL.insert(j, 'Stall') + i = i + 4 + n = n + 3 + + elif (ROL[i][0] == 'a') & (ROL[i+1][0] == 's'): + if ROL[i][5] == ROL[i+1][7]: + k = i + 1 + while k < i + 3: + ROL.insert(k, 'Stall') + k = k + 1 + i = i + 3 + n = n + 2 + + elif (ROL[i][0] == 'a') & (ROL[i+1][0] == 'b'): + if (ROL[i][6] == ROL[i+1][6]) or (ROL[i][6] == ROL[i+1][9]): + ROL.insert(i + 1, 'Stall') + i = i + 2 + n = n + 1 + + elif (ROL[i][0] == 'b'): + ROL.insert(i + 1, 'Stall') + i = i + 2 + n = n + 1 + + else: + i = i + 1 + print(i) + + elif ROL[i][0] == 'b': + ROL.insert(i + 1, 'Stall') + break + + else: + break + diff --git a/hw4/unroll/unroll.py b/hw4/unroll/unroll.py new file mode 100644 index 0000000..77b276c --- /dev/null +++ b/hw4/unroll/unroll.py @@ -0,0 +1,221 @@ +from hw4.ir.ir import * + +VREG_NUM = 500 +REG_NUM = 32 + +reg_status = {i: None for i in range(REG_NUM)} # 寄存器状态图,键为编号,值为使用该寄存器的指令,None表示空闲 +vreg_status = {'v%d' % i: None for i in range(VREG_NUM)} # 虚拟寄存器状态图 + + +class AllocateException(BaseException): + def __init__(self, info): + self.info = info + + def __str__(self): + return self.info + + +# 随机分配空闲虚拟寄存器 +def allocate_vreg(ir): + for vreg in vreg_status.keys(): + if vreg_status[vreg] is None: + vreg_status[vreg] = ir + return vreg + raise AllocateException('虚拟寄存器已满!') + + +# 释放某一虚拟寄存器 +def free_vreg(i): + vreg_status[i] = None + + +def free_reg(i): + reg_status[i] = None + + +def allocate_reg(ir): + for reg in reg_status.keys(): + if reg_status[reg] is None: + reg_status[reg] = ir + return reg + # 若寄存器已满,分配虚拟寄存器 + allocate_vreg(ir) + + +# 数据相关性分析 +def analyze_hazard(cycle): + hazard = {'RAW': [], + 'WAR': [], + 'WAW': []} + write = [] # 记录所有写操作 + read = [] # 记录所有读操作 + # 分析数据相关性 + for instr in cycle.instrList: # 标记所有读取和写入的寄存器 + if instr.rt is not None: + write.append(instr.rt) + if instr.rs is not None: + read.append(instr.rs) + # 检测写后读(RAW) + for i in range(len(write)): + for j in range(i + 1, len(read)): + if write[i] in read[j]: + hazard['RAW'].append((cycle.instrList[i], cycle.instrList[j])) + # 检测读后写(WAR) + for i in range(len(read)): + for j in range(i + 1, len(write)): + if write[j] in read[i]: + hazard['WAR'].append((cycle.instrList[i], cycle.instrList[j])) + # 检测读后读(WAW) + for i in range(len(write)): + for j in range(i + 1, len(write)): + if write[i] == write[j]: + hazard['WAW'].append((cycle.instrList[i], cycle.instrList[j])) + return hazard + + +# 判断两条指令是否相关 +def judge_hazard(instr1, instr2, hazard): + if (instr1, instr2) in hazard['RAW'] or (instr1, instr2) in hazard['WAR'] or (instr1, instr2) in hazard['WAW']: + return True + elif (instr2, instr1) in hazard['RAW'] or (instr2, instr1) in hazard['WAR'] or (instr2, instr1) in hazard['WAW']: + return True + return False + + +# 延迟分析 +def get_stall(op_this, op_next): + if isinstance(op_this, AluInstr): + if isinstance(op_next, AluInstr): + return 3 + elif isinstance(op_next, Store): + return 2 + elif isinstance(op_next, Condition): + return 1 + else: + return 0 + elif isinstance(op_this, Load): + if isinstance(op_next, AluInstr): + return 1 + elif isinstance(op_next, Store): + return 0 + elif isinstance(op_next, Condition): + return 1 + else: + raise ValueError('Error Instruction!') + elif isinstance(op_this, Condition): + return 1 + else: + return 0 + + +# 在指令1和指令2之间插入一条不相关的指令 +def insert_instr(cycle, hazard, instr1, instr2, isAllocated): + for item in cycle.instrList: + if not judge_hazard(instr1, instr2, hazard): + if isAllocated[item] == 0: + isAllocated[item] = 1 + return item + return None + + +# 循环展开 +# 输入: +# ir为源代码的中间表示 +# times为展开的次数 不少于2 +# 输出: +# ir中循环展开times次的中间表示 +def unroll(ir, times): + global ld_rt, ld_rs, ld_offset, st_rt, st_rs, add_rt, add_rs, addi_rt, addi_rs, addi_imm, cycle + rlt = {'before': [], + 'last': []} + isAllocated = {} + + # 找到循环部分 + for item in ir: + if isinstance(item, Loop): + cycle = item + if cycle is None: + raise ValueError('没有循环部分!') + + # 分析原始指令的操作数 + for item in cycle.instrList: + if isinstance(item, Load): + ld_rt = item.rt + ld_rs = item.rs + ld_offset = item.offset + elif isinstance(item, Store): + st_rt = item.rt + st_rs = item.rs + elif isinstance(item, Add): + add_rt = item.rt + add_rs = item.rs + elif isinstance(item, Addi): + addi_rt = item.rt + addi_rs = item.rs + addi_imm = item.imm + + + # 前若干次 + rlt['before'].append(cycle.instrList[0]) # beq语句 + for time in range(cycle.times): + for item in cycle.instrList: + flag_add = 0 + flag_load = 0 + add_rt_new = None + load_rt_new = None + if isinstance(item, Load): + flag_add = 1 + offset = addi_imm * (time + 1) # 每次offset增加一轮 + try: + load_rt_new = allocate_reg(item) # 分配虚拟寄存器 + new_load = Load(reg1=load_rt_new, offset=offset, reg2=ld_rs) + rlt['before'].append(new_load) + except AllocateException as e: + print(e) + + elif isinstance(item, Add): + flag_load = 1 + try: + add_rt_new = allocate_reg(item) + new_add = Add(reg1=add_rt_new, reg2=add_rs[0], reg3=add_rs[1]) + rlt['before'].append(new_add) + except AllocateException as e: + print(e) + + elif isinstance(item, Store): + if flag_add == 1 and flag_load == 1: # 找到与该stroe配套的load和add + flag_add = 0 + flag_load = 0 + offset = addi_imm * (time + 1) + try: + new_store = Store(reg1=item.rt, offset=offset, reg2=st_rs) + rlt['before'].append(new_store) + # store结束后即可释放之前的寄存器 + free_reg(add_rt_new) + free_reg(load_rt_new) + + except AllocateException as e: + print(e) + cycle_iter_new = None + for item in cycle.instrList: + if isinstance(item, Addi): # 循环变量自增语句 + cycle_iter_new = allocate_reg(item) + new_addi = Addi(reg1=cycle_iter_new, reg2=cycle.iter, imm=cycle.times * addi_imm) + rlt['before'].append(new_addi) + break + + # 计算新的终止条件 + new_reg_for_stop = allocate_reg(Addi(None, None, None)) + new_addi_for_stop = Addi(reg1=new_reg_for_stop, reg2=cycle.times, imm=1 - times) + rlt['before'].append(new_addi_for_stop) + + for item in cycle.instrList: + if isinstance(item, Bne): # Bne 循环终止条件为cycle.iter = cycle.times-times+1 + new_bne = Bne(reg1=cycle_iter_new, reg2=new_reg_for_stop) + rlt['before'].append(new_bne) + break + + # 最后一次 + rlt['last'] = cycle + return rlt + diff --git a/hw5/xzy/run.py b/hw5/xzy/run.py new file mode 100644 index 0000000..deff6df --- /dev/null +++ b/hw5/xzy/run.py @@ -0,0 +1,95 @@ +from scoreboard import Scoreboard + +class Runner: + #指令状态表项 + class InstrItem: + def __init__(self): + self.issue = 0 + self.read = 0 + self.execute = 0 + self.write = 0 + + #功能部件 + class FuncUnit: + def __init__(self, num, execTime, instrStat, scoreboard): + self.num = num + self.execTime = execTime + self.instrStat = instrStat + self.scoreboard = scoreboard + + self.clock = 0 + self.localClock = 0 + self.pc = 0 + + def issue(self, pc, clock): + self.clock = 1 + self.pc = pc + instrItem = Runner.InstrItem() + instrItem.issue = clock + self.instrStat.append(instrItem) + + def run(self, clock): + if self.clock == 1: #读操作数 + if self.scoreboard.readControl(self.num): + self.instrStat[self.pc].read = clock + self.clock += 1 + elif self.clock == 2: #执行 + if self.localClock == 0: #未开始执行 + if self.scoreboard.executeControl(self.num): + self.localClock = 1 + else: + self.localClock += 1 + + if self.localClock == self.execTime: + self.localClock = 0 + self.instrStat[self.pc].execute = clock + self.clock += 1 + elif self.clock == 3: #写回结果 + if self.scoreboard.writeControl(self.num): + self.instrStat[self.pc].write = clock + self.clock = 0 + self.pc = 0 + + def __init__(self, program): + self.regCnt = 32 + self.fuCnt = 4 + self.scoreboard = Scoreboard(32, 4) + self.instrStat = [] + + self.clock = 0 + self.fus = [ + Runner.FuncUnit(0, 1, self.instrStat, self.scoreboard), #整数部件 + Runner.FuncUnit(1, 10, self.instrStat, self.scoreboard), #乘法部件 + Runner.FuncUnit(2, 2, self.instrStat, self.scoreboard), #加法部件 + Runner.FuncUnit(3, 40, self.instrStat, self.scoreboard) #除法部件 + ] + + self.program = program + self.pc = 0 + + def singleStepRun(self): + self.clock += 1 + for i in range(4): + self.fus[i].run(self.clock) + if self.pc < len(self.program): + instr = self.program[self.pc] + if self.scoreboard.issueControl(instr): + self.fus[instr.fu].issue(self.pc, self.clock) + self.pc += 1 + self.scoreboard.sync() + + def run(self, circles): + for i in range(circles): + self.singleStepRun() + + def dump(self): + print('{:<10}{:<10}{:<10}{:<10}'.format('issue', 'read', 'execute', 'write')) + for item in self.instrStat: + print('{:<10}{:<10}{:<10}{:<10}'.format( + item.issue, + item.read, + item.execute, + item.write + )) + print('') + self.scoreboard.dump() diff --git a/hw5/xzy/scoreboard.py b/hw5/xzy/scoreboard.py new file mode 100644 index 0000000..a47e2f7 --- /dev/null +++ b/hw5/xzy/scoreboard.py @@ -0,0 +1,236 @@ +from util import Register + +#计分板 +class Scoreboard: + #功能部件状态表项 + class FuncUnitItem: + def __init__(self, fuCnt): + self.busy = Register(False) + self.op = Register('') + + self.src1Valid = Register(False) + self.src1 = Register(0) + self.fu1 = Register(fuCnt) + self.ready1 = Register(False) + + self.src2Valid = Register(False) + self.src2 = Register(0) + self.fu2 = Register(fuCnt) + self.ready2 = Register(False) + + self.destValid = Register(False) + self.dest = Register(0) + + #同步 + def sync(self): + self.busy.sync() + self.op.sync() + self.src1Valid.sync() + self.src1.sync() + self.fu1.sync() + self.ready1.sync() + self.src2Valid.sync() + self.src2.sync() + self.fu2.sync() + self.ready2.sync() + self.destValid.sync() + self.dest.sync() + + def __init__(self, regCnt, fuCnt): + self.regCnt = regCnt + self.fuCnt = fuCnt + self.regResStat = [Register(fuCnt) for i in range(regCnt)] #寄存器结果状态表 + self.funcUnitStat = [Scoreboard.FuncUnitItem(fuCnt) for i in range(fuCnt)] #功能部件状态表 + + #同步 + def sync(self): + for item in self.regResStat: + item.sync() + for item in self.funcUnitStat: + item.sync() + + #检查功能部件号是否有效 + #约定:功能部件号为功能部件总数表示无效 + def fuValid(self, fu): + return fu < self.fuCnt + + def issueControl(self, instr): + fuItem = self.funcUnitStat[instr.fu] + + #检查功能部件忙碌 + busy = fuItem.busy.read() + + #检查写后写 + waw = False + if instr.destValid: + waw |= self.fuValid(self.regResStat[instr.dest].read()) + + if busy or waw: #阻塞 + return False + + fuItem.busy.write(True) #占用功能部件 + fuItem.op.write(instr.op) #记录操作 + + #记录操作数信息 + fuItem.src1Valid.write(instr.src1Valid) + if instr.src1Valid: + fuItem.src1.write(instr.src1) + fu1 = self.regResStat[instr.src1].read() + fuItem.fu1.write(fu1) + fuItem.ready1.write(not self.fuValid(fu1)) + fuItem.src2Valid.write(instr.src2Valid) + if instr.src2Valid: + fuItem.src2.write(instr.src2) + fu2 = self.regResStat[instr.src2].read() + fuItem.fu2.write(fu2) + fuItem.ready2.write(not self.fuValid(fu2)) + + #记录结果信息 + fuItem.destValid.write(instr.destValid) + if instr.destValid: + fuItem.dest.write(instr.dest) + self.regResStat[instr.dest].write(instr.fu) + + return True + + def readControl(self, fu): + fuItem = self.funcUnitStat[fu] + src1Valid = fuItem.src1Valid.read() + src2Valid = fuItem.src2Valid.read() + + #检查指令未发出 + unissued = not fuItem.busy.read() + + #检查写后读 + raw = False + if src1Valid: + raw |= not fuItem.ready1.read() + if src2Valid: + raw |= not fuItem.ready2.read() + + if unissued or raw: #阻塞 + return False + + #操作数已读取 + if src1Valid: + fuItem.fu1.write(self.fuCnt) + fuItem.ready1.write(False) + if src2Valid: + fuItem.fu2.write(self.fuCnt) + fuItem.ready2.write(False) + + return True + + def executeControl(self, fu): + fuItem = self.funcUnitStat[fu] + + #检查指令未发出 + unissued = not fuItem.busy.read() + + if unissued: #阻塞 + return False + return True + + def writeControl(self, fu): + fuItem = self.funcUnitStat[fu] + destValid = fuItem.destValid.read() + + #检查指令未发出 + unissued = not fuItem.busy.read() + + #检查读后写 + war = False + if destValid: + dest = fuItem.dest.read() + for f in self.funcUnitStat: + if f.src1Valid.read(): + war |= (f.src1.read() == dest) and f.ready1.read() + if f.src2Valid.read(): + war |= (f.src2.read() == dest) and f.ready2.read() + + if unissued or war: #阻塞 + return False + + if destValid: + #所有依赖该结果的指令可以读操作数 + for f in self.funcUnitStat: + if f.src1Valid.read() and f.fu1.read() == fu: + f.ready1.write(True) + if f.src2Valid.read() and f.fu2.read() == fu: + f.ready2.write(True) + + #结果已写回 + self.regResStat[fuItem.dest.read()].write(self.fuCnt) + + #功能部件不再被占用 + fuItem.busy.write(False) + fuItem.src1Valid.write(False) + fuItem.src2Valid.write(False) + fuItem.destValid.write(False) + + return True + + #打印 + def dump(self): + #打印功能部件状态表 + print('{:<10}{:<10}{:<10}{:<10}{:<10}{:<10}{:<10}{:<10}'.format( + 'busy', + 'dest', + 'src1', + 'src2', + 'fu1', + 'fu2', + 'ready1', + 'ready2' + )) + for item in self.funcUnitStat: + busy = item.busy.read() + if item.destValid.read(): + dest = item.dest.read() + else: + dest = '' + + src1 = item.src1.read() + fu1 = item.fu1.read() + if not self.fuValid(fu1): + fu1 = '' + ready1 = item.ready1.read() + if not item.src1Valid.read(): + src1 = '' + fu1 = '' + ready1 = '' + + src2 = item.src2.read() + fu2 = item.fu2.read() + if not self.fuValid(fu2): + fu2 = '' + ready2 = item.ready2.read() + if not item.src2Valid.read(): + src2 = '' + fu2 = '' + ready2 = '' + + print('{:<10}{:<10}{:<10}{:<10}{:<10}{:<10}{:<10}{:<10}'.format( + busy, + dest, + src1, + src2, + fu1, + fu2, + ready1, + ready2 + )) + print('') + + #打印寄存器结果状态表 + for i in range(self.regCnt): + if i % 2 == 0: + print('F{:<3}'.format(i), end = ' ') + print('') + for i in range(self.regCnt): + if i % 2 == 0: + fu = self.regResStat[i].read() + if not self.fuValid(fu): + fu = '' + print('{:<4}'.format(fu), end = ' ') + print('') diff --git a/hw5/xzy/test.py b/hw5/xzy/test.py new file mode 100644 index 0000000..fd9eccd --- /dev/null +++ b/hw5/xzy/test.py @@ -0,0 +1,16 @@ +from run import Runner +from util import Instruction + +program = [] +program.append(Instruction('load', 0, True, 6, False, 0, True, 2)) +program.append(Instruction('load', 0, True, 2, False, 0, True, 3)) +program.append(Instruction('mult', 1, True, 0, True, 2, True, 4)) +program.append(Instruction('sub', 2, True, 8, True, 6, True, 2)) +program.append(Instruction('div', 3, True, 10, True, 0, True, 6)) +program.append(Instruction('add', 2, True, 6, True, 8, True, 2)) + +runner = Runner(program) +runner.run(70) +runner.dump() +print('') +print('clk: {}'.format(runner.clock)) diff --git a/hw5/xzy/util.py b/hw5/xzy/util.py new file mode 100644 index 0000000..11271d7 --- /dev/null +++ b/hw5/xzy/util.py @@ -0,0 +1,39 @@ +#寄存器 +class Register: + def __init__(self, initValue): + self.data = initValue + self.buff = None + + #读数据 + #输出: + # 寄存器中的数据 + def read(self): + return self.data + + #写数据 + #输入: + # data为写入的数据 + #效果: + # 将data写入缓冲区 + def write(self, data): + self.buff = data + + #同步 + #效果: + # 将缓冲区中的数据写入寄存器 + def sync(self): + if self.buff is not None: + self.data = self.buff + self.buff = None + +#指令 +class Instruction: + def __init__(self, op, fu, destValid, dest, src1Valid, src1, src2Valid, src2): + self.op = op #操作 + self.fu = fu #所需的功能部件 + self.destValid = destValid #目的寄存器是否有效 + self.dest = dest #目的寄存器号 + self.src1Valid = src1Valid #源寄存器1是否有效 + self.src1 = src1 #源寄存器号1 + self.src2Valid = src2Valid #源寄存器2是否有效 + self.src2 = src2 #源寄存器号2 diff --git a/hw5/yjy/ds.py b/hw5/yjy/ds.py new file mode 100644 index 0000000..76dfede --- /dev/null +++ b/hw5/yjy/ds.py @@ -0,0 +1,53 @@ + +# IS表中的元素 +class Ins_Status: + def __init__(self): + self.issue = 'None' + self.oper = 'None' + self.comp = 'None' + self.result = 'None' + + def __str__(self): + print_str = 'issue=' + str(self.issue) + ' ' + print_str += 'oper=' + str(self.oper) + ' ' + print_str += 'comp=' + str(self.comp) + ' ' + print_str += 'result=' + str(self.result) + return print_str + + +# FUS表的元素 +class FU_Status: + + def __init__(self): + self.busy = 'No' + self.op = 'None' + self.fi = 'None' + self.fj = 'None' + self.fk = 'None' + self.qj = 'None' + self.qk = 'None' + self.rj = 'None' + self.rk = 'None' + + def __str__(self): + print_str = 'busy=' + self.busy + ' ' + print_str += 'op=' + str(self.op) + ' ' + print_str += 'fi=' + self.fi + ' ' + print_str += 'fj=' + self.fj + ' ' + print_str += 'fk=' + self.fk + ' ' + print_str += 'qj=' + str(self.qj) + ' ' + print_str += 'qk=' + str(self.qk) + ' ' + print_str += 'rj=' + self.rj + ' ' + print_str += 'rk=' + self.rk + return print_str + + def clear(self): + self.busy = 'No' + self.op = 'None' + self.fi = 'None' + self.fj = 'None' + self.fk = 'None' + self.qj = 'None' + self.qk = 'None' + self.rj = 'None' + self.rk = 'None' diff --git a/hw5/yjy/hw5.py b/hw5/yjy/hw5.py new file mode 100644 index 0000000..4ea94ef --- /dev/null +++ b/hw5/yjy/hw5.py @@ -0,0 +1,245 @@ +from utils import * +from ir import * +from ds import Ins_Status, FU_Status + +INS_NUM = 6 + +# IS表 长度为指令条数 +IS = [Ins_Status() for _ in range(INS_NUM)] +# FUS表 +FUS = {'Integer': FU_Status(), + 'Mul1': FU_Status(), + 'Mul2': FU_Status(), + 'Add': FU_Status(), + 'Divide': FU_Status() + } +# RSS表 +RSS = {'F%d' % (2 * i): 'None' for i in range(16)} + +# 指令列表 +ins_list = [Load(reg1='F6', offset=34, reg2='R2'), + Load(reg1='F2', offset=45, reg2='R3'), + Mul(reg1='F0', reg2='F2', reg3='F4'), + Sub(reg1='F8', reg2='F6', reg3='F2'), + Div(reg1='F10', reg2='F0', reg3='F6'), + Add(reg1='F6', reg2='F8', reg3='F2')] + + +# 指令流出阶段 避免结构冲突和WAR冲突 +def Issue(ins_num): + fu = FU_allocate(ins_list[ins_num].fu, FUS) + if (fu is not None) and Result_write(ins_list[ins_num].rt, RSS): # 如果当前指令所需的部件空闲 and 记分牌中已经存在的指令不对当前指令的目的寄存器进行写操作 + FUS_item = FUS[fu] + # 改写FUS表该部件行 + FUS_item.busy = 'Yes' + FUS_item.op = type(ins_list[ins_num]) + FUS_item.fi = ins_list[ins_num].rt + FUS_item.fj = ins_list[ins_num].rs[0] + FUS_item.fk = ins_list[ins_num].rs[1] + + try: # 如果源操作数不来自任何一个部件则qj为空 + FUS_item.qj = RSS[FUS_item.fj] + except: + FUS_item.qj = 'None' + try: # 如果源操作数不来自任何一个部件则qk为空 + FUS_item.qk = RSS[FUS_item.fk] + except: + FUS_item.qk = 'None' + + # 源操作数寄存器是否就绪 + if FUS_item.fj != 'None': + if RS_ready(FUS_item.fj, RSS): + FUS_item.rj = 'Yes' + else: + FUS_item.rj = 'No' + else: + FUS_item.rj = 'None' + + if RS_ready(FUS_item.fk, RSS): + FUS_item.rk = 'Yes' + else: + FUS_item.rk = 'No' + + RSS[ins_list[ins_num].rt] = fu + + # 发出指令 + IS[ins_num].issue = clock + return fu + # 不满足条件则等待 + else: + return 'Wait' + + +# 读操作数阶段 避免RAW冲突 +def Read_Operands(ins_num, fu): + if (FUS[fu].rj != 'No') and (FUS[fu].rk != 'No'): # rj和rk就绪,读操作数 + # 检查RAW冲突 + if FUS[fu] not in hazards['RAW']: + IS[ins_num].oper = clock + # if FUS[fu].rj != 'None': + # FUS[fu].rj = 'No' + # if FUS[fu].rk != 'None': + # FUS[fu].rk = 'No' + # FUS[fu].qj = 'None' + # FUS[fu].qk = 'None' + return 'Success' + else: + return 'Wait' + + +# 执行阶段 无需对表的任何操作 +def Execution(ins_num, fu): + # 返回需要的时钟周期数 + if FUS[fu].rj != 'None': + FUS[fu].rj = 'No' + if FUS[fu].rk != 'None': + FUS[fu].rk = 'No' + FUS[fu].qj = 'None' + FUS[fu].qk = 'None' + if isinstance(ins_list[ins_num], Mul): + return 10 + elif isinstance(ins_list[ins_num], Div): + return 40 + elif isinstance(ins_list[ins_num], Add) or isinstance(ins_list[ins_num], Sub): + return 2 + else: + return 1 + + +# 写结果阶段 避免WAR冲突 +def Write_Resut(ins_num, fu): + # 在FUS表中的每一条指令进行逐一查看,如果不存在任意一条指令的源操作数寄存器与当前指令的目的操作数寄存器相同 且对应的寄存器处于读就绪状态 + for _, item in FUS.items(): + if (item.fj == ins_list[ins_num].rt) and item.rj == 'Yes': + return 'Wait' + try: + if (item.fk == ins_list[ins_num].rt) and item.rk == 'Yes': + return 'Wait' + finally: + pass + # 则修改记分牌内容 + # 检查FUS中每条指令的qj和qk域,如果存在一条指令以当前指令的结果作为源操作数,则将那一条指令对应的rj或rk设为Yes + for _, item in FUS.items(): + if item.qj == fu: + item.rj = 'Yes' + if item.qk == fu: + item.rk = 'Yes' + # 将RSS中当前指令对应的元素设置为空 + RSS[FUS[fu].fi] = 'None' + # 同时级联修改FUS中所有的qj和qk,如果存在当前部件则释放 + for _, value in FUS.items(): + if value.qj == fu: + value.qj = 'None' + if value.qk == fu: + value.qk = 'None' + + # ???? 将FUS中对应的部件的Busy域设置为No ???? + # ???? FUS[fu].busy = 'No' ???? + + # 将FUS中对应的行清空 + FUS[fu].clear() + IS[ins_num].result = clock + return 'Success' + + +def print_tables(): + print('---------------------IS---------------------') + for item in IS: + print(item) + print('---------------------FUS---------------------') + for key, value in FUS.items(): + print('{:7s}'.format(key), value) + print('---------------------RSS---------------------') + for key, _ in RSS.items(): + print('{:7s}'.format(key), end=' ') + print('\n', end='') + for _, value in RSS.items(): + print('{:7s}'.format(value), end=' ') + print('\n') + + +if __name__ == '__main__': + # 时钟 + clock = 1 + Uncomp_list = ins_list.copy() + # 初始阶段所有指令都等待Issue + IF_list = [i for i in range(len(ins_list))] + ID_list = [] # ID EX WB的元素都是元组 (指令,功能部件) + EX_list = [] + WB_list = [] + Comp_list = [] + + hazards = analyze_hazard(Uncomp_list) + ex_clock_list = {} + # 执行直到所有任务完成 + while len(Comp_list) < len(ins_list): + print('################ CLOCK = %d ################ ' % clock) + fu = '' + issued = False + fetched = [] + executed = [] + written = [] + if len(IF_list) != 0: # 发出指令,若成功,在IF中去除该指令,在ID中添加该指令 + fu = Issue(IF_list[0]) + if fu != 'Wait': + issued = True + + if len(ID_list) != 0: + for i in range(len(ID_list)): + if Read_Operands(ID_list[i][0], ID_list[i][1]) == 'Success': # 取操作数,若成功,在ID中去除该指令,在EX中添加该指令 + fetched.append(ID_list[i]) + + if len(EX_list) != 0: + for i in range(len(EX_list)): + # 如果该指令没有在“正在运行的指令”字典中,启动局部计数器 + try: + if ex_clock_list[EX_list[i][0]] is not None: + pass + except: + ex_clock = Execution(EX_list[i][0], EX_list[i][1]) + if ex_clock == 1: # 如果指令只需1个周期完成,则不需要计数器 + IS[EX_list[i][0]].comp = clock + executed.append(EX_list[i]) + else: + ex_clock_list[EX_list[i][0]] = ex_clock - 1 # 该次循环结束后已经过一个周期 + + # 若某条指令的计数器终止,则认为已完成 + for i in range(len(EX_list)): + try: + if ex_clock_list[EX_list[i][0]] == 0: + IS[EX_list[i][0]].comp = clock + executed.append(EX_list[i]) + ex_clock_list.pop(EX_list[i][0]) + except: + pass + + if len(WB_list) != 0: + for i in range(len(WB_list)): + if Write_Resut(WB_list[i][0], WB_list[i][1]) == 'Success': + written.append(WB_list[i]) + + # 统计该周期完成的动作,并且更新下一步动作 + if issued: + ID_list.append((IF_list[0], fu)) + IF_list.remove(IF_list[0]) + if len(fetched): + for item in fetched: + EX_list.append(item) + ID_list.remove(item) + if len(executed): + for item in executed: + WB_list.append(item) + EX_list.remove(item) + if len(written): + for item in written: + Comp_list.append(item) + Uncomp_list.remove(ins_list[item[0]]) # 一条指令结束后更新hazard表 + WB_list.remove(item) + hazards = analyze_hazard(Uncomp_list) + + clock += 1 + for key, value in ex_clock_list.items(): # 局部时钟-1 + print('局部时钟:', end=' ') + print(ins_list[key], value) + ex_clock_list[key] -= 1 + print_tables() diff --git a/hw5/yjy/ir.py b/hw5/yjy/ir.py new file mode 100644 index 0000000..2a2797e --- /dev/null +++ b/hw5/yjy/ir.py @@ -0,0 +1,234 @@ +# 程序类 +class Program: + def __init__(self): + self.instrList = [] # 指令列表,其中的元素或者是Instruction,或者是Loop + + # 将中间表示转化为代码并输出到文件 + def emit(self, stream, cnt): + for instr in self.instrList: + instr.emit(stream, cnt) + + return cnt + + +# 循环类 +class Loop: + def __init__(self, iterator, times): + self.iter = iterator # 循环变量,是一个寄存器 + self.times = times # 循环次数,是一个寄存器 + self.instrList = [] # 指令列表,其中的元素是Instruction或Loop,应该有如下的形式 + ''' + beq i, n, out + loop: + [loop body] + addi i, i, 1 + bne i, n, loop + out: + ''' + + def emit(self, stream, cnt): + cnt = cnt + 1 + for i in range(len(self.instrList)): + if i == 0: + self.instrList[0].emit(stream, cnt) + stream.write('loop' + str(cnt) + ':\n') + else: + self.instrList[i].emit(stream, cnt) + + stream.write('out' + str(cnt) + ':\n') + return cnt + + +# 指令类 +class Instruction: + def __init__(self): + self.rs = [] # 源寄存器,是一个列表,其中的元素是该指令读取的所有寄存器号 + # 注意这个列表里去掉了重复的元素 + self.rt = None # 目的寄存器,是该指令写入的寄存器号 + self.instrStr = None # 指令字符串 + + def emit(self, stream, cnt): + pass + + +# 存储访问指令类 +class MemInstr(Instruction): + def emit(self, stream, cnt): + stream.write(self.instrStr + '\n') + return cnt + + +# Load +class Load(MemInstr): + # load reg1, offset(reg2) + def __init__(self, reg1, offset, reg2): + super().__init__() + self.rt = reg1 + self.rs.append('None') + self.rs.append(reg2) + self.offset = offset + self.instrStr = 'load r' + str(reg1) + ', ' + str(offset) + '(r' + str(reg2) + ')' + self.fu = 'Integer' + + +# Store +class Store(MemInstr): + # store reg1, imm(reg2) + def __init__(self, reg1, offset, reg2): + super().__init__() + + # 去掉重复的元素 + self.rs.append(reg1) + if reg1 != reg2: + self.rs.append(reg2) + + self.offset = offset + self.instrStr = 'store r' + str(reg1) + ', ' + str(offset) + '(r' + str(reg2) + ')' + + +# ALU型指令类 +class AluInstr(Instruction): + def emit(self, stream, cnt): + stream.write(self.instrStr + '\n') + return cnt + + +# Nop +class Nop(AluInstr): + # nop + def __init__(self): + super().__init__() + self.instrStr = 'nop' + + +# Add +class Add(AluInstr): + # add reg1, reg2, reg3 + def __init__(self, reg1, reg2, reg3): + super().__init__() + self.rt = reg1 + self.fu = 'Add' + + # 去掉重复的元素 + self.rs.append(reg2) + if reg2 != reg3: + self.rs.append(reg3) + + self.instrStr = 'add r' + str(reg1) + ', r' + str(reg2) + ', ' + str(reg3) + + +# Sub +class Sub(AluInstr): + # add reg1, reg2, reg3 + def __init__(self, reg1, reg2, reg3): + super().__init__() + self.rt = reg1 + self.fu = 'Add' + + # 去掉重复的元素 + self.rs.append(reg2) + if reg2 != reg3: + self.rs.append(reg3) + + self.instrStr = 'sub r' + str(reg1) + ', r' + str(reg2) + ', ' + str(reg3) + +# Mul +class Mul(AluInstr): + # Mul reg1, reg2, reg3 + def __init__(self, reg1, reg2, reg3): + super().__init__() + self.rt = reg1 + self.fu = 'Mul' + + # 去掉重复的元素 + self.rs.append(reg2) + if reg2 != reg3: + self.rs.append(reg3) + + self.instrStr = 'mul r' + str(reg1) + ', r' + str(reg2) + ', ' + str(reg3) + + +# Div +class Div(AluInstr): + # Div reg1, reg2, reg3 + def __init__(self, reg1, reg2, reg3): + super().__init__() + self.rt = reg1 + self.fu = 'Div' + + # 去掉重复的元素 + self.rs.append(reg2) + if reg2 != reg3: + self.rs.append(reg3) + + self.instrStr = 'div r' + str(reg1) + ', r' + str(reg2) + ', ' + str(reg3) + + +# Move +class Move(AluInstr): + # move reg1, reg2 + def __init__(self, reg1, reg2): + super().__init__() + self.rt = reg1 + self.rs.append(reg2) + self.fu = 'Integer' + self.instrStr = 'move r' + str(reg1) + ', r' + str(reg2) + + +# Addi +class Addi(AluInstr): + # addi reg1, reg2, imm + def __init__(self, reg1, reg2, imm): + super().__init__() + self.rt = reg1 + self.rs.append(reg2) + self.imm = imm + self.fu = 'Add' + self.instrStr = 'addi r' + str(reg1) + ', r' + str(reg2) + ', ' + str(imm) + + +# 条件跳转指令类 +class Condition(Instruction): + pass + + +# Bne +class Bne(Condition): + # bne reg1, reg2, label + def __init__(self, reg1, reg2): + # Bne对象的属性中不需要包含label,它应该在将中间表示转化为代码时被加上 + super().__init__() + + # 去掉重复的元素 + self.rs.append(reg1) + if reg1 != reg2: + self.rs.append(reg2) + + self.instrStr = 'bne r' + str(reg1) + ', r' + str(reg2) + + def emit(self, stream, cnt): + instrStr = self.instrStr + ', out' + str(cnt) + stream.write(instrStr + '\n') + + return cnt + + +# Beq +class Beq(Condition): + # beq reg1, reg2, label + def __init__(self, reg1, reg2): + super().__init__() + + # 去掉重复的元素 + self.rs.append(reg1) + if reg1 != reg2: + self.rs.append(reg2) + + self.instrStr = 'beq r' + str(reg1) + ', r' + str(reg2) + + def emit(self, stream, cnt): + instrStr = self.instrStr + ', loop' + str(cnt) + stream.write(instrStr + '\n') + + return cnt + diff --git a/hw5/yjy/utils.py b/hw5/yjy/utils.py new file mode 100644 index 0000000..4a686bd --- /dev/null +++ b/hw5/yjy/utils.py @@ -0,0 +1,65 @@ +# 数据相关性分析 +def analyze_hazard(ins_list): + hazard = {'RAW': [], + 'WAR': [], + 'WAW': []} + write = [] # 记录所有的写操作 + read = [] # 记录所有的读操作 + # 分析数据相关性 + for instr in ins_list: # 标记所有读取和写入的寄存器 + if instr.rt is not None: + write.append(instr.rt) + if instr.rs is not None: + read.append(instr.rs) + # 检测写后读(RAW) + for i in range(len(write)): + for j in range(i + 1, len(read)): + if write[i] in read[j]: + hazard['RAW'].append((i, j)) + # 检测读后写(WAR) + for i in range(len(read)): + for j in range(i + 1, len(write)): + if write[j] in read[i]: + hazard['WAR'].append((i, j)) + # 检测读后读(WAW) + for i in range(len(write)): + for j in range(i + 1, len(write)): + if write[i] == write[j]: + hazard['WAW'].append((i, j)) + return hazard + + +# 为指令分配功能部件,如果没有空余返回None +def FU_allocate(fu, FUS): + if fu == 'Mul': + if not (FUS['Mul1'].busy == 'Yes' and FUS['Mul2'].busy == 'Yes'): + if FUS['Mul1'].busy == 'No': + return 'Mul1' + else: + return 'Mul2' + elif fu == 'Add': + if FUS['Add'].busy == 'No': + return 'Add' + elif fu == 'Div': + if FUS['Divide'].busy == 'No': + return 'Divide' + else: + if FUS['Integer'].busy == 'No': + return 'Integer' + return None + + +def Result_write(rs, RSS): + if RSS[rs] == 'None': + return True + return False + + +def RS_ready(rs, RSS): + try: + if RSS[rs] == 'None': + return True + else: + return False + except: + return True diff --git a/hw6/architecture.py b/hw6/architecture.py new file mode 100644 index 0000000..69d5fc8 --- /dev/null +++ b/hw6/architecture.py @@ -0,0 +1,130 @@ +INT_REG_SIZE = 32 #整数寄存器数 +FP_REG_SIZE = 32 #浮点寄存器数 +PC_REG_SIZE = 1 +BUF_REG_SIZE = 6 +REG_SIZE = INT_REG_SIZE + FP_REG_SIZE + PC_REG_SIZE + BUF_REG_SIZE +REG_OFF = 0 +INT_REG_OFF = REG_OFF +FP_REG_OFF = INT_REG_OFF + INT_REG_SIZE +PC_REG_OFF = FP_REG_OFF + FP_REG_SIZE +BUF_REG_OFF = PC_REG_OFF + PC_REG_SIZE + +INSTR_MEM_SIZE = 32 +DATA_MEM_SIZE = 32 +MEM_SIZE = INSTR_MEM_SIZE + DATA_MEM_SIZE +MEM_OFF = 0 +INSTR_MEM_OFF = MEM_OFF +DATA_MEM_OFF = INSTR_MEM_OFF + INSTR_MEM_SIZE + +FU_SIZE = 4 #功能部件数 +FU_OFF = 0 +INT_FU_OFF = FU_OFF +ADD_FU_OFF = INT_FU_OFF + 1 +MUL_FU_OFF = ADD_FU_OFF + 1 +MEM_FU_OFF = MUL_FU_OFF + 1 + +INT_RS_SIZE = 1 +ADD_RS_SIZE = 3 #浮点加法部件保留站数量 +MUL_RS_SIZE = 2 #浮点乘法部件保留站数量 +MEM_RS_SIZE = BUF_REG_SIZE +RS_SIZE = INT_RS_SIZE + ADD_RS_SIZE + MUL_RS_SIZE + MEM_RS_SIZE +RS_OFF = 1 +INT_RS_OFF = RS_OFF +ADD_RS_OFF = INT_RS_OFF + INT_RS_SIZE +MUL_RS_OFF = ADD_RS_OFF + ADD_RS_SIZE +MEM_RS_OFF = MUL_RS_OFF + MUL_RS_SIZE + +#寄存器 +class Register: + def __init__(self): + self.val = 0 + self.src = 0 + return + + def copy(self): + reg = Register() + reg.val = self.val + reg.src = self.src + return reg + +#功能部件 +class FuncUnit: + def __init__(self): + self.clk = 0 + self.op = '' + self.res = 0 + return + + def copy(self): + fu = FuncUnit() + fu.clk = self.clk + fu.op = self.op + fu.res = self.res + return fu + +#保留站 +class ReservStation: + def __init__(self): + self.busy = False + self.op = '' + self.val1 = 0 + self.src1 = 0 + self.val2 = 0 + self.src2 = 0 + self.addr = 0 + return + + def copy(self): + rs = ReservStation() + rs.busy = self.busy + rs.op = self.op + rs.val1 = self.val1 + rs.src1 = self.src1 + rs.val2 = self.val2 + rs.src2 = self.src2 + rs.addr = self.addr + return rs + +#指令 +class Instruction: + def __init__(self): + self.op = '' + self.dest = 0 + self.op1 = 0 + self.op2 = 0 + self.imm = 0 + return + + def copy(self): + instr = Instruction() + instr.op = self.op + instr.dest = self.dest + instr.op1 = self.op1 + instr.op2 = self.op2 + instr.imm = self.imm + return instr + +#架构 +class Architecture: + def __init__(self): + self.reg = [Register() for i in range(REG_OFF + REG_SIZE)] + self.mem = [0 for i in range(MEM_OFF + MEM_SIZE)] + self.fu = [FuncUnit() for i in range(FU_OFF + FU_SIZE)] + self.rs = [ReservStation() for i in range(RS_OFF + RS_SIZE)] + self.clk = 0 #时钟 + self.bus = 0 #总线 + return + + def copy(self): + arch = Architecture() + for i in range(REG_SIZE): + arch.reg[i] = self.reg[i].copy() + for i in range(MEM_SIZE): + arch.mem[i] = self.mem[i] + for i in range(FU_SIZE): + arch.fu[i] = self.fu[i].copy() + for i in range(RS_SIZE): + arch.rs[i] = self.rs[i].copy() + arch.clk = self.clk + arch.bus = self.bus + return arch diff --git a/hw6/debug.py b/hw6/debug.py new file mode 100644 index 0000000..30e516f --- /dev/null +++ b/hw6/debug.py @@ -0,0 +1,176 @@ +from architecture import * + +def dump(arch): + dumpClk(arch) + print('') + dumpPC(arch) + print('') + dumpIntReg(arch) + print('') + dumpFpReg(arch) + print('') + dumpIntUnit(arch) + print('') + dumpAddUnit(arch) + print('') + dumpMulUnit(arch) + print('') + dumpMemUnit(arch) + print('') + dumpDataMem(arch) + return + +def getInstr(op, dest, op1, op2, imm): + instr = Instruction() + instr.op = op + instr.dest = dest + instr.op1 = op1 + instr.op2 = op2 + instr.imm = imm + return instr + +def program(arch, program): + arch1 = arch.copy() + print('{:<6}{:<6}{:<6}{:<6}{:<6}'.format( + 'op', + 'dest', + 'op1', + 'op2', + 'imm' + )) + for i in range(len(program)): + instr = program[i] + print('{:<6}{:<6}{:<6}{:<6}{:<6}'.format( + instr.op, + instr.dest, + instr.op1, + instr.op2, + instr.imm + )) + arch1.mem[INSTR_MEM_OFF + i] = instr + return arch1 + +def valid(check, data): + if check: + return data + else: + return '' + +def dumpClk(arch): + print('{:<6}{:<6}'.format('clk', 'bus')) + print('{:<6}{:<6}'.format(arch.clk, arch.bus)) + return + +def dumpPC(arch): + print('pc:\n{:<6}{:<6}'.format('value', arch.reg[PC_REG_OFF].val), end = '') + src = arch.reg[PC_REG_OFF].src + src = valid(src, src) + print('\n{:<6}{:<6}'.format('Qi', src), end = '') + print('') + return + +def dumpReg(arch, offset, size): + print('{:<6}'.format(''), end = '') + for i in range(size): + print('{:<4}'.format(i), end = '') + print('\n{:<6}'.format('value'), end = '') + for i in range(size): + print('{:<4}'.format(arch.reg[offset + i].val), end = '') + print('\n{:<6}'.format('Qi'), end = '') + for i in range(size): + src = arch.reg[offset + i].src + src = valid(src, src) + print('{:<4}'.format(src), end = '') + print('') + return + +def dumpIntReg(arch): + print('integer registers:') + dumpReg(arch, INT_REG_OFF, INT_REG_SIZE) + return + +def dumpFpReg(arch): + print('floating point registers:') + dumpReg(arch, FP_REG_OFF, FP_REG_SIZE) + return + +def dumpRS(arch, offset): + busy = arch.rs[offset].busy + op = valid(busy, arch.rs[offset].op) + val1 = valid(busy, arch.rs[offset].val1) + val2 = valid(busy, arch.rs[offset].val2) + src1 = valid(busy, arch.rs[offset].src1) + src2 = valid(busy, arch.rs[offset].src2) + addr = valid(busy, arch.rs[offset].addr) + src1 = valid(src1, src1) + src2 = valid(src2, src2) + addr = valid(addr, addr) + print('{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}'.format( + busy, + op, + val1, + val2, + src1, + src2, + addr)) + return + +def dumpFU(arch, fuOff, rsOff, rsSize): + print('{:<6}{:<6}{:<6}'.format('clk', 'op', 'res')) + print('{:<6}{:<6}{:<6}'.format( + arch.fu[fuOff].clk, + arch.fu[fuOff].op, + arch.fu[fuOff].res)) + print('{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}'.format( + 'busy', + 'op', + 'Vj', + 'Vk', + 'Qj', + 'Qk', + 'A')) + for i in range(rsSize): + dumpRS(arch, rsOff + i) + return + +def dumpIntUnit(arch): + print('integer unit:') + dumpFU(arch, INT_FU_OFF, INT_RS_OFF, INT_RS_SIZE) + return + +def dumpAddUnit(arch): + print('add unit:') + dumpFU(arch, ADD_FU_OFF, ADD_RS_OFF, ADD_RS_SIZE) + return + +def dumpMulUnit(arch): + print('multiply unit:') + dumpFU(arch, MUL_FU_OFF, MUL_RS_OFF, MUL_RS_SIZE) + return + +def dumpMemUnit(arch): + print('memory access unit:') + dumpFU(arch, MEM_FU_OFF, MEM_RS_OFF, MEM_RS_SIZE) + print('memory access buffer:') + print('{:<6}'.format('A'), end = '') + for i in range(BUF_REG_SIZE): + src = arch.reg[BUF_REG_OFF + i].src + addr = valid(src, arch.reg[BUF_REG_OFF + i].val) + print('{:<6}'.format(addr), end = '') + print('\n{:<6}'.format('Qi'), end = '') + for i in range(BUF_REG_SIZE): + src = arch.reg[BUF_REG_OFF + i].src + src = valid(src, src) + print('{:<6}'.format(src), end = '') + print('') + return + +def dumpDataMem(arch): + print('data memory:') + for i in range(DATA_MEM_SIZE): + print('{:<4}'.format(i), end = '') + print('') + for i in range(DATA_MEM_SIZE): + print('{:<4}'.format(arch.mem[DATA_MEM_OFF + i]), end = '') + print('') + return diff --git a/hw6/run.py b/hw6/run.py new file mode 100644 index 0000000..ee80b6e --- /dev/null +++ b/hw6/run.py @@ -0,0 +1,149 @@ +from architecture import * + +#执行一个周期 +def run(arch): + arch1 = Architecture() + + for i in range(INSTR_MEM_SIZE): + arch1.mem[INSTR_MEM_OFF + i] = arch.mem[INSTR_MEM_OFF + i] + + arch1.clk = arch.clk + 1 + + arch1.reg[PC_REG_OFF] = runPC(arch) + ''' + for i in range(INT_REG_SIZE): + arch1.reg[INT_REG_OFF + i] = runIntReg(arch, i) + for i in range(FP_REG_SIZE): + arch1.reg[FP_REG_OFF + i] = runFpReg(arch, i) + + for i in range(DATA_MEM_SIZE): + arch1.mem[DATA_MEM_OFF + i] = runMem(arch, i) + arch1.fu[INT_FU_OFF] = runIntFU(arch) + arch1.fu[ADD_FU_OFF] = runAddFU(arch) + arch1.fu[MUL_FU_OFF] = runMulFU(arch) + arch1.fu[MEM_FU_OFF] = runMemFU(arch) + + arch1.rs[INT_RS_OFF] = runIntRS(arch) + for i in range(ADD_RS_SIZE): + arch1.rs[ADD_RS_OFF + i] = runAddRS(arch, i) + for i in range(MUL_RS_SIZE): + arch1.rs[MUL_RS_OFF + i] = runMulRS(arch, i) + for i in range(MEM_RS_SIZE): + arch1.rs[MEM_RS_OFF + i] = runMemRS(arch, i) + for i in range(BUF_REG_SIZE): + arch1.reg[BUF_REG_OFF + i] = runBufReg(arch, i) + + arch1.bus = runBus(arch) + ''' + + return arch1 + +def runPC(arch): + pc = Register() + + if issue(arch): + pc.val = arch.reg[PC_REG_OFF].val + 1 + + instr = fetch(arch) + if instr.op == 'jump': + pc.src = INT_RS_OFF + else: + pc.src = arch.reg[PC_REG_OFF].src + elif arch.reg[PC_REG_OFF].src and not arch.fu[INT_FU_OFF].clk: + pc.val = arch.fu[INT_FU_OFF].res + pc.src = 0 + else: + pc.val = arch.reg[PC_REG_OFF].val + pc.src = arch.reg[PC_REG_OFF].src + + return pc + +def runIntReg(arch, i): + reg = Register() + + fuOff = writeReg(arch, INT_REG_OFF + i) + if fuOff: + reg.val = arch.fu[fuOff].res + else: + reg.val = arch.reg[INT_REG_OFF + i].val + + rsOff = issue(arch) + if rsOff: + instr = fetch(arch) + + if instr.op == 'addi': + #TODO + +def runFpReg(arch, i): + pass + +def runMem(arch, i): + pass + +def runIntFU(arch): + pass + +def runAddFU(arch): + pass + +def runMulFU(arch): + pass + +def runMemFU(arch): + pass + +def runIntRS(arch): + pass + +def runAddRS(arch, i): + pass + +def runMulRS(arch, i): + pass + +def runMemRS(arch, i): + pass + +def runBufReg(arch, i): + pass + +def runBus(arch, i): + pass + +def issue(arch): + if not arch.reg[PC_REG_OFF].src: + instr = fetch(arch) + if instr: + rsMap = { + 'addi': (INT_RS_OFF, INT_RS_SIZE), + 'jump': (INT_RS_OFF, INT_RS_SIZE), + 'fadd': (ADD_RS_OFF, ADD_RS_SIZE), + 'fmul': (MUL_RS_OFF, MUL_RS_SIZE), + 'load': (MEM_RS_OFF, MEM_RS_SIZE), + 'store': (MEM_RS_OFF, MEM_RS_SIZE) + } + offset, size = rsMap[instr.op] + return first(arch, offset, size): + return 0 + +def fetch(arch): + return arch.mem[INSTR_MEM_OFF + arch.reg[PC_REG_OFF].val] + +def first(arch, offset, size): + for i in range(size): + if not arch.rs[offset + i].busy: + return offset + i + return 0 + +def writeReg(arch, i): + src = arch.reg[i].src + if src == INT_RS_OFF: + return INT_FU_OFF + elif src >= ADD_RS_OFF and src < ADD_RS_OFF + ADD_RS_SIZE: + return ADD_FU_OFF + elif src >= MUL_RS_OFF and src < MUL_RS_OFF + MUL_RS_SIZE: + return MUL_FU_OFF + elif src >= MEM_RS_OFF and src < MEM_RS_OFF + MEM_RS_SIZE: + return MEM_FU_OFF + else: + return 0 diff --git a/hw6/test.py b/hw6/test.py new file mode 100644 index 0000000..29a8640 --- /dev/null +++ b/hw6/test.py @@ -0,0 +1,19 @@ +from architecture import * +from debug import * +from run import run + +arch = Architecture() +prog = [ + getInstr('load', 0, 1, 0, 0), + getInstr('fmul', 4, 0, 2, 0), + getInstr('store', 0, 4, 1, 0), + getInstr('addi', 1, 1, 0, -8), + getInstr('jump', 0, 0, 0, -4) + ] +arch = program(arch, prog) +print('') +for i in range(6): + arch = run(arch) +dumpClk(arch) +print('') +dumpPC(arch)