Compare commits

...

5 Commits

  1. 94
      src/alu.verilog
  2. 584
      src/cpu.verilog
  3. 350
      src/decoder.verilog
  4. 31
      src/dmux.verilog
  5. 69
      src/mio.verilog
  6. 174
      src/parameters.vh
  7. 32
      src/slon.sby
  8. 24
      src/slon_decoder.sby
  9. 44
      tests/test_alu.verilog

94
src/alu.verilog

@ -1,86 +1,88 @@ @@ -1,86 +1,88 @@
module alu
(
input nrst,
input clk,
input [7:0] A,
input [7:0] B,
input C,
input [2:0] sel,
output [7:0] result,
output r_n,
output r_z,
output reg r_v,
output reg 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;
wire rst = !nrst;
reg [8:0] buffer;
wire [8:0] sum;
wire [8:0] diff;
assign result[7:0] = buffer[7:0];
assign r_z = buffer[7:0] == 0;
assign r_n = buffer[7];
assign r_z = result[7:0] == 0;
assign r_n = result[7];
assign sum = A + B + C;
assign diff = A - B - (1 - C);
initial begin
buffer <= 0;
r_v <= 0;
r_c <= 0;
end
always @(posedge clk)
always_comb
begin
result = 0;
r_c = 0;
r_v = 0;
case (sel)
OP_OR:
begin
buffer <= A | B;
result = A | B;
r_v = 0;
r_c = 0;
end
OP_AND:
begin
buffer <= A & B;
result = A & B;
r_v = 0;
r_c = 0;
end
OP_EOR:
begin
buffer <= A ^ B;
result = A ^ B;
r_v = 0;
r_c = 0;
end
OP_ADC:
begin
buffer <= sum;
r_c <= sum[8];
r_v <= !(A[7] ^ B[7]) & (A[7] & sum[7]);
result = sum[7:0];
r_c = sum[8];
r_v = !(A[7] ^ B[7]) & (A[7] ^ sum[7]);
end
OP_SUB:
begin
buffer <= diff;
r_c <= diff[8];
r_v <= !(A[7] ^ B[7]) & (A[7] & diff[7]);
result = diff;
r_c = diff[8];
r_v = !(A[7] ^ B[7]) & (A[7] ^ diff[7]);
end
OP_ROT:
begin
if (B == SHIFT_LEFT) begin
buffer[8:1] <= A[7:0];
buffer[0] <= C;
r_c <= A[7];
result[7:1] = A[6:0];
result[0] = C;
r_c = A[7];
end
else begin
buffer[6:0] <= A[7:1];
buffer[7] <= C;
r_c <= A[0];
result[6:0] = A[7:1];
result[7] = C;
r_c = A[0];
end
end
OP_SHF:
begin
if (B == SHIFT_LEFT) begin
buffer[8:1] <= A[7:0];
buffer[0] <= 0;
r_c <= A[7];
result[7:1] = A[6:0];
result[0] = 0;
r_c = A[7];
end
else begin
buffer[6:0] <= A[7:1];
buffer[7] <= 0;
r_c <= A[0];
result[6:0] = A[7:1];
result[7] = 0;
r_c = A[0];
end
end
endcase // case sel

584
src/cpu.verilog

@ -0,0 +1,584 @@ @@ -0,0 +1,584 @@
`default_nettype none
module cpu
(
nrst,
clk,
nmi,
irq,
o_led,
o_state);
`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_EXECUTE_ZP = 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;
output wire [31:0] o_state;
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] mem_aux_addr_lo;
logic [7:0] mem_aux_addr_hi;
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 [1:0] pending_y_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_y_read = 0;
initial pending_rel_branch = 0;
assign o_state[3:0] = state;
assign o_state[31:24] = A;
assign o_state[23:16] = X;
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_aux_addr_hi, mem_aux_addr_lo}),
.o_mux(mem_addr));
initial state = STATE_FETCH;
initial PC = 0;
initial mem_sel = 0;
always_comb
begin
mem_aux_addr_lo = mem_aux_addr;
mem_aux_addr_hi = 0;
if (address_code == ADDR_MODE_ABSOLUTE)
begin
mem_aux_addr_hi = mem_data;
end
else if (address_code == ADDR_MODE_ZP)
begin
mem_aux_addr_lo = mem_data;
end
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
else if (decoded_instr == I_DEY)
begin
alu_op_1 = Y;
alu_op_2 = 1'b1;
alu_op_c = 1'b1;
alu_op_sel = OP_SUB;
end
else if (address_code == ADDR_MODE_IMMEDIATE ||
address_code == ADDR_MODE_ABSOLUTE ||
address_code == ADDR_MODE_ZP)
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
else if (decoded_instr == I_AND)
begin
alu_op_1 = A;
alu_op_2 = mem_data;
alu_op_c = 0;
alu_op_sel = OP_AND;
end
else if (decoded_instr == I_ORA)
begin
alu_op_1 = A;
alu_op_2 = mem_data;
alu_op_c = 0;
alu_op_sel = OP_OR;
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;
if (pending_y_read == READ_SOURCE_MEM)
begin
Y <= mem_data;
P[P_Z] <= (mem_data == 0);
P[P_N] <= mem_data[7];
end
else if (pending_y_read == READ_SOURCE_ALU)
begin
Y <= alu_op_result;
P[P_Z] <= alu_z;
P[P_N] <= alu_n;
end
pending_y_read <= READ_SOURCE_NONE;
PC <= PC + 1;
state <= STATE_EXECUTE;
end
else 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;
end
else if (decoded_instr == I_LDA)
begin
pending_a_read <= READ_SOURCE_MEM;
end
else if (decoded_instr == I_EOR ||
decoded_instr == I_AND ||
decoded_instr == I_ORA)
begin
pending_a_read <= READ_SOURCE_ALU;
end
state <= STATE_FETCH;
PC <= PC + 1;
end
else if (address_code == ADDR_MODE_ZP)
begin
mem_sel <= DMUX_AUX;
state <= STATE_EXECUTE_ZP;
PC <= PC + 1;
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
else if (decoded_instr == I_DEY)
begin
pending_y_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
else if (state == STATE_EXECUTE_ZP)
begin
mem_aux_addr <= mem_data;
mem_sel <= DMUX_PC;
pending_a_read <= READ_SOURCE_ALU;
state <= STATE_FETCH;
end
else 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
else 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
else 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 ||
decoded_instr == I_AND ||
decoded_instr == I_ORA)
begin
tmp <= mem_data;
pending_a_read <= READ_SOURCE_ALU;
end
else if(decoded_instr == I_JMP)
begin
PC <= mem_addr;
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
else if (state == STATE_EXECUTE_ZP)
begin
if(decoded_instr == I_STA)
begin
mem_data_wr = A;
mem_wr = 1'b1;
end
end
end
`ifdef FORMAL
logic f_past_valid;
logic f2_past_valid;
logic f3_past_valid;
logic f4_past_valid;
logic f5_past_valid;
initial f_past_valid = 0;
initial f2_past_valid = 0;
initial f3_past_valid = 0;
initial f4_past_valid = 0;
initial f5_past_valid = 0;
always @(posedge clk)
f_past_valid <= 1;
always @(posedge clk)
if (f_past_valid)
f2_past_valid <= 1;
always @(posedge clk)
if (f2_past_valid)
f3_past_valid <= 1;
always @(posedge clk)
if (f3_past_valid)
f4_past_valid <= 1;
always @(posedge clk)
if (f4_past_valid)
f5_past_valid <= 1;
always @(posedge clk)
if (f2_past_valid && state == STATE_EXECUTE)
if ($past(decoded_instr) == I_DEX)
begin
assert(X == $past(X, 3) - 8'd1);
assert($past(PC) == $past(PC, 3) + 16'd1);
assert(P[P_Z] == (X == 0));
assert(P[P_N] == (X[7] == 1));
assert($stable(P[P_C]));
assert($stable(P[P_V]));
assert($stable(P[P_B]));
assert($stable(P[P_D]));
assert($stable(P[P_I]));
end
always @(posedge clk)
if (f2_past_valid && state == STATE_EXECUTE)
if ($past(decoded_instr) == I_DEY)
begin
assert(Y == $past(Y, 3) - 8'd1);
assert($past(PC) == $past(PC, 3) + 16'd1);
assert(P[P_Z] == (Y == 0));
assert(P[P_N] == (Y[7] == 1));
assert($stable(P[P_C]));
assert($stable(P[P_V]));
assert($stable(P[P_B]));
assert($stable(P[P_D]));
assert($stable(P[P_I]));
end
always @(posedge clk)
if (f2_past_valid && state == STATE_EXECUTE)
if ($past(decoded_instr) == I_LDX && $past(address_code) == ADDR_MODE_IMMEDIATE)
begin
assert(X == $past(mem_data));
assert(P[P_Z] == (X == 0));
assert(P[P_N] == (X[7] == 1));
if (f3_past_valid)
begin
assert($past(PC) == $past(PC, 3) + 16'd2);
end
end
always @(posedge clk)
if (f2_past_valid && state == STATE_EXECUTE)
if ($past(decoded_instr) == I_LDA && $past(address_code) == ADDR_MODE_IMMEDIATE)
begin
assert(A == $past(mem_data));
assert(P[P_Z] == (A == 0));
assert(P[P_N] == (A[7] == 1));
if (f3_past_valid)
begin
assert($past(PC) == $past(PC, 3) + 16'd2);
end
end
logic [15:0] f_abs_address;
initial f_abs_address = 0;
always_comb
begin
f_abs_address = 0;
if (f_past_valid)
begin
f_abs_address[15:8] = mem_data;
f_abs_address[7:0] = mem_aux_addr;
end
end
always @(posedge clk)
if (f2_past_valid && state == STATE_EXECUTE_DATA_2)
if ($past(decoded_instr) == I_STA && $past(address_code) == ADDR_MODE_ABSOLUTE)
begin
assert(mem_wr == 1'b1);
assert(mem_data_wr == A);
assert(f_abs_address == mem_addr_eff);
if (f3_past_valid)
begin
assert(PC == $past(PC, 3) + 16'd3);
end
end
always @(posedge clk)
if (f4_past_valid &&
state == STATE_EXECUTE &&
$past(state) == STATE_FETCH &&
($past(state, 2) == STATE_EXECUTE_DATA_2 ||
$past(state, 2) == STATE_EXECUTE_ZP ||
$past(state, 2) == STATE_EXECUTE))
begin
if ($past(decoded_instr, 2) == I_EOR)
assert(A == ($past(A) ^ $past(mem_data)));
else if ($past(decoded_instr, 2) == I_AND)
assert(A == ($past(A) & $past(mem_data)));
else if ($past(decoded_instr, 2) == I_ORA)
assert(A == ($past(A) | $past(mem_data)));
else
assume(0);
assert($past(mem_wr, 2) == 1'b0);
if ($past(address_code, 2) == ADDR_MODE_ABSOLUTE)
assert($past(f_abs_address, 2) == $past(mem_addr_eff, 2));
else if ($past(address_code, 2) == ADDR_MODE_ZP)
assert($past(mem_data, 2) == $past(mem_addr_eff, 2));
assert(P[P_Z] == (A == 0));
assert(P[P_N] == (A[7] == 1));
assert(P[P_C] == $past(P[P_C], 2));
assert(P[P_V] == $past(P[P_V], 2));
assert(P[P_B] == $past(P[P_B], 2));
assert(P[P_D] == $past(P[P_D], 2));
assert(P[P_I] == $past(P[P_I], 2));
assert(S == $past(S, 2));
assert(X == $past(X, 2));
assert(Y == $past(Y, 2));
if (f3_past_valid)
begin
if ($past(address_code, 2) == ADDR_MODE_ABSOLUTE)
assert($past(PC, 2) == $past(PC, 5) + 16'd3);
else if ($past(address_code, 2) == ADDR_MODE_ZP)
assert($past(PC, 2) == $past(PC, 4) + 16'd2);
else if ($past(address_code, 2) == ADDR_MODE_IMMEDIATE)
assert($past(PC, 1) == $past(PC, 3) + 16'd2);
end
end
always @(posedge clk)
if (f2_past_valid && state == STATE_FETCH)
if ($past(decoded_instr) == I_BNE && $past(address_code) == ADDR_MODE_RELATIVE)
begin
if ($past(state) == STATE_BRANCH)
begin
assert(PC == $past(PC) + {{8{$past(mem_data[7])}}, mem_data[7:0]} + 1'b1);
assert(!$past(P[P_Z]));
end
else
begin
assert(PC == $past(PC) + 1'b1);
assert($past(P[P_Z]));
end
end
always @(posedge clk)
if (f3_past_valid && state == STATE_FETCH)
if ($past(decoded_instr) == I_JMP && $past(address_code) == ADDR_MODE_ABSOLUTE)
begin
assert(PC == $past(f_abs_address));
assert(P == $past(P, 3));
assert(S == $past(S, 3));
assert(A == $past(A, 3));
assert(X == $past(X, 3));
assert(Y == $past(Y, 3));
end
always @(posedge clk)
if (f_past_valid)
assume(state != $past(state));
always @(posedge clk)
cover(state == STATE_EXECUTE);
`endif
endmodule

