Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's the right way to get posedge to appear in this Verilog output? #16

Open
Boscop opened this issue Apr 3, 2023 · 3 comments
Open
Assignees
Labels
bug Something isn't working

Comments

@Boscop
Copy link

Boscop commented Apr 3, 2023

Thanks for making this crate, it seems very useful for hardware design :)

I'm trying to implement https://en.wikipedia.org/wiki/Rule_110
What's the right way to get posedge to appear in this Verilog output?

module top(clock,load,data,q);
    
    // Module arguments
    input wire  clock;
    input wire  load;
    input wire  [511:0] data;
    output reg  [511:0] q;
    
    // Update code
    always @(*) begin // It needs posedge here
        if (load) begin
            q = data;
        end
        else begin
            q = (~(q >> 32'h1) & q) | (q ^ (q << 32'h1));
        end
    end
    
endmodule // top

To match https://www.hackster.io/Mayukhmali_Das/cellular-automata-and-verilog-c2f0ec#toc-rule-110-in-verilog-3

This doesn't work:

use rust_hdl::prelude::*;

#[derive(LogicBlock, Default)]
struct Rule110 {
	pub clock: Signal<In, Clock>,
	pub load: Signal<In, Bit>,
	pub data: Signal<In, Bits<512>>,
	pub q: Signal<Out, Bits<512>>,
}

impl Logic for Rule110 {
	#[hdl_gen]
	fn update(&mut self) {
		if self.clock.pos_edge() {
			if self.load.val() {
				self.q.next = self.data.val();
			} else {
				self.q.next = (!(self.q.val() >> 1) & self.q.val()) | (self.q.val() ^ (self.q.val() << 1));
			}
		}
	}
}

fn main() {
	let mut uut = Rule110::default();
	uut.connect_all();
	std::fs::write("Rule110.v", generate_verilog(&uut)).unwrap();
}
error: Unsupported method call for hardware conversion
  --> src\main.rs:14:6
14 |         if self.clock.pos_edge() {
   |            ^^^^^^^^^^^^^^^^^^^^^

I'd appreciate a hint :)

@samitbasu
Copy link
Owner

Hi! You need a dff. The Digital Flip Flop is inferred in the Verilog code, but explicit in Rust. So something like:

#[derive(LogicBlock, Default)]
struct Rule110 {
	pub clock: Signal<In, Clock>,
	pub load: Signal<In, Bit>,
	pub data: Signal<In, Bits<512>>,
	pub q: Signal<Out, Bits<512>>,
        dff: DFF<Bits<512>>,
}

impl Logic for Rule110 {
	#[hdl_gen]
	fn update(&mut self) {
                // Clock the flip flip
                self.dff.clock.next = self.clock.val();
                // Prevent latches
                self.dff.d.next = self.dff.q.val();
                // Connect q to the output of the flip flip
                self.q.next = self.dff.q.val();
		if self.load.val() {
                        self.dff.d.next = self.data.val(); 
		} else {
			self.dff.d.next = (!(self.dff.q.val() >> 1) & self.dff.q.val()) | (self.dff.q.val() ^ (self.dff.q.val() << 1));
		}
	}
}
  • or something along those lines... LMK if that works.

@Boscop
Copy link
Author

Boscop commented Apr 4, 2023

Thanks, makes sense!
Btw, what are the exact rules to prevent latches? Just writing before reading?

Btw, I ran into another problem:

#[derive(LogicStruct, Copy, Clone, Default, PartialEq)]
struct Node {
	k: Bits<32>,
	x: Bits<32>,
	y: Bits<32>,
	z: Bits<32>,
}

#[derive(LogicStruct, Copy, Clone, Default, PartialEq)]
struct Node3 {
	a: Node,
	b: Node,
	c: Node,
}

#[derive(LogicBlock, Default)]
struct Core {
	i: Signal<In, Node3>,
	o: Signal<Out, Node3>,
}

impl Logic for Core {
	#[hdl_gen]
	fn update(&mut self) {
		self.o.next = self.i.val();
		self.o.next.a.k = self.i.val().a.k + 1;
	}
}

generates this invalid expression o$next$a$k = i$val()$a$k + 32'h1;

module top$core(i,o);
    
    // Module arguments
    input wire  [383:0] i;
    output reg  [383:0] o;
    
    // Update code
    always @(*) begin
        o = i;
        o$next$a$k = i$val()$a$k + 32'h1;
    end
    
endmodule // top$core

What is the right way to express this principle? I want some bits to propagate unchanged and some should be changed.

@samitbasu
Copy link
Owner

Yes. The latch prevention logic is to check for writes before reads (and no un-driven signals).

I guess nested LogicStructs do not work. :( That is a bug.

There is nothing wrong with what you wrote, the code generator simply fails to handle the case of nested LogicStructs.

@samitbasu samitbasu self-assigned this Apr 15, 2023
@samitbasu samitbasu added the bug Something isn't working label Apr 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

2 participants