Beruflich Dokumente
Kultur Dokumente
2 (CSI-2)
TOP
TEST
ENV SCOREBOARD REG APB ADAPTER
VSEQR
REGMODEL
PPI AGENT APB AGENT PIXEL AGENT CCI AGENT REG AGENT
PPI INTF APB INTF PIXEL INTF CCI INTF REG INTF
DUT
ENV
INSTANTIATIONS: ………
• csi2_vseqr vseqr;
• csi2_ppi_tx_agt ppi_agt;
• apb_master_agt apb_m_agt;
• pixel_rx_agt pixel_agt;
• csi2_scb scb;
• ral_sys_CSI2_MEM_MAP regmodel;
• reg2apb_adapter reg2apb;
• csi2_cci_slave_agt cci_agt;
• csi2_rx_reg_agt reg_agt ;
build_phase:
vseqr = csi2_vseqr::type_id::create("vseqr",this);
ppi_agt = csi2_ppi_tx_agt::type_id::create("ppi_agt",this);
apb_m_agt = apb_master_agt::type_id::create("apb_m_agt",this);
pixel_agt = pixel_rx_agt::type_id::create("pixel_agt",this);
scb = csi2_scb::type_id::create("scb",this);
reg2apb = reg2apb_adapter::type_id::create("reg2apb",this);
//Adaptor creation
cci_agt = csi2_cci_slave_agt::type_id::create("cci_agt",this);
reg_agt = csi2_rx_reg_agt::type_id::create("reg_agt",this);
if(regmodel == null) begin
regmodel =
ral_sys_CSI2_MEM_MAP::type_id::create("regmodel",this);
regmodel.build();
regmodel.lock_model();
end
connect_phase:
• ppi_agt.a_port.connect(scb.ppi_pkt_export);
• pixel_agt.a_port.connect(scb.pixel_pkt_export);
• cci_agt.agent_port.connect(scb.cci_pkt_export);
• apb_m_agt.a_port.connect(scb.apb_pkt_export);
• vseqr.ppi_sqr = ppi_agt.seqr;
• vseqr.reg_sqr = reg_agt.seqr;
• vseqr.cci_sqr = cci_agt.seqr;
• vseqr.apb_sqr = apb_m_agt.seqr;
• regmodel.default_map.set_sequencer(apb_m_agt.seqr,reg2apb); // connect ral
map to bus sequencer and adaptor
• regmodel.default_map.set_auto_predict(1); //enable auto prediction ON if you are
not implementing predictor
• vseqr.regmodel = this.regmodel;
• scb.regmodel = this.regmodel;
• cci_agt.regmodel = this.regmodel ;
• uvm_config_db#(ral_sys_CSI2_MEM_MAP)::set(this,"*","ral_sys_CSI2_MEM_MAP",
regmodel);
VIRTUAL SEQUENCER
TEST
APB AGENT
ENV
SQR APB
VIRTUAL VIRTUAL
SEQUENCE SEQUENCER CCI AGENT
SQR CCI
SQR CCI PPI AGENT
• In that sequence we randomize the sequence_item of type req which is from uvm
library.
CCI AGENT
Camera Control Interface (CCI)
• CCI is a two-wire, bi-directional, half duplex, serial interface for controlling the
transmitter.
• CCI is compatible with the fast mode variant of the I2C interface.
• CCI is capable of handling multiple slaves on the bus. Multi-master mode is not
supported by CCI.
Cont.. •
•
`uvm_info(get_type_name(),"Begin of detect
start",UVM_LOW);
@(posedge m_vif.clk_50)
• task detect_stop();
• if(m_vif.sclk_out == 1 && m_vif.sda_out == 1) begin
• int j; //initially scl and sda should high
• `uvm_info(get_type_name(),"Begin of detect • end
stop",UVM_LOW);
• else begin
• forever begin
• `uvm_fatal(get_type_name()," start condition is violated");
• @(posedge m_vif.clk_50);
• end
• if(m_vif.sclk_out == 1 && m_vif.sda_out == 0) begin
• forever begin
• //`uvm_info("INFO" , "Waiting for stop condition",
UVM_LOW); • @(posedge m_vif.clk_50)
• end • if(m_vif.sclk_out == 1 && m_vif.sda_out == 1) begin
• if(m_vif.sclk_out == 1 && m_vif.sda_out == 1) begin • // `uvm_info("INFO" , "Waiting for start condition drv",
UVM_LOW);
• `uvm_info(get_type_name(),"Stop detected",
UVM_LOW); • end
• out_of_reset = 0; • if(m_vif.sclk_out == 1 && m_vif.sda_out == 0) begin
• `uvm_info(get_type_name(),"End of detect • `uvm_info(get_type_name(),"Start detected",
stop",UVM_LOW); UVM_LOW);
• return; • `uvm_info(get_type_name(),"End of detect
start",UVM_LOW);
• end
• return;
• end
• end
• endtask
Cont..
• task drive_ack();
• int i;
• for(i = 0; i < 160; i++) begin
• @(posedge m_vif.clk_50);
• end
• if(m_vif.sda_en == 0 && item.nack_en == 1) begin
• m_vif.tb_sda_out <= 1;
• end
• else if(m_vif.sda_en == 0 && item.nack_en == 0) begin
• m_vif.tb_sda_out <= 0;
• end
• else begin
• `uvm_info(get_type_name(),
• "sda_en should be pulled low to drive
ack",UVM_LOW);
• end
• endtask
Cnt..
• task write_data();
• task read_data();
• `uvm_info(get_type_name(),"Begin of write
• bit [7:0] temp;
data",UVM_LOW);
• int i,j; • get_address(); //Simply wait for 8 clock cycle as MASTER is
• `uvm_info(get_type_name(),"Begin of read data", transmiting data from DATA reg
UVM_LOW);
• drive_ack();
• /*--------- Repeats loop for number of bytes -----------------*/
• `uvm_info(get_type_name(),"End of write data",UVM_LOW);
• temp = item.data;
• endtask
• for(i = 7; i >= 0; i--) begin
• task get_address();
• for (j = 0; j< 160; j++) begin
• int i,j;
• @(posedge m_vif.clk_50);
• for(i = 7; i >= 0; i--) begin
• end
• for (j = 0; j< 160; j++) begin
• m_vif.tb_sda_out <= temp[i];
• @(posedge m_vif.clk_50);
• end
• end
• /*---- Waiting for next clock cycle and checks ack --------*/
• end
• for (j = 0; j< 160; j++) • endtask
• @(posedge m_vif.clk_50);
• `uvm_info(get_type_name(),"End of read data",UVM_LOW);
• endtask
Starting.. • for (j = 0; j< 160; j++) begin // 8th clock blank
• data=regmodel.CSI2_RX_ADDR_BLK.CCI_CONTROL_REG. • @(posedge m_vif.clk_50);
get(); • end
• @(posedge m_vif.sclk_out)
• drive_ack(); // drive ack from SLAVE
side
• item.slave_addr[6] = m_vif.sda_out; //MSB transmit • item.index_addr_en = data[3:2]; //Uses read
first data from the control register
• item.rd_wr = data[1];
• /*----------------- Getting slave address --------------------
*/ • item.byte_cnt = data[7:4];
• for( i = 5; i >= 0; i--) begin • item.rep_start = data[8];
• for (j = 0; j< 160; j++) begin
• @(posedge m_vif.clk_50);
• end
• item.slave_addr[i] = m_vif.sda_out;
• end
Cnt..
• /*--------------- Write loop - Random location ---------------*/
LANE MANAGMENT
D-PHY LAYER
PPI Signals
Low Level Protocol
Cont…
• The Low Level Protocol (LLP) is a byte orientated, packet based protocol
• Supports two packet structures
• Long packets
• Short packets.
• A Short Packet shall contain only a Packet Header; neither Packet Footer nor
Packet Filler bytes shall be present.
e.g. 0x07=0b0000_0111=P7P6P5P4P3P2P1P0
• The top row defines the three LSB of data position bit, and
the left column defines the three MSB of data position bit (there are 64-bit positions in total).
• e.g. 37th bit position is encoded 0b100_101 and has the syndrome 0x68.
• To derive the parity P0 for 24-bits, the P0’s in the orange rows will define if the corresponding bit
position is used in P0 parity or not.
• To correct a single-bit error, the syndrome has to be one of the syndromes Table 4, which will identify
the bit position in error.
•
// If there is 2-bit ecc error ,
// then the 8 and 18 bits of header are negated.
• else if(this.ecc_ertyp_e == ECC_2B_ERR ) begin
• hdr[3] = !hdr[3] ;
• // If there is 3-bit ecc error , • hdr[7] = !hdr[7] ;
• // then the 2,5 and 7 bits of header • end
are negated. •
• if(this.ecc_ertyp_e == ECC_3B_ERR • // If there is 1-bit ecc error , then the bit
) begin • // ,based on the value of ecc_err_pos, of header is negated.
• hdr[2] = !hdr[2]; • else if(this.ecc_ertyp_e == ECC_1B_ERR )
• hdr[3] = !hdr[3]; • hdr[this.ecc_err_pos] = !hdr[this.ecc_err_pos] ; //Here the
ecc_err_pos is random value when driver drive
• hdr[7] = !hdr[7];
• end • // The changes in the packet header fields are updated
• • // depending on the scenario of errors.
• {this.ecc,this.wc,this.vc_no} = hdr[31:6] ;
• this.dt_e = ftyp_enu'(hdr[5:0]); //Based on the new
Header update the ecc,wc,vc_no and dt_e
• endfunction
Cont…
Lane management
• The CSI-2 transmitter incorporates a Lane Distribution Function (LDF)
which accepts a sequence of packet bytes from the low level protocol
layer and distributes them across N Lanes, where each Lane is an
independent unit of physical-layer logic (serializers, etc.) and
transmission circuitry. The CSI-2 receiver incorporates a Lane
Merging Function (LMF) which collects incoming bytes from N Lanes
and consolidates (merges) them into complete packets to pass into
the packet decomposer in the receiver’s low level protocol layer.
Cont…
LDF
Cont..
• // the do_pack() function packs the fields of the LLP packet,based on the
• // type of the packet, to array of bytes.
• function void do_pack(uvm_packer packer);
• super.do_pack(packer);
• packer.pack_field_int(dt_e,$bits(dt_e));
• packer.pack_field_int(vc_no,$bits(vc_no));
• packer.pack_field_int(wc,$bits(wc));
• packer.pack_field_int(ecc,$bits(ecc));
• //if(this.dt_e[5:4] != 2'b00 || pyld_q.size() != 0 ) begin
• if(pyld_q.size() != 0 ) begin
• foreach(pyld_q[i]) packer.pack_field_int(pyld_q[i],8 );
• packer.pack_field_int(crc,$bits(crc));
• end
• endfunction
•
LMF
Cnt..
• // the do_u // the LLP packet,based on the type of the packet.
• function void do_unpack(uvm_packer packer);
• super.do_unpack(packer);
• this.dt_e = ftyp_enu'(packer.unpack_field_int($bits(dt_e)));
• this.vc_no = packer.unpack_field_int($bits(vc_no));
• this.wc = packer.unpack_field_int($bits(wc));
• this.ecc = packer.unpack_field_int($bits(ecc));
• this.check_ecc();
• // The payload and crc is unpacked for long packets .
•
• if(this.ecc_ertyp_e != ECC_2B_ERR && this.ecc_ertyp_e != ECC_3B_ERR &&
• this.dt_e[5:4] != 2'b00 ) begin
• for(int i = 0;i < ((packer.get_packed_size()/8)-6); i++ ) //get_packed_size() gives total no of bits packed.
• //divide by 8 gives no of bytes. again deducting 6 indicates 4 byte
HEADER //and 2 byte CRC
• this.pyld_q.push_back(packer.unpack_field_int(8));
• this.crc = packer.unpack_field_int($bits(crc));
• end
• endfunctionnpack() function unpacks the array of bytes to the fields of
Cont…
• This task get the packet from sequencer.
• Calculates ecc and crc. Then pack the packet using pack_bytes function.
• Calculates packed array size and calls drive_pkt task.
• If(pkt)
• if(shrt_pkt && 2-bit error) begin
• Update status registers
• Calling ecc and crc functions
• Packing variables into an array
• DRIVE_PCKT();
DRIVE_PKT
• HERE will check for modes with lp_mode_active signal .If high means LP-mode
and low means HS mode. While transforming one mode to another mode wait
for shutdown time and make previous mode low.
• Based on number of lines we select method and drive all lanes parllely.
• Based on the configured number of lanes, it calculates the loop cnt.
• From pkd_bytes array, it takes the data corresponding to lane_0 and drives the
data in lane_0 according to protocol.
Cnt..
• virtual task drive_lane_2();
• int lp_cnt;
• if (pkt_array_size % no_of_lanes >
2) begin
• lp_cnt =
(pkt_array_size/no_of_lanes) + 1;
• end else begin
• lp_cnt =
(pkt_array_size/no_of_lanes);
• end
• if(!lp_mode_active)
• drive_hs_lane_2(lp_cnt);
• else
• drive_lp_lane_2(lp_cnt);
• endtask
Cnt..
Cnt..
• task drive_hs_lane_2(int lp_cnt); • m_vif.rx_sync_hs_2 <= 'b1;
• int indx = 2; //For lane- • @(posedge m_vif.rx_byteclk_hs_2);
2, data transfer starts at index=2
• if (m_vif.reset_n) begin
• if(lp_mode_active != prev_speed)
begin • m_vif.rx_sync_hs_2 <= 'b0;
• repeat(hs_startup_time) • m_vif.rx_valid_hs_2 <= 'b1;
• @(posedge • end
m_vif.rx_byteclk_hs_2);
• for (int i = 0; i < lp_cnt; i ++) begin
• end
• @(posedge m_vif.rx_byteclk_hs_2); • if (!m_vif.reset_n) break;
• if (m_vif.reset_n) begin • if (i != 0) begin
• m_vif.rx_active_hs_2 <= 'b1; • @(posedge
m_vif.rx_byteclk_hs_2);
• end
• end
• repeat (active_to_sync_dly) begin
• @(posedge m_vif.rx_byteclk_hs_2); • m_vif.rx_data_hs_2 <=
pkd_bytes[indx];
• if (!m_vif.reset_n) break;
• indx = indx + no_of_lanes;
• end
• end;
PPI
• For a PHY with multiple Data Lanes, a set of PPI signals is used for each Lane.
Each signal has been assigned into one of six categories: High-Speed transmit
signals, High-Speed receive signals, Escape mode transmit signals, Escape mode
receive signals, control signals, and error signals.
HS-MODE Pn
DIGITAL ANALOG
Cn
CAMERA
Pn
DIGITAL ANALOG
DISPLAY Cn
GO
Hs-mode
PIXEL AGENT
PIXEL
• Pixel monitor receives the data (dut) from pixel interface. Inside pixel
Monitor we have frame start, frame end, line start, line end, short
packet and data.
capture_fr_start();
capture_fr_end();
capture_ln_start();
capture_ln_end();
capture_sh_pkt();
data_capture();
Cont…..
• capture_fr_start();
• Insede the frame start task we are randomize as the data type must be FS like wise
• packet.randomize() with { vc_no == m_vif.pixel_channel_no;
• dt_e == FS;
• wc == m_vif.pixel_word_cnt;
• ecc_err_en == 1'b0;
crc_err_en == 1'b0;
• wc_err_en == 1'b0;
• wc_err_val == 5'b0;
• dphy_err_en == 1'b0;
• ecc_err_pos == 1'b0;
• };
Cont…
• After randomizing according to the frame start or frame end or line start or
line end --- calculate the ecc for that
• packet.calc_ecc();
• Send the data of frame start or frame end or line start or line end to the
scoreboard through sequence item csi2_llp_pkt_txd(packet)
• send_2_aport(packet);
• After sending to the scoreboard get the data from the regmodel.
• if(regmodel.CSI2_RX_ADDR_BLK.ECC_Enable.get())
• frm_cntr++;
ECC_Enable Indicates ECC has performed on the received packet header
Cont….
• For the short packet
• if(m_vif.short_pkt_valid == 1 && m_vif.pixel_data_type[5:4] == 2'b00
&& !m_vif.frame_start && !m_vif.frame_end && !m_vif.line_start
&& !m_vif.line_end ) begin
• In data_capture() task we are collect the data from dut
• pixel_q.push_back(m_vif.pixel_data);
• based on the dt_type start reading byte from the pixel queue
• pixel_byt_conv(pixel_q,payld_q,ftyp_enu'(m_vif.pixel_data_type),m_
vif.pixel_word_cnt);
Cont….
• case(dt_type)
• RGB888 : begin
• bytpr_p = 3;//RGB888
• n_byt = 3;
• end
• RGB565 : begin
• bytpr_p = 4;//RGB565
• n_byt = 2;
• end
• RAW10 : begin
• bytpr_p = 5;//RAW10
• n_byt = 5;
• end
Cont…..
• if RAW10 the byte conversion is different the LSB's are rearranged to push into the payload queue
• if(dt_type == 6'h2B) begin (for RAW10 data type)
• the first four pixel byte are directly pushed into the queue
• for(int j = 9;j<= bytpr_p*8-1 ;j=j+10) begin
• payld_q.push_back(pixel_q[i][j -: 8]);
• end
• the LSB's are first assigned to a temp variablevthen the 8 bit temp is pushed into payload queue
• for(int j=31;j>0;j=j-10) begin
• temp = (temp<<2) | pixel_q[i][j -: 2];
• end
• payld_q.push_back(temp);
• end
SCOREBOARD
• Using macro `uvm_analysis_imp_decl(<_portname>), to declare
uvm_analysis_imp_<_portname> class.
• We need 2 import, one for expected packet which is sent by driver and received packet which is
coming from receiver.
Declare 2 imports using `uvm_analysis_imp_decl macros should not be defined inside the class.
• `uvm_analysis_imp_decl(_exp_data)
• `uvm_analysis_imp_decl(_obs_data)
• `uvm_analysis_imp_decl(_exp_data_apb)
• `uvm_analysis_imp_decl(_obs_data_cci)