/// <summary> /// Read OpCode Parameter value. /// /// BBBBBB AAAAAA 0000 /// /// Will decode either A or B (based on what is given in _opParam) and /// populate data into a readParamValue struct. /// /// The PC register is automatically incremented based on what needs to be read. /// </summary> /// <param name="_opParam"></param> /// <returns></returns> private readParamValue ReadParamValue(ushort _opParam) { readParamValue result = new readParamValue(); switch (_opParam) { // read Value in register case (ushort)dcpuRegisterCodes.A: case (ushort)dcpuRegisterCodes.B: case (ushort)dcpuRegisterCodes.C: case (ushort)dcpuRegisterCodes.X: case (ushort)dcpuRegisterCodes.Y: case (ushort)dcpuRegisterCodes.Z: case (ushort)dcpuRegisterCodes.I: case (ushort)dcpuRegisterCodes.J: result.ParmType = ParamType.Register; result.Location = _opParam; result.Value = m_registers.GP[result.Location]; break; // read value at memory location where register is pointing too case (ushort)dcpuRegisterCodes.A_Mem: case (ushort)dcpuRegisterCodes.B_Mem: case (ushort)dcpuRegisterCodes.C_Mem: case (ushort)dcpuRegisterCodes.X_Mem: case (ushort)dcpuRegisterCodes.Y_Mem: case (ushort)dcpuRegisterCodes.Z_Mem: case (ushort)dcpuRegisterCodes.I_Mem: case (ushort)dcpuRegisterCodes.J_Mem: result.ParmType = ParamType.Memory; result.Location = m_registers.GP[_opParam - (ushort)dcpuRegisterCodes.A_Mem]; result.Value = m_memory.RAM[result.Location]; m_cycles++; break; case (ushort)dcpuRegisterCodes.A_NextWord: case (ushort)dcpuRegisterCodes.B_NextWord: case (ushort)dcpuRegisterCodes.C_NextWord: case (ushort)dcpuRegisterCodes.X_NextWord: case (ushort)dcpuRegisterCodes.Y_NextWord: case (ushort)dcpuRegisterCodes.Z_NextWord: case (ushort)dcpuRegisterCodes.I_NextWord: case (ushort)dcpuRegisterCodes.J_NextWord: result.ParmType = ParamType.Memory; result.Location = (ushort)(m_registers.GP[_opParam - (ushort)dcpuRegisterCodes.A_NextWord] + ReadNextWord()); result.Value = m_memory.RAM[result.Location]; m_cycles += 2; // we read 2 words so this must cost 2 cycles. break; case (ushort)dcpuRegisterCodes.POP: if (m_ignoreNextInstruction != true) { result.ParmType = ParamType.Memory; result.Location = m_registers.SP++; result.Value = m_memory.RAM[result.Location]; } m_cycles++; break; case (ushort)dcpuRegisterCodes.PEEK: result.ParmType = ParamType.Memory; result.Location = m_registers.SP; result.Value = m_memory.RAM[result.Location]; m_cycles++; break; case (ushort)dcpuRegisterCodes.PUSH: if (m_ignoreNextInstruction != true) { result.ParmType = ParamType.Memory; result.Location = --m_registers.SP; result.Value = m_memory.RAM[result.Location]; } m_cycles++; break; case (ushort)dcpuRegisterCodes.O: result.ParmType = ParamType.Register; result.Location = _opParam; result.Value = m_registers.O; break; case (ushort)dcpuRegisterCodes.PC: result.ParmType = ParamType.Register; result.Location = _opParam; result.Value = m_registers.PC; break; case (ushort)dcpuRegisterCodes.SP: result.ParmType = ParamType.Register; result.Location = _opParam; result.Value = m_registers.SP; break; case (ushort)dcpuRegisterCodes.NextWord_Literal_Mem: result.ParmType = ParamType.Memory; result.Location = ReadNextWord(); result.Value = m_memory.RAM[result.Location]; m_cycles += 2; // we read 2 words so this must cost 2 cycles. break; /* * DensitY here once again :) * * We're going todo something special with the result * basically someone might do something like this * SET 0x8000, I * when they mean * SET [0x8000], I * So in case we do that, we'll handle it. * * SAYING THAT! * SET I, 0x8000 * and * SET I, [0x8000] * Will work properly! (first putting 0x8000 into the register I, second reading data from the memory location 0x8000 into register I) * * ---------------------------------------------------------------------------------- * UPDATE: DensitY 11th April 2012 * From Notch's Bible * "If any instruction tries to assign a literal value, the assignment fails silently. Other than that, the instruction behaves as normal." * Basically what I decided on doing above was against Notch's spec, so I'm taking it out. * --------------------------------------------------------------------------------- */ case (ushort)dcpuRegisterCodes.NextWord_Literal_Value: result.ParmType = ParamType.Literal; result.Location = ReadNextWord(); result.Value = result.Location; m_cycles++; break; default: break; } // Special Case for literal Values that are stored in the byte's param and not next word. used for values < 0x1F. if (_opParam >= 0x20 && _opParam <= 0x3F) { result.ParmType = ParamType.Literal; result.Location = (ushort)(_opParam - 0x20); result.Value = result.Location; // cycle free! } return result; }
/// <summary> /// Stores Read param values back into RAM or Registers. /// This is normally called after resolving a OpCode instruction in /// ExecuteInstruction(). /// </summary> /// <param name="_resultValue">read param value</param> private void SetResultValue(readParamValue _resultValue) { if (_resultValue.ParmType == ParamType.Memory) { // write to memory location m_memory.RAM[_resultValue.Location] = _resultValue.Value; /** * Notch's spec doesn't say anything (that I can find) regarding cost of write backs. So I'm assuming * they are the same as reads. Meaning registers are free, Memory/word writebacks cost 1 cycle */ m_cycles++; } else if (_resultValue.ParmType == ParamType.Register) { // Write to respective register switch (_resultValue.Location) { case (ushort)dcpuRegisterCodes.A: case (ushort)dcpuRegisterCodes.B: case (ushort)dcpuRegisterCodes.C: case (ushort)dcpuRegisterCodes.X: case (ushort)dcpuRegisterCodes.Y: case (ushort)dcpuRegisterCodes.Z: case (ushort)dcpuRegisterCodes.I: case (ushort)dcpuRegisterCodes.J: m_registers.GP[_resultValue.Location] = _resultValue.Value; break; case (ushort)dcpuRegisterCodes.PC: // program Counter m_registers.PC = _resultValue.Value; break; case (ushort)dcpuRegisterCodes.SP: // stack pointer m_registers.SP = _resultValue.Value; break; case (ushort)dcpuRegisterCodes.O: // overflow reigster m_registers.O = _resultValue.Value; break; default: break; } } // ignore literal assignment as per Notch's spec }