//! The memory map of the board.

use crate::utils::field::Field;


pub const START_PHYSICAL_ADDRESS: usize = 0x3F00_0000;

// ** GPIO addresses **
/// Offset between the GPIO addresses and the beginning of the physical addresses
pub const GPIO_OFFSET: usize = 0x0020_0000;
/// Beginning of the GPIO adresses
pub const GPIO_START: usize = START_PHYSICAL_ADDRESS + GPIO_OFFSET;

/// GPIO memory map.
pub mod gpio {
    use super::*;

    // Function Select
    /// GPIO Function Select 0, R/W register.
    ///
    /// # Bits distribution:
    ///
    /// - 29-27: FSEL9
    /// - 26-24: FSEL8
    /// - 23-21: FSEL7
    /// - 20-18: FSEL6
    /// - 17-15: FSEL5
    /// - 14-12: FSEL4
    /// - 11-9: FSEL3
    /// - 8-6: FSEL2
    /// - 5-3: FSEL1
    /// - 2-0: FSEL0
    pub const GPFSEL0: usize = GPIO_START + 0x00;
    /// GPIO Function Select 1, R/W register.
    ///
    /// # Bits distribution:
    ///
    /// - 29-27: FSEL19
    /// - 26-24: FSEL18
    /// - 23-21: FSEL17
    /// - 20-18: FSEL16
    /// - 17-15: FSEL15
    /// - 14-12: FSEL14
    /// - 11-9: FSEL13
    /// - 8-6: FSEL12
    /// - 5-3: FSEL11
    /// - 2-0: FSEL10
    pub const GPFSEL1:usize = GPIO_START + 0x04;
    /// GPIO Function Select 2, R/W register.
    ///
    /// # Bits distribution:
    ///
    /// - 29-27: FSEL29
    /// - 26-24: FSEL28
    /// - 23-21: FSEL27
    /// - 20-18: FSEL26
    /// - 17-15: FSEL25
    /// - 14-12: FSEL24
    /// - 11-9: FSEL23
    /// - 8-6: FSEL22
    /// - 5-3: FSEL21
    /// - 2-0: FSEL20
    pub const GPFSEL2:usize = GPIO_START + 0x08;
    /// GPIO Function Select 3, R/W register.
    ///
    /// # Bits distribution:
    ///
    /// - 29-27: FSEL39
    /// - 26-24: FSEL38
    /// - 23-21: FSEL37
    /// - 20-18: FSEL36
    /// - 17-15: FSEL35
    /// - 14-12: FSEL34
    /// - 11-9: FSEL33
    /// - 8-6: FSEL32
    /// - 5-3: FSEL31
    /// - 2-0: FSEL30
    pub const GPFSEL3:usize = GPIO_START + 0x0C;
    /// GPIO Function Select 4, R/W register.
    ///
    /// # Bits distribution:
    ///
    /// - 29-27: FSEL49
    /// - 26-24: FSEL48
    /// - 23-21: FSEL47
    /// - 20-18: FSEL46
    /// - 17-15: FSEL45
    /// - 14-12: FSEL44
    /// - 11-9: FSEL43
    /// - 8-6: FSEL42
    /// - 5-3: FSEL41
    /// - 2-0: FSEL40
    pub const GPFSEL4:usize = GPIO_START + 0x10;
    /// GPIO Function Select 5, R/W register.
    ///
    /// # Bits distribution:
    ///
    /// - 11-9: FSEL53
    /// - 8-6: FSEL52
    /// - 5-3: FSEL51
    /// - 2-0: FSEL50
    pub const GPFSEL5:usize = GPIO_START + 0x14;
    
    /// Return the field FSELn.
    /// 
    /// # Panic
    /// 
    /// Panic if the pin `n` does not exist.
    pub const fn get_fsel(n: usize) -> Field {
        if n > 53 {
            panic!("The PIN does not exist");
        }
        let address = [GPFSEL0, GPFSEL1, GPFSEL2, GPFSEL3, GPFSEL4, GPFSEL5][n/10];
        let offset = 3*(n%10);
        let size = 3;
        Field::new(address, offset, size)
    }
    
