/* * lcd.v * Copyright (C) 2020 Krzysztof Mazur * * 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 2 of the License, or * (at your option) any later version. */ `timescale 1ns / 1ns module lcd(E, RS, RW, DB); input E; input RS; input RW; inout [7:0] DB; parameter CLEAR_DISPLAY = 8'h01; parameter RETURN_CURSOR_HOME = 8'h02; parameter ENTRY_MODE_SET = 8'h04; parameter DISPLAY_ON_OFF = 8'h08; parameter CURSOR_AND_DISPLAY = 8'h10; parameter FUNCTION_SET = 8'h20; parameter SET_CG_RAM_ADDRESS = 8'h40; parameter SET_DD_RAM_ADDRESS = 8'h80; reg [7:0] data[0:127]; reg debug = 0; always @(posedge E) begin if (debug) $display("RW: %d RS: %d DB=%h", RW, RS, DB); end integer i; always @(posedge E) begin if (RW == 0 && RS == 0 && DB == CLEAR_DISPLAY) begin for (i = 0; i < 128; i = i + 1) data[i] = 8'h20; end else if (RW == 0 && RS == 1) begin data[cursor] <= DB; end end reg dirty = 0; always @(posedge E) begin if (RW == 0 && RS == 0 && DB == CLEAR_DISPLAY) dirty <= 1; else if (RW == 0 && RS == 1) dirty <= 1; else dirty <= dirty; end reg auto_increment = 0; always @(posedge E) begin if (RW == 0 && RS == 0 && DB[7:2] == ENTRY_MODE_SET[7:2]) auto_increment <= DB[1]; else auto_increment <= auto_increment; end reg [6:0] cursor = 0; always @(posedge E) begin if (RW == 0 && RS == 0 && DB == CLEAR_DISPLAY) cursor <= 0; else if (RW == 0 && RS == 0 && DB[7:1] == RETURN_CURSOR_HOME[7:1]) cursor <= 0; else if (RW == 0 && RS == 0 && DB[7] == SET_DD_RAM_ADDRESS[7]) cursor <= DB[6:0]; else if (RW == 0 && RS == 1 && auto_increment) cursor <= cursor + 1; else if (RW == 0 && RS == 1 && !auto_increment) cursor <= cursor - 1; else cursor <= cursor; end reg clk = 0; always #10000000 clk = !clk; integer j; always @(posedge clk) begin if (dirty) begin $display("**********************"); $write("*"); for (j = 0; j < 20; j = j + 1) $write("%c", data[j]); $display("*"); $write("*"); for (j = 64; j < 64 + 20; j = j + 1) $write("%c", data[j]); $display("*"); $display("**********************"); dirty <= 0; end end always @(RW) begin if (E) $display("lcd: timing violation: RW must be constant,", " while E is active"); end always @(RS) begin if (E) $display("lcd: timing violation: RS must be constant,", " while E is active"); end always @(DB) begin if (E) $display("lcd: timing violation: DB must be constant,", " while E is active"); end wire DE; assign #1 DE = E; specify specparam tsetup = 40; specparam thold = 10; $width(posedge E, 230); $width(negedge E, 1000); $setup(RS, posedge E, tsetup); $hold(negedge E, RS, thold); $setup(RS, posedge DE, 2); $setup(RS, negedge DE, 2); $setup(RW, posedge E, tsetup); $hold(negedge E, RW, thold); $setup(RW, posedge DE, 2); $setup(RW, negedge DE, 2); $setup(DB, posedge E, tsetup); $hold(negedge E, DB, thold); $setup(DB, posedge DE, 2); $setup(DB, negedge DE, 2); endspecify endmodule