6502 implementation in SystemVerilog
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
8.8 KiB

`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