module verilog6502_addr_decoder( input i_clk, input i_rst, input logic [15:0] i_cpu_addr, input logic [7:0] i_cpu_data, output logic [7:0] o_cpu_data, input logic i_cpu_we, input logic i_cpu_rdy, output logic o_cpu_rdy, output logic [15:0] o_mem_addr, output logic [7:0] o_mem_data, input logic [7:0] i_mem_data, output logic o_mem_rd, output logic o_mem_we, input logic i_mem_rdy, output logic [15:0] o_external_addr, output logic [7:0] o_external_data, input logic [7:0] i_external_data, output logic o_external_rd, output logic o_external_we, input logic i_external_rdy, output logic [15:0] o_io_addr, output logic [7:0] o_io_data, input logic [7:0] i_io_data, output logic o_io_rd, output logic o_io_we, input logic i_io_rdy ); enum logic [1:0] {NONE, MEM, EXT, IO} prev_addr, prev_addr_next; always_ff @(posedge i_clk) begin if (i_rst) begin prev_addr <= NONE; end else begin prev_addr <= prev_addr_next; end end always_comb begin prev_addr_next = prev_addr; o_mem_addr = '0; o_mem_data = '0; o_mem_rd = '0; o_mem_we = '0; o_external_addr = '0; o_external_data = '0; o_external_rd = '0; o_external_we = '0; o_io_addr = '0; o_io_data = '0; o_io_rd = '0; o_io_we = '0; case (prev_addr) NONE: begin o_cpu_rdy = '1; o_cpu_data = '0; end MEM: begin o_cpu_rdy = i_mem_rdy; o_cpu_data = i_mem_data; end EXT: begin o_cpu_rdy = i_external_rdy; o_cpu_data = i_external_data; end IO: begin o_cpu_rdy = i_io_rdy; o_cpu_data = i_io_data; end default: begin o_cpu_rdy = '1; o_cpu_data = '0; end endcase if (o_cpu_rdy) begin if (i_cpu_addr < 16'hE000) begin o_mem_addr = i_cpu_addr; o_mem_data = i_cpu_data; o_mem_we = i_cpu_we & o_cpu_rdy; o_mem_rd = ~i_cpu_we & o_cpu_rdy; prev_addr_next = MEM; end else if (i_cpu_addr < 16'hF000) begin o_external_addr = {4'b0, i_cpu_addr[11:0]}; o_external_data = i_cpu_data; o_external_we = i_cpu_we & o_cpu_rdy; o_external_rd = ~i_cpu_we & o_cpu_rdy; prev_addr_next = EXT; end else begin o_io_addr = {4'b0, i_cpu_addr[11:0]}; o_io_data = i_cpu_data; o_io_we = i_cpu_we & o_cpu_rdy; o_io_rd = ~i_cpu_we & o_cpu_rdy; prev_addr_next = IO; end end if (i_rst | ~i_cpu_rdy) begin prev_addr_next = NONE; o_mem_rd = 0; o_mem_we = 0; o_external_rd = 0; o_external_we = 0; o_io_rd = 0; o_io_we = 0; end end endmodule