Skip to content

Instantly share code, notes, and snippets.

@bit-hack
Last active January 10, 2020 18:14
Show Gist options
  • Save bit-hack/4866782e1e1cce60f8ec769d1eba3968 to your computer and use it in GitHub Desktop.
Save bit-hack/4866782e1e1cce60f8ec769d1eba3968 to your computer and use it in GitHub Desktop.
First cpu implementation scratchpad
`default_nettype none
`timescale 1ns / 1ps
module rom16x256(
input in_clk,
input in_rst,
input [7:0] in_addr,
output [15:0] out_data);
assign out_data = rom[ in_addr ];
reg [15:0] rom [255:0];
always @(posedge in_clk) begin
if (in_rst) begin
/**
rom[0] <= 16'b011_00_00000000_000; // mov R0 0
rom[1] <= 16'b011_00_00000001_001; // mov R1 1
rom[2] <= 16'b011_00_00000111_010; // mov R2 7
rom[3] <= 16'b001_0000_000_001_000; // add R0 R0 R1
rom[4] <= 16'b010_01_00_000_010_000; // st R2 R0
rom[5] <= 16'b011_00_00000001_011; // mov R3 1
rom[6] <= 16'b000_00_00_000_011_111; // jmp R3
**/
rom[0] <= 16'b0110000001111000;
rom[1] <= 16'b0110000000001001;
rom[2] <= 16'b0110000000010010;
rom[3] <= 16'b0110000000011011;
rom[4] <= 16'b0110000000100100;
rom[5] <= 16'b0110000000101101;
rom[6] <= 16'b0110000000110110;
rom[7] <= 16'b0110000000111111;
rom[8] <= 16'b0110000000000000;
rom[9] <= 16'b0000000000000001; // jmp R0
end
end
endmodule
module ram8x256(
input in_clk,
input in_rst,
input [7:0] in_addr,
input in_wr,
input [7:0] in_data,
output [7:0] out_data);
assign out_data = ram[in_addr];
reg [7:0] ram [255:0];
integer i = 0;
always @(posedge in_clk) begin
if (in_rst) begin
for(i=0; i<256; i=i+1) begin
ram[i] <= 8'h0;
end
end else begin
if (in_wr) begin
ram[in_addr] <= in_data;
end
end
end
endmodule
module power_on_reset(
input in_clk,
output out_rst);
reg [2:0] reset_cnt = 0;
wire resetn = &reset_cnt;
assign out_rst = !resetn;
always @(posedge in_clk) begin
reset_cnt <= reset_cnt + !resetn;
end
endmodule
// fedc ba98 7654 3210
// '''' '''' '''' ''''
// '''' '''' '''' 'ddd ---- d destination
// '''' '''' ''aa a ------- a source a
// '''' '''b bb - --------- b source b
// lll llll l ------- l literal
// x xxx ---- --------- x op 4
// y y -- ---- --------- y op 2
// fff ---- ---- --------- f format
//
// format 0 fffyy..bbbaaaddd jmp
// f = 0
// y = 0 jmp
// 1 cjmp
// b = condition
// a = target
// d = link
//
// format 1 fffxxxxbbbaaaddd alu
// f = 1
// x = operation
// b = source b
// a = source a
// d = destination
//
// format 2 fffyy..bbbaaaddd mem
// f = 2
// y = 0 load
// 1 store
// b = mem write data (to ram)
// a = mem address
// d = mem read data (to reg)
//
// format 3 fff..llllllllddd lit
// f = 3
// l = literal
// d = destination
//
module cpu1_regfile(
input in_clk,
input in_rst,
input [2:0] in_src_a,
output [7:0] out_src_a,
input [2:0] in_src_b,
output [7:0] out_src_b,
input [2:0] in_dst,
input [7:0] in_dst_data,
input in_wr);
reg [7:0] R [8];
assign out_src_a = R[in_src_a];
assign out_src_b = R[in_src_b];
integer i=0;
wire [7:0] r0 = R[0];
wire [7:0] r1 = R[1];
wire [7:0] r2 = R[2];
wire [7:0] r3 = R[3];
wire [7:0] r4 = R[4];
wire [7:0] r5 = R[5];
wire [7:0] r6 = R[6];
wire [7:0] r7 = R[7];
always @(posedge in_clk) begin
if (in_rst) begin
for(i=0; i<8; i=i+1) begin
R[i] <= 8'h0;
end
end else begin
if (in_wr) begin
R[in_dst] <= in_dst_data;
end
end
end
endmodule
module cpu1(
input in_clk,
input in_rst,
input [15:0] in_rom_data,
output [7:0] out_rom_addr,
output reg [7:0] out_mem_addr,
input [7:0] in_mem_data,
output reg [7:0] out_mem_data,
output reg out_mem_wr);
reg reset;
// instruction decode
reg [15:0] inst;
wire [2:0] ins_fmt = inst[15:13];
wire [1:0] ins_op_2 = inst[12:11];
wire [3:0] ins_op_4 = inst[12:9];
wire [7:0] ins_lit = inst[10:3];
wire [2:0] ins_reg_b = inst[8:6];
wire [2:0] ins_reg_a = inst[5:3];
wire [2:0] ins_reg_d = inst[2:0];
wire is_fmt_0 = (ins_fmt == 3'd0);
/* verilator lint_off UNUSED */
wire is_fmt_1 = (ins_fmt == 3'd1);
wire is_fmt_2 = (ins_fmt == 3'd2);
/* verilator lint_off UNUSED */
wire is_fmt_3 = (ins_fmt == 3'd3);
reg reg_wr;
reg rwr; // write to dst reg
wire [7:0] ra; // source Ra
wire [7:0] rb; // source Rb
reg [7:0] rd; // Rd value
cpu1_regfile reg_file(in_clk, reset, ins_reg_a, ra, ins_reg_b, rb, ins_reg_d, rd, reg_wr);
// program counter
reg [7:0] pc; // current pc
reg [7:0] pc_n; // next pc
wire [7:0] pc_p1 = pc + 8'd1; // pc + 1
assign out_rom_addr = pc_n; // prep to fetch next inst
// update ALU
reg [7:0] alu_res;
always @* begin
case(ins_op_4)
4'h0: alu_res = ra + rb;
4'h1: alu_res = ra - rb;
4'h2: alu_res = ra & rb;
4'h3: alu_res = ra | rb;
4'h4: alu_res = ra ^ rb;
4'h5: alu_res = ~ra;
4'h6: alu_res = ra >> 1;
4'h7: alu_res = ra << 1;
4'h8: alu_res = { 7'd0, (ra > rb) };
4'h9: alu_res = { 7'd0, (ra >= rb) };
4'ha: alu_res = { 7'd0, (ra < rb) };
4'hb: alu_res = { 7'd0, (ra <= rb) };
4'hc: alu_res = { 7'd0, (ra == rb) };
4'hd: alu_res = { 7'd0, (ra != rb) };
4'he: alu_res = 8'd1;
4'hf: alu_res = ra;
endcase
end
// update register indices
always @* begin
// update Rd
case (ins_fmt)
3'd0: rd = pc_p1; // link
3'd2: rd = in_mem_data; // mem
3'd3: rd = ins_lit; // literal
default: rd = alu_res; // alu
endcase
// write to Rd register
case ({reset, ins_fmt})
4'b0000: rwr = is_fmt_0; // link
4'b0001: rwr = 1; // alu
4'b0010: rwr = (ins_op_2 == 2'd0); // ld
4'b0011: rwr = 1; // literal
default: rwr = 0;
endcase
out_mem_addr = ra;
out_mem_data = rb;
out_mem_wr = !reset && (is_fmt_2 && (ins_op_2 == 2'd1)); // st
end
// update program counter
always @* begin
casez({reset, ins_fmt, ins_op_2})
6'b1_???_??: pc_n = 0; // reset
6'b0_000_?0: pc_n = ra; // jmp / call
6'b0_000_?1: pc_n = rb[0] ? ra : pc_p1; // cjmp / ccall
default: pc_n = pc_p1; // ...
endcase
end
always @(posedge in_clk) begin
if (in_rst) begin
{ pc, reg_wr, inst } <= 0;
reset <= 1;
end else begin
{ pc, reg_wr, inst } <= { pc_n, rwr, in_rom_data };
reset <= 0;
end
end
endmodule
module testbench();
reg clk;
initial begin
$dumpfile("dump.vcd");
$dumpvars;
clk <= 0;
#128; $finish;
end
always begin
#1 clk <= ~clk;
end
wire rst;
power_on_reset por(clk, rst);
wire [7:0] rom_addr;
wire [15:0] rom_data;
rom16x256 rom(clk, rst, rom_addr, rom_data);
wire [7:0] ram_addr;
wire [7:0] ram_data_in;
wire [7:0] ram_data_out;
wire ram_wr;
ram8x256 ram(clk, rst, ram_addr, ram_wr, ram_data_in, ram_data_out);
cpu1 cpu(clk, rst, rom_data, rom_addr, ram_addr, ram_data_out, ram_data_in, ram_wr);
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment