Simten

How Network Switches Work

Every time you open a web page, packets race through network switches that parse Ethernet frames, buffer data, arbitrate between ports, and route bytes to their destination — all in hardware, billions of times per second. Here we build one from scratch.

Interactive tutorial/~15 min read/Built with Simten

Detecting Ethernet Frames

Raw bytes arrive on a wire, but not every byte is a packet. An Ethernet frame starts with a preamble — a sequence of 0x55 bytes — followed by a Start-of-Frame Delimiter (SFD, 0xD5). The switch must detect this pattern to know when real data begins.

This circuit implements a small finite state machine with three states: Idle (0), Waiting for SFD (1), and In Frame (2). The state is stored in a register and updated each clock tick based on what byte arrives.

Set byteIn to 85 (0x55), toggle the valid switch, and tick — the state moves to 1 (waiting). Now set byteIn to 213 (0xD5) and tick again — the state jumps to 2 and the frameLed lights up: we’re in a frame.

Compiling...
Frame Detector
Detects the start of an Ethernet frame by matching a preamble byte (0x55) followed by Start-of-Frame Delimiter (0xD5).

Buffering Incoming Packets

Once the parser detects a frame, bytes need to go somewhere. The ingress buffer stores each incoming byte in a DualPortRAM. A write pointer register tracks the next free address and increments after each write.

Port A handles writes (the ingress side), while port B lets us read back any stored byte by address — this is how the forwarder will later fetch packet data for routing.

Set dataIn to any value, toggle writeCmd, and tick. The byte is written at the current pointer address, and the pointer advances. Change readAddr to read back previously stored bytes.

Compiling...
Packet Buffer
Stores incoming bytes in DualPortRAM as they arrive. A write pointer register tracks the next free address.

Fair Arbitration

When both ports have packets buffered and ready to send, someone has to decide who goes first. The arbiter implements a round-robin policy: it remembers which port was granted last and prefers the other one next time. If only one port is ready, it gets the grant immediately.

This is a purely combinational circuit — no clock needed. The lastPort input represents the last-granted port (0 or 1). Toggle port0_ready and port1_ready to see how the portDisplay and validLed respond.

Try both ports ready with lastPort = 0: port 1 wins. Change lastPort to 1: port 0 wins. Fair and simple.

Compiling...
Port Arbiter
Decides which port gets to send next. When both ports have packets ready, it alternates fairly between them.

Crossbar Routing

A real switch looks at the destination MAC address to decide where to forward each packet. Our simplified 2-port switch uses a static cross-over: anything from port 0 goes to port 1, and vice versa. This is the minimal useful routing — a 2-port crossbar.

The routing logic is just a comparator and a mux. If the source port equals 0, the Mux selects 1 as the destination (and the routedLed lights up). Otherwise, it selects 0.

Change sourcePort between 0 and 1 to see the destDisplay flip to the opposite port. This is instant — pure combinational logic.

Compiling...
Crossbar Router
Routes packets to the opposite port: port 0 sends to port 1 and vice versa. A comparator and mux implement the cross-over logic.

Serializing the Output

Once the forwarder copies packet data into the egress buffer, the egress controller reads it back out one byte at a time. A read pointer register steps through the RAM addresses, outputting each byte with a valid signal.

The RAM is pre-loaded with 8 bytes of test data: 0xAA, 0xBB, 0xCC, etc. Toggle the enable switch and tick repeatedly to watch the pointer advance through the data. When the pointer reaches 7, the doneLed lights up — the packet is fully serialized.

In the full switch, this same mechanism operates on each output port independently — both ports can serialize their egress buffers simultaneously.

Compiling...
Packet Serializer
Reads bytes from RAM one at a time and outputs them with a valid signal. A counter tracks progress and signals when the packet is complete.

The Full 2-Port Switch

Everything we’ve built — frame detection, packet buffering, fair arbitration, crossbar routing, and byte serialization — comes together in one circuit. The full MiniSwitch2Port has two complete data paths, each with its own parser, ingress controller, and egress controller, connected through a shared arbiter and forwarder.

Click Send Packet on either port to inject a full Ethernet frame (preamble + 8 data bytes). The circuit parses the frame, buffers it, wins arbitration, routes it across the crossbar to the opposite port, and serializes it out. Watch the activity log to follow each byte through the pipeline.

Try sending on both ports to see the arbiter alternate fairly. Use Free Run to let the switch tick continuously, or Step to advance one clock cycle at a time.

Loading network switch circuit...

This is a simplified but structurally accurate model of how real network switches work. Production switches use wider buses, deeper buffers, and more sophisticated routing tables — but the architecture is the same: parse, buffer, arbitrate, route, serialize.

The key insight is that a switch is not a computer running networking software. It’s a circuit that performs packet forwarding in hardware. Every stage runs concurrently: while one packet is being serialized out of port 0, another can be parsed and buffered on port 1. This pipeline parallelism is why hardware switches can forward millions of packets per second — far faster than any software router.