Last active
January 10, 2020 18:14
-
-
Save bit-hack/4866782e1e1cce60f8ec769d1eba3968 to your computer and use it in GitHub Desktop.
First cpu implementation scratchpad
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`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