/* top.v - Implements FPGA and Board specific circuitry This file is part of the 9086 project. Copyright (c) 2023 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 . */ `include "error_header.v" module fpga_top( input clk48, input user_button, // output reset_n, output rgb_led0_r, output rgb_led0_g, output rgb_led0_b, inout gpio_0,/*sda*/ output gpio_1 /*scl*/ ); wire HALT; wire [`ERROR_BITS-1:0]ERROR; wire [19:0] address_bus; wire [15:0] data_bus_read,data_bus_write; wire rd,wr,BHE,IOMEM; wire CPU_SPEED=counter[6]; system system( /* MISC */ CPU_SPEED,reset /* MEMORY / IO */ ,address_bus,data_bus_read,data_bus_write,BHE,rd,wr,IOMEM,HALT,ERROR ); reg [2:0]rgb_led_color; assign rgb_led0_r=rgb_led_color[0]; assign rgb_led0_g=rgb_led_color[1]; assign rgb_led0_b=rgb_led_color[2]; // A bit useless since if the cpu ERRORS out or HALTS it will continue executing anyway //always @(HALT or ERROR or user_button) begin // if (HALT==1) begin // /* yellow */ // rgb_led_color<=3'b100; // end else if (ERROR != `ERROR_BITS'b0) begin // /* red */ // rgb_led_color<=3'b110; // end else begin // /* green */ // rgb_led_color<=3'b101; // end //end // Create a 27 bit register reg [26:0] counter = 0; // Every positive edge increment register by 1 always @(posedge clk48) begin counter <= counter + 1; end /*** RESET CIRCUIT ***/ reg reset=0; reg [1:0] state=0; always @(posedge counter[15]) begin if(user_button==0) state=2'b00; case (state) 2'b00:begin reset<=0; state<=2'b01; end 2'b01:begin reset<=1; state<=2'b10; end default: begin end endcase end /* TODO This seems to be a bug with YOSYS. If I don't initialise the memory * it doesn't work (even though it does in sim), and for example if i * initialise 1 twice to the same value it breaks again. * * This seems to affect brainfuck_compiled.asm and specifically when the * compiled code starts running ( or the compiler i guess ) */ initial begin disp_write_cache[ 0]=8'h46; disp_write_cache[ 1]=8'h46; disp_write_cache[ 2]=8'h46; disp_write_cache[ 3]=8'h46; disp_write_cache[ 4]=8'h46; disp_write_cache[ 5]=8'h46; disp_write_cache[ 6]=8'h46; disp_write_cache[ 7]=8'h46; disp_write_cache[ 8]=8'h46; disp_write_cache[ 9]=8'h46; disp_write_cache[10]=8'h46; disp_write_cache[11]=8'h46; disp_write_cache[12]=8'h46; disp_write_cache[13]=8'h46; disp_write_cache[14]=8'h46; disp_write_cache[15]=8'h46; disp_write_cache[16]=8'h46; disp_write_cache[17]=8'h46; disp_write_cache[18]=8'h46; disp_write_cache[19]=8'h46; disp_write_cache[20]=8'h46; disp_write_cache[21]=8'h46; disp_write_cache[22]=8'h46; disp_write_cache[23]=8'h46; disp_write_cache[24]=8'h46; disp_write_cache[25]=8'h46; disp_write_cache[26]=8'h46; disp_write_cache[27]=8'h46; disp_write_cache[28]=8'h46; disp_write_cache[29]=8'h46; disp_write_cache[30]=8'h46; disp_write_cache[31]=8'h46; disp_write_cache[32]=8'h46; disp_write_cache[33]=8'h46; disp_write_cache[34]=8'h46; disp_write_cache[35]=8'h46; disp_write_cache[36]=8'h46; disp_write_cache[37]=8'h46; disp_write_cache[38]=8'h46; disp_write_cache[39]=8'h46; disp_write_cache[40]=8'h46; disp_write_cache[41]=8'h46; disp_write_cache[42]=8'h46; disp_write_cache[43]=8'h46; disp_write_cache[44]=8'h46; disp_write_cache[45]=8'h46; disp_write_cache[46]=8'h46; disp_write_cache[47]=8'h46; disp_write_cache[48]=8'h46; disp_write_cache[49]=8'h46; disp_write_cache[50]=8'h46; disp_write_cache[51]=8'h46; disp_write_cache[52]=8'h46; disp_write_cache[53]=8'h46; disp_write_cache[54]=8'h46; disp_write_cache[55]=8'h46; disp_write_cache[56]=8'h46; disp_write_cache[57]=8'h46; disp_write_cache[58]=8'h46; disp_write_cache[59]=8'h46; disp_write_cache[60]=8'h46; disp_write_cache[61]=8'h46; disp_write_cache[62]=8'h46; disp_write_cache[63]=8'h46; end //TODO similarly as above, if I remove this the same thing breaks always @(negedge wr) begin end //------------------------------------------// // Cache to allow the slow display to have a // chance to keep up with the relentless CPU reg [5:0] disp_cache_start=0; reg [5:0] disp_cache_end=0; reg [7:0] disp_write_cache [63:0]; reg ascii_state=0; always @(posedge CPU_SPEED)begin if(wr==0)begin if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin disp_write_cache[disp_cache_end]<=data_bus_write[15:8]; disp_cache_end<=disp_cache_end+6'd1; end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin if(data_bus_write[0:0]==1) rgb_led_color=3'b000; else rgb_led_color=3'b111; end end else if(ascii_state==1'b0)begin if(ascii_data_ready&disp_cache_start!=disp_cache_end)begin ascii_data<=disp_write_cache[disp_cache_start]; disp_cache_start<=disp_cache_start+6'd1; ascii_data_write_req<=1; ascii_state<=1'b1; end end if(ascii_state==1'b1)begin if(!ascii_data_ready)begin ascii_data_write_req<=0; ascii_state<=1'b0; end end end wire I2C_SPEED=counter[7]; // Display driver wire ascii_data_ready; reg ascii_data_write_req=0; reg [7:0] ascii_data; ascii_to_HD44780_driver LCD_DRIVER( /* system */ I2C_SPEED, 1'b1, /* Data Input */ ascii_data_ready, ascii_data_write_req, ascii_data, /* write circuitry */ !pcf_busy, pcf_write_req, pcf_data, pcf_command_data ); // Port expander driver wire pcf_write_req,pcf_command_data,pcf_busy; wire [3:0]pcf_data; wire [7:0]i2c_data; pcf8574_for_HD44780 PCF8574_driver( .clock(I2C_SPEED), .pcf_write_req(pcf_write_req), .pcf_command_data(pcf_command_data), .pcf_data(pcf_data), .pcf_busy(pcf_busy), .new_backlight(1'b0), .backlight_update(1'b0), .I2C_BUSY(I2C_BUSY), .I2C_SEND(I2C_SEND), .i2c_data(i2c_data) ); // I2C driver wire SCL,SDA,I2C_BUSY,I2C_SEND; assign gpio_1=SCL; assign gpio_0=SDA; I2C_driver i2c_driver( .clock(I2C_SPEED), .SDA_(SDA), .SCL(SCL), .address(7'h27), .I2C_BUSY(I2C_BUSY), .I2C_SEND(I2C_SEND), .i2c_data(i2c_data) ); endmodule