这种SOC结构是在高速总线协议和低速总线协议的互联支持下,将工作在不同频率的各个系统模块进行整合,最终协同处理器完成运算工作。其中低速总线往往采用APB协议,两种总线之间使用转接桥(bridge)完成协议转换。APB协议作为外围总线协议,将为各个低速模块提供通信接口。
uart的相关配置主要包括波特率、帧长、奇偶校验以及停止位。在apbuart_base_test中,有一个set_config_params的方法用来实现这些配置,同时,此方法中还有一个flag来决定是使用定向配置还是随机配置设置。
代码如下:
function void apbuart_base_test::set_config_params(input [31:0] bd_rate , input [3:0] frm_len , input [1:0] parity , input sb , input flag);
if(flag)//flag是用来决定使用定向配置还是随机配置(1 for random , 0 for directed)
begin
if (!cfg.randomize())
`uvm_error("RNDFAIL", " Config Randomization")
end
else
begin
cfg.frame_len = frm_len;
cfg.n_sb = sb;
cfg.parity = parity;
cfg.bRate = bd_rate;
end
cfg.baudRateFunc();
endfunction
function void uart_config::baudRateFunc();
case (bRate)
32'd4800: baud_rate = 32'd10416;
32'd9600: baud_rate = 32'd5208;
32'd14400: baud_rate = 32'd3472;
32'd19200: baud_rate = 32'd2604;
32'd38400: baud_rate = 32'd1302;
32'd57600: baud_rate = 32'd868;
32'd115200: baud_rate = 32'd434;
32'd128000: baud_rate = 32'd392;
default: baud_rate = 32'd5208;
endcase
endfunction
APB相关的主要配置包括address以及pselect(APB中的slave引脚)。使用apbuart_base_test中的set_apbconfig_params方法来实现相关配置。
代码如下:
function void apbuart_base_test::set_apbconfig_params(input [31:0] addr, input flag);
if(flag)
begin
if (!apb_cfg.randomize())
`uvm_error("RNDFAIL", " APB Config Randomization")
end
else
begin
apb_cfg.slave_Addr = addr;
end
apb_cfg.AddrCalcFunc();
endfunction
function void apb_config::AddrCalcFunc();
if ((slave_Addr >= ` UART_START_ADDR) && (slave_Addr <= ` UART_END_ADDR))
psel_Index = 1;
else if ((slave_Addr >= ` I2C_START_ADDR) && (slave_Addr <= ` I2C_END_ADDR))
psel_Index = 2;
else if ((slave_Addr >= ` SPI_START_ADDR) && (slave_Addr <= ` SPI_END_ADDR))
psel_Index = 4;
else
psel_Index = 0;
endfunction
在scoreboard的run_phase()中,调用了三个不同的函数来进行比较:
function void apbuart_scoreboard::compare_config (apb_transaction apb_pkt);
if(apb_pkt.PADDR == cfg.baud_config_addr)
begin
if(apb_pkt.PRDATA == baud_rate_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Baud Rate Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Baud Rate MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Baud Rate: %0d Actual Baud Rate: %0d",baud_rate_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
if(apb_pkt.PADDR == cfg.frame_config_addr)
begin
if(apb_pkt.PRDATA == frame_len_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Frame Rate Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Frame Rate MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Frame Rate: %0h Actual Frame Rate: %0h",frame_len_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
if(apb_pkt.PADDR == cfg.parity_config_addr)
begin
if(apb_pkt.PRDATA == parity_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Parity Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Parity MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Parity Value : %0h Actual Parity Value: %0h",parity_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
if(apb_pkt.PADDR == cfg.stop_bits_config_addr)
begin
if(apb_pkt.PRDATA == stopbit_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Stop Bit Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Stop Bit MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Stop Bit Value : %0h Actual Stop Value: %0h",stopbit_reg,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
endfunction
function void apbuart_scoreboard::compare_transmission (apb_transaction apb_pkt, uart_transaction uart_pkt);
if(apb_pkt.PWDATA == uart_pkt.transmitter_reg)
`uvm_info(get_type_name(),$sformatf("------ :: Transmission Data Packet Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Transmission Data Packet MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Transmission Data Value : %0h Actual Transmission Data Value: %0h",apb_pkt.PWDATA,uart_pkt.transmitter_reg),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
endfunction
function void apbuart_scoreboard::compare_receive (apb_transaction apb_pkt , uart_transaction uart_pkt);
if(apb_pkt.PRDATA == uart_pkt.payload)
`uvm_info(get_type_name(),$sformatf("------ :: Reciever Data Packet Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Reciever Data Packet MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Reciever Data Value : %0h Actual Reciever Data Value: %0h",uart_pkt.payload,apb_pkt.PRDATA),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
//$display("uart_pkt.sb_corr::%0b\tuart_pkt.sb_corr_bit[0]::%0b\tcfg.n_sb::%d",uart_pkt.sb_corr,uart_pkt.sb_corr_bit,cfg.parity[1]);
if((uart_pkt.bad_parity && cfg.parity[1]) || (uart_pkt.sb_corr && (cfg.n_sb || uart_pkt.sb_corr_bit[0])))
begin
//$display("uart_pkt.sb_corr::%0b\tuart_pkt.sb_corr_bit[0]::%0b\tcfg.n_sb::%d",uart_pkt.sb_corr,uart_pkt.sb_corr_bit[0],cfg.n_sb[0]);
if(apb_pkt.PSLVERR == 1'b1)
`uvm_info(get_type_name(),$sformatf("------ :: Error Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Error MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Error Value : %0h Actual Error Value: %0h",1'b1,apb_pkt.PSLVERR),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
else
begin
if(apb_pkt.PSLVERR == 1'b0)
`uvm_info(get_type_name(),$sformatf("------ :: Error Match :: ------"),UVM_LOW)
else
`uvm_error(get_type_name(),$sformatf("------ :: Error MisMatch :: ------"))
`uvm_info(get_type_name(),$sformatf("Expected Error Value : %0h Actual Error Value: %0h",1'b0,apb_pkt.PSLVERR),UVM_LOW)
`uvm_info(get_type_name(),"------------------------------------\n",UVM_LOW)
end
endfunction
run_phase部分的代码如下:
task apbuart_scoreboard::run_phase(uvm_phase phase);
apb_transaction apb_pkt_mon;
uart_transaction uart_pkt_mon;
apb_transaction apb_pkt_drv;
uart_transaction uart_pkt_drv;
forever
begin
wait(pkt_qu_monapb.size() > 0); // checking the fifo that it contains any valid entry from monitor apb
apb_pkt_mon = pkt_qu_monapb.pop_front(); // getting the entry from the start of fifo
if(apb_pkt_mon.PWRITE==1 && (apb_pkt_mon.PADDR == cfg.baud_config_addr || apb_pkt_mon.PADDR == cfg.frame_config_addr || apb_pkt_mon.PADDR == cfg.parity_config_addr || apb_pkt_mon.PADDR == cfg.stop_bits_config_addr))
begin
case(apb_pkt_mon.PADDR)
cfg.baud_config_addr : baud_rate_reg = apb_pkt_mon.PWDATA;
cfg.frame_config_addr : frame_len_reg = apb_pkt_mon.PWDATA;
cfg.parity_config_addr : parity_reg = apb_pkt_mon.PWDATA;
cfg.stop_bits_config_addr : stopbit_reg = apb_pkt_mon.PWDATA;
default : `uvm_error(get_type_name(),$sformatf("------ :: Incorrect Config Address :: ------"))
endcase
end
else if(apb_pkt_mon.PWRITE==0 && (apb_pkt_mon.PADDR == cfg.baud_config_addr || apb_pkt_mon.PADDR == cfg.frame_config_addr || apb_pkt_mon.PADDR == cfg.parity_config_addr || apb_pkt_mon.PADDR == cfg.stop_bits_config_addr))
begin
compare_config (apb_pkt_mon) ;
end
else if (apb_pkt_mon.PADDR == cfg.trans_data_addr)
begin
wait(pkt_qu_monuart.size() > 0);
uart_pkt_mon = pkt_qu_monuart.pop_front();
compare_transmission (apb_pkt_mon,uart_pkt_mon);
end
else if (apb_pkt_mon.PADDR == cfg.receive_data_addr)
begin
wait(pkt_qu_drvuart.size() > 0);
uart_pkt_drv = pkt_qu_drvuart.pop_front();
compare_receive (apb_pkt_mon,uart_pkt_drv);
end
end
endtask : run_phase
这里的pkt_qu_monapb、pkt_qu_monuart、pkt_qu_uartdrv分别用来存储scoreboard通过analysis_port从apb_monitor、uart_monitor、uart_driver取出的数据。