Esempio n. 1
0
        public Micron_MT25Q(MappedMemory underlyingMemory)
        {
            // original MT25Q supports capacity 8MB to 256MB,
            // but we extended it down to 64KB
            // to become compatible with N25Q line
            if (underlyingMemory.Size < 64.KB() || underlyingMemory.Size > 256.MB() || !Misc.IsPowerOfTwo((ulong)underlyingMemory.Size))
            {
                throw new ConstructionException("Size of the underlying memory must be a power of 2 value in range 64KB - 256MB");
            }

            volatileConfigurationRegister         = new ByteRegister(this, 0xfb).WithFlag(3, name: "XIP");
            nonVolatileConfigurationRegister      = new WordRegister(this, 0xffff).WithFlag(0, out numberOfAddressBytes, name: "addressWith3Bytes");
            enhancedVolatileConfigurationRegister = new ByteRegister(this, 0xff)
                                                    .WithValueField(0, 3, name: "Output driver strength")
                                                    .WithReservedBits(3, 1)
                                                    .WithTaggedFlag("Reset/hold", 4)
                                                    //these flags are intentionally not implemented, as they described physical details
                                                    .WithFlag(5, name: "Double transfer rate protocol")
                                                    .WithFlag(6, name: "Dual I/O protocol")
                                                    .WithFlag(7, name: "Quad I/O protocol");
            statusRegister     = new ByteRegister(this).WithFlag(1, out enable, name: "volatileControlBit");
            flagStatusRegister = new ByteRegister(this)
                                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => numberOfAddressBytes.Value, name: "Addressing")
                                 //other bits indicate either protection errors (not implemented) or pending operations (they already finished)
                                 .WithReservedBits(3, 1)
                                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true, name: "ProgramOrErase");

            this.underlyingMemory      = underlyingMemory;
            underlyingMemory.ResetByte = EmptySegment;

            deviceData = GetDeviceData();
        }
Esempio n. 2
0
 private void SetRegister(ByteRegister register, byte value)
 {
     if (register != ByteRegister.None)
     {
         _registers[(int)register] = value;
     }
 }
 public Micron_MT25Q(MicronFlashSize size, Endianess dataEndianess = Endianess.LittleEndian)
 {
     if (!Enum.IsDefined(typeof(MicronFlashSize), size))
     {
         throw new ConstructionException($"Undefined memory size: {size}");
     }
     this.dataEndianess                    = dataEndianess;
     volatileConfigurationRegister         = new ByteRegister(this, 0xfb).WithFlag(3, name: "XIP");
     nonVolatileConfigurationRegister      = new WordRegister(this, 0xffff).WithFlag(0, out numberOfAddressBytes, name: "addressWith3Bytes");
     enhancedVolatileConfigurationRegister = new ByteRegister(this, 0xff)
                                             .WithValueField(0, 3, name: "Output driver strength")
                                             .WithReservedBits(3, 1)
                                             .WithTaggedFlag("Reset/hold", 4)
                                             //these flags are intentionally not implemented, as they described physical details
                                             .WithFlag(5, name: "Double transfer rate protocol")
                                             .WithFlag(6, name: "Dual I/O protocol")
                                             .WithFlag(7, name: "Quad I/O protocol");
     statusRegister     = new ByteRegister(this).WithFlag(1, out enable, name: "volatileControlBit");
     flagStatusRegister = new ByteRegister(this)
                          .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => numberOfAddressBytes.Value, name: "Addressing")
                          //other bits indicate either protection errors (not implemented) or pending operations (they already finished)
                          .WithReservedBits(3, 1);
     fileBackendSize     = (uint)size;
     isCustomFileBackend = false;
     dataBackend         = DataStorage.Create(fileBackendSize, 0xFF);
     deviceData          = GetDeviceData();
 }
Esempio n. 4
0
 private byte GetRegister(ByteRegister register)
 {
     if (register == ByteRegister.None)
     {
         return(0xFF);
     }
     return(_registers[(int)register]);
 }
 public void Setup()
 {
     _byteFactory       = new ByteFactory(new Base10Converter());
     _and               = new And();
     _memoryGateFactory = new MemoryGateFactory(new NAnd(new Not(), _and));
     _byteMemoryGate    = new ByteMemoryGate(_memoryGateFactory, _byteFactory);
     _byteEnabler       = new ByteEnabler(_and, _byteFactory);
     _sut               = new ByteRegister(_byteMemoryGate, _byteEnabler, _byteFactory, wire => {});
 }
        public IRegister <IByte> Create(Action <IByte> dataToUpdate, string name)
        {
            var reg = new ByteRegister(_byteMemoryGateFactory.Create(), _byteEnabler, _byteFactory, dataToUpdate)
            {
                Name = name
            };

            return(reg);
        }
Esempio n. 7
0
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Flags           flags       = cpu.Flags;
            Registers       r           = cpu.Registers;

            sbyte        offset        = (sbyte)(data.Argument1);
            ByteRegister register      = instruction.Target.AsByteRegister();
            bool         previousCarry = flags.Carry;

            byte original, shifted;

            if (register != ByteRegister.None)
            {
                original = r[register];
                shifted  = (byte)(original >> 1);
                shifted  = shifted.SetBit(7, previousCarry);
                setFlags(original, shifted, original.GetBit(0));
                r[register] = shifted;
            }
            else
            {
                ushort address = instruction.Prefix switch
                {
                    0xCB => r.HL,
                    0xDDCB => (ushort)(r.IX + offset),
                    0xFDCB => (ushort)(r.IY + offset),
                    _ => (ushort)0xFFFF
                };
                original = cpu.Memory.Timed.ReadByteAt(address);
                shifted  = (byte)(original >> 1);
                shifted  = shifted.SetBit(7, previousCarry);
                setFlags(original, shifted, original.GetBit(0));
                if (instruction.IsIndexed)
                {
                    cpu.Timing.InternalOperationCycle(4);
                }
                cpu.Memory.Timed.WriteByteAt(address, shifted);
                if (instruction.CopyResultTo != ByteRegister.None)
                {
                    r[instruction.CopyResultTo.Value] = shifted;
                }
            }

            void setFlags(byte original, byte shifted, bool overflowBit)
            {
                flags           = FlagLookup.BitwiseFlags(original, BitwiseOperation.RotateRightThroughCarry, previousCarry);
                flags.Carry     = overflowBit;
                flags.HalfCarry = false;
                flags.Subtract  = false;
            }

            return(new ExecutionResult(package, flags));
        }
 private void InitializeFlashRegisters()
 {
     //These registers are for the Winbond W25Q80DV
     FlashStatus1 = new ByteRegister(this, 0x0)
                    .WithFlag(0, name: "BUSY")
                    .WithFlag(1, name: "WEL", mode: FieldMode.ReadToClear | FieldMode.Write)
                    .WithValueField(2, 3, name: "BLOCK_PROTECT_BITS")
                    .WithFlag(5, name: "TB")
                    .WithFlag(6, name: "SEC")
                    .WithFlag(7, name: "SRP0");
 }
