/////////////////////////////////////////////////////////////////////////////// // // m68000.cxx -> cpu32.cxx // // Motorola 68000 microprocessor class // // Sim68000 "Motorola 68000 Simulator" // Copyright (c) 1993 // By: Bradford W. Mott // October 31,1993 // // Adapted to 68360 - DJ - 1996/11 // - m68000 replaced by cpu32. // - VBR, SFC and DFC registers added. // - in Constructor, address space capability extended // (0x0fffffff instead of 0x00ffffff). // - in Reset, VBR, SFC and DFC resetted. // - in ExecuteInstruction, check event only when not running step by step. // - in InterruptRequest, acknowledge a masked device with a 0 level, // in order to tell it that it is currently masked. It is the up to the // device to drop the interrupt or to present it later... // /////////////////////////////////////////////////////////////////////////////// // $Id: m68000.cxx,v 1.1 1996/08/02 14:59:18 bwmott Exp $ /////////////////////////////////////////////////////////////////////////////// #include "Tools.hxx" #include "cpu32.hxx" #include "BasicDevice.hxx" #include "RegInfo.hxx" #include "AddressSpace.hxx" // Array of information about each register cpu32::RegisterData cpu32::ourRegisterData[] = { {"D0", 0xffffffff, "Data Register 0"}, {"D1", 0xffffffff, "Data Register 1"}, {"D2", 0xffffffff, "Data Register 2"}, {"D3", 0xffffffff, "Data Register 3"}, {"D4", 0xffffffff, "Data Register 4"}, {"D5", 0xffffffff, "Data Register 5"}, {"D6", 0xffffffff, "Data Register 6"}, {"D7", 0xffffffff, "Data Register 7"}, {"A0", 0xffffffff, "Address Register 0"}, {"A1", 0xffffffff, "Address Register 1"}, {"A2", 0xffffffff, "Address Register 2"}, {"A3", 0xffffffff, "Address Register 3"}, {"A4", 0xffffffff, "Address Register 4"}, {"A5", 0xffffffff, "Address Register 5"}, {"A6", 0xffffffff, "Address Register 6"}, {"A7", 0xffffffff, "Address Register 7 (User Stack Pointer)"}, {"A7'" ,0xffffffff, "Address Register 7 (Supervisor Stack Pointer)"}, {"PC", 0xffffffff, "Program Counter"}, {"SR", 0x0000ffff, "Status Register: T-S--III---XNZVC\n T: Trace Mode\n S: Supervisory Mode\n I: Interrupt Mask Level\n X: Extend\n N: Negative\n Z: Zero\n V: Overflow\n C: Carry"}, {"VBR", 0xffffffff, "Vector Base Register"}, {"SFC", 0x00000007, "Address space identification"}, {"DFC", 0x00000007, "Address space identification"} }; /////////////////////////////////////////////////////////////////////////////// // The cpu32 Class constructor /////////////////////////////////////////////////////////////////////////////// cpu32::cpu32() : BasicCPU("68360", 1, *(new vector), "{InstructionAddress 8} {Mnemonic 35}", "InstructionAddress Mnemonic"), myNumberOfRegisters(22), C_FLAG(0x0001), // SR flags V_FLAG(0x0002), Z_FLAG(0x0004), N_FLAG(0x0008), X_FLAG(0x0010), I0_FLAG(0x0100), I1_FLAG(0x0200), I2_FLAG(0x0400), S_FLAG(0x2000), T_FLAG(0x8000), D0_INDEX(0), // Register Indices A0_INDEX(8), USP_INDEX(15), SSP_INDEX(16), PC_INDEX(17), SR_INDEX(18), VBR_INDEX(19), SFC_INDEX(20), DFC_INDEX(21), EXECUTE_OK(0), // Execution return codes EXECUTE_PRIVILEGED_OK(1), EXECUTE_BUS_ERROR(2), EXECUTE_ADDRESS_ERROR(3), EXECUTE_ILLEGAL_INSTRUCTION(4), NORMAL_STATE(0), // Processor states HALT_STATE(1), STOP_STATE(2), BREAK_STATE(3) { // Create my single address space object myAddressSpaces.push_back(new AddressSpace(0x0fffffff)); // Build the decode cache if necessary if(ourDecodeCacheTable == 0) { // Allocate memory for the decode cache table ourDecodeCacheTable = new ExecutionPointer[65536]; // Set all cache entries to invalid (NULL) for(int t = 0;t < 65536; ++t) ourDecodeCacheTable[t] = 0; } // Allocate array for register values register_value = new unsigned long[myNumberOfRegisters]; // Clear the registers for(int t = 0; t < myNumberOfRegisters; ++t) register_value[t] = 0; // Reset the system Reset(); my_interrupt = -1; } /////////////////////////////////////////////////////////////////////////////// // The cpu32 Class destructor /////////////////////////////////////////////////////////////////////////////// cpu32::~cpu32() { // Free the register value array delete[] register_value; // Free the address space object delete myAddressSpaces[0]; // Free the address space vector delete &myAddressSpaces; } /////////////////////////////////////////////////////////////////////////////// // Preform a system reset /////////////////////////////////////////////////////////////////////////////// void cpu32::Reset() { unsigned int pc, ssp; // Reset all of the device's attached to the processor myAddressSpaces[0]->Reset(); // Reset the VBR SetRegister(VBR_INDEX, 0x0, LONG); // Reset DFC and SFC SetRegister(DFC_INDEX, 5, LONG); SetRegister(SFC_INDEX, 5, LONG); // Set the Status register to its reset value register_value[SR_INDEX] = S_FLAG | I0_FLAG | I1_FLAG | I2_FLAG; // Fetch the Supervisor Stack Pointer from location $00000000 if(Peek(0x00000000, ssp, LONG) != EXECUTE_OK) SetRegister(SSP_INDEX, 0, LONG); else SetRegister(SSP_INDEX, ssp, LONG); // Fetch the Program Counter from location $00000004 if(Peek(0x00000004, pc, LONG) != EXECUTE_OK) SetRegister(PC_INDEX, 0, LONG); else SetRegister(PC_INDEX, pc, LONG); // Put the processor in normal instrution execution mode myState = NORMAL_STATE; } /////////////////////////////////////////////////////////////////////////////// // Answer the value in the program counter /////////////////////////////////////////////////////////////////////////////// unsigned long cpu32::ValueOfProgramCounter() { return register_value[PC_INDEX]; } /////////////////////////////////////////////////////////////////////////////// // Build the statistics list for the StatisticalInformationList object /////////////////////////////////////////////////////////////////////////////// void cpu32::BuildStatisticalInformationList(StatisticalInformationList&) { // We're not keeping up with any stupid statistics :-} } /////////////////////////////////////////////////////////////////////////////// // Set the named register to the given value /////////////////////////////////////////////////////////////////////////////// void cpu32::SetRegister(const string& name, const string& hexValue) { for(int t = 0; t < myNumberOfRegisters; ++t) { if(name == ourRegisterData[t].name) { register_value[t] = StringToInt(hexValue) & ourRegisterData[t].mask; break; } } } /////////////////////////////////////////////////////////////////////////////// // Append all of the CPU's registers to the RegisterInformationList object /////////////////////////////////////////////////////////////////////////////// void cpu32::BuildRegisterInformationList(RegisterInformationList& lst) { for(unsigned int t = 0; t < (unsigned int)myNumberOfRegisters; ++t) { string value; if(t != SR_INDEX) value = IntToString(register_value[t] & ourRegisterData[t].mask, 8); else value = IntToString(register_value[t] & ourRegisterData[t].mask, 4); lst.Append(ourRegisterData[t].name, value, ourRegisterData[t].description); } } /////////////////////////////////////////////////////////////////////////////// // Execute the next instruction /////////////////////////////////////////////////////////////////////////////// const char* cpu32::ExecuteInstruction(string& traceRecord, bool tracing) { unsigned int opcode; int status; // Add instruction address to the trace record if(tracing) { traceRecord = "{InstructionAddress "; traceRecord += IntToString(register_value[PC_INDEX], 8); traceRecord += "} "; } // Make sure the CPU hasn't been halted if(myState != HALT_STATE) { bool serviceFlag; // Service any pending interrupts status = ServiceInterrupts(serviceFlag); // Only execute an instruction if we didn't service an interrupt if((!serviceFlag) && (status == EXECUTE_OK)) { // Make sure the CPU isn't stopped waiting for exceptions if(myState != STOP_STATE) { // Fetch the next instruction status = Peek(register_value[PC_INDEX], opcode, WORD); if(status == EXECUTE_OK) { register_value[PC_INDEX] += 2; // Execute the instruction ExecutionPointer executeMethod = DecodeInstruction(opcode); status = (this->*executeMethod)(opcode, traceRecord, tracing); // If the last instruction was not priviledged then check for trace if((status == EXECUTE_OK) && (register_value[SR_INDEX] & T_FLAG)) status = ProcessException(9); } } else { if(tracing) traceRecord += "{Mnemonic {CPU is stopped}} "; } } if(status == EXECUTE_BUS_ERROR) { if(ExecuteBusError(opcode, traceRecord, tracing) != EXECUTE_OK) { // Oh, no the cpu has fallen and it can't get up! myState = HALT_STATE; if(tracing) traceRecord += "{Mnemonic {Double Bus/Address Error CPU halted}} "; } } else if(status == EXECUTE_ADDRESS_ERROR) { if(ExecuteAddressError(opcode, traceRecord, tracing) != EXECUTE_OK) { // Now, where's that reset button??? myState = HALT_STATE; if(tracing) traceRecord += "{Mnemonic {Double Bus/Address Error CPU halted}} "; } } } else { if(tracing) traceRecord += "{Mnemonic {CPU has halted}} "; } // Check the event list - only if not in step by step execution if(!tracing) myEventHandler.Check(); // Signal if the processor is in a wierd state if(myState == HALT_STATE) { return "CPU has halted"; } else if(myState == BREAK_STATE) { myState = NORMAL_STATE; if(tracing) return 0; else return "BREAK instruction"; } else { return 0; } } /////////////////////////////////////////////////////////////////////////////// // Handle an interrupt request from a device /////////////////////////////////////////////////////////////////////////////// void cpu32::InterruptRequest(BasicDevice* device, int level) { // The 68000 has seven levels of interrupts if(level > 7) level = 7; else if(level < 1) level = 1; // Get the interrupt mask int interruptMask = (register_value[SR_INDEX] & 0x0700) >> 8; if((level > interruptMask) || (level == 7)) { my_interrupt = level; my_device = device; } else { // acknowledge with 0 to let the device know that it // is masked. device->InterruptAcknowledge(0); } } /////////////////////////////////////////////////////////////////////////////// // Service pending interrupts, serviceFlag set true iff something serviced /////////////////////////////////////////////////////////////////////////////// int cpu32::ServiceInterrupts(bool& serviceFlag) { if(my_interrupt != -1) { // Indicate that I had to service an interrupt serviceFlag = true; int level = my_interrupt; int status; my_interrupt = -1; // Put the processor into normal state if it's stopped if(myState == STOP_STATE) myState = NORMAL_STATE; // Copy the SR to a temp unsigned long tmp_sr = register_value[SR_INDEX]; // Set the Interrupt Mask in SR register_value[SR_INDEX] &= 0x0000f8ff; register_value[SR_INDEX] |= (level << 8); // Change to Supervisor mode and clear the Trace mode register_value[SR_INDEX] |= S_FLAG; register_value[SR_INDEX] &= ~T_FLAG; // Interrupt has occured so push the PC and the SR SetRegister(SSP_INDEX, register_value[SSP_INDEX]-4, LONG); status = Poke(register_value[SSP_INDEX], register_value[PC_INDEX], LONG); if(status != EXECUTE_OK) return status; SetRegister(SSP_INDEX, register_value[SSP_INDEX]-2, LONG); status = Poke(register_value[SSP_INDEX], tmp_sr, WORD); if(status != EXECUTE_OK) return status; // Get the vector number long vector = my_device->InterruptAcknowledge(level); if(vector == AUTOVECTOR_INTERRUPT) vector = 24 + level; else if(vector == SPURIOUS_INTERRUPT) vector = 24; // Get the interrupt service routine's address unsigned int service_address; status = Peek(vector * 4, service_address , LONG); if(status != EXECUTE_OK) return(status); // Change the program counter to the service routine's address SetRegister(PC_INDEX, service_address, LONG); } else { // Indicate that I didn't have to service an interrupt serviceFlag = false; } return EXECUTE_OK; }