initial commit

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2023-07-24 12:00:46 +08:00
commit 1166c4ce41
20 changed files with 69682 additions and 0 deletions

41
.gitattributes vendored Normal file
View File

@ -0,0 +1,41 @@
# Various C code
*.h text eol=lf
*.c text eol=lf
*.s text eol=lf
*.S text eol=lf
# Rust code
*.rs text eol=lf
*.toml text eol=lf
*.lock text eol=lf
# Misc scripting files
Makefile text eol=lf
*.mk text eol=lf
*.sh text eol=lf
*.ps1 text eol=crlf
*.py text eol=lf
# Human-readable files
*.md eol=lf
README.* text eol=lf
LICENSE text eol=lf
*.txt text eol=lf
# Binary files
*.dfu binary
*.png binary
*.jpg binary
*.bin binary
*.elf binary
# Git configuration files
.gitignore text eol=lf
.gitattributes text eol=lf
# System description files
*.svd eol=lf
# JSON
*.json eol=lf

48
.gitignore vendored Normal file
View File

@ -0,0 +1,48 @@
**/*.rs.bk
/peripherals.csproj
/emulation/obj
*.map
# Emacs
*~
# local utility shellscripts
update-precursors.sh
buildpush.ps1
# local-only routines used to start builds
/*.ps1
/*.bat
/*.sh
# notes to myself
/*.txt
tools/test-backup-analyze.sh
# don't record weirdnesses dealing with vscode
.vscode
.vs
settings.json
# Emacs backup files
*~
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
*.pyc
MANIFEST

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# Platonic RISC-V Device
Platonic is an ideal system useful for developing an operating system. It does not represent any sort of real hardware, though differences between platforms is minimal.
## Usage
For emulation, you will need to install Renode (use the [nightly](https://dl.antmicro.com/projects/renode/builds/) to get `SPI.NORFlash` peripheral support). Then, run `renode` on `xous-release.resc`. For example:
```
renode emulation/xous-resc.repl
```
## Editing Renode Peripherals
Renode supports adding peripherals written in C#. For example, many Betrusted peripherals have models created under the `peripherals/` directory.
Since there is no external compiler, it can be difficult to know if your code is correct. In fact, if you're unfamiliar with C# or the Renode codebase, editing unfamiliar C# code can be a slow exercise in frustration.
Fortunately, Visual Studio Code is free and has excellent C# tooling. All you need to do is point it at your Renode installation, load the C# plugin, and open a `.cs` file.
1. Copy `peripherals.csproj.template` to `peripherals.csproj`
2. Open `peripherals.csproj` and point `<RenodePath>` to your Renode installation directory. On ubuntu, this may be `/opt/renode/bin/`.
3. Install [C# for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp)
4. You can refer to [core Renode peripherals](https://github.com/renode/renode-infrastructure/tree/master/src/Emulator/Peripherals/Peripherals) as examples of what C# code looks like.
## Debugging with GDB
When running Renode, you can attach a GDB instance. It runs on port 3333. Simply run `tar ext :3333` in gdb to attach.
```
#!/bin/bash
if [ -z "$1" ]
then
echo "eg: flash.sh application.bin"
exit
fi
set -x
export FIRMWARE_PATH=$(dirname "$1")
dd if=/dev/zero bs=1M count=4 of=./flash.bin
dd if="$FIRMWARE_PATH/bootloader/bootloader.bin" bs=1 count=$(stat -c%s "$FIRMWARE_PATH/bootloader/bootloader.bin") seek=$((16#1000)) conv=notrunc of=./flash.bin
dd if="$FIRMWARE_PATH/partition_table/partition-table.bin" bs=1 count=$(stat -c%s "$FIRMWARE_PATH/partition_table/partition-table.bin") seek=$((16#8000)) conv=notrunc of=./flash.bin
dd if=$1 bs=1 count=$(stat -c%s "$1") seek=$((16#10000)) conv=notrunc of=./flash.bin
```

57
badge.repl Normal file
View File

@ -0,0 +1,57 @@
cpu: CPU.Xtensa @ sysbus
cpuType: "esp32s3"
// External data memory
edram: Memory.MappedMemory @ sysbus 0x3C000000
size: 0x2000000
// Internal data memory
dram: Memory.MappedMemory @ sysbus 0x3FC88000
size: 0x78000
// Internal data rom
irom: Memory.MappedMemory @ sysbus 0x3FF00000
size: 0x20000
// Internal instruction rom
drom: Memory.MappedMemory @ sysbus 0x40000000
size: 0x60000
// Internal instruction memory
iram: Memory.MappedMemory @ sysbus 0x40370000
size: 0x70000
// External instruction memory
eiram: Memory.MappedMemory @ sysbus 0x42000000
size: 0x2000000
// Internal RTC SLOW memory
rtcslow: Memory.MappedMemory @ sysbus 0x50000000
size: 0x2000
// Internal RTC FAST memory
rtcfast: Memory.MappedMemory @ sysbus 0x600FE000
size: 0x2000
uart0: UART.ESP32_UART @ sysbus 0x60000000
uart1: UART.ESP32_UART @ sysbus 0x60010000
extmem: Miscellaneous.ESP32S3_EXTMEM @ sysbus 0x600C4000
gpio: GPIOPort.ESP32S3_GPIO @ sysbus 0x60004000
// EFUSES
efuse: Memory.MappedMemory @ sysbus 0x60007000
size: 0x1000
// RTC Control
rtc_cntl: Miscellaneous.ESP32S3_RTC_CNTL @ sysbus 0x60008000
flash:
size: 0x200000
spiflash: SPI.Micron_MT25Q @ usart2
irq: 20
underlyingMemory: flash
sysbus:
init:
ApplySVD @esp32s3.svd

42
badge.resc Normal file
View File

@ -0,0 +1,42 @@
# Boot Renode Script (boot.resc)
# Add this script's path to the global path, so
# we can include files relative to ourselves.
path add $ORIGIN
i @peripherals/ESP32_UART.cs
i @peripherals/ESP32S3_EXTMEM.cs
i @peripherals/ESP32S3_GPIO.cs
i @peripherals/ESP32S3_RTC_CNTL.cs
using sysbus
mach create "SoC"
machine LoadPlatformDescription @badge.repl
# Silence regions we don't want to implement yet
sysbus SilenceRange <0x60038000, 0x60038FFF> # USB_DEVICE
sysbus SilenceRange <0x60080000, 0x60080FFF> # USB0
sysbus SilenceRange <0x60039000, 0x60039FFF> # USB_WRAP
machine StartGdbServer 3333 true
showAnalyzer uart0
showAnalyzer uart1
# The macro `reset` gets called implicitly when running `machine Reset`
macro reset
"""
sysbus LoadELF @blackmagic.elf
sysbus LoadBinary @partition-table.bin 0x3C008000
sysbus LoadBinary @esp32s3-irom.bin 0x40000000
sysbus LoadBinary @esp32s3-drom.bin 0x3FF00000
#sysbus LoadBinary @esp32s3-efuses.bin 0x60007000
sysbus LoadELF @bootloader.elf
cpu PC 0x40000400
"""
runMacro $reset
start

BIN
esp32s3-drom.bin Normal file

Binary file not shown.

BIN
esp32s3-efuses.bin Normal file

Binary file not shown.

BIN
esp32s3-irom.bin Normal file

Binary file not shown.

BIN
esp32s3-rtc-rom.bin Normal file

Binary file not shown.

BIN
esp32s3-rtccntrl.bin Normal file

Binary file not shown.

67737
esp32s3.svd Normal file

File diff suppressed because it is too large Load Diff

BIN
partition-table.bin Normal file

Binary file not shown.

144
peripherals.csproj.template Normal file
View File

@ -0,0 +1,144 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<PlatformTarget>AMD64</PlatformTarget>
<RenodePath>$PATH_TO_RENODE</RenodePath>
</PropertyGroup>
<ItemGroup>
<Reference Include="AdvancedLoggerViewerPlugin">
<HintPath>$(RenodePath)/AdvancedLoggerViewerPlugin.dll</HintPath>
</Reference>
<Reference Include="AntShell">
<HintPath>$(RenodePath)/AntShell.dll</HintPath>
</Reference>
<Reference Include="AsyncIO">
<HintPath>$(RenodePath)/AsyncIO.dll</HintPath>
</Reference>
<Reference Include="CookComputing.XmlRpcV2">
<HintPath>$(RenodePath)/CookComputing.XmlRpcV2.dll</HintPath>
</Reference>
<Reference Include="cores-arm">
<HintPath>$(RenodePath)/cores-arm.dll</HintPath>
</Reference>
<Reference Include="cores-arm-m">
<HintPath>$(RenodePath)/cores-arm-m.dll</HintPath>
</Reference>
<Reference Include="cores-i386">
<HintPath>$(RenodePath)/cores-i386.dll</HintPath>
</Reference>
<Reference Include="cores-ppc">
<HintPath>$(RenodePath)/cores-ppc.dll</HintPath>
</Reference>
<Reference Include="cores-ppc64">
<HintPath>$(RenodePath)/cores-ppc64.dll</HintPath>
</Reference>
<Reference Include="cores-riscv">
<HintPath>$(RenodePath)/cores-riscv.dll</HintPath>
</Reference>
<Reference Include="cores-riscv64">
<HintPath>$(RenodePath)/cores-riscv64.dll</HintPath>
</Reference>
<Reference Include="cores-sparc">
<HintPath>$(RenodePath)/cores-sparc.dll</HintPath>
</Reference>
<Reference Include="CxxDemangler">
<HintPath>$(RenodePath)/CxxDemangler.dll</HintPath>
</Reference>
<Reference Include="Dynamitey">
<HintPath>$(RenodePath)/Dynamitey.dll</HintPath>
</Reference>
<Reference Include="ELFSharp">
<HintPath>$(RenodePath)/ELFSharp.dll</HintPath>
</Reference>
<Reference Include="Emulator">
<HintPath>$(RenodePath)/Emulator.dll</HintPath>
</Reference>
<Reference Include="Extensions">
<HintPath>$(RenodePath)/Extensions.dll</HintPath>
</Reference>
<Reference Include="FdtSharp">
<HintPath>$(RenodePath)/FdtSharp.dll</HintPath>
</Reference>
<Reference Include="IronPython">
<HintPath>$(RenodePath)/IronPython.dll</HintPath>
</Reference>
<Reference Include="IronPython.Modules">
<HintPath>$(RenodePath)/IronPython.Modules.dll</HintPath>
</Reference>
<Reference Include="libtftp">
<HintPath>$(RenodePath)/libtftp.dll</HintPath>
</Reference>
<Reference Include="LLVMDisassembler">
<HintPath>$(RenodePath)/LLVMDisassembler.dll</HintPath>
</Reference>
<Reference Include="Lucene.Net">
<HintPath>$(RenodePath)/Lucene.Net.dll</HintPath>
</Reference>
<Reference Include="LZ4">
<HintPath>$(RenodePath)/LZ4.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Dynamic">
<HintPath>$(RenodePath)/Microsoft.Dynamic.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Scripting">
<HintPath>$(RenodePath)/Microsoft.Scripting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Scripting.Metadata">
<HintPath>$(RenodePath)/Microsoft.Scripting.Metadata.dll</HintPath>
</Reference>
<Reference Include="Migrant">
<HintPath>$(RenodePath)/Migrant.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil">
<HintPath>$(RenodePath)/Mono.Cecil.dll</HintPath>
</Reference>
<Reference Include="NetMQ">
<HintPath>$(RenodePath)/NetMQ.dll</HintPath>
</Reference>
<Reference Include="Nini">
<HintPath>$(RenodePath)/Nini.dll</HintPath>
</Reference>
<Reference Include="OptionsParser">
<HintPath>$(RenodePath)/OptionsParser.dll</HintPath>
</Reference>
<Reference Include="PacketDotNet">
<HintPath>$(RenodePath)/PacketDotNet.dll</HintPath>
</Reference>
<Reference Include="Renode">
<HintPath>$(RenodePath)/Renode.exe</HintPath>
</Reference>
<Reference Include="Renode-peripherals">
<HintPath>$(RenodePath)/Renode-peripherals.dll</HintPath>
</Reference>
<Reference Include="SampleCommandPlugin">
<HintPath>$(RenodePath)/SampleCommandPlugin.dll</HintPath>
</Reference>
<Reference Include="Sprache">
<HintPath>$(RenodePath)/Sprache.dll</HintPath>
</Reference>
<Reference Include="TermSharp">
<HintPath>$(RenodePath)/TermSharp.dll</HintPath>
</Reference>
<Reference Include="TracePlugin">
<HintPath>$(RenodePath)/TracePlugin.dll</HintPath>
</Reference>
<Reference Include="UI">
<HintPath>$(RenodePath)/UI.dll</HintPath>
</Reference>
<Reference Include="VerilatorPlugin">
<HintPath>$(RenodePath)/VerilatorPlugin.dll</HintPath>
</Reference>
<Reference Include="WiresharkPlugin">
<HintPath>$(RenodePath)/WiresharkPlugin.dll</HintPath>
</Reference>
<Reference Include="Xwt">
<HintPath>$(RenodePath)/Xwt.dll</HintPath>
</Reference>
<Reference Include="Xwt.WPF">
<HintPath>$(RenodePath)/Xwt.WPF.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,109 @@
//
// Copyright (c) 2010-2023 Antmicro
// Copyright (c) 2011-2015 Realtime Embedded
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
using System;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Logging;
using System.Collections.Generic;
namespace Antmicro.Renode.Peripherals.Memory
{
public class ArrayMemory : IBytePeripheral, IWordPeripheral, IDoubleWordPeripheral, IKnownSize, IMemory, IMultibyteWritePeripheral, IQuadWordPeripheral
{
public ArrayMemory(byte[] source)
{
array = source;
}
public ArrayMemory(int size)
{
array = new byte[size];
}
public virtual ulong ReadQuadWord(long offset)
{
var intOffset = (int)offset;
var result = BitConverter.ToUInt64(array, intOffset);
return result;
}
public virtual void WriteQuadWord(long offset, ulong value)
{
var bytes = BitConverter.GetBytes(value);
bytes.CopyTo(array, offset);
}
public uint ReadDoubleWord(long offset)
{
var intOffset = (int)offset;
var result = BitConverter.ToUInt32(array, intOffset);
return result;
}
public virtual void WriteDoubleWord(long offset, uint value)
{
var bytes = BitConverter.GetBytes(value);
bytes.CopyTo(array, offset);
}
public void Reset()
{
// nothing happens
}
public ushort ReadWord(long offset)
{
var intOffset = (int)offset;
var result = BitConverter.ToUInt16(array, intOffset);
return result;
}
public virtual void WriteWord(long offset, ushort value)
{
var bytes = BitConverter.GetBytes(value);
bytes.CopyTo(array, offset);
}
public byte ReadByte(long offset)
{
var intOffset = (int)offset;
var result = array[intOffset];
return result;
}
public virtual void WriteByte(long offset, byte value)
{
var intOffset = (int)offset;
array[intOffset] = value;
}
public byte[] ReadBytes(long offset, int count)
{
var result = new byte[count];
Array.Copy(array, offset, result, 0, count);
return result;
}
public void WriteBytes(long offset, byte[] bytes, int startingIndex, int count)
{
Array.Copy(bytes, startingIndex, array, offset, count);
}
public long Size
{
get
{
return array.Length;
}
}
protected readonly byte[] array;
}
}

View File

@ -0,0 +1,177 @@
//
// Copyright (c) 2010-2023 Antmicro
// Copyright (c) 2011-2015 Realtime Embedded
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
using System;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Core;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Logging;
using System.Collections.Generic;
using Antmicro.Renode.Core.Structure.Registers;
namespace Antmicro.Renode.Peripherals.Miscellaneous
{
public class ESP32S3_EXTMEM : IBytePeripheral, IDoubleWordPeripheral, IKnownSize
{
public ESP32S3_EXTMEM(Machine machine)
{
var registersMap = new Dictionary<long, DoubleWordRegister>
{
{(long)Registers.DCACHE_CTRL, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "DCACHE_ENABLE") // The bit is used to activate the data cache. 0: disable, 1: enable
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "DCACHE_SIZE_MODE") // The bit is used to configure cache memory size.0: 32KB, 1: 64KB
.WithValueField(2, 2, FieldMode.Read | FieldMode.Write, name: "DCACHE_BLOCKSIZE_MODE") // The bit is used to configure cache block size.0: 16 bytes, 1: 32 bytes,2: 64 bytes
},
{(long)Registers.DCACHE_CTRL1, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "DCACHE_SHUT_CORE0_BUS") // The bit is used to disable core0 dbus, 0: enable, 1: disable
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "DCACHE_SHUT_CORE1_BUS") // The bit is used to disable core1 dbus, 0: enable, 1: disable
},
{(long)Registers.DCACHE_SYNC_CTRL, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => false, name: "DCACHE_INVALIDATE_ENA") // The bit is used to enable invalidate operation. It will be cleared by hardware after invalidate operation done.
.WithFlag(1, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => false, name: "DCACHE_WRITEBACK_ENA") // The bit is used to enable writeback operation. It will be cleared by hardware after writeback operation done.
.WithFlag(2, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => false, name: "DCACHE_CLEAN_ENA") // The bit is used to enable clean operation. It will be cleared by hardware after clean operation done.
.WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => true, name: "DCACHE_SYNC_DONE") // The bit is used to indicate clean/writeback/invalidate operation is finished.
},
{(long)Registers.DCACHE_SYNC_ADDR, new DoubleWordRegister(this)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => 0, name: "DCACHE_SYNC_ADDR") // The bits are used to configure the start virtual address for clean operations. It should be combined with DCACHE_SYNC_SIZE_REG.
},
{(long)Registers.DCACHE_SYNC_SIZE, new DoubleWordRegister(this)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => 0, name: "DCACHE_SYNC_SIZE") // The bits are used to configure the length for sync operations. The bits are the counts of cache block. It should be combined with DCACHE_SYNC_ADDR_REG.
},
{(long)Registers.DCACHE_PRELOAD_CTRL, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => false, name: "DCACHE_PRELOAD_ENA") // The bit is used to enable preload operation. It will be cleared by hardware after preload operation done.
.WithFlag(1, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => true, name: "DCACHE_PRELOAD_DONE") // The bit is used to indicate preload operation is finished.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "DCACHE_PRELOAD_ORDER") // The bit is used to configure the direction of preload operation. 1: descending, 0: ascending.
},
{(long)Registers.DCACHE_AUTOLOAD_CTRL, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "DCACHE_AUTOLOAD_SCT0_ENA") // The bits are used to enable the first section for autoload operation.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "DCACHE_AUTOLOAD_SCT1_ENA") // The bits are used to enable the second section for autoload operation.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "DCACHE_AUTOLOAD_ENA") // The bit is used to enable and disable autoload operation. It is combined with dcache_autoload_done. 1: enable, 0: disable.
.WithFlag(3, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => true, name: "DCACHE_AUTOLOAD_DONE") // The bit is used to indicate autoload operation is finished.
.WithFlag(4, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => false, name: "DCACHE_AUTOLOAD_ORDER") // The bits are used to configure the direction of autoload. 1: descending, 0: ascending.
.WithValueField(5, 2, FieldMode.Read | FieldMode.Write, name: "DCACHE_AUTOLOAD_RQST") // The bits are used to configure trigger conditions for autoload. 0/3: cache miss, 1: cache hit, 2: both cache miss and hit.
.WithValueField(7, 2, FieldMode.Read | FieldMode.Write, name: "DCACHE_AUTOLOAD_SIZE") // The bits are used to configure the numbers of the cache block for the issuing autoload operation.
.WithFlag(9, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => false, name: "DCACHE_AUTOLOAD_BUFFER_CLEAR") // The bit is used to clear autoload buffer in dcache.
},
{(long)Registers.CACHE_ILG_INT_CLR, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "ICACHE_SYNC_OP_FAULT_INT_CLR") // The bit is used to clear interrupt by sync configurations fault.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "ICACHE_PRELOAD_OP_FAULT_INT_CLR") // The bit is used to clear interrupt by preload configurations fault.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "DCACHE_SYNC_OP_FAULT_INT_CLR") // The bit is used to clear interrupt by sync configurations fault.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "DCACHE_PRELOAD_OP_FAULT_INT_CLR") // The bit is used to clear interrupt by preload configurations fault.
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "DCACHE_WRITE_FLASH_INT_CLR") // The bit is used to clear interrupt by dcache trying to write flash.
.WithFlag(5, FieldMode.Read | FieldMode.Write, name: "MMU_ENTRY_FAULT_INT_CLR") // The bit is used to clear interrupt by mmu entry fault.
.WithFlag(6, FieldMode.Read | FieldMode.Write, name: "DCACHE_OCCUPY_EXC_INT_CLR") // The bit is used to clear interrupt by dcache trying to replace a line whose blocks all have been occupied by occupy-mode.
.WithFlag(7, FieldMode.Read | FieldMode.Write, name: "IBUS_CNT_OVF_INT_CLR") // The bit is used to clear interrupt by ibus counter overflow.
.WithFlag(8, FieldMode.Read | FieldMode.Write, name: "DBUS_CNT_OVF_INT_CLR") // The bit is used to clear interrupt by dbus counter overflow.
},
{(long)Registers.CACHE_WRAP_AROUND_CTRL, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "CACHE_FLASH_WRAP_AROUND") // The bit is used to enable wrap around mode when read data from flash.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "CACHE_SRAM_RD_WRAP_AROUND") // The bit is used to enable wrap around mode when read data from spiram.
// .WithValueField(0, 2, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => 0, name: "SW_STALL_APPCPU_C0") // {reg_sw_stall_appcpu_c1[5:0], reg_sw_stall_appcpu_c0[1:0]} == 0x86 will stall APP CPU
// .WithValueField(2, 2, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => 0, name: "SW_STALL_PROCPU_C0") // {reg_sw_stall_procpu_c1[5:0], reg_sw_stall_procpu_c0[1:0]} == 0x86 will stall PRO CPU
// .WithFlag(4, FieldMode.Read | FieldMode.Write, name: "SW_APPCPU_RST") // APP CPU SW reset
// .WithFlag(5, FieldMode.Read | FieldMode.Write, name: "SW_PROCPU_RST") // PRO CPU SW reset
// .WithFlag(6, FieldMode.Read | FieldMode.Write, name: "BB_I2C_FORCE_PD") // BB_I2C force power down
// .WithFlag(7, FieldMode.Read | FieldMode.Write, name: "BB_I2C_FORCE_PU") // BB_I2C force power up
// .WithFlag(8, FieldMode.Read | FieldMode.Write, name: "BBPLL_I2C_FORCE_PD") // BB_PLL _I2C force power down
// .WithFlag(9, FieldMode.Read | FieldMode.Write, name: "BBPLL_I2C_FORCE_PU") // BB_PLL_I2C force power up
// .WithFlag(10, FieldMode.Read | FieldMode.Write, name: "BBPLL_FORCE_PD") // BB_PLL force power down
// .WithFlag(11, FieldMode.Read | FieldMode.Write, name: "BBPLL_FORCE_PU") // BB_PLL force power up
// .WithFlag(12, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_PD") // crystall force power down
// .WithFlag(13, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_PU") // crystall force power up
// .WithValueField(14, 4, FieldMode.Read | FieldMode.Write, name: "XTL_EN_WAIT") // wait bias_sleep and current source wakeup
// .WithFlag(23, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_ISO") // No public
// .WithFlag(24, FieldMode.Read | FieldMode.Write, name: "PLL_FORCE_ISO") // No public
// .WithFlag(25, FieldMode.Read | FieldMode.Write, name: "ANALOG_FORCE_ISO") // No public
// .WithFlag(26, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_NOISO") // No public
// .WithFlag(27, FieldMode.Read | FieldMode.Write, name: "PLL_FORCE_NOISO") // No public
// .WithFlag(28, FieldMode.Read | FieldMode.Write, name: "ANALOG_FORCE_NOISO") // No public
// .WithFlag(29, FieldMode.Read | FieldMode.Write, name: "DG_WRAP_FORCE_RST") // digital wrap force reset in deep sleep
// .WithFlag(30, FieldMode.Read | FieldMode.Write, name: "DG_WRAP_FORCE_NORST") // digital core force no reset in deep sleep
// .WithFlag(31, FieldMode.Write, name: "SW_SYS_RST") // SW system reset
},
{(long)Registers.CACHE_MMU_OWNER, new DoubleWordRegister(this)
.WithValueField(7, 2, FieldMode.Read | FieldMode.Write, name: "CACHE_MMU_OWNER") // The bits are used to specify the owner of MMU.bit0: icache, bit1: dcache, bit2: dma, bit3: reserved.
},
{(long)Registers.DCACHE_FREEZE, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "ENA") // The bit is used to enable dcache freeze mode
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "MODE") // The bit is used to configure freeze mode, 0: assert busy if CPU miss 1: assert hit if CPU miss
.WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => true, name: "DONE") // The bit is used to indicate dcache freeze success
},
{(long)Registers.ICACHE_FREEZE, new DoubleWordRegister(this)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "ENA") // The bit is used to enable icache freeze mode
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "MODE") // The bit is used to configure freeze mode, 0: assert busy if CPU miss 1: assert hit if CPU miss
.WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => true, name: "DONE") // The bit is used to indicate icache freeze success
},
};
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 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 => 0x17C;
private readonly DoubleWordRegisterCollection registers;
private enum Registers : long
{
DCACHE_CTRL = 0x00,
DCACHE_CTRL1 = 0x04,
DCACHE_SYNC_CTRL = 0x28,
DCACHE_SYNC_ADDR = 0x2C,
DCACHE_SYNC_SIZE = 0x30,
DCACHE_PRELOAD_CTRL = 0x40,
DCACHE_AUTOLOAD_CTRL = 0x4C,
CACHE_ILG_INT_CLR = 0xE0,
CACHE_WRAP_AROUND_CTRL = 0x128,
CACHE_MMU_OWNER = 0x148,
DCACHE_FREEZE = 0x150,
ICACHE_FREEZE = 0x154,
}
}
}

269
peripherals/ESP32S3_GPIO.cs Normal file
View File

@ -0,0 +1,269 @@
//
// Copyright (c) 2010-2021 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.Core;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
namespace Antmicro.Renode.Peripherals.GPIOPort
{
public class ESP32S3_GPIO : BaseGPIOPort, IDoubleWordPeripheral, IKnownSize
{
public ESP32S3_GPIO(Machine machine) : base(machine, NumberOfPins)
{
locker = new object();
IRQ = new GPIO();
registers = new DoubleWordRegisterCollection(this, BuildRegisterMap());
data = new bool[NumberOfPins];
directionOutNotIn = new bool[NumberOfPins];
interruptEnabled = new bool[NumberOfPins];
interruptRequest = new bool[NumberOfPins];
edgeSelect = new bool[NumberOfPins];
interruptConfig = new InterruptConfig[NumberOfPins];
}
public override void Reset()
{
lock(locker)
{
base.Reset();
IRQ.Unset();
registers.Reset();
for(var i = 0; i < NumberOfPins; ++i)
{
data[i] = false;
directionOutNotIn[i] = false;
interruptEnabled[i] = false;
interruptRequest[i] = false;
edgeSelect[i] = false;
interruptConfig[i] = InterruptConfig.Low;
}
}
}
public uint ReadDoubleWord(long offset)
{
lock(locker)
{
return registers.Read(offset);
}
}
public void WriteDoubleWord(long offset, uint value)
{
lock(locker)
{
registers.Write(offset, value);
}
}
public override void OnGPIO(int number, bool value)
{
// if(!CheckPinNumber(number))
// {
// return;
// }
// if(directionOutNotIn[number])
// {
// this.Log(LogLevel.Warning, "gpio {0} is set to output, signal ignored.", number);
// return;
// }
// lock(locker)
// {
// var previousState = State[number];
// base.OnGPIO(number, value);
// UpdateSingleInterruptRequest(number, value, previousState != value);
// UpdateIRQ();
// }
}
public long Size => 0x634;
public GPIO IRQ { get; }
private Dictionary<long, DoubleWordRegister> BuildRegisterMap()
{
var registersDictionary = new Dictionary<long, DoubleWordRegister>
{
{(long)Registers.STRAP, new DoubleWordRegister(this)
.WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => !EnableBootMessages, name: "GPIO46") // GND = enable boot messages
.WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => !EnterBootloader, name: "GPIO0") // GND = enter bootloader
.WithFlag(4, FieldMode.Read, valueProviderCallback: (_) => false, name: "GPIO45") // GND = VDD_SPI @ 3.3V
.WithFlag(5, FieldMode.Read, valueProviderCallback: (_) => false, name: "GPIO3") // GND = JTAG from pins, not USB
},
// {(long)Registers.Data, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, name: "GR / GPIO data register",
// writeCallback: (id, _, val) => { data[id] = val; },
// valueProviderCallback: (id, _) =>
// {
// return (directionOutNotIn[id])
// ? data[id]
// : State[id];
// })
// .WithWriteCallback((_, __) => UpdateConnections())
// },
// {(long)Registers.Direction, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, name: "GDIR / GPIO direction register",
// writeCallback: (id, _, val) => { directionOutNotIn[id] = val; },
// valueProviderCallback: (id, _) => directionOutNotIn[id])
// .WithWriteCallback((_, __) => UpdateConnections())
// },
// {(long)Registers.PadStatus, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, FieldMode.Read, name: "PSR / GPIO pad status register",
// valueProviderCallback: (id, _) => State[id])
// },
// {(long)Registers.Mask, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, name: "IMR / GPIO interrupt mask register",
// writeCallback: (id, _, val) => { interruptEnabled[id] = val; },
// valueProviderCallback: (id, _) => interruptEnabled[id])
// .WithWriteCallback((_, __) => UpdateIRQ())
// },
// {(long)Registers.Status, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, FieldMode.Read | FieldMode.WriteOneToClear, name: "ISR / GPIO interrupt status register",
// writeCallback: (id, _, val) =>
// {
// if(val)
// {
// interruptRequest[id] = false;
// }
// },
// valueProviderCallback: (id, _) => interruptRequest[id])
// .WithWriteCallback((_, __) => UpdateIRQ())
// },
// {(long)Registers.EdgeSelect, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, name: "EDGE_SEL / GPIO edge select register",
// writeCallback: (id, _, val) => { edgeSelect[id] = val; },
// valueProviderCallback: (id, _) => edgeSelect[id])
// },
// {(long)Registers.DataSet, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, FieldMode.Write, name: "DR_SET / GPIO data register SET",
// writeCallback: (id, _, __) => { data[id] = true; })
// .WithWriteCallback((_, __) => UpdateConnections())
// },
// {(long)Registers.DataClear, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, FieldMode.Write, name: "DR_CLEAR / GPIO data register CLEAR",
// writeCallback: (id, _, __) => { data[id] = false; })
// .WithWriteCallback((_, __) => UpdateConnections())
// },
// {(long)Registers.DataToggle, new DoubleWordRegister(this)
// .WithFlags(0, NumberOfPins, FieldMode.Write, name: "DR_TOGGLE / GPIO data register TOGGLE",
// writeCallback: (id, _, __) => { data[id] ^= true; })
// .WithWriteCallback((_, __) => UpdateConnections())
// },
};
// var config1 = new DoubleWordRegister(this);
// var config2 = new DoubleWordRegister(this);
// var half = NumberOfPins / 2;
// for(var i = 0; i < half; ++i)
// {
// var j = i;
// config1.WithEnumField<DoubleWordRegister, InterruptConfig>(j * 2, 2,
// name: $"ICR{j} / Interrupt configuration {j}",
// writeCallback: (_, val) => { interruptConfig[j] = val; },
// valueProviderCallback: _ => interruptConfig[j]);
// config2.WithEnumField<DoubleWordRegister, InterruptConfig>(j * 2, 2,
// name: $"ICR{half + j} / Interrupt configuration {half + j}",
// writeCallback: (_, val) => { interruptConfig[half + j] = val; },
// valueProviderCallback: _ => interruptConfig[half + j]);
// }
// config1.WithWriteCallback((_, __) => UpdateAllInterruptRequests());
// config2.WithWriteCallback((_, __) => UpdateAllInterruptRequests());
// registersDictionary.Add((long)Registers.Config1, config1);
// registersDictionary.Add((long)Registers.Config2, config2);
return registersDictionary;
}
private void UpdateIRQ()
{
var flag = false;
for(var i = 0; i < NumberOfPins; ++i)
{
flag |= interruptEnabled[i] && interruptRequest[i];
}
IRQ.Set(flag);
}
private void UpdateConnections()
{
for(var i = 0; i < NumberOfPins; ++i)
{
Connections[i].Set(directionOutNotIn[i] && data[i]);
}
UpdateIRQ();
}
private void UpdateAllInterruptRequests()
{
for(var i = 0; i < NumberOfPins; ++i)
{
UpdateSingleInterruptRequest(i, State[i]);
}
UpdateIRQ();
}
private void UpdateSingleInterruptRequest(int i, bool currentState, bool stateChanged = false)
{
if(edgeSelect[i])
{
interruptRequest[i] |= stateChanged;
}
else
{
switch(interruptConfig[i])
{
case InterruptConfig.Low:
interruptRequest[i] |= !currentState;
break;
case InterruptConfig.High:
interruptRequest[i] |= currentState;
break;
case InterruptConfig.Rising:
interruptRequest[i] |= stateChanged && currentState;
break;
case InterruptConfig.Falling:
interruptRequest[i] |= stateChanged && !currentState;
break;
default:
this.Log(LogLevel.Error, "Invalid state (interruptConfig[{0}]: 0x{1:X}).", i, interruptConfig[i]);
break;
}
}
}
private readonly DoubleWordRegisterCollection registers;
private readonly object locker;
private readonly bool[] data;
private readonly bool[] directionOutNotIn;
private readonly bool[] interruptEnabled;
private readonly bool[] interruptRequest;
private readonly bool[] edgeSelect;
private readonly InterruptConfig[] interruptConfig;
public bool EnableBootMessages = true;
public bool EnterBootloader = false;
private const int NumberOfPins = 54;
private enum InterruptConfig
{
Low = 0b00,
High = 0b01,
Rising = 0b10,
Falling = 0b11,
}
private enum Registers : long
{
STRAP = 0x38,
}
}
}

View File

@ -0,0 +1,194 @@
//
// Copyright (c) 2010-2023 Antmicro
// Copyright (c) 2011-2015 Realtime Embedded
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
using System;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Core;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Logging;
using System.Collections.Generic;
using Antmicro.Renode.Core.Structure.Registers;
namespace Antmicro.Renode.Peripherals.Miscellaneous
{
public class ESP32S3_RTC_CNTL : IBytePeripheral, IDoubleWordPeripheral, IKnownSize
{
public ESP32S3_RTC_CNTL(Machine machine)
{
var registersMap = new Dictionary<long, DoubleWordRegister>
{
{(long)Registers.OPTIONS0, new DoubleWordRegister(this)
.WithValueField(0, 2, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => 0, name: "SW_STALL_APPCPU_C0") // {reg_sw_stall_appcpu_c1[5:0], reg_sw_stall_appcpu_c0[1:0]} == 0x86 will stall APP CPU
.WithValueField(2, 2, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => 0, name: "SW_STALL_PROCPU_C0") // {reg_sw_stall_procpu_c1[5:0], reg_sw_stall_procpu_c0[1:0]} == 0x86 will stall PRO CPU
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "SW_APPCPU_RST") // APP CPU SW reset
.WithFlag(5, FieldMode.Read | FieldMode.Write, name: "SW_PROCPU_RST") // PRO CPU SW reset
.WithFlag(6, FieldMode.Read | FieldMode.Write, name: "BB_I2C_FORCE_PD") // BB_I2C force power down
.WithFlag(7, FieldMode.Read | FieldMode.Write, name: "BB_I2C_FORCE_PU") // BB_I2C force power up
.WithFlag(8, FieldMode.Read | FieldMode.Write, name: "BBPLL_I2C_FORCE_PD") // BB_PLL _I2C force power down
.WithFlag(9, FieldMode.Read | FieldMode.Write, name: "BBPLL_I2C_FORCE_PU") // BB_PLL_I2C force power up
.WithFlag(10, FieldMode.Read | FieldMode.Write, name: "BBPLL_FORCE_PD") // BB_PLL force power down
.WithFlag(11, FieldMode.Read | FieldMode.Write, name: "BBPLL_FORCE_PU") // BB_PLL force power up
.WithFlag(12, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_PD") // crystall force power down
.WithFlag(13, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_PU") // crystall force power up
.WithValueField(14, 4, FieldMode.Read | FieldMode.Write, name: "XTL_EN_WAIT") // wait bias_sleep and current source wakeup
.WithFlag(23, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_ISO") // No public
.WithFlag(24, FieldMode.Read | FieldMode.Write, name: "PLL_FORCE_ISO") // No public
.WithFlag(25, FieldMode.Read | FieldMode.Write, name: "ANALOG_FORCE_ISO") // No public
.WithFlag(26, FieldMode.Read | FieldMode.Write, name: "XTL_FORCE_NOISO") // No public
.WithFlag(27, FieldMode.Read | FieldMode.Write, name: "PLL_FORCE_NOISO") // No public
.WithFlag(28, FieldMode.Read | FieldMode.Write, name: "ANALOG_FORCE_NOISO") // No public
.WithFlag(29, FieldMode.Read | FieldMode.Write, name: "DG_WRAP_FORCE_RST") // digital wrap force reset in deep sleep
.WithFlag(30, FieldMode.Read | FieldMode.Write, name: "DG_WRAP_FORCE_NORST") // digital core force no reset in deep sleep
.WithFlag(31, FieldMode.Write, name: "SW_SYS_RST") // SW system reset
},
{(long)Registers.RESET_STATE, new DoubleWordRegister(this)
.WithValueField(0, 6, FieldMode.Read, valueProviderCallback: (_) => (ulong)ResetReason.POWERON, name: "RESET_CAUSE_PROCPU")
.WithValueField(6, 6, FieldMode.Read, valueProviderCallback: (_) => 1, name: "RESET_CAUSE_APPCPU")
.WithFlag(12, FieldMode.Read | FieldMode.Write, name: "APPCPU_STAT_VECTOR_SEL")
.WithFlag(13, FieldMode.Read | FieldMode.Write, name: "PROCPU_STAT_VECTOR_SEL")
.WithFlag(14, FieldMode.Read, valueProviderCallback: (_) => true, name: "RESET_FLAG_PROCPU")
.WithFlag(15, FieldMode.Read, valueProviderCallback: (_) => true, name: "RESET_FLAG_APPCPU")
.WithFlag(16, FieldMode.Write, name: "RESET_FLAG_PROCPU_CLR")
.WithFlag(17, FieldMode.Write, name: "RESET_FLAG_APPCPU_CLR")
.WithFlag(18, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => true, name: "PROCPU_OCD_HALT_ON_RESET")
.WithFlag(19, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => true, name: "RESET_FLAG_APPCPU")
.WithFlag(20, FieldMode.Read, valueProviderCallback: (_) => true, name: "RESET_FLAG_JTAG_PROCPU")
.WithFlag(21, FieldMode.Read, valueProviderCallback: (_) => true, name: "RESET_FLAG_JTAG_APPCPU")
.WithFlag(22, FieldMode.Write, name: "RESET_FLAG_JTAG_PROCPU_CLR")
.WithFlag(23, FieldMode.Write, name: "RESET_FLAG_JTAG_APPCPU_CLR")
.WithFlag(24, FieldMode.Read | FieldMode.Write, name: "APP_DRESET_MASK")
.WithFlag(25, FieldMode.Read | FieldMode.Write, valueProviderCallback: (_) => true, name: "PRO_DRESET_MASK")
},
{(long)Registers.PWC, new DoubleWordRegister(this)
.WithValueField(0, 32)
},
{(long)Registers.DIG_ISO, new DoubleWordRegister(this)
.WithValueField(0, 32)
},
{(long)Registers.SWD_CONF, new DoubleWordRegister(this)
.WithValueField(0, 32)
},
{(long)Registers.STORE4, new DoubleWordRegister(this)
.WithValueField(0, 32, name: "SCRATCH4")
},
{(long)Registers.DIG_PAD_HOLD, new DoubleWordRegister(this)
.WithValueField(0, 32)
},
// {(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.TxFull, new DoubleWordRegister(this)
// .WithFlag(0, FieldMode.Read) //tx is never full
// },
// {(long)Registers.RxEmpty, new DoubleWordRegister(this)
// .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => Count == 0)
// },
// {(long)Registers.EventPending, new DoubleWordRegister(this)
// // `txEventPending` implements `WriteOneToClear` semantics to avoid fake warnings
// // `txEventPending` is generated on the falling edge of TxFull; in our case it means never
// .WithFlag(0, FieldMode.Read | FieldMode.WriteOneToClear, valueProviderCallback: _ => false, name: "txEventPending")
// .WithFlag(1, out rxEventPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "rxEventPending")
// .WithWriteCallback((_, __) => UpdateInterrupts())
// },
// {(long)Registers.EventEnable, new DoubleWordRegister(this)
// .WithFlag(0, name: "txEventEnabled")
// .WithFlag(1, out rxEventEnabled)
// .WithWriteCallback((_, __) => UpdateInterrupts())
// },
};
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 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 => 0x15C;
private readonly DoubleWordRegisterCollection registers;
private enum Registers : long
{
OPTIONS0 = 0x00, // RTC common configure register
RESET_STATE = 0x38, // get reset state
PWC = 0x88, // configure rtc power
DIG_ISO = 0x94, // congigure digital power isolation
SWD_CONF = 0xB4, // congfigure super watch dog
STORE4 = 0xC0, // reserved register
DIG_PAD_HOLD = 0xDC, // configure digtal pad hold
}
private enum ResetReason : long
{
POWERON = 0x01,
JTAG = 0x02,
RTC_SW_SYS_RST = 0x03,
DSLEEP = 0x05,
TG0WDT_SYS_RST = 0x07,
TG1WDT_SYS_RST = 0x08,
RTCWDT_SYS_RST = 0x09,
INTRUSION_RST = 0x0A,
TG0WDT_CPU_RST = 0x0B,
RTC_SW_CPU_RST = 0x0C,
RTCWDT_CPU_RST = 0x0D,
BROWNOUT_RST = 0x0F,
RTCWDT_RTC_RST = 0x10,
TG01DT_CPU_RST = 0x11,
SUPER_WDT_RST = 0x12,
GLITCH_RTC_RST = 0x13,
EFUSE_RST = 0x14,
USB_UART_CHIP_RESET = 0x15,
USB_JTAG_CHIP_RESET = 0x16,
POWER_GLITCH_RESET = 0x17,
}
}
}

View File

@ -0,0 +1,435 @@
using System.Linq;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.Memory;
using Antmicro.Renode.Peripherals.MTD;
namespace Antmicro.Renode.Peripherals.SPI
{
public class ESP32_SPIController : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
{
public GPIO IRQ { get; private set; }
public DoubleWordRegisterCollection RegistersCollection { get; }
public long Size => 0x1000; // 0xb4
private readonly Machine machine;
public ESP32_SPIController(Machine machine) : base(machine)
{
this.machine = machine;
IRQ = new GPIO();
RegistersCollection = new DoubleWordRegisterCollection(this);
DefineRegisters();
Reset();
}
private void DefineRegisters()
{
// SPI1 memory command register
Registers.CMD.Define(this, 0x0)
.WithFlag(17, FieldMode.Read | FieldMode.Write, name: "FLASH_PE") // In user mode, it is set to indicate that program/erase operation will be triggered. The bit is combined with SPI_MEM_USR bit. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(18, FieldMode.Read | FieldMode.Write, name: "USR") // User define command enable. An operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(19, FieldMode.Read | FieldMode.Write, name: "FLASH_HPM") // Drive Flash into high performance mode. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(20, FieldMode.Read | FieldMode.Write, name: "FLASH_RES") // This bit combined with SPI_MEM_RESANDRES bit releases Flash from the power-down state or high performance mode and obtains the devices ID. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(21, FieldMode.Read | FieldMode.Write, name: "FLASH_DP") // Drive Flash into power down. An operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(22, FieldMode.Read | FieldMode.Write, name: "FLASH_CE") // Chip erase enable. Chip erase operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(23, FieldMode.Read | FieldMode.Write, name: "FLASH_BE") // Block erase enable(32KB) . Block erase operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(24, FieldMode.Read | FieldMode.Write, name: "FLASH_SE") // Sector erase enable(4KB). Sector erase operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(25, FieldMode.Read | FieldMode.Write, name: "FLASH_PP") // Page program enable(1 byte ~64 bytes data to be programmed). Page program operation will be triggered when the bit is set. The bit will be cleared once the operation done .1: enable 0: disable.
.WithFlag(26, FieldMode.Read | FieldMode.Write, name: "FLASH_WRSR") // Write status register enable. Write status operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(27, FieldMode.Read | FieldMode.Write, name: "FLASH_RDSR") // Read status register-1. Read status operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(28, FieldMode.Read | FieldMode.Write, name: "FLASH_RDID") // Read JEDEC ID . Read ID command will be sent when the bit is set. The bit will be cleared once the operation done. 1: enable 0: disable.
.WithFlag(29, FieldMode.Read | FieldMode.Write, name: "FLASH_WRDI") // Write flash disable. Write disable command will be sent when the bit is set. The bit will be cleared once the operation done. 1: enable 0: disable.
.WithFlag(30, FieldMode.Read | FieldMode.Write, name: "FLASH_WREN") // Write flash enable. Write enable command will be sent when the bit is set. The bit will be cleared once the operation done. 1: enable 0: disable.
.WithFlag(31, FieldMode.Read | FieldMode.Write, name: "FLASH_READ") // Read flash enable. Read flash operation will be triggered when the bit is set. The bit will be cleared once the operation done. 1: enable 0: disable.
;
// SPI1 address register
Registers.ADDR.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "USR_ADDR_VALUE") // In user mode, it is the memory address. other then the bit0-bit23 is the memory address, the bit24-bit31 are the byte length of a transfer.
;
// SPI1 control register
Registers.CTRL.Define(this, 0x2ca000)
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "FDUMMY_OUT") // In the DUMMY phase the signal level of SPI bus is output by the SPI0 controller.
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "FDOUT_OCT") // Set this bit to enable 8-bit-mode(8-bm) in DOUT phase.
.WithFlag(5, FieldMode.Read | FieldMode.Write, name: "FDIN_OCT") // Set this bit to enable 8-bit-mode(8-bm) in DIN phase.
.WithFlag(6, FieldMode.Read | FieldMode.Write, name: "FADDR_OCT") // Set this bit to enable 8-bit-mode(8-bm) in ADDR phase.
.WithFlag(7, FieldMode.Read | FieldMode.Write, name: "FCMD_DUAL") // Set this bit to enable 2-bit-mode(2-bm) in CMD phase.
.WithFlag(8, FieldMode.Read | FieldMode.Write, name: "FCMD_QUAD") // Set this bit to enable 4-bit-mode(4-bm) in CMD phase.
.WithFlag(9, FieldMode.Read | FieldMode.Write, name: "FCMD_OCT") // Set this bit to enable 8-bit-mode(8-bm) in CMD phase.
.WithFlag(10, FieldMode.Read | FieldMode.Write, name: "FCS_CRC_EN") // For SPI1, initialize crc32 module before writing encrypted data to flash. Active low.
.WithFlag(11, FieldMode.Read | FieldMode.Write, name: "TX_CRC_EN") // For SPI1, enable crc32 when writing encrypted data to flash. 1: enable 0:disable
.WithFlag(13, FieldMode.Read | FieldMode.Write, name: "FASTRD_MODE") // This bit should be set when SPI_MEM_FREAD_QIO, SPI_MEM_FREAD_DIO, SPI_MEM_FREAD_QUAD or SPI_MEM_FREAD_DUAL is set.
.WithFlag(14, FieldMode.Read | FieldMode.Write, name: "FREAD_DUAL") // In hardware 0x3B read operation, DIN phase apply 2 signals. 1: enable 0: disable.
.WithFlag(15, FieldMode.Read | FieldMode.Write, name: "RESANDRES") // The Device ID is read out to SPI_MEM_RD_STATUS register, this bit combine with spi_mem_flash_res bit. 1: enable 0: disable.
.WithFlag(18, FieldMode.Read | FieldMode.Write, name: "Q_POL") // The bit is used to set MISO line polarity, 1: high 0, low
.WithFlag(19, FieldMode.Read | FieldMode.Write, name: "D_POL") // The bit is used to set MOSI line polarity, 1: high 0, low
.WithFlag(20, FieldMode.Read | FieldMode.Write, name: "FREAD_QUAD") // In hardware 0x6B read operation, DIN phase apply 4 signals(4-bit-mode). 1: enable 0: disable.
.WithFlag(21, FieldMode.Read | FieldMode.Write, name: "WP") // Write protect signal output when SPI is idle. 1: output high, 0: output low.
.WithFlag(22, FieldMode.Read | FieldMode.Write, name: "WRSR_2B") // Two bytes data will be written to status register when it is set. 1: enable 0: disable.
.WithFlag(23, FieldMode.Read | FieldMode.Write, name: "FREAD_DIO") // In hardware 0xBB read operation, ADDR phase and DIN phase apply 2 signals(2-bit-mode). 1: enable 0: disable.
.WithFlag(24, FieldMode.Read | FieldMode.Write, name: "FREAD_QIO") // In hardware 0xEB read operation, ADDR phase and DIN phase apply 4 signals(4-bit-mode). 1: enable 0: disable.
;
// SPI1 control1 register
Registers.CTRL1.Define(this, 0xffc)
.WithValueField(0, 2, FieldMode.Read | FieldMode.Write, name: "CLK_MODE") // SPI Bus clock (SPI_CLK) mode bits. 0: SPI Bus clock (SPI_CLK) is off when CS inactive 1: SPI_CLK is delayed one cycle after SPI_CS inactive 2: SPI_CLK is delayed two cycles after SPI_CS inactive 3: SPI_CLK is always on.
.WithValueField(2, 10, FieldMode.Read | FieldMode.Write, name: "CS_HOLD_DLY_RES") // After RES/DP/HPM/PES/PER command is sent, SPI1 may waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 4 or * 256) SPI_CLK cycles.
;
// SPI1 control2 register
Registers.CTRL2.Define(this, 0x0)
.WithFlag(31, FieldMode.Read | FieldMode.Write, name: "SYNC_RESET") // The FSM will be reset.
;
// SPI_CLK clock division register when SPI1 accesses to flash or Ext_RAM.
Registers.CLOCK.Define(this, 0x30103)
.WithValueField(0, 8, FieldMode.Read | FieldMode.Write, name: "CLKCNT_L") // It must equal to the value of SPI_MEM_CLKCNT_N.
.WithValueField(8, 8, FieldMode.Read | FieldMode.Write, name: "CLKCNT_H") // It must be a floor value of ((SPI_MEM_CLKCNT_N+1)/2-1).
.WithValueField(16, 8, FieldMode.Read | FieldMode.Write, name: "CLKCNT_N") // When SPI1 accesses to flash or Ext_RAM, f_SPI_CLK = f_MSPI_CORE_CLK/(SPI_MEM_CLKCNT_N+1)
.WithFlag(31, FieldMode.Read | FieldMode.Write, name: "CLK_EQU_SYSCLK") // When SPI1 access to flash or Ext_RAM, set this bit in 1-division mode, f_SPI_CLK = f_MSPI_CORE_CLK.
;
// SPI1 user register.
Registers.USER.Define(this, 0x80000000)
.WithFlag(9, FieldMode.Read | FieldMode.Write, name: "CK_OUT_EDGE") // This bit, combined with SPI_MEM_CK_IDLE_EDGE bit, is used to change the clock mode 0~3 of SPI_CLK.
.WithFlag(12, FieldMode.Read | FieldMode.Write, name: "FWRITE_DUAL") // Set this bit to enable 2-bm in DOUT phase in SPI1 write operation.
.WithFlag(13, FieldMode.Read | FieldMode.Write, name: "FWRITE_QUAD") // Set this bit to enable 4-bm in DOUT phase in SPI1 write operation.
.WithFlag(14, FieldMode.Read | FieldMode.Write, name: "FWRITE_DIO") // Set this bit to enable 2-bm in ADDR and DOUT phase in SPI1 write operation.
.WithFlag(15, FieldMode.Read | FieldMode.Write, name: "FWRITE_QIO") // Set this bit to enable 4-bit-mode(4-bm) in ADDR and DOUT phase in SPI1 write operation.
.WithFlag(24, FieldMode.Read | FieldMode.Write, name: "USR_MISO_HIGHPART") // DIN phase only access to high-part of the buffer SPI_MEM_W8_REG~SPI_MEM_W15_REG. 1: enable 0: disable.
.WithFlag(25, FieldMode.Read | FieldMode.Write, name: "USR_MOSI_HIGHPART") // DOUT phase only access to high-part of the buffer SPI_MEM_W8_REG~SPI_MEM_W15_REG. 1: enable 0: disable.
.WithFlag(26, FieldMode.Read | FieldMode.Write, name: "USR_DUMMY_IDLE") // SPI_CLK is disabled(No clock edges) in DUMMY phase when the bit is enable.
.WithFlag(27, FieldMode.Read | FieldMode.Write, name: "USR_MOSI") // Set this bit to enable the DOUT phase of an write-data operation.
.WithFlag(28, FieldMode.Read | FieldMode.Write, name: "USR_MISO") // Set this bit to enable enable the DIN phase of a read-data operation.
.WithFlag(29, FieldMode.Read | FieldMode.Write, name: "USR_DUMMY") // Set this bit to enable enable the DUMMY phase of an operation.
.WithFlag(30, FieldMode.Read | FieldMode.Write, name: "USR_ADDR") // Set this bit to enable enable the ADDR phase of an operation.
.WithFlag(31, FieldMode.Read | FieldMode.Write, name: "USR_COMMAND") // Set this bit to enable enable the CMD phase of an operation.
;
// SPI1 user1 register.
Registers.USER1.Define(this, 0x5c000007)
.WithValueField(0, 6, FieldMode.Read | FieldMode.Write, name: "USR_DUMMY_CYCLELEN") // The SPI_CLK cycle length minus 1 of DUMMY phase.
.WithValueField(26, 6, FieldMode.Read | FieldMode.Write, name: "USR_ADDR_BITLEN") // The length in bits of ADDR phase. The register value shall be (bit_num-1).
;
// SPI1 user2 register.
Registers.USER2.Define(this, 0x70000000)
.WithValueField(0, 16, FieldMode.Read | FieldMode.Write, name: "USR_COMMAND_VALUE") // The value of user defined(USR) command.
.WithValueField(28, 4, FieldMode.Read | FieldMode.Write, name: "USR_COMMAND_BITLEN") // The length in bits of CMD phase. The register value shall be (bit_num-1)
;
// SPI1 write-data bit length register.
Registers.MOSI_DLEN.Define(this, 0x0)
.WithValueField(0, 10, FieldMode.Read | FieldMode.Write, name: "USR_MOSI_DBITLEN") // The length in bits of DOUT phase. The register value shall be (bit_num-1).
;
// SPI1 read-data bit length register.
Registers.MISO_DLEN.Define(this, 0x0)
.WithValueField(0, 10, FieldMode.Read | FieldMode.Write, name: "USR_MISO_DBITLEN") // The length in bits of DIN phase. The register value shall be (bit_num-1).
;
// SPI1 read control register.
Registers.RD_STATUS.Define(this, 0x0)
.WithValueField(0, 16, FieldMode.Read | FieldMode.Write, name: "STATUS") // The value is stored when set SPI_MEM_FLASH_RDSR bit and SPI_MEM_FLASH_RES bit.
.WithValueField(16, 8, FieldMode.Read | FieldMode.Write, name: "WB_MODE") // Mode bits in the flash fast read mode it is combined with SPI_MEM_FASTRD_MODE bit.
;
// SPI1 extended address register.
Registers.EXT_ADDR.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "EXT_ADDR") // The register are the higher 32bits in the 64 bits address mode.
;
// SPI1 misc register.
Registers.MISC.Define(this, 0x2)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "CS0_DIS") // Set this bit to raise high SPI_CS pin, which means that the SPI device(flash) connected to SPI_CS is in low level when SPI1 transfer starts.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "CS1_DIS") // Set this bit to raise high SPI_CS1 pin, which means that the SPI device(Ext_RAM) connected to SPI_CS1 is in low level when SPI1 transfer starts.
.WithFlag(9, FieldMode.Read | FieldMode.Write, name: "CK_IDLE_EDGE") // 1: SPI_CLK line is high when MSPI is idle. 0: SPI_CLK line is low when MSPI is idle.
.WithFlag(10, FieldMode.Read | FieldMode.Write, name: "CS_KEEP_ACTIVE") // SPI_CS line keep low when the bit is set.
.WithFlag(11, FieldMode.Read | FieldMode.Write, name: "AUTO_PER") // Set this bit to enable auto PER function. Hardware will sent out PER command if PES command is sent.
;
// SPI1 CRC data register.
Registers.TX_CRC.Define(this, 0xffffffff)
.WithValueField(0, 32, FieldMode.Read, name: "DATA") // For SPI1, the value of crc32.
;
// SPI1 bit mode control register.
Registers.CACHE_FCTRL.Define(this, 0x0)
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "CACHE_USR_CMD_4BYTE") // Set this bit to enable SPI1 transfer with 32 bits address. The value of SPI_MEM_USR_ADDR_BITLEN should be 31.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "FDIN_DUAL") // When SPI1 accesses to flash or Ext_RAM, set this bit to enable 2-bm in DIN phase.
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "FDOUT_DUAL") // When SPI1 accesses to flash or Ext_RAM, set this bit to enable 2-bm in DOUT phase.
.WithFlag(5, FieldMode.Read | FieldMode.Write, name: "FADDR_DUAL") // When SPI1 accesses to flash or Ext_RAM, set this bit to enable 2-bm in ADDR phase.
.WithFlag(6, FieldMode.Read | FieldMode.Write, name: "FDIN_QUAD") // When SPI1 accesses to flash or Ext_RAM, set this bit to enable 4-bm in DIN phase.
.WithFlag(7, FieldMode.Read | FieldMode.Write, name: "FDOUT_QUAD") // When SPI1 accesses to flash or Ext_RAM, set this bit to enable 4-bm in DOUT phase.
.WithFlag(8, FieldMode.Read | FieldMode.Write, name: "FADDR_QUAD") // When SPI1 accesses to flash or Ext_RAM, set this bit to enable 4-bm in ADDR phase.
;
// SPI1 state machine(FSM) status register.
Registers.FSM.Define(this, 0x0)
.WithValueField(0, 3, FieldMode.Read, name: "ST") // The status of SPI1 state machine. 0: idle state(IDLE), 1: preparation state(PREP), 2: send command state(CMD), 3: send address state(ADDR), 4: red data state(DIN), 5:write data state(DOUT), 6: wait state(DUMMY), 7: done state(DONE).
;
// SPI1 memory data buffer0
Registers.W0.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF0") // data buffer
;
// SPI1 memory data buffer1
Registers.W1.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF1") // data buffer
;
// SPI1 memory data buffer2
Registers.W2.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF2") // data buffer
;
// SPI1 memory data buffer3
Registers.W3.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF3") // data buffer
;
// SPI1 memory data buffer4
Registers.W4.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF4") // data buffer
;
// SPI1 memory data buffer5
Registers.W5.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF5") // data buffer
;
// SPI1 memory data buffer6
Registers.W6.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF6") // data buffer
;
// SPI1 memory data buffer7
Registers.W7.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF7") // data buffer
;
// SPI1 memory data buffer8
Registers.W8.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF8") // data buffer
;
// SPI1 memory data buffer9
Registers.W9.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF9") // data buffer
;
// SPI1 memory data buffer10
Registers.W10.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF10") // data buffer
;
// SPI1 memory data buffer11
Registers.W11.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF11") // data buffer
;
// SPI1 memory data buffer12
Registers.W12.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF12") // data buffer
;
// SPI1 memory data buffer13
Registers.W13.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF13") // data buffer
;
// SPI1 memory data buffer14
Registers.W14.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF14") // data buffer
;
// SPI1 memory data buffer15
Registers.W15.Define(this, 0x0)
.WithValueField(0, 32, FieldMode.Read | FieldMode.Write, name: "BUF15") // data buffer
;
// SPI1 wait idle control register
Registers.FLASH_WAITI_CTRL.Define(this, 0x14)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "WAITI_EN") // Set this bit to enable auto-waiting flash idle operation when PP/SE/BE/CE/WRSR/PES command is sent.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "WAITI_DUMMY") // Set this bit to enable DUMMY phase in auto wait flash idle transfer(RDSR).
.WithValueField(2, 8, FieldMode.Read | FieldMode.Write, name: "WAITI_CMD") // The command value of auto wait flash idle transfer(RDSR).
.WithValueField(10, 6, FieldMode.Read | FieldMode.Write, name: "WAITI_DUMMY_CYCLELEN") // The dummy cycle length when wait flash idle(RDSR).
;
// SPI1 flash suspend control register
Registers.FLASH_SUS_CMD.Define(this, 0x0)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "FLASH_PER") // program erase resume bit, program erase suspend operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "FLASH_PES") // program erase suspend bit, program erase suspend operation will be triggered when the bit is set. The bit will be cleared once the operation done.1: enable 0: disable.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "FLASH_PER_WAIT_EN") // Set this bit to add delay time after program erase resume(PER) is sent.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "FLASH_PES_WAIT_EN") // Set this bit to add delay time after program erase suspend(PES) command is sent.
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "PES_PER_EN") // Set this bit to enable PES transfer trigger PES transfer option.
.WithFlag(5, FieldMode.Read | FieldMode.Write, name: "PESR_IDLE_EN") // 1: Separate PER flash wait idle and PES flash wait idle. 0: Not separate.
;
// SPI1 flash suspend command register
Registers.FLASH_SUS_CTRL.Define(this, 0xeaf4)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "FLASH_PES_EN") // Set this bit to enable auto-suspend function.
.WithValueField(1, 8, FieldMode.Read | FieldMode.Write, name: "FLASH_PER_COMMAND") // Program/Erase resume command value.
.WithValueField(9, 8, FieldMode.Read | FieldMode.Write, name: "FLASH_PES_COMMAND") // Program/Erase suspend command value.
;
// SPI1 flash suspend status register
Registers.SUS_STATUS.Define(this, 0x0)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "FLASH_SUS") // The status of flash suspend. This bit is set when PES command is sent, and cleared when PER is sent. Only used in SPI1.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "FLASH_HPM_DLY_256") // 1: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 256) SPI_CLK cycles after HPM command is sent. 0: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 4) SPI_CLK cycles after HPM command is sent.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "FLASH_RES_DLY_256") // 1: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 256) SPI_CLK cycles after RES command is sent. 0: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 4) SPI_CLK cycles after RES command is sent.
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "FLASH_DP_DLY_256") // 1: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 256) SPI_CLK cycles after DP command is sent. 0: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 4) SPI_CLK cycles after DP command is sent.
.WithFlag(5, FieldMode.Read | FieldMode.Write, name: "FLASH_PER_DLY_256") // Valid when SPI_MEM_FLASH_PER_WAIT_EN is 1. 1: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 256) SPI_CLK cycles after PER command is sent. 0: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 4) SPI_CLK cycles after PER command is sent.
.WithFlag(6, FieldMode.Read | FieldMode.Write, name: "FLASH_PES_DLY_256") // Valid when SPI_MEM_FLASH_PES_WAIT_EN is 1. 1: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 256) SPI_CLK cycles after PES command is sent. 0: SPI1 waits (SPI_MEM_CS_HOLD_DELAY_RES[9:0] * 4) SPI_CLK cycles after PES command is sent.
;
// SPI1 timing compensation register when accesses to flash or Ext_RAM.
Registers.TIMING_CALI.Define(this, 0x0)
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "TIMING_CALI") // Set this bit to add extra SPI_CLK cycles in DUMMY phase for all reading operations.
.WithValueField(2, 3, FieldMode.Read | FieldMode.Write, name: "EXTRA_DUMMY_CYCLELEN") // Extra SPI_CLK cycles added in DUMMY phase for timing compensation. Active when SPI_MEM_TIMING_CALI bit is set.
;
// SPI1 DDR control register
Registers.DDR.Define(this, 0x20)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DDR_EN") // 1: in DDR mode, 0: in SDR mode.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_VAR_DUMMY") // Set the bit to enable variable dummy cycle in DDRmode.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DDR_RDAT_SWP") // Set the bit to reorder RX data of the word in DDR mode.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DDR_WDAT_SWP") // Set the bit to reorder TX data of the word in DDR mode.
.WithFlag(4, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DDR_CMD_DIS") // the bit is used to disable dual edge in command phase when DDR mode.
.WithValueField(5, 7, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_OUTMINBYTELEN") // It is the minimum output data length in the panda device.
.WithValueField(14, 7, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_USR_DDR_DQS_THD") // The delay number of data strobe which from memory based on SPI_CLK.
.WithFlag(21, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DDR_DQS_LOOP") // 1: Use internal signal as data strobe, the strobe can not be delayed by input timing module. 0: Use input SPI_DQS signal from PAD as data strobe, the strobe can be delayed by input timing module
.WithFlag(22, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DDR_DQS_LOOP_MODE") // When SPI_FMEM_DDR_DQS_LOOP and SPI_FMEM_DDR_EN are set, 1: Use internal SPI_CLK as data strobe. 0: Use internal ~SPI_CLK as data strobe. Otherwise this bit is not active.
.WithFlag(24, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_CLK_DIFF_EN") // Set this bit to enable the differential SPI_CLK#.
.WithFlag(25, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_HYPERBUS_MODE") // Set this bit to enable the SPI HyperBus mode.
.WithFlag(26, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_DQS_CA_IN") // Set this bit to enable the input of SPI_DQS signal in SPI phases of CMD and ADDR.
.WithFlag(27, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_HYPERBUS_DUMMY_2X") // Set this bit to enable the vary dummy function in SPI HyperBus mode, when SPI0 accesses flash or SPI1 accesses flash or sram.
.WithFlag(28, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_CLK_DIFF_INV") // Set this bit to invert SPI_DIFF when accesses to flash. .
.WithFlag(29, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_OCTA_RAM_ADDR") // Set this bit to enable octa_ram address out when accesses to flash, which means ADDR_OUT[31:0] = {spi_usr_addr_value[25:4], 6'd0, spi_usr_addr_value[3:1], 1'b0}.
.WithFlag(30, FieldMode.Read | FieldMode.Write, name: "SPI_FMEM_HYPERBUS_CA") // Set this bit to enable HyperRAM address out when accesses to flash, which means ADDR_OUT[31:0] = {spi_usr_addr_value[19:4], 13'd0, spi_usr_addr_value[3:1]}.
;
// SPI1 clk_gate register
Registers.CLOCK_GATE.Define(this, 0x1)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "CLK_EN") // Register clock gate enable signal. 1: Enable. 0: Disable.
;
// SPI1 interrupt enable register
Registers.INT_ENA.Define(this, 0x0)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "PER_END_INT_ENA") // The enable bit for SPI_MEM_PER_END_INT interrupt.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "PES_END_INT_ENA") // The enable bit for SPI_MEM_PES_END_INT interrupt.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "TOTAL_TRANS_END_INT_ENA") // The enable bit for SPI_MEM_TOTAL_TRANS_END_INT interrupt.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "BROWN_OUT_INT_ENA") // The enable bit for SPI_MEM_BROWN_OUT_INT interrupt.
;
// SPI1 interrupt clear register
Registers.INT_CLR.Define(this, 0x0)
.WithFlag(0, FieldMode.Write, name: "PER_END_INT_CLR") // The clear bit for SPI_MEM_PER_END_INT interrupt.
.WithFlag(1, FieldMode.Write, name: "PES_END_INT_CLR") // The clear bit for SPI_MEM_PES_END_INT interrupt.
.WithFlag(2, FieldMode.Write, name: "TOTAL_TRANS_END_INT_CLR") // The clear bit for SPI_MEM_TOTAL_TRANS_END_INT interrupt.
.WithFlag(3, FieldMode.Write, name: "BROWN_OUT_INT_CLR") // The status bit for SPI_MEM_BROWN_OUT_INT interrupt.
;
// SPI1 interrupt raw register
Registers.INT_RAW.Define(this, 0x0)
.WithFlag(0, FieldMode.Read | FieldMode.Write, name: "PER_END_INT_RAW") // The raw bit for SPI_MEM_PER_END_INT interrupt. 1: Triggered when Auto Resume command (0x7A) is sent and flash is resumed successfully. 0: Others.
.WithFlag(1, FieldMode.Read | FieldMode.Write, name: "PES_END_INT_RAW") // The raw bit for SPI_MEM_PES_END_INT interrupt.1: Triggered when Auto Suspend command (0x75) is sent and flash is suspended successfully. 0: Others.
.WithFlag(2, FieldMode.Read | FieldMode.Write, name: "TOTAL_TRANS_END_INT_RAW") // The raw bit for SPI_MEM_TOTAL_TRANS_END_INT interrupt. 1: Triggered when SPI1 transfer is done and flash is already idle. When WRSR/PP/SE/BE/CE is sent and PES/PER command is sent, this bit is set when WRSR/PP/SE/BE/CE is success. 0: Others.
.WithFlag(3, FieldMode.Read | FieldMode.Write, name: "BROWN_OUT_INT_RAW") // The raw bit for SPI_MEM_BROWN_OUT_INT interrupt. 1: Triggered condition is that chip is loosing power and RTC module sends out brown out close flash request to SPI1. After SPI1 sends out suspend command to flash, this interrupt is triggered and MSPI returns to idle state. 0: Others.
;
// SPI1 interrupt status register
Registers.INT_ST.Define(this, 0x0)
.WithFlag(0, FieldMode.Read, name: "PER_END_INT_ST") // The status bit for SPI_MEM_PER_END_INT interrupt.
.WithFlag(1, FieldMode.Read, name: "PES_END_INT_ST") // The status bit for SPI_MEM_PES_END_INT interrupt.
.WithFlag(2, FieldMode.Read, name: "TOTAL_TRANS_END_INT_ST") // The status bit for SPI_MEM_TOTAL_TRANS_END_INT interrupt.
.WithFlag(3, FieldMode.Read, name: "BROWN_OUT_INT_ST") // The status bit for SPI_MEM_BROWN_OUT_INT interrupt.
;
// SPI0 version control register
Registers.DATE.Define(this, 0x2101040)
.WithValueField(0, 28, FieldMode.Read | FieldMode.Write, name: "DATE") // SPI register version.
;
}
public override void Reset()
{
RegistersCollection.Reset();
UpdateInterrupts();
}
public uint ReadDoubleWord(long offset)
{
return RegistersCollection.Read(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
RegistersCollection.Write(offset, value);
}
private void UpdateInterrupts()
{
var status = false;
this.Log(LogLevel.Noisy, "Setting IRQ to {0}", status);
IRQ.Set(status);
}
private enum Registers
{
CMD = 0x0,
ADDR = 0x4,
CTRL = 0x8,
CTRL1 = 0xc,
CTRL2 = 0x10,
CLOCK = 0x14,
USER = 0x18,
USER1 = 0x1c,
USER2 = 0x20,
MOSI_DLEN = 0x24,
MISO_DLEN = 0x28,
RD_STATUS = 0x2c,
EXT_ADDR = 0x30,
MISC = 0x34,
TX_CRC = 0x38,
CACHE_FCTRL = 0x3c,
FSM = 0x54,
W0 = 0x58,
W1 = 0x5c,
W2 = 0x60,
W3 = 0x64,
W4 = 0x68,
W5 = 0x6c,
W6 = 0x70,
W7 = 0x74,
W8 = 0x78,
W9 = 0x7c,
W10 = 0x80,
W11 = 0x84,
W12 = 0x88,
W13 = 0x8c,
W14 = 0x90,
W15 = 0x94,
FLASH_WAITI_CTRL = 0x98,
FLASH_SUS_CMD = 0x9c,
FLASH_SUS_CTRL = 0xa0,
SUS_STATUS = 0xa4,
TIMING_CALI = 0xa8,
DDR = 0xe0,
CLOCK_GATE = 0xe8,
INT_ENA = 0xf0,
INT_CLR = 0xf4,
INT_RAW = 0xf8,
INT_ST = 0xfc,
DATE = 0x3fc,
}
}
}

214
peripherals/ESP32_UART.cs Normal file
View File

@ -0,0 +1,214 @@
//
// 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,
}
}
}

171
svd-to-renode.py Normal file
View File

@ -0,0 +1,171 @@
#!/usr/bin/env python3
import xml.etree.ElementTree as ET
class SVDExtractor:
def __init__(self, filename):
self.tree = ET.parse(filename)
self.root = self.tree.getroot()
self.peripherals = self.root.find("peripherals")
def extract(
self,
peripheral_to_print,
namespace,
generated_peripheral_name,
imports=None,
extra_subclasses=None,
):
for peripheral in self.peripherals.iter("peripheral"):
peripheral_name = peripheral.find("name").text
if peripheral_name != peripheral_to_print:
continue
register_list = dict()
peripheral_size = int(peripheral.find("addressBlock").find("size").text, 0)
registers = peripheral.find("registers")
if imports is not None:
for i in imports:
print(f"using {i};")
print()
print(f"namespace {namespace}")
print("{")
print(f" public class {generated_peripheral_name} : ", end="")
if extra_subclasses is not None:
for esc in extra_subclasses:
print(f"{esc}, ", end="")
print(
"IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize"
)
print(" {")
print(" public GPIO IRQ { get; private set; }")
print(
" public DoubleWordRegisterCollection RegistersCollection { get; }"
)
print(f" public long Size => 0x1000; // {hex(peripheral_size)}")
print(" private readonly Machine machine;")
print()
print(
f" public {generated_peripheral_name}(Machine machine) : base(machine)"
)
print(" {")
print(" this.machine = machine;")
print()
print(" IRQ = new GPIO();")
print()
print(
" RegistersCollection = new DoubleWordRegisterCollection(this);"
)
print(" DefineRegisters();")
print(" Reset();")
print(" }")
print()
print(" private void DefineRegisters()")
print(" {")
for register in registers.iter("register"):
register_name = register.find("name").text
register_description = register.find("description").text
register_offset = int(register.find("addressOffset").text, 0)
register_default = 0
register_reset_value_field = register.find("resetValue")
if register_reset_value_field is not None:
register_default = int(register_reset_value_field.text, 0)
register_list[register_offset] = register_name
if "\n" in register_description:
raise Exception("Register description contains a newline")
print(f" // {register_description}")
print(f" Registers.{register_name}.Define(this, {hex(register_default)})")
for field in register.find("fields").iter("field"):
field_offset = int(field.find("bitOffset").text, 0)
field_width = int(field.find("bitWidth").text, 0)
field_name = field.find("name").text
field_description = field.find("description").text
field_access = field.find("access").text
field_access_mask = ""
if field_access == "read-write":
field_access_mask = "FieldMode.Read | FieldMode.Write, "
elif field_access == "read-only":
field_access_mask = "FieldMode.Read, "
elif field_access == "write-only":
field_access_mask = "FieldMode.Write, "
else:
raise Exception(
f"Unrecognized field access type: {field_access}"
)
if "\n" in field_description:
raise Exception("Field description contains a newline")
if field_width == 1:
print(
f' .WithFlag({field_offset}, {field_access_mask}name: "{field_name}") // {field_description}'
)
else:
print(
f' .WithValueField({field_offset}, {field_width}, {field_access_mask}name: "{field_name}") // {field_description}'
)
print(" ;")
print()
print(" }")
print()
print(" public override void Reset()")
print(" {")
print(" RegistersCollection.Reset();")
print(" UpdateInterrupts();")
print(" }")
print()
print(" public uint ReadDoubleWord(long offset)")
print(" {")
print(" return RegistersCollection.Read(offset);")
print(" }")
print()
print(" public void WriteDoubleWord(long offset, uint value)")
print(" {")
print(" RegistersCollection.Write(offset, value);")
print(" }")
print(" private void UpdateInterrupts()")
print(" {")
print(" var status = false;")
print(" this.Log(LogLevel.Noisy, \"Setting IRQ to {0}\", status);")
print(" IRQ.Set(status);")
print(" }")
print()
print(" private enum Registers")
print(" {")
for offset, name in register_list.items():
print(f" {name} = {hex(offset)},")
print(" }")
print(" }")
print("}")
if __name__ == "__main__":
extractor = SVDExtractor("esp32s3.svd")
extractor.extract(
"SPI1",
"Antmicro.Renode.Peripherals.SPI",
"ESP32_SPIController",
imports=[
"System.Linq",
"System.Collections.Generic",
"Antmicro.Renode.Core",
"Antmicro.Renode.Core.Structure",
"Antmicro.Renode.Core.Structure.Registers",
"Antmicro.Renode.Logging",
"Antmicro.Renode.Peripherals.Bus",
"Antmicro.Renode.Peripherals.Memory",
"Antmicro.Renode.Peripherals.MTD",
],
extra_subclasses=["NullRegistrationPointPeripheralContainer<ISPIPeripheral>"],
)