diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index 3bca9d404ce..fab417986bb 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -274,6 +274,7 @@ pub mod dma { } /// A DMA capable AES instance. + #[instability::unstable] pub struct AesDma<'d> { /// The underlying [`Aes`](super::Aes) driver pub aes: super::Aes<'d>, diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 1fd837faf0a..825b96d795b 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -906,6 +906,7 @@ where } /// Parallel IO TX channel +#[instability::unstable] pub struct ParlIoTx<'d, Dm> where Dm: DriverMode, @@ -987,6 +988,7 @@ where } /// Parallel IO RX channel +#[instability::unstable] pub struct ParlIoRx<'d, Dm> where Dm: DriverMode, diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index ed63854b2c1..6df42557c87 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -250,6 +250,11 @@ mod peripheral_macros { $name:ident <= $from_pac:tt $(($($interrupt:ident),*))? ),* $(,)? ], + unstable_peripherals: [ + $( + $unstable_name:ident <= $unstable_from_pac:tt $(($($unstable_interrupt:ident),*))? + ),* $(,)? + ], pins: [ $( ( $pin:literal, $($pin_tokens:tt)* ) )* ], @@ -260,12 +265,16 @@ mod peripheral_macros { ] ) => { + /// Contains the generated peripherals which implement [`Peripheral`] mod peripherals { pub use super::pac::*; $( $crate::create_peripheral!($name <= $from_pac); )* + $( + $crate::create_peripheral!(#[instability::unstable] $unstable_name <= $unstable_from_pac); + )* } pub(crate) mod gpio { @@ -280,7 +289,24 @@ mod peripheral_macros { pub struct Peripherals { $( #[doc = concat!("The ", stringify!($name), " peripheral.")] - pub $name: peripherals::$name, + pub $name: $name, + )* + $( + #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")] + #[doc = "**This API is marked as unstable** and is only available when the `unstable` + crate feature is enabled. This comes with no stability guarantees, and could be changed + or removed at any time."] + #[cfg(any(doc, feature = "unstable"))] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] + pub $unstable_name: $unstable_name, + + #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")] + #[doc = "**This API is marked as unstable** and is only available when the `unstable` + crate feature is enabled. This comes with no stability guarantees, and could be changed + or removed at any time."] + #[cfg(not(any(doc, feature = "unstable")))] + #[allow(unused)] + pub(crate) $unstable_name: $unstable_name, )* $( @@ -319,7 +345,10 @@ mod peripheral_macros { pub unsafe fn steal() -> Self { Self { $( - $name: peripherals::$name::steal(), + $name: $name::steal(), + )* + $( + $unstable_name: $unstable_name::steal(), )* $( @@ -334,17 +363,16 @@ mod peripheral_macros { } } - // expose the new structs - $( - pub use peripherals::$name; - )* + // expose the new structs, implement interrupt binder $( + pub use peripherals::$name; $( impl peripherals::$name { $( paste::paste!{ /// Binds an interrupt handler to the corresponding interrupt for this peripheral. + #[instability::unstable] pub fn [](&mut self, handler: unsafe extern "C" fn() -> ()) { unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$interrupt, handler); } } @@ -353,6 +381,24 @@ mod peripheral_macros { } )* )* + + $( + #[instability::unstable] + pub use peripherals::$unstable_name; + $( + impl peripherals::$unstable_name { + $( + paste::paste!{ + /// Binds an interrupt handler to the corresponding interrupt for this peripheral. + #[instability::unstable] + pub fn [](&mut self, handler: unsafe extern "C" fn() -> ()) { + unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$unstable_interrupt, handler); } + } + } + )* + } + )* + )* }; } @@ -382,7 +428,8 @@ mod peripheral_macros { #[macro_export] /// Macro to create a peripheral structure. macro_rules! create_peripheral { - ($name:ident <= virtual) => { + ($(#[$attr:meta])? $name:ident <= virtual) => { + $(#[$attr])? #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -414,8 +461,8 @@ mod peripheral_macros { impl $crate::private::Sealed for $name {} }; - ($name:ident <= $base:ident) => { - $crate::create_peripheral!($name <= virtual); + ($(#[$attr:meta])? $name:ident <= $base:ident) => { + $crate::create_peripheral!($(#[$attr])? $name <= virtual); impl $name { #[doc = r"Pointer to the register block"] diff --git a/esp-hal/src/soc/esp32/cpu_control.rs b/esp-hal/src/soc/esp32/cpu_control.rs index 3d557ed163a..cbdb0a5e261 100644 --- a/esp-hal/src/soc/esp32/cpu_control.rs +++ b/esp-hal/src/soc/esp32/cpu_control.rs @@ -174,6 +174,7 @@ unsafe fn internal_park_core(core: Cpu) { impl<'d> CpuControl<'d> { /// Creates a new instance of `CpuControl`. + #[instability::unstable] pub fn new(cpu_control: impl Peripheral

