Beispiel #1
0
 private void LogInstructionToDebugger(S8Instruction instr)
 {
     if (VerboseMode)
     {
         var regs = GetChangedRegs();
         if (!string.IsNullOrEmpty(regs))
         {
             LogMessage(regs);
         }
         instr.DecodeInstruction();
         LogMessage(instr.Instruction2Text(state.pc, true));
         prevRegs = (byte[])state.regs.Clone();
     }
 }
Beispiel #2
0
        public UInt16 Dissasemble(UInt16 start, UInt16 length, bool showAddress = false, bool allowOutsideLoadedMemory = false)
        {
            S8Instruction s8i;

            UInt16 currentAddress = start;
            UInt16 endAddress     = (UInt16)(currentAddress + length);

            // Special - if no length givien, assume 20 instructions
            if (length == 0)
            {
                endAddress = (UInt16)(currentAddress + 20);
                //endAddress = cpu.state.memoryUsed;
            }

            if (!allowOutsideLoadedMemory)
            {
                if (endAddress > cpu.state.memoryUsed)
                {
                    endAddress = cpu.state.memoryUsed;
                }
            }

            // Dont read outside physical memory
            if (endAddress > bytes.Length)
            {
                endAddress = (UInt16)(bytes.Length - 1);
            }


            while (currentAddress < endAddress)
            {
                int lineAddress = currentAddress;

                byte opcode = bytes[currentAddress++];
                byte param  = bytes[currentAddress++];

                s8i = new S8Instruction(opcode, param);
                s8i.DecodeInstruction();


                LogMessage(s8i.Instruction2Text(lineAddress, showAddress));
            }
            return(currentAddress);
        }
Beispiel #3
0
        public bool ExecuteInstruction(S8Instruction instr)
        {
            LogInstructionToDebugger(instr);

            // STOPP
            if (instr.operationClass == 0x0)
            {
                return(false);
            }

            // increase counter if we do anything else than STOPP
            state.pc += 2;


            // SETT
            if (instr.operationClass == 0x1)
            {
                state.regs[instr.operation] = (byte)instr.value;
            }
            else if (instr.operationClass == 0x2)
            {
                state.regs[instr.operation] = state.regs[instr.argument1];
            }
            // FINN
            else if (instr.operationClass == 0x3)
            {
                state.regs[1] = (byte)((instr.address & 0x0f00) >> 8);
                state.regs[0] = (byte)(instr.address & 0xff);
            }

            // LOAD / STORE
            else if (instr.operationClass == 0x4)
            {
                int addr = ((state.regs[1] << 8) | state.regs[0]) & 0xfff;
                switch (instr.operation)
                {
                case 0:     // LAST
                    state.regs[instr.argument1] = state.memory[addr];
                    break;

                case 1:     //LAGR
                    state.memory[addr] = (byte)state.regs[instr.argument1];
                    break;

#if _EXPERIMENTAL_
                case 2:     //VLAST
                    state.regs[instr.argument1] = this.HWDisplay.Memory[GetFrameBufferAddress()];
                    break;

                case 3:     //VLAGR
                    UInt16 hwaddr = GetFrameBufferAddress();
                    this.HWDisplay.Write(hwaddr, (byte)state.regs[instr.argument1]);
                    break;
#endif
                default:
                    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                    return(false);
                }
            }

            // ALU
            else if (instr.operationClass == 0x5)
            {
                byte reg1 = state.regs[instr.argument1];
                byte reg2 = state.regs[instr.argument2];

                if (instr.operation == 0x0)
                {
                    state.regs[instr.argument1] &= reg2;
                }
                else if (instr.operation == 0x1)
                {
                    state.regs[instr.argument1] |= reg2;
                }
                else if (instr.operation == 0x2)
                {
                    state.regs[instr.argument1] ^= reg2;
                }
                else if (instr.operation == 0x3)
                {
                    state.regs[instr.argument1] = (byte)((reg1 << reg2) & 0xff);
                }
                else if (instr.operation == 0x4)
                {
                    state.regs[instr.argument1] >>= reg2;
                }
                else if (instr.operation == 0x5)
                {
                    state.regs[instr.argument1] = (byte)((reg1 + reg2) & 0xff);
                }
                else if (instr.operation == 0x6)
                {
                    state.regs[instr.argument1] = (byte)((reg1 - reg2) & 0xff);
                }
                else
                {
                    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                    return(false);
                }
            }

            // I/O
            else if (instr.operationClass == 0x6)
            {
                switch (instr.operation)
                {
                case 0x0:     // LES
                    if (state.stdin.Length > state.inputPtr)
                    {
                        state.regs[instr.argument1] = state.stdin[state.inputPtr++];
                    }
                    else
                    {
                        LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.readAfterEndOfInput]);
                        return(false);
                    }

                    break;

                case 0x01:     // SKRIV
                {
                    // This limit broke the runner for the NPST 2021 day 7.

                    // It was put in as a security measure, but it created just pain :-(
                    // Removed!!!
                    //if (state.outputStream.Length > 1000)
                    //{
                    //    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                    //    return false;
                    //}

                    byte val = state.regs[instr.argument1];
                    //state.stdout += val.ToString("X2");

                    state.outputStream.Seek(0, SeekOrigin.End);
                    state.outputStream.WriteByte(val);
                }
                break;

#if _EXPERIMENTAL_
                case 0x02:     //INN
                    state.regs[instr.argument1] = this.HWIO.ReadIO(GetIOAddress());
                    break;

                case 0x03:     //UT
                    this.HWIO.WriteIO(GetIOAddress(), state.regs[instr.argument1]);
                    break;

                case 0x04:     //VSYNK
                    this.HWDisplay.VSync();
                    break;
#endif
                default:
                {
                    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                    return(false);
                }
                }
            }
            // CMP
            else if (instr.operationClass == 0x7)
            {
                byte reg1 = state.regs[instr.argument1];
                byte reg2 = state.regs[instr.argument2];

                if (instr.operation == 0x0)
                {
                    state.flag = reg1 == reg2;
                }
                else if (instr.operation == 0x1)
                {
                    state.flag = reg1 != reg2;
                }
                else if (instr.operation == 0x2)
                {
                    state.flag = reg1 < reg2;
                }
                else if (instr.operation == 0x3)
                {
                    state.flag = reg1 <= reg2;
                }
                else if (instr.operation == 0x4)
                {
                    state.flag = reg1 > reg2;
                }
                else if (instr.operation == 0x5)
                {
                    state.flag = reg1 >= reg2;
                }
                else
                {
                    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                    return(false);
                }
            }

            // JMP
            else if (instr.operationClass == 0x8)
            {
                state.pc = instr.address;
            }
            // COND JMP
            else if (instr.operationClass == 0x9)
            {
                if (state.flag)
                {
                    state.pc = instr.address;
                }
            }

            // CALL
            else if (instr.operationClass == 0xa)
            {
                if (!stack.Push(state.pc))
                {
                    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.recursionLimitExceeded]);
                    return(false);
                }
                state.pc = instr.address;
            }

            // RET
            else if (instr.operationClass == 0xb)
            {
                state.pc = stack.Pop();
                if (state.pc < 0)
                {
                    state.pc = 0;
                    LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                    return(false);
                }
            }
            else if (instr.operationClass == 0xc)
            {
                // No Op.. Do nothing
            }
            else
            {
                LogMessage(ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.segmentationFault]);
                return(false);
            }


            return(true);
        }
