Livt packages
Livt.Net
Version 1.4.1
Ethernet, IPv4, TCP, UDP, ARP, TFTP, and Telnet networking components for Livt hardware.
Published files (163)
src/ethernet/EthernetFrame.lvt
namespace Livt.Net
/**
* Ethernet II envelope over a prepared payload; FCS is supplied by the MAC.
* Prepare the child first, then this envelope. Keep the child unchanged during
* emission. Use one serialized application owner in the same clock context.
*/
component EthernetFrame<P: IPacketData & IEthernetPayload, MAX_PAYLOAD_LENGTH: int = 1500> : IPacketData
{
static assert MAX_PAYLOAD_LENGTH > 0 && MAX_PAYLOAD_LENGTH <= 65535, "Invalid Ethernet payload limit"
// Borrowed prepared payload; must remain stable until emission finishes.
payload: P
// Owned Ethernet header and prepared payload/frame lengths.
const PAYLOAD_BITS: int = Bits.RequiredFor(MAX_PAYLOAD_LENGTH)
const FRAME_BITS: int = Bits.RequiredFor(MAX_PAYLOAD_LENGTH + 60)
payloadLength: logic[PAYLOAD_BITS]
length: logic[FRAME_BITS]
source0: logic[16]
source1: logic[16]
source2: logic[16]
destination0: logic[16]
destination1: logic[16]
destination2: logic[16]
typeWord: logic[16]
ready: bool
/**
* Borrows the fixed payload; starts unprepared and performs no payload reads.
*/
new(payload: P)
{
this.payload = payload
}
/**
* Invalidates this envelope without changing the child.
*/
public fn Invalidate()
{
ready = false;
length = 0;
payloadLength = 0
}
/**
* Addresses use network byte order. Failure invalidates any previous frame.
*/
public fn TryPrepare(sourceMac: byte[6], destinationMac: byte[6]) PacketDataResult
{
this.Invalidate()
if (!payload.IsReady()) {
return PacketDataResult.NotReady
}
var size = payload.GetAvailableLength()
var etherType = payload.GetEtherType()
if (size <= 0 || size > MAX_PAYLOAD_LENGTH) {
return PacketDataResult.Invalid
}
if (etherType < 1536 || etherType > 65535) {
return PacketDataResult.Invalid
}
source0 = NetworkOrder.Word(sourceMac[0], sourceMac[1]) as logic[16]
source1 = NetworkOrder.Word(sourceMac[2], sourceMac[3]) as logic[16]
source2 = NetworkOrder.Word(sourceMac[4], sourceMac[5]) as logic[16]
destination0 = NetworkOrder.Word(destinationMac[0], destinationMac[1]) as logic[16]
destination1 = NetworkOrder.Word(destinationMac[2], destinationMac[3]) as logic[16]
destination2 = NetworkOrder.Word(destinationMac[4], destinationMac[5]) as logic[16]
typeWord = etherType as logic[16]
payloadLength = size as logic[PAYLOAD_BITS]
var frameLength = 14 + size
if (frameLength < 60) { frameLength = 60 }
length = frameLength as logic[FRAME_BITS]
ready = true
return PacketDataResult.Success
}
/**
* Reports prepared metadata; the owner must still keep all borrowed payloads stable.
*/
override fn IsReady() bool
{
return ready
}
/**
* Returns the prepared packet length in bytes, or zero while unprepared.
*/
override fn GetAvailableLength() int
{
if (!ready) {
return 0
}
return (length as uint) as int
}
/**
* Reads a packet-relative byte; returns NotReady while unprepared and Invalid
* outside the prepared length. Delegated payload errors propagate; the output
* is data only on Success. Keep the prepared graph stable throughout the call.
* Bytes 0..13 are the Ethernet header; payload follows, then zero padding to
* the prepared frame length. Preamble and FCS are excluded.
*/
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (!ready) {
return PacketDataResult.NotReady
}
if (index < 0 || index >= ((length as uint) as int)) {
return PacketDataResult.Invalid
}
if (index < 14) {
value = this.EthernetHeaderByte(index, source0, source1, source2, destination0, destination1, destination2, typeWord);
return PacketDataResult.Success
}
if (index < 14 + ((payloadLength as uint) as int)) {
return payload.TryRead(index - 14, value)
}
return PacketDataResult.Success
}
/** Pure byte selection; no additional scheduled transaction. */
inline fn EthernetHeaderByte[](index: int, snapshotsource0: logic[16], snapshotsource1: logic[16], snapshotsource2: logic[16], snapshotdestination0: logic[16], snapshotdestination1: logic[16], snapshotdestination2: logic[16], snapshottypeWord: logic[16]) byte
{
if (index == 0) { return (snapshotdestination0 >> 8) as byte }
if (index == 1) { return snapshotdestination0 as byte }
if (index == 2) { return (snapshotdestination1 >> 8) as byte }
if (index == 3) { return snapshotdestination1 as byte }
if (index == 4) { return (snapshotdestination2 >> 8) as byte }
if (index == 5) { return snapshotdestination2 as byte }
if (index == 6) { return (snapshotsource0 >> 8) as byte }
if (index == 7) { return snapshotsource0 as byte }
if (index == 8) { return (snapshotsource1 >> 8) as byte }
if (index == 9) { return snapshotsource1 as byte }
if (index == 10) { return (snapshotsource2 >> 8) as byte }
if (index == 11) { return snapshotsource2 as byte }
if (index == 12) { return (snapshottypeWord >> 8) as byte }
if (index == 13) { return snapshottypeWord as byte }
return 0x00
}
}