<commit_before>// Copyright Microsoft Corporation
// Copyright GHI Electronics, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <stdio.h>
#include <string.h>

#include <TinyCLR.h>
#include <Device.h>

#define SIZEOF_ARRAY(arr) (sizeof(arr) / sizeof(arr[0]))
#define CONCAT2(a, b) a##b
#define CONCAT(a, b) CONCAT2(a, b)
#define CHARIZE2(c) #c
#define CHARIZE(c) (CHARIZE2(c)[0])

void AT91_Startup_OnSoftReset(const TinyCLR_Api_Provider* apiProvider);
void AT91_Startup_OnSoftResetDevice(const TinyCLR_Api_Provider* apiProvider);

//
//  PERIPHERAL ID DEFINITIONS FOR AT91SAM9X35
//
#define AT91C_ID_FIQ		((unsigned int)  0) // Advanced Interrupt Controller (FIQ)
#define AT91C_ID_SYS		((unsigned int)  1) // System Interrupt
#define AT91C_ID_PIOA_PIOB	((unsigned int)  2) // Parallel IO Controller A and B
#define AT91C_ID_PIOC_PIOD	((unsigned int)  3) // Parallel IO Controller C and D
#define AT91C_ID_SMD		((unsigned int)  4) // SMD Soft Modem - not yet supported
#define AT91C_ID_USART0		((unsigned int)  5) // USART 0
#define AT91C_ID_USART1		((unsigned int)  6) // USART 1
#define AT91C_ID_USART2		((unsigned int)  7) // USART 2
#define AT91C_ID_TWI		AT91C_ID_TWI0       // only support one I2C
#define AT91C_ID_TWI0		((unsigned int)  9) // Two-Wire Interface 0
#define AT91C_ID_TWI1		((unsigned int) 10) // Two-Wire Interface 1
#define AT91C_ID_TWI2		((unsigned int) 11) // Two-Wire Interface 2
#define AT91C_ID_HSMCI0		((unsigned int) 12) // High Speed Multimedia Card Interface 0
#define AT91C_ID_SPI0		((unsigned int) 13) // Serial Peripheral Interface
#define AT91C_ID_SPI1		((unsigned int) 14) // Serial Peripheral Interface
#define AT91C_ID_UART0		((unsigned int) 15) // UART 0
#define AT91C_ID_UART1		((unsigned int) 16) // UART 1
#define AT91C_ID_TC0_TC1	((unsigned int) 17) // Timer Counter 0, 1, 2, 3, 4, 5
#define AT91C_ID_PWM		((unsigned int) 18) // Pulse Width Modulation Controller
#define AT91C_ID_ADC		((unsigned int) 19) // ADC Controller
#define AT91C_ID_DMAC0		((unsigned int) 20) // DMA Controller 0
#define AT91C_ID_DMAC1		((unsigned int) 21) // DMA Controller 1
#define AT91C_ID_UHPHS		((unsigned int) 22) // USB Host High Speed
#define AT91C_ID_UDPHS		((unsigned int) 23) // USB Device High Speed
#define AT91C_ID_EMAC		((unsigned int) 24) // Ethernet MAC
#define AT91C_ID_LCDC		((unsigned int) 25) // LCD Controller
#define AT91C_ID_HSMCI1		((unsigned int) 26) // High Speed Multimedia Card Interface 1
#define AT91C_ID_SSC		((unsigned int) 28) // Synchronous Serial Controller
#define AT91C_ID_CAN0		((unsigned int) 29) // CAN Controller 0
#define AT91C_ID_CAN1		((unsigned int) 30) // CAN Controller 1
#define AT91C_ID_IRQ0		((unsigned int) 31) // Advanced Interrupt Controller (IRQ0)

//
// BASE ADDRESS DEFINITIONS FOR AT91SAM9RL64
//
#define AT91C_BASE_SYS          0xFFFFE600 // (SYS) Base Address
#define AT91C_BASE_DMAC0        0xFFFFEC00 // Hydra original address 0xFFFFE600 // (DMAC)Address						- Not same Memory Address
#define AT91C_BASE_DDRS         0xFFFFE800 // (DDRS) Address
#define AT91C_BASE_SDRAMC       0xFFFFEA00 // (SDRAMC) Base Address
#define AT91C_BASE_SMC          0xFFFFEC00 // (SMC) Base Address
#define AT91C_BASE_MATRIX       0xFFFFEE00 // (MATRIX) Base Address				- Not same Memory Address
#define AT91C_BASE_AIC          0xFFFFF000 // (AIC) Base Address
#define AT91C_BASE_PDC_DBGU     0xFFFFF300 // (PDC_DBGU) Base Address
#define AT91C_BASE_DBGU         0xFFFFF200 // (DBGU) Base Address
#define AT91C_BASE_PIOA         0xFFFFF400 // (PIOA) Base Address
#define AT91C_BASE_PIOB         0xFFFFF600 // (PIOB) Base Address
#define AT91C_BASE_PIOC         0xFFFFF800 // (PIOC) Base Address
#define AT91C_BASE_PIOD         0xFFFFFA00 // (PIOD) Base Address
#define AT91C_BASE_CKGR         0xFFFFFC20 // (CKGR) Base Address
#define AT91C_BASE_PMC          0xFFFFFC00 // (PMC) Base Address
#define AT91C_BASE_RSTC         0xFFFFFE00 // (RSTC) Base Address				- Not same Memory Address
#define AT91C_BASE_RSTC_SR      0xFFFFFD04
#define AT91C_BASE_RSTC_MR      0xFFFFFD08
#define AT91C_BASE_SHDWC        0xFFFFFD10 // (SHDWC) Base Address
#define AT91C_BASE_RTTC         	0xFFFFFD20 // (RTTC) Base Address
#define AT91C_BASE_PITC         	0xFFFFFE30 // (PITC) Base Address
#define AT91C_BASE_WDTC         	0xFFFFFE40 // (WDTC) Base Address
#define AT91C_BASE_SCKCR        	0xFFFFFE50 // (SCKCR) Base Address
#define AT91C_BASE_GPBR         	0xFFFFFD60 // (GPBR) Base Address
#define AT91C_BASE_TC0         		0xF8008000 // Hydra original address 0xFFFA0000 // (TC0) Base Address
#define AT91C_BASE_TC1          	0xFFFA0040 // (TC1) Base Address
#define AT91C_BASE_TC2          	0xFFFA0080 // (TC2) Base Address
#define AT91C_BASE_TCB0         	0xFFFA0000 // (TCB0) Base Address
#define AT91C_BASE_PDC_MCI      	0xFFFA4100 // (PDC_MCI) Base Address
#define AT91C_BASE_MCI          	0xF0008000 // Hydra original address 0xFFFA4000 // (MCI) Base Address
#define AT91C_BASE_TWI0         	0xF8010000 // Hydra original address 0xFFFA8000 // (TWI1) Base Address
#define AT91C_BASE_TWI1         	0xF8014000 // Hydra original address 0xFFFAC000 // (TWI2) Base Address
#define AT91C_BASE_TWI2         	0xF8018000 // (TWI3) Base Address
#define AT91C_BASE_TWI          	AT91C_BASE_TWI0 // Support one I2C controller only
#define AT91C_BASE_USART0          	0xF801C000 // Hydra original address 0xFFFB0000 // (US0) Base Address				- Not same Memory Address
#define AT91C_BASE_USART1          	0xF8020000 // Hydra original address 0xFFFB4000 // (US1) Base Address				- Not same Memory Address
#define AT91C_BASE_USART2          	0xF8024000 // Hydra original address 0xFFFB8000 // (US2) Base Address				- Not same Memory Address
#define AT91C_BASE_UART0			0xF8040000
#define AT91C_BASE_UART1			0xF8044000
#define AT91C_BASE_PDC_US3      	0xFFFBC100 // (PDC_US3) Base Address
#define AT91C_BASE_US3          	0xF8008000 // Hydra original address 0xFFFBC000 // (US3) Base Address				- Not same Memory Address
#define AT91C_BASE_PDC_SSC0     	0xFFFC0100 // (PDC_SSC0) Base Address
#define AT91C_BASE_SSC0         	0xFFFC0000 // (SSC0) Base Address
#define AT91C_BASE_PDC_SSC1     	0xFFFC4100 // (PDC_SSC1) Base Address
#define AT91C_BASE_SSC1         	0xFFFC4000 // (SSC1) Base Address
#define AT91C_BASE_PWMC         	0xF8034000 // Hydra original address 0xFFFC8000 // (PWMC) Base Address				- Not same Memory Address
#define AT91C_BASE_PDC_SPI0     	0xFFFCC100 // (PDC_SPI0) Base Address
#define AT91C_BASE_SPI0         	0xF0000000 // (SPI0) Base Address // Hydra original address 0xFFFCC000
#define AT91C_BASE_SPI1         	0xF0004000 // (SPI1) Base Address
#define AT91C_BASE_TSADCC       	0xFFFD0000 // (ADC touch screen) Base Address
#define AT91C_BASE_UDP          	0xF803C000 // 0xFFFD4000 // (UDP) Base Address - Changed on G400
#define AT91C_BASE_AC97         	0xFFFD8000 // (UDP) Base Address
#define AT91C_BASE_ITCM         	0x00100000 // (ITCM) Base Address
#define AT91C_BASE_DTCM         	0x00200000 // (DTCM) Base Address
#define AT91C_BASE_LCDC         	0xF8038000 // Hydra original address 0x00500000 // (LCDC) Base Address
#define AT91C_BASE_UDP_DMA			0x00500000 // Hydra original address 0x00600000 // (UDP DMA) Base Address
#define AT91C_BASE_EMAC				0xF802C000

// RTSC bit defines
#define AT91C_RTSC__PROCRST     0x01         // processor reset bit
#define AT91C_RTSC__PERRST      0x04         // Peripheral reset bit
#define AT91C_RTSC__EXTRST      0x08         // asserts NRST pin
#define AT91C_RSTC__RESET_KEY   0xA5000000   // reset key
#define AT91C_RTSC_SR__SRCMP    (1ul < 17)   // Software Reset Command in progress
#define AT91C_RTSC_SR__NRSTL    (1ul < 16)   // Registers the NRST Pin Level at Master Clock (MCK)
#define AT91C_RTSC_SR__RSTTYP   (7ul <  8)   // Reset Type mask
#define AT91C_RTSC_SR__BODSTS   (1ul <  1)   // Brownout Detection Status
#define AT91C_RTSC_SR__URSTS    (1ul <  0)   // User Reset Status

