URL
https://opencores.org/ocsvn/altor32/altor32/trunk
Subversion Repositories altor32
[/] [altor32/] [trunk/] [or1k-sim/] [or32.cpp] - Rev 29
Go to most recent revision | Compare with Previous | Blame | View Log
//----------------------------------------------------------------- // AltOR32 // Alternative Lightweight OpenRisc // V2.0 // Ultra-Embedded.com // Copyright 2011 - 2013 // // Email: admin@ultra-embedded.com // // License: LGPL //----------------------------------------------------------------- // // Copyright (C) 2011 - 2013 Ultra-Embedded.com // // This source file may be used and distributed without // restriction provided that this copyright statement is not // removed from the file and that any derivative work contains // the original copyright notice and the associated disclaimer. // // This source file is free software; you can redistribute it // and/or modify it under the terms of the GNU Lesser General // Public License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any // later version. // // This source is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General // Public License along with this source; if not, write to the // Free Software Foundation, Inc., 59 Temple Place, Suite 330, // Boston, MA 02111-1307 USA //----------------------------------------------------------------- #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include "or32.h" #ifdef INCLUDE_INST_DUMP #include "or32_inst_dump.h" #endif //----------------------------------------------------------------- // Defines: //----------------------------------------------------------------- #define DPRINTF(l,a) do { if (Trace & l) printf a; } while (0) #define TRACE_ENABLED(l) (Trace & l) #define MEMTRACE_WRITES "mem_writes.txt" #define MEMTRACE_READS "mem_reads.txt" #define MEMTRACE_INST "mem_inst.txt" #define MEMTRACE_MIN 100 #define ADD_CARRY_OUT(a,b) ((((unsigned long long)(a) + (unsigned long long)(b)) & ((unsigned long long)1 << 32)) != 0) #define HTONL(n) (((((unsigned int)(n) & 0xFF)) << 24) | \ ((((unsigned int)(n) & 0xFF00)) << 8) | \ ((((unsigned int)(n) & 0xFF0000)) >> 8) | \ ((((unsigned int)(n) & 0xFF000000)) >> 24)) //----------------------------------------------------------------- // Constructor //----------------------------------------------------------------- OR32::OR32(bool delay_slot) { MemRegions = 0; int m; for (m=0;m<MAX_MEM_REGIONS;m++) { MemInstHits[m] = NULL; MemReadHits[m] = NULL; MemWriteHits[m] = NULL; } MemVectorBase = 0; Trace = 0; DelaySlotEnabled = delay_slot; EnablePutc = true; Reset(); } //----------------------------------------------------------------- // Constructor //----------------------------------------------------------------- OR32::OR32(unsigned int baseAddr, unsigned int len, bool delay_slot) { int m; MemBase[0] = baseAddr; MemSize[0] = len; Mem[0] = new TMemory[(len + 3)/4]; assert(Mem[0]); memset(Mem[0], 0, (len + 3)/4); MemRegions = 1; for (m=0;m<MAX_MEM_REGIONS;m++) { MemInstHits[m] = NULL; MemReadHits[m] = NULL; MemWriteHits[m] = NULL; } MemVectorBase = baseAddr; Trace = 0; DelaySlotEnabled = delay_slot; EnablePutc = true; Reset(); } //----------------------------------------------------------------- // Deconstructor //----------------------------------------------------------------- OR32::~OR32() { int m; for (m=0;m<MemRegions;m++) { if (Mem[m]) delete Mem[m]; Mem[m] = NULL; } } //----------------------------------------------------------------- // CreateMemory: //----------------------------------------------------------------- bool OR32::CreateMemory(unsigned int baseAddr, unsigned int len) { if (MemRegions < MAX_MEM_REGIONS) { MemBase[MemRegions] = baseAddr; MemSize[MemRegions] = len; Mem[MemRegions] = new TMemory[(len + 3)/4]; if (!Mem[MemRegions]) return false; memset(Mem[MemRegions], 0, (len + 3)/4); MemRegions++; return true; } return false; } //----------------------------------------------------------------- // EnableMemoryTrace: //----------------------------------------------------------------- void OR32::EnableMemoryTrace(void) { int m; for (m=0;m<MemRegions;m++) { MemInstHits[m] = new TRegister[MemSize[m]/4]; MemReadHits[m] = new TRegister[MemSize[m]/4]; MemWriteHits[m] = new TRegister[MemSize[m]/4]; assert(MemInstHits[m]); assert(MemReadHits[m]); assert(MemWriteHits[m]); memset(MemInstHits[m], 0, MemSize[m]); memset(MemReadHits[m], 0, MemSize[m]); memset(MemWriteHits[m], 0, MemSize[m]); } } //----------------------------------------------------------------- // Reset: Reset CPU state //----------------------------------------------------------------- void OR32::Reset(TRegister start_addr /*= VECTOR_RESET*/) { int i; r_pc = start_addr; r_pc_next = start_addr; r_pc_last = start_addr; r_sr = 0; r_epc = 0; r_esr = 0; for (i=0;i<REGISTERS;i++) r_gpr[i] = 0; r_reg_ra = 0; r_reg_rb = 0; r_reg_result = 0; r_rd_wb = 0; r_ra = 0; r_rb = 0; mem_addr = 0; mem_offset = 0; mem_wr = 0; mem_rd = 0; mem_ifetch = 0; Fault = 0; Break = 0; BreakValue = 0; Trace = 0; Cycle = 2; MemVectorBase = start_addr - VECTOR_RESET; ResetStats(); PeripheralReset(); } //----------------------------------------------------------------- // ResetStats: Reset runtime stats //----------------------------------------------------------------- void OR32::ResetStats(void) { int m; // Clear stats StatsMem = 0; StatsMarkers = 0; StatsMemWrites = 0; StatsInstructions = 0; StatsNop = 0; StatsBranches = 0; StatsExceptions = 0; StatsMulu = 0; StatsMul = 0; for (m=0;m<MemRegions;m++) { if (MemReadHits[m]) memset(MemReadHits[m], 0, MemSize[m]); if (MemWriteHits[m]) memset(MemWriteHits[m], 0, MemSize[m]); if (MemInstHits[m]) memset(MemInstHits[m], 0, MemSize[m]); } } //----------------------------------------------------------------- // Load: Load program code into startAddr offset //----------------------------------------------------------------- bool OR32::Load(unsigned int startAddr, unsigned char *data, int len) { int i; int j; for (j=0;j<MemRegions;j++) { // Program fits in memory? if ((startAddr >= MemBase[j]) && (startAddr + len) <= (MemBase[j] + MemSize[j])) { // Make relative to start of memory startAddr -= MemBase[j]; // Convert to word address startAddr /= 4; for (i=0;i<len / 4; i++) { Mem[j][startAddr+i] = *data++; Mem[j][startAddr+i] <<= 8; Mem[j][startAddr+i]|= *data++; Mem[j][startAddr+i] <<= 8; Mem[j][startAddr+i]|= *data++; Mem[j][startAddr+i] <<= 8; Mem[j][startAddr+i]|= *data++; Mem[j][startAddr+i] = HTONL(Mem[j][startAddr+i]); } return true; } } return false; } //----------------------------------------------------------------- // WriteMem: Write a block of memory //----------------------------------------------------------------- bool OR32::WriteMem(TAddress addr, unsigned char *data, int len) { int i; int j; for (j=0;j<MemRegions;j++) { if (addr >= MemBase[j] && addr < (MemBase[j] + MemSize[j])) { unsigned char *ptr = (unsigned char *)Mem[j]; ptr += (addr - MemBase[j]); for (i=0;i<len; i++) ptr[i] = data[i]; return true; } } return false; } //----------------------------------------------------------------- // ReadMem: Read a block of memory //----------------------------------------------------------------- bool OR32::ReadMem(TAddress addr, unsigned char *data, int len) { int i; int j; for (j=0;j<MemRegions;j++) { if (addr >= MemBase[j] && addr < (MemBase[j] + MemSize[j])) { unsigned char *ptr = (unsigned char *)Mem[j]; ptr += (addr - MemBase[j]); for (i=0;i<len; i++) data[i] = ptr[i]; return true; } } return false; } //----------------------------------------------------------------- // GetOpcode: Get instruction from address //----------------------------------------------------------------- TRegister OR32::GetOpcode(TRegister address) { int m; for (m=0;m<MemRegions;m++) { if (address >= MemBase[m] && address < (MemBase[m] + MemSize[m])) { TAddress wordAddress = (address - MemBase[m]) / 4; TRegister mem_word = Mem[m][wordAddress]; return HTONL(mem_word); } } return 0; } //----------------------------------------------------------------- // Decode: Instruction decode stage //----------------------------------------------------------------- void OR32::Decode(void) { // Instruction opcode read complete mem_wr = 0; mem_rd = 0; mem_ifetch = 0; // Fetch instruction from 'memory bus' r_opcode = mem_data_in; mem_data_in = 0; // Decode opcode in-order to perform register reads r_ra = (r_opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; r_rb = (r_opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; r_rd = (r_opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; } //----------------------------------------------------------------- // Execute: Instruction execution stage //----------------------------------------------------------------- void OR32::Execute(void) { TRegister v_ra = 0; TRegister v_rb = 0; TRegister v_rd = 0; TRegister v_inst = 0; TRegister v_op = 0; TRegister v_target = 0; TRegister v_pc = 0; TRegister v_pc_next = 0; TRegister v_imm = 0; TRegister v_imm_uint32 = 0; TRegister v_imm_int32 = 0; TRegister v_offset = 0; TRegister v_reg_ra = 0; TRegister v_reg_rb = 0; TRegister v_reg_result = 0; TRegister v_store_imm = 0; int v_branch = 0; int v_jmp = 0; int v_exception = 0; TRegister v_vector = 0; int v_write_rd = 0; TRegister v_alu_op = 0; TRegister v_shift_op = 0; TRegister v_sfxx_op = 0; // Notify observers of instruction execution MonInstructionExecute(r_pc, r_opcode); StatsInstructions++; DPRINTF(LOG_INST, ("%08x: Execute 0x%08x\n", r_pc, r_opcode)); DPRINTF(LOG_INST, (" rA[%2d] = 0x%08x\n", r_ra, r_reg_ra)); DPRINTF(LOG_INST, (" rB[%2d] = 0x%08x\n", r_rb, r_reg_rb)); // Decode opcode fields v_inst = (r_opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; v_rd = (r_opcode >> OR32_REG_D_SHIFT) & OR32_REG_D_MASK; v_ra = (r_opcode >> OR32_REG_A_SHIFT) & OR32_REG_A_MASK; v_rb = (r_opcode >> OR32_REG_B_SHIFT) & OR32_REG_B_MASK; v_imm = (r_opcode >> OR32_IMM16_SHIFT) & OR32_IMM16_MASK; v_target = (r_opcode >> OR32_ADDR_SHIFT) & OR32_ADDR_MASK; v_sfxx_op = (r_opcode >> OR32_SFXXX_OP_SHIFT) & OR32_SFXXX_OP_MASK; v_alu_op = (r_opcode >> OR32_ALU_OP_L_SHIFT) & OR32_ALU_OP_L_MASK; v_alu_op |= (r_opcode >> OR32_ALU_OP_H_SHIFT) & OR32_ALU_OP_H_MASK; v_shift_op = (r_opcode >> OR32_SHIFT_OP_SHIFT) & OR32_SHIFT_OP_MASK; v_store_imm = (r_opcode >> OR32_STORE_IMM_L_SHIFT) & OR32_STORE_IMM_L_MASK; v_store_imm|= (r_opcode >> OR32_STORE_IMM_H_SHIFT) & OR32_STORE_IMM_H_MASK; // Sign extend store immediate v_store_imm = (unsigned int)(signed short)v_store_imm; // Sign extend target immediate if (v_target & (1 << OR32_ADDR_SIGN_SHIFT)) v_target |= ~OR32_ADDR_MASK; // Signed & unsigned imm -> 32-bits v_imm_int32 = (unsigned int)(signed short)v_imm; v_imm_uint32 = v_imm; // Load register[ra] v_reg_ra = r_reg_ra; // Load register[rb] v_reg_rb = r_reg_rb; // Zero result v_reg_result = 0; // Default target is r_rd r_rd_wb = r_rd; if (DelaySlotEnabled) { // Update PC to next value v_pc = r_pc_next; // Increment next PC value (might be overriden by branch) v_pc_next = r_pc_next + 4; } else { v_pc = r_pc + 4; // Current PC + 4 v_pc_next = r_pc + 8; // Current PC + 8 (used in branches) } // Execute instruction switch(v_inst) { case INST_OR32_ALU: switch (v_alu_op) { case INST_OR32_ADD: // l.add v_reg_result = v_reg_ra + v_reg_rb; v_write_rd = 1; // Carry out r_sr = (r_sr & ~OR32_SR_CY_BIT) | (ADD_CARRY_OUT(v_reg_ra, v_reg_rb) ? OR32_SR_CY_BIT : 0); break; case INST_OR32_ADDC: // l.addc v_reg_result = v_reg_ra + v_reg_rb + ((r_sr & OR32_SR_CY_BIT) ? 1 : 0); v_write_rd = 1; // Carry out r_sr = (r_sr & ~OR32_SR_CY_BIT) | (ADD_CARRY_OUT(v_reg_ra, v_reg_rb) ? OR32_SR_CY_BIT : 0); break; case INST_OR32_AND: // l.and v_reg_result = v_reg_ra & v_reg_rb; v_write_rd = 1; break; case INST_OR32_OR: // l.or v_reg_result = v_reg_ra | v_reg_rb; v_write_rd = 1; break; case INST_OR32_SLL: // l.sll v_reg_result = v_reg_ra << (v_reg_rb & 0x3F); v_write_rd = 1; break; case INST_OR32_SRA: // l.sra v_reg_result = (int)v_reg_ra >> (v_reg_rb & 0x3F); v_write_rd = 1; break; case INST_OR32_SRL: // l.srl v_reg_result = v_reg_ra >> (v_reg_rb & 0x3F); v_write_rd = 1; break; case INST_OR32_SUB: // l.sub v_reg_result = v_reg_ra + ~v_reg_rb + 1; v_write_rd = 1; break; case INST_OR32_XOR: // l.xor v_reg_result = v_reg_ra ^ v_reg_rb; v_write_rd = 1; break; case INST_OR32_MUL: // l.mul { long long res = ((long long) (int)v_reg_ra) * ((long long)(int)v_reg_rb); v_reg_result = (int)(res >> 0); v_write_rd = 1; StatsMul++; } break; case INST_OR32_MULU: // l.mulu { // This implementation differs from other cores - l.mulu returns upper // 32-bits of multiplication result... long long res = ((long long) (int)v_reg_ra) * ((long long)(int)v_reg_rb); v_reg_result = (int)(res >> 32); v_write_rd = 1; StatsMulu++; } break; default: fprintf (stderr,"Bad ALU instruction @ PC %x\n", r_pc); Fault = 1; v_exception = 1; v_vector = MemVectorBase + VECTOR_ILLEGAL_INST; break; } break; case INST_OR32_ADDI: // l.addi v_reg_result = v_reg_ra + v_imm_int32; v_write_rd = 1; // Carry out r_sr = (r_sr & ~OR32_SR_CY_BIT) | (ADD_CARRY_OUT(v_reg_ra, v_reg_rb) ? OR32_SR_CY_BIT : 0); break; case INST_OR32_ANDI: // l.andi v_reg_result = v_reg_ra & v_imm_uint32; v_write_rd = 1; break; case INST_OR32_BF: // l.bf if (r_sr & OR32_SR_F_BIT) v_branch = 1; break; case INST_OR32_BNF: // l.bnf if (!(r_sr & OR32_SR_F_BIT)) v_branch = 1; break; case INST_OR32_J: // l.j v_branch = 1; break; case INST_OR32_JAL: // l.jal // Write next instruction address to LR if (DelaySlotEnabled) v_reg_result = v_pc_next; else v_reg_result = v_pc; r_rd_wb = REG_9_LR; v_write_rd = 1; v_branch = 1; break; case INST_OR32_JALR: // l.jalr // Write next instruction address to LR if (DelaySlotEnabled) v_reg_result = v_pc_next; else v_reg_result = v_pc; r_rd_wb = REG_9_LR; v_write_rd = 1; if (DelaySlotEnabled) v_pc_next = v_reg_rb; else v_pc = v_reg_rb; v_jmp = 1; break; case INST_OR32_JR: // l.jr if (DelaySlotEnabled) v_pc_next = v_reg_rb; else v_pc = v_reg_rb; v_jmp = 1; break; case INST_OR32_LBS: // l.lbs case INST_OR32_LHS: // l.lhs case INST_OR32_LWS: // l.lws case INST_OR32_LBZ: // l.lbz case INST_OR32_LHZ: // l.lhz case INST_OR32_LWZ: // l.lwz mem_addr = v_reg_ra + (int)v_imm_int32; mem_offset = mem_addr & 0x3; mem_wr = 0; mem_rd = 1; mem_data_out = 0; v_write_rd = 1; StatsMem++; break; case INST_OR32_MFSPR: // l.mfspr // Move from SPR register switch ((v_reg_ra | (v_imm_uint32 & OR32_MFSPR_IMM_MASK))) { // VR - Version register case SPR_REG_VR: v_reg_result = SPR_VERSION_CURRENT; v_write_rd = 1; break; // SR - Supervision register case SPR_REG_SR: v_reg_result = r_sr; v_write_rd = 1; break; // EPCR - EPC Exception saved PC case SPR_REG_EPCR: v_reg_result = r_epc; v_write_rd = 1; break; // ESR - Exception saved SR case SPR_REG_ESR: v_reg_result = r_esr; v_write_rd = 1; break; default: fprintf (stderr,"Unsupported SPR register (0x%x) access @ PC %x\n", (v_reg_ra | v_imm_uint32), r_pc); Fault = 1; v_exception = 1; v_vector = MemVectorBase + VECTOR_ILLEGAL_INST; break; } break; case INST_OR32_MTSPR: // l.mtspr // Move to SPR register switch ((v_reg_ra | (v_imm_uint32 & OR32_MTSPR_IMM_MASK))) { // SR - Supervision register case SPR_REG_SR: r_sr = v_reg_rb; break; // EPCR - EPC Exception saved PC case SPR_REG_EPCR: r_epc = v_reg_rb; break; // ESR - Exception saved SR case SPR_REG_ESR: r_esr = v_reg_rb; break; default: fprintf (stderr,"Unsupported SPR register (0x%x) access @ PC %x\n", (v_reg_ra | v_imm_uint32), r_pc); Fault = 1; v_exception = 1; v_vector = VECTOR_ILLEGAL_INST; break; } break; case INST_OR32_MOVHI: // l.movhi v_reg_result = v_imm_uint32 << 16; v_write_rd = 1; break; case INST_OR32_NOP: // l.nop StatsNop++; // NOP with simulator instruction? if (v_imm != NOP_NOP) MonNop(v_imm); break; case INST_OR32_ORI: // l.ori v_reg_result = v_reg_ra | v_imm_uint32; v_write_rd = 1; break; case INST_OR32_RFE: // l.rfe // Restore PC & SR from EPC & ESR if (DelaySlotEnabled) v_pc_next = r_epc; else v_pc = r_epc; r_sr = r_esr; v_jmp = 1; // TODO: Handle branch delay & next instruction flush break; case INST_OR32_SHIFTI: switch (v_shift_op) { case INST_OR32_SLLI: // l.slli v_reg_result = v_reg_ra << (r_opcode & 0x3F); v_write_rd = 1; break; case INST_OR32_SRAI: // l.srai v_reg_result = (int)v_reg_ra >> (r_opcode & 0x3F); v_write_rd = 1; break; case INST_OR32_SRLI: // l.srli v_reg_result = v_reg_ra >> (r_opcode & 0x3F); v_write_rd = 1; break; default: fprintf (stderr,"Bad shift instruction @ PC %x\n", r_pc); Fault = 1; v_exception = 1; v_vector = MemVectorBase + VECTOR_ILLEGAL_INST; break; } break; case INST_OR32_SB: // l.sb mem_addr = v_reg_ra + (int)v_store_imm; mem_offset = mem_addr & 0x3; mem_rd = 0; switch (mem_offset) { case 0x0: mem_data_out = (v_reg_rb & 0xFF) << 24; mem_wr = 8; break; case 0x1: mem_data_out = (v_reg_rb & 0xFF) << 16; mem_wr = 4; break; case 0x2: mem_data_out = (v_reg_rb & 0xFF) << 8; mem_wr = 2; break; case 0x3: mem_data_out = (v_reg_rb & 0xFF) << 0; mem_wr = 1; break; } StatsMem++; StatsMemWrites++; break; case INST_OR32_SFXX: case INST_OR32_SFXXI: switch (v_sfxx_op) { case INST_OR32_SFEQ: // l.sfeq if (v_reg_ra == v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFEQI: // l.sfeqi if (v_reg_ra == v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGES: // l.sfges if ((int)v_reg_ra >= (int)v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGESI: // l.sfgesi if ((int)v_reg_ra >= (int)v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGEU: // l.sfgeu if (v_reg_ra >= v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGEUI: // l.sfgeui if (v_reg_ra >= v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGTS: // l.sfgts if ((int)v_reg_ra > (int)v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGTSI: // l.sfgtsi if ((int)v_reg_ra > (int)v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGTU: // l.sfgtu if (v_reg_ra > v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFGTUI: // l.sfgtui if (v_reg_ra > v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLES: // l.sfles if ((int)v_reg_ra <= (int)v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLESI: // l.sflesi if ((int)v_reg_ra <= (int)v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLEU: // l.sfleu if (v_reg_ra <= v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLEUI: // l.sfleui if (v_reg_ra <= v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLTS: // l.sflts if ((int)v_reg_ra < (int)v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLTSI: // l.sfltsi if ((int)v_reg_ra < (int)v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLTU: // l.sfltu if (v_reg_ra < v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFLTUI: // l.sfltui if (v_reg_ra < v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFNE: // l.sfne if (v_reg_ra != v_reg_rb) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; case INST_OR32_SFNEI: // l.sfnei if (v_reg_ra != v_imm_int32) r_sr |= OR32_SR_F_BIT; else r_sr &=~OR32_SR_F_BIT; break; default: fprintf (stderr,"Bad SFxx instruction @ PC %x\n", r_pc); Fault = 1; v_exception = 1; v_vector = MemVectorBase + VECTOR_ILLEGAL_INST; break; } break; case INST_OR32_SH: // l.sh mem_addr = v_reg_ra + (int)v_store_imm; mem_offset = mem_addr & 0x3; mem_rd = 0; switch (mem_offset) { case 0x0: mem_data_out = (v_reg_rb & 0xFFFF) << 16; mem_wr = 0xC; break; case 0x2: mem_data_out = (v_reg_rb & 0xFFFF) << 0; mem_wr = 0x3; break; default: fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); Fault = 1; mem_wr = 0; break; } StatsMem++; StatsMemWrites++; break; case INST_OR32_SW: // l.sw mem_addr = v_reg_ra + (int)v_store_imm; mem_offset = mem_addr & 0x3; mem_rd = 0; mem_wr = 0xF; mem_data_out = v_reg_rb; if (mem_offset != 0) { fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); Fault = 1; mem_wr = 0; } StatsMem++; StatsMemWrites++; break; case INST_OR32_MISC: switch (r_opcode >> 24) { case INST_OR32_SYS: // l.sys v_exception = 1; v_vector = MemVectorBase + VECTOR_SYSCALL; break; case INST_OR32_TRAP: // l.trap Break = 1; BreakValue = v_imm_uint32; v_exception = 1; v_vector = MemVectorBase + VECTOR_TRAP; break; } break; case INST_OR32_XORI: // l.xori v_reg_result = v_reg_ra ^ v_imm_int32; v_write_rd = 1; break; default: fprintf (stderr,"Fault @ PC %x\n", r_pc); Fault = 1; v_exception = 1; v_vector = MemVectorBase + VECTOR_ILLEGAL_INST; break; } // Notify observer of fault if (Fault) MonFault(r_pc, r_opcode); // Handle branches (jumps relative to current PC) if (v_branch == 1) { v_offset = v_target << 2; if (DelaySlotEnabled) v_pc_next = r_pc + v_offset; else v_pc = r_pc + v_offset; StatsBranches++; } // If not branching, handle interrupts / exceptions else if (v_jmp == 0) { // Check for external interrupt if ((v_exception == 0) && (r_sr & (1 << OR32_SR_IEE))) { // External interrupt (and not handling an exception)? if (PeripheralInterrupt()) { v_exception = 1; v_vector = MemVectorBase + VECTOR_EXTINT; } } // Interrupt / Exception if (v_exception == 1) { // Save PC & SR r_epc = v_pc; r_esr = r_sr; v_pc = v_vector; v_pc_next = v_pc + 4; // Disable further interrupts r_sr = 0; StatsExceptions++; StatsBranches++; } } else StatsBranches++; // Update registers with variable values if (DelaySlotEnabled) { r_pc_last = r_pc; r_pc = v_pc; r_pc_next = v_pc_next; } else { r_pc_last = r_pc; r_pc = v_pc; } r_reg_result = v_reg_result; // No writeback required? if (v_write_rd == 0) { // Target register is $0 which is read-only r_rd_wb = 0; } } //----------------------------------------------------------------- // WriteBack: Register write back stage //----------------------------------------------------------------- void OR32::WriteBack(void) { TRegister v_inst; TRegister v_reg_result; mem_wr = 0; mem_rd = 0; mem_ifetch = 0; v_inst = (r_opcode >> OR32_OPCODE_SHIFT) & OR32_OPCODE_MASK; // Writeback read result switch(v_inst) { case INST_OR32_LBS: // l.lbs switch (mem_offset) { case 0x0: v_reg_result = (int)((signed char)(mem_data_in >> 24)); break; case 0x1: v_reg_result = (int)((signed char)(mem_data_in >> 16)); break; case 0x2: v_reg_result = (int)((signed char)(mem_data_in >> 8)); break; case 0x3: v_reg_result = (int)((signed char)(mem_data_in >> 0)); break; } break; case INST_OR32_LBZ: // l.lbz switch (mem_offset) { case 0x0: v_reg_result = ((unsigned char)(mem_data_in >> 24)); break; case 0x1: v_reg_result = ((unsigned char)(mem_data_in >> 16)); break; case 0x2: v_reg_result = ((unsigned char)(mem_data_in >> 8)); break; case 0x3: v_reg_result = ((unsigned char)(mem_data_in >> 0)); break; } break; case INST_OR32_LHS: // l.lhs switch (mem_offset) { case 0x0: v_reg_result = (int)((signed short)(mem_data_in >> 16)); break; case 0x2: v_reg_result = (int)((signed short)(mem_data_in >> 0)); break; default: fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); Fault = 1; break; } break; case INST_OR32_LHZ: // l.lhz switch (mem_offset) { case 0x0: v_reg_result = ((unsigned short)(mem_data_in >> 16)); break; case 0x2: v_reg_result = ((unsigned short)(mem_data_in >> 0)); break; default: fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); Fault = 1; break; } break; case INST_OR32_LWZ: // l.lwz case INST_OR32_LWS: // l.lws v_reg_result = mem_data_in; if (mem_offset != 0) { fprintf (stderr,"Bad mem access @ PC %x (%x)\n", r_pc, mem_offset); Fault = 1; } break; default: v_reg_result = r_reg_result; break; } // Decode instruction to full text? #ifdef INCLUDE_INST_DUMP if (TRACE_ENABLED(LOG_OR1K)) or32_instruction_dump(r_pc_last, r_opcode, r_gpr, r_rd_wb, v_reg_result, r_sr); #endif // Register writeback required? r_reg_rd_out = v_reg_result; if (r_rd_wb != 0) r_writeback = 1; // Fetch next instruction mem_addr = r_pc; mem_data_out = 0; mem_rd = 1; mem_ifetch = 1; } //----------------------------------------------------------------- // Clock: Execute a single instruction (including load / store) //----------------------------------------------------------------- bool OR32::Clock(void) { bool writeback = false; switch (Cycle) { // Instruction decode case 0: Cycle++; Decode(); break; // Execute case 1: Cycle++; Execute(); break; // Writeback & fetch next case 2: Cycle = 0; WriteBack(); writeback = true; break; } // Notify observers if memory write will occur if (mem_wr) { DPRINTF(LOG_MEM, ("MEM: Write Addr %x Value %x Mask %x\n", mem_addr, mem_data_out, mem_wr)); MonDataStore(mem_addr, mem_wr, mem_data_out); } // Internal Memory? int m; for (m=0;m<MemRegions;m++) { if (mem_addr >= MemBase[m] && mem_addr < (MemBase[m] + MemSize[m])) { TAddress wordAddress = (mem_addr - MemBase[m]) / 4; TRegister mem_word = Mem[m][wordAddress]; mem_word = HTONL(mem_word); // Write switch (mem_wr) { case 0xF: mem_word = mem_data_out; break; case 0x3: mem_data_out &= 0x0000FFFF; mem_word &=~ 0x0000FFFF; mem_word |= mem_data_out; break; case 0xC: mem_data_out &= 0xFFFF0000; mem_word &=~ 0xFFFF0000; mem_word |= mem_data_out; break; case 0x1: mem_data_out &= 0x000000FF; mem_word &=~ 0x000000FF; mem_word |= mem_data_out; break; case 0x2: mem_data_out &= 0x0000FF00; mem_word &=~ 0x0000FF00; mem_word |= mem_data_out; break; case 0x4: mem_data_out &= 0x00FF0000; mem_word &=~ 0x00FF0000; mem_word |= mem_data_out; break; case 0x8: mem_data_out &= 0xFF000000; mem_word &=~ 0xFF000000; mem_word |= mem_data_out; break; } Mem[m][wordAddress] = HTONL(mem_word); // Read mem_data_in = mem_word; if (!mem_ifetch) { if (mem_wr && MemWriteHits[m]) MemWriteHits[m][wordAddress]++; else if (mem_rd && MemReadHits[m]) MemReadHits[m][wordAddress]++; } else if (MemInstHits[m]) MemInstHits[m][wordAddress]++; break; } } // External / Peripheral memory if (m == MemRegions) { mem_data_in = PeripheralAccess(mem_addr, mem_data_out, mem_wr, mem_rd); } // Notify observers if memory read has occurred if (mem_rd) { DPRINTF(LOG_MEM, ("MEM: Read Addr %x Value %x\n", mem_addr, mem_data_in)); MonDataLoad(mem_addr, 0xF, mem_data_in); } // Clock peripherals PeripheralClock(); // Writeback (if target is not R0) if (r_writeback && r_rd_wb != REG_0_ZERO) { r_gpr[r_rd_wb] = r_reg_rd_out; r_writeback = 0; } // If write-back stage just completed, show register state... if (writeback && TRACE_ENABLED(LOG_REGISTERS)) { // Register trace int i; for (i=0;i<REGISTERS;i+=4) { printf(" %d: ", i); printf(" %08x %08x %08x %08x\n", r_gpr[i+0], r_gpr[i+1], r_gpr[i+2], r_gpr[i+3]); } printf(" SR = 0x%08x, EPC = 0x%08x, ESR = 0x%08x, SR_F=%d\n\n", r_sr, r_epc, r_esr, (r_sr & OR32_SR_F_BIT) ? 1 : 0); } // Reload register contents r_reg_ra = r_gpr[r_ra]; r_reg_rb = r_gpr[r_rb]; return writeback; } //----------------------------------------------------------------- // Step: Step through one instruction //----------------------------------------------------------------- bool OR32::Step(void) { while (!Clock()) ; return true; } //----------------------------------------------------------------- // MonNop: Default NOP functions //----------------------------------------------------------------- void OR32::MonNop(TRegister imm) { switch (imm) { // Exit case NOP_EXIT: exit(r_gpr[NOP_DATA_REG]); break; // Report value case NOP_REPORT: if (Trace) fprintf(stderr, "report(0x%x)\n", r_gpr[NOP_DATA_REG]); else printf("report(0x%x)\n", r_gpr[NOP_DATA_REG]); break; // putc() case NOP_PUTC: if (EnablePutc) { if (Trace) fprintf(stderr, "%c", r_gpr[NOP_DATA_REG]); else printf("%c", r_gpr[NOP_DATA_REG]); } break; // Trace Control case NOP_TRACE_ON: Trace = r_gpr[NOP_DATA_REG]; break; case NOP_TRACE_OFF: Trace = 0; break; case NOP_STATS_RESET: ResetStats(); break; case NOP_STATS_MARKER: StatsMarkers++; break; } } //----------------------------------------------------------------- // DumpStats: Show execution stats //----------------------------------------------------------------- void OR32::DumpStats(void) { printf("Runtime Stats:\n"); printf("- Total Instructions %d\n", StatsInstructions); printf("- Memory Operations %d (%d%%)\n", StatsMem, (StatsMem * 100) / StatsInstructions); printf(" - Reads %d (%d%%)\n", (StatsMem - StatsMemWrites), ((StatsMem - StatsMemWrites) * 100) / StatsMem); printf(" - Writes %d (%d%%)\n", StatsMemWrites, (StatsMemWrites * 100) / StatsMem); printf("- MUL %d (%d%%)\n", StatsMul, (StatsMul * 100) / StatsInstructions); printf("- MULU %d (%d%%)\n", StatsMulu, (StatsMulu * 100) / StatsInstructions); printf("- NOPS %d (%d%%)\n", StatsNop, (StatsNop * 100) / StatsInstructions); printf("- Markers %d (%d%%)\n", StatsMarkers, (StatsMarkers * 100) / StatsInstructions); printf("- Branches Operations %d (%d%%)\n", StatsBranches, (StatsBranches * 100) / StatsInstructions); printf("- Exceptions %d (%d%%)\n", StatsExceptions, (StatsExceptions * 100) / StatsInstructions); FILE *f; int i; int m; for (m=0;m<MemRegions;m++) { if (MemReadHits[m]) { printf("Saving %s\n", MEMTRACE_READS); f = fopen(MEMTRACE_READS, "w"); if (f) { for (i=0;i<MemSize[m]/4;i++) { unsigned int addr = MemBase[m] + (i * 4); if (MemReadHits[m][i] > MEMTRACE_MIN) { fprintf(f, "%08x %d\n", addr, MemReadHits[m][i]); } } fclose(f); } else fprintf (stderr,"Could not open file for writing\n"); } if (MemWriteHits[m]) { printf("Saving %s\n", MEMTRACE_WRITES); f = fopen(MEMTRACE_WRITES, "w"); if (f) { for (i=0;i<MemSize[m]/4;i++) { unsigned int addr = MemBase[m] + (i * 4); if (MemWriteHits[m][i] > MEMTRACE_MIN) { fprintf(f, "%08x %d\n", addr, MemWriteHits[m][i]); } } fclose(f); } else fprintf (stderr,"Could not open file for writing\n"); } if (MemInstHits[m]) { printf("Saving %s\n", MEMTRACE_INST); f = fopen(MEMTRACE_INST, "w"); if (f) { for (i=0;i<MemSize[m]/4;i++) { unsigned int addr = MemBase[m] + (i * 4); if (MemInstHits[m][i] > MEMTRACE_MIN) { fprintf(f, "%08x %d\n", addr, MemInstHits[m][i]); } } fclose(f); } else fprintf (stderr,"Could not open file for writing\n"); } } ResetStats(); }
Go to most recent revision | Compare with Previous | Blame | View Log