Esempio n. 9
0
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction instruction = package.Instruction;
            InstructionData data = package.Data;
            Flags flags = cpu.Flags;
            Registers r = cpu.Registers;
            sbyte offset = (sbyte)(data.Argument1);
            ByteRegister register = instruction.Target.AsByteRegister();

            void setFlags(byte original)
            {
                flags = FlagLookup.BitwiseFlags(original, BitwiseOperation.ShiftLeftSetBit0, flags.Carry);
                flags.Carry = original.GetBit(7);
                flags.HalfCarry = false;
                flags.Subtract = false;
            }

            byte original, shifted;
            if (register != ByteRegister.None)
            {
                original = r[register];
                shifted = (byte)((original << 1) + 1); // bit 0 is always set, adding 1 does this quicker than calling SetBit
                setFlags(original);
                r[register] = shifted;
            }
            else
            {
                ushort address = instruction.Prefix switch
                {
                    0xCB => r.HL,
                    0xDDCB => (ushort)(r.IX + offset),
                    0xFDCB => (ushort)(r.IY + offset),
                    _ => (ushort)0xFFFF
                };
                original = cpu.Memory.Timed.ReadByteAt(address);
                shifted = (byte)((original << 1) + 1);
                setFlags(original);
                cpu.Memory.Timed.WriteByteAt(address, shifted);
                if (instruction.CopyResultTo != ByteRegister.None)
                {
                    r[instruction.CopyResultTo.Value] = shifted;
                }
            }

            return new ExecutionResult(package, flags);
        }
Esempio n. 10
0
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Registers       r           = cpu.Registers;
            byte            offset      = data.Argument1;
            Flags           flags       = cpu.Flags;

            if (instruction.TargetsWordRegister)
            {
                // inc 16-bit
                WordRegister register = instruction.Target.AsWordRegister();
                ushort       value    = r[register];
                r[register] = (ushort)(value + 1);
            }
            else
            {
                byte value = 0;
                if (instruction.TargetsByteInMemory)
                {
                    // inc byte in memory
                    if (instruction.IsIndexed)
                    {
                        cpu.Timing.InternalOperationCycle(5);
                    }
                    value = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source);
                    cpu.Memory.Timed.WriteByteAt(address, (byte)(value + 1));
                }
                else
                {
                    // it's an 8-bit inc
                    ByteRegister register = instruction.Target.AsByteRegister();
                    value       = r[register];
                    r[register] = (byte)(value + 1);
                }

                bool carry = flags.Carry;
                flags = FlagLookup.ByteArithmeticFlags(value, 1, false, false);
                flags.ParityOverflow = (value == 0x7F);
                flags.Carry          = carry; // always unaffected
                flags.Subtract       = false;
            }

            return(new ExecutionResult(package, flags));
        }
Esempio n. 11
0
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Registers       r           = cpu.Registers;
            Flags           flags       = cpu.Flags;

            byte         bitIndex = instruction.GetBitIndex();
            byte         value;
            ByteRegister register = instruction.Source.AsByteRegister();

            if (register != ByteRegister.None)
            {
                value = r[register]; // BIT b, r
            }
            else
            {
                if (instruction.IsIndexed)
                {
                    cpu.Timing.InternalOperationCycle(5);
                }
                value = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source);
                byte valueXY = instruction.IsIndexed ? address.HighByte() : r.WZ.HighByte(); // this is literally the only place the WZ value is *ever* actually used
                flags.X = (valueXY & 0x08) > 0;                                              // copy bit 3
                flags.Y = (valueXY & 0x20) > 0;                                              // copy bit 5
            }

            bool set = value.GetBit(bitIndex);

            flags.Sign = bitIndex == 7 && set;

            if (register == ByteRegister.None)
            {
                flags.Y = bitIndex == 5 && set;
                flags.X = bitIndex == 3 && set;
            }

            flags.Zero           = !set;
            flags.ParityOverflow = flags.Zero;
            flags.HalfCarry      = true;
            flags.Subtract       = false;

            return(new ExecutionResult(package, flags));
        }
Esempio n. 12
0
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Registers       r           = cpu.Registers;
            byte            bitIndex    = instruction.GetBitIndex();
            sbyte           offset      = (sbyte)(data.Argument1);

            ByteRegister register = instruction.Source.AsByteRegister();

            if (register != ByteRegister.None)
            {
                byte value = r[register].SetBit(bitIndex, true);
                r[register] = value;
            }
            else
            {
                ushort address = instruction.Prefix switch
                {
                    0xCB => r.HL,
                    0xDDCB => (ushort)(r.IX + offset),
                    0xFDCB => (ushort)(r.IY + offset),
                    _ => (ushort)0xFFFF
                };
                if (instruction.IsIndexed)
                {
                    cpu.Timing.InternalOperationCycle(5);
                }

                byte value = cpu.Memory.Timed.ReadByteAt(address);
                value = value.SetBit(bitIndex, true);
                cpu.Memory.Timed.WriteByteAt(address, value);
                if (instruction.CopyResultTo != ByteRegister.None)
                {
                    r[instruction.CopyResultTo.Value] = value;
                }
            }

            return(new ExecutionResult(package, null));
        }
Esempio n. 13
0
        public static ByteRegister AsByteRegister(this InstructionElement argument)
        {
            ByteRegister register = argument switch
            {
                InstructionElement.A => ByteRegister.A,
                InstructionElement.B => ByteRegister.B,
                InstructionElement.C => ByteRegister.C,
                InstructionElement.D => ByteRegister.D,
                InstructionElement.E => ByteRegister.E,
                InstructionElement.F => ByteRegister.F,
                InstructionElement.H => ByteRegister.H,
                InstructionElement.L => ByteRegister.L,
                InstructionElement.IXh => ByteRegister.IXh,
                InstructionElement.IYh => ByteRegister.IYh,
                InstructionElement.IXl => ByteRegister.IXl,
                InstructionElement.IYl => ByteRegister.IYl,
                InstructionElement.I => ByteRegister.I,
                InstructionElement.R => ByteRegister.R,
                _ => ByteRegister.None
            };

            return(register);
        }
