diff --git a/milkymist/framebuffer/__init__.py b/milkymist/framebuffer/__init__.py index b30e1acd6..f7d8c1b71 100644 --- a/milkymist/framebuffer/__init__.py +++ b/milkymist/framebuffer/__init__.py @@ -111,12 +111,44 @@ class FIFO(Actor): self.vga_clk = Signal() self.vga_hsync_n = Signal() self.vga_vsync_n = Signal() - self.vga_r = Signal(BV(8)) - self.vga_g = Signal(BV(8)) - self.vga_b = Signal(BV(8)) + self.vga_r = Signal(BV(_bpc_dac)) + self.vga_g = Signal(BV(_bpc_dac)) + self.vga_b = Signal(BV(_bpc_dac)) def get_fragment(self): - return Fragment() # TODO + data_width = 2+3*_bpc_dac + asfifo = Instance("asfifo", + [ + ("data_out", BV(data_width)), + ("empty", BV(1)), + + ("full", BV(1)) + ], [ + ("read_en", BV(1)), + ("clk_read", self.vga_clk), + + ("data_in", BV(data_width)), + ("write_en", BV(1)), + + ("rst", BV(1)) + ], + parameters=[ + ("data_width", data_width), + ("address_width", 8) + ], + clkport="clk_write") + t = self.token("dac") + return Fragment([ + Cat(self.vga_hsync_n, self.vga_vsync_n, self.vga_r, self.vga_g, self.vga_b).eq(asfifo.outs["data_out"]), + asfifo.ins["read_en"].eq(1), + + self.endpoints["dac"].ack.eq(~asfifo.outs["full"]), + asfifo.ins["write_en"].eq(self.endpoints["dac"].stb), + asfifo.ins["data_in"].eq(Cat(~t.hsync, ~t.vsync, t.r, t.g, t.b)), + + self.busy.eq(0), + asfifo.ins["rst"].eq(0) + ], instances=[asfifo]) class Framebuffer: def __init__(self, address, asmiport): diff --git a/verilog/generic/asfifo.v b/verilog/generic/asfifo.v new file mode 100644 index 000000000..1618964b0 --- /dev/null +++ b/verilog/generic/asfifo.v @@ -0,0 +1,98 @@ +/* + * This file is based on "Asynchronous FIFO" by Alex Claros F., + * itself based on the article "Asynchronous FIFO in Virtex-II FPGAs" + * by Peter Alfke. + */ + +module asfifo #( + parameter data_width = 8, + parameter address_width = 4, + parameter fifo_depth = (1 << address_width) +) ( + /* Read port */ + output [data_width-1:0] data_out, + output reg empty, + input read_en, + input clk_read, + + /* Write port */ + input [data_width-1:0] data_in, + output reg full, + input write_en, + input clk_write, + + /* Asynchronous reset */ + input rst +); + +reg [data_width-1:0] mem[fifo_depth-1:0]; +wire [address_width-1:0] write_index, read_index; +wire equal_addresses; +wire write_en_safe, read_en_safe; +wire set_status, clear_status; +reg status; +wire preset_full, preset_empty; + +assign data_out = mem[read_index]; + +always @(posedge clk_write) begin + if(write_en & !full) + mem[write_index] <= data_in; +end + +assign write_en_safe = write_en & ~full; +assign read_en_safe = read_en & ~empty; + +asfifo_graycounter #( + .width(address_width) +) counter_write ( + .gray_count(write_index), + .ce(write_en_safe), + .rst(rst), + .clk(clk_write) +); + +asfifo_graycounter #( + .width(address_width) +) counter_read ( + .gray_count(read_index), + .ce(read_en_safe), + .rst(rst), + .clk(clk_read) +); + +assign equal_addresses = (write_index == read_index); + +assign set_status = (write_index[address_width-2] ~^ read_index[address_width-1]) & + (write_index[address_width-1] ^ read_index[address_width-2]); + +assign clear_status = ((write_index[address_width-2] ^ read_index[address_width-1]) & + (write_index[address_width-1] ~^ read_index[address_width-2])) + | rst; + +always @(posedge clear_status, posedge set_status) begin + if(clear_status) + status <= 1'b0; + else + status <= 1'b1; +end + +assign preset_full = status & equal_addresses; + +always @(posedge clk_write, posedge preset_full) begin + if(preset_full) + full <= 1'b1; + else + full <= 1'b0; +end + +assign preset_empty = ~status & equal_addresses; + +always @(posedge clk_read, posedge preset_empty) begin + if(preset_empty) + empty <= 1'b1; + else + empty <= 1'b0; +end + +endmodule diff --git a/verilog/generic/asfifo_graycounter.v b/verilog/generic/asfifo_graycounter.v new file mode 100644 index 000000000..531ca8058 --- /dev/null +++ b/verilog/generic/asfifo_graycounter.v @@ -0,0 +1,29 @@ +/* + * This file is based on "Asynchronous FIFO" by Alex Claros F., + * itself based on the article "Asynchronous FIFO in Virtex-II FPGAs" + * by Peter Alfke. + */ + +module asfifo_graycounter #( + parameter width = 2 +) ( + output reg [width-1:0] gray_count, + input ce, + input rst, + input clk +); + +reg [width-1:0] binary_count; + +always @(posedge clk, posedge rst) begin + if(rst) begin + binary_count <= {width{1'b0}} + 1; + gray_count <= {width{1'b0}}; + end else if(ce) begin + binary_count <= binary_count + 1; + gray_count <= {binary_count[width-1], + binary_count[width-2:0] ^ binary_count[width-1:1]}; + end +end + +endmodule