215 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			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,
 | |
|         }
 | |
|     }
 | |
| }
 |