Ejemplo n.º 1
0
        public void WriteDoubleWord(long offset, uint value)
        {
            this.NoisyLog("Write {0:X} to {1}", value, (Registers)offset);
            switch ((Registers)offset)
            {
            case Registers.MACConfiguration:
                macConfiguration          = value;
                crcStrippingForTypeFrames = (macConfiguration & 1u << 25) != 0;
                automaticPadCRCStripping  = (macConfiguration & 1u << 7) != 0;
                break;

            case Registers.MACFrameFilter:
                macFrameFilter = value;
                break;

            case Registers.MACMIIAddress:
                macMiiAddress = value;
                var busyClear = (value & 0x1) != 0;
                if (busyClear)
                {
                    macMiiAddress = macMiiAddress & ~0x1u;
                }
                var phyId    = (value >> 11) & 0x1F;
                var register = (ushort)((value >> 6) & 0x1F);
                var isRead   = ((value >> 1) & 0x1) == 0;
                if (!phys.ContainsKey(phyId))
                {
                    this.Log(LogLevel.Warning, "Access to unknown phy {0}", phyId);
                    break;
                }
                if (isRead)
                {
                    macMiiData = phys[phyId].Read(register);
                }
                else
                {
                    phys[phyId].Write(register, macMiiData);
                }

                break;

            case Registers.MACMIIData:
                macMiiData = (ushort)value;
                break;

            case Registers.MACFlowControl:
                macFlowControl = value;
                break;

            case Registers.MACAddress0High:
                MAC = MAC.WithNewOctets(f: (byte)(value >> 8), e: (byte)value);
                break;

            case Registers.MACAddress0Low:
                MAC = MAC.WithNewOctets(d: (byte)(value >> 24), c: (byte)(value >> 16), b: (byte)(value >> 8), a: (byte)value);
                break;

            case Registers.DMABusMode:
                dmaBusMode = value & ~0x1u;
                if ((value & 0x1) != 0)
                {
                    Reset();
                }
                break;

            case Registers.DMATransmitPollDemand:
                if ((dmaStatus | StartStopTransmission) != 0)
                {
                    SendFrames();
                }
                break;

            case Registers.DMAReceiveDescriptorListAddress:
                this.Log(LogLevel.Info, "Setting RDLA to 0x{0:X}.", value);
                dmaReceiveDescriptorListAddress      = value & ~3u;
                dmaReceiveDescriptorListAddressBegin = dmaReceiveDescriptorListAddress;
                break;

            case Registers.DMATransmitDescriptorListAddress:
                dmaTransmitDescriptorListAddress      = value & ~3u;
                dmaTransmitDescriptorListAddressBegin = dmaReceiveDescriptorListAddress;
                break;

            case Registers.DMAStatusRegister:
                dmaStatus &= ~value; //write 1 to clear;
                if ((value & 0x10000) > 0)
                {
                    IRQ.Unset();
                    TryDequeueFrame();
                }
                break;

            case Registers.DMAOperationMode:
                dmaOperationMode = value;
                if ((value & StartStopTransmission) != 0)
                {
                    SendFrames();
                }
                break;

            case Registers.DMAInterruptEnable:
                if (BitHelper.IsBitSet(value, 16)) //normal interrupt summary enable
                {
                    value |= (1u << 14) | (1u << 6) | (1u << 2) | 1u;
                }
                dmaInterruptEnable = value;
                break;

            default:
                this.LogUnhandledWrite(offset, value);
                break;
            }
        }
Ejemplo n.º 2
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
        }