350
src/decoder.verilog

@ -1,171 +1,305 @@ @@ -1,171 +1,305 @@
`default_nettype none
module decoder
(
input clk,
input rst,
input [7:0] instr,
output reg [3:0] address_code,
output reg [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 @* begin
if (rst) begin
address_code <= 0;
end
else begin
always_comb 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);
5: decoded <= I_LDA;
6: decoded <= I_CMP;
7: decoded <= I_SBC;
0: decoded = I_ORA;
1: decoded = I_AND;
2: decoded = I_EOR;
3: decoded = I_ADC;
4: decoded = (column == 2 ? I_NOP : I_STA);
5: decoded = I_LDA;
6: decoded = I_CMP;
7: decoded = I_SBC;
endcase
address_code <= column;
address_code = column;
end
else if (sector == 2) begin
case (row)
0: decoded <= (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_ASL));
1: decoded <= (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_ROL));
2: decoded <= (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_LSR));
3: decoded <= (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_ROR));
4: decoded <= (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : (column[0] ? I_STX : I_TXA)));
5: decoded <= (sec_2_stp ? I_STP : (column == 2 ? I_TAX : (column == 6 ? I_TSX : I_LDX)));
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));
0: decoded = (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_ASL));
1: decoded = (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_ROL));
2: decoded = (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_LSR));
3: decoded = (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : I_ROR));
4: decoded = (sec_2_stp ? I_STP : (sec_2_nop ? I_NOP : (column[0] ? I_STX : I_TXA)));
5: decoded = (sec_2_stp ? I_STP : (column == 2 ? I_TAX : (column == 6 ? I_TSX : I_LDX)));
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
case (row)
0: decoded <= I_BRK;
1: decoded <= I_JSR;
2: decoded <= I_RTI;
3: decoded <= I_RTS;
4: decoded <= I_NOP;
5: decoded <= I_LDY;
6: decoded <= I_CPY;
7: decoded <= I_CPX;
0: decoded = I_BRK;
1: decoded = I_JSR;
2: decoded = I_RTI;
3: decoded = I_RTS;
4: decoded = I_NOP;
5: decoded = I_LDY;
6: decoded = I_CPY;
7: decoded = I_CPX;
endcase
end
else if (column == 1) begin
case (row)
0: decoded <= I_NOP;
1: decoded <= I_BIT;
2: decoded <= I_NOP;
3: decoded <= I_NOP;
4: decoded <= I_STY;
5: decoded <= I_LDY;
6: decoded <= I_CPY;
7: decoded <= I_CPX;
0: decoded = I_NOP;
1: decoded = I_BIT;
2: decoded = I_NOP;
3: decoded = I_NOP;
4: decoded = I_STY;
5: decoded = I_LDY;
6: decoded = I_CPY;
7: decoded = I_CPX;
endcase
end
else if (column == 2) begin
case (row)
0: decoded <= I_PHP;
1: decoded <= I_PLP;
2: decoded <= I_PHA;
3: decoded <= I_PLA;
4: decoded <= I_DEY;
5: decoded <= I_TAY;
6: decoded <= I_INY;
7: decoded <= I_INX;
0: decoded = I_PHP;
1: decoded = I_PLP;
2: decoded = I_PHA;
3: decoded = I_PLA;
4: decoded = I_DEY;
5: decoded = I_TAY;
6: decoded = I_INY;
7: decoded = I_INX;
endcase
end
else if (column == 3) begin
case (row)
0: decoded <= I_NOP;
1: decoded <= I_BIT;
2: decoded <= I_JMP;
3: decoded <= I_JMP;
4: decoded <= I_STY;
5: decoded <= I_LDY;
6: decoded <= I_CPY;
7: decoded <= I_CPX;
0: decoded = I_NOP;
1: decoded = I_BIT;
2: decoded = I_JMP;
3: decoded = I_JMP;
4: decoded = I_STY;
5: decoded = I_LDY;
6: decoded = I_CPY;
7: decoded = I_CPX;
endcase
end
else if (column == 4) begin
case (row)
0: decoded <= I_BPL;
1: decoded <= I_BMI;
2: decoded <= I_BVC;
3: decoded <= I_BVS;
4: decoded <= I_BCC;
5: decoded <= I_BCS;
6: decoded <= I_BNE;
7: decoded <= I_BEQ;
0: decoded = I_BPL;
1: decoded = I_BMI;
2: decoded = I_BVC;
3: decoded = I_BVS;
4: decoded = I_BCC;
5: decoded = I_BCS;
6: decoded = I_BNE;
7: decoded = I_BEQ;
endcase
end
else if (column == 5) begin
case (row)
0: decoded <= I_NOP;
1: decoded <= I_NOP;
2: decoded <= I_NOP;
3: decoded <= I_NOP;
4: decoded <= I_STY;
5: decoded <= I_LDY;
6: decoded <= I_NOP;
7: decoded <= I_NOP;
0: decoded = I_NOP;
1: decoded = I_NOP;
2: decoded = I_NOP;
3: decoded = I_NOP;
4: decoded = I_STY;
5: decoded = I_LDY;
6: decoded = I_NOP;
7: decoded = I_NOP;
endcase
end
else if (column == 6) begin
case (row)
0: decoded <= I_CLC;
1: decoded <= I_SEC;
2: decoded <= I_CLI;
3: decoded <= I_SEI;
4: decoded <= I_TYA;
5: decoded <= I_CLV;
6: decoded <= I_CLD;
7: decoded <= I_SED;
0: decoded = I_CLC;
1: decoded = I_SEC;
2: decoded = I_CLI;
3: decoded = I_SEI;
4: decoded = I_TYA;
5: decoded = I_CLV;
6: decoded = I_CLD;
7: decoded = I_SED;
endcase
end
else if (column == 7) begin
case (row)
0: decoded <= I_NOP;
1: decoded <= I_NOP;
2: decoded <= I_NOP;
3: decoded <= I_NOP;
4: decoded <= I_SHY;
5: decoded <= I_LDY;
6: decoded <= I_NOP;
7: decoded <= I_NOP;
0: decoded = I_NOP;
1: decoded = I_NOP;
2: decoded = I_NOP;
3: decoded = I_NOP;
4: decoded = I_SHY;
5: decoded = I_LDY;
6: decoded = I_NOP;
7: decoded = I_NOP;
endcase
end
end
if (column > 0) begin
address_code <= column;
if (sector == 0) begin
if (column == 0) begin
if (row == 0 || (row >= 2 && row <= 4)) begin
address_code = ADDR_MODE_IMPLIED;
end
else if (row == 1) begin
address_code = ADDR_MODE_ABSOLUTE;
end
else begin
if (row >= 4) begin
address_code <= ADDR_MODE_IMMEDIATE;
address_code = ADDR_MODE_IMMEDIATE;
end
end
else if(column == 1) begin
address_code = ADDR_MODE_ZP;
end
else if (column == 2) begin
address_code = ADDR_MODE_IMPLIED;
end
else if (column == 3) begin
if (row == 2) begin
address_code = ADDR_MODE_ABSOLUTE;
end
else begin
address_code <= ADDR_MODE_ABSOLUTE;
address_code = ADDR_MODE_INDEXED_ABSOLUTE;
end
end
else if (column == 4) begin
address_code = ADDR_MODE_RELATIVE;
end
else if (column == 5) begin
address_code = ADDR_MODE_INDEXED_ZP;
end
else if (column == 6) begin
address_code = ADDR_MODE_IMPLIED;
end
else if (column == 7) begin
address_code = ADDR_MODE_INDEXED_ABSOLUTE;
end
end
else if(sector == 1) begin
if (column == 0) begin
address_code = ADDR_MODE_PREINDEXED_INDIRECT;
end
else if (column == 1) begin
address_code = ADDR_MODE_ZP;
end
else if (column == 2) begin
address_code = ADDR_MODE_IMMEDIATE;
end
else if (column == 3) begin
address_code = ADDR_MODE_ABSOLUTE;
end
else if (column == 4) begin
address_code = ADDR_MODE_POSTINDEXED_INDIRECT;
end
else if (column == 5) begin
address_code = ADDR_MODE_INDEXED_ZP;
end
else if (column == 6 || column == 7) begin
address_code = ADDR_MODE_INDEXED_ABSOLUTE;
end
end
else if(sector == 2) begin
if (column == 0) begin
address_code = ADDR_MODE_IMMEDIATE;
end
else if (column == 1) begin
address_code = ADDR_MODE_ZP;
end
else if (column == 2 || column == 6) begin
address_code = ADDR_MODE_IMPLIED;
end
else if (column == 3) begin
address_code = ADDR_MODE_ABSOLUTE;
end
// column == 4 are invalid opcodes
else if (column == 5) begin
address_code = ADDR_MODE_INDEXED_ZP;
end
else if (column == 7) begin
address_code = ADDR_MODE_INDEXED_ABSOLUTE;
end
end
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

69
src/mio.verilog

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
`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;
reg [14:0] mem_addr;
`ifndef VERILOG
//output wire [7:0] o_data;
//wire rst;
//wire ce;
//assign rst = 0;
//assign ce = 1;
`endif
output logic [7:0] o_data;
output logic [5:0] o_led;
reg [7:0] memory [0:32768];
initial o_led = 6'h3f;
`ifndef FORMAL
initial $readmemh("foo.hex", memory, 0, 32);
initial begin
for (integer i = 32; i < 256; i++)
begin
memory[i] = 0;
end
end
`else
reg f_init_done = 0;
always @(posedge clk)
begin
if (!f_init_done)
begin
for (integer i = 0; i < 32; i++)
begin
memory[i] = $anyconst;
end
f_init_done <= 1'b1;
end
end
`endif
always_comb
mem_addr = i_addr[14:0];
always @(posedge clk)
o_data <= memory[mem_addr];
always @(posedge clk)
if (i_wr)
begin
if (i_addr < 16'h8000)
begin
memory[mem_addr] <= i_data;
end
else if (i_addr == 16'h8000)
begin
o_led <= i_data[5:0];
end
end
endmodule

174
src/parameters.vh

@ -1,90 +1,100 @@ @@ -1,90 +1,100 @@
parameter ADDR_MODE_INDEXED_INDIRECT = 0;
parameter ADDR_MODE_ZP = 1;
parameter ADDR_MODE_IMMEDIATE = 2;
parameter ADDR_MODE_ABSOLUTE = 3;
parameter ADDR_MODE_INDIRECT_INDEXED = 4;
parameter ADDR_MODE_ZP_X = 5;
parameter ADDR_MODE_ABS_Y = 6;
parameter ADDR_MODE_ABS_X = 7;
localparam ADDR_MODE_IMPLIED = 0;
localparam ADDR_MODE_IMMEDIATE = 1;
localparam ADDR_MODE_ABSOLUTE = 2;
localparam ADDR_MODE_ZP = 3;
localparam ADDR_MODE_INDEXED_ABSOLUTE = 4;
localparam ADDR_MODE_INDEXED_ZP = 5;
localparam ADDR_MODE_INDIRECT = 6;
localparam ADDR_MODE_PREINDEXED_INDIRECT = 7;
localparam ADDR_MODE_POSTINDEXED_INDIRECT = 8;
localparam ADDR_MODE_RELATIVE = 9;
parameter OP_OR = 0;
parameter OP_AND = 1;
parameter OP_EOR = 2;
parameter OP_ADC = 3;
parameter OP_SUB = 4;
parameter OP_ROT = 5;
parameter OP_SHF = 6;
localparam OP_OR = 0;
localparam OP_AND = 1;
localparam OP_EOR = 2;
localparam OP_ADC = 3;
localparam OP_SUB = 4;
localparam OP_ROT = 5;
localparam OP_SHF = 6;
parameter SHIFT_LEFT = 0;
parameter SHIFT_RIGHT = 1;
localparam SHIFT_LEFT = 0;
localparam SHIFT_RIGHT = 1;
parameter I_LDA = 0;
parameter I_LDX = 1;
parameter I_LDY = 2;
parameter I_STA = 3;
parameter I_STX = 4;
parameter I_STY = 5;
parameter I_TAX = 6;
parameter I_TAY = 7;
parameter I_TXA = 8;
parameter I_TYA = 9;
parameter I_TSX = 10;
parameter I_TXS = 11;
parameter I_PHA = 12;
parameter I_PHP = 13;
parameter I_PLA = 14;
parameter I_PLP = 15;
parameter I_AND = 16;
parameter I_EOR = 17;
parameter I_ORA = 18;
parameter I_BIT = 19;
parameter I_ADC = 20;
parameter I_SBC = 21;
parameter I_CMP = 22;
parameter I_CPX = 23;
parameter I_CPY = 24;
parameter I_INC = 25;
parameter I_INX = 26;
parameter I_INY = 27;
parameter I_DEC = 28;
parameter I_DEX = 29;
parameter I_DEY = 30;
parameter I_ASL = 31;
parameter I_LSR = 32;
parameter I_ROL = 33;
parameter I_ROR = 34;
parameter I_JMP = 35;
parameter I_JSR = 36;
parameter I_RTS = 37;
parameter I_BCC = 38;
parameter I_BCS = 39;
parameter I_BEQ = 40;
parameter I_BMI = 41;
parameter I_BNE = 42;
parameter I_BPL = 43;
parameter I_BVC = 44;
parameter I_BVS = 45;
parameter I_CLC = 46;
parameter I_CLD = 47;
parameter I_CLI = 48;
parameter I_CLV = 49;
parameter I_SEC = 50;
parameter I_SED = 51;
parameter I_SEI = 52;
parameter I_BRK = 53;
parameter I_NOP = 54;
parameter I_RTI = 55;
localparam I_LDA = 0;
localparam I_LDX = 1;
localparam I_LDY = 2;
localparam I_STA = 3;
localparam I_STX = 4;
localparam I_STY = 5;
localparam I_TAX = 6;
localparam I_TAY = 7;
localparam I_TXA = 8;
localparam I_TYA = 9;
localparam I_TSX = 10;
localparam I_TXS = 11;
localparam I_PHA = 12;
localparam I_PHP = 13;
localparam I_PLA = 14;
localparam I_PLP = 15;
localparam I_AND = 16;
localparam I_EOR = 17;
localparam I_ORA = 18;
localparam I_BIT = 19;
localparam I_ADC = 20;
localparam I_SBC = 21;
localparam I_CMP = 22;
localparam I_CPX = 23;
localparam I_CPY = 24;
localparam I_INC = 25;
localparam I_INX = 26;
localparam I_INY = 27;
localparam I_DEC = 28;
localparam I_DEX = 29;
localparam I_DEY = 30;
localparam I_ASL = 31;
localparam I_LSR = 32;
localparam I_ROL = 33;
localparam I_ROR = 34;
localparam I_JMP = 35;
localparam I_JSR = 36;
localparam I_RTS = 37;
localparam I_BCC = 38;
localparam I_BCS = 39;
localparam I_BEQ = 40;
localparam I_BMI = 41;
localparam I_BNE = 42;
localparam I_BPL = 43;
localparam I_BVC = 44;
localparam I_BVS = 45;
localparam I_CLC = 46;
localparam I_CLD = 47;
localparam I_CLI = 48;
localparam I_CLV = 49;
localparam I_SEC = 50;
localparam I_SED = 51;
localparam I_SEI = 52;
localparam I_BRK = 53;
localparam I_NOP = 54;
localparam I_RTI = 55;
// Unofficial opcodes
parameter I_STP = 56;
parameter I_SHY = 57;
localparam I_STP = 56;
localparam I_SHY = 57;
parameter P_N = 8'h80;
parameter P_V = 8'h40;
parameter P_B = 8'h10;
parameter P_D = 8'h08;
parameter P_I = 8'h04;
parameter P_Z = 8'h02;
parameter P_C = 8'h01;
localparam P_N = 7;
localparam P_V = 6;
localparam P_B = 5;
localparam P_D = 3;
localparam P_I = 2;
localparam P_Z = 1;
localparam P_C = 0;
localparam DMUX_PC = 3'h0;
localparam DMUX_A = 3'h1;
localparam DMUX_X = 3'h2;
localparam DMUX_Y = 3'h3;
localparam DMUX_SP = 3'h4;
localparam DMUX_AUX = 3'h5;

32
src/slon.sby

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
[tasks]
prf
cvr
[options]
prf: mode prove
prf: depth 20
cvr: mode cover
cvr: depth 40
[engines]
smtbmc yices
[script]
read -formal decoder.verilog
read -formal cpu.verilog
read -formal mio.verilog
read -formal alu.verilog
read -formal dmux.verilog
read -formal parameters.vh
hierarchy -top cpu
proc -norom
prep -top cpu
[files]
decoder.verilog
cpu.verilog
mio.verilog
alu.verilog
dmux.verilog
parameters.vh

24
src/slon_decoder.sby

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
[tasks]
prf
cvr
[options]
prf: mode prove
prf: depth 40
cvr: mode cover
cvr: depth 40
[engines]
smtbmc yices
[script]
read -formal decoder.verilog
read -formal parameters.vh
hierarchy -top decoder
proc -norom
prep -top decoder
[files]
decoder.verilog
parameters.vh

44
tests/test_alu.verilog

@ -11,9 +11,6 @@ if (signal !== value) begin \ @@ -11,9 +11,6 @@ if (signal !== value) begin \
end
reg nrst = 1;
reg clk = 0;
reg [7:0] A;
reg [7:0] B;
reg C;
@ -25,11 +22,9 @@ if (signal !== value) begin \ @@ -25,11 +22,9 @@ if (signal !== value) begin \
wire r_c;
wire r_v;
always #1 clk = !clk;
`include "parameters.vh"
alu my_alu(
.nrst(nrst),
.clk(clk),
.A(A),
.B(B),
.C(C),
@ -41,18 +36,22 @@ if (signal !== value) begin \ @@ -41,18 +36,22 @@ if (signal !== value) begin \
.r_v(r_v));
initial begin
// Testing OR
#10 A = 8'h11;
B = 8'h22;
C = 0;
op_sel = 0; // OR
op_sel = OP_OR;
#2 `assert (result, 8'h33);
#2 op_sel = 1; // AND
// Testing AND
#2 op_sel = OP_AND;
#2 `assert (result, 8'h00);
#2 op_sel = 2; // EOR
// Testing EOR
#2 op_sel = OP_EOR;
#2 `assert (result, 8'h33);
@ -61,14 +60,18 @@ if (signal !== value) begin \ @@ -61,14 +60,18 @@ if (signal !== value) begin \
#2 `assert (result, 8'h00);
#2 op_sel = 3; // ADC
// Testing ADC
// Without carry
#2 op_sel = OP_ADC;
#2 A = 8'h22;
B = 8'h22;
C = 0;
#2 `assert (result, 8'h44);
#2 C = 1; // ADD with CARRY
// With carry
#2 C = 1;
#2 `assert (result, 8'h45);
@ -78,7 +81,8 @@ if (signal !== value) begin \ @@ -78,7 +81,8 @@ if (signal !== value) begin \
#2 `assert (r_c, 1);
#2 op_sel = 4;
// Test SUB
#2 op_sel = OP_SUB;
A = 8'hf0;
B = 8'h10;
C = 0;
@ -88,10 +92,11 @@ if (signal !== value) begin \ @@ -88,10 +92,11 @@ if (signal !== value) begin \
#2 `assert (result, 8'he0);
#2 op_sel = 5;
// Test ROT
#2 op_sel = OP_ROT;
A = 8'hf0;
B = 8'h00;
B = SHIFT_LEFT;
C = 1;
#2 `assert (result, 8'he1);
@ -101,7 +106,7 @@ if (signal !== value) begin \ @@ -101,7 +106,7 @@ if (signal !== value) begin \
#2 `assert (result, 8'he0);
#2 B = 1;
#2 B = SHIFT_RIGHT;
C = 0;
#2 `assert (result, 8'h78);
@ -112,7 +117,14 @@ if (signal !== value) begin \ @@ -112,7 +117,14 @@ if (signal !== value) begin \
#2 `assert (result, 8'hf8);
`assert (r_c, 1);
#2 op_sel = 6;
// Test SHF
#2 op_sel = OP_SHF;
A = 8'hf9;
B = SHIFT_LEFT;
#1 `assert (result, 8'hf2);
B = SHIFT_RIGHT;
#1 `assert (result, 8'h7c);
#500 $finish;
end

Loading…
Cancel
Save