renode-esp32s3/peripherals/ESP32_UART.cs

215 lines
9.6 KiB
C#

//
// 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, DoubleWordRegister>
{
{(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,
}
}
}