forked from libre-chip/cpu
change MemoryInterface types to have their own config
This commit is contained in:
parent
7f7e316b7b
commit
2c8de5bec4
7 changed files with 9358 additions and 23280 deletions
|
|
@ -9,8 +9,9 @@ use crate::{
|
||||||
CpuConfigMaxFetchesInFlight, PhantomConstCpuConfig,
|
CpuConfigMaxFetchesInFlight, PhantomConstCpuConfig,
|
||||||
},
|
},
|
||||||
main_memory_and_io::{
|
main_memory_and_io::{
|
||||||
MemoryInterface, MemoryOperationErrorKind, MemoryOperationFinish,
|
CpuConfigFetchMemoryInterfaceConfig, MemoryInterface, MemoryInterfaceConfig,
|
||||||
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
MemoryOperationErrorKind, MemoryOperationFinish, MemoryOperationFinishKind,
|
||||||
|
MemoryOperationKind, MemoryOperationStart,
|
||||||
},
|
},
|
||||||
next_pc::{
|
next_pc::{
|
||||||
FETCH_BLOCK_ID_WIDTH, NextPcToFetchInterface, NextPcToFetchInterfaceInner, ResetStatus,
|
FETCH_BLOCK_ID_WIDTH, NextPcToFetchInterface, NextPcToFetchInterfaceInner, ResetStatus,
|
||||||
|
|
@ -415,7 +416,9 @@ impl<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
||||||
self.state_expr.ty().config
|
self.state_expr.ty().config
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn try_start_memory_operation(&mut self) -> Option<SimValue<MemoryOperationStart<C>>> {
|
fn try_start_memory_operation(
|
||||||
|
&mut self,
|
||||||
|
) -> Option<SimValue<MemoryOperationStart<CpuConfigFetchMemoryInterfaceConfig<C>>>> {
|
||||||
let config = self.config();
|
let config = self.config();
|
||||||
for cache_miss in &mut self.cache_misses {
|
for cache_miss in &mut self.cache_misses {
|
||||||
let Some(next_start_fetch_block) = CacheMiss::next_start_fetch_block(cache_miss) else {
|
let Some(next_start_fetch_block) = CacheMiss::next_start_fetch_block(cache_miss) else {
|
||||||
|
|
@ -430,7 +433,7 @@ impl<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
||||||
error: _, // handled by CacheMiss::next_start_fetch_block()
|
error: _, // handled by CacheMiss::next_start_fetch_block()
|
||||||
config: _,
|
config: _,
|
||||||
} = cache_miss;
|
} = cache_miss;
|
||||||
let mem_op_ty = MemoryOperationStart[config];
|
let mem_op_ty = MemoryOperationStart[CpuConfigFetchMemoryInterfaceConfig[config]];
|
||||||
let mut addr = SplitAddr[config].split_addr_sim(addr);
|
let mut addr = SplitAddr[config].split_addr_sim(addr);
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
let SplitAddr::<_> {
|
let SplitAddr::<_> {
|
||||||
|
|
@ -453,8 +456,8 @@ impl<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
||||||
mem_op_ty.write_data.len(),
|
mem_op_ty.write_data.len(),
|
||||||
),
|
),
|
||||||
rw_mask: repeat(true, mem_op_ty.write_data.len()),
|
rw_mask: repeat(true, mem_op_ty.write_data.len()),
|
||||||
fetch_block_id,
|
op_id: SimValue::into_dyn_int(fetch_block_id.clone()),
|
||||||
config,
|
config: CpuConfigFetchMemoryInterfaceConfig[config],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -497,7 +500,9 @@ impl<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
||||||
fn do_memory_operation_finish<'a>(
|
fn do_memory_operation_finish<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ready_for_memory_operation_finish: ReadyForMemoryOperationFinish,
|
ready_for_memory_operation_finish: ReadyForMemoryOperationFinish,
|
||||||
memory_operation_finish: impl ToSimValue<Type = MemoryOperationFinish<C>>,
|
memory_operation_finish: impl ToSimValue<
|
||||||
|
Type = MemoryOperationFinish<CpuConfigFetchMemoryInterfaceConfig<C>>,
|
||||||
|
>,
|
||||||
) -> Option<SimValue<WriteBackStep<C>>> {
|
) -> Option<SimValue<WriteBackStep<C>>> {
|
||||||
let config = self.config();
|
let config = self.config();
|
||||||
let cache_miss = &mut self.cache_misses[ready_for_memory_operation_finish.cache_miss_index];
|
let cache_miss = &mut self.cache_misses[ready_for_memory_operation_finish.cache_miss_index];
|
||||||
|
|
@ -621,9 +626,7 @@ impl<C: PhantomConstCpuConfig> L1ICacheStateSim<C> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn check_memory_next_fetch_block_ids(
|
fn check_memory_next_fetch_block_ids(
|
||||||
&self,
|
&self,
|
||||||
memory_next_fetch_block_ids: SimValue<
|
memory_next_fetch_block_ids: SimValue<ArrayVec<UInt, DynSize>>,
|
||||||
ArrayVec<UInt<{ FETCH_BLOCK_ID_WIDTH }>, CpuConfigMaxFetchesInFlight<C>>,
|
|
||||||
>,
|
|
||||||
) {
|
) {
|
||||||
let memory_next_fetch_block_ids = ArrayVec::elements_sim_ref(&memory_next_fetch_block_ids);
|
let memory_next_fetch_block_ids = ArrayVec::elements_sim_ref(&memory_next_fetch_block_ids);
|
||||||
let mut expected_memory_next_fetch_block_ids = Vec::new();
|
let mut expected_memory_next_fetch_block_ids = Vec::new();
|
||||||
|
|
@ -1071,8 +1074,8 @@ fn l1_i_cache_impl(config: PhantomConst<CpuConfig>) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
let memory_interface: MemoryInterface<PhantomConst<MemoryInterfaceConfig>> =
|
||||||
m.output(MemoryInterface[config]);
|
m.output(MemoryInterface[CpuConfigFetchMemoryInterfaceConfig[config]]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
m.input(NextPcToFetchInterface[config]);
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
|
@ -1103,7 +1106,7 @@ fn l1_i_cache_impl(config: PhantomConst<CpuConfig>) {
|
||||||
async fn run(
|
async fn run(
|
||||||
mut sim: ExternModuleSimulationState,
|
mut sim: ExternModuleSimulationState,
|
||||||
cd: Expr<ClockDomain>,
|
cd: Expr<ClockDomain>,
|
||||||
memory_interface: Expr<MemoryInterface<PhantomConst<CpuConfig>>>,
|
memory_interface: Expr<MemoryInterface<PhantomConst<MemoryInterfaceConfig>>>,
|
||||||
from_next_pc: Expr<NextPcToFetchInterface<PhantomConst<CpuConfig>>>,
|
from_next_pc: Expr<NextPcToFetchInterface<PhantomConst<CpuConfig>>>,
|
||||||
to_decode_fetched: Expr<ReadyValid<FetchToDecodeInterfaceInner<PhantomConst<CpuConfig>>>>,
|
to_decode_fetched: Expr<ReadyValid<FetchToDecodeInterfaceInner<PhantomConst<CpuConfig>>>>,
|
||||||
to_decode_next_fetch_block_ids: Expr<
|
to_decode_next_fetch_block_ids: Expr<
|
||||||
|
|
@ -1196,9 +1199,8 @@ fn l1_i_cache_impl(config: PhantomConst<CpuConfig>) {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
if let HdlSome(next_fetch_block_ids) = sim
|
if let HdlSome(next_fetch_block_ids) =
|
||||||
.read_past(memory_interface.next_fetch_block_ids, cd.clk)
|
sim.read_past(memory_interface.next_op_ids, cd.clk).await
|
||||||
.await
|
|
||||||
{
|
{
|
||||||
state.check_memory_next_fetch_block_ids(next_fetch_block_ids);
|
state.check_memory_next_fetch_block_ids(next_fetch_block_ids);
|
||||||
}
|
}
|
||||||
|
|
@ -1359,7 +1361,7 @@ fn l1_i_cache_impl(config: PhantomConst<CpuConfig>) {
|
||||||
state_for_debug,
|
state_for_debug,
|
||||||
),
|
),
|
||||||
mut sim| async move {
|
mut sim| async move {
|
||||||
let config = memory_interface.ty().config;
|
let config = from_next_pc.ty().config;
|
||||||
let cache_line_ty = CacheLine[config];
|
let cache_line_ty = CacheLine[config];
|
||||||
sim.write(i_cache_port.clk, false).await; // externally overridden with cd.clk, so just write a constant here
|
sim.write(i_cache_port.clk, false).await; // externally overridden with cd.clk, so just write a constant here
|
||||||
sim.resettable(
|
sim.resettable(
|
||||||
|
|
@ -1426,8 +1428,8 @@ pub fn l1_i_cache(config: PhantomConst<CpuConfig>) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
let memory_interface: MemoryInterface<PhantomConst<MemoryInterfaceConfig>> =
|
||||||
m.output(MemoryInterface[config]);
|
m.output(MemoryInterface[CpuConfigFetchMemoryInterfaceConfig[config]]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
m.input(NextPcToFetchInterface[config]);
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
|
@ -1524,8 +1526,8 @@ pub fn fetch(config: PhantomConst<CpuConfig>) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
let memory_interface: MemoryInterface<PhantomConst<MemoryInterfaceConfig>> =
|
||||||
m.output(MemoryInterface[config]);
|
m.output(MemoryInterface[CpuConfigFetchMemoryInterfaceConfig[config]]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
m.input(NextPcToFetchInterface[config]);
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,53 @@
|
||||||
// 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 crate::{
|
use crate::{config::CpuConfig, next_pc::FETCH_BLOCK_ID_WIDTH, util::array_vec::ArrayVec};
|
||||||
config::{
|
|
||||||
CpuConfig, CpuConfigFetchWidthInBytes, CpuConfigMaxFetchesInFlight, PhantomConstCpuConfig,
|
|
||||||
},
|
|
||||||
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;
|
||||||
|
|
||||||
pub mod simple_uart;
|
pub mod simple_uart;
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct MemoryInterfaceConfig {
|
||||||
|
pub log2_bus_width_in_bytes: u8,
|
||||||
|
pub queue_capacity: NonZeroUsize,
|
||||||
|
pub op_id_width: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryInterfaceConfig {
|
||||||
|
pub const fn from_cpu_config_for_fetch(config: &CpuConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
log2_bus_width_in_bytes: config.log2_fetch_width_in_bytes,
|
||||||
|
queue_capacity: config.max_fetches_in_flight,
|
||||||
|
op_id_width: FETCH_BLOCK_ID_WIDTH,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn bus_width_in_bytes(&self) -> usize {
|
||||||
|
1usize.strict_shl(self.log2_bus_width_in_bytes as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(get(|c| PhantomConst::new_sized(MemoryInterfaceConfig::from_cpu_config_for_fetch(&c))))]
|
||||||
|
pub type CpuConfigFetchMemoryInterfaceConfig<C: PhantomConstGet<CpuConfig>> =
|
||||||
|
PhantomConst<MemoryInterfaceConfig>;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.log2_bus_width_in_bytes as usize))]
|
||||||
|
pub type MemoryInterfaceLog2BusWidthInBytes<C: PhantomConstGet<MemoryInterfaceConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.bus_width_in_bytes()))]
|
||||||
|
pub type MemoryInterfaceBusWidthInBytes<C: PhantomConstGet<MemoryInterfaceConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.queue_capacity.get()))]
|
||||||
|
pub type MemoryInterfaceQueueCapacity<C: PhantomConstGet<MemoryInterfaceConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.op_id_width))]
|
||||||
|
pub type MemoryInterfaceOpIdWidth<C: PhantomConstGet<MemoryInterfaceConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type MemoryInterfaceOpId<C: PhantomConstGet<MemoryInterfaceConfig>> =
|
||||||
|
UIntType<MemoryInterfaceOpIdWidth<C>>;
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub enum MemoryOperationKind {
|
pub enum MemoryOperationKind {
|
||||||
Read,
|
Read,
|
||||||
|
|
@ -19,12 +55,12 @@ pub enum MemoryOperationKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
pub struct MemoryOperationStart<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
pub struct MemoryOperationStart<C: PhantomConstGet<MemoryInterfaceConfig>> {
|
||||||
pub kind: MemoryOperationKind,
|
pub kind: MemoryOperationKind,
|
||||||
pub addr: UInt<64>,
|
pub addr: UInt<64>,
|
||||||
pub write_data: ArrayType<UInt<8>, CpuConfigFetchWidthInBytes<C>>,
|
pub write_data: ArrayType<UInt<8>, MemoryInterfaceBusWidthInBytes<C>>,
|
||||||
pub rw_mask: ArrayType<Bool, CpuConfigFetchWidthInBytes<C>>,
|
pub rw_mask: ArrayType<Bool, MemoryInterfaceBusWidthInBytes<C>>,
|
||||||
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>, // for debugging
|
pub op_id: MemoryInterfaceOpId<C>, // for debugging
|
||||||
pub config: C,
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,20 +76,19 @@ pub enum MemoryOperationFinishKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
pub struct MemoryOperationFinish<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
pub struct MemoryOperationFinish<C: PhantomConstGet<MemoryInterfaceConfig>> {
|
||||||
pub kind: MemoryOperationFinishKind,
|
pub kind: MemoryOperationFinishKind,
|
||||||
pub read_data: ArrayType<UInt<8>, CpuConfigFetchWidthInBytes<C>>,
|
pub read_data: ArrayType<UInt<8>, MemoryInterfaceBusWidthInBytes<C>>,
|
||||||
pub config: C,
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
pub struct MemoryInterface<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
pub struct MemoryInterface<C: PhantomConstGet<MemoryInterfaceConfig>> {
|
||||||
pub start: ReadyValid<MemoryOperationStart<C>>,
|
pub start: ReadyValid<MemoryOperationStart<C>>,
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
pub finish: ReadyValid<MemoryOperationFinish<C>>,
|
pub finish: ReadyValid<MemoryOperationFinish<C>>,
|
||||||
/// for debugging
|
/// for debugging
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
pub next_fetch_block_ids:
|
pub next_op_ids: HdlOption<ArrayVec<MemoryInterfaceOpId<C>, MemoryInterfaceQueueCapacity<C>>>,
|
||||||
HdlOption<ArrayVec<UInt<{ FETCH_BLOCK_ID_WIDTH }>, CpuConfigMaxFetchesInFlight<C>>>,
|
|
||||||
pub config: C,
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{CpuConfig, PhantomConstCpuConfig},
|
|
||||||
main_memory_and_io::{
|
main_memory_and_io::{
|
||||||
MemoryInterface, MemoryOperationErrorKind, MemoryOperationFinish,
|
MemoryInterface, MemoryInterfaceConfig, MemoryOperationErrorKind, MemoryOperationFinish,
|
||||||
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
||||||
},
|
},
|
||||||
util::array_vec::ArrayVec,
|
util::array_vec::ArrayVec,
|
||||||
|
|
@ -358,25 +357,38 @@ 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 = 2;
|
pub const SIMPLE_UART_SIZE: u64 = 1 << SIMPLE_UART_LOG2_SIZE;
|
||||||
|
pub const SIMPLE_UART_LOG2_SIZE: u8 = 1;
|
||||||
|
|
||||||
#[hdl(no_static)]
|
#[hdl(no_static)]
|
||||||
struct Operation<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
struct Operation<C: PhantomConstGet<MemoryInterfaceConfig>> {
|
||||||
start: MemoryOperationStart<C>,
|
start: MemoryOperationStart<C>,
|
||||||
finish: HdlOption<MemoryOperationFinish<C>>,
|
finish: HdlOption<MemoryOperationFinish<C>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn simple_uart_memory_interface_config(op_id_width: usize) -> MemoryInterfaceConfig {
|
||||||
|
MemoryInterfaceConfig {
|
||||||
|
log2_bus_width_in_bytes: SIMPLE_UART_LOG2_SIZE,
|
||||||
|
queue_capacity: const { NonZeroUsize::new(1).unwrap() },
|
||||||
|
op_id_width,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn simple_uart(
|
pub fn simple_uart(
|
||||||
config: PhantomConst<CpuConfig>,
|
config: PhantomConst<MemoryInterfaceConfig>,
|
||||||
clock_input_properties: PhantomConst<peripherals::ClockInputProperties>,
|
clock_input_properties: PhantomConst<peripherals::ClockInputProperties>,
|
||||||
baud_rate: f64,
|
baud_rate: f64,
|
||||||
receiver_queue_size: NonZeroUsize,
|
receiver_queue_size: NonZeroUsize,
|
||||||
) {
|
) {
|
||||||
|
assert_eq!(
|
||||||
|
*config.get(),
|
||||||
|
simple_uart_memory_interface_config(config.get().op_id_width),
|
||||||
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
let memory_interface: MemoryInterface<PhantomConst<MemoryInterfaceConfig>> =
|
||||||
m.input(MemoryInterface[config]);
|
m.input(MemoryInterface[config]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let uart: peripherals::Uart = m.output();
|
let uart: peripherals::Uart = m.output();
|
||||||
|
|
@ -415,26 +427,23 @@ pub fn simple_uart(
|
||||||
.clock_domain(cd)
|
.clock_domain(cd)
|
||||||
.reset(HdlOption[Operation[config]].HdlNone());
|
.reset(HdlOption[Operation[config]].HdlNone());
|
||||||
|
|
||||||
let next_fetch_block_ids_ty = memory_interface.ty().next_fetch_block_ids.HdlSome;
|
let next_op_ids_ty = memory_interface.ty().next_op_ids.HdlSome;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(operation) = operation_reg {
|
if let HdlSome(operation) = operation_reg {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let MemoryInterface::<_> {
|
let MemoryInterface::<_> {
|
||||||
start,
|
start,
|
||||||
finish,
|
finish,
|
||||||
next_fetch_block_ids,
|
next_op_ids,
|
||||||
config: _,
|
config: _,
|
||||||
} = memory_interface;
|
} = memory_interface;
|
||||||
connect(start.ready, false);
|
connect(start.ready, false);
|
||||||
connect(finish.data, operation.finish);
|
connect(finish.data, operation.finish);
|
||||||
connect(
|
connect(
|
||||||
next_fetch_block_ids,
|
next_op_ids,
|
||||||
HdlSome(ArrayVec::from_parts_unchecked(
|
HdlSome(ArrayVec::from_parts_unchecked(
|
||||||
repeat(
|
repeat(operation.start.op_id, next_op_ids_ty.capacity()),
|
||||||
operation.start.fetch_block_id,
|
1u8.cast_to(next_op_ids_ty.len_ty()),
|
||||||
next_fetch_block_ids_ty.capacity(),
|
|
||||||
),
|
|
||||||
1u8.cast_to(next_fetch_block_ids_ty.len_ty()),
|
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
connect(transmitter.input_byte.data, HdlNone());
|
connect(transmitter.input_byte.data, HdlNone());
|
||||||
|
|
@ -452,7 +461,7 @@ pub fn simple_uart(
|
||||||
addr,
|
addr,
|
||||||
write_data,
|
write_data,
|
||||||
rw_mask,
|
rw_mask,
|
||||||
fetch_block_id: _,
|
op_id: _,
|
||||||
config: _,
|
config: _,
|
||||||
} = operation.start;
|
} = operation.start;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -559,14 +568,14 @@ pub fn simple_uart(
|
||||||
let MemoryInterface::<_> {
|
let MemoryInterface::<_> {
|
||||||
start,
|
start,
|
||||||
finish,
|
finish,
|
||||||
next_fetch_block_ids,
|
next_op_ids,
|
||||||
config: _,
|
config: _,
|
||||||
} = memory_interface;
|
} = memory_interface;
|
||||||
connect(start.ready, true);
|
connect(start.ready, true);
|
||||||
connect(finish.data, finish.ty().data.HdlNone());
|
connect(finish.data, finish.ty().data.HdlNone());
|
||||||
connect(
|
connect(
|
||||||
next_fetch_block_ids,
|
next_op_ids,
|
||||||
HdlSome(next_fetch_block_ids_ty.new_sim(next_fetch_block_ids_ty.element().zero())),
|
HdlSome(next_op_ids_ty.new_sim(next_op_ids_ty.element().zero())),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(start) = start.data {
|
if let HdlSome(start) = start.data {
|
||||||
|
|
|
||||||
2608
crates/cpu/tests/expected/fetch.vcd
generated
2608
crates/cpu/tests/expected/fetch.vcd
generated
File diff suppressed because it is too large
Load diff
29727
crates/cpu/tests/expected/simple_uart.vcd
generated
29727
crates/cpu/tests/expected/simple_uart.vcd
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,8 +5,9 @@ use cpu::{
|
||||||
config::{CpuConfig, UnitConfig},
|
config::{CpuConfig, UnitConfig},
|
||||||
fetch::{FetchToDecodeInterface, FetchToDecodeInterfaceInner, fetch},
|
fetch::{FetchToDecodeInterface, FetchToDecodeInterfaceInner, fetch},
|
||||||
main_memory_and_io::{
|
main_memory_and_io::{
|
||||||
MemoryInterface, MemoryOperationErrorKind, MemoryOperationFinish,
|
CpuConfigFetchMemoryInterfaceConfig, MemoryInterface, MemoryInterfaceConfig,
|
||||||
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
MemoryOperationErrorKind, MemoryOperationFinish, MemoryOperationFinishKind,
|
||||||
|
MemoryOperationKind, MemoryOperationStart,
|
||||||
},
|
},
|
||||||
next_pc::{FETCH_BLOCK_ID_WIDTH, NextPcToFetchInterface, NextPcToFetchInterfaceInner},
|
next_pc::{FETCH_BLOCK_ID_WIDTH, NextPcToFetchInterface, NextPcToFetchInterfaceInner},
|
||||||
unit::UnitKind,
|
unit::UnitKind,
|
||||||
|
|
@ -92,8 +93,8 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
let memory_interface: MemoryInterface<PhantomConst<MemoryInterfaceConfig>> =
|
||||||
m.input(MemoryInterface[config]);
|
m.input(MemoryInterface[CpuConfigFetchMemoryInterfaceConfig[config]]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let queue_debug: ArrayVec<MemoryQueueEntry, ConstUsize<{ MEMORY_QUEUE_SIZE }>> = m.output();
|
let queue_debug: ArrayVec<MemoryQueueEntry, ConstUsize<{ MEMORY_QUEUE_SIZE }>> = m.output();
|
||||||
m.register_clock_for_past(cd.clk);
|
m.register_clock_for_past(cd.clk);
|
||||||
|
|
@ -109,13 +110,12 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
let MemoryInterface::<_> {
|
let MemoryInterface::<_> {
|
||||||
start,
|
start,
|
||||||
finish,
|
finish,
|
||||||
next_fetch_block_ids,
|
next_op_ids,
|
||||||
config: _,
|
config: _,
|
||||||
} = memory_interface;
|
} = memory_interface;
|
||||||
sim.write(start.ready, false).await;
|
sim.write(start.ready, false).await;
|
||||||
sim.write(finish.data, finish.ty().data.HdlNone()).await;
|
sim.write(finish.data, finish.ty().data.HdlNone()).await;
|
||||||
sim.write(next_fetch_block_ids, next_fetch_block_ids.ty().HdlNone())
|
sim.write(next_op_ids, next_op_ids.ty().HdlNone()).await;
|
||||||
.await;
|
|
||||||
sim.write(
|
sim.write(
|
||||||
queue_debug,
|
queue_debug,
|
||||||
queue_debug.ty().new_sim(MemoryQueueEntry.default_sim()),
|
queue_debug.ty().new_sim(MemoryQueueEntry.default_sim()),
|
||||||
|
|
@ -130,7 +130,7 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
async fn run_fn(
|
async fn run_fn(
|
||||||
cd: Expr<ClockDomain>,
|
cd: Expr<ClockDomain>,
|
||||||
memory_interface: Expr<MemoryInterface<PhantomConst<CpuConfig>>>,
|
memory_interface: Expr<MemoryInterface<PhantomConst<MemoryInterfaceConfig>>>,
|
||||||
queue_debug: Expr<ArrayVec<MemoryQueueEntry, ConstUsize<{ MEMORY_QUEUE_SIZE }>>>,
|
queue_debug: Expr<ArrayVec<MemoryQueueEntry, ConstUsize<{ MEMORY_QUEUE_SIZE }>>>,
|
||||||
random: &RefCell<Random>,
|
random: &RefCell<Random>,
|
||||||
mut sim: ExternModuleSimulationState,
|
mut sim: ExternModuleSimulationState,
|
||||||
|
|
@ -138,7 +138,7 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
let mut random = random.borrow_mut();
|
let mut random = random.borrow_mut();
|
||||||
let config = memory_interface.config.ty();
|
let config = memory_interface.config.ty();
|
||||||
let finish_data_ty = memory_interface.finish.data.ty();
|
let finish_data_ty = memory_interface.finish.data.ty();
|
||||||
let next_fetch_block_ids_ty = memory_interface.next_fetch_block_ids.ty();
|
let next_op_ids_ty = memory_interface.next_op_ids.ty();
|
||||||
let mut queue: VecDeque<SimValue<MemoryQueueEntry>> = VecDeque::new();
|
let mut queue: VecDeque<SimValue<MemoryQueueEntry>> = VecDeque::new();
|
||||||
loop {
|
loop {
|
||||||
for entry in &mut queue {
|
for entry in &mut queue {
|
||||||
|
|
@ -156,12 +156,17 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
sim.write(
|
sim.write(
|
||||||
memory_interface.next_fetch_block_ids,
|
memory_interface.next_op_ids,
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
next_fetch_block_ids_ty.HdlSome(
|
next_op_ids_ty.HdlSome(
|
||||||
next_fetch_block_ids_ty
|
next_op_ids_ty
|
||||||
.HdlSome
|
.HdlSome
|
||||||
.from_iter_sim(0u8, queue.iter().map(|entry| &entry.fetch_block_id))
|
.from_iter_sim(
|
||||||
|
0u8,
|
||||||
|
queue
|
||||||
|
.iter()
|
||||||
|
.map(|entry| SimValue::into_dyn_int(entry.fetch_block_id.clone())),
|
||||||
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.expect("queue is known to be small enough"),
|
.expect("queue is known to be small enough"),
|
||||||
),
|
),
|
||||||
|
|
@ -235,7 +240,7 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
addr,
|
addr,
|
||||||
write_data: _,
|
write_data: _,
|
||||||
rw_mask,
|
rw_mask,
|
||||||
fetch_block_id,
|
op_id,
|
||||||
config: _,
|
config: _,
|
||||||
} = memory_operation_start;
|
} = memory_operation_start;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
|
|
@ -250,7 +255,7 @@ fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
let entry = #[hdl(sim)]
|
let entry = #[hdl(sim)]
|
||||||
MemoryQueueEntry {
|
MemoryQueueEntry {
|
||||||
addr,
|
addr,
|
||||||
fetch_block_id,
|
fetch_block_id: SimValue::from_dyn_int(op_id),
|
||||||
cycles_left: MemoryQueueEntry::get_next_delay(&mut random),
|
cycles_left: MemoryQueueEntry::get_next_delay(&mut random),
|
||||||
};
|
};
|
||||||
println!("mock memory start: {entry:#?}");
|
println!("mock memory start: {entry:#?}");
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,16 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use cpu::{
|
use cpu::{
|
||||||
config::{CpuConfig, UnitConfig},
|
|
||||||
main_memory_and_io::{
|
main_memory_and_io::{
|
||||||
MemoryInterface, MemoryOperationErrorKind, MemoryOperationFinish,
|
MemoryInterface, MemoryInterfaceConfig, MemoryOperationErrorKind, MemoryOperationFinish,
|
||||||
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
MemoryOperationFinishKind, MemoryOperationKind, MemoryOperationStart,
|
||||||
simple_uart::{
|
simple_uart::{
|
||||||
ReceiverQueueStatus, SIMPLE_UART_RECEIVE_OFFSET, SIMPLE_UART_SIZE,
|
ReceiverQueueStatus, SIMPLE_UART_RECEIVE_OFFSET, SIMPLE_UART_SIZE,
|
||||||
SIMPLE_UART_STATUS_OFFSET, SIMPLE_UART_TRANSMIT_OFFSET, receiver, receiver_no_queue,
|
SIMPLE_UART_STATUS_OFFSET, SIMPLE_UART_TRANSMIT_OFFSET, receiver, receiver_no_queue,
|
||||||
simple_uart, transmitter, uart_clock_gen,
|
simple_uart, simple_uart_memory_interface_config, transmitter, uart_clock_gen,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
next_pc::FETCH_BLOCK_ID_WIDTH,
|
next_pc::FETCH_BLOCK_ID_WIDTH,
|
||||||
unit::UnitKind,
|
|
||||||
util::array_vec::ArrayVec,
|
util::array_vec::ArrayVec,
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
|
|
@ -579,7 +577,7 @@ fn test_receiver_and_uart_clock_gen() {
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
fn simple_uart_loopback(
|
fn simple_uart_loopback(
|
||||||
config: PhantomConst<CpuConfig>,
|
config: PhantomConst<MemoryInterfaceConfig>,
|
||||||
clock_input_properties: PhantomConst<peripherals::ClockInputProperties>,
|
clock_input_properties: PhantomConst<peripherals::ClockInputProperties>,
|
||||||
baud_rate: f64,
|
baud_rate: f64,
|
||||||
receiver_queue_size: NonZeroUsize,
|
receiver_queue_size: NonZeroUsize,
|
||||||
|
|
@ -587,7 +585,7 @@ fn simple_uart_loopback(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
let memory_interface: MemoryInterface<PhantomConst<MemoryInterfaceConfig>> =
|
||||||
m.input(MemoryInterface[config]);
|
m.input(MemoryInterface[config]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let tx: Bool = m.output();
|
let tx: Bool = m.output();
|
||||||
|
|
@ -604,15 +602,18 @@ fn simple_uart_loopback(
|
||||||
connect(inner.uart.rx, inner.uart.tx);
|
connect(inner.uart.rx, inner.uart.tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SIMPLE_UART_MEMORY_INTERFACE_CONFIG: MemoryInterfaceConfig =
|
||||||
|
simple_uart_memory_interface_config(FETCH_BLOCK_ID_WIDTH);
|
||||||
|
|
||||||
struct MemoryOperationRunner<Sim: BorrowMut<Simulation<T>>, T: BundleType> {
|
struct MemoryOperationRunner<Sim: BorrowMut<Simulation<T>>, T: BundleType> {
|
||||||
sim: Sim,
|
sim: Sim,
|
||||||
clk: Expr<Clock>,
|
clk: Expr<Clock>,
|
||||||
memory_interface: Expr<MemoryInterface<PhantomConst<CpuConfig>>>,
|
memory_interface: Expr<MemoryInterface<PhantomConst<MemoryInterfaceConfig>>>,
|
||||||
next_fetch_block_id: u64,
|
next_op_id: u64,
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const FETCH_WIDTH_IN_BYTES: usize = 1 << CpuConfig::DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES;
|
const BUS_WIDTH_IN_BYTES: usize = SIMPLE_UART_MEMORY_INTERFACE_CONFIG.bus_width_in_bytes();
|
||||||
|
|
||||||
impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T> {
|
impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -620,24 +621,22 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
&mut self,
|
&mut self,
|
||||||
kind: impl ToSimValue<Type = MemoryOperationKind>,
|
kind: impl ToSimValue<Type = MemoryOperationKind>,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
write_data: [u8; FETCH_WIDTH_IN_BYTES],
|
write_data: [u8; BUS_WIDTH_IN_BYTES],
|
||||||
rw_mask: [bool; FETCH_WIDTH_IN_BYTES],
|
rw_mask: [bool; BUS_WIDTH_IN_BYTES],
|
||||||
timeout_cycles: usize,
|
timeout_cycles: usize,
|
||||||
) -> Result<[u8; FETCH_WIDTH_IN_BYTES], SimValue<MemoryOperationErrorKind>> {
|
) -> Result<[u8; BUS_WIDTH_IN_BYTES], SimValue<MemoryOperationErrorKind>> {
|
||||||
let kind = kind.into_sim_value();
|
let kind = kind.into_sim_value();
|
||||||
assert_eq!(addr % FETCH_WIDTH_IN_BYTES as u64, 0);
|
assert_eq!(addr % BUS_WIDTH_IN_BYTES as u64, 0);
|
||||||
let config = self.memory_interface.ty().config;
|
let config = self.memory_interface.ty().config;
|
||||||
let fetch_block_id = self
|
let op_id = self.next_op_id.cast_to(UInt[FETCH_BLOCK_ID_WIDTH]);
|
||||||
.next_fetch_block_id
|
self.next_op_id += 1;
|
||||||
.cast_to_static::<UInt<{ FETCH_BLOCK_ID_WIDTH }>>();
|
|
||||||
self.next_fetch_block_id += 1;
|
|
||||||
println!(
|
println!(
|
||||||
"started: MemoryOperationStart {{\n \
|
"started: MemoryOperationStart {{\n \
|
||||||
kind: {kind:?},\n \
|
kind: {kind:?},\n \
|
||||||
addr: {addr:#x},\n \
|
addr: {addr:#x},\n \
|
||||||
write_data: {write_data:?},\n \
|
write_data: {write_data:?},\n \
|
||||||
rw_mask: {rw_mask:?},\n \
|
rw_mask: {rw_mask:?},\n \
|
||||||
fetch_block_id: {fetch_block_id},\n\
|
op_id: {op_id},\n\
|
||||||
}}"
|
}}"
|
||||||
);
|
);
|
||||||
let start_value = #[hdl(sim)]
|
let start_value = #[hdl(sim)]
|
||||||
|
|
@ -646,21 +645,21 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
addr,
|
addr,
|
||||||
write_data: &write_data[..],
|
write_data: &write_data[..],
|
||||||
rw_mask: &rw_mask[..],
|
rw_mask: &rw_mask[..],
|
||||||
fetch_block_id,
|
op_id: op_id,
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let MemoryInterface::<_> {
|
let MemoryInterface::<_> {
|
||||||
start,
|
start,
|
||||||
finish,
|
finish,
|
||||||
next_fetch_block_ids,
|
next_op_ids,
|
||||||
config: _,
|
config: _,
|
||||||
} = self.memory_interface;
|
} = self.memory_interface;
|
||||||
let sim = self.sim.borrow_mut();
|
let sim = self.sim.borrow_mut();
|
||||||
let check_io = |sim: &mut Simulation<T>,
|
let check_io = |sim: &mut Simulation<T>,
|
||||||
expected_start_ready: bool,
|
expected_start_ready: bool,
|
||||||
expected_finish_data_is_some: bool,
|
expected_finish_data_is_some: bool,
|
||||||
expected_next_fetch_block_ids: &[_]| {
|
expected_next_op_ids: &[_]| {
|
||||||
assert_eq!(sim.read_bool(start.ready), expected_start_ready);
|
assert_eq!(sim.read_bool(start.ready), expected_start_ready);
|
||||||
let finish_data = sim.read(finish.data);
|
let finish_data = sim.read(finish.data);
|
||||||
let finish_data_is_some = #[hdl(sim)]
|
let finish_data_is_some = #[hdl(sim)]
|
||||||
|
|
@ -675,15 +674,17 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
);
|
);
|
||||||
|
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
if let HdlSome(next_fetch_block_ids) = sim.read(next_fetch_block_ids) {
|
if let HdlSome(next_op_ids) = sim.read(next_op_ids) {
|
||||||
let next_fetch_block_ids: Vec<_> =
|
let next_op_ids: Vec<_> = ArrayVec::elements_sim_ref(&next_op_ids)
|
||||||
ArrayVec::elements_sim_ref(&next_fetch_block_ids)
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| v.as_int())
|
.map(|v| {
|
||||||
|
v.cast_to_static::<UInt<{ FETCH_BLOCK_ID_WIDTH }>>()
|
||||||
|
.as_int()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
assert_eq!(next_fetch_block_ids, expected_next_fetch_block_ids);
|
assert_eq!(next_op_ids, expected_next_op_ids);
|
||||||
} else {
|
} else {
|
||||||
panic!("next_fetch_block_ids should be HdlSome");
|
panic!("next_op_ids should be HdlSome");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
check_io(sim, true, false, &[]);
|
check_io(sim, true, false, &[]);
|
||||||
|
|
@ -702,7 +703,15 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
(start.ty().data).HdlNone(),
|
(start.ty().data).HdlNone(),
|
||||||
);
|
);
|
||||||
check_io(sim, false, false, &[start_value.fetch_block_id.as_int()]);
|
check_io(
|
||||||
|
sim,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
&[start_value
|
||||||
|
.op_id
|
||||||
|
.cast_to_static::<UInt<{ FETCH_BLOCK_ID_WIDTH }>>()
|
||||||
|
.as_int()],
|
||||||
|
);
|
||||||
for _ in 0..timeout_cycles {
|
for _ in 0..timeout_cycles {
|
||||||
sim.advance_time(CLOCK_HALF_PERIOD);
|
sim.advance_time(CLOCK_HALF_PERIOD);
|
||||||
sim.write_clock(self.clk, true);
|
sim.write_clock(self.clk, true);
|
||||||
|
|
@ -716,7 +725,7 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
read_data,
|
read_data,
|
||||||
config: _,
|
config: _,
|
||||||
} = finish_data;
|
} = finish_data;
|
||||||
assert_eq!(read_data.len(), FETCH_WIDTH_IN_BYTES);
|
assert_eq!(read_data.len(), BUS_WIDTH_IN_BYTES);
|
||||||
let read_data = std::array::from_fn(|i| read_data[i].as_int());
|
let read_data = std::array::from_fn(|i| read_data[i].as_int());
|
||||||
println!(
|
println!(
|
||||||
"finished: MemoryOperationFinish {{\n \
|
"finished: MemoryOperationFinish {{\n \
|
||||||
|
|
@ -724,7 +733,15 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
read_data: {read_data:?},\n\
|
read_data: {read_data:?},\n\
|
||||||
}}"
|
}}"
|
||||||
);
|
);
|
||||||
check_io(sim, false, true, &[start_value.fetch_block_id.as_int()]);
|
check_io(
|
||||||
|
sim,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
&[start_value
|
||||||
|
.op_id
|
||||||
|
.cast_to_static::<UInt<{ FETCH_BLOCK_ID_WIDTH }>>()
|
||||||
|
.as_int()],
|
||||||
|
);
|
||||||
sim.advance_time(CLOCK_HALF_PERIOD);
|
sim.advance_time(CLOCK_HALF_PERIOD);
|
||||||
sim.write_clock(self.clk, true);
|
sim.write_clock(self.clk, true);
|
||||||
sim.advance_time(CLOCK_HALF_PERIOD);
|
sim.advance_time(CLOCK_HALF_PERIOD);
|
||||||
|
|
@ -744,7 +761,15 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
MemoryOperationFinishKind::Error(error) => Err(error),
|
MemoryOperationFinishKind::Error(error) => Err(error),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
check_io(sim, false, false, &[start_value.fetch_block_id.as_int()]);
|
check_io(
|
||||||
|
sim,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
&[start_value
|
||||||
|
.op_id
|
||||||
|
.cast_to_static::<UInt<{ FETCH_BLOCK_ID_WIDTH }>>()
|
||||||
|
.as_int()],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
panic!("memory operation took too long");
|
panic!("memory operation took too long");
|
||||||
}
|
}
|
||||||
|
|
@ -756,16 +781,16 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
bytes: &mut [u8],
|
bytes: &mut [u8],
|
||||||
timeout_cycles: usize,
|
timeout_cycles: usize,
|
||||||
) -> Result<(), SimValue<MemoryOperationErrorKind>> {
|
) -> Result<(), SimValue<MemoryOperationErrorKind>> {
|
||||||
let offset_in_chunk = start_addr as usize % FETCH_WIDTH_IN_BYTES;
|
let offset_in_chunk = start_addr as usize % BUS_WIDTH_IN_BYTES;
|
||||||
let masked_addr = start_addr - offset_in_chunk as u64;
|
let masked_addr = start_addr - offset_in_chunk as u64;
|
||||||
assert!(
|
assert!(
|
||||||
offset_in_chunk
|
offset_in_chunk
|
||||||
.checked_add(bytes.len())
|
.checked_add(bytes.len())
|
||||||
.is_some_and(|v| v <= FETCH_WIDTH_IN_BYTES)
|
.is_some_and(|v| v <= BUS_WIDTH_IN_BYTES)
|
||||||
);
|
);
|
||||||
let bytes_range = offset_in_chunk..(offset_in_chunk + bytes.len());
|
let bytes_range = offset_in_chunk..(offset_in_chunk + bytes.len());
|
||||||
let mut write_data = [0u8; FETCH_WIDTH_IN_BYTES];
|
let mut write_data = [0u8; BUS_WIDTH_IN_BYTES];
|
||||||
let mut rw_mask = [false; FETCH_WIDTH_IN_BYTES];
|
let mut rw_mask = [false; BUS_WIDTH_IN_BYTES];
|
||||||
rw_mask[bytes_range.clone()].fill(true);
|
rw_mask[bytes_range.clone()].fill(true);
|
||||||
if !is_read {
|
if !is_read {
|
||||||
write_data[bytes_range.clone()].copy_from_slice(bytes);
|
write_data[bytes_range.clone()].copy_from_slice(bytes);
|
||||||
|
|
@ -813,16 +838,9 @@ impl<Sim: BorrowMut<Simulation<T>>, T: BundleType> MemoryOperationRunner<Sim, T>
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn test_simple_uart() {
|
fn test_simple_uart() {
|
||||||
let _n = SourceLocation::normalize_files_for_tests();
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
let config = CpuConfig::new(
|
|
||||||
vec![
|
|
||||||
UnitConfig::new(UnitKind::AluBranch),
|
|
||||||
UnitConfig::new(UnitKind::AluBranch),
|
|
||||||
],
|
|
||||||
NonZeroUsize::new(20).unwrap(),
|
|
||||||
);
|
|
||||||
const RECEIVER_QUEUE_SIZE: NonZeroUsize = NonZeroUsize::new(16).expect("not zero");
|
const RECEIVER_QUEUE_SIZE: NonZeroUsize = NonZeroUsize::new(16).expect("not zero");
|
||||||
let m = simple_uart_loopback(
|
let m = simple_uart_loopback(
|
||||||
PhantomConst::new_sized(config),
|
PhantomConst::new_sized(SIMPLE_UART_MEMORY_INTERFACE_CONFIG),
|
||||||
clock_input_properties(),
|
clock_input_properties(),
|
||||||
BAUD_RATE,
|
BAUD_RATE,
|
||||||
RECEIVER_QUEUE_SIZE,
|
RECEIVER_QUEUE_SIZE,
|
||||||
|
|
@ -859,7 +877,7 @@ fn test_simple_uart() {
|
||||||
let mut mem_op_runner = MemoryOperationRunner {
|
let mut mem_op_runner = MemoryOperationRunner {
|
||||||
clk: sim.io().cd.clk,
|
clk: sim.io().cd.clk,
|
||||||
memory_interface: sim.io().memory_interface,
|
memory_interface: sim.io().memory_interface,
|
||||||
next_fetch_block_id: 0,
|
next_op_id: 0,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
sim,
|
sim,
|
||||||
};
|
};
|
||||||
|
|
@ -896,7 +914,7 @@ fn test_simple_uart() {
|
||||||
[0, empty_status],
|
[0, empty_status],
|
||||||
);
|
);
|
||||||
|
|
||||||
for i in 0..2 * FETCH_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 + i, 1)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue