diff --git a/.editorconfig b/.editorconfig index 0d55951..0886cb4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ root = true -[src/**/*.{sv,svh}] +[**/*.{sv,svh}] charset = utf-8 indent_style = space indent_size = 2 @@ -8,10 +8,18 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -[Makefile] +[sim/Makefile] indent_style = tab -[tools/**/*.txt] +[sim/**/*.{c,cpp,h,hpp}] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[tools/*.txt] charset = utf-8 indent_style = tab indent_size = 8 diff --git a/.gitignore b/.gitignore index 29972c4..f7b787c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ vivado.log vivado.jou .library_mapping.xml .project -.settings \ No newline at end of file +.settings +.vscode diff --git a/resources/func_test/axi_wrap.v b/resources/func_test/axi_wrap.v new file mode 100755 index 0000000..e6c7d53 --- /dev/null +++ b/resources/func_test/axi_wrap.v @@ -0,0 +1,166 @@ +/*------------------------------------------------------------------------------ +-------------------------------------------------------------------------------- +Copyright (c) 2016, Loongson Technology Corporation Limited. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of Loongson Technology Corporation Limited nor the names of +its contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL LOONGSON TECHNOLOGY CORPORATION LIMITED BE LIABLE +TO ANY PARTY FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +------------------------------------------------------------------------------*/ + +module axi_wrap( + input m_aclk, + input m_aresetn, + //ar + input [3 :0] m_arid , + input [31:0] m_araddr , + input [3 :0] m_arlen , + input [2 :0] m_arsize , + input [1 :0] m_arburst, + input [1 :0] m_arlock , + input [3 :0] m_arcache, + input [2 :0] m_arprot , + input m_arvalid, + output m_arready, + //r + output [3 :0] m_rid , + output [31:0] m_rdata , + output [1 :0] m_rresp , + output m_rlast , + output m_rvalid , + input m_rready , + //aw + input [3 :0] m_awid , + input [31:0] m_awaddr , + input [3 :0] m_awlen , + input [2 :0] m_awsize , + input [1 :0] m_awburst, + input [1 :0] m_awlock , + input [3 :0] m_awcache, + input [2 :0] m_awprot , + input m_awvalid, + output m_awready, + //w + input [3 :0] m_wid , + input [31:0] m_wdata , + input [3 :0] m_wstrb , + input m_wlast , + input m_wvalid , + output m_wready , + //b + output [3 :0] m_bid , + output [1 :0] m_bresp , + output m_bvalid , + input m_bready , + + output s_aclk, + output s_aresetn, + //ar + output [3 :0] s_arid , + output [31:0] s_araddr , + output [3 :0] s_arlen , + output [2 :0] s_arsize , + output [1 :0] s_arburst, + output [1 :0] s_arlock , + output [3 :0] s_arcache, + output [2 :0] s_arprot , + output s_arvalid, + input s_arready, + //r + input [3 :0] s_rid , + input [31:0] s_rdata , + input [1 :0] s_rresp , + input s_rlast , + input s_rvalid , + output s_rready , + //aw + output [3 :0] s_awid , + output [31:0] s_awaddr , + output [3 :0] s_awlen , + output [2 :0] s_awsize , + output [1 :0] s_awburst, + output [1 :0] s_awlock , + output [3 :0] s_awcache, + output [2 :0] s_awprot , + output s_awvalid, + input s_awready, + //w + output [3 :0] s_wid , + output [31:0] s_wdata , + output [3 :0] s_wstrb , + output s_wlast , + output s_wvalid , + input s_wready , + //b + input [3 :0] s_bid , + input [1 :0] s_bresp , + input s_bvalid , + output s_bready +); +assign s_aclk = m_aclk ; +assign s_aresetn = m_aresetn; +//ar +assign s_arid = m_arid ; +assign s_araddr = m_araddr ; +assign s_arlen = m_arlen ; +assign s_arsize = m_arsize ; +assign s_arburst = m_arburst; +assign s_arlock = m_arlock ; +assign s_arcache = m_arcache; +assign s_arprot = m_arprot ; +assign s_arvalid = m_arvalid; +assign m_arready = s_arready; +//r +assign m_rid = m_rvalid ? s_rid : 4'd0 ; +assign m_rdata = m_rvalid ? s_rdata : 32'd0 ; +assign m_rresp = m_rvalid ? s_rresp : 2'd0 ; +assign m_rlast = m_rvalid ? s_rlast : 1'd0 ; +assign m_rvalid = s_rvalid; +assign s_rready = m_rready; +//aw +assign s_awid = m_awid ; +assign s_awaddr = m_awaddr ; +assign s_awlen = m_awlen ; +assign s_awsize = m_awsize ; +assign s_awburst = m_awburst; +assign s_awlock = m_awlock ; +assign s_awcache = m_awcache; +assign s_awprot = m_awprot ; +assign s_awvalid = m_awvalid; +assign m_awready = s_awready; +//w +assign s_wid = m_wid ; +assign s_wdata = m_wdata ; +assign s_wstrb = m_wstrb ; +assign s_wlast = m_wlast ; +assign s_wvalid = m_wvalid ; +assign m_wready = s_wready ; +//b +assign m_bid = m_bvalid ? s_bid : 4'd0 ; +assign m_bresp = m_bvalid ? s_bresp : 2'd0 ; +assign m_bvalid = s_bvalid ; +assign s_bready = m_bready ; +endmodule diff --git a/resources/func_test/axi_wrap_ram.v b/resources/func_test/axi_wrap_ram.v new file mode 100755 index 0000000..7639a60 --- /dev/null +++ b/resources/func_test/axi_wrap_ram.v @@ -0,0 +1,293 @@ +/*------------------------------------------------------------------------------ +-------------------------------------------------------------------------------- +Copyright (c) 2016, Loongson Technology Corporation Limited. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of Loongson Technology Corporation Limited nor the names of +its contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL LOONGSON TECHNOLOGY CORPORATION LIMITED BE LIABLE +TO ANY PARTY FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +------------------------------------------------------------------------------*/ +//for func test, no define RUN_PERF_TEST +`define _RUN_PERF_TEST +`define _RUN_PERF_NO_DELAY + +module axi_wrap_ram( + input aclk, + input aresetn, + //ar + input [3 :0] axi_arid , + input [31:0] axi_araddr , + input [7 :0] axi_arlen , + input [2 :0] axi_arsize , + input [1 :0] axi_arburst, + input [1 :0] axi_arlock , + input [3 :0] axi_arcache, + input [2 :0] axi_arprot , + input axi_arvalid, + output axi_arready, + //r + output [3 :0] axi_rid , + output [31:0] axi_rdata , + output [1 :0] axi_rresp , + output axi_rlast , + output axi_rvalid , + input axi_rready , + //aw + input [3 :0] axi_awid , + input [31:0] axi_awaddr , + input [7 :0] axi_awlen , + input [2 :0] axi_awsize , + input [1 :0] axi_awburst, + input [1 :0] axi_awlock , + input [3 :0] axi_awcache, + input [2 :0] axi_awprot , + input axi_awvalid, + output axi_awready, + //w + input [3 :0] axi_wid , + input [31:0] axi_wdata , + input [3 :0] axi_wstrb , + input axi_wlast , + input axi_wvalid , + output axi_wready , + //b + output [3 :0] axi_bid , + output [1 :0] axi_bresp , + output axi_bvalid , + input axi_bready , + + //from confreg + input [4 :0] ram_random_mask +); +wire axi_arvalid_m_masked; +wire axi_rready_m_masked; +wire axi_awvalid_m_masked; +wire axi_wvalid_m_masked; +wire axi_bready_m_masked; + +wire axi_arready_s_unmasked; +wire axi_rvalid_s_unmasked; +wire axi_awready_s_unmasked; +wire axi_wready_s_unmasked; +wire axi_bvalid_s_unmasked; + +wire ar_and; +wire r_and; +wire aw_and; +wire w_and; +wire b_and; +reg ar_nomask; +reg aw_nomask; +reg w_nomask; +reg [4:0] pf_r2r; +reg [1:0] pf_b2b; +wire pf_r2r_nomask= pf_r2r==5'd0; +wire pf_b2b_nomask= pf_b2b==2'd0; + +//mask +`ifdef RUN_PERF_TEST + assign ar_and = 1'b1; + assign aw_and = 1'b1; + assign w_and = 1'b1; + `ifdef RUN_PERF_NO_DELAY + assign r_and = 1'b1; + assign b_and = 1'b1; + `else + assign r_and = pf_r2r_nomask; + assign b_and = pf_b2b_nomask; + `endif +`else + assign ar_and = ram_random_mask[4] | ar_nomask; + assign r_and = ram_random_mask[3] ; + assign aw_and = ram_random_mask[2] | aw_nomask; + assign w_and = ram_random_mask[1] | w_nomask; + assign b_and = ram_random_mask[0] ; +`endif +always @(posedge aclk) +begin + //for func test, random mask + ar_nomask <= !aresetn ? 1'b0 : + axi_arvalid_m_masked&&axi_arready ? 1'b0 : + axi_arvalid_m_masked ? 1'b1 : ar_nomask; + + aw_nomask <= !aresetn ? 1'b0 : + axi_awvalid_m_masked&&axi_awready ? 1'b0 : + axi_awvalid_m_masked ? 1'b1 : aw_nomask; + + w_nomask <= !aresetn ? 1'b0 : + axi_wvalid_m_masked&&axi_wready ? 1'b0 : + axi_wvalid_m_masked ? 1'b1 : w_nomask; + //for perf test + pf_r2r <= !aresetn ? 5'd0 : + axi_arvalid_m_masked&&axi_arready ? 5'd25 : + !pf_r2r_nomask ? pf_r2r-1'b1 : pf_r2r; + pf_b2b <= !aresetn ? 2'd0 : + axi_awvalid_m_masked&&axi_awready ? 2'd3 : + !pf_b2b_nomask ? pf_b2b-1'b1 : pf_b2b; +end + + +//-----{master -> slave}----- +assign axi_arvalid_m_masked = axi_arvalid & ar_and; +assign axi_rready_m_masked = axi_rready & r_and; +assign axi_awvalid_m_masked = axi_awvalid & aw_and; +assign axi_wvalid_m_masked = axi_wvalid & w_and; +assign axi_bready_m_masked = axi_bready & b_and; + +//-----{slave -> master}----- +assign axi_arready = axi_arready_s_unmasked & ar_and; +assign axi_rvalid = axi_rvalid_s_unmasked & r_and; +assign axi_awready = axi_awready_s_unmasked & aw_and; +assign axi_wready = axi_wready_s_unmasked & w_and; +assign axi_bvalid = axi_bvalid_s_unmasked & b_and; + +//ram axi +//ar +wire [3 :0] ram_arid ; +wire [31:0] ram_araddr ; +wire [7 :0] ram_arlen ; +wire [2 :0] ram_arsize ; +wire [1 :0] ram_arburst; +wire [1 :0] ram_arlock ; +wire [3 :0] ram_arcache; +wire [2 :0] ram_arprot ; +wire ram_arvalid; +wire ram_arready; +//r +wire [3 :0] ram_rid ; +wire [31:0] ram_rdata ; +wire [1 :0] ram_rresp ; +wire ram_rlast ; +wire ram_rvalid ; +wire ram_rready ; +//aw +wire [3 :0] ram_awid ; +wire [31:0] ram_awaddr ; +wire [7 :0] ram_awlen ; +wire [2 :0] ram_awsize ; +wire [1 :0] ram_awburst; +wire [1 :0] ram_awlock ; +wire [3 :0] ram_awcache; +wire [2 :0] ram_awprot ; +wire ram_awvalid; +wire ram_awready; +//w +wire [3 :0] ram_wid ; +wire [31:0] ram_wdata ; +wire [3 :0] ram_wstrb ; +wire ram_wlast ; +wire ram_wvalid ; +wire ram_wready ; +//b +wire [3 :0] ram_bid ; +wire [1 :0] ram_bresp ; +wire ram_bvalid ; +wire ram_bready ; + + +// inst ram axi +axi_ram ram( + .s_aclk (aclk ), + .s_aresetn (aresetn ), + + //ar + .s_axi_arid (ram_arid ), + .s_axi_araddr (ram_araddr ), + .s_axi_arlen (ram_arlen ), + .s_axi_arsize (ram_arsize ), + .s_axi_arburst (ram_arburst ), + .s_axi_arvalid (ram_arvalid ), + .s_axi_arready (ram_arready ), + //r + .s_axi_rid (ram_rid ), + .s_axi_rdata (ram_rdata ), + .s_axi_rresp (ram_rresp ), + .s_axi_rlast (ram_rlast ), + .s_axi_rvalid (ram_rvalid ), + .s_axi_rready (ram_rready ), + //aw + .s_axi_awid (ram_awid ), + .s_axi_awaddr (ram_awaddr ), + .s_axi_awlen (ram_awlen ), + .s_axi_awsize (ram_awsize ), + .s_axi_awburst (ram_awburst ), + .s_axi_awvalid (ram_awvalid ), + .s_axi_awready (ram_awready ), + //w + .s_axi_wdata (ram_wdata ), + .s_axi_wstrb (ram_wstrb ), + .s_axi_wlast (ram_wlast ), + .s_axi_wvalid (ram_wvalid ), + .s_axi_wready (ram_wready ), + //b + .s_axi_bid (ram_bid ), + .s_axi_bresp (ram_bresp ), + .s_axi_bvalid (ram_bvalid ), + .s_axi_bready (ram_bready ) +); + +//ar +assign ram_arid = axi_arid ; +assign ram_araddr = axi_araddr ; +assign ram_arlen = axi_arlen ; +assign ram_arsize = axi_arsize ; +assign ram_arburst = axi_arburst; +assign ram_arlock = axi_arlock ; +assign ram_arcache = axi_arcache; +assign ram_arprot = axi_arprot ; +assign ram_arvalid = axi_arvalid_m_masked; +assign axi_arready_s_unmasked = ram_arready; +//r +assign axi_rid = axi_rvalid ? ram_rid : 4'd0 ; +assign axi_rdata = axi_rvalid ? ram_rdata : 32'd0 ; +assign axi_rresp = axi_rvalid ? ram_rresp : 2'd0 ; +assign axi_rlast = axi_rvalid ? ram_rlast : 1'd0 ; +assign axi_rvalid_s_unmasked = ram_rvalid; +assign ram_rready = axi_rready_m_masked; +//aw +assign ram_awid = axi_awid ; +assign ram_awaddr = axi_awaddr ; +assign ram_awlen = axi_awlen ; +assign ram_awsize = axi_awsize ; +assign ram_awburst = axi_awburst; +assign ram_awlock = axi_awlock ; +assign ram_awcache = axi_awcache; +assign ram_awprot = axi_awprot ; +assign ram_awvalid = axi_awvalid_m_masked; +assign axi_awready_s_unmasked = ram_awready; +//w +assign ram_wid = axi_wid ; +assign ram_wdata = axi_wdata ; +assign ram_wstrb = axi_wstrb ; +assign ram_wlast = axi_wlast ; +assign ram_wvalid = axi_wvalid_m_masked; +assign axi_wready_s_unmasked = ram_wready ; +//b +assign axi_bid = axi_bvalid ? ram_bid : 4'd0 ; +assign axi_bresp = axi_bvalid ? ram_bresp : 2'd0 ; +assign axi_bvalid_s_unmasked = ram_bvalid ; +assign ram_bready = axi_bready_m_masked; +endmodule diff --git a/resources/func_test/confreg.v b/resources/func_test/confreg.v new file mode 100755 index 0000000..1581413 --- /dev/null +++ b/resources/func_test/confreg.v @@ -0,0 +1,837 @@ +/*------------------------------------------------------------------------------ +-------------------------------------------------------------------------------- +Copyright (c) 2016, Loongson Technology Corporation Limited. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of Loongson Technology Corporation Limited nor the names of +its contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL LOONGSON TECHNOLOGY CORPORATION LIMITED BE LIABLE +TO ANY PARTY FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +------------------------------------------------------------------------------*/ + +//************************************************************************* +// > File Name : confreg.v +// > Description : Control module of +// 16 red leds, 2 green/red leds, +// 7-segment display, +// switchs, +// key board, +// bottom STEP, +// timer. +// +// > Author : LOONGSON +// > Date : 2017-08-04 +//************************************************************************* +`define RANDOM_SEED {7'b1010101,16'h00FF} + +`define CR0_ADDR 16'h8000 //32'hbfaf_8000 +`define CR1_ADDR 16'h8004 //32'hbfaf_8004 +`define CR2_ADDR 16'h8008 //32'hbfaf_8008 +`define CR3_ADDR 16'h800c //32'hbfaf_800c +`define CR4_ADDR 16'h8010 //32'hbfaf_8010 +`define CR5_ADDR 16'h8014 //32'hbfaf_8014 +`define CR6_ADDR 16'h8018 //32'hbfaf_8018 +`define CR7_ADDR 16'h801c //32'hbfaf_801c + +`define LED_ADDR 16'hf000 //32'hbfaf_f000 +`define LED_RG0_ADDR 16'hf004 //32'hbfaf_f004 +`define LED_RG1_ADDR 16'hf008 //32'hbfaf_f008 +`define NUM_ADDR 16'hf010 //32'hbfaf_f010 +`define SWITCH_ADDR 16'hf020 //32'hbfaf_f020 +`define BTN_KEY_ADDR 16'hf024 //32'hbfaf_f024 +`define BTN_STEP_ADDR 16'hf028 //32'hbfaf_f028 +`define SW_INTER_ADDR 16'hf02c //32'hbfaf_f02c +`define TIMER_ADDR 16'he000 //32'hbfaf_e000 + +`define IO_SIMU_ADDR 16'hffec //32'hbfaf_ffec +`define VIRTUAL_UART_ADDR 16'hfff0 //32'hbfaf_fff0 +`define SIMU_FLAG_ADDR 16'hfff4 //32'hbfaf_fff4 +`define OPEN_TRACE_ADDR 16'hfff8 //32'hbfaf_fff8 +`define NUM_MONITOR_ADDR 16'hfffc //32'hbfaf_fffc +module confreg +#(parameter SIMULATION=1'b0) +( + input aclk, + input timer_clk, + input aresetn, + // read and write from cpu + //ar + input [3 :0] arid , + input [31:0] araddr , + input [7 :0] arlen , + input [2 :0] arsize , + input [1 :0] arburst, + input [1 :0] arlock , + input [3 :0] arcache, + input [2 :0] arprot , + input arvalid, + output arready, + //r + output [3 :0] rid , + output [31:0] rdata , + output [1 :0] rresp , + output rlast , + output rvalid , + input rready , + //aw + input [3 :0] awid , + input [31:0] awaddr , + input [7 :0] awlen , + input [2 :0] awsize , + input [1 :0] awburst, + input [1 :0] awlock , + input [3 :0] awcache, + input [2 :0] awprot , + input awvalid, + output awready, + //w + input [3 :0] wid , + input [31:0] wdata , + input [3 :0] wstrb , + input wlast , + input wvalid , + output wready , + //b + output [3 :0] bid , + output [1 :0] bresp , + output bvalid , + input bready , + + //for lab6 + output [4 :0] ram_random_mask , + + // read and write to device on board + output [15:0] led, + output [1 :0] led_rg0, + output [1 :0] led_rg1, + output reg [7 :0] num_csn, + output reg [6 :0] num_a_g, + input [7 :0] switch, + output [3 :0] btn_key_col, + input [3 :0] btn_key_row, + input [1 :0] btn_step +); + reg [31:0] cr0; + reg [31:0] cr1; + reg [31:0] cr2; + reg [31:0] cr3; + reg [31:0] cr4; + reg [31:0] cr5; + reg [31:0] cr6; + reg [31:0] cr7; + + reg [31:0] led_data; + reg [31:0] led_rg0_data; + reg [31:0] led_rg1_data; + reg [31:0] num_data; + wire [31:0] switch_data; + wire [31:0] sw_inter_data; //switch interleave + wire [31:0] btn_key_data; + wire [31:0] btn_step_data; + reg [31:0] timer_r2; + reg [31:0] simu_flag; + reg [31:0] io_simu; + reg [7 :0] virtual_uart_data; + reg open_trace; + reg num_monitor; + +//--------------------------{axi interface}begin-------------------------// + reg busy,write,R_or_W; + reg s_wready; + + wire ar_enter = arvalid & arready; + wire r_retire = rvalid & rready & rlast; + wire aw_enter = awvalid & awready; + wire w_enter = wvalid & wready & wlast; + wire b_retire = bvalid & bready; + + assign arready = ~busy & (!R_or_W| !awvalid); + assign awready = ~busy & ( R_or_W| !arvalid); + + reg [3 :0] buf_id; + reg [31:0] buf_addr; + reg [7 :0] buf_len; + reg [2 :0] buf_size; + + always @(posedge aclk) + begin + if(~aresetn) busy <= 1'b0; + else if(ar_enter|aw_enter) busy <= 1'b1; + else if(r_retire|b_retire) busy <= 1'b0; + end + + always @(posedge aclk) + begin + if(~aresetn) + begin + R_or_W <= 1'b0; + buf_id <= 4'b0; + buf_addr <= 32'b0; + buf_len <= 8'b0; + buf_size <= 3'b0; + end + else + if(ar_enter | aw_enter) + begin + R_or_W <= ar_enter; + buf_id <= ar_enter ? arid : awid ; + buf_addr <= ar_enter ? araddr : awaddr ; + buf_len <= ar_enter ? arlen : awlen ; + buf_size <= ar_enter ? arsize : awsize ; + end + end + + reg conf_wready_reg; + assign wready = conf_wready_reg; + always@(posedge aclk) + begin + if (~aresetn ) conf_wready_reg <= 1'b0; + else if(aw_enter ) conf_wready_reg <= 1'b1; + else if(w_enter & wlast) conf_wready_reg <= 1'b0; + end + + // read data has one cycle delay + reg [31:0] conf_rdata_reg; + reg conf_rvalid_reg; + reg conf_rlast_reg; + assign rdata = conf_rdata_reg; + assign rvalid = conf_rvalid_reg; + assign rlast = conf_rlast_reg; + always @(posedge aclk) + begin + if(~aresetn) + begin + conf_rdata_reg <= 32'd0; + conf_rvalid_reg <= 1'd0; + conf_rlast_reg <= 1'd0; + end + else if(busy & R_or_W & !r_retire) + begin + conf_rvalid_reg <= 1'd1; + conf_rlast_reg <= 1'd1; + case (buf_addr[15:0]) + `CR0_ADDR : conf_rdata_reg <= cr0 ; + `CR1_ADDR : conf_rdata_reg <= cr1 ; + `CR2_ADDR : conf_rdata_reg <= cr2 ; + `CR3_ADDR : conf_rdata_reg <= cr3 ; + `CR4_ADDR : conf_rdata_reg <= cr4 ; + `CR5_ADDR : conf_rdata_reg <= cr5 ; + `CR6_ADDR : conf_rdata_reg <= cr6 ; + `CR7_ADDR : conf_rdata_reg <= cr7 ; + `LED_ADDR : conf_rdata_reg <= led_data ; + `LED_RG0_ADDR : conf_rdata_reg <= led_rg0_data ; + `LED_RG1_ADDR : conf_rdata_reg <= led_rg1_data ; + `NUM_ADDR : conf_rdata_reg <= num_data ; + `SWITCH_ADDR : conf_rdata_reg <= switch_data ; + `BTN_KEY_ADDR : conf_rdata_reg <= btn_key_data ; + `BTN_STEP_ADDR : conf_rdata_reg <= btn_step_data; + `SW_INTER_ADDR : conf_rdata_reg <= sw_inter_data; + `TIMER_ADDR : conf_rdata_reg <= timer_r2 ; + `SIMU_FLAG_ADDR: conf_rdata_reg <= simu_flag ; + `IO_SIMU_ADDR : conf_rdata_reg <= io_simu ; + `VIRTUAL_UART_ADDR : conf_rdata_reg <= {24'd0,virtual_uart_data} ; + `OPEN_TRACE_ADDR : conf_rdata_reg <= {31'd0,open_trace} ; + `NUM_MONITOR_ADDR: conf_rdata_reg <= {31'd0,num_monitor} ; + default : conf_rdata_reg <= 32'd0; + endcase + end + else if(r_retire) + begin + conf_rvalid_reg <= 1'b0; + end + end + + //conf write, only support a word write + wire conf_we; + wire [31:0] conf_addr; + wire [31:0] conf_wdata; + assign conf_we = w_enter; + assign conf_addr = buf_addr; + assign conf_wdata= wdata; + + reg conf_bvalid_reg; + assign bvalid = conf_bvalid_reg; + always @(posedge aclk) + begin + if (~aresetn) conf_bvalid_reg <= 1'b0; + else if(w_enter ) conf_bvalid_reg <= 1'b1; + else if(b_retire) conf_bvalid_reg <= 1'b0; + end + + assign rid = buf_id; + assign bid = buf_id; + assign bresp = 2'b0; + assign rresp = 2'b0; +//---------------------------{axi interface}end--------------------------// + +//-------------------------{confreg register}begin-----------------------// +wire write_cr0 = conf_we & (conf_addr[15:0]==`CR0_ADDR); +wire write_cr1 = conf_we & (conf_addr[15:0]==`CR1_ADDR); +wire write_cr2 = conf_we & (conf_addr[15:0]==`CR2_ADDR); +wire write_cr3 = conf_we & (conf_addr[15:0]==`CR3_ADDR); +wire write_cr4 = conf_we & (conf_addr[15:0]==`CR4_ADDR); +wire write_cr5 = conf_we & (conf_addr[15:0]==`CR5_ADDR); +wire write_cr6 = conf_we & (conf_addr[15:0]==`CR6_ADDR); +wire write_cr7 = conf_we & (conf_addr[15:0]==`CR7_ADDR); +always @(posedge aclk) +begin + cr0 <= !aresetn ? 32'd0 : + write_cr0 ? conf_wdata : cr0; + cr1 <= !aresetn ? 32'd0 : + write_cr1 ? conf_wdata : cr1; + cr2 <= !aresetn ? 32'd0 : + write_cr2 ? conf_wdata : cr2; + cr3 <= !aresetn ? 32'd0 : + write_cr3 ? conf_wdata : cr3; + cr4 <= !aresetn ? 32'd0 : + write_cr4 ? conf_wdata : cr4; + cr5 <= !aresetn ? 32'd0 : + write_cr5 ? conf_wdata : cr5; + cr6 <= !aresetn ? 32'd0 : + write_cr6 ? conf_wdata : cr6; + cr7 <= !aresetn ? 32'd0 : + write_cr7 ? conf_wdata : cr7; +end +//--------------------------{confreg register}end------------------------// + +//-------------------------------{timer}begin----------------------------// +reg write_timer_begin,write_timer_begin_r1, write_timer_begin_r2,write_timer_begin_r3; +reg write_timer_end_r1, write_timer_end_r2; +reg [31:0] conf_wdata_r, conf_wdata_r1,conf_wdata_r2; + +reg [31:0] timer_r1; +reg [31:0] timer; + +wire write_timer = conf_we & (conf_addr[15:0]==`TIMER_ADDR); +always @(posedge aclk) +begin + if (!aresetn) + begin + write_timer_begin <= 1'b0; + end + else if (write_timer) + begin + write_timer_begin <= 1'b1; + conf_wdata_r <= conf_wdata; + end + else if (write_timer_end_r2) + begin + write_timer_begin <= 1'b0; + end + + write_timer_end_r1 <= write_timer_begin_r2; + write_timer_end_r2 <= write_timer_end_r1; +end + +always @(posedge timer_clk) +begin + write_timer_begin_r1 <= write_timer_begin; + write_timer_begin_r2 <= write_timer_begin_r1; + write_timer_begin_r3 <= write_timer_begin_r2; + conf_wdata_r1 <= conf_wdata_r; + conf_wdata_r2 <= conf_wdata_r1; + + if(!aresetn) + begin + timer <= 32'd0; + end + else if (write_timer_begin_r2 && !write_timer_begin_r3) + begin + timer <= conf_wdata_r2[31:0]; + end + else + begin + timer <= timer + 1'b1; + end +end + +always @(posedge aclk) +begin + timer_r1 <= timer; + timer_r2 <= timer_r1; +end +//--------------------------------{timer}end-----------------------------// + +//--------------------------{simulation flag}begin-----------------------// +always @(posedge aclk) +begin + if(!aresetn) + begin + simu_flag <= {32{SIMULATION}}; + end +end +//---------------------------{simulation flag}end------------------------// + +//---------------------------{io simulation}begin------------------------// +wire write_io_simu = conf_we & (conf_addr[15:0]==`IO_SIMU_ADDR); +always @(posedge aclk) +begin + if(!aresetn) + begin + io_simu <= 32'd0; + end + else if(write_io_simu) + begin + io_simu <= {conf_wdata[15:0],conf_wdata[31:16]}; + end +end +//----------------------------{io simulation}end-------------------------// + +//-----------------------------{open trace}begin-------------------------// +wire write_open_trace = conf_we & (conf_addr[15:0]==`OPEN_TRACE_ADDR); +always @(posedge aclk) +begin + if(!aresetn) + begin + open_trace <= 1'b1; + end + else if(write_open_trace) + begin + open_trace <= |conf_wdata; + end +end +//-----------------------------{open trace}end---------------------------// + +//----------------------------{num monitor}begin-------------------------// +wire write_num_monitor = conf_we & (conf_addr[15:0]==`NUM_MONITOR_ADDR); +always @(posedge aclk) +begin + if(!aresetn) + begin + num_monitor <= 1'b1; + end + else if(write_num_monitor) + begin + num_monitor <= conf_wdata[0]; + end +end +//----------------------------{num monitor}end---------------------------// + +//---------------------------{virtual uart}begin-------------------------// +wire [7:0] write_uart_data; +wire write_uart_valid = conf_we & (conf_addr[15:0]==`VIRTUAL_UART_ADDR); +assign write_uart_data = conf_wdata[7:0]; +always @(posedge aclk) +begin + if(!aresetn) + begin + virtual_uart_data <= 8'd0; + end + else if(write_uart_valid) + begin + virtual_uart_data <= write_uart_data; + end +end +//----------------------------{virtual uart}end--------------------------// + +//--------------------------{axirandom mask}begin------------------------// +wire [15:0] switch_led; +wire [15:0] led_r_n; +assign led_r_n = ~switch_led; + +reg [22:0] pseudo_random_23; +reg no_mask; //if led_r_n is all 1, no mask +reg short_delay; //memory long delay +always @ (posedge aclk) +begin + if (!aresetn) + pseudo_random_23 <= simu_flag[0] ? `RANDOM_SEED : {7'b1010101,led_r_n}; + else + pseudo_random_23 <= {pseudo_random_23[21:0],pseudo_random_23[22] ^ pseudo_random_23[17]}; + + if(!aresetn) + no_mask <= pseudo_random_23[15:0]==16'h00FF; + + if(!aresetn) + short_delay <= pseudo_random_23[7:0]==8'hFF; +end +assign ram_random_mask[0] = (pseudo_random_23[10]&pseudo_random_23[20]) & (short_delay|(pseudo_random_23[11]^pseudo_random_23[5])) + | no_mask; +assign ram_random_mask[1] = (pseudo_random_23[ 9]&pseudo_random_23[17]) & (short_delay|(pseudo_random_23[12]^pseudo_random_23[4])) + | no_mask; +assign ram_random_mask[2] = (pseudo_random_23[ 8]^pseudo_random_23[22]) & (short_delay|(pseudo_random_23[13]^pseudo_random_23[3])) + | no_mask; +assign ram_random_mask[3] = (pseudo_random_23[ 7]&pseudo_random_23[19]) & (short_delay|(pseudo_random_23[14]^pseudo_random_23[2])) + | no_mask; +assign ram_random_mask[4] = (pseudo_random_23[ 6]^pseudo_random_23[16]) & (short_delay|(pseudo_random_23[15]^pseudo_random_23[1])) + | no_mask; + +//---------------------------{axirandom mask}end-------------------------// + +//--------------------------------{led}begin-----------------------------// +//led display +//led_data[31:0] +wire write_led = conf_we & (conf_addr[15:0]==`LED_ADDR); + +assign led = led_data[15:0]; + +assign switch_led = {{2{switch[7]}},{2{switch[6]}},{2{switch[5]}},{2{switch[4]}}, + {2{switch[3]}},{2{switch[2]}},{2{switch[1]}},{2{switch[0]}}}; +always @(posedge aclk) +begin + if(!aresetn) + begin + led_data <= {16'h0,switch_led}; + end + else if(write_led) + begin + led_data <= conf_wdata[31:0]; + end +end +//---------------------------------{led}end------------------------------// + +//-------------------------------{switch}begin---------------------------// +//switch data +//switch_data[7:0] +assign switch_data = {24'd0,switch}; +assign sw_inter_data = {16'd0, + switch[7],1'b0,switch[6],1'b0, + switch[5],1'b0,switch[4],1'b0, + switch[3],1'b0,switch[2],1'b0, + switch[1],1'b0,switch[0],1'b0}; +//--------------------------------{switch}end----------------------------// + +//------------------------------{btn key}begin---------------------------// +//btn key data +reg [15:0] btn_key_r; +assign btn_key_data = {16'd0,btn_key_r}; + +//state machine +reg [2:0] state; +wire [2:0] next_state; + +//eliminate jitter +reg key_flag; +reg [19:0] key_count; +reg [ 3:0] state_count; +wire key_start = (state==3'b000) && !(&btn_key_row); +wire key_end = (state==3'b111) && (&btn_key_row); +wire key_sample= key_count[19]; +always @(posedge aclk) +begin + if(!aresetn) + begin + key_flag <= 1'd0; + end + else if (key_sample && state_count[3]) + begin + key_flag <= 1'b0; + end + else if( key_start || key_end ) + begin + key_flag <= 1'b1; + end + + if(!aresetn || !key_flag) + begin + key_count <= 20'd0; + end + else + begin + key_count <= key_count + 1'b1; + end +end + +always @(posedge aclk) +begin + if(!aresetn || state_count[3]) + begin + state_count <= 4'd0; + end + else + begin + state_count <= state_count + 1'b1; + end +end + +always @(posedge aclk) +begin + if(!aresetn) + begin + state <= 3'b000; + end + else if (state_count[3]) + begin + state <= next_state; + end +end + +assign next_state = (state == 3'b000) ? ( (key_sample && !(&btn_key_row)) ? 3'b001 : 3'b000 ) : + (state == 3'b001) ? ( !(&btn_key_row) ? 3'b111 : 3'b010 ) : + (state == 3'b010) ? ( !(&btn_key_row) ? 3'b111 : 3'b011 ) : + (state == 3'b011) ? ( !(&btn_key_row) ? 3'b111 : 3'b100 ) : + (state == 3'b100) ? ( !(&btn_key_row) ? 3'b111 : 3'b000 ) : + (state == 3'b111) ? ( (key_sample && (&btn_key_row)) ? 3'b000 : 3'b111 ) : + 3'b000; +assign btn_key_col = (state == 3'b000) ? 4'b0000: + (state == 3'b001) ? 4'b1110: + (state == 3'b010) ? 4'b1101: + (state == 3'b011) ? 4'b1011: + (state == 3'b100) ? 4'b0111: + 4'b0000; +wire [15:0] btn_key_tmp; +always @(posedge aclk) begin + if(!aresetn) begin + btn_key_r <= 16'd0; + end + else if(next_state==3'b000) + begin + btn_key_r <=16'd0; + end + else if(next_state == 3'b111 && state != 3'b111) begin + btn_key_r <= btn_key_tmp; + end +end + +assign btn_key_tmp = (state == 3'b001)&(btn_key_row == 4'b1110) ? 16'h0001: + (state == 3'b001)&(btn_key_row == 4'b1101) ? 16'h0010: + (state == 3'b001)&(btn_key_row == 4'b1011) ? 16'h0100: + (state == 3'b001)&(btn_key_row == 4'b0111) ? 16'h1000: + (state == 3'b010)&(btn_key_row == 4'b1110) ? 16'h0002: + (state == 3'b010)&(btn_key_row == 4'b1101) ? 16'h0020: + (state == 3'b010)&(btn_key_row == 4'b1011) ? 16'h0200: + (state == 3'b010)&(btn_key_row == 4'b0111) ? 16'h2000: + (state == 3'b011)&(btn_key_row == 4'b1110) ? 16'h0004: + (state == 3'b011)&(btn_key_row == 4'b1101) ? 16'h0040: + (state == 3'b011)&(btn_key_row == 4'b1011) ? 16'h0400: + (state == 3'b011)&(btn_key_row == 4'b0111) ? 16'h4000: + (state == 3'b100)&(btn_key_row == 4'b1110) ? 16'h0008: + (state == 3'b100)&(btn_key_row == 4'b1101) ? 16'h0080: + (state == 3'b100)&(btn_key_row == 4'b1011) ? 16'h0800: + (state == 3'b100)&(btn_key_row == 4'b0111) ? 16'h8000:16'h0000; +//-------------------------------{btn key}end----------------------------// + +//-----------------------------{btn step}begin---------------------------// +//btn step data +reg btn_step0_r; //0:press +reg btn_step1_r; //0:press +assign btn_step_data = {30'd0,~btn_step0_r,~btn_step1_r}; //1:press + +//-----step0 +//eliminate jitter +reg step0_flag; +reg [19:0] step0_count; +wire step0_start = btn_step0_r && !btn_step[0]; +wire step0_end = !btn_step0_r && btn_step[0]; +wire step0_sample= step0_count[19]; +always @(posedge aclk) +begin + if(!aresetn) + begin + step0_flag <= 1'd0; + end + else if (step0_sample) + begin + step0_flag <= 1'b0; + end + else if( step0_start || step0_end ) + begin + step0_flag <= 1'b1; + end + + if(!aresetn || !step0_flag) + begin + step0_count <= 20'd0; + end + else + begin + step0_count <= step0_count + 1'b1; + end + + if(!aresetn) + begin + btn_step0_r <= 1'b1; + end + else if(step0_sample) + begin + btn_step0_r <= btn_step[0]; + end +end + +//-----step1 +//eliminate jitter +reg step1_flag; +reg [19:0] step1_count; +wire step1_start = btn_step1_r && !btn_step[1]; +wire step1_end = !btn_step1_r && btn_step[1]; +wire step1_sample= step1_count[19]; +always @(posedge aclk) +begin + if(!aresetn) + begin + step1_flag <= 1'd0; + end + else if (step1_sample) + begin + step1_flag <= 1'b0; + end + else if( step1_start || step1_end ) + begin + step1_flag <= 1'b1; + end + + if(!aresetn || !step1_flag) + begin + step1_count <= 20'd0; + end + else + begin + step1_count <= step1_count + 1'b1; + end + + if(!aresetn) + begin + btn_step1_r <= 1'b1; + end + else if(step1_sample) + begin + btn_step1_r <= btn_step[1]; + end +end +//------------------------------{btn step}end----------------------------// + +//-------------------------------{led rg}begin---------------------------// +//led_rg0_data[31:0] led_rg0_data[31:0] +//bfd0_f010 bfd0_f014 +wire write_led_rg0 = conf_we & (conf_addr[15:0]==`LED_RG0_ADDR); +wire write_led_rg1 = conf_we & (conf_addr[15:0]==`LED_RG1_ADDR); +assign led_rg0 = led_rg0_data[1:0]; +assign led_rg1 = led_rg1_data[1:0]; +always @(posedge aclk) +begin + if(!aresetn) + begin + led_rg0_data <= 32'h0; + end + else if(write_led_rg0) + begin + led_rg0_data <= conf_wdata[31:0]; + end + + if(!aresetn) + begin + led_rg1_data <= 32'h0; + end + else if(write_led_rg1) + begin + led_rg1_data <= conf_wdata[31:0]; + end +end +//--------------------------------{led rg}end----------------------------// + +//---------------------------{digital number}begin-----------------------// +//digital number display +//num_data[31:0] +wire write_num = conf_we & (conf_addr[15:0]==`NUM_ADDR); +always @(posedge aclk) +begin + if(!aresetn) + begin + num_data <= 32'h0; + end + else if(write_num) + begin + num_data <= conf_wdata[31:0]; + end +end + + +reg [19:0] count; +always @(posedge aclk) +begin + if(!aresetn) + begin + count <= 20'd0; + end + else + begin + count <= count + 1'b1; + end +end +//scan data +reg [3:0] scan_data; +always @ ( posedge aclk ) +begin + if ( !aresetn ) + begin + scan_data <= 32'd0; + num_csn <= 8'b1111_1111; + end + else + begin + case(count[19:17]) + 3'b000 : scan_data <= num_data[31:28]; + 3'b001 : scan_data <= num_data[27:24]; + 3'b010 : scan_data <= num_data[23:20]; + 3'b011 : scan_data <= num_data[19:16]; + 3'b100 : scan_data <= num_data[15:12]; + 3'b101 : scan_data <= num_data[11: 8]; + 3'b110 : scan_data <= num_data[7 : 4]; + 3'b111 : scan_data <= num_data[3 : 0]; + endcase + + case(count[19:17]) + 3'b000 : num_csn <= 8'b0111_1111; + 3'b001 : num_csn <= 8'b1011_1111; + 3'b010 : num_csn <= 8'b1101_1111; + 3'b011 : num_csn <= 8'b1110_1111; + 3'b100 : num_csn <= 8'b1111_0111; + 3'b101 : num_csn <= 8'b1111_1011; + 3'b110 : num_csn <= 8'b1111_1101; + 3'b111 : num_csn <= 8'b1111_1110; + endcase + end +end + +always @(posedge aclk) +begin + if ( !aresetn ) + begin + num_a_g <= 7'b0000000; + end + else + begin + case ( scan_data ) + 4'd0 : num_a_g <= 7'b1111110; //0 + 4'd1 : num_a_g <= 7'b0110000; //1 + 4'd2 : num_a_g <= 7'b1101101; //2 + 4'd3 : num_a_g <= 7'b1111001; //3 + 4'd4 : num_a_g <= 7'b0110011; //4 + 4'd5 : num_a_g <= 7'b1011011; //5 + 4'd6 : num_a_g <= 7'b1011111; //6 + 4'd7 : num_a_g <= 7'b1110000; //7 + 4'd8 : num_a_g <= 7'b1111111; //8 + 4'd9 : num_a_g <= 7'b1111011; //9 + 4'd10: num_a_g <= 7'b1110111; //a + 4'd11: num_a_g <= 7'b0011111; //b + 4'd12: num_a_g <= 7'b1001110; //c + 4'd13: num_a_g <= 7'b0111101; //d + 4'd14: num_a_g <= 7'b1001111; //e + 4'd15: num_a_g <= 7'b1000111; //f + endcase + end +end +//----------------------------{digital number}end------------------------// +endmodule diff --git a/resources/func_test/soc_axi_lite_top.v b/resources/func_test/soc_axi_lite_top.v new file mode 100755 index 0000000..54ff7a3 --- /dev/null +++ b/resources/func_test/soc_axi_lite_top.v @@ -0,0 +1,689 @@ +/*------------------------------------------------------------------------------ +-------------------------------------------------------------------------------- +Copyright (c) 2016, Loongson Technology Corporation Limited. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3. Neither the name of Loongson Technology Corporation Limited nor the names of +its contributors may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL LOONGSON TECHNOLOGY CORPORATION LIMITED BE LIABLE +TO ANY PARTY FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +------------------------------------------------------------------------------*/ +`timescale 1ns / 1ps +//************************************************************************* +// > File Name : soc_top.v +// > Description : SoC, included cpu, 2 x 3 bridge, +// inst ram, confreg, data ram +// +// ------------------------- +// | cpu | +// ------------------------- +// | axi +// | +// --------------------- +// | 1 x 2 bridge | +// --------------------- +// | | +// | | +// ----------- ----------- +// | axi ram | | confreg | +// ----------- ----------- +// +// > Author : LOONGSON +// > Date : 2017-08-04 +//************************************************************************* + +//for simulation: +//1. if define SIMU_USE_PLL = 1, will use clk_pll to generate cpu_clk/sys_clk, +// and simulation will be very slow. +//2. usually, please define SIMU_USE_PLL=0 to speed up simulation by assign +// cpu_clk=clk, sys_clk = clk. +// at this time, frequency of cpu_clk is 91MHz. +`define SIMU_USE_PLL 0 //set 0 to speed up simulation + +module soc_axi_lite_top #(parameter SIMULATION=1'b0) +( + input resetn, + input clk, + + //------gpio------- + output [15:0] led, + output [1 :0] led_rg0, + output [1 :0] led_rg1, + output [7 :0] num_csn, + output [6 :0] num_a_g, + input [7 :0] switch, + output [3 :0] btn_key_col, + input [3 :0] btn_key_row, + input [1 :0] btn_step +); +//debug signals +wire [31:0] debug_wb_pc; +wire [3 :0] debug_wb_rf_wen; +wire [4 :0] debug_wb_rf_wnum; +wire [31:0] debug_wb_rf_wdata; +wire [31:0] debug_wb1_pc; +wire [3 :0] debug_wb1_rf_wen; +wire [4 :0] debug_wb1_rf_wnum; +wire [31:0] debug_wb1_rf_wdata; +wire debug_wb_pc_A; + +//clk and resetn +wire cpu_clk; +wire sys_clk; +reg cpu_resetn_t, cpu_resetn; +reg sys_resetn_t, sys_resetn; +always @(posedge cpu_clk) +begin + cpu_resetn_t <= resetn; + cpu_resetn <= cpu_resetn_t; +end +always @(posedge sys_clk) +begin + sys_resetn_t <= resetn; + sys_resetn <= sys_resetn_t; +end +//simulation clk. +assign cpu_clk = clk; +assign sys_clk = clk; + +//cpu axi +wire [3 :0] cpu_arid ; +wire [31:0] cpu_araddr ; +wire [3 :0] cpu_arlen ; +wire [2 :0] cpu_arsize ; +wire [1 :0] cpu_arburst; +wire [1 :0] cpu_arlock ; +wire [3 :0] cpu_arcache; +wire [2 :0] cpu_arprot ; +wire cpu_arvalid; +wire cpu_arready; +wire [3 :0] cpu_rid ; +wire [31:0] cpu_rdata ; +wire [1 :0] cpu_rresp ; +wire cpu_rlast ; +wire cpu_rvalid ; +wire cpu_rready ; +wire [3 :0] cpu_awid ; +wire [31:0] cpu_awaddr ; +wire [3 :0] cpu_awlen ; +wire [2 :0] cpu_awsize ; +wire [1 :0] cpu_awburst; +wire [1 :0] cpu_awlock ; +wire [3 :0] cpu_awcache; +wire [2 :0] cpu_awprot ; +wire cpu_awvalid; +wire cpu_awready; +wire [3 :0] cpu_wid ; +wire [31:0] cpu_wdata ; +wire [3 :0] cpu_wstrb ; +wire cpu_wlast ; +wire cpu_wvalid ; +wire cpu_wready ; +wire [3 :0] cpu_bid ; +wire [1 :0] cpu_bresp ; +wire cpu_bvalid ; +wire cpu_bready ; + +//cpu axi wrap +wire cpu_wrap_aclk ; +wire cpu_wrap_aresetn; +wire [3 :0] cpu_wrap_arid ; +wire [31:0] cpu_wrap_araddr ; +wire [3 :0] cpu_wrap_arlen ; +wire [2 :0] cpu_wrap_arsize ; +wire [1 :0] cpu_wrap_arburst; +wire [1 :0] cpu_wrap_arlock ; +wire [3 :0] cpu_wrap_arcache; +wire [2 :0] cpu_wrap_arprot ; +wire cpu_wrap_arvalid; +wire cpu_wrap_arready; +wire [3 :0] cpu_wrap_rid ; +wire [31:0] cpu_wrap_rdata ; +wire [1 :0] cpu_wrap_rresp ; +wire cpu_wrap_rlast ; +wire cpu_wrap_rvalid ; +wire cpu_wrap_rready ; +wire [3 :0] cpu_wrap_awid ; +wire [31:0] cpu_wrap_awaddr ; +wire [3 :0] cpu_wrap_awlen ; +wire [2 :0] cpu_wrap_awsize ; +wire [1 :0] cpu_wrap_awburst; +wire [1 :0] cpu_wrap_awlock ; +wire [3 :0] cpu_wrap_awcache; +wire [2 :0] cpu_wrap_awprot ; +wire cpu_wrap_awvalid; +wire cpu_wrap_awready; +wire [3 :0] cpu_wrap_wid ; +wire [31:0] cpu_wrap_wdata ; +wire [3 :0] cpu_wrap_wstrb ; +wire cpu_wrap_wlast ; +wire cpu_wrap_wvalid ; +wire cpu_wrap_wready ; +wire [3 :0] cpu_wrap_bid ; +wire [1 :0] cpu_wrap_bresp ; +wire cpu_wrap_bvalid ; +wire cpu_wrap_bready ; +//cpu axi sync +wire [3 :0] cpu_sync_arid ; +wire [31:0] cpu_sync_araddr ; +wire [3 :0] cpu_sync_arlen ; +wire [2 :0] cpu_sync_arsize ; +wire [1 :0] cpu_sync_arburst; +wire [1 :0] cpu_sync_arlock ; +wire [3 :0] cpu_sync_arcache; +wire [2 :0] cpu_sync_arprot ; +wire cpu_sync_arvalid; +wire cpu_sync_arready; +wire [3 :0] cpu_sync_rid ; +wire [31:0] cpu_sync_rdata ; +wire [1 :0] cpu_sync_rresp ; +wire cpu_sync_rlast ; +wire cpu_sync_rvalid ; +wire cpu_sync_rready ; +wire [3 :0] cpu_sync_awid ; +wire [31:0] cpu_sync_awaddr ; +wire [3 :0] cpu_sync_awlen ; +wire [2 :0] cpu_sync_awsize ; +wire [1 :0] cpu_sync_awburst; +wire [1 :0] cpu_sync_awlock ; +wire [3 :0] cpu_sync_awcache; +wire [2 :0] cpu_sync_awprot ; +wire cpu_sync_awvalid; +wire cpu_sync_awready; +wire [3 :0] cpu_sync_wid ; +wire [31:0] cpu_sync_wdata ; +wire [3 :0] cpu_sync_wstrb ; +wire cpu_sync_wlast ; +wire cpu_sync_wvalid ; +wire cpu_sync_wready ; +wire [3 :0] cpu_sync_bid ; +wire [1 :0] cpu_sync_bresp ; +wire cpu_sync_bvalid ; +wire cpu_sync_bready ; +//axi ram +wire [3 :0] ram_arid ; +wire [31:0] ram_araddr ; +wire [7 :0] ram_arlen ; +wire [2 :0] ram_arsize ; +wire [1 :0] ram_arburst; +wire [1 :0] ram_arlock ; +wire [3 :0] ram_arcache; +wire [2 :0] ram_arprot ; +wire ram_arvalid; +wire ram_arready; +wire [3 :0] ram_rid ; +wire [31:0] ram_rdata ; +wire [1 :0] ram_rresp ; +wire ram_rlast ; +wire ram_rvalid ; +wire ram_rready ; +wire [3 :0] ram_awid ; +wire [31:0] ram_awaddr ; +wire [7 :0] ram_awlen ; +wire [2 :0] ram_awsize ; +wire [1 :0] ram_awburst; +wire [1 :0] ram_awlock ; +wire [3 :0] ram_awcache; +wire [2 :0] ram_awprot ; +wire ram_awvalid; +wire ram_awready; +wire [3 :0] ram_wid ; +wire [31:0] ram_wdata ; +wire [3 :0] ram_wstrb ; +wire ram_wlast ; +wire ram_wvalid ; +wire ram_wready ; +wire [3 :0] ram_bid ; +wire [1 :0] ram_bresp ; +wire ram_bvalid ; +wire ram_bready ; +//conf +wire [3 :0] conf_arid ; +wire [31:0] conf_araddr ; +wire [7 :0] conf_arlen ; +wire [2 :0] conf_arsize ; +wire [1 :0] conf_arburst; +wire [1 :0] conf_arlock ; +wire [3 :0] conf_arcache; +wire [2 :0] conf_arprot ; +wire conf_arvalid; +wire conf_arready; +wire [3 :0] conf_rid ; +wire [31:0] conf_rdata ; +wire [1 :0] conf_rresp ; +wire conf_rlast ; +wire conf_rvalid ; +wire conf_rready ; +wire [3 :0] conf_awid ; +wire [31:0] conf_awaddr ; +wire [7 :0] conf_awlen ; +wire [2 :0] conf_awsize ; +wire [1 :0] conf_awburst; +wire [1 :0] conf_awlock ; +wire [3 :0] conf_awcache; +wire [2 :0] conf_awprot ; +wire conf_awvalid; +wire conf_awready; +wire [3 :0] conf_wid ; +wire [31:0] conf_wdata ; +wire [3 :0] conf_wstrb ; +wire conf_wlast ; +wire conf_wvalid ; +wire conf_wready ; +wire [3 :0] conf_bid ; +wire [1 :0] conf_bresp ; +wire conf_bvalid ; +wire conf_bready ; + +//for lab6 +wire [4 :0] ram_random_mask; + +//cpu axi +//debug_* +mycpu_top u_cpu( + .ext_int (6'd0 ), //high active + + .aclk (cpu_clk ), + .aresetn (cpu_resetn ), //low active + + .arid (cpu_arid ), + .araddr (cpu_araddr ), + .arlen (cpu_arlen ), + .arsize (cpu_arsize ), + .arburst (cpu_arburst ), + .arlock (cpu_arlock ), + .arcache (cpu_arcache ), + .arprot (cpu_arprot ), + .arvalid (cpu_arvalid ), + .arready (cpu_arready ), + + .rid (cpu_rid ), + .rdata (cpu_rdata ), + .rresp (cpu_rresp ), + .rlast (cpu_rlast ), + .rvalid (cpu_rvalid ), + .rready (cpu_rready ), + + .awid (cpu_awid ), + .awaddr (cpu_awaddr ), + .awlen (cpu_awlen ), + .awsize (cpu_awsize ), + .awburst (cpu_awburst ), + .awlock (cpu_awlock ), + .awcache (cpu_awcache ), + .awprot (cpu_awprot ), + .awvalid (cpu_awvalid ), + .awready (cpu_awready ), + + .wid (cpu_wid ), + .wdata (cpu_wdata ), + .wstrb (cpu_wstrb ), + .wlast (cpu_wlast ), + .wvalid (cpu_wvalid ), + .wready (cpu_wready ), + + .bid (cpu_bid ), + .bresp (cpu_bresp ), + .bvalid (cpu_bvalid ), + .bready (cpu_bready ), + + //debug interface + .debug_wb_pc (debug_wb_pc ), + .debug_wb_rf_wen (debug_wb_rf_wen ), + .debug_wb_rf_wnum (debug_wb_rf_wnum ), + .debug_wb_rf_wdata (debug_wb_rf_wdata ), + .debug_wb1_pc (debug_wb1_pc ), + .debug_wb1_rf_wen (debug_wb1_rf_wen ), + .debug_wb1_rf_wnum (debug_wb1_rf_wnum ), + .debug_wb1_rf_wdata(debug_wb1_rf_wdata), + .debug_wb_pc_A (debug_wb_pc_A ) +); +//cpu axi wrap +axi_wrap u_cpu_axi_wrap( + .m_aclk ( cpu_clk ), + .m_aresetn ( cpu_resetn ), + //ar + .m_arid ( cpu_arid ), + .m_araddr ( cpu_araddr ), + .m_arlen ( cpu_arlen ), + .m_arsize ( cpu_arsize ), + .m_arburst ( cpu_arburst ), + .m_arlock ( cpu_arlock ), + .m_arcache ( cpu_arcache ), + .m_arprot ( cpu_arprot ), + .m_arvalid ( cpu_arvalid ), + .m_arready ( cpu_arready ), + //r + .m_rid ( cpu_rid ), + .m_rdata ( cpu_rdata ), + .m_rresp ( cpu_rresp ), + .m_rlast ( cpu_rlast ), + .m_rvalid ( cpu_rvalid ), + .m_rready ( cpu_rready ), + //aw + .m_awid ( cpu_awid ), + .m_awaddr ( cpu_awaddr ), + .m_awlen ( cpu_awlen ), + .m_awsize ( cpu_awsize ), + .m_awburst ( cpu_awburst ), + .m_awlock ( cpu_awlock ), + .m_awcache ( cpu_awcache ), + .m_awprot ( cpu_awprot ), + .m_awvalid ( cpu_awvalid ), + .m_awready ( cpu_awready ), + //w + .m_wid ( cpu_wid ), + .m_wdata ( cpu_wdata ), + .m_wstrb ( cpu_wstrb ), + .m_wlast ( cpu_wlast ), + .m_wvalid ( cpu_wvalid ), + .m_wready ( cpu_wready ), + //b + .m_bid ( cpu_bid ), + .m_bresp ( cpu_bresp ), + .m_bvalid ( cpu_bvalid ), + .m_bready ( cpu_bready ), + + .s_aclk ( cpu_wrap_aclk ), + .s_aresetn ( cpu_wrap_aresetn ), + //ar + .s_arid ( cpu_wrap_arid ), + .s_araddr ( cpu_wrap_araddr ), + .s_arlen ( cpu_wrap_arlen ), + .s_arsize ( cpu_wrap_arsize ), + .s_arburst ( cpu_wrap_arburst ), + .s_arlock ( cpu_wrap_arlock ), + .s_arcache ( cpu_wrap_arcache ), + .s_arprot ( cpu_wrap_arprot ), + .s_arvalid ( cpu_wrap_arvalid ), + .s_arready ( cpu_wrap_arready ), + //r + .s_rid ( cpu_wrap_rid ), + .s_rdata ( cpu_wrap_rdata ), + .s_rresp ( cpu_wrap_rresp ), + .s_rlast ( cpu_wrap_rlast ), + .s_rvalid ( cpu_wrap_rvalid ), + .s_rready ( cpu_wrap_rready ), + //aw + .s_awid ( cpu_wrap_awid ), + .s_awaddr ( cpu_wrap_awaddr ), + .s_awlen ( cpu_wrap_awlen ), + .s_awsize ( cpu_wrap_awsize ), + .s_awburst ( cpu_wrap_awburst ), + .s_awlock ( cpu_wrap_awlock ), + .s_awcache ( cpu_wrap_awcache ), + .s_awprot ( cpu_wrap_awprot ), + .s_awvalid ( cpu_wrap_awvalid ), + .s_awready ( cpu_wrap_awready ), + //w + .s_wid ( cpu_wrap_wid ), + .s_wdata ( cpu_wrap_wdata ), + .s_wstrb ( cpu_wrap_wstrb ), + .s_wlast ( cpu_wrap_wlast ), + .s_wvalid ( cpu_wrap_wvalid ), + .s_wready ( cpu_wrap_wready ), + //b + .s_bid ( cpu_wrap_bid ), + .s_bresp ( cpu_wrap_bresp ), + .s_bvalid ( cpu_wrap_bvalid ), + .s_bready ( cpu_wrap_bready ) +); + +//clock sync: from CPU to AXI_Crossbar (nothing) + +assign cpu_sync_awid = cpu_wrap_awid ; +assign cpu_sync_awaddr = cpu_wrap_awaddr ; +assign cpu_sync_awlen = cpu_wrap_awlen ; +assign cpu_sync_awsize = cpu_wrap_awsize ; +assign cpu_sync_awburst = cpu_wrap_awburst; +assign cpu_sync_awlock = cpu_wrap_awlock ; +assign cpu_sync_awcache = cpu_wrap_awcache; +assign cpu_sync_awprot = cpu_wrap_awprot ; +assign cpu_sync_awvalid = cpu_wrap_awvalid; +assign cpu_wrap_awready = cpu_sync_awready; + +assign cpu_sync_wid = cpu_wrap_wid ; +assign cpu_sync_wdata = cpu_wrap_wdata ; +assign cpu_sync_wstrb = cpu_wrap_wstrb ; +assign cpu_sync_wlast = cpu_wrap_wlast ; +assign cpu_sync_wvalid = cpu_wrap_wvalid; +assign cpu_wrap_wready = cpu_sync_wready; + + assign cpu_wrap_bid = cpu_sync_bid ; + assign cpu_wrap_bresp = cpu_sync_bresp ; + assign cpu_wrap_bvalid = cpu_sync_bvalid; + assign cpu_sync_bready = cpu_wrap_bready; + + assign cpu_sync_arid = cpu_wrap_arid ; + assign cpu_sync_araddr = cpu_wrap_araddr ; + assign cpu_sync_arlen = cpu_wrap_arlen ; + assign cpu_sync_arsize = cpu_wrap_arsize ; + assign cpu_sync_arburst = cpu_wrap_arburst; + assign cpu_sync_arlock = cpu_wrap_arlock ; + assign cpu_sync_arcache = cpu_wrap_arcache; + assign cpu_sync_arprot = cpu_wrap_arprot ; + assign cpu_sync_arvalid = cpu_wrap_arvalid; + assign cpu_wrap_arready = cpu_sync_arready; + + assign cpu_wrap_rid = cpu_sync_rid ; + assign cpu_wrap_rdata = cpu_sync_rdata ; + assign cpu_wrap_rresp = cpu_sync_rresp ; + assign cpu_wrap_rlast = cpu_sync_rlast ; + assign cpu_wrap_rvalid = cpu_sync_rvalid; + assign cpu_sync_rready = cpu_wrap_rready; + +axi_crossbar u_axi_crossbar_1x2( + .clk ( sys_clk ), // i, 1 + .rst ( ~sys_resetn ), // i, 1 + + .s_axi_arid ( cpu_sync_arid ), + .s_axi_araddr ( cpu_sync_araddr ), + .s_axi_arlen ( cpu_sync_arlen[3:0] ), + .s_axi_arsize ( cpu_sync_arsize ), + .s_axi_arburst ( cpu_sync_arburst ), + .s_axi_arlock ( cpu_sync_arlock ), + .s_axi_arcache ( cpu_sync_arcache ), + .s_axi_arprot ( cpu_sync_arprot ), + .s_axi_arqos ( 4'd0 ), + .s_axi_arvalid ( cpu_sync_arvalid ), + .s_axi_arready ( cpu_sync_arready ), + .s_axi_rid ( cpu_sync_rid ), + .s_axi_rdata ( cpu_sync_rdata ), + .s_axi_rresp ( cpu_sync_rresp ), + .s_axi_rlast ( cpu_sync_rlast ), + .s_axi_rvalid ( cpu_sync_rvalid ), + .s_axi_rready ( cpu_sync_rready ), + .s_axi_awid ( cpu_sync_awid ), + .s_axi_awaddr ( cpu_sync_awaddr ), + .s_axi_awlen ( cpu_sync_awlen[3:0] ), + .s_axi_awsize ( cpu_sync_awsize ), + .s_axi_awburst ( cpu_sync_awburst ), + .s_axi_awlock ( cpu_sync_awlock ), + .s_axi_awcache ( cpu_sync_awcache ), + .s_axi_awprot ( cpu_sync_awprot ), + .s_axi_awqos ( 4'd0 ), + .s_axi_awvalid ( cpu_sync_awvalid ), + .s_axi_awready ( cpu_sync_awready ), + //.s_axi_wid ( cpu_sync_wid ), + .s_axi_wdata ( cpu_sync_wdata ), + .s_axi_wstrb ( cpu_sync_wstrb ), + .s_axi_wlast ( cpu_sync_wlast ), + .s_axi_wvalid ( cpu_sync_wvalid ), + .s_axi_wready ( cpu_sync_wready ), + .s_axi_bid ( cpu_sync_bid ), + .s_axi_bresp ( cpu_sync_bresp ), + .s_axi_bvalid ( cpu_sync_bvalid ), + .s_axi_bready ( cpu_sync_bready ), + + .m_axi_arid ( {ram_arid ,conf_arid } ), + .m_axi_araddr ( {ram_araddr ,conf_araddr } ), + .m_axi_arlen ( {ram_arlen ,conf_arlen } ), + .m_axi_arsize ( {ram_arsize ,conf_arsize } ), + .m_axi_arburst ( {ram_arburst,conf_arburst} ), + .m_axi_arlock ( {ram_arlock ,conf_arlock } ), + .m_axi_arcache ( {ram_arcache,conf_arcache} ), + .m_axi_arprot ( {ram_arprot ,conf_arprot } ), + .m_axi_arqos ( ), + .m_axi_arvalid ( {ram_arvalid,conf_arvalid} ), + .m_axi_arready ( {ram_arready,conf_arready} ), + .m_axi_rid ( {ram_rid ,conf_rid } ), + .m_axi_rdata ( {ram_rdata ,conf_rdata } ), + .m_axi_rresp ( {ram_rresp ,conf_rresp } ), + .m_axi_rlast ( {ram_rlast ,conf_rlast } ), + .m_axi_rvalid ( {ram_rvalid ,conf_rvalid } ), + .m_axi_rready ( {ram_rready ,conf_rready } ), + .m_axi_awid ( {ram_awid ,conf_awid } ), + .m_axi_awaddr ( {ram_awaddr ,conf_awaddr } ), + .m_axi_awlen ( {ram_awlen ,conf_awlen } ), + .m_axi_awsize ( {ram_awsize ,conf_awsize } ), + .m_axi_awburst ( {ram_awburst,conf_awburst} ), + .m_axi_awlock ( {ram_awlock ,conf_awlock } ), + .m_axi_awcache ( {ram_awcache,conf_awcache} ), + .m_axi_awprot ( {ram_awprot ,conf_awprot } ), + .m_axi_awqos ( ), + .m_axi_awvalid ( {ram_awvalid,conf_awvalid} ), + .m_axi_awready ( {ram_awready,conf_awready} ), + //.m_axi_wid ( {ram_wid ,conf_wid } ), + .m_axi_wdata ( {ram_wdata ,conf_wdata } ), + .m_axi_wstrb ( {ram_wstrb ,conf_wstrb } ), + .m_axi_wlast ( {ram_wlast ,conf_wlast } ), + .m_axi_wvalid ( {ram_wvalid ,conf_wvalid } ), + .m_axi_wready ( {ram_wready ,conf_wready } ), + .m_axi_bid ( {ram_bid ,conf_bid } ), + .m_axi_bresp ( {ram_bresp ,conf_bresp } ), + .m_axi_bvalid ( {ram_bvalid ,conf_bvalid } ), + .m_axi_bready ( {ram_bready ,conf_bready } ) + + ); + +//axi ram +axi_wrap_ram u_axi_ram +( + .aclk ( sys_clk ), + .aresetn ( sys_resetn ), + //ar + .axi_arid ( ram_arid ), + .axi_araddr ( ram_araddr ), + .axi_arlen ( ram_arlen ), + .axi_arsize ( ram_arsize ), + .axi_arburst ( ram_arburst ), + .axi_arlock ( ram_arlock ), + .axi_arcache ( ram_arcache ), + .axi_arprot ( ram_arprot ), + .axi_arvalid ( ram_arvalid ), + .axi_arready ( ram_arready ), + //r + .axi_rid ( ram_rid ), + .axi_rdata ( ram_rdata ), + .axi_rresp ( ram_rresp ), + .axi_rlast ( ram_rlast ), + .axi_rvalid ( ram_rvalid ), + .axi_rready ( ram_rready ), + //aw + .axi_awid ( ram_awid ), + .axi_awaddr ( ram_awaddr ), + .axi_awlen ( {4'd0,ram_awlen[3:0]} ), + .axi_awsize ( ram_awsize ), + .axi_awburst ( ram_awburst ), + .axi_awlock ( ram_awlock ), + .axi_awcache ( ram_awcache ), + .axi_awprot ( ram_awprot ), + .axi_awvalid ( ram_awvalid ), + .axi_awready ( ram_awready ), + //w + .axi_wid ( ram_wid ), + .axi_wdata ( ram_wdata ), + .axi_wstrb ( ram_wstrb ), + .axi_wlast ( ram_wlast ), + .axi_wvalid ( ram_wvalid ), + .axi_wready ( ram_wready ), + //b ram + .axi_bid ( ram_bid ), + .axi_bresp ( ram_bresp ), + .axi_bvalid ( ram_bvalid ), + .axi_bready ( ram_bready ), + + //random mask + .ram_random_mask ( ram_random_mask ) +); + +//confreg +confreg #(.SIMULATION(SIMULATION)) u_confreg +( + .timer_clk ( sys_clk ), // i, 1 + .aclk ( sys_clk ), // i, 1 + .aresetn ( sys_resetn ), // i, 1 + + .arid (conf_arid ), + .araddr (conf_araddr ), + .arlen (conf_arlen ), + .arsize (conf_arsize ), + .arburst (conf_arburst ), + .arlock (conf_arlock ), + .arcache (conf_arcache ), + .arprot (conf_arprot ), + .arvalid (conf_arvalid ), + .arready (conf_arready ), + .rid (conf_rid ), + .rdata (conf_rdata ), + .rresp (conf_rresp ), + .rlast (conf_rlast ), + .rvalid (conf_rvalid ), + .rready (conf_rready ), + .awid (conf_awid ), + .awaddr (conf_awaddr ), + .awlen (conf_awlen ), + .awsize (conf_awsize ), + .awburst (conf_awburst ), + .awlock (conf_awlock ), + .awcache (conf_awcache ), + .awprot (conf_awprot ), + .awvalid (conf_awvalid ), + .awready (conf_awready ), + .wid (conf_wid ), + .wdata (conf_wdata ), + .wstrb (conf_wstrb ), + .wlast (conf_wlast ), + .wvalid (conf_wvalid ), + .wready (conf_wready ), + .bid (conf_bid ), + .bresp (conf_bresp ), + .bvalid (conf_bvalid ), + .bready (conf_bready ), + + .ram_random_mask ( ram_random_mask ), + .led ( led ), // o, 16 + .led_rg0 ( led_rg0 ), // o, 2 + .led_rg1 ( led_rg1 ), // o, 2 + .num_csn ( num_csn ), // o, 8 + .num_a_g ( num_a_g ), // o, 7 + .switch ( switch ), // i, 8 + .btn_key_col ( btn_key_col), // o, 4 + .btn_key_row ( btn_key_row), // i, 4 + .btn_step ( btn_step ) // i, 2 +); + +endmodule + diff --git a/resources/tb.sv b/resources/tb.sv new file mode 100644 index 0000000..3e4ea09 --- /dev/null +++ b/resources/tb.sv @@ -0,0 +1,172 @@ +`timescale 1ns / 1ps + +`define CONFREG_NUM_REG soc_lite.u_confreg.num_data +`define CONFREG_NUM_MONITOR soc_lite.u_confreg.num_monitor + +`define CONFREG_UART_DISPLAY soc_lite.u_confreg.write_uart_valid +`define CONFREG_UART_DATA soc_lite.u_confreg.write_uart_data + +`define END_PC 32'hbfc00100 + +module testbench_top ( + input clk, + input resetn, + output [15:0] led, + output [ 1:0] led_rg0, + output [ 1:0] led_rg1, + output [ 7:0] num_csn, + output [ 6:0] num_a_g +); + //gpio + logic [ 7:0] switch; + logic [ 3:0] btn_key_col; + logic [ 3:0] btn_key_row; + logic [ 1:0] btn_step; + + logic uart_display; + logic [ 7:0] uart_data; + logic [31:0] confreg_num_reg; + logic [31:0] confreg_num_reg_r; + + assign switch = 8'hff; + assign btn_key_row = 4'd0; + assign btn_step = 2'd3; + assign uart_display = `CONFREG_UART_DISPLAY; + assign uart_data = `CONFREG_UART_DATA; + assign confreg_num_reg = `CONFREG_NUM_REG; + + // soc clk & debug info + logic cpu_clk; + logic sys_clk; + logic [31:0] debug_wb_pc; + logic [ 3:0] debug_wb_rf_wen; + logic [ 4:0] debug_wb_rf_wnum; + logic [31:0] debug_wb_rf_wdata; + logic [31:0] debug_wb1_pc; + logic [ 3:0] debug_wb1_rf_wen; + logic [ 4:0] debug_wb1_rf_wnum; + logic [31:0] debug_wb1_rf_wdata; + logic debug_wb_pc_A; + logic [ 3:0] dbg_0_rf_wen; + logic [31:0] dbg_0_pc; + logic [ 4:0] dbg_0_rf_wnum; + logic [31:0] dbg_0_rf_wdata; + logic [ 3:0] dbg_1_rf_wen; + logic [31:0] dbg_1_pc; + logic [ 4:0] dbg_1_rf_wnum; + logic [31:0] dbg_1_rf_wdata; + assign cpu_clk = soc_lite.cpu_clk; + assign sys_clk = soc_lite.sys_clk; + assign debug_wb_pc = soc_lite.debug_wb_pc; + assign debug_wb_rf_wen = soc_lite.debug_wb_rf_wen; + assign debug_wb_rf_wnum = soc_lite.debug_wb_rf_wnum; + assign debug_wb_rf_wdata = soc_lite.debug_wb_rf_wdata; + assign debug_wb1_pc = soc_lite.u_cpu.debug_wb1_pc; + assign debug_wb1_rf_wen = soc_lite.u_cpu.debug_wb1_rf_wen; + assign debug_wb1_rf_wnum = soc_lite.u_cpu.debug_wb1_rf_wnum; + assign debug_wb1_rf_wdata = soc_lite.u_cpu.debug_wb1_rf_wdata; + assign debug_wb_pc_A = soc_lite.u_cpu.debug_wb_pc_A; + + always @(posedge cpu_clk) begin + if (debug_wb_pc_A) begin + dbg_0_rf_wen <= debug_wb1_rf_wen; + dbg_0_pc <= debug_wb1_pc; + dbg_0_rf_wnum <= debug_wb1_rf_wnum; + dbg_0_rf_wdata <= debug_wb1_rf_wdata; + + dbg_1_rf_wen <= debug_wb_rf_wen; + dbg_1_pc <= debug_wb_pc; + dbg_1_rf_wnum <= debug_wb_rf_wnum; + dbg_1_rf_wdata <= debug_wb_rf_wdata; + end else begin + dbg_1_rf_wen <= debug_wb1_rf_wen; + dbg_1_pc <= debug_wb1_pc; + dbg_1_rf_wnum <= debug_wb1_rf_wnum; + dbg_1_rf_wdata <= debug_wb1_rf_wdata; + + dbg_0_rf_wen <= debug_wb_rf_wen; + dbg_0_pc <= debug_wb_pc; + dbg_0_rf_wnum <= debug_wb_rf_wnum; + dbg_0_rf_wdata <= debug_wb_rf_wdata; + end + + if (|dbg_0_rf_wen) begin + $display("path0 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h, wen= %d", + dbg_0_pc, dbg_0_rf_wnum, dbg_0_rf_wdata, |dbg_0_rf_wen); + end + if (|dbg_1_rf_wen) begin + $display("path1 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h, wen= %d", + dbg_1_pc, dbg_1_rf_wnum, dbg_1_rf_wdata, |dbg_1_rf_wen); + end + end + + // UART + always @(posedge sys_clk) begin + if (uart_display) begin + if (uart_data == 8'hff) begin + ; //$finish; + end else begin + $write("%c", uart_data); + end + end + end + + // Numeric Display + logic [7:0] err_count; + always_ff @(posedge sys_clk) begin + confreg_num_reg_r <= confreg_num_reg; + if (!resetn) begin + err_count <= 8'd0; + end else if (confreg_num_reg_r != confreg_num_reg && `CONFREG_NUM_MONITOR) begin + if (confreg_num_reg[7:0] != confreg_num_reg_r[7:0] + 1'b1) begin + $display("--------------------------------------------------------------"); + $display("[%t] Error(%d)! Occurred in number 8'd%02d Functional Test Point!", $time, err_count, confreg_num_reg[31:24]); + $display("--------------------------------------------------------------"); + err_count <= err_count + 1'b1; + end else if (confreg_num_reg[31:24] != confreg_num_reg_r[31:24] + 1'b1) begin + $display("--------------------------------------------------------------"); + $display("[%t] Error(%d)! Unknown, Functional Test Point numbers are unequal!", $time, err_count); + $display("--------------------------------------------------------------"); + err_count <= err_count + 1'b1; + end else begin + $display("----[%t] Number 8'd%02d Functional Test Point PASS!", $time, confreg_num_reg[31:24]); + end + end + end + + //test end + logic test_end; + assign test_end = (dbg_0_pc == `END_PC) || (dbg_1_pc == `END_PC) || (uart_display && uart_data == 8'hff); + always @(posedge cpu_clk) + if (test_end) begin + if (err_count != 0) begin + $display(""); + $display("=============================================================="); + $display("Test end with ERROR!"); + end else begin + $display(""); + $display("=============================================================="); + $display("Test end!"); + end + $finish; + end + + soc_axi_lite_top #( + .SIMULATION(1'b1) + ) soc_lite ( + .resetn(resetn), + .clk (clk), + + //------gpio------- + .num_csn (num_csn), + .num_a_g (num_a_g), + .led (led), + .led_rg0 (led_rg0), + .led_rg1 (led_rg1), + .switch (switch), + .btn_key_col(btn_key_col), + .btn_key_row(btn_key_row), + .btn_step (btn_step) + ); + +endmodule diff --git a/resources/tb2.sv b/resources/tb2.sv deleted file mode 100644 index 3d78573..0000000 --- a/resources/tb2.sv +++ /dev/null @@ -1,308 +0,0 @@ -`timescale 1ns / 1ps - -`define SIMULATION_PC -`define TRACE_REF_FILE "../../../../../../../cpu132_gettrace/golden_trace.txt" -`define CONFREG_NUM_REG soc_lite.u_confreg.num_data -//`define CONFREG_OPEN_TRACE soc_lite.u_confreg.open_trace -`define CONFREG_OPEN_TRACE 1'b0 -`define CONFREG_NUM_MONITOR soc_lite.u_confreg.num_monitor -`define CONFREG_UART_DISPLAY soc_lite.u_confreg.write_uart_valid -`define CONFREG_UART_DATA soc_lite.u_confreg.write_uart_data -`define END_PC 32'hbfc00100 - -module tb2_top (); - logic resetn; - logic clk; - - //goio - logic [15:0] led; - logic [1:0] led_rg0; - logic [1:0] led_rg1; - logic [7:0] num_csn; - logic [6:0] num_a_g; - logic [7:0] switch; - logic [3:0] btn_key_col; - logic [3:0] btn_key_row; - logic [1:0] btn_step; - assign switch = 8'hff; - assign btn_key_row = 4'd0; - assign btn_step = 2'd3; - - initial begin - // $dumpfile("dump.vcd"); - // $dumpvars(); - - resetn = 1'b0; - #2000; - resetn = 1'b1; - end - - initial begin - clk = 1'b0; - forever begin - #5 clk = ~clk; - end - end - - soc_axi_lite_top #( - .SIMULATION(1'b1) - ) soc_lite ( - .resetn(resetn), - .clk (clk), - - //------gpio------- - .num_csn (num_csn), - .num_a_g (num_a_g), - .led (led), - .led_rg0 (led_rg0), - .led_rg1 (led_rg1), - .switch (switch), - .btn_key_col(btn_key_col), - .btn_key_row(btn_key_row), - .btn_step (btn_step) - ); - - //"cpu_clk" means cpu core clk - //"sys_clk" means system clk - //"wb" means write-back stage in pipeline - //"rf" means regfiles in cpu - //"w" in "wen/wnum/wdata" means writing - logic cpu_clk; - logic sys_clk; - logic [31:0] debug_wb_pc; - logic [3:0] debug_wb_rf_wen; - logic [4:0] debug_wb_rf_wnum; - logic [31:0] debug_wb_rf_wdata; - logic [31:0] debug_wb1_pc; - logic [3:0] debug_wb1_rf_wen; - logic [4:0] debug_wb1_rf_wnum; - logic [31:0] debug_wb1_rf_wdata; - logic debug_wb_pc_A; - - assign cpu_clk = soc_lite.cpu_clk; - assign sys_clk = soc_lite.sys_clk; - assign debug_wb_pc = soc_lite.debug_wb_pc; - assign debug_wb_rf_wen = soc_lite.debug_wb_rf_wen; - assign debug_wb_rf_wnum = soc_lite.debug_wb_rf_wnum; - assign debug_wb_rf_wdata = soc_lite.debug_wb_rf_wdata; - assign debug_wb1_pc = soc_lite.u_cpu.debug_wb1_pc; - assign debug_wb1_rf_wen = soc_lite.u_cpu.debug_wb1_rf_wen; - assign debug_wb1_rf_wnum = soc_lite.u_cpu.debug_wb1_rf_wnum; - assign debug_wb1_rf_wdata = soc_lite.u_cpu.debug_wb1_rf_wdata; - assign debug_wb_pc_A = soc_lite.u_cpu.debug_wb_pc_A; - - // open the trace file; - integer trace_ref; - initial begin - trace_ref = $fopen(`TRACE_REF_FILE, "r"); - end - - //get reference result in falling edge - logic debug_end; - - logic trace_cmp_flag; - logic [31:0] ref_wb_pc; - logic [4:0] ref_wb_rf_wnum; - logic [31:0] ref_wb_rf_wdata; - - typedef struct packed { - logic trace_cmp_flag; - logic [31:0] ref_wb_pc; - logic [4:0] ref_wb_rf_wnum; - logic [31:0] ref_wb_rf_wdata; - logic [31:0] lineno; - } TRACE_INFO; - - TRACE_INFO ref_trace[$]; - logic [31:0] lineno; - - initial begin - lineno = 0; - while (!$feof( - trace_ref - )) begin - lineno = lineno + 1; - $fscanf(trace_ref, "%h %h %h %h", trace_cmp_flag, ref_wb_pc, ref_wb_rf_wnum, ref_wb_rf_wdata); - if (trace_cmp_flag == 1) begin - ref_trace.push_back({trace_cmp_flag, ref_wb_pc, ref_wb_rf_wnum, ref_wb_rf_wdata, lineno}); - end - end - end - - //compare result in rsing edge - logic debug_wb_err; - - logic dbg_0_rf_wen; - logic [31:0] dbg_0_pc; - logic [ 4:0] dbg_0_rf_wnum; - logic [31:0] dbg_0_rf_wdata; - - logic dbg_1_rf_wen; - logic [31:0] dbg_1_pc; - logic [ 4:0] dbg_1_rf_wnum; - logic [31:0] dbg_1_rf_wdata; - - always @(posedge cpu_clk) begin - #2; - if (!resetn) begin - debug_wb_err <= 1'b0; - end else if (!debug_end) begin - if (debug_wb_pc_A) begin - dbg_0_rf_wen <= debug_wb1_rf_wen; - dbg_0_pc <= debug_wb1_pc; - dbg_0_rf_wnum <= debug_wb1_rf_wnum; - dbg_0_rf_wdata <= debug_wb1_rf_wdata; - - dbg_1_rf_wen <= debug_wb_rf_wen; - dbg_1_pc <= debug_wb_pc; - dbg_1_rf_wnum <= debug_wb_rf_wnum; - dbg_1_rf_wdata <= debug_wb_rf_wdata; - end else begin - dbg_1_rf_wen <= debug_wb1_rf_wen; - dbg_1_pc <= debug_wb1_pc; - dbg_1_rf_wnum <= debug_wb1_rf_wnum; - dbg_1_rf_wdata <= debug_wb1_rf_wdata; - - dbg_0_rf_wen <= debug_wb_rf_wen; - dbg_0_pc <= debug_wb_pc; - dbg_0_rf_wnum <= debug_wb_rf_wnum; - dbg_0_rf_wdata <= debug_wb_rf_wdata; - end - - if (|dbg_0_rf_wen && `CONFREG_OPEN_TRACE) begin - $display("mycpu0 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h, wen= %d", - dbg_0_pc, dbg_0_rf_wnum, dbg_0_rf_wdata, |dbg_0_rf_wen); - end - if (|dbg_1_rf_wen && `CONFREG_OPEN_TRACE) begin - $display("mycpu1 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h, wen= %d", - dbg_1_pc, dbg_1_rf_wnum, dbg_1_rf_wdata, |dbg_1_rf_wen); - end - - if (|dbg_0_rf_wen && dbg_0_rf_wnum != 5'd0 && `CONFREG_OPEN_TRACE) begin - if ( (dbg_0_pc !== ref_trace[0].ref_wb_pc ) - || (dbg_0_rf_wnum !== ref_trace[0].ref_wb_rf_wnum ) - || (dbg_0_rf_wdata !== ref_trace[0].ref_wb_rf_wdata) - ) - begin - $display("--------------------------------------------------------------"); - $display("[%t] Error!!!", $time); - $display(" reference: PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h, lineno = %d", - ref_trace[0].ref_wb_pc, ref_trace[0].ref_wb_rf_wnum, - ref_trace[0].ref_wb_rf_wdata, ref_trace[0].lineno); - $display(" mycpu0 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h", dbg_0_pc, - dbg_0_rf_wnum, dbg_0_rf_wdata); - $display(" mycpu1 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h", dbg_1_pc, - dbg_1_rf_wnum, dbg_1_rf_wdata); - $display("--------------------------------------------------------------"); - debug_wb_err <= 1'b1; - #40; - $finish; - end else ref_trace.pop_front(); - end - if (|dbg_1_rf_wen && dbg_1_rf_wnum != 5'd0 && `CONFREG_OPEN_TRACE) begin - if ( (dbg_1_pc !== ref_trace[0].ref_wb_pc ) - || (dbg_1_rf_wnum !== ref_trace[0].ref_wb_rf_wnum ) - || (dbg_1_rf_wdata !== ref_trace[0].ref_wb_rf_wdata) - ) - begin - $display("--------------------------------------------------------------"); - $display("[%t] Error!!!", $time); - $display(" reference: PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h, lineno = %d", - ref_trace[0].ref_wb_pc, ref_trace[0].ref_wb_rf_wnum, - ref_trace[0].ref_wb_rf_wdata, ref_trace[0].lineno); - $display(" mycpu0 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h", dbg_0_pc, - dbg_0_rf_wnum, dbg_0_rf_wdata); - $display(" mycpu1 : PC = 0x%8h, wb_rf_wnum = 0x%2h, wb_rf_wdata = 0x%8h", dbg_1_pc, - dbg_1_rf_wnum, dbg_1_rf_wdata); - $display("--------------------------------------------------------------"); - debug_wb_err <= 1'b1; - #40; - $finish; - end else ref_trace.pop_front(); - end - end - end - - //monitor numeric display - logic [ 7:0] err_count; - wire [31:0] confreg_num_reg = `CONFREG_NUM_REG; - logic [31:0] confreg_num_reg_r; - always_ff @(posedge sys_clk) begin - confreg_num_reg_r <= confreg_num_reg; - if (!resetn) begin - err_count <= 8'd0; - end else if (confreg_num_reg_r != confreg_num_reg && `CONFREG_NUM_MONITOR) begin - if (confreg_num_reg[7:0] != confreg_num_reg_r[7:0] + 1'b1) begin - $display("--------------------------------------------------------------"); - $display("[%t] Error(%d)!!! Occurred in number 8'd%02d Functional Test Point!", $time, - err_count, confreg_num_reg[31:24]); - $display("--------------------------------------------------------------"); - err_count <= err_count + 1'b1; - $finish; - end else if (confreg_num_reg[31:24] != confreg_num_reg_r[31:24] + 1'b1) begin - $display("--------------------------------------------------------------"); - $display("[%t] Error(%d)!!! Unknown, Functional Test Point numbers are unequal!", $time, - err_count); - $display("--------------------------------------------------------------"); - $display("=============================================================="); - err_count <= err_count + 1'b1; - $finish; - end else begin - $display("----[%t] Number 8'd%02d Functional Test Point PASS!!!", $time, - confreg_num_reg[31:24]); - end - end - end - - //monitor test - initial begin - $timeformat(-9, 0, " ns", 10); - while (!resetn) #5; - $display("=============================================================="); - $display("Test begin!"); - - #10000; - while (`CONFREG_NUM_MONITOR) begin - #10000; - $display(" [%t] Test is running, dbg_0_pc = 0x%8h, dbg_1_pc = 0x%8h", $time, dbg_0_pc, - dbg_1_pc); - end - end - - // Uart Display - logic uart_display; - logic [7:0] uart_data; - assign uart_display = `CONFREG_UART_DISPLAY; - assign uart_data = `CONFREG_UART_DATA; - - always_ff @(posedge sys_clk) begin - if (uart_display) begin - if (uart_data == 8'hff) begin - ; //$finish; - end else begin - $write("%c", uart_data); - end - end - end - - //test end - wire global_err = debug_wb_err || (err_count != 8'd0); - wire test_end = (dbg_0_pc == `END_PC) || (dbg_1_pc == `END_PC) || (uart_display && uart_data == 8'hff); - always @(posedge cpu_clk) begin - if (!resetn) begin - debug_end <= 1'b0; - end else if (test_end && !debug_end) begin - debug_end <= 1'b1; - $display("=============================================================="); - $display("Test end!"); - #40; - $fclose(trace_ref); - if (global_err) begin - $display("Fail!!!Total %d errors!", err_count); - end else begin - $display("----PASS!!!"); - end - $finish; - end - end -endmodule diff --git a/sim/.gitignore b/sim/.gitignore new file mode 100644 index 0000000..511a421 --- /dev/null +++ b/sim/.gitignore @@ -0,0 +1 @@ +obj_dir \ No newline at end of file diff --git a/sim/Makefile b/sim/Makefile new file mode 100644 index 0000000..8b74afa --- /dev/null +++ b/sim/Makefile @@ -0,0 +1,76 @@ +#################### +# Program # +#################### +VERILATOR = verilator +VERILATOR_COVERAGE = verilator_coverage + + +#################### +# Flags # +#################### +VERILATOR_BUILD_FLAGS = +# Generate C++ in executable form +VERILATOR_BUILD_FLAGS += -cc --exe +# Generate makefile dependencies (not shown as complicates the Makefile) +VERILATOR_BUILD_FLAGS += -MMD +# Optimize +VERILATOR_BUILD_FLAGS += -O3 -x-assign 0 +# Warn abount lint issues; may not want this on less solid designs +VERILATOR_BUILD_FLAGS += -Wall +# Make waveforms +VERILATOR_BUILD_FLAGS += --trace +# Check SystemVerilog assertions +VERILATOR_BUILD_FLAGS += --assert +# Generate coverage analysis +VERILATOR_BUILD_FLAGS += --coverage +# Run make to compile model, with as many CPUs as are free +VERILATOR_BUILD_FLAGS += --build -j + +# Simulation Defines +VERILATOR_FLAGS += -DSIMULATION_PC + +# Create annotated source +VERILATOR_COV_FLAGS += --annotate logs/annotated +# A single coverage hit is considered good enough +VERILATOR_COV_FLAGS += --annotate-min 1 +# Create LCOV info +VERILATOR_COV_FLAGS += --write-info logs/coverage.info +# Input file from Verilator +VERILATOR_COV_FLAGS += logs/coverage.dat + +#################### +# Sources # +#################### +SOURCE = ./config.vlt $(wildcard ./model/*.v ./model/*.sv ../src/*.v ../src/*.sv ../src/**/*.v ../src/**/*.sv) +INCLUDE = $(addprefix -I, $(dir $(wildcard ../src/*/. ../src/**/*/.))) +VERILATOR_INPUT = -top testbench_top sim_main.cpp + +FUNC_SOURCE = $(wildcard ../resources/tb.sv ../resources/func_test/*.v ../resources/func_test/**/*.v) + +#################### +# Targets # +#################### +.phony: test func_test func_coverage run clean + +default: run + +test: + @echo $(SOURCE) + +lint: + $(VERILATOR) --lint-only $(VERILATOR_FLAGS) $(INCLUDE) $(SOURCE) -top mycpu_top + +func_test: + $(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_BUILD_FLAGS) $(INCLUDE) $(SOURCE) $(FUNC_SOURCE) $(VERILATOR_INPUT) + +func_coverage: func_test + @rm -rf logs/annotated + $(VERILATOR_COVERAGE) $(VERILATOR_COV_FLAGS) + +run: func_test + @rm -rf logs + @mkdir -p logs + obj_dir/Vmycpu_top + +clean: + -rm -rf obj_dir logs *.log *.dmp *.vpd core diff --git a/sim/config.vlt b/sim/config.vlt new file mode 100644 index 0000000..728db32 --- /dev/null +++ b/sim/config.vlt @@ -0,0 +1,9 @@ +`verilator_config +lint_off -rule TIMESCALEMOD +lint_off -rule DECLFILENAME + +lint_off -file "model/*.v" +lint_off -file "../resources/func_test/*.v" + +lint_off -rule BLKSEQ -file "../src/CP0/CP0.sv" +lint_off -rule PINCONNECTEMPTY -file "../src/MU/MU.sv" diff --git a/sim/model/arbiter.v b/sim/model/arbiter.v new file mode 100644 index 0000000..d8956a2 --- /dev/null +++ b/sim/model/arbiter.v @@ -0,0 +1,154 @@ +/* +Copyright (c) 2014-2021 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Arbiter module + */ +module arbiter # +( + parameter PORTS = 4, + // select round robin arbitration + parameter ARB_TYPE_ROUND_ROBIN = 0, + // blocking arbiter enable + parameter ARB_BLOCK = 0, + // block on acknowledge assert when nonzero, request deassert when 0 + parameter ARB_BLOCK_ACK = 1, + // LSB priority selection + parameter ARB_LSB_HIGH_PRIORITY = 0 +) +( + input wire clk, + input wire rst, + + input wire [PORTS-1:0] request, + input wire [PORTS-1:0] acknowledge, + + output wire [PORTS-1:0] grant, + output wire grant_valid, + output wire [$clog2(PORTS)-1:0] grant_encoded +); + +reg [PORTS-1:0] grant_reg = 0, grant_next; +reg grant_valid_reg = 0, grant_valid_next; +reg [$clog2(PORTS)-1:0] grant_encoded_reg = 0, grant_encoded_next; + +assign grant_valid = grant_valid_reg; +assign grant = grant_reg; +assign grant_encoded = grant_encoded_reg; + +wire request_valid; +wire [$clog2(PORTS)-1:0] request_index; +wire [PORTS-1:0] request_mask; + +priority_encoder #( + .WIDTH(PORTS), + .LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY) +) +priority_encoder_inst ( + .input_unencoded(request), + .output_valid(request_valid), + .output_encoded(request_index), + .output_unencoded(request_mask) +); + +reg [PORTS-1:0] mask_reg = 0, mask_next; + +wire masked_request_valid; +wire [$clog2(PORTS)-1:0] masked_request_index; +wire [PORTS-1:0] masked_request_mask; + +priority_encoder #( + .WIDTH(PORTS), + .LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY) +) +priority_encoder_masked ( + .input_unencoded(request & mask_reg), + .output_valid(masked_request_valid), + .output_encoded(masked_request_index), + .output_unencoded(masked_request_mask) +); + +always @* begin + grant_next = 0; + grant_valid_next = 0; + grant_encoded_next = 0; + mask_next = mask_reg; + + if (ARB_BLOCK && !ARB_BLOCK_ACK && grant_reg & request) begin + // granted request still asserted; hold it + grant_valid_next = grant_valid_reg; + grant_next = grant_reg; + grant_encoded_next = grant_encoded_reg; + end else if (ARB_BLOCK && ARB_BLOCK_ACK && grant_valid && !(grant_reg & acknowledge)) begin + // granted request not yet acknowledged; hold it + grant_valid_next = grant_valid_reg; + grant_next = grant_reg; + grant_encoded_next = grant_encoded_reg; + end else if (request_valid) begin + if (ARB_TYPE_ROUND_ROBIN) begin + if (masked_request_valid) begin + grant_valid_next = 1; + grant_next = masked_request_mask; + grant_encoded_next = masked_request_index; + if (ARB_LSB_HIGH_PRIORITY) begin + mask_next = {PORTS{1'b1}} << (masked_request_index + 1); + end else begin + mask_next = {PORTS{1'b1}} >> (PORTS - masked_request_index); + end + end else begin + grant_valid_next = 1; + grant_next = request_mask; + grant_encoded_next = request_index; + if (ARB_LSB_HIGH_PRIORITY) begin + mask_next = {PORTS{1'b1}} << (request_index + 1); + end else begin + mask_next = {PORTS{1'b1}} >> (PORTS - request_index); + end + end + end else begin + grant_valid_next = 1; + grant_next = request_mask; + grant_encoded_next = request_index; + end + end +end + +always @(posedge clk) begin + if (rst) begin + grant_reg <= 0; + grant_valid_reg <= 0; + grant_encoded_reg <= 0; + mask_reg <= 0; + end else begin + grant_reg <= grant_next; + grant_valid_reg <= grant_valid_next; + grant_encoded_reg <= grant_encoded_next; + mask_reg <= mask_next; + end +end + +endmodule + +`resetall diff --git a/sim/model/axi_crossbar.v b/sim/model/axi_crossbar.v new file mode 100644 index 0000000..a97153c --- /dev/null +++ b/sim/model/axi_crossbar.v @@ -0,0 +1,386 @@ +/* +Copyright (c) 2018 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 crossbar + */ +module axi_crossbar # +( + // Number of AXI inputs (slave interfaces) + parameter S_COUNT = 1, + // Number of AXI outputs (master interfaces) + parameter M_COUNT = 2, + // Width of data bus in bits + parameter DATA_WIDTH = 32, + // Width of address bus in bits + parameter ADDR_WIDTH = 32, + // Width of wstrb (width of data bus in words) + parameter STRB_WIDTH = (DATA_WIDTH/8), + // Input ID field width (from AXI masters) + parameter S_ID_WIDTH = 4, + // Output ID field width (towards AXI slaves) + // Additional bits required for response routing + parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), + // Propagate awuser signal + parameter AWUSER_ENABLE = 0, + // Width of awuser signal + parameter AWUSER_WIDTH = 1, + // Propagate wuser signal + parameter WUSER_ENABLE = 0, + // Width of wuser signal + parameter WUSER_WIDTH = 1, + // Propagate buser signal + parameter BUSER_ENABLE = 0, + // Width of buser signal + parameter BUSER_WIDTH = 1, + // Propagate aruser signal + parameter ARUSER_ENABLE = 0, + // Width of aruser signal + parameter ARUSER_WIDTH = 1, + // Propagate ruser signal + parameter RUSER_ENABLE = 0, + // Width of ruser signal + parameter RUSER_WIDTH = 1, + // Number of concurrent unique IDs for each slave interface + // S_COUNT concatenated fields of 32 bits + parameter S_THREADS = {S_COUNT{32'd2}}, + // Number of concurrent operations for each slave interface + // S_COUNT concatenated fields of 32 bits + parameter S_ACCEPT = {S_COUNT{32'd16}}, + // Number of regions per master interface + parameter M_REGIONS = 1, + // Master interface base addresses + // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits + // set to zero for default addressing based on M_ADDR_WIDTH + parameter M_BASE_ADDR = 0, + // Master interface address widths + // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits + parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, + // Read connections between interfaces + // M_COUNT concatenated fields of S_COUNT bits + parameter M_CONNECT_READ = {M_COUNT{{S_COUNT{1'b1}}}}, + // Write connections between interfaces + // M_COUNT concatenated fields of S_COUNT bits + parameter M_CONNECT_WRITE = {M_COUNT{{S_COUNT{1'b1}}}}, + // Number of concurrent operations for each master interface + // M_COUNT concatenated fields of 32 bits + parameter M_ISSUE = {M_COUNT{32'd4}}, + // Secure master (fail operations based on awprot/arprot) + // M_COUNT bits + parameter M_SECURE = {M_COUNT{1'b0}}, + // Slave interface AW channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_AW_REG_TYPE = {S_COUNT{2'd0}}, + // Slave interface W channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_W_REG_TYPE = {S_COUNT{2'd0}}, + // Slave interface B channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_B_REG_TYPE = {S_COUNT{2'd1}}, + // Slave interface AR channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_AR_REG_TYPE = {S_COUNT{2'd0}}, + // Slave interface R channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_R_REG_TYPE = {S_COUNT{2'd2}}, + // Master interface AW channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_AW_REG_TYPE = {M_COUNT{2'd1}}, + // Master interface W channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_W_REG_TYPE = {M_COUNT{2'd2}}, + // Master interface B channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_B_REG_TYPE = {M_COUNT{2'd0}}, + // Master interface AR channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_AR_REG_TYPE = {M_COUNT{2'd1}}, + // Master interface R channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_R_REG_TYPE = {M_COUNT{2'd0}} +) +( + input wire clk, + input wire rst, + + /* + * AXI slave interfaces + */ + input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid, + input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [S_COUNT*8-1:0] s_axi_awlen, + input wire [S_COUNT*3-1:0] s_axi_awsize, + input wire [S_COUNT*2-1:0] s_axi_awburst, + input wire [S_COUNT-1:0] s_axi_awlock, + input wire [S_COUNT*4-1:0] s_axi_awcache, + input wire [S_COUNT*3-1:0] s_axi_awprot, + input wire [S_COUNT*4-1:0] s_axi_awqos, + input wire [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser, + input wire [S_COUNT-1:0] s_axi_awvalid, + output wire [S_COUNT-1:0] s_axi_awready, + input wire [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata, + input wire [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb, + input wire [S_COUNT-1:0] s_axi_wlast, + input wire [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser, + input wire [S_COUNT-1:0] s_axi_wvalid, + output wire [S_COUNT-1:0] s_axi_wready, + output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid, + output wire [S_COUNT*2-1:0] s_axi_bresp, + output wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser, + output wire [S_COUNT-1:0] s_axi_bvalid, + input wire [S_COUNT-1:0] s_axi_bready, + input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid, + input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr, + input wire [S_COUNT*8-1:0] s_axi_arlen, + input wire [S_COUNT*3-1:0] s_axi_arsize, + input wire [S_COUNT*2-1:0] s_axi_arburst, + input wire [S_COUNT-1:0] s_axi_arlock, + input wire [S_COUNT*4-1:0] s_axi_arcache, + input wire [S_COUNT*3-1:0] s_axi_arprot, + input wire [S_COUNT*4-1:0] s_axi_arqos, + input wire [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser, + input wire [S_COUNT-1:0] s_axi_arvalid, + output wire [S_COUNT-1:0] s_axi_arready, + output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid, + output wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata, + output wire [S_COUNT*2-1:0] s_axi_rresp, + output wire [S_COUNT-1:0] s_axi_rlast, + output wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser, + output wire [S_COUNT-1:0] s_axi_rvalid, + input wire [S_COUNT-1:0] s_axi_rready, + + /* + * AXI master interfaces + */ + output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid, + output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [M_COUNT*8-1:0] m_axi_awlen, + output wire [M_COUNT*3-1:0] m_axi_awsize, + output wire [M_COUNT*2-1:0] m_axi_awburst, + output wire [M_COUNT-1:0] m_axi_awlock, + output wire [M_COUNT*4-1:0] m_axi_awcache, + output wire [M_COUNT*3-1:0] m_axi_awprot, + output wire [M_COUNT*4-1:0] m_axi_awqos, + output wire [M_COUNT*4-1:0] m_axi_awregion, + output wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser, + output wire [M_COUNT-1:0] m_axi_awvalid, + input wire [M_COUNT-1:0] m_axi_awready, + output wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata, + output wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb, + output wire [M_COUNT-1:0] m_axi_wlast, + output wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser, + output wire [M_COUNT-1:0] m_axi_wvalid, + input wire [M_COUNT-1:0] m_axi_wready, + input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid, + input wire [M_COUNT*2-1:0] m_axi_bresp, + input wire [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser, + input wire [M_COUNT-1:0] m_axi_bvalid, + output wire [M_COUNT-1:0] m_axi_bready, + output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid, + output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr, + output wire [M_COUNT*8-1:0] m_axi_arlen, + output wire [M_COUNT*3-1:0] m_axi_arsize, + output wire [M_COUNT*2-1:0] m_axi_arburst, + output wire [M_COUNT-1:0] m_axi_arlock, + output wire [M_COUNT*4-1:0] m_axi_arcache, + output wire [M_COUNT*3-1:0] m_axi_arprot, + output wire [M_COUNT*4-1:0] m_axi_arqos, + output wire [M_COUNT*4-1:0] m_axi_arregion, + output wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser, + output wire [M_COUNT-1:0] m_axi_arvalid, + input wire [M_COUNT-1:0] m_axi_arready, + input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid, + input wire [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata, + input wire [M_COUNT*2-1:0] m_axi_rresp, + input wire [M_COUNT-1:0] m_axi_rlast, + input wire [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser, + input wire [M_COUNT-1:0] m_axi_rvalid, + output wire [M_COUNT-1:0] m_axi_rready +); + +axi_crossbar_wr #( + .S_COUNT(S_COUNT), + .M_COUNT(M_COUNT), + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .S_ID_WIDTH(S_ID_WIDTH), + .M_ID_WIDTH(M_ID_WIDTH), + .AWUSER_ENABLE(AWUSER_ENABLE), + .AWUSER_WIDTH(AWUSER_WIDTH), + .WUSER_ENABLE(WUSER_ENABLE), + .WUSER_WIDTH(WUSER_WIDTH), + .BUSER_ENABLE(BUSER_ENABLE), + .BUSER_WIDTH(BUSER_WIDTH), + .S_THREADS(S_THREADS), + .S_ACCEPT(S_ACCEPT), + .M_REGIONS(M_REGIONS), + .M_BASE_ADDR(M_BASE_ADDR), + .M_ADDR_WIDTH(M_ADDR_WIDTH), + .M_CONNECT(M_CONNECT_WRITE), + .M_ISSUE(M_ISSUE), + .M_SECURE(M_SECURE), + .S_AW_REG_TYPE(S_AW_REG_TYPE), + .S_W_REG_TYPE (S_W_REG_TYPE), + .S_B_REG_TYPE (S_B_REG_TYPE) +) +axi_crossbar_wr_inst ( + .clk(clk), + .rst(rst), + + /* + * AXI slave interfaces + */ + .s_axi_awid(s_axi_awid), + .s_axi_awaddr(s_axi_awaddr), + .s_axi_awlen(s_axi_awlen), + .s_axi_awsize(s_axi_awsize), + .s_axi_awburst(s_axi_awburst), + .s_axi_awlock(s_axi_awlock), + .s_axi_awcache(s_axi_awcache), + .s_axi_awprot(s_axi_awprot), + .s_axi_awqos(s_axi_awqos), + .s_axi_awuser(s_axi_awuser), + .s_axi_awvalid(s_axi_awvalid), + .s_axi_awready(s_axi_awready), + .s_axi_wdata(s_axi_wdata), + .s_axi_wstrb(s_axi_wstrb), + .s_axi_wlast(s_axi_wlast), + .s_axi_wuser(s_axi_wuser), + .s_axi_wvalid(s_axi_wvalid), + .s_axi_wready(s_axi_wready), + .s_axi_bid(s_axi_bid), + .s_axi_bresp(s_axi_bresp), + .s_axi_buser(s_axi_buser), + .s_axi_bvalid(s_axi_bvalid), + .s_axi_bready(s_axi_bready), + + /* + * AXI master interfaces + */ + .m_axi_awid(m_axi_awid), + .m_axi_awaddr(m_axi_awaddr), + .m_axi_awlen(m_axi_awlen), + .m_axi_awsize(m_axi_awsize), + .m_axi_awburst(m_axi_awburst), + .m_axi_awlock(m_axi_awlock), + .m_axi_awcache(m_axi_awcache), + .m_axi_awprot(m_axi_awprot), + .m_axi_awqos(m_axi_awqos), + .m_axi_awregion(m_axi_awregion), + .m_axi_awuser(m_axi_awuser), + .m_axi_awvalid(m_axi_awvalid), + .m_axi_awready(m_axi_awready), + .m_axi_wdata(m_axi_wdata), + .m_axi_wstrb(m_axi_wstrb), + .m_axi_wlast(m_axi_wlast), + .m_axi_wuser(m_axi_wuser), + .m_axi_wvalid(m_axi_wvalid), + .m_axi_wready(m_axi_wready), + .m_axi_bid(m_axi_bid), + .m_axi_bresp(m_axi_bresp), + .m_axi_buser(m_axi_buser), + .m_axi_bvalid(m_axi_bvalid), + .m_axi_bready(m_axi_bready) +); + +axi_crossbar_rd #( + .S_COUNT(S_COUNT), + .M_COUNT(M_COUNT), + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .S_ID_WIDTH(S_ID_WIDTH), + .M_ID_WIDTH(M_ID_WIDTH), + .ARUSER_ENABLE(ARUSER_ENABLE), + .ARUSER_WIDTH(ARUSER_WIDTH), + .RUSER_ENABLE(RUSER_ENABLE), + .RUSER_WIDTH(RUSER_WIDTH), + .S_THREADS(S_THREADS), + .S_ACCEPT(S_ACCEPT), + .M_REGIONS(M_REGIONS), + .M_BASE_ADDR(M_BASE_ADDR), + .M_ADDR_WIDTH(M_ADDR_WIDTH), + .M_CONNECT(M_CONNECT_READ), + .M_ISSUE(M_ISSUE), + .M_SECURE(M_SECURE), + .S_AR_REG_TYPE(S_AR_REG_TYPE), + .S_R_REG_TYPE (S_R_REG_TYPE) +) +axi_crossbar_rd_inst ( + .clk(clk), + .rst(rst), + + /* + * AXI slave interfaces + */ + .s_axi_arid(s_axi_arid), + .s_axi_araddr(s_axi_araddr), + .s_axi_arlen(s_axi_arlen), + .s_axi_arsize(s_axi_arsize), + .s_axi_arburst(s_axi_arburst), + .s_axi_arlock(s_axi_arlock), + .s_axi_arcache(s_axi_arcache), + .s_axi_arprot(s_axi_arprot), + .s_axi_arqos(s_axi_arqos), + .s_axi_aruser(s_axi_aruser), + .s_axi_arvalid(s_axi_arvalid), + .s_axi_arready(s_axi_arready), + .s_axi_rid(s_axi_rid), + .s_axi_rdata(s_axi_rdata), + .s_axi_rresp(s_axi_rresp), + .s_axi_rlast(s_axi_rlast), + .s_axi_ruser(s_axi_ruser), + .s_axi_rvalid(s_axi_rvalid), + .s_axi_rready(s_axi_rready), + + /* + * AXI master interfaces + */ + .m_axi_arid(m_axi_arid), + .m_axi_araddr(m_axi_araddr), + .m_axi_arlen(m_axi_arlen), + .m_axi_arsize(m_axi_arsize), + .m_axi_arburst(m_axi_arburst), + .m_axi_arlock(m_axi_arlock), + .m_axi_arcache(m_axi_arcache), + .m_axi_arprot(m_axi_arprot), + .m_axi_arqos(m_axi_arqos), + .m_axi_arregion(m_axi_arregion), + .m_axi_aruser(m_axi_aruser), + .m_axi_arvalid(m_axi_arvalid), + .m_axi_arready(m_axi_arready), + .m_axi_rid(m_axi_rid), + .m_axi_rdata(m_axi_rdata), + .m_axi_rresp(m_axi_rresp), + .m_axi_rlast(m_axi_rlast), + .m_axi_ruser(m_axi_ruser), + .m_axi_rvalid(m_axi_rvalid), + .m_axi_rready(m_axi_rready) +); + +endmodule + +`resetall diff --git a/sim/model/axi_crossbar_addr.v b/sim/model/axi_crossbar_addr.v new file mode 100644 index 0000000..f076458 --- /dev/null +++ b/sim/model/axi_crossbar_addr.v @@ -0,0 +1,413 @@ +/* +Copyright (c) 2018 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 crossbar address decode and admission control + */ +module axi_crossbar_addr # +( + // Slave interface index + parameter S = 0, + // Number of AXI inputs (slave interfaces) + parameter S_COUNT = 4, + // Number of AXI outputs (master interfaces) + parameter M_COUNT = 4, + // Width of address bus in bits + parameter ADDR_WIDTH = 32, + // ID field width + parameter ID_WIDTH = 8, + // Number of concurrent unique IDs + parameter S_THREADS = 32'd2, + // Number of concurrent operations + parameter S_ACCEPT = 32'd16, + // Number of regions per master interface + parameter M_REGIONS = 1, + // Master interface base addresses + // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits + // set to zero for default addressing based on M_ADDR_WIDTH + parameter M_BASE_ADDR = 0, + // Master interface address widths + // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits + parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, + // Connections between interfaces + // M_COUNT concatenated fields of S_COUNT bits + parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}}, + // Secure master (fail operations based on awprot/arprot) + // M_COUNT bits + parameter M_SECURE = {M_COUNT{1'b0}}, + // Enable write command output + parameter WC_OUTPUT = 0 +) +( + input wire clk, + input wire rst, + + /* + * Address input + */ + input wire [ID_WIDTH-1:0] s_axi_aid, + input wire [ADDR_WIDTH-1:0] s_axi_aaddr, + input wire [2:0] s_axi_aprot, + input wire [3:0] s_axi_aqos, + input wire s_axi_avalid, + output wire s_axi_aready, + + /* + * Address output + */ + output wire [3:0] m_axi_aregion, + output wire [$clog2(M_COUNT)-1:0] m_select, + output wire m_axi_avalid, + input wire m_axi_aready, + + /* + * Write command output + */ + output wire [$clog2(M_COUNT)-1:0] m_wc_select, + output wire m_wc_decerr, + output wire m_wc_valid, + input wire m_wc_ready, + + /* + * Reply command output + */ + output wire m_rc_decerr, + output wire m_rc_valid, + input wire m_rc_ready, + + /* + * Completion input + */ + input wire [ID_WIDTH-1:0] s_cpl_id, + input wire s_cpl_valid +); + +parameter CL_S_COUNT = $clog2(S_COUNT); +parameter CL_M_COUNT = $clog2(M_COUNT); + +parameter S_INT_THREADS = S_THREADS > S_ACCEPT ? S_ACCEPT : S_THREADS; +parameter CL_S_INT_THREADS = $clog2(S_INT_THREADS); +parameter CL_S_ACCEPT = $clog2(S_ACCEPT); + +// default address computation +function [M_COUNT*M_REGIONS*ADDR_WIDTH-1:0] calcBaseAddrs(input [31:0] dummy); + integer i; + reg [ADDR_WIDTH-1:0] base; + reg [ADDR_WIDTH-1:0] width; + reg [ADDR_WIDTH-1:0] size; + reg [ADDR_WIDTH-1:0] mask; + begin + calcBaseAddrs = {M_COUNT*M_REGIONS*ADDR_WIDTH{1'b0}}; + base = 0; + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + width = M_ADDR_WIDTH[i*32 +: 32]; + mask = {ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - width); + size = mask + 1; + if (width > 0) begin + if ((base & mask) != 0) begin + base = base + size - (base & mask); // align + end + calcBaseAddrs[i * ADDR_WIDTH +: ADDR_WIDTH] = base; + base = base + size; // increment + end + end + end +endfunction + +parameter M_BASE_ADDR_INT = M_BASE_ADDR ? M_BASE_ADDR : calcBaseAddrs(0); + +integer i, j; + +// check configuration +initial begin + if (S_ACCEPT < 1) begin + $error("Error: need at least 1 accept (instance %m)"); + $finish; + end + + if (S_THREADS < 1) begin + $error("Error: need at least 1 thread (instance %m)"); + $finish; + end + + if (S_THREADS > S_ACCEPT) begin + $warning("Warning: requested thread count larger than accept count; limiting thread count to accept count (instance %m)"); + end + + if (M_REGIONS < 1) begin + $error("Error: need at least 1 region (instance %m)"); + $finish; + end + + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin + $error("Error: address width out of range (instance %m)"); + $finish; + end + end + + $display("Addressing configuration for axi_crossbar_addr instance %m"); + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + if (M_ADDR_WIDTH[i*32 +: 32]) begin + $display("%2d (%2d): %x / %02d -- %x-%x", + i/M_REGIONS, i%M_REGIONS, + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], + M_ADDR_WIDTH[i*32 +: 32], + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])) + ); + end + end + + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + if ((M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & (2**M_ADDR_WIDTH[i*32 +: 32]-1)) != 0) begin + $display("Region not aligned:"); + $display("%2d (%2d): %x / %2d -- %x-%x", + i/M_REGIONS, i%M_REGIONS, + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], + M_ADDR_WIDTH[i*32 +: 32], + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])) + ); + $error("Error: address range not aligned (instance %m)"); + $finish; + end + end + + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + for (j = i+1; j < M_COUNT*M_REGIONS; j = j + 1) begin + if (M_ADDR_WIDTH[i*32 +: 32] && M_ADDR_WIDTH[j*32 +: 32]) begin + if (((M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32])) <= (M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])))) + && ((M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32])) <= (M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32]))))) begin + $display("Overlapping regions:"); + $display("%2d (%2d): %x / %2d -- %x-%x", + i/M_REGIONS, i%M_REGIONS, + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], + M_ADDR_WIDTH[i*32 +: 32], + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), + M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])) + ); + $display("%2d (%2d): %x / %2d -- %x-%x", + j/M_REGIONS, j%M_REGIONS, + M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH], + M_ADDR_WIDTH[j*32 +: 32], + M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32]), + M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])) + ); + $error("Error: address ranges overlap (instance %m)"); + $finish; + end + end + end + end +end + +localparam [2:0] + STATE_IDLE = 3'd0, + STATE_DECODE = 3'd1; + +reg [2:0] state_reg = STATE_IDLE, state_next; + +reg s_axi_aready_reg = 0, s_axi_aready_next; + +reg [3:0] m_axi_aregion_reg = 4'd0, m_axi_aregion_next; +reg [CL_M_COUNT-1:0] m_select_reg = 0, m_select_next; +reg m_axi_avalid_reg = 1'b0, m_axi_avalid_next; +reg m_decerr_reg = 1'b0, m_decerr_next; +reg m_wc_valid_reg = 1'b0, m_wc_valid_next; +reg m_rc_valid_reg = 1'b0, m_rc_valid_next; + +assign s_axi_aready = s_axi_aready_reg; + +assign m_axi_aregion = m_axi_aregion_reg; +assign m_select = m_select_reg; +assign m_axi_avalid = m_axi_avalid_reg; + +assign m_wc_select = m_select_reg; +assign m_wc_decerr = m_decerr_reg; +assign m_wc_valid = m_wc_valid_reg; + +assign m_rc_decerr = m_decerr_reg; +assign m_rc_valid = m_rc_valid_reg; + +reg match; +reg trans_start; +reg trans_complete; + +reg [$clog2(S_ACCEPT+1)-1:0] trans_count_reg = 0; +wire trans_limit = trans_count_reg >= S_ACCEPT && !trans_complete; + +// transfer ID thread tracking +reg [ID_WIDTH-1:0] thread_id_reg[S_INT_THREADS-1:0]; +reg [CL_M_COUNT-1:0] thread_m_reg[S_INT_THREADS-1:0]; +reg [3:0] thread_region_reg[S_INT_THREADS-1:0]; +reg [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0]; + +wire [S_INT_THREADS-1:0] thread_active; +wire [S_INT_THREADS-1:0] thread_match; +wire [S_INT_THREADS-1:0] thread_match_dest; +wire [S_INT_THREADS-1:0] thread_cpl_match; +wire [S_INT_THREADS-1:0] thread_trans_start; +wire [S_INT_THREADS-1:0] thread_trans_complete; + +generate + genvar n; + + for (n = 0; n < S_INT_THREADS; n = n + 1) begin + initial begin + thread_count_reg[n] <= 0; + end + + assign thread_active[n] = thread_count_reg[n] != 0; + assign thread_match[n] = thread_active[n] && thread_id_reg[n] == s_axi_aid; + assign thread_match_dest[n] = thread_match[n] && thread_m_reg[n] == m_select_next && (M_REGIONS < 2 || thread_region_reg[n] == m_axi_aregion_next); + assign thread_cpl_match[n] = thread_active[n] && thread_id_reg[n] == s_cpl_id; + assign thread_trans_start[n] = (thread_match[n] || (!thread_active[n] && !thread_match && !(thread_trans_start & ({S_INT_THREADS{1'b1}} >> (S_INT_THREADS-n))))) && trans_start; + assign thread_trans_complete[n] = thread_cpl_match[n] && trans_complete; + + always @(posedge clk) begin + if (rst) begin + thread_count_reg[n] <= 0; + end else begin + if (thread_trans_start[n] && !thread_trans_complete[n]) begin + thread_count_reg[n] <= thread_count_reg[n] + 1; + end else if (!thread_trans_start[n] && thread_trans_complete[n]) begin + thread_count_reg[n] <= thread_count_reg[n] - 1; + end + end + + if (thread_trans_start[n]) begin + thread_id_reg[n] <= s_axi_aid; + thread_m_reg[n] <= m_select_next; + thread_region_reg[n] <= m_axi_aregion_next; + end + end + end +endgenerate + +always @* begin + state_next = STATE_IDLE; + + match = 1'b0; + trans_start = 1'b0; + trans_complete = 1'b0; + + s_axi_aready_next = 1'b0; + + m_axi_aregion_next = m_axi_aregion_reg; + m_select_next = m_select_reg; + m_axi_avalid_next = m_axi_avalid_reg && !m_axi_aready; + m_decerr_next = m_decerr_reg; + m_wc_valid_next = m_wc_valid_reg && !m_wc_ready; + m_rc_valid_next = m_rc_valid_reg && !m_rc_ready; + + case (state_reg) + STATE_IDLE: begin + // idle state, store values + s_axi_aready_next = 1'b0; + + if (s_axi_avalid && !s_axi_aready) begin + match = 1'b0; + for (i = 0; i < M_COUNT; i = i + 1) begin + for (j = 0; j < M_REGIONS; j = j + 1) begin + if (M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32] && (!M_SECURE[i] || !s_axi_aprot[1]) && (M_CONNECT & (1 << (S+i*S_COUNT))) && (s_axi_aaddr >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32]) == (M_BASE_ADDR_INT[(i*M_REGIONS+j)*ADDR_WIDTH +: ADDR_WIDTH] >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32])) begin + m_select_next = i; + m_axi_aregion_next = j; + match = 1'b1; + end + end + end + + if (match) begin + // address decode successful + if (!trans_limit && (thread_match_dest || (!(&thread_active) && !thread_match))) begin + // transaction limit not reached + m_axi_avalid_next = 1'b1; + m_decerr_next = 1'b0; + m_wc_valid_next = WC_OUTPUT; + m_rc_valid_next = 1'b0; + trans_start = 1'b1; + state_next = STATE_DECODE; + end else begin + // transaction limit reached; block in idle + state_next = STATE_IDLE; + end + end else begin + // decode error + m_axi_avalid_next = 1'b0; + m_decerr_next = 1'b1; + m_wc_valid_next = WC_OUTPUT; + m_rc_valid_next = 1'b1; + state_next = STATE_DECODE; + end + end else begin + state_next = STATE_IDLE; + end + end + STATE_DECODE: begin + if (!m_axi_avalid_next && (!m_wc_valid_next || !WC_OUTPUT) && !m_rc_valid_next) begin + s_axi_aready_next = 1'b1; + state_next = STATE_IDLE; + end else begin + state_next = STATE_DECODE; + end + end + endcase + + // manage completions + trans_complete = s_cpl_valid; +end + +always @(posedge clk) begin + if (rst) begin + state_reg <= STATE_IDLE; + s_axi_aready_reg <= 1'b0; + m_axi_avalid_reg <= 1'b0; + m_wc_valid_reg <= 1'b0; + m_rc_valid_reg <= 1'b0; + + trans_count_reg <= 0; + end else begin + state_reg <= state_next; + s_axi_aready_reg <= s_axi_aready_next; + m_axi_avalid_reg <= m_axi_avalid_next; + m_wc_valid_reg <= m_wc_valid_next; + m_rc_valid_reg <= m_rc_valid_next; + + if (trans_start && !trans_complete) begin + trans_count_reg <= trans_count_reg + 1; + end else if (!trans_start && trans_complete) begin + trans_count_reg <= trans_count_reg - 1; + end + end + + m_axi_aregion_reg <= m_axi_aregion_next; + m_select_reg <= m_select_next; + m_decerr_reg <= m_decerr_next; +end + +endmodule + +`resetall diff --git a/sim/model/axi_crossbar_rd.v b/sim/model/axi_crossbar_rd.v new file mode 100644 index 0000000..ff17e63 --- /dev/null +++ b/sim/model/axi_crossbar_rd.v @@ -0,0 +1,564 @@ +/* +Copyright (c) 2018 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 crossbar (read) + */ +module axi_crossbar_rd # +( + // Number of AXI inputs (slave interfaces) + parameter S_COUNT = 4, + // Number of AXI outputs (master interfaces) + parameter M_COUNT = 4, + // Width of data bus in bits + parameter DATA_WIDTH = 32, + // Width of address bus in bits + parameter ADDR_WIDTH = 32, + // Width of wstrb (width of data bus in words) + parameter STRB_WIDTH = (DATA_WIDTH/8), + // Input ID field width (from AXI masters) + parameter S_ID_WIDTH = 8, + // Output ID field width (towards AXI slaves) + // Additional bits required for response routing + parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), + // Propagate aruser signal + parameter ARUSER_ENABLE = 0, + // Width of aruser signal + parameter ARUSER_WIDTH = 1, + // Propagate ruser signal + parameter RUSER_ENABLE = 0, + // Width of ruser signal + parameter RUSER_WIDTH = 1, + // Number of concurrent unique IDs for each slave interface + // S_COUNT concatenated fields of 32 bits + parameter S_THREADS = {S_COUNT{32'd2}}, + // Number of concurrent operations for each slave interface + // S_COUNT concatenated fields of 32 bits + parameter S_ACCEPT = {S_COUNT{32'd16}}, + // Number of regions per master interface + parameter M_REGIONS = 1, + // Master interface base addresses + // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits + // set to zero for default addressing based on M_ADDR_WIDTH + parameter M_BASE_ADDR = 0, + // Master interface address widths + // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits + parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, + // Read connections between interfaces + // M_COUNT concatenated fields of S_COUNT bits + parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}}, + // Number of concurrent operations for each master interface + // M_COUNT concatenated fields of 32 bits + parameter M_ISSUE = {M_COUNT{32'd4}}, + // Secure master (fail operations based on awprot/arprot) + // M_COUNT bits + parameter M_SECURE = {M_COUNT{1'b0}}, + // Slave interface AR channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_AR_REG_TYPE = {S_COUNT{2'd0}}, + // Slave interface R channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_R_REG_TYPE = {S_COUNT{2'd2}}, + // Master interface AR channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_AR_REG_TYPE = {M_COUNT{2'd1}}, + // Master interface R channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_R_REG_TYPE = {M_COUNT{2'd0}} +) +( + input wire clk, + input wire rst, + + /* + * AXI slave interfaces + */ + input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid, + input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr, + input wire [S_COUNT*8-1:0] s_axi_arlen, + input wire [S_COUNT*3-1:0] s_axi_arsize, + input wire [S_COUNT*2-1:0] s_axi_arburst, + input wire [S_COUNT-1:0] s_axi_arlock, + input wire [S_COUNT*4-1:0] s_axi_arcache, + input wire [S_COUNT*3-1:0] s_axi_arprot, + input wire [S_COUNT*4-1:0] s_axi_arqos, + input wire [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser, + input wire [S_COUNT-1:0] s_axi_arvalid, + output wire [S_COUNT-1:0] s_axi_arready, + output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid, + output wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata, + output wire [S_COUNT*2-1:0] s_axi_rresp, + output wire [S_COUNT-1:0] s_axi_rlast, + output wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser, + output wire [S_COUNT-1:0] s_axi_rvalid, + input wire [S_COUNT-1:0] s_axi_rready, + + /* + * AXI master interfaces + */ + output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid, + output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr, + output wire [M_COUNT*8-1:0] m_axi_arlen, + output wire [M_COUNT*3-1:0] m_axi_arsize, + output wire [M_COUNT*2-1:0] m_axi_arburst, + output wire [M_COUNT-1:0] m_axi_arlock, + output wire [M_COUNT*4-1:0] m_axi_arcache, + output wire [M_COUNT*3-1:0] m_axi_arprot, + output wire [M_COUNT*4-1:0] m_axi_arqos, + output wire [M_COUNT*4-1:0] m_axi_arregion, + output wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser, + output wire [M_COUNT-1:0] m_axi_arvalid, + input wire [M_COUNT-1:0] m_axi_arready, + input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid, + input wire [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata, + input wire [M_COUNT*2-1:0] m_axi_rresp, + input wire [M_COUNT-1:0] m_axi_rlast, + input wire [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser, + input wire [M_COUNT-1:0] m_axi_rvalid, + output wire [M_COUNT-1:0] m_axi_rready +); + +parameter CL_S_COUNT = $clog2(S_COUNT); +parameter CL_M_COUNT = $clog2(M_COUNT); +parameter M_COUNT_P1 = M_COUNT+1; +parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1); + +integer i; + +// check configuration +initial begin + if (M_ID_WIDTH < S_ID_WIDTH+$clog2(S_COUNT)) begin + $error("Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH (instance %m)"); + $finish; + end + + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin + $error("Error: value out of range (instance %m)"); + $finish; + end + end +end + +wire [S_COUNT*S_ID_WIDTH-1:0] int_s_axi_arid; +wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axi_araddr; +wire [S_COUNT*8-1:0] int_s_axi_arlen; +wire [S_COUNT*3-1:0] int_s_axi_arsize; +wire [S_COUNT*2-1:0] int_s_axi_arburst; +wire [S_COUNT-1:0] int_s_axi_arlock; +wire [S_COUNT*4-1:0] int_s_axi_arcache; +wire [S_COUNT*3-1:0] int_s_axi_arprot; +wire [S_COUNT*4-1:0] int_s_axi_arqos; +wire [S_COUNT*4-1:0] int_s_axi_arregion; +wire [S_COUNT*ARUSER_WIDTH-1:0] int_s_axi_aruser; +wire [S_COUNT-1:0] int_s_axi_arvalid; +wire [S_COUNT-1:0] int_s_axi_arready; + +wire [S_COUNT*M_COUNT-1:0] int_axi_arvalid; +wire [M_COUNT*S_COUNT-1:0] int_axi_arready; + +wire [M_COUNT*M_ID_WIDTH-1:0] int_m_axi_rid; +wire [M_COUNT*DATA_WIDTH-1:0] int_m_axi_rdata; +wire [M_COUNT*2-1:0] int_m_axi_rresp; +wire [M_COUNT-1:0] int_m_axi_rlast; +wire [M_COUNT*RUSER_WIDTH-1:0] int_m_axi_ruser; +wire [M_COUNT-1:0] int_m_axi_rvalid; +wire [M_COUNT-1:0] int_m_axi_rready; + +wire [M_COUNT*S_COUNT-1:0] int_axi_rvalid; +wire [S_COUNT*M_COUNT-1:0] int_axi_rready; + +generate + + genvar m, n; + + for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces + // address decode and admission control + wire [CL_M_COUNT-1:0] a_select; + + wire m_axi_avalid; + wire m_axi_aready; + + wire m_rc_decerr; + wire m_rc_valid; + wire m_rc_ready; + + wire [S_ID_WIDTH-1:0] s_cpl_id; + wire s_cpl_valid; + + axi_crossbar_addr #( + .S(m), + .S_COUNT(S_COUNT), + .M_COUNT(M_COUNT), + .ADDR_WIDTH(ADDR_WIDTH), + .ID_WIDTH(S_ID_WIDTH), + .S_THREADS(S_THREADS[m*32 +: 32]), + .S_ACCEPT(S_ACCEPT[m*32 +: 32]), + .M_REGIONS(M_REGIONS), + .M_BASE_ADDR(M_BASE_ADDR), + .M_ADDR_WIDTH(M_ADDR_WIDTH), + .M_CONNECT(M_CONNECT), + .M_SECURE(M_SECURE), + .WC_OUTPUT(0) + ) + addr_inst ( + .clk(clk), + .rst(rst), + + /* + * Address input + */ + .s_axi_aid(int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .s_axi_aaddr(int_s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]), + .s_axi_aprot(int_s_axi_arprot[m*3 +: 3]), + .s_axi_aqos(int_s_axi_arqos[m*4 +: 4]), + .s_axi_avalid(int_s_axi_arvalid[m]), + .s_axi_aready(int_s_axi_arready[m]), + + /* + * Address output + */ + .m_axi_aregion(int_s_axi_arregion[m*4 +: 4]), + .m_select(a_select), + .m_axi_avalid(m_axi_avalid), + .m_axi_aready(m_axi_aready), + + /* + * Write command output + */ + .m_wc_select(), + .m_wc_decerr(), + .m_wc_valid(), + .m_wc_ready(1'b1), + + /* + * Response command output + */ + .m_rc_decerr(m_rc_decerr), + .m_rc_valid(m_rc_valid), + .m_rc_ready(m_rc_ready), + + /* + * Completion input + */ + .s_cpl_id(s_cpl_id), + .s_cpl_valid(s_cpl_valid) + ); + + assign int_axi_arvalid[m*M_COUNT +: M_COUNT] = m_axi_avalid << a_select; + assign m_axi_aready = int_axi_arready[a_select*S_COUNT+m]; + + // decode error handling + reg [S_ID_WIDTH-1:0] decerr_m_axi_rid_reg = {S_ID_WIDTH{1'b0}}, decerr_m_axi_rid_next; + reg decerr_m_axi_rlast_reg = 1'b0, decerr_m_axi_rlast_next; + reg decerr_m_axi_rvalid_reg = 1'b0, decerr_m_axi_rvalid_next; + wire decerr_m_axi_rready; + + reg [7:0] decerr_len_reg = 8'd0, decerr_len_next; + + assign m_rc_ready = !decerr_m_axi_rvalid_reg; + + always @* begin + decerr_len_next = decerr_len_reg; + decerr_m_axi_rid_next = decerr_m_axi_rid_reg; + decerr_m_axi_rlast_next = decerr_m_axi_rlast_reg; + decerr_m_axi_rvalid_next = decerr_m_axi_rvalid_reg; + + if (decerr_m_axi_rvalid_reg) begin + if (decerr_m_axi_rready) begin + if (decerr_len_reg > 0) begin + decerr_len_next = decerr_len_reg-1; + decerr_m_axi_rlast_next = (decerr_len_next == 0); + decerr_m_axi_rvalid_next = 1'b1; + end else begin + decerr_m_axi_rvalid_next = 1'b0; + end + end + end else if (m_rc_valid && m_rc_ready) begin + decerr_len_next = int_s_axi_arlen[m*8 +: 8]; + decerr_m_axi_rid_next = int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]; + decerr_m_axi_rlast_next = (decerr_len_next == 0); + decerr_m_axi_rvalid_next = 1'b1; + end + end + + always @(posedge clk) begin + if (rst) begin + decerr_m_axi_rvalid_reg <= 1'b0; + end else begin + decerr_m_axi_rvalid_reg <= decerr_m_axi_rvalid_next; + end + + decerr_m_axi_rid_reg <= decerr_m_axi_rid_next; + decerr_m_axi_rlast_reg <= decerr_m_axi_rlast_next; + decerr_len_reg <= decerr_len_next; + end + + // read response arbitration + wire [M_COUNT_P1-1:0] r_request; + wire [M_COUNT_P1-1:0] r_acknowledge; + wire [M_COUNT_P1-1:0] r_grant; + wire r_grant_valid; + wire [CL_M_COUNT_P1-1:0] r_grant_encoded; + + arbiter #( + .PORTS(M_COUNT_P1), + .ARB_TYPE_ROUND_ROBIN(1), + .ARB_BLOCK(1), + .ARB_BLOCK_ACK(1), + .ARB_LSB_HIGH_PRIORITY(1) + ) + r_arb_inst ( + .clk(clk), + .rst(rst), + .request(r_request), + .acknowledge(r_acknowledge), + .grant(r_grant), + .grant_valid(r_grant_valid), + .grant_encoded(r_grant_encoded) + ); + + // read response mux + wire [S_ID_WIDTH-1:0] m_axi_rid_mux = {decerr_m_axi_rid_reg, int_m_axi_rid} >> r_grant_encoded*M_ID_WIDTH; + wire [DATA_WIDTH-1:0] m_axi_rdata_mux = {{DATA_WIDTH{1'b0}}, int_m_axi_rdata} >> r_grant_encoded*DATA_WIDTH; + wire [1:0] m_axi_rresp_mux = {2'b11, int_m_axi_rresp} >> r_grant_encoded*2; + wire m_axi_rlast_mux = {decerr_m_axi_rlast_reg, int_m_axi_rlast} >> r_grant_encoded; + wire [RUSER_WIDTH-1:0] m_axi_ruser_mux = {{RUSER_WIDTH{1'b0}}, int_m_axi_ruser} >> r_grant_encoded*RUSER_WIDTH; + wire m_axi_rvalid_mux = ({decerr_m_axi_rvalid_reg, int_m_axi_rvalid} >> r_grant_encoded) & r_grant_valid; + wire m_axi_rready_mux; + + assign int_axi_rready[m*M_COUNT +: M_COUNT] = (r_grant_valid && m_axi_rready_mux) << r_grant_encoded; + assign decerr_m_axi_rready = (r_grant_valid && m_axi_rready_mux) && (r_grant_encoded == M_COUNT_P1-1); + + for (n = 0; n < M_COUNT; n = n + 1) begin + assign r_request[n] = int_axi_rvalid[n*S_COUNT+m] && !r_grant[n]; + assign r_acknowledge[n] = r_grant[n] && int_axi_rvalid[n*S_COUNT+m] && m_axi_rlast_mux && m_axi_rready_mux; + end + + assign r_request[M_COUNT_P1-1] = decerr_m_axi_rvalid_reg && !r_grant[M_COUNT_P1-1]; + assign r_acknowledge[M_COUNT_P1-1] = r_grant[M_COUNT_P1-1] && decerr_m_axi_rvalid_reg && decerr_m_axi_rlast_reg && m_axi_rready_mux; + + assign s_cpl_id = m_axi_rid_mux; + assign s_cpl_valid = m_axi_rvalid_mux && m_axi_rready_mux && m_axi_rlast_mux; + + // S side register + axi_register_rd #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .ID_WIDTH(S_ID_WIDTH), + .ARUSER_ENABLE(ARUSER_ENABLE), + .ARUSER_WIDTH(ARUSER_WIDTH), + .RUSER_ENABLE(RUSER_ENABLE), + .RUSER_WIDTH(RUSER_WIDTH), + .AR_REG_TYPE(S_AR_REG_TYPE[m*2 +: 2]), + .R_REG_TYPE(S_R_REG_TYPE[m*2 +: 2]) + ) + reg_inst ( + .clk(clk), + .rst(rst), + .s_axi_arid(s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .s_axi_araddr(s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]), + .s_axi_arlen(s_axi_arlen[m*8 +: 8]), + .s_axi_arsize(s_axi_arsize[m*3 +: 3]), + .s_axi_arburst(s_axi_arburst[m*2 +: 2]), + .s_axi_arlock(s_axi_arlock[m]), + .s_axi_arcache(s_axi_arcache[m*4 +: 4]), + .s_axi_arprot(s_axi_arprot[m*3 +: 3]), + .s_axi_arqos(s_axi_arqos[m*4 +: 4]), + .s_axi_arregion(4'd0), + .s_axi_aruser(s_axi_aruser[m*ARUSER_WIDTH +: ARUSER_WIDTH]), + .s_axi_arvalid(s_axi_arvalid[m]), + .s_axi_arready(s_axi_arready[m]), + .s_axi_rid(s_axi_rid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .s_axi_rdata(s_axi_rdata[m*DATA_WIDTH +: DATA_WIDTH]), + .s_axi_rresp(s_axi_rresp[m*2 +: 2]), + .s_axi_rlast(s_axi_rlast[m]), + .s_axi_ruser(s_axi_ruser[m*RUSER_WIDTH +: RUSER_WIDTH]), + .s_axi_rvalid(s_axi_rvalid[m]), + .s_axi_rready(s_axi_rready[m]), + .m_axi_arid(int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .m_axi_araddr(int_s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]), + .m_axi_arlen(int_s_axi_arlen[m*8 +: 8]), + .m_axi_arsize(int_s_axi_arsize[m*3 +: 3]), + .m_axi_arburst(int_s_axi_arburst[m*2 +: 2]), + .m_axi_arlock(int_s_axi_arlock[m]), + .m_axi_arcache(int_s_axi_arcache[m*4 +: 4]), + .m_axi_arprot(int_s_axi_arprot[m*3 +: 3]), + .m_axi_arqos(int_s_axi_arqos[m*4 +: 4]), + .m_axi_arregion(), + .m_axi_aruser(int_s_axi_aruser[m*ARUSER_WIDTH +: ARUSER_WIDTH]), + .m_axi_arvalid(int_s_axi_arvalid[m]), + .m_axi_arready(int_s_axi_arready[m]), + .m_axi_rid(m_axi_rid_mux), + .m_axi_rdata(m_axi_rdata_mux), + .m_axi_rresp(m_axi_rresp_mux), + .m_axi_rlast(m_axi_rlast_mux), + .m_axi_ruser(m_axi_ruser_mux), + .m_axi_rvalid(m_axi_rvalid_mux), + .m_axi_rready(m_axi_rready_mux) + ); + end // s_ifaces + + for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces + // in-flight transaction count + wire trans_start; + wire trans_complete; + reg [$clog2(M_ISSUE[n*32 +: 32]+1)-1:0] trans_count_reg = 0; + + wire trans_limit = trans_count_reg >= M_ISSUE[n*32 +: 32] && !trans_complete; + + always @(posedge clk) begin + if (rst) begin + trans_count_reg <= 0; + end else begin + if (trans_start && !trans_complete) begin + trans_count_reg <= trans_count_reg + 1; + end else if (!trans_start && trans_complete) begin + trans_count_reg <= trans_count_reg - 1; + end + end + end + + // address arbitration + wire [S_COUNT-1:0] a_request; + wire [S_COUNT-1:0] a_acknowledge; + wire [S_COUNT-1:0] a_grant; + wire a_grant_valid; + wire [CL_S_COUNT-1:0] a_grant_encoded; + + arbiter #( + .PORTS(S_COUNT), + .ARB_TYPE_ROUND_ROBIN(1), + .ARB_BLOCK(1), + .ARB_BLOCK_ACK(1), + .ARB_LSB_HIGH_PRIORITY(1) + ) + a_arb_inst ( + .clk(clk), + .rst(rst), + .request(a_request), + .acknowledge(a_acknowledge), + .grant(a_grant), + .grant_valid(a_grant_valid), + .grant_encoded(a_grant_encoded) + ); + + // address mux + wire [M_ID_WIDTH-1:0] s_axi_arid_mux = int_s_axi_arid[a_grant_encoded*S_ID_WIDTH +: S_ID_WIDTH] | (a_grant_encoded << S_ID_WIDTH); + wire [ADDR_WIDTH-1:0] s_axi_araddr_mux = int_s_axi_araddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH]; + wire [7:0] s_axi_arlen_mux = int_s_axi_arlen[a_grant_encoded*8 +: 8]; + wire [2:0] s_axi_arsize_mux = int_s_axi_arsize[a_grant_encoded*3 +: 3]; + wire [1:0] s_axi_arburst_mux = int_s_axi_arburst[a_grant_encoded*2 +: 2]; + wire s_axi_arlock_mux = int_s_axi_arlock[a_grant_encoded]; + wire [3:0] s_axi_arcache_mux = int_s_axi_arcache[a_grant_encoded*4 +: 4]; + wire [2:0] s_axi_arprot_mux = int_s_axi_arprot[a_grant_encoded*3 +: 3]; + wire [3:0] s_axi_arqos_mux = int_s_axi_arqos[a_grant_encoded*4 +: 4]; + wire [3:0] s_axi_arregion_mux = int_s_axi_arregion[a_grant_encoded*4 +: 4]; + wire [ARUSER_WIDTH-1:0] s_axi_aruser_mux = int_s_axi_aruser[a_grant_encoded*ARUSER_WIDTH +: ARUSER_WIDTH]; + wire s_axi_arvalid_mux = int_axi_arvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid; + wire s_axi_arready_mux; + + assign int_axi_arready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axi_arready_mux) << a_grant_encoded; + + for (m = 0; m < S_COUNT; m = m + 1) begin + assign a_request[m] = int_axi_arvalid[m*M_COUNT+n] && !a_grant[m] && !trans_limit; + assign a_acknowledge[m] = a_grant[m] && int_axi_arvalid[m*M_COUNT+n] && s_axi_arready_mux; + end + + assign trans_start = s_axi_arvalid_mux && s_axi_arready_mux && a_grant_valid; + + // read response forwarding + wire [CL_S_COUNT-1:0] r_select = m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH] >> S_ID_WIDTH; + + assign int_axi_rvalid[n*S_COUNT +: S_COUNT] = int_m_axi_rvalid[n] << r_select; + assign int_m_axi_rready[n] = int_axi_rready[r_select*M_COUNT+n]; + + assign trans_complete = int_m_axi_rvalid[n] && int_m_axi_rready[n] && int_m_axi_rlast[n]; + + // M side register + axi_register_rd #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .ID_WIDTH(M_ID_WIDTH), + .ARUSER_ENABLE(ARUSER_ENABLE), + .ARUSER_WIDTH(ARUSER_WIDTH), + .RUSER_ENABLE(RUSER_ENABLE), + .RUSER_WIDTH(RUSER_WIDTH), + .AR_REG_TYPE(M_AR_REG_TYPE[n*2 +: 2]), + .R_REG_TYPE(M_R_REG_TYPE[n*2 +: 2]) + ) + reg_inst ( + .clk(clk), + .rst(rst), + .s_axi_arid(s_axi_arid_mux), + .s_axi_araddr(s_axi_araddr_mux), + .s_axi_arlen(s_axi_arlen_mux), + .s_axi_arsize(s_axi_arsize_mux), + .s_axi_arburst(s_axi_arburst_mux), + .s_axi_arlock(s_axi_arlock_mux), + .s_axi_arcache(s_axi_arcache_mux), + .s_axi_arprot(s_axi_arprot_mux), + .s_axi_arqos(s_axi_arqos_mux), + .s_axi_arregion(s_axi_arregion_mux), + .s_axi_aruser(s_axi_aruser_mux), + .s_axi_arvalid(s_axi_arvalid_mux), + .s_axi_arready(s_axi_arready_mux), + .s_axi_rid(int_m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH]), + .s_axi_rdata(int_m_axi_rdata[n*DATA_WIDTH +: DATA_WIDTH]), + .s_axi_rresp(int_m_axi_rresp[n*2 +: 2]), + .s_axi_rlast(int_m_axi_rlast[n]), + .s_axi_ruser(int_m_axi_ruser[n*RUSER_WIDTH +: RUSER_WIDTH]), + .s_axi_rvalid(int_m_axi_rvalid[n]), + .s_axi_rready(int_m_axi_rready[n]), + .m_axi_arid(m_axi_arid[n*M_ID_WIDTH +: M_ID_WIDTH]), + .m_axi_araddr(m_axi_araddr[n*ADDR_WIDTH +: ADDR_WIDTH]), + .m_axi_arlen(m_axi_arlen[n*8 +: 8]), + .m_axi_arsize(m_axi_arsize[n*3 +: 3]), + .m_axi_arburst(m_axi_arburst[n*2 +: 2]), + .m_axi_arlock(m_axi_arlock[n]), + .m_axi_arcache(m_axi_arcache[n*4 +: 4]), + .m_axi_arprot(m_axi_arprot[n*3 +: 3]), + .m_axi_arqos(m_axi_arqos[n*4 +: 4]), + .m_axi_arregion(m_axi_arregion[n*4 +: 4]), + .m_axi_aruser(m_axi_aruser[n*ARUSER_WIDTH +: ARUSER_WIDTH]), + .m_axi_arvalid(m_axi_arvalid[n]), + .m_axi_arready(m_axi_arready[n]), + .m_axi_rid(m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH]), + .m_axi_rdata(m_axi_rdata[n*DATA_WIDTH +: DATA_WIDTH]), + .m_axi_rresp(m_axi_rresp[n*2 +: 2]), + .m_axi_rlast(m_axi_rlast[n]), + .m_axi_ruser(m_axi_ruser[n*RUSER_WIDTH +: RUSER_WIDTH]), + .m_axi_rvalid(m_axi_rvalid[n]), + .m_axi_rready(m_axi_rready[n]) + ); + end // m_ifaces + +endgenerate + +endmodule + +`resetall diff --git a/sim/model/axi_crossbar_wr.v b/sim/model/axi_crossbar_wr.v new file mode 100644 index 0000000..0d018f2 --- /dev/null +++ b/sim/model/axi_crossbar_wr.v @@ -0,0 +1,673 @@ +/* +Copyright (c) 2018 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 crossbar (write) + */ +module axi_crossbar_wr # +( + // Number of AXI inputs (slave interfaces) + parameter S_COUNT = 4, + // Number of AXI outputs (master interfaces) + parameter M_COUNT = 4, + // Width of data bus in bits + parameter DATA_WIDTH = 32, + // Width of address bus in bits + parameter ADDR_WIDTH = 32, + // Width of wstrb (width of data bus in words) + parameter STRB_WIDTH = (DATA_WIDTH/8), + // Input ID field width (from AXI masters) + parameter S_ID_WIDTH = 8, + // Output ID field width (towards AXI slaves) + // Additional bits required for response routing + parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), + // Propagate awuser signal + parameter AWUSER_ENABLE = 0, + // Width of awuser signal + parameter AWUSER_WIDTH = 1, + // Propagate wuser signal + parameter WUSER_ENABLE = 0, + // Width of wuser signal + parameter WUSER_WIDTH = 1, + // Propagate buser signal + parameter BUSER_ENABLE = 0, + // Width of buser signal + parameter BUSER_WIDTH = 1, + // Number of concurrent unique IDs for each slave interface + // S_COUNT concatenated fields of 32 bits + parameter S_THREADS = {S_COUNT{32'd2}}, + // Number of concurrent operations for each slave interface + // S_COUNT concatenated fields of 32 bits + parameter S_ACCEPT = {S_COUNT{32'd16}}, + // Number of regions per master interface + parameter M_REGIONS = 1, + // Master interface base addresses + // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits + // set to zero for default addressing based on M_ADDR_WIDTH + parameter M_BASE_ADDR = 0, + // Master interface address widths + // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits + parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, + // Write connections between interfaces + // M_COUNT concatenated fields of S_COUNT bits + parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}}, + // Number of concurrent operations for each master interface + // M_COUNT concatenated fields of 32 bits + parameter M_ISSUE = {M_COUNT{32'd4}}, + // Secure master (fail operations based on awprot/arprot) + // M_COUNT bits + parameter M_SECURE = {M_COUNT{1'b0}}, + // Slave interface AW channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_AW_REG_TYPE = {S_COUNT{2'd0}}, + // Slave interface W channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_W_REG_TYPE = {S_COUNT{2'd0}}, + // Slave interface B channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter S_B_REG_TYPE = {S_COUNT{2'd1}}, + // Master interface AW channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_AW_REG_TYPE = {M_COUNT{2'd1}}, + // Master interface W channel register type (output) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_W_REG_TYPE = {M_COUNT{2'd2}}, + // Master interface B channel register type (input) + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter M_B_REG_TYPE = {M_COUNT{2'd0}} +) +( + input wire clk, + input wire rst, + + /* + * AXI slave interfaces + */ + input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid, + input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [S_COUNT*8-1:0] s_axi_awlen, + input wire [S_COUNT*3-1:0] s_axi_awsize, + input wire [S_COUNT*2-1:0] s_axi_awburst, + input wire [S_COUNT-1:0] s_axi_awlock, + input wire [S_COUNT*4-1:0] s_axi_awcache, + input wire [S_COUNT*3-1:0] s_axi_awprot, + input wire [S_COUNT*4-1:0] s_axi_awqos, + input wire [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser, + input wire [S_COUNT-1:0] s_axi_awvalid, + output wire [S_COUNT-1:0] s_axi_awready, + input wire [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata, + input wire [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb, + input wire [S_COUNT-1:0] s_axi_wlast, + input wire [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser, + input wire [S_COUNT-1:0] s_axi_wvalid, + output wire [S_COUNT-1:0] s_axi_wready, + output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid, + output wire [S_COUNT*2-1:0] s_axi_bresp, + output wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser, + output wire [S_COUNT-1:0] s_axi_bvalid, + input wire [S_COUNT-1:0] s_axi_bready, + + /* + * AXI master interfaces + */ + output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid, + output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [M_COUNT*8-1:0] m_axi_awlen, + output wire [M_COUNT*3-1:0] m_axi_awsize, + output wire [M_COUNT*2-1:0] m_axi_awburst, + output wire [M_COUNT-1:0] m_axi_awlock, + output wire [M_COUNT*4-1:0] m_axi_awcache, + output wire [M_COUNT*3-1:0] m_axi_awprot, + output wire [M_COUNT*4-1:0] m_axi_awqos, + output wire [M_COUNT*4-1:0] m_axi_awregion, + output wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser, + output wire [M_COUNT-1:0] m_axi_awvalid, + input wire [M_COUNT-1:0] m_axi_awready, + output wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata, + output wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb, + output wire [M_COUNT-1:0] m_axi_wlast, + output wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser, + output wire [M_COUNT-1:0] m_axi_wvalid, + input wire [M_COUNT-1:0] m_axi_wready, + input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid, + input wire [M_COUNT*2-1:0] m_axi_bresp, + input wire [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser, + input wire [M_COUNT-1:0] m_axi_bvalid, + output wire [M_COUNT-1:0] m_axi_bready +); + +parameter CL_S_COUNT = $clog2(S_COUNT); +parameter CL_M_COUNT = $clog2(M_COUNT); +parameter M_COUNT_P1 = M_COUNT+1; +parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1); + +integer i; + +// check configuration +initial begin + if (M_ID_WIDTH < S_ID_WIDTH+$clog2(S_COUNT)) begin + $error("Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH (instance %m)"); + $finish; + end + + for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin + if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin + $error("Error: value out of range (instance %m)"); + $finish; + end + end +end + +wire [S_COUNT*S_ID_WIDTH-1:0] int_s_axi_awid; +wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axi_awaddr; +wire [S_COUNT*8-1:0] int_s_axi_awlen; +wire [S_COUNT*3-1:0] int_s_axi_awsize; +wire [S_COUNT*2-1:0] int_s_axi_awburst; +wire [S_COUNT-1:0] int_s_axi_awlock; +wire [S_COUNT*4-1:0] int_s_axi_awcache; +wire [S_COUNT*3-1:0] int_s_axi_awprot; +wire [S_COUNT*4-1:0] int_s_axi_awqos; +wire [S_COUNT*4-1:0] int_s_axi_awregion; +wire [S_COUNT*AWUSER_WIDTH-1:0] int_s_axi_awuser; +wire [S_COUNT-1:0] int_s_axi_awvalid; +wire [S_COUNT-1:0] int_s_axi_awready; + +wire [S_COUNT*M_COUNT-1:0] int_axi_awvalid; +wire [M_COUNT*S_COUNT-1:0] int_axi_awready; + +wire [S_COUNT*DATA_WIDTH-1:0] int_s_axi_wdata; +wire [S_COUNT*STRB_WIDTH-1:0] int_s_axi_wstrb; +wire [S_COUNT-1:0] int_s_axi_wlast; +wire [S_COUNT*WUSER_WIDTH-1:0] int_s_axi_wuser; +wire [S_COUNT-1:0] int_s_axi_wvalid; +wire [S_COUNT-1:0] int_s_axi_wready; + +wire [S_COUNT*M_COUNT-1:0] int_axi_wvalid; +wire [M_COUNT*S_COUNT-1:0] int_axi_wready; + +wire [M_COUNT*M_ID_WIDTH-1:0] int_m_axi_bid; +wire [M_COUNT*2-1:0] int_m_axi_bresp; +wire [M_COUNT*BUSER_WIDTH-1:0] int_m_axi_buser; +wire [M_COUNT-1:0] int_m_axi_bvalid; +wire [M_COUNT-1:0] int_m_axi_bready; + +wire [M_COUNT*S_COUNT-1:0] int_axi_bvalid; +wire [S_COUNT*M_COUNT-1:0] int_axi_bready; + +generate + + genvar m, n; + + for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces + // address decode and admission control + wire [CL_M_COUNT-1:0] a_select; + + wire m_axi_avalid; + wire m_axi_aready; + + wire [CL_M_COUNT-1:0] m_wc_select; + wire m_wc_decerr; + wire m_wc_valid; + wire m_wc_ready; + + wire m_rc_decerr; + wire m_rc_valid; + wire m_rc_ready; + + wire [S_ID_WIDTH-1:0] s_cpl_id; + wire s_cpl_valid; + + axi_crossbar_addr #( + .S(m), + .S_COUNT(S_COUNT), + .M_COUNT(M_COUNT), + .ADDR_WIDTH(ADDR_WIDTH), + .ID_WIDTH(S_ID_WIDTH), + .S_THREADS(S_THREADS[m*32 +: 32]), + .S_ACCEPT(S_ACCEPT[m*32 +: 32]), + .M_REGIONS(M_REGIONS), + .M_BASE_ADDR(M_BASE_ADDR), + .M_ADDR_WIDTH(M_ADDR_WIDTH), + .M_CONNECT(M_CONNECT), + .M_SECURE(M_SECURE), + .WC_OUTPUT(1) + ) + addr_inst ( + .clk(clk), + .rst(rst), + + /* + * Address input + */ + .s_axi_aid(int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .s_axi_aaddr(int_s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]), + .s_axi_aprot(int_s_axi_awprot[m*3 +: 3]), + .s_axi_aqos(int_s_axi_awqos[m*4 +: 4]), + .s_axi_avalid(int_s_axi_awvalid[m]), + .s_axi_aready(int_s_axi_awready[m]), + + /* + * Address output + */ + .m_axi_aregion(int_s_axi_awregion[m*4 +: 4]), + .m_select(a_select), + .m_axi_avalid(m_axi_avalid), + .m_axi_aready(m_axi_aready), + + /* + * Write command output + */ + .m_wc_select(m_wc_select), + .m_wc_decerr(m_wc_decerr), + .m_wc_valid(m_wc_valid), + .m_wc_ready(m_wc_ready), + + /* + * Response command output + */ + .m_rc_decerr(m_rc_decerr), + .m_rc_valid(m_rc_valid), + .m_rc_ready(m_rc_ready), + + /* + * Completion input + */ + .s_cpl_id(s_cpl_id), + .s_cpl_valid(s_cpl_valid) + ); + + assign int_axi_awvalid[m*M_COUNT +: M_COUNT] = m_axi_avalid << a_select; + assign m_axi_aready = int_axi_awready[a_select*S_COUNT+m]; + + // write command handling + reg [CL_M_COUNT-1:0] w_select_reg = 0, w_select_next; + reg w_drop_reg = 1'b0, w_drop_next; + reg w_select_valid_reg = 1'b0, w_select_valid_next; + + assign m_wc_ready = !w_select_valid_reg; + + always @* begin + w_select_next = w_select_reg; + w_drop_next = w_drop_reg && !(int_s_axi_wvalid[m] && int_s_axi_wready[m] && int_s_axi_wlast[m]); + w_select_valid_next = w_select_valid_reg && !(int_s_axi_wvalid[m] && int_s_axi_wready[m] && int_s_axi_wlast[m]); + + if (m_wc_valid && !w_select_valid_reg) begin + w_select_next = m_wc_select; + w_drop_next = m_wc_decerr; + w_select_valid_next = m_wc_valid; + end + end + + always @(posedge clk) begin + if (rst) begin + w_select_valid_reg <= 1'b0; + end else begin + w_select_valid_reg <= w_select_valid_next; + end + + w_select_reg <= w_select_next; + w_drop_reg <= w_drop_next; + end + + // write data forwarding + assign int_axi_wvalid[m*M_COUNT +: M_COUNT] = (int_s_axi_wvalid[m] && w_select_valid_reg && !w_drop_reg) << w_select_reg; + assign int_s_axi_wready[m] = int_axi_wready[w_select_reg*S_COUNT+m] || w_drop_reg; + + // decode error handling + reg [S_ID_WIDTH-1:0] decerr_m_axi_bid_reg = {S_ID_WIDTH{1'b0}}, decerr_m_axi_bid_next; + reg decerr_m_axi_bvalid_reg = 1'b0, decerr_m_axi_bvalid_next; + wire decerr_m_axi_bready; + + assign m_rc_ready = !decerr_m_axi_bvalid_reg; + + always @* begin + decerr_m_axi_bid_next = decerr_m_axi_bid_reg; + decerr_m_axi_bvalid_next = decerr_m_axi_bvalid_reg; + + if (decerr_m_axi_bvalid_reg) begin + if (decerr_m_axi_bready) begin + decerr_m_axi_bvalid_next = 1'b0; + end + end else if (m_rc_valid && m_rc_ready) begin + decerr_m_axi_bid_next = int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]; + decerr_m_axi_bvalid_next = 1'b1; + end + end + + always @(posedge clk) begin + if (rst) begin + decerr_m_axi_bvalid_reg <= 1'b0; + end else begin + decerr_m_axi_bvalid_reg <= decerr_m_axi_bvalid_next; + end + + decerr_m_axi_bid_reg <= decerr_m_axi_bid_next; + end + + // write response arbitration + wire [M_COUNT_P1-1:0] b_request; + wire [M_COUNT_P1-1:0] b_acknowledge; + wire [M_COUNT_P1-1:0] b_grant; + wire b_grant_valid; + wire [CL_M_COUNT_P1-1:0] b_grant_encoded; + + arbiter #( + .PORTS(M_COUNT_P1), + .ARB_TYPE_ROUND_ROBIN(1), + .ARB_BLOCK(1), + .ARB_BLOCK_ACK(1), + .ARB_LSB_HIGH_PRIORITY(1) + ) + b_arb_inst ( + .clk(clk), + .rst(rst), + .request(b_request), + .acknowledge(b_acknowledge), + .grant(b_grant), + .grant_valid(b_grant_valid), + .grant_encoded(b_grant_encoded) + ); + + // write response mux + wire [S_ID_WIDTH-1:0] m_axi_bid_mux = {decerr_m_axi_bid_reg, int_m_axi_bid} >> b_grant_encoded*M_ID_WIDTH; + wire [1:0] m_axi_bresp_mux = {2'b11, int_m_axi_bresp} >> b_grant_encoded*2; + wire [BUSER_WIDTH-1:0] m_axi_buser_mux = {{BUSER_WIDTH{1'b0}}, int_m_axi_buser} >> b_grant_encoded*BUSER_WIDTH; + wire m_axi_bvalid_mux = ({decerr_m_axi_bvalid_reg, int_m_axi_bvalid} >> b_grant_encoded) & b_grant_valid; + wire m_axi_bready_mux; + + assign int_axi_bready[m*M_COUNT +: M_COUNT] = (b_grant_valid && m_axi_bready_mux) << b_grant_encoded; + assign decerr_m_axi_bready = (b_grant_valid && m_axi_bready_mux) && (b_grant_encoded == M_COUNT_P1-1); + + for (n = 0; n < M_COUNT; n = n + 1) begin + assign b_request[n] = int_axi_bvalid[n*S_COUNT+m] && !b_grant[n]; + assign b_acknowledge[n] = b_grant[n] && int_axi_bvalid[n*S_COUNT+m] && m_axi_bready_mux; + end + + assign b_request[M_COUNT_P1-1] = decerr_m_axi_bvalid_reg && !b_grant[M_COUNT_P1-1]; + assign b_acknowledge[M_COUNT_P1-1] = b_grant[M_COUNT_P1-1] && decerr_m_axi_bvalid_reg && m_axi_bready_mux; + + assign s_cpl_id = m_axi_bid_mux; + assign s_cpl_valid = m_axi_bvalid_mux && m_axi_bready_mux; + + // S side register + axi_register_wr #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .ID_WIDTH(S_ID_WIDTH), + .AWUSER_ENABLE(AWUSER_ENABLE), + .AWUSER_WIDTH(AWUSER_WIDTH), + .WUSER_ENABLE(WUSER_ENABLE), + .WUSER_WIDTH(WUSER_WIDTH), + .BUSER_ENABLE(BUSER_ENABLE), + .BUSER_WIDTH(BUSER_WIDTH), + .AW_REG_TYPE(S_AW_REG_TYPE[m*2 +: 2]), + .W_REG_TYPE(S_W_REG_TYPE[m*2 +: 2]), + .B_REG_TYPE(S_B_REG_TYPE[m*2 +: 2]) + ) + reg_inst ( + .clk(clk), + .rst(rst), + .s_axi_awid(s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .s_axi_awaddr(s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]), + .s_axi_awlen(s_axi_awlen[m*8 +: 8]), + .s_axi_awsize(s_axi_awsize[m*3 +: 3]), + .s_axi_awburst(s_axi_awburst[m*2 +: 2]), + .s_axi_awlock(s_axi_awlock[m]), + .s_axi_awcache(s_axi_awcache[m*4 +: 4]), + .s_axi_awprot(s_axi_awprot[m*3 +: 3]), + .s_axi_awqos(s_axi_awqos[m*4 +: 4]), + .s_axi_awregion(4'd0), + .s_axi_awuser(s_axi_awuser[m*AWUSER_WIDTH +: AWUSER_WIDTH]), + .s_axi_awvalid(s_axi_awvalid[m]), + .s_axi_awready(s_axi_awready[m]), + .s_axi_wdata(s_axi_wdata[m*DATA_WIDTH +: DATA_WIDTH]), + .s_axi_wstrb(s_axi_wstrb[m*STRB_WIDTH +: STRB_WIDTH]), + .s_axi_wlast(s_axi_wlast[m]), + .s_axi_wuser(s_axi_wuser[m*WUSER_WIDTH +: WUSER_WIDTH]), + .s_axi_wvalid(s_axi_wvalid[m]), + .s_axi_wready(s_axi_wready[m]), + .s_axi_bid(s_axi_bid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .s_axi_bresp(s_axi_bresp[m*2 +: 2]), + .s_axi_buser(s_axi_buser[m*BUSER_WIDTH +: BUSER_WIDTH]), + .s_axi_bvalid(s_axi_bvalid[m]), + .s_axi_bready(s_axi_bready[m]), + .m_axi_awid(int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]), + .m_axi_awaddr(int_s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]), + .m_axi_awlen(int_s_axi_awlen[m*8 +: 8]), + .m_axi_awsize(int_s_axi_awsize[m*3 +: 3]), + .m_axi_awburst(int_s_axi_awburst[m*2 +: 2]), + .m_axi_awlock(int_s_axi_awlock[m]), + .m_axi_awcache(int_s_axi_awcache[m*4 +: 4]), + .m_axi_awprot(int_s_axi_awprot[m*3 +: 3]), + .m_axi_awqos(int_s_axi_awqos[m*4 +: 4]), + .m_axi_awregion(), + .m_axi_awuser(int_s_axi_awuser[m*AWUSER_WIDTH +: AWUSER_WIDTH]), + .m_axi_awvalid(int_s_axi_awvalid[m]), + .m_axi_awready(int_s_axi_awready[m]), + .m_axi_wdata(int_s_axi_wdata[m*DATA_WIDTH +: DATA_WIDTH]), + .m_axi_wstrb(int_s_axi_wstrb[m*STRB_WIDTH +: STRB_WIDTH]), + .m_axi_wlast(int_s_axi_wlast[m]), + .m_axi_wuser(int_s_axi_wuser[m*WUSER_WIDTH +: WUSER_WIDTH]), + .m_axi_wvalid(int_s_axi_wvalid[m]), + .m_axi_wready(int_s_axi_wready[m]), + .m_axi_bid(m_axi_bid_mux), + .m_axi_bresp(m_axi_bresp_mux), + .m_axi_buser(m_axi_buser_mux), + .m_axi_bvalid(m_axi_bvalid_mux), + .m_axi_bready(m_axi_bready_mux) + ); + end // s_ifaces + + for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces + // in-flight transaction count + wire trans_start; + wire trans_complete; + reg [$clog2(M_ISSUE[n*32 +: 32]+1)-1:0] trans_count_reg = 0; + + wire trans_limit = trans_count_reg >= M_ISSUE[n*32 +: 32] && !trans_complete; + + always @(posedge clk) begin + if (rst) begin + trans_count_reg <= 0; + end else begin + if (trans_start && !trans_complete) begin + trans_count_reg <= trans_count_reg + 1; + end else if (!trans_start && trans_complete) begin + trans_count_reg <= trans_count_reg - 1; + end + end + end + + // address arbitration + reg [CL_S_COUNT-1:0] w_select_reg = 0, w_select_next; + reg w_select_valid_reg = 1'b0, w_select_valid_next; + reg w_select_new_reg = 1'b0, w_select_new_next; + + wire [S_COUNT-1:0] a_request; + wire [S_COUNT-1:0] a_acknowledge; + wire [S_COUNT-1:0] a_grant; + wire a_grant_valid; + wire [CL_S_COUNT-1:0] a_grant_encoded; + + arbiter #( + .PORTS(S_COUNT), + .ARB_TYPE_ROUND_ROBIN(1), + .ARB_BLOCK(1), + .ARB_BLOCK_ACK(1), + .ARB_LSB_HIGH_PRIORITY(1) + ) + a_arb_inst ( + .clk(clk), + .rst(rst), + .request(a_request), + .acknowledge(a_acknowledge), + .grant(a_grant), + .grant_valid(a_grant_valid), + .grant_encoded(a_grant_encoded) + ); + + // address mux + wire [M_ID_WIDTH-1:0] s_axi_awid_mux = int_s_axi_awid[a_grant_encoded*S_ID_WIDTH +: S_ID_WIDTH] | (a_grant_encoded << S_ID_WIDTH); + wire [ADDR_WIDTH-1:0] s_axi_awaddr_mux = int_s_axi_awaddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH]; + wire [7:0] s_axi_awlen_mux = int_s_axi_awlen[a_grant_encoded*8 +: 8]; + wire [2:0] s_axi_awsize_mux = int_s_axi_awsize[a_grant_encoded*3 +: 3]; + wire [1:0] s_axi_awburst_mux = int_s_axi_awburst[a_grant_encoded*2 +: 2]; + wire s_axi_awlock_mux = int_s_axi_awlock[a_grant_encoded]; + wire [3:0] s_axi_awcache_mux = int_s_axi_awcache[a_grant_encoded*4 +: 4]; + wire [2:0] s_axi_awprot_mux = int_s_axi_awprot[a_grant_encoded*3 +: 3]; + wire [3:0] s_axi_awqos_mux = int_s_axi_awqos[a_grant_encoded*4 +: 4]; + wire [3:0] s_axi_awregion_mux = int_s_axi_awregion[a_grant_encoded*4 +: 4]; + wire [AWUSER_WIDTH-1:0] s_axi_awuser_mux = int_s_axi_awuser[a_grant_encoded*AWUSER_WIDTH +: AWUSER_WIDTH]; + wire s_axi_awvalid_mux = int_axi_awvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid; + wire s_axi_awready_mux; + + assign int_axi_awready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axi_awready_mux) << a_grant_encoded; + + for (m = 0; m < S_COUNT; m = m + 1) begin + assign a_request[m] = int_axi_awvalid[m*M_COUNT+n] && !a_grant[m] && !trans_limit && !w_select_valid_next; + assign a_acknowledge[m] = a_grant[m] && int_axi_awvalid[m*M_COUNT+n] && s_axi_awready_mux; + end + + assign trans_start = s_axi_awvalid_mux && s_axi_awready_mux && a_grant_valid; + + // write data mux + wire [DATA_WIDTH-1:0] s_axi_wdata_mux = int_s_axi_wdata[w_select_reg*DATA_WIDTH +: DATA_WIDTH]; + wire [STRB_WIDTH-1:0] s_axi_wstrb_mux = int_s_axi_wstrb[w_select_reg*STRB_WIDTH +: STRB_WIDTH]; + wire s_axi_wlast_mux = int_s_axi_wlast[w_select_reg]; + wire [WUSER_WIDTH-1:0] s_axi_wuser_mux = int_s_axi_wuser[w_select_reg*WUSER_WIDTH +: WUSER_WIDTH]; + wire s_axi_wvalid_mux = int_axi_wvalid[w_select_reg*M_COUNT+n] && w_select_valid_reg; + wire s_axi_wready_mux; + + assign int_axi_wready[n*S_COUNT +: S_COUNT] = (w_select_valid_reg && s_axi_wready_mux) << w_select_reg; + + // write data routing + always @* begin + w_select_next = w_select_reg; + w_select_valid_next = w_select_valid_reg && !(s_axi_wvalid_mux && s_axi_wready_mux && s_axi_wlast_mux); + w_select_new_next = w_select_new_reg || !a_grant_valid || a_acknowledge; + + if (a_grant_valid && !w_select_valid_reg && w_select_new_reg) begin + w_select_next = a_grant_encoded; + w_select_valid_next = a_grant_valid; + w_select_new_next = 1'b0; + end + end + + always @(posedge clk) begin + if (rst) begin + w_select_valid_reg <= 1'b0; + w_select_new_reg <= 1'b1; + end else begin + w_select_valid_reg <= w_select_valid_next; + w_select_new_reg <= w_select_new_next; + end + + w_select_reg <= w_select_next; + end + + // write response forwarding + wire [CL_S_COUNT-1:0] b_select = m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH] >> S_ID_WIDTH; + + assign int_axi_bvalid[n*S_COUNT +: S_COUNT] = int_m_axi_bvalid[n] << b_select; + assign int_m_axi_bready[n] = int_axi_bready[b_select*M_COUNT+n]; + + assign trans_complete = int_m_axi_bvalid[n] && int_m_axi_bready[n]; + + // M side register + axi_register_wr #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .ID_WIDTH(M_ID_WIDTH), + .AWUSER_ENABLE(AWUSER_ENABLE), + .AWUSER_WIDTH(AWUSER_WIDTH), + .WUSER_ENABLE(WUSER_ENABLE), + .WUSER_WIDTH(WUSER_WIDTH), + .BUSER_ENABLE(BUSER_ENABLE), + .BUSER_WIDTH(BUSER_WIDTH), + .AW_REG_TYPE(M_AW_REG_TYPE[n*2 +: 2]), + .W_REG_TYPE(M_W_REG_TYPE[n*2 +: 2]), + .B_REG_TYPE(M_B_REG_TYPE[n*2 +: 2]) + ) + reg_inst ( + .clk(clk), + .rst(rst), + .s_axi_awid(s_axi_awid_mux), + .s_axi_awaddr(s_axi_awaddr_mux), + .s_axi_awlen(s_axi_awlen_mux), + .s_axi_awsize(s_axi_awsize_mux), + .s_axi_awburst(s_axi_awburst_mux), + .s_axi_awlock(s_axi_awlock_mux), + .s_axi_awcache(s_axi_awcache_mux), + .s_axi_awprot(s_axi_awprot_mux), + .s_axi_awqos(s_axi_awqos_mux), + .s_axi_awregion(s_axi_awregion_mux), + .s_axi_awuser(s_axi_awuser_mux), + .s_axi_awvalid(s_axi_awvalid_mux), + .s_axi_awready(s_axi_awready_mux), + .s_axi_wdata(s_axi_wdata_mux), + .s_axi_wstrb(s_axi_wstrb_mux), + .s_axi_wlast(s_axi_wlast_mux), + .s_axi_wuser(s_axi_wuser_mux), + .s_axi_wvalid(s_axi_wvalid_mux), + .s_axi_wready(s_axi_wready_mux), + .s_axi_bid(int_m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH]), + .s_axi_bresp(int_m_axi_bresp[n*2 +: 2]), + .s_axi_buser(int_m_axi_buser[n*BUSER_WIDTH +: BUSER_WIDTH]), + .s_axi_bvalid(int_m_axi_bvalid[n]), + .s_axi_bready(int_m_axi_bready[n]), + .m_axi_awid(m_axi_awid[n*M_ID_WIDTH +: M_ID_WIDTH]), + .m_axi_awaddr(m_axi_awaddr[n*ADDR_WIDTH +: ADDR_WIDTH]), + .m_axi_awlen(m_axi_awlen[n*8 +: 8]), + .m_axi_awsize(m_axi_awsize[n*3 +: 3]), + .m_axi_awburst(m_axi_awburst[n*2 +: 2]), + .m_axi_awlock(m_axi_awlock[n]), + .m_axi_awcache(m_axi_awcache[n*4 +: 4]), + .m_axi_awprot(m_axi_awprot[n*3 +: 3]), + .m_axi_awqos(m_axi_awqos[n*4 +: 4]), + .m_axi_awregion(m_axi_awregion[n*4 +: 4]), + .m_axi_awuser(m_axi_awuser[n*AWUSER_WIDTH +: AWUSER_WIDTH]), + .m_axi_awvalid(m_axi_awvalid[n]), + .m_axi_awready(m_axi_awready[n]), + .m_axi_wdata(m_axi_wdata[n*DATA_WIDTH +: DATA_WIDTH]), + .m_axi_wstrb(m_axi_wstrb[n*STRB_WIDTH +: STRB_WIDTH]), + .m_axi_wlast(m_axi_wlast[n]), + .m_axi_wuser(m_axi_wuser[n*WUSER_WIDTH +: WUSER_WIDTH]), + .m_axi_wvalid(m_axi_wvalid[n]), + .m_axi_wready(m_axi_wready[n]), + .m_axi_bid(m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH]), + .m_axi_bresp(m_axi_bresp[n*2 +: 2]), + .m_axi_buser(m_axi_buser[n*BUSER_WIDTH +: BUSER_WIDTH]), + .m_axi_bvalid(m_axi_bvalid[n]), + .m_axi_bready(m_axi_bready[n]) + ); + end // m_ifaces + +endgenerate + +endmodule + +`resetall diff --git a/sim/model/axi_ram.v b/sim/model/axi_ram.v new file mode 100644 index 0000000..21b399c --- /dev/null +++ b/sim/model/axi_ram.v @@ -0,0 +1,362 @@ +/* +Copyright (c) 2018 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 RAM + */ +module axi_ram # +( + // Width of data bus in bits + parameter DATA_WIDTH = 32, + // Width of address bus in bits + parameter ADDR_WIDTH = 16, + // Width of wstrb (width of data bus in words) + parameter STRB_WIDTH = (DATA_WIDTH/8), + // Width of ID signal + parameter ID_WIDTH = 4, + // Extra pipeline register on output + parameter PIPELINE_OUTPUT = 0 +) +( + input wire s_aclk, + input wire s_aresetn, + + input wire [ID_WIDTH-1:0] s_axi_awid, + input wire [ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [7:0] s_axi_awlen, + input wire [2:0] s_axi_awsize, + input wire [1:0] s_axi_awburst, + input wire s_axi_awvalid, + output wire s_axi_awready, + input wire [DATA_WIDTH-1:0] s_axi_wdata, + input wire [STRB_WIDTH-1:0] s_axi_wstrb, + input wire s_axi_wlast, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [ID_WIDTH-1:0] s_axi_bid, + output wire [1:0] s_axi_bresp, + output wire s_axi_bvalid, + input wire s_axi_bready, + input wire [ID_WIDTH-1:0] s_axi_arid, + input wire [ADDR_WIDTH-1:0] s_axi_araddr, + input wire [7:0] s_axi_arlen, + input wire [2:0] s_axi_arsize, + input wire [1:0] s_axi_arburst, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [ID_WIDTH-1:0] s_axi_rid, + output wire [DATA_WIDTH-1:0] s_axi_rdata, + output wire [1:0] s_axi_rresp, + output wire s_axi_rlast, + output wire s_axi_rvalid, + input wire s_axi_rready +); + +parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); +parameter WORD_WIDTH = STRB_WIDTH; +parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH; + +// bus width assertions +initial begin + if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin + $error("Error: AXI data width not evenly divisble (instance %m)"); + $finish; + end + + if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin + $error("Error: AXI word width must be even power of two (instance %m)"); + $finish; + end +end + +localparam [0:0] + READ_STATE_IDLE = 1'd0, + READ_STATE_BURST = 1'd1; + +reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next; + +localparam [1:0] + WRITE_STATE_IDLE = 2'd0, + WRITE_STATE_BURST = 2'd1, + WRITE_STATE_RESP = 2'd2; + +reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next; + +reg mem_wr_en; +reg mem_rd_en; + +reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next; +reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next; +reg [7:0] read_count_reg = 8'd0, read_count_next; +reg [2:0] read_size_reg = 3'd0, read_size_next; +reg [1:0] read_burst_reg = 2'd0, read_burst_next; +reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next; +reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next; +reg [7:0] write_count_reg = 8'd0, write_count_next; +reg [2:0] write_size_reg = 3'd0, write_size_next; +reg [1:0] write_burst_reg = 2'd0, write_burst_next; + +reg s_axi_awready_reg = 1'b0, s_axi_awready_next; +reg s_axi_wready_reg = 1'b0, s_axi_wready_next; +reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next; +reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; +reg s_axi_arready_reg = 1'b0, s_axi_arready_next; +reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next; +reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next; +reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next; +reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; +reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}}; +reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}}; +reg s_axi_rlast_pipe_reg = 1'b0; +reg s_axi_rvalid_pipe_reg = 1'b0; + +// (* RAM_STYLE="BLOCK" *) +reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0]; + +wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); +wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); +wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); +wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); + +assign s_axi_awready = s_axi_awready_reg; +assign s_axi_wready = s_axi_wready_reg; +assign s_axi_bid = s_axi_bid_reg; +assign s_axi_bresp = 2'b00; +assign s_axi_bvalid = s_axi_bvalid_reg; +assign s_axi_arready = s_axi_arready_reg; +assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : s_axi_rid_reg; +assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : s_axi_rdata_reg; +assign s_axi_rresp = 2'b00; +assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg; +assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg; + +integer i, j; + +initial begin + // two nested loops for smaller number of iterations per loop + // workaround for synthesizer complaints about large loop counts + for (i = 0; i < 2**VALID_ADDR_WIDTH; i = i + 2**(VALID_ADDR_WIDTH/2)) begin + for (j = i; j < i + 2**(VALID_ADDR_WIDTH/2); j = j + 1) begin + mem[j] = 0; + end + end +end + +always @* begin + write_state_next = WRITE_STATE_IDLE; + + mem_wr_en = 1'b0; + + write_id_next = write_id_reg; + write_addr_next = write_addr_reg; + write_count_next = write_count_reg; + write_size_next = write_size_reg; + write_burst_next = write_burst_reg; + + s_axi_awready_next = 1'b0; + s_axi_wready_next = 1'b0; + s_axi_bid_next = s_axi_bid_reg; + s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready; + + case (write_state_reg) + WRITE_STATE_IDLE: begin + s_axi_awready_next = 1'b1; + + if (s_axi_awready && s_axi_awvalid) begin + write_id_next = s_axi_awid; + write_addr_next = s_axi_awaddr; + write_count_next = s_axi_awlen; + write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH); + write_burst_next = s_axi_awburst; + + s_axi_awready_next = 1'b0; + s_axi_wready_next = 1'b1; + write_state_next = WRITE_STATE_BURST; + end else begin + write_state_next = WRITE_STATE_IDLE; + end + end + WRITE_STATE_BURST: begin + s_axi_wready_next = 1'b1; + + if (s_axi_wready && s_axi_wvalid) begin + mem_wr_en = 1'b1; + if (write_burst_reg != 2'b00) begin + write_addr_next = write_addr_reg + (1 << write_size_reg); + end + write_count_next = write_count_reg - 1; + if (write_count_reg > 0) begin + write_state_next = WRITE_STATE_BURST; + end else begin + s_axi_wready_next = 1'b0; + if (s_axi_bready || !s_axi_bvalid) begin + s_axi_bid_next = write_id_reg; + s_axi_bvalid_next = 1'b1; + s_axi_awready_next = 1'b1; + write_state_next = WRITE_STATE_IDLE; + end else begin + write_state_next = WRITE_STATE_RESP; + end + end + end else begin + write_state_next = WRITE_STATE_BURST; + end + end + WRITE_STATE_RESP: begin + if (s_axi_bready || !s_axi_bvalid) begin + s_axi_bid_next = write_id_reg; + s_axi_bvalid_next = 1'b1; + s_axi_awready_next = 1'b1; + write_state_next = WRITE_STATE_IDLE; + end else begin + write_state_next = WRITE_STATE_RESP; + end + end + endcase +end + +always @(posedge s_aclk) begin + write_state_reg <= write_state_next; + + write_id_reg <= write_id_next; + write_addr_reg <= write_addr_next; + write_count_reg <= write_count_next; + write_size_reg <= write_size_next; + write_burst_reg <= write_burst_next; + + s_axi_awready_reg <= s_axi_awready_next; + s_axi_wready_reg <= s_axi_wready_next; + s_axi_bid_reg <= s_axi_bid_next; + s_axi_bvalid_reg <= s_axi_bvalid_next; + + for (i = 0; i < WORD_WIDTH; i = i + 1) begin + if (mem_wr_en & s_axi_wstrb[i]) begin + mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= s_axi_wdata[WORD_SIZE*i +: WORD_SIZE]; + end + end + + if (~s_aresetn) begin + write_state_reg <= WRITE_STATE_IDLE; + + s_axi_awready_reg <= 1'b0; + s_axi_wready_reg <= 1'b0; + s_axi_bvalid_reg <= 1'b0; + end +end + +always @* begin + read_state_next = READ_STATE_IDLE; + + mem_rd_en = 1'b0; + + s_axi_rid_next = s_axi_rid_reg; + s_axi_rlast_next = s_axi_rlast_reg; + s_axi_rvalid_next = s_axi_rvalid_reg && !(s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg)); + + read_id_next = read_id_reg; + read_addr_next = read_addr_reg; + read_count_next = read_count_reg; + read_size_next = read_size_reg; + read_burst_next = read_burst_reg; + + s_axi_arready_next = 1'b0; + + case (read_state_reg) + READ_STATE_IDLE: begin + s_axi_arready_next = 1'b1; + + if (s_axi_arready && s_axi_arvalid) begin + read_id_next = s_axi_arid; + read_addr_next = s_axi_araddr; + read_count_next = s_axi_arlen; + read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH); + read_burst_next = s_axi_arburst; + + s_axi_arready_next = 1'b0; + read_state_next = READ_STATE_BURST; + end else begin + read_state_next = READ_STATE_IDLE; + end + end + READ_STATE_BURST: begin + if (s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg) || !s_axi_rvalid_reg) begin + mem_rd_en = 1'b1; + s_axi_rvalid_next = 1'b1; + s_axi_rid_next = read_id_reg; + s_axi_rlast_next = read_count_reg == 0; + if (read_burst_reg != 2'b00) begin + read_addr_next = read_addr_reg + (1 << read_size_reg); + end + read_count_next = read_count_reg - 1; + if (read_count_reg > 0) begin + read_state_next = READ_STATE_BURST; + end else begin + s_axi_arready_next = 1'b1; + read_state_next = READ_STATE_IDLE; + end + end else begin + read_state_next = READ_STATE_BURST; + end + end + endcase +end + +always @(posedge s_aclk) begin + read_state_reg <= read_state_next; + + read_id_reg <= read_id_next; + read_addr_reg <= read_addr_next; + read_count_reg <= read_count_next; + read_size_reg <= read_size_next; + read_burst_reg <= read_burst_next; + + s_axi_arready_reg <= s_axi_arready_next; + s_axi_rid_reg <= s_axi_rid_next; + s_axi_rlast_reg <= s_axi_rlast_next; + s_axi_rvalid_reg <= s_axi_rvalid_next; + + if (mem_rd_en) begin + s_axi_rdata_reg <= mem[read_addr_valid]; + end + + if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin + s_axi_rid_pipe_reg <= s_axi_rid_reg; + s_axi_rdata_pipe_reg <= s_axi_rdata_reg; + s_axi_rlast_pipe_reg <= s_axi_rlast_reg; + s_axi_rvalid_pipe_reg <= s_axi_rvalid_reg; + end + + if (~s_aresetn) begin + read_state_reg <= READ_STATE_IDLE; + + s_axi_arready_reg <= 1'b0; + s_axi_rvalid_reg <= 1'b0; + s_axi_rvalid_pipe_reg <= 1'b0; + end +end + +endmodule + +`resetall diff --git a/sim/model/axi_register_rd.v b/sim/model/axi_register_rd.v new file mode 100644 index 0000000..c0df03a --- /dev/null +++ b/sim/model/axi_register_rd.v @@ -0,0 +1,530 @@ +/* + +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 register (read) + */ +module axi_register_rd # +( + // Width of data bus in bits + parameter DATA_WIDTH = 32, + // Width of address bus in bits + parameter ADDR_WIDTH = 32, + // Width of wstrb (width of data bus in words) + parameter STRB_WIDTH = (DATA_WIDTH/8), + // Width of ID signal + parameter ID_WIDTH = 8, + // Propagate aruser signal + parameter ARUSER_ENABLE = 0, + // Width of aruser signal + parameter ARUSER_WIDTH = 1, + // Propagate ruser signal + parameter RUSER_ENABLE = 0, + // Width of ruser signal + parameter RUSER_WIDTH = 1, + // AR channel register type + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter AR_REG_TYPE = 1, + // R channel register type + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter R_REG_TYPE = 2 +) +( + input wire clk, + input wire rst, + + /* + * AXI slave interface + */ + input wire [ID_WIDTH-1:0] s_axi_arid, + input wire [ADDR_WIDTH-1:0] s_axi_araddr, + input wire [7:0] s_axi_arlen, + input wire [2:0] s_axi_arsize, + input wire [1:0] s_axi_arburst, + input wire s_axi_arlock, + input wire [3:0] s_axi_arcache, + input wire [2:0] s_axi_arprot, + input wire [3:0] s_axi_arqos, + input wire [3:0] s_axi_arregion, + input wire [ARUSER_WIDTH-1:0] s_axi_aruser, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [ID_WIDTH-1:0] s_axi_rid, + output wire [DATA_WIDTH-1:0] s_axi_rdata, + output wire [1:0] s_axi_rresp, + output wire s_axi_rlast, + output wire [RUSER_WIDTH-1:0] s_axi_ruser, + output wire s_axi_rvalid, + input wire s_axi_rready, + + /* + * AXI master interface + */ + output wire [ID_WIDTH-1:0] m_axi_arid, + output wire [ADDR_WIDTH-1:0] m_axi_araddr, + output wire [7:0] m_axi_arlen, + output wire [2:0] m_axi_arsize, + output wire [1:0] m_axi_arburst, + output wire m_axi_arlock, + output wire [3:0] m_axi_arcache, + output wire [2:0] m_axi_arprot, + output wire [3:0] m_axi_arqos, + output wire [3:0] m_axi_arregion, + output wire [ARUSER_WIDTH-1:0] m_axi_aruser, + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [ID_WIDTH-1:0] m_axi_rid, + input wire [DATA_WIDTH-1:0] m_axi_rdata, + input wire [1:0] m_axi_rresp, + input wire m_axi_rlast, + input wire [RUSER_WIDTH-1:0] m_axi_ruser, + input wire m_axi_rvalid, + output wire m_axi_rready +); + +generate + +// AR channel + +if (AR_REG_TYPE > 1) begin +// skid buffer, no bubble cycles + +// datapath registers +reg s_axi_arready_reg = 1'b0; + +reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}}; +reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}; +reg [7:0] m_axi_arlen_reg = 8'd0; +reg [2:0] m_axi_arsize_reg = 3'd0; +reg [1:0] m_axi_arburst_reg = 2'd0; +reg m_axi_arlock_reg = 1'b0; +reg [3:0] m_axi_arcache_reg = 4'd0; +reg [2:0] m_axi_arprot_reg = 3'd0; +reg [3:0] m_axi_arqos_reg = 4'd0; +reg [3:0] m_axi_arregion_reg = 4'd0; +reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}; +reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next; + +reg [ID_WIDTH-1:0] temp_m_axi_arid_reg = {ID_WIDTH{1'b0}}; +reg [ADDR_WIDTH-1:0] temp_m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}; +reg [7:0] temp_m_axi_arlen_reg = 8'd0; +reg [2:0] temp_m_axi_arsize_reg = 3'd0; +reg [1:0] temp_m_axi_arburst_reg = 2'd0; +reg temp_m_axi_arlock_reg = 1'b0; +reg [3:0] temp_m_axi_arcache_reg = 4'd0; +reg [2:0] temp_m_axi_arprot_reg = 3'd0; +reg [3:0] temp_m_axi_arqos_reg = 4'd0; +reg [3:0] temp_m_axi_arregion_reg = 4'd0; +reg [ARUSER_WIDTH-1:0] temp_m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}; +reg temp_m_axi_arvalid_reg = 1'b0, temp_m_axi_arvalid_next; + +// datapath control +reg store_axi_ar_input_to_output; +reg store_axi_ar_input_to_temp; +reg store_axi_ar_temp_to_output; + +assign s_axi_arready = s_axi_arready_reg; + +assign m_axi_arid = m_axi_arid_reg; +assign m_axi_araddr = m_axi_araddr_reg; +assign m_axi_arlen = m_axi_arlen_reg; +assign m_axi_arsize = m_axi_arsize_reg; +assign m_axi_arburst = m_axi_arburst_reg; +assign m_axi_arlock = m_axi_arlock_reg; +assign m_axi_arcache = m_axi_arcache_reg; +assign m_axi_arprot = m_axi_arprot_reg; +assign m_axi_arqos = m_axi_arqos_reg; +assign m_axi_arregion = m_axi_arregion_reg; +assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}}; +assign m_axi_arvalid = m_axi_arvalid_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +wire s_axi_arready_early = m_axi_arready | (~temp_m_axi_arvalid_reg & (~m_axi_arvalid_reg | ~s_axi_arvalid)); + +always @* begin + // transfer sink ready state to source + m_axi_arvalid_next = m_axi_arvalid_reg; + temp_m_axi_arvalid_next = temp_m_axi_arvalid_reg; + + store_axi_ar_input_to_output = 1'b0; + store_axi_ar_input_to_temp = 1'b0; + store_axi_ar_temp_to_output = 1'b0; + + if (s_axi_arready_reg) begin + // input is ready + if (m_axi_arready | ~m_axi_arvalid_reg) begin + // output is ready or currently not valid, transfer data to output + m_axi_arvalid_next = s_axi_arvalid; + store_axi_ar_input_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_m_axi_arvalid_next = s_axi_arvalid; + store_axi_ar_input_to_temp = 1'b1; + end + end else if (m_axi_arready) begin + // input is not ready, but output is ready + m_axi_arvalid_next = temp_m_axi_arvalid_reg; + temp_m_axi_arvalid_next = 1'b0; + store_axi_ar_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + s_axi_arready_reg <= 1'b0; + m_axi_arvalid_reg <= 1'b0; + temp_m_axi_arvalid_reg <= 1'b0; + end else begin + s_axi_arready_reg <= s_axi_arready_early; + m_axi_arvalid_reg <= m_axi_arvalid_next; + temp_m_axi_arvalid_reg <= temp_m_axi_arvalid_next; + end + + // datapath + if (store_axi_ar_input_to_output) begin + m_axi_arid_reg <= s_axi_arid; + m_axi_araddr_reg <= s_axi_araddr; + m_axi_arlen_reg <= s_axi_arlen; + m_axi_arsize_reg <= s_axi_arsize; + m_axi_arburst_reg <= s_axi_arburst; + m_axi_arlock_reg <= s_axi_arlock; + m_axi_arcache_reg <= s_axi_arcache; + m_axi_arprot_reg <= s_axi_arprot; + m_axi_arqos_reg <= s_axi_arqos; + m_axi_arregion_reg <= s_axi_arregion; + m_axi_aruser_reg <= s_axi_aruser; + end else if (store_axi_ar_temp_to_output) begin + m_axi_arid_reg <= temp_m_axi_arid_reg; + m_axi_araddr_reg <= temp_m_axi_araddr_reg; + m_axi_arlen_reg <= temp_m_axi_arlen_reg; + m_axi_arsize_reg <= temp_m_axi_arsize_reg; + m_axi_arburst_reg <= temp_m_axi_arburst_reg; + m_axi_arlock_reg <= temp_m_axi_arlock_reg; + m_axi_arcache_reg <= temp_m_axi_arcache_reg; + m_axi_arprot_reg <= temp_m_axi_arprot_reg; + m_axi_arqos_reg <= temp_m_axi_arqos_reg; + m_axi_arregion_reg <= temp_m_axi_arregion_reg; + m_axi_aruser_reg <= temp_m_axi_aruser_reg; + end + + if (store_axi_ar_input_to_temp) begin + temp_m_axi_arid_reg <= s_axi_arid; + temp_m_axi_araddr_reg <= s_axi_araddr; + temp_m_axi_arlen_reg <= s_axi_arlen; + temp_m_axi_arsize_reg <= s_axi_arsize; + temp_m_axi_arburst_reg <= s_axi_arburst; + temp_m_axi_arlock_reg <= s_axi_arlock; + temp_m_axi_arcache_reg <= s_axi_arcache; + temp_m_axi_arprot_reg <= s_axi_arprot; + temp_m_axi_arqos_reg <= s_axi_arqos; + temp_m_axi_arregion_reg <= s_axi_arregion; + temp_m_axi_aruser_reg <= s_axi_aruser; + end +end + +end else if (AR_REG_TYPE == 1) begin +// simple register, inserts bubble cycles + +// datapath registers +reg s_axi_arready_reg = 1'b0; + +reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}}; +reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}; +reg [7:0] m_axi_arlen_reg = 8'd0; +reg [2:0] m_axi_arsize_reg = 3'd0; +reg [1:0] m_axi_arburst_reg = 2'd0; +reg m_axi_arlock_reg = 1'b0; +reg [3:0] m_axi_arcache_reg = 4'd0; +reg [2:0] m_axi_arprot_reg = 3'd0; +reg [3:0] m_axi_arqos_reg = 4'd0; +reg [3:0] m_axi_arregion_reg = 4'd0; +reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}; +reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next; + +// datapath control +reg store_axi_ar_input_to_output; + +assign s_axi_arready = s_axi_arready_reg; + +assign m_axi_arid = m_axi_arid_reg; +assign m_axi_araddr = m_axi_araddr_reg; +assign m_axi_arlen = m_axi_arlen_reg; +assign m_axi_arsize = m_axi_arsize_reg; +assign m_axi_arburst = m_axi_arburst_reg; +assign m_axi_arlock = m_axi_arlock_reg; +assign m_axi_arcache = m_axi_arcache_reg; +assign m_axi_arprot = m_axi_arprot_reg; +assign m_axi_arqos = m_axi_arqos_reg; +assign m_axi_arregion = m_axi_arregion_reg; +assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}}; +assign m_axi_arvalid = m_axi_arvalid_reg; + +// enable ready input next cycle if output buffer will be empty +wire s_axi_arready_early = !m_axi_arvalid_next; + +always @* begin + // transfer sink ready state to source + m_axi_arvalid_next = m_axi_arvalid_reg; + + store_axi_ar_input_to_output = 1'b0; + + if (s_axi_arready_reg) begin + m_axi_arvalid_next = s_axi_arvalid; + store_axi_ar_input_to_output = 1'b1; + end else if (m_axi_arready) begin + m_axi_arvalid_next = 1'b0; + end +end + +always @(posedge clk) begin + if (rst) begin + s_axi_arready_reg <= 1'b0; + m_axi_arvalid_reg <= 1'b0; + end else begin + s_axi_arready_reg <= s_axi_arready_early; + m_axi_arvalid_reg <= m_axi_arvalid_next; + end + + // datapath + if (store_axi_ar_input_to_output) begin + m_axi_arid_reg <= s_axi_arid; + m_axi_araddr_reg <= s_axi_araddr; + m_axi_arlen_reg <= s_axi_arlen; + m_axi_arsize_reg <= s_axi_arsize; + m_axi_arburst_reg <= s_axi_arburst; + m_axi_arlock_reg <= s_axi_arlock; + m_axi_arcache_reg <= s_axi_arcache; + m_axi_arprot_reg <= s_axi_arprot; + m_axi_arqos_reg <= s_axi_arqos; + m_axi_arregion_reg <= s_axi_arregion; + m_axi_aruser_reg <= s_axi_aruser; + end +end + +end else begin + + // bypass AR channel + assign m_axi_arid = s_axi_arid; + assign m_axi_araddr = s_axi_araddr; + assign m_axi_arlen = s_axi_arlen; + assign m_axi_arsize = s_axi_arsize; + assign m_axi_arburst = s_axi_arburst; + assign m_axi_arlock = s_axi_arlock; + assign m_axi_arcache = s_axi_arcache; + assign m_axi_arprot = s_axi_arprot; + assign m_axi_arqos = s_axi_arqos; + assign m_axi_arregion = s_axi_arregion; + assign m_axi_aruser = ARUSER_ENABLE ? s_axi_aruser : {ARUSER_WIDTH{1'b0}}; + assign m_axi_arvalid = s_axi_arvalid; + assign s_axi_arready = m_axi_arready; + +end + +// R channel + +if (R_REG_TYPE > 1) begin +// skid buffer, no bubble cycles + +// datapath registers +reg m_axi_rready_reg = 1'b0; + +reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}; +reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}; +reg [1:0] s_axi_rresp_reg = 2'b0; +reg s_axi_rlast_reg = 1'b0; +reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = {RUSER_WIDTH{1'b0}}; +reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; + +reg [ID_WIDTH-1:0] temp_s_axi_rid_reg = {ID_WIDTH{1'b0}}; +reg [DATA_WIDTH-1:0] temp_s_axi_rdata_reg = {DATA_WIDTH{1'b0}}; +reg [1:0] temp_s_axi_rresp_reg = 2'b0; +reg temp_s_axi_rlast_reg = 1'b0; +reg [RUSER_WIDTH-1:0] temp_s_axi_ruser_reg = {RUSER_WIDTH{1'b0}}; +reg temp_s_axi_rvalid_reg = 1'b0, temp_s_axi_rvalid_next; + +// datapath control +reg store_axi_r_input_to_output; +reg store_axi_r_input_to_temp; +reg store_axi_r_temp_to_output; + +assign m_axi_rready = m_axi_rready_reg; + +assign s_axi_rid = s_axi_rid_reg; +assign s_axi_rdata = s_axi_rdata_reg; +assign s_axi_rresp = s_axi_rresp_reg; +assign s_axi_rlast = s_axi_rlast_reg; +assign s_axi_ruser = RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}}; +assign s_axi_rvalid = s_axi_rvalid_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +wire m_axi_rready_early = s_axi_rready | (~temp_s_axi_rvalid_reg & (~s_axi_rvalid_reg | ~m_axi_rvalid)); + +always @* begin + // transfer sink ready state to source + s_axi_rvalid_next = s_axi_rvalid_reg; + temp_s_axi_rvalid_next = temp_s_axi_rvalid_reg; + + store_axi_r_input_to_output = 1'b0; + store_axi_r_input_to_temp = 1'b0; + store_axi_r_temp_to_output = 1'b0; + + if (m_axi_rready_reg) begin + // input is ready + if (s_axi_rready | ~s_axi_rvalid_reg) begin + // output is ready or currently not valid, transfer data to output + s_axi_rvalid_next = m_axi_rvalid; + store_axi_r_input_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_s_axi_rvalid_next = m_axi_rvalid; + store_axi_r_input_to_temp = 1'b1; + end + end else if (s_axi_rready) begin + // input is not ready, but output is ready + s_axi_rvalid_next = temp_s_axi_rvalid_reg; + temp_s_axi_rvalid_next = 1'b0; + store_axi_r_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + m_axi_rready_reg <= 1'b0; + s_axi_rvalid_reg <= 1'b0; + temp_s_axi_rvalid_reg <= 1'b0; + end else begin + m_axi_rready_reg <= m_axi_rready_early; + s_axi_rvalid_reg <= s_axi_rvalid_next; + temp_s_axi_rvalid_reg <= temp_s_axi_rvalid_next; + end + + // datapath + if (store_axi_r_input_to_output) begin + s_axi_rid_reg <= m_axi_rid; + s_axi_rdata_reg <= m_axi_rdata; + s_axi_rresp_reg <= m_axi_rresp; + s_axi_rlast_reg <= m_axi_rlast; + s_axi_ruser_reg <= m_axi_ruser; + end else if (store_axi_r_temp_to_output) begin + s_axi_rid_reg <= temp_s_axi_rid_reg; + s_axi_rdata_reg <= temp_s_axi_rdata_reg; + s_axi_rresp_reg <= temp_s_axi_rresp_reg; + s_axi_rlast_reg <= temp_s_axi_rlast_reg; + s_axi_ruser_reg <= temp_s_axi_ruser_reg; + end + + if (store_axi_r_input_to_temp) begin + temp_s_axi_rid_reg <= m_axi_rid; + temp_s_axi_rdata_reg <= m_axi_rdata; + temp_s_axi_rresp_reg <= m_axi_rresp; + temp_s_axi_rlast_reg <= m_axi_rlast; + temp_s_axi_ruser_reg <= m_axi_ruser; + end +end + +end else if (R_REG_TYPE == 1) begin +// simple register, inserts bubble cycles + +// datapath registers +reg m_axi_rready_reg = 1'b0; + +reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}; +reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}; +reg [1:0] s_axi_rresp_reg = 2'b0; +reg s_axi_rlast_reg = 1'b0; +reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = {RUSER_WIDTH{1'b0}}; +reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; + +// datapath control +reg store_axi_r_input_to_output; + +assign m_axi_rready = m_axi_rready_reg; + +assign s_axi_rid = s_axi_rid_reg; +assign s_axi_rdata = s_axi_rdata_reg; +assign s_axi_rresp = s_axi_rresp_reg; +assign s_axi_rlast = s_axi_rlast_reg; +assign s_axi_ruser = RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}}; +assign s_axi_rvalid = s_axi_rvalid_reg; + +// enable ready input next cycle if output buffer will be empty +wire m_axi_rready_early = !s_axi_rvalid_next; + +always @* begin + // transfer sink ready state to source + s_axi_rvalid_next = s_axi_rvalid_reg; + + store_axi_r_input_to_output = 1'b0; + + if (m_axi_rready_reg) begin + s_axi_rvalid_next = m_axi_rvalid; + store_axi_r_input_to_output = 1'b1; + end else if (s_axi_rready) begin + s_axi_rvalid_next = 1'b0; + end +end + +always @(posedge clk) begin + if (rst) begin + m_axi_rready_reg <= 1'b0; + s_axi_rvalid_reg <= 1'b0; + end else begin + m_axi_rready_reg <= m_axi_rready_early; + s_axi_rvalid_reg <= s_axi_rvalid_next; + end + + // datapath + if (store_axi_r_input_to_output) begin + s_axi_rid_reg <= m_axi_rid; + s_axi_rdata_reg <= m_axi_rdata; + s_axi_rresp_reg <= m_axi_rresp; + s_axi_rlast_reg <= m_axi_rlast; + s_axi_ruser_reg <= m_axi_ruser; + end +end + +end else begin + + // bypass R channel + assign s_axi_rid = m_axi_rid; + assign s_axi_rdata = m_axi_rdata; + assign s_axi_rresp = m_axi_rresp; + assign s_axi_rlast = m_axi_rlast; + assign s_axi_ruser = RUSER_ENABLE ? m_axi_ruser : {RUSER_WIDTH{1'b0}}; + assign s_axi_rvalid = m_axi_rvalid; + assign m_axi_rready = s_axi_rready; + +end + +endgenerate + +endmodule + +`resetall diff --git a/sim/model/axi_register_wr.v b/sim/model/axi_register_wr.v new file mode 100644 index 0000000..9176d6b --- /dev/null +++ b/sim/model/axi_register_wr.v @@ -0,0 +1,691 @@ +/* + +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * AXI4 register (write) + */ +module axi_register_wr # +( + // Width of data bus in bits + parameter DATA_WIDTH = 32, + // Width of address bus in bits + parameter ADDR_WIDTH = 32, + // Width of wstrb (width of data bus in words) + parameter STRB_WIDTH = (DATA_WIDTH/8), + // Width of ID signal + parameter ID_WIDTH = 8, + // Propagate awuser signal + parameter AWUSER_ENABLE = 0, + // Width of awuser signal + parameter AWUSER_WIDTH = 1, + // Propagate wuser signal + parameter WUSER_ENABLE = 0, + // Width of wuser signal + parameter WUSER_WIDTH = 1, + // Propagate buser signal + parameter BUSER_ENABLE = 0, + // Width of buser signal + parameter BUSER_WIDTH = 1, + // AW channel register type + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter AW_REG_TYPE = 1, + // W channel register type + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter W_REG_TYPE = 2, + // B channel register type + // 0 to bypass, 1 for simple buffer, 2 for skid buffer + parameter B_REG_TYPE = 1 +) +( + input wire clk, + input wire rst, + + /* + * AXI slave interface + */ + input wire [ID_WIDTH-1:0] s_axi_awid, + input wire [ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [7:0] s_axi_awlen, + input wire [2:0] s_axi_awsize, + input wire [1:0] s_axi_awburst, + input wire s_axi_awlock, + input wire [3:0] s_axi_awcache, + input wire [2:0] s_axi_awprot, + input wire [3:0] s_axi_awqos, + input wire [3:0] s_axi_awregion, + input wire [AWUSER_WIDTH-1:0] s_axi_awuser, + input wire s_axi_awvalid, + output wire s_axi_awready, + input wire [DATA_WIDTH-1:0] s_axi_wdata, + input wire [STRB_WIDTH-1:0] s_axi_wstrb, + input wire s_axi_wlast, + input wire [WUSER_WIDTH-1:0] s_axi_wuser, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [ID_WIDTH-1:0] s_axi_bid, + output wire [1:0] s_axi_bresp, + output wire [BUSER_WIDTH-1:0] s_axi_buser, + output wire s_axi_bvalid, + input wire s_axi_bready, + + /* + * AXI master interface + */ + output wire [ID_WIDTH-1:0] m_axi_awid, + output wire [ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [7:0] m_axi_awlen, + output wire [2:0] m_axi_awsize, + output wire [1:0] m_axi_awburst, + output wire m_axi_awlock, + output wire [3:0] m_axi_awcache, + output wire [2:0] m_axi_awprot, + output wire [3:0] m_axi_awqos, + output wire [3:0] m_axi_awregion, + output wire [AWUSER_WIDTH-1:0] m_axi_awuser, + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [DATA_WIDTH-1:0] m_axi_wdata, + output wire [STRB_WIDTH-1:0] m_axi_wstrb, + output wire m_axi_wlast, + output wire [WUSER_WIDTH-1:0] m_axi_wuser, + output wire m_axi_wvalid, + input wire m_axi_wready, + input wire [ID_WIDTH-1:0] m_axi_bid, + input wire [1:0] m_axi_bresp, + input wire [BUSER_WIDTH-1:0] m_axi_buser, + input wire m_axi_bvalid, + output wire m_axi_bready +); + +generate + +// AW channel + +if (AW_REG_TYPE > 1) begin +// skid buffer, no bubble cycles + +// datapath registers +reg s_axi_awready_reg = 1'b0; + +reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}}; +reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}; +reg [7:0] m_axi_awlen_reg = 8'd0; +reg [2:0] m_axi_awsize_reg = 3'd0; +reg [1:0] m_axi_awburst_reg = 2'd0; +reg m_axi_awlock_reg = 1'b0; +reg [3:0] m_axi_awcache_reg = 4'd0; +reg [2:0] m_axi_awprot_reg = 3'd0; +reg [3:0] m_axi_awqos_reg = 4'd0; +reg [3:0] m_axi_awregion_reg = 4'd0; +reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}; +reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next; + +reg [ID_WIDTH-1:0] temp_m_axi_awid_reg = {ID_WIDTH{1'b0}}; +reg [ADDR_WIDTH-1:0] temp_m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}; +reg [7:0] temp_m_axi_awlen_reg = 8'd0; +reg [2:0] temp_m_axi_awsize_reg = 3'd0; +reg [1:0] temp_m_axi_awburst_reg = 2'd0; +reg temp_m_axi_awlock_reg = 1'b0; +reg [3:0] temp_m_axi_awcache_reg = 4'd0; +reg [2:0] temp_m_axi_awprot_reg = 3'd0; +reg [3:0] temp_m_axi_awqos_reg = 4'd0; +reg [3:0] temp_m_axi_awregion_reg = 4'd0; +reg [AWUSER_WIDTH-1:0] temp_m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}; +reg temp_m_axi_awvalid_reg = 1'b0, temp_m_axi_awvalid_next; + +// datapath control +reg store_axi_aw_input_to_output; +reg store_axi_aw_input_to_temp; +reg store_axi_aw_temp_to_output; + +assign s_axi_awready = s_axi_awready_reg; + +assign m_axi_awid = m_axi_awid_reg; +assign m_axi_awaddr = m_axi_awaddr_reg; +assign m_axi_awlen = m_axi_awlen_reg; +assign m_axi_awsize = m_axi_awsize_reg; +assign m_axi_awburst = m_axi_awburst_reg; +assign m_axi_awlock = m_axi_awlock_reg; +assign m_axi_awcache = m_axi_awcache_reg; +assign m_axi_awprot = m_axi_awprot_reg; +assign m_axi_awqos = m_axi_awqos_reg; +assign m_axi_awregion = m_axi_awregion_reg; +assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}}; +assign m_axi_awvalid = m_axi_awvalid_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +wire s_axi_awready_early = m_axi_awready | (~temp_m_axi_awvalid_reg & (~m_axi_awvalid_reg | ~s_axi_awvalid)); + +always @* begin + // transfer sink ready state to source + m_axi_awvalid_next = m_axi_awvalid_reg; + temp_m_axi_awvalid_next = temp_m_axi_awvalid_reg; + + store_axi_aw_input_to_output = 1'b0; + store_axi_aw_input_to_temp = 1'b0; + store_axi_aw_temp_to_output = 1'b0; + + if (s_axi_awready_reg) begin + // input is ready + if (m_axi_awready | ~m_axi_awvalid_reg) begin + // output is ready or currently not valid, transfer data to output + m_axi_awvalid_next = s_axi_awvalid; + store_axi_aw_input_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_m_axi_awvalid_next = s_axi_awvalid; + store_axi_aw_input_to_temp = 1'b1; + end + end else if (m_axi_awready) begin + // input is not ready, but output is ready + m_axi_awvalid_next = temp_m_axi_awvalid_reg; + temp_m_axi_awvalid_next = 1'b0; + store_axi_aw_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + s_axi_awready_reg <= 1'b0; + m_axi_awvalid_reg <= 1'b0; + temp_m_axi_awvalid_reg <= 1'b0; + end else begin + s_axi_awready_reg <= s_axi_awready_early; + m_axi_awvalid_reg <= m_axi_awvalid_next; + temp_m_axi_awvalid_reg <= temp_m_axi_awvalid_next; + end + + // datapath + if (store_axi_aw_input_to_output) begin + m_axi_awid_reg <= s_axi_awid; + m_axi_awaddr_reg <= s_axi_awaddr; + m_axi_awlen_reg <= s_axi_awlen; + m_axi_awsize_reg <= s_axi_awsize; + m_axi_awburst_reg <= s_axi_awburst; + m_axi_awlock_reg <= s_axi_awlock; + m_axi_awcache_reg <= s_axi_awcache; + m_axi_awprot_reg <= s_axi_awprot; + m_axi_awqos_reg <= s_axi_awqos; + m_axi_awregion_reg <= s_axi_awregion; + m_axi_awuser_reg <= s_axi_awuser; + end else if (store_axi_aw_temp_to_output) begin + m_axi_awid_reg <= temp_m_axi_awid_reg; + m_axi_awaddr_reg <= temp_m_axi_awaddr_reg; + m_axi_awlen_reg <= temp_m_axi_awlen_reg; + m_axi_awsize_reg <= temp_m_axi_awsize_reg; + m_axi_awburst_reg <= temp_m_axi_awburst_reg; + m_axi_awlock_reg <= temp_m_axi_awlock_reg; + m_axi_awcache_reg <= temp_m_axi_awcache_reg; + m_axi_awprot_reg <= temp_m_axi_awprot_reg; + m_axi_awqos_reg <= temp_m_axi_awqos_reg; + m_axi_awregion_reg <= temp_m_axi_awregion_reg; + m_axi_awuser_reg <= temp_m_axi_awuser_reg; + end + + if (store_axi_aw_input_to_temp) begin + temp_m_axi_awid_reg <= s_axi_awid; + temp_m_axi_awaddr_reg <= s_axi_awaddr; + temp_m_axi_awlen_reg <= s_axi_awlen; + temp_m_axi_awsize_reg <= s_axi_awsize; + temp_m_axi_awburst_reg <= s_axi_awburst; + temp_m_axi_awlock_reg <= s_axi_awlock; + temp_m_axi_awcache_reg <= s_axi_awcache; + temp_m_axi_awprot_reg <= s_axi_awprot; + temp_m_axi_awqos_reg <= s_axi_awqos; + temp_m_axi_awregion_reg <= s_axi_awregion; + temp_m_axi_awuser_reg <= s_axi_awuser; + end +end + +end else if (AW_REG_TYPE == 1) begin +// simple register, inserts bubble cycles + +// datapath registers +reg s_axi_awready_reg = 1'b0; + +reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}}; +reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}; +reg [7:0] m_axi_awlen_reg = 8'd0; +reg [2:0] m_axi_awsize_reg = 3'd0; +reg [1:0] m_axi_awburst_reg = 2'd0; +reg m_axi_awlock_reg = 1'b0; +reg [3:0] m_axi_awcache_reg = 4'd0; +reg [2:0] m_axi_awprot_reg = 3'd0; +reg [3:0] m_axi_awqos_reg = 4'd0; +reg [3:0] m_axi_awregion_reg = 4'd0; +reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}; +reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next; + +// datapath control +reg store_axi_aw_input_to_output; + +assign s_axi_awready = s_axi_awready_reg; + +assign m_axi_awid = m_axi_awid_reg; +assign m_axi_awaddr = m_axi_awaddr_reg; +assign m_axi_awlen = m_axi_awlen_reg; +assign m_axi_awsize = m_axi_awsize_reg; +assign m_axi_awburst = m_axi_awburst_reg; +assign m_axi_awlock = m_axi_awlock_reg; +assign m_axi_awcache = m_axi_awcache_reg; +assign m_axi_awprot = m_axi_awprot_reg; +assign m_axi_awqos = m_axi_awqos_reg; +assign m_axi_awregion = m_axi_awregion_reg; +assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}}; +assign m_axi_awvalid = m_axi_awvalid_reg; + +// enable ready input next cycle if output buffer will be empty +wire s_axi_awready_eawly = !m_axi_awvalid_next; + +always @* begin + // transfer sink ready state to source + m_axi_awvalid_next = m_axi_awvalid_reg; + + store_axi_aw_input_to_output = 1'b0; + + if (s_axi_awready_reg) begin + m_axi_awvalid_next = s_axi_awvalid; + store_axi_aw_input_to_output = 1'b1; + end else if (m_axi_awready) begin + m_axi_awvalid_next = 1'b0; + end +end + +always @(posedge clk) begin + if (rst) begin + s_axi_awready_reg <= 1'b0; + m_axi_awvalid_reg <= 1'b0; + end else begin + s_axi_awready_reg <= s_axi_awready_eawly; + m_axi_awvalid_reg <= m_axi_awvalid_next; + end + + // datapath + if (store_axi_aw_input_to_output) begin + m_axi_awid_reg <= s_axi_awid; + m_axi_awaddr_reg <= s_axi_awaddr; + m_axi_awlen_reg <= s_axi_awlen; + m_axi_awsize_reg <= s_axi_awsize; + m_axi_awburst_reg <= s_axi_awburst; + m_axi_awlock_reg <= s_axi_awlock; + m_axi_awcache_reg <= s_axi_awcache; + m_axi_awprot_reg <= s_axi_awprot; + m_axi_awqos_reg <= s_axi_awqos; + m_axi_awregion_reg <= s_axi_awregion; + m_axi_awuser_reg <= s_axi_awuser; + end +end + +end else begin + + // bypass AW channel + assign m_axi_awid = s_axi_awid; + assign m_axi_awaddr = s_axi_awaddr; + assign m_axi_awlen = s_axi_awlen; + assign m_axi_awsize = s_axi_awsize; + assign m_axi_awburst = s_axi_awburst; + assign m_axi_awlock = s_axi_awlock; + assign m_axi_awcache = s_axi_awcache; + assign m_axi_awprot = s_axi_awprot; + assign m_axi_awqos = s_axi_awqos; + assign m_axi_awregion = s_axi_awregion; + assign m_axi_awuser = AWUSER_ENABLE ? s_axi_awuser : {AWUSER_WIDTH{1'b0}}; + assign m_axi_awvalid = s_axi_awvalid; + assign s_axi_awready = m_axi_awready; + +end + +// W channel + +if (W_REG_TYPE > 1) begin +// skid buffer, no bubble cycles + +// datapath registers +reg s_axi_wready_reg = 1'b0; + +reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}}; +reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}}; +reg m_axi_wlast_reg = 1'b0; +reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = {WUSER_WIDTH{1'b0}}; +reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next; + +reg [DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {DATA_WIDTH{1'b0}}; +reg [STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {STRB_WIDTH{1'b0}}; +reg temp_m_axi_wlast_reg = 1'b0; +reg [WUSER_WIDTH-1:0] temp_m_axi_wuser_reg = {WUSER_WIDTH{1'b0}}; +reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next; + +// datapath control +reg store_axi_w_input_to_output; +reg store_axi_w_input_to_temp; +reg store_axi_w_temp_to_output; + +assign s_axi_wready = s_axi_wready_reg; + +assign m_axi_wdata = m_axi_wdata_reg; +assign m_axi_wstrb = m_axi_wstrb_reg; +assign m_axi_wlast = m_axi_wlast_reg; +assign m_axi_wuser = WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}}; +assign m_axi_wvalid = m_axi_wvalid_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +wire s_axi_wready_early = m_axi_wready | (~temp_m_axi_wvalid_reg & (~m_axi_wvalid_reg | ~s_axi_wvalid)); + +always @* begin + // transfer sink ready state to source + m_axi_wvalid_next = m_axi_wvalid_reg; + temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg; + + store_axi_w_input_to_output = 1'b0; + store_axi_w_input_to_temp = 1'b0; + store_axi_w_temp_to_output = 1'b0; + + if (s_axi_wready_reg) begin + // input is ready + if (m_axi_wready | ~m_axi_wvalid_reg) begin + // output is ready or currently not valid, transfer data to output + m_axi_wvalid_next = s_axi_wvalid; + store_axi_w_input_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_m_axi_wvalid_next = s_axi_wvalid; + store_axi_w_input_to_temp = 1'b1; + end + end else if (m_axi_wready) begin + // input is not ready, but output is ready + m_axi_wvalid_next = temp_m_axi_wvalid_reg; + temp_m_axi_wvalid_next = 1'b0; + store_axi_w_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + s_axi_wready_reg <= 1'b0; + m_axi_wvalid_reg <= 1'b0; + temp_m_axi_wvalid_reg <= 1'b0; + end else begin + s_axi_wready_reg <= s_axi_wready_early; + m_axi_wvalid_reg <= m_axi_wvalid_next; + temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next; + end + + // datapath + if (store_axi_w_input_to_output) begin + m_axi_wdata_reg <= s_axi_wdata; + m_axi_wstrb_reg <= s_axi_wstrb; + m_axi_wlast_reg <= s_axi_wlast; + m_axi_wuser_reg <= s_axi_wuser; + end else if (store_axi_w_temp_to_output) begin + m_axi_wdata_reg <= temp_m_axi_wdata_reg; + m_axi_wstrb_reg <= temp_m_axi_wstrb_reg; + m_axi_wlast_reg <= temp_m_axi_wlast_reg; + m_axi_wuser_reg <= temp_m_axi_wuser_reg; + end + + if (store_axi_w_input_to_temp) begin + temp_m_axi_wdata_reg <= s_axi_wdata; + temp_m_axi_wstrb_reg <= s_axi_wstrb; + temp_m_axi_wlast_reg <= s_axi_wlast; + temp_m_axi_wuser_reg <= s_axi_wuser; + end +end + +end else if (W_REG_TYPE == 1) begin +// simple register, inserts bubble cycles + +// datapath registers +reg s_axi_wready_reg = 1'b0; + +reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}}; +reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}}; +reg m_axi_wlast_reg = 1'b0; +reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = {WUSER_WIDTH{1'b0}}; +reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next; + +// datapath control +reg store_axi_w_input_to_output; + +assign s_axi_wready = s_axi_wready_reg; + +assign m_axi_wdata = m_axi_wdata_reg; +assign m_axi_wstrb = m_axi_wstrb_reg; +assign m_axi_wlast = m_axi_wlast_reg; +assign m_axi_wuser = WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}}; +assign m_axi_wvalid = m_axi_wvalid_reg; + +// enable ready input next cycle if output buffer will be empty +wire s_axi_wready_ewly = !m_axi_wvalid_next; + +always @* begin + // transfer sink ready state to source + m_axi_wvalid_next = m_axi_wvalid_reg; + + store_axi_w_input_to_output = 1'b0; + + if (s_axi_wready_reg) begin + m_axi_wvalid_next = s_axi_wvalid; + store_axi_w_input_to_output = 1'b1; + end else if (m_axi_wready) begin + m_axi_wvalid_next = 1'b0; + end +end + +always @(posedge clk) begin + if (rst) begin + s_axi_wready_reg <= 1'b0; + m_axi_wvalid_reg <= 1'b0; + end else begin + s_axi_wready_reg <= s_axi_wready_ewly; + m_axi_wvalid_reg <= m_axi_wvalid_next; + end + + // datapath + if (store_axi_w_input_to_output) begin + m_axi_wdata_reg <= s_axi_wdata; + m_axi_wstrb_reg <= s_axi_wstrb; + m_axi_wlast_reg <= s_axi_wlast; + m_axi_wuser_reg <= s_axi_wuser; + end +end + +end else begin + + // bypass W channel + assign m_axi_wdata = s_axi_wdata; + assign m_axi_wstrb = s_axi_wstrb; + assign m_axi_wlast = s_axi_wlast; + assign m_axi_wuser = WUSER_ENABLE ? s_axi_wuser : {WUSER_WIDTH{1'b0}}; + assign m_axi_wvalid = s_axi_wvalid; + assign s_axi_wready = m_axi_wready; + +end + +// B channel + +if (B_REG_TYPE > 1) begin +// skid buffer, no bubble cycles + +// datapath registers +reg m_axi_bready_reg = 1'b0; + +reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}; +reg [1:0] s_axi_bresp_reg = 2'b0; +reg [BUSER_WIDTH-1:0] s_axi_buser_reg = {BUSER_WIDTH{1'b0}}; +reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; + +reg [ID_WIDTH-1:0] temp_s_axi_bid_reg = {ID_WIDTH{1'b0}}; +reg [1:0] temp_s_axi_bresp_reg = 2'b0; +reg [BUSER_WIDTH-1:0] temp_s_axi_buser_reg = {BUSER_WIDTH{1'b0}}; +reg temp_s_axi_bvalid_reg = 1'b0, temp_s_axi_bvalid_next; + +// datapath control +reg store_axi_b_input_to_output; +reg store_axi_b_input_to_temp; +reg store_axi_b_temp_to_output; + +assign m_axi_bready = m_axi_bready_reg; + +assign s_axi_bid = s_axi_bid_reg; +assign s_axi_bresp = s_axi_bresp_reg; +assign s_axi_buser = BUSER_ENABLE ? s_axi_buser_reg : {BUSER_WIDTH{1'b0}}; +assign s_axi_bvalid = s_axi_bvalid_reg; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +wire m_axi_bready_early = s_axi_bready | (~temp_s_axi_bvalid_reg & (~s_axi_bvalid_reg | ~m_axi_bvalid)); + +always @* begin + // transfer sink ready state to source + s_axi_bvalid_next = s_axi_bvalid_reg; + temp_s_axi_bvalid_next = temp_s_axi_bvalid_reg; + + store_axi_b_input_to_output = 1'b0; + store_axi_b_input_to_temp = 1'b0; + store_axi_b_temp_to_output = 1'b0; + + if (m_axi_bready_reg) begin + // input is ready + if (s_axi_bready | ~s_axi_bvalid_reg) begin + // output is ready or currently not valid, transfer data to output + s_axi_bvalid_next = m_axi_bvalid; + store_axi_b_input_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_s_axi_bvalid_next = m_axi_bvalid; + store_axi_b_input_to_temp = 1'b1; + end + end else if (s_axi_bready) begin + // input is not ready, but output is ready + s_axi_bvalid_next = temp_s_axi_bvalid_reg; + temp_s_axi_bvalid_next = 1'b0; + store_axi_b_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + m_axi_bready_reg <= 1'b0; + s_axi_bvalid_reg <= 1'b0; + temp_s_axi_bvalid_reg <= 1'b0; + end else begin + m_axi_bready_reg <= m_axi_bready_early; + s_axi_bvalid_reg <= s_axi_bvalid_next; + temp_s_axi_bvalid_reg <= temp_s_axi_bvalid_next; + end + + // datapath + if (store_axi_b_input_to_output) begin + s_axi_bid_reg <= m_axi_bid; + s_axi_bresp_reg <= m_axi_bresp; + s_axi_buser_reg <= m_axi_buser; + end else if (store_axi_b_temp_to_output) begin + s_axi_bid_reg <= temp_s_axi_bid_reg; + s_axi_bresp_reg <= temp_s_axi_bresp_reg; + s_axi_buser_reg <= temp_s_axi_buser_reg; + end + + if (store_axi_b_input_to_temp) begin + temp_s_axi_bid_reg <= m_axi_bid; + temp_s_axi_bresp_reg <= m_axi_bresp; + temp_s_axi_buser_reg <= m_axi_buser; + end +end + +end else if (B_REG_TYPE == 1) begin +// simple register, inserts bubble cycles + +// datapath registers +reg m_axi_bready_reg = 1'b0; + +reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}; +reg [1:0] s_axi_bresp_reg = 2'b0; +reg [BUSER_WIDTH-1:0] s_axi_buser_reg = {BUSER_WIDTH{1'b0}}; +reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; + +// datapath control +reg store_axi_b_input_to_output; + +assign m_axi_bready = m_axi_bready_reg; + +assign s_axi_bid = s_axi_bid_reg; +assign s_axi_bresp = s_axi_bresp_reg; +assign s_axi_buser = BUSER_ENABLE ? s_axi_buser_reg : {BUSER_WIDTH{1'b0}}; +assign s_axi_bvalid = s_axi_bvalid_reg; + +// enable ready input next cycle if output buffer will be empty +wire m_axi_bready_early = !s_axi_bvalid_next; + +always @* begin + // transfer sink ready state to source + s_axi_bvalid_next = s_axi_bvalid_reg; + + store_axi_b_input_to_output = 1'b0; + + if (m_axi_bready_reg) begin + s_axi_bvalid_next = m_axi_bvalid; + store_axi_b_input_to_output = 1'b1; + end else if (s_axi_bready) begin + s_axi_bvalid_next = 1'b0; + end +end + +always @(posedge clk) begin + if (rst) begin + m_axi_bready_reg <= 1'b0; + s_axi_bvalid_reg <= 1'b0; + end else begin + m_axi_bready_reg <= m_axi_bready_early; + s_axi_bvalid_reg <= s_axi_bvalid_next; + end + + // datapath + if (store_axi_b_input_to_output) begin + s_axi_bid_reg <= m_axi_bid; + s_axi_bresp_reg <= m_axi_bresp; + s_axi_buser_reg <= m_axi_buser; + end +end + +end else begin + + // bypass B channel + assign s_axi_bid = m_axi_bid; + assign s_axi_bresp = m_axi_bresp; + assign s_axi_buser = BUSER_ENABLE ? m_axi_buser : {BUSER_WIDTH{1'b0}}; + assign s_axi_bvalid = m_axi_bvalid; + assign m_axi_bready = s_axi_bready; + +end + +endgenerate + +endmodule + +`resetall diff --git a/sim/model/div_signed.sv b/sim/model/div_signed.sv new file mode 100644 index 0000000..7ac7927 --- /dev/null +++ b/sim/model/div_signed.sv @@ -0,0 +1,24 @@ +`include "defines.svh" + +module div_signed( + input logic aclk, + input logic s_axis_dividend_tvalid, + input logic [31:0] s_axis_dividend_tdata, + input logic s_axis_divisor_tvalid, + input logic [31:0] s_axis_divisor_tdata, + output logic m_axis_dout_tvalid, + output logic [63:0] m_axis_dout_tdata +); + + always_ff @(posedge aclk) + if (s_axis_dividend_tvalid & s_axis_divisor_tvalid) begin + m_axis_dout_tvalid <= 1'b1; + m_axis_dout_tdata[63:32] <= $signed(s_axis_dividend_tdata) / $signed(s_axis_divisor_tdata); + m_axis_dout_tdata[31: 0] <= $signed(s_axis_dividend_tdata) % $signed(s_axis_divisor_tdata); + end else begin + m_axis_dout_tvalid <= 0; + m_axis_dout_tdata <= 0; + end + + +endmodule diff --git a/sim/model/div_unsigned.sv b/sim/model/div_unsigned.sv new file mode 100644 index 0000000..f7d2731 --- /dev/null +++ b/sim/model/div_unsigned.sv @@ -0,0 +1,24 @@ +`include "defines.svh" + +module div_unsigned( + input logic aclk, + input logic s_axis_dividend_tvalid, + input logic [31:0] s_axis_dividend_tdata, + input logic s_axis_divisor_tvalid, + input logic [31:0] s_axis_divisor_tdata, + output logic m_axis_dout_tvalid, + output logic [63:0] m_axis_dout_tdata +); + + always_ff @(posedge aclk) + if (s_axis_dividend_tvalid & s_axis_divisor_tvalid) begin + m_axis_dout_tvalid <= 1'b1; + m_axis_dout_tdata[63:32] <= $unsigned(s_axis_dividend_tdata) / $unsigned(s_axis_divisor_tdata); + m_axis_dout_tdata[31: 0] <= $unsigned(s_axis_dividend_tdata) % $unsigned(s_axis_divisor_tdata); + end else begin + m_axis_dout_tvalid <= 0; + m_axis_dout_tdata <= 0; + end + + +endmodule diff --git a/sim/model/mul_signed.sv b/sim/model/mul_signed.sv new file mode 100644 index 0000000..135703e --- /dev/null +++ b/sim/model/mul_signed.sv @@ -0,0 +1,14 @@ +`include "defines.svh" + +module mul_signed( + input logic CLK, + input logic [31:0] A, + input logic [31:0] B, + output logic [63:0] P +); + + always_ff @(posedge CLK) + P <= $signed(A) * $signed(B); + + +endmodule diff --git a/sim/model/mul_unsigned.sv b/sim/model/mul_unsigned.sv new file mode 100644 index 0000000..6bc3082 --- /dev/null +++ b/sim/model/mul_unsigned.sv @@ -0,0 +1,14 @@ +`include "defines.svh" + +module mul_unsigned( + input logic CLK, + input logic [31:0] A, + input logic [31:0] B, + output logic [63:0] P +); + + always_ff @(posedge CLK) + P <= $unsigned(A) * $unsigned(B); + + +endmodule diff --git a/sim/model/priority_encoder.v b/sim/model/priority_encoder.v new file mode 100644 index 0000000..29bad18 --- /dev/null +++ b/sim/model/priority_encoder.v @@ -0,0 +1,87 @@ +/* +Copyright (c) 2014-2021 Alex Forencich +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Language: Verilog 2001 + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * Priority encoder module + */ +module priority_encoder # +( + parameter WIDTH = 4, + // LSB priority selection + parameter LSB_HIGH_PRIORITY = 0 +) +( + input wire [WIDTH-1:0] input_unencoded, + output wire output_valid, + output wire [$clog2(WIDTH)-1:0] output_encoded, + output wire [WIDTH-1:0] output_unencoded +); + +parameter LEVELS = WIDTH > 2 ? $clog2(WIDTH) : 1; +parameter W = 2**LEVELS; + +// pad input to even power of two +wire [W-1:0] input_padded = {{W-WIDTH{1'b0}}, input_unencoded}; + +wire [W/2-1:0] stage_valid[LEVELS-1:0]; +wire [W/2-1:0] stage_enc[LEVELS-1:0]; + +generate + genvar l, n; + + // process input bits; generate valid bit and encoded bit for each pair + for (n = 0; n < W/2; n = n + 1) begin : loop_in + assign stage_valid[0][n] = |input_padded[n*2+1:n*2]; + if (LSB_HIGH_PRIORITY) begin + // bit 0 is highest priority + assign stage_enc[0][n] = !input_padded[n*2+0]; + end else begin + // bit 0 is lowest priority + assign stage_enc[0][n] = input_padded[n*2+1]; + end + end + + // compress down to single valid bit and encoded bus + for (l = 1; l < LEVELS; l = l + 1) begin : loop_levels + for (n = 0; n < W/(2*2**l); n = n + 1) begin : loop_compress + assign stage_valid[l][n] = |stage_valid[l-1][n*2+1:n*2]; + if (LSB_HIGH_PRIORITY) begin + // bit 0 is highest priority + assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+0] ? {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]} : {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]}; + end else begin + // bit 0 is lowest priority + assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+1] ? {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]} : {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]}; + end + end + end +endgenerate + +assign output_valid = stage_valid[LEVELS-1]; +assign output_encoded = stage_enc[LEVELS-1]; +assign output_unencoded = 1 << output_encoded; + +endmodule + +`resetall diff --git a/sim/sim_main.cpp b/sim/sim_main.cpp new file mode 100644 index 0000000..40d88ec --- /dev/null +++ b/sim/sim_main.cpp @@ -0,0 +1,45 @@ +#include + +#include "Vtestbench_top.h" + +vluint64_t main_time = 0; +double sc_time_stamp() { + return main_time; +} + +int main(int argc, char **argv, char **env) { + Verilated::debug(0); + Verilated::randReset(2); + Verilated::traceEverOn(true); + Verilated::commandArgs(argc, argv); + Verilated::mkdir("logs"); + + const int reset_time = 10; + + Vtestbench_top *top = new Vtestbench_top; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper + + top->clk = 0; + while (!Verilated::gotFinish()) { + ++main_time; + top->clk = !top->clk; + top->resetn = (main_time < reset_time) ? 1 : 0; + if (main_time < reset_time) { + // Zero coverage if still early in reset, otherwise toggles there may + // falsely indicate a signal is covered + VerilatedCov::zero(); + } + top->eval(); + } + + top->final(); + + // Coverage analysis (since test passed) +#if VM_COVERAGE + Verilated::mkdir("logs"); + VerilatedCov::write("logs/coverage.dat"); +#endif + + delete top; + top = NULL; + exit(0); +} diff --git a/src/CP0/CP0.sv b/src/CP0/CP0.sv index 01798fc..23f929d 100644 --- a/src/CP0/CP0.sv +++ b/src/CP0/CP0.sv @@ -21,22 +21,10 @@ module CP0 ( output logic interrupt, // MMU - input logic tlbr, - input logic tlbp, - output logic [2:0] K0, - output logic in_kernel, - output Random_t Random, - output Index_t Index, - output EntryHi_t EntryHi, - output EntryLo_t EntryLo1, - output EntryLo_t EntryLo0, - input EntryHi_t tlb_EntryHi, - input EntryLo_t tlb_EntryLo1, - input EntryLo_t tlb_EntryLo0, - input Index_t tlb_Index + CP0_i.cp0 c0 ); - CP0_REGS_t rf_cp0; + CP0_REGS_t rf_cp0/*verilator split_var*/; logic count_lo; // int comb logic @@ -168,7 +156,7 @@ module CP0 ( 9: rf_cp0.Count = wdata; 8: rf_cp0.BadVAddr = wdata; // 7: rf_cp0.HWREna = wdata; - 6: begin + 6: begin rf_cp0.Wired.Wired = wdata[2:0]; rf_cp0.Random.Random = 3'b111; end @@ -197,25 +185,25 @@ module CP0 ( endcase end - if (tlbr) begin - rf_cp0.EntryHi.VPN2 = tlb_EntryHi.VPN2; - rf_cp0.EntryHi.ASID = tlb_EntryHi.ASID; + if (c0.cpu_tlbr) begin + rf_cp0.EntryHi.VPN2 = c0.tlb_EntryHi.VPN2; + rf_cp0.EntryHi.ASID = c0.tlb_EntryHi.ASID; // rf_cp0.PageMask.Mask = tlb_PageMask.Mask; - rf_cp0.EntryLo0.PFN = tlb_EntryLo0.PFN; - rf_cp0.EntryLo0.C = tlb_EntryLo0.C; - rf_cp0.EntryLo0.D = tlb_EntryLo0.D; - rf_cp0.EntryLo0.V = tlb_EntryLo0.V; - rf_cp0.EntryLo0.G = tlb_EntryLo0.G; - rf_cp0.EntryLo1.PFN = tlb_EntryLo1.PFN; - rf_cp0.EntryLo1.C = tlb_EntryLo1.C; - rf_cp0.EntryLo1.D = tlb_EntryLo1.D; - rf_cp0.EntryLo1.V = tlb_EntryLo1.V; - rf_cp0.EntryLo1.G = tlb_EntryLo1.G; + rf_cp0.EntryLo0.PFN = c0.tlb_EntryLo0.PFN; + rf_cp0.EntryLo0.C = c0.tlb_EntryLo0.C; + rf_cp0.EntryLo0.D = c0.tlb_EntryLo0.D; + rf_cp0.EntryLo0.V = c0.tlb_EntryLo0.V; + rf_cp0.EntryLo0.G = c0.tlb_EntryLo0.G; + rf_cp0.EntryLo1.PFN = c0.tlb_EntryLo1.PFN; + rf_cp0.EntryLo1.C = c0.tlb_EntryLo1.C; + rf_cp0.EntryLo1.D = c0.tlb_EntryLo1.D; + rf_cp0.EntryLo1.V = c0.tlb_EntryLo1.V; + rf_cp0.EntryLo1.G = c0.tlb_EntryLo1.G; end - if (tlbp) begin - rf_cp0.Index.P = tlb_Index.P; - rf_cp0.Index.Index = tlb_Index.Index; + if (c0.cpu_c0_tlbp) begin + rf_cp0.Index.P = c0.tlb_Index.P; + rf_cp0.Index.Index = c0.tlb_Index.Index; end if (rf_cp0.Count == rf_cp0.Compare) rf_cp0.Cause.TI = 1; @@ -289,14 +277,14 @@ module CP0 ( assign Bev = rf_cp0.Status.Bev; assign EBase = rf_cp0.EBase[31:12]; - assign K0 = rf_cp0.Config.K0; - assign Random = rf_cp0.Random; - assign Index = rf_cp0.Index; - assign EntryHi = rf_cp0.EntryHi; + assign c0.cp0_K0 = rf_cp0.Config.K0; + assign c0.cp0_Random = rf_cp0.Random; + assign c0.cp0_Index = rf_cp0.Index; + assign c0.cp0_EntryHi = rf_cp0.EntryHi; // assign PageMask = rf_cp0.PageMask; - assign EntryLo1 = rf_cp0.EntryLo1; - assign EntryLo0 = rf_cp0.EntryLo0; + assign c0.cp0_EntryLo1 = rf_cp0.EntryLo1; + assign c0.cp0_EntryLo0 = rf_cp0.EntryLo0; - assign in_kernel = ~rf_cp0.Status.UM | rf_cp0.Status.EXL; // currently no ERL + assign c0.cp0_in_kernel = ~rf_cp0.Status.UM | rf_cp0.Status.EXL; // currently no ERL endmodule diff --git a/src/Core/ALU.sv b/src/Core/ALU.sv index ff673d0..d803ee9 100644 --- a/src/Core/ALU.sv +++ b/src/Core/ALU.sv @@ -1,35 +1,34 @@ `include "defines.svh" module ALU( - input word_t a, b, - input ALUCtrl_t aluctrl, - output word_t aluout, - output logic overflow); + input word_t a, b, + input ALUCtrl_t aluctrl, + output word_t aluout, + output logic overflow +); - wire logic alt = aluctrl.alt; + wire logic alt = aluctrl.alt; - wire logic [4:0] sa = a[4:0]; - wire logic ex = alt & b[31]; - wire word_t sl = b << sa; - /* verilator lint_off WIDTH */ - wire word_t sr = {{31{ex}}, b} >> sa; - /* verilator lint_on WIDTH */ - - wire word_t b2 = alt ? ~b : b; - wire word_t sum; - wire logic lt, ltu; - - /* verilator lint_off WIDTH */ - assign {lt, ltu, sum} = {a[31], 1'b0, a} + {b2[31], 1'b1, b2} + alt; // alt for cin(CARRY4) at synthesis - /* verilator lint_on WIDTH */ - assign aluout = (aluctrl.f_sl ? sl : 32'b0) - | (aluctrl.f_sr ? sr : 32'b0) - | (aluctrl.f_add ? sum : 32'b0) - | (aluctrl.f_and ? a & b : 32'b0) - | (aluctrl.f_or ? alt ? ~(a | b) : a | b : 32'b0) - | (aluctrl.f_xor ? a ^ b : 32'b0) - | (aluctrl.f_slt ? {31'b0, lt } : 32'b0) - | (aluctrl.f_sltu ? {31'b0, ltu} : 32'b0) - | (aluctrl.f_mova ? a : 32'b0); - assign overflow = lt ^ sum[31]; + wire logic [4:0] sa = a[4:0]; + wire logic ex = alt & b[31]; + wire word_t sl = b << sa; + /* verilator lint_off WIDTH */ + wire word_t sr = {{31{ex}}, b} >> sa; + /* verilator lint_on WIDTH */ + wire word_t b2 = alt ? ~b : b; + wire word_t sum; + wire logic lt, ltu; + /* verilator lint_off WIDTH */ + assign {lt, ltu, sum} = {a[31], 1'b0, a} + {b2[31], 1'b1, b2} + alt; // alt for cin(CARRY4) at synthesis + /* verilator lint_on WIDTH */ + assign aluout = (aluctrl.f_sl ? sl : 32'b0) + | (aluctrl.f_sr ? sr : 32'b0) + | (aluctrl.f_add ? sum : 32'b0) + | (aluctrl.f_and ? a & b : 32'b0) + | (aluctrl.f_or ? alt ? ~(a | b) : a | b : 32'b0) + | (aluctrl.f_xor ? a ^ b : 32'b0) + | (aluctrl.f_slt ? {31'b0, lt } : 32'b0) + | (aluctrl.f_sltu ? {31'b0, ltu} : 32'b0) + | (aluctrl.f_mova ? a : 32'b0); + assign overflow = lt ^ sum[31]; endmodule diff --git a/src/Core/Controller.sv b/src/Core/Controller.sv index 2b36f2c..49a6578 100644 --- a/src/Core/Controller.sv +++ b/src/Core/Controller.sv @@ -5,7 +5,7 @@ module Controller ( input logic eq, input logic ltz, input word_t rt, - output Ctrl_t ctrl, + output Ctrl_t ctrl/*verilator split_var*/, output word_t imm, output logic [4:0] sa ); diff --git a/src/Core/Datapath.sv b/src/Core/Datapath.sv index 7049344..ff92386 100644 --- a/src/Core/Datapath.sv +++ b/src/Core/Datapath.sv @@ -10,20 +10,9 @@ module Datapath ( InstFetch_i.cpu fetch, Memory_i.cpu mem, CacheOp_i.cpu cache_op, - input logic iTLBRefill, - input logic iTLBInvalid, - input logic iAddressError, - input logic dTLBRefill, - input logic dTLBInvalid, - input logic dTLBModified, - input logic dAddressError, - output logic tlb_tlbwi, - output logic tlb_tlbwr, - output logic tlb_tlbp, - output logic c0_tlbr, - output logic c0_tlbp, // CP0 + CP0_i.cpu C0, input logic C0_int, output logic [4:0] C0_addr, output logic [2:0] C0_sel, @@ -34,7 +23,6 @@ module Datapath ( input word_t C0_ERETPC, input logic C0_Bev, input logic [19:0] C0_EBase, - input logic C0_kernel, //debug interface output wire [31:0] debug_wb_pc, @@ -52,12 +40,12 @@ module Datapath ( logic rstD, rstM; - PF_t PF; - F_t F; - D_t D; - E_t E; - M_t M; - W_t W; + PF_t PF/*verilator split_var*/; + F_t F/*verilator split_var*/; + D_t D/*verilator split_var*/; + E_t E/*verilator split_var*/; + M_t M/*verilator split_var*/; + W_t W/*verilator split_var*/; // Pre Fetch logic PF_go; @@ -330,7 +318,7 @@ module Datapath ( assign F.en = PF.pc[1:0] != 2'b00 & D_IA_can_dispatch | fetch.req & fetch.addr_ok; - assign F.ExcValid = F.pc[1:0] != 2'b00 | iTLBRefill | iTLBInvalid | iAddressError; + assign F.ExcValid = F.pc[1:0] != 2'b00 | C0.tlb_iTLBRefill | C0.tlb_iTLBInvalid | C0.tlb_iAddressError; //---------------------------------------------------------------------------// // Instr Queue // @@ -342,7 +330,7 @@ module Datapath ( .vinA(fetch.data_ok | F.ExcValid), .inA ({F.pc[2] ? fetch.rdata1 : fetch.rdata0, F.pc, - iTLBRefill, iTLBInvalid, iAddressError}), + C0.tlb_iTLBRefill, C0.tlb_iTLBInvalid, C0.tlb_iAddressError}), .vinB(fetch.data_ok & ~F.pc[2]), .inB ({fetch.rdata1, F.pc[31:3], 3'b100, 3'b00}), @@ -462,7 +450,7 @@ module Datapath ( | D_IA_TLBRefill | D_IA_TLBInvalid | D_IA_AddressError | D.IA.SYSCALL | D.IA.BREAK | D.IA.ERET - | D.IA.PRV & ~C0_kernel); + | D.IA.PRV & ~C0.cp0_in_kernel); assign D.IA_ERET = D_IA_valid & D.IA_pc[1:0] == 2'b00 & ~D_IA_TLBRefill & ~D_IA_TLBInvalid & ~D_IA_AddressError & D_IA_iv & D.IA.ERET; assign D.IA_REFILL = D_IA_valid & D.IB_pc[1:0] == 2'b00 & D_IA_TLBRefill; assign D.IA_ExcCode = D.IA_pc[1:0] != 2'b00 | D_IA_AddressError ? `EXCCODE_ADEL @@ -479,7 +467,7 @@ module Datapath ( | D_IB_AddressError | D.IB.SYSCALL | D.IB.BREAK | D.IB.ERET | D.IB_Delay & D.IB.BJRJ - | D.IB.PRV & ~C0_kernel); + | D.IB.PRV & ~C0.cp0_in_kernel); assign D.IB_ERET = D_IB_valid & D.IB_pc[1:0] == 2'b00 & ~D_IB_TLBRefill & ~D_IB_TLBInvalid & ~D_IB_AddressError & D_IB_iv & D.IB.ERET & ~D.IB_Delay; assign D.IB_REFILL = D_IB_valid & D.IB_pc[1:0] == 2'b00 & D_IB_TLBRefill; // EXCCODE_BP and EXCCODE_SYSCALL -> exc.txt @@ -534,6 +522,15 @@ module Datapath ( | D.IA.WCtrl.RW & D.IB.RT == D.IA.RD & D.IB.MCtrl1.MWR & ~D.IA.DP1 // Not Arith -> LWL/LWR | D.IA.WCtrl.RW & D.IB.RT == D.IA.RD & |D.IB.MCtrl1.ALR & ~D.IA.DP1 + // D.IA -> MOVN/MOVZ + | D.IA.WCtrl.RW & D.IB.RT == D.IA.RD & D.IB.DT + // Arith -> MOVN/MOVZ + | E.I0.WCtrl.RW & D.IB.RT == E.I0.RD & D.IB.DT + | E.I1.WCtrl.RW & D.IB.RT == E.I1.RD & D.IB.DT + // Not Arith -> MOVN/MOVZ + | M.I0.WCtrl.RW & D.IB.RT == M.I0.RD & D.IB.DT & ~M.I0.MCtrl.RS0[2] + // Load -> MOVN/MOVZ + | M.I1.WCtrl.RW & D.IB.RT == M.I1.RD & D.IB.DT & M.I1.MCtrl.MR // CP0 Execution Hazards // Hazards Related to the TLB | D.IA.MCtrl0.C0W & D.IB.MCtrl1.TLBR & D.IA.MCtrl0.C0D == C0_INDEX @@ -787,7 +784,7 @@ module Datapath ( E.en, E.I1.ECtrl ); - ffenrc #(14) E_I1_MCtrl_ff ( + ffenrc #(15) E_I1_MCtrl_ff ( clk, rst | rstM, D.I1.MCtrl, @@ -927,15 +924,15 @@ module Datapath ( E_I1_STRBERROR ); - assign tlb_tlbp = E.I1.MCtrl.TLBP; + assign C0.cpu_tlb_tlbp = E.I1.MCtrl.TLBP; assign mem.req = E.I1.MCtrl.MR & E_I1_goWithoutOF & M.en & ~rstM; assign E_I1_ADDR = E_I1_ForwardS + E.I1.imm; - assign mem.addr = |E.I1.MCtrl.ALR ? {E_I1_ADDR[31:2], 2'b0} - : (cache_op == CNOP | ~cache_op[1]) ? E_I1_ADDR - : cache_op[2] ? {E_I1_ADDR[32-`DC_INDEXL-1:0], `DC_INDEXL'b0} - : {E_I1_ADDR[32-`IC_INDEXL-1:0], `IC_INDEXL'b0}; - assign mem.size = {E.I1.MCtrl.SZ[1], E.I1.MCtrl.SZ[0] & ~E.I1.MCtrl.SZ[1]}; - assign cache_op = E.I1.MCtrl.CACHE_OP; + assign mem.addr = |E.I1.MCtrl.ALR ? {E_I1_ADDR[31:2], 2'b0} + : (~cache_op.op.icache_op & ~cache_op.op.dcache_op | ~cache_op.op.index_or_hit) ? E_I1_ADDR + : cache_op.op.dcache_op ? {E_I1_ADDR[32-`DC_INDEXL-1:0], `DC_INDEXL'b0} + : {E_I1_ADDR[32-`IC_INDEXL-1:0], `IC_INDEXL'b0}; + assign mem.size = {E.I1.MCtrl.SZ[1], E.I1.MCtrl.SZ[0] & ~E.I1.MCtrl.SZ[1]}; + assign cache_op.op = E.I1.MCtrl.CACHE_OP; assign E.en = E_go & M.en; assign E_go = ~mem.req | mem.addr_ok; @@ -1087,7 +1084,7 @@ module Datapath ( M.en, M.I1.ALUOut ); - ffenrc #(14) M_I1_MCtrl_ff ( + ffenrc #(15) M_I1_MCtrl_ff ( clk, rst | rstM, E.I1.MCtrl, @@ -1124,7 +1121,7 @@ module Datapath ( ); myBuffer0 #(4) dExc_buffer ( clk, rst, - {dTLBRefill, dTLBInvalid, dTLBModified, dAddressError}, + {C0.tlb_dTLBRefill, C0.tlb_dTLBInvalid, C0.tlb_dTLBModified, C0.tlb_dAddressError}, dTLBExcValid, {dTLBRefillB, dTLBInvalidB, dTLBModifiedB, dAddressErrorB} ); @@ -1235,10 +1232,10 @@ module Datapath ( assign C0_wdata = M_I0_ForwardT; // M.I1.MEM - assign tlb_tlbwi = M.I1.MCtrl.TLBWI; - assign tlb_tlbwr = M.I1.MCtrl.TLBWR; - assign c0_tlbr = M.I1.MCtrl.TLBR; - assign c0_tlbp = M.I1.MCtrl.TLBP & M.en; + assign C0.cpu_tlbwi = M.I1.MCtrl.TLBWI; + assign C0.cpu_tlbwr = M.I1.MCtrl.TLBWR; + assign C0.cpu_tlbr = M.I1.MCtrl.TLBR; + assign C0.cpu_c0_tlbp = M.I1.MCtrl.TLBP & M.en; assign mem.wr = M.I1.MCtrl.MWR; memoutput M_I1_memoutput ( .addr (M.I1.ALUOut[1:0]), diff --git a/src/Gadgets/addr_virt_to_phy.sv b/src/Gadgets/addr_virt_to_phy.sv index 498733c..8eaa681 100644 --- a/src/Gadgets/addr_virt_to_phy.sv +++ b/src/Gadgets/addr_virt_to_phy.sv @@ -1,4 +1,5 @@ module addr_virt_to_phy ( + input logic [ 2:0] K0, input word_t virt_addr, input logic [19:0] tlb_addr, input logic tlb_hit, diff --git a/src/Gadgets/bram.sv b/src/Gadgets/bram.sv index 9289768..8f3855a 100644 --- a/src/Gadgets/bram.sv +++ b/src/Gadgets/bram.sv @@ -14,11 +14,11 @@ module bram #( for(genvar i = 0; i < DATA_DEPTH; i++) initial ram[i] = 0; - + always_ff @(posedge clka) begin if (~rst) begin if(wea) ram[addra] <= dina; douta <= ~wea ? ram[addra] : dina; end end -endmodule \ No newline at end of file +endmodule diff --git a/src/MU/AXI.sv b/src/MU/AXI.sv index 3b16ca9..ad703d8 100644 --- a/src/MU/AXI.sv +++ b/src/MU/AXI.sv @@ -1,48 +1,48 @@ module AXI ( - output wire [ 3:0] arid, - output wire [31:0] araddr, - output wire [ 3:0] arlen, - output wire [ 2:0] arsize, - output wire [ 1:0] arburst, - output wire [ 1:0] arlock, - output wire [ 3:0] arcache, - output wire [ 2:0] arprot, - output wire arvalid, - input wire arready, + output wire logic [ 3:0] arid, + output wire logic [31:0] araddr, + output wire logic [ 3:0] arlen, + output wire logic [ 2:0] arsize, + output wire logic [ 1:0] arburst, + output wire logic [ 1:0] arlock, + output wire logic [ 3:0] arcache, + output wire logic [ 2:0] arprot, + output wire logic arvalid, + input wire logic arready, - input wire [ 3:0] rid, - input wire [31:0] rdata, - input wire [ 1:0] rresp, - input wire rlast, - input wire rvalid, - output wire rready, + input wire logic [ 3:0] rid, + input wire logic [31:0] rdata, + input wire logic [ 1:0] rresp, + input wire logic rlast, + input wire logic rvalid, + output wire logic rready, - output wire [ 3:0] awid, - output wire [31:0] awaddr, - output wire [ 3:0] awlen, - output wire [ 2:0] awsize, - output wire [ 1:0] awburst, - output wire [ 1:0] awlock, - output wire [ 3:0] awcache, - output wire [ 2:0] awprot, - output wire awvalid, - input wire awready, + output wire logic [ 3:0] awid, + output wire logic [31:0] awaddr, + output wire logic [ 3:0] awlen, + output wire logic [ 2:0] awsize, + output wire logic [ 1:0] awburst, + output wire logic [ 1:0] awlock, + output wire logic [ 3:0] awcache, + output wire logic [ 2:0] awprot, + output wire logic awvalid, + input wire logic awready, - output wire [ 3:0] wid, - output wire [31:0] wdata, - output wire [ 3:0] wstrb, - output wire wlast, - output wire wvalid, - input wire wready, + output wire logic [ 3:0] wid, + output wire logic [31:0] wdata, + output wire logic [ 3:0] wstrb, + output wire logic wlast, + output wire logic wvalid, + input wire logic wready, - input wire [3:0] bid, - input wire [1:0] bresp, - input wire bvalid, - output wire bready, + input wire logic [3:0] bid, + input wire logic [1:0] bresp, + input wire logic bvalid, + output wire logic bready, - AXIRead_i.axi inst, - AXIRead_i.axi rdata, - AXIWrite_i.axi wdata + AXIRead_i.axi axi_inst, + AXIRead_i.axi axi_rdata, + AXIWrite_i.axi axi_wdata ); // ============================== @@ -50,19 +50,19 @@ module AXI ( // ============================== always_comb begin - inst.rdata = rdata; - rdata.rdata = rdata; + axi_inst.rdata = rdata; + axi_rdata.rdata = rdata; if (rid == 0) begin - inst.rvalid = rvalid; - inst.data_ok = rlast; - rdata.rvalid = 1'b0; - rdata.data_ok = 1'b0; + axi_inst.rvalid = rvalid; + axi_inst.data_ok = rlast; + axi_rdata.rvalid = 1'b0; + axi_rdata.data_ok = 1'b0; end else begin - rdata.rvalid = rvalid; - rdata.data_ok = rlast; - inst.rvalid = 1'b0; - inst.data_ok = 1'b0; + axi_rdata.rvalid = rvalid; + axi_rdata.data_ok = rlast; + axi_inst.rvalid = 1'b0; + axi_inst.data_ok = 1'b0; end end @@ -79,22 +79,22 @@ module AXI ( // Burst arburst = 2'b10; // Wrap - arvalid = rdata.req | inst.req; - rdata.addr_ok = arready; - if (rdata.req) begin + arvalid = axi_rdata.req | axi_inst.req; + axi_rdata.addr_ok = arready; + if (axi_rdata.req) begin arid = 4'b0001; arprot = 3'b001; - araddr = rdata.addr; - arlen = rdata.len; - arsize = rdata.size; - inst.addr_ok = 1'b0; + araddr = axi_rdata.addr; + arlen = axi_rdata.len; + arsize = axi_rdata.size; + axi_inst.addr_ok = 1'b0; end else begin arid = 4'b0000; arprot = 3'b101; - araddr = inst.addr; - arlen = inst.len; - arsize = inst.size; - inst.addr_ok = arready; + araddr = axi_inst.addr; + arlen = axi_inst.len; + arsize = axi_inst.size; + axi_inst.addr_ok = arready; end end @@ -103,15 +103,15 @@ module AXI ( // ======= Write Request ======== // ============================== - assign wdata.data_ok = bvalid; - assign wdata.wready = wready; + assign axi_wdata.data_ok = bvalid; + assign axi_wdata.wready = wready; always_comb begin wid = 4'b1; - wdata = wdata.wdata; - wstrb = wdata.wstrb; - wlast = wdata.wlast; - wvalid = wdata.wvalid; + wdata = axi_wdata.wdata; + wstrb = axi_wdata.wstrb; + wlast = axi_wdata.wlast; + wvalid = axi_wdata.wvalid; end always_comb begin @@ -126,11 +126,11 @@ module AXI ( awid = 4'b1; awprot = 3'b001; - awvalid = wdata.req; - awaddr = wdata.addr; - awlen = wdata.len; - awsize = wdata.size; - wdata.addr_ok = awready; + awvalid = axi_wdata.req; + awaddr = axi_wdata.addr; + awlen = axi_wdata.len; + awsize = axi_wdata.size; + axi_wdata.addr_ok = awready; end diff --git a/src/MU/AXIReader.sv b/src/MU/AXIReader.sv new file mode 100644 index 0000000..7ea15ee --- /dev/null +++ b/src/MU/AXIReader.sv @@ -0,0 +1,101 @@ +`include "defines.svh" + +module AXIReader #(parameter DATA_LEN = 8) +( + input clk, + input rst, + + input AXIRead_i axi, + + input call, + input word_t addr, + input [3:0] len, + input [2:0] size, + + output done, + output reg [DATA_LEN-1:0] buffer +); + word_t stored_addr; + logic [3:0] stored_len; + logic [2:0] stored_size; + logic [DATA_LEN-1:0] nxt_buffer; + + ffen #(`XLEN) addr_store (.*, .d(addr), .en(call), .q(stored_addr)); + ffen #(4) len_store (.*, .d(len), .en(call), .q(stored_len)); + ffen #(3) size_store (.*, .d(size), .en(call), .q(stored_size)); + + typedef enum bit [1:0] { IDLE, WAIT_ADDR, DATA } state_t; + state_t cur_state; + state_t nxt_state; + + always_comb begin + nxt_state = cur_state; + nxt_buffer = buffer; + + done = 0; + + axi.req = 0; + axi.addr = call ? addr : stored_addr; + axi.len = call ? len : stored_len; + axi.size = call ? size : stored_size; + + case (cur_state) + IDLE: begin + if (call) begin + // axi control + axi.req = 1'b1; + + // check addr_ok + if (~axi.addr_ok) + nxt_state = WAIT_ADDR; + else + nxt_state = DATA; + end + end + + WAIT_ADDR: begin + // axi control + axi.req = 1'b1; + + // check addr_ok + if (~axi.addr_ok) + nxt_state = WAIT_ADDR; + // check received data + else if (axi.rvalid) begin + nxt_buffer = {axi.rdata, buffer[DATA_LEN-1:`XLEN]}; + if (axi.data_ok) begin + nxt_state = IDLE; + done = 1'b1; + end else + nxt_state = DATA; + end + end + + DATA: begin + if (axi.rvalid) begin + nxt_buffer = {axi.rdata, buffer[DATA_LEN-1:`XLEN]}; + if (axi.data_ok) begin + nxt_state = IDLE; + done = 1'b1; + + // TODO: immediately receive next request + // $assert (done & call); + end else + nxt_state = DATA; + end + end + default: begin end + endcase + end + + always_ff @(posedge clk) begin + if (rst) begin + cur_state <= IDLE; + buffer <= 0; + end else begin + cur_state <= nxt_state; + buffer <= nxt_buffer; + end + end + +endmodule diff --git a/src/MU/AXIWriter.sv b/src/MU/AXIWriter.sv new file mode 100644 index 0000000..9be0206 --- /dev/null +++ b/src/MU/AXIWriter.sv @@ -0,0 +1,126 @@ +`include "defines.svh" + +module AXIWriter #(parameter DATA_LEN = 8) +( + input clk, + input rst, + + input AXIWrite_i axi, + + input call, + input word_t addr, + input [3:0] len, + input [2:0] size, + input [3:0] wstrb, + input [DATA_LEN-1:0] data, + + output done +); + word_t stored_addr; + logic [3:0] stored_len; + logic [2:0] stored_size; + logic [3:0] stored_wstrb; + logic [DATA_LEN-1:0] stored_data; + + ffen #(`XLEN) addr_store (.*, .d(addr), .en(call), .q(stored_addr)); + ffen #(4) len_store (.*, .d(len), .en(call), .q(stored_len)); + ffen #(3) size_store (.*, .d(size), .en(call), .q(stored_size)); + ffen #(4) wstrb_store (.*, .d(wstrb), .en(call), .q(stored_wstrb)); + ffen #(DATA_LEN) data_store (.*, .d(data), .en(call), .q(stored_data)); + + logic shift; + logic [3:0] data_cntr; + logic [DATA_LEN-1:0] data_select; + + ffen #(4) cntr_ff (.*, .d(call ? len : data_cntr - 1) , .en(shift | call), .q(data_cntr)); + assign data_select = call ? data : stored_data; + + typedef enum bit [1:0] { DIDLE, DATA } data_state_t; + typedef enum bit [1:0] { AIDLE, ADDR } addr_state_t; + data_state_t cur_data_state; + data_state_t nxt_data_state; + addr_state_t cur_addr_state; + addr_state_t nxt_addr_state; + + // TODO: check whether it's correct + assign done = axi.data_ok; + + // data + always_comb begin + nxt_data_state = cur_data_state; + + shift = 0; + + axi.wstrb = call ? wstrb : stored_wstrb; + axi.wdata = data_select[data_cntr * 32 +: 32]; + axi.wvalid = 0; + axi.wlast = (call ? len : data_cntr) == 0; + + case (cur_data_state) + DIDLE: begin + if (call) begin + // axi.wstrb + // axi.wdata + axi.wvalid = 1'b1; + // axi.wlast + + if (axi.wready) shift = 1'b1; + if (~axi.wlast | ~axi.wready) + nxt_data_state = DATA; + end + end + + DATA: begin + // axi.wstrb + // axi.wdata + axi.wvalid = 1'b1; + // axi.wlast + + if (axi.wready) shift = 1'b1; + if (axi.wlast & axi.wready) nxt_data_state = DIDLE; + end + + default: begin end + endcase + + end + + // addr + always_comb begin + nxt_addr_state = cur_addr_state; + + axi.req = 0; + + axi.addr = call ? addr : stored_addr; + axi.len = call ? len : stored_len; + axi.size = call ? size : stored_size; + + case (cur_addr_state) + AIDLE: begin + if (call) begin + axi.req = 1'b1; + if (~axi.addr_ok) nxt_addr_state = ADDR; + end + end + + ADDR: begin + axi.req = 1'b1; + if (axi.addr_ok) nxt_addr_state = AIDLE; + end + + default: begin end + endcase + + end + + always_ff @(posedge clk) begin + if (rst) begin + cur_data_state <= DIDLE; + cur_addr_state <= AIDLE; + end else begin + cur_data_state <= nxt_data_state; + cur_addr_state <= nxt_addr_state; + end + end + +endmodule diff --git a/src/MU/DCache.sv b/src/MU/DCache.sv index 54f252c..1d91581 100644 --- a/src/MU/DCache.sv +++ b/src/MU/DCache.sv @@ -11,8 +11,8 @@ module DCache ( // ============ Vars ============ // ============================== - DCTagRAM_t TagRAM0, TagRAM1, TagRAM2, TagRAM3; - DCDataRAM_t DataRAM0, DataRAM1, DataRAM2, DataRAM3; + DCTagRAM_t TagRAM0/*verilator split_var*/, TagRAM1/*verilator split_var*/, TagRAM2/*verilator split_var*/, TagRAM3/*verilator split_var*/; + DCDataRAM_t DataRAM0/*verilator split_var*/, DataRAM1/*verilator split_var*/, DataRAM2/*verilator split_var*/, DataRAM3/*verilator split_var*/; (* RAM_STYLE="block" *) logic [3:0] LRU[128]; @@ -54,7 +54,7 @@ module DCache ( assign hitway[1] = tag[1].valid & tag[1].tag == port.tag; assign hitway[2] = tag[2].valid & tag[2].tag == port.tag; assign hitway[3] = tag[3].valid & tag[3].tag == port.tag; - + assign port.hit = |{hitway}; assign port.hit_row = (hitway[0] ? data[0] : `DC_DATA_LENGTH'b0) | (hitway[1] ? data[1] : `DC_DATA_LENGTH'b0) @@ -168,7 +168,7 @@ module DCache ( tag_ram2 (.rst(rst), .addra(TagRAM2.addr), .clka(clk), .dina(TagRAM2.wdata), .douta(TagRAM2.rdata), .wea(TagRAM2.wen)); bram #(.DATA_WIDTH(32-`DC_TAGL+2), .DATA_DEPTH(2 ** (`DC_TAGL-`DC_INDEXL))) tag_ram3 (.rst(rst), .addra(TagRAM3.addr), .clka(clk), .dina(TagRAM3.wdata), .douta(TagRAM3.rdata), .wea(TagRAM3.wen)); - + bram #(.DATA_WIDTH(`DC_DATA_LENGTH), .DATA_DEPTH(2 ** (`DC_TAGL-`DC_INDEXL))) data_ram0 (.rst(rst), .addra(DataRAM0.addr), .clka(clk), .dina(DataRAM0.wdata), .douta(DataRAM0.rdata), .wea(DataRAM0.wen)); bram #(.DATA_WIDTH(`DC_DATA_LENGTH), .DATA_DEPTH(2 ** (`DC_TAGL-`DC_INDEXL))) diff --git a/src/MU/ICache.sv b/src/MU/ICache.sv index da410ab..3c814ce 100644 --- a/src/MU/ICache.sv +++ b/src/MU/ICache.sv @@ -11,8 +11,8 @@ module ICache ( // ============ Vars ============ // ============================== - ICTagRAM_t TagRAM0, TagRAM1, TagRAM2, TagRAM3; - ICDataRAM_t DataRAM0, DataRAM1, DataRAM2, DataRAM3; + ICTagRAM_t TagRAM0/*verilator split_var*/, TagRAM1/*verilator split_var*/, TagRAM2/*verilator split_var*/, TagRAM3/*verilator split_var*/; + ICDataRAM_t DataRAM0/*verilator split_var*/, DataRAM1/*verilator split_var*/, DataRAM2/*verilator split_var*/, DataRAM3/*verilator split_var*/; (* RAM_STYLE="block" *) logic [3:0] LRU[64]; @@ -122,7 +122,7 @@ module ICache ( assign DataRAM2.wdata = port.update_row; assign DataRAM3.wdata = port.update_row; - bram #(.DATA_WIDTH(32-`IC_TAGL+1), .DATA_DEPTH(2 ** (`IC_TAGL-`IC_INDEXL))) + bram #(.DATA_WIDTH(32-`IC_TAGL+1), .DATA_DEPTH(2 ** (`IC_TAGL-`IC_INDEXL))) tag_ram0 (.rst(rst), .addra(TagRAM0.addr), .clka(clk), .dina(TagRAM0.wdata), .douta(TagRAM0.rdata), .wea(TagRAM0.wen)); bram #(.DATA_WIDTH(32-`IC_TAGL+1), .DATA_DEPTH(2 ** (`IC_TAGL-`IC_INDEXL))) tag_ram1 (.rst(rst), .addra(TagRAM1.addr), .clka(clk), .dina(TagRAM1.wdata), .douta(TagRAM1.rdata), .wea(TagRAM1.wen)); diff --git a/src/MU/MU.sv b/src/MU/MU.sv index cc82cb9..3ebd66d 100644 --- a/src/MU/MU.sv +++ b/src/MU/MU.sv @@ -3,620 +3,610 @@ `include "TLB.svh" module MU ( - input clk, - input rst, - ICache_i.mu icache, - DCache_i.mu dcache, - InstFetch_i.mu instfetch, - Memory_i.mu memory, - CacheOp_i.mu cacheop, - AXIRead_i.mu axiread_inst, - AXIRead_i.mu axiread_data, - AXIWrite_i.mu axiwrite_data, - CP0_i.mu cp0 + input clk, + input rst, + ICache_i.mu icache, + DCache_i.mu dcache, + InstFetch_i.mu instfetch, + Memory_i.mu memory, + CacheOp_i.mu cacheop, + AXIRead_i.mu axiread_inst, + AXIRead_i.mu axiread_data, + AXIWrite_i.mu axiwrite_data, + CP0_i.mu cp0 ); - // ====================== - // ======== Defs ======== - // ====================== - typedef enum bit [3:0] { - I_IDLE, - I_WA, - I_WD1, - I_WD2, - I_WD3, - I_WD4, - I_WD5, - I_WD6, - I_WD7, - I_WD8, - I_REFILL - } istate_t; - typedef enum bit [2:0] { - DR_IDLE, - DR_WA, - DR_WD1, - DR_WD2, - DR_WD3, - DR_WD4, - DR_REFILL - } drstate_t; - typedef enum bit [2:0] { - DW_IDLE, - DW_WD1, - DW_WD2, - DW_WD3, - DW_WD4, - DW_WB, - DW_WAITR - } dwstate_t; - typedef enum bit { - DWA_IDLE, - DWA_WA - } dwastate_t; - // ====================== - // ======== iVar ======== - // ====================== - word_t iVA; - logic iEn, iEn2; - logic iReq1; - logic iHit1; - logic iCached1, iCached2; - logic iMValid1; - logic iValid1; - logic iUser1; - word_t iPA1, iPA2; - word_t iD1, iD2, iD3, iD4, iD5, iD6, iD7; - // ================================ - // ======== iState Machine ======== - // ================================ - istate_t iState; - istate_t iNextState; - always_ff @(posedge clk) begin - if (rst) iState <= I_IDLE; - else iState <= iNextState; - end + + // ============= + // == CacheOp == + // ============= + + logic cop_i_req = cacheop.req & cacheop.op.icache_op; + logic cop_d_req = cacheop.req & cacheop.op.dcache_op; + logic cop_i_ok, cop_d_ok; + assign cacheop.addr_ok = (cop_i_req & cop_i_ok) | (cop_d_req & cop_d_ok); + + word_t stored_cacheop_addr; + CacheOp_t stored_cacheop_op; + ffen #(`XLEN + `CACHEOP_T_LEN) icacheop_store ( + .*, + .d({cacheop.addr, cacheop.op}), + .en(cacheop.req), + .q({stored_cacheop_addr, stored_cacheop_op}) + ); + + // ========================= + // == InstFetch Functions == + // ========================= + + // handshake + logic in_if_valid; + logic in_if_ready; + logic out_if_valid; + logic out_if_ready; // stub + + assign in_if_valid = instfetch.req; + assign instfetch.addr_ok = in_if_ready; + assign instfetch.data_ok = out_if_valid; + assign out_if_ready = 1'b1; + + // TLB + word_t instfetch_phy_addr; + logic instfetch_hit; + logic instfetch_cached; + logic instfetch_valid; + logic instfetch_privilege; + + // =============== + // AXI Read Worker + // =============== + + // input + logic ai_call; + word_t ai_addr; + logic [3:0] ai_len; + // output + logic ai_done; + ICData_t ai_buffer; + + AXIReader #(`IC_DATA_LENGTH) + if_reader ( + .*, + .axi(axiread_inst), + .call(ai_call), + .addr(ai_addr), + .len(ai_len), + .size(3'b010), + .done(ai_done), + .buffer(ai_buffer) + ); + + // =============== + // instfetch store + // =============== + + logic if_req; + // NOTE: TLB Check + word_t stored_instfetch_addr; + ffenr #(1) ifreq_store (.*, .d(instfetch.req), .en(in_if_ready), .q(if_req)); + ffen #(`XLEN) ifaddr_store (.*, .d(instfetch.addr), .en(in_if_ready), .q(stored_instfetch_addr)); + + // ============ + // row data mux + // ============ + logic if_source_select_direct; // only used when non-cached + ICData_t if_source_data; + // TODO: use macro/generator to dynamic mux + mux5 #(2 * `XLEN) if_rdata_mux( + if_source_data[ 63: 0], + if_source_data[127: 64], + if_source_data[191:128], + if_source_data[255:192], + if_source_data[255:192], // uncached + {if_source_select_direct, stored_instfetch_addr[`IC_INDEXL-1:3]}, + {instfetch.rdata1, instfetch.rdata0} + ); + + // ===================================== + // == InstFetch Control State Machine == + // ===================================== + + // cache ctrl: + // read_and_hit : lookup(0) and hit(1) + // read_but_replace : lookup(0) but miss(1), replace(2) + // cache_index_invalid : lookup(0) and invalid(2) all 4 rows + // cache_hit_invalid : lookup(0) and invalid(2) the hited(1) row + + typedef enum bit [1:0] { + IFC_LOOKUP, // deal with current request + // read if non-cached or not hited + // cache + IFC_READ, // wait for AXI read + // refill if cached + IFC_CACHE_INVALID // cache_index_invalid, cache_hit_invalid + } IFC_state_t; + + IFC_state_t ifc_cur_state; + IFC_state_t ifc_next_state; + always_comb begin - iEn = 0; - iEn2 = 0; - iNextState = iState; - inst.data_ok = 0; - inst_axi.req = 0; - case (iState) - I_IDLE: begin - if (~iValid1) iEn = 1; - else begin - iEn2 = 1; - if (iCached1 & ic.hit) begin - iEn = 1; - inst.data_ok = 1; + ifc_next_state = ifc_cur_state; + + // To CPU + in_if_ready = 0; + out_if_valid = 0; + if_source_select_direct = 0; + + // AXI Inst + ai_call = 0; + ai_addr = {instfetch_phy_addr[`XLEN-1:`IC_INDEXL], {`IC_INDEXL'b0}}; + ai_len = 4'b0001; + + // I$ + cop_i_ok = 0; + icache.ctrl = 4'b0; + icache.index_for_lookup = instfetch.addr[`IC_TAGL-1:`IC_INDEXL]; + icache.index = stored_instfetch_addr[`IC_TAGL-1:`IC_INDEXL]; + icache.tag = instfetch_phy_addr[`XLEN-1:`IC_TAGL]; + icache.update_row = ai_buffer; + + case (ifc_cur_state) + IFC_LOOKUP: begin + if (cop_i_req) begin + // Handle Cache Instruction + ifc_next_state = IFC_CACHE_INVALID; + + cacheop.addr_ok = 1; + icache.index_for_lookup = cacheop.addr[`IC_TAGL-1:`IC_INDEXL]; + + end else if (if_req & instfetch_cached & icache.hit) begin + // Cached + Hit -> return + ifc_next_state = IFC_LOOKUP; + + in_if_ready = 1'b1; + out_if_valid = 1'b1; + + icache.ctrl.read_and_hit = 1'b1; // notify cache to update LRU + // icache.index + + if_source_select_direct = 0; + if_source_data = icache.hit_row; + + end else if (if_req) begin + // Handle non-cached and miss + ifc_next_state = IFC_READ; + + ai_call = 1; + if (~instfetch_cached) begin + // non-cached + ai_addr = {instfetch_phy_addr[`XLEN-1:3], 3'b0}; + ai_len = 4'b0001; end else begin - inst_axi.req = 1; - if (~inst_axi.addr_ok) iNextState = I_WA; - else iNextState = I_WD1; + ai_addr = {instfetch_phy_addr[`XLEN-1:`IC_INDEXL], {`IC_INDEXL'b0}}; + ai_len = `IC_ROW_LENGTH; end - end - end - I_WA: begin - inst_axi.req = 1; - if (inst_axi.addr_ok) begin - if (~inst_axi.rvalid) iNextState = I_WD1; - else iNextState = I_WD2; - end - end - I_WD1: begin - if (inst_axi.rvalid) iNextState = I_WD2; - end - I_WD2: begin - if (inst_axi.rvalid) begin - if (iCached2) iNextState = I_WD3; - else begin - inst.data_ok = 1; - iEn = 1; - iNextState = I_IDLE; - end - end - end - I_WD3: begin - if (inst_axi.rvalid) iNextState = I_WD4; - end - I_WD4: begin - if (inst_axi.rvalid) iNextState = I_WD5; - end - I_WD5: begin - if (inst_axi.rvalid) iNextState = I_WD6; - end - I_WD6: begin - if (inst_axi.rvalid) iNextState = I_WD7; - end - I_WD7: begin - if (inst_axi.rvalid) iNextState = I_WD8; - end - I_WD8: begin - if (inst_axi.rvalid) begin - iNextState = I_REFILL; - inst.data_ok = 1; - end - end - I_REFILL: begin - iEn = 1; - iNextState = I_IDLE; - end - endcase - end - // ============================ - // ======== iFlip-Flop ======== - // ============================ - ffenr #(1) ivalid_ff ( - clk, - rst, - inst.req, - iEn, - iReq1 - ); - ffen #(32) iPA_ff ( - clk, - iPA1, - iEn2, - iPA2 - ); - ffen #(1) iCached_ff ( - clk, - iCached1, - iEn2, - iCached2 - ); - ffen #(32) id1_ff ( - clk, - inst_axi.rdata, - iState == I_WA | iState == I_WD1, - iD1 - ); - ffen #(32) id2_ff ( - clk, - inst_axi.rdata, - iState == I_WD2, - iD2 - ); - ffen #(32) id3_ff ( - clk, - inst_axi.rdata, - iState == I_WD3, - iD3 - ); - ffen #(32) id4_ff ( - clk, - inst_axi.rdata, - iState == I_WD4, - iD4 - ); - ffen #(32) id5_ff ( - clk, - inst_axi.rdata, - iState == I_WD5, - iD5 - ); - ffen #(32) id6_ff ( - clk, - inst_axi.rdata, - iState == I_WD6, - iD6 - ); - ffen #(32) id7_ff ( - clk, - inst_axi.rdata, - iState == I_WD7, - iD7 - ); - // =============================== - // ========== iFunction ========== - // =============================== - assign iVA = inst.addr; - assign iValid1 = iReq1 & iHit1 & iMValid1 & (in_kernel | iUser1); - assign inst.addr_ok = iEn; - mux5 #(64) inst_rdata_mux ( - ic.row[ 63: 0], - ic.row[127: 64], - ic.row[191:128], - ic.row[255:192], - {iState == I_WD2 ? inst_axi.rdata : iD2, iD1}, - {iState != I_IDLE, iPA1[4:3]}, - {inst.rdata1, inst.rdata0} - ); - assign ic.req = iEn; - assign ic.valid = iValid1 & iCached1; - assign ic.index = iVA[`IC_TAGL-1:`IC_INDEXL]; - assign ic.tag1 = iEn2 ? iPA1[31:`IC_TAGL] : iPA2[31:`IC_TAGL]; - assign ic.rvalid = inst_axi.rvalid & inst_axi.data_ok; - mux4 #(256) ic_rdata_mux ( - {inst_axi.rdata, iD7, iD6, iD5, iD4, iD3, iD2, iD1}, - {iD6, iD5, iD4, iD3, iD2, iD1, inst_axi.rdata, iD7}, - {iD4, iD3, iD2, iD1, inst_axi.rdata, iD7, iD6, iD5}, - {iD2, iD1, inst_axi.rdata, iD7, iD6, iD5, iD4, iD3}, - iPA2[4:3], - ic.rdata - ); - assign inst_axi.addr = iEn2 ? iPA1 : iPA2; - assign inst_axi.len = (iEn2 ? iCached1 : iCached2) ? 4'b0111 : 4'b0001; - assign inst_axi.size = 3'b010; - assign iTLBRefill = (iState == I_IDLE) & iReq1 & ~iHit1; - assign iTLBInvalid = (iState == I_IDLE) & iReq1 & ~iMValid1; - assign iAddressError = (iState == I_IDLE) & iReq1 & ~in_kernel & ~iUser1; - - - - - - - - - - - // ====================== - // ======== dVar ======== - // ====================== - word_t dVA; - logic dEn; - logic dReq1; - logic dHit1; - logic dCached1, dCached2; - logic dDirty1; - logic dMValid1; - logic dValid1; - logic dUser1; - word_t dPA1, dPA2; - logic [1:0] dSize1; - logic dEn2; - logic dwr1; - logic [3:0] dWstrb1; - word_t dWdata1; - word_t drD1, drD2, drD3; - logic wdata_ok; - word_t ddAddr1; - logic [127:0] ddData1; - // ============================ - // ======== dFlip-Flop ======== - // ============================ - ffenr #(1) dvalid_ff (clk,rst,data.req,dEn,dReq1); - ffen #(2) dsize_ff (clk,data.size,dEn,dSize1); - ffen #(32) dPA_ff (clk,dPA1,dEn2,dPA2); - ffen #(1) dCached_ff (clk,dCached1,dEn2,dCached2); - ffen #(1) dwr_ff (clk,data.wr,dEn2,dwr1); - ffen #(4) dwstrb_ff (clk,data.wstrb,dEn2,dWstrb1); - ffen #(32) dwdata_ff (clk,data.wdata,dEn2,dWdata1); - // ================================= - // ======== drState Machine ======== - // ================================= - drstate_t drState; - drstate_t drNextState; - always_ff @(posedge clk) begin - if (rst) drState <= DR_IDLE; - else drState <= drNextState; - end - always_comb begin - dEn = 0; - dEn2 = 0; - drNextState = drState; - data.data_ok = 0; - rdata_axi.req = 0; - case (drState) - DR_IDLE: begin - if (~dValid1) dEn = 1; - else begin - dEn2 = 1; - if (data.wr) data.data_ok = 1; - if (data.wr & (~dCached1 | dc.hit)) drNextState = DR_REFILL; - else if (dCached1 & dc.hit) begin - dEn = 1; - data.data_ok = 1; - end else begin - rdata_axi.req = 1; - if (~rdata_axi.addr_ok) drNextState = DR_WA; - else drNextState = DR_WD1; - end - end - end - DR_WA: begin - rdata_axi.req = 1; - if (rdata_axi.addr_ok) begin - if (~rdata_axi.rvalid) drNextState = DR_WD1; - else begin - data.data_ok = 1; - if (dCached2) drNextState = DR_WD2; - else begin - dEn = 1; - drNextState = DR_IDLE; - end - end - end - end - DR_WD1: begin - if (rdata_axi.rvalid) begin - if (dCached2) drNextState = DR_WD2; - else begin - data.data_ok = 1; - dEn = 1; - drNextState = DR_IDLE; - end - end - end - DR_WD2: begin - if (rdata_axi.rvalid) drNextState = DR_WD3; - end - DR_WD3: begin - if (rdata_axi.rvalid) drNextState = DR_WD4; - end - DR_WD4: begin - if (rdata_axi.rvalid) begin - drNextState = DR_REFILL; - data.data_ok = 1; - end - end - DR_REFILL: begin - if (wdata_ok) begin - dEn = 1; - drNextState = DR_IDLE; - end - end - endcase - end - // ================================ - // ========== dFunction ========== - // ================================ - assign dVA = data.addr; - assign dValid1 = dReq1 & dHit1 & dMValid1 & (~data.wr | dDirty1) & (in_kernel | dUser1); - assign dTLBRefill = (drState == DR_IDLE) & dReq1 & ~dHit1; - assign dTLBInvalid = (drState == DR_IDLE) & dReq1 & ~dMValid1; - assign dTLBModified = (drState == DR_IDLE) & dReq1 & data.wr & ~dDirty1; - assign dAddressError = (drState == DR_IDLE) & dReq1 & ~in_kernel & ~dUser1; - // ============================= - // ======== drFlip-Flop ======== - // ============================= - ffen #(32) drd1_ff ( - clk, - rdata_axi.rdata, - drState == DR_WA | drState == DR_WD1, - drD1 - ); - ffen #(32) drd2_ff ( - clk, - rdata_axi.rdata, - drState == DR_WD2, - drD2 - ); - ffen #(32) drd3_ff ( - clk, - rdata_axi.rdata, - drState == DR_WD3, - drD3 - ); - // ================================ - // ========== drFunction ========== - // ================================ - assign data.addr_ok = dEn; - mux5 #(32) data_rdata_mux ( - dc.row[ 31: 0], - dc.row[ 63:32], - dc.row[ 95:64], - dc.row[127:96], - drState == DR_WD4 ? drD1 : rdata_axi.rdata, - {drState != DR_IDLE, dPA1[3:2]}, - data.rdata - ); - assign dc.req = dEn; - assign dc.valid = dValid1 & dCached1; - assign dc.index = dVA[`DC_TAGL-1:`DC_INDEXL]; - assign dc.tag1 = dEn2 ? dPA1[31:`DC_TAGL] : dPA2[31:`DC_TAGL]; - assign dc.sel1 = dEn2 ? dPA1[3:2] : dPA2[3:2]; - assign dc.rvalid = rdata_axi.rvalid & rdata_axi.data_ok; - mux4 #(128) dc_rdata_mux ( - {rdata_axi.rdata, drD3, drD2, drD1}, - {drD3, drD2, drD1, rdata_axi.rdata}, - {drD2, drD1, rdata_axi.rdata, drD3}, - {drD1, rdata_axi.rdata, drD3, drD2}, - dPA2[3:2], - dc.rdata - ); - assign rdata_axi.addr = dEn2 ? dPA1 : dPA2; - assign rdata_axi.len = (dEn2 ? dCached1 : dCached2) ? 4'b0011 : 4'b0000; - assign rdata_axi.size = (dEn2 ? dCached1 : dCached2) ? 3'b010 : {1'b0, dSize1}; - // ================================= - // ======== dwState Machine ======== - // ================================= - dwstate_t dwState; - dwstate_t dwNextState; - always_ff @(posedge clk) begin - if (rst) dwState <= DW_IDLE; - else dwState <= dwNextState; - end - always_comb begin - dwNextState = dwState; - wdata_axi.wdata = 0; - wdata_axi.wstrb = 0; - wdata_axi.wvalid = 0; - wdata_axi.wlast = 0; - case (dwState) - DW_IDLE: begin - if (dEn2 & (~dCached1 & data.wr | dCached1 & ~dc.hit & dc.dirt_valid)) begin - if (dCached1) begin - wdata_axi.wdata = dc.dirt_data[31:0]; - wdata_axi.wstrb = 4'b1111; - wdata_axi.wvalid = 1'b1; - end else begin - wdata_axi.wdata = data.wdata; - wdata_axi.wstrb = data.wstrb; - wdata_axi.wvalid = 1'b1; - wdata_axi.wlast = 1'b1; - end - if (~wdata_axi.wready) dwNextState = DW_WD1; - else begin - if (dCached1) dwNextState = DW_WD2; - else begin - if (~wdata_axi.data_ok) dwNextState = DW_WB; - else begin - // fixme: AXI3 wait WA - // if (drState == DR_REFILL) $error("drState == DR_REFILL"); - dwNextState = DW_WAITR; - end - end - end - end - end - DW_WD1: begin - if (dCached2) begin - wdata_axi.wdata = ddData1[31:0]; - wdata_axi.wstrb = 4'b1111; - wdata_axi.wvalid = 1'b1; + end else begin - wdata_axi.wdata = dWdata1; - wdata_axi.wstrb = dWstrb1; - wdata_axi.wvalid = 1'b1; - wdata_axi.wlast = 1'b1; + // allow in when idle + in_if_ready = 1; end - if (wdata_axi.wready) begin - if (dCached2) dwNextState = DW_WD2; - else begin - if (~wdata_axi.data_ok) dwNextState = DW_WB; - else begin - // fixme: AXI3 wait WA - // if (drState != DR_REFILL) $error("drState != DR_REFILL"); - dwNextState = DW_IDLE; - end + end + + IFC_READ: begin + if (ai_done) begin + ifc_next_state = IFC_LOOKUP; + if (instfetch_cached) begin + // Write Back to Cache and return to CPU + + icache.ctrl.read_but_replace = 1'b1; + // BRAM & LRU addr + icache.index_for_lookup = stored_instfetch_addr[`IC_TAGL-1:`IC_INDEXL]; + // write data + // icache.update_row = ai_buffer (default) + + // To CPU + out_if_valid = 1'b1; + if_source_select_direct = 0; + if_source_data = ai_buffer; + + // Cache require one more cycle to write into bram + in_if_ready = 0; + + end else begin + // un-cached: return to CPU and receive next req + out_if_valid = 1'b1; + if_source_select_direct = 1'b1; + if_source_data = ai_buffer; end end end - DW_WD2: begin - wdata_axi.wdata = ddData1[63:32]; - wdata_axi.wstrb = 4'b1111; - wdata_axi.wvalid = 1'b1; - if (wdata_axi.wready) dwNextState = DW_WD3; - end - DW_WD3: begin - wdata_axi.wdata = ddData1[95:64]; - wdata_axi.wstrb = 4'b1111; - wdata_axi.wvalid = 1'b1; - if (wdata_axi.wready) dwNextState = DW_WD4; - end - DW_WD4: begin - wdata_axi.wdata = ddData1[127:96]; - wdata_axi.wstrb = 4'b1111; - wdata_axi.wvalid = 1'b1; - wdata_axi.wlast = 1'b1; - if (wdata_axi.wready) begin - if (~wdata_axi.data_ok) dwNextState = DW_WB; - else begin - // fixme: AXI3 wait WA - if (drState == DR_REFILL) dwNextState = DW_IDLE; - else dwNextState = DW_WAITR; - end - end - end - DW_WB: begin - // TODO: goto IDLE on failure - if (wdata_axi.data_ok) begin - // fixme: AXI3 wait WA - if (drState == DR_REFILL) dwNextState = DW_IDLE; - else dwNextState = DW_WAITR; - end - end - DW_WAITR: begin - if (drState == DR_REFILL) dwNextState = DW_IDLE; + + IFC_CACHE_INVALID: begin + ifc_next_state = IFC_LOOKUP; + + cop_i_ok = 1'b1; + + // next state -> write into bram + + icache.ctrl.cache_index_invalidate = ~stored_cacheop_op.index_or_hit; + icache.ctrl.cache_hit_invalidate = stored_cacheop_op.index_or_hit; + + icache.index_for_lookup = stored_cacheop_addr[`IC_TAGL-1:`IC_INDEXL]; end + default: begin end endcase end - assign wdata_ok = (dwNextState == DW_IDLE) | (dwNextState == DW_WAITR); - dwastate_t dwaState; - dwastate_t dwaNextState; + always_ff @(posedge clk) begin - if (rst) dwaState <= DWA_IDLE; - else dwaState <= dwaNextState; + if (rst) ifc_cur_state <= IFC_LOOKUP; + else ifc_cur_state <= ifc_next_state; end + + + + // ======================= + // == Memory Functions == + // ======================= + + // handshake + logic in_mem_valid; + logic in_mem_ready; + logic out_mem_valid; + logic out_mem_ready; // stub + + assign in_mem_valid = memory.req; + assign memory.addr_ok = in_mem_ready; + assign memory.data_ok = out_mem_valid; + assign out_mem_ready = 1'b1; + + // TLB + word_t memory_phy_addr; + logic memory_hit; + logic memory_cached; + logic memory_dirty; + logic memory_valid; + logic memory_privilege; + + // =============== + // AXI Read Worker + // =============== + + // input + logic amr_call; + word_t amr_addr; + logic [3:0] amr_len; + logic [2:0] amr_size; + // output + logic amr_done; + DCData_t amr_buffer; + + AXIReader #(`DC_DATA_LENGTH) + mem_reader ( + .*, + .axi(axiread_data), + .call(amr_call), + .addr(amr_addr), + .len(amr_len), + .size(amr_size), + .done(amr_done), + .buffer(amr_buffer) + ); + + // ================ + // AXI Write Worker + // ================ + + // input + logic amw_call; + word_t amw_addr; + logic [3:0] amw_len; + logic [2:0] amw_size; + logic [3:0] amw_wstrb; + DCData_t amw_data; + // output + logic amw_done; + + AXIWriter #(`DC_DATA_LENGTH) + mem_writer ( + .*, + .axi(axiwrite_data), + .call(amw_call), + .addr(amw_addr), + .len(amw_len), + .size(amw_size), + .wstrb(amw_wstrb), + .data(amw_data), + .done(amw_done) + ); + + // ============ + // memory store + // ============ + + logic mem_req; + logic [2:0] stored_memory_size; + word_t stored_memory_addr; + ffenr #(1) memreq_store (.*, .d(memory.req), .en(in_mem_ready), .q(mem_req)); + ffen #(3) memsize_store (.*, .d({1'b0, memory.size}), .en(in_mem_ready), .q(stored_memory_size)); + ffen #(`XLEN) memaddr_store (.*, .d(memory.addr), .en(in_mem_ready), .q(stored_memory_addr)); + + logic stored_memory_wr; + logic [3:0] stored_memory_wstrb; + word_t stored_memory_wdata; + ffen #(1) memwr_store (.*, .d(memory.wr), .en(mem_req), .q(stored_memory_wr)); + ffen #(4) memwstrb_store (.*, .d(memory.wstrb), .en(mem_req), .q(stored_memory_wstrb)); + ffen #(`XLEN) memwdata_store (.*, .d(memory.wdata), .en(mem_req), .q(stored_memory_wdata)); + // ============ + // row data mux + // ============ + + logic mem_source_select_direct; // only used when non-cached + DCData_t mem_source_data; + // TODO: use macro/generator to dynamic mux + mux5 #(`XLEN) mem_rdata_mux( + mem_source_data[ 31: 0], + mem_source_data[ 63: 32], + mem_source_data[ 95: 64], + mem_source_data[127: 96], + mem_source_data[127: 96], // uncached + {mem_source_select_direct, stored_memory_addr[`DC_INDEXL-1:2]}, + memory.rdata + ); + + DCData_t mem_source_base_data, mem_output_data; + word_t mem_source_wdata; + logic [1:0] base = stored_memory_addr[`DC_INDEXL-1:2]; always_comb begin - wdata_axi.req = 0; - dwaNextState = dwaState; - case (dwaState) - DWA_IDLE: begin - if (dEn2 & (~dCached1 & data.wr | dCached1 & ~dc.hit & dc.dirt_valid)) begin - wdata_axi.req = 1'b1; - if (~wdata_axi.addr_ok) dwaNextState = DWA_WA; + mem_output_data = mem_source_base_data; + if (stored_memory_wstrb[3]) mem_output_data[{base, 5'd24}+:8] = mem_source_wdata[24+:8]; + if (stored_memory_wstrb[2]) mem_output_data[{base, 5'd16}+:8] = mem_source_wdata[16+:8]; + if (stored_memory_wstrb[1]) mem_output_data[{base, 5'd08}+:8] = mem_source_wdata[ 8+:8]; + if (stored_memory_wstrb[0]) mem_output_data[{base, 5'd00}+:8] = mem_source_wdata[ 0+:8]; + end + + + // ================================== + // == Memory Control State Machine == + // ================================== + + typedef enum bit [1:0] { + MEM_LOOKUP, + MEM_READ, + MEM_WRITE, + MEM_CACHE_INVALID + } mem_state_t; + + mem_state_t mem_pre_state; + mem_state_t mem_cur_state; + mem_state_t mem_nxt_state; + + always_comb begin + mem_nxt_state = mem_cur_state; + + // To CPU + in_mem_ready = 0; + out_mem_valid = 0; + + mem_source_select_direct = 0; + mem_source_data = dcache.hit_row; + mem_source_base_data = dcache.hit_row; + mem_source_wdata = stored_memory_wdata; + + // AXI Data Read + amr_call = 0; + amr_addr = {memory_phy_addr[`XLEN-1:2], 2'b0}; + amr_len = 0; + amr_size = stored_memory_size; + + // AXI Data Write + amw_call = 0; + amw_addr = {memory_phy_addr[`XLEN-1:2], 2'b0}; + amw_len = 0; + amw_size = stored_memory_size; + amw_wstrb = 4'b1111; + amw_data = dcache.dirt_row; + + // D$ + cop_d_ok = 0; + dcache.ctrl = 8'b0; + dcache.index_for_lookup = memory.addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.index = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.tag = memory_phy_addr[`XLEN-1:`DC_TAGL]; + dcache.update_row = amr_buffer; + + case (mem_cur_state) + MEM_LOOKUP: begin + if (cop_d_req) begin + // Handle Cache Instruction + mem_nxt_state = MEM_CACHE_INVALID; + dcache.index_for_lookup = cacheop.addr[`DC_TAGL-1:`DC_INDEXL]; + end else if (mem_req & memory_cached & dcache.hit) begin + // Cached + Hit + if (~memory.wr) begin + mem_nxt_state = MEM_LOOKUP; + + dcache.ctrl.read_and_hit = 1'b1; + dcache.index = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + + in_mem_ready = 1'b1; + out_mem_valid = 1'b1; + mem_source_select_direct = 0; + mem_source_data = dcache.hit_row; + end else begin + mem_nxt_state = MEM_LOOKUP; + + in_mem_ready = 1'b0; // cache requires one more cycle to write + out_mem_valid = 1'b1; + + dcache.ctrl.write_and_hit = 1'b1; + dcache.index_for_lookup = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.index = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + + mem_source_base_data = dcache.hit_row; + mem_source_wdata = stored_memory_wdata; + dcache.update_row = mem_output_data; + end + end else if (mem_req) begin + // Handle Non-Cached or Miss + if (~memory_cached) begin + if (~memory.wr) begin + // non-cached read + mem_nxt_state = MEM_READ; + amr_call = 1'b1; + amr_addr = memory_phy_addr; + amr_len = 0; + amr_size = stored_memory_size; + end else begin + // non-cached write + mem_nxt_state = MEM_WRITE; + amw_call = 1'b1; + amw_addr = memory_phy_addr; + amw_len = 0; + amw_size = stored_memory_size; + amw_wstrb = memory.wstrb; + amw_data = {{(`DC_DATA_LENGTH-`XLEN){1'b0}}, memory.wdata}; + end + end else if (dcache.dirt) begin + // dirty read / write + mem_nxt_state = MEM_WRITE; + + amw_call = 1'b1; + amw_addr = dcache.dirt_addr; + amw_len = `DC_ROW_LENGTH; + amw_size = 3'b010; + amw_wstrb = 4'b1111; + amw_data = dcache.dirt_row; + + dcache.index_for_lookup = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + end else begin + // non-dirty read / write + mem_nxt_state = MEM_READ; + + amr_call = 1'b1; + amr_addr = {stored_memory_addr[`XLEN-1:`DC_INDEXL], {`DC_INDEXL'b0}}; + amr_len = `DC_ROW_LENGTH; + amr_size = 3'b010; + + dcache.index_for_lookup = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + end + end else begin + // allow in when idle + in_mem_ready = 1; + end + + end + + MEM_READ: begin + // LOOKUP -> ~memory_cache & ~memory.rw -> LOOKUP + // LOOKUP -> dcache ~hit (r/w) -> LOOKUP + + dcache.index_for_lookup = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.index = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + + if (amr_done) begin + mem_nxt_state = MEM_LOOKUP; + out_mem_valid = 1'b1; + + if (memory_cached) begin + // cache replace back + dcache.ctrl.read_but_replace = ~stored_memory_wr; + dcache.ctrl.write_but_replace = stored_memory_wr; + dcache.tag = stored_memory_addr[`XLEN-1:`DC_TAGL]; + // dcache.update_row + + if (stored_memory_wr) begin + mem_source_base_data = amr_buffer; + mem_source_wdata = stored_memory_wdata; + dcache.update_row = mem_output_data; + end else begin + dcache.update_row = amr_buffer; + mem_source_select_direct = 0; + mem_source_data = amr_buffer; + end + + end else begin + // uncached read + mem_source_select_direct = 1'b1; + mem_source_data = amr_buffer; + end end end - DWA_WA: begin - wdata_axi.req = 1'b1; - if (wdata_axi.addr_ok) dwaNextState = DWA_IDLE; + + MEM_WRITE: begin + // LOOKUP -> ~memory_cache & memory.rw -> LOOKUP + // LOOKUP -> dache.dirt -> MEM_READ + // CACHE_INVALID -> -> CACHE_INVALID + + dcache.index_for_lookup = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.index = stored_memory_addr[`DC_TAGL-1:`DC_INDEXL]; + + if (amw_done) begin + if (mem_pre_state == MEM_CACHE_INVALID) begin + mem_nxt_state = MEM_CACHE_INVALID; + end else if (memory_cached) begin + mem_nxt_state = MEM_READ; + end else begin + mem_nxt_state = MEM_LOOKUP; + // to CPU + out_mem_valid = 1'b1; + end + + end + end + + MEM_CACHE_INVALID: begin + dcache.index_for_lookup = stored_cacheop_addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.index = stored_cacheop_addr[`DC_TAGL-1:`DC_INDEXL]; + dcache.tag = stored_cacheop_addr[`XLEN-1:`DC_TAGL]; + + if (~stored_cacheop_op.writeback) begin + mem_nxt_state = MEM_LOOKUP; + cop_d_ok = 1'b1; + + dcache.ctrl.cache_index_invalidate = ~stored_cacheop_op.index_or_hit; + dcache.ctrl.cache_hit_invalidate = stored_cacheop_op.index_or_hit; + end else begin + dcache.ctrl.cache_index_writeback = ~stored_cacheop_op.index_or_hit; + dcache.ctrl.cache_hit_writeback = stored_cacheop_op.index_or_hit; + + if (dcache.dirt) begin + mem_nxt_state = MEM_WRITE; + + amw_call = 1'b1; + amw_addr = dcache.dirt_addr; + amw_len = `DC_ROW_LENGTH; + amw_size = 3'b010; + amw_wstrb = 4'b1111; + amw_data = dcache.dirt_row; + + end else begin + mem_nxt_state = MEM_LOOKUP; + cop_d_ok = 1'b1; + end + end + end + default: begin end endcase + + end + + always_ff @(posedge clk) begin + if (rst) begin + mem_pre_state <= MEM_LOOKUP; + mem_cur_state <= MEM_LOOKUP; + end else begin + mem_cur_state <= mem_nxt_state; + if (mem_cur_state != mem_nxt_state) + mem_pre_state <= mem_cur_state; + end end - // ============================= - // ======== dwFlip-Flop ======== - // ============================= - ffen #(32) ddaddr_ff ( - clk, - dc.dirt_addr, - dc.dirt_valid, - ddAddr1 - ); - ffen #(128) dddata_ff ( - clk, - dc.dirt_data, - dc.dirt_valid, - ddData1 - ); - // ================================ - // ========== dwFunction ========== - // ================================ - assign wdata_axi.addr = (dEn2 ? dCached1 : dCached2) ? (dwaState == DWA_IDLE) ? dc.dirt_addr : ddAddr1 : dEn2 ? dPA1 : dPA2; - assign wdata_axi.len = (dEn2 ? dCached1 : dCached2) ? 4'b0011 : 4'b0000; - assign wdata_axi.size = (dEn2 ? dCached1 : dCached2) ? 3'b010 : {1'b0, dSize1}; - assign dc.wvalid = dEn2 ? data.wr : dwr1; - assign dc.wdata = dEn2 ? data.wdata : dWdata1; - assign dc.wstrb = dEn2 ? data.wstrb : dWstrb1; // ===================================== // ======= virt addr -> phy addr ======= // ===================================== - // turns stored addr to its phy addr - -`ifdef ENABLE_TLB - - logic tlbw; - logic [2:0] c0_Index_u; - assign tlbw = tlbwi | tlbwr; - assign c0_Index_u = tlbwr ? c0_Random[2:0] : c0_Index[2:0]; - TLB TLB ( - .clk(clk), - .rst(rst), - .K0 (K0), - .tlbw (tlbw), - .tlbp (tlbp), - .c0_Index (c0_Index_u), - .c0_EntryHi (c0_EntryHi), - // .c0_PageMask(c0_PageMask), - .c0_EntryLo1(c0_EntryLo1), - .c0_EntryLo0(c0_EntryLo0), - .EntryHi (EntryHi), - // .PageMask(PageMask), - .EntryLo1(EntryLo1), - .EntryLo0(EntryLo0), - .Index (Index), - .iVAddr (iVA), - .iPAddr (iPA1), - .iHit (iHit1), - .iCached(iCached1), - .iValid (iMValid1), - .iUser (iUser1), - .dVAddr (dVA), - .dPAddr (dPA1), - .dHit (dHit1), - .dCached(dCached1), - .dDirty (dDirty1), - .dValid (dMValid1), - .dUser (dUser1) - ); - -`else - addr_virt_to_phy instfetch_addr_convert( + .K0 (cp0.cp0_K0), .virt_addr (stored_instfetch_addr), .tlb_addr (stored_instfetch_addr[31:12]), .tlb_hit (1'b1), @@ -631,6 +621,7 @@ module MU ( .privilege (instfetch_privilege) ); addr_virt_to_phy memory_addr_convert( + .K0 (cp0.cp0_K0), .virt_addr (stored_memory_addr), .tlb_addr (stored_memory_addr[31:12]), .tlb_hit (1'b1), @@ -645,62 +636,5 @@ module MU ( .privilege (memory_privilege) ); -`endif - - // ===================================== - // == InstFetch Control State Machine == - // ===================================== - - // cache ctrl: - // read_and_hit : lookup(0) and hit(1) - // read_but_replace : lookup(0) but miss(1), replace(2) - // cache_index_invalid : lookup(0) and invalid(2) all 4 rows - // cache_hit_invalid : lookup(0) and invalid(2) the hited(1) row - - typedef enum bit [1:0] { - IFC_LOOKUP, // deal with current request - // read if non-cached or not hited - // cache - IFC_READ, // wait for AXI read - // refill if cached - IFC_CACHE_INVALID // cache_index_invalid, cache_hit_invalid - } IFC_state_t; - - IFC_state_t IFC_cur_state; - IFC_state_t IFC_next_state; - - always_ff @(posedge clk) begin - if (rst) IFC_cur_state <= IFC_LOOKUP; - else IFC_cur_state <= IFC_next_state; - end - - always_comb begin - IFC_next_state = IFC_cur_state; - - instfetch_allow_next_req = 1'b0; - - // AXI action - // ????? - - case (IFC_cur_state) - instfetch.addr_ok = 1'b0; - instfetch.data_ok = 1'b0; - instfetch.rdata0 = 32'h0; - instfetch.rdata1 = 32'h0; - - // cacheop.addr_ok - - icache.ctrl = 4'b0; - icache.index_for_lookup = stored.addr; - icache.index = ?????; - icache.tag = ?????; - icache.update_row = ?????; - - IFC_LOOKUP: begin - if (stored.cacheop.icache_op) begin - end - end - endcase - end endmodule diff --git a/src/MU/interface.sv b/src/MU/interface.sv index 2a1b637..4e3550f 100644 --- a/src/MU/interface.sv +++ b/src/MU/interface.sv @@ -125,15 +125,17 @@ interface CP0_i; logic cp0_in_kernel; logic cpu_tlbwi; logic cpu_tlbwr; - logic cpu_tlbp; + logic cpu_c0_tlbp; + logic cpu_tlb_tlbp; + logic cpu_tlbr; Random_t cp0_Random; // TLBWR EntryHi_t cp0_EntryHi; // TLBWI + F/M(ASID) - PageMask_t cp0_PageMask; // TLBWI + // PageMask_t cp0_PageMask; // TLBWI EntryLo_t cp0_EntryLo1; // TLBWI EntryLo_t cp0_EntryLo0; // TLBWI Index_t cp0_Index; // TLBWI + TLBR EntryHi_t tlb_EntryHi; - PageMask_t tlb_PageMask; + // PageMask_t tlb_PageMask; EntryLo_t tlb_EntryLo1; EntryLo_t tlb_EntryLo0; Index_t tlb_Index; // TLBP @@ -150,15 +152,15 @@ interface CP0_i; input cp0_in_kernel, input cpu_tlbwi, input cpu_tlbwr, - input cpu_tlbp, + input cpu_tlb_tlbp, input cp0_Random, input cp0_Index, input cp0_EntryHi, - input cp0_PageMask, + // input cp0_PageMask, input cp0_EntryLo1, input cp0_EntryLo0, output tlb_EntryHi, - output tlb_PageMask, + // output tlb_PageMask, output tlb_EntryLo1, output tlb_EntryLo0, output tlb_Index, @@ -173,17 +175,16 @@ interface CP0_i; modport cp0( output cp0_K0, output cp0_in_kernel, - output cpu_tlbwi, - output cpu_tlbwr, - output cpu_tlbp, + input cpu_c0_tlbp, + input cpu_tlbr, output cp0_Random, output cp0_Index, output cp0_EntryHi, - output cp0_PageMask, + // output cp0_PageMask, output cp0_EntryLo1, output cp0_EntryLo0, input tlb_EntryHi, - input tlb_PageMask, + // input tlb_PageMask, input tlb_EntryLo1, input tlb_EntryLo0, input tlb_Index @@ -191,7 +192,10 @@ interface CP0_i; modport cpu( output cpu_tlbwi, output cpu_tlbwr, - output cpu_tlbp, + output cpu_c0_tlbp, + output cpu_tlb_tlbp, + output cpu_tlbr, + input cp0_in_kernel, input tlb_iTLBRefill, input tlb_iTLBInvalid, input tlb_iAddressError, @@ -200,5 +204,5 @@ interface CP0_i; input tlb_dTLBModified, input tlb_dAddressError ); - -endinterface \ No newline at end of file + +endinterface diff --git a/src/include/Cache.svh b/src/include/Cache.svh index 0a27fdc..a6a7cc5 100644 --- a/src/include/Cache.svh +++ b/src/include/Cache.svh @@ -4,10 +4,11 @@ `include "defines.svh" // IC for I-Cache -`define IC_TAGL 11 -`define IC_INDEXL 5 -`define IC_TAG_LENGTH 22 // Tag + Valid +`define IC_TAGL 11 +`define IC_INDEXL 5 +`define IC_TAG_LENGTH 22 // Tag + Valid `define IC_DATA_LENGTH 256 // 32Bytes +`define IC_ROW_LENGTH (2 ** (`IC_INDEXL - 1) - 1) typedef logic [`IC_DATA_LENGTH-1:0] ICData_t; typedef logic [32-`IC_TAGL-1:0] ICTagL_t; @@ -44,6 +45,7 @@ typedef struct packed { `define DC_INDEXL 4 `define DC_TAG_LENGTH 23 // Tag + Valid + Dirty `define DC_DATA_LENGTH 128 // 16Bytes +`define DC_ROW_LENGTH (2 ** (`DC_INDEXL - 1) - 1) typedef logic [`DC_DATA_LENGTH-1:0] DCData_t; typedef logic [32-`DC_TAGL-1:0] DCTagL_t; diff --git a/src/include/defines.svh b/src/include/defines.svh index 5109593..fec77a4 100644 --- a/src/include/defines.svh +++ b/src/include/defines.svh @@ -1,6 +1,8 @@ `ifndef DEFINES_SVH `define DEFINES_SVH +`define XLEN 32 + `define PCRST 32'hBFC00000 `define Off_TRef 9'h000 `define Off_GExc 9'h180 @@ -84,6 +86,7 @@ typedef enum logic [1:0] { URIGHT = 2'b10 } ALR_t; +`define CACHEOP_T_LEN 4 typedef struct packed { logic icache_op; logic dcache_op; diff --git a/src/mycpu_top.sv b/src/mycpu_top.sv index 00f27eb..426df52 100644 --- a/src/mycpu_top.sv +++ b/src/mycpu_top.sv @@ -73,8 +73,9 @@ module mycpu_top ( InstFetch_i inst(); Memory_i data(); - + CacheOp_i cache_op(); + CP0_i c0; logic C0_int; logic [4:0] C0_addr; @@ -114,7 +115,7 @@ module mycpu_top ( logic c0_tlbp; - AXI axi ( + AXI axi ( .arid (arid), .araddr (araddr), .arlen (arlen), @@ -156,45 +157,23 @@ module mycpu_top ( .bvalid(bvalid), .bready(bready), - .inst (inst_axi.axi), - .rdata(rdata_axi.axi), - .wdata(wdata_axi.axi) + .axi_inst (inst_axi.axi), + .axi_rdata(rdata_axi.axi), + .axi_wdata(wdata_axi.axi) ); - MMU mmu ( - .clk (aclk), - .rst (~aresetn), - .ic (icache.mu), - .dc (dcache.mu), - .inst (inst.mu), - .data (data.mu), - .cacheOp (cache_op.mu), - .inst_axi (inst_axi.mu), - .rdata_axi (rdata_axi.mu), - .wdata_axi (wdata_axi.mu), - .K0 (K0), - .in_kernel (in_kernel), - .tlbwi (tlb_tlbwi), - .tlbwr (tlb_tlbwr), - .tlbp (tlb_tlbp), - .c0_Random (c0_Random), - .c0_Index (c0_Index), - .c0_EntryHi (c0_EntryHi), - // .c0_PageMask (c0_PageMask), - .c0_EntryLo1 (c0_EntryLo1), - .c0_EntryLo0 (c0_EntryLo0), - .EntryHi (tlb_EntryHi), - // .PageMask (tlb_PageMask), - .EntryLo1 (tlb_EntryLo1), - .EntryLo0 (tlb_EntryLo0), - .Index (tlb_Index), - .iTLBRefill (iTLBRefill), - .iTLBInvalid (iTLBInvalid), - .iAddressError(iAddressError), - .dTLBRefill (dTLBRefill), - .dTLBInvalid (dTLBInvalid), - .dTLBModified (dTLBModified), - .dAddressError(dAddressError) + MU mmu ( + .clk (aclk), + .rst (~aresetn), + .icache (icache.mu), + .dcache (dcache.mu), + .instfetch (inst.mu), + .memory (data.mu), + .cacheop (cache_op.mu), + .axiread_inst (inst_axi.mu), + .axiread_data (rdata_axi.mu), + .axiwrite_data (wdata_axi.mu), + .cp0 (c0.mu) ); ICache ICache ( @@ -223,21 +202,7 @@ module mycpu_top ( .EBase (C0_EBase), .ext_int (ext_int), .interrupt (C0_int), - .tlbr (c0_tlbr), - .tlbp (c0_tlbp), - .K0 (K0), - .in_kernel (in_kernel), - .Random (c0_Random), - .Index (c0_Index), - .EntryHi (c0_EntryHi), - // .PageMask (c0_PageMask), - .EntryLo1 (c0_EntryLo1), - .EntryLo0 (c0_EntryLo0), - .tlb_EntryHi (tlb_EntryHi), - // .tlb_PageMask(tlb_PageMask), - .tlb_EntryLo1(tlb_EntryLo1), - .tlb_EntryLo0(tlb_EntryLo0), - .tlb_Index (tlb_Index) + .c0 (c0.cp0) ); Datapath datapath ( @@ -247,19 +212,7 @@ module mycpu_top ( .mem (data.cpu), .cache_op(cache_op.cpu), - .iTLBRefill (iTLBRefill), - .iTLBInvalid (iTLBInvalid), - .iAddressError(iAddressError), - .dTLBRefill (dTLBRefill), - .dTLBInvalid (dTLBInvalid), - .dTLBModified (dTLBModified), - .dAddressError(dAddressError), - .tlb_tlbwi (tlb_tlbwi), - .tlb_tlbwr (tlb_tlbwr), - .tlb_tlbp (tlb_tlbp), - .c0_tlbr (c0_tlbr), - .c0_tlbp (c0_tlbp), - + .C0 (c0.cpu), .C0_int (C0_int), .C0_addr (C0_addr), .C0_sel (C0_sel), @@ -270,7 +223,6 @@ module mycpu_top ( .C0_ERETPC (C0_ERETPC), .C0_Bev (C0_Bev), .C0_EBase (C0_EBase), - .C0_kernel (in_kernel), .debug_wb_pc (debug_wb_pc), .debug_wb_rf_wen (debug_wb_rf_wen), diff --git a/tools/ctrl2_maker.py b/tools/ctrl2_maker.py new file mode 100644 index 0000000..d492378 --- /dev/null +++ b/tools/ctrl2_maker.py @@ -0,0 +1,40 @@ +from curses.ascii import isdigit + +from zeroconf import instance_name_from_service_info + + +file_list = [('ectrl.txt', '.ECtrl'), + ('exc.txt', ''), + ('global.txt', ''), + ('mctrl0.txt', '.MCtrl0'), + ('mctrl1.txt', '.MCtrl1'), + ('pcs.txt', ''), + ('privilege.txt', ''), + ('trap.txt', '.Trap'), + ('wctrl.txt', '.WCtrl')] +mp = {} +inst_name = {} +for fi, subname in file_list: + with open(fi) as f: + lines = f.readlines() + title = lines[0].split() + items = [item.split() for item in lines[1:]] + for item in items: + for i in range(1, len(title)): + if title[i][-1].isdigit() and title[i] not in ['RS0', 'DP0', 'DP1']: + continue + if item[i] == '?': + continue + inst = item[0] + inst_name[inst] = ' '.join(item[len(title)+1:]) + signal_name = 'ctrl' + subname + '.' + title[i] + if inst not in mp: + mp[inst] = [(signal_name, item[i])] + else: + mp[inst].append((signal_name, item[i])) + +for inst in mp: + print(f'case {inst}: begin /* {inst_name[inst]} */') + for sig in mp[inst]: + print(f' {sig[0]} = {sig[1]}') + print('end') diff --git a/tools/ctrl_maker.py b/tools/ctrl_maker.py index ec48f5f..2f1fc48 100644 --- a/tools/ctrl_maker.py +++ b/tools/ctrl_maker.py @@ -1,4 +1,4 @@ -with open('global.txt') as f: +with open('clo.txt') as f: lines = f.readlines() title = lines[0].split() items = [x.split() for x in lines[1:]] diff --git a/tools/ectrl.txt b/tools/ectrl.txt index a849974..9ccdddb 100644 --- a/tools/ectrl.txt +++ b/tools/ectrl.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 ? ? ? ? ? ? ? ? ? ? ? // MUL 32'b100000?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LB 32'b100001?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LH -32'h100010?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LWL +32'b100010?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LWL 32'b100011?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LW 32'b100100?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LBU 32'b100101?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LHU -32'h100110?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LWR +32'b100110?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // LWR 32'b101000?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // SB 32'b101001?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // SH 32'b101010?????????????????????????? ADD 0 RS 1 1 IMM 1 ? IX 0 1 // SWL diff --git a/tools/global.txt b/tools/global.txt index 5726335..a44cfcc 100644 --- a/tools/global.txt +++ b/tools/global.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 0 0 0 1 1 0 0 1 0 // MUL 32'b100000?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LB 32'b100001?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LH -32'h100010?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LWL +32'b100010?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LWL 32'b100011?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LW 32'b100100?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LBU 32'b100101?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LHU -32'h100110?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LWR +32'b100110?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // LWR 32'b101000?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // SB 32'b101001?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // SH 32'b101010?????????????????????????? 0 0 0 0 1 0 0 0 0 1 // SWL diff --git a/tools/mctrl0.txt b/tools/mctrl0.txt index cf56b96..e51b24f 100644 --- a/tools/mctrl0.txt +++ b/tools/mctrl0.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 0 MUL? 1 0 ? PASST 0 0 0 MUL 0 1 0 // MUL 32'b100000?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LB 32'b100001?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LH -32'h100010?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LWL +32'b100010?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LWL 32'b100011?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LW 32'b100100?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LBU 32'b100101?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LHU -32'h100110?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LWR +32'b100110?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // LWR 32'b101000?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // SB 32'b101001?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // SH 32'b101010?????????????????????????? ? ? ? 0 ? ? ? ? ? 0 ? ? ? ? // SWL diff --git a/tools/mctrl1.txt b/tools/mctrl1.txt index 8c57f45..01d12bc 100644 --- a/tools/mctrl1.txt +++ b/tools/mctrl1.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 0 0 0 ? ? ? ? ? ? ? ? ? ? // MUL 32'b100000?????????????????????????? 0 0 0 0 1 0 1 ALIGN 0 0 CNOP 0 0 0 // LB 32'b100001?????????????????????????? 0 0 0 0 1 0 1 ALIGN 0 0 CNOP 0 0 0 // LH -32'h100010?????????????????????????? 0 0 0 0 1 0 ? ULEFT 0 1 CNOP 0 0 0 // LWL +32'b100010?????????????????????????? 0 0 0 0 1 0 ? ULEFT 0 1 CNOP 0 0 0 // LWL 32'b100011?????????????????????????? 0 0 0 0 1 0 ? ALIGN 0 0 CNOP 0 0 0 // LW 32'b100100?????????????????????????? 0 0 0 0 1 0 0 ALIGN 0 0 CNOP 0 0 0 // LBU 32'b100101?????????????????????????? 0 0 0 0 1 0 0 ALIGN 0 0 CNOP 0 0 0 // LHU -32'h100110?????????????????????????? 0 0 0 0 1 0 ? URIGHT 1 0 CNOP 0 0 0 // LWR +32'b100110?????????????????????????? 0 0 0 0 1 0 ? URIGHT 1 0 CNOP 0 0 0 // LWR 32'b101000?????????????????????????? 0 0 0 0 1 1 ? ALIGN 0 0 CNOP 0 0 0 // SB 32'b101001?????????????????????????? 0 0 0 0 1 1 ? ALIGN 0 0 CNOP 0 0 0 // SH 32'b101010?????????????????????????? 0 0 0 0 1 1 ? ULEFT 0 1 CNOP 0 0 0 // SWL diff --git a/tools/pcs.txt b/tools/pcs.txt index d1cf094..8e7fb13 100644 --- a/tools/pcs.txt +++ b/tools/pcs.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 0 0 0 // MUL 32'b100000?????????????????????????? 0 0 0 0 // LB 32'b100001?????????????????????????? 0 0 0 0 // LH -32'h100010?????????????????????????? 0 0 0 0 // LWL +32'b100010?????????????????????????? 0 0 0 0 // LWL 32'b100011?????????????????????????? 0 0 0 0 // LW 32'b100100?????????????????????????? 0 0 0 0 // LBU 32'b100101?????????????????????????? 0 0 0 0 // LHU -32'h100110?????????????????????????? 0 0 0 0 // LWR +32'b100110?????????????????????????? 0 0 0 0 // LWR 32'b101000?????????????????????????? 0 0 0 0 // SB 32'b101001?????????????????????????? 0 0 0 0 // SH 32'b101010?????????????????????????? 0 0 0 0 // SWL diff --git a/tools/privilege.txt b/tools/privilege.txt index a7c0de6..42bada7 100644 --- a/tools/privilege.txt +++ b/tools/privilege.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 // MUL 32'b100000?????????????????????????? 0 // LB 32'b100001?????????????????????????? 0 // LH -32'h100010?????????????????????????? 0 // LWL +32'b100010?????????????????????????? 0 // LWL 32'b100011?????????????????????????? 0 // LW 32'b100100?????????????????????????? 0 // LBU 32'b100101?????????????????????????? 0 // LHU -32'h100110?????????????????????????? 0 // LWR +32'b100110?????????????????????????? 0 // LWR 32'b101000?????????????????????????? 0 // SB 32'b101001?????????????????????????? 0 // SH 32'b101010?????????????????????????? 0 // SWL diff --git a/tools/test1.txt b/tools/test1.txt new file mode 100644 index 0000000..fb086cd --- /dev/null +++ b/tools/test1.txt @@ -0,0 +1,87 @@ +000000 00000 ????? ????? ????? 000000 +000000 ????? 00000 00000 00000 001000 +000000 00000 00000 00000 ????? 001111 +000000 00000 00000 ????? 00000 010000 +000000 ????? 00000 00000 00000 010001 +000000 00000 00000 ????? 00000 010010 +000000 ????? 00000 00000 00000 010011 +000000 ????? 00000 ????? 00000 001001 +000000 ????? ????? 00000 00000 011000 +000000 ????? ????? 00000 00000 011001 +000000 ????? ????? 00000 00000 011010 +000000 ????? ????? 00000 00000 011011 +000000 00000 ????? ????? ????? 000010 +000000 00000 ????? ????? ????? 000011 +000000 ????? ????? ????? 00000 000100 +000000 ????? ????? ????? 00000 000110 +000000 ????? ????? ????? 00000 000111 +000000 ????? ????? ????? 00000 001010 +000000 ????? ????? ????? 00000 001011 +000000 ????? ????? ????? 00000 100000 +000000 ????? ????? ????? 00000 100001 +000000 ????? ????? ????? 00000 100010 +000000 ????? ????? ????? 00000 100011 +000000 ????? ????? ????? 00000 100100 +000000 ????? ????? ????? 00000 100101 +000000 ????? ????? ????? 00000 100110 +000000 ????? ????? ????? 00000 100111 +000000 ????? ????? ????? 00000 101010 +000000 ????? ????? ????? 00000 101011 +000000 ????? ????? ????? ????? 001100 +000000 ????? ????? ????? ????? 001101 +000000 ????? ????? ????? ????? 110000 +000000 ????? ????? ????? ????? 110001 +000000 ????? ????? ????? ????? 110010 +000000 ????? ????? ????? ????? 110011 +000000 ????? ????? ????? ????? 110100 +000000 ????? ????? ????? ????? 110110 +000001 ????? 00000 ????? ????? ?????? +000001 ????? 00001 ????? ????? ?????? +000001 ????? 01000 ????? ????? ?????? +000001 ????? 01001 ????? ????? ?????? +000001 ????? 01010 ????? ????? ?????? +000001 ????? 01011 ????? ????? ?????? +000001 ????? 01100 ????? ????? ?????? +000001 ????? 01110 ????? ????? ?????? +000001 ????? 10000 ????? ????? ?????? +000001 ????? 10001 ????? ????? ?????? +000010 ????? ????? ????? ????? ?????? +000011 ????? ????? ????? ????? ?????? +000100 ????? ????? ????? ????? ?????? +000101 ????? ????? ????? ????? ?????? +000110 ????? 00000 ????? ????? ?????? +000111 ????? 00000 ????? ????? ?????? +001000 ????? ????? ????? ????? ?????? +001001 ????? ????? ????? ????? ?????? +001010 ????? ????? ????? ????? ?????? +001011 ????? ????? ????? ????? ?????? +001100 ????? ????? ????? ????? ?????? +001101 ????? ????? ????? ????? ?????? +001110 ????? ????? ????? ????? ?????? +001111 00000 ????? ????? ????? ?????? +010000 00000 ????? ????? 00000 000??? +010000 00100 ????? ????? 00000 000??? +010000 10000 00000 00000 00000 000001 +010000 10000 00000 00000 00000 000010 +010000 10000 00000 00000 00000 000110 +010000 10000 00000 00000 00000 001000 +010000 10000 00000 00000 00000 011000 +011100 ????? ????? 00000 00000 000000 +011100 ????? ????? 00000 00000 000001 +011100 ????? ????? 00000 00000 000100 +011100 ????? ????? 00000 00000 000101 +011100 ????? ????? ????? 00000 000010 +100000 ????? ????? ????? ????? ?????? +100001 ????? ????? ????? ????? ?????? +100010 ????? ????? ????? ????? ?????? +100011 ????? ????? ????? ????? ?????? +100100 ????? ????? ????? ????? ?????? +100101 ????? ????? ????? ????? ?????? +100110 ????? ????? ????? ????? ?????? +101000 ????? ????? ????? ????? ?????? +101001 ????? ????? ????? ????? ?????? +101010 ????? ????? ????? ????? ?????? +101011 ????? ????? ????? ????? ?????? +101110 ????? ????? ????? ????? ?????? +101111 ????? ????? ????? ????? ?????? +110011 ????? ????? ????? ????? ?????? \ No newline at end of file diff --git a/tools/trap.txt b/tools/trap.txt index 845fdd3..9d74dcb 100644 --- a/tools/trap.txt +++ b/tools/trap.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 ? ? ? // MUL 32'b100000?????????????????????????? 0 ? ? ? // LB 32'b100001?????????????????????????? 0 ? ? ? // LH -32'h100010?????????????????????????? 0 ? ? ? // LWL +32'b100010?????????????????????????? 0 ? ? ? // LWL 32'b100011?????????????????????????? 0 ? ? ? // LW 32'b100100?????????????????????????? 0 ? ? ? // LBU 32'b100101?????????????????????????? 0 ? ? ? // LHU -32'h100110?????????????????????????? 0 ? ? ? // LWR +32'b100110?????????????????????????? 0 ? ? ? // LWR 32'b101000?????????????????????????? 0 ? ? ? // SB 32'b101001?????????????????????????? 0 ? ? ? // SH 32'b101010?????????????????????????? 0 ? ? ? // SWL diff --git a/tools/wctrl.txt b/tools/wctrl.txt index 6a49917..26f53b3 100644 --- a/tools/wctrl.txt +++ b/tools/wctrl.txt @@ -74,11 +74,11 @@ 32'b011100???????????????00000000010 0 1 RD 0 0 // MUL 32'b100000?????????????????????????? 0 1 RT 1 ? // LB 32'b100001?????????????????????????? 0 1 RT 1 ? // LH -32'h100010?????????????????????????? 0 1 RT 1 ? // LWL +32'b100010?????????????????????????? 0 1 RT 1 ? // LWL 32'b100011?????????????????????????? 0 1 RT 1 ? // LW 32'b100100?????????????????????????? 0 1 RT 1 ? // LBU 32'b100101?????????????????????????? 0 1 RT 1 ? // LHU -32'h100110?????????????????????????? 0 1 RT 1 ? // LWR +32'b100110?????????????????????????? 0 1 RT 1 ? // LWR 32'b101000?????????????????????????? 0 0 ? ? ? // SB 32'b101001?????????????????????????? 0 0 ? ? ? // SH 32'b101010?????????????????????????? 0 0 ? ? ? // SWL