/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package tools.mips; import API.Utils; import Export.MemoryInitializationFile; import common.Instruction; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import targets.mips.Descriprion; /** * * @author EUGENIO CARVALHO */ public class MipsProcessor { public String ID = "default"; public Integer WORD = 4, BYTE = 1; public MipsSettings settings; public Memory DataMemory; public Memory InstructionMemory; public Long PC = 0L; public RegisterBank RBank; public HashMap instructions = new HashMap<>(); public TreeMap breakPoint = new TreeMap<>(); public MipsProcessor(MipsSettings settings) throws Exception { this.settings = new MipsSettings(); this.settings.Set("mode", "debug").Set("step.by.step", "false"); InstructionMemory = new Memory( settings.Get("memory.instruction"), settings.GetInt("memory.instruction.size") ); InstructionMemory.SetIO(new MemoryInitializationFile()); DataMemory = new Memory( settings.Get("memory.data"), settings.GetInt("memory.data.size") ); DataMemory.SetIO(new MemoryInitializationFile()); WORD = 4; // Limpa todos os dados armazenados // DataMemory.Reset(); // System.out.println("Init Md:" + DataMemory.R(0L)); RBank = new RegisterBank(32); InitInstructions(); this.settings.copy( "debugmode," + "mode," + "step.by.step," + "breakpoints," + "memory.instruction," + "memory.instruction.size," + "memory.data," + "memory.data.reset," + "memory.data.size", settings); SetBreak(this.settings.Get("breakpoints")); } public MipsProcessor SetBreak(String address) { for (String addrs : address.split(",")) { if (!addrs.equals("")) { // Range address if (addrs.contains("-")) { String[] parts = addrs.split("-"); Long init = Long.parseLong(parts[0], 16), end = Long.parseLong(parts[1], 16); for (; init <= end; init += WORD) { breakPoint.put(Long.toString(init, 16), true); } } else { breakPoint.put(addrs, true); } } } System.out.println("Breakpoints:\n" + breakPoint); return this; } public MipsProcessor Persist() throws Exception { DataMemory.Save(); return this; } protected void Log(String msg) { if (!settings.eq("mode", "debug")) { return; } if (breakPoint.size() > 0 && !breakPoint.containsKey(Long.toHexString(PC))) { return; } System.out.println(msg); } public MipsProcessor Run() throws Exception { Instruction instruction; Integer interation = 0; String cAddress; BufferedReader br = null; Boolean stepByStep = settings.eq("step.by.step", "true"); if (stepByStep || !breakPoint.isEmpty()) { br = new BufferedReader(new InputStreamReader(System.in)); } // Carrega o conteudo das memorias InstructionMemory.ReadFile(); if (!settings.eq("memory.data.reset", "true")) { DataMemory.ReadFile(); } // Fetch // System.out.println("InstructionMemory:" + InstructionMemory); System.out.println("Start simulation ... " + ID); while (true) { instruction = Decode(InstructionMemory.R(PC, WORD)); // Quando encontra a instrucao stop para a simulacao if (instruction.eq("inst", "stop")) { break; } cAddress = Long.toHexString(PC); // Executa a instrucao Log("Interation(" + (interation++) + ")[ " + cAddress + " ] " + instruction.Get("inst")); Execute(instruction); // PC já incrementou Log("Registradores(\n" + RBank + ")\n Next PC:" + Long.toHexString(PC)); // Verifica o controle de execução do simulador if ((stepByStep || breakPoint.containsKey(cAddress)) && br != null) { br.readLine(); } } return this; } public Instruction Decode(String bin) { // int val = (int) instruction; // String bin = Utils.Pad(32, Integer.toBinaryString(val)); // System.out.println("Run:" + bin + ":" + bin.length()); String codop = bin.substring(0, 6), key, func = ""; String rs = bin.substring(6, 11), rt = bin.substring(11, 16); switch (codop) { case "000000": func = bin.substring(26); key = "@" + func; break; case "000001": key = codop + rt; break; default: key = codop; } if (!instructions.containsKey(key)) { System.out.println("Não encontrou a instrução " + key); return null; } Instruction i = instructions.get(key).copy(); switch (i.Get("type")) { case "R": i.Set("rs.bin", rs); i.Set("rt.bin", rt); i.Set("rd.bin", bin.substring(16, 21)); i.Set("shamt.bin", bin.substring(21, 26)); i.Set("funct.bin", func); i.Set("rs", Long.parseLong(rs, 2)); i.Set("rt", Long.parseLong(rt, 2)); i.Set("rd", Long.parseLong(bin.substring(16, 21), 2)); i.Set("shamt", Long.parseLong(bin.substring(21, 26), 2)); i.Set("funct", func); break; case "I": i.Set("rs.bin", rs); i.Set("rt.bin", rt); i.Set("imm.bin", bin.substring(16)); i.Set("rs", Long.parseLong(rs, 2)); i.Set("rt", Long.parseLong(rt, 2)); i.Set("imm", Utils.bin32ToDec(bin.substring(16))); break; case "J": i.Set("addr.bin", bin.substring(6)); i.Set("imm", Utils.bin32ToDec(bin.substring(6))); } return i; } // public Integer IntToHex(Integer n) { // return Integer.valueOf(String.valueOf(n), 16); // } protected void InitInstructions() throws Exception { String key; for (Map.Entry entry : Descriprion.Codops.entrySet()) { // String string = entry.getKey(); Instruction instruction = entry.getValue(); key = instruction.Get("codop"); switch (key) { case "000000": key = "@" + instruction.Get("func"); break; case "000001": key += instruction.Get("rt"); break; } instructions.put(key, instruction); }; } private void Execute(Instruction inst) throws Exception { long rs = 0, rt = 0, imm = 0, rd = 0, shamt = 0; boolean hasImm = true; switch (inst.Get("type")) { case "R": rd = inst.GetInt("rd"); shamt = inst.GetInt("shamt"); hasImm = false; case "I": rs = inst.GetInt("rs"); rt = inst.GetInt("rt"); case "J": if (hasImm) { // System.out.println("HAS_IMM:" + inst.Get("imm")); imm = inst.getLong("imm"); } } Log(inst.Get("inst") + " [rd:" + RBank.names.get((int) rd) + "] [rs:" + RBank.names.get((int) rs) + "] [rt:" + RBank.names.get((int) rt) + "] [shamt:" + shamt + "] [imm:" + imm + "]"); switch (inst.Get("inst")) { // R case "add": case "addu": RBank.W(rd, RBank.R(rs) + RBank.R(rt)); break; case "addi": case "addiu": // System.out.println("RBank.R(rs) + imm:" + RBank.R(rs) + ":" + imm); RBank.W(rt, RBank.R(rs) + imm); break; case "stop": break; case "and": case "andi": RBank.W(rd, RBank.R(rs) & RBank.R(rt)); break; case "div": case "divu": RBank.W(RBank.REG_LO, RBank.R(rs) / RBank.R(rt)); RBank.W(RBank.REG_HI, RBank.R(rs) % RBank.R(rt)); break; case "jr": PC = RBank.R(rs); break; case "mfhi": RBank.W(rd, RBank.R(RBank.REG_HI)); break; case "mflo": RBank.W(rd, RBank.R(RBank.REG_LO)); break; case "mthi": RBank.W(RBank.R(RBank.REG_HI), RBank.R(rs)); break; case "mtlo": RBank.W(RBank.R(RBank.REG_LO), RBank.R(rs)); break; case "mult": case "multu": // verificar a questao do hi e lo // System.out.println("Mult:" // + rs + "(" + RBank.names.Get((int) rs) + "):" // + rt + "(" + RBank.names.Get((int) rt) + ")"); RBank.W(RBank.REG_LO, RBank.R(rs) * RBank.R(rt)); break; // case "nor": // RBank.W(rd, rs * rt); // break; case "or": RBank.W(rd, RBank.R(rs) | RBank.R(rt)); break; case "sll": RBank.W(rd, RBank.R(rt) << shamt); break; case "slt": RBank.W(rd, (RBank.R(rs) < RBank.R(rt)) ? 1 : 0); break; case "sra": RBank.W(rd, RBank.R(rt) >> shamt); break; case "srl": RBank.W(rd, RBank.R(rt) >>> shamt); break; case "sub": case "subu": RBank.W(rd, RBank.R(rs) - RBank.R(rt)); break; case "xor": RBank.W(rd, RBank.R(rs) ^ RBank.R(rt)); break; // // I case "beq": if (RBank.R(rs) == RBank.R(rt)) { PC += ((imm + 1) << 2); return; } break; case "bgez": if (RBank.R(rs) >= 0) { PC += ((imm + 1) << 2); return; } break; case "bgtz": if (RBank.R(rs) > 0) { PC += ((imm + 1) << 2); return; } break; case "blez": if (RBank.R(rs) <= 0) { PC += ((imm + 1) << 2); return; } break; case "bltz": // System.out.println("BLTZ:" + rs); if (RBank.R(rs) < 0) { PC += ((imm + 1) << 2); return; } break; case "bne": if (RBank.R(rs) != RBank.R(rt)) { PC += ((imm + 1) << 2); return; } break; // case "lb": // if (RBank.R(rs) != RBank.R(rt)) { // PC += imm << 2; // return; // } // case "lbu": // case "lh": // case "lhu": case "lui": RBank.W(rt, imm); break; case "lb": RBank.W( rt, DataMemory.ReadLong( RBank.R(rs) + imm, BYTE // Apenas 1 byte )); Log(String.format( "Load endereco '%d' <- '%d'\n", RBank.R(rs) + imm, DataMemory.ReadLong(RBank.R(rs) + imm, BYTE) )); break; case "lw": // Escreve no banco de registradores no registrador enderecado por rt RBank.W( rt, // Lê da memoria de dados uma palavra de 4 bytes DataMemory.ReadLong( // Endereco de leitura equivale ao conteudo do registrador rs + imediato RBank.R(rs) + imm, WORD )); Log(String.format( "Load endereco '%d' <- '%d'\n", RBank.R(rs) + imm, DataMemory.ReadLong(RBank.R(rs) + imm, WORD) )); break; case "ori": RBank.W(rt, RBank.R(rs) | imm); break; case "slti": // case "sltiu": case "sw": DataMemory.W( RBank.R(rs) + imm, RBank.R(rt), WORD // uma palavra inteira ); Log(String.format("Store '%d' no endereco '%d'\n", RBank.R(rt), RBank.R(rs) + imm)); break; // case "xori": // J case "jal": RBank.W(31, PC); case "j": PC = imm << 2; return; default: throw new Exception("Instrução " + inst.Get("inst") + " não definida!"); } PC += WORD; } }