func (p *Pipeline) Dispatch() { /* if p.ins_reg != nil { debug.Debug("Not dispatching when IFETCH is in progress\n"); return; } */ if !p.ready { debug.Debug("Dispatching new instruction\n"); p.ready = true; } //debug.Debug("Dispatch: from pc = %d, next inst = %s\n", p.cpu.pc, p.ins_reg.String()); }
func (p *parser) Parse() { for p.tok != t.EOF { switch p.tok { case t.D_DATA: p.section = 1 p.next() case t.D_TEXT: p.section = 0 p.next() case t.LABEL: fmt.Printf("label is %s %s\n", p.str, string(p.str[0:len(p.str)-1])) var lab *inst.LabelT if p.section == 0 { lab = &inst.LabelT{0, uint16(p.Instlist.Len())} } else { lab = &inst.LabelT{1, p.CurMemPos} } p.Labels[string(p.str[0:len(p.str)-1])] = lab p.next() case t.D_WORD: first_time := true reading := true for reading == true { p.next() if !first_time { if p.tok != t.COMMA { reading = false break } p.next() } if p.tok == t.INT { i, _ := strconv.Atoi(string(p.str)) p.Memory[p.CurMemPos] = uint32(i) p.CurMemPos += 4 } else { p.Error(p.pos, "Nonint in .word") } first_time = false } case t.D_ASCIIZ: p.expect(t.STRING) fmt.Printf("%d %s\n", len(p.str), p.str) for i := 1; i < len(p.str)-1; i++ { p.Memory[p.CurMemPos] = uint32(p.str[i]) p.CurMemPos += 1 } p.next() case t.D_SPACE: p.next() continue default: var pushInst bool = true newInst := &inst.Inst{p.tok, 0, 0, 0, 0, 0, &inst.LabelT{}} debug.Debug("Trying to parse a %s: ", p.str) switch ty, _ := inst.AType[p.tok]; ty { case inst.RRR: p.expect(t.REG) newInst.RD = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.REG) newInst.RS = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.REG) newInst.RT = inst.Regnum(p.str) case inst.RR: p.expect(t.REG) newInst.RS = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.REG) newInst.RT = inst.Regnum(p.str) case inst.R: tok := p.tok p.expect(t.REG) switch tok { case t.MFHI, t.MFLO: newInst.RD = inst.Regnum(p.str) case t.MTHI, t.MTLO, t.JR: newInst.RS = inst.Regnum(p.str) } case inst.RRI: p.expect(t.REG) newInst.RT = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.REG) newInst.RS = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.INT) newInst.IMM, _ = strconv.Atoi(string(p.str)) case inst.RRL: p.expect(t.REG) newInst.RS = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.REG) newInst.RT = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.IDENT) newInst.TGT = p.Labels[string(p.str)] case inst.RL: p.expect(t.REG) newInst.RS = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.IDENT) newInst.TGT = p.Labels[string(p.str)] case inst.RIR: p.expect(t.REG) newInst.RT = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.INT) newInst.IMM, _ = strconv.Atoi(string(p.str)) p.expect(t.LPAREN) p.expect(t.REG) newInst.RS = inst.Regnum(p.str) p.expect(t.RPAREN) case inst.RI: p.expect(t.REG) newInst.RT = inst.Regnum(p.str) p.expect(t.COMMA) p.expect(t.INT) newInst.IMM, _ = strconv.Atoi(string(p.str)) case inst.L: p.expect(t.IDENT) newInst.TGT = p.Labels[string(p.str)] default: pushInst = false fmt.Printf("Ignoring token %s\n", p.str) p.next() } if pushInst { p.Instlist.Push(newInst) } p.next() } } }
func (p *Pipeline) Step() { /* ifetch already happened due to dispatch. we start at the end of the pipeline and work our way backwards, to avoid the usage of temporary pipeline latches. */ /* writeback: */ var hazard bool = false; if p.memwb.full { p.memwb.was_full = true; debug.Debug("WRITE: "); switch inst.IType[p.memwb.inst.Opname] { case inst.ARITH: switch p.memwb.inst.Opname { case t.ADD, t.ADDU, t.AND, t.NOR, t.OR, t.SUB, t.SUBU, t.XOR, t.MFLO, t.MFHI: p.cpu.Regs[p.memwb.inst.RD] = p.memwb.alu_out; debug.Debug("Reg[%d] <- ALU_OUT (%d): ", p.memwb.inst.RD,p.memwb.alu_out) case t.ADDI, t.ANDI, t.ORI, t.XORI: p.cpu.Regs[p.memwb.inst.RT] = p.memwb.alu_out; debug.Debug("Reg[%d] <- ALU_OUT (%d): ", p.memwb.inst.RT,p.memwb.alu_out) } case inst.LOSTO: switch p.memwb.inst.Opname { case t.LB, t.LH, t.LW: p.cpu.Regs[p.memwb.inst.RT] = p.memwb.lmd; debug.Debug("Reg[%d] <- LMD (%d): ",p.memwb.inst.RT,p.memwb.lmd) case t.SB, t.SH, t.SW: debug.Debug("got a store, doing nothing: "); case t.LA: p.cpu.Regs[p.memwb.inst.RS] = p.memwb.lmd; debug.Debug("Reg[%d] <- LMD (%d): ",p.memwb.inst.RS,p.memwb.lmd) } case inst.BRANCH: debug.Debug("got a branch, doing nothing: "); } debug.Debug("%s\n", p.memwb.String()); p.memwb.full = false; } /* memory access */ if p.exmem.full { debug.Debug("MEM: "); switch inst.IType[p.exmem.inst.Opname] { case inst.ARITH: p.memwb.inst = p.exmem.inst; p.memwb.alu_out = p.exmem.alu_out; debug.Debug("ARITH inst: forwarding inst, alu out: "); p.memwb.full = true; case inst.LOSTO: p.memwb.inst = p.exmem.inst; switch p.exmem.inst.Opname { case t.LB, t.LH, t.LW: p.memwb.lmd = p.cpu.Mem[p.exmem.alu_out]; debug.Debug("LOAD inst: LMD <- mem[alu_out]: "); case t.SB, t.SH, t.SW: p.cpu.Mem[p.exmem.alu_out] = p.exmem.reg_b; debug.Debug("STOR inst: mem[alu_out] <- reg_b: "); case t.LA: if p.exmem.inst.TGT.Section == 0 { fmt.Printf("Loading from text section? Sorry dave...\n"); os.Exit(-1); } p.memwb.lmd=uint32(p.ifid.inst.TGT.Offset); } p.memwb.full = true; case inst.BRANCH: debug.Debug("BRANCH inst: ending instruction: "); } debug.Debug("%s\n", p.memwb.String()); p.exmem.full = false; } /* exec */ if p.idex.full { debug.Debug("EXEC: "); hazard = false; /* Check for RAW data hazards */ if p.ifid.full { switch p.idex.inst.Opname { case t.LA, t.LB, t.LW, t.LH: if inst.AType[p.ifid.inst.Opname] == inst.RRR && (p.idex.inst.RT == p.ifid.inst.RS || p.idex.inst.RT == p.ifid.inst.RT) { hazard = true; } switch p.ifid.inst.Opname { case t.LA, t.LB, t.LW, t.LH, t.SB, t.SW, t.SH, t.ADDI, t.ADDIU, t.LUI, t.ANDI, t.ORI, t.XORI: if p.idex.inst.RT == p.ifid.inst.RS { hazard = true; } } } } switch inst.IType[p.idex.inst.Opname] { case inst.ARITH: p.exmem.inst = p.idex.inst; p.exmem.alu_out = do_arith(p.cpu, &p.idex); case inst.LOSTO: p.exmem.inst = p.idex.inst; p.exmem.alu_out = p.idex.reg_a + p.idex.imm; p.exmem.reg_b = p.idex.reg_b; case inst.BRANCH: p.exmem.alu_out = p.idex.npc + p.idex.imm; /* <<2? */ p.exmem.cond = p.idex.reg_a == 0; } debug.Debug("%s\n", p.exmem.String()); p.exmem.full = true; p.idex.full = false; } /* decode */ if p.ifid.full { debug.Debug("DECODE: "); if !hazard { p.idex.reg_a = p.cpu.Regs[p.ifid.inst.RS]; p.idex.reg_b = p.cpu.Regs[p.ifid.inst.RT]; p.idex.npc = p.ifid.npc; p.idex.inst = p.ifid.inst; p.idex.imm = uint32(p.ifid.inst.IMM); /* Sign extend? */ debug.Debug("%s\n", p.idex.String()); p.idex.full = true; p.ifid.full = false; } } /* fetch: calcuate next PC, fetch operands */ /* Our instruction memory is not in byte form like a real machine would be, instead its just an array of pointers to instruction structs. So the program counter is just incremented, not += 4. */ if p.ready { debug.Debug("IFETCH: "); p.ifid.inst = p.cpu.get_inst_at_pc(); debug.Debug("%s\n", p.ifid.inst.String()); var branch bool; if inst.IType[p.ifid.inst.Opname] == inst.BRANCH { op := p.ifid.inst; switch op.Opname { case t.BEQ: branch = p.cpu.Regs[op.RT] == p.cpu.Regs[op.RS]; case t.BGEZ: branch = p.cpu.Regs[op.RS] >= 0; //case t.BGEZAL: branch = case t.BGTZ: branch = p.cpu.Regs[op.RS] > 0; case t.BLEZ: branch = p.cpu.Regs[op.RS] <= 0; case t.BLT: branch = p.cpu.Regs[op.RS] < p.cpu.Regs[op.RT]; case t.BLTZ: branch = p.cpu.Regs[op.RS] < 0; //case t.BLTZAL: case t.BNE: branch = p.cpu.Regs[op.RT] != p.cpu.Regs[op.RS]; case t.BNEZ: branch = p.cpu.Regs[op.RS] != 0; } } if branch { if p.ifid.inst.TGT.Section == 1 { debug.Debug("Trying to branch to data section? Uhoh...\n"); } p.ifid.npc = uint32(p.ifid.inst.TGT.Offset); } else { p.ifid.npc = p.cpu.pc + 1; } p.cpu.pc = p.ifid.npc; //debug.Debug("%s\n", p.ifid.String()); if !branch { p.ifid.full = true; } p.ready = false; } if p.cpu.cycles % 20 == 0 { debug.PPrint("\tIFETCH\tDECODE\tEXEC\tMEM\tWB\n"); } p.cpu.cycles += 1; debug.PPrint("%d:", p.cpu.cycles); //if p.ifid.full { debug.PPrint("\t%s %s\t", p.ifid.inst.Opname.String(), p.ifid.inst.String()) } if p.ifid.full { debug.PPrint("\t%s\t", p.ifid.inst.Opname.String()) } else { debug.PPrint ("\t\t") } if p.idex.full { debug.PPrint("%s\t", p.idex.inst.Opname.String()) } else { debug.PPrint ("\t") } if p.exmem.full { debug.PPrint("%s\t", p.exmem.inst.Opname.String()) } else { debug.PPrint ("\t") } if p.memwb.full { debug.PPrint("%s\t", p.memwb.inst.Opname.String()) } else { debug.PPrint ("\t") } if p.memwb.was_full { debug.PPrint("%s => alu:%d lmd:%d\t", p.memwb.inst.Opname.String(), p.memwb.alu_out, p.memwb.lmd) } else { debug.PPrint ("\t") } p.memwb.was_full = false; debug.PPrint("\n"); }
func (p *parser) next() { p.pos, p.tok, p.str = p.scanner.Scan() debug.Debug("next() returned %s: %s\n", p.tok.String(), p.str) }