1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-30 08:32:52 +08:00

merged changes in pcie

This commit is contained in:
Alex Forencich 2021-10-20 19:32:15 -07:00
commit dc0c5a17ff
142 changed files with 3948 additions and 231 deletions

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -414,3 +416,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1120,3 +1122,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -422,3 +424,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1117,3 +1119,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -422,3 +424,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1117,3 +1119,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -401,3 +403,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1109,3 +1111,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -410,3 +412,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1120,3 +1122,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -409,3 +411,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1122,3 +1124,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -408,3 +410,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1120,3 +1122,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -439,3 +441,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1112,3 +1114,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -453,3 +455,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1122,3 +1124,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -422,3 +424,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1117,3 +1119,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes switch and button inputs with a slow sampled shift register
@ -87,3 +89,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -444,3 +446,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1122,3 +1124,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2018 Alex Forencich
Copyright (c) 2018-2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -46,323 +46,317 @@ static int map_bars(struct example_dev *edev, struct pci_dev *pdev);
static void free_bars(struct example_dev *edev, struct pci_dev *pdev);
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(0x1234, 0x0001) },
{ 0 /* end */ }
{PCI_DEVICE(0x1234, 0x0001)},
{0 /* end */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static irqreturn_t edev_intr(int irq, void *data)
{
struct example_dev *edev = data;
struct device *dev = &edev->pdev->dev;
struct example_dev *edev = data;
struct device *dev = &edev->pdev->dev;
edev->irqcount++;
edev->irqcount++;
dev_info(dev, "Interrupt");
dev_info(dev, "Interrupt");
return IRQ_HANDLED;
return IRQ_HANDLED;
}
static int edev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret = 0;
struct example_dev *edev;
struct device *dev = &pdev->dev;
int ret = 0;
struct example_dev *edev;
struct device *dev = &pdev->dev;
int k;
int k;
dev_info(dev, DRIVER_NAME " probe");
dev_info(dev, " Vendor: 0x%04x", pdev->vendor);
dev_info(dev, " Device: 0x%04x", pdev->device);
dev_info(dev, " Class: 0x%06x", pdev->class);
dev_info(dev, " PCI ID: %04x:%02x:%02x.%d", pci_domain_nr(pdev->bus),
pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
if (pdev->pcie_cap) {
u16 devctl;
u32 lnkcap;
u16 lnksta;
pci_read_config_word(pdev, pdev->pcie_cap + PCI_EXP_DEVCTL, &devctl);
pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &lnkcap);
pci_read_config_word(pdev, pdev->pcie_cap + PCI_EXP_LNKSTA, &lnksta);
dev_info(dev, " Max payload size: %d bytes", 128 << ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5));
dev_info(dev, " Max read request size: %d bytes", 128 << ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12));
dev_info(dev, " Link capability: gen %d x%d", lnkcap & PCI_EXP_LNKCAP_SLS, (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4);
dev_info(dev, " Link status: gen %d x%d", lnksta & PCI_EXP_LNKSTA_CLS, (lnksta & PCI_EXP_LNKSTA_NLW) >> 4);
dev_info(dev, " Relaxed ordering: %s", devctl & PCI_EXP_DEVCTL_RELAX_EN ? "enabled" : "disabled");
dev_info(dev, " Phantom functions: %s", devctl & PCI_EXP_DEVCTL_PHANTOM ? "enabled" : "disabled");
dev_info(dev, " Extended tags: %s", devctl & PCI_EXP_DEVCTL_EXT_TAG ? "enabled" : "disabled");
dev_info(dev, " No snoop: %s", devctl & PCI_EXP_DEVCTL_NOSNOOP_EN ? "enabled" : "disabled");
}
dev_info(dev, DRIVER_NAME " probe");
dev_info(dev, " Vendor: 0x%04x", pdev->vendor);
dev_info(dev, " Device: 0x%04x", pdev->device);
dev_info(dev, " Class: 0x%06x", pdev->class);
dev_info(dev, " PCI ID: %04x:%02x:%02x.%d", pci_domain_nr(pdev->bus),
pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
if (pdev->pcie_cap) {
u16 devctl;
u32 lnkcap;
u16 lnksta;
pci_read_config_word(pdev, pdev->pcie_cap + PCI_EXP_DEVCTL, &devctl);
pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &lnkcap);
pci_read_config_word(pdev, pdev->pcie_cap + PCI_EXP_LNKSTA, &lnksta);
dev_info(dev, " Max payload size: %d bytes",
128 << ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5));
dev_info(dev, " Max read request size: %d bytes",
128 << ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12));
dev_info(dev, " Link capability: gen %d x%d",
lnkcap & PCI_EXP_LNKCAP_SLS, (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4);
dev_info(dev, " Link status: gen %d x%d",
lnksta & PCI_EXP_LNKSTA_CLS, (lnksta & PCI_EXP_LNKSTA_NLW) >> 4);
dev_info(dev, " Relaxed ordering: %s",
devctl & PCI_EXP_DEVCTL_RELAX_EN ? "enabled" : "disabled");
dev_info(dev, " Phantom functions: %s",
devctl & PCI_EXP_DEVCTL_PHANTOM ? "enabled" : "disabled");
dev_info(dev, " Extended tags: %s",
devctl & PCI_EXP_DEVCTL_EXT_TAG ? "enabled" : "disabled");
dev_info(dev, " No snoop: %s",
devctl & PCI_EXP_DEVCTL_NOSNOOP_EN ? "enabled" : "disabled");
}
#ifdef CONFIG_NUMA
dev_info(dev, " NUMA node: %d", pdev->dev.numa_node);
dev_info(dev, " NUMA node: %d", pdev->dev.numa_node);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
pcie_print_link_status(pdev);
pcie_print_link_status(pdev);
#endif
if (!(edev = devm_kzalloc(dev, sizeof(struct example_dev), GFP_KERNEL))) {
return -ENOMEM;
}
edev = devm_kzalloc(dev, sizeof(struct example_dev), GFP_KERNEL);
if (!edev) {
dev_err(dev, "Failed to allocate memory");
return -ENOMEM;
}
edev->pdev = pdev;
pci_set_drvdata(pdev, edev);
edev->pdev = pdev;
pci_set_drvdata(pdev, edev);
// Allocate DMA buffer
edev->dma_region_len = 16*1024;
edev->dma_region = dma_alloc_coherent(dev, edev->dma_region_len, &edev->dma_region_addr, GFP_KERNEL | __GFP_ZERO);
if (!edev->dma_region)
{
dev_err(dev, "Failed to allocate DMA buffer");
ret = -ENOMEM;
goto fail_dma_alloc;
}
// Allocate DMA buffer
edev->dma_region_len = 16 * 1024;
edev->dma_region = dma_alloc_coherent(dev, edev->dma_region_len,
&edev->dma_region_addr,
GFP_KERNEL | __GFP_ZERO);
if (!edev->dma_region) {
dev_err(dev, "Failed to allocate DMA buffer");
ret = -ENOMEM;
goto fail_dma_alloc;
}
dev_info(dev, "Allocated DMA region virt %p, phys %p", edev->dma_region, (void *)edev->dma_region_addr);
dev_info(dev, "Allocated DMA region virt %p, phys %p",
edev->dma_region, (void *)edev->dma_region_addr);
// Disable ASPM
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
// Disable ASPM
pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
// Enable device
ret = pci_enable_device_mem(pdev);
if (ret)
{
dev_err(dev, "Failed to enable PCI device");
//ret = -ENODEV;
goto fail_enable_device;
}
// Enable device
ret = pci_enable_device_mem(pdev);
if (ret) {
dev_err(dev, "Failed to enable PCI device");
goto fail_enable_device;
}
// Enable bus mastering for DMA
pci_set_master(pdev);
// Enable bus mastering for DMA
pci_set_master(pdev);
// Reserve regions
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret)
{
dev_err(dev, "Failed to reserve regions");
//ret = -EBUSY;
goto fail_regions;
}
// Reserve regions
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret) {
dev_err(dev, "Failed to reserve regions");
goto fail_regions;
}
// Enumerate BARs
enumerate_bars(edev, pdev);
// Enumerate BARs
enumerate_bars(edev, pdev);
// Map BARs
ret = map_bars(edev, pdev);
if (ret)
{
dev_err(dev, "Failed to map BARs");
goto fail_map_bars;
}
// Map BARs
ret = map_bars(edev, pdev);
if (ret) {
dev_err(dev, "Failed to map BARs");
goto fail_map_bars;
}
// Allocate MSI IRQs
ret = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
if (ret < 0)
{
dev_err(dev, "Failed to allocate IRQs");
goto fail_map_bars;
}
// Allocate MSI IRQs
ret = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
if (ret < 0) {
dev_err(dev, "Failed to allocate IRQs");
goto fail_map_bars;
}
// Set up interrupt
ret = pci_request_irq(pdev, 0, edev_intr, 0, edev, DRIVER_NAME);
if (ret < 0)
{
dev_err(dev, "Failed to request IRQ");
goto fail_irq;
}
// Set up interrupt
ret = pci_request_irq(pdev, 0, edev_intr, 0, edev, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "Failed to request IRQ");
goto fail_irq;
}
// Read/write test
dev_info(dev, "write to BAR2");
iowrite32(0x11223344, edev->bar[2]);
// Read/write test
dev_info(dev, "write to BAR2");
iowrite32(0x11223344, edev->bar[2]);
dev_info(dev, "read from BAR2");
dev_info(dev, "%08x", ioread32(edev->bar[2]));
dev_info(dev, "read from BAR2");
dev_info(dev, "%08x", ioread32(edev->bar[2]));
// PCIe DMA test
dev_info(dev, "write test data");
for (k = 0; k < 256; k++)
{
((char *)edev->dma_region)[k] = k;
}
// PCIe DMA test
dev_info(dev, "write test data");
for (k = 0; k < 256; k++)
((char *)edev->dma_region)[k] = k;
dev_info(dev, "read test data");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, edev->dma_region, 256, true);
dev_info(dev, "read test data");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
edev->dma_region, 256, true);
dev_info(dev, "check DMA enable");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000000));
dev_info(dev, "check DMA enable");
dev_info(dev, "%08x", ioread32(edev->bar[0] + 0x000000));
dev_info(dev, "enable DMA");
iowrite32(0x1, edev->bar[0]+0x000000);
dev_info(dev, "enable DMA");
iowrite32(0x1, edev->bar[0] + 0x000000);
dev_info(dev, "check DMA enable");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000000));
dev_info(dev, "check DMA enable");
dev_info(dev, "%08x", ioread32(edev->bar[0] + 0x000000));
dev_info(dev, "start copy to card");
iowrite32((edev->dma_region_addr+0x0000)&0xffffffff, edev->bar[0]+0x000100);
iowrite32(((edev->dma_region_addr+0x0000) >> 32)&0xffffffff, edev->bar[0]+0x000104);
iowrite32(0x100, edev->bar[0]+0x000108);
iowrite32(0, edev->bar[0]+0x00010C);
iowrite32(0x100, edev->bar[0]+0x000110);
iowrite32(0xAA, edev->bar[0]+0x000114);
dev_info(dev, "start copy to card");
iowrite32((edev->dma_region_addr + 0x0000) & 0xffffffff, edev->bar[0] + 0x000100);
iowrite32(((edev->dma_region_addr + 0x0000) >> 32) & 0xffffffff, edev->bar[0] + 0x000104);
iowrite32(0x100, edev->bar[0] + 0x000108);
iowrite32(0, edev->bar[0] + 0x00010C);
iowrite32(0x100, edev->bar[0] + 0x000110);
iowrite32(0xAA, edev->bar[0] + 0x000114);
msleep(1);
msleep(1);
dev_info(dev, "Read status");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000118));
dev_info(dev, "Read status");
dev_info(dev, "%08x", ioread32(edev->bar[0] + 0x000118));
dev_info(dev, "start copy to host");
iowrite32((edev->dma_region_addr+0x0200)&0xffffffff, edev->bar[0]+0x000200);
iowrite32(((edev->dma_region_addr+0x0200) >> 32)&0xffffffff, edev->bar[0]+0x000204);
iowrite32(0x100, edev->bar[0]+0x000208);
iowrite32(0, edev->bar[0]+0x00020C);
iowrite32(0x100, edev->bar[0]+0x000210);
iowrite32(0x55, edev->bar[0]+0x000214);
dev_info(dev, "start copy to host");
iowrite32((edev->dma_region_addr + 0x0200) & 0xffffffff, edev->bar[0] + 0x000200);
iowrite32(((edev->dma_region_addr + 0x0200) >> 32) & 0xffffffff, edev->bar[0] + 0x000204);
iowrite32(0x100, edev->bar[0] + 0x000208);
iowrite32(0, edev->bar[0] + 0x00020C);
iowrite32(0x100, edev->bar[0] + 0x000210);
iowrite32(0x55, edev->bar[0] + 0x000214);
msleep(1);
msleep(1);
dev_info(dev, "Read status");
dev_info(dev, "%08x", ioread32(edev->bar[0]+0x000218));
dev_info(dev, "Read status");
dev_info(dev, "%08x", ioread32(edev->bar[0] + 0x000218));
dev_info(dev, "read test data");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, edev->dma_region+0x0200, 256, true);
dev_info(dev, "read test data");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
edev->dma_region + 0x0200, 256, true);
// probe complete
return 0;
// probe complete
return 0;
// error handling
// error handling
fail_irq:
pci_free_irq_vectors(pdev);
pci_free_irq_vectors(pdev);
fail_map_bars:
free_bars(edev, pdev);
pci_release_regions(pdev);
free_bars(edev, pdev);
pci_release_regions(pdev);
fail_regions:
pci_clear_master(pdev);
pci_disable_device(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
fail_enable_device:
dma_free_coherent(dev, edev->dma_region_len, edev->dma_region, edev->dma_region_addr);
dma_free_coherent(dev, edev->dma_region_len, edev->dma_region, edev->dma_region_addr);
fail_dma_alloc:
return ret;
return ret;
}
static void edev_remove(struct pci_dev *pdev)
{
struct example_dev *edev;
struct device *dev = &pdev->dev;
struct example_dev *edev = pci_get_drvdata(pdev);
struct device *dev = &pdev->dev;
dev_info(dev, DRIVER_NAME " remove");
dev_info(dev, DRIVER_NAME " remove");
if (!(edev = pci_get_drvdata(pdev))) {
return;
}
pci_free_irq(pdev, 0, edev);
pci_free_irq_vectors(pdev);
free_bars(edev, pdev);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
dma_free_coherent(dev, edev->dma_region_len, edev->dma_region, edev->dma_region_addr);
pci_free_irq(pdev, 0, edev);
pci_free_irq_vectors(pdev);
free_bars(edev, pdev);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
dma_free_coherent(dev, edev->dma_region_len, edev->dma_region, edev->dma_region_addr);
}
static void edev_shutdown(struct pci_dev *pdev)
{
dev_info(&pdev->dev, DRIVER_NAME " shutdown");
dev_info(&pdev->dev, DRIVER_NAME " shutdown");
edev_remove(pdev);
edev_remove(pdev);
}
static int enumerate_bars(struct example_dev *edev, struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
int i;
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < 6; i++)
{
resource_size_t bar_start = pci_resource_start(pdev, i);
if (bar_start)
{
resource_size_t bar_end = pci_resource_end(pdev, i);
unsigned long bar_flags = pci_resource_flags(pdev, i);
dev_info(dev, "BAR[%d] 0x%08llx-0x%08llx flags 0x%08lx",
i, bar_start, bar_end, bar_flags);
}
}
for (i = 0; i < 6; i++) {
resource_size_t bar_start = pci_resource_start(pdev, i);
if (bar_start) {
resource_size_t bar_end = pci_resource_end(pdev, i);
unsigned long bar_flags = pci_resource_flags(pdev, i);
dev_info(dev, "BAR[%d] 0x%08llx-0x%08llx flags 0x%08lx",
i, bar_start, bar_end, bar_flags);
}
}
return 0;
return 0;
}
static int map_bars(struct example_dev *edev, struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
int i;
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < 6; i++)
{
resource_size_t bar_start = pci_resource_start(pdev, i);
resource_size_t bar_end = pci_resource_end(pdev, i);
resource_size_t bar_len = bar_end - bar_start + 1;
edev->bar_len[i] = bar_len;
for (i = 0; i < 6; i++) {
resource_size_t bar_start = pci_resource_start(pdev, i);
resource_size_t bar_end = pci_resource_end(pdev, i);
resource_size_t bar_len = bar_end - bar_start + 1;
edev->bar_len[i] = bar_len;
if (!bar_start || !bar_end)
{
edev->bar_len[i] = 0;
continue;
}
if (!bar_start || !bar_end) {
edev->bar_len[i] = 0;
continue;
}
if (bar_len < 1)
{
dev_warn(dev, "BAR[%d] is less than 1 byte", i);
continue;
}
if (bar_len < 1) {
dev_warn(dev, "BAR[%d] is less than 1 byte", i);
continue;
}
edev->bar[i] = pci_ioremap_bar(pdev, i);
edev->bar[i] = pci_ioremap_bar(pdev, i);
if (!edev->bar[i])
{
dev_err(dev, "Could not map BAR[%d]", i);
return -1;
}
if (!edev->bar[i]) {
dev_err(dev, "Could not map BAR[%d]", i);
return -1;
}
dev_info(dev, "BAR[%d] mapped at 0x%p with length %llu", i, edev->bar[i], bar_len);
}
dev_info(dev, "BAR[%d] mapped at 0x%p with length %llu",
i, edev->bar[i], bar_len);
}
return 0;
return 0;
}
static void free_bars(struct example_dev *edev, struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
int i;
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < 6; i++)
{
if (edev->bar[i])
{
pci_iounmap(pdev, edev->bar[i]);
edev->bar[i] = NULL;
dev_info(dev, "Unmapped BAR[%d]", i);
}
}
for (i = 0; i < 6; i++) {
if (edev->bar[i]) {
pci_iounmap(pdev, edev->bar[i]);
edev->bar[i] = NULL;
dev_info(dev, "Unmapped BAR[%d]", i);
}
}
}
static struct pci_driver pci_driver = {
.name = DRIVER_NAME,
.id_table = pci_ids,
.probe = edev_probe,
.remove = edev_remove,
.shutdown = edev_shutdown
.name = DRIVER_NAME,
.id_table = pci_ids,
.probe = edev_probe,
.remove = edev_remove,
.shutdown = edev_shutdown
};
static int __init edev_init(void)
{
return pci_register_driver(&pci_driver);
return pci_register_driver(&pci_driver);
}
static void __exit edev_exit(void)
{
pci_unregister_driver(&pci_driver);
pci_unregister_driver(&pci_driver);
}
module_init(edev_init);
module_exit(edev_exit);

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2018 Alex Forencich
Copyright (c) 2018-2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -31,18 +31,18 @@ THE SOFTWARE.
#define DRIVER_VERSION "0.1"
struct example_dev {
struct pci_dev *pdev;
struct pci_dev *pdev;
// BAR pointers
void * __iomem bar[6];
resource_size_t bar_len[6];
// BAR pointers
void __iomem *bar[6];
resource_size_t bar_len[6];
// DMA buffer
size_t dma_region_len;
void *dma_region;
dma_addr_t dma_region_addr;
// DMA buffer
size_t dma_region_len;
void *dma_region;
dma_addr_t dma_region_addr;
int irqcount;
int irqcount;
};
#endif /* EXAMPLE_DRIVER_H */

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4 RAM
@ -363,3 +365,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream register
@ -262,3 +264,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA top-level module
@ -449,3 +451,5 @@ core_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* FPGA core logic
@ -1122,3 +1124,5 @@ pcie_us_msi_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* LED shift register driver
@ -133,3 +135,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
@ -50,3 +52,5 @@ always @(posedge clk or posedge rst) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog-2001
`resetall
`timescale 1 ns / 1 ps
`default_nettype none
/*
* Synchronizes an asyncronous signal to a given clock by using a pipeline of
@ -56,3 +58,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Arbiter module
@ -153,3 +155,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI4-Stream arbitrated multiplexer
@ -248,3 +250,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI stream sink DMA client
@ -629,3 +631,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI stream source DMA client
@ -562,3 +564,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -0,0 +1,330 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI DMA interface
*/
module dma_if_axi #
(
// Width of AXI data bus in bits
parameter AXI_DATA_WIDTH = 32,
// Width of AXI address bus in bits
parameter AXI_ADDR_WIDTH = 16,
// Width of AXI wstrb (width of data bus in words)
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
// Width of AXI ID signal
parameter AXI_ID_WIDTH = 8,
// Maximum AXI burst length to generate
parameter AXI_MAX_BURST_LEN = 256,
// RAM segment count
parameter RAM_SEG_COUNT = 2,
// RAM segment data width
parameter RAM_SEG_DATA_WIDTH = AXI_DATA_WIDTH*2/RAM_SEG_COUNT,
// RAM segment address width
parameter RAM_SEG_ADDR_WIDTH = 8,
// RAM segment byte enable width
parameter RAM_SEG_BE_WIDTH = RAM_SEG_DATA_WIDTH/8,
// RAM select width
parameter RAM_SEL_WIDTH = 2,
// RAM address width
parameter RAM_ADDR_WIDTH = RAM_SEG_ADDR_WIDTH+$clog2(RAM_SEG_COUNT)+$clog2(RAM_SEG_BE_WIDTH),
// Length field width
parameter LEN_WIDTH = 16,
// Tag field width
parameter TAG_WIDTH = 8,
// Operation table size (read)
parameter READ_OP_TABLE_SIZE = 2**(AXI_ID_WIDTH),
// Operation table size (write)
parameter WRITE_OP_TABLE_SIZE = 2**(AXI_ID_WIDTH),
// Use AXI ID signals
parameter USE_AXI_ID = 1
)
(
input wire clk,
input wire rst,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* AXI read descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr,
input wire [RAM_SEL_WIDTH-1:0] s_axis_read_desc_ram_sel,
input wire [RAM_ADDR_WIDTH-1:0] s_axis_read_desc_ram_addr,
input wire [LEN_WIDTH-1:0] s_axis_read_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_read_desc_tag,
input wire s_axis_read_desc_valid,
output wire s_axis_read_desc_ready,
/*
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire [3:0] m_axis_read_desc_status_error,
output wire m_axis_read_desc_status_valid,
/*
* AXI write descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr,
input wire [RAM_SEL_WIDTH-1:0] s_axis_write_desc_ram_sel,
input wire [RAM_ADDR_WIDTH-1:0] s_axis_write_desc_ram_addr,
input wire [LEN_WIDTH-1:0] s_axis_write_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_write_desc_tag,
input wire s_axis_write_desc_valid,
output wire s_axis_write_desc_ready,
/*
* AXI write descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag,
output wire [3:0] m_axis_write_desc_status_error,
output wire m_axis_write_desc_status_valid,
/*
* RAM interface
*/
output wire [RAM_SEG_COUNT*RAM_SEL_WIDTH-1:0] ram_wr_cmd_sel,
output wire [RAM_SEG_COUNT*RAM_SEG_BE_WIDTH-1:0] ram_wr_cmd_be,
output wire [RAM_SEG_COUNT*RAM_SEG_ADDR_WIDTH-1:0] ram_wr_cmd_addr,
output wire [RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH-1:0] ram_wr_cmd_data,
output wire [RAM_SEG_COUNT-1:0] ram_wr_cmd_valid,
input wire [RAM_SEG_COUNT-1:0] ram_wr_cmd_ready,
input wire [RAM_SEG_COUNT-1:0] ram_wr_done,
output wire [RAM_SEG_COUNT*RAM_SEL_WIDTH-1:0] ram_rd_cmd_sel,
output wire [RAM_SEG_COUNT*RAM_SEG_ADDR_WIDTH-1:0] ram_rd_cmd_addr,
output wire [RAM_SEG_COUNT-1:0] ram_rd_cmd_valid,
input wire [RAM_SEG_COUNT-1:0] ram_rd_cmd_ready,
input wire [RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH-1:0] ram_rd_resp_data,
input wire [RAM_SEG_COUNT-1:0] ram_rd_resp_valid,
output wire [RAM_SEG_COUNT-1:0] ram_rd_resp_ready,
/*
* Configuration
*/
input wire read_enable,
input wire write_enable
);
dma_if_axi_rd #(
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.RAM_SEG_COUNT(RAM_SEG_COUNT),
.RAM_SEG_DATA_WIDTH(RAM_SEG_DATA_WIDTH),
.RAM_SEG_ADDR_WIDTH(RAM_SEG_ADDR_WIDTH),
.RAM_SEG_BE_WIDTH(RAM_SEG_BE_WIDTH),
.RAM_SEL_WIDTH(RAM_SEL_WIDTH),
.RAM_ADDR_WIDTH(RAM_ADDR_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH),
.OP_TABLE_SIZE(READ_OP_TABLE_SIZE),
.USE_AXI_ID(USE_AXI_ID)
)
dma_if_axi_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI master interface
*/
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
/*
* AXI read descriptor input
*/
.s_axis_read_desc_axi_addr(s_axis_read_desc_axi_addr),
.s_axis_read_desc_ram_sel(s_axis_read_desc_ram_sel),
.s_axis_read_desc_ram_addr(s_axis_read_desc_ram_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
/*
* AXI read descriptor status output
*/
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_error(m_axis_read_desc_status_error),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
/*
* RAM interface
*/
.ram_wr_cmd_sel(ram_wr_cmd_sel),
.ram_wr_cmd_be(ram_wr_cmd_be),
.ram_wr_cmd_addr(ram_wr_cmd_addr),
.ram_wr_cmd_data(ram_wr_cmd_data),
.ram_wr_cmd_valid(ram_wr_cmd_valid),
.ram_wr_cmd_ready(ram_wr_cmd_ready),
.ram_wr_done(ram_wr_done),
/*
* Configuration
*/
.enable(read_enable)
);
dma_if_axi_wr #(
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.RAM_SEG_COUNT(RAM_SEG_COUNT),
.RAM_SEG_DATA_WIDTH(RAM_SEG_DATA_WIDTH),
.RAM_SEG_ADDR_WIDTH(RAM_SEG_ADDR_WIDTH),
.RAM_SEG_BE_WIDTH(RAM_SEG_BE_WIDTH),
.RAM_SEL_WIDTH(RAM_SEL_WIDTH),
.RAM_ADDR_WIDTH(RAM_ADDR_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH),
.OP_TABLE_SIZE(WRITE_OP_TABLE_SIZE),
.USE_AXI_ID(USE_AXI_ID)
)
dma_if_axi_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI master interface
*/
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
/*
* AXI write descriptor input
*/
.s_axis_write_desc_axi_addr(s_axis_write_desc_axi_addr),
.s_axis_write_desc_ram_sel(s_axis_write_desc_ram_sel),
.s_axis_write_desc_ram_addr(s_axis_write_desc_ram_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
/*
* AXI write descriptor status output
*/
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_error(m_axis_write_desc_status_error),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
/*
* RAM interface
*/
.ram_rd_cmd_sel(ram_rd_cmd_sel),
.ram_rd_cmd_addr(ram_rd_cmd_addr),
.ram_rd_cmd_valid(ram_rd_cmd_valid),
.ram_rd_cmd_ready(ram_rd_cmd_ready),
.ram_rd_resp_data(ram_rd_resp_data),
.ram_rd_resp_valid(ram_rd_resp_valid),
.ram_rd_resp_ready(ram_rd_resp_ready),
/*
* Configuration
*/
.enable(write_enable)
);
endmodule
`resetall

