| // | |
| // 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); | |
| } | |
| } | |
| } | |
| } | |
| } |