Exemple #1
0
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());
}
Exemple #2
0
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()
		}
	}
}
Exemple #3
0
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");
}
Exemple #4
0
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)
}