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):
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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