Skip to content

Commit 5a411fd

Browse files
committed
Fix d latch simulation
1 parent 9215637 commit 5a411fd

File tree

5 files changed

+148
-21
lines changed

5 files changed

+148
-21
lines changed

src/app.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ impl App {
324324
}
325325

326326
fn is_on(&self, pin: Pin) -> bool {
327+
let pin = pin.is_passthrough(&self.db).unwrap_or(pin);
327328
let Some(v) = self.simulator.current.get(&pin) else {
328329
return false;
329330
};
@@ -448,6 +449,7 @@ impl App {
448449
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Nor));
449450
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Xor));
450451
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Xnor));
452+
self.draw_panel_button(ui, InstanceKind::Gate(GateKind::Not));
451453
self.draw_panel_button(ui, InstanceKind::Power);
452454
self.draw_panel_button(ui, InstanceKind::Lamp);
453455
self.draw_panel_button(ui, InstanceKind::Clock);
@@ -726,7 +728,7 @@ impl App {
726728
Self::draw_grid(ui, canvas_rect, self.viewport_offset);
727729

728730
let mouse_clicked_canvas = resp.clicked();
729-
let mouse_dragging_canvas = resp.dragged();
731+
let mouse_dragging_canvas = resp.dragged_by(egui::PointerButton::Primary);
730732
let double_clicked = ui.input(|i| {
731733
i.pointer
732734
.button_double_clicked(egui::PointerButton::Primary)
@@ -949,7 +951,7 @@ impl App {
949951
}
950952
}
951953

952-
fn draw_instance_graphics_new(
954+
fn draw_instance_graphics(
953955
&mut self,
954956
ui: &mut Ui,
955957
graphics: assets::InstanceGraphics,
@@ -1024,15 +1026,15 @@ impl App {
10241026
let gate = self.db.circuit.get_gate(id);
10251027
(gate.pos, gate.kind)
10261028
};
1027-
self.draw_instance_graphics_new(ui, kind.graphics(), self.adjusted_pos(pos), id);
1029+
self.draw_instance_graphics(ui, kind.graphics(), self.adjusted_pos(pos), id);
10281030
}
10291031

10301032
fn draw_power(&mut self, ui: &mut Ui, id: InstanceId) {
10311033
let (pos, graphics) = {
10321034
let power = self.db.circuit.get_power(id);
10331035
(power.pos, power.graphics())
10341036
};
1035-
self.draw_instance_graphics_new(ui, graphics, self.adjusted_pos(pos), id);
1037+
self.draw_instance_graphics(ui, graphics, self.adjusted_pos(pos), id);
10361038
}
10371039

10381040
fn draw_lamp(&mut self, ui: &mut Ui, id: InstanceId) {
@@ -1058,7 +1060,7 @@ impl App {
10581060
}
10591061
}
10601062

1061-
self.draw_instance_graphics_new(ui, graphics, pos, id);
1063+
self.draw_instance_graphics(ui, graphics, pos, id);
10621064
}
10631065

10641066
fn draw_clock(&mut self, ui: &mut Ui, id: InstanceId) {
@@ -1067,7 +1069,7 @@ impl App {
10671069
(clock.pos, clock.graphics())
10681070
};
10691071
let pos = self.adjusted_pos(pos);
1070-
self.draw_instance_graphics_new(ui, graphics, pos, id);
1072+
self.draw_instance_graphics(ui, graphics, pos, id);
10711073
}
10721074

10731075
fn draw_module(&mut self, ui: &mut Ui, id: InstanceId) {
@@ -1253,7 +1255,7 @@ impl App {
12531255
&& let Some(split_point) = self.wire_branching_action_point(mouse, id)
12541256
{
12551257
ui.painter().circle_filled(
1256-
split_point,
1258+
self.adjusted_pos(split_point),
12571259
PIN_HOVER_THRESHOLD,
12581260
COLOR_HOVER_PIN_TO_WIRE,
12591261
);
@@ -1267,7 +1269,7 @@ impl App {
12671269
&& let Some(split_point) = self.wire_branching_action_point(mouse, id)
12681270
{
12691271
ui.painter().circle_filled(
1270-
split_point,
1272+
self.adjusted_pos(split_point),
12711273
PIN_HOVER_THRESHOLD,
12721274
COLOR_HOVER_PIN_TO_WIRE,
12731275
);
@@ -1869,7 +1871,7 @@ impl App {
18691871
pos - self.viewport_offset
18701872
}
18711873

1872-
fn mouse_pos_world(&self, ui: &Ui) -> Option<Pos2> {
1874+
pub fn mouse_pos_world(&self, ui: &Ui) -> Option<Pos2> {
18731875
ui.ctx()
18741876
.pointer_interact_pos()
18751877
.map(|p| p + self.viewport_offset)

src/assets.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ pub static XNOR_GRAPHICS: InstanceGraphics = InstanceGraphics {
141141
],
142142
};
143143

144+
pub static NOT_GRAPHICS: InstanceGraphics = InstanceGraphics {
145+
svg: include_image!("../assets/not.svg"),
146+
pins: &[
147+
PinGraphics {
148+
kind: PinKind::Input,
149+
offset: Vec2::new(-40.0, 0.0),
150+
},
151+
PinGraphics {
152+
kind: PinKind::Output,
153+
offset: Vec2::new(40.0, 0.0),
154+
},
155+
],
156+
};
157+
144158
pub static POWER_ON_GRAPHICS: InstanceGraphics = InstanceGraphics {
145159
svg: include_image!("../assets/switch-on.svg"),
146160
pins: &[PinGraphics {

src/db.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use egui::{Pos2, Vec2, pos2};
66
use slotmap::{SecondaryMap, SlotMap};
77

88
use crate::assets::PinKind;
9+
use crate::connection_manager::ConnectionKind;
910
use crate::{
1011
assets::{self},
1112
config::CanvasConfig,
@@ -297,6 +298,82 @@ impl Circuit {
297298
)
298299
.ok();
299300
}
301+
302+
// Show instance members for modules with indentation
303+
if let InstanceKind::Module(_) = kind {
304+
let module = self.get_module(*id);
305+
let member_count = module.instance_members.len();
306+
for (member_idx, member_id) in module.instance_members.iter().enumerate() {
307+
let is_last_member = member_idx == member_count - 1;
308+
let member_branch = if is_last_member { "`-" } else { "|-" };
309+
let member_cont = if is_last_member {
310+
format!("{cont} ")
311+
} else {
312+
format!("{cont}| ")
313+
};
314+
315+
// Member header
316+
let member_kind = self.ty(*member_id);
317+
let member_header = self.instance_header(*member_id, member_kind, db);
318+
writeln!(out, "{cont}{member_branch} {member_header}").ok();
319+
320+
// Get pins for this member
321+
let member_pins = self.pins_of(*member_id, db);
322+
let member_pin_count = member_pins.len();
323+
324+
for (member_pin_idx, member_pin) in member_pins.iter().enumerate() {
325+
let is_last_member_pin = member_pin_idx == member_pin_count - 1;
326+
let member_pin_branch = if is_last_member_pin { "`-" } else { "|-" };
327+
328+
// Get connections for this member pin
329+
let member_connected = self.connected_pins(*member_pin);
330+
let member_kind_str = match member_pin.kind {
331+
PinKind::Input => "In",
332+
PinKind::Output => "Out",
333+
};
334+
let member_arrow = match member_pin.kind {
335+
PinKind::Input => "<-",
336+
PinKind::Output => "->",
337+
};
338+
339+
let member_conn_str = if member_connected.is_empty() {
340+
"(unconnected)".to_owned()
341+
} else {
342+
member_connected
343+
.iter()
344+
.map(|p| p.display_short(self, db))
345+
.collect::<Vec<_>>()
346+
.join(", ")
347+
};
348+
349+
// Get pin state if simulator is available
350+
let member_state_str = if let Some(sim) = simulator {
351+
if let Some(&value) = sim.current.get(member_pin) {
352+
match value {
353+
crate::simulator::Value::One => " O",
354+
crate::simulator::Value::Zero => " N",
355+
crate::simulator::Value::X => " X",
356+
}
357+
} else {
358+
""
359+
}
360+
} else {
361+
""
362+
};
363+
364+
writeln!(
365+
out,
366+
"{member_cont}{member_pin_branch} #{} ({}) {} {}{}",
367+
member_pin.index,
368+
member_kind_str,
369+
member_arrow,
370+
member_conn_str,
371+
member_state_str
372+
)
373+
.ok();
374+
}
375+
}
376+
}
300377
}
301378

302379
writeln!(out).ok();
@@ -873,6 +950,7 @@ pub enum GateKind {
873950
Nor,
874951
Xor,
875952
Xnor,
953+
Not,
876954
}
877955

878956
#[derive(serde::Deserialize, serde::Serialize, Copy, Debug, Clone)]
@@ -890,6 +968,7 @@ impl GateKind {
890968
Self::Nor => assets::NOR_GRAPHICS.clone(),
891969
Self::Xor => assets::XOR_GRAPHICS.clone(),
892970
Self::Xnor => assets::XNOR_GRAPHICS.clone(),
971+
Self::Not => assets::NOT_GRAPHICS.clone(),
893972
}
894973
}
895974
}
@@ -1110,4 +1189,17 @@ impl Pin {
11101189
pub fn new(ins: InstanceId, index: u32, kind: PinKind) -> Self {
11111190
Self { ins, index, kind }
11121191
}
1192+
1193+
pub fn is_passthrough(&self, db: &DB) -> Option<Self> {
1194+
let conns = db.circuit.connections_containing(*self);
1195+
1196+
for conn in conns {
1197+
if conn.kind != ConnectionKind::BI {
1198+
continue;
1199+
}
1200+
let connected_pin = conn.get_other_pin(*self);
1201+
return Some(connected_pin);
1202+
}
1203+
None
1204+
}
11131205
}

src/drag.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use egui::{CornerRadius, Pos2, Rect, Stroke, StrokeKind, Ui, Vec2, pos2};
44

55
use crate::app::{App, COLOR_HOVER_PIN_TO_WIRE, COLOR_SELECTION_BOX, MIN_WIRE_SIZE};
66

7+
use crate::assets::PinKind;
78
use crate::db::{InstanceId, InstanceKind, LabelId, Pin, Wire};
89

910
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, Copy)]
@@ -172,26 +173,33 @@ impl App {
172173
self.connection_manager.mark_instance_dirty(id);
173174
}
174175
}
175-
// TODO: There is an issue with non zero viewport_offset. It causes the wire to start
176-
// from wrong place and distance to calculate wrong
177176
Some(Drag::PinToWire { source_pin }) => {
178-
let start = self.adjusted_pos(source_pin.pos(&self.db, &self.canvas_config));
177+
let start = source_pin.pos(&self.db, &self.canvas_config);
179178
let end_abs = mouse;
180179
let drag_distance = start.distance(end_abs);
181180

182181
if drag_distance >= MIN_WIRE_SIZE {
183-
let wire = Wire::new(start, mouse);
182+
// Start is input so if the current pin is input we need to reverse the wire
183+
let (new_w_start, new_w_end) = if source_pin.kind == PinKind::Input {
184+
(mouse, start)
185+
} else {
186+
(start, mouse)
187+
};
188+
let wire = Wire::new(new_w_start, new_w_end);
184189
let wire_id = self.db.circuit.new_wire(wire);
185190

186191
self.drag = Some(Drag::Resize {
187192
id: wire_id,
188-
start: false,
193+
start: source_pin.kind == PinKind::Input,
189194
});
190195

191196
self.connection_manager.mark_instance_dirty(wire_id);
192197
} else {
193-
ui.painter()
194-
.line_segment([start, mouse], Stroke::new(2.0, COLOR_HOVER_PIN_TO_WIRE));
198+
// TODO: There is an issue with non zero viewport_offset.
199+
ui.painter().line_segment(
200+
[self.adjusted_pos(start), self.adjusted_pos(mouse)],
201+
Stroke::new(2.0, COLOR_HOVER_PIN_TO_WIRE),
202+
);
195203
}
196204
}
197205
Some(Drag::BranchWire {

src/simulator.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ use log;
44

55
use crate::{
66
assets::PinKind,
7-
connection_manager::ConnectionKind,
87
db::{Circuit, DB, GateKind, InstanceId, InstanceKind, Pin},
98
};
109

11-
const MAX_ITERATIONS: usize = 1000;
10+
const MAX_ITERATIONS: usize = 10;
1211
const STABILIZATION_THRESHOLD: usize = 3;
1312

1413
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, Copy, PartialEq, Eq)]
@@ -223,6 +222,16 @@ impl Simulator {
223222
return;
224223
};
225224

225+
// Not has one input so handle specially
226+
if matches!(kind, GateKind::Not) {
227+
let inp1 = gate_inp1(id);
228+
let out = Pin::new(id, 1, PinKind::Output);
229+
let a = self.get_pin_value(db, circuit, inp1);
230+
let out_val = a.not();
231+
self.current.insert(out, out_val);
232+
return;
233+
}
234+
226235
let inp1 = gate_inp1(id);
227236
let inp2 = gate_inp2(id);
228237
let out = gate_output(id);
@@ -237,6 +246,7 @@ impl Simulator {
237246
GateKind::Nor => a.or(b).not(),
238247
GateKind::Xor => a.xor(b),
239248
GateKind::Xnor => a.xnor(b),
249+
GateKind::Not => unreachable!("Handled above"),
240250
};
241251

242252
self.current.insert(out, out_val);
@@ -249,16 +259,17 @@ impl Simulator {
249259
}
250260

251261
fn get_pin_value(&self, db: &DB, circuit: &Circuit, pin: Pin) -> Value {
262+
let pin = pin.is_passthrough(db).unwrap_or(pin);
252263
let conns = circuit.connections_containing(pin);
253264

254265
let mut result = Value::Zero;
255266
for conn in conns {
256-
let other = conn.get_other_pin(pin);
257-
if other.kind != PinKind::Output && conn.kind != ConnectionKind::BI {
267+
let connected_pin = conn.get_other_pin(pin);
268+
if connected_pin.kind != PinKind::Output {
258269
continue;
259270
}
260271

261-
if let Some(&val) = self.current.get(&other) {
272+
if let Some(&val) = self.current.get(&connected_pin) {
262273
result = result.or(val);
263274
}
264275
}

0 commit comments

Comments
 (0)