diff --git a/src/alu.verilog b/src/alu.verilog index ea8d2eb..76f3d00 100644 --- a/src/alu.verilog +++ b/src/alu.verilog @@ -1,18 +1,18 @@ -module alu - ( - input logic [7:0] A, - input logic [7:0] B, - input logic C, - input logic [2:0] sel, - output logic [7:0] result, - output logic r_n, - output logic r_z, - output logic r_v, - output logic r_c - ); +`default_nettype none +module alu (A, B, C, sel, result, r_n, r_z, r_v, r_c); `include "parameters.vh" + input logic [7:0] A; + input logic [7:0] B; + input logic C; + input logic [2:0] sel; + output logic [7:0] result; + output logic r_n; + output logic r_z; + output logic r_v; + output logic r_c; + reg [8:0] buffer; wire [8:0] sum; wire [8:0] diff; diff --git a/src/cpu.verilog b/src/cpu.verilog new file mode 100644 index 0000000..12cbdc8 --- /dev/null +++ b/src/cpu.verilog @@ -0,0 +1,365 @@ +`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 diff --git a/src/decoder.verilog b/src/decoder.verilog index 936871c..1c680ea 100644 --- a/src/decoder.verilog +++ b/src/decoder.verilog @@ -1,37 +1,43 @@ +`default_nettype none -module decoder - ( - input clk, - input rst, - input [7:0] instr, - output logic [4:0] address_code, - output logic [7:0] decoded - ); +module decoder (clk, rst, instr, address_code, decoded); `include "parameters.vh" - wire [2:0] row = instr[7:5]; - wire [2:0] column = instr[4:2]; - wire [1:0] sector = instr[1:0]; + input wire clk; + input wire rst; + input wire [7:0] instr; + output logic [4:0] address_code; + output logic [7:0] decoded; + + logic [2:0] row; + logic [2:0] column; + logic [1:0] sector; + +initial address_code = 0; +always_comb + begin + row = instr[7:5]; + column = instr[4:2]; + sector = instr[1:0]; + end + wire sec_2_stp = (sector == 2) && ((column == 0 && row <= 3) || (column == 4)); wire sec_2_nop = (sector == 2) && ((column == 0 && (row == 4 || row == 6 || row == 7)) || (column == 6 && (row != 4 && row != 5))); always_comb begin - address_code = 0; - decoded = 0; - if (rst) begin - address_code = 8'h0; - end - else begin + address_code = 5'h1f; + decoded = 8'hff; + if (!rst) begin if (sector == 1) begin case (row) 0: decoded = I_ORA; 1: decoded = I_AND; 2: decoded = I_EOR; 3: decoded = I_ADC; - 4: decoded = (column == 2 ? I_STA : I_NOP); + 4: decoded = (column == 2 ? I_NOP : I_STA); 5: decoded = I_LDA; 6: decoded = I_CMP; 7: decoded = I_SBC; @@ -50,12 +56,6 @@ always_comb begin 6: decoded = (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : (column == 2 ? I_DEX : I_DEC))); 7: decoded = (sec_2_stp ? I_STP : ((sec_2_nop || column == 2) ? I_NOP : I_INC)); endcase - if (column > 0) begin - address_code = column; - end - else begin - address_code = ADDR_MODE_IMMEDIATE; - end end else if (sector == 0) begin if (column == 0) begin @@ -175,7 +175,7 @@ always_comb begin address_code = ADDR_MODE_IMPLIED; end else if (column == 3) begin - if (row == 3) begin + if (row == 2) begin address_code = ADDR_MODE_ABSOLUTE; end else begin @@ -242,4 +242,64 @@ always_comb begin end end +`ifdef FORMAL + + reg f_past_valid; +initial f_past_valid = 0; + +always_comb + assume(rst == 0); + +always @(posedge clk) + f_past_valid <= 1; + +always_comb + if (instr == 8'h00) // BRK + begin + assert (decoded == I_BRK); + end; + +always_comb + if (instr == 8'h4C) // JMP abs + begin + assert (decoded == I_JMP); + assert (address_code == ADDR_MODE_ABSOLUTE); + end; + +always_comb + if (instr == 8'h8D) // STA abs + begin + assert (decoded == I_STA); + assert (address_code == ADDR_MODE_ABSOLUTE); + end; + +always_comb + if (instr == 8'hA2) // LDX imm + begin + assert (decoded == I_LDX); + assert (address_code == ADDR_MODE_IMMEDIATE); + end; + +always_comb + if (instr == 8'hA9) // LDA imm + begin + assert (decoded == I_LDA); + assert (address_code == ADDR_MODE_IMMEDIATE); + end; + +always_comb + if (instr == 8'hCA) // DEX + begin + assert (decoded == I_DEX); + assert (address_code == ADDR_MODE_IMPLIED); + end; + +always_comb + if (instr == 8'hE0) // CPX + begin + assert (decoded == I_CPX); + end; + +`endif + endmodule diff --git a/src/dmux.verilog b/src/dmux.verilog new file mode 100644 index 0000000..b10e6cf --- /dev/null +++ b/src/dmux.verilog @@ -0,0 +1,31 @@ +`default_nettype none +module dmux(sel, i_pc, i_a, i_x, i_y, i_sp, i_aux, o_mux); + input wire [2:0] sel; + input wire [15:0] i_pc; + input wire [7:0] i_a; + input wire [7:0] i_x; + input wire [7:0] i_y; + input wire [7:0] i_sp; + input wire [15:0] i_aux; + output logic [15:0] o_mux; + +`include "parameters.vh" + +always_comb + begin + o_mux = 0; + if (sel == DMUX_PC) + o_mux = i_pc; + else if (sel == DMUX_A) + o_mux[15:0] = { 8'h0, i_a }; + else if (sel == DMUX_X) + o_mux[15:0] = { 8'h0, i_x }; + else if (sel == DMUX_Y) + o_mux[15:0] = { 8'h0, i_y }; + else if (sel == DMUX_SP) + o_mux[15:0] = { 8'h1, i_sp }; + else if (sel == DMUX_AUX) + o_mux = i_aux; + end + +endmodule diff --git a/src/mio.verilog b/src/mio.verilog new file mode 100644 index 0000000..dc75c03 --- /dev/null +++ b/src/mio.verilog @@ -0,0 +1,32 @@ +`default_nettype none +module mio(clk, i_data, i_addr, i_wr, o_data, o_led); + + input wire clk; + input wire [7:0] i_data; + input wire [15:0] i_addr; + input wire i_wr; + output logic [7:0] o_data; + output logic [5:0] o_led; + + reg [7:0] memory [0:65535]; + +initial $readmemh("foo.hex", memory); +initial begin + memory[32768] <= 8'h00; + memory[65532] <= 8'h00; + memory[65533] <= 8'h00; +end; + +always @(posedge clk) + o_data <= memory[i_addr]; + +always @(posedge clk) + o_led <= memory[32768]; + +always @(posedge clk) + if (i_wr) + begin + memory[i_addr] <= i_data; + end + +endmodule diff --git a/src/parameters.vh b/src/parameters.vh index fef2968..65e3849 100644 --- a/src/parameters.vh +++ b/src/parameters.vh @@ -90,3 +90,11 @@ parameter P_D = 8'h08; parameter P_I = 8'h04; parameter P_Z = 8'h02; parameter P_C = 8'h01; + + +parameter DMUX_PC = 3'h0; +parameter DMUX_A = 3'h1; +parameter DMUX_X = 3'h2; +parameter DMUX_Y = 3'h3; +parameter DMUX_SP = 3'h4; +parameter DMUX_AUX = 3'h5;