    // Pin Output Set
    /// Pin Output Set 0, W register.
    ///
    /// # Bits distribution:
    ///
    /// - 31: SET31
    /// - ...
    /// - 0: SET0
    pub const GPSET0:usize = GPIO_START + 0x1C;
    /// Pin Output Set 1, W register.
    ///
    /// # Bits distribution:
    ///
    /// - 21: SET53
    /// - ...
    /// - 0: SET32
    pub const GPSET1:usize = GPIO_START + 0x20;
    
    /// Return the field SETn.
    /// 
    /// # Panic
    /// 
    /// Panic if the pin `n` does not exist.
    pub const fn get_set(n: usize) -> Field {
        if n > 53 {
            panic!("The PIN does not exist");
        }
        let (address, offset) = if n < 32 {
            (GPSET0, n)
        } else {
            (GPSET1, n-32)
        };
        let size = 1;
        Field::new(address, offset, size)
    }
    
    // Pin Output Clear
    /// Pin Output Clear 0, W register.
    ///
    /// # Bits distribution:
    ///
    /// - 31: CLR31
    /// - ...
    /// - 0: CLR0
    pub const GPCLR0:usize = GPIO_START + 0x28;
    /// Pin Output Clear 1, W register.
    ///
    /// # Bits distribution:
    ///
    /// - 21: CLR53
    /// - ...
    /// - 0: CLR32
    pub const GPCLR1:usize = GPIO_START + 0x2C;
    
    /// Return the field CLRn.
    /// 
    /// # Panic
    /// 
    /// Panic if the pin `n` does not exist.
    pub const fn get_clr(n: usize) -> Field {
        if n > 53 {
            panic!("The PIN does not exist");
        }
        let (address, offset) = if n < 32 {
            (GPCLR0, n)
        } else {
            (GPCLR1, n-32)
        };
        let size = 1;
        Field::new(address, offset, size)
    }
    
    // Pin Level
    /// Pin Level 0, R register.
    pub const GPLEV0:usize = GPIO_START + 0x34;
    /// Pin Level 1, R register.
    pub const GPLEV1:usize = GPIO_START + 0x38;
    
    // Pin Event Detect Status
    /// Pin Event Detect Status 0, R/W register.
    pub const GPEDS0:usize = GPIO_START + 0x40;
    /// Pin Event Detect Status 1, R/W register.
    pub const GPEDS1:usize = GPIO_START + 0x44;
    
    // Pin Rising Edge Detect Enable
    /// Pin Rising Edge Detect Enable 0, R/W register.
    pub const GPREN0:usize = GPIO_START + 0x4C;
    /// Pin Rising Edge Detect Enable 1, R/W register.
    pub const GPREN1:usize = GPIO_START + 0x50;
    
    // Pin Falling Edge Detect Enable
    /// Pin Falling Edge Detect Enable 0, R/W register.
    pub const GPFEN0:usize = GPIO_START + 0x58;
    /// Pin Falling Edge Detect Enable 1, R/W register.
    pub const GPFEN1:usize = GPIO_START + 0x5C;
    
    // Pin High Detect Enable
    /// Pin High Detect Enable 0, R/W register.
    pub const GPHEN0:usize = GPIO_START + 0x64;
    /// Pin High Detect Enable 1, R/W register.
    pub const GPHEN1:usize = GPIO_START + 0x68;
    
    // Pin Low Detect Enable
    /// Pin Low Detect Enable 0, R/W register.
    pub const GPLEN0:usize = GPIO_START + 0x70;
    /// Pin Low Detect Enable 1, R/W register.
    pub const GPLEN1:usize = GPIO_START + 0x74;
    
    // Pin Async, Rising Edge Detect
    /// Pin Async, Rising Edge Detect 0, R/W register.
    pub const GPAREN0:usize = GPIO_START + 0x7C;
    /// Pin Async, Rising Edge Detect 1, R/W register.
    pub const GPAREN1:usize = GPIO_START + 0x80;
    
    // Pin Async, Falling Edge Detect
    /// Pin Async, Falling Edge Detect 0, R/W register.
    pub const GPAFEN0:usize = GPIO_START + 0x88;
    /// Pin Async, Falling Edge Detect1, R/W register.
    pub const GPAFEN1:usize = GPIO_START + 0x8C;
    
    // Pin Pull-up/down Enable, R/W
    /// Pin Pull-up/down Enable, R/W register.
    pub const GPPUD:usize = GPIO_START + 0x94;
    
