преобразовать программу fifo systemC на язык PROMELA со свойствами безопасности и живучести

пожалуйста, я большой специалист в области tihs, как я могу преобразовать классический пример FIFO, написанный в коде systemC, в язык PROMELA со свойствами в LTL, удовлетворяющими следующим трем свойствам:

Взаимное исключение: процессы производителя и потребителя никогда не обращаются к общему буферу одновременно.

Не голодание: потребитель обращается к буферу бесконечно часто. (Вы можете предположить, что у производителя никогда не заканчиваются данные для предоставления, а потребитель никогда не прекращает попытки прочитать новые данные.)

Производитель-потребитель: производитель никогда не перезаписывает буфер данных, если только потребитель уже не прочитал текущие данные. Потребитель никогда не читает буфер данных, если он не содержит новых данных. Обычный алгоритм для производителя-потребителя использует один флаговый бит. Бит флага устанавливается производителем, когда данные готовы к чтению, и сбрасывается потребителем после того, как он прочитал данные. Ради этого назначения нам нужно только моделировать, был ли прочитан буфер данных, а не моделировать содержимое данных. Для этого мы будем использовать один бит.

Ваша задача — смоделировать этот алгоритм в Promela, а затем проверить указанные выше свойства. Полезно помнить, что (1) и (3) — это свойства безопасности, а (2) — это свойство живучести. Вы можете использовать как LTL, так и встроенные утверждения, где это уместно.


Это моя первая попытка решить эту проблему:

#define NUMCHAN 4 

chan channels[NUMCHAN]; 
chan full[0]; 

init
{
    chan ch1 = [1] of { byte };
    chan ch2 = [1] of { byte };
    chan ch3 = [1] of { byte };
    chan ch4 = [1] of { byte };
    channels[0] = ch1;
    channels[1] = ch2;
    channels[2] = ch3;
    channels[3] = ch4;
    // Add further channels above, in accordance with NUMCHAN
    // First let the producer write something, then start the consumer
    run producer(); 
    atomic {
        _nr_pr == 1 -> run consumer();
    }
}

proctype read()
{
    byte var, i;
    chan theChan;
    do
        :: fread?1 ->
        if readptr == writeptr -> empty ! 1 
        fi  
        read ! 0 
        readptr = readptr+1 mod NUMCHAN
        ack ?1
    od 
    ack!1
    i = 0;
    do
        :: i == NUMCHAN -> break
        :: else -> theChan = channels[i];
        if
            :: skip // non-deterministic skip
            :: nempty(theChan) ->
                theChan ? var;
                printf("Read value %d from channel %d\n", var, i+1)
        fi;
        i++
    od
}

proctype consumer()
{
    do // empty
        if
            empty ? 0 // read // data 
            theChan ? data 
            :: fread!1 -> ack ?1 
    od 
}

Я создал два основных процесса: производитель и потребитель.

Производитель связан с другим процессом, называемым write, посредством канала fwrite, а потребитель связан с другим процессом, называемым прочитано по каналу fread. Здесь read и write содержат указатели read и write.

Потребитель неполный, я только набросал идею, которая у меня есть. Я хочу, чтобы чтение происходило после полной записи каналов или таблицы FIFO и что производитель может записать N количество информации, не довольствуясь размером FIFO.


person lamia    schedule 15.12.2016    source источник
comment
Комментарии не для расширенного обсуждения; этот разговор был перемещен на чат.   -  person Flexo    schedule 18.12.2016
comment
Для производителя, как я могу заставить его вставить информацию N и использовать указатель записи. Я уже сделал первую попытку, но я не мог уважать то, что описано выше proctype производителя() { byte var, i; Чан Чан; я = 0; do :: i == NUMCHAN -> break :: else -> theChan = channels[i]; если :: пропустить; :: empty(theChan) -> theChan ! 1; printf(Записать значение 1 в канал %d\n, i+1) fi; я++ один }   -  person lamia    schedule 19.12.2016


Ответы (1)


Примечание: судя по комментариям, проблема, которую вы пытаетесь решить, достаточно сложна и, вероятно, было бы полезно разбить на < em>меньшие и более простые части.


Часть 01: простой производитель/потребитель вместо свойств FIFO + ltl

IMHO, это предпочтительный подход при работе с проверкой модели и формальной проверкой: вы должны абстрагироваться исключить функции, зависящие от реализации и языка, из системы, которую вы хотите моделировать, и сосредоточиться на основных аспектах ее поведение.

