Exemplo n.º 1
0
        public void emulateCycle()
        {
            if (m_Interrupt != InterruptSignal.None)
            {
                m_State = CPUState.interrupt;
            }

            switch (m_State)
            {
            case CPUState.fetchopcode:
                m_PC_Start         = m_PC;
                m_Cycle            = 1;
                m_ExtraCycles      = false;
                m_byteDisplacement = 0;

                m_OpCodePrefix = 0;
                m_OpCodeIndex  = getNextMemByte();
                m_oc           = m_OpCodes[m_OpCodeIndex];

                int iIndexOffset = 0;

                if (m_OpCodeIndex == 0xCB ||       // evaluate prefix
                    m_OpCodeIndex == 0xDD ||
                    m_OpCodeIndex == 0xED ||
                    m_OpCodeIndex == 0xFD)
                {
                    m_OpCodePrefix = m_OpCodeIndex;
                    iIndexOffset   = m_dictOpCodePrefix[m_OpCodePrefix];
                    m_OpCodeIndex  = getNextMemByte();

                    if (m_OpCodeIndex == 0xCB)    // DD CB or FD CB combination
                    {
                        m_OpCodePrefix   <<= 8;
                        m_OpCodePrefix    |= m_OpCodeIndex;
                        iIndexOffset       = m_dictOpCodePrefix[m_OpCodePrefix];
                        m_byteDisplacement = getNextMemByte();     // contains displacement before OpCode
                        m_OpCodeIndex      = getNextMemByte();
                    }

                    m_oc = m_OpCodes[iIndexOffset + m_OpCodeIndex];
                }

                // check if OpCode is defined
                if (String.IsNullOrEmpty(m_oc.OpCode) || m_oc.executeOperation == null)
                {
                    string sMessage;
                    if (m_OpCodePrefix > 0)
                    {
                        sMessage = String.Format("PC {0:X4} : OpCode {1:X2} {2:X2} unknown!!!",
                                                 m_PC_Start, (byte)m_OpCodePrefix, (byte)m_OpCodeIndex);
                    }
                    else
                    {
                        sMessage = String.Format("PC {0:X4} : OpCode {1:X2} unknown!!!",
                                                 m_PC_Start, (byte)m_OpCodeIndex);
                    }
                    throw new NotImplementedException(sMessage);
                }

#if CPU_TRACE
                m_ei.Counter++;
                m_ei.PC    = m_PC_Start;
                m_ei.Bytes = "";
                if (m_OpCodePrefix != 0)
                {
                    m_ei.Bytes += String.Format("{0:X2} ", m_OpCodePrefix);
                }
                m_ei.Bytes += String.Format("{0:X2} ", m_OpCodeIndex);
                m_ei.OpCode = m_oc.OpCode;
                m_ei.Op1    = "";
                m_ei.Op2    = "";
#endif
                // increase R register (only bits 6-0)
                m_reg_R = (byte)((m_reg_R & 0x80) | ((m_reg_R + 1) & 0x7F));

                // set for next processing state
                m_wordValue = 0;
                m_byteValue = 0;
#if NO_CYCLE_FILLUP
                m_MaxCycles = m_PC - m_PC_Start;
#else
                m_MaxCycles = m_oc.Cycles;
#endif
                m_State = CPUState.addressing;
                break;

            case CPUState.interrupt:     // interrupt
                switch (m_Interrupt)
                {
                case InterruptSignal.NMI:
                    // perform a RST 66h
                    m_reg_SP -= 2;;
                    writeMemWord(m_reg_SP, m_PC);
                    m_PC        = 0x0066;
                    m_State     = CPUState.fetchopcode;
                    m_Interrupt = InterruptSignal.None;
                    break;

                case InterruptSignal.IRQ:
                    switch (m_IM)
                    {
                    case 0:
                        // TODO Z80 implement IM 0
                        throw new NotImplementedException("Z80 IM 0 not implemented!");

                    case 1:             // IM 1 - perform a RST 38h
                        m_reg_SP -= 2;;
                        writeMemWord(m_reg_SP, m_PC);
                        m_PC        = 0x0038;
                        m_State     = CPUState.fetchopcode;
                        m_Interrupt = InterruptSignal.None;
                        break;

                    case 2:             // IM 2 - jump to interrupt vector
                        m_reg_SP -= 2;;
                        writeMemWord(m_reg_SP, m_PC);
                        m_PC        = m_reg_I;
                        m_State     = CPUState.fetchopcode;
                        m_Interrupt = InterruptSignal.None;
                        break;
                    }
                    break;
                }
                break;

            case CPUState.addressing:     // addressing
                m_Cycle++;
                m_oc.executeAddressing();

                break;

            case CPUState.operation:
                if (m_Cycle >= m_MaxCycles)     // emulate cycle exactness by making operation effective on last cycle
                {
                    m_oc.executeOperation();
                    if (m_Cycle < m_MaxCycles)
                    {
                        m_Cycle++;     // operation executed induced another cycle (e.g. branch operations)
                    }
                    else
                    {
                        m_State = CPUState.fetchopcode;      // operation finished -> get next opcode
                    }
#if CPU_TRACE
                    //if (m_PC_Start == 0x188) { m_TraceActive = true; m_ei.Counter = 1; }
                    //if (m_PC_Start == 0x18B) m_TraceActive = false;

                    if (m_State == CPUState.fetchopcode && m_TraceActive)
                    {
                        StringBuilder sb = new StringBuilder();

                        if ((m_ei.Counter % 20) == 1)
                        {
                            sb.Clear();
                            sb.Append("PC-- ");
                            sb.Append("----------- OpCo Op1,Op2---|");
                            sb.Append("A  F  B  C  D  E  H  L  ");
                            //sb.Append("A' F' B' C' D' E' H' L' ");
                            sb.Append("IX   IY   SP   I  R  |");
                            sb.Append("SZ5H3vNC|");
                            sb.Append("Disassembly Check---|");
                            sb.Append("STACK ---------------");
                            Debug.WriteLine(sb.ToString());
                        }
                        sb.Clear();
                        sb.AppendFormat("{0:X4} ", m_ei.PC);
                        sb.Append(m_ei.Bytes.PadRight(12));
                        sb.Append(m_ei.OpCode.PadRight(5));
                        if (!String.IsNullOrEmpty(m_ei.Op1) && !String.IsNullOrEmpty(m_ei.Op2))
                        {
                            sb.Append((m_ei.Op1 + "," + m_ei.Op2).PadRight(10));
                        }
                        else
                        {
                            sb.Append((m_ei.Op1 + m_ei.Op2).PadRight(10));
                        }
                        sb.Append("|");

                        sb.AppendFormat("{0:X2} ", m_reg_A);
                        sb.AppendFormat("{0:X2} ", Flags);
                        sb.AppendFormat("{0:X2} ", m_reg_B);
                        sb.AppendFormat("{0:X2} ", m_reg_C);
                        sb.AppendFormat("{0:X2} ", m_reg_D);
                        sb.AppendFormat("{0:X2} ", m_reg_E);
                        sb.AppendFormat("{0:X2} ", m_reg_H);
                        sb.AppendFormat("{0:X2} ", m_reg_L);

                        //sb.AppendFormat("{0:X2} ", m_reg_A_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_Flags_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_B_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_C_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_D_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_E_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_H_Alt);
                        //sb.AppendFormat("{0:X2} ", m_reg_L_Alt);

                        sb.AppendFormat("{0:X4} ", m_reg_IX);
                        sb.AppendFormat("{0:X4} ", m_reg_IY);
                        sb.AppendFormat("{0:X4} ", m_reg_SP);
                        sb.AppendFormat("{0:X2} ", m_reg_I);
                        sb.AppendFormat("{0:X2} ", m_reg_R);
                        sb.Append("|");

                        sb.Append(Convert.ToString(Flags, 2).PadLeft(8, '0'));
                        sb.Append("|");

                        string strDisassemblyCheck = m_dis.Disassemble(() => readMemByte(m_ei.PC++));
                        sb.Append(strDisassemblyCheck.PadRight(20));
                        sb.Append("|");

                        for (int spDump = m_reg_SP; spDump <= m_reg_SP + 5; spDump++)
                        {
                            sb.AppendFormat("{0:X2} ", readMemByte((UInt16)spDump));
                        }

                        Debug.WriteLine(sb.ToString());
                        sb = null;
                    }
#endif
                }
                else
                {
                    m_Cycle++;
                }
                break;
            }
        }