    // Pin Pull-up/down enable clock, R/W
    /// Pin Pull-up/down enable clock 0, R/W register.
    pub const GPPUDCLK0:usize = GPIO_START + 0x98;
    /// Pin Pull-up/down enable clock 1, R/W register.
    pub const GPPUDCLK1:usize = GPIO_START + 0x9C;
    
    // Test ?, R/W, 4 bits
    /// Test register? only 4 bits long.
    pub const GPIO_TEST:usize = GPIO_START + 0xB0;
}
// ** GPIO addresses **

// ** UART addresses **
/// Offset between the UART addresses and the beginning of the physical addresses
pub const UART_OFFSET: usize = 0x0020_1000;
/// Begeinning of the UART addresses.
pub const UART_START: usize = START_PHYSICAL_ADDRESS + UART_OFFSET;

/// UART memory map.
pub mod uart {
    use super::*;

    pub struct UartMemoryMap {
        /// Data Register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-12: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 11: OE, Overrun Error. Set to 1 if data received with FIFO full, R/W.
        /// - 10: BE, Break Error. Set to 1 if a break condition was detected, R/W.
        /// - 9: PE, Parity Error. Set to 1 when the parity don't match data, R/W.
        /// - 8: FE, Framing Error. Set to 1 when character don't have valid stop bit, R/W.
        /// - 7-0: DATA, Data character. R/W.
        pub dr: Field,

        /// OE, Overrun Error. Set to 1 if data received with FIFO full, R/W.
        /// 
        /// Field located inside the Data Register [`dr`].
        pub dr_oe: Field,

        /// BE, Break Error. Set to 1 if a break condition was detected, R/W.
        /// 
        /// Field located inside the Data Register [`dr`].
        pub dr_be: Field,

        /// PE, Parity Error. Set to 1 when the parity don't match data, R/W.
        /// 
        /// Field located inside the Data Register [`dr`].
        pub dr_pe: Field,

        /// FE, Framing Error. Set to 1 when character don't have valid stop bit, R/W.
        /// 
        /// Field located inside the Data Register [`dr`].
        pub dr_fe: Field,

        /// DATA, Data character. R/W.
        /// 
        /// Field located inside the Data Register [`dr`].
        pub dr_data: Field,


        /// Receive Status Register/Error Clear Register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-12: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 3: OE, Overrun Error. Set to 1 if data received with FIFO full, R/W.
        /// - 2: BE, Break Error. Set to 1 if a break condition was detected, R/W.
        /// - 1: PE, Parity Error. Set to 1 when the parity don't match data, R/W.
        /// - 0: FE, Framing Error. Set to 1 when characteur don't have valid stop bit, R/W.
        pub rsrecr: Field,

        /// OE, Overrun Error. Set to 1 if data received with FIFO full, R/W.
        /// 
        /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
        pub rsrecr_oe: Field,

        /// BE, Break Error. Set to 1 if a break condition was detected, R/W.
        /// 
        /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
        pub rsrecr_be: Field,

        /// PE, Parity Error. Set to 1 when the parity don't match data, R/W.
        /// 
        /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
        pub rsrecr_pe: Field,

        /// FE, Framing Error. Set to 1 when characteur don't have valid stop bit, R/W.
        /// 
        /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
        pub rsrecr_fe: Field,

        /// Flag Register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-9: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 8: RI, unsuported. Write as 0, value read don't have meaning, R/W.
        /// - 7: TXFE, Transmit FIFO Empty. If FIFO disabled, set when tx holding register empty.
        ///     If FIFO enabled, set when tx FIFP is empty. R/W.
        /// - 6: RXFF, Receive FIFO Full. If FIFO disabled, set when rx holding register is full.
        ///     If FIFO enabled, set when rx FIFO is full. R/W.
        /// - 5: TXFF, Transmit FIFO Full. If FIFO disabled, set when tx holding register full.
        ///     If FIFO enabled, set when tx FIFP is full. R/W.
        /// - 4: RXFE, Receive FIFO Empty. If FIFO disabled, set when rx holding register is empty.
        ///     If FIFO enabled, set when rx FIFO is empty. R/W.
        /// - 3: BUSY. Is set, UART is busy transmitting data. R/W.
        /// - 2: DCD, unsuported. Write as 0, value read don't have meaning, R/W.
        /// - 1: DSR, unsuported. Write as 0, value read don't have meaning, R/W.
        /// - 0: CTS, Clear To Send. 
        pub fr: Field,