Esempio n. 14
0
 public byte this[ByteRegister register] {
     get { return(GetRegister(register)); } set { SetRegister(register, value); }
 }
Esempio n. 15
0
 public void SRA(ByteRegister op)
 {
     _registerFile.F = (byte)(op.Value & FlagRegisterDefinition.C);
     op.Value = (byte)((op.Value & 0x80) | (op.Value >> 1));
     _registerFile.F |= _lookupTables.Sz53P[op.Value];
 }
Esempio n. 16
0
 public void SRL(ByteRegister op)
 {
     _registerFile.F = (byte)(op.Value & FlagRegisterDefinition.C);
     op.Value >>= 1;
     _registerFile.F |= _lookupTables.Sz53P[op.Value];
 }
        public static ByteRegister Bind(this IConvertible o, IProvidesRegisterCollection <ByteRegisterCollection> p, ByteRegister reg, string name = "")
        {
            if (!o.GetType().IsEnum)
            {
                throw new ArgumentException("This method should be called on enumerated type");
            }

            return(p.RegistersCollection.AddRegister(Convert.ToInt64(o), reg));
        }
Esempio n. 18
0
        public static byte MarshalSourceByte(this Instruction instruction, InstructionData data, Processor cpu, out ushort address, out ByteRegister source)
        {
            // this fetches a byte operand value for the instruction given, adjusting how it is fetched based on the addressing of the instruction

            Registers r = cpu.Registers;

            address = 0x0000;

            byte value;

            source = instruction.Source.AsByteRegister();
            if (source != ByteRegister.None)
            {
                // operand comes from another byte register directly (eg LD A,B)
                value = r[source];
            }
            else
            {
                if (instruction.Argument1 == InstructionElement.ByteValue)
                {
                    // operand is supplied as an argument (eg LD A,n)
                    value = data.Argument1;
                }
                else if (instruction.Source == InstructionElement.None)
                {
                    // operand is fetched from a memory location but the source and target are the same (eg INC (HL) or INC (IX+d))
                    address = instruction.Target.AsWordRegister() switch
                    {
                        WordRegister.IX => (ushort)(r.IX + (sbyte)data.Argument1),
                        WordRegister.IY => (ushort)(r.IY + (sbyte)data.Argument1),
                        _ => r.HL
                    };

                    value = cpu.Memory.Timed.ReadByteAt(address);
                }
                else
                {
                    // operand is fetched from a memory location and assigned elsewhere (eg LD A,(HL) or LD B,(IX+d))
                    address = instruction.Source.AsWordRegister() switch
                    {
                        WordRegister.IX => (ushort)(r.IX + (sbyte)data.Argument1),
                        WordRegister.IY => (ushort)(r.IY + (sbyte)data.Argument1),
                        _ => r.HL
                    };

                    value = cpu.Memory.Timed.ReadByteAt(address);
                }
            }

            return(value);
        }
