vkorehovisback (vkorehovisback) wrote in engineering_ru,
vkorehovisback
vkorehovisback
engineering_ru

Как сделать PCI карту своими руками, Часть 6 (Больше верилога!)

Оригинал взят у vkorehovisback в Как сделать PCI карту своими руками, Часть 6 (Больше верилога!)
https://github.com/vkorehov/cncfpga2

Дело в том что использовать закрытые коры это не православно.
Поэтому первым делом я решил от нее избавится.
Я решил оставить тестбенч, временные констрейнты в UCF, некоторые настройки компиляции.
Все остальное (что было закрыто) я решил переписать на чистом верилоге!

Начать нужно с секции ввода вывода она скопирована из коры, и не является закрытой (cnc_top.v).
Она содержит, входные буферы и входные триггеры:
module cnc_top(
    inout [31:0] AD,
...
...
IOBUF_PCI33_5 XPCI_ADB3  (.O(AD_IN3 ),.IO(AD[3 ]),.I(AD_O3 ),.T(OE_AD_N));
IOBUF_PCI33_5 XPCI_ADB2  (.O(AD_IN2 ),.IO(AD[2 ]),.I(AD_O2 ),.T(OE_AD_N));
IOBUF_PCI33_5 XPCI_ADB1  (.O(AD_IN1 ),.IO(AD[1 ]),.I(AD_O1 ),.T(OE_AD_N));
IOBUF_PCI33_5 XPCI_ADB0  (.O(AD_IN0 ),.IO(AD[0 ]),.I(AD_O0 ),.T(OE_AD_N));
...
FDPE XPCI_ADIQ3  (.Q(AD_I3 ),.D(AD_IN3 ),.C(CLK),.CE(1'b1),.PRE(RST));
FDPE XPCI_ADIQ2  (.Q(AD_I2 ),.D(AD_IN2 ),.C(CLK),.CE(1'b1),.PRE(RST));
FDPE XPCI_ADIQ1  (.Q(AD_I1 ),.D(AD_IN1 ),.C(CLK),.CE(1'b1),.PRE(RST));
FDPE XPCI_ADIQ0  (.Q(AD_I0 ),.D(AD_IN0 ),.C(CLK),.CE(1'b1),.PRE(RST));
...
// instantiate our PCI interface implementation
PCI PCI(
    .AD_I({... AD_I3, AD_I2, AD_I1, AD_I0}),
    .AD_O({... AD_O3, AD_O2, AD_O1, AD_O0}),
    .OE_AD_N(OE_AD_N),
...

это все примитивы библиотеки unisim. Найти таблицы истинности можно в гугле.



Для всех остальных сигналов все делается похожим способом. Иногда вместо IOBUF используется IBUF или ОBUF если соответствующий сигнал только выход или только вход, и т.д.
Клок обрабатывается по особенному:
module cnc_top(
...
    input PCLK,
...
    );
...
// clock
IBUFG_PCI33_5 XPCI_CKI      (.O(NUB),.I(PCLK));
BUFG XPCI_CKA               (.O(CLK),.I(NUB));
...

Далее везде используется CLK

Особенно нужно остановиться на реализации ресета, в коре использовалась стандартная реализация:
always @(posedge RST)
begin
    something_to_init = 111;
end

Для Xilinx есть более экономичный и элегантный способ:
http://www.eetimes.com/document.asp?doc_id=1278998
module cnc_top(
...
    input RST_N,
...
    );
IBUF_PCI33_5  XPCI_RST      (.O(RST_I),.I(RST_N));
assign RST = ~RST_I;
// make sure that RST is bound to Global Reset Request,
// which will put all state to initial block defined one.
STARTUP_SPARTAN2 SPARTAN2(.GSR(RST));


Далее уже нужно сделать скелетон нашей реализации PCI (pci.v)
module PCI(
    input [31:0] AD_I,
    output reg [31:0] AD_O,
    output reg OE_AD_N,
    input [3:0] CBE_I_N,
    output [3:0] CBE_O_N,
    output OE_CBE_N,
    input PAR_I,
    output reg PAR_O,
    output reg OE_PAR_N,
    input FRAME_I_N,
    output FRAME_O_N,
    output OE_FRAME_N,
    input TRDY_I_N,
    output reg TRDY_O_N,
    output reg OE_TRDY_N,
    input IRDY_I_N,
    output IRDY_O_N,
    output OE_IRDY_N,
    input STOP_I_N,
    output reg STOP_O_N,
    output reg OE_STOP_N,
    input DEVSEL_I_N,
    output reg DEVSEL_O_N,
    output reg OE_DEVSEL_N,
    input IDSEL_I,
    input PERR_I_N,
    output PERR_O_N,     
    output OE_PERR_N,
    input SERR_I_N,
    output OE_SERR_N,
    output OE_REQ_N,     
    input GNT_I_N,
    input CLK,
    output OE_INTA_N,
    output reg PING_DONE,
    input RST
    );
...

Заметьте что некоторые выходы помещены в регистры! это важно!.
когда я смотрел на реализацию в старой коре, они используют триггеры как для входов так для выходов, так и для сигналов включения выходов (OE_...)

Далее временная спецификация (сохранена от старой коры):
Первым делом они назначают выводам различные временные группы.
NET  "SERR_N"                                  TNM = PADS:PCI_PADS_C ;
NET  "PERR_N"                                  TNM = PADS:PCI_PADS_C ;
NET  "REQ_N"                                   TNM = PADS:PCI_PADS_G ;
NET  "GNT_N"                                   TNM = PADS:PCI_PADS_G ;
NET  "FRAME_N"                                 TNM = PADS:PCI_PADS_C ;
NET  "IRDY_N"                                  TNM = PADS:PCI_PADS_C ;
NET  "TRDY_N"                                  TNM = PADS:PCI_PADS_C ;
NET  "DEVSEL_N"                                TNM = PADS:PCI_PADS_C ;
NET  "STOP_N"                                  TNM = PADS:PCI_PADS_C ;
NET  "CBE_N<3>"                                TNM = PADS:PCI_PADS_B ;
NET  "CBE_N<2>"                                TNM = PADS:PCI_PADS_B ;
NET  "CBE_N<1>"                                TNM = PADS:PCI_PADS_B ;
NET  "CBE_N<0>"                                TNM = PADS:PCI_PADS_B ;
NET  "PAR"                                     TNM = PADS:PCI_PADS_P ;
NET  "IDSEL"                                   TNM = PADS:PCI_PADS_C ;
NET  "INTA_N"                                  TNM = PADS:PCI_PADS_X ;
NET  "RST_N"                                   TNM = PADS:PCI_PADS_X ;
#
NET  "AD<31>"                                TNM = PADS:PCI_PADS_D ;
NET  "AD<30>"                                TNM = PADS:PCI_PADS_D ;
...
NET  "AD<0>"                                 TNM = PADS:PCI_PADS_D ;

названия будут: PCI_PADS_C, PCI_PADS_G, PCI_PADS_B и т.д.
Далее специальные названия для триггеров входных данных+комманд и выходных данных (команды я не использую)
...
INST XPCI_CBIQ3                                TNM = FFS:PCI_FFS_ICE ;
INST XPCI_CBIQ2                                TNM = FFS:PCI_FFS_ICE ;
INST XPCI_CBIQ1                                TNM = FFS:PCI_FFS_ICE ;
INST XPCI_CBIQ0                                TNM = FFS:PCI_FFS_ICE ;
#
INST XPCI_ADIQ31                               TNM = FFS:PCI_FFS_ICE ;
INST XPCI_ADIQ30                               TNM = FFS:PCI_FFS_ICE ;
INST XPCI_ADIQ29                               TNM = FFS:PCI_FFS_ICE ;
...
INST PCI/AD_O_0                    TNM = FFS:PCI_FFS_OCE ;
INST PCI/AD_O_1                    TNM = FFS:PCI_FFS_OCE ;
INST PCI/AD_O_2                    TNM = FFS:PCI_FFS_OCE ;
INST PCI/AD_O_3                    TNM = FFS:PCI_FFS_OCE ;
...
INST PCI/PING_DONE                             TNM = FFS:USER_FFS;

обратите в нимание, что при работе с шинами, в верилоге у нас выход с регистром называется AD_O, в процессе компиляции он разбивается на провода и соответственно в файле с константами его нужно указывать как AD_O_xxx
Если что-то удалилось из дизайна в процессе оптимиазации, то также эти регистры нельзя указать в файле с константами и это будет вызывать ошибки.
Следует отметить что поскольку некоторые сигналы PCI коммутируются одновременно (TRDY и STOP например), то компилятор будет считать их эквивалентными и пытаться убрать второй регистр, это крайне нежелательно, по причинам которые обьясню чуть позже, но пока лишь скажу что для того чтобы этого не происходило нужно убрать галку с
Equivalent Register Removal в настройках синтеза.

Далее определяем одни группы через логические операции над другими:
TIMEGRP "ALL_FFS" = FFS : EXCEPT : "USER_FFS" ;
TIMEGRP "FAST_FFS" = "PCI_FFS_ICE" : "PCI_FFS_OCE" ;
TIMEGRP "SLOW_FFS" = PCI_FFS : EXCEPT : "FAST_FFS" ;


Далее когда названия групп определены, переходим к спецификации констрейнтов оптимизации (скопировано из коры как есть):
################################################################################
# Time Specs
################################################################################
#
# Important Note:  The timespecs used in this section cover all possible
# paths.  Depending on the design options, some of the timespecs may
# not contain any paths.  Such timespecs are ignored by PAR and TRCE.
#
# Note:  Timespecs are derived from the PCI Bus Specification, the
# minimum clock delay of 0.000 ns, the maximum clock delay of 3.000 ns,
# and a 90% tracking ratio between clock and data paths.
#
# Then, for paths on the primary global clock network:
#
#          1) Clk To Out   = 11.000ns - 3.000ns            =  8.000ns
#          2) Setup        =  7.000ns + 0.90 * 0.000ns     =  7.000ns
#          3) Grant Setup  = 10.000ns + 0.90 * 0.000ns     = 10.000ns
#          4) AD/CBE Toff  = 28.000ns - 3.000ns            = 25.000ns
#          5) AD/CBE Ton   = 30.000ns + 11.000ns - 3.000ns = 38.000ns
#          6) Period       =                               = 30.000ns
#
# The following timespecs are for setup specifications.  When using a
# single clock, these timespecs are merged as pads-to-all.
#
TIMESPEC TS_ADF_SETUP = FROM : "PCI_PADS_D" : TO : ALL_FFS :  7.000 ;
TIMESPEC TS_PAF_SETUP = FROM : "PCI_PADS_P" : TO : ALL_FFS :  7.000 ;
TIMESPEC TS_BYF_SETUP = FROM : "PCI_PADS_B" : TO : ALL_FFS :  7.000 ;
TIMESPEC TS_CNF_SETUP = FROM : "PCI_PADS_C" : TO : ALL_FFS :  7.000 ;
TIMESPEC TS_GNF_SETUP = FROM : "PCI_PADS_G" : TO : ALL_FFS : 10.000 ;
#
# All critical input and output is registered to ensure clock to out
# specifications are met by silicon.  When using a single clock, these
# timespecs are merged as all-to-pads.
#
TIMESPEC TS_CNF_CKOUT = FROM : ALL_FFS : TO : "PCI_PADS_C" :  8.000 ;
TIMESPEC TS_GNF_CKOUT = FROM : ALL_FFS : TO : "PCI_PADS_G" :  8.000 ;
#
# Similar to above, the critical input and output paths are registered
# to ensure clock to out specifications are made by silicon.  Since this
# interface uses address stepping, the clock to valid and clock to data
# have different specifications.
#
TIMESPEC TS_ADF_CKOUT = FROM : "FAST_FFS" : TO : "PCI_PADS_D" :  8.000 ;
TIMESPEC TS_ADS_TSOUT = FROM : "SLOW_FFS" : TO : "PCI_PADS_D" : 25.000 ;
#
TIMESPEC TS_BYF_CKOUT = FROM : "FAST_FFS" : TO : "PCI_PADS_B" :  8.000 ;
TIMESPEC TS_BYS_TSOUT = FROM : "SLOW_FFS" : TO : "PCI_PADS_B" : 25.000 ;
#
TIMESPEC TS_PAF_CKOUT = FROM : "FAST_FFS" : TO : "PCI_PADS_P" :  8.000 ;
TIMESPEC TS_PAS_TSOUT = FROM : "SLOW_FFS" : TO : "PCI_PADS_P" : 25.000 ;
#
# The design may be covered by a default period constraint.  This is
# generally sufficient when using a single clock.  The period should
# be set at the minimum PCI Bus clock period.
#
NET "PCLK" PERIOD = 30.000;


Если такой файл попробовать имплементировать, то имплементация выдаст ошибку таймингов.
Для того чтобы тайминги соответствовали спецификации PCI, нужно запихнуть входные триггеры, выходные триггеры а также триггеры Output Enable (OE_) в блоки ввода-вывода (IOB)
Для этого используются вот такие директивы:
INST "XPCI_CBIQ3"                                           IOB = TRUE ;
INST "XPCI_CBIQ2"                                           IOB = TRUE ;
INST "XPCI_CBIQ1"                                           IOB = TRUE ;
INST "XPCI_CBIQ0"                                           IOB = TRUE ;
#
INST "XPCI_ADIQ31"                                          IOB = TRUE ;
INST "XPCI_ADIQ30"                                          IOB = TRUE ;
INST "XPCI_ADIQ29"                                          IOB = TRUE ;
INST "XPCI_ADIQ28"                                          IOB = TRUE ;
...
INST XPCI_IDSELIQ                                           IOB = TRUE;
INST XPCI_SERRIQ                                            IOB = TRUE;
INST XPCI_PERRIQ                                            IOB = TRUE;
INST XPCI_FRAMEIQ                                           IOB = TRUE;
INST XPCI_IRDYIQ                                            IOB = TRUE;

INST XPCI_DEVSELIQ                                          IOB = TRUE;
INST PCI/DEVSEL_O_N                                         IOB = TRUE;
INST PCI/OE_DEVSEL_N                                        IOB = TRUE;

INST XPCI_STOPIQ                                            IOB = TRUE;
INST XPCI_TRDYIQ                                            IOB = TRUE;
INST PCI/TRDY_O_N                                           IOB = TRUE;
INST PCI/OE_TRDY_N                                          IOB = TRUE;
INST PCI/STOP_O_N                                           IOB = TRUE;
INST PCI/OE_STOP_N                                          IOB = TRUE;
INST PCI/PAR_O                                              IOB = TRUE;
INST PCI/OE_PAR_N                                           IOB = TRUE;

INST PCI/AD_O_0                                             IOB = TRUE;
INST PCI/AD_O_1                                             IOB = TRUE;
INST PCI/AD_O_2                                             IOB = TRUE;
INST PCI/AD_O_3                                             IOB = TRUE;
...

После этого все должно скомпилироваться успешно, а в конце маппинга, выдается вот такая вот таблица:
...
| AD<28>                             | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
|                                    |         |           |             |          |      | OUTFF    |          |       |
| AD<29>                             | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
|                                    |         |           |             |          |      | OUTFF    |          |       |
| AD<30>                             | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
|                                    |         |           |             |          |      | OUTFF    |          |       |
| AD<31>                             | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
|                                    |         |           |             |          |      | OUTFF    |          |       |
| CBE_N<0>                           | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
| CBE_N<1>                           | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
| CBE_N<2>                           | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
| CBE_N<3>                           | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
| DEVSEL_N                           | IOB     | BIDIR     | PCI33_5     |          |      | OUTFF    |          |       |
|                                    |         |           |             |          |      | ENFF     |          |       |
| FRAME_N                            | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
| IDSEL                              | IOB     | INPUT     | PCI33_5     |          |      | INFF     |          | IFD   |
| IRDY_N                             | IOB     | BIDIR     | PCI33_5     |          |      | INFF     |          | IFD   |
| PAR                                | IOB     | BIDIR     | PCI33_5     |          |      | OUTFF    |          |       |
|                                    |         |           |             |          |      | ENFF     |          |       |
| PING_DONE                          | IOB     | OUTPUT    | LVTTL       | 12       | SLOW | OUTFF    |          |       |
| RST_N                              | IOB     | INPUT     | PCI33_5     |          |      |          |          |       |
| STOP_N                             | IOB     | BIDIR     | PCI33_5     |          |      | OUTFF    |          |       |
|                                    |         |           |             |          |      | ENFF     |          |       |
| TRDY_N                             | IOB     | BIDIR     | PCI33_5     |          |      | OUTFF    |          |       |
|                                    |         |           |             |          |      | ENFF     |          |       |
+------------------------------------------------------------------------------------------------------------------------+

Обратите внимание на INFF, OUTFF и ENFF.
Я использовал ровно такие настройки как и старая кора.

Далее собственно имплементация интерфейса.
я разделил это на три блока:
сигналы PCI и управление шиной:
reg IsWrite;
wire BAR1Matches = (CBE_I_N[3:1] == 3'b001) & (AD_I[31:BAR1_WINDOW_BITS]==Bar1Addr[31:BAR1_WINDOW_BITS]) & (AD_I[1:0] == 2'b00);
wire BAR2Matches = (CBE_I_N[3:1] == 3'b011) & (AD_I[31:BAR2_WINDOW_BITS]==Bar2Addr[31:BAR2_WINDOW_BITS]);
wire CFGMatches = (CBE_I_N[3:1] == 3'b101) & (AD_I[1:0] == 2'b00) & (AD_I[10:8] == 3'b000);

reg [1:0] AccessType; // local
parameter ACCESS_IO = 2'b00;
parameter ACCESS_MEM = 2'b01;
parameter ACCESS_CONFIG = 2'b10;

always @(posedge CLK)
begin
   case(Transaction)   
       TX_STOP: begin
           Transaction <= TX_IDLE;
       end
       TX_DEVSEL: begin
           Transaction <= TX_TRDY;
       end
       TX_TRDY: begin
           if (FRAME_I_N)
               Transaction <= TX_STOP;
       end
       default: // TX_IDLE
       begin
           if (~FRAME_I_N & ((IDSEL_I & CFGMatches) | (PCICommandIOSpaceBit0 & BAR1Matches) | (PCICommandMEMSpaceBit1 & BAR2Matches)))
               Transaction <= TX_DEVSEL;
       end
   endcase
end

always @(posedge CLK)
begin
    if (Transaction == TX_IDLE) begin
        IsWrite <= CBE_I_N[0];
        AccessType <= {CBE_I_N[3], CBE_I_N[2]};
        CurrentAddr <= (IDSEL_I ? AD_I[7:2] :
                           (CBE_I_N[2] ? {32'b0, AD_I[BAR2_WINDOW_BITS-1:2]} :
                               {32'b0, AD_I[BAR1_WINDOW_BITS-1:2]}));        
    end
    
    DEVSEL_O_N <= ~(Transaction == TX_DEVSEL | Transaction == TX_TRDY);
    OE_DEVSEL_N <= ~(Transaction == TX_DEVSEL | Transaction == TX_TRDY | Transaction == TX_STOP);
    TRDY_O_N <= ~(Transaction == TX_TRDY);
    OE_TRDY_N <= ~(Transaction == TX_TRDY | Transaction == TX_STOP);
    STOP_O_N <= ~(Transaction == TX_TRDY);
    OE_STOP_N <= ~(Transaction == TX_TRDY | Transaction == TX_STOP);
    OE_AD_N <= ~((Transaction == TX_DEVSEL | Transaction == TX_TRDY) & ~IsWrite);
    OE_PAR_N <= ~((Transaction == TX_DEVSEL | Transaction == TX_TRDY | Transaction == TX_STOP) & ~IsWrite);
    
    // Output parity with 1 clock shift
    PAR_O <= ^{AD_I, CBE_I_N};
end

Ввод данных:
always @(posedge CLK)
begin
    if (Transaction == TX_TRDY & AccessType == ACCESS_CONFIG & IsWrite)
    case (CurrentAddr)
        1: begin
            if (~CBE_I_N[0]) begin
                PCICommandIOSpaceBit0  <= AD_I[0];
                PCICommandMEMSpaceBit1 <= AD_I[1];
            end
            if (~CBE_I_N[1])
                PCICommandIntrDisableBit10 <= AD_I[10];
        end
        4: begin
            Bar1Addr[31:BAR1_WINDOW_BITS] <= AD_I[31:BAR1_WINDOW_BITS];
        end
        5: begin
            Bar2Addr[31:BAR2_WINDOW_BITS] <= AD_I[31:BAR2_WINDOW_BITS];
        end
        15: begin
            if (~CBE_I_N[0])
                PCIInterruptLine <= AD_I[7:0];
        end
    endcase
end
always @(posedge CLK)
begin
    if (Transaction == TX_TRDY & IsWrite & AccessType == ACCESS_MEM)
        mem[CurrentAddr] <= AD_I;
end

always @(posedge CLK)
begin
    if (Transaction == TX_TRDY & IsWrite & AccessType == ACCESS_IO)
        io[CurrentAddr] <= AD_I;
end


Вывод данных:
always @(posedge CLK)
begin
   case (AccessType)
       ACCESS_CONFIG: begin
           case(CurrentAddr)
               0: AD_O <= {CFG_DEVICE, CFG_VENDOR};
               1: AD_O <= {PCIStatus, PCICommand};
               2: AD_O <= {CFG_CC, CFG_REVISION};
               4: AD_O <= {Bar1Addr[31:BAR1_WINDOW_BITS], {(BAR1_WINDOW_BITS-1){1'b0}}, /* IO space */1'b1};
               5: AD_O <= {Bar2Addr[31:BAR2_WINDOW_BITS], {(BAR2_WINDOW_BITS-4){1'b0}}, /* MEM space, Prefetch=true,location=32bit */4'b1000};
               15: AD_O <= {PCIMaxLat, PCIMinGnt, PCIInterruptPin, PCIInterruptLine};
               16: AD_O <= {32'b0, Bar1Addr};
               17: AD_O <= {32'b0, Bar2Addr};
               default: AD_O <= 32'b0;
           endcase
       end
       ACCESS_MEM : begin
           AD_O <= mem[CurrentAddr];
       end
       ACCESS_IO : begin
           AD_O <= io[CurrentAddr];           
       end
   endcase
end


как видно я использую два бара, один бар ввода вывода, а другой памяти.
размеры задаются параметрами:
parameter BAR1_WINDOW_BITS = 4;
parameter BAR2_WINDOW_BITS = 4;

следует иметь ввиду, что размер окна памяти (BAR2_) не может быть меньше 16 адресов (потому как первые 4 бита конфигурационного регистра зарезервивованы) а размер окна I/O не может быть меньше 4 адресов , потому как адресация I/O 8-битная, и только два младших бита зарезервивованы.
Я жестко требую выравнивания памяти при обращении. Byte Enable не использую все должно быть выравнено на 32 бита.

Далее важно проверить соответствие спецификации, конечной Post-Route симуляции!
Например я пытался слишком быстро устанавливать TRDY в результате чего адреса читались как нули (не успевали устаовиться) я это исправил задержав TRDY на один клок, это кстати быстрее оригинальной коры на один клок, у них задерживалось на два клока относительно DEVSEL.

Генерируем файл верилога для конечной симуляции:
prt
это создаст файлы в папке nergen.
Создадим новый .do файл для Modelsim: timesim.do
vlib work
vlog -f cnc_tb_timesim.f
vsim -novopt cnc_tb glbl
view signals structure wave

add wave -logic /CLK
add wave -logic /RST_N
add wave -literal -hex /AD
add wave -literal -hex /CBE
add wave -logic /PAR
add wave -logic /FRAME_N
add wave -logic /IRDY_N
add wave -logic /TRDY_N
add wave -logic /STOP_N
add wave -logic /DEVSEL_N
add wave -logic /REQ_N
add wave -logic /GNT_N
add wave -logic /SERR_N
add wave -logic /PERR_N
add wave -logic /IDSEL
add wave -logic /INTR_A
add wave -label "OPERATION" -radix ascii /cnc_tb/STM/operation

run -all

Создадим новый .f файл для Modelsim: cnc_tb_timesim.f
+licq_all+
+access+r
./netgen/par/cnc_top_timesim.v
./busrecord.v
./dumb_arbiter.v
./dumb_targ32.v
./stimulus.v
./cnc_tb.v
+libext+.vmd+.v
-y $XILINX/verilog/src/unisims
-y $XILINX/verilog/src/simprims


Запустим симуляцию:
проверим чтобы нигде не было красного (1'bx) что означает неинициализированные данные.
а синее (1'bz) какраз было в так называемых turnaround циклах PCI. естественно нас интересуют:
AD, CBE, TRDY, DEVSEL, STOP, PAR.
да, важно понять что PAR устанавливатся на следующем клоке, т.е. сначала мы пишем данные, а на следующем клоке устанавливаем их parity. и так это сдвинуто на протяжении всей транзакции (если использовать Burst, что мне не нужно):

wave

Далее записываем новую прошивку в устройство, выключаем питание, загружаемся, драйвер показывает новые ресурсы.
проверяем соответствие верилогу:
res

Tags: проектирование & проекты, своими руками, электроника
Subscribe
promo engineering_ru апрель 30, 2014 15:00 70
Buy for 200 tokens
Originally posted by zilm at Как будут ремонтировать автомобили с углепластиковым кузовом? Когда инженеры BMW создавали свои подзаряжаемые автомобили, они столкнулись с необходимостью снижения веса. Аккумуляторы делают электромобиль или плагин-гибрид тяжелее аналога с ДВС, а…
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 104 comments