├── .vscode └── settings.json ├── README.md ├── sim ├── Makefile ├── top.sv └── bench.f ├── src └── sv │ ├── yuu_apb_slave │ ├── yuu_apb_slave_memory.sv │ ├── yuu_apb_slave_pkg.svh │ ├── yuu_apb_slave_sequencer.sv │ ├── yuu_apb_slave_sequence_lib.sv │ ├── yuu_apb_slave_item.sv │ ├── yuu_apb_slave_callbacks.sv │ ├── yuu_apb_slave_collector.sv │ ├── yuu_apb_slave_interface.svi │ ├── yuu_apb_slave_agent.sv │ ├── yuu_apb_slave_analyzer.sv │ ├── yuu_apb_slave_config.sv │ ├── yuu_apb_slave_monitor.sv │ └── yuu_apb_slave_driver.sv │ ├── yuu_apb_env │ ├── yuu_apb_env_pkg.svh │ ├── yuu_apb_virtual_sequencer.sv │ ├── yuu_apb_env_config.sv │ └── yuu_apb_env.sv │ ├── yuu_apb_common │ ├── yuu_apb_common_pkg.svh │ ├── yuu_apb_error.sv │ ├── yuu_apb_type.sv │ ├── yuu_apb_agent_config.sv │ └── yuu_apb_item.sv │ └── yuu_apb_master │ ├── yuu_apb_master_pkg.svh │ ├── yuu_apb_master_sequencer.sv │ ├── yuu_apb_master_sequence_lib.sv │ ├── yuu_apb_master_callbacks.sv │ ├── yuu_apb_master_item.sv │ ├── yuu_apb_master_adapter.sv │ ├── yuu_apb_master_collector.sv │ ├── yuu_apb_master_interface.svi │ ├── yuu_apb_master_analyzer.sv │ ├── yuu_apb_master_config.sv │ ├── yuu_apb_master_agent.sv │ ├── yuu_apb_master_monitor.sv │ └── yuu_apb_master_driver.sv ├── include ├── yuu_apb_pkg.sv ├── yuu_apb_defines.svh └── yuu_apb_interface.svi ├── LICENSE └── test ├── yuu_apb_ral_case.sv ├── yuu_apb_b2b_case.sv ├── yuu_apb_reset_case.sv ├── yuu_apb_direct_case.sv ├── yuu_apb_base_case.sv └── slave_ral_model.sv /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "window.zoomLevel": 2, 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yuu_apb 2 | UVM APB VIP, part of AMBA3&AMBA4 features supported 3 | 4 | ## Note 5 | [yuu_common](https://github.com/seabeam/yuu_common "YUU UVM utilities package") package is needed 6 | [yuu_amba](https://github.com/seabeam/yuu_amba "YUU UVM AMBA base package") package is needed -------------------------------------------------------------------------------- /sim/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | @rm .[a-zA-Z0-9]* -rf 3 | @ls | grep -v Makefile | grep -v bench.f | grep -v top.sv | xargs rm -rf 4 | @echo clean done 5 | 6 | comp: 7 | @mkdir -p log 8 | vcs -sverilog -full64 ${ADD} -debug_acc+all \ 9 | -q -ntb_opts uvm -lca -kdb \ 10 | -f bench.f \ 11 | -l log/compile.log 12 | 13 | case: 14 | @ls ../test | grep case | cut -d "." -f 1 15 | 16 | run: 17 | simv +UVM_TESTNAME=${CASE} -l log/sim.log ${ADD} 18 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_memory.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_MEMORY_SV 6 | `define YUU_APB_SLAVE_MEMORY_SV 7 | 8 | typedef yuu_common_memory yuu_apb_slave_memory; 9 | 10 | `endif 11 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_env/yuu_apb_env_pkg.svh: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_ENV_PKG_SVH 6 | `define YUU_APB_ENV_PKG_SVH 7 | 8 | `include "yuu_apb_env_config.sv" 9 | `include "yuu_apb_virtual_sequencer.sv" 10 | `include "yuu_apb_env.sv" 11 | 12 | `endif 13 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_common/yuu_apb_common_pkg.svh: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_COMMON_PKG_SVH 6 | `define YUU_APB_COMMON_PKG_SVH 7 | 8 | `include "yuu_apb_type.sv" 9 | `include "yuu_apb_error.sv" 10 | `include "yuu_apb_item.sv" 11 | `include "yuu_apb_agent_config.sv" 12 | 13 | `endif 14 | -------------------------------------------------------------------------------- /include/yuu_apb_pkg.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_PKG_SV 6 | `define YUU_APB_PKG_SV 7 | 8 | `include "yuu_apb_defines.svh" 9 | `include "yuu_apb_interface.svi" 10 | 11 | package yuu_apb_pkg; 12 | import uvm_pkg::*; 13 | `include "uvm_macros.svh" 14 | 15 | import yuu_common_pkg::*; 16 | import yuu_amba_pkg::*; 17 | 18 | `include "yuu_apb_common_pkg.svh" 19 | `include "yuu_apb_master_pkg.svh" 20 | `include "yuu_apb_slave_pkg.svh" 21 | `include "yuu_apb_env_pkg.svh" 22 | endpackage 23 | 24 | `endif 25 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_pkg.svh: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_PKG_SVH 6 | `define YUU_APB_SLAVE_PKG_SVH 7 | 8 | `include "yuu_apb_slave_config.sv" 9 | `include "yuu_apb_slave_item.sv" 10 | `include "yuu_apb_slave_memory.sv" 11 | `include "yuu_apb_slave_sequence_lib.sv" 12 | `include "yuu_apb_slave_callbacks.sv" 13 | `include "yuu_apb_slave_sequencer.sv" 14 | `include "yuu_apb_slave_driver.sv" 15 | `include "yuu_apb_slave_monitor.sv" 16 | `include "yuu_apb_slave_analyzer.sv" 17 | `include "yuu_apb_slave_collector.sv" 18 | `include "yuu_apb_slave_agent.sv" 19 | 20 | `endif 21 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_pkg.svh: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_PKG_SVH 6 | `define YUU_APB_MASTER_PKG_SVH 7 | 8 | `include "yuu_apb_master_config.sv" 9 | `include "yuu_apb_master_item.sv" 10 | `include "yuu_apb_master_sequence_lib.sv" 11 | `include "yuu_apb_master_callbacks.sv" 12 | `include "yuu_apb_master_sequencer.sv" 13 | `include "yuu_apb_master_driver.sv" 14 | `include "yuu_apb_master_monitor.sv" 15 | `include "yuu_apb_master_analyzer.sv" 16 | `include "yuu_apb_master_collector.sv" 17 | `include "yuu_apb_master_adapter.sv" 18 | `include "yuu_apb_master_agent.sv" 19 | 20 | `endif 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 seabeam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_sequencer.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_SEQUENCER_SV 6 | `define YUU_APB_SLAVE_SEQUENCER_SV 7 | 8 | class yuu_apb_slave_sequencer extends uvm_sequencer #(yuu_apb_slave_item); 9 | virtual yuu_apb_slave_interface vif; 10 | 11 | yuu_apb_slave_config cfg; 12 | uvm_event_pool events; 13 | 14 | `uvm_component_utils(yuu_apb_slave_sequencer) 15 | 16 | extern function new(string name, uvm_component parent); 17 | extern virtual function void connect_phase(uvm_phase phase); 18 | endclass 19 | 20 | function yuu_apb_slave_sequencer::new(string name, uvm_component parent); 21 | super.new(name, parent); 22 | endfunction 23 | 24 | function void yuu_apb_slave_sequencer::connect_phase(uvm_phase phase); 25 | super.connect_phase(phase); 26 | 27 | this.vif = cfg.vif; 28 | this.events = cfg.events; 29 | endfunction 30 | 31 | `endif 32 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_sequencer.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_SEQUENCER_SV 6 | `define YUU_APB_MASTER_SEQUENCER_SV 7 | 8 | class yuu_apb_master_sequencer extends uvm_sequencer #(yuu_apb_master_item); 9 | virtual yuu_apb_master_interface vif; 10 | 11 | yuu_apb_master_config cfg; 12 | uvm_event_pool events; 13 | 14 | `uvm_component_utils(yuu_apb_master_sequencer) 15 | 16 | extern function new(string name, uvm_component parent); 17 | extern virtual function void connect_phase(uvm_phase phase); 18 | endclass 19 | 20 | function yuu_apb_master_sequencer::new(string name, uvm_component parent); 21 | super.new(name, parent); 22 | endfunction 23 | 24 | function void yuu_apb_master_sequencer::connect_phase(uvm_phase phase); 25 | super.connect_phase(phase); 26 | 27 | this.vif = cfg.vif; 28 | this.events = cfg.events; 29 | endfunction 30 | 31 | `endif 32 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_sequence_lib.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_SEQUENCE_LIB_SV 6 | `define YUU_APB_SLAVE_SEQUENCE_LIB_SV 7 | 8 | typedef class yuu_apb_slave_sequencer; 9 | class yuu_apb_slave_sequence_base extends uvm_sequence #(yuu_apb_slave_item); 10 | virtual yuu_apb_slave_interface vif; 11 | 12 | yuu_apb_slave_config cfg; 13 | uvm_event_pool events; 14 | 15 | yuu_apb_error error_object; 16 | 17 | `uvm_object_utils(yuu_apb_slave_sequence_base) 18 | `uvm_declare_p_sequencer(yuu_apb_slave_sequencer) 19 | 20 | function new(string name = "yuu_apb_slave_response_sequence"); 21 | super.new(name); 22 | endfunction 23 | 24 | task pre_start(); 25 | cfg = p_sequencer.cfg; 26 | vif = cfg.vif; 27 | events = cfg.events; 28 | endtask 29 | 30 | task body(); 31 | `uvm_warning("body", "The body task should be OVERRIDED by derived class") 32 | endtask 33 | endclass 34 | 35 | `endif 36 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_sequence_lib.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_SEQUENCE_LIB_SV 6 | `define YUU_APB_MASTER_SEQUENCE_LIB_SV 7 | 8 | typedef class yuu_apb_master_sequencer; 9 | class yuu_apb_master_sequence_base extends uvm_sequence #(yuu_apb_master_item); 10 | virtual yuu_apb_master_interface vif; 11 | 12 | yuu_apb_master_config cfg; 13 | uvm_event_pool events; 14 | 15 | int unsigned n_item = 10; 16 | 17 | yuu_apb_error error_object; 18 | 19 | `uvm_object_utils(yuu_apb_master_sequence_base) 20 | `uvm_declare_p_sequencer(yuu_apb_master_sequencer) 21 | 22 | function new(string name = "yuu_apb_master_sequence_base"); 23 | super.new(name); 24 | endfunction 25 | 26 | virtual task pre_start(); 27 | cfg = p_sequencer.cfg; 28 | vif = cfg.vif; 29 | events = cfg.events; 30 | endtask 31 | 32 | virtual task body(); 33 | `uvm_warning("body", "The body task should be OVERRIDED by derived class") 34 | endtask 35 | endclass 36 | 37 | `endif 38 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_common/yuu_apb_error.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_ERROR_SV 6 | `define YUU_APB_ERROR_SV 7 | 8 | class yuu_apb_error extends uvm_object; 9 | int unsigned no_error_wt = 100; 10 | int unsigned invalid_addr_wt = 0; 11 | int unsigned read_only_wt = 0; 12 | int unsigned write_only_wt = 0; 13 | int unsigned currupt_data_wt = 0; 14 | 15 | rand e_yuu_apb_error_type error_type; 16 | 17 | constraint c_error_type { 18 | error_type dist { 19 | NO_ERROR := no_error_wt, 20 | INVALID_ADDR := invalid_addr_wt, 21 | READ_ONLY := read_only_wt, 22 | WRITE_ONLY := write_only_wt, 23 | CURRUPT_DATA := currupt_data_wt 24 | }; 25 | } 26 | 27 | 28 | `uvm_object_utils_begin(yuu_apb_error) 29 | `uvm_field_enum(e_yuu_apb_error_type, error_type, UVM_DEFAULT | UVM_NOCOMPARE) 30 | `uvm_object_utils_end 31 | 32 | function new(string name = "yuu_apb_error"); 33 | super.new(name); 34 | endfunction 35 | endclass 36 | 37 | `endif 38 | -------------------------------------------------------------------------------- /sim/top.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | 6 | module dummy( 7 | yuu_apb_master_interface m_if, 8 | yuu_apb_slave_interface s_if 9 | ); 10 | assign s_if.paddr = m_if.paddr; 11 | assign s_if.penable = m_if.penable; 12 | assign s_if.pwrite = m_if.pwrite; 13 | assign s_if.pwdata = m_if.pwdata; 14 | assign s_if.psel = m_if.psel; 15 | assign s_if.pstrb = m_if.pstrb; 16 | assign s_if.pprot = m_if.pprot; 17 | 18 | assign m_if.prdata = s_if.prdata; 19 | assign m_if.pready = s_if.pready; 20 | assign m_if.pslverr = s_if.pslverr; 21 | endmodule 22 | 23 | module top; 24 | logic clk; 25 | logic rst; 26 | 27 | yuu_apb_interface yuu_apb_if(); 28 | 29 | dummy DUT(yuu_apb_if.master_if[0], yuu_apb_if.slave_if[0]); 30 | 31 | initial begin 32 | uvm_config_db#(virtual yuu_apb_interface)::set(null, "*", "vif", yuu_apb_if); 33 | 34 | run_test(); 35 | end 36 | 37 | initial begin 38 | clk = 'b0; 39 | rst = 'b0; 40 | #12; 41 | rst = 'b1; 42 | end 43 | 44 | always #5 clk = ~clk; 45 | 46 | assign yuu_apb_if.pclk = clk; 47 | assign yuu_apb_if.preset_n = rst; 48 | endmodule 49 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_common/yuu_apb_type.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_TYPE_SV 6 | `define YUU_APB_TYPE_SV 7 | 8 | typedef bit[`YUU_APB_ADDR_WIDTH-1:0] yuu_apb_addr_t; 9 | typedef bit[`YUU_APB_DATA_WIDTH-1:0] yuu_apb_data_t; 10 | typedef bit[`YUU_APB_STRB_WIDTH-1:0] yuu_apb_strb_t; 11 | typedef class yuu_apb_master_item; 12 | typedef uvm_reg_predictor #(yuu_apb_master_item) yuu_apb_master_predictor; 13 | 14 | typedef enum bit{ 15 | READ, 16 | WRITE 17 | } yuu_apb_direction_e; 18 | 19 | typedef enum bit{ 20 | OKAY, 21 | ERROR 22 | } yuu_apb_response_e; 23 | 24 | typedef enum bit{ 25 | NORMAL, 26 | PRIVILEGED 27 | } yuu_apb_prot0_e; 28 | 29 | typedef enum bit{ 30 | SECURE, 31 | NON_SECURE 32 | } yuu_apb_prot1_e; 33 | 34 | typedef enum bit{ 35 | DATA, 36 | INSTRUCTION 37 | } yuu_apb_prot2_e; 38 | 39 | typedef enum bit[3:0]{ 40 | NO_ERROR, 41 | EARLIER_ENBALE, 42 | MISSED_ENABLE, 43 | MISSED_SELECT, 44 | INVALID_ADDR, 45 | READ_ONLY, 46 | WRITE_ONLY, 47 | CURRUPT_DATA 48 | } e_yuu_apb_error_type; 49 | 50 | `endif 51 | -------------------------------------------------------------------------------- /include/yuu_apb_defines.svh: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_DEFINES_SVH 6 | `define YUU_APB_DEFINES_SVH 7 | `ifndef YUU_APB_MASTER_NUM 8 | `define YUU_APB_MASTER_NUM 1 9 | `endif 10 | 11 | `ifndef YUU_APB_SLAVE_NUM 12 | `define YUU_APB_SLAVE_NUM 1 13 | `endif 14 | 15 | `ifndef YUU_APB_ADDR_WIDTH 16 | `define YUU_APB_ADDR_WIDTH 32 17 | `endif 18 | 19 | `ifndef YUU_APB_DATA_WIDTH 20 | `define YUU_APB_DATA_WIDTH 32 21 | `endif 22 | 23 | `define YUU_APB_STRB_WIDTH $clog2(`YUU_APB_DATA_WIDTH/8) 24 | 25 | `ifndef YUU_APB_MASTER_INPUT_TIME 26 | `define YUU_APB_MASTER_INPUT_TIME 1ns 27 | `endif 28 | 29 | `ifndef YUU_APB_MASTER_OUTPUT_TIME 30 | `define YUU_APB_MASTER_OUTPUT_TIME 1ns 31 | `endif 32 | 33 | `ifndef YUU_APB_SLAVE_INPUT_TIME 34 | `define YUU_APB_SLAVE_INPUT_TIME 1ns 35 | `endif 36 | 37 | `ifndef YUU_APB_SLAVE_OUTPUT_TIME 38 | `define YUU_APB_SLAVE_OUTPUT_TIME 1ns 39 | `endif 40 | 41 | `ifndef YUU_APB_MAX_IDLE 42 | `define YUU_APB_MAX_IDLE 16 43 | `endif 44 | 45 | `ifndef YUU_APB_MAX_WAIT 46 | `define YUU_APB_MAX_WAIT 16 47 | `endif 48 | 49 | `endif 50 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_item.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_ITEM_SV 6 | `define YUU_APB_SLAVE_ITEM_SV 7 | 8 | class yuu_apb_slave_item extends yuu_apb_item; 9 | yuu_apb_slave_config cfg; 10 | 11 | rand int unsigned wait_cycle; 12 | 13 | constraint c_wait { 14 | cfg.wait_enable == False -> wait_cycle == 0; 15 | wait_cycle < `YUU_APB_MAX_WAIT; 16 | } 17 | 18 | `uvm_object_utils_begin(yuu_apb_slave_item) 19 | `uvm_field_object (cfg, UVM_PRINT | UVM_COPY) 20 | `uvm_field_int (wait_cycle, UVM_PRINT | UVM_COPY) 21 | `uvm_object_utils_end 22 | 23 | extern function new(string name = "yuu_apb_slave_item"); 24 | extern function void pre_randomize(); 25 | endclass 26 | 27 | function yuu_apb_slave_item::new(string name = "yuu_apb_slave_item"); 28 | super.new(name); 29 | endfunction 30 | 31 | function void yuu_apb_slave_item::pre_randomize(); 32 | super.pre_randomize(); 33 | 34 | if (!uvm_config_db #(yuu_apb_slave_config)::get(null, get_full_name(), "cfg", cfg) && cfg == null) 35 | `uvm_fatal("pre_randomize", "Cannot get APB slave configuration in transaction") 36 | endfunction 37 | 38 | `endif 39 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_callbacks.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_CALLBACKS_SV 6 | `define YUU_APB_SLAVE_CALLBACKS_SV 7 | 8 | typedef class yuu_apb_slave_driver; 9 | typedef class yuu_apb_slave_monitor; 10 | 11 | class yuu_apb_slave_driver_callback extends uvm_callback; 12 | `uvm_object_utils(yuu_apb_slave_driver_callback) 13 | 14 | function new(string name = "yuu_apb_slave_driver_callback"); 15 | super.new(name); 16 | endfunction 17 | 18 | virtual task pre_send(yuu_apb_slave_driver driver, yuu_apb_slave_item item); 19 | endtask 20 | 21 | virtual task post_send(yuu_apb_slave_driver driver, yuu_apb_slave_item item); 22 | endtask 23 | endclass 24 | 25 | 26 | class yuu_apb_slave_monitor_callback extends uvm_callback; 27 | `uvm_object_utils(yuu_apb_slave_monitor_callback) 28 | 29 | function new(string name = "yuu_apb_slave_monitor_callback"); 30 | super.new(name); 31 | endfunction 32 | 33 | virtual task pre_collect(yuu_apb_slave_monitor monitor, yuu_apb_slave_item item); 34 | endtask 35 | 36 | virtual task post_collect(yuu_apb_slave_monitor monitor, yuu_apb_slave_item item); 37 | endtask 38 | endclass 39 | 40 | `endif 41 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_callbacks.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_CALLBACKS_SV 6 | `define YUU_APB_MASTER_CALLBACKS_SV 7 | 8 | typedef class yuu_apb_master_driver; 9 | typedef class yuu_apb_master_monitor; 10 | 11 | class yuu_apb_master_driver_callback extends uvm_callback; 12 | `uvm_object_utils(yuu_apb_master_driver_callback) 13 | 14 | function new(string name = "yuu_apb_master_driver_callback"); 15 | super.new(name); 16 | endfunction 17 | 18 | virtual task pre_send(yuu_apb_master_driver driver, yuu_apb_master_item item); 19 | endtask 20 | 21 | virtual task post_send(yuu_apb_master_driver driver, yuu_apb_master_item item); 22 | endtask 23 | endclass 24 | 25 | 26 | class yuu_apb_master_monitor_callback extends uvm_callback; 27 | `uvm_object_utils(yuu_apb_master_monitor_callback) 28 | 29 | function new(string name = "yuu_apb_master_monitor_callback"); 30 | super.new(name); 31 | endfunction 32 | 33 | virtual task pre_collect(yuu_apb_master_monitor monitor, yuu_apb_master_item item); 34 | endtask 35 | 36 | virtual task post_collect(yuu_apb_master_monitor monitor, yuu_apb_master_item item); 37 | endtask 38 | endclass 39 | 40 | `endif 41 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_item.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_ITEM_SV 6 | `define YUU_APB_MASTER_ITEM_SV 7 | 8 | class yuu_apb_master_item extends yuu_apb_item; 9 | yuu_apb_master_config cfg; 10 | 11 | rand int unsigned idle_delay; 12 | 13 | constraint c_idle { 14 | cfg.idle_enable == False -> idle_delay == 0; 15 | idle_delay < `YUU_APB_MAX_IDLE; 16 | } 17 | 18 | constraint c_response { 19 | resp == OKAY; 20 | } 21 | 22 | `uvm_object_utils_begin(yuu_apb_master_item) 23 | `uvm_field_int (idle_delay, UVM_PRINT | UVM_COPY) 24 | `uvm_object_utils_end 25 | 26 | extern function new(string name = "yuu_apb_master_item"); 27 | extern function void pre_randomize(); 28 | endclass 29 | 30 | function yuu_apb_master_item::new(string name = "yuu_apb_master_item"); 31 | super.new(name); 32 | endfunction 33 | 34 | function void yuu_apb_master_item::pre_randomize(); 35 | super.pre_randomize(); 36 | 37 | if (!uvm_config_db #(yuu_apb_master_config)::get(null, get_full_name(), "cfg", cfg) && cfg == null) 38 | `uvm_fatal("pre_randomize", "Cannot get APB master configuration in transaction") 39 | 40 | if (!cfg.apb4_enable) begin 41 | prot0.rand_mode(0); 42 | prot1.rand_mode(0); 43 | prot2.rand_mode(0); 44 | end 45 | endfunction 46 | 47 | `endif 48 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_env/yuu_apb_virtual_sequencer.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_VIRTUAL_SEQUENCER_SV 6 | `define YUU_APB_VIRTUAL_SEQUENCER_SV 7 | 8 | class yuu_apb_virtual_sequencer extends uvm_virtual_sequencer; 9 | virtual yuu_apb_interface vif; 10 | 11 | yuu_apb_env_config cfg; 12 | uvm_event_pool events; 13 | 14 | yuu_apb_master_sequencer master_sequencer[]; 15 | yuu_apb_slave_sequencer slave_sequencer[]; 16 | 17 | `uvm_component_utils(yuu_apb_virtual_sequencer) 18 | 19 | extern function new(string name, uvm_component parent); 20 | extern function void connect_phase(uvm_phase phase); 21 | endclass 22 | 23 | function yuu_apb_virtual_sequencer::new(string name, uvm_component parent); 24 | super.new(name, parent); 25 | endfunction 26 | 27 | function void yuu_apb_virtual_sequencer::connect_phase(uvm_phase phase); 28 | super.connect_phase(phase); 29 | 30 | if (cfg == null) 31 | `uvm_fatal("connect_phase", "Virtual sequencer cannot get env configuration object") 32 | 33 | vif = cfg.apb_if; 34 | events = cfg.events; 35 | endfunction 36 | 37 | class yuu_apb_virtual_sequence extends uvm_sequence_base; 38 | `uvm_object_utils(yuu_apb_virtual_sequence) 39 | `uvm_declare_p_sequencer(yuu_apb_virtual_sequencer) 40 | 41 | function new(string name = "yuu_apb_virtual_sequence"); 42 | super.new(name); 43 | endfunction 44 | endclass 45 | 46 | `endif 47 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_adapter.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_ADAPTER_SV 6 | `define YUU_APB_MASTER_ADAPTER_SV 7 | 8 | class yuu_apb_master_adapter extends uvm_reg_adapter; 9 | yuu_apb_master_config cfg; 10 | 11 | `uvm_object_utils(yuu_apb_master_adapter) 12 | 13 | extern function new(string name = "yuu_apb_master_adapter"); 14 | extern virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 15 | extern virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 16 | endclass 17 | 18 | function yuu_apb_master_adapter::new(string name = "yuu_apb_master_adapter"); 19 | super.new(name); 20 | endfunction 21 | 22 | function uvm_sequence_item yuu_apb_master_adapter::reg2bus(const ref uvm_reg_bus_op rw); 23 | yuu_apb_master_item item = yuu_apb_master_item::type_id::create("item"); 24 | item.direction = (rw.kind == UVM_READ) ? READ : WRITE; 25 | item.addr = rw.addr; 26 | item.data = rw.data; 27 | return item; 28 | endfunction 29 | 30 | function void yuu_apb_master_adapter::bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 31 | yuu_apb_master_item item; 32 | if (!$cast(item, bus_item)) begin 33 | `uvm_fatal("bus2reg", "Provided bus_item is not of the correct type(yuu_apb_master_item)") 34 | return; 35 | end 36 | rw.kind = int'(item.direction) ? UVM_WRITE : UVM_READ; 37 | rw.addr = item.addr; 38 | rw.data = item.data; 39 | rw.status = (item.resp == OKAY) ? UVM_IS_OK : UVM_NOT_OK; 40 | endfunction 41 | 42 | `endif 43 | -------------------------------------------------------------------------------- /sim/bench.f: -------------------------------------------------------------------------------- 1 | -timescale=1ns/1ps 2 | //------------------------------------- 3 | // DUT Define 4 | //------------------------------------- 5 | 6 | //------------------------------------- 7 | // DUT Include 8 | //------------------------------------- 9 | 10 | //------------------------------------- 11 | // DUT Filelist 12 | //------------------------------------- 13 | 14 | //------------------------------------- 15 | // C Define 16 | //------------------------------------- 17 | 18 | //------------------------------------- 19 | // C Include 20 | //------------------------------------- 21 | //-I../src/c 22 | 23 | //------------------------------------- 24 | // C Filelist 25 | //------------------------------------- 26 | 27 | //------------------------------------- 28 | // SV Define 29 | //------------------------------------- 30 | +define+YUU_APB_MASTER_NUM=1 31 | +define+YUU_APB_SLAVE_NUM=1 32 | +define+YUU_APB_ADDR_WIDTH=32 33 | +define+YUU_APB_DATA_WIDTH=32 34 | 35 | //------------------------------------- 36 | // SV Include 37 | //------------------------------------- 38 | +incdir+../../yuu_common/include 39 | +incdir+../../yuu_common/src/sv 40 | +incdir+../../yuu_amba/include/ 41 | +incdir+../../yuu_amba/src/sv 42 | +incdir+../include 43 | +incdir+../src/sv/yuu_apb_common 44 | +incdir+../src/sv/yuu_apb_master 45 | +incdir+../src/sv/yuu_apb_slave 46 | +incdir+../src/sv/yuu_apb_env 47 | +incdir+../test 48 | 49 | //------------------------------------- 50 | // SV Filelist 51 | //------------------------------------- 52 | ../../yuu_common/include/yuu_common_pkg.sv 53 | ../../yuu_amba/include/yuu_amba_pkg.sv 54 | ../include/yuu_apb_pkg.sv 55 | 56 | //------------------------------------- 57 | // Case List 58 | //------------------------------------- 59 | ../test/yuu_apb_base_case.sv 60 | ../test/yuu_apb_direct_case.sv 61 | ../test/yuu_apb_b2b_case.sv 62 | ../test/yuu_apb_ral_case.sv 63 | ../test/yuu_apb_reset_case.sv 64 | 65 | //------------------------------------- 66 | // Top Module 67 | //------------------------------------- 68 | top.sv 69 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_collector.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_COLLECTOR_SV 6 | `define YUU_APB_SLAVE_COLLECTOR_SV 7 | 8 | class yuu_apb_slave_collector extends uvm_subscriber #(yuu_apb_slave_item); 9 | virtual yuu_apb_slave_interface vif; 10 | 11 | yuu_apb_slave_config cfg; 12 | uvm_event_pool events; 13 | 14 | yuu_apb_slave_item item; 15 | 16 | covergroup apb_transaction_cg(); 17 | direction: coverpoint item.direction { 18 | bins apb_write = {WRITE}; 19 | bins apb_read = {READ}; 20 | } 21 | 22 | response: coverpoint item.resp { 23 | bins apb_okay = {OKAY}; 24 | bins apb_error = {ERROR}; 25 | } 26 | endgroup 27 | 28 | `uvm_component_utils_begin(yuu_apb_slave_collector) 29 | `uvm_component_utils_end 30 | 31 | extern function new(string name, uvm_component parent); 32 | extern virtual function void connect_phase(uvm_phase phase); 33 | extern virtual task run_phase(uvm_phase phase); 34 | 35 | extern virtual function void write(yuu_apb_slave_item t); 36 | endclass 37 | 38 | function yuu_apb_slave_collector::new(string name, uvm_component parent); 39 | super.new(name, parent); 40 | 41 | apb_transaction_cg = new; 42 | endfunction 43 | 44 | function void yuu_apb_slave_collector::connect_phase(uvm_phase phase); 45 | this.vif = cfg.vif; 46 | this.events = cfg.events; 47 | endfunction 48 | 49 | task yuu_apb_slave_collector::run_phase(uvm_phase phase); 50 | endtask 51 | 52 | function void yuu_apb_slave_collector::write(yuu_apb_slave_item t); 53 | item = yuu_apb_slave_item::type_id::create("item"); 54 | item.copy(t); 55 | apb_transaction_cg.sample(); 56 | endfunction 57 | 58 | `endif 59 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_collector.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_COLLECTOR_SV 6 | `define YUU_APB_MASTER_COLLECTOR_SV 7 | 8 | class yuu_apb_master_collector extends uvm_subscriber #(yuu_apb_master_item); 9 | virtual yuu_apb_master_interface vif; 10 | 11 | yuu_apb_master_config cfg; 12 | uvm_event_pool events; 13 | 14 | yuu_apb_master_item item; 15 | 16 | covergroup apb_transaction_cg(); 17 | direction: coverpoint item.direction { 18 | bins apb_write = {WRITE}; 19 | bins apb_read = {READ}; 20 | } 21 | 22 | response: coverpoint item.resp { 23 | bins apb_okay = {OKAY}; 24 | bins apb_error = {ERROR}; 25 | } 26 | endgroup 27 | 28 | `uvm_component_utils_begin(yuu_apb_master_collector) 29 | `uvm_component_utils_end 30 | 31 | extern function new(string name, uvm_component parent); 32 | extern virtual function void connect_phase(uvm_phase phase); 33 | extern virtual task run_phase(uvm_phase phase); 34 | 35 | extern virtual function void write(yuu_apb_master_item t); 36 | endclass 37 | 38 | function yuu_apb_master_collector::new(string name, uvm_component parent); 39 | super.new(name, parent); 40 | 41 | apb_transaction_cg = new; 42 | endfunction 43 | 44 | function void yuu_apb_master_collector::connect_phase(uvm_phase phase); 45 | this.vif = cfg.vif; 46 | this.events = cfg.events; 47 | endfunction 48 | 49 | task yuu_apb_master_collector::run_phase(uvm_phase phase); 50 | endtask 51 | 52 | 53 | function void yuu_apb_master_collector::write(yuu_apb_master_item t); 54 | item = yuu_apb_master_item::type_id::create("item"); 55 | item.copy(t); 56 | apb_transaction_cg.sample(); 57 | endfunction 58 | 59 | `endif 60 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_common/yuu_apb_agent_config.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_AGENT_CONFIG_SV 6 | `define YUU_APB_AGENT_CONFIG_SV 7 | 8 | class yuu_apb_agent_config extends uvm_object; 9 | uvm_event_pool events; 10 | 11 | int index = -1; 12 | int unsigned addr_width = `YUU_APB_ADDR_WIDTH; 13 | int unsigned data_width = `YUU_APB_DATA_WIDTH; 14 | int unsigned timeout = 0; 15 | uvm_active_passive_enum is_active = UVM_ACTIVE; 16 | 17 | boolean coverage_enable = False; 18 | boolean analysis_enable = False; 19 | // APB3 support, include Wait states and Error reporting 20 | boolean apb3_enable = False; 21 | // APB4 support, include Transaction protection and Sparse data transfer 22 | boolean apb4_enable = False; 23 | boolean protocol_check_enable = True; 24 | 25 | `uvm_object_utils_begin(yuu_apb_agent_config) 26 | `uvm_field_int ( index, UVM_PRINT | UVM_COPY) 27 | `uvm_field_int ( addr_width, UVM_PRINT | UVM_COPY) 28 | `uvm_field_int ( data_width, UVM_PRINT | UVM_COPY) 29 | `uvm_field_int ( timeout, UVM_PRINT | UVM_COPY) 30 | `uvm_field_enum (uvm_active_passive_enum, is_active, UVM_PRINT | UVM_COPY) 31 | `uvm_field_enum (boolean, coverage_enable, UVM_PRINT | UVM_COPY) 32 | `uvm_field_enum (boolean, analysis_enable, UVM_PRINT | UVM_COPY) 33 | `uvm_field_enum (boolean, apb3_enable, UVM_PRINT | UVM_COPY) 34 | `uvm_field_enum (boolean, apb4_enable, UVM_PRINT | UVM_COPY) 35 | `uvm_field_enum (boolean, protocol_check_enable,UVM_PRINT | UVM_COPY) 36 | `uvm_object_utils_end 37 | 38 | function new(string name = "yuu_apb_agent_config"); 39 | super.new(name); 40 | endfunction 41 | endclass 42 | 43 | `endif 44 | -------------------------------------------------------------------------------- /test/yuu_apb_ral_case.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_RAL_CASE_SV 6 | `define YUU_APB_RAL_CASE_SV 7 | 8 | class yuu_master_ral_virtual_sequence extends yuu_apb_virtual_sequence; 9 | slave_ral_model model; 10 | 11 | `uvm_object_utils(yuu_master_ral_virtual_sequence) 12 | 13 | function new(string name="yuu_master_ral_virtual_sequence"); 14 | super.new(name); 15 | endfunction : new 16 | 17 | task body(); 18 | yuu_apb_response_sequence rsp_seq = yuu_apb_response_sequence::type_id::create("rsp_seq"); 19 | fork 20 | begin 21 | uvm_status_e status; 22 | uvm_reg_data_t value; 23 | 24 | #100ns; 25 | model.control.Clock.write(status, 32'h12); 26 | model.common.TIMER.write(status, 32'h5A); 27 | #100ns; 28 | model.control.Clock.read(status, value); 29 | `uvm_info("body", $sformatf("Register Clock value is %8h", value), UVM_LOW); 30 | model.common.TIMER.read(status, value); 31 | `uvm_info("body", $sformatf("Register Timer value is %8h", value), UVM_LOW); 32 | end 33 | rsp_seq.start(p_sequencer.slave_sequencer[0]); 34 | join_any 35 | endtask 36 | endclass : yuu_master_ral_virtual_sequence 37 | 38 | 39 | class yuu_apb_ral_case extends yuu_apb_base_case; 40 | `uvm_component_utils(yuu_apb_ral_case) 41 | 42 | function new(string name, uvm_component parent); 43 | super.new(name, parent); 44 | endfunction : new 45 | 46 | function void build_phase(uvm_phase phase); 47 | super.build_phase(phase); 48 | 49 | cfg.mst_cfg[0].idle_enable = False; 50 | cfg.mst_cfg[0].use_reg_model = True; 51 | cfg.slv_cfg[0].wait_enable = False; 52 | endfunction : build_phase 53 | 54 | task run_phase(uvm_phase phase); 55 | yuu_master_ral_virtual_sequence seq; 56 | 57 | seq = yuu_master_ral_virtual_sequence::type_id::create("seq"); 58 | seq.model = model; 59 | phase.raise_objection(this); 60 | seq.start(vsequencer); 61 | phase.drop_objection(this); 62 | endtask : run_phase 63 | endclass : yuu_apb_ral_case 64 | 65 | `endif 66 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_env/yuu_apb_env_config.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_ENV_CONFIG_SV 6 | `define YUU_APB_ENV_CONFIG_SV 7 | 8 | class yuu_apb_env_config extends uvm_object; 9 | virtual yuu_apb_interface apb_if; 10 | 11 | yuu_apb_master_config mst_cfg[$]; 12 | yuu_apb_slave_config slv_cfg[$]; 13 | uvm_event_pool events; 14 | 15 | boolean compare_enable = False; 16 | boolean bus_checker_enable= False; 17 | 18 | `uvm_object_utils_begin(yuu_apb_env_config) 19 | `uvm_field_enum (boolean, compare_enable, UVM_PRINT | UVM_COPY) 20 | `uvm_field_enum (boolean, bus_checker_enable, UVM_PRINT | UVM_COPY) 21 | `uvm_field_queue_object ( mst_cfg, UVM_PRINT | UVM_COPY) 22 | `uvm_field_queue_object ( slv_cfg, UVM_PRINT | UVM_COPY) 23 | `uvm_object_utils_end 24 | 25 | extern function new(string name = "yuu_apb_env_config"); 26 | extern virtual function void set_config(yuu_apb_agent_config cfg); 27 | extern virtual function void set_configs(yuu_apb_agent_config cfg[]); 28 | endclass 29 | 30 | function yuu_apb_env_config::new(string name = "yuu_apb_env_config"); 31 | super.new(name); 32 | endfunction 33 | 34 | function void yuu_apb_env_config::set_config(yuu_apb_agent_config cfg); 35 | yuu_apb_master_config m_cfg; 36 | yuu_apb_slave_config s_cfg; 37 | 38 | if (cfg == null) 39 | `uvm_fatal("set_config", "Which yuu_apb agent config set is null") 40 | 41 | cfg.events = events; 42 | if ($cast(m_cfg, cfg)) begin 43 | if(m_cfg.index >= 0) 44 | m_cfg.vif = apb_if.get_master_if(m_cfg.index); 45 | mst_cfg.push_back(m_cfg); 46 | end 47 | else if ($cast(s_cfg, cfg))begin 48 | if (s_cfg.index >= 0) 49 | s_cfg.vif = apb_if.get_slave_if(s_cfg.index); 50 | slv_cfg.push_back(s_cfg); 51 | end 52 | else 53 | `uvm_fatal("set_config", "Invalid yuu_apb agent configure object type") 54 | endfunction 55 | 56 | function void yuu_apb_env_config::set_configs(yuu_apb_agent_config cfg[]); 57 | foreach (cfg[i]) 58 | set_config(cfg[i]); 59 | endfunction 60 | 61 | `endif 62 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_common/yuu_apb_item.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_ITEM_SV 6 | `define YUU_APB_ITEM_SV 7 | 8 | class yuu_apb_item extends yuu_amba_item; 9 | rand yuu_apb_addr_t addr; 10 | rand yuu_apb_data_t data; 11 | rand yuu_apb_direction_e direction; 12 | rand yuu_apb_response_e resp; 13 | yuu_apb_strb_t strb; 14 | rand yuu_apb_prot0_e prot0 = PRIVILEGED; 15 | rand yuu_apb_prot1_e prot1 = NON_SECURE; 16 | rand yuu_apb_prot2_e prot2 = DATA; 17 | 18 | yuu_apb_error error_object; 19 | 20 | 21 | constraint c_len { 22 | len == 0; 23 | } 24 | 25 | constraint c_address { 26 | addr == start_address; 27 | } 28 | 29 | constraint c_burst_type { 30 | burst_type == INCR; 31 | } 32 | 33 | constraint c_data { 34 | direction == READ -> data == 'h0; 35 | } 36 | 37 | `uvm_object_utils_begin(yuu_apb_item) 38 | `uvm_field_int ( addr, UVM_DEFAULT) 39 | `uvm_field_int ( data, UVM_DEFAULT) 40 | `uvm_field_enum (yuu_apb_direction_e, direction, UVM_DEFAULT | UVM_NOCOMPARE) 41 | `uvm_field_enum (yuu_apb_response_e, resp, UVM_DEFAULT | UVM_NOCOMPARE) 42 | `uvm_field_int ( strb, UVM_DEFAULT | UVM_NOCOMPARE) 43 | `uvm_field_enum (yuu_apb_prot0_e, prot0, UVM_DEFAULT | UVM_NOCOMPARE) 44 | `uvm_field_enum (yuu_apb_prot1_e, prot1, UVM_DEFAULT | UVM_NOCOMPARE) 45 | `uvm_field_enum (yuu_apb_prot2_e, prot2, UVM_DEFAULT | UVM_NOCOMPARE) 46 | `uvm_field_object ( error_object, UVM_DEFAULT | UVM_NOCOMPARE) 47 | `uvm_object_utils_end 48 | 49 | extern function new(string name = "yuu_apb_item"); 50 | extern function void pre_randomize(); 51 | extern function void post_randomize(); 52 | endclass 53 | 54 | function yuu_apb_item::new(string name = "yuu_apb_item"); 55 | super.new(name); 56 | endfunction 57 | 58 | function void yuu_apb_item::pre_randomize(); 59 | address_aligned_enable = True; 60 | endfunction 61 | 62 | function void yuu_apb_item::post_randomize(); 63 | super.post_randomize(); 64 | 65 | strb = 0; 66 | if (direction == READ) begin 67 | data = 0; 68 | end 69 | else begin 70 | for (int i=lower_byte_lane[0]; i<=upper_byte_lane[0]; i++) begin 71 | strb[i] = 1'b1; 72 | end 73 | end 74 | endfunction 75 | 76 | `endif 77 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_interface.svi: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_INTERFACE_SVI 6 | `define YUU_APB_SLAVE_INTERFACE_SVI 7 | 8 | interface yuu_apb_slave_interface(); 9 | // AMBA2 APB Specification 10 | logic pclk; 11 | logic preset_n; 12 | logic [`YUU_APB_ADDR_WIDTH-1:0] paddr; 13 | logic penable; 14 | logic pwrite; 15 | logic [`YUU_APB_DATA_WIDTH-1:0] pwdata; 16 | logic [`YUU_APB_DATA_WIDTH-1:0] prdata; 17 | logic psel; 18 | 19 | // AMBA3 APB Protocol Specification v1.0 20 | logic pready; 21 | logic pslverr; 22 | 23 | // AMBA APB Protocol Specification v2.0 24 | logic [2:0] pprot; 25 | logic [`YUU_APB_DATA_WIDTH/8-1:0] pstrb; 26 | 27 | clocking cb @(posedge pclk); 28 | endclocking 29 | 30 | clocking drv_cb @(posedge pclk); 31 | default input #`YUU_APB_SLAVE_INPUT_TIME output #`YUU_APB_SLAVE_OUTPUT_TIME; 32 | 33 | input paddr; 34 | input penable; 35 | input pwrite; 36 | input pwdata; 37 | input psel; 38 | input pstrb; 39 | input pprot; 40 | 41 | output prdata; 42 | output pready; 43 | output pslverr; 44 | endclocking 45 | 46 | clocking mon_cb @(posedge pclk); 47 | default input #`YUU_APB_SLAVE_INPUT_TIME output #`YUU_APB_SLAVE_OUTPUT_TIME; 48 | 49 | input paddr; 50 | input penable; 51 | input pwrite; 52 | input pwdata; 53 | input psel; 54 | input pstrb; 55 | input pprot; 56 | 57 | input prdata; 58 | input pready; 59 | input pslverr; 60 | endclocking 61 | 62 | modport drv_mp ( 63 | input preset_n, 64 | input paddr, 65 | input penable, 66 | input pwrite, 67 | input pwdata, 68 | input psel, 69 | input pstrb, 70 | input pprot, 71 | 72 | output prdata, 73 | output pready, 74 | output pslverr 75 | ); 76 | 77 | modport mon_mp ( 78 | input preset_n, 79 | input paddr, 80 | input penable, 81 | input pwrite, 82 | input pwdata, 83 | input psel, 84 | input pstrb, 85 | input pprot, 86 | 87 | input prdata, 88 | input pready, 89 | input pslverr 90 | ); 91 | 92 | task wait_cycle(); 93 | @(posedge pclk); 94 | endtask 95 | endinterface 96 | 97 | `endif 98 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_env/yuu_apb_env.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_ENV_SV 6 | `define YUU_APB_ENV_SV 7 | 8 | class yuu_apb_env extends uvm_env; 9 | yuu_apb_master_agent master[]; 10 | yuu_apb_slave_agent slave[]; 11 | yuu_apb_virtual_sequencer vsequencer; 12 | 13 | yuu_apb_env_config cfg; 14 | 15 | `uvm_component_utils(yuu_apb_env) 16 | 17 | extern function new(string name, uvm_component parent); 18 | extern function void build_phase(uvm_phase phase); 19 | extern function void connect_phase(uvm_phase phase); 20 | endclass 21 | 22 | function yuu_apb_env::new(string name, uvm_component parent); 23 | super.new(name, parent); 24 | endfunction 25 | 26 | function void yuu_apb_env::build_phase(uvm_phase phase); 27 | if(!uvm_config_db#(yuu_apb_env_config)::get(null, get_full_name(), "cfg", cfg)) 28 | `uvm_fatal("build_phase", "Cannot get yuu_apb_env_config.") 29 | if (cfg == null) 30 | `uvm_fatal("build_phase", "Get a null env configuration") 31 | 32 | vsequencer = yuu_apb_virtual_sequencer::type_id::create("vsequencer", this); 33 | 34 | master = new[cfg.mst_cfg.size()]; 35 | vsequencer.master_sequencer = new[cfg.mst_cfg.size()]; 36 | foreach(master[i]) begin 37 | if (cfg.mst_cfg[i].index != -1) begin 38 | uvm_config_db#(yuu_apb_master_config)::set(this, $sformatf("master_%s", cfg.mst_cfg[i].get_name()), "cfg", cfg.mst_cfg[i]); 39 | master[i] = yuu_apb_master_agent::type_id::create($sformatf("master_%s", cfg.mst_cfg[i].get_name()), this); 40 | end 41 | end 42 | 43 | slave = new[cfg.slv_cfg.size()]; 44 | vsequencer.slave_sequencer = new[cfg.slv_cfg.size()]; 45 | foreach(slave[i]) begin 46 | if (cfg.slv_cfg[i].index != -1) begin 47 | uvm_config_db#(yuu_apb_slave_config)::set(this, $sformatf("slave_%s", cfg.slv_cfg[i].get_name()), "cfg", cfg.slv_cfg[i]); 48 | slave[i] = yuu_apb_slave_agent::type_id::create($sformatf("slave_%s", cfg.slv_cfg[i].get_name()), this); 49 | end 50 | end 51 | 52 | vsequencer.cfg = cfg; 53 | endfunction 54 | 55 | function void yuu_apb_env::connect_phase(uvm_phase phase); 56 | foreach (cfg.mst_cfg[i]) begin 57 | cfg.mst_cfg[i].events = cfg.events; 58 | vsequencer.master_sequencer[i] = master[i].sequencer; 59 | end 60 | foreach (cfg.slv_cfg[i]) begin 61 | cfg.slv_cfg[i].events = cfg.events; 62 | vsequencer.slave_sequencer[i] = slave[i].sequencer; 63 | end 64 | endfunction 65 | 66 | `endif 67 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_interface.svi: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_INTERFACE_SVI 6 | `define YUU_APB_MASTER_INTERFACE_SVI 7 | 8 | interface yuu_apb_master_interface(); 9 | // AMBA2 APB Specification 10 | logic pclk; 11 | logic preset_n; 12 | logic [`YUU_APB_ADDR_WIDTH-1:0] paddr; 13 | logic penable; 14 | logic pwrite; 15 | logic [`YUU_APB_DATA_WIDTH-1:0] pwdata; 16 | logic [`YUU_APB_DATA_WIDTH-1:0] prdata; 17 | logic psel; 18 | 19 | // AMBA3 APB Protocol Specification v1.0 20 | logic pready; 21 | logic pslverr; 22 | 23 | // AMBA APB Protocol Specification v2.0 24 | logic [2:0] pprot; 25 | logic [`YUU_APB_DATA_WIDTH/8-1:0] pstrb; 26 | 27 | clocking cb @(posedge pclk); 28 | endclocking 29 | 30 | clocking drv_cb @(posedge pclk); 31 | default input #`YUU_APB_MASTER_INPUT_TIME output #`YUU_APB_MASTER_OUTPUT_TIME; 32 | 33 | output paddr; 34 | output penable; 35 | output pwrite; 36 | output pwdata; 37 | output psel; 38 | output pstrb; 39 | output pprot; 40 | 41 | input prdata; 42 | input pready; 43 | input pslverr; 44 | endclocking 45 | 46 | clocking mon_cb @(posedge pclk); 47 | default input #`YUU_APB_MASTER_INPUT_TIME output #`YUU_APB_MASTER_OUTPUT_TIME; 48 | 49 | input paddr; 50 | input penable; 51 | input pwrite; 52 | input pwdata; 53 | input psel; 54 | input pstrb; 55 | input pprot; 56 | 57 | input prdata; 58 | input pready; 59 | input pslverr; 60 | endclocking 61 | 62 | modport drv_mp ( 63 | output paddr, 64 | output penable, 65 | output pwrite, 66 | output pwdata, 67 | output psel, 68 | output pstrb, 69 | output pprot, 70 | 71 | input preset_n, 72 | input prdata, 73 | input pready, 74 | input pslverr 75 | ); 76 | 77 | modport mon_mp ( 78 | input preset_n, 79 | input paddr, 80 | input penable, 81 | input pwrite, 82 | input pwdata, 83 | input psel, 84 | input pstrb, 85 | input pprot, 86 | 87 | input prdata, 88 | input pready, 89 | input pslverr 90 | ); 91 | 92 | task wait_cycle(); 93 | @(posedge pclk); 94 | endtask 95 | endinterface 96 | 97 | `endif 98 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_agent.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_AGENT_SV 6 | `define YUU_APB_SLAVE_AGENT_SV 7 | 8 | class yuu_apb_slave_agent extends uvm_agent; 9 | yuu_apb_slave_config cfg; 10 | 11 | yuu_apb_slave_sequencer sequencer; 12 | yuu_apb_slave_driver driver; 13 | yuu_apb_slave_monitor monitor; 14 | yuu_apb_slave_collector collector; 15 | yuu_apb_slave_analyzer analyzer; 16 | 17 | uvm_analysis_port #(yuu_apb_slave_item) out_driver_ap; 18 | uvm_analysis_port #(yuu_apb_slave_item) out_monitor_ap; 19 | 20 | `uvm_component_utils_begin(yuu_apb_slave_agent) 21 | `uvm_component_utils_end 22 | 23 | extern function new(string name, uvm_component parent); 24 | extern function void build_phase(uvm_phase phase); 25 | extern function void connect_phase(uvm_phase phase); 26 | endclass 27 | 28 | function yuu_apb_slave_agent::new(string name, uvm_component parent); 29 | super.new(name, parent); 30 | endfunction 31 | 32 | function void yuu_apb_slave_agent::build_phase(uvm_phase phase); 33 | if (!uvm_config_db #(yuu_apb_slave_config)::get(null, get_full_name(), "cfg", cfg)) 34 | `uvm_fatal("build_phase", "Cannot get slave configuration") 35 | if (cfg == null) 36 | `uvm_fatal("build_phase", "Get a null slave configuration") 37 | 38 | monitor = yuu_apb_slave_monitor::type_id::create("monitor", this); 39 | monitor.cfg = this.cfg; 40 | if (cfg.is_active == UVM_ACTIVE) begin 41 | sequencer = yuu_apb_slave_sequencer::type_id::create("sequencer", this); 42 | driver = yuu_apb_slave_driver::type_id::create("driver", this); 43 | sequencer.cfg = this.cfg; 44 | driver.cfg = this.cfg; 45 | end 46 | if (cfg.coverage_enable) begin 47 | collector = yuu_apb_slave_collector::type_id::create("collector", this); 48 | collector.cfg = this.cfg; 49 | end 50 | if (cfg.analysis_enable) begin 51 | analyzer = yuu_apb_slave_analyzer::type_id::create("analyzer", this); 52 | analyzer.cfg = this.cfg; 53 | end 54 | endfunction 55 | 56 | function void yuu_apb_slave_agent::connect_phase(uvm_phase phase); 57 | out_monitor_ap = monitor.out_monitor_ap; 58 | 59 | if (cfg.is_active) begin 60 | driver.seq_item_port.connect(sequencer.seq_item_export); 61 | out_driver_ap = driver.out_driver_ap; 62 | end 63 | if (cfg.coverage_enable) begin 64 | monitor.out_monitor_ap.connect(collector.analysis_export); 65 | end 66 | if (cfg.analysis_enable) begin 67 | monitor.out_monitor_ap.connect(analyzer.analysis_export); 68 | end 69 | endfunction 70 | 71 | `endif 72 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_analyzer.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_ANALYZER_SV 6 | `define YUU_APB_SLAVE_ANALYZER_SV 7 | 8 | class yuu_apb_slave_analyzer extends uvm_subscriber #(yuu_apb_slave_item); 9 | virtual yuu_apb_slave_interface vif; 10 | 11 | yuu_apb_slave_config cfg; 12 | uvm_event_pool events; 13 | 14 | local time m_start_time; 15 | local time m_end_time; 16 | local bit m_start = 0; 17 | local int m_count = 0; 18 | 19 | `uvm_component_utils_begin(yuu_apb_slave_analyzer) 20 | `uvm_component_utils_end 21 | 22 | extern function new(string name, uvm_component parent); 23 | extern virtual function void connect_phase(uvm_phase phase); 24 | extern virtual task run_phase(uvm_phase phase); 25 | extern virtual function void report_phase(uvm_phase phase); 26 | 27 | extern virtual function void write(yuu_apb_slave_item t); 28 | extern protected virtual task measure_start(); 29 | extern protected virtual task measure_end(); 30 | endclass 31 | 32 | function yuu_apb_slave_analyzer::new(string name, uvm_component parent); 33 | super.new(name, parent); 34 | endfunction 35 | 36 | function void yuu_apb_slave_analyzer::connect_phase(uvm_phase phase); 37 | this.vif = cfg.vif; 38 | this.events = cfg.events; 39 | endfunction 40 | 41 | task yuu_apb_slave_analyzer::run_phase(uvm_phase phase); 42 | measure_start(); 43 | measure_end(); 44 | endtask 45 | 46 | function void yuu_apb_slave_analyzer::report_phase(uvm_phase phase); 47 | real tput_rate; 48 | 49 | if (m_count == 0) begin 50 | `uvm_warning("report_phase", "Analyzer haven't received any transaction") 51 | return; 52 | end 53 | 54 | tput_rate = real'(m_count)/(m_end_time - m_start_time) * 1000; 55 | `uvm_info("report_phase", $sformatf("APB slave speed is %f", tput_rate), UVM_LOW); 56 | endfunction 57 | 58 | 59 | function void yuu_apb_slave_analyzer::write(yuu_apb_slave_item t); 60 | if (m_start) 61 | m_count ++; 62 | endfunction 63 | 64 | task yuu_apb_slave_analyzer::measure_start(); 65 | uvm_event e = events.get($sformatf("%s_measure_begin", cfg.get_name())); 66 | e.wait_on(); 67 | m_start_time = $realtime(); 68 | m_start = 1; 69 | `uvm_info("measure_start", $sformatf("%s analyzer start measure @ %t", cfg.get_name(), m_start_time), UVM_LOW) 70 | endtask 71 | 72 | task yuu_apb_slave_analyzer::measure_end(); 73 | uvm_event e = events.get($sformatf("%s_measure_end", cfg.get_name())); 74 | 75 | e.wait_on(); 76 | m_end_time = $realtime(); 77 | m_start = 0; 78 | `uvm_info("measure_end", $sformatf("%s analyzer end measure @ %t", cfg.get_name(), m_end_time), UVM_LOW) 79 | endtask 80 | 81 | `endif 82 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_analyzer.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_ANALYZER_SV 6 | `define YUU_APB_MASTER_ANALYZER_SV 7 | 8 | class yuu_apb_master_analyzer extends uvm_subscriber #(yuu_apb_master_item); 9 | virtual yuu_apb_master_interface vif; 10 | 11 | yuu_apb_master_config cfg; 12 | uvm_event_pool events; 13 | 14 | protected time m_start_time; 15 | protected time m_end_time; 16 | protected bit m_start = 0; 17 | protected int m_count = 0; 18 | 19 | `uvm_component_utils_begin(yuu_apb_master_analyzer) 20 | `uvm_component_utils_end 21 | 22 | extern function new(string name, uvm_component parent); 23 | extern virtual function void connect_phase(uvm_phase phase); 24 | extern virtual task run_phase(uvm_phase phase); 25 | extern virtual function void report_phase(uvm_phase phase); 26 | 27 | extern virtual function void write(yuu_apb_master_item t); 28 | extern protected virtual task measure_start(); 29 | extern protected virtual task measure_end(); 30 | endclass 31 | 32 | function yuu_apb_master_analyzer::new(string name, uvm_component parent); 33 | super.new(name, parent); 34 | endfunction 35 | 36 | function void yuu_apb_master_analyzer::connect_phase(uvm_phase phase); 37 | this.vif = cfg.vif; 38 | this.events = cfg.events; 39 | endfunction 40 | 41 | task yuu_apb_master_analyzer::run_phase(uvm_phase phase); 42 | measure_start(); 43 | measure_end(); 44 | endtask 45 | 46 | function void yuu_apb_master_analyzer::report_phase(uvm_phase phase); 47 | real tput_rate; 48 | 49 | if (m_count == 0) begin 50 | `uvm_warning("report_phase", "Analyzer haven't received any transaction") 51 | return; 52 | end 53 | 54 | tput_rate = real'(m_count)/(m_end_time - m_start_time) * 1000; 55 | `uvm_info("report_phase", $sformatf("APB master speed is %f", tput_rate), UVM_LOW); 56 | endfunction 57 | 58 | function void yuu_apb_master_analyzer::write(yuu_apb_master_item t); 59 | if (m_start) 60 | m_count ++; 61 | endfunction 62 | 63 | task yuu_apb_master_analyzer::measure_start(); 64 | uvm_event e = events.get($sformatf("%s_measure_begin", cfg.get_name())); 65 | 66 | e.wait_on(); 67 | m_start_time = $realtime(); 68 | m_start = 1; 69 | `uvm_info("measure_start", $sformatf("%s analyzer start measure @ %t", cfg.get_name(), m_start_time), UVM_LOW) 70 | endtask 71 | 72 | task yuu_apb_master_analyzer::measure_end(); 73 | uvm_event e = events.get($sformatf("%s_measure_end", cfg.get_name())); 74 | 75 | e.wait_on(); 76 | m_end_time = $realtime(); 77 | m_start = 0; 78 | `uvm_info("measure_end", $sformatf("%s analyzer end measure @ %t", cfg.get_name(), m_end_time), UVM_LOW) 79 | endtask 80 | 81 | `endif 82 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_config.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_CONFIG_SV 6 | `define YUU_APB_MASTER_CONFIG_SV 7 | 8 | class yuu_apb_master_config extends yuu_apb_agent_config; 9 | virtual yuu_apb_master_interface vif; 10 | 11 | boolean idle_enable = True; 12 | boolean use_reg_model = False; 13 | 14 | yuu_amba_addr_map addressable_maps[]; 15 | 16 | `uvm_object_utils_begin(yuu_apb_master_config) 17 | `uvm_field_enum (boolean, idle_enable, UVM_PRINT | UVM_COPY) 18 | `uvm_field_enum (boolean, use_reg_model, UVM_PRINT | UVM_COPY) 19 | `uvm_field_array_object( addressable_maps, UVM_PRINT | UVM_COPY) 20 | `uvm_object_utils_end 21 | 22 | extern function new(string name = "yuu_apb_master_config"); 23 | extern virtual function void set_map(yuu_amba_addr_t low, yuu_amba_addr_t high); 24 | extern virtual function void set_maps(yuu_amba_addr_t lows[], yuu_amba_addr_t highs[]); 25 | extern virtual function yuu_amba_addr_map get_map(); 26 | extern virtual function void get_maps(ref yuu_amba_addr_map maps[]); 27 | endclass 28 | 29 | function yuu_apb_master_config::new(string name = "yuu_apb_master_config"); 30 | super.new(name); 31 | endfunction 32 | 33 | // set_map 34 | // 35 | // Set master address range 36 | // low: low address boundary 37 | // high: high address boundary 38 | function void yuu_apb_master_config::set_map(yuu_amba_addr_t low, yuu_amba_addr_t high); 39 | addressable_maps = new[1]; 40 | addressable_maps[0] = yuu_amba_addr_map::type_id::create($sformatf("%s_addressable_maps[0]", this.get_name())); 41 | 42 | addressable_maps[0].set_map(low, high); 43 | endfunction 44 | 45 | function void yuu_apb_master_config::set_maps(yuu_amba_addr_t lows[], yuu_amba_addr_t highs[]); 46 | if (lows.size() == 0|| highs.size() == 0) 47 | `uvm_error("set_maps", "The lows or highs array is empty") 48 | else if (lows.size() != highs.size()) 49 | `uvm_error("set_maps", "The lows and highs array must in the same size") 50 | else begin 51 | addressable_maps = new[lows.size()]; 52 | foreach (addressable_maps[i]) 53 | addressable_maps[i] = yuu_amba_addr_map::type_id::create($sformatf("addressable_maps[%0d]", i)); 54 | foreach (lows[i]) 55 | addressable_maps[i].set_map(lows[i], highs[i]); 56 | end 57 | endfunction 58 | 59 | function yuu_amba_addr_map yuu_apb_master_config::get_map(); 60 | return this.addressable_maps[0]; 61 | endfunction 62 | 63 | function void yuu_apb_master_config::get_maps(ref yuu_amba_addr_map maps[]); 64 | maps = new[this.addressable_maps.size()]; 65 | foreach (maps[i]) begin 66 | maps[i] = yuu_amba_addr_map::type_id::create($sformatf("map[%0d]", i)); 67 | maps[i].copy(this.addressable_maps[i]); 68 | end 69 | endfunction 70 | 71 | `endif 72 | -------------------------------------------------------------------------------- /test/yuu_apb_b2b_case.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_B2B_CASE_SV 6 | `define YUU_APB_B2B_CASE_SV 7 | 8 | class yuu_apb_master_b2b_sequence extends yuu_apb_master_sequence_base; 9 | `uvm_object_utils(yuu_apb_master_b2b_sequence) 10 | 11 | function new(string name="yuu_apb_master_b2b_sequence"); 12 | super.new(name); 13 | endfunction : new 14 | 15 | task body(); 16 | yuu_apb_master_item m_item; 17 | yuu_apb_data_t write_data[$]; 18 | 19 | for (int i=0; i<4; i++) begin 20 | m_item = new("m_item"); 21 | m_item.cfg = cfg; 22 | m_item.randomize() with {direction == WRITE; 23 | addr == 32'h1000_0000+i*4;}; 24 | start_item(m_item); 25 | finish_item(m_item); 26 | write_data.push_back(m_item.data); 27 | end 28 | 29 | for (int i=0; i<4; i++) begin 30 | m_item = new("m_item"); 31 | m_item.cfg = cfg; 32 | m_item.randomize() with {direction == READ; 33 | addr == 32'h1000_0000+i*4;}; 34 | start_item(m_item); 35 | finish_item(m_item); 36 | if (write_data[i] != m_item.data) 37 | `uvm_error("body", $sformatf("Compare failed, write data is %0h, read data is %0h", write_data[i], m_item.data)) 38 | else 39 | `uvm_info("body", $sformatf("Compare pass, read data is %0h", write_data[i]), UVM_LOW) 40 | end 41 | endtask 42 | endclass : yuu_apb_master_b2b_sequence 43 | 44 | class yuu_apb_b2b_virtual_sequence extends yuu_apb_virtual_sequence; 45 | `uvm_object_utils(yuu_apb_b2b_virtual_sequence) 46 | 47 | function new(string name = "yuu_apb_b2b_virtual_sequence"); 48 | super.new(name); 49 | endfunction 50 | 51 | task body(); 52 | yuu_apb_master_b2b_sequence mst_seq = yuu_apb_master_b2b_sequence::type_id::create("mst_seq"); 53 | yuu_apb_response_sequence rsp_seq = yuu_apb_response_sequence::type_id::create("rsp_seq"); 54 | 55 | fork 56 | mst_seq.start(p_sequencer.master_sequencer[0]); 57 | rsp_seq.start(p_sequencer.slave_sequencer[0]); 58 | join_any 59 | endtask 60 | endclass : yuu_apb_b2b_virtual_sequence 61 | 62 | 63 | class yuu_apb_b2b_case extends yuu_apb_base_case; 64 | `uvm_component_utils(yuu_apb_b2b_case) 65 | 66 | function new(string name, uvm_component parent); 67 | super.new(name, parent); 68 | endfunction : new 69 | 70 | function void build_phase(uvm_phase phase); 71 | super.build_phase(phase); 72 | 73 | cfg.mst_cfg[0].idle_enable = False; 74 | cfg.slv_cfg[0].wait_enable = False; 75 | endfunction : build_phase 76 | 77 | task run_phase(uvm_phase phase); 78 | yuu_apb_b2b_virtual_sequence seq = yuu_apb_b2b_virtual_sequence::type_id::create("seq"); 79 | 80 | phase.raise_objection(this); 81 | seq.start(vsequencer); 82 | wait_scb_done(); 83 | phase.drop_objection(this); 84 | endtask : run_phase 85 | endclass : yuu_apb_b2b_case 86 | 87 | `endif 88 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_config.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_CONFIG_SV 6 | `define YUU_APB_SLAVE_CONFIG_SV 7 | 8 | class yuu_apb_slave_config extends yuu_apb_agent_config; 9 | virtual yuu_apb_slave_interface vif; 10 | 11 | boolean wait_enable = True; 12 | boolean use_response= False; 13 | protected boolean multi_range = False; 14 | yuu_common_mem_pattern_e mem_init_pattern = PATTERN_ALL_0; 15 | 16 | yuu_amba_addr_map maps[]; 17 | 18 | `uvm_object_utils_begin(yuu_apb_slave_config) 19 | `uvm_field_enum (boolean, wait_enable, UVM_PRINT | UVM_COPY) 20 | `uvm_field_enum (boolean, use_response, UVM_PRINT | UVM_COPY) 21 | `uvm_field_enum (boolean, multi_range, UVM_PRINT | UVM_COPY) 22 | `uvm_field_enum (yuu_common_mem_pattern_e, mem_init_pattern,UVM_PRINT | UVM_COPY) 23 | `uvm_field_array_object( maps, UVM_PRINT | UVM_COPY) 24 | `uvm_object_utils_end 25 | 26 | extern function new(string name = "yuu_apb_slave_config"); 27 | extern virtual function void set_map(yuu_amba_addr_t low, yuu_amba_addr_t high); 28 | extern virtual function void set_maps(yuu_amba_addr_t lows[], yuu_amba_addr_t highs[]); 29 | extern virtual function yuu_amba_addr_map get_map(); 30 | extern virtual function void get_maps(ref yuu_amba_addr_map maps[]); 31 | extern virtual function boolean is_multi_range(); 32 | endclass 33 | 34 | function yuu_apb_slave_config::new(string name = "yuu_apb_slave_config"); 35 | super.new(name); 36 | endfunction 37 | 38 | // set_map 39 | // 40 | // Set slave address range 41 | // low: low address boundary 42 | // high: high address boundary 43 | function void yuu_apb_slave_config::set_map(yuu_amba_addr_t low, yuu_amba_addr_t high); 44 | maps = new[1]; 45 | maps[0] = yuu_amba_addr_map::type_id::create($sformatf("%s_maps[0]", this.get_name())); 46 | 47 | maps[0].set_map(low, high); 48 | endfunction 49 | 50 | function void yuu_apb_slave_config::set_maps(yuu_amba_addr_t lows[], yuu_amba_addr_t highs[]); 51 | if (lows.size() == 0|| highs.size() == 0) 52 | `uvm_error("set_maps", "The lows or highs array is empty") 53 | else if (lows.size() != highs.size()) 54 | `uvm_error("set_maps", "The lows and highs array must in the same size") 55 | else begin 56 | maps = new[lows.size()]; 57 | foreach (maps[i]) 58 | maps[i] = yuu_amba_addr_map::type_id::create($sformatf("%s_maps[%0d]", this.get_name(), i)); 59 | foreach (lows[i]) 60 | maps[i].set_map(lows[i], highs[i]); 61 | multi_range = True; 62 | end 63 | endfunction 64 | 65 | function yuu_amba_addr_map yuu_apb_slave_config::get_map(); 66 | return this.maps[0]; 67 | endfunction 68 | 69 | function void yuu_apb_slave_config::get_maps(ref yuu_amba_addr_map maps[]); 70 | maps = new[this.maps.size()]; 71 | foreach (maps[i]) begin 72 | maps[i] = yuu_amba_addr_map::type_id::create("map"); 73 | maps[i].copy(this.maps[i]); 74 | end 75 | endfunction 76 | 77 | function boolean yuu_apb_slave_config::is_multi_range(); 78 | return this.multi_range; 79 | endfunction 80 | 81 | `endif 82 | -------------------------------------------------------------------------------- /include/yuu_apb_interface.svi: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_INTERFACE_SVI 6 | `define YUU_APB_INTERFACE_SVI 7 | 8 | `include "yuu_apb_master_interface.svi" 9 | `include "yuu_apb_slave_interface.svi" 10 | 11 | interface yuu_apb_interface(); 12 | logic preset_n; 13 | logic pclk; 14 | 15 | yuu_apb_master_interface master_if[16](); 16 | yuu_apb_slave_interface slave_if[16](); 17 | 18 | 19 | // Sub-interface connection 20 | genvar i; 21 | 22 | generate 23 | for (i=0; i<`YUU_APB_MASTER_NUM; i++) begin : master_reset_connection 24 | assign master_if[i].preset_n = preset_n; 25 | end 26 | for (i=0; i<`YUU_APB_SLAVE_NUM; i++) begin : slave_reset_connection 27 | assign slave_if[i].preset_n = preset_n; 28 | end 29 | endgenerate 30 | 31 | generate 32 | for (i=0; i<`YUU_APB_MASTER_NUM; i++) begin : master_clock_connection 33 | assign master_if[i].pclk = pclk; 34 | end 35 | for (i=0; i<`YUU_APB_SLAVE_NUM; i++) begin : slave_clock_connection 36 | assign slave_if[i].pclk = pclk; 37 | end 38 | endgenerate 39 | 40 | 41 | // Methods 42 | function void check_master_define(int idx); 43 | if (idx>=`YUU_APB_MASTER_NUM) begin 44 | $display("[FATAL] yuu_apb_interface: the master index %0d has not been defined, check the YUU_APB_MASTER_NUM define", idx); 45 | $finish; 46 | end 47 | endfunction 48 | 49 | function void check_slave_define(int idx); 50 | if (idx>=`YUU_APB_SLAVE_NUM) begin 51 | $display("[FATAL] yuu_apb_interface: the slave index %0d has not been defined, check the YUU_APB_SLAVE_NUM define", idx); 52 | $finish; 53 | end 54 | endfunction 55 | 56 | function virtual yuu_apb_master_interface get_master_if(int idx); 57 | check_master_define(idx); 58 | 59 | // Max: 16 60 | case(idx) 61 | 00: return master_if[00]; 62 | 01: return master_if[01]; 63 | 02: return master_if[02]; 64 | 03: return master_if[03]; 65 | 04: return master_if[04]; 66 | 05: return master_if[05]; 67 | 06: return master_if[06]; 68 | 07: return master_if[07]; 69 | 08: return master_if[08]; 70 | 09: return master_if[09]; 71 | 10: return master_if[10]; 72 | 11: return master_if[11]; 73 | 12: return master_if[12]; 74 | 13: return master_if[13]; 75 | 14: return master_if[14]; 76 | 15: return master_if[15]; 77 | endcase 78 | endfunction 79 | 80 | function virtual yuu_apb_slave_interface get_slave_if(int idx); 81 | check_slave_define(idx); 82 | 83 | // Max: 16 84 | case(idx) 85 | 00: return slave_if[00]; 86 | 01: return slave_if[01]; 87 | 02: return slave_if[02]; 88 | 03: return slave_if[03]; 89 | 04: return slave_if[04]; 90 | 05: return slave_if[05]; 91 | 06: return slave_if[06]; 92 | 07: return slave_if[07]; 93 | 08: return slave_if[08]; 94 | 09: return slave_if[09]; 95 | 10: return slave_if[10]; 96 | 11: return slave_if[11]; 97 | 12: return slave_if[12]; 98 | 13: return slave_if[13]; 99 | 14: return slave_if[14]; 100 | 15: return slave_if[15]; 101 | endcase 102 | endfunction 103 | endinterface 104 | 105 | `endif 106 | -------------------------------------------------------------------------------- /test/yuu_apb_reset_case.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_RESET_CASE_SV 6 | `define YUU_APB_RESET_CASE_SV 7 | 8 | class yuu_apb_master_reset_sequence extends yuu_apb_master_sequence_base; 9 | `uvm_object_utils(yuu_apb_master_reset_sequence) 10 | 11 | function new(string name="yuu_apb_master_reset_sequence"); 12 | super.new(name); 13 | endfunction : new 14 | 15 | task body(); 16 | fork 17 | begin 18 | yuu_apb_master_item m_item; 19 | yuu_apb_data_t write_data[$]; 20 | 21 | for (int i=0; i<4; i++) begin 22 | m_item = new("m_item"); 23 | m_item.cfg = cfg; 24 | m_item.randomize() with {direction == WRITE; 25 | addr == 32'h1000_0000+i*4;}; 26 | start_item(m_item); 27 | finish_item(m_item); 28 | write_data.push_back(m_item.data); 29 | end 30 | 31 | for (int i=0; i<4; i++) begin 32 | m_item = new("m_item"); 33 | m_item.cfg = cfg; 34 | m_item.randomize() with {direction == READ; 35 | addr == 32'h1000_0000+i*4;}; 36 | start_item(m_item); 37 | finish_item(m_item); 38 | if (write_data[i] != m_item.data) 39 | `uvm_error("body", $sformatf("Compare failed, write data is %0h, read data is %0h", write_data[i], m_item.data)) 40 | else 41 | `uvm_info("body", $sformatf("Compare pass, read data is %0h", write_data[i]), UVM_LOW) 42 | end 43 | end 44 | begin 45 | @(negedge vif.mon_mp.preset_n); 46 | end 47 | join_any 48 | disable fork; 49 | endtask 50 | endclass : yuu_apb_master_reset_sequence 51 | 52 | class yuu_apb_reset_virtual_sequence extends yuu_apb_virtual_sequence; 53 | `uvm_object_utils(yuu_apb_reset_virtual_sequence) 54 | 55 | function new(string name = "yuu_apb_reset_virtual_sequence"); 56 | super.new(name); 57 | endfunction 58 | 59 | task body(); 60 | yuu_apb_master_reset_sequence mst_seq = yuu_apb_master_reset_sequence::type_id::create("mst_seq"); 61 | yuu_apb_response_sequence rsp_seq = yuu_apb_response_sequence::type_id::create("rsp_seq"); 62 | 63 | fork 64 | mst_seq.start(p_sequencer.master_sequencer[0], this); 65 | rsp_seq.start(p_sequencer.slave_sequencer[0], this); 66 | join_any 67 | endtask 68 | endclass : yuu_apb_reset_virtual_sequence 69 | 70 | 71 | class yuu_apb_reset_case extends yuu_apb_base_case; 72 | yuu_apb_reset_virtual_sequence seq = yuu_apb_reset_virtual_sequence::type_id::create("seq"); 73 | 74 | `uvm_component_utils(yuu_apb_reset_case) 75 | 76 | function new(string name, uvm_component parent); 77 | super.new(name, parent); 78 | endfunction : new 79 | 80 | task run_phase(uvm_phase phase); 81 | phase.raise_objection(this); 82 | fork 83 | seq.start(vsequencer); 84 | assert_reset(); 85 | join 86 | seq.start(vsequencer); 87 | wait_scb_done(); 88 | phase.drop_objection(this); 89 | endtask : run_phase 90 | 91 | task assert_reset(); 92 | #502ns; 93 | vif.preset_n = 1'b0; 94 | #505ns; 95 | vif.preset_n = 1'b1; 96 | endtask 97 | endclass : yuu_apb_reset_case 98 | 99 | `endif 100 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_agent.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_AGENT_SV 6 | `define YUU_APB_MASTER_AGENT_SV 7 | 8 | class yuu_apb_master_agent extends uvm_agent; 9 | yuu_apb_master_config cfg; 10 | 11 | yuu_apb_master_sequencer sequencer; 12 | yuu_apb_master_driver driver; 13 | yuu_apb_master_monitor monitor; 14 | yuu_apb_master_collector collector; 15 | yuu_apb_master_analyzer analyzer; 16 | yuu_apb_master_adapter adapter; 17 | yuu_apb_master_predictor predictor; 18 | 19 | uvm_analysis_port #(yuu_apb_master_item) out_driver_ap; 20 | uvm_analysis_port #(yuu_apb_master_item) out_monitor_ap; 21 | 22 | `uvm_component_utils_begin(yuu_apb_master_agent) 23 | `uvm_component_utils_end 24 | 25 | extern function new(string name, uvm_component parent); 26 | extern virtual function void build_phase(uvm_phase phase); 27 | extern virtual function void connect_phase(uvm_phase phase); 28 | extern virtual function void end_of_elaboration_phase(uvm_phase phase); 29 | endclass 30 | 31 | function yuu_apb_master_agent::new(string name, uvm_component parent); 32 | super.new(name, parent); 33 | endfunction 34 | 35 | function void yuu_apb_master_agent::build_phase(uvm_phase phase); 36 | if (!uvm_config_db #(yuu_apb_master_config)::get(null, get_full_name(), "cfg", cfg)) 37 | `uvm_fatal("build_phase", "Cannot get master configuration") 38 | if (cfg == null) 39 | `uvm_fatal("build_phase", "Get a null master configuration") 40 | 41 | monitor = yuu_apb_master_monitor::type_id::create("monitor", this); 42 | monitor.cfg = cfg; 43 | if (cfg.is_active == UVM_ACTIVE) begin 44 | sequencer = yuu_apb_master_sequencer::type_id::create("sequencer", this); 45 | driver = yuu_apb_master_driver::type_id::create("driver", this); 46 | sequencer.cfg = cfg; 47 | driver.cfg = cfg; 48 | end 49 | if (cfg.coverage_enable) begin 50 | collector = yuu_apb_master_collector::type_id::create("collector", this); 51 | collector.cfg = this.cfg; 52 | end 53 | if (cfg.analysis_enable) begin 54 | analyzer = yuu_apb_master_analyzer::type_id::create("analyzer", this); 55 | analyzer.cfg = this.cfg; 56 | end 57 | 58 | if (cfg.use_reg_model) begin 59 | adapter = yuu_apb_master_adapter::type_id::create("adapter"); 60 | adapter.cfg = cfg; 61 | adapter.provides_responses = 1; 62 | 63 | predictor = yuu_apb_master_predictor::type_id::create("predictor", this); 64 | predictor.adapter = adapter; 65 | end 66 | endfunction 67 | 68 | function void yuu_apb_master_agent::connect_phase(uvm_phase phase); 69 | out_monitor_ap = monitor.out_monitor_ap; 70 | 71 | if (cfg.is_active) begin 72 | driver.seq_item_port.connect(sequencer.seq_item_export); 73 | out_driver_ap = driver.out_driver_ap; 74 | end 75 | if (cfg.coverage_enable) begin 76 | monitor.out_monitor_ap.connect(collector.analysis_export); 77 | end 78 | if (cfg.analysis_enable) begin 79 | monitor.out_monitor_ap.connect(analyzer.analysis_export); 80 | end 81 | if (cfg.use_reg_model) begin 82 | monitor.out_monitor_ap.connect(predictor.bus_in); 83 | end 84 | endfunction 85 | 86 | function void yuu_apb_master_agent::end_of_elaboration_phase(uvm_phase phase); 87 | if (cfg.use_reg_model) begin 88 | if (predictor.map == null) 89 | `uvm_fatal("end_of_elaboration_phase", "When register model used, the predictor map should be set") 90 | end 91 | endfunction 92 | 93 | `endif 94 | -------------------------------------------------------------------------------- /test/yuu_apb_direct_case.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_DIRECT_CASE_SV 6 | `define YUU_APB_DIRECT_CASE_SV 7 | 8 | class yuu_apb_master_direct_sequence extends yuu_apb_master_sequence_base; 9 | `uvm_object_utils(yuu_apb_master_direct_sequence) 10 | 11 | function new(string name="yuu_apb_master_direct_sequence"); 12 | super.new(name); 13 | endfunction : new 14 | 15 | task body(); 16 | yuu_apb_master_item m_item; 17 | yuu_apb_data_t write_data[$]; 18 | 19 | for (int i=0; i<4; i++) begin 20 | m_item = new("m_item"); 21 | m_item.cfg = cfg; 22 | m_item.randomize() with {direction == WRITE; 23 | addr == 32'h1000_0000+i*4;}; 24 | start_item(m_item); 25 | finish_item(m_item); 26 | write_data.push_back(m_item.data); 27 | end 28 | 29 | for (int i=0; i<4; i++) begin 30 | m_item = new("m_item"); 31 | m_item.cfg = cfg; 32 | m_item.randomize() with {direction == READ; 33 | addr == 32'h1000_0000+i*4;}; 34 | start_item(m_item); 35 | finish_item(m_item); 36 | if (write_data[i] != m_item.data) 37 | `uvm_error("body", $sformatf("Compare failed, write data is %0h, read data is %0h", write_data[i], m_item.data)) 38 | else 39 | `uvm_info("body", $sformatf("Compare pass, read data is %0h", write_data[i]), UVM_LOW) 40 | end 41 | endtask 42 | endclass : yuu_apb_master_direct_sequence 43 | 44 | class yuu_apb_response_sequence extends yuu_apb_slave_sequence_base; 45 | `uvm_object_utils(yuu_apb_response_sequence) 46 | 47 | function new(string name = "yuu_apb_response_sequence"); 48 | super.new(name); 49 | endfunction 50 | 51 | task body(); 52 | vif = cfg.vif; 53 | 54 | fork 55 | forever begin 56 | req = yuu_apb_slave_item::type_id::create("req"); 57 | req.cfg = cfg; 58 | start_item(req); 59 | req.randomize() with {resp == OKAY;}; 60 | finish_item(req); 61 | end 62 | begin 63 | @(negedge vif.mon_mp.preset_n); 64 | end 65 | join_any 66 | disable fork; 67 | endtask 68 | endclass : yuu_apb_response_sequence 69 | 70 | class yuu_apb_direct_virtual_sequence extends yuu_apb_virtual_sequence; 71 | `uvm_object_utils(yuu_apb_direct_virtual_sequence) 72 | 73 | function new(string name = "yuu_apb_direct_virtual_sequence"); 74 | super.new(name); 75 | endfunction 76 | 77 | task body(); 78 | yuu_apb_master_direct_sequence mst_seq = yuu_apb_master_direct_sequence::type_id::create("mst_seq"); 79 | yuu_apb_response_sequence rsp_seq = yuu_apb_response_sequence::type_id::create("rsp_seq"); 80 | 81 | fork 82 | mst_seq.start(p_sequencer.master_sequencer[0]); 83 | rsp_seq.start(p_sequencer.slave_sequencer[0]); 84 | join_any 85 | endtask 86 | endclass : yuu_apb_direct_virtual_sequence 87 | 88 | 89 | class yuu_apb_direct_case extends yuu_apb_base_case; 90 | `uvm_component_utils(yuu_apb_direct_case) 91 | 92 | function new(string name, uvm_component parent); 93 | super.new(name, parent); 94 | endfunction : new 95 | 96 | task run_phase(uvm_phase phase); 97 | yuu_apb_direct_virtual_sequence seq = yuu_apb_direct_virtual_sequence::type_id::create("seq"); 98 | 99 | phase.raise_objection(this); 100 | seq.start(vsequencer); 101 | phase.drop_objection(this); 102 | endtask : run_phase 103 | 104 | endclass : yuu_apb_direct_case 105 | 106 | `endif 107 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_monitor.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_MONITOR_SV 6 | `define YUU_APB_SLAVE_MONITOR_SV 7 | 8 | class yuu_apb_slave_monitor extends uvm_monitor; 9 | virtual yuu_apb_slave_interface vif; 10 | uvm_analysis_port #(yuu_apb_slave_item) out_monitor_ap; 11 | 12 | yuu_apb_slave_config cfg; 13 | uvm_event_pool events; 14 | protected process processes[string]; 15 | 16 | protected yuu_apb_slave_item monitor_item; 17 | 18 | `uvm_register_cb(yuu_apb_slave_monitor, yuu_apb_slave_monitor_callback) 19 | 20 | `uvm_component_utils_begin(yuu_apb_slave_monitor) 21 | `uvm_component_utils_end 22 | 23 | extern function new(string name, uvm_component parent); 24 | extern virtual function void build_phase(uvm_phase phase); 25 | extern virtual function void connect_phase(uvm_phase phase); 26 | extern virtual task run_phase(uvm_phase phase); 27 | 28 | extern protected virtual task init_component(); 29 | extern protected virtual task collect(); 30 | extern protected virtual task wait_reset(); 31 | endclass 32 | 33 | function yuu_apb_slave_monitor::new(string name, uvm_component parent); 34 | super.new(name, parent); 35 | endfunction 36 | 37 | function void yuu_apb_slave_monitor::build_phase(uvm_phase phase); 38 | out_monitor_ap = new("out_monitor_ap", this); 39 | endfunction 40 | 41 | function void yuu_apb_slave_monitor::connect_phase(uvm_phase phase); 42 | this.vif = cfg.vif; 43 | this.events = cfg.events; 44 | endfunction 45 | 46 | task yuu_apb_slave_monitor::run_phase(uvm_phase phase); 47 | process proc_monitor; 48 | 49 | init_component(); 50 | fork 51 | forever begin 52 | wait(vif.mon_mp.preset_n === 1'b1); 53 | fork 54 | begin 55 | proc_monitor = process::self(); 56 | processes["proc_monitor"] = proc_monitor; 57 | monitor_item = yuu_apb_slave_item::type_id::create("monitor_item"); 58 | monitor_item.cfg = cfg; 59 | `uvm_do_callbacks(yuu_apb_slave_monitor, yuu_apb_slave_monitor_callback, pre_collect(this, monitor_item)); 60 | collect(); 61 | `uvm_do_callbacks(yuu_apb_slave_monitor, yuu_apb_slave_monitor_callback, post_collect(this, monitor_item)); 62 | end 63 | join 64 | end 65 | wait_reset(); 66 | join 67 | endtask 68 | 69 | 70 | task yuu_apb_slave_monitor::init_component(); 71 | return; 72 | endtask 73 | 74 | task yuu_apb_slave_monitor::collect(); 75 | uvm_event observe_trans_begin = events.get($sformatf("%s_observe_trans_begin", cfg.get_name())); 76 | uvm_event observe_trans_end = events.get($sformatf("%s_observe_trans_end", cfg.get_name())); 77 | 78 | while(vif.mon_cb.psel !== 1'b1) 79 | vif.wait_cycle(); 80 | 81 | observe_trans_begin.trigger(); 82 | 83 | monitor_item.addr = vif.mon_cb.paddr; 84 | monitor_item.direction = yuu_apb_direction_e'(vif.mon_cb.pwrite); 85 | monitor_item.strb = vif.mon_cb.pstrb; 86 | {monitor_item.prot2, monitor_item.prot1, monitor_item.prot0} = vif.mon_cb.pprot; 87 | if (monitor_item.direction == WRITE) 88 | monitor_item.data = vif.mon_cb.pwdata; 89 | while (vif.mon_cb.penable !== 1'b1) 90 | vif.wait_cycle(); 91 | if (cfg.apb3_enable) 92 | while (vif.mon_cb.pready !== 1'b1) 93 | vif.wait_cycle(); 94 | if (monitor_item.direction == READ) 95 | monitor_item.data = vif.mon_cb.prdata; 96 | out_monitor_ap.write(monitor_item); 97 | //monitor_item.print(); 98 | `uvm_info("collect", $sformatf("Collected yuu_apb_slave transaction (Direction:%s Addr:%8h Data:%8h)", monitor_item.direction, monitor_item.addr, monitor_item.data), UVM_HIGH) 99 | vif.wait_cycle(); 100 | 101 | observe_trans_end.trigger(); 102 | endtask 103 | 104 | task yuu_apb_slave_monitor::wait_reset(); 105 | forever begin 106 | @(negedge vif.mon_mp.preset_n); 107 | `uvm_warning("wait_reset", "Reset signal is asserted, transaction may be dropped") 108 | foreach (processes[i]) 109 | processes[i].kill(); 110 | init_component(); 111 | @(posedge vif.mon_mp.preset_n); 112 | end 113 | endtask 114 | 115 | `endif 116 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_monitor.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_MONITOR_SV 6 | `define YUU_APB_MASTER_MONITOR_SV 7 | 8 | class yuu_apb_master_monitor extends uvm_monitor; 9 | virtual yuu_apb_master_interface vif; 10 | uvm_analysis_port #(yuu_apb_master_item) out_monitor_ap; 11 | 12 | yuu_apb_master_config cfg; 13 | uvm_event_pool events; 14 | protected process processes[string]; 15 | 16 | protected yuu_apb_master_item monitor_item; 17 | 18 | `uvm_register_cb(yuu_apb_master_monitor, yuu_apb_master_monitor_callback) 19 | 20 | `uvm_component_utils_begin(yuu_apb_master_monitor) 21 | `uvm_component_utils_end 22 | 23 | extern function new(string name, uvm_component parent); 24 | extern virtual function void build_phase(uvm_phase phase); 25 | extern virtual function void connect_phase(uvm_phase phase); 26 | extern virtual task run_phase(uvm_phase phase); 27 | 28 | extern protected virtual task init_component(); 29 | extern protected virtual task collect(); 30 | extern protected virtual task wait_reset(); 31 | endclass 32 | 33 | function yuu_apb_master_monitor::new(string name, uvm_component parent); 34 | super.new(name, parent); 35 | endfunction 36 | 37 | function void yuu_apb_master_monitor::build_phase(uvm_phase phase); 38 | out_monitor_ap = new("out_monitor_ap", this); 39 | endfunction 40 | 41 | function void yuu_apb_master_monitor::connect_phase(uvm_phase phase); 42 | this.vif = cfg.vif; 43 | this.events = cfg.events; 44 | endfunction 45 | 46 | task yuu_apb_master_monitor::run_phase(uvm_phase phase); 47 | process proc_monitor; 48 | 49 | init_component(); 50 | fork 51 | forever begin 52 | wait(vif.mon_mp.preset_n === 1'b1); 53 | fork 54 | begin 55 | proc_monitor = process::self(); 56 | processes["proc_monitor"] = proc_monitor; 57 | monitor_item = yuu_apb_master_item::type_id::create("monitor_item"); 58 | `uvm_do_callbacks(yuu_apb_master_monitor, yuu_apb_master_monitor_callback, pre_collect(this, monitor_item)); 59 | collect(); 60 | `uvm_do_callbacks(yuu_apb_master_monitor, yuu_apb_master_monitor_callback, post_collect(this, monitor_item)); 61 | end 62 | join 63 | end 64 | wait_reset(); 65 | join 66 | endtask 67 | 68 | 69 | task yuu_apb_master_monitor::init_component(); 70 | return; 71 | endtask 72 | 73 | task yuu_apb_master_monitor::collect(); 74 | uvm_event observe_trans_begin = events.get($sformatf("%s_observe_trans_begin", cfg.get_name())); 75 | uvm_event observe_trans_end = events.get($sformatf("%s_observe_trans_end", cfg.get_name())); 76 | 77 | while (vif.mon_cb.psel !== 1'b1) 78 | vif.wait_cycle(); 79 | 80 | observe_trans_begin.trigger(); 81 | 82 | monitor_item.addr = vif.mon_cb.paddr; 83 | monitor_item.direction = yuu_apb_direction_e'(vif.mon_cb.pwrite); 84 | if (monitor_item.direction == WRITE) 85 | monitor_item.data = vif.mon_cb.pwdata; 86 | monitor_item.strb = vif.mon_cb.pstrb; 87 | {monitor_item.prot2, monitor_item.prot1, monitor_item.prot0} = vif.mon_cb.pprot; 88 | while (vif.mon_cb.penable !== 1'b1) 89 | vif.wait_cycle(); 90 | if (cfg.apb3_enable) begin 91 | while (vif.mon_cb.pready !== 1'b1) 92 | vif.wait_cycle(); 93 | monitor_item.resp = yuu_apb_response_e'(vif.mon_cb.pslverr); 94 | end 95 | if (monitor_item.direction == READ) 96 | monitor_item.data = vif.mon_cb.prdata; 97 | out_monitor_ap.write(monitor_item); 98 | `uvm_info("collect", $sformatf("Collected yuu_apb_master transaction (Direction:%s Addr:%8h Data:%8h)", monitor_item.direction, monitor_item.addr, monitor_item.data), UVM_HIGH) 99 | vif.wait_cycle(); 100 | 101 | observe_trans_end.trigger(); 102 | endtask 103 | 104 | task yuu_apb_master_monitor::wait_reset(); 105 | forever begin 106 | @(negedge vif.mon_mp.preset_n); 107 | `uvm_warning("wait_reset", "Reset signal is asserted, transaction may be dropped") 108 | foreach (processes[i]) 109 | processes[i].kill(); 110 | init_component(); 111 | @(posedge vif.mon_mp.preset_n); 112 | end 113 | endtask 114 | 115 | `endif 116 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_master/yuu_apb_master_driver.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_MASTER_DRIVER_SV 6 | `define YUU_APB_MASTER_DRIVER_SV 7 | 8 | class yuu_apb_master_driver extends uvm_driver #(yuu_apb_master_item); 9 | virtual yuu_apb_master_interface vif; 10 | uvm_analysis_port #(yuu_apb_master_item) out_driver_ap; 11 | 12 | yuu_apb_master_config cfg; 13 | uvm_event_pool events; 14 | protected process processes[string]; 15 | 16 | `uvm_register_cb(yuu_apb_master_driver, yuu_apb_master_driver_callback) 17 | 18 | `uvm_component_utils_begin(yuu_apb_master_driver) 19 | `uvm_component_utils_end 20 | 21 | extern function new(string name = "yuu_apb_master_driver", uvm_component parent); 22 | extern virtual function void build_phase(uvm_phase phase); 23 | extern virtual function void connect_phase(uvm_phase phase); 24 | extern virtual task run_phase(uvm_phase phase); 25 | 26 | extern protected virtual task init_component(); 27 | extern protected virtual task reset_signal(); 28 | extern protected virtual task get_and_drive(); 29 | extern protected virtual task drive_bus(); 30 | extern protected virtual task wait_reset(); 31 | endclass 32 | 33 | function yuu_apb_master_driver::new(string name = "yuu_apb_master_driver", uvm_component parent); 34 | super.new(name, parent); 35 | endfunction 36 | 37 | function void yuu_apb_master_driver::build_phase(uvm_phase phase); 38 | out_driver_ap = new("out_driver_ap", this); 39 | endfunction 40 | 41 | function void yuu_apb_master_driver::connect_phase(uvm_phase phase); 42 | this.vif = cfg.vif; 43 | this.events = cfg.events; 44 | endfunction 45 | 46 | task yuu_apb_master_driver::run_phase(uvm_phase phase); 47 | process proc_drive; 48 | 49 | init_component(); 50 | fork 51 | forever begin 52 | wait(vif.drv_mp.preset_n === 1'b1); 53 | fork 54 | begin 55 | proc_drive = process::self(); 56 | processes["proc_drive"] = proc_drive; 57 | get_and_drive(); 58 | end 59 | join 60 | end 61 | wait_reset(); 62 | join 63 | endtask 64 | 65 | 66 | task yuu_apb_master_driver::init_component(); 67 | reset_signal(); 68 | endtask 69 | 70 | task yuu_apb_master_driver::reset_signal(); 71 | uvm_event reset_begin = events.get($sformatf("%s_reset_begin", cfg.get_name())); 72 | 73 | vif.drv_cb.paddr <= 'h0; 74 | vif.drv_cb.penable <= 1'b0; 75 | vif.drv_cb.pwrite <= 1'b0; 76 | vif.drv_cb.pwdata <= 'h0; 77 | vif.drv_cb.pstrb <= -'h1; 78 | vif.drv_cb.pprot <= 1'b0; 79 | vif.drv_cb.psel <= 1'b0; 80 | 81 | reset_begin.trigger(); 82 | endtask 83 | 84 | task yuu_apb_master_driver::get_and_drive(); 85 | uvm_event handshake = events.get($sformatf("%s_handshake", cfg.get_name())); 86 | 87 | seq_item_port.get_next_item(req); 88 | out_driver_ap.write(req); 89 | handshake.trigger(); 90 | @(vif.drv_cb); 91 | `uvm_do_callbacks(yuu_apb_master_driver, yuu_apb_master_driver_callback, pre_send(this, req)); 92 | drive_bus(); 93 | `uvm_do_callbacks(yuu_apb_master_driver, yuu_apb_master_driver_callback, post_send(this, req)); 94 | rsp = yuu_apb_master_item::type_id::create("rsp"); 95 | rsp.copy(req); 96 | rsp.set_id_info(req); 97 | seq_item_port.item_done(rsp); 98 | handshake.reset(); 99 | endtask 100 | 101 | task yuu_apb_master_driver::drive_bus(); 102 | uvm_event drive_trans_begin = events.get($sformatf("%s_drive_trans_begin", cfg.get_name())); 103 | uvm_event drive_trans_end = events.get($sformatf("%s_drive_trans_end", cfg.get_name())); 104 | 105 | repeat(req.idle_delay) vif.wait_cycle(); 106 | 107 | drive_trans_begin.trigger(); 108 | 109 | vif.drv_cb.paddr <= req.addr; 110 | vif.drv_cb.pwrite <= bit'(req.direction); 111 | vif.drv_cb.psel <= 1'b1; 112 | vif.drv_cb.pstrb <= req.strb; 113 | vif.drv_cb.pprot <= {bit'(req.prot2), bit'(req.prot1), bit'(req.prot0)}; 114 | if (req.direction == WRITE) 115 | vif.drv_cb.pwdata <= req.data; 116 | vif.wait_cycle(); 117 | vif.drv_cb.penable <= 1'b1; 118 | vif.wait_cycle(); 119 | if (cfg.apb3_enable) begin 120 | int count = 0; 121 | while(vif.drv_cb.pready !== 1'b1) begin 122 | vif.wait_cycle(); 123 | count ++; 124 | if (cfg.timeout > 0 && count >= cfg.timeout) begin 125 | `uvm_warning("drive_bus", "APB device timeout") 126 | return; 127 | end 128 | end 129 | end 130 | if (req.direction == READ) begin 131 | req.data = vif.drv_cb.prdata; 132 | end 133 | vif.drv_cb.psel <= 1'b0; 134 | vif.drv_cb.penable <= 1'b0; 135 | 136 | drive_trans_end.trigger(); 137 | endtask 138 | 139 | task yuu_apb_master_driver::wait_reset(); 140 | uvm_event handshake = events.get($sformatf("%s_handshake", cfg.get_name())); 141 | 142 | forever begin 143 | @(negedge vif.drv_mp.preset_n); 144 | `uvm_warning("wait_reset", "Reset signal is asserted, transaction may be dropped") 145 | if (handshake.is_on()) 146 | seq_item_port.item_done(); 147 | foreach (processes[i]) 148 | processes[i].kill(); 149 | init_component(); 150 | @(posedge vif.drv_mp.preset_n); 151 | end 152 | endtask 153 | 154 | `endif 155 | -------------------------------------------------------------------------------- /test/yuu_apb_base_case.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_BASE_CASE_SV 6 | `define YUU_APB_BASE_CASE_SV 7 | 8 | import uvm_pkg::*; 9 | `include "uvm_macros.svh" 10 | 11 | import yuu_common_pkg::*; 12 | import yuu_apb_pkg::*; 13 | 14 | `include "slave_ral_model.sv" 15 | `uvm_analysis_imp_decl(_master_monitor) 16 | `uvm_analysis_imp_decl(_slave_monitor) 17 | class yuu_apb_mini_scoreboard extends uvm_scoreboard; 18 | virtual yuu_apb_master_interface vif; 19 | 20 | uvm_analysis_imp_master_monitor #(yuu_apb_master_item, yuu_apb_mini_scoreboard) mst_mon_export; 21 | uvm_analysis_imp_slave_monitor #(yuu_apb_slave_item, yuu_apb_mini_scoreboard) slv_mon_export; 22 | 23 | yuu_apb_master_item mst_mon_item_q[$]; 24 | yuu_apb_slave_item slv_mon_item_q[$]; 25 | 26 | process processes[string]; 27 | `uvm_component_utils(yuu_apb_mini_scoreboard) 28 | 29 | function new(string name, uvm_component parent); 30 | super.new(name, parent); 31 | endfunction : new 32 | 33 | function void build_phase(uvm_phase phase); 34 | mst_mon_export = new("mst_mon_export", this); 35 | slv_mon_export = new("slv_mon_export", this); 36 | endfunction 37 | 38 | function write_master_monitor(yuu_apb_master_item t); 39 | mst_mon_item_q.push_back(t); 40 | endfunction 41 | 42 | function write_slave_monitor(yuu_apb_slave_item t); 43 | slv_mon_item_q.push_back(t); 44 | endfunction 45 | 46 | task run_phase(uvm_phase phase); 47 | process proc_compare; 48 | yuu_apb_master_item m0; 49 | yuu_apb_slave_item s0; 50 | 51 | fork 52 | forever begin 53 | wait(vif.mon_mp.preset_n === 1'b1); 54 | fork 55 | begin 56 | proc_compare = process::self(); 57 | processes["proc_compare"] = proc_compare; 58 | wait(mst_mon_item_q.size() > 0); 59 | wait(slv_mon_item_q.size() > 0); 60 | 61 | m0 = mst_mon_item_q.pop_front(); 62 | s0 = slv_mon_item_q.pop_front(); 63 | if (m0.addr != s0.addr || m0.data != s0.data || m0.direction != s0.direction) 64 | `uvm_error("run_phase", $sformatf("Comapre failed, addr_m: 0x%0h, data_m: 0x%0h, dir_m: %s addr_s: 0x%0h, data_s: 0x%0h, dir_s: %s", 65 | m0.addr, m0.data, m0.direction, 66 | s0.addr, s0.data, s0.direction)) 67 | else 68 | `uvm_info("run_phase", $sformatf("Compare passed, addr: 0x%0h, data: 0x%0h, dir: %s", s0.addr, s0.data, s0.direction), UVM_LOW) 69 | end 70 | join 71 | end 72 | wait_reset(); 73 | join 74 | endtask 75 | 76 | 77 | task init_component(); 78 | mst_mon_item_q.delete(); 79 | slv_mon_item_q.delete(); 80 | endtask 81 | 82 | task wait_reset(); 83 | forever begin 84 | @(negedge vif.mon_mp.preset_n); 85 | foreach (processes[i]) 86 | processes[i].kill(); 87 | init_component(); 88 | @(posedge vif.mon_mp.preset_n); 89 | end 90 | endtask 91 | endclass : yuu_apb_mini_scoreboard 92 | 93 | 94 | class yuu_apb_base_case extends uvm_test; 95 | virtual yuu_apb_interface vif; 96 | 97 | yuu_apb_env env; 98 | yuu_apb_env_config cfg; 99 | yuu_apb_virtual_sequencer vsequencer; 100 | yuu_apb_mini_scoreboard scb; 101 | slave_ral_model model; 102 | 103 | `uvm_component_utils(yuu_apb_base_case) 104 | 105 | function new(string name, uvm_component parent); 106 | super.new(name, parent); 107 | endfunction 108 | 109 | function void build_phase(uvm_phase phase); 110 | cfg = new("cfg"); 111 | cfg.events = new("events"); 112 | uvm_config_db #(virtual yuu_apb_interface)::get(null, get_full_name(), "vif", vif); 113 | 114 | cfg.apb_if = vif; 115 | begin 116 | yuu_apb_master_config m_cfg = new("e0_m0"); 117 | m_cfg.apb3_enable = True; 118 | m_cfg.idle_enable = True; 119 | m_cfg.coverage_enable = True; 120 | m_cfg.index = 0; 121 | cfg.set_config(m_cfg); 122 | end 123 | begin 124 | yuu_apb_slave_config s_cfg = new("e0_s0"); 125 | s_cfg.apb3_enable = True; 126 | s_cfg.wait_enable = True; 127 | s_cfg.index = 0; 128 | s_cfg.set_map(0, 32'hF000_0000); 129 | cfg.set_config(s_cfg); 130 | end 131 | 132 | uvm_config_db #(yuu_apb_env_config)::set(this, "env", "cfg", cfg); 133 | env = yuu_apb_env::type_id::create("env", this); 134 | 135 | scb = yuu_apb_mini_scoreboard::type_id::create("scb", this); 136 | endfunction : build_phase 137 | 138 | function void connect_phase(uvm_phase phase); 139 | if (cfg.mst_cfg[0].use_reg_model) begin 140 | model = slave_ral_model::type_id::create("model"); 141 | model.build(); 142 | model.lock_model(); 143 | model.reset(); 144 | model.default_map.set_sequencer(env.vsequencer.master_sequencer[0], env.master[0].adapter); 145 | env.master[0].predictor.map = model.default_map; 146 | end 147 | vsequencer = env.vsequencer; 148 | 149 | scb.vif = cfg.mst_cfg[0].vif; 150 | env.master[0].out_monitor_ap.connect(scb.mst_mon_export); 151 | env.slave[0].out_monitor_ap.connect(scb.slv_mon_export); 152 | endfunction 153 | 154 | task wait_scb_done(); 155 | wait(scb.mst_mon_item_q.size() == 0); 156 | wait(scb.slv_mon_item_q.size() == 0); 157 | endtask 158 | endclass 159 | 160 | `endif 161 | -------------------------------------------------------------------------------- /src/sv/yuu_apb_slave/yuu_apb_slave_driver.sv: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright 2019 seabeam@yahoo.com - Licensed under the Apache License, Version 2.0 3 | // For more information, see LICENCE in the main folder 4 | ///////////////////////////////////////////////////////////////////////////////////// 5 | `ifndef YUU_APB_SLAVE_DRIVER_SV 6 | `define YUU_APB_SLAVE_DRIVER_SV 7 | 8 | class yuu_apb_slave_driver extends uvm_driver #(yuu_apb_slave_item); 9 | virtual yuu_apb_slave_interface vif; 10 | uvm_analysis_port #(yuu_apb_slave_item) out_driver_ap; 11 | 12 | yuu_apb_slave_config cfg; 13 | uvm_event_pool events; 14 | protected process processes[string]; 15 | protected yuu_amba_addr_map maps[]; 16 | 17 | protected yuu_apb_slave_memory m_mem; 18 | 19 | `uvm_register_cb(yuu_apb_slave_driver, yuu_apb_slave_driver_callback) 20 | 21 | `uvm_component_utils_begin(yuu_apb_slave_driver) 22 | `uvm_component_utils_end 23 | 24 | extern function new(string name = "yuu_apb_slave_driver", uvm_component parent); 25 | extern virtual function void build_phase(uvm_phase phase); 26 | extern virtual function void connect_phase(uvm_phase phase); 27 | extern virtual task run_phase(uvm_phase phase); 28 | 29 | extern protected virtual task init_component(); 30 | extern protected virtual function void init_mem(); 31 | extern protected virtual function boolean is_out(yuu_apb_addr_t addr); 32 | extern protected virtual task reset_signal(); 33 | extern protected virtual task get_and_drive(); 34 | extern protected virtual task drive_bus(); 35 | extern protected virtual task wait_reset(); 36 | endclass 37 | 38 | function yuu_apb_slave_driver::new(string name = "yuu_apb_slave_driver", uvm_component parent); 39 | super.new(name, parent); 40 | endfunction 41 | 42 | function void yuu_apb_slave_driver::build_phase(uvm_phase phase); 43 | out_driver_ap = new("out_driver_ap", this); 44 | cfg.get_maps(maps); 45 | endfunction 46 | 47 | function void yuu_apb_slave_driver::connect_phase(uvm_phase phase); 48 | this.vif = cfg.vif; 49 | this.events = cfg.events; 50 | endfunction 51 | 52 | task yuu_apb_slave_driver::run_phase(uvm_phase phase); 53 | process proc_drive; 54 | 55 | init_component(); 56 | fork 57 | forever begin 58 | wait(vif.drv_mp.preset_n === 1'b1); 59 | fork 60 | begin 61 | proc_drive = process::self(); 62 | processes["proc_drive"] = proc_drive; 63 | get_and_drive(); 64 | end 65 | join 66 | end 67 | wait_reset(); 68 | join 69 | endtask 70 | 71 | 72 | task yuu_apb_slave_driver::init_component(); 73 | init_mem(); 74 | reset_signal(); 75 | endtask 76 | 77 | function void yuu_apb_slave_driver::init_mem(); 78 | if (!uvm_config_db #(yuu_apb_slave_memory)::get(null, get_full_name(), "mem", m_mem)) begin 79 | m_mem = new; 80 | end 81 | m_mem.init_pattern = cfg.mem_init_pattern; 82 | m_mem.data_width = cfg.data_width; 83 | endfunction 84 | 85 | function boolean yuu_apb_slave_driver::is_out(yuu_apb_addr_t addr); 86 | foreach (maps[i]) begin 87 | if (maps[i].is_contain(addr)) 88 | return False; 89 | end 90 | 91 | `uvm_warning("is_out", $sformatf("Address 0x%0h out of bound", addr)) 92 | return True; 93 | endfunction 94 | 95 | task yuu_apb_slave_driver::reset_signal(); 96 | vif.drv_cb.prdata <= 'h0; 97 | vif.drv_cb.pready <= 1'b1; 98 | vif.drv_cb.pslverr <= 1'b0; 99 | endtask 100 | 101 | task yuu_apb_slave_driver::get_and_drive(); 102 | drive_bus(); 103 | endtask 104 | 105 | task yuu_apb_slave_driver::drive_bus(); 106 | uvm_event drive_trans_begin = events.get($sformatf("%s_drive_trans_begin", cfg.get_name())); 107 | uvm_event drive_trans_end = events.get($sformatf("%s_drive_trans_end", cfg.get_name())); 108 | uvm_event handshake = events.get($sformatf("%s_handshake", cfg.get_name())); 109 | 110 | while(vif.drv_cb.psel !== 1'b1) 111 | vif.wait_cycle(); 112 | 113 | seq_item_port.get_next_item(req); 114 | handshake.trigger(); 115 | @(vif.drv_cb); 116 | `uvm_do_callbacks(yuu_apb_slave_driver, yuu_apb_slave_driver_callback, pre_send(this, req)); 117 | drive_trans_begin.trigger(); 118 | 119 | req.addr = vif.drv_cb.paddr; 120 | req.direction = yuu_apb_direction_e'(vif.drv_cb.pwrite); 121 | req.strb = vif.drv_cb.pstrb; 122 | {req.prot2, req.prot1, req.prot0} = vif.mon_cb.pprot; 123 | if (is_out(req.addr)) 124 | req.resp = ERROR; 125 | 126 | if (cfg.apb3_enable) begin 127 | vif.drv_cb.pready <= 1'b0; 128 | repeat(req.wait_cycle) vif.wait_cycle(); 129 | vif.drv_cb.pready <= 1'b1; 130 | end 131 | 132 | if (req.direction == WRITE) begin 133 | if (req.resp != ERROR) begin 134 | req.data = vif.drv_cb.pwdata; 135 | if (cfg.apb4_enable) 136 | m_mem.write(req.addr, req.data, req.strb); 137 | else 138 | m_mem.write(req.addr, req.data); 139 | end 140 | end 141 | else if (req.direction == READ) begin 142 | yuu_apb_data_t data; 143 | 144 | if (req.resp != ERROR) begin 145 | m_mem.read(req.addr, data); 146 | vif.drv_cb.prdata <= data; 147 | req.data = data; 148 | end 149 | else begin 150 | vif.drv_cb.prdata <= 'h0; 151 | req.data = 'h0; 152 | end 153 | end 154 | if (cfg.apb3_enable && req.resp == ERROR) begin 155 | vif.drv_cb.pslverr <= 1'b1; 156 | end 157 | vif.wait_cycle(); 158 | vif.drv_cb.pslverr <= 1'b0; 159 | 160 | `uvm_do_callbacks(yuu_apb_slave_driver, yuu_apb_slave_driver_callback, post_send(this, req)); 161 | out_driver_ap.write(req); 162 | if (cfg.use_response) begin 163 | rsp = yuu_apb_slave_item::type_id::create("rsp"); 164 | rsp.copy(req); 165 | rsp.set_id_info(req); 166 | end 167 | seq_item_port.item_done(rsp); 168 | handshake.reset(); 169 | drive_trans_end.trigger(); 170 | vif.wait_cycle(); 171 | endtask 172 | 173 | task yuu_apb_slave_driver::wait_reset(); 174 | uvm_event handshake = events.get($sformatf("%s_handshake", cfg.get_name())); 175 | 176 | forever begin 177 | @(negedge vif.drv_mp.preset_n); 178 | `uvm_warning("wait_reset", "Reset signal is asserted, transaction may be dropped") 179 | if (handshake.is_on()) 180 | seq_item_port.item_done(); 181 | foreach (processes[i]) 182 | processes[i].kill(); 183 | init_component(); 184 | @(posedge vif.drv_mp.preset_n); 185 | end 186 | endtask 187 | 188 | `endif 189 | 190 | -------------------------------------------------------------------------------- /test/slave_ral_model.sv: -------------------------------------------------------------------------------- 1 | /* 2 | THIS MODEL IS GENERATED BY SCRIPT AUTOMATICALLY 3 | */ 4 | 5 | `ifndef SLAVE_RAL_MODEL_SV 6 | `define SLAVE_RAL_MODEL_SV 7 | 8 | class reg_slave_ID extends uvm_reg; 9 | rand uvm_reg_field ID; 10 | 11 | `uvm_object_utils_begin(reg_slave_ID) 12 | `uvm_field_object(ID, UVM_ALL_ON) 13 | `uvm_object_utils_end 14 | 15 | function new(string name="reg_slave_ID"); 16 | super.new(name, 32, UVM_CVR_ALL); 17 | endfunction 18 | 19 | virtual function void build(); 20 | ID = uvm_reg_field::type_id::create("ID"); 21 | ID.configure(.parent(this), .size(32), .lsb_pos(0), 22 | .access("RO"), .volatile(0), .reset(32'hDEADBEEF), 23 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 24 | endfunction 25 | endclass : reg_slave_ID 26 | 27 | class reg_slave_Clock extends uvm_reg; 28 | rand uvm_reg_field res_0; 29 | rand uvm_reg_field EN; 30 | rand uvm_reg_field FREQ; 31 | rand uvm_reg_field DIV; 32 | 33 | `uvm_object_utils_begin(reg_slave_Clock) 34 | `uvm_field_object(res_0, UVM_ALL_ON) 35 | `uvm_field_object(EN, UVM_ALL_ON) 36 | `uvm_field_object(FREQ, UVM_ALL_ON) 37 | `uvm_field_object(DIV, UVM_ALL_ON) 38 | `uvm_object_utils_end 39 | 40 | function new(string name="reg_slave_Clock"); 41 | super.new(name, 32, UVM_CVR_ALL); 42 | endfunction 43 | 44 | virtual function void build(); 45 | res_0 = uvm_reg_field::type_id::create("res_0"); 46 | res_0.configure(.parent(this), .size(27), .lsb_pos(5), 47 | .access("RO"), .volatile(0), .reset(32'h0), 48 | .has_reset(1), .is_rand(0), .individually_accessible(0)); 49 | EN = uvm_reg_field::type_id::create("EN"); 50 | EN.configure(.parent(this), .size(1), .lsb_pos(4), 51 | .access("RW"), .volatile(0), .reset(32'h1), 52 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 53 | FREQ = uvm_reg_field::type_id::create("FREQ"); 54 | FREQ.configure(.parent(this), .size(2), .lsb_pos(2), 55 | .access("RW"), .volatile(0), .reset(32'h0), 56 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 57 | DIV = uvm_reg_field::type_id::create("DIV"); 58 | DIV.configure(.parent(this), .size(2), .lsb_pos(0), 59 | .access("RW"), .volatile(0), .reset(32'h0), 60 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 61 | endfunction 62 | endclass : reg_slave_Clock 63 | 64 | class reg_slave_TIMER extends uvm_reg; 65 | rand uvm_reg_field res_0; 66 | rand uvm_reg_field START; 67 | rand uvm_reg_field ENABLE; 68 | rand uvm_reg_field COUNTER; 69 | 70 | `uvm_object_utils_begin(reg_slave_TIMER) 71 | `uvm_field_object(res_0, UVM_ALL_ON) 72 | `uvm_field_object(START, UVM_ALL_ON) 73 | `uvm_field_object(ENABLE, UVM_ALL_ON) 74 | `uvm_field_object(COUNTER, UVM_ALL_ON) 75 | `uvm_object_utils_end 76 | 77 | function new(string name="reg_slave_TIMER"); 78 | super.new(name, 32, UVM_CVR_ALL); 79 | endfunction 80 | 81 | virtual function void build(); 82 | res_0 = uvm_reg_field::type_id::create("res_0"); 83 | res_0.configure(.parent(this), .size(26), .lsb_pos(6), 84 | .access("RO"), .volatile(0), .reset(32'h0), 85 | .has_reset(1), .is_rand(0), .individually_accessible(0)); 86 | START = uvm_reg_field::type_id::create("START"); 87 | START.configure(.parent(this), .size(1), .lsb_pos(5), 88 | .access("WO"), .volatile(0), .reset(32'h0), 89 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 90 | ENABLE = uvm_reg_field::type_id::create("ENABLE"); 91 | ENABLE.configure(.parent(this), .size(1), .lsb_pos(4), 92 | .access("RW"), .volatile(0), .reset(32'h0), 93 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 94 | COUNTER = uvm_reg_field::type_id::create("COUNTER"); 95 | COUNTER.configure(.parent(this), .size(4), .lsb_pos(0), 96 | .access("RW"), .volatile(0), .reset(32'hF), 97 | .has_reset(1), .is_rand(1), .individually_accessible(0)); 98 | endfunction 99 | endclass : reg_slave_TIMER 100 | 101 | class block_slave_control extends uvm_reg_block; 102 | rand reg_slave_ID ID; 103 | rand reg_slave_Clock Clock; 104 | 105 | `uvm_object_utils_begin(block_slave_control) 106 | `uvm_field_object(ID, UVM_ALL_ON) 107 | `uvm_field_object(Clock, UVM_ALL_ON) 108 | `uvm_object_utils_end 109 | 110 | function new(string name="block_slave_control"); 111 | super.new(name, UVM_CVR_ALL); 112 | endfunction 113 | 114 | function void build(); 115 | default_map = create_map("default_map", 32'h00000000, 4, UVM_LITTLE_ENDIAN); 116 | 117 | ID = reg_slave_ID::type_id::create("ID"); 118 | ID.configure(this, null, ""); 119 | ID.build(); 120 | default_map.add_reg(ID, 32'h00, "RO"); 121 | 122 | Clock = reg_slave_Clock::type_id::create("Clock"); 123 | Clock.configure(this, null, ""); 124 | Clock.build(); 125 | default_map.add_reg(Clock, 32'h04, "RW"); 126 | endfunction 127 | endclass : block_slave_control 128 | 129 | class block_slave_common extends uvm_reg_block; 130 | rand reg_slave_TIMER TIMER; 131 | 132 | `uvm_object_utils_begin(block_slave_common) 133 | `uvm_field_object(TIMER, UVM_ALL_ON) 134 | `uvm_object_utils_end 135 | 136 | function new(string name="block_slave_common"); 137 | super.new(name, UVM_CVR_ALL); 138 | endfunction 139 | 140 | function void build(); 141 | default_map = create_map("default_map", 32'h00000100, 4, UVM_LITTLE_ENDIAN); 142 | 143 | TIMER = reg_slave_TIMER::type_id::create("TIMER"); 144 | TIMER.configure(this, null, ""); 145 | TIMER.build(); 146 | default_map.add_reg(TIMER, 32'h00, "RW"); 147 | endfunction 148 | endclass : block_slave_common 149 | 150 | class slave_ral_model extends uvm_reg_block; 151 | rand block_slave_control control; 152 | rand block_slave_common common; 153 | 154 | `uvm_object_utils_begin(slave_ral_model) 155 | `uvm_field_object(control, UVM_ALL_ON) 156 | `uvm_field_object(common, UVM_ALL_ON) 157 | `uvm_object_utils_end 158 | 159 | function new(string name="slave_ral_model"); 160 | super.new(name); 161 | endfunction 162 | 163 | function void build(); 164 | default_map = create_map("default_map", 0, 4, UVM_LITTLE_ENDIAN); 165 | 166 | control = block_slave_control::type_id::create("control"); 167 | control.configure(this); 168 | control.build(); 169 | default_map.add_submap(control.default_map, 32'h00000000); 170 | 171 | common = block_slave_common::type_id::create("common"); 172 | common.configure(this); 173 | common.build(); 174 | default_map.add_submap(common.default_map, 32'h00000100); 175 | endfunction 176 | endclass : slave_ral_model 177 | 178 | `endif --------------------------------------------------------------------------------