2020年10月8日木曜日

UVMのreactive slaveを作ってみた話

UVMでslave動作するモデルを作成してみた話。実装したものはこちら。命名が微妙なのは諦めている。

Verilabの資料を参考に作成してみた。 資料とは異なり、sequencerはuvm_sequencerを使用し、その代わりにconfig_dbを使用してreact_req_fifoをsequenceから利用できるようにしている。参照させるためだけにクラス定義もあれかと思ったので。
加えてmonitor_icsからstorageのアップデートをせず、ics_reactive_seqに管理を一任している。passiveで使うならslaveでないものを使用すれば良いし、その状況下でstorageが必要になるとも思えないと思ったので。

 



プロトコル変換するのと同様に無限ループするシーケンスを用意し、react_req_fifoからデータを取り出して、応答データを作成してsequencerに実行させている。
get_sequencer()でsequencerに設定された設定値をsequenceで取得できるので使用している。
該当の実装は以下の通り。

class simple_ics_slave_env extends uvm_env;
    `uvm_component_utils(simple_ics_slave_env)
    `uvm_new_func
    simple_ics_env ics_env;
    simple_ics_slave_storage storage;
    uvm_tlm_analysis_fifo#(simple_ics_seq_item) react_req_fifo;
    //uvm_sequencer#(simple_ics_seq_item) sequencer;
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ics_env = simple_ics_env::type_id::create("ics_env",this);
        react_req_fifo = new("react_req_fifo",this);
        storage = simple_ics_slave_storage::type_id::create("storage",this);
        storage.init();
        uvm_config_db #(uvm_tlm_analysis_fifo#(simple_ics_seq_item))::set(this, "*", "react_req_fifo", react_req_fifo);
        uvm_config_db #(simple_ics_slave_storage)::set(this, "*", "storage", storage);
    endfunction

    function void connect_phase(uvm_phase phase);
        ics_env.monitor.react_req_port.connect(react_req_fifo.analysis_export);
    endfunction

    task run_phase(uvm_phase phase);
        ics_reactive_seq reactive_seq;
        reactive_seq = ics_reactive_seq::type_id::create("reactive_seq",this);
        reactive_seq.start(ics_env.sequencer);
    endtask
endclass
class ics_reactive_seq extends uvm_sequence #(simple_ics_seq_item);
    `uvm_object_utils(ics_reactive_seq)
    simple_ics_seq_item received_item;
    simple_ics_seq_item responce_item;
    uvm_tlm_analysis_fifo#(simple_ics_seq_item) react_req_fifo;
    simple_ics_slave_storage storage;
    int baud_rate;
    int bit_period;
    int stop_bit_num;

    function new(string name="ics_reactive_seq");
        super.new(name);
    endfunction

    task body();
        logic[7:0]      rdata;

        if(!uvm_config_db #(uvm_tlm_analysis_fifo#(simple_ics_seq_item))::get(get_sequencer(), "", "react_req_fifo", react_req_fifo)) begin
            `uvm_fatal("CONFIG_DB_ERROR", "Could not find react_req_fifo")
        end
        if(!uvm_config_db #(simple_ics_slave_storage)::get(get_sequencer(),"", "storage", storage)) begin
            `uvm_fatal("CONFIG_DB_ERROR", "Could not find simple_ics_slave_storage")
        end
        //baud rate
        if(!uvm_config_db#(int)::get(get_sequencer(), "", "simple_uart_baud_rate", baud_rate)) begin
            uvm_report_info("CONFIG","baud rate set to default value(115200 bps)");
            baud_rate = 115200;//default value
        end
        case(baud_rate)
            115200: bit_period = 8681;//8680.6 ns for 115200 bps.
            default: `uvm_fatal("CONFIG_ERR","Undefined baud rate.")
        endcase
        //number of stop bit
        if(!uvm_config_db#(int)::get(get_sequencer(), "", "simple_uart_stop_bit_num", stop_bit_num)) begin
            uvm_report_info("CONFIG","number of stop bit set to default value(1bit)");
            stop_bit_num = 1;//default value
        end

        forever begin
            react_req_fifo.get(received_item);
            uvm_report_info("REACT","get item");
            #(bit_period*(0.2+stop_bit_num));
            received_item.print();
            responce_item = new();

            case(received_item.cmd)
                simple_ics_seq_item::POSITION_R: uvm_report_fatal("REACT", "Invalid POSITION_R command received.");
                simple_ics_seq_item::READ_R: uvm_report_fatal("REACT", "Invalid READ_R command received.");
                simple_ics_seq_item::WRITE_R: uvm_report_fatal("REACT", "Invalid WRITE_R command received.");
                simple_ics_seq_item::ID_R: uvm_report_fatal("REACT", "Invalid ID_R command received.");
                simple_ics_seq_item::POSITION:
                    begin
                        storage.write_reg(received_item.id, simple_ics_seq_item::TCH, received_item.data);
                        responce_item.cmd = simple_ics_seq_item::POSITION_R;
                        responce_item.id = received_item.id;
                        responce_item.data = storage.read_reg(received_item.id, simple_ics_seq_item::TCH);
                    end
                simple_ics_seq_item::READ:
                    begin
                        responce_item.cmd = simple_ics_seq_item::READ_R;
                        responce_item.id = received_item.id;
                        if(received_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            logic[7:0] eeprom[0:63];
                            //responce_item.eeprom_data = new[64];
                            storage.read_mem(received_item.id, eeprom);
                            responce_item.eeprom_data = eeprom;
                        end else begin
                            responce_item.sub_cmd = received_item.sub_cmd;
                            responce_item.data = storage.read_reg(received_item.id, received_item.sub_cmd);
                        end
                    end
                simple_ics_seq_item::WRITE:
                    begin
                        responce_item.cmd = simple_ics_seq_item::WRITE_R;
                        responce_item.id = received_item.id;
                        if(received_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            storage.write_mem(received_item.id, received_item.eeprom_data);
                            responce_item.sub_cmd = simple_ics_seq_item::EEPROM;
                            responce_item.data = 0;
                        end else begin
                            storage.write_reg(received_item.id, received_item.sub_cmd, received_item.data);
                            responce_item.sub_cmd = received_item.sub_cmd;
                            responce_item.data = storage.read_reg(received_item.id, received_item.sub_cmd);
                        end
                    end
                simple_ics_seq_item::ID:
                    begin
                        uvm_report_fatal("REACT", "ID command is not implemented yet.");
                    end
            endcase
            responce_item.print();
            `uvm_send(responce_item);
        end
    endtask

endclass

0 件のコメント:

コメントを投稿