Skip to content

Commit

Permalink
io core with ethernet working!
Browse files Browse the repository at this point in the history
  • Loading branch information
fischermoseley committed Feb 4, 2024
1 parent a75a6a3 commit a5afad6
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 25 deletions.
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,14 @@ build/
*.v
*.sv
*.vcd
*.out
*.out

# Vivado files from the occasional debugging sesh
*.log
*.jou
*.rpt
*.bin
*.bit
*.out
*.xdc
.Xil/*
2 changes: 1 addition & 1 deletion project_0/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ def send_to_host_test(host_ip, udp_port):
# for _ in range(64):
# send_to_host_test("192.168.0.107", 42069)
# leds_test(ip_address, udp_port)
send_variable_length_test()
# send_variable_length_test()
16 changes: 14 additions & 2 deletions project_1/manta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ cores:
led: 16

ethernet:
desired_fpga_ip: "192.168.0.110"
host_ip: "192.168.0.107"
phy: LiteEthPHYRMII
vendor: xilinx
toolchain: vivado

refclk_freq: 50e6
clk_freq: 50e6

fpga_ip_addr: "192.168.0.110"
host_ip_addr: "192.168.0.100"
udp_port: 42069

core: udp # we handle this
mac_address: # this should be optional
dhcp: # should be optional, default to true?
data_width: 32 # using DHCP will force this to 32, but for ease of use we should design for that even for static IP devices
47 changes: 35 additions & 12 deletions project_1/stream.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
from manta import Manta
import socket
import time
def write(addrs, datas):
bytes_out = b""
for addr, data in zip(addrs, datas):
bytes_out += int(1).to_bytes(4, byteorder="little")
bytes_out += int(addr).to_bytes(2, byteorder="little")
bytes_out += int(data).to_bytes(2, byteorder="little")

if __name__ == "__main__":
ip_address = "192.168.0.110"
udp_port = 42069
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(bytes_out, (fpga_ip_addr, udp_port))

def read(addrs):
bytes_out = b""
for addr in addrs:
bytes_out += int(0).to_bytes(4, byteorder="little")
bytes_out += int(addr).to_bytes(2, byteorder="little")
bytes_out += int(0).to_bytes(2, byteorder="little")

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((host_ip_addr, udp_port))
sock.sendto(bytes_out, (fpga_ip_addr, udp_port))
data, addr = sock.recvfrom(1024)

return int.from_bytes(data, "little")

if __name__ == "__main__":
host_ip_addr = "192.168.0.100"
fpga_ip_addr = "192.168.0.110"
udp_port = 42069

for i in range(256):
data = [0, 0]
data = [int(d).to_bytes(4, byteorder="big") for d in data]
data = b"".join(data)
print(data)
sock.sendto(data, (ip_address, udp_port))
# time.sleep(0.2)
for i in range(2**16):
write([0x0000],[0x0000])
write([0x0000],[0x0001])
write([0x0000],[0x0000])
write([0x0002],[i])
# print(read([0x0002]))
# write([0x0002],[0b0101_0101_0101_0101])
# write([0x0000],[0x0000])
# write([0x0000],[0x0001])
# write([0x0000],[0x0000])
5 changes: 5 additions & 0 deletions project_1/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from manta import Manta
m = Manta("manta.yaml")

print(bin(m.io_core.get_probe("sw")))
m.io_core.set_probe("led", 4)
87 changes: 80 additions & 7 deletions src/manta/ethernet.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from amaranth import *
from manta.utils import *
import socket


class EthernetInterface(Elaboratable):
def __init__(self, config):
self.desired_fpga_ip = config["desired_fpga_ip"]
self.host_ip = config["host_ip"]
self.fpga_ip_addr = config["fpga_ip_addr"]
self.host_ip_addr = config["host_ip_addr"]
self.udp_port = config["udp_port"]

self.bus_i = Signal(InternalBus())
Expand Down Expand Up @@ -76,7 +77,7 @@ def elaborate(self, platform):
# ("o", "dhcp_ip_address", 1),
("i", "dhcp_start", self.dhcp_start),
# ("o", "dhcp_timeout", 1),
("i", "ip_address", self.binarize_ip_addr(self.desired_fpga_ip)),
("i", "ip_address", self.binarize_ip_addr(self.fpga_ip_addr)),
# UDP Port
("i", "udp0_udp_port", self.udp_port),
# UDP from host
Expand All @@ -86,7 +87,7 @@ def elaborate(self, platform):
("i", "udp0_source_ready", self.source_ready),
("o", "udp0_source_valid", self.source_valid),
# UDP back to host
("i", "udp0_ip_address", self.binarize_ip_addr(self.host_ip)),
("i", "udp0_ip_address", self.binarize_ip_addr(self.host_ip_addr)),
("i", "udp0_sink_data", self.sink_data),
("i", "udp0_sink_last", self.sink_last),
("o", "udp0_sink_ready", self.sink_ready),
Expand All @@ -111,6 +112,78 @@ def elaborate(self, platform):

return m

def read(self, addrs):
"""
Read the data stored in a set of address on Manta's internal memory. Addresses
must be specified as either integers or a list of integers.
"""

# Handle a single integer address
if isinstance(addrs, int):
return self.read([addrs])[0]

# Make sure all list elements are integers
if not all(isinstance(a, int) for a in addrs):
raise ValueError("Read address must be an integer or list of integers.")

# Send read requests, and get responses
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((self.host_ip_addr, self.udp_port))
chunk_size = 128
addr_chunks = split_into_chunks(addrs, chunk_size)
datas = []

for addr_chunk in addr_chunks:
bytes_out = b""
for addr in addr_chunk:
bytes_out += int(0).to_bytes(4, byteorder="little")
bytes_out += int(addr).to_bytes(2, byteorder="little")
bytes_out += int(0).to_bytes(2, byteorder="little")

sock.sendto(bytes_out, (self.fpga_ip_addr, self.udp_port))
data, addr = sock.recvfrom(4 * chunk_size)

# Split into groups of four bytes
datas += [int.from_bytes(d, "little") for d in split_into_chunks(data, 4)]

return datas

def write(self, addrs, datas):
"""
Write the provided data into the provided addresses in Manta's internal memory.
Addresses and data must be specified as either integers or a list of integers.
"""

# Handle a single integer address and data
if isinstance(addrs, int) and isinstance(datas, int):
return self.write([addrs], [datas])

# Make sure address and datas are all integers
if not isinstance(addrs, list) or not isinstance(datas, list):
raise ValueError(
"Write addresses and data must be an integer or list of integers."
)

if not all(isinstance(a, int) for a in addrs):
raise ValueError("Write addresses must be all be integers.")

if not all(isinstance(d, int) for d in datas):
raise ValueError("Write data must all be integers.")

# Since the FPGA doesn't issue any responses to write requests, we
# the host's input buffer isn't written to, and we don't need to
# send the data as chunks as the to avoid overflowing the input buffer.

# Encode addrs and datas into write requests
bytes_out = b""
for addr, data in zip(addrs, datas):
bytes_out += int(1).to_bytes(4, byteorder="little")
bytes_out += int(addr).to_bytes(2, byteorder="little")
bytes_out += int(data).to_bytes(2, byteorder="little")

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(bytes_out, (self.fpga_ip_addr, self.udp_port))


class UDPSourceBridge(Elaboratable):
def __init__(self):
Expand Down Expand Up @@ -142,7 +215,7 @@ def elaborate(self, platform):
m.d.sync += self.bus_o.data.eq(self.data_i[16:])
m.d.sync += self.bus_o.rw.eq(rw_buf)
m.d.sync += self.bus_o.valid.eq(1)
# m.d.sync += self.bus_o.last.eq(self.last_i)
m.d.sync += self.bus_o.last.eq(self.last_i)

return m

Expand All @@ -163,9 +236,9 @@ def elaborate(self, platform):
m.d.sync += self.last_o.eq(0)
m.d.sync += self.valid_o.eq(0)

with m.If(self.bus_i.valid):
with m.If( (self.bus_i.valid) & (~self.bus_i.rw)):
m.d.sync += self.data_o.eq(self.bus_i.data)
# m.d.sync += self.last_o.eq(self.bus_i.last)
m.d.sync += self.last_o.eq(self.bus_i.last)
m.d.sync += self.valid_o.eq(1)

return m
5 changes: 3 additions & 2 deletions src/manta/uart/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ def write(self, addrs, datas):
if not all(isinstance(d, int) for d in datas):
raise ValueError("Write data must all be integers.")

# I'm not sure if it's necessary to split outputs into chunks
# I think the output buffer doesn't really drop stuff, just the input buffer
# Since the FPGA doesn't issue any responses to write requests, we
# the host's input buffer isn't written to, and we don't need to
# send the data as chunks as the to avoid overflowing the input buffer.

# Encode addrs and datas into write requests
bytes_out = "".join([f"W{a:04X}{d:04X}\r\n" for a, d in zip(addrs, datas)])
Expand Down
1 change: 1 addition & 0 deletions src/manta/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self):
"data": 16,
"rw": 1,
"valid": 1,
"last": 1,
}
)

Expand Down

0 comments on commit a5afad6

Please sign in to comment.