module moyes0_top_module (
  input  [7:0] io_in,
  output [7:0] io_out
);

  // --- ASIC Inputs ---
  wire clk     = io_in[0];      // System clock (~6000 Hz)
  wire rst     = io_in[1];      // Reset line, active high
  wire spi_miso= io_in[2];      // SPI bus, ASIC input, target output
  wire uart_rx = io_in[3];      // Serial port, ASIC Receive
  wire in4     = io_in[4];
  wire in5     = io_in[5];
  wire in6     = io_in[6];
  wire in7     = io_in[7];

  // --- ASIC Outputs ---
  wire spi_cs0;
  wire spi_cs1;
  wire spi_clk;
  wire spi_mosi;
  wire uart_tx;
  wire out5;
  wire out6;
  wire out7;

  wire [7:0] io_out;
  assign io_out[0] = spi_cs0;  // SPI bus, Chip Select for RAM, Words 0000-7FFF
  assign io_out[1] = spi_cs1;  // SPI bus, Chip Select for ROM, Words 8000-FFFF
  assign io_out[2] = spi_clk;  // SPI bus, Clock
  assign io_out[3] = spi_mosi; // SPI bus, ASIC output, target input
  assign io_out[4] = uart_tx;  // Serial port, ASIC Transmit
  assign io_out[5] = out5;
  assign io_out[6] = out6;
  assign io_out[7] = out7;

  // --- Internal Timing Signals ---
  wire ShiftAddr;
  wire ShiftDataRead;
  wire ShiftDataWrite;
  wire PresetCarry;
  wire EndOfPhase;
  wire PrepOutput;

  // --- SPI Control Signals
  wire Addr15;
  wire Read_notWrite;
  wire SPIAddr;
  wire SPIDataIn;

  // --- CPU Registers ---
  reg [15:0] PC;
  reg [15:0] TMP;
  reg [15:0] ADR;
  reg PCCarry;
  reg TBorrow;
  reg TZero;
  reg LEQ;

  assign out7 = !in7;  // For bring-up testing, out7 = !in7. No other internal connections

  SPIController spi (
     // System Interfaces
    .clk(clk),
    .rst(rst),

    // SPI Bus Interfaces
    .CS0(spi_cs0),
    .CS1(spi_cs1),
    .SPICLK(spi_clk),
    .MOSI(spi_mosi),
    .MISO(spi_miso),

    // Input Signals
    .Addr15(Addr15),
    .Read_notWrite(Read_notWrite),
    .Addr(SPIAddr),
    .Data(SPIDataIn),

    // Timing Output Signals
    .ShiftAddr(ShiftAddr),
    .ShiftDataRead(ShiftDataRead),
    .ShiftDataWrite(ShiftDataWrite),
    .PresetCarry(PresetCarry),
    .EndOfPhase(EndOfPhase),
    .PrepOutput(PrepOutput)
  );

  reg [2:0]  CPUphase;
  always @(posedge clk) begin
    if (rst)
      CPUphase <= 3'd0;
    else if (!EndOfPhase)
      CPUphase <= CPUphase;
    else begin
      if (CPUphase == 3'd5)
         CPUphase <= 3'd0;
      else
         CPUphase <= CPUphase + 3'd1;
    end
  end

  wire PCphase = (CPUphase == 0) || (CPUphase == 2) || (CPUphase == 5);

  assign Addr15 = PCphase ? PC[15] : ADR[15];

  assign Read_notWrite = (CPUphase != 4);

  always @(posedge clk) begin

    if (rst)
      PC  <= 16'h8000;
    else begin
      if (PresetCarry)
        PCCarry <= 1;

      if (PCphase && ShiftAddr) begin
        PCCarry <= PC[0] & PCCarry;
        PC <= {PC[0] ^ PCCarry, PC[15:1]};
      end

      if ((CPUphase == 5) && ShiftDataRead) begin
        PC <= {LEQ ? spi_miso : PC[0], PC[15:1]};
      end
    end
  end

  assign SPIAddr = PCphase ? PC[0] : ADR[0];

  assign SPIDataIn = TMP[0];

  wire ReadADR = (CPUphase == 0) || (CPUphase == 2);
  wire ReadTMP = (CPUphase == 1) || (CPUphase == 3);

  always @(posedge clk) begin
    if (ReadADR & ShiftDataRead)
      ADR <= {spi_miso, ADR[15:1]};

    if (!PCphase & ShiftAddr)
      ADR <= {ADR[0], ADR[15:1]};
  end

  // Transmit UART
  reg BwasFFFF;
  reg UARTout;
  assign uart_tx = UARTout;
  reg [4:0] UARTcount;
  always @(posedge clk) begin
    if (EndOfPhase) begin
      BwasFFFF <= 1;
      UARTout <= 1;
      UARTcount <= 0;
    end

    if (ShiftAddr & !ADR[0])
      BwasFFFF <= 0;

    if (BwasFFFF & (CPUphase == 3)& PrepOutput) begin
      UARTout <= 0;
      UARTcount <= 9;
    end

    if ((UARTcount != 0) & ShiftDataRead) begin
      UARTcount <= UARTcount - 1;
      UARTout <= (UARTcount != 1) ? TMP[0] : 1;
    end;

  end


  wire sub_b;
  wire sub_r;
  assign {sub_b, sub_r} = spi_miso - TMP[0] - TBorrow;

  always @(posedge clk) begin
    if (PresetCarry) begin
      TBorrow <= 0;
      TZero <= 1;
    end

    if ((CPUphase == 1) & ShiftDataRead)
      TMP <= {spi_miso, TMP[15:1]};

    if ((CPUphase == 3) & ShiftDataRead) begin
      TBorrow <= sub_b;
      TMP <= {sub_r, TMP[15:1]};
      if (sub_r)
        TZero <= 0;
    end

    if (!Read_notWrite & ShiftDataWrite)
      TMP <= {TMP[0], TMP[15:1]};

  end

  always @(posedge clk) begin
    if (EndOfPhase & (CPUphase == 3)) begin
      LEQ <= TZero | TMP[15];
    end
  end



endmodule