blob: d557345a605ffb4290fd36b643df06433d07492b [file] [log] [blame]
//
// Copyright (c) 2021 Google LLC
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Concurrent;
// This is a very simple Renode periperal that provides a byte-oriented
// communication port to the simulated SOC that's backed by a network port on
// the host workstation. The port is intended for debugging only - it has no
// real flow control, no interrupts, no error checking - but it should be around
// 5x faster than using a real UART model to communicate with your SOC.
//
// Add this to your SOC .repl file:
//
// net_uart: NetUart @ sysbus <base_address>
// name: "NetUart"
// port: <network_port>
//
// Communicate with the port in your firmware like this:
//
// struct NetUart {
// uint32_t avail;
// uint32_t read;
// uint32_t write;
// };
// volatile NetUart* net_uart = reinterpret_cast<NetUart*>(base_address);
//
// uint8_t get_byte() {
// while (!net_uart->avail) {}
// return net_uart->read;
// };
//
// void set_byte(uint8_t b) {
// net_uart->write = b;
// };
//
// And then you can run "telnet localhost <network_port>" on your workstation to
// communicate with your SOC.
namespace Antmicro.Renode.Peripherals
{
public class NetUart : IDoubleWordPeripheral, IKnownSize
{
public long Size => 0x12;
TcpListener listener = null;
Socket client = null;
byte[] buffer = null;
Thread accept_thread;
string name;
public NetUart(string name, int port) {
this.name = name;
listener = new TcpListener(port);
listener.Start();
this.Log(LogLevel.Info, "NetUart '{0}' starting at {1}", name, listener.LocalEndpoint);
buffer = new byte[4096];
accept_thread = new Thread(Accept);
accept_thread.Start();
}
public void Accept() {
while(true) {
Socket new_client = listener.AcceptSocket();
this.Log(LogLevel.Info, "NetUart '{0}' got connection from {1}", name, new_client.RemoteEndPoint);
lock (this) {
client = new_client;
}
}
}
public void Reset() {
}
public uint ReadDoubleWord(long offset) {
lock(this) {
if (client == null) {
return 0;
}
else if (offset == 0) {
return (uint)client.Available;
}
else if (offset == 4 && client.Available > 0) {
client.Receive(buffer, 1, 0);
return buffer[0];
}
else {
return 0;
}
}
}
public void WriteDoubleWord(long offset, uint value) {
lock(this) {
if (client != null && offset == 8) {
buffer[0] = (byte)value;
client.Send(buffer, 1, 0);
}
}
}
}
}