目录
- class ctrl_reg extends uvm_reg;
- `uvm_object_utils(ctrl_reg)
- uvm_reg_field reserved;
- rand uvm_reg_field pkt_len;//声明域,且可以随机化
- rand uvm_reg_field prio_level;
- rand uvm_reg_field chnl_en;
- function new(string name ="ctrl_reg");
- super.new(name, 32, UVM_NO_COVERAGE);
- endfunction
- virtual function build();
- reserved = uvm_reg_field::type_id::create("");
- pkt_len = uvm_reg_field::type_id::create("");
- prio_level = uvm_reg_field::type_id::create("");
- chnl_en = uvm_reg_field::type_id::create("");//例化
- reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0 , 0);//配置
- pkt_len.configure(this,3,3,"RW",0,3'h0,1,1,0);
- prio_level.configure(this,2,1,"RW",0,2'h3,1,1,0);
- chnl_en.configure(this,1,0,"RW",0,1'h0,1,1,0);
- endfunction
- endclass
-
- class stat_reg extends uvm_reg;
- `uvm_object_utils()
- uvm_reg_field reserved;//保留位的域
- rand uvm_reg_field fifo_avail;
- function new(string name="stat_reg");
- super.new(name, 32, UVM_NO_COVERAGE);
- endfunction
- virtual function build();
- reserved = uvm_reg_field::type_id::create("");
- fifo_avail= uvm_reg_field::type_id::create("");
- reserved.configure(this,24,8,"RO",0,24'h0,1,0,0);
- fifo_avail.configure(this,8,0,"RO",0,8'h0,1,1,0);
- endfunction
- endclass
-
- class mcdf_rgm extends uvm_reg_block;
- `uvm_object_utils(mcdf_rgm)
- rand ctrl_reg chnl0_ctrl_reg;
- rand ctrl_reg chnl1_ctrl_reg;
- rand ctrl_reg chnl2_ctrl_reg;
- rand stat_reg chnl0_stat_reg;
- rand stat_reg chnl1_stat_reg;
- rand stat_reg chnl2_stat_reg;
- uvm_reg_map map;
- function new(string name ="")
- super.new(name, UVM_NO_COVERAGE);
- endfunction
-
- virtual function build();
- chnl0_ctrl_reg=ctrl_reg::type_id::create("");
- chnl0_ctrl_reg.configure(this);//创建,配置,
- chnl0_ctrl_reg.build();
- chnl1_ctrl_reg=ctrl_reg::type_id::create("");
- chnl1_ctrl_reg.configure(this);
- chnl1_ctrl_reg.build();
- chnl2_ctrl_reg=ctrl_reg::type_id::create("");
- chnl2_ctrl_reg.configure(this);
- chnl2_ctrl_reg.build();
- chnl0_stat_reg=stat_reg::type_id::create("");
- chnl0_stat_reg.configure(this);
- chnl0_stat_reg.build();
- chnl1_stat_reg=stat_reg::type_id::create("");
- chnl1_stat_reg.configure(this);
- chnl1_stat_reg.build();
- chnl2_stat_reg=stat_reg::type_id::create("");
- chnl2_stat_reg.configure(this);
- chnl2_stat_reg.build();
- map=create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);//map名字,基地址,位宽,endianess
- map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW");//偏移地址offset addr
- map.add_reg(chnl1_ctrl_reg, 32'h00000004, "RW");//完整reg地址addr=base addr+offset addr
- map.add_reg(chnl2_ctrl_reg, 32'h00000008, "RW");
- map.add_reg(chnl0_stat_reg, 32'h00000010, "RO");//添加每个reg的偏移地址和访问属性(模式)
- map.add_reg(chnl1_stat_reg, 32'h00000014, "RO");
- map.add_reg(chnl2_stat_reg, 32'h00000018, "RO");
- lock_model();//reg构建后锁住这个模型,不允许外部访问寄存器内部,只可以用预测组件来改变
- endfunction
- endclass
-
- class mcdf_bus_trans extends uvm_sequence_item;
- rand bit[1:0] cmd;
- rand bit[7:0] addr;
- rand bit[31:0] data;
- bit[31:0] rdata;//从总线读回来的,不可随机化
- `uvm_object_utils_begin()...//注册以及域的自动化
- ...endclass
-
- class mcdf_bus_sequencer extends uvm_sequencer;
- virtual mcdf_if vif;
- `uvm_component_utils()
- ...//注册,例化
- function void build_phase(u p);
- if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
- `uvm_error("", "") end
- endfunction
- endclass
-
- class mcdf_bus_monitor extends uvm_monitor;//等下连接到uvm_reg_predictor
- virtual mcdf_if vif;
- uvm_analysis_port #(mcdf_bus_trans) ap;//monitor要广播
- `uvm_component_utils()
- ...
- function void build_phase(u p);
- if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
- `uvm_error("", "") end
- ap =new("", this);//不能用create,因为port不是object
- endfunction
- task run_phase(u p);
- forever begin
- mon_trnas() end
- endtask
- task mon_trans();
- mcdf_bus_trans t;
- @(posedge vif.clk);
- if(vif.cmd==`WRITE) begin
- t=new();
- t.cmd=`WRITE;
- t.addr=vif.addr;
- t.wdata=vif.wdata;
- ap.write(t);
- end
- else if(vif.cmd==`READ) begin
- t=new();
- t.cmd=`READ;
- t.addr=vif.addr;
- fork begin//等下一个周期
- @(posedge vif.clk);
- #10ps;
- t.rdata=vif.rdata;
- ap.write(t); end
- join_none//的同时不错过下一拍
- end
- endtask
- endclass
-
- class mcdf_bus_driver extends uvm_driver;
- virtual mcdf_if vif;
- ...//注册+例化
- function void build_phase(u p);
- if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
- `uvm_error("", "") end
- endfunction
- task run_phase(u p);
- REQ tmp;
- mcdf_bus_trans req, rsp;
- reset_listener();
- forever begin
- seq_item_port.get_next_item(tmp);
- void'($cast(req,tmp));
- `uvm_info("got")
- void'($cast(rsp, req.clone()));
- rsp.set_sequence_id(req.get_sequence_id());
- rsp.set_transaction_id(req.get_transaction_id());
- driver_bus(rsp);
- set_item_port.item_done(rsp);
- `uvm_info("sent")
- end
- endtask
- task reset_listener();
- fork
- forever begin
- @(negdege vif.rstn) drive_idle();
- end
- join_none
- endtask
- task drive_bus(mcdf_bus_trans t);
- case (t.cmd)
- `WRITE:drive_write(t);
- `READ :drive_read(t);
- `IDLE :drive_idle();
- default: `uvm_error()
- endcase
- endtask
- task drive_write(mcdf_bus_trans t);
- @(posedge vif.clk);
- vif.cmd<=t.cmd;
- vif.addr<=t.addr;
- vif.data<=t.wdata;
- endtask
- task drive_read(mcdf_bus_trans t);
- @(posedge vif.clk);
- vif.cmd<=t.cmd;
- vif.addr<=t.addr;
- @(posedge vif.clk);
- #10ps;
- t.rdata=vif.rdata;
- endtask
- task drive_idle(bit is_sync=0);
- if(is_sync) @(posedge vif.clk);
- vif.cmd<='h0;
- vif.addr<='h0;
- vif.data<='h0;
- endtask
- endclass
-
- class mcdf_bus_agent extends uvm_agent;
- mcdf_bus_driver driver;
- mcdf_bus_sequencer sequencer;
- mcdf_bus_monitor monitor;
- ...
- function void build_phase(u p);
- driver =mcdf_bus_driver::type_id::create("", this);
- sequencer=mcdf_bus_sequencer::type_id::create("", this);
- monitor =mcdf_bus_monitor::type_id::create("", this);
- endfunction
- function void connect_phase(u p);
- driver.seq_item_port.connect(sequencer.seq_item_export);
- endfunction
- endclass
硬件reg
module ctrl_regs();
还差个adapter和predictor
- class ref2mcdf_adapter extends uvm_reg_adapter;
- `uvm_object_utils()
- function new(string name ="");
- super.new(name);
- provides_responses=1;//enable了provides_responses,总线可以返回rsp的数据
- endfunction
- //预定义的,也是必须实现的,名字一个字都不能差
- function uvm_sequence_item reg2bus (const ref uvm_reg_bus_op rw);
- mcdf_bus_trans t=mcdf_bus_trnas::type_id::create("t");//创建子类对象
- t.cmd=(rw.kind == UVM_WRITE)? `WRITE : `READ;
- t.addr=rw.addr;
- t.wdata=rw.data;
- return t;//做了隐式转换
- endfunction//完成了寄存器级别操作rw到bus上的桥接,下面的func反之
-
- function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
- //从driver将数据写会sequencer,adapter从sqr拿到rsp(t)后自动调用
- mcdf_bus_trans t;
- if(!$cast(t, bus_item)) begin//父类句柄,转换成子类mcdf_bus_trans句柄
- `uvm_fatal("", "")
- return; end
- rw.kind=(t.cmd==`WRITE)? UVM_WRITE : UVM_READ;//转换后才可以访问子类对象
- rw.addr=t.addr;
- rw.data=(t.cmd==`WRITE)? t.wdata : t.rdata;
- rw.status=UVM_IS_OK;
- endfunction
- endclass
uvm_reg_bus_op包含这些成员变量,要转换成mcdf_bus_trans
如何将adapter集成到环境中?
- class mcdf_bus_env extends uvm_env;
- mcdf_bus_agent agent;
- mcdf_rgm rgm;
- reg2mcdf_adapter reg2mcdf;
- ...//注册+例化
- function void build_phase(u p);
- agent=mcdf_bus_agent::type_id::create("", this);
- if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
- `uvm_info()
- rgm=mcdf_rgm::type_id::create("", this);
- end
- rgm.build();//创建,配置reg,调用各个reg的build,以及它们的field
- rgm.map.set_auto_predict();
- reg2mcdf=reg2mcdf_adapter::type_id::create("");
- endfunction
-
- function void connect_phase(u p);
- rgm.map.set_sequencer(agent.sequencer, reg2mcdf);//!连接
- endfunction
- endclass
-
- class test1 extends uvm_test;
- mcdf_rgm rgm;
- mcdf_bus_env env;
- ...//注册+例化
- function void build_phase(u p);
- rgm=mcdf_rgm::type_id::create("", this);
- uvm_config_db#(mcdf_rgm)::set(this, "env*", "rgm", rgm)
- env=mcdf_bus_env::type_id::create("", this);
- endfunction
- task run_phase(u p); ...
- endclass
- class mcdf_example_seq extends uvm_reg_sequence;
- mcdf_rgm rgm;
- `uvm_object_utils()
- `uvm_declare_p_sequencer(mcdf_bus_sequencer)
- ...
- task body();
- uvm_status_e status;
- uvm_reg_data_t data;
- if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
- `uvm_error("", "") end
- //方式1:uvm_reg::read()/write()
- rgm.chnl0_ctrl_reg.read (status, data, UVM_FRONTDOOR, .parent(this));
- rgm.chnl0_ctrl_reg.write(status, 'h11, UVM_FRONTDOOR, .parent(this));
- rgm.chnl0_ctrl_reg.read (status, data, UVM_FRONTDOOR, .parent(this));
- //方式2:uvm_reg_sequence::read_reg()/write_reg()
- read_reg (rgm.chnl1_ctrl_reg.read, status, data, UVM_FRONTDOOR);
- write_reg (rgm.chnl1_ctrl_reg.read, status, 'h22, UVM_FRONTDOOR);
- read_reg (rgm.chnl1_ctrl_reg.read, status, data, UVM_FRONTDOOR);
- endtask
- endclass
- class mcdf_rgm extends uvm_reg_block;
- ...//reg成员,map声明
- virtual function build();
- ...//创建
- add_hdl_path("reg_backdoor_access,dut");
- chnl0_ctrl_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV0_RW_REG), 0,32);
- chnl1_ctrl_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV1_RW_REG), 0,32);
- chnl2_ctrl_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV2_RW_REG), 0,32);
- chnl0_stat_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV0_R_REG), 0,32);
- chnl1_stat_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV1_R_REG), 0,32);
- chnl2_stat_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV2_R_REG), 0,32);
- lock_model();//结束地址映射关系,保证model不会被其他用户修改
- endfunction
- endclass
- class mcdf_example_seq extends uvm_reg_sequence;
- mcdf_rgm rgm;
- `uvm_object_utils()
- `uvm_declare_p_sequencer(mcdf_bus_sequencer)
- ...
- task body();
- uvm_status_e status;
- uvm_reg_data_t data;
- if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
- `uvm_error("", "") end
- //read()/write()
- rgm.chnl0_ctrl_reg.read (status, data, UVM_BACKDOOR, .parent(this));
- rgm.chnl0_ctrl_reg.write(status, 'h11, UVM_BACKDOOR, .parent(this));
- rgm.chnl0_ctrl_reg.read (status, data, UVM_BACKDOOR, .parent(this));
- rgm.chnl1_ctrl_reg.peek (status, data, .parent(this));
- rgm.chnl1_ctrl_reg.poke (status, 'h22, .parent(this));
- rgm.chnl1_ctrl_reg.peek (status, data, .parent(this));
- //peek()/poke()
- read_reg (rgm.chnl2_ctrl_reg.read, status, data, UVM_BACKDOOR);
- write_reg (rgm.chnl2_ctrl_reg.read, status, 'h22, UVM_BACKDOOR);
- read_reg (rgm.chnl2_ctrl_reg.read, status, data, UVM_BACKDOOR);
- peek_reg (rgm.chnl2_ctrl_reg, status, data);//peek读取reg
- poke_reg (rgm.chnl2_ctrl_reg, status, 'h33);//poke修改reg
- peek_reg (rgm.chnl2_ctrl_reg, status, data);
-
- endtask
- endclass
二者比较如下