From 9f68cbb953980d4bf197684a53b874664a6beb53 Mon Sep 17 00:00:00 2001 From: Tobias Alexandra Platen Date: Sun, 5 Oct 2025 11:04:18 +0200 Subject: [PATCH 1/6] add main_memory --- crates/cpu/src/lib.rs | 2 ++ crates/cpu/src/main_memory.rs | 62 ++++++++++++++++++++++++++++++++ crates/cpu/tests/main_memory.rs | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 crates/cpu/src/main_memory.rs create mode 100644 crates/cpu/tests/main_memory.rs diff --git a/crates/cpu/src/lib.rs b/crates/cpu/src/lib.rs index bae3720..c6fd36c 100644 --- a/crates/cpu/src/lib.rs +++ b/crates/cpu/src/lib.rs @@ -6,3 +6,5 @@ pub mod reg_alloc; pub mod register; pub mod unit; pub mod util; +//TODO read other modules +pub mod main_memory; diff --git a/crates/cpu/src/main_memory.rs b/crates/cpu/src/main_memory.rs new file mode 100644 index 0000000..f386061 --- /dev/null +++ b/crates/cpu/src/main_memory.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +// first copied code block -- changes needed +use crate::{ + config::CpuConfig, + instruction::{ + AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp, + UnitOutRegNum, mop_enum, + }, + register::{FlagsMode, PRegValue}, + unit::unit_base::UnitToRegAlloc, +}; +use fayalite::{ + bundle::{Bundle, BundleType}, + intern::{Intern, Interned}, + prelude::*, +}; + +//input address <32> bit ? +//output data word <8> bit for first test (read only) + +#[hdl_module] +/// add a comment here +pub fn main_memory(config: &CpuConfig) { + #[hdl] + let addr: UInt<64> = m.input(); + #[hdl] + let read_data: UInt<8> = m.output(); + #[hdl] + let en: Bool = m.input(); + + #[hdl] + let cd: ClockDomain = m.input(); + // for each instance do + // connect(instance.cd, cd); + + + #[hdl] + //let mut mem = memory_with_init([0x12u8, 0x34, 0x56, 0x78]); + let mut my_memory = memory_with_init([0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8]); + + let read_port = my_memory.new_read_port(); + // note that `read_addr` is `UInt<2>` since the memory only has 4 elements + //need to connect addr en clk and data->out + connect_any(read_port.addr, addr); //FIXME + connect(read_port.en, en); + connect(read_port.clk, cd.clk); + connect(read_data,read_port.data); + + + + +} + +// see https://git.libre-chip.org/libre-chip/fayalite/src/branch/master/crates/fayalite/tests/sim.rs +// how to write testbenches +// start with a very simple memory model -> +// TODO create a branch for the memory + +// 1 connect up the read port, add write later +// ask how I make the memory pipelined later ... not today diff --git a/crates/cpu/tests/main_memory.rs b/crates/cpu/tests/main_memory.rs new file mode 100644 index 0000000..4792bef --- /dev/null +++ b/crates/cpu/tests/main_memory.rs @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use cpu::{ + config::{CpuConfig, UnitConfig}, + instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode}, + reg_alloc::{FetchedDecodedMOp, reg_alloc}, + register::{FlagsMode, PRegFlagsPowerISA}, + unit::{GlobalState, UnitKind}, + main_memory::main_memory, +}; +use fayalite::{ + assert_export_firrtl, + firrtl::ExportOptions, + prelude::*, + sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls}, + util::RcWriter, +}; +use std::num::NonZeroUsize; + +#[hdl] +#[test] +fn test_main_memory() { +// see reg_alloc.rs for reference + let _n = SourceLocation::normalize_files_for_tests(); + let mut config = CpuConfig::new( + vec![ + UnitConfig::new(UnitKind::AluBranch), + UnitConfig::new(UnitKind::AluBranch), + ], + NonZeroUsize::new(20).unwrap(), + ); + config.fetch_width = NonZeroUsize::new(2).unwrap(); //unchanged for now + let m = main_memory(&config); + let mut sim = Simulation::new(m); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, true); + //TODO sim.write_bool + //TODO sim.write( + //footer for tests + // FIXME: vcd is just whatever reg_alloc does now, which isn't known to be correct + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + //if vcd != include_str!("expected/reg_alloc.vcd") { //FIXME panic on result compare + // panic!(); //test is incomplete here, getting panic + //} + // #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 + // assert_export_firrtl! { + // m => + // options: ExportOptions { + // simplify_enums: None, + // ..ExportOptions::default() + // }, + // "/test/reg_alloc.fir": "", + // }; + // let sim_debug = format!("{sim:#?}"); + // println!("#######\n{sim_debug}\n#######"); + // if sim_debug != include_str!("expected/reg_alloc.txt") { + // panic!(); + // } + +} From 540a91878ccab483b2b3fbc730135770a80f2966 Mon Sep 17 00:00:00 2001 From: Tobias Alexandra Platen Date: Sun, 5 Oct 2025 12:11:27 +0200 Subject: [PATCH 2/6] more work on test case --- crates/cpu/src/main_memory.rs | 3 +- crates/cpu/tests/main_memory.rs | 61 ++++++++++++++------------------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/crates/cpu/src/main_memory.rs b/crates/cpu/src/main_memory.rs index f386061..2d19ece 100644 --- a/crates/cpu/src/main_memory.rs +++ b/crates/cpu/src/main_memory.rs @@ -44,9 +44,10 @@ pub fn main_memory(config: &CpuConfig) { // note that `read_addr` is `UInt<2>` since the memory only has 4 elements //need to connect addr en clk and data->out connect_any(read_port.addr, addr); //FIXME - connect(read_port.en, en); + connect_any(read_port.en, addr.cmp_lt(4u64)); connect(read_port.clk, cd.clk); connect(read_data,read_port.data); + diff --git a/crates/cpu/tests/main_memory.rs b/crates/cpu/tests/main_memory.rs index 4792bef..622d488 100644 --- a/crates/cpu/tests/main_memory.rs +++ b/crates/cpu/tests/main_memory.rs @@ -18,11 +18,9 @@ use fayalite::{ }; use std::num::NonZeroUsize; -#[hdl] +//new test - much simpler #[test] fn test_main_memory() { -// see reg_alloc.rs for reference - let _n = SourceLocation::normalize_files_for_tests(); let mut config = CpuConfig::new( vec![ UnitConfig::new(UnitKind::AluBranch), @@ -30,35 +28,28 @@ fn test_main_memory() { ], NonZeroUsize::new(20).unwrap(), ); - config.fetch_width = NonZeroUsize::new(2).unwrap(); //unchanged for now - let m = main_memory(&config); - let mut sim = Simulation::new(m); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.write_clock(sim.io().cd.clk, false); - sim.write_reset(sim.io().cd.rst, true); - //TODO sim.write_bool - //TODO sim.write( - //footer for tests - // FIXME: vcd is just whatever reg_alloc does now, which isn't known to be correct - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - //if vcd != include_str!("expected/reg_alloc.vcd") { //FIXME panic on result compare - // panic!(); //test is incomplete here, getting panic - //} - // #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 - // assert_export_firrtl! { - // m => - // options: ExportOptions { - // simplify_enums: None, - // ..ExportOptions::default() - // }, - // "/test/reg_alloc.fir": "", - // }; - // let sim_debug = format!("{sim:#?}"); - // println!("#######\n{sim_debug}\n#######"); - // if sim_debug != include_str!("expected/reg_alloc.txt") { - // panic!(); - // } - -} + // create a simulation from main_memory() + let mut sim = Simulation::new(main_memory(&config)); + // add a .vcd writer that writes to main_memory.vcd -- this is simple for demo purposes, + // but for our actual code we should do better than just writing + // to main_memory.vcd in the repository's root + //WRONG: sim.add_trace_writer(std::fs::File::create("main_memory.vcd").unwrap()); + + let out_file = std::fs::File::create("main_memory.vcd").unwrap(); + sim.add_trace_writer(VcdWriterDecls::new(out_file)); + + sim.write(sim.io().en, true); + sim.write(sim.io().cd.rst, false); + sim.write(sim.io().cd.clk, false); + + // TODO convert to for loop + // you need to write an initial value to all inputs before you can start running the simulation + sim.write(sim.io().addr, 0x12345u64); + // now wait 1us because why not + sim.advance_time(SimDuration::from_micros(1)); //panic here at simulation + + dbg!(sim.read(sim.io().read_data)); // dbg! macro just displays the value you pass to it + + + sim.flush_traces().unwrap(); // make sure everything is written to the output file +} \ No newline at end of file From 1ead550d1356a4ef263a0ac9ad41e618e820ab8a Mon Sep 17 00:00:00 2001 From: Tobias Alexandra Platen Date: Tue, 14 Oct 2025 18:50:29 +0200 Subject: [PATCH 3/6] use for loop in unit test --- crates/cpu/tests/main_memory.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/cpu/tests/main_memory.rs b/crates/cpu/tests/main_memory.rs index 622d488..fa9e2d2 100644 --- a/crates/cpu/tests/main_memory.rs +++ b/crates/cpu/tests/main_memory.rs @@ -49,7 +49,16 @@ fn test_main_memory() { sim.advance_time(SimDuration::from_micros(1)); //panic here at simulation dbg!(sim.read(sim.io().read_data)); // dbg! macro just displays the value you pass to it + + + for n in 0u64..4u64 { + sim.write(sim.io().addr, n); + // now wait 1us because why not + sim.advance_time(SimDuration::from_micros(1)); + } + + sim.flush_traces().unwrap(); // make sure everything is written to the output file -} \ No newline at end of file +} From 35ea85d074714c5e23c06a1dc5dcbd67c751e9cb Mon Sep 17 00:00:00 2001 From: Tobias Alexandra Platen Date: Tue, 14 Oct 2025 20:08:29 +0200 Subject: [PATCH 4/6] add write port --- crates/cpu/src/main_memory.rs | 14 ++++++++++++++ crates/cpu/tests/main_memory.rs | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/crates/cpu/src/main_memory.rs b/crates/cpu/src/main_memory.rs index 2d19ece..521e96f 100644 --- a/crates/cpu/src/main_memory.rs +++ b/crates/cpu/src/main_memory.rs @@ -29,6 +29,11 @@ pub fn main_memory(config: &CpuConfig) { let read_data: UInt<8> = m.output(); #[hdl] let en: Bool = m.input(); + // add write support + #[hdl] + let write_en: Bool = m.input(); + #[hdl] + let write_data: UInt<8> = m.input(); #[hdl] let cd: ClockDomain = m.input(); @@ -48,6 +53,15 @@ pub fn main_memory(config: &CpuConfig) { connect(read_port.clk, cd.clk); connect(read_data,read_port.data); + let write_port = my_memory.new_write_port(); + connect_any(write_port.addr, addr); + connect_any(write_port.en, addr.cmp_lt(4u64) & write_en); + connect_any(write_port.data, write_data); + connect(write_port.clk, cd.clk); + //connect_any(write_port.mask, 0xFFu8); //try that one + connect_any(write_port.mask, true); + + diff --git a/crates/cpu/tests/main_memory.rs b/crates/cpu/tests/main_memory.rs index fa9e2d2..bc0ba29 100644 --- a/crates/cpu/tests/main_memory.rs +++ b/crates/cpu/tests/main_memory.rs @@ -41,6 +41,8 @@ fn test_main_memory() { sim.write(sim.io().en, true); sim.write(sim.io().cd.rst, false); sim.write(sim.io().cd.clk, false); + sim.write(sim.io().write_en, false); + sim.write(sim.io().write_data, 0xFFu8); // TODO convert to for loop // you need to write an initial value to all inputs before you can start running the simulation @@ -57,6 +59,20 @@ fn test_main_memory() { sim.advance_time(SimDuration::from_micros(1)); } + sim.write(sim.io().write_en, true); + sim.write(sim.io().addr, 0u64); + sim.write(sim.io().write_data, 0x11u8); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 1u64); + sim.write(sim.io().write_data, 0x22u8); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 2u64); + sim.write(sim.io().write_data, 0x33u8); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 3u64); + sim.write(sim.io().write_data, 0x44u8); + sim.advance_time(SimDuration::from_micros(1)); + From 672a29e76d37b3674f164400f6cabca0a44c02f9 Mon Sep 17 00:00:00 2001 From: Tobias Alexandra Platen Date: Tue, 14 Oct 2025 20:11:24 +0200 Subject: [PATCH 5/6] run cargo fmt on main_memory --- crates/cpu/src/main_memory.rs | 23 ++++++++--------------- crates/cpu/tests/main_memory.rs | 28 ++++++++++++---------------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/crates/cpu/src/main_memory.rs b/crates/cpu/src/main_memory.rs index 521e96f..1719927 100644 --- a/crates/cpu/src/main_memory.rs +++ b/crates/cpu/src/main_memory.rs @@ -34,14 +34,13 @@ pub fn main_memory(config: &CpuConfig) { let write_en: Bool = m.input(); #[hdl] let write_data: UInt<8> = m.input(); - - #[hdl] + + #[hdl] let cd: ClockDomain = m.input(); // for each instance do // connect(instance.cd, cd); - - - #[hdl] + + #[hdl] //let mut mem = memory_with_init([0x12u8, 0x34, 0x56, 0x78]); let mut my_memory = memory_with_init([0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8]); @@ -51,8 +50,8 @@ pub fn main_memory(config: &CpuConfig) { connect_any(read_port.addr, addr); //FIXME connect_any(read_port.en, addr.cmp_lt(4u64)); connect(read_port.clk, cd.clk); - connect(read_data,read_port.data); - + connect(read_data, read_port.data); + let write_port = my_memory.new_write_port(); connect_any(write_port.addr, addr); connect_any(write_port.en, addr.cmp_lt(4u64) & write_en); @@ -60,18 +59,12 @@ pub fn main_memory(config: &CpuConfig) { connect(write_port.clk, cd.clk); //connect_any(write_port.mask, 0xFFu8); //try that one connect_any(write_port.mask, true); - - - - - - } // see https://git.libre-chip.org/libre-chip/fayalite/src/branch/master/crates/fayalite/tests/sim.rs // how to write testbenches -// start with a very simple memory model -> -// TODO create a branch for the memory +// start with a very simple memory model -> +// TODO create a branch for the memory // 1 connect up the read port, add write later // ask how I make the memory pipelined later ... not today diff --git a/crates/cpu/tests/main_memory.rs b/crates/cpu/tests/main_memory.rs index bc0ba29..d558c79 100644 --- a/crates/cpu/tests/main_memory.rs +++ b/crates/cpu/tests/main_memory.rs @@ -4,10 +4,10 @@ use cpu::{ config::{CpuConfig, UnitConfig}, instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode}, + main_memory::main_memory, reg_alloc::{FetchedDecodedMOp, reg_alloc}, register::{FlagsMode, PRegFlagsPowerISA}, unit::{GlobalState, UnitKind}, - main_memory::main_memory, }; use fayalite::{ assert_export_firrtl, @@ -51,30 +51,26 @@ fn test_main_memory() { sim.advance_time(SimDuration::from_micros(1)); //panic here at simulation dbg!(sim.read(sim.io().read_data)); // dbg! macro just displays the value you pass to it - - + for n in 0u64..4u64 { sim.write(sim.io().addr, n); - // now wait 1us because why not - sim.advance_time(SimDuration::from_micros(1)); + // now wait 1us because why not + sim.advance_time(SimDuration::from_micros(1)); } - + sim.write(sim.io().write_en, true); sim.write(sim.io().addr, 0u64); sim.write(sim.io().write_data, 0x11u8); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().addr, 1u64); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 1u64); sim.write(sim.io().write_data, 0x22u8); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().addr, 2u64); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 2u64); sim.write(sim.io().write_data, 0x33u8); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().addr, 3u64); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 3u64); sim.write(sim.io().write_data, 0x44u8); - sim.advance_time(SimDuration::from_micros(1)); - - - + sim.advance_time(SimDuration::from_micros(1)); sim.flush_traces().unwrap(); // make sure everything is written to the output file } From 8433f4f1507a123aa95929ae317ce848533ffde5 Mon Sep 17 00:00:00 2001 From: Tobias Alexandra Platen Date: Sun, 19 Oct 2025 10:26:26 +0200 Subject: [PATCH 6/6] increase memory bandwidth and size --- crates/cpu/src/lib.rs | 2 +- crates/cpu/src/main_memory.rs | 36 ++++++++++++--------------------- crates/cpu/tests/main_memory.rs | 26 +++++++++++++++++++----- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/crates/cpu/src/lib.rs b/crates/cpu/src/lib.rs index c6fd36c..575357b 100644 --- a/crates/cpu/src/lib.rs +++ b/crates/cpu/src/lib.rs @@ -7,4 +7,4 @@ pub mod register; pub mod unit; pub mod util; //TODO read other modules -pub mod main_memory; +pub mod main_memory; diff --git a/crates/cpu/src/main_memory.rs b/crates/cpu/src/main_memory.rs index 1719927..b933cb9 100644 --- a/crates/cpu/src/main_memory.rs +++ b/crates/cpu/src/main_memory.rs @@ -26,45 +26,35 @@ pub fn main_memory(config: &CpuConfig) { #[hdl] let addr: UInt<64> = m.input(); #[hdl] - let read_data: UInt<8> = m.output(); + let read_data: UInt<64> = m.output(); #[hdl] let en: Bool = m.input(); - // add write support + + //WIP: add write support #[hdl] let write_en: Bool = m.input(); #[hdl] - let write_data: UInt<8> = m.input(); + let write_data: UInt<64> = m.input(); #[hdl] let cd: ClockDomain = m.input(); - // for each instance do - // connect(instance.cd, cd); - #[hdl] - //let mut mem = memory_with_init([0x12u8, 0x34, 0x56, 0x78]); - let mut my_memory = memory_with_init([0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8]); + #[hdl] // FIXME: do not hardcode memory size and content -- + //let mut my_memory = memory_with_init([0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8]); + let mut my_memory = memory(); + my_memory.depth(256); //TODO make configurable let read_port = my_memory.new_read_port(); - // note that `read_addr` is `UInt<2>` since the memory only has 4 elements - //need to connect addr en clk and data->out - connect_any(read_port.addr, addr); //FIXME - connect_any(read_port.en, addr.cmp_lt(4u64)); + connect_any(read_port.addr, addr); + connect_any(read_port.en, addr.cmp_lt(256u64) & en); // and not write_en connect(read_port.clk, cd.clk); connect(read_data, read_port.data); let write_port = my_memory.new_write_port(); connect_any(write_port.addr, addr); - connect_any(write_port.en, addr.cmp_lt(4u64) & write_en); + connect_any(write_port.en, addr.cmp_lt(256u64) & en & write_en); connect_any(write_port.data, write_data); connect(write_port.clk, cd.clk); - //connect_any(write_port.mask, 0xFFu8); //try that one - connect_any(write_port.mask, true); + + connect_any(write_port.mask, true); //can only write 8 bits at a time } - -// see https://git.libre-chip.org/libre-chip/fayalite/src/branch/master/crates/fayalite/tests/sim.rs -// how to write testbenches -// start with a very simple memory model -> -// TODO create a branch for the memory - -// 1 connect up the read port, add write later -// ask how I make the memory pipelined later ... not today diff --git a/crates/cpu/tests/main_memory.rs b/crates/cpu/tests/main_memory.rs index d558c79..7ac85a2 100644 --- a/crates/cpu/tests/main_memory.rs +++ b/crates/cpu/tests/main_memory.rs @@ -42,7 +42,7 @@ fn test_main_memory() { sim.write(sim.io().cd.rst, false); sim.write(sim.io().cd.clk, false); sim.write(sim.io().write_en, false); - sim.write(sim.io().write_data, 0xFFu8); + sim.write(sim.io().write_data, 0xFF00FF00FF00FF00u64); // TODO convert to for loop // you need to write an initial value to all inputs before you can start running the simulation @@ -60,16 +60,32 @@ fn test_main_memory() { sim.write(sim.io().write_en, true); sim.write(sim.io().addr, 0u64); - sim.write(sim.io().write_data, 0x11u8); + sim.write(sim.io().write_data, 0xFFFFFFFFFFFFFFFFu64); //fill with ones + + sim.write_clock(sim.io().cd.clk, true); sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 1u64); - sim.write(sim.io().write_data, 0x22u8); + + sim.write_clock(sim.io().cd.clk, true); sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 2u64); - sim.write(sim.io().write_data, 0x33u8); + + sim.write_clock(sim.io().cd.clk, true); sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write(sim.io().addr, 3u64); - sim.write(sim.io().write_data, 0x44u8); + + sim.write_clock(sim.io().cd.clk, true); + sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, false); sim.advance_time(SimDuration::from_micros(1)); sim.flush_traces().unwrap(); // make sure everything is written to the output file