Esempio n. 19
0
        /// <summary>
        ///     Execution of ED xx codes
        /// </summary>
        /// <param name="opcode">opcode to execute</param>
        private void Execute_ED_Prefix(byte opcode)
        {
            if ((opcode & 0xC7) == 0x40) // IN r,(C)
            {
                ByteRegister reg = GetByteRegisterByOpcode((byte) (opcode >> 3));

                // In this case 110 does not write in (HL) but affects only the flags
                if (reg == null)
                    reg = new ByteRegister();

                _cpuTicks += 12;
                IN(reg, _registerFile.BC);
            }
            else if ((opcode & 0xC7) == 0x41) // OUT (C),r
            {
                // The contents of register C are placed on the bottom half (A0 through A7) of
                // the address bus to select the I/O device at one of 256 possible ports. The
                // contents of Register B are placed on the top half (A8 through A15) of the
                // address bus at this time. Then the byte contained in register r is placed on
                // the data bus and written to the selected peripheral device.
                ByteRegister reg = GetByteRegisterByOpcode((byte) (opcode >> 3));

                // In this case 110 outputs 0 in out port
                if (reg == null)
                    reg = new ByteRegister(0);

                _cpuTicks += 12;
                _inputOutputDevice.WritePort(_registerFile.BC, reg.Value);
            }
            else if ((opcode & 0xC7) == 0x42) // ALU operations with HL
            {
                _cpuTicks += 15;
                WordRegister reg = GetWordRegister(opcode, true);
                switch (opcode & 0x08)
                {
                    case 0: // SBC HL,ss
                        _alu.SBC_HL(reg.Word);
                        break;
                    case 8: // ADC HL,ss
                        _alu.ADC_HL(reg.Word);
                        break;
                    default:
                        throw new Exception("No no no!!!");
                }
            }
            else if ((opcode & 0xC7) == 0x43) // Load register from to memory address
            {
                _cpuTicks += 20;
                WordRegister reg = GetWordRegister(opcode, true);
                switch (opcode & 0x08)
                {
                    case 0: // LD (nnnn),ss
                        LD_nndd(reg);
                        break;
                    case 8: // LD ss,(nnnn)
                        LD_ddnn(reg);
                        break;
                    default:
                        throw new Exception("No no no!!!");
                }
            }
            else
            {
                switch (opcode)
                {
                    case 0x44:
                    case 0x4c:
                    case 0x54:
                    case 0x5c:
                    case 0x64:
                    case 0x6c:
                    case 0x74:
                    case 0x7c: // NEG
                        // The contents of the Accumulator are negated (two’s complement). This is
                        // the same as subtracting the contents of the Accumulator from zero. Note
                        // that 80H is left unchanged.
                        // Condition Bits Affected:
                        // S is set if result is negative; reset otherwise
                        // Z is set if result is 0; reset otherwise
                        // H is set if borrow from bit 4; reset otherwise
                        // P/V is set if Accumulator was 80H before operation; reset otherwise
                        // N is set
                        // C is set if Accumulator was not 00H before operation; reset otherwise
                        _cpuTicks += 8;
                    {
                        byte _b = _registerFile.A;
                        _registerFile.A = 0;
                        _alu.SUB_r(_b);
                    }
                        break;

                    case 0x45:
                    case 0x4d: // RETI
                        // This instruction is used at the end of a maskable interrupt service routine to:
                        // • Restore the contents of the Program Counter (PC) (analogous to the
                        // RET instruction)
                        // • Signal an I/O device that the interrupt routine is completed. The RETI
                        // instruction also facilitates the nesting of interrupts, allowing higher
                        // priority devices to temporarily suspend service of lower priority
                        // service routines. However, this instruction does not enable interrupts
                        // that were disabled when the interrupt routine was entered. Before
                        // doing the RETI instruction, the enable interrupt instruction (EI)
                        // should be executed to allow recognition of interrupts after completion
                        // of the current service routine.

                        // TODO: Reading Z80 specs this instruction should not copy IFF2 to IFF1 but
                        // in real Z80 seems that the operation is done.
                    case 0x55:
                    case 0x5d:
                    case 0x65:
                    case 0x6d:
                    case 0x75:
                    case 0x7d: // RETN
                        // This instruction is used at the end of a non-maskable interrupts service
                        // routine to restore the contents of the Program Counter (PC) (analogous to
                        // the RET instruction). The state of IFF2 is copied back to IFF1 so that
                        // maskable interrupts are enabled immediately following the RETN if they
                        // were enabled before the nonmaskable interrupt.
                        _cpuTicks += 14;
                        _registerFile.IFF1 = _registerFile.IFF2;
                        RET();
                        break;

                    case 0x46:
                    case 0x4e:
                    case 0x66:
                    case 0x6e: // IM 0
                        // The IM 0 instruction sets interrupt mode 0. In this mode, the interrupting
                        // device can insert any instruction on the data bus for execution by the
                        // CPU. The first byte of a multi-byte instruction is read during the interrupt
                        // acknowledge cycle. Subsequent bytes are read in by a normal memory
                        // read sequence.
                        _cpuTicks += 8;
                        _registerFile.IM = 0;
                        break;

                    case 0x47: // LD I,A
                        _cpuTicks += 9;
                        _registerFile.I = _registerFile.A;
                        break;

                    case 0x4F: // LD R,A
                        _cpuTicks += 9;
                        _registerFile.R = _registerFile.R7 = _registerFile.A;
                        break;

                    case 0x56:
                    case 0x76: // IM 1
                        _cpuTicks += 8;
                        // The IM 1 instruction sets interrupt mode 1. In this mode, the processor
                        // responds to an interrupt by executing a restart to location 0038H.
                        _registerFile.IM = 1;
                        break;
                    case 0x57: // LD A,I
                        _cpuTicks += 9;
                        // The contents of the Interrupt Vector Register I are loaded to the Accumulator.
                        // Condition Bits Affected:
                        // S is set if I-Register is negative; reset otherwise
                        // Z is set if I-Register is zero; reset otherwise
                        // H is reset
                        // P/V contains contents of IFF2
                        // N is reset
                        // C is not affected
                        // If an interrupt occurs during execution of this instruction, the Parity
                        // flag contains a 0.
                        _registerFile.A = _registerFile.I;
                        _registerFile.F =
                            (byte)
                                ((_registerFile.F & FlagRegisterDefinition.C) |
                                 _lookupTables.Sz53[_registerFile.A] |
                                 (_registerFile.IFF2 ? FlagRegisterDefinition.V : 0));
                        break;
                    case 0x5E:
                    case 0x7E: // IM 2
                        // The IM 2 instruction sets the vectored interrupt mode 2. This mode allows
                        // an indirect call to any memory location by an 8-bit vector supplied from the
                        // peripheral device. This vector then becomes the least-significant eight bits
                        // of the indirect pointer, while the I register in the CPU provides the most-significant
                        // eight bits. This address points to an address in a vector table that
                        // is the starting address for the interrupt service routine.
                        _cpuTicks += 8;
                        _registerFile.IM = 2;
                        break;

                    case 0x5F: // LD A,R
                        _cpuTicks += 9;
                        _registerFile.A = (byte) ((_registerFile.R & 0x7F) | (_registerFile.R7 & 0x80));
                        _registerFile.F =
                            (byte)
                                ((_registerFile.F & FlagRegisterDefinition.C) |
                                 _lookupTables.Sz53[_registerFile.A] |
                                 (_registerFile.IFF2 ? FlagRegisterDefinition.V : 0));
                        break;

                    case 0x67: // RRD
                        _cpuTicks += 18;
                        _alu.RRD();
                        break;
                    case 0x6F: // RLD
                        _cpuTicks += 18;
                        _alu.RLD();
                        break;
                    case 0xA0: // LDI
                        _cpuTicks += 16;
                        LDI();
                        break;
                    case 0xA1: // CPI
                        _cpuTicks += 16;
                        CPI();
                        break;

                    case 0xA2: // INI
                        _cpuTicks += 16;
                        INI();
                        break;

                    case 0xA3: // OUTI
                        _cpuTicks += 16;
                        OUTI();
                        break;

                    case 0xA8: // LDD
                        _cpuTicks += 16;
                        LDD();
                        break;

                    case 0xA9: // CPD
                        _cpuTicks += 16;
                        CPD();
                        break;
                    case 0xAA: // IND
                        _cpuTicks += 16;
                        IND();
                        break;

                    case 0xAB: // OUTD
                        _cpuTicks += 16;
                        OUTD();
                        break;

                    case 0xB0: // LDIR
                        _cpuTicks += 16;
                        LDIR();
                        break;

                    case 0xB1: // CPIR
                        _cpuTicks += 16;
                        CPIR();
                        break;

                    case 0xB2: // INIR
                        _cpuTicks += 16;
                        INIR();
                        break;

                    case 0xB3: // OTIR
                        _cpuTicks += 16;
                        OTIR();
                        break;

                    case 0xB8: // LDDR
                        _cpuTicks += 17;
                        LDDR();
                        break;

                    case 0xB9: // CPDR
                        _cpuTicks += 16;
                        CPDR();
                        break;

                    case 0xba: // INDR
                        _cpuTicks += 16;
                        INDR();
                        break;

                    case 0xbb: // OTDR
                        _cpuTicks += 16;
                        OTDR();
                        break;

                    default: // All other opcodes are NOPD
                        _cpuTicks += 8;
                        break;
                }
            }
        }