Имея в виду этот подход, становится само собой разумеющимся, что, хотя имеет смысл моделировать в Promela активные агенты, такие как Producer и Потребитель как процессы, нет особого смысла моделировать класс FIFO вашего кода SystemC, особенно если учесть, что Promela уже предоставляет chan, который может вести себя как синхронная и асинхронная очередь FIFO.

Здесь я привожу очень базовую модель системы только с одним производителем и одним покупателем, что допускает несколько упрощений:

/**
 * Producer / Consumer 
 */

mtype = { PAYLOAD_MSG };

// Asynchronous Channel
chan fifo = [1] of { mtype, int };
bool data_read = true;

active [1] proctype producer()
{
  int v;
  do
    :: nfull(fifo) ->
        select(v : 0..16);
        printf("P[%d] - produced: %d\n", _pid, v);
access_fifo:
        atomic {
            fifo!PAYLOAD_MSG(v);
            data_read = false;
        }
  od
}

active [1] proctype consumer()
{
  int v;
  do
    :: nempty(fifo) ->
access_fifo:
        atomic {
            fifo?PAYLOAD_MSG(v);
            data_read = true;
        }
        printf("P[%d] - consumed: %d\n", _pid, v);
  od
}

#define prod_uses_fifo    (producer@access_fifo)
#define cons_uses_fifo    (consumer@access_fifo)
#define fair_production   ([]<> (_last == 0))
#define cons_not_starving ([]<> (_last == 1))
#define no_overwrite      ([] (prod_uses_fifo -> data_read))
#define no_invalid_read   ([] (cons_uses_fifo -> !data_read))

// Mutual Exclusion
ltl p1 { [] (!prod_uses_fifo || !cons_uses_fifo) }

// Non-Starvation
ltl p2 { fair_production && fair_production -> cons_not_starving }

// Producer-Consumer
ltl p3 { no_overwrite && no_invalid_read }

Обратите внимание, что я решил объявить fifo как асинхронный канал с chan fifo = [1], а не как синхронный канал с chan fifo = [0], потому что ваш свойство взаимного исключения требует, чтобы производитель и потребитель не обращались к fifo одновременно. В синхронном fifo потребитель и производитель всегда [и только] обращаются к fifo в одно и то же время. время, но нет состояния гонки, поскольку сообщение передается напрямую от производителя к потребителю.


Часть 02: FIFO как процесс

Теперь давайте оставим позади producer, consumers и ltl свойства и сосредоточимся на том, как можно смоделировать очередь FIFO как Процесс.

Опять же, фокус должен быть на абстрагировании желаемого поведения, а не на однозначном отображении исходного SystemC исходный код. Я позволю себе отбросить входной сигнал часы и объединить все входы [соотв. выходы] в один провод. Поскольку в своих комментариях вы заявили, что вам нужен синхронный fifo, я также запрещаю события write-after-write и предполагаю, что fifo размером 1.

mtype = { PUSH, POP, IS_EMPTY, IS_FULL };

#define PRODUCER_UID 0
#define CONSUMER_UID 1

proctype fifo(chan inputs, outputs)
{
    mtype command;
    int data, tmp, src_uid;
    bool data_valid = false;

    do
        :: true ->
            inputs?command(tmp, src_uid);
            if
                :: command == PUSH ->
                    if
                        :: data_valid ->
                            outputs!IS_FULL(true, src_uid);
                        :: else ->
                            data = tmp
                            data_valid = true;
                            outputs!PUSH(data, src_uid);
                    fi
                :: command == POP ->
                    if
                        :: !data_valid ->
                            outputs!IS_EMPTY(true, src_uid);
                        :: else ->
                            outputs!POP(data, src_uid);
                            data = -1;
                            data_valid = false;
                    fi
                :: command == IS_EMPTY ->
                    outputs!IS_EMPTY(!data_valid, src_uid);
                :: command == IS_FULL ->
                    outputs!IS_FULL(data_valid, src_uid);
            fi;
    od;
}

Я решил сделать попытки push/pop отказоустойчивыми: по замыслу невозможно перезаписать или прочитать неверные данные.

Собираем все вместе.

Затем можно обновить процессы producer и consumer, чтобы они использовали этот процесс fifo вместо встроенного чан:

proctype producer(chan inputs, outputs)
{
    mtype command;
    int v;

    do
        :: true ->
            atomic {
                inputs!IS_FULL(false, PRODUCER_UID) ->
                outputs?IS_FULL(v, PRODUCER_UID);
            }
            if
                :: v == 1 ->
                    skip
                :: else ->
                    select(v: 0..16);
                    printf("P[%d] - produced: %d\n", _pid, v);
access_fifo:
                    atomic {
                        inputs!PUSH(v, PRODUCER_UID);
                        outputs?command(v, PRODUCER_UID);
                    }
                    assert(command == PUSH);
            fi;
    od;
}

