173 lines
4.4 KiB
Systemverilog
173 lines
4.4 KiB
Systemverilog
`default_nettype none
|
|
|
|
module CPU(
|
|
input var logic enable,
|
|
input var logic clock,
|
|
input var logic reset,
|
|
|
|
// TODO: Replace with Input/Output module
|
|
input var logic[7:0] cpuin,
|
|
output var logic[7:0] cpuout,
|
|
|
|
// Debug Outputs
|
|
output var logic dbg_fetch,
|
|
output var logic dbg_decode,
|
|
output var logic dbg_execute,
|
|
output var logic dbg_writeback,
|
|
output var logic[7:0] dbg_pcout,
|
|
output var logic[7:0] dbg_romout,
|
|
output var logic[7:0] dbg_savebus,
|
|
output var logic[7:0] dbg_loadbus,
|
|
output var logic[7:0] dbg_jumptarget,
|
|
output var logic[7:0] dbg_aluopA,
|
|
output var logic[7:0] dbg_aluopB,
|
|
output var logic[7:0] dbg_aluresult
|
|
);
|
|
|
|
// Decoder
|
|
var logic fetch, decode, execute, writeback, clk;
|
|
assign clk = enable && clock; // Only clock the CPU when enabled
|
|
Decoder dec(
|
|
.clock(clk),
|
|
.reset(reset),
|
|
.fetch(fetch),
|
|
.decode(decode),
|
|
.execute(execute),
|
|
.writeback(writeback)
|
|
);
|
|
|
|
// Program Counter
|
|
var logic pc_set;
|
|
var logic[7:0] pc_in, pc_out;
|
|
Counter pc(
|
|
.clock(fetch), // WARNING: Phase 1 - Fetch
|
|
.reset(reset),
|
|
.decrement(0),
|
|
.setvalue(pc_set),
|
|
.valuein(pc_in),
|
|
.valueout(pc_out)
|
|
);
|
|
|
|
// ROM (Instruction Memory)
|
|
var logic[7:0] rom_data;
|
|
ROM rom(
|
|
.address(pc_out),
|
|
.dataout(rom_data)
|
|
);
|
|
|
|
// Controller
|
|
var logic ctrl_regsset, ctrl_pcset;
|
|
var logic[1:0] ctrl_opcode;
|
|
var logic[2:0] ctrl_arg0, ctrl_arg1, ctrl_regssavesel, ctrl_regsloadsel, ctrl_aluopc, ctrl_condopc;
|
|
var logic[5:0] ctrl_arg;
|
|
Controller ctrl(
|
|
.clock(decode), // WARNING: Phase 2 - Decode
|
|
.reset(reset),
|
|
.databus(rom_data),
|
|
.opcode(ctrl_opcode),
|
|
.arg(ctrl_arg),
|
|
.arg0(ctrl_arg0),
|
|
.arg1(ctrl_arg1),
|
|
.regs_set(ctrl_regsset),
|
|
.regs_savesel(ctrl_regssavesel),
|
|
.regs_loadsel(ctrl_regsloadsel),
|
|
.alu_opc(ctrl_aluopc),
|
|
.cond_opc(ctrl_condopc),
|
|
.pc_set(ctrl_pcset)
|
|
);
|
|
|
|
// Register Bank
|
|
var logic regs_set;
|
|
var logic[7:0] regs_savebus, regs_loadbus, regs_jumptarget, regs_aluopA, regs_aluopB, regs_aluresult;
|
|
RegisterFile regs(
|
|
.clock(writeback), // WARNING: Phase 4 - Writeback
|
|
.reset(reset),
|
|
.save(regs_set),
|
|
.saveselector(ctrl_regssavesel),
|
|
.savebus(regs_savebus),
|
|
.loadselector(ctrl_regsloadsel),
|
|
.loadbus(regs_loadbus),
|
|
.jumptarget(regs_jumptarget),
|
|
.aluoperandA(regs_aluopA),
|
|
.aluoperandB(regs_aluopB),
|
|
.aluresult(regs_aluresult)
|
|
);
|
|
|
|
// Arithmetic and Logical Unit
|
|
var logic[7:0] alu_result;
|
|
ALU alu(
|
|
// .clock(execute), // WARNING: Phase 3 - Execute // TODO
|
|
.opcode(ctrl_aluopc),
|
|
.operandA(regs_aluopA),
|
|
.operandB(regs_aluopB),
|
|
.result(alu_result)
|
|
);
|
|
|
|
// Conditional Unit
|
|
var logic cond_result;
|
|
ConditionalUnit cond(
|
|
// .clock(execute), // WARNING: Phase 3 - Execute // TODO
|
|
.opcode(ctrl_condopc),
|
|
.operand(regs_aluresult),
|
|
.result(cond_result)
|
|
);
|
|
|
|
// Missing CPU Inter-Component Connections
|
|
assign pc_set = cond_result && ctrl_pcset;
|
|
assign pc_in = regs_jumptarget;
|
|
assign regs_set = ctrl_regsset && (ctrl_arg0 != 3'b110);
|
|
|
|
// FIXME: ALU writeback doesn't work:
|
|
// - Execute clocks the ALU
|
|
// - Execute connects alu_result to regs_savebus.
|
|
// This has to happen after the ALU was clocked.
|
|
// Remove the ALU/Cond clock entirely (for now)?
|
|
// TODO: Should add this to the Controller probably?
|
|
// Or a new module, like "BusController"? Or just "Bus"?
|
|
always @(execute) case (ctrl_opcode) // WARNING: Phase 3 - Execute ("Execute" currently means "BusControl")
|
|
2'b00: begin
|
|
// Load constant
|
|
cpuout = 8'b00000000;
|
|
regs_savebus = ctrl_arg;
|
|
end
|
|
2'b01: begin
|
|
// Save ALU result
|
|
cpuout = 8'b00000000;
|
|
regs_savebus = alu_result;
|
|
end
|
|
2'b10: if (ctrl_arg0 == 3'b110) begin
|
|
// Write to output
|
|
cpuout = regs_loadbus;
|
|
regs_savebus = 8'b00000000;
|
|
end else if (ctrl_arg1 == 3'b110) begin
|
|
// Load from input
|
|
cpuout = 8'b00000000;
|
|
regs_savebus = cpuin;
|
|
end else begin
|
|
// Copy from reg to reg
|
|
cpuout = 8'b00000000;
|
|
regs_savebus = regs_loadbus;
|
|
end
|
|
default: begin
|
|
// Conditional jump
|
|
cpuout = 8'b00000000;
|
|
regs_savebus = 8'b00000000;
|
|
end
|
|
endcase
|
|
|
|
// Debug outputs
|
|
assign dbg_fetch = fetch;
|
|
assign dbg_decode = decode;
|
|
assign dbg_execute = execute;
|
|
assign dbg_writeback = writeback;
|
|
assign dbg_pcout = pc_out;
|
|
assign dbg_romout = rom_data;
|
|
assign dbg_savebus = regs_savebus;
|
|
assign dbg_loadbus = regs_loadbus;
|
|
assign dbg_jumptarget = regs_jumptarget;
|
|
assign dbg_aluopA = regs_aluopA;
|
|
assign dbg_aluopB = regs_aluopB;
|
|
assign dbg_aluresult = regs_aluresult;
|
|
|
|
endmodule
|