URL
https://opencores.org/ocsvn/openmsp430/openmsp430/trunk
Subversion Repositories openmsp430
[/] [openmsp430/] [trunk/] [fpga/] [altera_de0_nano_soc/] [rtl/] [verilog/] [opengfx430/] [ogfx_backend_frame_fifo.v] - Rev 224
Go to most recent revision | Compare with Previous | Blame | View Log
//---------------------------------------------------------------------------- // Copyright (C) 2015 Authors // // This source file may be used and distributed without restriction provided // that this copyright statement is not removed from the file and that any // derivative work contains the original copyright notice and the associated // disclaimer. // // This source file is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This source is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this source; if not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // //---------------------------------------------------------------------------- // // *File Name: ogfx_backend_frame_fifo.v // // *Module Description: // Mini-cache memory for frame memory access. // // *Author(s): // - Olivier Girard, olgirard@gmail.com // //---------------------------------------------------------------------------- // $Rev$ // $LastChangedBy$ // $LastChangedDate$ //---------------------------------------------------------------------------- `ifdef OGFX_NO_INCLUDE `else `include "openGFX430_defines.v" `endif module ogfx_backend_frame_fifo ( // OUTPUTs frame_data_o, // Frame data frame_data_ready_o, // Frame data ready vid_ram_addr_o, // Video-RAM address vid_ram_cen_o, // Video-RAM enable (active low) // INPUTs mclk, // Main system clock puc_rst, // Main system reset display_width_i, // Display width display_height_i, // Display height display_size_i, // Display size (number of pixels) display_y_swap_i, // Display configuration: swap Y axis (horizontal symmetry) display_x_swap_i, // Display configuration: swap X axis (vertical symmetry) display_cl_swap_i, // Display configuration: swap column/lines frame_data_request_i, // Request for next frame data gfx_mode_i, // Video mode (1xx:16bpp / 011:8bpp / 010:4bpp / 001:2bpp / 000:1bpp) vid_ram_dout_i, // Video-RAM data output vid_ram_dout_rdy_nxt_i, // Video-RAM data output ready during next cycle refresh_active_i, // Display refresh on going refresh_frame_base_addr_i // Refresh frame base address ); // OUTPUTs //========= output [15:0] frame_data_o; // Frame data output frame_data_ready_o; // Frame data ready output[`VRAM_MSB:0] vid_ram_addr_o; // Video-RAM address output vid_ram_cen_o; // Video-RAM enable (active low) // INPUTs //========= input mclk; // Main system clock input puc_rst; // Main system reset input [`LPIX_MSB:0] display_width_i; // Display width input [`LPIX_MSB:0] display_height_i; // Display height input [`SPIX_MSB:0] display_size_i; // Display size (number of pixels) input display_y_swap_i; // Display configuration: swap Y axis (horizontal symmetry) input display_x_swap_i; // Display configuration: swap X axis (vertical symmetry) input display_cl_swap_i; // Display configuration: swap column/lines input frame_data_request_i; // Request for next frame data input [2:0] gfx_mode_i; // Video mode (1xx:16bpp / 011:8bpp / 010:4bpp / 001:2bpp / 000:1bpp) input [15:0] vid_ram_dout_i; // Video-RAM data output input vid_ram_dout_rdy_nxt_i; // Video-RAM data output ready during next cycle input refresh_active_i; // Display refresh on going input [`APIX_MSB:0] refresh_frame_base_addr_i; // Refresh frame base address //============================================================================= // 1) WIRE, REGISTERS AND PARAMETER DECLARATION //============================================================================= // Some parameter(s) parameter FIFO_EMPTY = 2'h0, FIFO_FULL = 2'h3; // Video modes decoding wire gfx_mode_1_bpp = (gfx_mode_i == 3'b000); wire gfx_mode_2_bpp = (gfx_mode_i == 3'b001); wire gfx_mode_4_bpp = (gfx_mode_i == 3'b010); wire gfx_mode_8_bpp = (gfx_mode_i == 3'b011); wire gfx_mode_16_bpp = ~(gfx_mode_8_bpp | gfx_mode_4_bpp | gfx_mode_2_bpp | gfx_mode_1_bpp); // Others reg [1:0] fifo_counter; wire [1:0] fifo_counter_nxt; wire fifo_data_ready; wire read_from_fifo; reg vid_ram_data_mux_ready; reg vid_ram_dout_ready; wire [15:0] vid_ram_dout_processed; //============================================================================ // 1) FRAME ADDRESS GENERATION //============================================================================ //-------------------------------- // FIFO data request //-------------------------------- // The FIFO requests for new data whenever it is not full (or not about to get full) reg fifo_data_request; wire fifo_data_request_nxt = refresh_active_i & (fifo_counter_nxt != FIFO_FULL) & // FIFO is full ~((fifo_counter_nxt == (FIFO_FULL-1)) & fifo_data_ready); // FIFO is about to be full always @(posedge mclk or posedge puc_rst) if (puc_rst) fifo_data_request <= 1'h0; else fifo_data_request <= fifo_data_request_nxt; //-------------------------------- // Video RAM Address generation //-------------------------------- reg [`APIX_MSB:0] vid_ram_pixel_addr; reg [`APIX_MSB:0] vid_ram_line_addr; reg [`LPIX_MSB:0] vid_ram_column_count; // Detect when the fifo is done reading the current pixel data wire vid_ram_pixel_done = fifo_data_request & fifo_data_ready; // Detect when the current line refresh is done wire [`LPIX_MSB:0] line_length = display_cl_swap_i ? display_height_i : display_width_i; wire vid_ram_line_done = vid_ram_pixel_done & (vid_ram_column_count==(line_length-{{`LPIX_MSB{1'b0}}, 1'b1})); // Zero extension for LINT cleanup wire [`VRAM_MSB*3:0] display_size_norm = {{`VRAM_MSB*3-`SPIX_MSB{1'b0}}, display_size_i}; wire [`VRAM_MSB*3:0] display_width_norm = {{`VRAM_MSB*3-`LPIX_MSB{1'b0}}, display_width_i}; // Based on the display configuration (i.e. X-Swap / Y-Swap / CL-Swap) // the screen is not going to be refreshed in the same way. // The screen refresh is the performed according to the following // pseudo-code procedure: // // for (l_idx=0; l_idx<HEIGHT; l_idx++) // for (c_idx=0; c_idx<WIDTH; c_idx++) // addr = FIRST + 0 + WIDTH*l_idx + c_idx // Normal // addr = FIRST + WIDTH-1 + WIDTH*l_idx - c_idx // X-Swap // addr = LAST - WIDTH+1 - WIDTH*l_idx + c_idx // Y-Swap // addr = LAST - 0 - WIDTH*l_idx - c_idx // X/Y-Swap // wire [`APIX_MSB:0] next_base_addr = ~refresh_active_i ? refresh_frame_base_addr_i : vid_ram_line_done ? vid_ram_line_addr : vid_ram_pixel_addr ; wire [`APIX_MSB:0] next_addr = next_base_addr + (display_size_norm[`APIX_MSB:0] & {`APIX_MSB+1{refresh_active_i ? 1'b0 : display_y_swap_i}}) + (display_width_norm[`APIX_MSB:0] & {`APIX_MSB+1{refresh_active_i ? (~display_y_swap_i & (display_cl_swap_i ^ vid_ram_line_done)) : display_x_swap_i}}) - (display_width_norm[`APIX_MSB:0] & {`APIX_MSB+1{refresh_active_i ? ( display_y_swap_i & (display_cl_swap_i ^ vid_ram_line_done)) : display_y_swap_i}}) + ({{`APIX_MSB{1'b0}}, 1'b1} & {`APIX_MSB+1{refresh_active_i ? (~display_x_swap_i & ~(display_cl_swap_i ^ vid_ram_line_done)) : 1'b0 }}) - ({{`APIX_MSB{1'b0}}, 1'b1} & {`APIX_MSB+1{refresh_active_i ? ( display_x_swap_i & ~(display_cl_swap_i ^ vid_ram_line_done)) : display_x_swap_i}}); wire update_line_addr = ~refresh_active_i | vid_ram_line_done; wire update_pixel_addr = update_line_addr | vid_ram_pixel_done; // Start RAM address of currentely refreshed line always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_line_addr <= {`APIX_MSB+1{1'b0}}; else if (update_line_addr) vid_ram_line_addr <= next_addr; // Current RAM address of the currentely refreshed pixel wire [`APIX_MSB:0] vid_ram_pixel_addr_nxt = update_pixel_addr ? next_addr : vid_ram_pixel_addr; always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_pixel_addr <= {`APIX_MSB+1{1'b0}}; else vid_ram_pixel_addr <= vid_ram_pixel_addr_nxt; // Count the pixel number in the current line // (used to detec the end of a line) always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_column_count <= {`LPIX_MSB+1{1'b0}}; else if (~refresh_active_i) vid_ram_column_count <= {`LPIX_MSB+1{1'b0}}; else if (vid_ram_line_done) vid_ram_column_count <= {`LPIX_MSB+1{1'b0}}; else if (vid_ram_pixel_done) vid_ram_column_count <= vid_ram_column_count + {{`LPIX_MSB{1'b0}}, 1'b1}; // Depending on the color mode, format the address for doing the RAM accesses. assign vid_ram_addr_o = ({`VRAM_MSB+1{gfx_mode_1_bpp }} & vid_ram_pixel_addr[`VRAM_MSB+4:4]) | ({`VRAM_MSB+1{gfx_mode_2_bpp }} & vid_ram_pixel_addr[`VRAM_MSB+3:3]) | ({`VRAM_MSB+1{gfx_mode_4_bpp }} & vid_ram_pixel_addr[`VRAM_MSB+2:2]) | ({`VRAM_MSB+1{gfx_mode_8_bpp }} & vid_ram_pixel_addr[`VRAM_MSB+1:1]) | ({`VRAM_MSB+1{gfx_mode_16_bpp}} & vid_ram_pixel_addr[`VRAM_MSB+0:0]) ; // Compute the next RAM address to detect when a new address is generated wire [`VRAM_MSB:0] vid_ram_addr_nxt = ({`VRAM_MSB+1{gfx_mode_1_bpp }} & vid_ram_pixel_addr_nxt[`VRAM_MSB+4:4]) | ({`VRAM_MSB+1{gfx_mode_2_bpp }} & vid_ram_pixel_addr_nxt[`VRAM_MSB+3:3]) | ({`VRAM_MSB+1{gfx_mode_4_bpp }} & vid_ram_pixel_addr_nxt[`VRAM_MSB+2:2]) | ({`VRAM_MSB+1{gfx_mode_8_bpp }} & vid_ram_pixel_addr_nxt[`VRAM_MSB+1:1]) | ({`VRAM_MSB+1{gfx_mode_16_bpp}} & vid_ram_pixel_addr_nxt[`VRAM_MSB+0:0]) ; // Detect when a new word needs to be fetched from the memory // (i.e. detect when the RAM address is updated) reg vid_ram_addr_update; wire vid_ram_addr_update_nxt = (vid_ram_addr_o != vid_ram_addr_nxt); always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_addr_update <= 1'h0; else if (~refresh_active_i) vid_ram_addr_update <= 1'h1; else if (vid_ram_pixel_done) vid_ram_addr_update <= vid_ram_addr_update_nxt; // Disable RAM access if there is no need to fetch a new word assign vid_ram_cen_o = vid_ram_addr_update ? ~fifo_data_request : 1'b1; // If the next FIFO data doesn't come from the RAM, then it is ready as // soon as it is requested assign fifo_data_ready = vid_ram_addr_update ? vid_ram_dout_rdy_nxt_i : fifo_data_request; //============================================================================ // 2) FRAME DATA-PRE-PROCESSING (PRIOR BEING PUSHED INTO FIFO) //============================================================================ //-------------------------------- // Data buffer //-------------------------------- // For the LUT modes, it is not necessary to access the RAM for // every pixel. In that case, the FIFO is filled with the values // coming from the buffer. // (i.e. we only take data directly from the RAM when it is just read) reg [15:0] vid_ram_dout_buf; always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_dout_buf <= 16'h0000; else if (vid_ram_dout_ready) vid_ram_dout_buf <= vid_ram_dout_i; wire [15:0] vid_ram_dout_mux = vid_ram_dout_ready ? vid_ram_dout_i : vid_ram_dout_buf; //-------------------------------- // Data formating //-------------------------------- // Depending on the mode, the address LSBs are used to select which bits // of the current data word need to be put in the FIFO wire [3:0] vid_ram_data_sel_nxt = ({4{gfx_mode_1_bpp}} & {vid_ram_pixel_addr[3:0] }) | ({4{gfx_mode_2_bpp}} & {vid_ram_pixel_addr[2:0], 1'b0 }) | ({4{gfx_mode_4_bpp}} & {vid_ram_pixel_addr[1:0], 2'b00 }) | ({4{gfx_mode_8_bpp}} & {vid_ram_pixel_addr[0], 3'b000 }) ; reg [3:0] vid_ram_data_sel; always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_data_sel <= 4'h0; else if (vid_ram_pixel_done) vid_ram_data_sel <= vid_ram_data_sel_nxt; wire [15:0] vid_ram_dout_shifted = (vid_ram_dout_mux >> vid_ram_data_sel); // Format data output for LUT processing // (8 bit LSBs are used to address the LUT memory, MSBs are ignored) assign vid_ram_dout_processed = ({16{gfx_mode_1_bpp }} & {8'h00, 7'b0000000, vid_ram_dout_shifted[0] }) | ({16{gfx_mode_2_bpp }} & {8'h00, 6'b000000 , vid_ram_dout_shifted[1:0]}) | ({16{gfx_mode_4_bpp }} & {8'h00, 4'b0000 , vid_ram_dout_shifted[3:0]}) | ({16{gfx_mode_8_bpp }} & {8'h00, vid_ram_dout_shifted[7:0]}) | ({16{gfx_mode_16_bpp}} & { vid_ram_dout_shifted[15:0] }) ; //-------------------------------- // Data Ready //-------------------------------- // Data is available on the bus one cycle after the rdy_nxt signals always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_data_mux_ready <= 1'b0; else vid_ram_data_mux_ready <= fifo_data_ready; always @(posedge mclk or posedge puc_rst) if (puc_rst) vid_ram_dout_ready <= 1'b0; else vid_ram_dout_ready <= vid_ram_dout_rdy_nxt_i; //============================================================================ // 3) FIFO COUNTER //============================================================================ // Declaration // Control signals wire fifo_push = vid_ram_data_mux_ready & (fifo_counter != FIFO_FULL); wire fifo_pop = read_from_fifo & (fifo_counter != FIFO_EMPTY); // Fifo counter assign fifo_counter_nxt = ~refresh_active_i ? FIFO_EMPTY : // Initialize (fifo_push & fifo_pop) ? fifo_counter : // Keep value (pop & push at the same time) fifo_push ? fifo_counter + 2'h1 : // Push fifo_pop ? fifo_counter - 2'h1 : // Pop fifo_counter; // Hold always @(posedge mclk or posedge puc_rst) if (puc_rst) fifo_counter <= FIFO_EMPTY; else fifo_counter <= fifo_counter_nxt; //============================================================================ // 4) FIFO MEMORY & RD/WR POINTERS //============================================================================ // Write pointer reg [1:0] wr_ptr; always @(posedge mclk or posedge puc_rst) if (puc_rst) wr_ptr <= 2'h0; else if (~refresh_active_i) wr_ptr <= 2'h0; else if (fifo_push) begin if (wr_ptr==(FIFO_FULL-1)) wr_ptr <= 2'h0; else wr_ptr <= wr_ptr + 2'h1; end // Memory reg [15:0] fifo_mem [0:2]; always @(posedge mclk or posedge puc_rst) if (puc_rst) begin fifo_mem[0] <= 16'h0000; fifo_mem[1] <= 16'h0000; fifo_mem[2] <= 16'h0000; end else if (fifo_push) begin fifo_mem[wr_ptr] <= vid_ram_dout_processed; end // Read pointer reg [1:0] rd_ptr; always @(posedge mclk or posedge puc_rst) if (puc_rst) rd_ptr <= 2'h0; else if (~refresh_active_i) rd_ptr <= 2'h0; else if (fifo_pop) begin if (rd_ptr==(FIFO_FULL-1)) rd_ptr <= 2'h0; else rd_ptr <= rd_ptr + 2'h1; end //============================================================================ // 5) FRAME DATA FROM FIFO //============================================================================ // RAW Data is valid reg frame_data_init; wire frame_data_init_nxt = ~refresh_active_i ? 1'h0 : fifo_pop ? 1'b1 : frame_data_init; always @(posedge mclk or posedge puc_rst) if (puc_rst) frame_data_init <= 1'h0; else frame_data_init <= frame_data_init_nxt; // RAW Data from the frame buffer reg [15:0] frame_data_o; always @(posedge mclk or posedge puc_rst) if (puc_rst) frame_data_o <= 16'h0000; else if (fifo_pop) frame_data_o <= fifo_mem[rd_ptr]; // Data is ready assign frame_data_ready_o = frame_data_init_nxt & (fifo_counter != FIFO_EMPTY); // Read from FIFO command assign read_from_fifo = ~refresh_active_i | ~frame_data_init | ((fifo_counter != FIFO_EMPTY) & frame_data_request_i); endmodule // ogfx_backend_frame_fifo `ifdef OGFX_NO_INCLUDE `else `include "openGFX430_undefines.v" `endif
Go to most recent revision | Compare with Previous | Blame | View Log