202 lines
6.3 KiB
Verilog
202 lines
6.3 KiB
Verilog
// Copyright (c) 2014 Sergiusz 'q3k' BazaĆski <sergiusz@bazanski.pl>
|
|
// Licensed under 2-clause BSD - see COPYING file from software distribution
|
|
|
|
`timescale 1ns / 1ps
|
|
|
|
/* verilator lint_off UNDRIVEN */
|
|
/* verilator lint_off UNUSED */
|
|
/* verilator lint_off LITENDIAN */
|
|
module cpu (
|
|
input reset,
|
|
input cpu_clock,
|
|
input [15:0] keypad
|
|
);
|
|
|
|
// 4k (12 bits) of 8-bit ram
|
|
reg [7:0] ram[0:4095]/* verilator public */;
|
|
// 16 8-bit V registers
|
|
reg [7:0] vr[0:15]/* verilator public */;
|
|
// 16-bit I register
|
|
reg [15:0] i;
|
|
// 12-bit program counter
|
|
reg [11:0] pc/* verilator public */;
|
|
// 16-element, 12-bit stack
|
|
reg [11:0] stack [0:15];
|
|
// 4-bit stack pointer
|
|
reg [3:0] sp;
|
|
|
|
// internal cycle counter (0 - fetch)
|
|
`define FETCH 0
|
|
`define EXECUTE 1
|
|
`define WRITEBACK 2
|
|
reg [1:0] c;
|
|
|
|
// Instruction register
|
|
reg [15:0] ins;
|
|
wire [3:0] family = ins[15:12];
|
|
|
|
// ALU operation
|
|
wire [3:0] alu_op = ins[3:0];
|
|
wire is_alu_op = (c == `EXECUTE) && (family == 8);
|
|
// Source register indexes
|
|
wire [3:0] x = ins[11:8];
|
|
wire [3:0] y = ins[7:4];
|
|
// Immediates
|
|
wire [7:0] kk = ins[7:0];
|
|
wire [11:0] nnn = ins[11:0];
|
|
|
|
// Jump register
|
|
reg[11:0] jmp;
|
|
// Should jump on FETCH?
|
|
reg should_jmp;
|
|
|
|
always @(posedge cpu_clock)
|
|
begin
|
|
if (!reset) begin
|
|
i <= 0;
|
|
pc <= 0;
|
|
sp <= 0;
|
|
should_jmp <= 0;
|
|
c <= 0;
|
|
|
|
vr[0] <= 0;
|
|
vr[1] <= 0;
|
|
vr[2] <= 0;
|
|
vr[3] <= 0;
|
|
vr[4] <= 0;
|
|
vr[5] <= 0;
|
|
vr[6] <= 0;
|
|
vr[7] <= 0;
|
|
vr[8] <= 0;
|
|
vr[9] <= 0;
|
|
vr[10] <= 0;
|
|
vr[11] <= 0;
|
|
vr[12] <= 0;
|
|
vr[13] <= 0;
|
|
vr[14] <= 0;
|
|
vr[15] <= 0;
|
|
end else begin
|
|
case(c)
|
|
`FETCH: begin
|
|
ins <= {ram[pc], ram[pc + 1]};
|
|
c <= 1;
|
|
end
|
|
`EXECUTE: begin
|
|
case (family)
|
|
// Jump to address
|
|
1: begin
|
|
should_jmp <= 1;
|
|
jmp <= nnn;
|
|
end
|
|
// Call address
|
|
2: begin
|
|
should_jmp <= 1;
|
|
stack[sp] <= pc;
|
|
sp <= sp + 1;
|
|
jmp <= nnn;
|
|
end
|
|
// Skip next if Vx == kk (3xkk)
|
|
3: begin
|
|
if (vr[x] == kk) begin
|
|
should_jmp <= 1;
|
|
jmp <= pc + 4;
|
|
end
|
|
end
|
|
// Skip next if Vx != kk (4xkk)
|
|
4: begin
|
|
if (vr[x] != kk) begin
|
|
should_jmp <= 1;
|
|
jmp <= pc + 4;
|
|
end
|
|
end
|
|
// Skip next if Vx == Vy (5xy0)
|
|
5: begin
|
|
if (vr[x] == vr[y]) begin
|
|
should_jmp <= 1;
|
|
jmp <= pc + 4;
|
|
end
|
|
end
|
|
// Vx <= kk
|
|
6: vr[x] <= kk;
|
|
// Vx += kk
|
|
7: vr[x] <= vr[x] + kk;
|
|
// Skip if Vx != Vy (9xy0)
|
|
9: begin
|
|
if (vr[x] != vr[y]) begin
|
|
should_jmp <= 1;
|
|
jmp <= pc + 4;
|
|
end
|
|
end
|
|
// Set I to nnn
|
|
10: i <= {4'h0, nnn};
|
|
// Jump to nnn + V0
|
|
11: begin
|
|
should_jmp <= 1;
|
|
jmp <= nnn + {4'h0, vr[0]};
|
|
end
|
|
// Set Vx to random and kk
|
|
// TODO: undo fair dice roll
|
|
12: vr[x] <= 42 & kk;
|
|
// TODO: draw sprites
|
|
13: begin end
|
|
// Key functions
|
|
14: begin
|
|
if (kk == 8'h9E) begin
|
|
if (keypad[x]) begin
|
|
should_jmp <= 1;
|
|
jmp <= pc + 4;
|
|
end
|
|
end else if (kk == 8'hA1) begin
|
|
if (~keypad[x]) begin
|
|
should_jmp <= 1;
|
|
jmp <= pc + 4;
|
|
end
|
|
end
|
|
end
|
|
endcase
|
|
c <= 2;
|
|
end
|
|
`WRITEBACK: begin
|
|
if (should_jmp) begin
|
|
pc <= jmp;
|
|
end else begin
|
|
pc <= pc + 2;
|
|
end
|
|
should_jmp <= 0;
|
|
c <= 0;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// ALU
|
|
always @(posedge cpu_clock)
|
|
begin
|
|
if (is_alu_op) begin
|
|
case(alu_op)
|
|
0: vr[x] <= vr[y];
|
|
1: vr[x] <= vr[x] | vr[y];
|
|
2: vr[x] <= vr[x] & vr[y];
|
|
3: vr[x] <= vr[x] ^ vr[y];
|
|
4: { vr[15], vr[x] } <= {8'b0, vr[x]} + {8'b0, vr[y]};
|
|
5: begin
|
|
vr[x] <= vr[x] - vr[y];
|
|
vr[15] <= {7'b0, vr[x] >= vr[y]};
|
|
end
|
|
6: begin
|
|
vr[15] <= {7'b0, vr[x][0]};
|
|
vr[x] <= vr[x] >> 1;
|
|
end
|
|
7: begin
|
|
vr[x] <= vr[y] - vr[x];
|
|
vr[15] <= {7'b0, vr[y] >= vr[x]};
|
|
end
|
|
14: begin
|
|
vr[15] <= {7'b0, vr[x][7]};
|
|
vr[x] <= vr[x] << 1;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
endmodule
|