`default_nettype none module cpu ( nrst, clk, nmi, irq, o_led); `include "parameters.vh" localparam STATE_START_1 = 4'hc; localparam STATE_START_2 = 4'hd; localparam STATE_START_3 = 4'he; localparam STATE_START_4 = 4'hf; localparam STATE_START_0 = 4'hb; localparam STATE_FETCH = 0; localparam STATE_EXECUTE = 1; localparam STATE_WRITE = 2; localparam STATE_FETCH_DATA_1 = 3; localparam STATE_FETCH_DATA_2 = 4; localparam STATE_EXECUTE_DATA_2 = 5; localparam STATE_BRANCH = 7; localparam READ_SOURCE_NONE = 2'h0, READ_SOURCE_MEM = 2'h1, READ_SOURCE_ALU = 2'h2; input wire nrst; input wire clk; input wire nmi; input wire irq; output wire [5:0] o_led; reg [7:0] X; reg [7:0] Y; reg [7:0] A; reg [15:0] PC; reg [7:0] S; reg [7:0] P; reg [7:0] tmp; reg [3:0] state; reg [7:0] instr; wire [4:0] address_code; wire [7:0] decoded_instr; wire rst = !nrst; logic mem_wr; wire [7:0] mem_data; wire [15:0] mem_addr_eff; logic [7:0] mem_data_wr; logic [2:0] mem_sel; logic [7:0] mem_aux_addr; logic [7:0] alu_op_1; logic [7:0] alu_op_2; logic alu_op_c; logic [2:0] alu_op_sel; wire [7:0] alu_op_result; logic alu_n; logic alu_z; logic alu_v; logic alu_c; reg [7:0] data; reg [15:0] mem_addr; reg [2:0] mem_addr_offset; logic [1:0] pending_a_read; logic [1:0] pending_x_read; logic pending_rel_branch; initial A = 0; initial X = 0; initial Y = 0; initial P = 0; initial S = 8'hff; initial mem_data_wr = 0; initial mem_wr = 0; assign mem_addr_eff = mem_addr; initial pending_a_read = 0; initial pending_x_read = 0; initial pending_rel_branch = 0; alu alui( .A(alu_op_1), .B(alu_op_2), .C(alu_op_c), .sel(alu_op_sel), .result(alu_op_result), .r_n(alu_n), .r_z(alu_z), .r_v(alu_v), .r_c(alu_c)); decoder decoder ( .clk(clk), .rst(rst), .instr((state == STATE_EXECUTE ? mem_data : instr)), .address_code(address_code), .decoded(decoded_instr) ); mio mioi(.clk(clk), .i_data(mem_data_wr), .i_addr(mem_addr_eff), .i_wr(mem_wr), .o_data(mem_data), .o_led(o_led)); dmux dmuxi( .sel(mem_sel), .i_pc(PC), .i_a(A), .i_x(X), .i_y(Y), .i_sp(S), .i_aux({mem_data, mem_aux_addr}), .o_mux(mem_addr)); initial state = STATE_FETCH; initial PC = 0; initial mem_sel = 0; always @(posedge clk) if (state == STATE_START_0) begin mem_sel <= DMUX_AUX; mem_aux_addr <= 16'hfffc; state <= STATE_START_1; end else if (state == STATE_START_1) begin state <= STATE_START_2; end else if (state == STATE_START_2) begin PC[7:0] <= mem_data; mem_aux_addr <= 16'hfffd; state <= STATE_START_3; end else if(state == STATE_START_3) begin PC[15:8] <= mem_data; mem_sel <= DMUX_PC; state <= STATE_FETCH; end always_comb begin alu_op_1 = 0; alu_op_2 = 0; alu_op_c = 0; alu_op_sel = 0; if (decoded_instr == I_DEX) begin alu_op_1 = X; alu_op_2 = 1'b1; alu_op_c = 1'b1; alu_op_sel = OP_SUB; end if (address_code == ADDR_MODE_ABSOLUTE) begin if (decoded_instr == I_EOR) begin alu_op_1 = A; alu_op_2 = mem_data; alu_op_c = 0; alu_op_sel = OP_EOR; end end end always @(posedge clk) if (state == STATE_FETCH) begin if (pending_a_read == READ_SOURCE_MEM) begin A <= mem_data; P[P_Z] <= (mem_data == 0); P[P_N] <= mem_data[7]; end else if (pending_a_read == READ_SOURCE_ALU) begin A <= alu_op_result; P[P_Z] <= alu_z; P[P_N] <= alu_n; end pending_a_read <= READ_SOURCE_NONE; if (pending_x_read == READ_SOURCE_MEM) begin X <= mem_data; P[P_Z] <= (mem_data == 0); P[P_N] <= mem_data[7]; end else if (pending_x_read == READ_SOURCE_ALU) begin X <= alu_op_result; P[P_Z] <= alu_z; P[P_N] <= alu_n; end pending_x_read <= READ_SOURCE_NONE; PC <= PC + 1; state <= STATE_EXECUTE; end always @(posedge clk) if (state == STATE_EXECUTE) begin instr <= mem_data; if (address_code == ADDR_MODE_ABSOLUTE) begin PC <= PC + 1; state <= STATE_FETCH_DATA_2; end else if (address_code == ADDR_MODE_IMMEDIATE) begin if (decoded_instr == I_LDX) begin pending_x_read <= READ_SOURCE_MEM; state <= STATE_FETCH; PC <= PC + 1; end else if (decoded_instr == I_LDA) begin pending_a_read <= READ_SOURCE_MEM; state <= STATE_FETCH; PC <= PC + 1; end end else if (address_code == ADDR_MODE_IMPLIED) begin if (decoded_instr == I_DEX) begin pending_x_read <= READ_SOURCE_ALU; state <= STATE_FETCH; end end else if (decoded_instr == I_BNE) begin if(!P[P_Z]) begin pending_rel_branch = 1'b1; state <= STATE_BRANCH; end else begin state <= STATE_FETCH; PC <= PC + 1; end end end always @(posedge clk) if (state == STATE_BRANCH) begin if (pending_rel_branch) begin PC <= PC + {{8{mem_data[7]}}, mem_data[7:0]} + 1'b1; end pending_rel_branch <= 0; state <= STATE_FETCH; end always @(posedge clk) if (state == STATE_FETCH_DATA_2) begin if (address_code == ADDR_MODE_ABSOLUTE) begin mem_aux_addr[7:0] <= mem_data; mem_sel <= DMUX_AUX; state <= STATE_EXECUTE_DATA_2; PC <= PC + 1'b1; end end always @(posedge clk) begin if (state == STATE_EXECUTE_DATA_2) begin if (address_code == ADDR_MODE_ABSOLUTE) begin mem_sel <= DMUX_PC; state <= STATE_FETCH; if (decoded_instr == I_EOR) begin tmp <= mem_data; pending_a_read <= READ_SOURCE_ALU; end else if(decoded_instr == I_JMP) begin PC <= mem_addr; end end end end always_comb begin mem_data_wr = 0; mem_wr = 0; if (state == STATE_EXECUTE_DATA_2) begin if (address_code == ADDR_MODE_ABSOLUTE) begin if(decoded_instr == I_STA) begin mem_data_wr = A; mem_wr = 1'b1; end end end end always_comb begin mem_addr_offset = 0; // if (state == STATE_FETCH) // begin // mem_addr_offset = 1; // end // if (state == STATE_BRANCH) // begin // mem_addr_offset = 0; // end // if (state == STATE_EXECUTE) // begin // if (address_code == ADDR_MODE_IMMEDIATE) // begin // mem_addr_offset = 1; // end // else if (address_code == ADDR_MODE_RELATIVE) // begin // if (decoded_instr == I_BNE ) // if (!P[P_Z]) // mem_addr_offset = 0; // else // mem_addr_offset = 1; // end // else if (address_code == ADDR_MODE_ABSOLUTE) // begin // mem_addr_offset = 1; // end // end // if (state == STATE_FETCH_DATA_2) // begin // if (address_code == ADDR_MODE_ABSOLUTE) // begin // mem_addr_offset = 1; // end // end end endmodule