proctype consumer(chan inputs, outputs)
{
    mtype command;
    int v;

    do
        :: true ->
            atomic {
                inputs!IS_EMPTY(false, CONSUMER_UID) ->
                outputs?IS_EMPTY(v, CONSUMER_UID);
            }
            if
                :: v == 1 ->
                    skip
                :: else ->
access_fifo:
                    atomic {
                        inputs!POP(v, CONSUMER_UID);
                        outputs?command(v, CONSUMER_UID);
                    }
                    assert(command == POP);
                    printf("P[%d] - consumed: %d\n", _pid, v);
            fi;
    od;
}

Вы должны заметить, что эта реализация основана на опросе занятости, что не является мудрой идеей с точки зрения производительности, хотя это < em>самый простой подход к модели.

Альтернативным подходом может быть использование общих переменных и мьютексов, но это нарушит концепцию FIFO как компонента с входами. и выходные данные, которые, очевидно, вы хотите смоделировать.

Компоненты могут быть соединены вместе следующим образом:

init {
    chan inputs  = [0] of { mtype, int, int };
    chan outputs = [0] of { mtype, int, int };

    run fifo(inputs, outputs);     // pid: 1
    run producer(inputs, outputs); // pid: 2
    run consumer(inputs, outputs); // pid: 3
}

и последнее, но не менее важное, свойства ltl:

#define prod_uses_fifo    (producer@access_fifo)
#define cons_uses_fifo    (consumer@access_fifo)
#define fair_production   ([]<> (prod_uses_fifo && _last == 2))
#define cons_not_starving ([]<> (cons_uses_fifo && _last == 3))

// Mutual Exclusion
ltl p1 { [] (!prod_uses_fifo || !cons_uses_fifo) }

// Non-Starvation
ltl p2 { fair_production && fair_production -> cons_not_starving }

// Producer-Consumer
// assertions already guarantee that there is no attempt to 
// overwrite or read invalid data

Теперь я не совсем уверен, что этот подход ведет в том направлении, в котором вы хотели двигаться, поэтому я подожду дальнейших отзывов и, в случае необходимости, обновлю свой ответ.

person Patrick Trentin    schedule 19.12.2016
comment
Спасибо за помощь; можете ли вы прокомментировать, кто обслуживает: command, tmp, src_uid, data_valid, data и, пожалуйста, как я могу проверить свойство LTL на Ispin и могу ли я проверить их все сразу или шаг за шагом. Я уже сделал это: оставьте параметры по умолчанию, за исключением панели Never Claims, или проверьте заявление об использовании, введя имя свойства LTL, которое должно быть объявлено в файле promela. и как узнать, что свойство было проверено? - person lamia; 22.12.2016
comment
Как я уже писал в заголовке ответа, я упростил немного, чтобы показать вам, как я буду справляться с основным препятствием, которое, я думаю, есть в вашей задаче. Это не дословный перевод и ни в коем случае не полный охват исходной системы. Я боюсь, что такой вопрос был бы слишком общим для stackoverflow, поскольку здесь он занял бы слишком много времени и места. - person Patrick Trentin; 22.12.2016
comment
На самом деле я проверяю свойства через командную строку, поэтому я не могу вам помочь в этом отношении. Я предлагаю вам прочитать документацию ispin, чтобы узнать, как это сделать. - person Patrick Trentin; 22.12.2016
comment
Привет, М. Патрик, пожалуйста, как насчет проверки свойств LTL в программе promela. благодарю вас - person lamia; 02.01.2017
comment
Что вы подразумеваете под проверкой свойств LTL в программе promela.. как указать свойство? как проверить имущество? - person Patrick Trentin; 02.01.2017
comment
Я хотел добавить в программу wr_ptr и rd_ptr для указания указателей записи и чтения относительно глубины FIFO при нажатии wr_ptr =wr_ptr%depth; пусто=0; if :: (rd_ptr==wr_ptr) -> full=true; fi Можете ли вы помочь мне добавить это в эту программу? - person lamia; 09.02.2017
comment
@lamia, не могли бы вы открыть новый вопрос с полным описанием / кодом / чем угодно? это пространство уже стало очень людным :) - person Patrick Trentin; 10.02.2017