        /// RI, unsuported. Write as 0, value read don't have meaning, R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_ri: Field,

        /// TXFE, Transmit FIFO Empty. If FIFO disabled, set when tx holding register empty.
        ///     If FIFO enabled, set when tx FIFP is empty. R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_txfe: Field,

        /// RXFF, Receive FIFO Full. If FIFO disabled, set when rx holding register is full.
        ///     If FIFO enabled, set when rx FIFO is full. R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_rxff: Field,

        /// TXFF, Transmit FIFO Full. If FIFO disabled, set when tx holding register full.
        ///     If FIFO enabled, set when tx FIFP is full. R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_txff: Field,

        /// RXFE, Receive FIFO Empty. If FIFO disabled, set when rx holding register is empty.
        ///     If FIFO enabled, set when rx FIFO is empty. R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_rxfe: Field,

        /// BUSY. Is set, UART is busy transmitting data. R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_busy: Field,

        /// DCD, unsuported. Write as 0, value read don't have meaning, R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_dcd: Field,

        /// DSR, unsuported. Write as 0, value read don't have meaning, R/W.
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_dsr: Field,

        /// CTS, Clear To Send. 
        ///
        /// Field located inside the Flag Register [`fr`].
        pub fr_cts: Field,

        /// Not in use. 32 bits long.
        pub ilpr: Field,

        /// Integer Baud rate divisor, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-16: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 15-0: IBRD. The integer baud rate divisor, R/W.
        pub ibrd: Field,

        /// Fractional Baud rate divisor, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-6: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 5-0: FBRD. The fractional baud rate divisor, R/W.
        pub fbrd: Field,

        /// Line Constrol Register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-8: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 7: SPS, Stick Parity Select. 0: the stick parity is disabled, 1: either
        ///     depending on EPS (Event Parity Select), R/W.
        /// - 6-5: WLEN: World lenght. Number of data bits transmitted by frame (0b00 -> 5b, 0b11 ->
        ///     8b), R/W.
        /// - 4: FEN, Enable FIFOs. 0: FIFOs disabled, 1: FIFO buffers are enables, R/W.
        /// - 3: STP2, 2 Stop bit select. 1: 2 stop bits are transmitted at the end of the frame 
        ///     (rx logic is not affected), R/W.
        /// - 2: EPS, Event Parity Select. 0: odd parity, check for odd number of 1 in data+parity
        ///     bits, 1: event parity, check for even number of 1 in data+parity. No effect when
        ///     PEN disable parity check. R/W.
        /// - 1: PEN, Parity Enable. 0: Don't add parity bit and don't check parity, 1: add parity bit
        ///     and check for parity, R/W.
        /// - 0: BRK: Send break. If set, send continuous low level to TXD after the current char, R/W.
        pub lcrh: Field,

        /// SPS, Stick Parity Select. 0: the stick parity is disabled, 1: either
        ///     depending on [EPS](lcrh_eps) (Event Parity Select), R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_sps: Field,

        /// WLEN: World lenght. Number of data bits transmitted by frame (0b00 -> 5b, 0b11 ->
        ///     8b), R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_wlen: Field,

        /// FEN, Enable FIFOs. 0: FIFOs disabled, 1: FIFO buffers are enables, R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_fen: Field,

        /// STP2, 2 Stop bit select. 1: 2 stop bits are transmitted at the end of the frame 
        ///     (rx logic is not affected), R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_stp2: Field,

        /// EPS, Event Parity Select. 0: odd parity, check for odd number of 1 in data+parity
        ///     bits, 1: event parity, check for even number of 1 in data+parity. No effect when
        ///     PEN disable parity check. R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_eps: Field,

        /// PEN, Parity Enable. 0: Don't add parity bit and don't check parity, 1: add parity bit
        ///     and check for parity, R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_pen: Field,

        /// BRK: Send break. If set, send continuous low level to TXD after the current char, R/W.
        ///
        /// Field located inside the Line Constrol Register [`lcrh`].
        pub lcrh_brk: Field,

