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