View File

@ -0,0 +1,859 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI DMA read interface
*/
module dma_if_axi_rd #
(
// Width of AXI data bus in bits
parameter AXI_DATA_WIDTH = 32,
// Width of AXI address bus in bits
parameter AXI_ADDR_WIDTH = 16,
// Width of AXI wstrb (width of data bus in words)
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
// Width of AXI ID signal
parameter AXI_ID_WIDTH = 8,
// Maximum AXI burst length to generate
parameter AXI_MAX_BURST_LEN = 256,
// RAM segment count
parameter RAM_SEG_COUNT = 2,
// RAM segment data width
parameter RAM_SEG_DATA_WIDTH = AXI_DATA_WIDTH*2/RAM_SEG_COUNT,
// RAM segment address width
parameter RAM_SEG_ADDR_WIDTH = 8,
// RAM segment byte enable width
parameter RAM_SEG_BE_WIDTH = RAM_SEG_DATA_WIDTH/8,
// RAM select width
parameter RAM_SEL_WIDTH = 2,
// RAM address width
parameter RAM_ADDR_WIDTH = RAM_SEG_ADDR_WIDTH+$clog2(RAM_SEG_COUNT)+$clog2(RAM_SEG_BE_WIDTH),
// Length field width
parameter LEN_WIDTH = 16,
// Tag field width
parameter TAG_WIDTH = 8,
// Operation table size
parameter OP_TABLE_SIZE = 2**(AXI_ID_WIDTH),
// Use AXI ID signals
parameter USE_AXI_ID = 1
)
(
input wire clk,
input wire rst,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* AXI read descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_axi_addr,
input wire [RAM_SEL_WIDTH-1:0] s_axis_read_desc_ram_sel,
input wire [RAM_ADDR_WIDTH-1:0] s_axis_read_desc_ram_addr,
input wire [LEN_WIDTH-1:0] s_axis_read_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_read_desc_tag,
input wire s_axis_read_desc_valid,
output wire s_axis_read_desc_ready,
/*
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire [3:0] m_axis_read_desc_status_error,
output wire m_axis_read_desc_status_valid,
/*
* RAM interface
*/
output wire [RAM_SEG_COUNT*RAM_SEL_WIDTH-1:0] ram_wr_cmd_sel,
output wire [RAM_SEG_COUNT*RAM_SEG_BE_WIDTH-1:0] ram_wr_cmd_be,
output wire [RAM_SEG_COUNT*RAM_SEG_ADDR_WIDTH-1:0] ram_wr_cmd_addr,
output wire [RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH-1:0] ram_wr_cmd_data,
output wire [RAM_SEG_COUNT-1:0] ram_wr_cmd_valid,
input wire [RAM_SEG_COUNT-1:0] ram_wr_cmd_ready,
input wire [RAM_SEG_COUNT-1:0] ram_wr_done,
/*
* Configuration
*/
input wire enable
);
parameter RAM_WORD_WIDTH = RAM_SEG_BE_WIDTH;
parameter RAM_WORD_SIZE = RAM_SEG_DATA_WIDTH/RAM_WORD_WIDTH;
parameter AXI_WORD_WIDTH = AXI_STRB_WIDTH;
parameter AXI_WORD_SIZE = AXI_DATA_WIDTH/AXI_WORD_WIDTH;
parameter AXI_BURST_SIZE = $clog2(AXI_STRB_WIDTH);
parameter AXI_MAX_BURST_SIZE = AXI_MAX_BURST_LEN << AXI_BURST_SIZE;
parameter OFFSET_WIDTH = AXI_STRB_WIDTH > 1 ? $clog2(AXI_STRB_WIDTH) : 1;
parameter OFFSET_MASK = AXI_STRB_WIDTH > 1 ? {OFFSET_WIDTH{1'b1}} : 0;
parameter RAM_OFFSET_WIDTH = $clog2(RAM_SEG_COUNT*RAM_SEG_BE_WIDTH);
parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
parameter OP_TAG_WIDTH = $clog2(OP_TABLE_SIZE);
parameter OP_TABLE_READ_COUNT_WIDTH = AXI_ID_WIDTH+1;
parameter OP_TABLE_WRITE_COUNT_WIDTH = LEN_WIDTH;
parameter STATUS_FIFO_ADDR_WIDTH = 5;
parameter OUTPUT_FIFO_ADDR_WIDTH = 5;
// bus width assertions
initial begin
if (AXI_WORD_SIZE * AXI_STRB_WIDTH != AXI_DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (AXI_WORD_SIZE != RAM_WORD_SIZE) begin
$error("Error: word size mismatch (instance %m)");
$finish;
end
if (2**$clog2(AXI_WORD_WIDTH) != AXI_WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256) begin
$error("Error: AXI_MAX_BURST_LEN must be between 1 and 256 (instance %m)");
$finish;
end
if (RAM_SEG_COUNT < 2) begin
$error("Error: RAM interface requires at least 2 segments (instance %m)");
$finish;
end
if (RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH != AXI_DATA_WIDTH*2) begin
$error("Error: RAM interface width must be double the AXI interface width (instance %m)");
$finish;
end
if (2**$clog2(RAM_WORD_WIDTH) != RAM_WORD_WIDTH) begin
$error("Error: RAM word width must be even power of two (instance %m)");
$finish;
end
if (RAM_ADDR_WIDTH != RAM_SEG_ADDR_WIDTH+$clog2(RAM_SEG_COUNT)+$clog2(RAM_SEG_BE_WIDTH)) begin
$error("Error: RAM_ADDR_WIDTH does not match RAM configuration (instance %m)");
$finish;
end
end
localparam [1:0]
AXI_RESP_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10,
AXI_RESP_DECERR = 2'b11;
localparam [3:0]
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
DMA_ERROR_AXI_RD_SLVERR = 4'd4,
DMA_ERROR_AXI_RD_DECERR = 4'd5,
DMA_ERROR_AXI_WR_SLVERR = 4'd6,
DMA_ERROR_AXI_WR_DECERR = 4'd7,
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
localparam [0:0]
REQ_STATE_IDLE = 1'd0,
REQ_STATE_START = 1'd1;
reg [0:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_WRITE = 1'd1;
reg [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
reg [AXI_ADDR_WIDTH-1:0] req_axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, req_axi_addr_next;
reg [RAM_SEL_WIDTH-1:0] req_ram_sel_reg = {RAM_SEL_WIDTH{1'b0}}, req_ram_sel_next;
reg [RAM_ADDR_WIDTH-1:0] req_ram_addr_reg = {RAM_ADDR_WIDTH{1'b0}}, req_ram_addr_next;
reg [LEN_WIDTH-1:0] req_op_count_reg = {LEN_WIDTH{1'b0}}, req_op_count_next;
reg [LEN_WIDTH-1:0] req_tr_count_reg = {LEN_WIDTH{1'b0}}, req_tr_count_next;
reg [TAG_WIDTH-1:0] req_tag_reg = {TAG_WIDTH{1'b0}}, req_tag_next;
reg [RAM_SEL_WIDTH-1:0] ram_sel_reg = {RAM_SEL_WIDTH{1'b0}}, ram_sel_next;
reg [RAM_ADDR_WIDTH-1:0] addr_reg = {RAM_ADDR_WIDTH{1'b0}}, addr_next;
reg [RAM_ADDR_WIDTH-1:0] addr_delay_reg = {RAM_ADDR_WIDTH{1'b0}}, addr_delay_next;
reg [12:0] op_count_reg = 13'd0, op_count_next;
reg [RAM_SEG_COUNT-1:0] ram_mask_reg = {RAM_SEG_COUNT{1'b0}}, ram_mask_next;
reg [RAM_SEG_COUNT-1:0] ram_mask_0_reg = {RAM_SEG_COUNT{1'b0}}, ram_mask_0_next;
reg [RAM_SEG_COUNT-1:0] ram_mask_1_reg = {RAM_SEG_COUNT{1'b0}}, ram_mask_1_next;
reg ram_wrap_reg = 1'b0, ram_wrap_next;
reg [OFFSET_WIDTH+1-1:0] cycle_byte_count_reg = {OFFSET_WIDTH+1{1'b0}}, cycle_byte_count_next;
reg [RAM_OFFSET_WIDTH-1:0] start_offset_reg = {RAM_OFFSET_WIDTH{1'b0}}, start_offset_next;
reg [RAM_OFFSET_WIDTH-1:0] end_offset_reg = {RAM_OFFSET_WIDTH{1'b0}}, end_offset_next;
reg [OFFSET_WIDTH-1:0] offset_reg = {OFFSET_WIDTH{1'b0}}, offset_next;
reg [OP_TAG_WIDTH-1:0] op_tag_reg = {OP_TAG_WIDTH{1'b0}}, op_tag_next;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] status_fifo_wr_ptr_reg = 0;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] status_fifo_rd_ptr_reg = 0, status_fifo_rd_ptr_next;
reg [OP_TAG_WIDTH-1:0] status_fifo_op_tag[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [RAM_SEG_COUNT-1:0] status_fifo_mask[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg status_fifo_finish[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [OP_TAG_WIDTH-1:0] status_fifo_wr_op_tag;
reg [RAM_SEG_COUNT-1:0] status_fifo_wr_mask;
reg status_fifo_wr_finish;
reg status_fifo_we;
reg status_fifo_finish_reg = 1'b0, status_fifo_finish_next;
reg status_fifo_we_reg = 1'b0, status_fifo_we_next;
reg status_fifo_half_full_reg = 1'b0;
reg [OP_TAG_WIDTH-1:0] status_fifo_rd_op_tag_reg = 0, status_fifo_rd_op_tag_next;
reg [RAM_SEG_COUNT-1:0] status_fifo_rd_mask_reg = 0, status_fifo_rd_mask_next;
reg status_fifo_rd_finish_reg = 1'b0, status_fifo_rd_finish_next;
reg status_fifo_rd_valid_reg = 1'b0, status_fifo_rd_valid_next;
reg [AXI_DATA_WIDTH-1:0] m_axi_rdata_int_reg = {AXI_DATA_WIDTH{1'b0}}, m_axi_rdata_int_next;
reg m_axi_rvalid_int_reg = 1'b0, m_axi_rvalid_int_next;
reg [AXI_ID_WIDTH-1:0] m_axi_arid_reg = {AXI_ID_WIDTH{1'b0}}, m_axi_arid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_araddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_araddr_next;
reg [7:0] m_axi_arlen_reg = 8'd0, m_axi_arlen_next;
reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next;
reg m_axi_rready_reg = 1'b0, m_axi_rready_next;
reg s_axis_read_desc_ready_reg = 1'b0, s_axis_read_desc_ready_next;
reg [TAG_WIDTH-1:0] m_axis_read_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_read_desc_status_tag_next;
reg [3:0] m_axis_read_desc_status_error_reg = 4'd0, m_axis_read_desc_status_error_next;
reg m_axis_read_desc_status_valid_reg = 1'b0, m_axis_read_desc_status_valid_next;
// internal datapath
reg [RAM_SEG_COUNT*RAM_SEL_WIDTH-1:0] ram_wr_cmd_sel_int;
reg [RAM_SEG_COUNT*RAM_SEG_BE_WIDTH-1:0] ram_wr_cmd_be_int;
reg [RAM_SEG_COUNT*RAM_SEG_ADDR_WIDTH-1:0] ram_wr_cmd_addr_int;
reg [RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH-1:0] ram_wr_cmd_data_int;
reg [RAM_SEG_COUNT-1:0] ram_wr_cmd_valid_int;
reg [RAM_SEG_COUNT-1:0] ram_wr_cmd_ready_int;
wire [RAM_SEG_COUNT-1:0] out_done;
reg [RAM_SEG_COUNT-1:0] out_done_ack;
assign m_axi_arid = m_axi_arid_reg;
assign m_axi_araddr = m_axi_araddr_reg;
assign m_axi_arlen = m_axi_arlen_reg;
assign m_axi_arsize = AXI_BURST_SIZE;
assign m_axi_arburst = 2'b01;
assign m_axi_arlock = 1'b0;
assign m_axi_arcache = 4'b0011;
assign m_axi_arprot = 3'b010;
assign m_axi_arvalid = m_axi_arvalid_reg;
assign m_axi_rready = m_axi_rready_reg;
assign s_axis_read_desc_ready = s_axis_read_desc_ready_reg;
assign m_axis_read_desc_status_tag = m_axis_read_desc_status_tag_reg;
assign m_axis_read_desc_status_error = m_axis_read_desc_status_error_reg;
assign m_axis_read_desc_status_valid = m_axis_read_desc_status_valid_reg;
// operation tag management
reg [OP_TAG_WIDTH+1-1:0] op_table_start_ptr_reg = 0;
reg [AXI_ADDR_WIDTH-1:0] op_table_start_axi_addr;
reg [RAM_SEL_WIDTH-1:0] op_table_start_ram_sel;
reg [RAM_ADDR_WIDTH-1:0] op_table_start_ram_addr;
reg [11:0] op_table_start_len;
reg [CYCLE_COUNT_WIDTH-1:0] op_table_start_cycle_count;
reg [TAG_WIDTH-1:0] op_table_start_tag;
reg op_table_start_last;
reg op_table_start_en;
reg op_table_write_complete_en;
reg [OP_TAG_WIDTH-1:0] op_table_write_complete_ptr;
reg [OP_TAG_WIDTH+1-1:0] op_table_finish_ptr_reg = 0;
reg op_table_finish_en;
reg [2**OP_TAG_WIDTH-1:0] op_table_active = 0;
reg [AXI_ADDR_WIDTH-1:0] op_table_axi_addr [2**OP_TAG_WIDTH-1:0];
reg [RAM_SEL_WIDTH-1:0] op_table_ram_sel [2**OP_TAG_WIDTH-1:0];
reg [RAM_ADDR_WIDTH-1:0] op_table_ram_addr [2**OP_TAG_WIDTH-1:0];
reg [11:0] op_table_len[2**OP_TAG_WIDTH-1:0];
reg [CYCLE_COUNT_WIDTH-1:0] op_table_cycle_count[2**OP_TAG_WIDTH-1:0];
reg [TAG_WIDTH-1:0] op_table_tag[2**OP_TAG_WIDTH-1:0];
reg op_table_last[2**OP_TAG_WIDTH-1:0];
reg op_table_write_complete[2**OP_TAG_WIDTH-1:0];
integer i;
initial begin
for (i = 0; i < 2**OP_TAG_WIDTH; i = i + 1) begin
op_table_axi_addr[i] = 0;
op_table_ram_sel[i] = 0;
op_table_ram_addr[i] = 0;
op_table_len[i] = 0;
op_table_cycle_count[i] = 0;
op_table_tag[i] = 0;
op_table_last[i] = 0;
op_table_write_complete[i] = 0;
end
end
always @* begin
req_state_next = REQ_STATE_IDLE;
s_axis_read_desc_ready_next = 1'b0;
req_axi_addr_next = req_axi_addr_reg;
req_ram_sel_next = req_ram_sel_reg;
req_ram_addr_next = req_ram_addr_reg;
req_op_count_next = req_op_count_reg;
req_tr_count_next = req_tr_count_reg;
req_tag_next = req_tag_reg;
m_axi_arid_next = m_axi_arid_reg;
m_axi_araddr_next = m_axi_araddr_reg;
m_axi_arlen_next = m_axi_arlen_reg;
m_axi_arvalid_next = m_axi_arvalid_reg && !m_axi_arready;
op_table_start_axi_addr = req_axi_addr_reg;
op_table_start_ram_sel = req_ram_sel_reg;
op_table_start_ram_addr = req_ram_addr_reg;
op_table_start_len = 0;
op_table_start_tag = req_tag_reg;
op_table_start_cycle_count = 0;
op_table_start_last = 0;
op_table_start_en = 1'b0;
// segmentation and request generation
case (req_state_reg)
REQ_STATE_IDLE: begin
s_axis_read_desc_ready_next = !op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] && ($unsigned(op_table_start_ptr_reg - op_table_finish_ptr_reg) < 2**OP_TAG_WIDTH) && enable;
req_axi_addr_next = s_axis_read_desc_axi_addr;
req_ram_sel_next = s_axis_read_desc_ram_sel;
req_ram_addr_next = s_axis_read_desc_ram_addr;
req_op_count_next = s_axis_read_desc_len;
req_tag_next = s_axis_read_desc_tag;
if (req_op_count_next <= AXI_MAX_BURST_SIZE - (req_axi_addr_next & OFFSET_MASK) || AXI_MAX_BURST_SIZE >= 4096) begin
// packet smaller than max burst size
if (((req_axi_addr_next & 12'hfff) + (req_op_count_next & 12'hfff)) >> 12 != 0 || req_op_count_next >> 12 != 0) begin
// crosses 4k boundary
req_tr_count_next = 13'h1000 - req_axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
req_tr_count_next = req_op_count_next;
end
end else begin
// packet larger than max burst size
if (((req_axi_addr_next & 12'hfff) + AXI_MAX_BURST_SIZE) >> 12 != 0) begin
// crosses 4k boundary
req_tr_count_next = 13'h1000 - req_axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
req_tr_count_next = AXI_MAX_BURST_SIZE - (req_axi_addr_next & OFFSET_MASK);
end
end
if (s_axis_read_desc_ready && s_axis_read_desc_valid) begin
$display("AXI DMA start read (AXI 0x%x, RAM 0x%x 0x%x, len %d, tag 0x%x)", s_axis_read_desc_axi_addr, s_axis_read_desc_ram_sel, s_axis_read_desc_ram_addr, s_axis_read_desc_len, s_axis_read_desc_tag);
s_axis_read_desc_ready_next = 1'b0;
req_state_next = REQ_STATE_START;
end else begin
req_state_next = REQ_STATE_IDLE;
end
end
REQ_STATE_START: begin
if (!op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] && ($unsigned(op_table_start_ptr_reg - op_table_finish_ptr_reg) < 2**OP_TAG_WIDTH) && (!m_axi_arvalid || m_axi_arready)) begin
req_axi_addr_next = req_axi_addr_reg + req_tr_count_reg;
req_ram_addr_next = req_ram_addr_reg + req_tr_count_reg;
req_op_count_next = req_op_count_reg - req_tr_count_reg;
op_table_start_axi_addr = req_axi_addr_reg;
op_table_start_ram_sel = req_ram_sel_reg;
op_table_start_ram_addr = req_ram_addr_reg;
op_table_start_len = req_tr_count_next;
op_table_start_tag = req_tag_reg;
op_table_start_cycle_count = (req_tr_count_next + (req_axi_addr_reg & OFFSET_MASK) - 1) >> AXI_BURST_SIZE;
op_table_start_last = req_op_count_reg == req_tr_count_next;
op_table_start_en = 1'b1;
m_axi_arid_next = op_table_start_ptr_reg[OP_TAG_WIDTH-1:0];
m_axi_araddr_next = req_axi_addr_reg;
m_axi_arlen_next = op_table_start_cycle_count;
m_axi_arvalid_next = 1'b1;
if (req_op_count_next <= AXI_MAX_BURST_SIZE - (req_axi_addr_next & OFFSET_MASK) || AXI_MAX_BURST_SIZE >= 4096) begin
// packet smaller than max burst size
if (((req_axi_addr_next & 12'hfff) + (req_op_count_next & 12'hfff)) >> 12 != 0 || req_op_count_next >> 12 != 0) begin
// crosses 4k boundary
req_tr_count_next = 13'h1000 - req_axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
req_tr_count_next = req_op_count_next;
end
end else begin
// packet larger than max burst size
if (((req_axi_addr_next & 12'hfff) + AXI_MAX_BURST_SIZE) >> 12 != 0) begin
// crosses 4k boundary
req_tr_count_next = 13'h1000 - req_axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
req_tr_count_next = AXI_MAX_BURST_SIZE - (req_axi_addr_next & OFFSET_MASK);
end
end
if (!op_table_start_last) begin
req_state_next = REQ_STATE_START;
end else begin
s_axis_read_desc_ready_next = !op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] && ($unsigned(op_table_start_ptr_reg - op_table_finish_ptr_reg) < 2**OP_TAG_WIDTH) && enable;
req_state_next = REQ_STATE_IDLE;
end
end else begin
req_state_next = REQ_STATE_START;
end
end
endcase
end
always @* begin
axi_state_next = AXI_STATE_IDLE;
m_axi_rready_next = 1'b0;
ram_sel_next = ram_sel_reg;
addr_next = addr_reg;
addr_delay_next = addr_delay_reg;
op_count_next = op_count_reg;
ram_mask_next = ram_mask_reg;
ram_mask_0_next = ram_mask_0_reg;
ram_mask_1_next = ram_mask_1_reg;
ram_wrap_next = ram_wrap_reg;
cycle_byte_count_next = cycle_byte_count_reg;
start_offset_next = start_offset_reg;
end_offset_next = end_offset_reg;
offset_next = offset_reg;
op_tag_next = op_tag_reg;
op_table_write_complete_en = 1'b0;
op_table_write_complete_ptr = m_axi_rid;
m_axi_rdata_int_next = m_axi_rdata_int_reg;
m_axi_rvalid_int_next = 1'b0;
status_fifo_finish_next = 1'b0;
status_fifo_we_next = 1'b0;
out_done_ack = {RAM_SEG_COUNT{1'b0}};
// Write generation
ram_wr_cmd_sel_int = {RAM_SEG_COUNT{ram_sel_reg}};
if (!ram_wrap_reg) begin
ram_wr_cmd_be_int = ({RAM_SEG_COUNT*RAM_SEG_BE_WIDTH{1'b1}} << start_offset_reg) & ({RAM_SEG_COUNT*RAM_SEG_BE_WIDTH{1'b1}} >> (RAM_SEG_COUNT*RAM_SEG_BE_WIDTH-1-end_offset_reg));
end else begin
ram_wr_cmd_be_int = ({RAM_SEG_COUNT*RAM_SEG_BE_WIDTH{1'b1}} << start_offset_reg) | ({RAM_SEG_COUNT*RAM_SEG_BE_WIDTH{1'b1}} >> (RAM_SEG_COUNT*RAM_SEG_BE_WIDTH-1-end_offset_reg));
end
for (i = 0; i < RAM_SEG_COUNT; i = i + 1) begin
ram_wr_cmd_addr_int[i*RAM_SEG_ADDR_WIDTH +: RAM_SEG_ADDR_WIDTH] = addr_delay_reg[RAM_ADDR_WIDTH-1:RAM_ADDR_WIDTH-RAM_SEG_ADDR_WIDTH];
if (ram_mask_1_reg[i]) begin
ram_wr_cmd_addr_int[i*RAM_SEG_ADDR_WIDTH +: RAM_SEG_ADDR_WIDTH] = addr_delay_reg[RAM_ADDR_WIDTH-1:RAM_ADDR_WIDTH-RAM_SEG_ADDR_WIDTH]+1;
end
end
ram_wr_cmd_data_int = {3{m_axi_rdata_int_reg}} >> (AXI_DATA_WIDTH - offset_reg*AXI_WORD_SIZE);
ram_wr_cmd_valid_int = {RAM_SEG_COUNT{1'b0}};
if (m_axi_rvalid_int_reg) begin
ram_wr_cmd_valid_int = ram_mask_reg;
end
// AXI read response handling
case (axi_state_reg)
AXI_STATE_IDLE: begin
// idle state, wait for read data
m_axi_rready_next = &ram_wr_cmd_ready_int && !status_fifo_half_full_reg;
op_tag_next = m_axi_rid[OP_TAG_WIDTH-1:0];
ram_sel_next = op_table_ram_sel[op_tag_next];
addr_next = op_table_ram_addr[op_tag_next];
op_count_next = op_table_len[op_tag_next];
offset_next = op_table_ram_addr[op_tag_next][RAM_OFFSET_WIDTH-1:0]-(op_table_axi_addr[op_tag_next] & OFFSET_MASK);
if (m_axi_rready && m_axi_rvalid) begin
if (op_count_next > AXI_WORD_WIDTH-(op_table_axi_addr[m_axi_rid[OP_TAG_WIDTH-1:0]] & OFFSET_MASK)) begin
cycle_byte_count_next = AXI_WORD_WIDTH-(op_table_axi_addr[m_axi_rid[OP_TAG_WIDTH-1:0]] & OFFSET_MASK);
end else begin
cycle_byte_count_next = op_count_next;
end
start_offset_next = addr_next;
{ram_wrap_next, end_offset_next} = start_offset_next+cycle_byte_count_next-1;
ram_mask_0_next = {RAM_SEG_COUNT{1'b1}} << (start_offset_next >> $clog2(RAM_SEG_BE_WIDTH));
ram_mask_1_next = {RAM_SEG_COUNT{1'b1}} >> (RAM_SEG_COUNT-1-(end_offset_next >> $clog2(RAM_SEG_BE_WIDTH)));
if (!ram_wrap_next) begin
ram_mask_next = ram_mask_0_next & ram_mask_1_next;
ram_mask_0_next = ram_mask_0_next & ram_mask_1_next;
ram_mask_1_next = 0;
end else begin
ram_mask_next = ram_mask_0_next | ram_mask_1_next;
end
addr_delay_next = addr_next;
addr_next = addr_next + cycle_byte_count_next;
op_count_next = op_count_next - cycle_byte_count_next;
m_axi_rdata_int_next = m_axi_rdata;
m_axi_rvalid_int_next = 1'b1;
status_fifo_finish_next = 1'b0;
status_fifo_we_next = 1'b1;
if (m_axi_rlast) begin
status_fifo_finish_next = 1'b1;
axi_state_next = AXI_STATE_IDLE;
end else begin
axi_state_next = AXI_STATE_WRITE;
end
end else begin
axi_state_next = AXI_STATE_IDLE;
end
end
AXI_STATE_WRITE: begin
// write state - generate write operations
m_axi_rready_next = &ram_wr_cmd_ready_int && !status_fifo_half_full_reg;
if (m_axi_rready && m_axi_rvalid) begin
if (op_count_next > AXI_WORD_WIDTH) begin
cycle_byte_count_next = AXI_WORD_WIDTH;
end else begin
cycle_byte_count_next = op_count_next;
end
start_offset_next = addr_next;
{ram_wrap_next, end_offset_next} = start_offset_next+cycle_byte_count_next-1;
ram_mask_0_next = {RAM_SEG_COUNT{1'b1}} << (start_offset_next >> $clog2(RAM_SEG_BE_WIDTH));
ram_mask_1_next = {RAM_SEG_COUNT{1'b1}} >> (RAM_SEG_COUNT-1-(end_offset_next >> $clog2(RAM_SEG_BE_WIDTH)));
if (!ram_wrap_next) begin
ram_mask_next = ram_mask_0_next & ram_mask_1_next;
ram_mask_0_next = ram_mask_0_next & ram_mask_1_next;
ram_mask_1_next = 0;
end else begin
ram_mask_next = ram_mask_0_next | ram_mask_1_next;
end
addr_delay_next = addr_next;
addr_next = addr_next + cycle_byte_count_next;
op_count_next = op_count_next - cycle_byte_count_next;
m_axi_rdata_int_next = m_axi_rdata;
m_axi_rvalid_int_next = 1'b1;
status_fifo_finish_next = 1'b0;
status_fifo_we_next = 1'b1;
if (m_axi_rlast) begin
status_fifo_finish_next = 1'b1;
axi_state_next = AXI_STATE_IDLE;
end else begin
axi_state_next = AXI_STATE_WRITE;
end
end else begin
axi_state_next = AXI_STATE_WRITE;
end
end
endcase
status_fifo_rd_ptr_next = status_fifo_rd_ptr_reg;
status_fifo_wr_op_tag = op_tag_reg;
status_fifo_wr_mask = ram_mask_reg;
status_fifo_wr_finish = status_fifo_finish_reg;
status_fifo_we = 1'b0;
if (status_fifo_we_reg) begin
status_fifo_wr_op_tag = op_tag_reg;
status_fifo_wr_mask = ram_mask_reg;
status_fifo_wr_finish = status_fifo_finish_reg;
status_fifo_we = 1'b1;
end
status_fifo_rd_op_tag_next = status_fifo_rd_op_tag_reg;
status_fifo_rd_mask_next = status_fifo_rd_mask_reg;
status_fifo_rd_finish_next = status_fifo_rd_finish_reg;
status_fifo_rd_valid_next = status_fifo_rd_valid_reg;
op_table_write_complete_ptr = status_fifo_rd_op_tag_reg;
op_table_write_complete_en = 1'b0;
if (status_fifo_rd_valid_reg && (status_fifo_rd_mask_reg & ~out_done) == 0) begin
// got write completion, pop and return status
status_fifo_rd_valid_next = 1'b0;
out_done_ack = status_fifo_rd_mask_reg;
if (status_fifo_rd_finish_reg) begin
// mark done
op_table_write_complete_ptr = status_fifo_rd_op_tag_reg;
op_table_write_complete_en = 1'b1;
end
end
if (!status_fifo_rd_valid_next && status_fifo_rd_ptr_reg != status_fifo_wr_ptr_reg) begin
// status FIFO not empty
status_fifo_rd_op_tag_next = status_fifo_op_tag[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
status_fifo_rd_mask_next = status_fifo_mask[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
status_fifo_rd_finish_next = status_fifo_finish[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
status_fifo_rd_valid_next = 1'b1;
status_fifo_rd_ptr_next = status_fifo_rd_ptr_reg + 1;
end
// commit operations in-order
op_table_finish_en = 1'b0;
m_axis_read_desc_status_tag_next = op_table_tag[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]];
m_axis_read_desc_status_error_next = 0;
m_axis_read_desc_status_valid_next = 1'b0;
if (op_table_active[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]] && op_table_write_complete[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]] && op_table_finish_ptr_reg != op_table_start_ptr_reg) begin
op_table_finish_en = 1'b1;
if (op_table_last[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]]) begin
m_axis_read_desc_status_tag_next = op_table_tag[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]];
m_axis_read_desc_status_error_next = 0;
m_axis_read_desc_status_valid_next = 1'b1;
end
end
end
always @(posedge clk) begin
req_state_reg <= req_state_next;
axi_state_reg <= axi_state_next;
req_axi_addr_reg <= req_axi_addr_next;
req_ram_sel_reg <= req_ram_sel_next;
req_ram_addr_reg <= req_ram_addr_next;
req_op_count_reg <= req_op_count_next;
req_tr_count_reg <= req_tr_count_next;
req_tag_reg <= req_tag_next;
ram_sel_reg <= ram_sel_next;
addr_reg <= addr_next;
addr_delay_reg <= addr_delay_next;
op_count_reg <= op_count_next;
ram_mask_reg <= ram_mask_next;
ram_mask_0_reg <= ram_mask_0_next;
ram_mask_1_reg <= ram_mask_1_next;
ram_wrap_reg <= ram_wrap_next;
cycle_byte_count_reg <= cycle_byte_count_next;
start_offset_reg <= start_offset_next;
end_offset_reg <= end_offset_next;
offset_reg <= offset_next;
op_tag_reg <= op_tag_next;
m_axi_rdata_int_reg <= m_axi_rdata_int_next;
m_axi_rvalid_int_reg <= m_axi_rvalid_int_next;
m_axi_arid_reg <= m_axi_arid_next;
m_axi_araddr_reg <= m_axi_araddr_next;
m_axi_arlen_reg <= m_axi_arlen_next;
m_axi_arvalid_reg <= m_axi_arvalid_next;
m_axi_rready_reg <= m_axi_rready_next;
s_axis_read_desc_ready_reg <= s_axis_read_desc_ready_next;
m_axis_read_desc_status_tag_reg <= m_axis_read_desc_status_tag_next;
m_axis_read_desc_status_error_reg <= m_axis_read_desc_status_error_next;
m_axis_read_desc_status_valid_reg <= m_axis_read_desc_status_valid_next;
if (status_fifo_we) begin
status_fifo_op_tag[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_op_tag;
status_fifo_mask[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_mask;
status_fifo_finish[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_finish;
status_fifo_wr_ptr_reg <= status_fifo_wr_ptr_reg + 1;
end
status_fifo_rd_ptr_reg <= status_fifo_rd_ptr_next;
status_fifo_finish_reg <= status_fifo_finish_next;
status_fifo_we_reg <= status_fifo_we_next;
status_fifo_rd_op_tag_reg <= status_fifo_rd_op_tag_next;
status_fifo_rd_mask_reg <= status_fifo_rd_mask_next;
status_fifo_rd_finish_reg <= status_fifo_rd_finish_next;
status_fifo_rd_valid_reg <= status_fifo_rd_valid_next;
status_fifo_half_full_reg <= $unsigned(status_fifo_wr_ptr_reg - status_fifo_rd_ptr_reg) >= 2**(STATUS_FIFO_ADDR_WIDTH-1);
if (op_table_start_en) begin
op_table_start_ptr_reg <= op_table_start_ptr_reg + 1;
op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= 1'b1;
op_table_axi_addr[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_axi_addr;
op_table_ram_sel[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_ram_sel;
op_table_ram_addr[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_ram_addr;
op_table_len[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_len;
op_table_cycle_count[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_cycle_count;
op_table_tag[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_tag;
op_table_last[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_last;
op_table_write_complete[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= 1'b0;
end
if (op_table_write_complete_en) begin
op_table_write_complete[op_table_write_complete_ptr] <= 1'b1;
end
if (op_table_finish_en) begin
op_table_finish_ptr_reg <= op_table_finish_ptr_reg + 1;
op_table_active[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]] <= 1'b0;
end
if (rst) begin
req_state_reg <= REQ_STATE_IDLE;
axi_state_reg <= AXI_STATE_IDLE;
m_axi_rdata_int_reg <= 1'b0;
m_axi_arvalid_reg <= 1'b0;
m_axi_rready_reg <= 1'b0;
s_axis_read_desc_ready_reg <= 1'b0;
m_axis_read_desc_status_valid_reg <= 1'b0;
status_fifo_wr_ptr_reg <= 0;
status_fifo_rd_ptr_reg <= 0;
status_fifo_we_reg <= 1'b0;
status_fifo_rd_valid_reg <= 1'b0;
op_table_active <= 0;
end
end
// output datapath logic (write data)
generate
genvar n;
for (n = 0; n < RAM_SEG_COUNT; n = n + 1) begin
reg [RAM_SEL_WIDTH-1:0] ram_wr_cmd_sel_reg = {RAM_SEL_WIDTH{1'b0}};
reg [RAM_SEG_BE_WIDTH-1:0] ram_wr_cmd_be_reg = {RAM_SEG_BE_WIDTH{1'b0}};
reg [RAM_SEG_ADDR_WIDTH-1:0] ram_wr_cmd_addr_reg = {RAM_SEG_ADDR_WIDTH{1'b0}};
reg [RAM_SEG_DATA_WIDTH-1:0] ram_wr_cmd_data_reg = {RAM_SEG_DATA_WIDTH{1'b0}};
reg ram_wr_cmd_valid_reg = 1'b0;
reg [OUTPUT_FIFO_ADDR_WIDTH-1:0] out_fifo_wr_ptr_reg = 0;
reg [OUTPUT_FIFO_ADDR_WIDTH-1:0] out_fifo_rd_ptr_reg = 0;
reg out_fifo_half_full_reg = 1'b0;
wire out_fifo_full = out_fifo_wr_ptr_reg == (out_fifo_rd_ptr_reg ^ {1'b1, {OUTPUT_FIFO_ADDR_WIDTH{1'b0}}});
wire out_fifo_empty = out_fifo_wr_ptr_reg == out_fifo_rd_ptr_reg;
(* ram_style = "distributed" *)
reg [RAM_SEL_WIDTH-1:0] out_fifo_wr_cmd_sel[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [RAM_SEG_BE_WIDTH-1:0] out_fifo_wr_cmd_be[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [RAM_SEG_ADDR_WIDTH-1:0] out_fifo_wr_cmd_addr[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [RAM_SEG_DATA_WIDTH-1:0] out_fifo_wr_cmd_data[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] done_count_reg = 0;
reg done_reg = 1'b0;
assign ram_wr_cmd_ready_int[n +: 1] = !out_fifo_half_full_reg;
assign ram_wr_cmd_sel[n*RAM_SEL_WIDTH +: RAM_SEL_WIDTH] = ram_wr_cmd_sel_reg;
assign ram_wr_cmd_be[n*RAM_SEG_BE_WIDTH +: RAM_SEG_BE_WIDTH] = ram_wr_cmd_be_reg;
assign ram_wr_cmd_addr[n*RAM_SEG_ADDR_WIDTH +: RAM_SEG_ADDR_WIDTH] = ram_wr_cmd_addr_reg;
assign ram_wr_cmd_data[n*RAM_SEG_DATA_WIDTH +: RAM_SEG_DATA_WIDTH] = ram_wr_cmd_data_reg;
assign ram_wr_cmd_valid[n +: 1] = ram_wr_cmd_valid_reg;
assign out_done[n] = done_reg;
always @(posedge clk) begin
ram_wr_cmd_valid_reg <= ram_wr_cmd_valid_reg && !ram_wr_cmd_ready[n +: 1];
out_fifo_half_full_reg <= $unsigned(out_fifo_wr_ptr_reg - out_fifo_rd_ptr_reg) >= 2**(OUTPUT_FIFO_ADDR_WIDTH-1);
if (!out_fifo_full && ram_wr_cmd_valid_int[n +: 1]) begin
out_fifo_wr_cmd_sel[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= ram_wr_cmd_sel_int[n*RAM_SEL_WIDTH +: RAM_SEL_WIDTH];
out_fifo_wr_cmd_be[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= ram_wr_cmd_be_int[n*RAM_SEG_BE_WIDTH +: RAM_SEG_BE_WIDTH];
out_fifo_wr_cmd_addr[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= ram_wr_cmd_addr_int[n*RAM_SEG_ADDR_WIDTH +: RAM_SEG_ADDR_WIDTH];
out_fifo_wr_cmd_data[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= ram_wr_cmd_data_int[n*RAM_SEG_DATA_WIDTH +: RAM_SEG_DATA_WIDTH];
out_fifo_wr_ptr_reg <= out_fifo_wr_ptr_reg + 1;
end
if (!out_fifo_empty && (!ram_wr_cmd_valid_reg || ram_wr_cmd_ready[n +: 1])) begin
ram_wr_cmd_sel_reg <= out_fifo_wr_cmd_sel[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
ram_wr_cmd_be_reg <= out_fifo_wr_cmd_be[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
ram_wr_cmd_addr_reg <= out_fifo_wr_cmd_addr[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
ram_wr_cmd_data_reg <= out_fifo_wr_cmd_data[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
ram_wr_cmd_valid_reg <= 1'b1;
out_fifo_rd_ptr_reg <= out_fifo_rd_ptr_reg + 1;
end
if (done_count_reg < 2**OUTPUT_FIFO_ADDR_WIDTH && ram_wr_done[n] && !out_done_ack[n]) begin
done_count_reg <= done_count_reg + 1;
done_reg <= 1;
end else if (done_count_reg > 0 && !ram_wr_done[n] && out_done_ack[n]) begin
done_count_reg <= done_count_reg - 1;
done_reg <= done_count_reg > 1;
end
if (rst) begin
out_fifo_wr_ptr_reg <= 0;
out_fifo_rd_ptr_reg <= 0;
ram_wr_cmd_valid_reg <= 1'b0;
done_count_reg <= 0;
done_reg <= 1'b0;
end
end
end
endgenerate
endmodule
`resetall

View File

@ -0,0 +1,972 @@
/*
Copyright (c) 2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* AXI DMA write interface
*/
module dma_if_axi_wr #
(
// Width of AXI data bus in bits
parameter AXI_DATA_WIDTH = 32,
// Width of AXI address bus in bits
parameter AXI_ADDR_WIDTH = 16,
// Width of AXI wstrb (width of data bus in words)
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
// Width of AXI ID signal
parameter AXI_ID_WIDTH = 8,
// Maximum AXI burst length to generate
parameter AXI_MAX_BURST_LEN = 256,
// RAM segment countm_axis_read_desc_status_error
parameter RAM_SEG_COUNT = 2,
// RAM segment data width
parameter RAM_SEG_DATA_WIDTH = AXI_DATA_WIDTH*2/RAM_SEG_COUNT,
// RAM segment address width
parameter RAM_SEG_ADDR_WIDTH = 8,
// RAM segment byte enable width
parameter RAM_SEG_BE_WIDTH = RAM_SEG_DATA_WIDTH/8,
// RAM select width
parameter RAM_SEL_WIDTH = 2,
// RAM address width
parameter RAM_ADDR_WIDTH = RAM_SEG_ADDR_WIDTH+$clog2(RAM_SEG_COUNT)+$clog2(RAM_SEG_BE_WIDTH),
// Length field width
parameter LEN_WIDTH = 16,
// Tag field width
parameter TAG_WIDTH = 8,
// Operation table size
parameter OP_TABLE_SIZE = 2**(AXI_ID_WIDTH),
// Use AXI ID signals
parameter USE_AXI_ID = 1
)
(
input wire clk,
input wire rst,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
/*
* AXI write descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_axi_addr,
input wire [RAM_SEL_WIDTH-1:0] s_axis_write_desc_ram_sel,
input wire [RAM_ADDR_WIDTH-1:0] s_axis_write_desc_ram_addr,
input wire [LEN_WIDTH-1:0] s_axis_write_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_write_desc_tag,
input wire s_axis_write_desc_valid,
output wire s_axis_write_desc_ready,
/*
* AXI write descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag,
output wire [3:0] m_axis_write_desc_status_error,
output wire m_axis_write_desc_status_valid,
/*
* RAM interface
*/
output wire [RAM_SEG_COUNT*RAM_SEL_WIDTH-1:0] ram_rd_cmd_sel,
output wire [RAM_SEG_COUNT*RAM_SEG_ADDR_WIDTH-1:0] ram_rd_cmd_addr,
output wire [RAM_SEG_COUNT-1:0] ram_rd_cmd_valid,
input wire [RAM_SEG_COUNT-1:0] ram_rd_cmd_ready,
input wire [RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH-1:0] ram_rd_resp_data,
input wire [RAM_SEG_COUNT-1:0] ram_rd_resp_valid,
output wire [RAM_SEG_COUNT-1:0] ram_rd_resp_ready,
/*
* Configuration
*/
input wire enable
);
parameter RAM_WORD_WIDTH = RAM_SEG_BE_WIDTH;
parameter RAM_WORD_SIZE = RAM_SEG_DATA_WIDTH/RAM_WORD_WIDTH;
parameter AXI_WORD_WIDTH = AXI_STRB_WIDTH;
parameter AXI_WORD_SIZE = AXI_DATA_WIDTH/AXI_WORD_WIDTH;
parameter AXI_BURST_SIZE = $clog2(AXI_STRB_WIDTH);
parameter AXI_MAX_BURST_SIZE = AXI_MAX_BURST_LEN << AXI_BURST_SIZE;
parameter OFFSET_WIDTH = AXI_STRB_WIDTH > 1 ? $clog2(AXI_STRB_WIDTH) : 1;
parameter OFFSET_MASK = AXI_STRB_WIDTH > 1 ? {OFFSET_WIDTH{1'b1}} : 0;
parameter RAM_OFFSET_WIDTH = $clog2(RAM_SEG_COUNT*RAM_SEG_BE_WIDTH);
parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
parameter MASK_FIFO_ADDR_WIDTH = $clog2(OP_TABLE_SIZE)+1;
parameter OP_TAG_WIDTH = $clog2(OP_TABLE_SIZE);
parameter OUTPUT_FIFO_ADDR_WIDTH = 5;
// bus width assertions
initial begin
if (AXI_WORD_SIZE * AXI_STRB_WIDTH != AXI_DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (AXI_WORD_SIZE != RAM_WORD_SIZE) begin
$error("Error: word size mismatch (instance %m)");
$finish;
end
if (2**$clog2(AXI_WORD_WIDTH) != AXI_WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256) begin
$error("Error: AXI_MAX_BURST_LEN must be between 1 and 256 (instance %m)");
$finish;
end
if (RAM_SEG_COUNT < 2) begin
$error("Error: RAM interface requires at least 2 segments (instance %m)");
$finish;
end
if (RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH != AXI_DATA_WIDTH*2) begin
$error("Error: RAM interface width must be double the AXI interface width (instance %m)");
$finish;
end
if (2**$clog2(RAM_WORD_WIDTH) != RAM_WORD_WIDTH) begin
$error("Error: RAM word width must be even power of two (instance %m)");
$finish;
end
if (RAM_ADDR_WIDTH != RAM_SEG_ADDR_WIDTH+$clog2(RAM_SEG_COUNT)+$clog2(RAM_SEG_BE_WIDTH)) begin
$error("Error: RAM_ADDR_WIDTH does not match RAM configuration (instance %m)");
$finish;
end
end
localparam [1:0]
AXI_RESP_OKAY = 2'b00,
AXI_RESP_EXOKAY = 2'b01,
AXI_RESP_SLVERR = 2'b10,
AXI_RESP_DECERR = 2'b11;
localparam [3:0]
DMA_ERROR_NONE = 4'd0,
DMA_ERROR_TIMEOUT = 4'd1,
DMA_ERROR_PARITY = 4'd2,
DMA_ERROR_AXI_RD_SLVERR = 4'd4,
DMA_ERROR_AXI_RD_DECERR = 4'd5,
DMA_ERROR_AXI_WR_SLVERR = 4'd6,
DMA_ERROR_AXI_WR_DECERR = 4'd7,
DMA_ERROR_PCIE_FLR = 4'd8,
DMA_ERROR_PCIE_CPL_POISONED = 4'd9,
DMA_ERROR_PCIE_CPL_STATUS_UR = 4'd10,
DMA_ERROR_PCIE_CPL_STATUS_CA = 4'd11;
localparam [0:0]
REQ_STATE_IDLE = 1'd0,
REQ_STATE_START = 1'd1;
reg [0:0] req_state_reg = REQ_STATE_IDLE, req_state_next;
localparam [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_READ = 1'd1;
reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
localparam [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_TRANSFER = 1'd1;
reg [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
// datapath control signals
reg mask_fifo_we;
reg read_cmd_ready;
reg [AXI_ADDR_WIDTH-1:0] axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, axi_addr_next;
reg [RAM_SEL_WIDTH-1:0] ram_sel_reg = {RAM_SEL_WIDTH{1'b0}}, ram_sel_next;
reg [RAM_ADDR_WIDTH-1:0] ram_addr_reg = {RAM_ADDR_WIDTH{1'b0}}, ram_addr_next;
reg [LEN_WIDTH-1:0] op_count_reg = {LEN_WIDTH{1'b0}}, op_count_next;
reg [LEN_WIDTH-1:0] tr_count_reg = {LEN_WIDTH{1'b0}}, tr_count_next;
reg [12:0] tr_word_count_reg = 13'd0, tr_word_count_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [AXI_ADDR_WIDTH-1:0] read_axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, read_axi_addr_next;
reg [RAM_SEL_WIDTH-1:0] read_ram_sel_reg = {RAM_SEL_WIDTH{1'b0}}, read_ram_sel_next;
reg [RAM_ADDR_WIDTH-1:0] read_ram_addr_reg = {RAM_ADDR_WIDTH{1'b0}}, read_ram_addr_next;
reg [LEN_WIDTH-1:0] read_len_reg = {LEN_WIDTH{1'b0}}, read_len_next;
reg [RAM_SEG_COUNT-1:0] read_ram_mask_reg = {RAM_SEG_COUNT{1'b0}}, read_ram_mask_next;
reg [RAM_SEG_COUNT-1:0] read_ram_mask_0_reg = {RAM_SEG_COUNT{1'b0}}, read_ram_mask_0_next;
reg [RAM_SEG_COUNT-1:0] read_ram_mask_1_reg = {RAM_SEG_COUNT{1'b0}}, read_ram_mask_1_next;
reg ram_wrap_reg = 1'b0, ram_wrap_next;
reg [CYCLE_COUNT_WIDTH-1:0] read_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, read_cycle_count_next;
reg read_last_cycle_reg = 1'b0, read_last_cycle_next;
reg [OFFSET_WIDTH+1-1:0] cycle_byte_count_reg = {OFFSET_WIDTH+1{1'b0}}, cycle_byte_count_next;
reg [RAM_OFFSET_WIDTH-1:0] start_offset_reg = {RAM_OFFSET_WIDTH{1'b0}}, start_offset_next;
reg [RAM_OFFSET_WIDTH-1:0] end_offset_reg = {RAM_OFFSET_WIDTH{1'b0}}, end_offset_next;
reg [AXI_ADDR_WIDTH-1:0] tlp_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, tlp_addr_next;
reg [11:0] tlp_len_reg = 12'd0, tlp_len_next;
reg [RAM_OFFSET_WIDTH-1:0] offset_reg = {RAM_OFFSET_WIDTH{1'b0}}, offset_next;
reg [AXI_STRB_WIDTH-1:0] strb_offset_mask_reg = {AXI_STRB_WIDTH{1'b1}}, strb_offset_mask_next;
reg [OFFSET_WIDTH-1:0] last_cycle_offset_reg = {OFFSET_WIDTH{1'b0}}, last_cycle_offset_next;
reg [RAM_SEG_COUNT-1:0] ram_mask_reg = {RAM_SEG_COUNT{1'b0}}, ram_mask_next;
reg ram_mask_valid_reg = 1'b0, ram_mask_valid_next;
reg [CYCLE_COUNT_WIDTH-1:0] cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, cycle_count_next;
reg last_cycle_reg = 1'b0, last_cycle_next;
reg [AXI_ADDR_WIDTH-1:0] read_cmd_axi_addr_reg = {AXI_ADDR_WIDTH{1'b0}}, read_cmd_axi_addr_next;
reg [RAM_SEL_WIDTH-1:0] read_cmd_ram_sel_reg = {RAM_SEL_WIDTH{1'b0}}, read_cmd_ram_sel_next;
reg [RAM_ADDR_WIDTH-1:0] read_cmd_ram_addr_reg = {RAM_ADDR_WIDTH{1'b0}}, read_cmd_ram_addr_next;
reg [11:0] read_cmd_len_reg = 12'd0, read_cmd_len_next;
reg [CYCLE_COUNT_WIDTH-1:0] read_cmd_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, read_cmd_cycle_count_next;
reg read_cmd_last_cycle_reg = 1'b0, read_cmd_last_cycle_next;
reg read_cmd_valid_reg = 1'b0, read_cmd_valid_next;
reg [MASK_FIFO_ADDR_WIDTH+1-1:0] mask_fifo_wr_ptr_reg = 0;
reg [MASK_FIFO_ADDR_WIDTH+1-1:0] mask_fifo_rd_ptr_reg = 0, mask_fifo_rd_ptr_next;
reg [RAM_SEG_COUNT-1:0] mask_fifo_mask[(2**MASK_FIFO_ADDR_WIDTH)-1:0];
reg [RAM_SEG_COUNT-1:0] mask_fifo_wr_mask;
wire mask_fifo_empty = mask_fifo_wr_ptr_reg == mask_fifo_rd_ptr_reg;
wire mask_fifo_full = mask_fifo_wr_ptr_reg == (mask_fifo_rd_ptr_reg ^ (1 << MASK_FIFO_ADDR_WIDTH));
reg [AXI_ID_WIDTH-1:0] m_axi_awid_reg = {AXI_ID_WIDTH{1'b0}}, m_axi_awid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_awaddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_awaddr_next;
reg [7:0] m_axi_awlen_reg = 8'd0, m_axi_awlen_next;
reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next;
reg m_axi_bready_reg = 1'b0, m_axi_bready_next;
reg s_axis_write_desc_ready_reg = 1'b0, s_axis_write_desc_ready_next;
reg [TAG_WIDTH-1:0] m_axis_write_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_write_desc_status_tag_next;
reg [3:0] m_axis_write_desc_status_error_reg = 4'd0, m_axis_write_desc_status_error_next;
reg m_axis_write_desc_status_valid_reg = 1'b0, m_axis_write_desc_status_valid_next;
reg [RAM_SEG_COUNT*RAM_SEL_WIDTH-1:0] ram_rd_cmd_sel_reg = 0, ram_rd_cmd_sel_next;
reg [RAM_SEG_COUNT*RAM_SEG_ADDR_WIDTH-1:0] ram_rd_cmd_addr_reg = 0, ram_rd_cmd_addr_next;
reg [RAM_SEG_COUNT-1:0] ram_rd_cmd_valid_reg = 0, ram_rd_cmd_valid_next;
reg [RAM_SEG_COUNT-1:0] ram_rd_resp_ready_cmb;
// internal datapath
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_int;
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_int;
reg m_axi_wlast_int;
reg m_axi_wvalid_int;
wire m_axi_wready_int;
assign m_axi_awid = m_axi_awid_reg;
assign m_axi_awaddr = m_axi_awaddr_reg;
assign m_axi_awlen = m_axi_awlen_reg;
assign m_axi_awsize = AXI_BURST_SIZE;
assign m_axi_awburst = 2'b01;
assign m_axi_awlock = 1'b0;
assign m_axi_awcache = 4'b0011;
assign m_axi_awprot = 3'b010;
assign m_axi_awvalid = m_axi_awvalid_reg;
assign m_axi_bready = m_axi_bready_reg;
assign s_axis_write_desc_ready = s_axis_write_desc_ready_reg;
assign m_axis_write_desc_status_tag = m_axis_write_desc_status_tag_reg;
assign m_axis_write_desc_status_error = m_axis_write_desc_status_error_reg;
assign m_axis_write_desc_status_valid = m_axis_write_desc_status_valid_reg;
assign ram_rd_cmd_sel = ram_rd_cmd_sel_reg;
assign ram_rd_cmd_addr = ram_rd_cmd_addr_reg;
assign ram_rd_cmd_valid = ram_rd_cmd_valid_reg;
assign ram_rd_resp_ready = ram_rd_resp_ready_cmb;
// operation tag management
reg [OP_TAG_WIDTH+1-1:0] op_table_start_ptr_reg = 0;
reg [AXI_ADDR_WIDTH-1:0] op_table_start_axi_addr;
reg [11:0] op_table_start_len;
reg [CYCLE_COUNT_WIDTH-1:0] op_table_start_cycle_count;
reg [RAM_OFFSET_WIDTH-1:0] op_table_start_offset;
reg [TAG_WIDTH-1:0] op_table_start_tag;
reg op_table_start_last;
reg op_table_start_en;
reg [OP_TAG_WIDTH+1-1:0] op_table_tx_start_ptr_reg = 0;
reg op_table_tx_start_en;
reg [OP_TAG_WIDTH+1-1:0] op_table_tx_finish_ptr_reg = 0;
reg op_table_tx_finish_en;
reg op_table_write_complete_en;
reg [OP_TAG_WIDTH-1:0] op_table_write_complete_ptr;
reg [OP_TAG_WIDTH+1-1:0] op_table_finish_ptr_reg = 0;
reg op_table_finish_en;
reg [2**OP_TAG_WIDTH-1:0] op_table_active = 0;
reg [2**OP_TAG_WIDTH-1:0] op_table_write_complete = 0;
reg [AXI_ADDR_WIDTH-1:0] op_table_axi_addr[2**OP_TAG_WIDTH-1:0];
reg [11:0] op_table_len[2**OP_TAG_WIDTH-1:0];
reg [CYCLE_COUNT_WIDTH-1:0] op_table_cycle_count[2**OP_TAG_WIDTH-1:0];
reg [RAM_OFFSET_WIDTH-1:0] op_table_offset[2**OP_TAG_WIDTH-1:0];
reg [TAG_WIDTH-1:0] op_table_tag[2**OP_TAG_WIDTH-1:0];
reg op_table_last[2**OP_TAG_WIDTH-1:0];
integer i;
initial begin
for (i = 0; i < 2**OP_TAG_WIDTH; i = i + 1) begin
op_table_axi_addr[i] = 0;
op_table_len[i] = 0;
op_table_cycle_count[i] = 0;
op_table_offset[i] = 0;
op_table_tag[i] = 0;
op_table_last[i] = 0;
end
end
always @* begin
req_state_next = REQ_STATE_IDLE;
s_axis_write_desc_ready_next = 1'b0;
tag_next = tag_reg;
axi_addr_next = axi_addr_reg;
ram_sel_next = ram_sel_reg;
ram_addr_next = ram_addr_reg;
op_count_next = op_count_reg;
tr_count_next = tr_count_reg;
tr_word_count_next = tr_word_count_reg;
read_cmd_axi_addr_next = read_cmd_axi_addr_reg;
read_cmd_ram_sel_next = read_cmd_ram_sel_reg;
read_cmd_ram_addr_next = read_cmd_ram_addr_reg;
read_cmd_len_next = read_cmd_len_reg;
read_cmd_cycle_count_next = read_cmd_cycle_count_reg;
read_cmd_last_cycle_next = read_cmd_last_cycle_reg;
read_cmd_valid_next = read_cmd_valid_reg && !read_cmd_ready;
op_table_start_axi_addr = axi_addr_reg;
op_table_start_len = 0;
op_table_start_cycle_count = 0;
op_table_start_offset = (axi_addr_reg & OFFSET_MASK)-ram_addr_reg[RAM_OFFSET_WIDTH-1:0];
op_table_start_tag = tag_reg;
op_table_start_last = 0;
op_table_start_en = 1'b0;
// TLP segmentation
case (req_state_reg)
REQ_STATE_IDLE: begin
// idle state, wait for incoming descriptor
s_axis_write_desc_ready_next = !op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] && ($unsigned(op_table_start_ptr_reg - op_table_finish_ptr_reg) < 2**OP_TAG_WIDTH) && enable;
axi_addr_next = s_axis_write_desc_axi_addr;
ram_sel_next = s_axis_write_desc_ram_sel;
ram_addr_next = s_axis_write_desc_ram_addr;
op_count_next = s_axis_write_desc_len;
tag_next = s_axis_write_desc_tag;
if (op_count_next <= AXI_MAX_BURST_SIZE - (axi_addr_next & OFFSET_MASK) || AXI_MAX_BURST_SIZE >= 4096) begin
// packet smaller than max burst size
if (((axi_addr_next & 12'hfff) + (op_count_next & 12'hfff)) >> 12 != 0 || op_count_next >> 12 != 0) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = op_count_next;
end
end else begin
// packet larger than max burst size
if (((axi_addr_next & 12'hfff) + AXI_MAX_BURST_SIZE) >> 12 != 0) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = AXI_MAX_BURST_SIZE - (axi_addr_next & OFFSET_MASK);
end
end
if (s_axis_write_desc_ready & s_axis_write_desc_valid) begin
$display("AXI DMA start write (AXI 0x%x, RAM 0x%x 0x%x, len %d, tag 0x%x)", s_axis_write_desc_axi_addr, s_axis_write_desc_ram_sel, s_axis_write_desc_ram_addr, s_axis_write_desc_len, s_axis_write_desc_tag);
s_axis_write_desc_ready_next = 1'b0;
req_state_next = REQ_STATE_START;
end else begin
req_state_next = REQ_STATE_IDLE;
end
end
REQ_STATE_START: begin
// start state, compute length
if (!op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] && ($unsigned(op_table_start_ptr_reg - op_table_finish_ptr_reg) < 2**OP_TAG_WIDTH) && (!ram_rd_cmd_valid_reg || ram_rd_cmd_ready) && (!read_cmd_valid_reg || read_cmd_ready)) begin
read_cmd_axi_addr_next = axi_addr_reg;
read_cmd_ram_sel_next = ram_sel_reg;
read_cmd_ram_addr_next = ram_addr_reg;
read_cmd_len_next = tr_word_count_next;
read_cmd_cycle_count_next = (tr_word_count_next + (axi_addr_reg & OFFSET_MASK) - 1) >> AXI_BURST_SIZE;
op_table_start_cycle_count = read_cmd_cycle_count_next;
read_cmd_last_cycle_next = read_cmd_cycle_count_next == 0;
read_cmd_valid_next = 1'b1;
axi_addr_next = axi_addr_reg + tr_word_count_next;
ram_addr_next = ram_addr_reg + tr_word_count_next;
op_count_next = op_count_reg - tr_word_count_next;
op_table_start_axi_addr = axi_addr_reg;
op_table_start_len = tr_word_count_next;
op_table_start_offset = (axi_addr_reg & OFFSET_MASK)-ram_addr_reg[RAM_OFFSET_WIDTH-1:0];
op_table_start_tag = tag_reg;
op_table_start_last = op_count_reg == tr_word_count_next;
op_table_start_en = 1'b1;
if (op_count_next <= AXI_MAX_BURST_SIZE - (axi_addr_next & OFFSET_MASK) || AXI_MAX_BURST_SIZE >= 4096) begin
// packet smaller than max burst size
if (((axi_addr_next & 12'hfff) + (op_count_next & 12'hfff)) >> 12 != 0 || op_count_next >> 12 != 0) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = op_count_next;
end
end else begin
// packet larger than max burst size
if (((axi_addr_next & 12'hfff) + AXI_MAX_BURST_SIZE) >> 12 != 0) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - axi_addr_next[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = AXI_MAX_BURST_SIZE - (axi_addr_next & OFFSET_MASK);
end
end
if (!op_table_start_last) begin
req_state_next = REQ_STATE_START;
end else begin
s_axis_write_desc_ready_next = !op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] && ($unsigned(op_table_start_ptr_reg - op_table_finish_ptr_reg) < 2**OP_TAG_WIDTH) && enable;
req_state_next = REQ_STATE_IDLE;
end
end else begin
req_state_next = REQ_STATE_START;
end
end
endcase
end
always @* begin
read_state_next = READ_STATE_IDLE;
read_cmd_ready = 1'b0;
ram_rd_cmd_sel_next = ram_rd_cmd_sel_reg;
ram_rd_cmd_addr_next = ram_rd_cmd_addr_reg;
ram_rd_cmd_valid_next = ram_rd_cmd_valid_reg & ~ram_rd_cmd_ready;
read_axi_addr_next = read_axi_addr_reg;
read_ram_sel_next = read_ram_sel_reg;
read_ram_addr_next = read_ram_addr_reg;
read_len_next = read_len_reg;
read_ram_mask_next = read_ram_mask_reg;
read_ram_mask_0_next = read_ram_mask_0_reg;
read_ram_mask_1_next = read_ram_mask_1_reg;
ram_wrap_next = ram_wrap_reg;
read_cycle_count_next = read_cycle_count_reg;
read_last_cycle_next = read_last_cycle_reg;
cycle_byte_count_next = cycle_byte_count_reg;
start_offset_next = start_offset_reg;
end_offset_next = end_offset_reg;
mask_fifo_wr_mask = read_ram_mask_reg;
mask_fifo_we = 1'b0;
// Read request generation
case (read_state_reg)
READ_STATE_IDLE: begin
// idle state, wait for read command
read_axi_addr_next = read_cmd_axi_addr_reg;
read_ram_sel_next = read_cmd_ram_sel_reg;
read_ram_addr_next = read_cmd_ram_addr_reg;
read_len_next = read_cmd_len_reg;
read_cycle_count_next = read_cmd_cycle_count_reg;
read_last_cycle_next = read_cmd_last_cycle_reg;
if (read_len_next > AXI_STRB_WIDTH-(read_axi_addr_next & OFFSET_MASK)) begin
cycle_byte_count_next = AXI_STRB_WIDTH-(read_axi_addr_next & OFFSET_MASK);
end else begin
cycle_byte_count_next = read_len_next;
end
start_offset_next = read_ram_addr_next;
{ram_wrap_next, end_offset_next} = start_offset_next+cycle_byte_count_next-1;
read_ram_mask_0_next = {RAM_SEG_COUNT{1'b1}} << (start_offset_next >> $clog2(RAM_SEG_BE_WIDTH));
read_ram_mask_1_next = {RAM_SEG_COUNT{1'b1}} >> (RAM_SEG_COUNT-1-(end_offset_next >> $clog2(RAM_SEG_BE_WIDTH)));
if (!ram_wrap_next) begin
read_ram_mask_next = read_ram_mask_0_next & read_ram_mask_1_next;
read_ram_mask_0_next = read_ram_mask_0_next & read_ram_mask_1_next;
read_ram_mask_1_next = 0;
end else begin
read_ram_mask_next = read_ram_mask_0_next | read_ram_mask_1_next;
end
if (read_cmd_valid_reg) begin
read_cmd_ready = 1'b1;
read_state_next = READ_STATE_READ;
end else begin
read_state_next = READ_STATE_IDLE;
end
end
READ_STATE_READ: begin
// read state - start new read operations
if (!(ram_rd_cmd_valid & ~ram_rd_cmd_ready & read_ram_mask_reg) && !mask_fifo_full) begin
// update counters
read_ram_addr_next = read_ram_addr_reg + cycle_byte_count_reg;
read_len_next = read_len_reg - cycle_byte_count_reg;
read_cycle_count_next = read_cycle_count_reg - 1;
read_last_cycle_next = read_cycle_count_next == 0;
for (i = 0; i < RAM_SEG_COUNT; i = i + 1) begin
if (read_ram_mask_0_reg[i]) begin
ram_rd_cmd_sel_next[i*RAM_SEL_WIDTH +: RAM_SEL_WIDTH] = read_ram_sel_reg;
ram_rd_cmd_addr_next[i*RAM_SEG_ADDR_WIDTH +: RAM_SEG_ADDR_WIDTH] = read_ram_addr_reg[RAM_ADDR_WIDTH-1:RAM_ADDR_WIDTH-RAM_SEG_ADDR_WIDTH];
ram_rd_cmd_valid_next[i] = 1'b1;
end
if (read_ram_mask_1_reg[i]) begin
ram_rd_cmd_sel_next[i*RAM_SEL_WIDTH +: RAM_SEL_WIDTH] = read_ram_sel_reg;
ram_rd_cmd_addr_next[i*RAM_SEG_ADDR_WIDTH +: RAM_SEG_ADDR_WIDTH] = read_ram_addr_reg[RAM_ADDR_WIDTH-1:RAM_ADDR_WIDTH-RAM_SEG_ADDR_WIDTH]+1;
ram_rd_cmd_valid_next[i] = 1'b1;
end
end
mask_fifo_wr_mask = read_ram_mask_reg;
mask_fifo_we = 1'b1;
if (read_len_next > AXI_STRB_WIDTH) begin
cycle_byte_count_next = AXI_STRB_WIDTH;
end else begin
cycle_byte_count_next = read_len_next;
end
start_offset_next = read_ram_addr_next;
{ram_wrap_next, end_offset_next} = start_offset_next+cycle_byte_count_next-1;
read_ram_mask_0_next = {RAM_SEG_COUNT{1'b1}} << (start_offset_next >> $clog2(RAM_SEG_BE_WIDTH));
read_ram_mask_1_next = {RAM_SEG_COUNT{1'b1}} >> (RAM_SEG_COUNT-1-(end_offset_next >> $clog2(RAM_SEG_BE_WIDTH)));
if (!ram_wrap_next) begin
read_ram_mask_next = read_ram_mask_0_next & read_ram_mask_1_next;
read_ram_mask_0_next = read_ram_mask_0_next & read_ram_mask_1_next;
read_ram_mask_1_next = 0;
end else begin
read_ram_mask_next = read_ram_mask_0_next | read_ram_mask_1_next;
end
if (!read_last_cycle_reg) begin
read_state_next = READ_STATE_READ;
end else if (read_cmd_valid_reg) begin
read_axi_addr_next = read_cmd_axi_addr_reg;
read_ram_sel_next = read_cmd_ram_sel_reg;
read_ram_addr_next = read_cmd_ram_addr_reg;
read_len_next = read_cmd_len_reg;
read_cycle_count_next = read_cmd_cycle_count_reg;
read_last_cycle_next = read_cmd_last_cycle_reg;
if (read_len_next > AXI_STRB_WIDTH-(read_axi_addr_next & OFFSET_MASK)) begin
cycle_byte_count_next = AXI_STRB_WIDTH-(read_axi_addr_next & OFFSET_MASK);
end else begin
cycle_byte_count_next = read_len_next;
end
start_offset_next = read_ram_addr_next;
{ram_wrap_next, end_offset_next} = start_offset_next+cycle_byte_count_next-1;
read_ram_mask_0_next = {RAM_SEG_COUNT{1'b1}} << (start_offset_next >> $clog2(RAM_SEG_BE_WIDTH));
read_ram_mask_1_next = {RAM_SEG_COUNT{1'b1}} >> (RAM_SEG_COUNT-1-(end_offset_next >> $clog2(RAM_SEG_BE_WIDTH)));
if (!ram_wrap_next) begin
read_ram_mask_next = read_ram_mask_0_next & read_ram_mask_1_next;
read_ram_mask_0_next = read_ram_mask_0_next & read_ram_mask_1_next;
read_ram_mask_1_next = 0;
end else begin
read_ram_mask_next = read_ram_mask_0_next | read_ram_mask_1_next;
end
read_cmd_ready = 1'b1;
read_state_next = READ_STATE_READ;
end else begin
read_state_next = READ_STATE_IDLE;
end
end else begin
read_state_next = READ_STATE_READ;
end
end
endcase
end
always @* begin
axi_state_next = AXI_STATE_IDLE;
ram_rd_resp_ready_cmb = {RAM_SEG_COUNT{1'b0}};
tlp_addr_next = tlp_addr_reg;
tlp_len_next = tlp_len_reg;
offset_next = offset_reg;
strb_offset_mask_next = strb_offset_mask_reg;
last_cycle_offset_next = last_cycle_offset_reg;
ram_mask_next = ram_mask_reg;
ram_mask_valid_next = ram_mask_valid_reg;
cycle_count_next = cycle_count_reg;
last_cycle_next = last_cycle_reg;
mask_fifo_rd_ptr_next = mask_fifo_rd_ptr_reg;
op_table_tx_start_en = 1'b0;
op_table_tx_finish_en = 1'b0;
op_table_write_complete_en = 1'b0;
op_table_write_complete_ptr = m_axi_bid;
m_axi_awid_next = m_axi_awid_reg;
m_axi_awaddr_next = m_axi_awaddr_reg;
m_axi_awlen_next = m_axi_awlen_reg;
m_axi_awvalid_next = m_axi_awvalid_reg && !m_axi_awready;
m_axi_bready_next = 1'b0;
m_axi_wdata_int = 0;
m_axi_wstrb_int = 0;
m_axi_wlast_int = 1'b0;
m_axi_wvalid_int = 1'b0;
// read response processing and AXI write generation
case (axi_state_reg)
AXI_STATE_IDLE: begin
// idle state, wait for command
ram_rd_resp_ready_cmb = {RAM_SEG_COUNT{1'b0}};
tlp_addr_next = op_table_axi_addr[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
tlp_len_next = op_table_len[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
offset_next = op_table_offset[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
strb_offset_mask_next = {AXI_STRB_WIDTH{1'b1}} << (tlp_addr_next & OFFSET_MASK);
last_cycle_offset_next = tlp_addr_next + (tlp_len_next & OFFSET_MASK);
cycle_count_next = op_table_cycle_count[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
last_cycle_next = op_table_cycle_count[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]] == 0;
if (op_table_active[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]] && op_table_tx_start_ptr_reg != op_table_start_ptr_reg && (!m_axi_awvalid_reg || m_axi_awready)) begin
m_axi_awid_next = op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0];
m_axi_awaddr_next = tlp_addr_next;
m_axi_awlen_next = cycle_count_next;
m_axi_awvalid_next = 1'b1;
op_table_tx_start_en = 1'b1;
axi_state_next = AXI_STATE_TRANSFER;
end else begin
axi_state_next = AXI_STATE_IDLE;
end
end
AXI_STATE_TRANSFER: begin
// transfer state, transfer data
ram_rd_resp_ready_cmb = {RAM_SEG_COUNT{1'b0}};
if (!(ram_mask_reg & ~ram_rd_resp_valid) && ram_mask_valid_reg && m_axi_wready_int) begin
// transfer in read data
ram_rd_resp_ready_cmb = ram_mask_reg;
ram_mask_valid_next = 1'b0;
// update counters
cycle_count_next = cycle_count_reg - 1;
last_cycle_next = cycle_count_next == 0;
offset_next = offset_reg + AXI_STRB_WIDTH;
strb_offset_mask_next = {AXI_STRB_WIDTH{1'b1}};
m_axi_wdata_int = {2{ram_rd_resp_data}} >> (RAM_SEG_COUNT*RAM_SEG_DATA_WIDTH-offset_reg*AXI_WORD_SIZE);
m_axi_wstrb_int = strb_offset_mask_reg;
m_axi_wvalid_int = 1'b1;
if (last_cycle_reg) begin
// no more data to transfer, finish operation
m_axi_wlast_int = 1'b1;
op_table_tx_finish_en = 1'b1;
if (last_cycle_offset_reg) begin
m_axi_wstrb_int = strb_offset_mask_reg & {AXI_STRB_WIDTH{1'b1}} >> (AXI_STRB_WIDTH - last_cycle_offset_reg);
end
// skip idle state if possible
tlp_addr_next = op_table_axi_addr[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
tlp_len_next = op_table_len[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
offset_next = op_table_offset[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
strb_offset_mask_next = {AXI_STRB_WIDTH{1'b1}} << (tlp_addr_next & OFFSET_MASK);
last_cycle_offset_next = tlp_addr_next + (tlp_len_next & OFFSET_MASK);
cycle_count_next = op_table_cycle_count[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]];
last_cycle_next = op_table_cycle_count[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]] == 0;
if (op_table_active[op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0]] && op_table_tx_start_ptr_reg != op_table_start_ptr_reg && (!m_axi_awvalid_reg || m_axi_awready)) begin
m_axi_awid_next = op_table_tx_start_ptr_reg[OP_TAG_WIDTH-1:0];
m_axi_awaddr_next = tlp_addr_next;
m_axi_awlen_next = cycle_count_next;
m_axi_awvalid_next = 1'b1;
op_table_tx_start_en = 1'b1;
axi_state_next = AXI_STATE_TRANSFER;
end else begin
axi_state_next = AXI_STATE_IDLE;
end
end else begin
axi_state_next = AXI_STATE_TRANSFER;
end
end else begin
axi_state_next = AXI_STATE_TRANSFER;
end
end
endcase
if (!ram_mask_valid_next && !mask_fifo_empty) begin
ram_mask_next = mask_fifo_mask[mask_fifo_rd_ptr_reg[MASK_FIFO_ADDR_WIDTH-1:0]];
ram_mask_valid_next = 1'b1;
mask_fifo_rd_ptr_next = mask_fifo_rd_ptr_reg+1;
end
// accept write completions
m_axi_bready_next = 1'b1;
if (m_axi_bready && m_axi_bvalid) begin
op_table_write_complete_en = 1'b1;
op_table_write_complete_ptr = m_axi_bid;
end
// commit operations in-order
op_table_finish_en = 1'b0;
m_axis_write_desc_status_tag_next = op_table_tag[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]];
m_axis_write_desc_status_error_next = 0;
m_axis_write_desc_status_valid_next = 1'b0;
if (op_table_active[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]] && op_table_write_complete[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]] && op_table_finish_ptr_reg != op_table_tx_finish_ptr_reg) begin
op_table_finish_en = 1'b1;
if (op_table_last[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]]) begin
m_axis_write_desc_status_tag_next = op_table_tag[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]];
m_axis_write_desc_status_error_next = 0;
m_axis_write_desc_status_valid_next = 1'b1;
end
end
end
always @(posedge clk) begin
req_state_reg <= req_state_next;
read_state_reg <= read_state_next;
axi_state_reg <= axi_state_next;
axi_addr_reg <= axi_addr_next;
ram_sel_reg <= ram_sel_next;
ram_addr_reg <= ram_addr_next;
op_count_reg <= op_count_next;
tr_count_reg <= tr_count_next;
tr_word_count_reg <= tr_word_count_next;
tag_reg <= tag_next;
read_axi_addr_reg <= read_axi_addr_next;
read_ram_sel_reg <= read_ram_sel_next;
read_ram_addr_reg <= read_ram_addr_next;
read_len_reg <= read_len_next;
read_ram_mask_reg <= read_ram_mask_next;
read_ram_mask_0_reg <= read_ram_mask_0_next;
read_ram_mask_1_reg <= read_ram_mask_1_next;
ram_wrap_reg <= ram_wrap_next;
read_cycle_count_reg <= read_cycle_count_next;
read_last_cycle_reg <= read_last_cycle_next;
cycle_byte_count_reg <= cycle_byte_count_next;
start_offset_reg <= start_offset_next;
end_offset_reg <= end_offset_next;
tlp_addr_reg <= tlp_addr_next;
tlp_len_reg <= tlp_len_next;
offset_reg <= offset_next;
strb_offset_mask_reg <= strb_offset_mask_next;
last_cycle_offset_reg <= last_cycle_offset_next;
ram_mask_reg <= ram_mask_next;
ram_mask_valid_reg <= ram_mask_valid_next;
cycle_count_reg <= cycle_count_next;
last_cycle_reg <= last_cycle_next;
read_cmd_axi_addr_reg <= read_cmd_axi_addr_next;
read_cmd_ram_sel_reg <= read_cmd_ram_sel_next;
read_cmd_ram_addr_reg <= read_cmd_ram_addr_next;
read_cmd_len_reg <= read_cmd_len_next;
read_cmd_cycle_count_reg <= read_cmd_cycle_count_next;
read_cmd_last_cycle_reg <= read_cmd_last_cycle_next;
read_cmd_valid_reg <= read_cmd_valid_next;
m_axi_awid_reg <= m_axi_awid_next;
m_axi_awaddr_reg <= m_axi_awaddr_next;
m_axi_awlen_reg <= m_axi_awlen_next;
m_axi_awvalid_reg <= m_axi_awvalid_next;
m_axi_bready_reg <= m_axi_bready_next;
s_axis_write_desc_ready_reg <= s_axis_write_desc_ready_next;
m_axis_write_desc_status_tag_reg <= m_axis_write_desc_status_tag_next;
m_axis_write_desc_status_error_reg <= m_axis_write_desc_status_error_next;
m_axis_write_desc_status_valid_reg <= m_axis_write_desc_status_valid_next;
ram_rd_cmd_sel_reg <= ram_rd_cmd_sel_next;
ram_rd_cmd_addr_reg <= ram_rd_cmd_addr_next;
ram_rd_cmd_valid_reg <= ram_rd_cmd_valid_next;
if (mask_fifo_we) begin
mask_fifo_mask[mask_fifo_wr_ptr_reg[MASK_FIFO_ADDR_WIDTH-1:0]] <= mask_fifo_wr_mask;
mask_fifo_wr_ptr_reg <= mask_fifo_wr_ptr_reg + 1;
end
mask_fifo_rd_ptr_reg <= mask_fifo_rd_ptr_next;
if (op_table_start_en) begin
op_table_start_ptr_reg <= op_table_start_ptr_reg + 1;
op_table_active[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= 1'b1;
op_table_write_complete[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= 1'b0;
op_table_axi_addr[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_axi_addr;
op_table_len[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_len;
op_table_cycle_count[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_cycle_count;
op_table_offset[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_offset;
op_table_tag[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_tag;
op_table_last[op_table_start_ptr_reg[OP_TAG_WIDTH-1:0]] <= op_table_start_last;
end
if (op_table_tx_start_en) begin
op_table_tx_start_ptr_reg <= op_table_tx_start_ptr_reg + 1;
end
if (op_table_tx_finish_en) begin
op_table_tx_finish_ptr_reg <= op_table_tx_finish_ptr_reg + 1;
end
if (op_table_write_complete_en) begin
op_table_write_complete[op_table_write_complete_ptr] <= 1'b1;
end
if (op_table_finish_en) begin
op_table_finish_ptr_reg <= op_table_finish_ptr_reg + 1;
op_table_active[op_table_finish_ptr_reg[OP_TAG_WIDTH-1:0]] <= 1'b0;
end
if (rst) begin
req_state_reg <= REQ_STATE_IDLE;
read_state_reg <= READ_STATE_IDLE;
axi_state_reg <= AXI_STATE_IDLE;
read_cmd_valid_reg <= 1'b0;
ram_mask_valid_reg <= 1'b0;
m_axi_awvalid_reg <= 1'b0;
m_axi_bready_reg <= 1'b0;
s_axis_write_desc_ready_reg <= 1'b0;
m_axis_write_desc_status_valid_reg <= 1'b0;
ram_rd_cmd_valid_reg <= {RAM_SEG_COUNT{1'b0}};
mask_fifo_wr_ptr_reg <= 0;
mask_fifo_rd_ptr_reg <= 0;
op_table_start_ptr_reg <= 0;
op_table_tx_start_ptr_reg <= 0;
op_table_tx_finish_ptr_reg <= 0;
op_table_finish_ptr_reg <= 0;
op_table_active <= 0;
end
end
// output datapath logic
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg m_axi_wvalid_reg = 1'b0;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_wr_ptr_reg = 0;
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_rd_ptr_reg = 0;
reg out_fifo_half_full_reg = 1'b0;
wire out_fifo_full = out_fifo_wr_ptr_reg == (out_fifo_rd_ptr_reg ^ {1'b1, {OUTPUT_FIFO_ADDR_WIDTH{1'b0}}});
wire out_fifo_empty = out_fifo_wr_ptr_reg == out_fifo_rd_ptr_reg;
(* ram_style = "distributed" *)
reg [AXI_DATA_WIDTH-1:0] out_fifo_wdata[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg [AXI_STRB_WIDTH-1:0] out_fifo_wstrb[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
(* ram_style = "distributed" *)
reg out_fifo_wlast[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
assign m_axi_wready_int = !out_fifo_half_full_reg;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wvalid = m_axi_wvalid_reg;
assign m_axi_wlast = m_axi_wlast_reg;
always @(posedge clk) begin
m_axi_wvalid_reg <= m_axi_wvalid_reg && !m_axi_wready;
out_fifo_half_full_reg <= $unsigned(out_fifo_wr_ptr_reg - out_fifo_rd_ptr_reg) >= 2**(OUTPUT_FIFO_ADDR_WIDTH-1);
if (!out_fifo_full && m_axi_wvalid_int) begin
out_fifo_wdata[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wdata_int;
out_fifo_wstrb[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wstrb_int;
out_fifo_wlast[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axi_wlast_int;
out_fifo_wr_ptr_reg <= out_fifo_wr_ptr_reg + 1;
end
if (!out_fifo_empty && (!m_axi_wvalid_reg || m_axi_wready)) begin
m_axi_wdata_reg <= out_fifo_wdata[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wstrb_reg <= out_fifo_wstrb[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wlast_reg <= out_fifo_wlast[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
m_axi_wvalid_reg <= 1'b1;
out_fifo_rd_ptr_reg <= out_fifo_rd_ptr_reg + 1;
end
if (rst) begin
out_fifo_wr_ptr_reg <= 0;
out_fifo_rd_ptr_reg <= 0;
m_axi_wvalid_reg <= 1'b0;
end
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA interface descriptor mux
@ -299,3 +301,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA interface mux
@ -334,3 +336,5 @@ dma_if_mux_wr_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA interface mux (read)
@ -216,3 +218,5 @@ dma_ram_demux_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA interface mux (write)
@ -215,3 +217,5 @@ dma_ram_demux_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* PCIe DMA interface
@ -476,3 +478,5 @@ dma_if_pcie_wr_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* PCIe DMA read interface
@ -1606,3 +1608,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Ultrascale PCIe DMA interface
@ -406,3 +408,5 @@ dma_if_pcie_us_wr_inst (
);
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Ultrascale PCIe DMA read interface
@ -1827,3 +1829,5 @@ end
endgenerate
endmodule
`resetall

View File

@ -24,7 +24,9 @@ THE SOFTWARE.
// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* Ultrascale PCIe DMA write interface
@ -1390,3 +1392,5 @@ always @(posedge clk) begin
end
endmodule
`resetall

Some files were not shown because too many files have changed in this diff Show More