Exemplo n.º 1
0
 public NTPUCPU(uint ram_size, ushort[] rom)
 {
     _memory           = new ushort[ram_size];
     _rom              = rom;
     _registers        = new ushort[8]; // PC stored seperately.
     _pc               = 0x0000;
     _interrupt_enable = false;
     _pt_enable        = false;
     _sys_curr_mode    = NTPUMode.System;
     Halted            = false;
     _active_interrupt = 0;
     _flag_neg         = false;
     _flag_zero        = false;
     _flag_carry       = false;
     _flag_overflow    = false;
     _last_reset_addr  = 0;
     _interrupt_stack  = 0;
 }
Exemplo n.º 2
0
        public void ExecuteInstruction()
        {
            var instr = ReadMemoryPaged(_pc);

            if (instr == 0x0000)
            {
                Halted = true;
                return;
            }
            byte opcode = (byte)(instr & 0xFF);
            byte upbyte = (byte)((instr & 0xFF00) >> 8);

            Console.WriteLine("Executing instr {0:X4}", instr);
            byte src               = (byte)((instr & 0x700) >> 8);
            byte ctrl              = (byte)((instr & 0x1800) >> 11);
            byte r7offs            = (byte)((instr & 0xF000) >> 12);
            byte dest              = (byte)((instr & 0xE000) >> 13);
            bool standard_encode_1 = false;
            bool standard_encode_2 = false;
            bool calc_flags        = true;
            bool do_pc_increment   = true;

            Console.WriteLine("Dest: {0:x1}, ctrl: {1:x1}, r7offs: {2:x1}, src: {3:x1}", dest, ctrl, r7offs, src);
            // Ew. handles if an instr should use the normal load/store setup.
            switch (opcode)
            {
            case byte n when(n <= 0x20 && ((n & 0x01) == 0)):
                standard_encode_1 = true;

                break;

            case byte n when(n <= 0x20 && ((n & 0x01) == 1)):
                standard_encode_2 = true;

                break;

            case 0xFC:     // Jcc Rn
            case 0xFD:     // Jcc imm
            case 0xFE:     // rst vector
            case 0xFF:     // hlt code
                // neither of the normal encodes.
                break;
            }

            ushort src_val;
            ushort dest_val;
            ushort dest_write = 0;
            ushort imm        = 0; // Yes, globalizing this is nasty. But it removes

            // prevents a spurious memory read that shouldn't
            // occur
            if (standard_encode_1)
            {
                dest_val = _registers[dest];
                if (ctrl == 0)
                {
                    src_val = _registers[src];
                }
                else if (ctrl == 2)
                {
                    var addr = _registers[src];
                    src_val = ReadMemoryPaged(addr);
                }
                else
                {
                    var addr = (ushort)(_registers[7] + (ushort)SextR7Offs(r7offs));
                    src_val = ReadMemoryPaged(addr);
                }
            }
            else if (standard_encode_2)
            {
                if (ctrl == 0)
                {
                    // Immediate modes
                    imm  = ReadMemoryPaged((ushort)(_pc + 1));
                    _pc += 1;
                    switch (src)
                    {
                    case 0:
                        dest_val = _registers[dest];
                        src_val  = imm;
                        break;

                    case 1:
                        src_val  = ReadMemoryPaged(imm);
                        dest_val = _registers[dest];
                        break;

                    case 2:
                        src_val  = _registers[dest];    // swap mode.
                        dest_val = ReadMemoryPaged(imm);
                        break;

                    default:
                        _active_interrupt = 1;     // Invalid instr
                        return;
                    }
                }
                else
                {
                    src_val = _registers[src];
                    if (ctrl == 1)
                    {
                        dest_val = ReadMemoryPaged(_registers[dest]);
                    }
                    else
                    {
                        var addr = (ushort)(_registers[7] + (ushort)SextR7Offs(r7offs));
                        dest_val = ReadMemoryPaged(addr);
                    }
                }
            }
            else
            {
                src_val  = 0;
                dest_val = 0;
            }

            switch (opcode)
            {
            case 0x00:
            case 0x01:
                calc_flags = false;
                dest_write = src_val;
                break;

            case 0x02:
            case 0x03:
                InstrAdd(src_val, dest_val, out dest_write);
                break;

            case 0x04:
            case 0x05:
                InstrSub(src_val, dest_val, out dest_write);
                break;

            case 0x06:
            case 0x07:
                InstrAnd(src_val, dest_val, out dest_write);
                break;

            case 0x08:
            case 0x09:
                InstrOr(src_val, dest_val, out dest_write);
                break;

            case 0x0A:
            case 0x0B:
                InstrXor(src_val, dest_val, out dest_write);
                break;

            case 0x0C:
            case 0x0D:
                InstrShl(src_val, dest_val, out dest_write);
                break;

            case 0x0E:
            case 0x0F:
                InstrShr(src_val, dest_val, out dest_write);
                break;

            case 0x14:
            case 0x15:
                InstrCmp(src_val, dest_val, out dest_write);
                break;

            case 0x16:
            case 0x17:
                InstrTst(src_val, dest_val, out dest_write);
                break;

            case 0xF8:
                do_pc_increment = false;
                calc_flags      = false;
                InstrCall(dest);
                break;

            case 0xF9:
                do_pc_increment = false;
                calc_flags      = false;
                InstrRet(dest);
                break;

            case 0xFA:
            case 0xFB:
                InstrLdpr(instr);
                calc_flags = false;
                break;

            case 0xFC:
            case 0xFD:
                do_pc_increment = false;
                InstrJCC(opcode, upbyte, src);
                calc_flags = false;
                break;

            case 0xFF:
                if (_sys_curr_mode == NTPUMode.User)
                {
                    goto case 0xFE;     //would be fallthrough, but C#.
                }
                calc_flags            = false;
                Halted                = true;
                do_pc_increment       = false;
                _last_reset_addr      = CalculateFullAddress(_pc, (_sys_curr_mode == NTPUMode.System) ? _sys_page_table_r : _user_page_table_r);
                _last_reset_addr_virt = _pc;
                break;

            case 0xFE:
                calc_flags            = false;
                do_pc_increment       = false;
                _last_reset_addr      = CalculateFullAddress(_pc, (_sys_curr_mode == NTPUMode.System) ? _sys_page_table_r : _user_page_table_r);
                _last_reset_addr_virt = _pc;
                if (_sys_curr_mode == NTPUMode.User)
                {
                    _sys_curr_mode = NTPUMode.System;

                    _pc = _syscall_entry;     // Go to wherever the system says to.
                }
                else
                {
                    _pc               = 0;
                    _pt_enable        = false;
                    _interrupt_enable = false;
                }
                break;

            default:
                break;
            }

            if (standard_encode_1)
            {
                _registers[dest] = dest_write;
            }
            else if (standard_encode_2)
            {
                if (ctrl == 0)
                {
                    switch (src)
                    {
                    case 0:     // LD_1
                    case 1:
                        _registers[dest] = dest_write;
                        break;

                    case 2:
                        WriteMemoryPaged(imm, dest_write);
                        break;
                    }
                }
                else if (ctrl == 1)
                {
                    WriteMemoryPaged(_registers[dest], dest_write);
                }
                else
                {
                    var addr = (ushort)(_registers[7] + (ushort)SextR7Offs(r7offs));
                    WriteMemoryPaged(addr, dest_write);
                }
            }

            if (calc_flags)
            {
                _flag_zero |= dest_write == 0;
                _flag_neg  |= dest_write >= 0x7FFF;
            }

            if (do_pc_increment)
            {
                _pc += 1;
            }
            if (_pc > 513)
            {
                Halted = true;
            }
        }