// // Copyright (c) 2010-2018 Antmicro // // This file is licensed under the MIT License. // Full license text is available in 'licenses/MIT.txt'. // using System.Collections.Generic; using Antmicro.Renode.Peripherals.Bus; using Antmicro.Renode.Core.Structure.Registers; using Antmicro.Renode.Core; using Antmicro.Renode.Logging; namespace Antmicro.Renode.Peripherals.UART { public class ESP32_UART : UARTBase, IDoubleWordPeripheral, IBytePeripheral, IKnownSize { public ESP32_UART(Machine machine) : base(machine) { IRQ = new GPIO(); var registersMap = new Dictionary { {(long)Registers.FIFO, new DoubleWordRegister(this) .WithValueField(0, 8, writeCallback: (_, value) => this.TransmitCharacter((byte)value), valueProviderCallback: _ => { if(!TryGetCharacter(out var character)) { this.Log(LogLevel.Warning, "Trying to read from an empty FIFO."); } return character; }) }, {(long)Registers.INT_ENA, new DoubleWordRegister(this) .WithFlag(0, FieldMode.Write, name: "UART_RXFIFO_FULL_INT_ENA") }, {(long)Registers.INT_CLR, new DoubleWordRegister(this) .WithValueField(0, 32, FieldMode.Write) // Temporary hack }, {(long)Registers.RX_FILT, new DoubleWordRegister(this) .WithValueField(0, 8, FieldMode.Read | FieldMode.Write, name: "GLITCH_FILT") // when input pulse width is lower than this value, the pulse is ignored. .WithFlag(8, FieldMode.Read | FieldMode.Write, name: "GLITCH_FILT_EN") // Set this bit to enable Rx signal filter. }, {(long)Registers.STATUS, new DoubleWordRegister(this) .WithValueField(0, 10, FieldMode.Read, name: "RXFIFO_CNT") .WithFlag(13, FieldMode.Read, name: "UART_DSRN") .WithFlag(14, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_CTSN") .WithFlag(15, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_RXD") .WithValueField(16, 10, FieldMode.Read, name: "TXFIFO_CNT") .WithFlag(29, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_DTRN") .WithFlag(30, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_RTSN") .WithFlag(31, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_TXD") }, {(long)Registers.CONF0, new DoubleWordRegister(this) .WithFlag(0, FieldMode.Write, name: "UART_PARITY") .WithFlag(1, FieldMode.Write, name: "UART_PARITY_EN") .WithValueField(2, 2, FieldMode.Read, name: "UART_BIT_NUM") .WithValueField(4, 2, FieldMode.Read, name: "UART_STOPBIT_NUM") .WithFlag(17, FieldMode.Write, name: "UART_RXFIFO_RST") .WithFlag(18, FieldMode.Write, name: "UART_TXFIFO_RST") .WithFlag(26, FieldMode.Write, name: "UART_ERR_WR_MASK") .WithFlag(27, FieldMode.Write, name: "UART_AUTOBAUD_EN") }, {(long)Registers.CONF1, new DoubleWordRegister(this) .WithValueField(0, 10, FieldMode.Read | FieldMode.Write, name: "RXFIFO_FULL_THRHD") // It will produce rxfifo_full_int interrupt when receiver receives more data than this register value. .WithValueField(10, 10, FieldMode.Read | FieldMode.Write, name: "TXFIFO_EMPTY_THRHD") // It will produce txfifo_empty_int interrupt when the data amount in Tx-FIFO is less than this register value. .WithFlag(20, FieldMode.Read | FieldMode.Write, name: "DIS_RX_DAT_OVF") // Disable UART Rx data overflow detect. .WithFlag(21, FieldMode.Read | FieldMode.Write, name: "RX_TOUT_FLOW_DIS") // Set this bit to stop accumulating idle_cnt when hardware flow control works. .WithFlag(22, FieldMode.Read | FieldMode.Write, name: "RX_FLOW_EN") // This is the flow enable bit for UART receiver. .WithFlag(23, FieldMode.Read | FieldMode.Write, name: "RX_TOUT_EN") // This is the enble bit for uart receiver's timeout function. }, {(long)Registers.RXD_CNT, new DoubleWordRegister(this) .WithValueField(0, 10, FieldMode.Read, name: "RXD_EDGE_CNT") // This register stores the count of rxd edge change. It is used in baud rate-detect process. }, {(long)Registers.CLKDIV, new DoubleWordRegister(this) .WithValueField(0, 12, FieldMode.Read | FieldMode.Write, name: "CLKDIV") // Clock divider configuration .WithValueField(20, 4, FieldMode.Read | FieldMode.Write, name: "FRAG") // The decimal part of the frequency divider factor. }, {(long)Registers.CLK_CONF, new DoubleWordRegister(this) .WithValueField(0, 6, FieldMode.Read | FieldMode.Write, name: "SCLK_DIV_B") // The denominator of the frequency divider factor. .WithValueField(6, 6, FieldMode.Read | FieldMode.Write, name: "SCLK_DIV_A") // The numerator of the frequency divider factor. .WithValueField(12, 8, FieldMode.Read | FieldMode.Write, name: "SCLK_DIV_NUM") // The integral part of the frequency divider factor. .WithValueField(20, 2, FieldMode.Read | FieldMode.Write, name: "SCLK_SEL") // UART clock source select. 1: 80Mhz, 2: 8Mhz, 3: XTAL. .WithFlag(22, FieldMode.Read | FieldMode.Write, name: "SCLK_EN") // Set this bit to enable UART Tx/Rx clock. .WithFlag(23, FieldMode.Read | FieldMode.Write, name: "RST_CORE") // Write 1 then write 0 to this bit, reset UART Tx/Rx. .WithFlag(24, FieldMode.Read | FieldMode.Write, name: "TX_SCLK_EN") // Set this bit to enable UART Tx clock. .WithFlag(25, FieldMode.Read | FieldMode.Write, name: "RX_SCLK_EN") // Set this bit to enable UART Rx clock. .WithFlag(26, FieldMode.Read | FieldMode.Write, name: "TX_RST_CORE") // Write 1 then write 0 to this bit, reset UART Tx. .WithFlag(27, FieldMode.Read | FieldMode.Write, name: "RX_RST_CORE") // Write 1 then write 0 to this bit, reset UART Rx. }, }; registers = new DoubleWordRegisterCollection(this, registersMap); } public uint ReadDoubleWord(long offset) { return registers.Read(offset); } public byte ReadByte(long offset) { if (offset % 4 != 0) { // in the current configuration, only the lowest byte // contains a meaningful data return 0; } return (byte)ReadDoubleWord(offset); } public override void Reset() { base.Reset(); registers.Reset(); UpdateInterrupts(); } public void WriteDoubleWord(long offset, uint value) { registers.Write(offset, value); } public void WriteByte(long offset, byte value) { if (offset % 4 != 0) { // in the current configuration, only the lowest byte // contains a meaningful data return; } WriteDoubleWord(offset, value); } public long Size => 0x100; public GPIO IRQ { get; private set; } public override Bits StopBits => Bits.One; public override Parity ParityBit => Parity.None; public override uint BaudRate => 115200; protected override void CharWritten() { UpdateInterrupts(); } protected override void QueueEmptied() { UpdateInterrupts(); } private void UpdateInterrupts() { IRQ.Set(false); } private IFlagRegisterField rxEventEnabled; private IFlagRegisterField rxEventPending; private readonly DoubleWordRegisterCollection registers; private enum Registers : long { // FIFO Configuration FIFO = 0x00, MEM_CONF = 0x60, // UART interrupt register INT_RAW = 0x04, INT_ST = 0x08, INT_ENA = 0x0c, INT_CLR = 0x10, // Configuration register CLKDIV = 0x14, RX_FILT = 0x18, CONF0 = 0x20, CONF1 = 0x24, FLOW_CONF = 0x34, SLEEP_CONF = 0x38, SWFC_CONF0 = 0x3c, SWFC_CONF1 = 0x40, TXBRK_CONF = 0x44, IDLE_CONF = 0x48, RS485_CONF = 0x4c, CLK_CONF = 0x78, // Status register STATUS = 0x1c, MEM_TX_STATUS = 0x64, MEM_RX_STATUS = 0x68, FSM_STATUS = 0x6c, // Autobaud register LOWPULSE = 0x28, HIGHPULSE = 0x2c, RXD_CNT = 0x30, POSPULSE = 0x70, NEGPULSE = 0x74, // Escape sequence selection configuration AT_CMD_PRECNT = 0x50, AT_CMD_POSTCNT = 0x54, AT_CMD_GAPTOUT = 0x58, AT_CMD_CHAR = 0x5c, // Version DATE = 0x7c, ID = 0x80, } } }