        /// Control Register, 32 bits long.
        ///
        /// # Warning
        ///
        /// To program the CR:
        /// 
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        ///
        /// # Bits distribution:
        ///
        /// - 31-16: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 15: CTSEN, CTS hardware flow control enable. If set, data is only transmitted when
        ///     nUARTCTS is asserted, R/W.
        /// - 14: RTSEN, RST hardware flow control enable. If set, data is only requested when there
        ///     is space in the receive FIFO, R/W.
        /// - 13: OUT2, unsuported, Write as 0, value read don't have meaning, R.
        /// - 12: OUT1, unsuported, Write as 0, value read don't have meaning, R.
        /// - 11: RTS, Request To Send. When set to 1, nUARTRTS is low, R/W.
        /// - 10: DTR, unsuported, Write as 0, value read don't have meaning, R.
        /// - 9: RXE, Receive enable. If set, (and if UARTEN is set), the uart can read data, R/W.
        /// - 8: TXE, Transmit enable. If set, (and if UARTEN is set), the uart can send data, R/W.
        /// - 7: LBE, LoopBack Enable. If set, UARTTXD is fed through to the UARTRXD path, R/W.
        /// - 6-3: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 2: SIRLP, unsuported, Write as 0, value read don't have meaning, R.
        /// - 1: SIREN, unsuported, Write as 0, value read don't have meaning, R.
        /// - 0: UARTEN, UART enable. If set, the UART is enable, R/W. 
        pub cr: Field,

        /// CTSEN, CTS hardware flow control enable. If set, data is only transmitted when
        ///     nUARTCTS is asserted, R/W.
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        pub cr_ctsen: Field,

        /// RTSEN, RST hardware flow control enable. If set, data is only requested when there
        ///     is space in the receive FIFO, R/W.
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        pub cr_rtsen: Field,

        /// OUT2, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_out2: Field,

        /// OUT1, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_out1: Field,

        /// RTS, Request To Send. When set to 1, nUARTRTS is low, R/W.
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        pub cr_rts: Field,

        /// DTR, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_dtr: Field,

        /// RXE, Receive enable. If set, (and if UARTEN is set), the uart can read data, R/W.
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        /// DTR, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_rxe: Field,

        /// TXE, Transmit enable. If set, (and if UARTEN is set), the uart can send data, R/W.
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        /// DTR, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_txe: Field,

        /// LBE, LoopBack Enable. If set, UARTTXD is fed through to the UARTRXD path, R/W.
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        /// DTR, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_lbe: Field,

        /// SIRLP, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_sirlp: Field,

        /// SIREN, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_siren: Field,

        /// UARTEN, UART enable. If set, the UART is enable, R/W. 
        ///
        /// Field located inside the Control Register [`cr`].
        ///
        /// # Warning:
        ///
        /// According to the doc, the following operation must be performed to program CR:
        ///
        /// - 1) Disable UART
        /// - 2) Wait for the end of tx/rx of the current char
        /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
        /// - 4) Reprogram `CR`.
        /// - 5) Enable UART
        /// DTR, unsuported, Write as 0, value read don't have meaning, R.
        ///
        /// Field located inside the Control Register [`cr`].
        pub cr_uarten: Field,

        // TODO: Finish detailling the registers

