Skip to content

Commit

Permalink
feat: [labcpu] Add the fpga implementation (#42)
Browse files Browse the repository at this point in the history
* wip: blockram for cpu

* wip: cpu debugger

* wip: labcpu vivado and opensource

* wip: second clock for ram and init data

* fix: otp button

* fix: reg PC display

* fix: incPC and cheatsheet
  • Loading branch information
sdcioc authored Nov 24, 2024
1 parent 39408ec commit 982ee7b
Show file tree
Hide file tree
Showing 31 changed files with 6,779 additions and 986 deletions.
27 changes: 27 additions & 0 deletions common/verilog/core/clock_divider.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module clock_divider #(
parameter p_divisor = 2 // Clock division factor
) (
output reg o_w_clk, // Output divided clock
input wire i_w_clk, // Input clock
input wire i_w_reset // Reset signal
);

// Compute the size of the counter for the division
localparam l_p_counter_width = $clog2(p_divisor) + 1;
reg [l_p_counter_width:0] counter;

always @(posedge i_w_clk or negedge i_w_reset) begin
if (!i_w_reset) begin
counter <= 0;
o_w_clk <= 0;
end else begin
if (counter == (p_divisor - 1)) begin
counter <= 0;
o_w_clk <= ~o_w_clk;
end else begin
counter <= counter + 1;
end
end
end

endmodule
31 changes: 31 additions & 0 deletions common/verilog/core/debouncer.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module debouncer #(
parameter p_no_cycles = 1000000 // Clock cycles for debouncing
) (
output reg o_w_out, // Debounced output
input wire i_w_in, // Input signal
input wire i_w_clk, // Clock signal
input wire i_w_reset // Reset signal
);

// Compute the size of the counter for the debouncing
localparam l_p_counter_width = $clog2(p_no_cycles);
reg[(l_p_counter_width - 1):0] l_r_counter;

