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; } }
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 }