Esempio n. 20
0
        /// <summary>
        ///     Execution of DD CB xx codes or FD CB xx codes
        /// </summary>
        /// <param name="Address">Address to act on - Address = I_ + d</param>
        /// <param name="opcode">opcode</param>
        private void Execute_DDFD_CB_Prefix(ushort Address, byte opcode)
        {
            // This is a mix of DD/FD opcodes (Normal operation but access to
            // I_ register instead of HL register) and CB op codes.
            // Behaviour is a little different:
            // if (Opcodes use B, C, D, E, H, L)  -  opcodes with rrr different from 110
            //   r = (I_ + d)
            //   execute_op r
            //   (I_ + d) = r
            // if (Opcodes use (HL))              -  opcodes with rrr = 110
            //   execute_op (I_ + d)
            //
            // if execute_op is a bit checking operation BIT n,r no assignement are done

            ByteRegister reg;

            // Check if the operation is a bit checking operation
            // The format is 01 bbb rrr
            if (opcode >> 6 == 0x01)
            {
                reg = new ByteRegister();
                _cpuTicks += 20;
            }
            else
            {
                // Retrieve the register from opcode xxxxx rrr
                reg = GetByteRegisterByOpcode(opcode);

                // Check if the source is (I_ + d) so the op will not act on any register
                // but only on memory
                if (reg == null)
                {
                    _cpuTicks += 23;
                    reg = new ByteRegister();
                }
                else
                    _cpuTicks += 23;
                // In case reg is not null the timings are not documented. I think the operation
                // take at least 23 CpuTicks (the same of the operation without storing the
                // result in register too).
            }

            // Assign (I_ + d) value to reg
            reg.Value = _memory.ReadByte(Address);

            Execute_CB_on_reg(opcode, reg);

            _memory.WriteByte(Address, reg.Value);
        }
Esempio n. 21
0
 public void INC(ByteRegister op)
 {
     op.Value++;
     _registerFile.F = (byte)(
         (_registerFile.F & FlagRegisterDefinition.C) |
         (op.Value == 0x80 ? FlagRegisterDefinition.V : (byte)0) |
         ((op.Value & 0x0F) != 0 ? (byte)0 : FlagRegisterDefinition.H) |
         (op.Value != 0 ? (byte)0 : FlagRegisterDefinition.Z) |
         _lookupTables.Sz53[op.Value]);
 }
Esempio n. 22
0
 public void RL(ByteRegister op)
 {
     byte _op = op.Value;
     op.Value = (byte)((op.Value << 1) | (_registerFile.F & FlagRegisterDefinition.C));
     _registerFile.F = (byte)((_op >> 7) | _lookupTables.Sz53P[op.Value]);
 }
Esempio n. 23
0
 public void IN(ByteRegister reg, ushort port)
 {
     reg.Value = _inputOutputDevice.ReadPort(port);
     _registerFile.F = (byte)((_registerFile.F & FlagRegisterDefinition.C) | _lookupTables.Sz53P[reg.Value]);
 }
Esempio n. 24
0
        /// <summary>
        ///     This is the low level function called within a CB opcode fetch
        ///     (single byte or DD CB or FD CB)
        ///     It must be called after the execution unit has determined on
        ///     wich register act
        /// </summary>
        /// <param name="opcode">opcode</param>
        /// <param name="reg">Register to act on</param>
        private void Execute_CB_on_reg(byte opcode, ByteRegister reg)
        {
            switch (opcode >> 3)
            {
                case 0: // RLC r
                    _alu.RLC(reg);
                    break;
                case 1: // RRC r
                    _alu.RRC(reg);
                    break;
                case 2: // RL r
                    _alu.RL(reg);
                    break;
                case 3: // RR r
                    _alu.RR(reg);
                    break;
                case 4: // SLA r
                    _alu.SLA(reg);
                    break;
                case 5: // SRA r
                    _alu.SRA(reg);
                    break;
                case 6: // SLL r
                    _alu.SLL(reg);
                    break;
                case 7: // SRL r
                    _alu.SRL(reg);
                    break;
                default:
                    // Work on bits

                    // The format is oo bbb rrr
                    // oo is the operation (01 BIT, 10 RES, 11 SET)
                    // bbb is the bit number
                    // rrr is the register
                    var bit = (byte) ((opcode >> 3) & 0x07);

                    switch (opcode >> 6)
                    {
                        case 1: // BIT n,r
                            if (bit == 7)
                                BIT7(reg.Value);
                            else
                                BIT(bit, reg.Value);
                            break;
                        case 2: // RES n,r
                            reg.Value &= (byte) ~(1 << bit);
                            break;
                        case 3: // SET n,r
                            reg.Value |= (byte) (1 << bit);
                            break;
                        default:
                            throw new Exception("What am I doing here?!?");
                    }

                    break;
            }
        }
Esempio n. 25
0
 public void INC(ByteRegister op)
 {
     _alu.INC(op);
 }
Esempio n. 26
0
 public void LD_d_r(ByteRegister destinationRegister, ByteRegister sourceRegister)
 {
     throw new NotImplementedException();
 }
Esempio n. 27
0
 public void RLC(ByteRegister op)
 {
     _alu.RLC(op);
 }
Esempio n. 28
0
 public void DEC(ByteRegister op)
 {
     _alu.DEC(op);
 }
Esempio n. 29
0
 public void RLC(ByteRegister op)
 {
     op.Value = (byte)((op.Value << 1) | (op.Value >> 7));
     _registerFile.F = (byte)(
         (op.Value & FlagRegisterDefinition.C) |
         _lookupTables.Sz53P[op.Value]);
 }
Esempio n. 30
0
 private void INC_R(ByteRegister reg)
 {
     if (reg == null)
     {
         // The target is (HL)
         CpuTicks += 7;
         reg = new ByteRegister(_memory.ReadByte(_registerFile.HL));
         _alu.INC(reg);
         _memory.WriteByte(_registerFile.HL, reg.Value);
     }
     else
     {
         // The target is a normal registry
         CpuTicks += 4;
         _alu.INC(reg);
     }
 }
Esempio n. 31
0
 public void RR(ByteRegister op)
 {
     byte _op = op.Value;
     op.Value = (byte)((op.Value >> 1) | (_registerFile.F << 7));
     _registerFile.F = (byte)(
         (_op & FlagRegisterDefinition.C) |
         _lookupTables.Sz53P[op.Value]);
 }