        /// Interrupt FIFO Level Select register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-12: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 11-9: RXIFPSEL, unsuported, Write as 0, value read don't have meaning, R.
        /// - 8-6: TXIFPSEL, unsuported, Write as 0, value read don't have meaning, R.
        /// - 5-3: RXIFLSEL, Receive Interrupt FIFO Level Select. The level from which the 
        ///     reveive interrupt is send:
        ///   - `0b000`: Send when FIFO becom 1/8 full
        ///   - `0b001`: Send when FIFO becom 1/4 full
        ///   - `0b010`: Send when FIFO becom 1/2 full
        ///   - `0b011`: Send when FIFO becom 3/4 full
        ///   - `0b100`: Send when FIFO becom 7/7 full
        ///   - Other values are reserved.
        ///   R/W.
        /// - 2-0: TXIFLSEL, Transmit Interrupt FIFO Level Select. The level from which the 
        ///     transmit interrupt is send:
        ///   - `0b000`: Send when FIFO becom 1/8 full
        ///   - `0b001`: Send when FIFO becom 1/4 full
        ///   - `0b010`: Send when FIFO becom 1/2 full
        ///   - `0b011`: Send when FIFO becom 3/4 full
        ///   - `0b100`: Send when FIFO becom 7/7 full
        ///   - Other values are reserved.
        ///   R/W.
        pub ifls: Field,
        /// Interupt Mask Set Clear register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-11: reserved. Write as 0, value read don't have meaning, R/W.
        /// - 10: OEIM, Overrun Error Interrupt Mask. Value of the mask for OE Interrupt, R/W.
        /// - 9: BEIM, Break Error Interrupt Mask. Value of the mask for BE Interrupt, R/W.
        /// - 8: PEIM, Parity Error Interrupt Mask. Value of the mask for PE Interrupt, R/W.
        /// - 7: FEIM, Framing Error Interrupt Mask. Value of the mask for FE Interrupt, R/W.
        /// - 6: RT Interrupt, Receive Timeout Interrupt Mask. Value of the mask for RTIM, R/W.
        /// - 5: TXIM, Transmit Interrupt Mask. Value of the mask for TX Interrupt, R/W.
        /// - 4: RXIM, Receive Interrupt Mask. Value of the mask for RX Interrupt, R/W.
        /// - 3: DSRMIM, unsuported, Write as 0, value read don't have meaning, R.
        /// - 2: DCDMIM, unsuported, Write as 0, value read don't have meaning, R.
        /// - 1: CTSMIM, nUARTCTS Modem Interrupt Mask. Value of the mask for CTS Interrupt, R/W.
        /// - 0: RIMIM, unsuported, Write as 0, value read don't have meaning, R.
        pub imsc: Field,
        /// Raw Interupt Status register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-11: reserved. Write as 0, value read don't have meaning, R.
        /// - 10: OERIS, Overrun Error Raw Interrupt Status. Raw interrupt state of the OE Interrupt, R.
        /// - 9: BERIS, Break Error Raw Interrupt Status. Raw interrupt state of the BE Interrupt, R.
        /// - 8: PERIS, Parity Error Raw Interrupt Status. Raw interrupt state of the PE Interrupt, R.
        /// - 7: FERIS, Framing Error Raw Interrupt Status. Raw interrupt state of the FE Interrupt, R.
        /// - 6: RT Interrupt, Receive Timeout Raw Interrupt Status. Raw interrupt state of the RTRIS, R.
        /// - 5: TXRIS, Transmit Raw Interrupt Status. Raw interrupt state of the TX Interrupt, R.
        /// - 4: RXRIS, Receive Raw Interrupt Status. Raw interrupt state of the RX Interrupt, R.
        /// - 3: DSRMRIS, unsuported, Write as 0, value read don't have meaning, R.
        /// - 2: DCDMRIS, unsuported, Write as 0, value read don't have meaning, R.
        /// - 1: CTSMRIS, nUARTCTS Modem Raw Interrupt Status. Raw interrupt state of the CTS Interrupt, R.
        /// - 0: RRISIM, unsuported, Write as 0, value read don't have meaning, R.
        pub ris: Field,
        /// Masked Interupt Status register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-11: reserved. Write as 0, value read don't have meaning, R.
        /// - 10: OEMIS, Overrun Error Masked Interrupt Status. Masked interrupt state of the OE Interrupt, R.
        /// - 9: BEMIS, Break Error Masked Interrupt Status. Masked interrupt state of the BE Interrupt, R.
        /// - 8: PEMIS, Parity Error Masked Interrupt Status. Masked interrupt state of the PE Interrupt, R.
        /// - 7: FEMIS, Framing Error Masked Interrupt Status. Masked interrupt state of the FE Interrupt, R.
        /// - 6: RT Interrupt, Receive Timeout Masked Interrupt Status. Masked interrupt state of the RTMIS, R.
        /// - 5: TXMIS, Transmit Masked Interrupt Status. Masked interrupt state of the TX Interrupt, R.
        /// - 4: RXMIS, Receive Masked Interrupt Status. Masked interrupt state of the RX Interrupt, R.
        /// - 3: DSRMMIS, unsuported, Write as 0, value read don't have meaning, R.
        /// - 2: DCDMMIS, unsuported, Write as 0, value read don't have meaning, R.
        /// - 1: CTSMMIS, nUARTCTS Modem Masked Interrupt Status. Masked interrupt state of the CTS Interrupt, R.
        /// - 0: RMISIM, unsuported, Write as 0, value read don't have meaning, R.
        pub mis: Field,
        /// Interupt Clear Register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-11: reserved. Write as 0, value read don't have meaning, R.
        /// - 10: OEIC, Overrun Error Interrupt Clear. Clear the OE Interrupt, R.
        /// - 9: BEIC, Break Error Interrupt Clear. Clear the BE Interrupt, R.
        /// - 8: PEIC, Parity Error Interrupt Clear. Clear the PE Interrupt, R.
        /// - 7: FEIC, Framing Error Interrupt Clear. Clear the FE Interrupt, R.
        /// - 6: RT Interrupt, Receive Timeout Interrupt Clear. Clear the RTIC, R.
        /// - 5: TXIC, Transmit Interrupt Clear. Clear the TX Interrupt, R.
        /// - 4: RXIC, Receive Interrupt Clear. Clear the RX Interrupt, R.
        /// - 3: DSRMIC, unsuported, Write as 0, value read don't have meaning, R.
        /// - 2: DCDMIC, unsuported, Write as 0, value read don't have meaning, R.
        /// - 1: CTSMIC, nUARTCTS Modem Interrupt Clear. Clear the CTS Interrupt, R.
        /// - 0: RICIM, unsuported, Write as 0, value read don't have meaning, R.
        pub icr: Field,
        /// DMA Control Register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-3: reserved. Write as 0, value read don't have meaning, R.
        /// - 2: DMAONERR, unsuported, Write as 0, value read don't have meaning, R.
        /// - 1: TXDMAE, unsuported, Write as 0, value read don't have meaning, R.
        /// - 0: RXDMAE, unsuported, Write as 0, value read don't have meaning, R.
        pub dmacr: Field,
        /// Test Control register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-2: reserved. Write as 0, value read don't have meaning, R.
        /// - 1: ITCR1, Test FIFO enable. If set, read/write directly to the FIFOs with TDR10_0, R/W.
        /// - 0: ITCR0, Integration Test Enable. If set, the UART is placed in intergration test mode,
        ///     R/W.
        pub itcr: Field,
        /// Integration Test Input register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-4: reserved. Write as 0, value read don't have meaning, R.
        /// - 3: ITIP3. Reads returns the value of nUARTCTS, R/W.
        /// - 2-1: reserved. Write as 0, value read don't have meaning, R.
        /// - 0: ITIP0. Reads the value of UARTRXD, R/W.
        pub itip: Field,
        /// Integration Test Output register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-12: reserved. Write as 0, value read don't have meaning, R.
        /// - 11: ITOP11, Intra-chip Output. Writes set the value to be driven on UARTLSINTR, Reads
        ///     returns the value of UARTLSINTR at the output of the test multiplexor, R/W.
        /// - 10: ITOP10, Intra-chip Output. Writes set the value to be driven on UARTRXINTR, Reads
        ///     returns the value of UARTRXINTR at the output of the test multiplexor, R/W.
        /// - 9: ITOP9, Intra-chip Output. Writes set the value to be driven on UARTTXINTR, Reads
        ///     returns the value of UARTTXINTR at the output of the test multiplexor, R/W.
        /// - 8: ITOP8, Intra-chip Output. Writes set the value to be driven on UARTRTINTR, Reads
        ///     returns the value of UARTRTINTR at the output of the test multiplexor, R/W.
        /// - 7: ITOP7, Intra-chip Output. Writes set the value to be driven on UARTEINTR, Reads
        ///     returns the value of UARTEINTR at the output of the test multiplexor, R/W.
        /// - 6: ITOP6, Intra-chip Output. Writes set the value to be driven on UARTINTR, Reads
        ///     returns the value of UARTINTR at the output of the test multiplexor, R/W.
        /// - 5-4: reserved. Write as 0, value read don't have meaning, R.
        /// - 3: ITIP3: Primary Output. Writes specify the value on nUARTRTS, R/W.
        /// - 2-1:  reserved. Write as 0, value read don't have meaning, R.
        /// - 0: ITIP0, Primary Output. Writes specify the value to be driven on UARTTXD, R/W.
        pub itop: Field,
        /// Test Data register, 32 bits long.
        ///
        /// # Bits distribution:
        ///
        /// - 31-11: reserved. Write as 0, value read don't have meaning, R.
        /// - 10-0: TDR10_0. When ITCRI1 is set to 1, data read an write directly from the FIFOs, R/W.
        pub tdr: Field,
        
    }