always @(posedge i_w_clk or negedge i_w_reset) begin
if(!i_w_reset) begin
l_r_counter <= 0;
o_w_out <= 0;
end else begin
if(i_w_in == o_w_out) begin
l_r_counter <= 0;
end else begin
if(l_r_counter == (p_no_cycles - 1)) begin
o_w_out <= i_w_in;
l_r_counter <= 0;
end else begin
l_r_counter <= l_r_counter + 1;
end
end
end
end
endmodule
16 changes: 2 additions & 14 deletions common/verilog/led7hex.v → common/verilog/core/led7hex.v
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
module led7conv (
output wire o_w_ca,
output wire o_w_cb,
output wire o_w_cc,
output wire o_w_cd,
output wire o_w_ce,
output wire o_w_cf,
output wire o_w_cg,
output wire o_w_dp,
module led7hex (
output reg [7:0] l_r_led7,
input wire [3:0] i_w_value
);
reg [7:0] l_r_led7;

always @(*) begin
case (i_w_value)
4'h0: l_r_led7 = 8'b1100_0000;
Expand All @@ -32,7 +23,4 @@ module led7conv (
default: l_r_led7 = 8'b1111_1111;
endcase
end

assign {o_w_dp, o_w_cg, o_w_cf, o_w_ce, o_w_cd, o_w_cc, o_w_cb, o_w_ca} = l_r_led7;

endmodule
42 changes: 42 additions & 0 deletions common/verilog/core/otp_button.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module otp_button (
output wire o_w_button_press,
input wire i_w_clk,
input wire i_w_button
);

localparam l_p_state_ButtonReleased = 2'd0;
localparam l_p_state_ButtonFirstPressed = 2'd1;
localparam l_p_state_ButtonPressed = 2'd2;

reg [1:0] l_r_state;
reg [1:0] l_r_next_state;

always @(posedge i_w_clk) begin
l_r_state <= l_r_next_state;
end

always @(*) begin
l_r_next_state = l_p_state_ButtonReleased;
case(l_r_state)
l_p_state_ButtonReleased: begin
if (i_w_button)
l_r_next_state = l_p_state_ButtonFirstPressed;
else
l_r_next_state = l_p_state_ButtonReleased;
end
l_p_state_ButtonFirstPressed: begin
l_r_next_state = l_p_state_ButtonPressed;
end
l_p_state_ButtonPressed: begin
if (i_w_button)
l_r_next_state = l_p_state_ButtonPressed;
else
l_r_next_state = l_p_state_ButtonReleased;
end
default: l_r_next_state = l_p_state_ButtonReleased;
endcase
end

assign o_w_button_press = (l_r_state == l_p_state_ButtonFirstPressed);

endmodule
37 changes: 27 additions & 10 deletions common/verilog/labcpu/Makefile
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
all: build

build: build_project/build.xpr
COMPILER=iverilog
INTERPRETER=vvp
SIMULATOR=gtkwave
FLAGS=-Wall -Winfloop

# TODO: use the command line to pass the following parameters
TOP_MODULE=cpu_debugger
OTHER_SOURCES=alu.v bus.v cpu.v control_unit.v cram.v state_display.v
RAM_DATA_FILE=cram.data
MEMORY_SOURCES=../memory/block_ram.v ../memory/block_dpram.v ../memory/register.v ../memory/regfile.v
CORE_SOURCES=../core/clock_divider.v ../core/debouncer.v ../core/led7hex.v ../core/otp_button.v

build_project/build.xpr:
vivado -mode batch -source tcl_files/build.tcl
# compute the filenames
TOP_MODULE_FILE=$(TOP_MODULE).v
TOP_SIM_MODULE_FILE=test_${TOP_MODULE}.v
TOP_MODULE_BIN=$(TOP_MODULE).vvp

run: build_project/build.xpr
vivado -mode batch -source tcl_files/run.tcl
all: build

simulation: build_project/build.xpr
vivado -mode batch -source tcl_files/simulation.tcl
build:
$(COMPILER) $(FLAGS) $(TOP_MODULE_FILE) $(TOP_SIM_MODULE_FILE) $(OTHER_SOURCES) $(MEMORY_SOURCES) $(CORE_SOURCES) -o $(TOP_MODULE_BIN)
@echo "Build completed"

vivado: build_project/build.xpr
vivado build_project/build.xpr
run: build
$(INTERPRETER) $(TOP_MODULE_BIN)

clean:
rm $(TOP_MODULE_BIN)

vivado:
vivado -mode batch -source tcl_files/vivado.tcl

clean_vivado:
rm -rf vivado*
rm -rf build_project
rm -rf .Xil
60 changes: 31 additions & 29 deletions common/verilog/labcpu/alu.v
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
`timescale 1ns / 1ps
module alu #(
parameter p_data_width = 16,
parameter p_flags_width = 5
)(
parameter p_flags_width = 5,
parameter p_opcode_width = 4,
parameter p_opcode_ADC = 4'd0,
parameter p_opcode_SBB1 = 4'd1,
parameter p_opcode_SBB2 = 4'd2,
parameter p_opcode_NOT = 4'd3,
parameter p_opcode_AND = 4'd4,
parameter p_opcode_OR = 4'd5,
parameter p_opcode_XOR = 4'd6,
parameter p_opcode_SHL = 4'd7,
parameter p_opcode_SHR = 4'd8,
parameter p_opcode_SAR = 4'd9
) (
output wire [(p_data_width-1):0] o_w_out,
output wire [(p_flags_width-1):0] o_w_flags,
input wire [(p_data_width-1):0] i_w_in1,
input wire [(p_data_width-1):0] i_w_in2,
input wire [3:0] i_w_opcode,
input wire [(p_opcode_width-1):0] i_w_opcode,
input wire i_w_carry,
input wire i_w_oe
);

localparam ADC = 4'd0;
localparam SBB1 = 4'd1;
localparam SBB2 = 4'd2;
localparam NOT = 4'd3;
localparam AND = 4'd4;
localparam OR = 4'd5;
localparam XOR = 4'd6;
localparam SHL = 4'd7;
localparam SHR = 4'd8;
localparam SAR = 4'd9;

// result
reg [(p_data_width-1) : 0] l_r_result;
// flags
reg l_r_parity;
reg l_r_sign;
reg l_r_zero;
Expand All @@ -32,61 +33,62 @@ reg l_r_carry;

always @(*) begin
case(i_w_opcode)
ADC: begin
p_opcode_ADC: begin
{l_r_carry, l_r_result} = i_w_in1 + i_w_in2 + i_w_carry;
l_r_overflow = (i_w_in1[p_data_width-1] == i_w_in2[p_data_width-1]) &&
(i_w_in1[p_data_width-1] != l_r_result[p_data_width-1]);
end

SBB1: begin
p_opcode_SBB1: begin
{l_r_carry, l_r_result} = i_w_in1 - i_w_in2 - i_w_carry;
l_r_overflow = (i_w_in1[p_data_width-1] != i_w_in2[p_data_width-1]) &&
(i_w_in1[p_data_width-1] != l_r_result[p_data_width-1]);
end

SBB2: begin
p_opcode_SBB2: begin
{l_r_carry, l_r_result} = i_w_in2 - i_w_in1 - i_w_carry;
l_r_overflow = (i_w_in2[p_data_width-1] != i_w_in1[p_data_width-1]) &&
(i_w_in2[p_data_width-1] != l_r_result[p_data_width-1]);
end

AND: begin
l_r_result = i_w_in1 & i_w_in2;
p_opcode_NOT: begin
l_r_result = ~(i_w_in1 | i_w_in2);
l_r_carry = 0;
l_r_overflow = 0;
end

OR: begin
l_r_result = i_w_in1 | i_w_in2;
p_opcode_AND: begin
l_r_result = i_w_in1 & i_w_in2;
l_r_carry = 0;
l_r_overflow = 0;
end

XOR: begin
l_r_result = i_w_in1 ^ i_w_in2;
p_opcode_OR: begin
l_r_result = i_w_in1 | i_w_in2;
l_r_carry = 0;
l_r_overflow = 0;
end

NOT: begin
l_r_result = ~(i_w_in1 | i_w_in2);
p_opcode_XOR: begin
l_r_result = i_w_in1 ^ i_w_in2;
l_r_carry = 0;
l_r_overflow = 0;
end

SHL: begin

p_opcode_SHL: begin
l_r_result = (i_w_in1 << 1) | (i_w_in2 << 1);
l_r_carry = i_w_in1[p_data_width-1] | i_w_in2[p_data_width - 1];
l_r_overflow = l_r_result[p_data_width-1] != l_r_carry;
end

SHR: begin
p_opcode_SHR: begin
l_r_result = (i_w_in1 >> 1) | (i_w_in2 >> 1);
l_r_carry = i_w_in1[0] | i_w_in2[0];
l_r_overflow = i_w_in1[p_data_width-1] | i_w_in2[p_data_width-1];
end

SAR: begin
p_opcode_SAR: begin
l_r_result = {i_w_in1[p_data_width-1], i_w_in1[p_data_width-1:1]} |
{i_w_in2[p_data_width-1], i_w_in2[p_data_width-1:1]};
l_r_carry = i_w_in1[0] | i_w_in2[0];
Expand Down
35 changes: 20 additions & 15 deletions common/verilog/labcpu/bus.v
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
`timescale 1ns / 1ps
`define DEBUG 1
module bus #(
parameter p_data_width = 16
) (
`ifdef DEBUG
output wire [(p_data_width - 1) : 0] o_w_disp_out,
`endif
output wire [(p_data_width - 1) : 0] o_w_bus_to_ram,
output wire [(p_data_width - 1) : 0] o_w_bus_to_io,
output wire [(p_data_width - 1) : 0] o_w_bus_to_regs,
output wire [(p_data_width - 1) : 0] o_w_bus_to_cp,
output wire [(p_data_width - 1) : 0] o_w_bus_to_ind,
output wire [(p_data_width - 1) : 0] o_w_bus_to_am,
output wire [(p_data_width - 1) : 0] o_w_bus_to_aie,
output wire [(p_data_width - 1) : 0] o_w_bus_to_pc,
output wire [(p_data_width - 1) : 0] o_w_bus_to_flags,
output wire [(p_data_width - 1) : 0] o_w_bus_to_ma,
output wire [(p_data_width - 1) : 0] o_w_bus_to_ioa,
output wire [(p_data_width - 1) : 0] o_w_bus_to_t1,
output wire [(p_data_width - 1) : 0] o_w_bus_to_t2,
output wire [(p_data_width - 1) : 0] o_w_bus_to_ri,
output wire [(p_data_width - 1) : 0] o_w_bus_to_ir,
input wire [(p_data_width - 1) : 0] i_w_alu_to_bus,
input wire [(p_data_width - 1) : 0] i_w_ram_to_bus,
input wire [(p_data_width - 1) : 0] i_w_io_to_bus,
input wire [(p_data_width - 1) : 0] i_w_regs_to_bus,
input wire [(p_data_width - 1) : 0] i_w_cp_to_bus,
input wire [(p_data_width - 1) : 0] i_w_ind_to_bus,
input wire [(p_data_width - 1) : 0] i_w_pc_to_bus,
input wire [(p_data_width - 1) : 0] i_w_flags_to_bus,
input wire [(p_data_width - 1) : 0] i_w_offset_to_bus
);

Expand All @@ -27,19 +30,21 @@ assign l_w_bus = i_w_alu_to_bus |
i_w_ram_to_bus |
i_w_io_to_bus |
i_w_regs_to_bus |
i_w_cp_to_bus |
i_w_ind_to_bus |
i_w_pc_to_bus |
i_w_flags_to_bus |
i_w_offset_to_bus;

assign o_w_bus_to_ram = l_w_bus;
assign o_w_bus_to_io = l_w_bus;
assign o_w_bus_to_regs = l_w_bus;
assign o_w_bus_to_cp = l_w_bus;
assign o_w_bus_to_ind = l_w_bus;
assign o_w_bus_to_am = l_w_bus;
assign o_w_bus_to_aie = l_w_bus;
assign o_w_bus_to_pc = l_w_bus;
assign o_w_bus_to_flags = l_w_bus;
assign o_w_bus_to_ma = l_w_bus;
assign o_w_bus_to_ioa = l_w_bus;
assign o_w_bus_to_t1 = l_w_bus;
assign o_w_bus_to_t2 = l_w_bus;
assign o_w_bus_to_ri = l_w_bus;
assign o_w_bus_to_ir = l_w_bus;

assign o_w_disp_out = l_w_bus;

endmodule
Loading

0 comments on commit 982ee7b

Please sign in to comment.