Esempio n. 32
0
        private void Execute_DDFD_Prefix(WordRegister RegisterI_, byte opcode)
        {
            ByteRegister _I__;
            ushort Address;

            if (opcode == 0x76)     // HALT
            {
                // The first check is for HALT otherwise it could be
                // interpreted as LD (I_ + d),(I_ + d)
                _cpuTicks += 4;
                _registerFile.Halted = true;
            }
            else if ((opcode & 0xC0) == 0x40)   // LD r,r'
            {
                ByteRegister reg1 = GetByteRegisterByOpcode((byte)(opcode >> 3));
                ByteRegister reg2 = GetByteRegisterByOpcode(opcode);

                if (reg1 == null)
                {
                    // The target is (I_ + d)
                    _cpuTicks += 19;
                    Address = (ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++));
                    _memory.WriteByte(Address, reg2.Value);
                }
                else if (reg2 == null)
                {
                    // The source is (I_ + d)
                    _cpuTicks += 19;
                    Address = (ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++));
                    reg1.Value = _memory.ReadByte(Address);
                }
                else
                {
                    // Source and target are normal registers but HL is now substituted by I_
                    if (reg1 == _registerFile.RegisterHL.High)
                        reg1 = RegisterI_.High;
                    if (reg1 == _registerFile.RegisterHL.Low)
                        reg1 = RegisterI_.Low;

                    if (reg2 == _registerFile.RegisterHL.High)
                        reg2 = RegisterI_.High;
                    if (reg2 == _registerFile.RegisterHL.Low)
                        reg2 = RegisterI_.Low;

                    _cpuTicks += 8;
                    reg1.Value = reg2.Value;
                }
            }
            else if ((opcode & 0xC0) == 0x80)
            {
                // Operation beetween accumulator and other registers
                // Usually are identified by 10 ooo rrr where ooo is the operation and rrr is the source register
                ByteRegister reg = GetByteRegisterByOpcode(opcode);
                byte _Value;

                if (reg == null)
                {
                    // The source is (I_ + d)
                    _cpuTicks += 19;
                    _Value = _memory.ReadByte((ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++)));
                }
                else
                {
                    // The source is a normal registry but HL is substituted by I_
                    _cpuTicks += 8;
                    if (reg == _registerFile.RegisterHL.High)
                        _Value = RegisterI_.High.Value;
                    else if (reg == _registerFile.RegisterHL.Low)
                        _Value = RegisterI_.Low.Value;
                    else
                        _Value = reg.Value;
                }

                switch (opcode & 0xF8)
                {
                    case 0x80:  // ADD A,r
                        _alu.ADC_A_r(_Value);
                        break;
                    case 0x88:  // ADC A,r
                        _alu.ADC_A_r(_Value);
                        break;
                    case 0x90:  // SUB r
                        _alu.SUB_r(_Value);
                        break;
                    case 0x98:  // SBC A,r
                        _alu.SBC_A_r(_Value);
                        break;
                    case 0xA0:  // AND r
                        _alu.AND_r(_Value);
                        break;
                    case 0xA8:  // XOR r
                        _alu.XOR_r(_Value);
                        break;
                    case 0xB0:  // OR r
                        _alu.OR_r(_Value);
                        break;
                    case 0xB8:  // CP r
                        CP_r(_Value);
                        break;
                    default:
                        throw new Exception("Wrong place in the right time...");
                }

            }
            else
            {

                switch (opcode)
                {
                    case 0x09:      // ADD I_,BC
                        _cpuTicks += 15;
                        ADD_16(RegisterI_, _registerFile.BC);
                        break;

                    case 0x19:      // ADD I_,DE
                        _cpuTicks += 15;
                        ADD_16(RegisterI_, _registerFile.DE);
                        break;

                    case 0x21:      // LD I_,nnnn
                        _cpuTicks += 14;
                        RegisterI_.Word = _memory.ReadWord(_registerFile.PC);
                        _registerFile.PC += 2;
                        break;

                    case 0x22:      // LD (nnnn),I_
                        _cpuTicks += 20;
                        LD_nndd(RegisterI_);
                        break;

                    case 0x23:      // INC I_
                        _cpuTicks += 10;
                        RegisterI_.Word++;
                        break;

                    case 0x24:      // INC I_.h
                        _cpuTicks += 8;
                        INC(RegisterI_.High);
                        break;

                    case 0x25:      // DEC I_.h
                        _cpuTicks += 8;
                        DEC(RegisterI_.High);
                        break;

                    case 0x26:      // LD I_.h,nn
                        _cpuTicks += 11;
                        RegisterI_.High.Value = _memory.ReadByte(_registerFile.PC++);
                        break;

                    case 0x29:      // ADD I_,I_
                        _cpuTicks += 15;
                        ADD_16(RegisterI_, RegisterI_.Word);
                        break;

                    case 0x2A:      // LD I_,(nnnn)
                        _cpuTicks += 20;
                        LD_ddnn(RegisterI_);
                        break;

                    case 0x2B:      // DEC I_
                        _cpuTicks += 10;
                        RegisterI_.Word--;
                        break;

                    case 0x2C:      // INC I_.l
                        _cpuTicks += 8;
                        INC(RegisterI_.Low);
                        break;

                    case 0x2D:      // DEC I_.l
                        _cpuTicks += 8;
                        DEC(RegisterI_.Low);
                        break;

                    case 0x2E:      // LD I_.l,nn
                        _cpuTicks += 11;
                        RegisterI_.Low.Value = _memory.ReadByte(_registerFile.PC++);
                        break;

                    case 0x34:      // INC (I_ + d)
                        _cpuTicks += 23;
                        Address = (ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++));
                        _I__ = new ByteRegister(_memory.ReadByte(Address));
                        INC(_I__);
                        _memory.WriteByte(Address, _I__.Value);
                        break;

                    case 0x35:      // DEC (I_ + d)
                        _cpuTicks += 23;
                        Address = (ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++));
                        _I__ = new ByteRegister(_memory.ReadByte(Address));
                        DEC(_I__);
                        _memory.WriteByte(Address, _I__.Value);
                        break;

                    case 0x36:      // LD (I_ + d),nn
                        _cpuTicks += 19;
                        Address = (ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++));
                        _memory.WriteByte(Address, _memory.ReadByte(_registerFile.PC++));
                        break;

                    case 0x39:      // ADD I_,SP
                        _cpuTicks += 15;
                        ADD_16(RegisterI_, _registerFile.SP);
                        break;

                    case 0xCB:      // {DD|FD}CBxx opcodes
                        {
                            Address = (ushort)(RegisterI_.Word + (sbyte)_memory.ReadByte(_registerFile.PC++));
                            Execute_DDFD_CB_Prefix(Address, _memory.ReadByte(_registerFile.PC++));
                        }
                        break;
                    case 0xE1:      // POP I_
                        _cpuTicks += 14;
                        Pop(RegisterI_);
                        break;

                    case 0xE3:      // EX (SP),I_
                        _cpuTicks += 23;
                        {
                            ushort _w = _memory.ReadWord(_registerFile.SP);
                            _memory.WriteWord(_registerFile.SP, RegisterI_.Word);
                            RegisterI_.Word = _w;
                        }
                        break;
                    case 0xE5:      // PUSH I_
                        _cpuTicks += 15;
                        Push(RegisterI_);
                        break;

                    case 0xE9:      // JP I_
                        _cpuTicks += 8;
                        _registerFile.PC = RegisterI_.Word;
                        break;

                    // Note EB (EX DE,HL) does not get modified to use either IX or IY;
                    // this is because all EX DE,HL does is switch an internal flip-flop
                    // in the Z80 which says which way round DE and HL are, which can't
                    // be used with IX or IY. (This is also why EX DE,HL is very quick
                    // at only 4 T states).

                    case 0xF9:      // LD SP,I_
                        _cpuTicks += 10;
                        _registerFile.SP = RegisterI_.Word;
                        break;

                    default:
                        // Instruction did not involve H or L, so backtrack one instruction and parse again
                        _cpuTicks += 4;
                        _registerFile.PC--;
                        break;

                }
            }
        }
