164 lines
5.7 KiB
Verilog
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
|