+ 'd) -> CpuControl<'d> { crate::into_ref!(cpu_control); diff --git a/esp-hal/src/soc/esp32/peripherals.rs b/esp-hal/src/soc/esp32/peripherals.rs index c29e0bcce0a..1213b8df1ea 100644 --- a/esp-hal/src/soc/esp32/peripherals.rs +++ b/esp-hal/src/soc/esp32/peripherals.rs @@ -8,7 +8,7 @@ //! from the PAC, allowing users to handle interrupts associated with these //! peripherals. -use esp32 as pac; +pub(crate) use esp32 as pac; // We need to export this for users to use pub use pac::Interrupt; @@ -21,6 +21,16 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + I2C1 <= I2C1, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), + UART0 <= UART0, + UART1 <= UART1, + UART2 <= UART2, + ], + unstable_peripherals: [ ADC1 <= virtual, ADC2 <= virtual, AES <= AES, @@ -30,46 +40,41 @@ crate::peripherals! { CPU_CTRL <= virtual, DAC1 <= virtual, DAC2 <= virtual, + DPORT <= DPORT, EFUSE <= EFUSE, FLASH_ENCRYPTION <= FLASH_ENCRYPTION, FRC_TIMER <= FRC_TIMER, + GPIO <= GPIO, GPIO_SD <= GPIO_SD, HINF <= HINF, - I2C0 <= I2C0, - I2C1 <= I2C1, I2S0 <= I2S0 (I2S0), I2S1 <= I2S1 (I2S1), - IO_MUX <= IO_MUX, LEDC <= LEDC, + LPWR <= RTC_CNTL, MCPWM0 <= MCPWM0, MCPWM1 <= MCPWM1, NRX <= NRX, PCNT <= PCNT, PSRAM <= virtual, + RADIO_CLK <= virtual, RMT <= RMT, RNG <= RNG, RSA <= RSA, - LPWR <= RTC_CNTL, - RADIO_CLK <= virtual, - RTC_IO <= RTC_IO, RTC_I2C <= RTC_I2C, + RTC_IO <= RTC_IO, SDHOST <= SDHOST, + SENS <= SENS, SHA <= SHA, SLC <= SLC, SLCHOST <= SLCHOST, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2_DMA, SPI2), - SPI3 <= SPI3 (SPI3_DMA, SPI3), SYSTEM <= DPORT, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, TIMG1 <= TIMG1, TOUCH <= virtual, TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UART2 <= UART2, UHCI0 <= UHCI0, UHCI1 <= UHCI1, WIFI <= WIFI, diff --git a/esp-hal/src/soc/esp32c2/peripherals.rs b/esp-hal/src/soc/esp32c2/peripherals.rs index 03db06e0a0e..9e0fcda0b01 100644 --- a/esp-hal/src/soc/esp32c2/peripherals.rs +++ b/esp-hal/src/soc/esp32c2/peripherals.rs @@ -8,7 +8,7 @@ //! from the PAC, allowing users to handle interrupts associated with these //! peripherals. -use esp32c2 as pac; +pub(crate) use esp32c2 as pac; // We need to export this for users to use pub use pac::Interrupt; @@ -21,31 +21,38 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2), + UART0 <= UART0, + UART1 <= UART1, + ], + unstable_peripherals: [ ADC1 <= virtual, APB_CTRL <= APB_CTRL, + APB_SARADC <= APB_SARADC, ASSIST_DEBUG <= ASSIST_DEBUG, + BB <= BB, BT <= virtual, + DMA <= DMA, ECC <= ECC, EFUSE <= EFUSE, EXTMEM <= EXTMEM, - I2C0 <= I2C0, + GPIO <= GPIO, INTERRUPT_CORE0 <= INTERRUPT_CORE0, - IO_MUX <= IO_MUX, LEDC <= LEDC, LPWR <= RTC_CNTL, + MODEM_CLKRST <= MODEM_CLKRST, RADIO_CLK <= virtual, RNG <= RNG, SENSITIVE <= SENSITIVE, SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, - UART0 <= UART0, - UART1 <= UART1, WIFI <= virtual, XTS_AES <= XTS_AES, MEM2MEM1 <= virtual, diff --git a/esp-hal/src/soc/esp32c3/peripherals.rs b/esp-hal/src/soc/esp32c3/peripherals.rs index 10180d39077..9ecc2273cd6 100644 --- a/esp-hal/src/soc/esp32c3/peripherals.rs +++ b/esp-hal/src/soc/esp32c3/peripherals.rs @@ -8,7 +8,7 @@ //! from the PAC, allowing users to handle interrupts associated with these //! peripherals. -use esp32c3 as pac; +pub(crate) use esp32c3 as pac; // We need to export this for users to use pub use pac::Interrupt; @@ -21,23 +21,35 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2), + UART0 <= UART0, + UART1 <= UART1, + ], + unstable_peripherals: [ ADC1 <= virtual, ADC2 <= virtual, AES <= AES, APB_CTRL <= APB_CTRL, + APB_SARADC <= APB_SARADC, ASSIST_DEBUG <= ASSIST_DEBUG, + BB <= BB, BT <= virtual, + DMA <= DMA, DS <= DS, EFUSE <= EFUSE, EXTMEM <= EXTMEM, + FE <= FE, + FE2 <= FE2, + GPIO <= GPIO, GPIO_SD <= GPIO_SD, HMAC <= HMAC, - I2C0 <= I2C0, I2S0 <= I2S0 (I2S0), INTERRUPT_CORE0 <= INTERRUPT_CORE0, - IO_MUX <= IO_MUX, LEDC <= LEDC, LPWR <= RTC_CNTL, + NRX <= NRX, RADIO_CLK <= virtual, RMT <= RMT, RNG <= RNG, @@ -46,7 +58,6 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, @@ -54,8 +65,6 @@ crate::peripherals! { TIMG1 <= TIMG1, TSENS <= virtual, TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, UHCI0 <= UHCI0, UHCI1 <= UHCI1, USB_DEVICE <= USB_DEVICE, diff --git a/esp-hal/src/soc/esp32c6/peripherals.rs b/esp-hal/src/soc/esp32c6/peripherals.rs index 6ae4c7c535d..17f235c0d44 100644 --- a/esp-hal/src/soc/esp32c6/peripherals.rs +++ b/esp-hal/src/soc/esp32c6/peripherals.rs @@ -8,7 +8,7 @@ //! from the PAC, allowing users to handle interrupts associated with these //! peripherals. -use esp32c6 as pac; +pub(crate) use esp32c6 as pac; // We need to export this for users to use pub use pac::Interrupt; @@ -21,26 +21,34 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2), + UART0 <= UART0, + UART1 <= UART1, + ], + unstable_peripherals: [ ADC1 <= virtual, AES <= AES, + APB_SARADC <= APB_SARADC, ASSIST_DEBUG <= ASSIST_DEBUG, ATOMIC <= ATOMIC, BT <= virtual, + DMA <= DMA, DS <= DS, ECC <= ECC, EFUSE <= EFUSE, EXTMEM <= EXTMEM, + GPIO <= GPIO, GPIO_SD <= GPIO_SD, HINF <= HINF, HMAC <= HMAC, HP_APM <= HP_APM, HP_SYS <= HP_SYS, - I2C0 <= I2C0, I2S0 <= I2S0 (I2S0), IEEE802154 <= IEEE802154, INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTPRI <= INTPRI, - IO_MUX <= IO_MUX, LEDC <= LEDC, LPWR <= LP_CLKRST, LP_CORE <= virtual, @@ -58,10 +66,14 @@ crate::peripherals! { LP_WDT <= LP_WDT, MCPWM0 <= MCPWM0, MEM_MONITOR <= MEM_MONITOR, + MODEM_LPCON <= MODEM_LPCON, + MODEM_SYSCON <= MODEM_SYSCON, OTP_DEBUG <= OTP_DEBUG, PARL_IO <= PARL_IO (PARL_IO), PAU <= PAU, + PCR <= PCR, PCNT <= PCNT, + PLIC_MX <= PLIC_MX, PMU <= PMU, RADIO_CLK <= virtual, RMT <= RMT, @@ -72,7 +84,6 @@ crate::peripherals! { SOC_ETM <= SOC_ETM, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), SYSTEM <= PCR, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, @@ -83,8 +94,6 @@ crate::peripherals! { TSENS <= virtual, TWAI0 <= TWAI0, TWAI1 <= TWAI1, - UART0 <= UART0, - UART1 <= UART1, UHCI0 <= UHCI0, USB_DEVICE <= USB_DEVICE, WIFI <= virtual, diff --git a/esp-hal/src/soc/esp32h2/peripherals.rs b/esp-hal/src/soc/esp32h2/peripherals.rs index b5743079885..55e0ee26b81 100644 --- a/esp-hal/src/soc/esp32h2/peripherals.rs +++ b/esp-hal/src/soc/esp32h2/peripherals.rs @@ -8,7 +8,7 @@ //! from the PAC, allowing users to handle interrupts associated with these //! peripherals. -use esp32h2 as pac; +pub(crate) use esp32h2 as pac; // We need to export this for users to use pub use pac::Interrupt; @@ -21,24 +21,32 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + I2C1 <= I2C1, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2), + UART0 <= UART0, + UART1 <= UART1, + ], + unstable_peripherals: [ ADC1 <= virtual, AES <= AES, + APB_SARADC <= APB_SARADC, ASSIST_DEBUG <= ASSIST_DEBUG, BT <= virtual, + DMA <= DMA, DS <= DS, ECC <= ECC, EFUSE <= EFUSE, + GPIO <= GPIO, GPIO_SD <= GPIO_SD, HMAC <= HMAC, HP_APM <= HP_APM, HP_SYS <= HP_SYS, - I2C0 <= I2C0, - I2C1 <= I2C1, I2S0 <= I2S0 (I2S0), IEEE802154 <= IEEE802154, INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTPRI <= INTPRI, - IO_MUX <= IO_MUX, LEDC <= LEDC, LPWR <= LP_CLKRST, LP_ANA <= LP_ANA, @@ -55,6 +63,8 @@ crate::peripherals! { PARL_IO <= PARL_IO (PARL_IO_TX, PARL_IO_RX), PAU <= PAU, PCNT <= PCNT, + PCR <= PCR, + PLIC_MX <= PLIC_MX, PMU <= PMU, RADIO_CLK <= virtual, RMT <= RMT, @@ -64,7 +74,6 @@ crate::peripherals! { SOC_ETM <= SOC_ETM, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), SYSTEM <= PCR, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, @@ -73,8 +82,6 @@ crate::peripherals! { TIMG1 <= TIMG1, TRACE0 <= TRACE, TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, UHCI0 <= UHCI0, USB_DEVICE <= USB_DEVICE, MEM2MEM1 <= virtual, diff --git a/esp-hal/src/soc/esp32s2/peripherals.rs b/esp-hal/src/soc/esp32s2/peripherals.rs index 40752aac96e..8b70eba8167 100644 --- a/esp-hal/src/soc/esp32s2/peripherals.rs +++ b/esp-hal/src/soc/esp32s2/peripherals.rs @@ -8,7 +8,7 @@ //! from the PAC, allowing users to handle interrupts associated with these //! peripherals. -use esp32s2 as pac; +pub(crate) use esp32s2 as pac; // We need to export this for users to use pub use pac::Interrupt; @@ -21,22 +21,31 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + I2C1 <= I2C1, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), + UART0 <= UART0, + UART1 <= UART1, + ], + unstable_peripherals: [ ADC1 <= virtual, ADC2 <= virtual, AES <= AES, + APB_SARADC <= APB_SARADC, DAC1 <= virtual, DAC2 <= virtual, + CRYPTO_DMA <= CRYPTO_DMA, DEDICATED_GPIO <= DEDICATED_GPIO, DS <= DS, EFUSE <= EFUSE, EXTMEM <= EXTMEM, + GPIO <= GPIO, GPIO_SD <= GPIO_SD, HMAC <= HMAC, - I2C0 <= I2C0, - I2C1 <= I2C1, I2S0 <= I2S0 (I2S0), INTERRUPT_CORE0 <= INTERRUPT_CORE0, - IO_MUX <= IO_MUX, LEDC <= LEDC, LPWR <= RTC_CNTL, PCNT <= PCNT, @@ -48,11 +57,10 @@ crate::peripherals! { RSA <= RSA, RTC_IO <= RTC_IO, RTC_I2C <= RTC_I2C, + SENS <= SENS, SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2_DMA, SPI2), - SPI3 <= SPI3 (SPI3_DMA, SPI3), SYSCON <= SYSCON, SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, @@ -60,8 +68,6 @@ crate::peripherals! { TIMG0 <= TIMG0, TIMG1 <= TIMG1, TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, UHCI0 <= UHCI0, ULP_RISCV_CORE <= virtual, USB0 <= USB0, diff --git a/esp-hal/src/soc/esp32s3/cpu_control.rs b/esp-hal/src/soc/esp32s3/cpu_control.rs index f2494bf44f0..cd64bfbe75a 100644 --- a/esp-hal/src/soc/esp32s3/cpu_control.rs +++ b/esp-hal/src/soc/esp32s3/cpu_control.rs @@ -174,6 +174,7 @@ unsafe fn internal_park_core(core: Cpu) { impl<'d> CpuControl<'d> { /// Creates a new instance of `CpuControl`. + #[instability::unstable] pub fn new(cpu_control: impl Peripheral

+ 'd) -> CpuControl<'d> { crate::into_ref!(cpu_control); diff --git a/esp-hal/src/soc/esp32s3/peripherals.rs b/esp-hal/src/soc/esp32s3/peripherals.rs index c27239702c8..00c34297772 100644 --- a/esp-hal/src/soc/esp32s3/peripherals.rs +++ b/esp-hal/src/soc/esp32s3/peripherals.rs @@ -21,25 +21,35 @@ pub(crate) use self::peripherals::*; // creating "virtual peripherals" for them. crate::peripherals! { peripherals: [ + I2C0 <= I2C0, + I2C1 <= I2C1, + IO_MUX <= IO_MUX, + SPI2 <= SPI2 (SPI2), + SPI3 <= SPI3 (SPI3), + UART0 <= UART0, + UART1 <= UART1, + UART2 <= UART2, + ], + unstable_peripherals: [ ADC1 <= virtual, ADC2 <= virtual, AES <= AES, + APB_SARADC <= APB_SARADC, APB_CTRL <= APB_CTRL, ASSIST_DEBUG <= ASSIST_DEBUG, BT <= virtual, CPU_CTRL <= virtual, + DMA <= DMA, DS <= DS, EFUSE <= EFUSE, EXTMEM <= EXTMEM, + GPIO <= GPIO, GPIO_SD <= GPIO_SD, HMAC <= HMAC, - I2C0 <= I2C0, - I2C1 <= I2C1, I2S0 <= I2S0 (I2S0), I2S1 <= I2S1 (I2S1), INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE1 <= INTERRUPT_CORE1, - IO_MUX <= IO_MUX, LCD_CAM <= LCD_CAM, LEDC <= LEDC, LPWR <= RTC_CNTL, @@ -54,21 +64,17 @@ crate::peripherals! { RSA <= RSA, RTC_I2C <= RTC_I2C, RTC_IO <= RTC_IO, + SENS <= SENS, SENSITIVE <= SENSITIVE, SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), - SPI3 <= SPI3 (SPI3), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, TIMG1 <= TIMG1, TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UART2 <= UART2, UHCI0 <= UHCI0, UHCI1 <= UHCI1, ULP_RISCV_CORE <= virtual,