// SHDWC bit defines
#define AT91C_SHDWC__SHUTDOWN_KEY   0xA5000000   // reset key
#define AT91C_SHDWC__SHDW           0x01         // processor reset bit

extern const TinyCLR_Api_Provider* apiProvider;

struct AT91_PMC {
    static const uint32_t c_Base = AT91C_BASE_PMC;

    volatile uint32_t PMC_SCER;                // System Clock Enable Register

    volatile uint32_t PMC_SCDR;                // System Clock Disable Register

    volatile uint32_t PMC_SCSR;                // System Clock Status Register

    volatile uint32_t Reserved0[1];

    volatile uint32_t PMC_PCER;                // Peripheral Clock Enable Register

    volatile uint32_t PMC_PCDR;                // Peripheral Clock Disable Register

    volatile uint32_t PMC_PCSR;                // Peripheral Clock Status Register

    volatile uint32_t PMC_CKGR_UCKR;            // UTMI Clock Register

    volatile uint32_t PMC_CKGR_MOR;            // Main Oscillator Register
    static const    uint32_t CKGR_MOSCEN = (0x1 << 0);       // (CKGR) Main Oscillator Enable
    static const    uint32_t CKGR_OSCBYPASS = (0x1 << 1);       // (CKGR) Main Oscillator Bypass
    static const    uint32_t CKGR_OSCOUNT = (0xFF << 8);      // (CKGR) Main Oscillator Start-up Time


    volatile uint32_t PMC_CKGR_MCFR;  // Main Clock  Frequency Register
    static const    uint32_t CKGR_MAINF = (0xFFFF << 0);     // (CKGR) Main Clock Frequency
    static const    uint32_t CKGR_MAINRDY = (0x1 << 16);       // (CKGR) Main Clock Ready


    volatile uint32_t PMC_CKGR_PLLAR;  // PLL Register


