9086/system/peripherals/ascii_to_HD44780_driver.v

349 lines
7.4 KiB
Coq
Raw Permalink Normal View History

/* ascii_to_HD44780_driver.v - driver that takes in ascii and outputs control
sequences for an HD44780 display
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module ascii_to_HD44780_driver (
/* system */
input wire clock,
input wire rst_n,
/* Data Input */
output reg in_data_ready=0,
input data_write_req,
input [7:0] in_ascii_data,
/* write circuitry */
input wire done_writing,
output reg write_req=0,
output reg [3:0] data,
output reg cmd_data=0
);
initial begin
init_cmd_data[ 0] = 4'h3;
init_cmd_data[ 1] = 4'h3;
init_cmd_data[ 2] = 4'h3;
init_cmd_data[ 3] = 4'h2;
init_cmd_data[ 4] = 4'h2; //0x28
init_cmd_data[ 5] = 4'h8;
init_cmd_data[ 6] = 4'h0; //0x07
init_cmd_data[ 7] = 4'h7;
init_cmd_data[ 8] = 4'h0; //0x0F
init_cmd_data[ 9] = 4'hF;
init_cmd_data[10] = 4'h0; //0x01
init_cmd_data[11] = 4'h1;
init_cmd_data[12] = 4'h0; //0x06
init_cmd_data[13] = 4'h6;
init_cmd_data[14] = 4'h0; // 0x02
init_cmd_data[15] = 4'h2;
end
reg [4:0] init_seq=0;
reg [3:0] init_cmd_data [15:0];
reg [7:0]print_data;
reg [1:0]line=0;
reg [5:0]col=0;
reg [7:0] driver_state =0;
reg next_line;
reg [7:0]clear_count;
always @(posedge clock) begin
if(rst_n==0)begin
in_data_ready<=0;
write_req<=1'b0;
init_seq<=5'd0;
cmd_data<=1'b0;
line<=0;
col<=0;
driver_state<=0;
end else begin
case(driver_state)
8'd0:begin
if(init_seq!=5'd16)begin
/** Initialise display **/
data<=init_cmd_data[init_seq[3:0]];
cmd_data<=1'b0;
in_data_ready<=0;
if(!done_writing)begin
init_seq<=init_seq+5'd1;
driver_state<=8'd12;
write_req<=1'b0;
end else begin
write_req<=1'b1;
end
end else if(col==6'd20)begin
/** Check if we run out of screen **/
driver_state<=8'd6;
cmd_data<=1'b0;
next_line<=1;
end else if(data_write_req==1)begin
if(in_ascii_data==8'h0A)begin // '\n'
driver_state<=8'd6;
cmd_data<=1'b0;
next_line<=1;
end else if(in_ascii_data==8'h0D)begin // '\r'
driver_state<=8'd6;
cmd_data<=1'b0;
next_line<=0;
end else if(in_ascii_data==8'h1b)begin // '\e'
driver_state<=8'd13;
cmd_data<=1'b1;
in_data_ready<=0;
end else begin
if (in_ascii_data[7:5]==3'b000||in_ascii_data[7:7]==1'b1)
if(in_ascii_data==8'h00)
print_data<=8'h23;
else
print_data<=8'h3F;
else
print_data<=in_ascii_data;
cmd_data<=1'b1;
driver_state<=8'd9;
end
in_data_ready<=0;
end else begin
in_data_ready<=1;
end
end
8'd6:begin
if(next_line)begin
case(line)
2'd0: data<=4'hC;
2'd1: data<=4'h9;
2'd2: data<=4'hD;
2'd3: data<=4'hD;
endcase
end else begin
case(line)
2'd0: data<=4'h8;
2'd1: data<=4'hC;
2'd2: data<=4'h9;
2'd3: data<=4'hD;
endcase
end
if(done_writing==0)begin
driver_state<=8'd7;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd7:begin
if(done_writing==1)
driver_state<=8'd8;
end
8'd8:begin
if(next_line)begin
case(line)
2'd0: begin data<=4'h0; end
2'd1: begin data<=4'h4; end
2'd2: begin data<=4'h4; end
2'd3: begin data<=4'h4; end
endcase
end else begin
case(line)
2'd0: begin data<=4'h0; end
2'd1: begin data<=4'h0; end
2'd2: begin data<=4'h4; end
2'd3: begin data<=4'h4; end
endcase
end
if(!done_writing)begin
driver_state<=8'd12;
col<=0;
write_req<=1'b0;
if(next_line)begin
case(line)
2'd0: begin line<=1; end
2'd1: begin line<=2; end
2'd2: begin line<=3; end
2'd3: begin line<=3; end
endcase
end
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd9:begin
data<=print_data[7:4];
if(!done_writing)begin
driver_state<=8'd10;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd10:begin
if(done_writing==1)
driver_state<=8'd11;
end
8'd11:begin
data<=print_data[3:0];
if(!done_writing)begin
driver_state<=8'd12;
write_req<=1'b0;
col<=col+1;
end else
write_req<=1'b1;
end
8'd12:begin
if(done_writing)
driver_state<=8'd0;
end
8'd13:begin // Escape sequence start
if(data_write_req==1'b0)begin
driver_state<=8'd14;
in_data_ready<=1;
end
end
8'd14:begin
if(data_write_req==1'b1)begin
in_data_ready<=1'b0;
case(in_ascii_data[7:0])
8'h5b:begin// '['
driver_state<=8'd16;
end
default:begin
driver_state<=8'd15;
end
endcase
end
end
8'd15:begin
if(data_write_req==1'b0)begin
driver_state<=8'd0;
end
end
8'd16:begin // Second part of escape sequency
if(data_write_req==1'b0)begin
in_data_ready<=1'b1;
driver_state<=8'd17;
end
end
8'd17:begin
if(data_write_req==1'b1)begin
driver_state<=8'd17;
in_data_ready<=1'b0;
case(in_ascii_data[7:0])
8'h48:begin// 'H'
driver_state<=8'd25;
cmd_data<=1'b0;
clear_count<=8'd80;
end
8'h32:begin// '2'
driver_state<=8'd23;
end
default: begin
driver_state<=8'd15;
end
endcase
end
end
8'd18:begin
data<=4'h2;
if(!done_writing)begin
driver_state<=8'd19;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd19:begin
if(done_writing==1)
driver_state<=8'd20;
end
8'd20:begin
data<=4'h0;
if(!done_writing)begin
driver_state<=8'd21;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd21:begin
if(done_writing)begin
driver_state<=8'd22;
clear_count<=clear_count-8'd1;
end
end
8'd22:begin
if(clear_count==8'd0)begin
driver_state<=8'd0;
end else begin
driver_state<=8'd18;
end
end
8'd23:begin
if(data_write_req==1'b0)begin
in_data_ready<=1'b1;
driver_state<=8'd24;
end
end
8'd24:begin
if(data_write_req==1'b1)begin
driver_state<=8'd17;
in_data_ready<=1'b0;
case(in_ascii_data[7:0])
8'h4a:begin// 'J'
driver_state<=8'd18;
clear_count<=8'd80;
end
default:begin
driver_state<=8'd0;
end
endcase
end
end
8'd25:begin
data<=4'h8;
if(!done_writing)begin
driver_state<=8'd26;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd26:begin
if(done_writing==1)
driver_state<=8'd27;
end
8'd27:begin
data<=4'h0;
if(!done_writing)begin
driver_state<=8'd28;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd28:begin
if(done_writing)begin
driver_state<=8'd0;
col<=0;
line<=0;
end
end
default: begin driver_state<=0; end
endcase
end
end
endmodule