MPLABシミュレータでのSCLによるソフトウェアの自動操作

MPLABでシミュレータを自動操作する手段にSCL(Stimulus Control Language)のスクリプトがある。
このスクリプトIDEで設定して自動生成することが多いけれど、手書きで作成することも可能だ。

スクリプトの記述力は十分とは言えないものの、ファイル操作・文字列検索のAPIや、標準出力(SimulatorのOutput)を操作するreport()のAPIなど、最低限の機能が揃っている。UARTやテスト用IFがなくとも、シミュレータ上のソフトウェアを自動操作し出力を比較検証することが可能となっており、自動テストにも使えるので、簡単に例をメモ。

記述例

例えばPICで動作するソフトウェアを対象として、UARTでデジタル出力を操作し、その結果を評価するスクリプトならば、以下のようになる。

testbench for "pic12f1822" is
    begin
        process is
            begin
                report("start");
                RCREG <= 16#E2#;
                wait for 10 ms; 
                if RA0 == '1' then
                    report("ra0-0 fail");
                else
                    report("pass");
                end if;
                if RA1 == '0' then
                    report("ra1-1 fail");
                else
                    report("pass");
                end if;
                wait;
        end process;
    end testbench;

また複雑なスクリプトは、MPLABで生成して、手描きで追加編集すると作りやすい。
例えばファイルでリストアップした文字列をUART入力する処理をSCL化すると、以下の様なスクリプトが生成される。
これに「elsif match(〜」の行を追加してオリジナルのイベント命令を追加したり、report()を挿入したりすれば、それなりの自動テストのスクリプトに組み替えられると思う。

〜
        file_open(status_RCREG, data_file_RCREG, "input_data.txt", read_mode);
        if status_RCREG == open_ok then
            while endfile(data_file_RCREG) == false loop
                readline(data_file_RCREG, pkt_line_RCREG);
                // skip empty line and comment line
                if match(pkt_line_RCREG, "") == true then // do nothing
                elsif match(pkt_line_RCREG, "//") == true then // do nothing
                else
                    if match(pkt_line_RCREG, "wait ") == true then
                        read(pkt_line_RCREG, dummy_RCREG); // to consume 'wait' command
                        read(pkt_line_RCREG, waitime_RCREG);
                        wait for waitime_RCREG;
                        new_packet_RCREG := true;
                    elsif match(pkt_line_RCREG, "rand ") == true then
                        read(pkt_line_RCREG, dummy_RCREG); // to consume 'rand' command
                        read(pkt_line_RCREG, rand_lower_RCREG);
                        read(pkt_line_RCREG, rand_upper_RCREG);
                        read(pkt_line_RCREG, rand_unit_RCREG);
                        random_time(rand_lower_RCREG, rand_upper_RCREG, rand_unit_RCREG,
                                    rand_seed1_RCREG, rand_seed2_RCREG, randime_RCREG);
                        wait for randime_RCREG;
                        new_packet_RCREG := true;
                    else
                        if new_packet_RCREG == true then
                            packetin(pkt_line_RCREG, RCREG, false); // new packet
                            wait until RCREG_packet_done;
                            new_packet_RCREG := false;
                        else
                            packetin(pkt_line_RCREG, RCREG, true); // append to previous
                            wait until RCREG_packet_done;
                        end if;
                    end if;
                end if;
            end loop;
        else
            file_close(data_file_RCREG);
            wait;
        end if;
        file_close(data_file_RCREG);
〜