mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 09:10:10 +00:00
625 lines
19 KiB
Systemverilog
625 lines
19 KiB
Systemverilog
/* -----------------------------------------------------------------------------
|
||
* Project Name : Architectures of Processor Systems (APS) lab work
|
||
* Organization : National Research University of Electronic Technology (MIET)
|
||
* Department : Institute of Microdevices and Control Systems
|
||
* Author(s) : Alexander Kharlamov
|
||
* Email(s) : sasha_xarlamov@org.miet.ru
|
||
|
||
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
|
||
* ------------------------------------------------------------------------------
|
||
*/
|
||
module vgachargen
|
||
import vgachargen_pkg::*;
|
||
#(
|
||
parameter int unsigned CLK_FACTOR_25M = 100 / 25,
|
||
parameter CH_T_RO_INIT_FILE_NAME = "lab12_vga_ch_t_ro.mem",
|
||
parameter bit CH_T_RO_INIT_FILE_IS_BIN = 1,
|
||
parameter CH_T_RW_INIT_FILE_NAME = "lab12_vga_ch_t_rw.mem",
|
||
parameter bit CH_T_RW_INIT_FILE_IS_BIN = 1,
|
||
parameter CH_MAP_INIT_FILE_NAME = "lab12_vga_ch_map.mem",
|
||
parameter bit CH_MAP_INIT_FILE_IS_BIN = 0,
|
||
parameter COL_MAP_INIT_FILE_NAME = "lab12_vga_col_map.mem",
|
||
parameter bit COL_MAP_INIT_FILE_IS_BIN = 0
|
||
) (
|
||
input logic clk_i, // системный синхроимпульс
|
||
input logic clk100m_i, // клок с частотой 100МГц
|
||
input logic rst_i, // сигнал сброса
|
||
|
||
/*
|
||
Интерфейс записи выводимого символа
|
||
*/
|
||
input logic [ 9:0] char_map_addr_i, // адрес позиции выводимого символа
|
||
input logic char_map_we_i, // сигнал разрешения записи кода
|
||
input logic [ 3:0] char_map_be_i, // сигнал выбора байтов для записи
|
||
input logic [31:0] char_map_wdata_i, // ascii-код выводимого символа
|
||
output logic [31:0] char_map_rdata_o, // сигнал чтения кода символа
|
||
|
||
/*
|
||
Интерфейс установки цветовой схемы
|
||
*/
|
||
input logic [ 9:0] col_map_addr_i, // адрес позиции устанавливаемой схемы
|
||
input logic col_map_we_i, // сигнал разрешения записи схемы
|
||
input logic [ 3:0] col_map_be_i, // сигнал выбора байтов для записи
|
||
input logic [31:0] col_map_wdata_i, // код устанавливаемой цветовой схемы
|
||
output logic [31:0] col_map_rdata_o, // сигнал чтения кода схемы
|
||
|
||
/*
|
||
Интерфейс установки шрифта.
|
||
*/
|
||
input logic [ 9:0] char_tiff_addr_i, // адрес позиции устанавливаемого шрифта
|
||
input logic char_tiff_we_i, // сигнал разрешения записи шрифта
|
||
input logic [ 3:0] char_tiff_be_i, // сигнал выбора байтов для записи
|
||
input logic [31:0] char_tiff_wdata_i, // отображаемые пиксели в текущей позиции шрифта
|
||
output logic [31:0] char_tiff_rdata_o, // сигнал чтения пикселей шрифта
|
||
|
||
output logic [3:0] vga_r_o, // красный канал vga
|
||
output logic [3:0] vga_g_o, // зеленый канал vga
|
||
output logic [3:0] vga_b_o, // синий канал vga
|
||
output logic vga_hs_o, // линия горизонтальной синхронизации vga
|
||
output logic vga_vs_o // линия вертикальной синхронизации vga
|
||
);
|
||
|
||
logic [3:0] char_map_be_gated;
|
||
assign char_map_be_gated = char_map_be_i & {4{char_map_we_i}};
|
||
|
||
logic [3:0] col_map_be_gated;
|
||
assign col_map_be_gated = col_map_be_i & {4{col_map_we_i}};
|
||
|
||
logic arstn_i;
|
||
assign arstn_i = ~rst_i;
|
||
|
||
logic [VGA_MAX_H_WIDTH-1:0] hcount_pixels;
|
||
logic [VGA_MAX_V_WIDTH-1:0] vcount_pixels;
|
||
|
||
logic pixel_enable;
|
||
logic pixel_enable_delayed;
|
||
|
||
delay #(
|
||
.DATA_WIDTH (1),
|
||
.DELAY_BY (2)
|
||
) pixel_enable_delay (
|
||
.clk_i (clk100m_i),
|
||
.arstn_i (arstn_i),
|
||
.data_i (pixel_enable),
|
||
.data_o (pixel_enable_delayed)
|
||
);
|
||
|
||
logic vga_vs_delayed;
|
||
logic vga_vs;
|
||
|
||
delay #(
|
||
.DATA_WIDTH (1),
|
||
.DELAY_BY (2)
|
||
) vga_vs_delay (
|
||
.clk_i (clk100m_i),
|
||
.arstn_i (arstn_i),
|
||
.data_i (vga_vs),
|
||
.data_o (vga_vs_delayed)
|
||
);
|
||
|
||
logic vga_hs_delayed;
|
||
logic vga_hs;
|
||
|
||
delay #(
|
||
.DATA_WIDTH (1),
|
||
.DELAY_BY (2)
|
||
) vga_hs_delay (
|
||
.clk_i (clk100m_i),
|
||
.arstn_i (arstn_i),
|
||
.data_i (vga_hs),
|
||
.data_o (vga_hs_delayed)
|
||
);
|
||
|
||
|
||
vga_block #(
|
||
.CLK_FACTOR_25M (CLK_FACTOR_25M)
|
||
) vga_block (
|
||
.clk_i (clk100m_i),
|
||
.arstn_i (arstn_i),
|
||
.hcount_o (hcount_pixels),
|
||
.vcount_o (vcount_pixels),
|
||
.pixel_enable_o (pixel_enable),
|
||
.vga_hs_o (vga_hs),
|
||
.vga_vs_o (vga_vs)
|
||
);
|
||
|
||
logic [CH_MAP_ADDR_WIDTH-1:0] ch_map_addr_internal;
|
||
|
||
logic [BITMAP_ADDR_WIDTH-1:0] bitmap_addr;
|
||
logic [BITMAP_ADDR_WIDTH-1:0] bitmap_addr_delayed;
|
||
|
||
delay #(
|
||
.DATA_WIDTH (BITMAP_ADDR_WIDTH),
|
||
.DELAY_BY (2)
|
||
) bitmap_delay (
|
||
.clk_i (clk100m_i),
|
||
.arstn_i (arstn_i),
|
||
.data_i (bitmap_addr),
|
||
.data_o (bitmap_addr_delayed)
|
||
);
|
||
|
||
index_generator index_generator (
|
||
.vcount_i (vcount_pixels),
|
||
.hcount_i (hcount_pixels),
|
||
.ch_map_addr_o (ch_map_addr_internal),
|
||
.bitmap_addr_o (bitmap_addr)
|
||
);
|
||
|
||
|
||
logic [CH_T_ADDR_WIDTH:0] ch_t_addr_internal;
|
||
|
||
logic [3:0][7:0] ch_map_data_word;
|
||
|
||
assign ch_t_addr_internal = ch_map_data_word[ch_map_addr_internal[1:0]];
|
||
|
||
true_dual_port_rw_bram #(
|
||
.INIT_FILE_NAME (CH_MAP_INIT_FILE_NAME),
|
||
.INIT_FILE_IS_BIN (CH_MAP_INIT_FILE_IS_BIN),
|
||
.ADDR_WIDTH (10)
|
||
) ch_map (
|
||
.clka_i (clk_i),
|
||
.clkb_i (clk100m_i),
|
||
.addra_i (char_map_addr_i),
|
||
.addrb_i (ch_map_addr_internal[$left(ch_map_addr_internal):2]),
|
||
.wea_i (char_map_be_gated),
|
||
.dina_i (char_map_wdata_i),
|
||
.douta_o (char_map_rdata_o),
|
||
.doutb_o (ch_map_data_word)
|
||
);
|
||
|
||
logic [CH_T_ADDR_WIDTH-1:0] ch_t_ro_addr_internal;
|
||
assign ch_t_ro_addr_internal = ch_t_addr_internal[CH_T_ADDR_WIDTH-1:0];
|
||
logic [CH_T_DATA_WIDTH-1:0] ch_t_ro_data_internal;
|
||
|
||
single_port_ro_bram #(
|
||
.INIT_FILE_NAME (CH_T_RO_INIT_FILE_NAME),
|
||
.INIT_FILE_IS_BIN (CH_T_RO_INIT_FILE_IS_BIN),
|
||
.DATA_WIDTH (CH_T_DATA_WIDTH),
|
||
.ADDR_WIDTH (CH_T_ADDR_WIDTH)
|
||
) ch_t_ro (
|
||
.clk_i (clk100m_i),
|
||
.addr_i(ch_t_ro_addr_internal),
|
||
.dout_o(ch_t_ro_data_internal)
|
||
);
|
||
|
||
logic [CH_T_ADDR_WIDTH-1:0] ch_t_rw_addr_internal;
|
||
assign ch_t_rw_addr_internal = ch_t_ro_addr_internal;
|
||
logic [CH_T_DATA_WIDTH-1:0] ch_t_rw_data_internal;
|
||
|
||
true_dual_port_rw_bram #(
|
||
.INIT_FILE_NAME (CH_T_RW_INIT_FILE_NAME),
|
||
.INIT_FILE_IS_BIN (CH_T_RW_INIT_FILE_IS_BIN),
|
||
.NUM_COLS (1),
|
||
.COL_WIDTH (CH_T_DATA_WIDTH),
|
||
.ADDR_WIDTH (CH_T_ADDR_WIDTH)
|
||
) ch_t_rw (
|
||
.clka_i (clk_i),
|
||
.clkb_i (clk100m_i),
|
||
// .addra_i (ch_t_rw_addr_i),
|
||
.addra_i (),
|
||
.addrb_i (ch_t_rw_addr_internal),
|
||
// .wea_i (ch_t_rw_wen_i),
|
||
.wea_i (),
|
||
// .dina_i (ch_t_rw_data_i),
|
||
.dina_i (),
|
||
// .douta_o (ch_t_rw_data_o),
|
||
.douta_o (),
|
||
.doutb_o (ch_t_rw_data_internal)
|
||
);
|
||
|
||
logic [CH_T_DATA_WIDTH-1:0] ch_t_data_internal;
|
||
assign ch_t_data_internal = ch_t_addr_internal[CH_T_ADDR_WIDTH] ? ch_t_rw_data_internal
|
||
: ch_t_ro_data_internal;
|
||
|
||
logic [7:0] col_map_data_internal;
|
||
logic [7:0] col_map_data_internal_delayed;
|
||
|
||
logic [3:0][7:0] col_map_data_internal_word;
|
||
|
||
assign col_map_data_internal = col_map_data_internal_word[ch_map_addr_internal[1:0]];
|
||
|
||
delay #(
|
||
.DATA_WIDTH (8),
|
||
.DELAY_BY (1)
|
||
) col_map_data_delay (
|
||
.clk_i (clk100m_i),
|
||
.arstn_i (arstn_i),
|
||
.data_i (col_map_data_internal),
|
||
.data_o (col_map_data_internal_delayed)
|
||
);
|
||
|
||
logic [3:0] fg_col_map_data;
|
||
logic [3:0] bg_col_map_data;
|
||
|
||
assign fg_col_map_data = col_map_data_internal_delayed[7:4];
|
||
assign bg_col_map_data = col_map_data_internal_delayed[3:0];
|
||
|
||
true_dual_port_rw_bram #(
|
||
.INIT_FILE_NAME (COL_MAP_INIT_FILE_NAME),
|
||
.INIT_FILE_IS_BIN (COL_MAP_INIT_FILE_IS_BIN),
|
||
.ADDR_WIDTH (10)
|
||
) col_map (
|
||
.clka_i (clk_i),
|
||
.clkb_i (clk100m_i),
|
||
.addra_i (col_map_addr_i),
|
||
.addrb_i (ch_map_addr_internal[$left(ch_map_addr_internal):2]),
|
||
.wea_i (col_map_be_gated),
|
||
.dina_i (col_map_wdata_i),
|
||
.douta_o (col_map_rdata_o),
|
||
.doutb_o (col_map_data_internal_word)
|
||
);
|
||
|
||
logic currentPixel;
|
||
assign currentPixel = ch_t_data_internal[bitmap_addr_delayed];
|
||
|
||
logic [11:0] fg_color;
|
||
assign fg_color = color_decode(fg_col_map_data);
|
||
|
||
logic [11:0] bg_color;
|
||
assign bg_color = color_decode(bg_col_map_data);
|
||
|
||
// register outputs
|
||
logic [3:0] vga_r_ff;
|
||
logic [3:0] vga_r_next;
|
||
logic [3:0] vga_g_ff;
|
||
logic [3:0] vga_g_next;
|
||
logic [3:0] vga_b_ff;
|
||
logic [3:0] vga_b_next;
|
||
logic vga_vs_ff;
|
||
logic vga_vs_next;
|
||
logic vga_hs_ff;
|
||
logic vga_hs_next;
|
||
|
||
assign vga_r_next = pixel_enable_delayed ? (currentPixel ? fg_color[11:8]: bg_color[11:8]) : '0;
|
||
assign vga_g_next = pixel_enable_delayed ? (currentPixel ? fg_color[7:4] : bg_color[7:4]) : '0;
|
||
assign vga_b_next = pixel_enable_delayed ? (currentPixel ? fg_color[3:0] : bg_color[3:0]) : '0;
|
||
|
||
assign vga_vs_next = vga_vs_delayed;
|
||
assign vga_hs_next = vga_hs_delayed;
|
||
|
||
always_ff @(posedge clk100m_i or negedge arstn_i) begin
|
||
if (!arstn_i) begin
|
||
vga_r_ff <= '0;
|
||
vga_g_ff <= '0;
|
||
vga_b_ff <= '0;
|
||
vga_hs_ff <= '0;
|
||
vga_vs_ff <= '0;
|
||
end else begin
|
||
vga_r_ff <= vga_r_next;
|
||
vga_g_ff <= vga_g_next;
|
||
vga_b_ff <= vga_b_next;
|
||
vga_hs_ff <= vga_hs_next;
|
||
vga_vs_ff <= vga_vs_next;
|
||
end
|
||
end
|
||
|
||
assign vga_r_o = vga_r_ff;
|
||
assign vga_g_o = vga_g_ff;
|
||
assign vga_b_o = vga_b_ff;
|
||
|
||
assign vga_hs_o = vga_hs_ff;
|
||
assign vga_vs_o = vga_vs_ff;
|
||
|
||
endmodule
|
||
|
||
module clk_divider # (
|
||
parameter int unsigned DIVISOR = 2
|
||
) (
|
||
input logic clk_i,
|
||
input logic arstn_i,
|
||
output logic strb_o
|
||
);
|
||
localparam int unsigned COUNTER_WIDTH = (DIVISOR > 1) ? $clog2(DIVISOR) : 1;
|
||
|
||
logic [COUNTER_WIDTH-1:0] counter_next;
|
||
logic [COUNTER_WIDTH-1:0] counter_ff;
|
||
|
||
assign counter_next = ~|counter_ff ? COUNTER_WIDTH'(DIVISOR - 1) : (counter_ff - COUNTER_WIDTH'(1));
|
||
|
||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||
if (~arstn_i) counter_ff <= '0;
|
||
else counter_ff <= counter_next;
|
||
end
|
||
|
||
logic strb_ff;
|
||
logic strb_next;
|
||
|
||
assign strb_next = ~|counter_ff;
|
||
|
||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||
if (~arstn_i) strb_ff <= '0;
|
||
else strb_ff <= strb_next;
|
||
end
|
||
|
||
assign strb_o = strb_ff;
|
||
|
||
endmodule
|
||
|
||
module delay #(
|
||
parameter int unsigned DATA_WIDTH = 8,
|
||
parameter int unsigned DELAY_BY = 2
|
||
) (
|
||
input logic clk_i,
|
||
input logic arstn_i,
|
||
input logic [DATA_WIDTH-1:0] data_i,
|
||
output logic [DATA_WIDTH-1:0] data_o
|
||
);
|
||
logic [DELAY_BY-1:0][DATA_WIDTH-1:0] data_ff ;
|
||
logic [DELAY_BY-1:0][DATA_WIDTH-1:0] data_next;
|
||
|
||
if (DELAY_BY == 1) begin
|
||
assign data_next = data_i;
|
||
assign data_o = data_ff;
|
||
end else begin
|
||
assign data_next = {data_ff[DELAY_BY-2:0], data_i};
|
||
assign data_o = data_ff[DELAY_BY-1];
|
||
end
|
||
|
||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||
if (!arstn_i) data_ff <= '0;
|
||
else data_ff <= data_next;
|
||
end
|
||
endmodule
|
||
|
||
module index_generator
|
||
import vgachargen_pkg::*;
|
||
(
|
||
input logic [VGA_MAX_V_WIDTH -1:0] vcount_i,
|
||
input logic [VGA_MAX_H_WIDTH -1:0] hcount_i,
|
||
|
||
output logic [CH_MAP_ADDR_WIDTH-1:0] ch_map_addr_o,
|
||
output logic [BITMAP_ADDR_WIDTH-1:0] bitmap_addr_o
|
||
);
|
||
|
||
logic [CH_H_WIDTH-1:0] haddr_chars;
|
||
logic [CH_V_WIDTH-1:0] vaddr_chars;
|
||
|
||
assign haddr_chars = CH_H_WIDTH'(hcount_i >> BITMAP_H_WIDTH);
|
||
assign vaddr_chars = CH_V_WIDTH'(vcount_i >> BITMAP_V_WIDTH);
|
||
|
||
`define _MULT_BY_80(_x) ((_x << 6) + (_x << 4))
|
||
assign ch_map_addr_o = `_MULT_BY_80(vaddr_chars) + haddr_chars;
|
||
`undef _MULT_BY_80
|
||
|
||
logic [BITMAP_H_WIDTH-1:0] haddr_pixels;
|
||
logic [BITMAP_V_WIDTH-1:0] vaddr_pixels;
|
||
|
||
assign haddr_pixels = hcount_i[BITMAP_H_WIDTH-1:0];
|
||
assign vaddr_pixels = vcount_i[BITMAP_V_WIDTH-1:0];
|
||
|
||
`define _MULT_BY_8(_x) (_x << 3)
|
||
assign bitmap_addr_o = `_MULT_BY_8(vaddr_pixels) + haddr_pixels;
|
||
`undef _MULT_BY_8
|
||
|
||
|
||
endmodule
|
||
|
||
module single_port_ro_bram #(
|
||
parameter INIT_FILE_NAME = "",
|
||
parameter INIT_FILE_IS_BIN = 0,
|
||
parameter int unsigned DATA_WIDTH = 2,
|
||
parameter int unsigned ADDR_WIDTH = 4,
|
||
localparam int unsigned DEPTH_WORDS = 2 ** ADDR_WIDTH
|
||
) (
|
||
input logic clk_i,
|
||
input logic [ADDR_WIDTH-1:0] addr_i,
|
||
output logic [DATA_WIDTH-1:0] dout_o
|
||
);
|
||
logic [DATA_WIDTH-1:0] mem[DEPTH_WORDS];
|
||
|
||
if (INIT_FILE_IS_BIN) initial $readmemb(INIT_FILE_NAME, mem, 0, DEPTH_WORDS-1);
|
||
else initial $readmemh(INIT_FILE_NAME, mem, 0, DEPTH_WORDS-1);
|
||
|
||
always_ff @(posedge clk_i) begin
|
||
dout_o <= mem[addr_i];
|
||
end
|
||
|
||
endmodule
|
||
|
||
module timing_generator
|
||
import vgachargen_pkg::*;
|
||
(
|
||
input logic clk_i,
|
||
input logic arstn_i,
|
||
input logic en_i,
|
||
|
||
output logic vga_hs_o,
|
||
output logic vga_vs_o,
|
||
|
||
// Display timing counters
|
||
output logic [VGA_MAX_H_WIDTH-1:0] hcount_o,
|
||
output logic [VGA_MAX_V_WIDTH-1:0] vcount_o,
|
||
output logic pixel_enable_o
|
||
|
||
);
|
||
|
||
logic [VGA_MAX_H_WIDTH-1:0] hcount_ff;
|
||
logic hcount_en;
|
||
logic [VGA_MAX_H_WIDTH-1:0] hcount_next;
|
||
|
||
logic [VGA_MAX_V_WIDTH-1:0] vcount_ff;
|
||
logic vcount_en;
|
||
logic [VGA_MAX_V_WIDTH-1:0] vcount_next;
|
||
|
||
// Horizontal counter
|
||
assign hcount_next = ( hcount_ff < ( HTOTAL - 1 ) ) ? ( hcount_ff + 1 ) : ( '0 );
|
||
always_ff @ ( posedge clk_i or negedge arstn_i )
|
||
if ( ~arstn_i ) hcount_ff <= '0;
|
||
else if (en_i) hcount_ff <= hcount_next;
|
||
|
||
// Vertical counter
|
||
assign vcount_en = ( hcount_ff == ( HTOTAL - 1 ) ) & en_i;
|
||
assign vcount_next = ( vcount_ff < ( VTOTAL - 1 ) ) ? ( vcount_ff + 1 ) : ( '0 );
|
||
always_ff @( posedge clk_i or negedge arstn_i )
|
||
if ( ~arstn_i ) vcount_ff <= '0;
|
||
else if ( vcount_en ) vcount_ff <= vcount_next;
|
||
|
||
enum {
|
||
DISPLAY_S,
|
||
FRONT_S,
|
||
SYNC_S,
|
||
BACK_S
|
||
} hstate_ff, hstate_next,
|
||
vstate_ff, vstate_next;
|
||
|
||
always_ff @( posedge clk_i or negedge arstn_i )
|
||
if( ~arstn_i ) begin
|
||
hstate_ff <= DISPLAY_S;
|
||
vstate_ff <= DISPLAY_S;
|
||
end else if (en_i) begin
|
||
hstate_ff <= hstate_next;
|
||
vstate_ff <= vstate_next;
|
||
end
|
||
|
||
always_comb begin
|
||
hstate_next = hstate_ff;
|
||
unique case( hstate_ff)
|
||
DISPLAY_S: if( hcount_ff == HD - 1 ) hstate_next = FRONT_S;
|
||
|
||
FRONT_S: if( hcount_ff == HD + HF - 1 ) hstate_next = SYNC_S;
|
||
|
||
SYNC_S: if( hcount_ff == HD + HF + HR - 1 ) hstate_next = BACK_S;
|
||
|
||
BACK_S: if( hcount_ff == HTOTAL - 1 ) hstate_next = DISPLAY_S;
|
||
|
||
default: hstate_next = DISPLAY_S;
|
||
endcase
|
||
end
|
||
|
||
always_comb begin
|
||
vstate_next = vstate_ff;
|
||
if( vcount_en ) begin
|
||
unique case( vstate_ff)
|
||
DISPLAY_S: if( vcount_ff == VD - 1 ) vstate_next = FRONT_S;
|
||
|
||
FRONT_S: if( vcount_ff == VD + VF - 1 ) vstate_next = SYNC_S;
|
||
|
||
SYNC_S: if( vcount_ff == VD + VF + VR - 1 ) vstate_next = BACK_S;
|
||
|
||
BACK_S: if( vcount_ff == VTOTAL - 1 ) vstate_next = DISPLAY_S;
|
||
|
||
default: vstate_next = DISPLAY_S;
|
||
endcase
|
||
end
|
||
end
|
||
|
||
logic vga_vs_ff;
|
||
logic vga_vs_next;
|
||
|
||
assign vga_vs_next = vstate_next inside {DISPLAY_S, FRONT_S, BACK_S};
|
||
|
||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||
if (!arstn_i) vga_vs_ff <= 1'b1;
|
||
else if (en_i) vga_vs_ff <= vga_vs_next;
|
||
end
|
||
|
||
logic vga_hs_ff;
|
||
logic vga_hs_next;
|
||
|
||
assign vga_hs_next = hstate_next inside {DISPLAY_S, FRONT_S, BACK_S};
|
||
|
||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||
if (!arstn_i) vga_hs_ff <= 1'b1;
|
||
else if (en_i) vga_hs_ff <= vga_hs_next;
|
||
end
|
||
|
||
logic pixel_enable_ff;
|
||
logic pixel_enable_next;
|
||
|
||
assign pixel_enable_next = ( vstate_next == DISPLAY_S ) && ( hstate_next == DISPLAY_S );
|
||
|
||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||
if (!arstn_i) pixel_enable_ff <= 1'b0;
|
||
else if (en_i) pixel_enable_ff <= pixel_enable_next;
|
||
end
|
||
|
||
assign vga_hs_o = vga_hs_ff;
|
||
assign vga_vs_o = vga_vs_ff;
|
||
|
||
assign pixel_enable_o = pixel_enable_ff;
|
||
|
||
assign hcount_o = hcount_ff;
|
||
assign vcount_o = vcount_ff;
|
||
endmodule
|
||
|
||
module true_dual_port_rw_bram #(
|
||
parameter INIT_FILE_NAME = "",
|
||
parameter INIT_FILE_IS_BIN = 0,
|
||
parameter int unsigned COL_WIDTH = 8,
|
||
parameter int unsigned NUM_COLS = 4,
|
||
parameter int unsigned ADDR_WIDTH = 4,
|
||
localparam int unsigned DATA_WIDTH = NUM_COLS * COL_WIDTH,
|
||
localparam int unsigned DEPTH_WORDS = 2 ** ADDR_WIDTH
|
||
) (
|
||
input logic clka_i,
|
||
input logic clkb_i,
|
||
input logic [ADDR_WIDTH-1:0] addra_i,
|
||
input logic [ADDR_WIDTH-1:0] addrb_i,
|
||
input logic [NUM_COLS -1:0] wea_i,
|
||
input logic [DATA_WIDTH-1:0] dina_i,
|
||
output logic [DATA_WIDTH-1:0] douta_o,
|
||
output logic [DATA_WIDTH-1:0] doutb_o
|
||
);
|
||
logic [DATA_WIDTH-1:0] mem[DEPTH_WORDS];
|
||
|
||
if (INIT_FILE_NAME != "") begin : use_init_file
|
||
if (INIT_FILE_IS_BIN) initial $readmemb(INIT_FILE_NAME, mem, 0, DEPTH_WORDS-1);
|
||
else initial $readmemh(INIT_FILE_NAME, mem, 0, DEPTH_WORDS-1);
|
||
end else begin : init_bram_to_zero
|
||
initial begin
|
||
for (int unsigned i = 0; i < DEPTH_WORDS; ++i) mem[i] = '0;
|
||
end
|
||
end
|
||
|
||
always_ff @(posedge clka_i) begin
|
||
for (int i = 0; i < NUM_COLS; ++i) begin
|
||
if (wea_i[i]) mem[addra_i][i*COL_WIDTH+:COL_WIDTH] <= dina_i[i*COL_WIDTH+:COL_WIDTH];
|
||
end
|
||
end
|
||
|
||
always_ff @(posedge clka_i) begin
|
||
douta_o <= mem[addra_i];
|
||
end
|
||
|
||
always_ff @(posedge clkb_i) begin
|
||
doutb_o <= mem[addrb_i];
|
||
end
|
||
|
||
endmodule
|
||
|
||
module vga_block
|
||
import vgachargen_pkg::*;
|
||
#(
|
||
parameter int unsigned CLK_FACTOR_25M = 4
|
||
) (
|
||
input logic clk_i,
|
||
input logic arstn_i,
|
||
output logic [VGA_MAX_H_WIDTH-1:0] hcount_o,
|
||
output logic [VGA_MAX_V_WIDTH-1:0] vcount_o,
|
||
output logic pixel_enable_o,
|
||
output logic vga_hs_o,
|
||
output logic vga_vs_o
|
||
);
|
||
logic clk_divider_strb;
|
||
|
||
clk_divider # (
|
||
.DIVISOR (CLK_FACTOR_25M)
|
||
) clk_divider (
|
||
.clk_i,
|
||
.arstn_i,
|
||
.strb_o (clk_divider_strb)
|
||
);
|
||
|
||
timing_generator timing_generator (
|
||
.clk_i,
|
||
.arstn_i,
|
||
.en_i (clk_divider_strb),
|
||
.vga_hs_o,
|
||
.vga_vs_o,
|
||
.hcount_o,
|
||
.vcount_o,
|
||
.pixel_enable_o
|
||
|
||
);
|
||
endmodule
|