跳转至

输入查询内容

    本页内容

    RAL 端序、访问粒度、响应与失败预测矩阵

    环境:VCS W-2024.09-SP2-8。1.2 使用 uvm-1.2,2.0 使用 uvm-ieee-2020-2.0

    实验检查观察值是否符合预期;成功复现问题不代表问题已修复。

    结果对比

    小端,直接返回请求结果

    观察内容 UVM 1.2 UVM 2.0
    写状态(0=成功,1=失败) write_status 0 0
    字段访问状态(0=成功,1=失败) field_status 0 0
    一次字段访问产生的总线传输数 field_transfers 1 2
    读状态(0=成功,1=失败) read_status 0 0
    字段操作后的完整寄存器数据(十六进制) field_preserved_data 0123456789abcd55 0123456789abcd55
    寄存器镜像值(十六进制) mirror 0123456789abcd55 0123456789abcd55
    字段写入后相邻硬件数据(十六进制) adjacent_hardware_data deadbeef89abcd66 0123456789abcd66
    突发写状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_write_status 0 0
    突发读状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_read_status 0 0
    突发传输第一个数据(十六进制) burst0 0000000076543210 0000000076543210
    突发传输第二个数据(十六进制) burst1 0000000044556677 0000000044556677
    两次并发访问的状态(0=成功) concurrent_status 0:0 0:0
    并发访问的第一项数据(十六进制) concurrent_first 1111222233334444 1111222233334444
    并发访问的第二项数据(十六进制) concurrent_second aaaabbbbccccdddd aaaabbbbccccdddd
    失败写入的状态(1=UVM_NOT_OK) failed_write_status 1 1
    失败写入后的寄存器镜像(十六进制) failed_write_mirror ffffffffffffffff 1111222233334444

    小端,独立响应

    本组配置:+RESPONSES

    观察内容 UVM 1.2 UVM 2.0
    写状态(0=成功,1=失败) write_status 0 0
    字段访问状态(0=成功,1=失败) field_status 0 0
    一次字段访问产生的总线传输数 field_transfers 1 2
    读状态(0=成功,1=失败) read_status 0 0
    字段操作后的完整寄存器数据(十六进制) field_preserved_data 0123456789abcd55 0123456789abcd55
    寄存器镜像值(十六进制) mirror 0123456789abcd55 0123456789abcd55
    字段写入后相邻硬件数据(十六进制) adjacent_hardware_data deadbeef89abcd66 0123456789abcd66
    突发写状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_write_status 0 0
    突发读状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_read_status 0 0
    突发传输第一个数据(十六进制) burst0 0000000076543210 0000000076543210
    突发传输第二个数据(十六进制) burst1 0000000044556677 0000000044556677
    两次并发访问的状态(0=成功) concurrent_status 0:0 0:0
    并发访问的第一项数据(十六进制) concurrent_first 1111222233334444 1111222233334444
    并发访问的第二项数据(十六进制) concurrent_second aaaabbbbccccdddd aaaabbbbccccdddd
    失败写入的状态(1=UVM_NOT_OK) failed_write_status 1 1
    失败写入后的寄存器镜像(十六进制) failed_write_mirror ffffffffffffffff 1111222233334444

    大端,直接返回请求结果

    本组配置:+BIG_ENDIAN

    观察内容 UVM 1.2 UVM 2.0
    写状态(0=成功,1=失败) write_status 0 0
    字段访问状态(0=成功,1=失败) field_status 0 0
    一次字段访问产生的总线传输数 field_transfers 1 2
    读状态(0=成功,1=失败) read_status 0 0
    字段操作后的完整寄存器数据(十六进制) field_preserved_data 0123456789abcd55 0000000000000000
    寄存器镜像值(十六进制) mirror 0123456789abcd55 0000000000000000
    字段写入后相邻硬件数据(十六进制) adjacent_hardware_data deadbeef89abcd66 0000000000000000
    突发写状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_write_status 0 0
    突发读状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_read_status 0 0
    突发传输第一个数据(十六进制) burst0 0000000076543210 0000000000000000
    突发传输第二个数据(十六进制) burst1 0000000044556677 0000000000000000
    两次并发访问的状态(0=成功) concurrent_status 0:0 0:0
    并发访问的第一项数据(十六进制) concurrent_first 1111222233334444 0000000000000000
    并发访问的第二项数据(十六进制) concurrent_second aaaabbbbccccdddd 0000000000000000
    失败写入的状态(1=UVM_NOT_OK) failed_write_status 1 1
    失败写入后的寄存器镜像(十六进制) failed_write_mirror ffffffffffffffff 0000000000000000

    大端,独立响应

    本组配置:+BIG_ENDIAN · +RESPONSES

    观察内容 UVM 1.2 UVM 2.0
    写状态(0=成功,1=失败) write_status 0 0
    字段访问状态(0=成功,1=失败) field_status 0 0
    一次字段访问产生的总线传输数 field_transfers 1 2
    读状态(0=成功,1=失败) read_status 0 0
    字段操作后的完整寄存器数据(十六进制) field_preserved_data 0123456789abcd55 0000000000000000
    寄存器镜像值(十六进制) mirror 0123456789abcd55 0000000000000000
    字段写入后相邻硬件数据(十六进制) adjacent_hardware_data deadbeef89abcd66 0000000000000000
    突发写状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_write_status 0 0
    突发读状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_read_status 0 0
    突发传输第一个数据(十六进制) burst0 0000000076543210 0000000000000000
    突发传输第二个数据(十六进制) burst1 0000000044556677 0000000000000000
    两次并发访问的状态(0=成功) concurrent_status 0:0 0:0
    并发访问的第一项数据(十六进制) concurrent_first 1111222233334444 0000000000000000
    并发访问的第二项数据(十六进制) concurrent_second aaaabbbbccccdddd 0000000000000000
    失败写入的状态(1=UVM_NOT_OK) failed_write_status 1 1
    失败写入后的寄存器镜像(十六进制) failed_write_mirror ffffffffffffffff 0000000000000000

    大端,独立响应,adapter 字节补偿

    本组配置:+BIG_ENDIAN · +RESPONSES · +BE_ADAPTER_COMPENSATION

    观察内容 UVM 1.2 UVM 2.0
    写状态(0=成功,1=失败) write_status 0 0
    字段访问状态(0=成功,1=失败) field_status 0 0
    一次字段访问产生的总线传输数 field_transfers 1 2
    读状态(0=成功,1=失败) read_status 0 0
    字段操作后的完整寄存器数据(十六进制) field_preserved_data 0123456789abcd55 0123456789abcd55
    寄存器镜像值(十六进制) mirror 0123456789abcd55 0123456789abcd55
    字段写入后相邻硬件数据(十六进制) adjacent_hardware_data deadbeef89abcd66 0123456789abcd66
    突发写状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_write_status 0 0
    突发读状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_read_status 0 0
    突发传输第一个数据(十六进制) burst0 0000000076543210 0000000076543210
    突发传输第二个数据(十六进制) burst1 0000000044556677 0000000044556677
    两次并发访问的状态(0=成功) concurrent_status 0:0 0:0
    并发访问的第一项数据(十六进制) concurrent_first 1111222233334444 1111222233334444
    并发访问的第二项数据(十六进制) concurrent_second aaaabbbbccccdddd aaaabbbbccccdddd
    失败写入的状态(1=UVM_NOT_OK) failed_write_status 1 1
    失败写入后的寄存器镜像(十六进制) failed_write_mirror ffffffffffffffff 1111222233334444

    大端,字节补偿,直接字段写入

    本组配置:+BIG_ENDIAN · +RESPONSES · +BE_ADAPTER_COMPENSATION · +DIRECT_FIELD_WRITE

    观察内容 UVM 1.2 UVM 2.0
    写状态(0=成功,1=失败) write_status 0 0
    字段访问状态(0=成功,1=失败) field_status 0 0
    一次字段访问产生的总线传输数 field_transfers 1 2
    读状态(0=成功,1=失败) read_status 0 0
    字段操作后的完整寄存器数据(十六进制) field_preserved_data 0123456789abcd55 0123456789abcd55
    寄存器镜像值(十六进制) mirror 0123456789abcd55 0123456789abcd55
    字段写入后相邻硬件数据(十六进制) adjacent_hardware_data deadbeef89abcd66 deadbeef89abcd66
    突发写状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_write_status 0 0
    突发读状态(0=UVM_IS_OK,1=UVM_NOT_OK) burst_read_status 0 0
    突发传输第一个数据(十六进制) burst0 0000000076543210 0000000076543210
    突发传输第二个数据(十六进制) burst1 0000000044556677 0000000044556677
    两次并发访问的状态(0=成功) concurrent_status 0:0 0:0
    并发访问的第一项数据(十六进制) concurrent_first 1111222233334444 1111222233334444
    并发访问的第二项数据(十六进制) concurrent_second aaaabbbbccccdddd aaaabbbbccccdddd
    失败写入的状态(1=UVM_NOT_OK) failed_write_status 1 1
    失败写入后的寄存器镜像(十六进制) failed_write_mirror ffffffffffffffff 1111222233334444

    运行命令

    目录与环境准备;从解包根目录执行:

    uv run tools/run_reg_review.py
    

    最小源码

    reg_access_probe.sv

    reg_access_probe.sv
    `timescale 1ns/1ps
    `include "uvm_macros.svh"
    import uvm_pkg::*;
    
    class access_item extends uvm_sequence_item;
      `uvm_object_utils(access_item)
      bit write;
      int unsigned address, data;
      bit [3:0] byte_enable;
      uvm_status_e status;
      function new(string name="access_item"); super.new(name); endfunction
    endclass
    
    class access_driver extends uvm_driver#(access_item);
      `uvm_component_utils(access_driver)
      int unsigned memory[int unsigned];
      int transfers;
      bit responses, fail_access;
      function new(string name, uvm_component parent); super.new(name, parent); endfunction
      task run_phase(uvm_phase phase);
        access_item item, response;
        forever begin
          seq_item_port.get_next_item(item);
          #1;
          item.status = fail_access ? UVM_NOT_OK : UVM_IS_OK;
          if (!fail_access) begin
            if (item.write) begin
              for (int i=0; i<4; i++)
                if (item.byte_enable[i]) memory[item.address][i*8+:8] = item.data[i*8+:8];
            end
            else item.data = memory.exists(item.address) ? memory[item.address] : 0;
          end
          transfers++;
          $display("REVIEW_BUS|%0d|%0h|%08h|%h|%0d", item.write, item.address, item.data, item.byte_enable, item.status);
          if (responses) begin
            response = new("response");
            response.set_id_info(item);
            response.write = item.write;
            response.address = item.address;
            response.data = item.data;
            response.status = item.status;
            response.byte_enable = item.byte_enable;
            seq_item_port.item_done(response);
          end
          else seq_item_port.item_done();
        end
      endtask
    endclass
    
    class access_adapter extends uvm_reg_adapter;
      `uvm_object_utils(access_adapter)
      function new(string name="access_adapter");
        super.new(name);
        supports_byte_enable = 1;
      endfunction
      function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
        access_item item = new("access");
        uvm_reg_data_t data = rw.data;
    `ifdef REVIEW_UVM20
        if ($test$plusargs("BE_ADAPTER_COMPENSATION") && $test$plusargs("BIG_ENDIAN") && rw.kind == UVM_WRITE)
          data = {<< byte {data}};
    `endif
        item.write = rw.kind inside {UVM_WRITE, UVM_BURST_WRITE};
        item.address = rw.addr;
        item.data = data;
        item.byte_enable = rw.byte_en;
        return item;
      endfunction
      function void bus2reg(uvm_sequence_item bus, ref uvm_reg_bus_op rw);
        access_item item;
        if (!$cast(item, bus)) `uvm_fatal("ACCESS", "Unexpected transaction type")
        rw.kind = item.write ? UVM_WRITE : UVM_READ;
        rw.addr = item.address;
        rw.data = item.data;
    `ifdef REVIEW_UVM20
        if ($test$plusargs("BE_ADAPTER_COMPENSATION") && $test$plusargs("BIG_ENDIAN") && !item.write)
          rw.data = {<< byte {rw.data}};
    `endif
        rw.byte_en = item.byte_enable;
        rw.status = item.status;
      endfunction
    endclass
    
    class byte_write_sequence extends uvm_sequence#(access_item);
      bit responses;
      int unsigned address;
      function new(string name="byte_write_sequence"); super.new(name); endfunction
      task body();
        access_item item = new("byte_write"), response;
        start_item(item);
        item.address = address;
        item.write = 1;
        item.data = 'h66;
        item.byte_enable = 4'b0001;
        finish_item(item);
        if (responses) get_response(response);
      endtask
    endclass
    
    class access_register extends uvm_reg;
      `uvm_object_utils(access_register)
      uvm_reg_field low_byte, upper;
      function new(string name="access_register"); super.new(name, 64, UVM_NO_COVERAGE); endfunction
      function void build();
        low_byte = uvm_reg_field::type_id::create("low_byte");
        upper = uvm_reg_field::type_id::create("upper");
        low_byte.configure(this, 8, 0, "RW", 0, 0, 1, 1, 1);
        upper.configure(this, 56, 8, "RW", 0, 0, 1, 1, 0);
      endfunction
    endclass
    
    class access_memory extends uvm_mem;
      function new(string name="memory"); super.new(name, 8, 32, "RW", UVM_NO_COVERAGE); endfunction
    endclass
    
    class access_block extends uvm_reg_block;
      `uvm_object_utils(access_block)
      access_register first, second;
      access_memory memory;
      function new(string name="access_block"); super.new(name, UVM_NO_COVERAGE); endfunction
      function void build();
        first = new("first"); second = new("second"); memory = new();
        first.configure(this); second.configure(this); memory.configure(this);
        first.build(); second.build();
        default_map = create_map("map", 'h100, 4,
          $test$plusargs("BIG_ENDIAN") ? UVM_BIG_ENDIAN : UVM_LITTLE_ENDIAN, 1);
        default_map.add_reg(first, 'h20, "RW");
        default_map.add_reg(second, 'h40, "RW");
        default_map.add_mem(memory, 'h80, "RW");
        lock_model();
      endfunction
    endclass
    
    class access_test extends uvm_test;
      `uvm_component_utils(access_test)
      uvm_sequencer#(access_item) sequencer;
      access_driver driver;
      access_adapter adapter;
      access_block model;
      function new(string name, uvm_component parent); super.new(name, parent); endfunction
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        sequencer = new("sequencer", this);
        driver = new("driver", this);
        adapter = new();
        driver.responses = $test$plusargs("RESPONSES");
        adapter.provides_responses = driver.responses;
        model = new(); model.build();
      endfunction
      function void connect_phase(uvm_phase phase);
        driver.seq_item_port.connect(sequencer.seq_item_export);
        model.default_map.set_sequencer(sequencer, adapter);
        model.default_map.set_auto_predict(1);
      endfunction
      task run_phase(uvm_phase phase);
        uvm_status_e status, status_a, status_b;
        uvm_reg_data_t value, values[] = '{64'h76543210, 64'h44556677};
        uvm_reg_data_t read_values[];
        int before_field;
        byte_write_sequence byte_write = new();
        phase.raise_objection(this);
        model.first.write(status, 64'h01234567_89abcdef);
        $display("REVIEW|write_status|%0d", status);
        before_field = driver.transfers;
        model.first.low_byte.write(status, 'h55);
        $display("REVIEW|field_status|%0d", status);
        $display("REVIEW|field_transfers|%0d", driver.transfers - before_field);
        model.first.read(status, value);
        $display("REVIEW|read_status|%0d", status);
        $display("REVIEW|field_preserved_data|%016h", value);
        $display("REVIEW|mirror|%016h", model.first.get_mirrored_value());
        driver.memory[$test$plusargs("BIG_ENDIAN") ? 'h120 : 'h124] = 'hdeadbeef;
        if ($test$plusargs("DIRECT_FIELD_WRITE")) begin
          byte_write.responses = driver.responses;
          byte_write.address = $test$plusargs("BIG_ENDIAN") ? 'h124 : 'h120;
          byte_write.start(sequencer);
          void'(model.first.low_byte.predict('h66, -1, UVM_PREDICT_WRITE));
        end
        else model.first.low_byte.write(status, 'h66);
        model.first.read(status, value);
        $display("REVIEW|adjacent_hardware_data|%016h", value);
        model.memory.burst_write(status, 1, values);
        $display("REVIEW|burst_write_status|%0d", status);
        read_values = new[2];
        model.memory.burst_read(status, 1, read_values);
        $display("REVIEW|burst_read_status|%0d", status);
        $display("REVIEW|burst0|%016h", read_values[0]);
        $display("REVIEW|burst1|%016h", read_values[1]);
        fork
          model.first.write(status_a, 64'h11112222_33334444);
          model.second.write(status_b, 64'haaaabbbb_ccccdddd);
        join
        $display("REVIEW|concurrent_status|%0d:%0d", status_a, status_b);
        model.first.read(status, value);
        $display("REVIEW|concurrent_first|%016h", value);
        model.second.read(status, value);
        $display("REVIEW|concurrent_second|%016h", value);
        driver.fail_access = 1;
        model.first.write(status, '1);
        $display("REVIEW|failed_write_status|%0d", status);
        $display("REVIEW|failed_write_mirror|%016h", model.first.get_mirrored_value());
        driver.fail_access = 0;
        $display("REVIEW|done|1");
        phase.drop_objection(this);
      endtask
    endclass
    
    module reg_access_probe;
      initial run_test("access_test");
      initial begin #10000; $fatal(1, "Review timeout"); end
    endmodule
    

    全部用例 · 证据摘要

    版本适用范围