io core with ethernet working!
This commit is contained in:
parent
a75a6a3ccf
commit
a5afad6992
|
|
@ -13,4 +13,14 @@ build/
|
||||||
*.v
|
*.v
|
||||||
*.sv
|
*.sv
|
||||||
*.vcd
|
*.vcd
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
|
# Vivado files from the occasional debugging sesh
|
||||||
|
*.log
|
||||||
|
*.jou
|
||||||
|
*.rpt
|
||||||
|
*.bin
|
||||||
|
*.bit
|
||||||
|
*.out
|
||||||
|
*.xdc
|
||||||
|
.Xil/*
|
||||||
|
|
@ -65,4 +65,4 @@ if __name__ == "__main__":
|
||||||
# for _ in range(64):
|
# for _ in range(64):
|
||||||
# send_to_host_test("192.168.0.107", 42069)
|
# send_to_host_test("192.168.0.107", 42069)
|
||||||
# leds_test(ip_address, udp_port)
|
# leds_test(ip_address, udp_port)
|
||||||
send_variable_length_test()
|
# send_variable_length_test()
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,18 @@ cores:
|
||||||
led: 16
|
led: 16
|
||||||
|
|
||||||
ethernet:
|
ethernet:
|
||||||
desired_fpga_ip: "192.168.0.110"
|
phy: LiteEthPHYRMII
|
||||||
host_ip: "192.168.0.107"
|
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
|
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
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,40 @@
|
||||||
from manta import Manta
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
def write(addrs, datas):
|
||||||
|
bytes_out = b""
|
||||||
if __name__ == "__main__":
|
for addr, data in zip(addrs, datas):
|
||||||
ip_address = "192.168.0.110"
|
bytes_out += int(1).to_bytes(4, byteorder="little")
|
||||||
udp_port = 42069
|
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 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.sendto(bytes_out, (fpga_ip_addr, udp_port))
|
||||||
|
|
||||||
for i in range(256):
|
def read(addrs):
|
||||||
data = [0, 0]
|
bytes_out = b""
|
||||||
data = [int(d).to_bytes(4, byteorder="big") for d in data]
|
for addr in addrs:
|
||||||
data = b"".join(data)
|
bytes_out += int(0).to_bytes(4, byteorder="little")
|
||||||
print(data)
|
bytes_out += int(addr).to_bytes(2, byteorder="little")
|
||||||
sock.sendto(data, (ip_address, udp_port))
|
bytes_out += int(0).to_bytes(2, byteorder="little")
|
||||||
# time.sleep(0.2)
|
|
||||||
|
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])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
from amaranth import *
|
from amaranth import *
|
||||||
from manta.utils import *
|
from manta.utils import *
|
||||||
|
import socket
|
||||||
|
|
||||||
|
|
||||||
class EthernetInterface(Elaboratable):
|
class EthernetInterface(Elaboratable):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.desired_fpga_ip = config["desired_fpga_ip"]
|
self.fpga_ip_addr = config["fpga_ip_addr"]
|
||||||
self.host_ip = config["host_ip"]
|
self.host_ip_addr = config["host_ip_addr"]
|
||||||
self.udp_port = config["udp_port"]
|
self.udp_port = config["udp_port"]
|
||||||
|
|
||||||
self.bus_i = Signal(InternalBus())
|
self.bus_i = Signal(InternalBus())
|
||||||
|
|
@ -76,7 +77,7 @@ class EthernetInterface(Elaboratable):
|
||||||
# ("o", "dhcp_ip_address", 1),
|
# ("o", "dhcp_ip_address", 1),
|
||||||
("i", "dhcp_start", self.dhcp_start),
|
("i", "dhcp_start", self.dhcp_start),
|
||||||
# ("o", "dhcp_timeout", 1),
|
# ("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
|
# UDP Port
|
||||||
("i", "udp0_udp_port", self.udp_port),
|
("i", "udp0_udp_port", self.udp_port),
|
||||||
# UDP from host
|
# UDP from host
|
||||||
|
|
@ -86,7 +87,7 @@ class EthernetInterface(Elaboratable):
|
||||||
("i", "udp0_source_ready", self.source_ready),
|
("i", "udp0_source_ready", self.source_ready),
|
||||||
("o", "udp0_source_valid", self.source_valid),
|
("o", "udp0_source_valid", self.source_valid),
|
||||||
# UDP back to host
|
# 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_data", self.sink_data),
|
||||||
("i", "udp0_sink_last", self.sink_last),
|
("i", "udp0_sink_last", self.sink_last),
|
||||||
("o", "udp0_sink_ready", self.sink_ready),
|
("o", "udp0_sink_ready", self.sink_ready),
|
||||||
|
|
@ -111,6 +112,78 @@ class EthernetInterface(Elaboratable):
|
||||||
|
|
||||||
return m
|
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):
|
class UDPSourceBridge(Elaboratable):
|
||||||
def __init__(self):
|
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.data.eq(self.data_i[16:])
|
||||||
m.d.sync += self.bus_o.rw.eq(rw_buf)
|
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.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
|
return m
|
||||||
|
|
||||||
|
|
@ -163,9 +236,9 @@ class UDPSinkBridge(Elaboratable):
|
||||||
m.d.sync += self.last_o.eq(0)
|
m.d.sync += self.last_o.eq(0)
|
||||||
m.d.sync += self.valid_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.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)
|
m.d.sync += self.valid_o.eq(1)
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
|
|
||||||
|
|
@ -179,8 +179,9 @@ class UARTInterface(Elaboratable):
|
||||||
if not all(isinstance(d, int) for d in datas):
|
if not all(isinstance(d, int) for d in datas):
|
||||||
raise ValueError("Write data must all be integers.")
|
raise ValueError("Write data must all be integers.")
|
||||||
|
|
||||||
# I'm not sure if it's necessary to split outputs into chunks
|
# Since the FPGA doesn't issue any responses to write requests, we
|
||||||
# I think the output buffer doesn't really drop stuff, just the input buffer
|
# 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
|
# 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)])
|
bytes_out = "".join([f"W{a:04X}{d:04X}\r\n" for a, d in zip(addrs, datas)])
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class InternalBus(data.StructLayout):
|
||||||
"data": 16,
|
"data": 16,
|
||||||
"rw": 1,
|
"rw": 1,
|
||||||
"valid": 1,
|
"valid": 1,
|
||||||
|
"last": 1,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue