io core with ethernet working!

This commit is contained in:
Fischer Moseley 2024-02-04 14:29:39 -08:00
parent a75a6a3ccf
commit a5afad6992
8 changed files with 151 additions and 26 deletions

12
.gitignore vendored
View File

@ -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/*

View File

@ -65,4 +65,4 @@ if __name__ == "__main__":
# 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()

View File

@ -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

View File

@ -1,17 +1,40 @@
from manta import Manta
import socket
import time
if __name__ == "__main__":
ip_address = "192.168.0.110"
udp_port = 42069
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")
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(bytes_out, (fpga_ip_addr, udp_port))
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)
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(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
project_1/test.py Normal file
View File

@ -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)

View File

@ -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())
@ -76,7 +77,7 @@ class EthernetInterface(Elaboratable):
# ("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
@ -86,7 +87,7 @@ class EthernetInterface(Elaboratable):
("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),
@ -111,6 +112,78 @@ class EthernetInterface(Elaboratable):
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):
@ -142,7 +215,7 @@ class UDPSourceBridge(Elaboratable):
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
@ -163,9 +236,9 @@ class UDPSinkBridge(Elaboratable):
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

View File

@ -179,8 +179,9 @@ class UARTInterface(Elaboratable):
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)])

View File

@ -17,6 +17,7 @@ class InternalBus(data.StructLayout):
"data": 16,
"rw": 1,
"valid": 1,
"last": 1,
}
)