Esempio n. 33
0
 public void SLA(ByteRegister op)
 {
     _registerFile.F = (byte)(op.Value >> 7);
     op.Value <<= 1;
     _registerFile.F |= _lookupTables.Sz53P[op.Value];
 }
Esempio n. 34
0
        /// <summary>
        ///     Execution of CB xx codes
        /// </summary>
        /// <param name="opcode">opcode to execute</param>
        private void Execute_CB_Prefix(byte opcode)
        {
            // Operations with single byte register
            // The format is 00 ooo rrr where ooo is the operation and rrr is the register
            ByteRegister reg = GetByteRegisterByOpcode(opcode);
            ByteRegister _HL_ = null;

            // Check if the source/target is (HL)
            if (reg == null)
                reg = _HL_ = new ByteRegister(_memory.ReadByte(_registerFile.HL));

            Execute_CB_on_reg(opcode, reg);

            if (reg == _HL_)
            {
                // The target is (HL)
                _cpuTicks += 15;
                _memory.WriteByte(_registerFile.HL, _HL_.Value); //We should not do this when we check bits (BIT n,r)!
            }
            else
            {
                // The source is a normal registry
                _cpuTicks += 8;
            }
        }
Esempio n. 35
0
 public void SLL(ByteRegister op)
 {
     _registerFile.F = (byte)(op.Value >> 7);
     op.Value = (byte)((op.Value << 1) | 0x01);
     _registerFile.F |= _lookupTables.Sz53P[op.Value];
 }
Esempio n. 36
0
 public void DEC(ByteRegister op)
 {
     _registerFile.F = (byte)((_registerFile.F & FlagRegisterDefinition.C) | ((op.Value & 0x0F) != 0 ? (byte)0 : FlagRegisterDefinition.H) | FlagRegisterDefinition.N);
     op.Value--;
     _registerFile.F |= (byte)((op.Value == 0x79 ? FlagRegisterDefinition.V : (byte)0) | _lookupTables.Sz53[op.Value]);
 }
Esempio n. 37
0
 public void RR(ByteRegister op)
 {
     _alu.RR(op);
 }