    impl UartMemoryMap {
        /// Contructor for a [`UartMemoryMap`] starting at `start_address`.
        const fn new(start_address: usize) -> Self {
            Self {
                // TODO: set unsuported field to size 0?
                dr: Field::new(start_address + 0x00, 0, 32),
                dr_oe: Field::new(start_address + 0x00, 11, 1),
                dr_be: Field::new(start_address + 0x00, 10, 1),
                dr_pe: Field::new(start_address + 0x00, 9, 1),
                dr_fe: Field::new(start_address + 0x00, 8, 1),
                dr_data: Field::new(start_address + 0x00, 0, 8),
                rsrecr: Field::new(start_address + 0x04, 0, 32),
                rsrecr_oe: Field::new(start_address + 0x04, 3, 1),
                rsrecr_be: Field::new(start_address + 0x04, 2, 1),
                rsrecr_pe: Field::new(start_address + 0x04, 1, 1),
                rsrecr_fe: Field::new(start_address + 0x04, 0, 1),
                fr: Field::new(start_address + 0x18, 0, 32),
                fr_ri: Field::new(start_address + 0x18, 8, 1),
                fr_txfe: Field::new(start_address + 0x18, 7, 1),
                fr_rxff: Field::new(start_address + 0x18, 6, 1),
                fr_txff: Field::new(start_address + 0x18, 5, 1),
                fr_rxfe: Field::new(start_address + 0x18, 4, 1),
                fr_busy: Field::new(start_address + 0x18, 3, 1),
                fr_dcd: Field::new(start_address + 0x18, 2, 1),
                fr_dsr: Field::new(start_address + 0x18, 1, 1),
                fr_cts: Field::new(start_address + 0x18, 0, 1),
                ilpr: Field::new(start_address + 0x20, 0, 32),
                ibrd: Field::new(start_address + 0x24, 0, 16),
                fbrd: Field::new(start_address + 0x28, 0, 6),
                lcrh: Field::new(start_address + 0x2C, 0, 32),
                lcrh_sps: Field::new(start_address + 0x2C, 7, 1),
                lcrh_wlen: Field::new(start_address + 0x2C, 5, 2),
                lcrh_fen: Field::new(start_address + 0x2C, 4, 1),
                lcrh_stp2: Field::new(start_address + 0x2C, 3, 1),
                lcrh_eps: Field::new(start_address + 0x2C, 2, 1),
                lcrh_pen: Field::new(start_address + 0x2C, 1, 1),
                lcrh_brk: Field::new(start_address + 0x2C, 0, 1),
                cr: Field::new(start_address + 0x30, 0, 32),
                cr_ctsen: Field::new(start_address + 0x30, 15, 1),
                cr_rtsen: Field::new(start_address + 0x30, 14, 1),
                cr_out2: Field::new(start_address + 0x30, 13, 1),
                cr_out1: Field::new(start_address + 0x30, 12, 1),
                cr_rts: Field::new(start_address + 0x30, 11, 1),
                cr_dtr: Field::new(start_address + 0x30, 10, 1),
                cr_rxe: Field::new(start_address + 0x30, 9, 1),
                cr_txe: Field::new(start_address + 0x30, 8, 1),
                cr_lbe: Field::new(start_address + 0x30, 7, 1),
                cr_sirlp: Field::new(start_address + 0x30, 2, 1),
                cr_siren: Field::new(start_address + 0x30, 1, 1),
                cr_uarten: Field::new(start_address + 0x30, 0, 1),

                ifls: Field::new(start_address + 0x34, 0, 32),
                imsc: Field::new(start_address + 0x38, 0, 32),
                ris: Field::new(start_address + 0x3C, 0, 32),
                mis: Field::new(start_address + 0x40, 0, 32),
                icr: Field::new(start_address + 0x44, 0, 32),
                dmacr: Field::new(start_address + 0x48, 0, 32),
                itcr: Field::new(start_address + 0x80, 0, 32),
                itip: Field::new(start_address + 0x84, 0, 32),
                itop: Field::new(start_address + 0x88, 0, 32),
                tdr: Field::new(start_address + 0x8C, 0, 32),
            }
        }
    }

    pub const UART: UartMemoryMap = UartMemoryMap::new(UART_START);

}
