Adding my SOC design with CPU and RAM
diff --git a/README.md b/README.md index 3077244..bbd3ee7 100644 --- a/README.md +++ b/README.md
@@ -1,12 +1,9 @@ -# Caravel User Project +# ISA 16-bit microprocessor -[](https://opensource.org/licenses/Apache-2.0) [](https://github.com/efabless/caravel_project_example/actions/workflows/user_project_ci.yml) [](https://github.com/efabless/caravel_project_example/actions/workflows/caravel_build.yml) +This is the next version of the SOC. 1KB of memory has been added. +The memory can be loadded via logic analyzer bus from management core. +Then the program and data can be used from memory. -| :exclamation: Important Note | -|-----------------------------------------| - -## Please fill in your project documentation in this README.md file - -Refer to [README](docs/source/quickstart.rst) for a quick start of how to use caravel_user_project - -Refer to [README](docs/source/index.rst) for this sample project documentation. +The clock can be chosen from wishbone clock or user_clock2 or external. +The reset can be chosen from wishbone reset or external pin. +A soc configuration block has been aceated to control memory and cpu.
diff --git a/openlane/cpu/config.tcl b/openlane/cpu/config.tcl new file mode 100755 index 0000000..4c4f528 --- /dev/null +++ b/openlane/cpu/config.tcl
@@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +set ::env(PDK) $::env(PDK) +set ::env(STD_CELL_LIBRARY) "sky130_fd_sc_hd" + +set script_dir [file dirname [file normalize [info script]]] + +set ::env(DESIGN_NAME) cpu + +set ::env(VERILOG_FILES) "\ + $::env(CARAVEL_ROOT)/verilog/rtl/defines.v \ + $script_dir/../../verilog/rtl/cpu.v" + +set ::env(DESIGN_IS_CORE) 0 + +set ::env(CLOCK_PORT) "clk" +#set ::env(CLOCK_NET) "counter.clk" +set ::env(CLOCK_PERIOD) "10" + +set ::env(FP_SIZING) absolute +set ::env(DIE_AREA) "0 0 420 280" + +#set ::env(FP_PIN_ORDER_CFG) $script_dir/pin_order.cfg + +set ::env(PL_BASIC_PLACEMENT) 0 +set ::env(FP_CORE_UTIL) 5 +set ::env(PL_TARGET_DENSITY) 0.1 + +# Maximum layer used for routing is metal 4. +# This is because this macro will be inserted in a top level (user_project_wrapper) +# where the PDN is planned on metal 5. So, to avoid having shorts between routes +# in this macro and the top level metal 5 stripes, we have to restrict routes to metal4. +# +set ::env(RT_MAX_LAYER) {met4} + +# You can draw more power domains if you need to +set ::env(VDD_NETS) [list {vccd1}] +set ::env(GND_NETS) [list {vssd1}] + +set ::env(DIODE_INSERTION_STRATEGY) 4 +# If you're going to use multiple power domains, then disable cvc run. +set ::env(RUN_CVC) 1
diff --git a/openlane/cpu/pin_order.cfg b/openlane/cpu/pin_order.cfg new file mode 100644 index 0000000..2fda806 --- /dev/null +++ b/openlane/cpu/pin_order.cfg
@@ -0,0 +1,10 @@ +#BUS_SORT + +#S +wb_.* +wbs_.* +la_.* +irq.* + +#N +io_.*
diff --git a/openlane/soc_config/config.tcl b/openlane/soc_config/config.tcl new file mode 100755 index 0000000..124aede --- /dev/null +++ b/openlane/soc_config/config.tcl
@@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +set ::env(PDK) $::env(PDK) +set ::env(STD_CELL_LIBRARY) "sky130_fd_sc_hd" + +set script_dir [file dirname [file normalize [info script]]] + +set ::env(DESIGN_NAME) soc_config + +set ::env(VERILOG_FILES) "\ + $::env(CARAVEL_ROOT)/verilog/rtl/defines.v \ + $script_dir/../../verilog/rtl/soc_config.v" + +set ::env(DESIGN_IS_CORE) 0 + +set ::env(CLOCK_PORT) "user_clock2" +set ::env(CLOCK_PORT) "wb_clk_i" +set ::env(CLOCK_PORT) "io_in\[19\]" +set ::env(CLOCK_NET) "soc_clk" +set ::env(CLOCK_PERIOD) "10" + +set ::env(FP_SIZING) absolute +set ::env(DIE_AREA) "0 0 330 220" + +set ::env(FP_PIN_ORDER_CFG) $script_dir/pin_order.cfg + +set ::env(PL_BASIC_PLACEMENT) 0 +set ::env(FP_CORE_UTIL) 5 +set ::env(PL_TARGET_DENSITY) 0.1 + +# Maximum layer used for routing is metal 4. +# This is because this macro will be inserted in a top level (user_project_wrapper) +# where the PDN is planned on metal 5. So, to avoid having shorts between routes +# in this macro and the top level metal 5 stripes, we have to restrict routes to metal4. +# +set ::env(RT_MAX_LAYER) {met4} + +# You can draw more power domains if you need to +set ::env(VDD_NETS) [list {vccd1}] +set ::env(GND_NETS) [list {vssd1}] + +set ::env(DIODE_INSERTION_STRATEGY) 4 +# If you're going to use multiple power domains, then disable cvc run. +set ::env(RUN_CVC) 1
diff --git a/openlane/soc_config/pin_order.cfg b/openlane/soc_config/pin_order.cfg new file mode 100644 index 0000000..99cd3b3 --- /dev/null +++ b/openlane/soc_config/pin_order.cfg
@@ -0,0 +1,17 @@ +#BUS_SORT + +#S +wb_.* +wbs_.* +la_.* +irq.* + +#N +io_.* + +en_.* +addr_.* +data_.* +rw_.* +soc_.* +user_.*
diff --git a/openlane/user_project_wrapper/config.tcl b/openlane/user_project_wrapper/config.tcl index 2b03104..ec7c34b 100755 --- a/openlane/user_project_wrapper/config.tcl +++ b/openlane/user_project_wrapper/config.tcl
@@ -46,7 +46,10 @@ ## Internal Macros ### Macro PDN Connections set ::env(FP_PDN_MACRO_HOOKS) "\ - mprj vccd1 vssd1 vccd1 vssd1" + mprj vccd1 vssd1 vccd1 vssd1 \ + cpu0 vccd1 vssd1 vccd1 vssd1 \ + memLword vccd1 vssd1 vccd1 vssd1 \ + memLword vccd1 vssd1 vccd1 vssd1" ### Macro Placement set ::env(MACRO_PLACEMENT_CFG) $script_dir/macro.cfg @@ -54,13 +57,19 @@ ### Black-box verilog and views set ::env(VERILOG_FILES_BLACKBOX) "\ $::env(CARAVEL_ROOT)/verilog/rtl/defines.v \ - $script_dir/../../verilog/rtl/user_proj_example.v" + $script_dir/../../verilog/rtl/cpu.v \ + $script_dir/../../verilog/rtl/soc_config.v \ + $::env(PDK_ROOT)/$::env(PDK)/libs.ref/sky130_sram_macros/verilog/sky130_sram_1kbyte_1rw1r_8x1024_8.v" set ::env(EXTRA_LEFS) "\ - $script_dir/../../lef/user_proj_example.lef" + $script_dir/../../lef/cpu.lef \ + $script_dir/../../lef/soc_config.lef \ + $::env(PDK_ROOT)/$::env(PDK)/libs.ref/sky130_sram_macros/lef/sky130_sram_1kbyte_1rw1r_8x1024_8.lef" set ::env(EXTRA_GDS_FILES) "\ - $script_dir/../../gds/user_proj_example.gds" + $script_dir/../../gds/cpu.gds \ + $script_dir/../../gds/soc_config.gds \ + $::env(PDK_ROOT)/$::env(PDK)/libs.ref/sky130_sram_macros/gds/sky130_sram_1kbyte_1rw1r_8x1024_8.gds" # set ::env(GLB_RT_MAXLAYER) 5 set ::env(RT_MAX_LAYER) {met4} @@ -85,4 +94,7 @@ set ::env(TAP_DECAP_INSERTION) 0 set ::env(CLOCK_TREE_SYNTH) 0 - +set ::env(RUN_KLAYOUT_DRC) 0 +set ::env(RUN_MAGIC_DRC) 0 +set ::env(LVS_INSERT_POWER_PINS) 0 +set ::env(QUIT_ON_LVS_ERROR) 0
diff --git a/openlane/user_project_wrapper/macro.cfg b/openlane/user_project_wrapper/macro.cfg index a7365ab..332952a 100644 --- a/openlane/user_project_wrapper/macro.cfg +++ b/openlane/user_project_wrapper/macro.cfg
@@ -1 +1,4 @@ mprj 1175 1690 N +cpu0 1300 500 N +memLword 500 2500 N +memHword 1900 2500 N
diff --git a/verilog/rtl/cpu.v b/verilog/rtl/cpu.v new file mode 100644 index 0000000..d70816c --- /dev/null +++ b/verilog/rtl/cpu.v
@@ -0,0 +1,196 @@ +module cpu ( +`ifdef USE_POWER_PINS + vccd1, + vssd1, +`endif + clk, + addr, + datain, + dataout, + en_inp, + en_out, + rdwr, + en, + rst, + keyboard, + display +); + +`ifdef USE_POWER_PINS + inout vccd1; // User area 1 1.8V power + inout vssd1; // User area 1 digital ground +`endif + + input [15:0] datain; + output [15:0] dataout; + output [11:0] addr; + input clk, en_inp, en_out, rst; + output en, rdwr; + input [7:0] keyboard; + output [7:0] display; + + reg e, ac0,ac15; + reg [15:0] ir, ac, dr; + reg [11:0] pc, addr; + reg [10:0] t; + wire [7:0] d; + wire rstEn, rstT; + wire rdwr, en; + +`ifdef DEBUG + debug debug1(.of(e), .lcd(display), .dcod(d), .fsm(t), .ar(addr), .prgctr(pc), .datr(dr), .accu(ac), .instr(ir)); +`endif + + assign dataout = (t[4] && d[3]) ? ac : 16'hzzzz; + assign dataout = (t[4] && d[5]) ? {4'h0, pc} : 16'hzzzz; + assign dataout = (t[6] && d[6]) ? dr : 16'hzzzz; + + assign display = (t[3] && d[7] && ir[10] && ir[15] && en_out) ? ac[7:0] : display; + + DECODER decode2 ( + .d(d), + .a(ir[14:12]), + .e(1'b1) + ); + + assign rstT = rst || (t[4] && d[7] && !ir[6] && !ir[7]) || (!ir[15] && ((t[4] && d[4]) || (t[5] && d[3]))) || (t[5] && d[7] && (ir[6] || ir[7])) || (ir[15] && t[7] && d[4]) || (!ir[15] && t[7] && (d[0] || d[1] || d[2] || d[5])) || (t[7] && d[3]) || (t[9] && (d[0] || d[1] || d[2])) || (t[10] && d[6]); + always @(posedge clk or posedge rstT) begin + if (rstT) begin + t <= 1; + end else begin + t <= t << 1; + end + end + + assign en = (t[1] || (t[6] && !d[7] && ir[15]) || (t[4] && (d[0] || d[1] || d[2] || d[3] || d[5] || d[6])) || (ir[15] && t[4] && d[4]) || (t[6] && d[6])); + assign rdwr = (!ir[15] && t[4] && (d[3] || d[5])) || (!ir[15] && t[6] && d[6]) || (ir[15] && t[8] && d[6]); + always @(posedge clk or posedge rst) begin + if (rst) begin + pc <= 0; + end else if ( t[0] || + (t[6] && d[5]) || + (!ir[15] && t[7] && d[6] && !dr) || + (t[9] && d[6] && ir[15] && !dr) || + (t[3] && d[7] && ((ir[15] && ((ir[8] && en_out) || + (ir[9] && en_inp))) || + (!ir[15] && ((ir[1] && !e) || + (ir[2] && !ac) || + (ir[3] && ac[15]) || + (ir[4] && !ac[15])))))) + begin + pc <= pc + 1; + end else if ((t[4] && d[4]) || (t[5] && d[5]) || (ir[15] && t[6] && d[4])) begin + pc <= addr; + end + end + + always @(posedge clk or posedge rst) begin + if (rst) begin + ir <= 0; + end else if (!rdwr && t[2]) begin + ir <= datain; + end + end + + always @(posedge clk or posedge rst) begin + if (rst) begin + dr <= 0; + end else if (!rdwr && ((!d[5] && t[5]) || (t[7] && ir[15]))) begin + dr <= datain; + end else if ((!ir[15] && t[6] && d[6]) || (ir[15] && t[8] && d[6])) begin + dr <= dr + 1; + end + end + + always @(posedge clk or posedge rst) begin + if (rst) begin + addr <= 0; + end else if (t[0]) begin + addr <= pc; + end else if (t[3]) begin + addr <= ir[11:0]; + end else if (!rdwr && (t[4] || (t[5] && ir[15]))) begin + addr <= datain; + end + end + + always @(posedge clk or posedge rst) begin + if (rst) begin + e <= 0; + ac <= 0; + ac0 <= 0; + ac15 <= 0; + end else if (t[3]) begin + if (d[7]) begin +////////////////////////* input/output instructions *///////////////////////// + if (ir[15]) begin + if (ir[11] && en_inp) begin + ac[7:0] <= keyboard; + end + +////////////////////* REGISTER REFERENCE INSTRUCTIONS */////////////////////// + end else begin + if (ir[5]) ac <= ac + 1; + if (ir[6]) begin + ac15 <= ac[15]; + ac <= ac << 1; + ac[0] <= e; + //e <= ac15; + end + if (ir[7]) begin + ac0 <= ac[0]; + ac <= ac >> 1; + ac[15] <= e; + //e <= ac0; + end + if (ir[8]) e <= ~e; + if (ir[9]) ac <= ~ac; + if (ir[10]) e <= 0; + if (ir[11]) ac <= 0; + end + end + end else if (t[4]) begin + if (d[7]) begin + if (!ir[15]) begin + if (ir[6]) begin + e <= ac15; + end + if (ir[7]) begin + e <= ac0; + end + end + end + end else if (t[8] || (!ir[15] && t[6])) begin + if (d[0]) begin + ac <= (ac & dr); + end + if (d[1]) begin + {e, ac} <= ac + dr; + end + if (d[2]) begin + ac <= dr; + end + end + end + +endmodule + +module DECODER ( + d, + e, + a +); + input [2:0] a; + input e; + output [7:0] d; + + assign d[0] = ~a[2] & ~a[1] & ~a[0] & e; + assign d[1] = ~a[2] & ~a[1] & a[0] & e; + assign d[2] = ~a[2] & a[1] & ~a[0] & e; + assign d[3] = ~a[2] & a[1] & a[0] & e; + assign d[4] = a[2] & ~a[1] & ~a[0] & e; + assign d[5] = a[2] & ~a[1] & a[0] & e; + assign d[6] = a[2] & a[1] & ~a[0] & e; + assign d[7] = a[2] & a[1] & a[0] & e; + +endmodule
diff --git a/verilog/rtl/soc_config.v b/verilog/rtl/soc_config.v new file mode 100644 index 0000000..7bb26c1 --- /dev/null +++ b/verilog/rtl/soc_config.v
@@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2020 Efabless Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// SPDX-License-Identifier: Apache-2.0 + +`default_nettype none +/* + *------------------------------------------------------------- + * + * + *------------------------------------------------------------- + */ + +module soc_config #( + parameter BITS = 32 +)( +`ifdef USE_POWER_PINS + inout vccd1, // User area 1 1.8V supply + inout vssd1, // User area 1 digital ground +`endif + + input user_clock2, + // Wishbone Slave ports (WB MI A) + input wb_clk_i, + input wb_rst_i, + input wbs_stb_i, + input wbs_cyc_i, + input wbs_we_i, + input [3:0] wbs_sel_i, + input [31:0] wbs_dat_i, + input [31:0] wbs_adr_i, + output wbs_ack_o, + output [31:0] wbs_dat_o, + + // Logic Analyzer Signals + input [127:0] la_data_in, + output [127:0] la_data_out, + input [127:0] la_oenb, + + // IOs + input [`MPRJ_IO_PADS-1:0] io_in, + output [`MPRJ_IO_PADS-1:0] io_out, + output [`MPRJ_IO_PADS-1:0] io_oeb, + + // IRQ + output [2:0] irq, + + // CPU specific + input rw_from_cpu, + input en_from_cpu, + input [11:0] addr_from_cpu, + input [15:0] data_from_cpu, + output [15:0] data_to_cpu, + input [15:0] data_from_mem, + output [15:0] data_to_mem, + output [9:0] addr_to_mem, + output rw_to_mem, + output en_to_mem, + output en_keyboard, + output en_display, + output soc_rst, + output soc_clk +); + wire rst; + + wire [`MPRJ_IO_PADS-1:0] io_in; + wire [`MPRJ_IO_PADS-1:0] io_out; + wire [`MPRJ_IO_PADS-1:0] io_oeb; + + wire rw, n; + + // IRQ + assign irq = 3'b000; // Unused + + // IO + assign io_oeb[37:30] = 8'hFF; // input + assign io_oeb[29:22] = 8'h00; // output + assign io_oeb[21:18] = 8'hFF; // input + + // LA + // if la_data_in[0] is input, then wbclk or usrclk can be used. Else io_in[19] is the clock + assign soc_clk = la_oenb[0] ? (la_data_in[0] ? user_clock2 : wb_clk_i) : io_in[19]; + // if la_data_in[1] is input, then wbrst or io_in[18] can be used. Else io_in[18] is the reset + assign soc_rst = la_oenb[1] ? (la_data_in[1] ? io_in[18] : wb_rst_i) : io_in[18]; + // Enable display and keyboard by LA or io_in 21/20 + assign en_keyboard = la_oenb[2] ? la_data_in[2] : io_in[21]; + assign en_display = la_oenb[3] ? la_data_in[3] : io_in[20]; + + // Provision to read/write ram from LA + assign data_to_mem = la_data_in[127] ? la_data_in[126:111] : data_from_cpu; + assign addr_to_mem = la_data_in[127] ? la_data_in[110:101] : addr_from_cpu[9:0]; + assign rw_to_mem = la_data_in[127] ? la_data_in[100] : ~rw_from_cpu; // active low for openram + assign en_to_mem = la_data_in[127] ? la_data_in[99] : ~en_from_cpu; // active low for openram + assign data_to_cpu = data_from_mem; + assign la_data_out[98:83] = data_from_mem; + +endmodule + +`default_nettype wire
diff --git a/verilog/rtl/user_project_wrapper.v b/verilog/rtl/user_project_wrapper.v index 5ee1cee..0300942 100644 --- a/verilog/rtl/user_project_wrapper.v +++ b/verilog/rtl/user_project_wrapper.v
@@ -78,16 +78,22 @@ output [2:0] user_irq ); +wire [9:0] adr_mem; +wire [11:0] adr_cpu; +wire [15:0] cpdatin, cpdatout, memdatin, memdatout; +wire cpuen, cpurw, memrw, memen, enkbd, endisp, rst, clk; + /*--------------------------------------*/ /* User project is instantiated here */ /*--------------------------------------*/ -user_proj_example mprj ( +soc_config mprj ( `ifdef USE_POWER_PINS - .vccd1(vccd1), // User area 1 1.8V power - .vssd1(vssd1), // User area 1 digital ground + .vccd1(vccd1), // User area 1 1.8V power + .vssd1(vssd1), // User area 1 digital ground `endif + .user_clock2(user_clock2), .wb_clk_i(wb_clk_i), .wb_rst_i(wb_rst_i), @@ -114,10 +120,73 @@ .io_out(io_out), .io_oeb(io_oeb), + // CPU specific + .addr_from_cpu(adr_cpu), + .data_from_cpu(cpdatout), + .data_to_cpu(cpdatin), + .addr_to_mem(adr_mem), + .data_from_mem(memdatin), + .data_to_mem(memdatout), + .rw_from_cpu(cpurw), + .en_from_cpu(cpuen), + .rw_to_mem(memrw), + .en_to_mem(memen), + .en_keyboard(enkbd), + .en_display(endisp), + .soc_clk(clk), + .soc_rst(rst), + // IRQ .irq(user_irq) ); +cpu cpu0 ( +`ifdef USE_POWER_PINS + .vccd1(vccd1), // User area 1 1.8V power + .vssd1(vssd1), // User area 1 digital ground +`endif + + .clk(clk), + .addr(adr_cpu), + .datain(cpdatin), + .dataout(cpdatout), + .en_inp(enkbd), + .en_out(endisp), + .rdwr(cpurw), + .en(cpuen), + .rst(rst), + .keyboard(io_in[37:30]), + .display(io_out[29:22]) +); + +sky130_sram_1kbyte_1rw1r_8x1024_8 #(.NUM_WMASKS(2)) memLword ( +`ifdef USE_POWER_PINS + .vccd1(vccd1), // User area 1 1.8V power + .vssd1(vssd1), // User area 1 digital ground +`endif + .clk0(clk), + .addr0(adr_mem), + .din0(memdatout[7:0]), + .dout0(memdatin[7:0]), + .web0(memrw), + .csb0(memen), + .wmask0({cpuen, cpuen}) +); + + sky130_sram_1kbyte_1rw1r_8x1024_8 #(.NUM_WMASKS(2)) memHword ( +`ifdef USE_POWER_PINS + .vccd1(vccd1), // User area 1 1.8V power + .vssd1(vssd1), // User area 1 digital ground +`endif + .clk0(clk), + .addr0(adr_mem), + .din0(memdatout[15:8]), + .dout0(memdatin[15:8]), + .web0(memrw), + .csb0(memen), + .wmask0({cpuen, cpuen}) +); + endmodule // user_project_wrapper `default_nettype wire