Exemplo n.º 2
0
        public void emulateCycle()
        {
            switch (m_State)
            {
            case CPUState.fetchopcode:

                // check and process Interrupt (only when in OpCode fetch)
                if (m_Interrupt)
                {
                    m_MaxCycles    = 7;
                    m_Cycle        = 1;
                    m_address      = 0;
                    m_addr         = Addressing._not_set_;
                    m_OperandValue = 0;
                    m_State        = CPUState.interrupt;
                    break;
                }

                // save current PC for debugging / tracing
                m_PC_Start = m_PC;

                // get the next byte and then move the program counter forward
                byte opCode = getNextMemByte();


                // get from OpCode table
                m_oc = m_OpCodes[opCode];

                // check if OpCode is defined
                if (String.IsNullOrEmpty(m_oc.OpCode) || m_oc.executeOperation == null || m_oc.executeAddressing == null)
                {
                    string sMessage = String.Format("PC {0:X4} : OpCode {1:X2} unknown!!!", m_PC_Start, opCode);
                    throw new NotImplementedException(sMessage);
                }

#if CPU_TRACE
                m_sbDebug = new StringBuilder();
                m_sbDebug.AppendFormat("{0:X4}:{1:X2} {2} ", m_PC_Start, opCode, m_oc.OpCode);
#endif

                m_MaxCycles    = m_oc.Cycles;
                m_Cycle        = 1;
                m_address      = 0;
                m_addr         = Addressing._not_set_;
                m_OperandValue = 0;
                m_State        = CPUState.addressing;

                break;

            case CPUState.addressing:     // addressing
                m_oc.executeAddressing();
                m_Cycle++;

                break;

            case CPUState.operation:
                if (m_Cycle == m_MaxCycles)     // emulate cycle exactness by making operation effective on last cycle
                {
                    m_oc.executeOperation();
                    if (m_Cycle < m_MaxCycles)
                    {
                        m_Cycle++;     // operation executed induced another cycle (e.g. branch operations)
                    }
                    else
                    {
                        m_State = CPUState.fetchopcode;      // operation finished -> get next opcode
#if CPU_TRACE
                        m_sbDebug.AppendFormat("\tPC:{0:X4} A:{1:X2} X:{2:X2} Y:{3:X2} SP:{4:X4} |{5}| STACK: {6:X2} {7:X2} {8:X2} {9:X2}",
                                               m_PC,
                                               m_reg_A,
                                               m_reg_X,
                                               m_reg_Y,
                                               Reg_SP,
                                               StatusString,
                                               m_ram[m_StackPtr - m_ramOffset],
                                               m_ram[m_StackPtr + 1 - m_ramOffset],
                                               m_ram[m_StackPtr + 2 - m_ramOffset],
                                               m_ram[m_StackPtr + 3 - m_ramOffset]);

                        Debug.WriteLine(m_sbDebug.ToString());
#endif
                    }
                }
                else
                {
                    m_Cycle++;
                }

                break;

            case CPUState.interrupt:
                if (m_Cycle == m_MaxCycles)     // emulate cycle exactness by making operation effective on last cycle
                {
                    push_stack((byte)(m_PC >> 8));
                    push_stack((byte)m_PC);
                    push_stack(m_reg_SR);
                    Flag_I      = true;
                    m_PC        = readMemWord(0xFFFE); // fetch IRQ vector
                    m_State     = CPUState.fetchopcode;
                    m_Interrupt = false;
                }
                else
                {
                    m_Cycle++;
                }
                break;
            }
        }