samitbasu / rust-hdl

A framework for writing FPGA firmware using the Rust Programming Language
Other
325 stars 17 forks source link

Correct way to drive inputs? #43

Closed Necromaticon closed 4 months ago

Necromaticon commented 4 months ago

Hi there!

So I've been playing around with this tool, reading the API doc, tutorial, and unit test examples, and I couldn't find anything about how one is supposed to drive inputs.

Picture this: You design a small module which you want to drive manually, no simulation macro, no clock cycles.

#[derive(LogicBlock)]
struct logic_or{
    pub in1: Signal<In, Bit>,
    pub in2: Signal<In, Bit>, 
    pub out: Signal<Out, Bit>, 
}

impl Default for logic_or {
    fn default() -> Self {
        Self {
         in1: Default::default(),
         in2: Default::default(),
         out: Default::default(),

        }
     }
 }

 impl Logic for logic_or {
     #[hdl_gen]
     fn update(&mut self) {
          self.out.next = self.in1() ^ self.in2.val();
     }
 }

Driving this with something like:

 fn main(){
    let mut uut = logic_or::default();
    uut.in1.next = 1;
    uut.in2.next = 0;
    uut.update();
    println!("{}", uut.out.val());
}

The output in this case would be false, despite expecting true. Changing the two input signals to outputs would fix this, but would be an inelegant solution as soon as generating something into its Verilog equivalent will occur.

From RustHDL Signals I've gathered that inputs can not be driven, but I noticed that they can be accessed in the way mentioned above if wrapped inside a simulation.

Is there a way to set input values like that without having to simulate the modules completely?

Necromaticon commented 4 months ago

Figured it out and it turned out to be a pretty simple mistake: "Variables propagate one step on each update!"

This means that in that first assignment uut.in1.next = 1, the value of 1 is set as the next value for in1. So when calling update the value gets pushed into in1, but doesn't propagate through the OR gate yet. That would happen on a second update() call!