mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 17:20:10 +00:00
BREAKING CHANGE! Сдвиг нумерации в лабах
Лабу по дейзи-цепочке необходимо вставить сразу после лабы по интеграции контроллера прерываний, поэтому приходится увеличить нумерацию оставшихся лаб.
This commit is contained in:
100
Labs/13. Peripheral units/peripheral modules/PS2Receiver.sv
Normal file
100
Labs/13. Peripheral units/peripheral modules/PS2Receiver.sv
Normal file
@@ -0,0 +1,100 @@
|
||||
module PS2Receiver(
|
||||
input logic clk_i,
|
||||
input logic rst_i,
|
||||
input logic kclk_i,
|
||||
input logic kdata_i,
|
||||
output logic [7:0] keycodeout_o,
|
||||
output keycode_valid_o
|
||||
);
|
||||
|
||||
logic flag;
|
||||
logic [3:0] flag_shift;
|
||||
logic kclkf, kdataf;
|
||||
logic [3:0] cnt;
|
||||
|
||||
assign keycode_valid_o = flag_shift[0] && !flag_shift[2];
|
||||
|
||||
debouncer debounce(
|
||||
.clk(clk_i),
|
||||
.I0(kclk_i),
|
||||
.I1(kdata_i),
|
||||
.O0(kclkf),
|
||||
.O1(kdataf)
|
||||
);
|
||||
always@(posedge clk_i) begin
|
||||
if(rst_i) begin
|
||||
flag_shift <= '0;
|
||||
end
|
||||
else begin
|
||||
flag_shift <= {flag_shift[2:0], flag};
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge kclkf or posedge rst_i)begin
|
||||
if(rst_i) begin
|
||||
cnt <= '0;
|
||||
end
|
||||
else if (cnt <= 9) begin
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
else begin
|
||||
cnt <= '0;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge kclkf or posedge rst_i) begin
|
||||
if(rst_i) begin
|
||||
keycodeout_o <= '0;
|
||||
end
|
||||
else begin
|
||||
case(cnt)
|
||||
1:keycodeout_o[0]<=kdataf;
|
||||
2:keycodeout_o[1]<=kdataf;
|
||||
3:keycodeout_o[2]<=kdataf;
|
||||
4:keycodeout_o[3]<=kdataf;
|
||||
5:keycodeout_o[4]<=kdataf;
|
||||
6:keycodeout_o[5]<=kdataf;
|
||||
7:keycodeout_o[6]<=kdataf;
|
||||
8:keycodeout_o[7]<=kdataf;
|
||||
default: keycodeout_o <= keycodeout_o;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign flag = cnt == 9;
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module debouncer(
|
||||
input logic clk,
|
||||
input logic I0,
|
||||
input logic I1,
|
||||
output logic O0,
|
||||
output logic O1
|
||||
);
|
||||
|
||||
logic [4:0]cnt0, cnt1;
|
||||
logic Iv0=0,Iv1=0;
|
||||
logic out0, out1;
|
||||
|
||||
always_ff @(posedge(clk))begin
|
||||
if (I0==Iv0) begin
|
||||
if (cnt0==19)O0<=I0;
|
||||
else cnt0<=cnt0+1;
|
||||
end
|
||||
else begin
|
||||
cnt0<=5'd0;
|
||||
Iv0<=I0;
|
||||
end
|
||||
if (I1==Iv1)begin
|
||||
if (cnt1==19)O1<=I1;
|
||||
else cnt1<=cnt1+1;
|
||||
end
|
||||
else begin
|
||||
cnt1<=5'd0;
|
||||
Iv1<=I1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
92
Labs/13. Peripheral units/peripheral modules/hex_digits.sv
Normal file
92
Labs/13. Peripheral units/peripheral modules/hex_digits.sv
Normal file
@@ -0,0 +1,92 @@
|
||||
module hex_digits(
|
||||
input logic clk_i,
|
||||
input logic rst_i,
|
||||
input logic [3:0] hex0_i, // Цифра, выводимой на нулевой (самый правый) индикатор
|
||||
input logic [3:0] hex1_i, // Цифра, выводимая на первый индикатор
|
||||
input logic [3:0] hex2_i, // Цифра, выводимая на второй индикатор
|
||||
input logic [3:0] hex3_i, // Цифра, выводимая на третий индикатор
|
||||
input logic [3:0] hex4_i, // Цифра, выводимая на четвертый индикатор
|
||||
input logic [3:0] hex5_i, // Цифра, выводимая на пятый индикатор
|
||||
input logic [3:0] hex6_i, // Цифра, выводимая на шестой индикатор
|
||||
input logic [3:0] hex7_i, // Цифра, выводимая на седьмой индикатор
|
||||
input logic [7:0] bitmask_i, // Битовая маска для включения/отключения
|
||||
// отдельных индикаторов
|
||||
|
||||
output logic [6:0] hex_led_o, // Сигнал, контролирующий каждый отдельный
|
||||
// светодиод индикатора
|
||||
output logic [7:0] hex_sel_o // Сигнал, указывающий на какой индикатор
|
||||
// выставляется hex_led
|
||||
);
|
||||
|
||||
logic [4:0] hex0, hex1, hex2, hex3, hex4, hex5, hex6, hex7;
|
||||
assign hex0 = {bitmask_i[0], hex0_i};
|
||||
assign hex1 = {bitmask_i[1], hex1_i};
|
||||
assign hex2 = {bitmask_i[2], hex2_i};
|
||||
assign hex3 = {bitmask_i[3], hex3_i};
|
||||
assign hex4 = {bitmask_i[4], hex4_i};
|
||||
assign hex5 = {bitmask_i[5], hex5_i};
|
||||
assign hex6 = {bitmask_i[6], hex6_i};
|
||||
assign hex7 = {bitmask_i[7], hex7_i};
|
||||
|
||||
localparam pwm = 32'd1000; //шим сегментов
|
||||
|
||||
logic [9:0] counter;
|
||||
logic [4:0] semseg;
|
||||
logic [7:0] ANreg;
|
||||
logic [6:0] hex_ledr;
|
||||
|
||||
assign hex_sel_o = ANreg;
|
||||
assign hex_led_o = hex_ledr;
|
||||
|
||||
always_ff @(posedge clk_i) begin
|
||||
if (rst_i) begin
|
||||
counter <= 'b0;
|
||||
ANreg[7:0] <= 8'b11111111;
|
||||
hex_ledr <= 7'b1111111;
|
||||
end
|
||||
else begin
|
||||
if (counter < pwm) counter <= counter + 'b1;
|
||||
else begin
|
||||
counter <= 'b0;
|
||||
ANreg[1] <= ANreg[0];
|
||||
ANreg[2] <= ANreg[1];
|
||||
ANreg[3] <= ANreg[2];
|
||||
ANreg[4] <= ANreg[3];
|
||||
ANreg[5] <= ANreg[4];
|
||||
ANreg[6] <= ANreg[5];
|
||||
ANreg[7] <= ANreg[6];
|
||||
ANreg[0] <= !(ANreg[6:0] == 7'b1111111);
|
||||
end
|
||||
case (1'b0)
|
||||
ANreg[0]: semseg <= hex0;
|
||||
ANreg[1]: semseg <= hex1;
|
||||
ANreg[2]: semseg <= hex2;
|
||||
ANreg[3]: semseg <= hex3;
|
||||
ANreg[4]: semseg <= hex4;
|
||||
ANreg[5]: semseg <= hex5;
|
||||
ANreg[6]: semseg <= hex6;
|
||||
ANreg[7]: semseg <= hex7;
|
||||
endcase
|
||||
case (semseg)
|
||||
5'h10: hex_ledr <= 7'b0000001;
|
||||
5'h11: hex_ledr <= 7'b1001111;
|
||||
5'h12: hex_ledr <= 7'b0010010;
|
||||
5'h13: hex_ledr <= 7'b0000110;
|
||||
5'h14: hex_ledr <= 7'b1001100;
|
||||
5'h15: hex_ledr <= 7'b0100100;
|
||||
5'h16: hex_ledr <= 7'b0100000;
|
||||
5'h17: hex_ledr <= 7'b0001111;
|
||||
5'h18: hex_ledr <= 7'b0000000;
|
||||
5'h19: hex_ledr <= 7'b0000100;
|
||||
5'h1A: hex_ledr <= 7'b0001000;
|
||||
5'h1B: hex_ledr <= 7'b1100000;
|
||||
5'h1C: hex_ledr <= 7'b0110001;
|
||||
5'h1D: hex_ledr <= 7'b1000010;
|
||||
5'h1E: hex_ledr <= 7'b0110000;
|
||||
5'h1F: hex_ledr <= 7'b0111000;
|
||||
default: hex_ledr <= 7'b1111111;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
279
Labs/13. Peripheral units/peripheral modules/uart_rx.sv
Normal file
279
Labs/13. Peripheral units/peripheral modules/uart_rx.sv
Normal file
@@ -0,0 +1,279 @@
|
||||
// Copyright 2017 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the “License”); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
module uart_rx (
|
||||
input logic clk_i,
|
||||
input logic rst_i,
|
||||
input logic rx_i,
|
||||
output logic busy_o,
|
||||
input logic [16:0] baudrate_i,
|
||||
input logic parity_en_i,
|
||||
input logic stopbit_i,
|
||||
output logic [7:0] rx_data_o,
|
||||
output logic rx_valid_o
|
||||
//, input logic cfg_en_i,
|
||||
// input logic [1:0] cfg_bits_i,
|
||||
// output logic err_o,
|
||||
// input logic err_clr_i,
|
||||
// input logic rx_ready_i
|
||||
);
|
||||
|
||||
logic rx_ready_i;
|
||||
logic cfg_en_i;
|
||||
logic [1:0] cfg_bits_i;
|
||||
logic rstn_i;
|
||||
logic [15:0] cfg_div_i;
|
||||
always_comb begin
|
||||
case(baudrate_i)
|
||||
17'd9600 : cfg_div_i = 15'd1041;
|
||||
17'd19200 : cfg_div_i = 15'd520;
|
||||
17'd38400 : cfg_div_i = 15'd259;
|
||||
17'd57600 : cfg_div_i = 15'd173;
|
||||
17'd115200: cfg_div_i = 15'd86;
|
||||
default : cfg_div_i = 15'd1041;
|
||||
endcase
|
||||
end
|
||||
assign rstn_i = !rst_i;
|
||||
assign rx_ready_i = 1'b1;
|
||||
assign cfg_en_i = 1'b1;
|
||||
assign cfg_bits_i = 2'd3;
|
||||
enum logic [2:0] {IDLE,START_BIT,DATA,SAVE_DATA,PARITY,STOP_BIT} CS, NS;
|
||||
|
||||
logic [7:0] reg_data;
|
||||
logic [7:0] reg_data_next;
|
||||
|
||||
logic [2:0] reg_rx_sync;
|
||||
|
||||
|
||||
logic [2:0] reg_bit_count;
|
||||
logic [2:0] reg_bit_count_next;
|
||||
|
||||
logic [2:0] s_target_bits;
|
||||
|
||||
logic parity_bit;
|
||||
logic parity_bit_next;
|
||||
|
||||
logic sampleData;
|
||||
|
||||
logic [15:0] baud_cnt;
|
||||
logic baudgen_en;
|
||||
logic bit_done;
|
||||
|
||||
logic start_bit;
|
||||
logic set_error;
|
||||
logic s_rx_fall;
|
||||
|
||||
|
||||
assign busy_o = (CS != IDLE);
|
||||
|
||||
always_comb
|
||||
begin
|
||||
case(cfg_bits_i)
|
||||
2'b00:
|
||||
s_target_bits = 3'h4;
|
||||
2'b01:
|
||||
s_target_bits = 3'h5;
|
||||
2'b10:
|
||||
s_target_bits = 3'h6;
|
||||
2'b11:
|
||||
s_target_bits = 3'h7;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb
|
||||
begin
|
||||
NS = CS;
|
||||
sampleData = 1'b0;
|
||||
reg_bit_count_next = reg_bit_count;
|
||||
reg_data_next = reg_data;
|
||||
rx_valid_o = 1'b0;
|
||||
baudgen_en = 1'b0;
|
||||
start_bit = 1'b0;
|
||||
parity_bit_next = parity_bit;
|
||||
set_error = 1'b0;
|
||||
|
||||
case(CS)
|
||||
IDLE:
|
||||
begin
|
||||
if (s_rx_fall)
|
||||
begin
|
||||
NS = START_BIT;
|
||||
baudgen_en = 1'b1;
|
||||
start_bit = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
START_BIT:
|
||||
begin
|
||||
parity_bit_next = 1'b0;
|
||||
baudgen_en = 1'b1;
|
||||
start_bit = 1'b1;
|
||||
if (bit_done)
|
||||
NS = DATA;
|
||||
end
|
||||
|
||||
DATA:
|
||||
begin
|
||||
baudgen_en = 1'b1;
|
||||
parity_bit_next = parity_bit ^ reg_rx_sync[2];
|
||||
case(cfg_bits_i)
|
||||
2'b00:
|
||||
reg_data_next = {3'b000,reg_rx_sync[2],reg_data[4:1]};
|
||||
2'b01:
|
||||
reg_data_next = {2'b00,reg_rx_sync[2],reg_data[5:1]};
|
||||
2'b10:
|
||||
reg_data_next = {1'b0,reg_rx_sync[2],reg_data[6:1]};
|
||||
2'b11:
|
||||
reg_data_next = {reg_rx_sync[2],reg_data[7:1]};
|
||||
endcase
|
||||
|
||||
if (bit_done)
|
||||
begin
|
||||
sampleData = 1'b1;
|
||||
if (reg_bit_count == s_target_bits)
|
||||
begin
|
||||
reg_bit_count_next = 'h0;
|
||||
NS = SAVE_DATA;
|
||||
end
|
||||
else
|
||||
begin
|
||||
reg_bit_count_next = reg_bit_count + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
SAVE_DATA:
|
||||
begin
|
||||
baudgen_en = 1'b1;
|
||||
rx_valid_o = 1'b1;
|
||||
if(rx_ready_i)
|
||||
if (parity_en_i)
|
||||
NS = PARITY;
|
||||
else
|
||||
NS = STOP_BIT;
|
||||
end
|
||||
PARITY:
|
||||
begin
|
||||
baudgen_en = 1'b1;
|
||||
if (bit_done)
|
||||
begin
|
||||
if(parity_bit != reg_rx_sync[2])
|
||||
set_error = 1'b1;
|
||||
NS = STOP_BIT;
|
||||
end
|
||||
end
|
||||
STOP_BIT:
|
||||
begin
|
||||
baudgen_en = 1'b1;
|
||||
if (bit_done)
|
||||
begin
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
default:
|
||||
NS = IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rstn_i)
|
||||
begin
|
||||
if (rstn_i == 1'b0)
|
||||
begin
|
||||
CS <= IDLE;
|
||||
reg_data <= 8'hFF;
|
||||
reg_bit_count <= 'h0;
|
||||
parity_bit <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(bit_done)
|
||||
parity_bit <= parity_bit_next;
|
||||
if(sampleData)
|
||||
reg_data <= reg_data_next;
|
||||
|
||||
reg_bit_count <= reg_bit_count_next;
|
||||
if(cfg_en_i)
|
||||
CS <= NS;
|
||||
else
|
||||
CS <= IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
assign s_rx_fall = ~reg_rx_sync[1] & reg_rx_sync[2];
|
||||
always_ff @(posedge clk_i or negedge rstn_i)
|
||||
begin
|
||||
if (rstn_i == 1'b0)
|
||||
reg_rx_sync <= 3'b111;
|
||||
else
|
||||
begin
|
||||
if (cfg_en_i)
|
||||
reg_rx_sync <= {reg_rx_sync[1:0],rx_i};
|
||||
else
|
||||
reg_rx_sync <= 3'b111;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rstn_i)
|
||||
begin
|
||||
if (rstn_i == 1'b0)
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(baudgen_en)
|
||||
begin
|
||||
if(!start_bit && (baud_cnt == cfg_div_i))
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b1;
|
||||
end
|
||||
else if(start_bit && (baud_cnt == {1'b0,cfg_div_i[15:1]}))
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
baud_cnt <= baud_cnt + 1;
|
||||
bit_done <= 1'b0;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// always_ff @(posedge clk_i or negedge rstn_i)
|
||||
// begin
|
||||
// if (rstn_i == 1'b0)
|
||||
// begin
|
||||
// err_o <= 1'b0;
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// if(err_clr_i)
|
||||
// begin
|
||||
// err_o <= 1'b0;
|
||||
// end
|
||||
// else
|
||||
// begin
|
||||
// if(set_error)
|
||||
// err_o <= 1'b1;
|
||||
// end
|
||||
// end
|
||||
// end
|
||||
|
||||
assign rx_data_o = reg_data;
|
||||
|
||||
endmodule
|
233
Labs/13. Peripheral units/peripheral modules/uart_tx.sv
Normal file
233
Labs/13. Peripheral units/peripheral modules/uart_tx.sv
Normal file
@@ -0,0 +1,233 @@
|
||||
// Copyright 2017 ETH Zurich and University of Bologna.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the “License”); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
||||
// or agreed to in writing, software, hardware and materials distributed under
|
||||
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
module uart_tx (
|
||||
input logic clk_i,
|
||||
input logic rst_i,
|
||||
output logic tx_o,
|
||||
output logic busy_o,
|
||||
input logic [16:0] baudrate_i,
|
||||
input logic parity_en_i,
|
||||
input logic stopbit_i,
|
||||
input logic [7:0] tx_data_i,
|
||||
input logic tx_valid_i
|
||||
//, input logic cfg_en_i,
|
||||
// input logic [15:0] cfg_div_i,
|
||||
// input logic cfg_parity_en_i,
|
||||
// input logic [1:0] cfg_bits_i,
|
||||
// input logic stopbit_i,
|
||||
// output logic tx_ready_o
|
||||
);
|
||||
logic rstn_i;
|
||||
logic cfg_en_i;
|
||||
logic [1:0] cfg_bits_i;
|
||||
logic [15:0] cfg_div_i;
|
||||
logic tx_ready_o;
|
||||
assign rstn_i = !rst_i;
|
||||
assign cfg_en_i = 1'b1;
|
||||
assign cfg_bits_i = 2'd3;
|
||||
always_comb begin
|
||||
case(baudrate_i)
|
||||
17'd9600 : cfg_div_i = 15'd1041;
|
||||
17'd19200 : cfg_div_i = 15'd520;
|
||||
17'd38400 : cfg_div_i = 15'd259;
|
||||
17'd57600 : cfg_div_i = 15'd173;
|
||||
17'd115200: cfg_div_i = 15'd86;
|
||||
default : cfg_div_i = 15'd1041;
|
||||
endcase
|
||||
end
|
||||
enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT_FIRST,STOP_BIT_LAST} CS,NS;
|
||||
|
||||
logic [7:0] reg_data;
|
||||
logic [7:0] reg_data_next;
|
||||
|
||||
|
||||
logic [2:0] reg_bit_count;
|
||||
logic [2:0] reg_bit_count_next;
|
||||
|
||||
logic [2:0] s_target_bits;
|
||||
|
||||
logic parity_bit;
|
||||
logic parity_bit_next;
|
||||
|
||||
logic sampleData;
|
||||
|
||||
logic [15:0] baud_cnt;
|
||||
logic baudgen_en;
|
||||
logic bit_done;
|
||||
|
||||
assign busy_o = (CS != IDLE);
|
||||
|
||||
always_comb
|
||||
begin
|
||||
case(cfg_bits_i)
|
||||
2'b00:
|
||||
s_target_bits = 3'h4;
|
||||
2'b01:
|
||||
s_target_bits = 3'h5;
|
||||
2'b10:
|
||||
s_target_bits = 3'h6;
|
||||
2'b11:
|
||||
s_target_bits = 3'h7;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb
|
||||
begin
|
||||
NS = CS;
|
||||
tx_o = 1'b1;
|
||||
sampleData = 1'b0;
|
||||
reg_bit_count_next = reg_bit_count;
|
||||
reg_data_next = {1'b1,reg_data[7:1]};
|
||||
tx_ready_o = 1'b0;
|
||||
baudgen_en = 1'b0;
|
||||
parity_bit_next = parity_bit;
|
||||
case(CS)
|
||||
IDLE:
|
||||
begin
|
||||
if (cfg_en_i)
|
||||
tx_ready_o = 1'b1;
|
||||
if (tx_valid_i)
|
||||
begin
|
||||
NS = START_BIT;
|
||||
sampleData = 1'b1;
|
||||
reg_data_next = tx_data_i;
|
||||
end
|
||||
end
|
||||
|
||||
START_BIT:
|
||||
begin
|
||||
tx_o = 1'b0;
|
||||
parity_bit_next = 1'b0;
|
||||
baudgen_en = 1'b1;
|
||||
if (bit_done)
|
||||
NS = DATA;
|
||||
end
|
||||
|
||||
DATA:
|
||||
begin
|
||||
tx_o = reg_data[0];
|
||||
baudgen_en = 1'b1;
|
||||
parity_bit_next = parity_bit ^ reg_data[0];
|
||||
if (bit_done)
|
||||
begin
|
||||
if (reg_bit_count == s_target_bits)
|
||||
begin
|
||||
reg_bit_count_next = 'h0;
|
||||
if (parity_en_i)
|
||||
begin
|
||||
NS = PARITY;
|
||||
end
|
||||
else
|
||||
begin
|
||||
NS = STOP_BIT_FIRST;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
reg_bit_count_next = reg_bit_count + 1;
|
||||
sampleData = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PARITY:
|
||||
begin
|
||||
tx_o = parity_bit;
|
||||
baudgen_en = 1'b1;
|
||||
if (bit_done)
|
||||
NS = STOP_BIT_FIRST;
|
||||
end
|
||||
STOP_BIT_FIRST:
|
||||
begin
|
||||
tx_o = 1'b1;
|
||||
baudgen_en = 1'b1;
|
||||
if (bit_done)
|
||||
begin
|
||||
if (stopbit_i)
|
||||
NS = STOP_BIT_LAST;
|
||||
else
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
STOP_BIT_LAST:
|
||||
begin
|
||||
tx_o = 1'b1;
|
||||
baudgen_en = 1'b1;
|
||||
if (bit_done)
|
||||
begin
|
||||
NS = IDLE;
|
||||
end
|
||||
end
|
||||
default:
|
||||
NS = IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rstn_i)
|
||||
begin
|
||||
if (rstn_i == 1'b0)
|
||||
begin
|
||||
CS <= IDLE;
|
||||
reg_data <= 8'hFF;
|
||||
reg_bit_count <= 'h0;
|
||||
parity_bit <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(bit_done)
|
||||
begin
|
||||
parity_bit <= parity_bit_next;
|
||||
end
|
||||
|
||||
if(sampleData)
|
||||
begin
|
||||
reg_data <= reg_data_next;
|
||||
end
|
||||
|
||||
reg_bit_count <= reg_bit_count_next;
|
||||
if(cfg_en_i)
|
||||
CS <= NS;
|
||||
else
|
||||
CS <= IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rstn_i)
|
||||
begin
|
||||
if (rstn_i == 1'b0)
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if(baudgen_en)
|
||||
begin
|
||||
if(baud_cnt == cfg_div_i)
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
baud_cnt <= baud_cnt + 1;
|
||||
bit_done <= 1'b0;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
baud_cnt <= 'h0;
|
||||
bit_done <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
614
Labs/13. Peripheral units/peripheral modules/vgachargen.sv
Normal file
614
Labs/13. Peripheral units/peripheral modules/vgachargen.sv
Normal file
@@ -0,0 +1,614 @@
|
||||
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
|
@@ -0,0 +1,78 @@
|
||||
package vgachargen_pkg;
|
||||
|
||||
parameter int unsigned HD = 640; // Display area
|
||||
parameter int unsigned HF = 16; // Front porch
|
||||
parameter int unsigned HR = 96; // Retrace/Sync
|
||||
parameter int unsigned HB = 48; // Back Porch
|
||||
parameter int unsigned VD = 480;
|
||||
parameter int unsigned VF = 10;
|
||||
parameter int unsigned VR = 2;
|
||||
parameter int unsigned VB = 33;
|
||||
|
||||
parameter int unsigned HTOTAL = HD + HF + HR + HB;
|
||||
parameter int unsigned VTOTAL = VD + VF + VR + VB;
|
||||
|
||||
parameter int unsigned VGA_MAX_H_WIDTH = $clog2(HTOTAL);
|
||||
parameter int unsigned VGA_MAX_V_WIDTH = $clog2(VTOTAL);
|
||||
|
||||
parameter int unsigned BITMAP_H_PIXELS = 8;
|
||||
parameter int unsigned BITMAP_V_PIXELS = 16;
|
||||
parameter int unsigned BITMAP_H_WIDTH = $clog2(BITMAP_H_PIXELS);
|
||||
parameter int unsigned BITMAP_V_WIDTH = $clog2(BITMAP_V_PIXELS);
|
||||
parameter int unsigned CH_T_DATA_WIDTH = BITMAP_H_PIXELS * BITMAP_V_PIXELS;
|
||||
parameter int unsigned BITMAP_ADDR_WIDTH = $clog2(CH_T_DATA_WIDTH);
|
||||
parameter int unsigned CHARSET_COUNT = 256;
|
||||
parameter int unsigned CH_T_ADDR_WIDTH = $clog2(CHARSET_COUNT/2);
|
||||
|
||||
parameter int unsigned CH_H_PIXELS = HD / BITMAP_H_PIXELS;
|
||||
parameter int unsigned CH_V_PIXELS = VD / BITMAP_V_PIXELS;
|
||||
parameter int unsigned CH_V_WIDTH = $clog2(CH_V_PIXELS);
|
||||
parameter int unsigned CH_H_WIDTH = $clog2(CH_H_PIXELS);
|
||||
parameter int unsigned CH_MAP_ADDR_WIDTH = CH_V_WIDTH + CH_H_WIDTH;
|
||||
parameter int unsigned CH_MAP_DATA_WIDTH = CH_T_ADDR_WIDTH + 1;
|
||||
parameter int unsigned COL_MAP_ADDR_WIDTH = CH_MAP_ADDR_WIDTH;
|
||||
|
||||
typedef enum logic [23:0] {
|
||||
COL_0 = 24'h000000,
|
||||
COL_1 = 24'h0000d8,
|
||||
COL_2 = 24'h00d800,
|
||||
COL_3 = 24'h00d8d8,
|
||||
COL_4 = 24'hd80000,
|
||||
COL_5 = 24'hd800d8,
|
||||
COL_6 = 24'hd8d800,
|
||||
COL_7 = 24'hd8d8d8,
|
||||
COL_9 = 24'h0000ff,
|
||||
COL_10 = 24'h00ff00,
|
||||
COL_11 = 24'h00ffff,
|
||||
COL_12 = 24'hff0000,
|
||||
COL_13 = 24'hff00ff,
|
||||
COL_14 = 24'hffff00,
|
||||
COL_15 = 24'hffffff
|
||||
} rgb_t;
|
||||
|
||||
function automatic logic [11:0] rgb2half(rgb_t rgb_i);
|
||||
return {rgb_i[23:20], rgb_i[15:12], rgb_i[7:4]};
|
||||
endfunction
|
||||
|
||||
function automatic logic [11:0] color_decode(logic [3:0] color_encoded_i);
|
||||
unique case (color_encoded_i)
|
||||
4'h0 : return rgb2half(COL_0 );
|
||||
4'h1 : return rgb2half(COL_1 );
|
||||
4'h2 : return rgb2half(COL_2 );
|
||||
4'h3 : return rgb2half(COL_3 );
|
||||
4'h4 : return rgb2half(COL_4 );
|
||||
4'h5 : return rgb2half(COL_5 );
|
||||
4'h6 : return rgb2half(COL_6 );
|
||||
4'h7 : return rgb2half(COL_7 );
|
||||
4'h8 : return rgb2half(COL_0 );
|
||||
4'h9 : return rgb2half(COL_9 );
|
||||
4'ha : return rgb2half(COL_10);
|
||||
4'hb : return rgb2half(COL_11);
|
||||
4'hc : return rgb2half(COL_12);
|
||||
4'hd : return rgb2half(COL_13);
|
||||
4'he : return rgb2half(COL_14);
|
||||
4'hf : return rgb2half(COL_15);
|
||||
default: return rgb2half(COL_0 );
|
||||
endcase
|
||||
endfunction
|
||||
endpackage
|
Reference in New Issue
Block a user