forked from libre-chip/cpu
add address_range to MemoryInterfaceConfig and add support to simple_uart
This commit is contained in:
parent
2c8de5bec4
commit
3080ea4ce2
5 changed files with 169 additions and 50 deletions
|
|
@ -3,16 +3,110 @@
|
||||||
|
|
||||||
use crate::{config::CpuConfig, next_pc::FETCH_BLOCK_ID_WIDTH, util::array_vec::ArrayVec};
|
use crate::{config::CpuConfig, next_pc::FETCH_BLOCK_ID_WIDTH, util::array_vec::ArrayVec};
|
||||||
use fayalite::{prelude::*, util::ready_valid::ReadyValid};
|
use fayalite::{prelude::*, util::ready_valid::ReadyValid};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::{NonZeroU64, NonZeroUsize, Wrapping};
|
||||||
|
|
||||||
pub mod simple_uart;
|
pub mod simple_uart;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum AddressRange {
|
||||||
|
Full,
|
||||||
|
Limited {
|
||||||
|
start: Wrapping<u64>,
|
||||||
|
size: NonZeroU64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressRange {
|
||||||
|
pub const fn from_wrapping_range_inclusive(range: std::ops::RangeInclusive<u64>) -> Self {
|
||||||
|
let start = Wrapping(*range.start());
|
||||||
|
let Some(size) = NonZeroU64::new(range.end().wrapping_sub(start.0).wrapping_add(1)) else {
|
||||||
|
return Self::Full;
|
||||||
|
};
|
||||||
|
Self::Limited { start, size }
|
||||||
|
}
|
||||||
|
pub const fn try_from_range(range: std::ops::Range<u64>) -> Option<Self> {
|
||||||
|
let start = Wrapping(range.start);
|
||||||
|
let Some(size) = NonZeroU64::new(range.end.saturating_sub(range.start)) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(Self::Limited { start, size })
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub const fn from_range(range: std::ops::Range<u64>) -> Self {
|
||||||
|
Self::try_from_range(range).expect("range must not be empty")
|
||||||
|
}
|
||||||
|
pub const fn try_from_range_inclusive(range: std::ops::RangeInclusive<u64>) -> Option<Self> {
|
||||||
|
let start = Wrapping(*range.start());
|
||||||
|
let Some(end_minus_start) = range.end().checked_sub(start.0) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(size) = end_minus_start.checked_add(1) else {
|
||||||
|
return Some(Self::Full);
|
||||||
|
};
|
||||||
|
let Some(size) = NonZeroU64::new(size) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
Some(Self::Limited { start, size })
|
||||||
|
}
|
||||||
|
#[track_caller]
|
||||||
|
pub const fn from_range_inclusive(range: std::ops::RangeInclusive<u64>) -> Self {
|
||||||
|
Self::try_from_range_inclusive(range).expect("range must not be empty")
|
||||||
|
}
|
||||||
|
pub const fn start(self) -> Wrapping<u64> {
|
||||||
|
match self {
|
||||||
|
Self::Full => Wrapping(0),
|
||||||
|
Self::Limited { start, .. } => start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn size(self) -> Option<NonZeroU64> {
|
||||||
|
match self {
|
||||||
|
Self::Full => None,
|
||||||
|
Self::Limited { size, .. } => Some(size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn size_minus_one(self) -> u64 {
|
||||||
|
match self {
|
||||||
|
AddressRange::Full => u64::MAX,
|
||||||
|
AddressRange::Limited { size, .. } => size.get() - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// last address contained in `self`
|
||||||
|
pub const fn last(self) -> u64 {
|
||||||
|
self.start().0.wrapping_add(self.size_minus_one())
|
||||||
|
}
|
||||||
|
pub const fn contains(self, address: u64) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Full => true,
|
||||||
|
Self::Limited { start, size } => address.wrapping_sub(start.0) < size.get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn wrapping_add(self, offset: u64) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Full => Self::Full,
|
||||||
|
Self::Limited { start, size } => Self::Limited {
|
||||||
|
start: Wrapping(start.0.wrapping_add(offset)),
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn wrapping_sub(self, offset: u64) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Full => Self::Full,
|
||||||
|
Self::Limited { start, size } => Self::Limited {
|
||||||
|
start: Wrapping(start.0.wrapping_sub(offset)),
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct MemoryInterfaceConfig {
|
pub struct MemoryInterfaceConfig {
|
||||||
pub log2_bus_width_in_bytes: u8,
|
pub log2_bus_width_in_bytes: u8,
|
||||||
pub queue_capacity: NonZeroUsize,
|
pub queue_capacity: NonZeroUsize,
|
||||||
pub op_id_width: usize,
|
pub op_id_width: usize,
|
||||||
|
pub address_range: AddressRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryInterfaceConfig {
|
impl MemoryInterfaceConfig {
|
||||||
|
|
@ -21,6 +115,7 @@ impl MemoryInterfaceConfig {
|
||||||
log2_bus_width_in_bytes: config.log2_fetch_width_in_bytes,
|
log2_bus_width_in_bytes: config.log2_fetch_width_in_bytes,
|
||||||
queue_capacity: config.max_fetches_in_flight,
|
queue_capacity: config.max_fetches_in_flight,
|
||||||
op_id_width: FETCH_BLOCK_ID_WIDTH,
|
op_id_width: FETCH_BLOCK_ID_WIDTH,
|
||||||
|
address_range: AddressRange::Full,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const fn bus_width_in_bytes(&self) -> usize {
|
pub const fn bus_width_in_bytes(&self) -> usize {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use std::num::NonZeroUsize;
|
use std::num::{NonZeroU64, NonZeroUsize, Wrapping};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
main_memory_and_io::{
|
main_memory_and_io::{
|
||||||
MemoryInterface, MemoryInterfaceConfig, MemoryOperationErrorKind, MemoryOperationFinish,
|
AddressRange, MemoryInterface, MemoryInterfaceConfig, MemoryOperationErrorKind,
|
||||||
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
MemoryOperationFinish, MemoryOperationFinishKind, MemoryOperationKind,
|
||||||
|
MemoryOperationStart,
|
||||||
},
|
},
|
||||||
util::array_vec::ArrayVec,
|
util::array_vec::ArrayVec,
|
||||||
};
|
};
|
||||||
|
|
@ -357,7 +358,8 @@ pub fn receiver(queue_capacity: NonZeroUsize) {
|
||||||
pub const SIMPLE_UART_RECEIVE_OFFSET: u64 = 0;
|
pub const SIMPLE_UART_RECEIVE_OFFSET: u64 = 0;
|
||||||
pub const SIMPLE_UART_TRANSMIT_OFFSET: u64 = 0;
|
pub const SIMPLE_UART_TRANSMIT_OFFSET: u64 = 0;
|
||||||
pub const SIMPLE_UART_STATUS_OFFSET: u64 = 1;
|
pub const SIMPLE_UART_STATUS_OFFSET: u64 = 1;
|
||||||
pub const SIMPLE_UART_SIZE: u64 = 1 << SIMPLE_UART_LOG2_SIZE;
|
pub const SIMPLE_UART_SIZE: NonZeroU64 =
|
||||||
|
NonZeroU64::new(1 << SIMPLE_UART_LOG2_SIZE).expect("known to be non-zero");
|
||||||
pub const SIMPLE_UART_LOG2_SIZE: u8 = 1;
|
pub const SIMPLE_UART_LOG2_SIZE: u8 = 1;
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
|
|
@ -366,11 +368,22 @@ struct Operation<C: PhantomConstGet<MemoryInterfaceConfig>> {
|
||||||
finish: HdlOption<MemoryOperationFinish<C>>,
|
finish: HdlOption<MemoryOperationFinish<C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn simple_uart_memory_interface_config(op_id_width: usize) -> MemoryInterfaceConfig {
|
pub const fn simple_uart_memory_interface_config(
|
||||||
|
op_id_width: usize,
|
||||||
|
start_address: Wrapping<u64>,
|
||||||
|
) -> MemoryInterfaceConfig {
|
||||||
|
assert!(
|
||||||
|
start_address.0 % SIMPLE_UART_SIZE.get() == 0,
|
||||||
|
"start_address must be properly aligned"
|
||||||
|
);
|
||||||
MemoryInterfaceConfig {
|
MemoryInterfaceConfig {
|
||||||
log2_bus_width_in_bytes: SIMPLE_UART_LOG2_SIZE,
|
log2_bus_width_in_bytes: SIMPLE_UART_LOG2_SIZE,
|
||||||
queue_capacity: const { NonZeroUsize::new(1).unwrap() },
|
queue_capacity: const { NonZeroUsize::new(1).unwrap() },
|
||||||
op_id_width,
|
op_id_width,
|
||||||
|
address_range: AddressRange::Limited {
|
||||||
|
start: start_address,
|
||||||
|
size: SIMPLE_UART_SIZE,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -381,9 +394,10 @@ pub fn simple_uart(
|
||||||
baud_rate: f64,
|
baud_rate: f64,
|
||||||
receiver_queue_size: NonZeroUsize,
|
receiver_queue_size: NonZeroUsize,
|
||||||
) {
|
) {
|
||||||
|
let start_address = config.get().address_range.start();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*config.get(),
|
*config.get(),
|
||||||
simple_uart_memory_interface_config(config.get().op_id_width),
|
simple_uart_memory_interface_config(config.get().op_id_width, start_address),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
|
|
@ -486,14 +500,18 @@ pub fn simple_uart(
|
||||||
match kind {
|
match kind {
|
||||||
MemoryOperationKind::Read => {
|
MemoryOperationKind::Read => {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if byte_addr.cmp_eq(SIMPLE_UART_RECEIVE_OFFSET) {
|
if byte_addr
|
||||||
|
.cmp_eq(start_address.0.wrapping_add(SIMPLE_UART_RECEIVE_OFFSET))
|
||||||
|
{
|
||||||
connect(receiver.output_byte.ready, valid_addr);
|
connect(receiver.output_byte.ready, valid_addr);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(byte) = receiver.output_byte.data {
|
if let HdlSome(byte) = receiver.output_byte.data {
|
||||||
connect(read_data, byte);
|
connect(read_data, byte);
|
||||||
}
|
}
|
||||||
// if there is no byte ready yet, we read a zero to avoid blocking the CPU on external inputs.
|
// if there is no byte ready yet, we read a zero to avoid blocking the CPU on external inputs.
|
||||||
} else if byte_addr.cmp_eq(SIMPLE_UART_STATUS_OFFSET) {
|
} else if byte_addr
|
||||||
|
.cmp_eq(start_address.0.wrapping_add(SIMPLE_UART_STATUS_OFFSET))
|
||||||
|
{
|
||||||
connect(
|
connect(
|
||||||
read_data,
|
read_data,
|
||||||
receiver
|
receiver
|
||||||
|
|
@ -507,7 +525,9 @@ pub fn simple_uart(
|
||||||
}
|
}
|
||||||
MemoryOperationKind::Write => {
|
MemoryOperationKind::Write => {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if byte_addr.cmp_eq(SIMPLE_UART_TRANSMIT_OFFSET) {
|
if byte_addr
|
||||||
|
.cmp_eq(start_address.0.wrapping_add(SIMPLE_UART_TRANSMIT_OFFSET))
|
||||||
|
{
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if !transmitter.input_byte.ready {
|
if !transmitter.input_byte.ready {
|
||||||
connect(all_ready, false);
|
connect(all_ready, false);
|
||||||
|
|
|
||||||
48
crates/cpu/tests/expected/fetch.vcd
generated
48
crates/cpu/tests/expected/fetch.vcd
generated
|
|
@ -3633,7 +3633,7 @@ b0 UA{3,"
|
||||||
0mS#3<"
|
0mS#3<"
|
||||||
0^qjb["
|
0^qjb["
|
||||||
b0 tN>yu"
|
b0 tN>yu"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) '@T[?"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) '@T[?"
|
||||||
0BXk&["
|
0BXk&["
|
||||||
sHdlNone\x20(0) &wG|&"
|
sHdlNone\x20(0) &wG|&"
|
||||||
sSuccess\x20(0) ^F2z4"
|
sSuccess\x20(0) ^F2z4"
|
||||||
|
|
@ -3647,7 +3647,7 @@ b0 VXdV?"
|
||||||
b0 =`@6L"
|
b0 =`@6L"
|
||||||
b0 e2JF6"
|
b0 e2JF6"
|
||||||
b0 ]ocL{"
|
b0 ]ocL{"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) ^<ah9"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) ^<ah9"
|
||||||
02sb.i"
|
02sb.i"
|
||||||
sHdlNone\x20(0) JC:kM"
|
sHdlNone\x20(0) JC:kM"
|
||||||
b0 .*4N""
|
b0 .*4N""
|
||||||
|
|
@ -3668,7 +3668,7 @@ b0 huWrb"
|
||||||
b0 EO39y"
|
b0 EO39y"
|
||||||
b0 |d_{U"
|
b0 |d_{U"
|
||||||
sPhantomConst(\"0..=16\") 3(idJ"
|
sPhantomConst(\"0..=16\") 3(idJ"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) P'(UK"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) P'(UK"
|
||||||
sHdlSome\x20(1) N^Lck"
|
sHdlSome\x20(1) N^Lck"
|
||||||
b1000000000000 q3ltq"
|
b1000000000000 q3ltq"
|
||||||
b0 zZOnr"
|
b0 zZOnr"
|
||||||
|
|
@ -3756,7 +3756,7 @@ b0 46)Xi"
|
||||||
0"(@LS"
|
0"(@LS"
|
||||||
0&NGtM"
|
0&NGtM"
|
||||||
b0 "tB6}"
|
b0 "tB6}"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) Hn\.r"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) Hn\.r"
|
||||||
0jbUZ8"
|
0jbUZ8"
|
||||||
sHdlNone\x20(0) NcD^Z"
|
sHdlNone\x20(0) NcD^Z"
|
||||||
sSuccess\x20(0) X3rb0"
|
sSuccess\x20(0) X3rb0"
|
||||||
|
|
@ -3770,7 +3770,7 @@ b0 vyE_1"
|
||||||
b0 D}2RZ"
|
b0 D}2RZ"
|
||||||
b0 \XUCp"
|
b0 \XUCp"
|
||||||
b0 [^@q%"
|
b0 [^@q%"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) G4KC#"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) G4KC#"
|
||||||
01thaQ"
|
01thaQ"
|
||||||
sHdlNone\x20(0) +5LtZ"
|
sHdlNone\x20(0) +5LtZ"
|
||||||
b0 {6^Pl"
|
b0 {6^Pl"
|
||||||
|
|
@ -3791,7 +3791,7 @@ b0 iB{BF"
|
||||||
b0 eR=Hx"
|
b0 eR=Hx"
|
||||||
b0 8!8=?"
|
b0 8!8=?"
|
||||||
sPhantomConst(\"0..=16\") V?X!X"
|
sPhantomConst(\"0..=16\") V?X!X"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) T-cQB"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) T-cQB"
|
||||||
sHdlSome\x20(1) JqP67"
|
sHdlSome\x20(1) JqP67"
|
||||||
b1000000000000 iRy|N"
|
b1000000000000 iRy|N"
|
||||||
b0 IIeMq"
|
b0 IIeMq"
|
||||||
|
|
@ -4439,7 +4439,7 @@ b0 H{?Xz"
|
||||||
03\z-w"
|
03\z-w"
|
||||||
00^&W_"
|
00^&W_"
|
||||||
b0 n/%-/"
|
b0 n/%-/"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) ./0U4"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) ./0U4"
|
||||||
0NE4rt"
|
0NE4rt"
|
||||||
sHdlNone\x20(0) :GU,#"
|
sHdlNone\x20(0) :GU,#"
|
||||||
sSuccess\x20(0) D87*9"
|
sSuccess\x20(0) D87*9"
|
||||||
|
|
@ -4453,7 +4453,7 @@ b0 d%H]f"
|
||||||
b0 zgzi@"
|
b0 zgzi@"
|
||||||
b0 7B-!)"
|
b0 7B-!)"
|
||||||
b0 Y1Qf)"
|
b0 Y1Qf)"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) a.$Aw"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) a.$Aw"
|
||||||
0*d$ca"
|
0*d$ca"
|
||||||
sHdlNone\x20(0) /N@6H"
|
sHdlNone\x20(0) /N@6H"
|
||||||
b0 '10Cg"
|
b0 '10Cg"
|
||||||
|
|
@ -4474,7 +4474,7 @@ b0 hn|]["
|
||||||
b0 bWF^\"
|
b0 bWF^\"
|
||||||
b0 -"k'e"
|
b0 -"k'e"
|
||||||
sPhantomConst(\"0..=16\") uoZP0"
|
sPhantomConst(\"0..=16\") uoZP0"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) /KK^t"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) /KK^t"
|
||||||
sHdlSome\x20(1) e\)?v"
|
sHdlSome\x20(1) e\)?v"
|
||||||
b1000000000000 %G_Dt"
|
b1000000000000 %G_Dt"
|
||||||
b0 E7iTa"
|
b0 E7iTa"
|
||||||
|
|
@ -4919,7 +4919,7 @@ b0 H{?Xz
|
||||||
03\z-w
|
03\z-w
|
||||||
00^&W_
|
00^&W_
|
||||||
b0 n/%-/
|
b0 n/%-/
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) ./0U4
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) ./0U4
|
||||||
0NE4rt
|
0NE4rt
|
||||||
sHdlNone\x20(0) :GU,#
|
sHdlNone\x20(0) :GU,#
|
||||||
sSuccess\x20(0) D87*9
|
sSuccess\x20(0) D87*9
|
||||||
|
|
@ -4933,7 +4933,7 @@ b0 d%H]f
|
||||||
b0 zgzi@
|
b0 zgzi@
|
||||||
b0 7B-!)
|
b0 7B-!)
|
||||||
b0 Y1Qf)
|
b0 Y1Qf)
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) a.$Aw
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) a.$Aw
|
||||||
0*d$ca
|
0*d$ca
|
||||||
sHdlNone\x20(0) /N@6H
|
sHdlNone\x20(0) /N@6H
|
||||||
b0 '10Cg
|
b0 '10Cg
|
||||||
|
|
@ -4954,7 +4954,7 @@ b0 hn|][
|
||||||
b0 bWF^\
|
b0 bWF^\
|
||||||
b0 -"k'e
|
b0 -"k'e
|
||||||
sPhantomConst(\"0..=16\") uoZP0
|
sPhantomConst(\"0..=16\") uoZP0
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) /KK^t
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) /KK^t
|
||||||
sHdlSome\x20(1) e\)?v
|
sHdlSome\x20(1) e\)?v
|
||||||
b1000000000000 %G_Dt
|
b1000000000000 %G_Dt
|
||||||
b0 E7iTa
|
b0 E7iTa
|
||||||
|
|
@ -5399,7 +5399,7 @@ b0 46)Xi
|
||||||
0"(@LS
|
0"(@LS
|
||||||
0&NGtM
|
0&NGtM
|
||||||
b0 "tB6}
|
b0 "tB6}
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) Hn\.r
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) Hn\.r
|
||||||
0jbUZ8
|
0jbUZ8
|
||||||
sHdlNone\x20(0) NcD^Z
|
sHdlNone\x20(0) NcD^Z
|
||||||
sSuccess\x20(0) X3rb0
|
sSuccess\x20(0) X3rb0
|
||||||
|
|
@ -5413,7 +5413,7 @@ b0 vyE_1
|
||||||
b0 D}2RZ
|
b0 D}2RZ
|
||||||
b0 \XUCp
|
b0 \XUCp
|
||||||
b0 [^@q%
|
b0 [^@q%
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) G4KC#
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) G4KC#
|
||||||
01thaQ
|
01thaQ
|
||||||
sHdlNone\x20(0) +5LtZ
|
sHdlNone\x20(0) +5LtZ
|
||||||
b0 {6^Pl
|
b0 {6^Pl
|
||||||
|
|
@ -5434,7 +5434,7 @@ b0 iB{BF
|
||||||
b0 eR=Hx
|
b0 eR=Hx
|
||||||
b0 8!8=?
|
b0 8!8=?
|
||||||
sPhantomConst(\"0..=16\") V?X!X
|
sPhantomConst(\"0..=16\") V?X!X
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) T-cQB
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) T-cQB
|
||||||
sHdlSome\x20(1) JqP67
|
sHdlSome\x20(1) JqP67
|
||||||
b1000000000000 iRy|N
|
b1000000000000 iRy|N
|
||||||
b0 IIeMq
|
b0 IIeMq
|
||||||
|
|
@ -5522,7 +5522,7 @@ b0 UA{3,
|
||||||
0mS#3<
|
0mS#3<
|
||||||
0^qjb[
|
0^qjb[
|
||||||
b0 tN>yu
|
b0 tN>yu
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) '@T[?
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) '@T[?
|
||||||
0BXk&[
|
0BXk&[
|
||||||
sHdlNone\x20(0) &wG|&
|
sHdlNone\x20(0) &wG|&
|
||||||
sSuccess\x20(0) ^F2z4
|
sSuccess\x20(0) ^F2z4
|
||||||
|
|
@ -5536,7 +5536,7 @@ b0 VXdV?
|
||||||
b0 =`@6L
|
b0 =`@6L
|
||||||
b0 e2JF6
|
b0 e2JF6
|
||||||
b0 ]ocL{
|
b0 ]ocL{
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) ^<ah9
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) ^<ah9
|
||||||
02sb.i
|
02sb.i
|
||||||
sHdlNone\x20(0) JC:kM
|
sHdlNone\x20(0) JC:kM
|
||||||
b0 .*4N"
|
b0 .*4N"
|
||||||
|
|
@ -5557,7 +5557,7 @@ b0 huWrb
|
||||||
b0 EO39y
|
b0 EO39y
|
||||||
b0 |d_{U
|
b0 |d_{U
|
||||||
sPhantomConst(\"0..=16\") 3(idJ
|
sPhantomConst(\"0..=16\") 3(idJ
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) P'(UK
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) P'(UK
|
||||||
sHdlSome\x20(1) N^Lck
|
sHdlSome\x20(1) N^Lck
|
||||||
b1000000000000 q3ltq
|
b1000000000000 q3ltq
|
||||||
b0 zZOnr
|
b0 zZOnr
|
||||||
|
|
@ -5645,7 +5645,7 @@ b0 %poA2"
|
||||||
0Bw<V4"
|
0Bw<V4"
|
||||||
0'@.QH"
|
0'@.QH"
|
||||||
b0 !3G%M"
|
b0 !3G%M"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) nRws$"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) nRws$"
|
||||||
0";E`m"
|
0";E`m"
|
||||||
sHdlNone\x20(0) QVVGm"
|
sHdlNone\x20(0) QVVGm"
|
||||||
sSuccess\x20(0) H{!U&"
|
sSuccess\x20(0) H{!U&"
|
||||||
|
|
@ -5659,7 +5659,7 @@ b0 hCJZ("
|
||||||
b0 yV&`["
|
b0 yV&`["
|
||||||
b0 o&C+Q"
|
b0 o&C+Q"
|
||||||
b0 :R>Z\"
|
b0 :R>Z\"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) %zH|b"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) %zH|b"
|
||||||
0'(8m+"
|
0'(8m+"
|
||||||
sHdlNone\x20(0) MMwRE"
|
sHdlNone\x20(0) MMwRE"
|
||||||
b0 96-j|"
|
b0 96-j|"
|
||||||
|
|
@ -5680,7 +5680,7 @@ b0 n:O1E"
|
||||||
b0 \TnT)"
|
b0 \TnT)"
|
||||||
b0 %KEY#"
|
b0 %KEY#"
|
||||||
sPhantomConst(\"0..=16\") 2S<L;"
|
sPhantomConst(\"0..=16\") 2S<L;"
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) <f)US"
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) <f)US"
|
||||||
b0 i/#1{"
|
b0 i/#1{"
|
||||||
b0 $/d2*"
|
b0 $/d2*"
|
||||||
b0 mdUW+"
|
b0 mdUW+"
|
||||||
|
|
@ -5753,7 +5753,7 @@ b0 %poA2
|
||||||
0Bw<V4
|
0Bw<V4
|
||||||
0'@.QH
|
0'@.QH
|
||||||
b0 !3G%M
|
b0 !3G%M
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) nRws$
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) nRws$
|
||||||
0";E`m
|
0";E`m
|
||||||
sHdlNone\x20(0) QVVGm
|
sHdlNone\x20(0) QVVGm
|
||||||
sSuccess\x20(0) H{!U&
|
sSuccess\x20(0) H{!U&
|
||||||
|
|
@ -5767,7 +5767,7 @@ b0 hCJZ(
|
||||||
b0 yV&`[
|
b0 yV&`[
|
||||||
b0 o&C+Q
|
b0 o&C+Q
|
||||||
b0 :R>Z\
|
b0 :R>Z\
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) %zH|b
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) %zH|b
|
||||||
0'(8m+
|
0'(8m+
|
||||||
sHdlNone\x20(0) MMwRE
|
sHdlNone\x20(0) MMwRE
|
||||||
b0 96-j|
|
b0 96-j|
|
||||||
|
|
@ -5788,7 +5788,7 @@ b0 n:O1E
|
||||||
b0 \TnT)
|
b0 \TnT)
|
||||||
b0 %KEY#
|
b0 %KEY#
|
||||||
sPhantomConst(\"0..=16\") 2S<L;
|
sPhantomConst(\"0..=16\") 2S<L;
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8}) <f)US
|
sPhantomConst({\"log2_bus_width_in_bytes\":3,\"queue_capacity\":16,\"op_id_width\":8,\"address_range\":\"Full\"}) <f)US
|
||||||
b0 i/#1{
|
b0 i/#1{
|
||||||
b0 $/d2*
|
b0 $/d2*
|
||||||
b0 mdUW+
|
b0 mdUW+
|
||||||
|
|
|
||||||
22
crates/cpu/tests/expected/simple_uart.vcd
generated
22
crates/cpu/tests/expected/simple_uart.vcd
generated
|
|
@ -549,7 +549,7 @@ b0 YK<TM
|
||||||
0dM>i/
|
0dM>i/
|
||||||
0f><7V
|
0f><7V
|
||||||
b0 #+y/d
|
b0 #+y/d
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) k$)j$
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) k$)j$
|
||||||
1z'<O{
|
1z'<O{
|
||||||
sHdlNone\x20(0) kC4Z@
|
sHdlNone\x20(0) kC4Z@
|
||||||
sSuccess\x20(0) DSj6>
|
sSuccess\x20(0) DSj6>
|
||||||
|
|
@ -557,13 +557,13 @@ sRead\x20(0) i8%Hy
|
||||||
sGeneric\x20(0) }u<b|
|
sGeneric\x20(0) }u<b|
|
||||||
b0 [i|C-
|
b0 [i|C-
|
||||||
b0 NB*xP
|
b0 NB*xP
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) b|P(G
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) b|P(G
|
||||||
0p\ULz
|
0p\ULz
|
||||||
sHdlSome\x20(1) $x:NB
|
sHdlSome\x20(1) $x:NB
|
||||||
b0 E*{c-
|
b0 E*{c-
|
||||||
0:C'8U
|
0:C'8U
|
||||||
sPhantomConst(\"0..=1\") E=NM+
|
sPhantomConst(\"0..=1\") E=NM+
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) eQf|o
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) eQf|o
|
||||||
1-x}z)
|
1-x}z)
|
||||||
0*K&(X
|
0*K&(X
|
||||||
1N12hA
|
1N12hA
|
||||||
|
|
@ -575,7 +575,7 @@ b0 ^'LkA
|
||||||
0LMy1=
|
0LMy1=
|
||||||
0YG=uN
|
0YG=uN
|
||||||
b0 ),#g]
|
b0 ),#g]
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) pukV=
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) pukV=
|
||||||
1\u*{A
|
1\u*{A
|
||||||
sHdlNone\x20(0) ax>!d
|
sHdlNone\x20(0) ax>!d
|
||||||
sSuccess\x20(0) $TH!~
|
sSuccess\x20(0) $TH!~
|
||||||
|
|
@ -583,13 +583,13 @@ sRead\x20(0) @nru
|
||||||
sGeneric\x20(0) =rNet
|
sGeneric\x20(0) =rNet
|
||||||
b0 _aF6z
|
b0 _aF6z
|
||||||
b0 fBY~q
|
b0 fBY~q
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) 3Cr%:
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) 3Cr%:
|
||||||
0jP_rY
|
0jP_rY
|
||||||
sHdlSome\x20(1) fl1G|
|
sHdlSome\x20(1) fl1G|
|
||||||
b0 >-gg}
|
b0 >-gg}
|
||||||
0d2Gl|
|
0d2Gl|
|
||||||
sPhantomConst(\"0..=1\") |@PWl
|
sPhantomConst(\"0..=1\") |@PWl
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) 7A<7@
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) 7A<7@
|
||||||
1?:DT^
|
1?:DT^
|
||||||
1*V%!4
|
1*V%!4
|
||||||
01-L[%
|
01-L[%
|
||||||
|
|
@ -730,14 +730,14 @@ b0 &]$B;
|
||||||
0N-YM;
|
0N-YM;
|
||||||
0R,uS'
|
0R,uS'
|
||||||
b0 GEq-0
|
b0 GEq-0
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) ,;U@A
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) ,;U@A
|
||||||
sHdlNone\x20(0) 0?MV,
|
sHdlNone\x20(0) 0?MV,
|
||||||
sSuccess\x20(0) D>VoK
|
sSuccess\x20(0) D>VoK
|
||||||
sRead\x20(0) d8ku7
|
sRead\x20(0) d8ku7
|
||||||
sGeneric\x20(0) Y[<1d
|
sGeneric\x20(0) Y[<1d
|
||||||
b0 .^N`/
|
b0 .^N`/
|
||||||
b0 'ThQe
|
b0 'ThQe
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) 8pZSz
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) 8pZSz
|
||||||
1'LW/7
|
1'LW/7
|
||||||
1(+=/^
|
1(+=/^
|
||||||
b0 Whx|K
|
b0 Whx|K
|
||||||
|
|
@ -752,7 +752,7 @@ b0 qwy9i
|
||||||
044.En
|
044.En
|
||||||
0Pq(.9
|
0Pq(.9
|
||||||
b0 4zG]Q
|
b0 4zG]Q
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) MTVBb
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) MTVBb
|
||||||
1IifsN
|
1IifsN
|
||||||
sHdlNone\x20(0) EA1Ra
|
sHdlNone\x20(0) EA1Ra
|
||||||
sSuccess\x20(0) [<sgF
|
sSuccess\x20(0) [<sgF
|
||||||
|
|
@ -760,13 +760,13 @@ sRead\x20(0) j.}nI
|
||||||
sGeneric\x20(0) z\\(W
|
sGeneric\x20(0) z\\(W
|
||||||
b0 Z*eyX
|
b0 Z*eyX
|
||||||
b0 MRBv>
|
b0 MRBv>
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) {[zRy
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) {[zRy
|
||||||
0q2OoF
|
0q2OoF
|
||||||
sHdlSome\x20(1) d#Of8
|
sHdlSome\x20(1) d#Of8
|
||||||
b0 J4y0s
|
b0 J4y0s
|
||||||
0vC#Sj
|
0vC#Sj
|
||||||
sPhantomConst(\"0..=1\") ye/Gl
|
sPhantomConst(\"0..=1\") ye/Gl
|
||||||
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8}) bH=hU
|
sPhantomConst({\"log2_bus_width_in_bytes\":1,\"queue_capacity\":1,\"op_id_width\":8,\"address_range\":{\"Limited\":{\"start\":0,\"size\":2}}}) bH=hU
|
||||||
1"QAdC
|
1"QAdC
|
||||||
1K%|4s
|
1K%|4s
|
||||||
$end
|
$end
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,11 @@ use fayalite::{
|
||||||
sim::vcd::VcdWriterDecls,
|
sim::vcd::VcdWriterDecls,
|
||||||
util::{RcWriter, ready_valid::ReadyValid},
|
util::{RcWriter, ready_valid::ReadyValid},
|
||||||
};
|
};
|
||||||
use std::{borrow::BorrowMut, marker::PhantomData, num::NonZeroUsize};
|
use std::{
|
||||||
|
borrow::BorrowMut,
|
||||||
|
marker::PhantomData,
|
||||||
|
num::{NonZeroUsize, Wrapping},
|
||||||
|
};
|
||||||
|
|
||||||
const fn half_period(frequency: f64) -> SimDuration {
|
const fn half_period(frequency: f64) -> SimDuration {
|
||||||
SimDuration::from_attos((SimDuration::from_secs(1).as_attos() as f64 / frequency / 2.0) as u128)
|
SimDuration::from_attos((SimDuration::from_secs(1).as_attos() as f64 / frequency / 2.0) as u128)
|
||||||
|
|
@ -603,7 +607,7 @@ fn simple_uart_loopback(
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIMPLE_UART_MEMORY_INTERFACE_CONFIG: MemoryInterfaceConfig =
|
const SIMPLE_UART_MEMORY_INTERFACE_CONFIG: MemoryInterfaceConfig =
|
||||||
simple_uart_memory_interface_config(FETCH_BLOCK_ID_WIDTH);
|
simple_uart_memory_interface_config(FETCH_BLOCK_ID_WIDTH, Wrapping(0));
|
||||||
|
|
||||||
struct MemoryOperationRunner<Sim: BorrowMut<Simulation<T>>, T: BundleType> {
|
struct MemoryOperationRunner<Sim: BorrowMut<Simulation<T>>, T: BundleType> {
|
||||||
sim: Sim,
|
sim: Sim,
|
||||||
|
|
@ -916,10 +920,10 @@ fn test_simple_uart() {
|
||||||
|
|
||||||
for i in 0..2 * BUS_WIDTH_IN_BYTES as u64 {
|
for i in 0..2 * BUS_WIDTH_IN_BYTES as u64 {
|
||||||
mem_op_runner
|
mem_op_runner
|
||||||
.read_bytes::<1>(SIMPLE_UART_SIZE + i, 1)
|
.read_bytes::<1>(SIMPLE_UART_SIZE.get() + i, 1)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
mem_op_runner
|
mem_op_runner
|
||||||
.write_bytes(SIMPLE_UART_SIZE + i, [0], 1)
|
.write_bytes(SIMPLE_UART_SIZE.get() + i, [0], 1)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue