io core with ethernet working!
This commit is contained in:
parent
a75a6a3ccf
commit
a5afad6992
|
|
@ -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/*
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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 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
|
||||
|
|
|
|||
|
|
@ -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)])
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class InternalBus(data.StructLayout):
|
|||
"data": 16,
|
||||
"rw": 1,
|
||||
"valid": 1,
|
||||
"last": 1,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue