1use std::{
2 cell::UnsafeCell,
3 ffi::{c_void, CString},
4 ptr::null_mut,
5 path::Path,
6};
7
8mod ffi;
9
10#[repr(C)]
13#[derive(Clone, Copy)]
14struct RawCallbackFnMut {
15 fun: unsafe extern "C" fn(data: *mut c_void, addr: u64, is_write: bool),
16 data: *mut c_void,
17}
18
19impl RawCallbackFnMut {
20 pub const fn invalid() -> Self {
21 RawCallbackFnMut {
22 fun: Self::_invalid_fn,
23 data: null_mut(),
24 }
25 }
26
27 pub fn from_fn_mut<F: FnMut(u64, bool)>(f: &mut F) -> Self {
28 RawCallbackFnMut {
29 fun: Self::_invoke_fn_mut::<F>,
30 data: f as *mut F as *mut c_void,
31 }
32 }
33
34 unsafe extern "C" fn _invalid_fn(_data: *mut c_void, _addr: u64, _is_write: bool) {
35 unreachable!("callback is invoked outside tick");
36 }
37
38 unsafe extern "C" fn _invoke_fn_mut<F: FnMut(u64, bool)>(
39 f: *mut c_void,
40 addr: u64,
41 is_write: bool,
42 ) {
43 (*(f as *mut F))(addr, is_write)
44 }
45
46 extern "C" fn _invoke_cb(this: *mut c_void, addr: u64, is_write: bool) {
47 unsafe {
48 let this = *(this as *mut RawCallbackFnMut);
49 (this.fun)(this.data, addr, is_write);
50 }
51 }
52}
53
54#[derive(Clone, Copy, Debug)]
55pub enum MemorySystemCreationError {
56 NulInConfig,
57 NulInDir,
58}
59
60pub struct MemorySystem {
61 ffi_ptr: *mut c_void,
62
63 _cb: Box<UnsafeCell<RawCallbackFnMut>>,
66}
67
68unsafe impl Send for MemorySystem {}
70
71impl MemorySystem {
72 pub fn new(config: impl AsRef<Path>, dir: impl AsRef<Path>) -> Result<MemorySystem, MemorySystemCreationError> {
73 let config_cstr = CString::new(config.as_ref().as_os_str().as_encoded_bytes()).map_err(|_| MemorySystemCreationError::NulInConfig)?;
74 let dir_cstr = CString::new(dir.as_ref().as_os_str().as_encoded_bytes()).map_err(|_| MemorySystemCreationError::NulInDir)?;
75
76 let cb_box: Box<UnsafeCell<RawCallbackFnMut>> =
77 Box::new(UnsafeCell::new(RawCallbackFnMut::invalid()));
78 let cb_ptr: *mut RawCallbackFnMut = cb_box.get();
79
80 let handle = unsafe {
81 ffi::ds3_create(
82 cb_ptr as *mut c_void,
83 config_cstr.as_ptr(),
84 dir_cstr.as_ptr(),
85 RawCallbackFnMut::_invoke_cb,
86 )
87 };
88
89 Ok(MemorySystem {
90 ffi_ptr: handle,
91 _cb: cb_box,
92 })
93 }
94
95 pub fn tick(&mut self, mut f: impl FnMut(u64, bool)) {
96 let cb_ptr: *mut RawCallbackFnMut = self._cb.get();
97 unsafe {
99 *cb_ptr = RawCallbackFnMut::from_fn_mut(&mut f);
100 ffi::ds3_tick(self.ffi_ptr);
101
102 *cb_ptr = RawCallbackFnMut::invalid();
104 }
105 }
106
107 pub fn can_add(&self, addr: u64, is_write: bool) -> bool {
108 unsafe { ffi::ds3_can_add(self.ffi_ptr, addr, is_write) }
109 }
110
111 pub fn add(&mut self, addr: u64, is_write: bool) -> bool {
112 unsafe { ffi::ds3_add(self.ffi_ptr, addr, is_write) }
113 }
114
115 pub fn tck(&self) -> f64 {
116 unsafe { ffi::ds3_get_tck(self.ffi_ptr) }
117 }
118
119 pub fn bus_bits(&self) -> usize {
120 (unsafe { ffi::ds3_get_bus_bits(self.ffi_ptr) }) as usize
121 }
122
123 pub fn burst_length(&self) -> usize {
124 (unsafe { ffi::ds3_get_burst_length(self.ffi_ptr) }) as usize
125 }
126
127 pub fn queue_size(&self) -> usize {
128 (unsafe { ffi::ds3_get_queue_size(self.ffi_ptr) }) as usize
129 }
130}
131
132impl Drop for MemorySystem {
133 fn drop(&mut self) {
134 unsafe {
135 ffi::ds3_drop(self.ffi_ptr);
136 }
137 }
138}
139
140#[test]
141fn test() -> anyhow::Result<()> {
142 use std::cell::RefCell;
143 use std::path::PathBuf;
144 use std::rc::Rc;
145
146 let mut config = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
147 config.push("DRAMsim3/configs/HBM2_4Gb_x128.ini");
148
149 let dir = tempfile::tempdir()?;
150
151 let mut pushed = false;
152 let resolved: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));
153
154 let sys_resolved = resolved.clone();
155
156 let mut sys = MemorySystem::new(&config, &dir).unwrap();
157
158 loop {
159 sys.tick(|addr, is_write| {
160 assert_eq!(addr, 0xdeadbeef);
161 assert_eq!(is_write, false);
162 *sys_resolved.borrow_mut() = true;
163 });
164 if !pushed && sys.can_add(0xdeadbeef, false) {
165 assert!(sys.add(0xdeadbeef, false));
166 pushed = true;
167 }
168
169 {
170 if *resolved.borrow() {
171 break;
172 }
173 }
174 }
175
176 Ok(())
177}