/**
 * The HACK computer, including CPU, ROM and RAM.
 * When RST is 1, the program stored in the computer's ROM executes.
 * When RST is 0, the execution of the program restarts. 
 * Thus, to start a program's execution, reset must be pushed "down" (0)
 * and "up" (1). From this point onward the user is at the mercy of 
 * the software. In particular, depending on the program's code, the 
 * LED may show some output and the user may be able to interact 
 * with the computer via the BUT.
 */

`default_nettype none
module HACK( 
    input  CLK,				// external clock 100 MHz	
    input  [1:0] BUT,		// user button  ("pushed down" == 0) ("up" == 1)
    output [1:0] LED,		// leds (0 off, 1 on)
    input  UART_RX,			// UART recieve
    output UART_TX,			// UART transmit
    output SPI_SDO,			// SPI data out
    input  SPI_SDI,			// SPI data in
    output SPI_SCK,			// SPI serial clock
    output SPI_CSX,			// SPI chip select not
    output [17:0] SRAM_ADDR,// SRAM address 18 Bit = 256K
    inout [15:0] SRAM_DATA,	// SRAM data 16 Bit
    output SRAM_WEX,		// SRAM write_enable_not
    output SRAM_OEX,		// SRAM output_enable_not
    output SRAM_CSX, 		// SRAM chip_select_not
    output LCD_DCX,			// LCD data/command not
    output LCD_SDO,			// LCD data out 
    output LCD_SCK,			// LCD serial clock
    output LCD_CSX,			// LCD chip select not
    input  RTP_SDI,			// RTP data in s
    output RTP_SDO,			// RTP data out 
    output RTP_SCK			// RTP serial clock
);

    // Put your code here:
    wire loadRAM;
    wire loadIO0;
    wire loadIO1;
    wire loadIO2;
    wire loadIO3;
    wire loadIO4;
    wire loadIO5;
    wire loadIO6;
    wire loadIO7;
    wire loadIO8;
    wire loadIO9;
    wire loadIOA;
    wire loadIOB;
    wire loadIOC;
    wire loadIOD;
    wire loadIOE;
    wire loadIOF;
    wire [15:0] inRAM;
    wire [15:0] inIO0;
    wire [15:0] inIO1;
    wire [15:0] inIO2;
    wire [15:0] inIO3;
    wire [15:0] inIO4;
    wire [15:0] inIO5;
    wire [15:0] inIO6;
    wire [15:0] inIO7;
    wire [15:0] inIO8;
    wire [15:0] inIO9;
    wire [15:0] inIOA=0;
    wire [15:0] inIOB;
    wire [15:0] inIOC;
    wire [15:0] inIOD=0;
    wire [15:0] inIOE=0;
    wire [15:0] inIOF=0;

    wire writeM;
    wire [15:0] inM;
    wire [15:0] instruction;
    wire [15:0] outM;
    wire [15:0] addressM;
    wire [15:0] pc;

    wire clk, reset, RESET;
    wire [15:0] ROM_DATA;
    wire [15:0] fromLCD;
    wire [15:0] outDEBUG0;
    wire [15:0] outDEBUG1;
    //wire [15:0] outDEBUG2;
    wire loadDEBUG0;
    wire loadDEBUG1;
    //wire loadDEBUG2;
    // Put your code here:
    wire [15:0] fromGO;
    assign SRAM_ADDR[17:16]=2'b0;
    assign SRAM_ADDR[15:0]=fromGO;
    assign LED[1:0] = inIO0[1:0];
    assign inIO8 = fromLCD;
    assign inIO9 = fromLCD;

    assign outDEBUG0 = inIOB;
    assign outDEBUG1 = inIOC;
    //assign outDEBUG2 = inIOD;
    //assign loadDEBUG0 = loadIOB;
    //assign loadDEBUG1 = loadIOC;
    //assign loadDEBUG2 = loadIOD;
    Clock25_Reset20 CLKR(CLK, clk, reset);
    Or OR(reset, loadIO7, RESET);
    CPU CPU(clk, inM, instruction, RESET, outM, writeM, addressM, pc);

    Memory Memory(addressM, writeM, inM, loadRAM,
        loadIO0, loadIO1, loadIO2, loadIO3, loadIO4, loadIO5, loadIO6, loadIO7,
        loadIO8, loadIO9, loadIOA, loadIOB, loadIOC, loadIOD, loadIOE, loadIOF,
        inRAM, inIO0, inIO1, inIO2, inIO3, inIO4, inIO5, inIO6, inIO7,
        inIO8, inIO9, inIOA, inIOB, inIOC, inIOD, inIOE, inIOF);

    ROM ROM(pc, ROM_DATA);
    RAM3840 RAM(clk, addressM[11:0], outM, loadRAM, inRAM);

    Register LED12(clk, outM, loadIO0, inIO0);
    Register BUT12(clk, {14'b0, BUT[1:0]}, 1'b1, inIO1);

    UartTX UartTX(clk, loadIO2, outM, UART_TX, inIO2);
    UartRX UartRX(clk, loadIO3, UART_RX, inIO3);

    SPI SPI(clk, loadIO4, outM, inIO4, SPI_CSX, SPI_SDO, SPI_SDI, SPI_SCK);

    // if loadIO7=1 then instruction = SRAM_DATA/inIO6 otherwise output ROM_DATA
    //GO GO(clk, loadIO7, pc, inIO5, SRAM_ADDR[15:0], inIO6, ROM_DATA, instruction);
    reg load_sram=0;
    always @(posedge clk) begin
        if (loadIO7) begin
            load_sram <= 1;
        end
    end

    Mux16 SWITCHA(inIO5, pc, load_sram, fromGO);
    Mux16 SWITCHD(ROM_DATA, inIO6, load_sram, instruction);
    Register SRAM_A(clk, outM, loadIO5, inIO5);
    SRAM_D   SRAM_D(clk, loadIO6, outM, inIO6, SRAM_DATA, SRAM_CSX, SRAM_OEX, SRAM_WEX);
    LCD LCD(clk, loadIO8, loadIO9, outM, fromLCD, LCD_DCX, LCD_CSX, LCD_SDO, LCD_SCK);

    Register DEBUG0(clk, outM, loadIOB, inIOB);
    Register DEBUG1(clk, outM, loadIOC, inIOC);
    //Register DEBUG2(clk, outM, loadIOD, inIOD);
    //Register DEBUG3(clk, outM, loadIOE, inIOE);
    //Register DEBUG4(clk, outM, loadIOF, inIOF);

//assign SPI_SDO=0;
//assign SPI_SCK=0;
//assign SPI_CSX=0;

//assign SRAM_DATA=0;
//assign SRAM_WEX=0;
//assign SRAM_OEX=0;
//assign SRAM_CSX=0;
// assign LCD_DCX=0;
// assign LCD_SDO=0;
// assign LCD_SCK=0;
// assign LCD_CSX=0;
assign RTP_SDO=0;
assign RTP_SCK=0;
endmodule