Beispiel #4
0
        /// <summary>
        /// Run the code "runSteps" number of cpu steps.
        /// </summary>
        /// <param name="runSteps">Number of CPU steps to run. 0 means no limit, runs until STOPP or crash</param>
        /// <param name="verbose"></param>
        /// <param name="showaddress"></param>
        /// <returns></returns>
        public bool RunSteps(int runSteps)
        {
            int stepsLeft = 1;// Default 1 step left

            if (runSteps > 0)
            {
                stepsLeft = runSteps;
            }


            if (state.memoryUsed == 0)
            {
                LogMessage("No s8 program loaded");
                return(false);
            }

            if (state.memoryUsed == 0)
            {
                return(false);
            }

            while ((stepsLeft > 0) && (!state.crashed))
            {
                // if there is a limit of how many steps we can run, reduce the steps left
                if (runSteps > 0)
                {
                    stepsLeft--;
                }


                if (++state.tick > state.maxTicks)
                {
                    var strErr = ERROR_MESSAGE[(int)ERROR_MESSAGE_ID.resourcesExhausted].Replace("${maxTicks}", state.tick.ToString());
                    LogMessage(strErr);
                    return(false);
                }


                byte opcode = state.memory[state.pc];
                byte param  = state.memory[state.pc + 1];
                //yield { pc, flag, regs, memory, stdout, inputPtr };

                S8Instruction s8 = new S8Instruction(opcode, param);

                if (!ExecuteInstruction(s8))
                {
                    state.crashed = true;
                }

                // After each step in the CPU tell anyone listening to events about the step. Used to update UI
                CpuStepInfo(state.pc);

                if (state.breakpoints[state.pc])
                {
                    return(true);
                }
            }

            if (state.crashed)
            {
                return(false);
            }
            return(true);
        }