vchip8/cpu.v

164 lines
5.7 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
module core (
input reset,
input cpu_clock,
input timer_clock,
input [15:0] keypad
);
// 4k (12 bits) of 8-bit ram
reg [7:0] ram[0:4095];
// 16 8-bit V registers
reg [7:0] v[0:15];
// 16-bit I register
reg [15:0] i;
// 12-bit program counter
reg [11:0] pc;
// 8-bit stack pointer
reg [7: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 family = (ins >> 12);
// ALU operation
wire [3:0] alu_op = ins & 4'hF;
// ALU source registers
wire [3:0] alu_x = (ins >> 8) & 4'hF;
wire [3:0] alu_y = (ins >> 4) & 4'hF;
// ALU immediate
wire [7:0] kk = ins & 8'hFF;
wire [11:0] nnn = ins & 12'hFFF;
// Jump register
reg[15:0] jmp;
// Should jump on FETCH?
reg should_jmp;
always @(cpu_clock)
begin
if (!reset) begin
i <= 0;
pc <= 0;
sp <= 0;
should_jmp <= 0;
end else begin
case(c)
`FETCH: begin
ins <= ram[pc] << 8 | ram[pc + 1];
end
`EXECUTE: begin
case (family)
// Jump to address
1: begin
should_jmp <= 1;
jmp <= nnn;
end
// Call address
2: begin
should_jmp <= 1;
ram[sp] <= pc;
sp <= sp + 1;
jmp <= nnn;
end
// Skip next if Vx == kk (3xkk)
3: begin
if (v[alu_x] == kk) begin
should_jmp <= 1;
jmp <= pc + 4;
end
end
// Skip next if Vx != kk (4xkk)
4: begin
if (v[alu_x] != kk) begin
should_jmp <= 1;
jmp <= pc + 4;
end
end
// Skip next if Vx == Vy (5xy0)
5: begin
if (v[alu_x] == v[alu_y]) begin
should_jmp <= 1;
jmp <= pc + 4;
end
end
// Vx <= kk
6: v[alu_x] <= kk;
// Vx += kk
7: v[alu_x] <= v[alu_x] + kk;
// ALU operation
8: case(alu_op)
0: v[alu_x] <= v[alu_y];
1: v[alu_x] <= v[alu_x] | v[alu_y];
2: v[alu_x] <= v[alu_x] & v[alu_y];
3: v[alu_x] <= v[alu_x] ^ v[alu_y];
4: { v[15], v[alu_x] } <= v[alu_x] + v[alu_y];
5: { v[15], v[alu_x] } <= (v[alu_x] - v[alu_y]) ^ (1 << 8);
6: begin
v[15] <= v[alu_x][0];
v[alu_x] <= v[alu_x] >> 1;
end
7: { v[15], v[alu_x] } <= (v[alu_y] - v[alu_x]) ^ (1 << 8);
15: begin
v[15] <= v[alu_x][7];
v[alu_x] <= v[alu_x] << 1;
end
endcase
// Skip if Vx != Vy (9xy0)
9: begin
if (v[alu_x] != v[alu_y]) begin
should_jmp <= 1;
jmp <= pc + 4;
end
end
// Set I to nnn
10: i <= nnn;
// Jump to nnn + V0
11: begin
should_jmp <= 1;
jmp <= nnn + v[0];
end
// Set Vx to random and kk
// TODO: undo fair dice roll
12: v[alu_x] <= 42 & kk;
// TODO: draw sprites
13: begin end
// Key functions
14: begin
if (kk == 8'h9E) begin
if ((keypad >> alu_x) & 1) begin
should_jmp <= 1;
jmp <= pc + 4;
end
end else if (kk == 8'hA1) begin
if (((keypad >> alu_x) & 1) == 0) begin
should_jmp <= 1;
jmp <= pc + 4;
end
end
end
endcase
end
`WRITEBACK: begin
if (should_jmp) begin
pc <= jmp;
end else begin
pc <= pc + 2;
end
should_jmp <= 0;
end
endcase
end
end
endmodule