Esempio n. 38
0
        public ENC28J60()
        {
            sync = new object();
            ResetPointers();

            var econ1 = new ByteRegister(this).WithValueField(0, 2, out currentBank, name: "BSEL")
                        .WithFlag(2, out ethernetReceiveEnabled, name: "RXEN")
                        .WithFlag(3, FieldMode.Read, writeCallback: (_, value) => { if (value)
                                                                                    {
                                                                                        TransmitPacket();
                                                                                    }
                                  }, name: "TXRTS")
                        .WithFlag(7, name: "TXRST");

            var econ2 = new ByteRegister(this, 0x80).WithFlag(6, FieldMode.Read, writeCallback: delegate {
                waitingPacketCount = Math.Max(0, waitingPacketCount - 1);
                RefreshInterruptStatus();
            }, name: "PKTDEC")
                        .WithFlag(7, out autoIncrement, name: "AUTOINC");

            var estat = new ByteRegister(this, 1).WithReadCallback(delegate { transmitPacketInterrupt.Value = false; RefreshInterruptStatus(); }) // not sure
                        .WithFlag(0, FieldMode.Read, name: "CLKRDY");                                                                             // we're always ready, so the reset value is 1

            var eie = new ByteRegister(this).WithFlag(3, out transmitPacketInterruptEnabled, writeCallback: delegate { RefreshInterruptStatus(); }, name: "TXIE")
                      .WithFlag(6, out receivePacketInterruptEnabled, writeCallback: delegate { RefreshInterruptStatus(); }, name: "PKTIE")
                      .WithFlag(7, out interruptsEnabled, writeCallback: delegate { RefreshInterruptStatus(); }, name: "INTIE");

            var eir = new ByteRegister(this).WithFlag(0, name: "RXERIF")
                      .WithFlag(3, out transmitPacketInterrupt, writeCallback: delegate { RefreshInterruptStatus(); }, name: "TXIF")
                      .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => IsReceiveInterruptActive(), name: "PKTIF");

            var bank0Map = new Dictionary <long, ByteRegister>
            {
                // ERDPTL
                { 0x00, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(bufferReadPointer),
                                                              writeCallback: (_, value) => SetLowByteOf(ref bufferReadPointer, (byte)value)) },

                // ERDPTH
                { 0x01, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(bufferReadPointer),
                                                              writeCallback: (_, value) => SetHighByteOf(ref bufferReadPointer, (byte)value)) },

                // EWRPTL
                { 0x02, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(bufferWritePointer),
                                                              writeCallback: (_, value) => SetLowByteOf(ref bufferWritePointer, (byte)value)) },

                // EWRPTH
                { 0x03, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(bufferWritePointer),
                                                              writeCallback: (_, value) => SetHighByteOf(ref bufferWritePointer, (byte)value)) },

                // ETXSTL
                { 0x04, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(transmitBufferStart),
                                                              writeCallback: (_, value) => SetLowByteOf(ref transmitBufferStart, (byte)value)) },

                // ETXSTH
                { 0x05, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(transmitBufferStart),
                                                              writeCallback: (_, value) => SetHighByteOf(ref transmitBufferStart, (byte)value)) },

                // ETXNDL
                { 0x06, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(transmitBufferEnd),
                                                              writeCallback: (_, value) => SetLowByteOf(ref transmitBufferEnd, (byte)value)) },

                // ETXNDH
                { 0x07, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(transmitBufferEnd),
                                                              writeCallback: (_, value) => SetHighByteOf(ref transmitBufferEnd, (byte)value)) },

                // ERXSTL
                { 0x08, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(receiveBufferStart),
                                                              writeCallback: (_, value) => { SetLowByteOf(ref receiveBufferStart, (byte)value); currentReceiveWritePointer = receiveBufferStart; }) },

                // ERXSTH
                { 0x09, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(receiveBufferStart),
                                                              writeCallback: (_, value) => { SetHighByteOf(ref receiveBufferStart, (byte)value); currentReceiveWritePointer = receiveBufferStart; }) },

                // ERXNDL
                { 0x0A, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(receiveBufferEnd),
                                                              writeCallback: (_, value) => SetLowByteOf(ref receiveBufferEnd, (byte)value)) },

                // ERXNDH
                { 0x0B, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(receiveBufferEnd),
                                                              writeCallback: (_, value) => SetHighByteOf(ref receiveBufferEnd, (byte)value)) },

                // ERXRDPTL
                { 0x0C, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => GetLowByteOf(receiveReadPointer),
                                                              writeCallback: (_, value) => bufferedLowByteOfReceiveReadPointer = (byte)value) },

                // ERXRDPTH
                { 0x0D, new ByteRegister(this).WithValueField(0, 5, valueProviderCallback: _ => GetHighByteOf(receiveReadPointer),
                                                              writeCallback: (_, value) => receiveReadPointer = (int)(bufferedLowByteOfReceiveReadPointer | ((value << 8)))) }
            };

            var bank1Map = new Dictionary <long, ByteRegister>
            {
                // ERXFCON
                { 0x18, new ByteRegister(this, 0xA1).WithFlag(5, out crcEnabled, name: "CRCEN") },

                // EPKTCNT
                { 0x19, new ByteRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (uint)waitingPacketCount) }
            };

            var bank2Map = new Dictionary <long, ByteRegister>
            {
                // MACON1
                // note that we currently ignore all the Pause Control Frame stuff
                { 0x00, new ByteRegister(this).WithFlag(0, out macReceiveEnabled, name: "MARXEN").WithFlag(2, name: "RXPAUS").WithFlag(3, name: "TXPAUS") },

                // MACON3
                { 0x02, new ByteRegister(this).WithFlag(0, name: "FULDPX") },

                // MABBIPG (too low level parameter for emulation)
                { 0x04, new ByteRegister(this).WithValueField(0, 7) },

                // MAIPGL (same as above)
                { 0x06, new ByteRegister(this).WithValueField(0, 7) },

                // MAIPGH (same as above)
                { 0x07, new ByteRegister(this).WithValueField(0, 7) },

                // MICMD
                { 0x12, new ByteRegister(this).WithFlag(0, writeCallback: (_, value) => { if (value)
                                                                                          {
                                                                                              ReadPhyRegister();
                                                                                          }
                                                        }, name: "MIIRD") },

                // MIREGADR
                { 0x14, new ByteRegister(this).WithValueField(0, 5, out miiRegisterAddress) },

                // MIWRL
                { 0x16, new ByteRegister(this).WithValueField(0, 8, out phyWriteLow) },

                // MIWRH
                { 0x17, new ByteRegister(this).WithValueField(0, 8, writeCallback: (_, value) => WritePhyRegister((ushort)(phyWriteLow.Value | (value << 8)))) },

                // MIRDL
                { 0x18, new ByteRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)lastReadPhyRegisterValue) },

                // MIRDH
                { 0x19, new ByteRegister(this).WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)(lastReadPhyRegisterValue >> 8)) }
            };

            var bank3Map = new Dictionary <long, ByteRegister>
            {
                // MAADR5
                { 0x00, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.E, writeCallback: (_, value) => MAC = MAC.WithNewOctets(e: (byte)value)) },

                // MADDR6
                { 0x01, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.F, writeCallback: (_, value) => MAC = MAC.WithNewOctets(f: (byte)value)) },

                // MADDR3
                { 0x02, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.C, writeCallback: (_, value) => MAC = MAC.WithNewOctets(c: (byte)value)) },

                // MADDR4
                { 0x03, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.D, writeCallback: (_, value) => MAC = MAC.WithNewOctets(d: (byte)value)) },

                // MADDR1
                { 0x04, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.A, writeCallback: (_, value) => MAC = MAC.WithNewOctets(a: (byte)value)) },

                // MADDR2
                { 0x05, new ByteRegister(this).WithValueField(0, 8, valueProviderCallback: _ => MAC.B, writeCallback: (_, value) => MAC = MAC.WithNewOctets(b: (byte)value)) },

                // MISTAT
                { 0x0A, new ByteRegister(this).WithFlag(0, FieldMode.Read, name: "BUSY") } // we're never busy
            };

            var maps = new[] { bank0Map, bank1Map, bank2Map, bank3Map };

            // registers below are available in all banks
            foreach (var map in maps)
            {
                map.Add(0x1B, eie);   // EIE
                map.Add(0x1C, eir);   // EIR
                map.Add(0x1D, estat); // ESTAT
                map.Add(0x1E, econ2); // ECON2
                map.Add(0x1F, econ1); // ECON1
            }
            registers = maps.Select(x => new ByteRegisterCollection(this, x)).ToArray();

            ethernetBuffer = new byte[8.KB()];

            phyRegisters = new WordRegisterCollection(this, new Dictionary <long, WordRegister>
            {
                // PHCON1
                { 0x00, new WordRegister(this).WithFlag(8, name: "PDPXMD") }, // full duplex stuff, ignored

                // PHCON2
                { 0x10, new WordRegister(this) }
            });
            IRQ = new GPIO();
            IRQ.Set(); // the interrupt output is negated
        }
Esempio n. 39
0
 public void SRL(ByteRegister op)
 {
     throw new NotImplementedException();
 }