今天我们讲memory model的写法,例子是OTP class svidOTPXactor extends vmm_xactor; //应为都是异步信号,因此直接使用interface virtual svidIntf svid_intf; // xactor应该留有的外部CFG 成员 svidSYSCfg sys_cfg; svidREGCfg reg_cfg; // associative 数组 bit[7:0] ram[*];//RAM // 定义事件,用户事件都从0开始 typedef enum int {RESET_DONE,ADDR_UPDATE} otpevent_e; extern function new( svidSYSCfg sys_cfg, svidREGCfg reg_cfg, virtual svidIntf svid_intf); extern virtual protected task main(); extern virtual task load_ram(); extern virtual task read(); extern virtual task write(); extern function void poke(bit[9:0] address, bit prgbit); extern function byte peek(bit[9:0] address); extern task wait_rstb(); extern task addr_sensor(); endclass //*************************************************** // function new() //*************************************************** function svidOTPXactor::new( svidSYSCfg sys_cfg, svidREGCfg reg_cfg, virtual svidIntf svid_intf); super.new("svidOTPXactor", "class"); this.sys_cfg=sys_cfg; this.reg_cfg=reg_cfg; this.svid_intf=svid_intf; this.notify.configure(RESET_DONE,vmm_notify::ON_OFF); this.notify.configure(ADDR_UPDATE,vmm_notify::ONE_SHOT); endfunction //*************************************************** // main() //*************************************************** task svidOTPXactor::main(); super.main(); //load RAM `vmm_note(log,$psprintf("Load Sram ...")); load_ram(); svid_intf.otp_dout<='z; fork while(1) begin//rstb wait_rstb(); end while(1) begin//addr addr_sensor(); end while(1) begin//read read(); end while(1) begin//write write(); end join endtask //*************************************************** // load_ram //*************************************************** task svidOTPXactor::load_ram(); this.ram[8'h00]=reg_cfg.Vendor_ID; this.ram[8'h01]=reg_cfg.ProductID; this.ram[8'h02]=reg_cfg.Product_Revision; this.ram[8'h03]=reg_cfg.Product_data_code; this.ram[8'h04]=reg_cfg.Lot_Code; this.ram[8'h05]=reg_cfg.Protocol_ID; this.ram[8'h06]=reg_cfg.Capability; this.ram[8'h10]=reg_cfg.Phase_EnableA; this.ram[8'h11]=reg_cfg.VR_addressA; this.ram[8'h12]=reg_cfg.ICC_MAXA; this.ram[8'h13]=reg_cfg.Temp_MaxA; this.ram[8'h14]=reg_cfg.DC_LLA; this.ram[8'h15]=reg_cfg.SR_fastA; this.ram[8'h16]=reg_cfg.SR_slowA; this.ram[8'h17]=reg_cfg.VbootA; this.ram[8'h18]=reg_cfg.VR_toleranceA; this.ram[8'h19]=reg_cfg.Current_offsetA; this.ram[8'h1a]=reg_cfg.Temperature_offsetA; this.ram[8'h30]=reg_cfg.Phase_EnableB; this.ram[8'h31]=reg_cfg.VR_addressB; this.ram[8'h32]=reg_cfg.ICC_MAXB; this.ram[8'h33]=reg_cfg.Temp_MaxB; this.ram[8'h34]=reg_cfg.DC_LLB; this.ram[8'h35]=reg_cfg.SR_fastB; this.ram[8'h36]=reg_cfg.SR_slowB; this.ram[8'h37]=reg_cfg.VbootB; this.ram[8'h38]=reg_cfg.VR_toleranceB; this.ram[8'h39]=reg_cfg.Current_offsetB; this.ram[8'h3a]=reg_cfg.Temperature_offsetB; endtask //*************************************************** // poke //*************************************************** function void svidOTPXactor::poke(bit[9:0] address, bit prgbit); ram[address[9:3]][address[2:0]]=prgbit; `vmm_trace(this.log,$psprintf("Program OTP address:%s with bit:%s",address,prgbit)); endfunction //*************************************************** // peek //*************************************************** function byte svidOTPXactor::peek(bit[9:0] address); logic[7:0] data; if(ram.exists(address[9:3])==0) begin `vmm_warning(this.log,$psprintf("byte address %h Out-of-rang peek",address[9:3])); data='x; end else begin data=ram[address[9:3]]; `vmm_trace(this.log,$psprintf("Read OTP address:%h with data:%h",address[9:3],data[7:0])); end return(data); endfunction //*************************************************** // wait_rstb(); //*************************************************** task svidOTPXactor::wait_rstb(); wait(svid_intf.otp_rstb==0 && svid_intf.otp_ceb==0); wait(svid_intf.otp_rstb==1 && svid_intf.otp_ceb==0); `vmm_trace(log,$psprintf("OTP RESETB Checked ...")); this.notify.indicate(RESET_DONE); endtask //*************************************************** // addr_sensor(); //*************************************************** task svidOTPXactor::addr_sensor(); @(svid_intf.otp_addr) this.notify.indicate(ADDR_UPDATE); endtask //*************************************************** // read(); //*************************************************** task svidOTPXactor::read(); this.notify.wait_for(RESET_DONE); this.notify.wait_for(ADDR_UPDATE); wait(svid_intf.otp_rden); #70ns; svid_intf.otp_dout<=peek(svid_intf.otp_addr); endtask //*************************************************** // write(); //*************************************************** task svidOTPXactor::write(); this.notify.wait_for(RESET_DONE); wait(svid_intf.otp_web==0 && svid_intf.otp_ceb==0 && svid_intf.otp_rden==0 && svid_intf.otp_dle==1); poke(svid_intf.otp_addr,svid_intf.otp_din); this.notify.reset(RESET_DONE); endtask