    static const    uint32_t CKGR_DIV = (0xFF << 0);     // (CKGR) Divider Selected
    static const    uint32_t CKGR_DIV_0 = (0x0);           // (CKGR) Divider output is 0
    static const    uint32_t CKGR_DIV_BYPASS = (0x1);           // (CKGR) Divider is bypassed
    static const    uint32_t CKGR_PLLCOUNT = (0x3F << 8);     // (CKGR) PLL Counter
    static const    uint32_t CKGR_OUT = (0x3 << 14);     // (CKGR) PLL Output Frequency Range
    static const    uint32_t CKGR_OUT_0 = (0x0 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_OUT_1 = (0x1 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_OUT_2 = (0x2 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_OUT_3 = (0x3 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_MUL = (0x7FF << 16);   // (CKGR) PLL Multiplier
    static const    uint32_t CKGR_USBDIV = (0x3 << 28);     // (CKGR) Divider for USB Clocks
    static const    uint32_t CKGR_USBDIV_0 = (0x0 << 28);     // (CKGR) Divider output is PLL clock output
    static const    uint32_t CKGR_USBDIV_1 = (0x1 << 28);     // (CKGR) Divider output is PLL clock output divided by 2
    static const    uint32_t CKGR_USBDIV_2 = (0x2 << 28);     // (CKGR) Divider output is PLL clock output divided by 4

    volatile uint32_t Reserved1[1];

    volatile uint32_t PMC_MCKR;  // Master Clock Register
    static const    uint32_t PMC_CSS = (0x3 << 0);   //  (PMC) Programmable Clock Selection
    static const    uint32_t PMC_CSS_SLOW_CLK = (0x0);         //  (PMC) Slow Clock is selected
    static const    uint32_t PMC_CSS_MAIN_CLK = (0x1);         //  (PMC) Main Clock is selected
    static const    uint32_t PMC_CSS_PLLA_CLK = (0x2);         //  (PMC) Clock from PLL1 is selected = (SAM9 only);
    static const    uint32_t PMC_CSS_PLL_CLK = (0x3);         //  (PMC) Clock from PLL is selected
    static const    uint32_t PMC_PRES = (0x7 << 2);   //  (PMC) Programmable Clock Prescaler
    static const    uint32_t PMC_PRES_CLK = (0x0 << 2);   //  (PMC) Selected clock
    static const    uint32_t PMC_PRES_CLK_2 = (0x1 << 2);   //  (PMC) Selected clock divided by 2
    static const    uint32_t PMC_PRES_CLK_4 = (0x2 << 2);   //  (PMC) Selected clock divided by 4
    static const    uint32_t PMC_PRES_CLK_8 = (0x3 << 2);   //  (PMC) Selected clock divided by 8
    static const    uint32_t PMC_PRES_CLK_16 = (0x4 << 2);   //  (PMC) Selected clock divided by 16
    static const    uint32_t PMC_PRES_CLK_32 = (0x5 << 2);   //  (PMC) Selected clock divided by 32
    static const    uint32_t PMC_PRES_CLK_64 = (0x6 << 2);   //  (PMC) Selected clock divided by 64
    static const    uint32_t PMC_MDIV = (0x3 << 8);   //  (PMC) Master Clock Division
    static const    uint32_t PMC_MDIV_1 = (0x0 << 8);   //  (PMC) The master clock and the processor clock are the same
    static const    uint32_t PMC_MDIV_2 = (0x1 << 8);   //  (PMC) The processor clock is twice as fast as the master clock
    static const    uint32_t PMC_MDIV_3 = (0x2 << 8);   //  (PMC) The processor clock is four times faster than the master clock

    volatile uint32_t Reserved3[3];  // TQD: Just a note PMC_USB and PMC_SMD are in here

    volatile uint32_t PMC_PCKR[2];   // Programmable Clock Register

    volatile uint32_t Reserved4[6];

    volatile uint32_t PMC_IER;   // Interrupt Enable Register
    static const    uint32_t PMC_MOSCS = (0x1 << 0);       // (PMC) MOSC Status/Enable/Disable/Mask
    static const    uint32_t PMC_LOCKA = (0x1 << 1);       // (PMC) PLL Status/Enable/Disable/Mask =(SAM9 Only);
    static const    uint32_t PMC_LOCK = (0x1 << 2);       // (PMC) PLL Status/Enable/Disable/Mask
    static const    uint32_t PMC_MCKRDY = (0x1 << 3);       // (PMC) MCK_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK0RDY = (0x1 << 8);       // (PMC) PCK0_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK1RDY = (0x1 << 9);       // (PMC) PCK1_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK2RDY = (0x1 << 10);       // (PMC) PCK2_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK3RDY = (0x1 << 11);       // (PMC) PCK3_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_LOCKU = (0x1 << 6);           //(PMC) USB clock locked
    volatile uint32_t PMC_IDR;   // Interrupt Disable Register

    volatile uint32_t PMC_SR;    // Status Register

    volatile uint32_t PMC_IMR;   // Interrupt Mask Register

    volatile uint32_t Reserved5[3]; // Reserved

    volatile uint32_t PMC_PLLICPR; // Charge Pump Current Register
    static const    uint32_t PMC_PLLICPR__PLLA = (0x1 << 0);
    static const    uint32_t PMC_PLLICPR__PLLB = (0x1 << 16);

    __inline void EnableSystemClock(uint32_t clkIds) {
        PMC_SCER = clkIds;
    }

    __inline void DisableSystemClock(uint32_t clkIds) {
        PMC_SCDR = clkIds;
    }

    __inline void EnablePeriphClock(uint32_t periphIds) {
        PMC_PCER = (1 << periphIds);
    }

    __inline void DisablePeriphClock(uint32_t periphIds) {
        PMC_PCDR = (1 << periphIds);
    }


};


// MMU
struct ARM9_MMU {
    static const uint32_t c_TTB_size = 0x4000;

    static const uint32_t c_MMU_L1_Fault = 0x00;
    static const uint32_t c_MMU_L1_Coarse = 0x11;
    static const uint32_t c_MMU_L1_Section = 0x12;
    static const uint32_t c_MMU_L1_Fine = 0x13;
    static const uint32_t c_MMU_L1_size = 1 << 20;

    static const uint32_t c_AP__NoAccess = 0;
    static const uint32_t c_AP__Client = 1;
    static const uint32_t c_AP__Reserved = 2;
    static const uint32_t c_AP__Manager = 3;

    //--//

    static uint32_t* GetL1Entry(uint32_t* base, uint32_t address);
    static void    InitializeL1(uint32_t* baseOfTTBs);
    static uint32_t  GenerateL1_Section(uint32_t address, uint32_t AP, uint32_t domain, bool Cachable, bool Buffered, bool Xtended = false);
    static void    GenerateL1_Sections(uint32_t* baseOfTTBs, uint32_t mappedAddress, uint32_t physAddress, int32_t size, uint32_t AP, uint32_t domain, bool Cachable, bool Buffered, bool Xtended = false);
};

void AT91_MMU_Initialize();
void AT91_CPU_InvalidateTLBs();
void AT91_CPU_EnableMMU(void* TTB);
void AT91_CPU_DisableMMU();
bool AT91_CPU_IsMMUEnabled();
void AT91_CPU_BootstrapCode();

// Cache
void AT91_Cache_FlushCaches();
void AT91_Cache_DrainWriteBuffers();
void AT91_Cache_InvalidateCaches();
void AT91_Cache_EnableCaches();
void AT91_Cache_DisableCaches();
template <typename T> void AT91_Cache_InvalidateAddress(T* address);
size_t AT91_Cache_GetCachableAddress(size_t address);
size_t AT91_Cache_GetUncachableAddress(size_t address);

// GPIO

//////////////////////////////////////////////////////////////////////////////
// AT91_GPIO
//
struct AT91_PIO {
    static const uint32_t c_Base = AT91C_BASE_PIOA;

    static const uint32_t c_Base_Offset = 0x200;

    volatile uint32_t PIO_PER;       /**< \brief (Pio Offset: 0x0000) PIO Enable Register */

    volatile uint32_t PIO_PDR;       /**< \brief (Pio Offset: 0x0004) PIO Disable Register */

    volatile uint32_t PIO_PSR;       /**< \brief (Pio Offset: 0x0008) PIO Status Register */

    volatile uint32_t Reserved1[1];

    volatile uint32_t PIO_OER;       /**< \brief (Pio Offset: 0x0010) Output Enable Register */

    volatile uint32_t PIO_ODR;       /**< \brief (Pio Offset: 0x0014) Output Disable Register */

    volatile uint32_t PIO_OSR;       /**< \brief (Pio Offset: 0x0018) Output Status Register */

    volatile uint32_t Reserved2[1];

    volatile uint32_t PIO_IFER;      /**< \brief (Pio Offset: 0x0020) Glitch Input Filter Enable Register */

    volatile uint32_t PIO_IFDR;      /**< \brief (Pio Offset: 0x0024) Glitch Input Filter Disable Register */

    volatile uint32_t PIO_IFSR;      /**< \brief (Pio Offset: 0x0028) Glitch Input Filter Status Register */

    volatile uint32_t Reserved3[1];

    volatile uint32_t PIO_SODR;      /**< \brief (Pio Offset: 0x0030) Set Output Data Register */

    volatile uint32_t PIO_CODR;      /**< \brief (Pio Offset: 0x0034) Clear Output Data Register */

    volatile uint32_t PIO_ODSR;      /**< \brief (Pio Offset: 0x0038) Output Data Status Register */

    volatile uint32_t PIO_PDSR;      /**< \brief (Pio Offset: 0x003C) Pin Data Status Register */

    volatile uint32_t PIO_IER;       /**< \brief (Pio Offset: 0x0040) Interrupt Enable Register */

    volatile uint32_t PIO_IDR;       /**< \brief (Pio Offset: 0x0044) Interrupt Disable Register */

    volatile uint32_t PIO_IMR;       /**< \brief (Pio Offset: 0x0048) Interrupt Mask Register */

    volatile uint32_t PIO_ISR;       /**< \brief (Pio Offset: 0x004C) Interrupt Status Register */

    volatile uint32_t PIO_MDER;      /**< \brief (Pio Offset: 0x0050) Multi-driver Enable Register */

    volatile uint32_t PIO_MDDR;      /**< \brief (Pio Offset: 0x0054) Multi-driver Disable Register */

    volatile uint32_t PIO_MDSR;      /**< \brief (Pio Offset: 0x0058) Multi-driver Status Register */

    volatile uint32_t Reserved4[1];

    volatile uint32_t PIO_PUDR;      /**< \brief (Pio Offset: 0x0060) Pull-up Disable Register */

    volatile uint32_t PIO_PUER;      /**< \brief (Pio Offset: 0x0064) Pull-up Enable Register */

    volatile uint32_t PIO_PUSR;      /**< \brief (Pio Offset: 0x0068) Pad Pull-up Status Register */

    volatile uint32_t Reserved5[1];

    volatile uint32_t PIO_ABCDSR[2]; /**< \brief (Pio Offset: 0x0070) Peripheral Select Register */

    volatile uint32_t Reserved6[2];

    volatile uint32_t PIO_IFSCDR;    /**< \brief (Pio Offset: 0x0080) Input Filter Slow Clock Disable Register */

    volatile uint32_t PIO_IFSCER;    /**< \brief (Pio Offset: 0x0084) Input Filter Slow Clock Enable Register */

    volatile uint32_t PIO_IFSCSR;    /**< \brief (Pio Offset: 0x0088) Input Filter Slow Clock Status Register */

    volatile uint32_t PIO_SCDR;      /**< \brief (Pio Offset: 0x008C) Slow Clock Divider Debouncing Register */

    volatile uint32_t PIO_PPDDR;     /**< \brief (Pio Offset: 0x0090) Pad Pull-down Disable Register */

    volatile uint32_t PIO_PPDER;     /**< \brief (Pio Offset: 0x0094) Pad Pull-down Enable Register */

    volatile uint32_t PIO_PPDSR;     /**< \brief (Pio Offset: 0x0098) Pad Pull-down Status Register */

    volatile uint32_t Reserved7[1];

    volatile uint32_t PIO_OWER;      /**< \brief (Pio Offset: 0x00A0) Output Write Enable */

    volatile uint32_t PIO_OWDR;      /**< \brief (Pio Offset: 0x00A4) Output Write Disable */

    volatile uint32_t PIO_OWSR;      /**< \brief (Pio Offset: 0x00A8) Output Write Status Register */

    volatile uint32_t Reserved8[1];
    volatile uint32_t PIO_AIMER;     /**< \brief (Pio Offset: 0x00B0) Additional Interrupt Modes Enable Register */

    volatile uint32_t PIO_AIMDR;     /**< \brief (Pio Offset: 0x00B4) Additional Interrupt Modes Disables Register */

    volatile uint32_t PIO_AIMMR;     /**< \brief (Pio Offset: 0x00B8) Additional Interrupt Modes Mask Register */

    volatile uint32_t Reserved9[1];

    volatile uint32_t PIO_ESR;       /**< \brief (Pio Offset: 0x00C0) Edge Select Register */

    volatile uint32_t PIO_LSR;       /**< \brief (Pio Offset: 0x00C4) Level Select Register */

    volatile uint32_t PIO_ELSR;      /**< \brief (Pio Offset: 0x00C8) Edge/Level Status Register */

    volatile uint32_t Reserved10[1];

    volatile uint32_t PIO_FELLSR;    /**< \brief (Pio Offset: 0x00D0) Falling Edge/Low Level Select Register */

    volatile uint32_t PIO_REHLSR;    /**< \brief (Pio Offset: 0x00D4) Rising Edge/ High Level Select Register */

    volatile uint32_t PIO_FRLHSR;    /**< \brief (Pio Offset: 0x00D8) Fall/Rise - Low/High Status Register */

    volatile uint32_t Reserved11[1];

    volatile uint32_t PIO_LOCKSR;    /**< \brief (Pio Offset: 0x00E0) Lock Status */

    volatile uint32_t PIO_WPMR;      /**< \brief (Pio Offset: 0x00E4) Write Protect Mode Register */

    volatile uint32_t PIO_WPSR;      /**< \brief (Pio Offset: 0x00E8) Write Protect Status Register */

    volatile uint32_t Reserved12[5];

    volatile uint32_t PIO_SCHMITT;   /**< \brief (Pio Offset: 0x0100) Schmitt Trigger Register */

    volatile uint32_t Reserved13[3];

    volatile uint32_t PIO_DELAYR;    /**< \brief (Pio Offset: 0x0110) IO Delay Register */

    volatile uint32_t PIO_DRIVER1;   /**< \brief (Pio Offset: 0x0114) I/O Drive Register 1 */

    volatile uint32_t PIO_DRIVER2;   /**< \brief (Pio Offset: 0x0118) I/O Drive Register 2 */
};

// --//


enum class AT91_Gpio_PeripheralSelection : uint8_t {
    None = 0,
    PeripheralA = 1,
    PeripheralB = 2,
    PeripheralC = 3,
    PeripheralD = 4
};

enum class AT91_Gpio_Direction : uint8_t {
    Input = 0,
    Output = 1
};

enum class AT91_Gpio_ResistorMode : uint8_t {
    Inactive = 0,
    PullUp = 1,
    PullDown = 2,
};

enum class AT91_Gpio_MultiDriver : uint8_t {
    Disable = 0,
    Enable = 1
};

enum class AT91_Gpio_Filter : uint8_t {
    Disable = 0,
    Enable = 1
};

enum class AT91_Gpio_FilterSlowClock : uint8_t {
    Disable = 0,
    Enable = 1
};

enum class AT91_Gpio_Schmitt : uint8_t {
    Enable = 0,
    Disable = 1
};

enum class AT91_Gpio_DriveSpeed : uint8_t {
    High = 0,
    Medium = 1,
    Low = 2,
    Reserved = 3
};

struct AT91_Gpio_Pin {
    uint32_t number;
    AT91_Gpio_PeripheralSelection peripheralSelection;
};

struct AT91_Gpio_PinConfiguration {
    AT91_Gpio_Direction direction;
    AT91_Gpio_ResistorMode resistorMode;
    AT91_Gpio_MultiDriver multiDriver;
    AT91_Gpio_Filter filter;
    AT91_Gpio_FilterSlowClock filterSlowClock;
    AT91_Gpio_Schmitt schmitt;
    AT91_Gpio_DriveSpeed speed;
    AT91_Gpio_PeripheralSelection peripheralSelection;
    bool apply;
};

#define PIN(port, pin) ((CHARIZE(port) - 'A') * 32 + pin)
#define PIN_NONE 0xFFFFFFFF
#define PS(num) (CONCAT(AT91_Gpio_PeripheralSelection::Peripheral, num))
#define PS_NONE AT91_Gpio_PeripheralSelection::None

#define INIT(pinDirection, resistorMode, peripheralSelection, apply) { AT91_Gpio_Direction::pinDirection, AT91_Gpio_ResistorMode::resistorMode, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable,  AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::peripheralSelection, apply }
#define ALTFUN(direction, resistorMode, peripheralSelection) { AT91_Gpio_Direction::direction, AT91_Gpio_ResistorMode::resistorMode, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable,  AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::peripheralSelection, true }
#define INPUT(resistorMode) { AT91_Gpio_Direction::Input, AT91_Gpio_ResistorMode::resistorMode, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable, AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::None, true }
#define DEFAULT() { AT91_Gpio_Direction::Input, AT91_Gpio_ResistorMode::Inactive, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable, AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::None, false }

void AT91_Gpio_Reset();
const TinyCLR_Api_Info* AT91_Gpio_GetApi();
TinyCLR_Result AT91_Gpio_Acquire(const TinyCLR_Gpio_Provider* self);
TinyCLR_Result AT91_Gpio_Release(const TinyCLR_Gpio_Provider* self);
TinyCLR_Result AT91_Gpio_EnableAlternatePin(int32_t pin, TinyCLR_Gpio_PinDriveMode resistor, uint32_t alternate);
TinyCLR_Result AT91_Gpio_Read(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinValue& value);
TinyCLR_Result AT91_Gpio_Write(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinValue value);
TinyCLR_Result AT91_Gpio_SetDebounceTimeout(const TinyCLR_Gpio_Provider* self, int32_t pin, int32_t debounceTime);
TinyCLR_Result AT91_Gpio_SetDriveMode(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinDriveMode mode);
TinyCLR_Result AT91_Gpio_AcquirePin(const TinyCLR_Gpio_Provider* self, int32_t pin);
bool AT91_Gpio_IsDriveModeSupported(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinDriveMode mode);
TinyCLR_Gpio_PinDriveMode AT91_Gpio_GetDriveMode(const TinyCLR_Gpio_Provider* self, int32_t pin);
int32_t AT91_Gpio_GetDebounceTimeout(const TinyCLR_Gpio_Provider* self, int32_t pin);
int32_t AT91_Gpio_GetPinCount(const TinyCLR_Gpio_Provider* self);
TinyCLR_Result AT91_Gpio_SetValueChangedHandler(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_ValueChangedHandler ISR);
TinyCLR_Result AT91_Gpio_ReleasePin(const TinyCLR_Gpio_Provider* self, int32_t pin);
void AT91_Gpio_EnableOutputPin(int32_t pin, bool initialState);
void AT91_Gpio_EnableInputPin(int32_t pin, TinyCLR_Gpio_PinDriveMode resistor);
bool AT91_Gpio_OpenPin(int32_t pin);
bool AT91_Gpio_ClosePin(int32_t pin);
bool AT91_Gpio_ReadPin(int32_t pin);
void AT91_Gpio_WritePin(int32_t pin, bool value);
bool AT91_Gpio_ConfigurePin(int32_t pin, AT91_Gpio_Direction pinDir, AT91_Gpio_PeripheralSelection peripheralSelection, AT91_Gpio_ResistorMode resistorMode);
bool AT91_Gpio_ConfigurePin(int32_t pin, AT91_Gpio_Direction pinDir, AT91_Gpio_PeripheralSelection peripheralSelection, AT91_Gpio_ResistorMode resistorMode, AT91_Gpio_MultiDriver multiDrive, AT91_Gpio_Filter filter, AT91_Gpio_FilterSlowClock filterSlowClock, AT91_Gpio_Schmitt schmitt, AT91_Gpio_DriveSpeed driveSpeed);

// ADC
const TinyCLR_Api_Info* AT91_Adc_GetApi();
void AT91_Adc_Reset();
int32_t AT91_Adc_GetControllerCount();
int32_t AT91_Adc_GetPin(int32_t channel);
AT91_Gpio_PeripheralSelection AT91_Adc_GetPeripheralSelection(int32_t channel);
TinyCLR_Result AT91_Adc_Acquire(const TinyCLR_Adc_Provider* self);
TinyCLR_Result AT91_Adc_Release(const TinyCLR_Adc_Provider* self);
TinyCLR_Result AT91_Adc_AcquireChannel(const TinyCLR_Adc_Provider* self, int32_t channel);
TinyCLR_Result AT91_Adc_ReleaseChannel(const TinyCLR_Adc_Provider* self, int32_t channel);
TinyCLR_Result AT91_Adc_ReadValue(const TinyCLR_Adc_Provider* self, int32_t channel, int32_t& value);
int32_t AT91_Adc_GetChannelCount(const TinyCLR_Adc_Provider* self);
int32_t AT91_Adc_GetResolutionInBits(const TinyCLR_Adc_Provider* self);
int32_t AT91_Adc_GetMinValue(const TinyCLR_Adc_Provider* self);
int32_t AT91_Adc_GetMaxValue(const TinyCLR_Adc_Provider* self);
TinyCLR_Adc_ChannelMode AT91_Adc_GetChannelMode(const TinyCLR_Adc_Provider* self);
TinyCLR_Result AT91_Adc_SetChannelMode(const TinyCLR_Adc_Provider* self, TinyCLR_Adc_ChannelMode mode);
bool AT91_Adc_IsChannelModeSupported(const TinyCLR_Adc_Provider* self, TinyCLR_Adc_ChannelMode mode);

// CAN
const TinyCLR_Api_Info* AT91_Can_GetApi();
TinyCLR_Result AT91_Can_Acquire(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_Release(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_SoftReset(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_WriteMessage(const TinyCLR_Can_Provider* self, uint32_t arbitrationId, bool isExtendedId, bool isRemoteTransmissionRequest, uint8_t* data, size_t length);
TinyCLR_Result AT91_Can_ReadMessage(const TinyCLR_Can_Provider* self, uint32_t& arbitrationId, bool& isExtendedId, bool& isRemoteTransmissionRequest, uint64_t& timestamp, uint8_t* data, size_t& length);
TinyCLR_Result AT91_Can_SetBitTiming(const TinyCLR_Can_Provider* self, int32_t propagation, int32_t phase1, int32_t phase2, int32_t baudratePrescaler, int32_t synchronizationJumpWidth, int8_t useMultiBitSampling);
TinyCLR_Result AT91_Can_GetUnreadMessageCount(const TinyCLR_Can_Provider* self, size_t& count);
TinyCLR_Result AT91_Can_SetMessageReceivedHandler(const TinyCLR_Can_Provider* self, TinyCLR_Can_MessageReceivedHandler handler);
TinyCLR_Result AT91_Can_SetErrorReceivedHandler(const TinyCLR_Can_Provider* self, TinyCLR_Can_ErrorReceivedHandler handler);
TinyCLR_Result AT91_Can_SetExplicitFilters(const TinyCLR_Can_Provider* self, uint8_t* filters, size_t length);
TinyCLR_Result AT91_Can_SetGroupFilters(const TinyCLR_Can_Provider* self, uint8_t* lowerBounds, uint8_t* upperBounds, size_t length);
TinyCLR_Result AT91_Can_ClearReadBuffer(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_IsWritingAllowed(const TinyCLR_Can_Provider* self, bool& allowed);
TinyCLR_Result AT91_Can_GetWriteErrorCount(const TinyCLR_Can_Provider* self, size_t& count);
TinyCLR_Result AT91_Can_GetReadErrorCount(const TinyCLR_Can_Provider* self, size_t& count);
TinyCLR_Result AT91_Can_GetSourceClock(const TinyCLR_Can_Provider* self, uint32_t& sourceClock);
TinyCLR_Result AT91_Can_SetReadBufferSize(const TinyCLR_Can_Provider* self, size_t size);
TinyCLR_Result AT91_Can_GetReadBufferSize(const TinyCLR_Can_Provider* self, size_t& size);
TinyCLR_Result AT91_Can_GetWriteBufferSize(const TinyCLR_Can_Provider* self, size_t& size);
TinyCLR_Result AT91_Can_SetWriteBufferSize(const TinyCLR_Can_Provider* self, size_t size);
void AT91_Can_Reset();

//DAC
const TinyCLR_Api_Info* AT91_Dac_GetApi();
void AT91_Dac_Reset();
TinyCLR_Result AT91_Dac_Acquire(const TinyCLR_Dac_Provider* self);
TinyCLR_Result AT91_Dac_Release(const TinyCLR_Dac_Provider* self);
TinyCLR_Result AT91_Dac_AcquireChannel(const TinyCLR_Dac_Provider* self, int32_t channel);
TinyCLR_Result AT91_Dac_ReleaseChannel(const TinyCLR_Dac_Provider* self, int32_t channel);
TinyCLR_Result AT91_Dac_WriteValue(const TinyCLR_Dac_Provider* self, int32_t channel, int32_t value);
int32_t AT91_Dac_GetChannelCount(const TinyCLR_Dac_Provider* self);
int32_t AT91_Dac_GetResolutionInBits(const TinyCLR_Dac_Provider* self);
int32_t AT91_Dac_GetMinValue(const TinyCLR_Dac_Provider* self);
int32_t AT91_Dac_GetMaxValue(const TinyCLR_Dac_Provider* self);

// PWM
struct PwmController {

    uint32_t                        *channelModeReg;
    uint32_t                        *dutyCycleReg;
    uint32_t                        *channelUpdateReg;

    AT91_Gpio_Pin                   gpioPin[MAX_PWM_PER_CONTROLLER];

    bool                            invert[MAX_PWM_PER_CONTROLLER];
    bool                            isOpened[MAX_PWM_PER_CONTROLLER];

    double                          frequency;
    double                          dutyCycle[MAX_PWM_PER_CONTROLLER];
};
const TinyCLR_Api_Info* AT91_Pwm_GetApi();
void AT91_Pwm_Reset();
void AT91_Pwm_ResetController(int32_t controller);
AT91_Gpio_Pin AT91_Pwm_GetPins(int32_t controller, int32_t channel);
TinyCLR_Result AT91_Pwm_Acquire(const TinyCLR_Pwm_Provider* self);
TinyCLR_Result AT91_Pwm_Release(const TinyCLR_Pwm_Provider* self);
int32_t AT91_Pwm_GetGpioPinForChannel(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_SetDesiredFrequency(const TinyCLR_Pwm_Provider* self, double& frequency);
TinyCLR_Result AT91_Pwm_AcquirePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_ReleasePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_EnablePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_DisablePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_SetPulseParameters(const TinyCLR_Pwm_Provider* self, int32_t pin, double dutyCycle, bool invertPolarity);
double AT91_Pwm_GetMinFrequency(const TinyCLR_Pwm_Provider* self);
double AT91_Pwm_GetMaxFrequency(const TinyCLR_Pwm_Provider* self);
double AT91_Pwm_GetActualFrequency(const TinyCLR_Pwm_Provider* self);
int32_t AT91_Pwm_GetPinCount(const TinyCLR_Pwm_Provider* self);


//RTC
const TinyCLR_Api_Info* AT91_Rtc_GetApi();
TinyCLR_Result AT91_Rtc_Acquire(const TinyCLR_Rtc_Provider* self);
TinyCLR_Result AT91_Rtc_Release(const TinyCLR_Rtc_Provider* self);
TinyCLR_Result AT91_Rtc_GetNow(const TinyCLR_Rtc_Provider* self, TinyCLR_Rtc_DateTime& value);
TinyCLR_Result AT91_Rtc_SetNow(const TinyCLR_Rtc_Provider* self, TinyCLR_Rtc_DateTime value);
<commit_msg>Tweak<commit_after>// Copyright Microsoft Corporation
// Copyright GHI Electronics, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <stdio.h>
#include <string.h>

#include <TinyCLR.h>
#include <Device.h>

#define SIZEOF_ARRAY(arr) (sizeof(arr) / sizeof(arr[0]))
#define CONCAT2(a, b) a##b
#define CONCAT(a, b) CONCAT2(a, b)
#define CHARIZE2(c) #c
#define CHARIZE(c) (CHARIZE2(c)[0])

void AT91_Startup_OnSoftReset(const TinyCLR_Api_Provider* apiProvider);
void AT91_Startup_OnSoftResetDevice(const TinyCLR_Api_Provider* apiProvider);

//
//  PERIPHERAL ID DEFINITIONS FOR AT91SAM9X35
//
#define AT91C_ID_FIQ		((unsigned int)  0) // Advanced Interrupt Controller (FIQ)
#define AT91C_ID_SYS		((unsigned int)  1) // System Interrupt
#define AT91C_ID_PIOA_PIOB	((unsigned int)  2) // Parallel IO Controller A and B
#define AT91C_ID_PIOC_PIOD	((unsigned int)  3) // Parallel IO Controller C and D
#define AT91C_ID_SMD		((unsigned int)  4) // SMD Soft Modem - not yet supported
#define AT91C_ID_USART0		((unsigned int)  5) // USART 0
#define AT91C_ID_USART1		((unsigned int)  6) // USART 1
#define AT91C_ID_USART2		((unsigned int)  7) // USART 2
#define AT91C_ID_TWI		AT91C_ID_TWI0       // only support one I2C
#define AT91C_ID_TWI0		((unsigned int)  9) // Two-Wire Interface 0
#define AT91C_ID_TWI1		((unsigned int) 10) // Two-Wire Interface 1
#define AT91C_ID_TWI2		((unsigned int) 11) // Two-Wire Interface 2
#define AT91C_ID_HSMCI0		((unsigned int) 12) // High Speed Multimedia Card Interface 0
#define AT91C_ID_SPI0		((unsigned int) 13) // Serial Peripheral Interface
#define AT91C_ID_SPI1		((unsigned int) 14) // Serial Peripheral Interface
#define AT91C_ID_UART0		((unsigned int) 15) // UART 0
#define AT91C_ID_UART1		((unsigned int) 16) // UART 1
#define AT91C_ID_TC0_TC1	((unsigned int) 17) // Timer Counter 0, 1, 2, 3, 4, 5
#define AT91C_ID_PWM		((unsigned int) 18) // Pulse Width Modulation Controller
#define AT91C_ID_ADC		((unsigned int) 19) // ADC Controller
#define AT91C_ID_DMAC0		((unsigned int) 20) // DMA Controller 0
#define AT91C_ID_DMAC1		((unsigned int) 21) // DMA Controller 1
#define AT91C_ID_UHPHS		((unsigned int) 22) // USB Host High Speed
#define AT91C_ID_UDPHS		((unsigned int) 23) // USB Device High Speed
#define AT91C_ID_EMAC		((unsigned int) 24) // Ethernet MAC
#define AT91C_ID_LCDC		((unsigned int) 25) // LCD Controller
#define AT91C_ID_HSMCI1		((unsigned int) 26) // High Speed Multimedia Card Interface 1
#define AT91C_ID_SSC		((unsigned int) 28) // Synchronous Serial Controller
#define AT91C_ID_CAN0		((unsigned int) 29) // CAN Controller 0
#define AT91C_ID_CAN1		((unsigned int) 30) // CAN Controller 1
#define AT91C_ID_IRQ0		((unsigned int) 31) // Advanced Interrupt Controller (IRQ0)

//
// BASE ADDRESS DEFINITIONS FOR AT91SAM9RL64
//
#define AT91C_BASE_SYS          0xFFFFE600 // (SYS) Base Address
#define AT91C_BASE_DMAC0        0xFFFFEC00 // Hydra original address 0xFFFFE600 // (DMAC)Address						- Not same Memory Address
#define AT91C_BASE_DDRS         0xFFFFE800 // (DDRS) Address
#define AT91C_BASE_SDRAMC       0xFFFFEA00 // (SDRAMC) Base Address
#define AT91C_BASE_SMC          0xFFFFEC00 // (SMC) Base Address
#define AT91C_BASE_MATRIX       0xFFFFEE00 // (MATRIX) Base Address				- Not same Memory Address
#define AT91C_BASE_AIC          0xFFFFF000 // (AIC) Base Address
#define AT91C_BASE_PDC_DBGU     0xFFFFF300 // (PDC_DBGU) Base Address
#define AT91C_BASE_DBGU         0xFFFFF200 // (DBGU) Base Address
#define AT91C_BASE_PIOA         0xFFFFF400 // (PIOA) Base Address
#define AT91C_BASE_PIOB         0xFFFFF600 // (PIOB) Base Address
#define AT91C_BASE_PIOC         0xFFFFF800 // (PIOC) Base Address
#define AT91C_BASE_PIOD         0xFFFFFA00 // (PIOD) Base Address
#define AT91C_BASE_CKGR         0xFFFFFC20 // (CKGR) Base Address
#define AT91C_BASE_PMC          0xFFFFFC00 // (PMC) Base Address
#define AT91C_BASE_RSTC         0xFFFFFE00 // (RSTC) Base Address				- Not same Memory Address
#define AT91C_BASE_RSTC_SR      0xFFFFFD04
#define AT91C_BASE_RSTC_MR      0xFFFFFD08
#define AT91C_BASE_SHDWC        0xFFFFFD10 // (SHDWC) Base Address
#define AT91C_BASE_RTTC         	0xFFFFFD20 // (RTTC) Base Address
#define AT91C_BASE_PITC         	0xFFFFFE30 // (PITC) Base Address
#define AT91C_BASE_WDTC         	0xFFFFFE40 // (WDTC) Base Address
#define AT91C_BASE_SCKCR        	0xFFFFFE50 // (SCKCR) Base Address
#define AT91C_BASE_GPBR         	0xFFFFFD60 // (GPBR) Base Address
#define AT91C_BASE_TC0         		0xF8008000 // Hydra original address 0xFFFA0000 // (TC0) Base Address
#define AT91C_BASE_TC1          	0xFFFA0040 // (TC1) Base Address
#define AT91C_BASE_TC2          	0xFFFA0080 // (TC2) Base Address
#define AT91C_BASE_TCB0         	0xFFFA0000 // (TCB0) Base Address
#define AT91C_BASE_PDC_MCI      	0xFFFA4100 // (PDC_MCI) Base Address
#define AT91C_BASE_MCI          	0xF0008000 // Hydra original address 0xFFFA4000 // (MCI) Base Address
#define AT91C_BASE_TWI0         	0xF8010000 // Hydra original address 0xFFFA8000 // (TWI1) Base Address
#define AT91C_BASE_TWI1         	0xF8014000 // Hydra original address 0xFFFAC000 // (TWI2) Base Address
#define AT91C_BASE_TWI2         	0xF8018000 // (TWI3) Base Address
#define AT91C_BASE_TWI          	AT91C_BASE_TWI0 // Support one I2C controller only
#define AT91C_BASE_USART0          	0xF801C000 // Hydra original address 0xFFFB0000 // (US0) Base Address				- Not same Memory Address
#define AT91C_BASE_USART1          	0xF8020000 // Hydra original address 0xFFFB4000 // (US1) Base Address				- Not same Memory Address
#define AT91C_BASE_USART2          	0xF8024000 // Hydra original address 0xFFFB8000 // (US2) Base Address				- Not same Memory Address
#define AT91C_BASE_UART0			0xF8040000
#define AT91C_BASE_UART1			0xF8044000
#define AT91C_BASE_PDC_US3      	0xFFFBC100 // (PDC_US3) Base Address
#define AT91C_BASE_US3          	0xF8008000 // Hydra original address 0xFFFBC000 // (US3) Base Address				- Not same Memory Address
#define AT91C_BASE_PDC_SSC0     	0xFFFC0100 // (PDC_SSC0) Base Address
#define AT91C_BASE_SSC0         	0xFFFC0000 // (SSC0) Base Address
#define AT91C_BASE_PDC_SSC1     	0xFFFC4100 // (PDC_SSC1) Base Address
#define AT91C_BASE_SSC1         	0xFFFC4000 // (SSC1) Base Address
#define AT91C_BASE_PWMC         	0xF8034000 // Hydra original address 0xFFFC8000 // (PWMC) Base Address				- Not same Memory Address
#define AT91C_BASE_PDC_SPI0     	0xFFFCC100 // (PDC_SPI0) Base Address
#define AT91C_BASE_SPI0         	0xF0000000 // (SPI0) Base Address // Hydra original address 0xFFFCC000
#define AT91C_BASE_SPI1         	0xF0004000 // (SPI1) Base Address
#define AT91C_BASE_TSADCC       	0xFFFD0000 // (ADC touch screen) Base Address
#define AT91C_BASE_UDP          	0xF803C000 // 0xFFFD4000 // (UDP) Base Address - Changed on G400
#define AT91C_BASE_AC97         	0xFFFD8000 // (UDP) Base Address
#define AT91C_BASE_ITCM         	0x00100000 // (ITCM) Base Address
#define AT91C_BASE_DTCM         	0x00200000 // (DTCM) Base Address
#define AT91C_BASE_LCDC         	0xF8038000 // Hydra original address 0x00500000 // (LCDC) Base Address
#define AT91C_BASE_UDP_DMA			0x00500000 // Hydra original address 0x00600000 // (UDP DMA) Base Address
#define AT91C_BASE_EMAC				0xF802C000

// RTSC bit defines
#define AT91C_RTSC__PROCRST     0x01         // processor reset bit
#define AT91C_RTSC__PERRST      0x04         // Peripheral reset bit
#define AT91C_RTSC__EXTRST      0x08         // asserts NRST pin
#define AT91C_RSTC__RESET_KEY   0xA5000000   // reset key
#define AT91C_RTSC_SR__SRCMP    (1ul < 17)   // Software Reset Command in progress
#define AT91C_RTSC_SR__NRSTL    (1ul < 16)   // Registers the NRST Pin Level at Master Clock (MCK)
#define AT91C_RTSC_SR__RSTTYP   (7ul <  8)   // Reset Type mask
#define AT91C_RTSC_SR__BODSTS   (1ul <  1)   // Brownout Detection Status
#define AT91C_RTSC_SR__URSTS    (1ul <  0)   // User Reset Status

// SHDWC bit defines
#define AT91C_SHDWC__SHUTDOWN_KEY   0xA5000000   // reset key
#define AT91C_SHDWC__SHDW           0x01         // processor reset bit

extern const TinyCLR_Api_Provider* apiProvider;

struct AT91_PMC {
    static const uint32_t c_Base = AT91C_BASE_PMC;

    volatile uint32_t PMC_SCER;                // System Clock Enable Register

    volatile uint32_t PMC_SCDR;                // System Clock Disable Register

    volatile uint32_t PMC_SCSR;                // System Clock Status Register

    volatile uint32_t Reserved0[1];

    volatile uint32_t PMC_PCER;                // Peripheral Clock Enable Register

    volatile uint32_t PMC_PCDR;                // Peripheral Clock Disable Register

    volatile uint32_t PMC_PCSR;                // Peripheral Clock Status Register

    volatile uint32_t PMC_CKGR_UCKR;            // UTMI Clock Register

    volatile uint32_t PMC_CKGR_MOR;            // Main Oscillator Register
    static const    uint32_t CKGR_MOSCEN = (0x1 << 0);       // (CKGR) Main Oscillator Enable
    static const    uint32_t CKGR_OSCBYPASS = (0x1 << 1);       // (CKGR) Main Oscillator Bypass
    static const    uint32_t CKGR_OSCOUNT = (0xFF << 8);      // (CKGR) Main Oscillator Start-up Time


    volatile uint32_t PMC_CKGR_MCFR;  // Main Clock  Frequency Register
    static const    uint32_t CKGR_MAINF = (0xFFFF << 0);     // (CKGR) Main Clock Frequency
    static const    uint32_t CKGR_MAINRDY = (0x1 << 16);       // (CKGR) Main Clock Ready


    volatile uint32_t PMC_CKGR_PLLAR;  // PLL Register


    static const    uint32_t CKGR_DIV = (0xFF << 0);     // (CKGR) Divider Selected
    static const    uint32_t CKGR_DIV_0 = (0x0);           // (CKGR) Divider output is 0
    static const    uint32_t CKGR_DIV_BYPASS = (0x1);           // (CKGR) Divider is bypassed
    static const    uint32_t CKGR_PLLCOUNT = (0x3F << 8);     // (CKGR) PLL Counter
    static const    uint32_t CKGR_OUT = (0x3 << 14);     // (CKGR) PLL Output Frequency Range
    static const    uint32_t CKGR_OUT_0 = (0x0 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_OUT_1 = (0x1 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_OUT_2 = (0x2 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_OUT_3 = (0x3 << 14);     // (CKGR) Please refer to the PLL datasheet
    static const    uint32_t CKGR_MUL = (0x7FF << 16);   // (CKGR) PLL Multiplier
    static const    uint32_t CKGR_USBDIV = (0x3 << 28);     // (CKGR) Divider for USB Clocks
    static const    uint32_t CKGR_USBDIV_0 = (0x0 << 28);     // (CKGR) Divider output is PLL clock output
    static const    uint32_t CKGR_USBDIV_1 = (0x1 << 28);     // (CKGR) Divider output is PLL clock output divided by 2
    static const    uint32_t CKGR_USBDIV_2 = (0x2 << 28);     // (CKGR) Divider output is PLL clock output divided by 4

    volatile uint32_t Reserved1[1];

    volatile uint32_t PMC_MCKR;  // Master Clock Register
    static const    uint32_t PMC_CSS = (0x3 << 0);   //  (PMC) Programmable Clock Selection
    static const    uint32_t PMC_CSS_SLOW_CLK = (0x0);         //  (PMC) Slow Clock is selected
    static const    uint32_t PMC_CSS_MAIN_CLK = (0x1);         //  (PMC) Main Clock is selected
    static const    uint32_t PMC_CSS_PLLA_CLK = (0x2);         //  (PMC) Clock from PLL1 is selected = (SAM9 only);
    static const    uint32_t PMC_CSS_PLL_CLK = (0x3);         //  (PMC) Clock from PLL is selected
    static const    uint32_t PMC_PRES = (0x7 << 2);   //  (PMC) Programmable Clock Prescaler
    static const    uint32_t PMC_PRES_CLK = (0x0 << 2);   //  (PMC) Selected clock
    static const    uint32_t PMC_PRES_CLK_2 = (0x1 << 2);   //  (PMC) Selected clock divided by 2
    static const    uint32_t PMC_PRES_CLK_4 = (0x2 << 2);   //  (PMC) Selected clock divided by 4
    static const    uint32_t PMC_PRES_CLK_8 = (0x3 << 2);   //  (PMC) Selected clock divided by 8
    static const    uint32_t PMC_PRES_CLK_16 = (0x4 << 2);   //  (PMC) Selected clock divided by 16
    static const    uint32_t PMC_PRES_CLK_32 = (0x5 << 2);   //  (PMC) Selected clock divided by 32
    static const    uint32_t PMC_PRES_CLK_64 = (0x6 << 2);   //  (PMC) Selected clock divided by 64
    static const    uint32_t PMC_MDIV = (0x3 << 8);   //  (PMC) Master Clock Division
    static const    uint32_t PMC_MDIV_1 = (0x0 << 8);   //  (PMC) The master clock and the processor clock are the same
    static const    uint32_t PMC_MDIV_2 = (0x1 << 8);   //  (PMC) The processor clock is twice as fast as the master clock
    static const    uint32_t PMC_MDIV_3 = (0x2 << 8);   //  (PMC) The processor clock is four times faster than the master clock

    volatile uint32_t Reserved3[3];  // TQD: Just a note PMC_USB and PMC_SMD are in here

    volatile uint32_t PMC_PCKR[2];   // Programmable Clock Register

    volatile uint32_t Reserved4[6];

    volatile uint32_t PMC_IER;   // Interrupt Enable Register
    static const    uint32_t PMC_MOSCS = (0x1 << 0);       // (PMC) MOSC Status/Enable/Disable/Mask
    static const    uint32_t PMC_LOCKA = (0x1 << 1);       // (PMC) PLL Status/Enable/Disable/Mask =(SAM9 Only);
    static const    uint32_t PMC_LOCK = (0x1 << 2);       // (PMC) PLL Status/Enable/Disable/Mask
    static const    uint32_t PMC_MCKRDY = (0x1 << 3);       // (PMC) MCK_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK0RDY = (0x1 << 8);       // (PMC) PCK0_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK1RDY = (0x1 << 9);       // (PMC) PCK1_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK2RDY = (0x1 << 10);       // (PMC) PCK2_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_PCK3RDY = (0x1 << 11);       // (PMC) PCK3_RDY Status/Enable/Disable/Mask
    static const    uint32_t PMC_LOCKU = (0x1 << 6);           //(PMC) USB clock locked
    volatile uint32_t PMC_IDR;   // Interrupt Disable Register

    volatile uint32_t PMC_SR;    // Status Register

    volatile uint32_t PMC_IMR;   // Interrupt Mask Register

    volatile uint32_t Reserved5[3]; // Reserved

    volatile uint32_t PMC_PLLICPR; // Charge Pump Current Register
    static const    uint32_t PMC_PLLICPR__PLLA = (0x1 << 0);
    static const    uint32_t PMC_PLLICPR__PLLB = (0x1 << 16);

    __inline void EnableSystemClock(uint32_t clkIds) {
        PMC_SCER = clkIds;
    }

    __inline void DisableSystemClock(uint32_t clkIds) {
        PMC_SCDR = clkIds;
    }

    __inline void EnablePeriphClock(uint32_t periphIds) {
        PMC_PCER = (1 << periphIds);
    }

    __inline void DisablePeriphClock(uint32_t periphIds) {
        PMC_PCDR = (1 << periphIds);
    }


};


// MMU
struct ARM9_MMU {
    static const uint32_t c_TTB_size = 0x4000;

    static const uint32_t c_MMU_L1_Fault = 0x00;
    static const uint32_t c_MMU_L1_Coarse = 0x11;
    static const uint32_t c_MMU_L1_Section = 0x12;
    static const uint32_t c_MMU_L1_Fine = 0x13;
    static const uint32_t c_MMU_L1_size = 1 << 20;

    static const uint32_t c_AP__NoAccess = 0;
    static const uint32_t c_AP__Client = 1;
    static const uint32_t c_AP__Reserved = 2;
    static const uint32_t c_AP__Manager = 3;

    //--//

    static uint32_t* GetL1Entry(uint32_t* base, uint32_t address);
    static void    InitializeL1(uint32_t* baseOfTTBs);
    static uint32_t  GenerateL1_Section(uint32_t address, uint32_t AP, uint32_t domain, bool Cachable, bool Buffered, bool Xtended = false);
    static void    GenerateL1_Sections(uint32_t* baseOfTTBs, uint32_t mappedAddress, uint32_t physAddress, int32_t size, uint32_t AP, uint32_t domain, bool Cachable, bool Buffered, bool Xtended = false);
};

void AT91_MMU_Initialize();
void AT91_CPU_InvalidateTLBs();
void AT91_CPU_EnableMMU(void* TTB);
void AT91_CPU_DisableMMU();
bool AT91_CPU_IsMMUEnabled();
void AT91_CPU_BootstrapCode();

// Cache
void AT91_Cache_FlushCaches();
void AT91_Cache_DrainWriteBuffers();
void AT91_Cache_InvalidateCaches();
void AT91_Cache_EnableCaches();
void AT91_Cache_DisableCaches();
template <typename T> void AT91_Cache_InvalidateAddress(T* address);
size_t AT91_Cache_GetCachableAddress(size_t address);
size_t AT91_Cache_GetUncachableAddress(size_t address);

// GPIO

//////////////////////////////////////////////////////////////////////////////
// AT91_GPIO
//
struct AT91_PIO {
    static const uint32_t c_Base = AT91C_BASE_PIOA;

    static const uint32_t c_Base_Offset = 0x200;

    volatile uint32_t PIO_PER;       /**< \brief (Pio Offset: 0x0000) PIO Enable Register */

    volatile uint32_t PIO_PDR;       /**< \brief (Pio Offset: 0x0004) PIO Disable Register */

    volatile uint32_t PIO_PSR;       /**< \brief (Pio Offset: 0x0008) PIO Status Register */

    volatile uint32_t Reserved1[1];

    volatile uint32_t PIO_OER;       /**< \brief (Pio Offset: 0x0010) Output Enable Register */

    volatile uint32_t PIO_ODR;       /**< \brief (Pio Offset: 0x0014) Output Disable Register */

    volatile uint32_t PIO_OSR;       /**< \brief (Pio Offset: 0x0018) Output Status Register */

    volatile uint32_t Reserved2[1];

    volatile uint32_t PIO_IFER;      /**< \brief (Pio Offset: 0x0020) Glitch Input Filter Enable Register */

    volatile uint32_t PIO_IFDR;      /**< \brief (Pio Offset: 0x0024) Glitch Input Filter Disable Register */

    volatile uint32_t PIO_IFSR;      /**< \brief (Pio Offset: 0x0028) Glitch Input Filter Status Register */

    volatile uint32_t Reserved3[1];

    volatile uint32_t PIO_SODR;      /**< \brief (Pio Offset: 0x0030) Set Output Data Register */

    volatile uint32_t PIO_CODR;      /**< \brief (Pio Offset: 0x0034) Clear Output Data Register */

    volatile uint32_t PIO_ODSR;      /**< \brief (Pio Offset: 0x0038) Output Data Status Register */

    volatile uint32_t PIO_PDSR;      /**< \brief (Pio Offset: 0x003C) Pin Data Status Register */

    volatile uint32_t PIO_IER;       /**< \brief (Pio Offset: 0x0040) Interrupt Enable Register */

    volatile uint32_t PIO_IDR;       /**< \brief (Pio Offset: 0x0044) Interrupt Disable Register */

    volatile uint32_t PIO_IMR;       /**< \brief (Pio Offset: 0x0048) Interrupt Mask Register */

    volatile uint32_t PIO_ISR;       /**< \brief (Pio Offset: 0x004C) Interrupt Status Register */

    volatile uint32_t PIO_MDER;      /**< \brief (Pio Offset: 0x0050) Multi-driver Enable Register */

    volatile uint32_t PIO_MDDR;      /**< \brief (Pio Offset: 0x0054) Multi-driver Disable Register */

    volatile uint32_t PIO_MDSR;      /**< \brief (Pio Offset: 0x0058) Multi-driver Status Register */

    volatile uint32_t Reserved4[1];

    volatile uint32_t PIO_PUDR;      /**< \brief (Pio Offset: 0x0060) Pull-up Disable Register */

    volatile uint32_t PIO_PUER;      /**< \brief (Pio Offset: 0x0064) Pull-up Enable Register */

    volatile uint32_t PIO_PUSR;      /**< \brief (Pio Offset: 0x0068) Pad Pull-up Status Register */

    volatile uint32_t Reserved5[1];

    volatile uint32_t PIO_ABCDSR[2]; /**< \brief (Pio Offset: 0x0070) Peripheral Select Register */

    volatile uint32_t Reserved6[2];

    volatile uint32_t PIO_IFSCDR;    /**< \brief (Pio Offset: 0x0080) Input Filter Slow Clock Disable Register */

    volatile uint32_t PIO_IFSCER;    /**< \brief (Pio Offset: 0x0084) Input Filter Slow Clock Enable Register */

    volatile uint32_t PIO_IFSCSR;    /**< \brief (Pio Offset: 0x0088) Input Filter Slow Clock Status Register */

    volatile uint32_t PIO_SCDR;      /**< \brief (Pio Offset: 0x008C) Slow Clock Divider Debouncing Register */

    volatile uint32_t PIO_PPDDR;     /**< \brief (Pio Offset: 0x0090) Pad Pull-down Disable Register */

    volatile uint32_t PIO_PPDER;     /**< \brief (Pio Offset: 0x0094) Pad Pull-down Enable Register */

    volatile uint32_t PIO_PPDSR;     /**< \brief (Pio Offset: 0x0098) Pad Pull-down Status Register */

    volatile uint32_t Reserved7[1];

    volatile uint32_t PIO_OWER;      /**< \brief (Pio Offset: 0x00A0) Output Write Enable */

    volatile uint32_t PIO_OWDR;      /**< \brief (Pio Offset: 0x00A4) Output Write Disable */

    volatile uint32_t PIO_OWSR;      /**< \brief (Pio Offset: 0x00A8) Output Write Status Register */

    volatile uint32_t Reserved8[1];
    volatile uint32_t PIO_AIMER;     /**< \brief (Pio Offset: 0x00B0) Additional Interrupt Modes Enable Register */

    volatile uint32_t PIO_AIMDR;     /**< \brief (Pio Offset: 0x00B4) Additional Interrupt Modes Disables Register */

    volatile uint32_t PIO_AIMMR;     /**< \brief (Pio Offset: 0x00B8) Additional Interrupt Modes Mask Register */

    volatile uint32_t Reserved9[1];

    volatile uint32_t PIO_ESR;       /**< \brief (Pio Offset: 0x00C0) Edge Select Register */

    volatile uint32_t PIO_LSR;       /**< \brief (Pio Offset: 0x00C4) Level Select Register */

    volatile uint32_t PIO_ELSR;      /**< \brief (Pio Offset: 0x00C8) Edge/Level Status Register */

    volatile uint32_t Reserved10[1];

    volatile uint32_t PIO_FELLSR;    /**< \brief (Pio Offset: 0x00D0) Falling Edge/Low Level Select Register */

    volatile uint32_t PIO_REHLSR;    /**< \brief (Pio Offset: 0x00D4) Rising Edge/ High Level Select Register */

    volatile uint32_t PIO_FRLHSR;    /**< \brief (Pio Offset: 0x00D8) Fall/Rise - Low/High Status Register */

    volatile uint32_t Reserved11[1];

    volatile uint32_t PIO_LOCKSR;    /**< \brief (Pio Offset: 0x00E0) Lock Status */

    volatile uint32_t PIO_WPMR;      /**< \brief (Pio Offset: 0x00E4) Write Protect Mode Register */

    volatile uint32_t PIO_WPSR;      /**< \brief (Pio Offset: 0x00E8) Write Protect Status Register */

    volatile uint32_t Reserved12[5];

    volatile uint32_t PIO_SCHMITT;   /**< \brief (Pio Offset: 0x0100) Schmitt Trigger Register */

    volatile uint32_t Reserved13[3];

    volatile uint32_t PIO_DELAYR;    /**< \brief (Pio Offset: 0x0110) IO Delay Register */

    volatile uint32_t PIO_DRIVER1;   /**< \brief (Pio Offset: 0x0114) I/O Drive Register 1 */

    volatile uint32_t PIO_DRIVER2;   /**< \brief (Pio Offset: 0x0118) I/O Drive Register 2 */
};

// --//


enum class AT91_Gpio_PeripheralSelection : uint8_t {
    None = 0,
    PeripheralA = 1,
    PeripheralB = 2,
    PeripheralC = 3,
    PeripheralD = 4
};

enum class AT91_Gpio_Direction : uint8_t {
    Input = 0,
    Output = 1
};

enum class AT91_Gpio_ResistorMode : uint8_t {
    Inactive = 0,
    PullUp = 1,
    PullDown = 2,
};

enum class AT91_Gpio_MultiDriver : uint8_t {
    Disable = 0,
    Enable = 1
};

enum class AT91_Gpio_Filter : uint8_t {
    Disable = 0,
    Enable = 1
};

enum class AT91_Gpio_FilterSlowClock : uint8_t {
    Disable = 0,
    Enable = 1
};

enum class AT91_Gpio_Schmitt : uint8_t {
    Enable = 0,
    Disable = 1
};

enum class AT91_Gpio_DriveSpeed : uint8_t {
    High = 0,
    Medium = 1,
    Low = 2,
    Reserved = 3
};

struct AT91_Gpio_Pin {
    uint32_t number;
    AT91_Gpio_PeripheralSelection peripheralSelection;
};

struct AT91_Gpio_PinConfiguration {
    AT91_Gpio_Direction direction;
    AT91_Gpio_ResistorMode resistorMode;
    AT91_Gpio_MultiDriver multiDriver;
    AT91_Gpio_Filter filter;
    AT91_Gpio_FilterSlowClock filterSlowClock;
    AT91_Gpio_Schmitt schmitt;
    AT91_Gpio_DriveSpeed speed;
    AT91_Gpio_PeripheralSelection peripheralSelection;
    bool apply;
};

#define PIN(port, pin) ((CHARIZE(port) - 'A') * 32 + pin)
#define PIN_NONE 0xFFFFFFFF
#define PS(num) (CONCAT(AT91_Gpio_PeripheralSelection::Peripheral, num))
#define PS_NONE AT91_Gpio_PeripheralSelection::None

#define INIT(pinDirection, resistorMode, peripheralSelection, apply) { AT91_Gpio_Direction::pinDirection, AT91_Gpio_ResistorMode::resistorMode, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable,  AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::peripheralSelection, apply }
#define ALTFUN(direction, resistorMode, peripheralSelection) { AT91_Gpio_Direction::direction, AT91_Gpio_ResistorMode::resistorMode, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable,  AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::peripheralSelection, true }
#define INPUT(resistorMode) { AT91_Gpio_Direction::Input, AT91_Gpio_ResistorMode::resistorMode, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable, AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::None, true }
#define DEFAULT() { AT91_Gpio_Direction::Input, AT91_Gpio_ResistorMode::Inactive, AT91_Gpio_MultiDriver::Disable, AT91_Gpio_Filter::Disable, AT91_Gpio_FilterSlowClock::Disable, AT91_Gpio_Schmitt::Disable, AT91_Gpio_DriveSpeed::High, AT91_Gpio_PeripheralSelection::None, false }

void AT91_Gpio_Reset();
const TinyCLR_Api_Info* AT91_Gpio_GetApi();
TinyCLR_Result AT91_Gpio_Acquire(const TinyCLR_Gpio_Provider* self);
TinyCLR_Result AT91_Gpio_Release(const TinyCLR_Gpio_Provider* self);
TinyCLR_Result AT91_Gpio_EnableAlternatePin(int32_t pin, TinyCLR_Gpio_PinDriveMode resistor, uint32_t alternate);
TinyCLR_Result AT91_Gpio_Read(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinValue& value);
TinyCLR_Result AT91_Gpio_Write(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinValue value);
TinyCLR_Result AT91_Gpio_SetDebounceTimeout(const TinyCLR_Gpio_Provider* self, int32_t pin, int32_t debounceTime);
TinyCLR_Result AT91_Gpio_SetDriveMode(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinDriveMode mode);
TinyCLR_Result AT91_Gpio_AcquirePin(const TinyCLR_Gpio_Provider* self, int32_t pin);
bool AT91_Gpio_IsDriveModeSupported(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_PinDriveMode mode);
TinyCLR_Gpio_PinDriveMode AT91_Gpio_GetDriveMode(const TinyCLR_Gpio_Provider* self, int32_t pin);
int32_t AT91_Gpio_GetDebounceTimeout(const TinyCLR_Gpio_Provider* self, int32_t pin);
int32_t AT91_Gpio_GetPinCount(const TinyCLR_Gpio_Provider* self);
TinyCLR_Result AT91_Gpio_SetValueChangedHandler(const TinyCLR_Gpio_Provider* self, int32_t pin, TinyCLR_Gpio_ValueChangedHandler ISR);
TinyCLR_Result AT91_Gpio_ReleasePin(const TinyCLR_Gpio_Provider* self, int32_t pin);
void AT91_Gpio_EnableOutputPin(int32_t pin, bool initialState);
void AT91_Gpio_EnableInputPin(int32_t pin, TinyCLR_Gpio_PinDriveMode resistor);
bool AT91_Gpio_OpenPin(int32_t pin);
bool AT91_Gpio_ClosePin(int32_t pin);
bool AT91_Gpio_ReadPin(int32_t pin);
void AT91_Gpio_WritePin(int32_t pin, bool value);
bool AT91_Gpio_ConfigurePin(int32_t pin, AT91_Gpio_Direction pinDir, AT91_Gpio_PeripheralSelection peripheralSelection, AT91_Gpio_ResistorMode resistorMode);
bool AT91_Gpio_ConfigurePin(int32_t pin, AT91_Gpio_Direction pinDir, AT91_Gpio_PeripheralSelection peripheralSelection, AT91_Gpio_ResistorMode resistorMode, AT91_Gpio_MultiDriver multiDrive, AT91_Gpio_Filter filter, AT91_Gpio_FilterSlowClock filterSlowClock, AT91_Gpio_Schmitt schmitt, AT91_Gpio_DriveSpeed driveSpeed);

// ADC
const TinyCLR_Api_Info* AT91_Adc_GetApi();
void AT91_Adc_Reset();
int32_t AT91_Adc_GetControllerCount();
int32_t AT91_Adc_GetPin(int32_t channel);
AT91_Gpio_PeripheralSelection AT91_Adc_GetPeripheralSelection(int32_t channel);
TinyCLR_Result AT91_Adc_Acquire(const TinyCLR_Adc_Provider* self);
TinyCLR_Result AT91_Adc_Release(const TinyCLR_Adc_Provider* self);
TinyCLR_Result AT91_Adc_AcquireChannel(const TinyCLR_Adc_Provider* self, int32_t channel);
TinyCLR_Result AT91_Adc_ReleaseChannel(const TinyCLR_Adc_Provider* self, int32_t channel);
TinyCLR_Result AT91_Adc_ReadValue(const TinyCLR_Adc_Provider* self, int32_t channel, int32_t& value);
int32_t AT91_Adc_GetChannelCount(const TinyCLR_Adc_Provider* self);
int32_t AT91_Adc_GetResolutionInBits(const TinyCLR_Adc_Provider* self);
int32_t AT91_Adc_GetMinValue(const TinyCLR_Adc_Provider* self);
int32_t AT91_Adc_GetMaxValue(const TinyCLR_Adc_Provider* self);
TinyCLR_Adc_ChannelMode AT91_Adc_GetChannelMode(const TinyCLR_Adc_Provider* self);
TinyCLR_Result AT91_Adc_SetChannelMode(const TinyCLR_Adc_Provider* self, TinyCLR_Adc_ChannelMode mode);
bool AT91_Adc_IsChannelModeSupported(const TinyCLR_Adc_Provider* self, TinyCLR_Adc_ChannelMode mode);

// CAN
const TinyCLR_Api_Info* AT91_Can_GetApi();
TinyCLR_Result AT91_Can_Acquire(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_Release(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_SoftReset(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_WriteMessage(const TinyCLR_Can_Provider* self, uint32_t arbitrationId, bool isExtendedId, bool isRemoteTransmissionRequest, uint8_t* data, size_t length);
TinyCLR_Result AT91_Can_ReadMessage(const TinyCLR_Can_Provider* self, uint32_t& arbitrationId, bool& isExtendedId, bool& isRemoteTransmissionRequest, uint64_t& timestamp, uint8_t* data, size_t& length);
TinyCLR_Result AT91_Can_SetBitTiming(const TinyCLR_Can_Provider* self, int32_t propagation, int32_t phase1, int32_t phase2, int32_t baudratePrescaler, int32_t synchronizationJumpWidth, int8_t useMultiBitSampling);
TinyCLR_Result AT91_Can_GetUnreadMessageCount(const TinyCLR_Can_Provider* self, size_t& count);
TinyCLR_Result AT91_Can_SetMessageReceivedHandler(const TinyCLR_Can_Provider* self, TinyCLR_Can_MessageReceivedHandler handler);
TinyCLR_Result AT91_Can_SetErrorReceivedHandler(const TinyCLR_Can_Provider* self, TinyCLR_Can_ErrorReceivedHandler handler);
TinyCLR_Result AT91_Can_SetExplicitFilters(const TinyCLR_Can_Provider* self, uint8_t* filters, size_t length);
TinyCLR_Result AT91_Can_SetGroupFilters(const TinyCLR_Can_Provider* self, uint8_t* lowerBounds, uint8_t* upperBounds, size_t length);
TinyCLR_Result AT91_Can_ClearReadBuffer(const TinyCLR_Can_Provider* self);
TinyCLR_Result AT91_Can_IsWritingAllowed(const TinyCLR_Can_Provider* self, bool& allowed);
TinyCLR_Result AT91_Can_GetWriteErrorCount(const TinyCLR_Can_Provider* self, size_t& count);
TinyCLR_Result AT91_Can_GetReadErrorCount(const TinyCLR_Can_Provider* self, size_t& count);
TinyCLR_Result AT91_Can_GetSourceClock(const TinyCLR_Can_Provider* self, uint32_t& sourceClock);
TinyCLR_Result AT91_Can_SetReadBufferSize(const TinyCLR_Can_Provider* self, size_t size);
TinyCLR_Result AT91_Can_GetReadBufferSize(const TinyCLR_Can_Provider* self, size_t& size);
TinyCLR_Result AT91_Can_GetWriteBufferSize(const TinyCLR_Can_Provider* self, size_t& size);
TinyCLR_Result AT91_Can_SetWriteBufferSize(const TinyCLR_Can_Provider* self, size_t size);
void AT91_Can_Reset();

//DAC
const TinyCLR_Api_Info* AT91_Dac_GetApi();
void AT91_Dac_Reset();
TinyCLR_Result AT91_Dac_Acquire(const TinyCLR_Dac_Provider* self);
TinyCLR_Result AT91_Dac_Release(const TinyCLR_Dac_Provider* self);
TinyCLR_Result AT91_Dac_AcquireChannel(const TinyCLR_Dac_Provider* self, int32_t channel);
TinyCLR_Result AT91_Dac_ReleaseChannel(const TinyCLR_Dac_Provider* self, int32_t channel);
TinyCLR_Result AT91_Dac_WriteValue(const TinyCLR_Dac_Provider* self, int32_t channel, int32_t value);
int32_t AT91_Dac_GetChannelCount(const TinyCLR_Dac_Provider* self);
int32_t AT91_Dac_GetResolutionInBits(const TinyCLR_Dac_Provider* self);
int32_t AT91_Dac_GetMinValue(const TinyCLR_Dac_Provider* self);
int32_t AT91_Dac_GetMaxValue(const TinyCLR_Dac_Provider* self);

// PWM
struct PwmController {

    uint32_t                        *channelModeReg;
    uint32_t                        *dutyCycleReg;
    uint32_t                        *channelUpdateReg;

    AT91_Gpio_Pin                   gpioPin[MAX_PWM_PER_CONTROLLER];

    bool                            invert[MAX_PWM_PER_CONTROLLER];
    bool                            isOpened[MAX_PWM_PER_CONTROLLER];

    double                          frequency;
    double                          dutyCycle[MAX_PWM_PER_CONTROLLER];
};
const TinyCLR_Api_Info* AT91_Pwm_GetApi();
void AT91_Pwm_Reset();
void AT91_Pwm_ResetController(int32_t controller);
AT91_Gpio_Pin AT91_Pwm_GetPins(int32_t controller, int32_t channel);
TinyCLR_Result AT91_Pwm_Acquire(const TinyCLR_Pwm_Provider* self);
TinyCLR_Result AT91_Pwm_Release(const TinyCLR_Pwm_Provider* self);
int32_t AT91_Pwm_GetGpioPinForChannel(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_SetDesiredFrequency(const TinyCLR_Pwm_Provider* self, double& frequency);
TinyCLR_Result AT91_Pwm_AcquirePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_ReleasePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_EnablePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_DisablePin(const TinyCLR_Pwm_Provider* self, int32_t pin);
TinyCLR_Result AT91_Pwm_SetPulseParameters(const TinyCLR_Pwm_Provider* self, int32_t pin, double dutyCycle, bool invertPolarity);
double AT91_Pwm_GetMinFrequency(const TinyCLR_Pwm_Provider* self);
double AT91_Pwm_GetMaxFrequency(const TinyCLR_Pwm_Provider* self);
double AT91_Pwm_GetActualFrequency(const TinyCLR_Pwm_Provider* self);
int32_t AT91_Pwm_GetPinCount(const TinyCLR_Pwm_Provider* self);

//RTC
const TinyCLR_Api_Info* AT91_Rtc_GetApi();
TinyCLR_Result AT91_Rtc_Acquire(const TinyCLR_Rtc_Provider* self);
TinyCLR_Result AT91_Rtc_Release(const TinyCLR_Rtc_Provider* self);
TinyCLR_Result AT91_Rtc_GetNow(const TinyCLR_Rtc_Provider* self, TinyCLR_Rtc_DateTime& value);
TinyCLR_Result AT91_Rtc_SetNow(const TinyCLR_Rtc_Provider* self, TinyCLR_Rtc_DateTime value);

{'fraction_non_alphanumeric': 0.08451701402716934, 'fraction_numerical': 0.06345413513872296, 'mean_word_length': 4.013161786453712, 'pattern_counts': {'":': 0, '<': 299, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5293473', 'n_tokens_mistral': 27575, 'n_tokens_neox': 24485, 'n_words': 6070}