Осваиваю PCI карту ADM-XRC-4/LX160-10, пытаюсь собрать пример из ADM SDK User Guide:
Synopsis
The Simple FPGA design demonstrates how to implement host-accessible registers in an FPGA design.
Код
/*
** simple.v - Trivial design demonstrating how to implement
** registers in the FPGA.
`timescale 1ns / 100ps
module simple(
lclk,
lreset_l,
lwrite,
lads_l,
lblast_l,
lbterm_l,
la,
ld,
lready_l,
lbe_l,
fholda);
input lclk;
wire lclk;
input lreset_l;
wire lreset_l;
input lwrite;
wire lwrite;
input lads_l;
wire lads_l;
input lblast_l;
wire lblast_l;
output lbterm_l;
wire lbterm_l;
inout [31:0] ld;
wire [31:0] ld;
input [23:2] la;
wire [23:2] la;
output lready_l;
wire lready_l;
input [3:0] lbe_l;
wire [3:0] lbe_l;
input fholda;
wire fholda;
wire rst;
wire lblast_i;
wire lads_i;
wire lwrite_i;
wire lready_o;
wire lready_oe;
wire lbterm_o;
wire lbterm_oe;
wire [23:2] la_i;
wire [31:0] ld_o;
wire [31:0] ld_i;
wire ld_oe;
wire [3:0] lbe_i;
wire qlads;
wire ds_xfer;
wire ds_decode;
wire ds_write;
reg [23:2] la_q;
reg [31:0] reg0;
wire [31:0] reg0_rev;
reg oe_reg0;
reg [31:0] reg1;
reg oe_reg1;
//
// Convert the inputs to active high.
//
assign rst = ~lreset_l;
assign lblast_i = ~lblast_l;
assign lads_i = ~lads_l;
assign lwrite_i = lwrite;
assign la_i = la;
assign ld_i = ld;
assign lbe_i = ~lbe_l;
//
// Generate a qualified version of 'lads_l', which is
// asserted when the FPGA is addressed AND the FPGA is
// not the local bus master.
//
assign qlads = lads_i && !la_i[23] && !fholda;
//
// Latch the local bus address on the 'lads_l' pulse.
//
always @ (posedge rst or posedge lclk)
begin
if (rst) begin
la_q <= 0;
end else begin
if (lads_i) begin
la_q <= la_i;
end
end
end
//
// 'lbterm_l' should only be driven when the FPGA is addressed; otherwise
// float, because the control logic on the card might also drive it.
//
assign lbterm_l = lbterm_oe ? ~lbterm_o : 1'bZ;
//
// 'lready_l' should only be driven when the FPGA is addressed; otherwise
// float because the control logic on the card might also drive it.
//
assign lready_l = lready_oe ? ~lready_o : 1'bZ;
//
// Drive the local data bus on a read.
//
assign ld = ld_oe ? ld_o : 32'hZZZZZZZZ;
//
// If the current cycle is a write, update the registers
//
always @ (posedge rst or posedge lclk)
begin
if (rst) begin
reg0 <= 0;
reg1 <= 0;
end else begin
if (ds_xfer && ds_write) begin
if (!la_q[2]) begin
if (lbe_i[0]) begin
reg0[7:0] <= ld_i[7:0];
end
if (lbe_i[1]) begin
reg0[15:8] <= ld_i[15:8];
end
if (lbe_i[2]) begin
reg0[23:16] <= ld_i[23:16];
end
if (lbe_i[3]) begin
reg0[31:24] <= ld_i[31:24];
end
end else begin
if (lbe_i[0]) begin
reg1[7:0] <= ld_i[7:0];
end
if (lbe_i[1]) begin
reg1[15:8] <= ld_i[15:8];
end
if (lbe_i[2]) begin
reg1[23:16] <= ld_i[23:16];
end
if (lbe_i[3]) begin
reg1[31:24] <= ld_i[31:24];
end
end
end
end
end
//
// Generate the 'oe_reg*' signals, for enabling registers onto
// the internal data bus.
//
always @ (posedge rst or posedge lclk)
begin
if (rst) begin
oe_reg0 <= 1'b0;
oe_reg1 <= 1'b0;
end else begin
if (ds_xfer && (lblast_i || lbterm_o)) begin
oe_reg0 <= 1'b0;
oe_reg1 <= 1'b0;
end else begin
if (ds_decode && !ds_write) begin
oe_reg0 <= ~la_q[2];
oe_reg1 <= la_q[2];
end
end
end
end
//
// Drive 'ld_o' with nibble reversed 'reg0' when register 0 is read,
// and with 'reg1' when register 1 is read.
//
// This synthesises to an internal tristate bus, unless the
// synthesis tool optimises it into a multiplexor.
//
assign reg0_rev = { reg0[3:0],
reg0[7:4],
reg0[11:8],
reg0[15:12],
reg0[19:16],
reg0[23:20],
reg0[27:24],
reg0[31:28] };
assign ld_o = oe_reg0 ? reg0_rev : 32'hZZZZZZZZ;
assign ld_o = oe_reg1 ? reg1 : 32'hZZZZZZZZ;
//
// Instantiate the direct slave state machine; monitors the local bus for
// direct slave cycles and responds appropriately.
//
plxdssm plxdssm0(
.clk (lclk),
.rst (rst),
.sr (1'b0),
.qlads (qlads),
.lblast (lblast_i),
.lwrite (lwrite_i),
.ld_oe (ld_oe),
.lready (lready_o),
.lready_oe (lready_oe),
.lbterm (lbterm_o),
.lbterm_oe (lbterm_oe),
.transfer (ds_xfer),
.decode (ds_decode),
.write (ds_write),
.ready (1'b1),
.stop (1'b1));
endmodule
** simple.v - Trivial design demonstrating how to implement
** registers in the FPGA.
`timescale 1ns / 100ps
module simple(
lclk,
lreset_l,
lwrite,
lads_l,
lblast_l,
lbterm_l,
la,
ld,
lready_l,
lbe_l,
fholda);
input lclk;
wire lclk;
input lreset_l;
wire lreset_l;
input lwrite;
wire lwrite;
input lads_l;
wire lads_l;
input lblast_l;
wire lblast_l;
output lbterm_l;
wire lbterm_l;
inout [31:0] ld;
wire [31:0] ld;
input [23:2] la;
wire [23:2] la;
output lready_l;
wire lready_l;
input [3:0] lbe_l;
wire [3:0] lbe_l;
input fholda;
wire fholda;
wire rst;
wire lblast_i;
wire lads_i;
wire lwrite_i;
wire lready_o;
wire lready_oe;
wire lbterm_o;
wire lbterm_oe;
wire [23:2] la_i;
wire [31:0] ld_o;
wire [31:0] ld_i;
wire ld_oe;
wire [3:0] lbe_i;
wire qlads;
wire ds_xfer;
wire ds_decode;
wire ds_write;
reg [23:2] la_q;
reg [31:0] reg0;
wire [31:0] reg0_rev;
reg oe_reg0;
reg [31:0] reg1;
reg oe_reg1;
//
// Convert the inputs to active high.
//
assign rst = ~lreset_l;
assign lblast_i = ~lblast_l;
assign lads_i = ~lads_l;
assign lwrite_i = lwrite;
assign la_i = la;
assign ld_i = ld;
assign lbe_i = ~lbe_l;
//
// Generate a qualified version of 'lads_l', which is
// asserted when the FPGA is addressed AND the FPGA is
// not the local bus master.
//
assign qlads = lads_i && !la_i[23] && !fholda;
//
// Latch the local bus address on the 'lads_l' pulse.
//
always @ (posedge rst or posedge lclk)
begin
if (rst) begin
la_q <= 0;
end else begin
if (lads_i) begin
la_q <= la_i;
end
end
end
//
// 'lbterm_l' should only be driven when the FPGA is addressed; otherwise
// float, because the control logic on the card might also drive it.
//
assign lbterm_l = lbterm_oe ? ~lbterm_o : 1'bZ;
//
// 'lready_l' should only be driven when the FPGA is addressed; otherwise
// float because the control logic on the card might also drive it.
//
assign lready_l = lready_oe ? ~lready_o : 1'bZ;
//
// Drive the local data bus on a read.
//
assign ld = ld_oe ? ld_o : 32'hZZZZZZZZ;
//
// If the current cycle is a write, update the registers
//
always @ (posedge rst or posedge lclk)
begin
if (rst) begin
reg0 <= 0;
reg1 <= 0;
end else begin
if (ds_xfer && ds_write) begin
if (!la_q[2]) begin
if (lbe_i[0]) begin
reg0[7:0] <= ld_i[7:0];
end
if (lbe_i[1]) begin
reg0[15:8] <= ld_i[15:8];
end
if (lbe_i[2]) begin
reg0[23:16] <= ld_i[23:16];
end
if (lbe_i[3]) begin
reg0[31:24] <= ld_i[31:24];
end
end else begin
if (lbe_i[0]) begin
reg1[7:0] <= ld_i[7:0];
end
if (lbe_i[1]) begin
reg1[15:8] <= ld_i[15:8];
end
if (lbe_i[2]) begin
reg1[23:16] <= ld_i[23:16];
end
if (lbe_i[3]) begin
reg1[31:24] <= ld_i[31:24];
end
end
end
end
end
//
// Generate the 'oe_reg*' signals, for enabling registers onto
// the internal data bus.
//
always @ (posedge rst or posedge lclk)
begin
if (rst) begin
oe_reg0 <= 1'b0;
oe_reg1 <= 1'b0;
end else begin
if (ds_xfer && (lblast_i || lbterm_o)) begin
oe_reg0 <= 1'b0;
oe_reg1 <= 1'b0;
end else begin
if (ds_decode && !ds_write) begin
oe_reg0 <= ~la_q[2];
oe_reg1 <= la_q[2];
end
end
end
end
//
// Drive 'ld_o' with nibble reversed 'reg0' when register 0 is read,
// and with 'reg1' when register 1 is read.
//
// This synthesises to an internal tristate bus, unless the
// synthesis tool optimises it into a multiplexor.
//
assign reg0_rev = { reg0[3:0],
reg0[7:4],
reg0[11:8],
reg0[15:12],
reg0[19:16],
reg0[23:20],
reg0[27:24],
reg0[31:28] };
assign ld_o = oe_reg0 ? reg0_rev : 32'hZZZZZZZZ;
assign ld_o = oe_reg1 ? reg1 : 32'hZZZZZZZZ;
//
// Instantiate the direct slave state machine; monitors the local bus for
// direct slave cycles and responds appropriately.
//
plxdssm plxdssm0(
.clk (lclk),
.rst (rst),
.sr (1'b0),
.qlads (qlads),
.lblast (lblast_i),
.lwrite (lwrite_i),
.ld_oe (ld_oe),
.lready (lready_o),
.lready_oe (lready_oe),
.lbterm (lbterm_o),
.lbterm_oe (lbterm_oe),
.transfer (ds_xfer),
.decode (ds_decode),
.write (ds_write),
.ready (1'b1),
.stop (1'b1));
endmodule
собсна нужное действие с входом происходит вот тут
Код
assign reg0_rev = { reg0[3:0],
reg0[7:4],
reg0[11:8],
reg0[15:12],
reg0[19:16],
reg0[23:20],
reg0[27:24],
reg0[31:28] };
reg0[7:4],
reg0[11:8],
reg0[15:12],
reg0[19:16],
reg0[23:20],
reg0[27:24],
reg0[31:28] };
т.е. шестнадцатиричные цифры переставляются в обратном порядке.
А когда пытаюсь только в этом месте что-нибудь другое с входом сделать, например вот
parameter oper1 = 32'b11111100000011110000111000110010;
assign reg0_rev = $signed(reg0)*$signed(oper1);
т.е. умножить на константу - система падает, когда приложение посылает карте первое же число. Умножать можно и просто на 2, результат тот же. Все функции вплоть до ADMXRC2_ConfigureFromFile выполняются успешно, все падает уже на этапе
Код
while (1)
{
scanf("%lx", &dataOut);
fpgaSpace[0] = (DWORD) dataOut;
dataIn = (unsigned long) fpgaSpace[0];
printf("Out = %8.8lx, In = %8.8lx\n", (unsigned long) dataOut, (unsigned long) dataIn);
if (dataOut == 0x55AAU)
{
break;
}
}
{
scanf("%lx", &dataOut);
fpgaSpace[0] = (DWORD) dataOut;
dataIn = (unsigned long) fpgaSpace[0];
printf("Out = %8.8lx, In = %8.8lx\n", (unsigned long) dataOut, (unsigned long) dataIn);
if (dataOut == 0x55AAU)
{
break;
}
}
Win2003Server
Собираю .bit в Xilinx ISE8.1+XST с .ucf из этого же примера.
Для общения с карточкой использую ADM SDK4.6.0, С++ код приложения собираю в Visual Studio (также из примера, и не изменяю его вообще никак).
Что может вызывать такую странную реакцию машины? Почему общение с картой происходит нормально вплоть до разводки, а первое же обращение уже не срабатывает?