Browse Source

Implement some of instructions

master
Denis Tereshkin 1 month ago
parent
commit
cc9a2e0dc4
  1. 24
      src/alu.verilog
  2. 365
      src/cpu.verilog
  3. 110
      src/decoder.verilog
  4. 31
      src/dmux.verilog
  5. 32
      src/mio.verilog
  6. 8
      src/parameters.vh

24
src/alu.verilog

@ -1,18 +1,18 @@ @@ -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;

365
src/cpu.verilog

@ -0,0 +1,365 @@ @@ -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

110
src/decoder.verilog

@ -1,37 +1,43 @@ @@ -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 @@ -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 @@ -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 @@ -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

31
src/dmux.verilog

@ -0,0 +1,31 @@ @@ -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

32
src/mio.verilog

@ -0,0 +1,32 @@ @@ -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

8
src/parameters.vh

@ -90,3 +90,11 @@ parameter P_D = 8'h08; @@ -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;

Loading…
Cancel
Save