Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/AI_Brain / the_tired_agi/core/src/fpga_memory_bus.v |
| Date | Not specified in source |
| Repository | Janady13/AI_Brain |
| Revision | d6c309d3fa439714ca46b9d3bb94caf478ea5376 |
| Branch | main |
| Path or archive member | the_tired_agi/core/src/fpga_memory_bus.v |
| Original SHA-256 | 2eca66be66339aba7be98a31d1b5ae0949c4bfc44feafe0df97d1d074070ca9f |
| Git blob SHA | 51d531d6d114b96742291ead5d9c53a5d9d488d9 |
| Reading-copy SHA-256 | 2eca66be66339aba7be98a31d1b5ae0949c4bfc44feafe0df97d1d074070ca9f |
Every recorded occurrence
These 2 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/AI_Brain / the_tired_agi/core/src/fpga_memory_bus.v | main | d6c309d3fa439714ca46b9d3bb94caf478ea5376 | Open original |
| Janady13/AI_Brain / the_tired_agi/core/src/fpga_memory_bus.v | claude/binary-helix-fibonacci-hive-011CUj7dx1WWJLVYcWCjBbYv | 527d4882c71eb041393f9d8945996177c5ac9e86 | Open original |
Recovered source transcript
Download complete source text ↓520 lines · 19.5 KB
//=============================================================================
// FPGA Memory Bus - Production Implementation
// 256-bit wide memory interface with DMA support
// Target: PCIe Gen3 x4 (4 GB/s), DDR3/DDR4 controller integration
// Synthesizable for Lattice ECP5 / Xilinx Artix-7
//=============================================================================
`timescale 1ns / 1ps
module fpga_memory_bus #(
parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 256,
parameter ID_WIDTH = 4,
parameter NUM_CHANNELS = 4,
parameter FIFO_DEPTH = 512
)(
input wire clk,
input wire rst_n,
//=========================================================================
// AXI4-Style Memory Interface (to DDR controller)
//=========================================================================
// Write Address Channel
output reg [ID_WIDTH-1:0] m_axi_awid,
output reg [ADDR_WIDTH-1:0] m_axi_awaddr,
output reg [7:0] m_axi_awlen, // Burst length - 1
output reg [2:0] m_axi_awsize, // Burst size
output reg [1:0] m_axi_awburst, // Burst type
output reg m_axi_awvalid,
input wire m_axi_awready,
// Write Data Channel
output reg [DATA_WIDTH-1:0] m_axi_wdata,
output reg [DATA_WIDTH/8-1:0] m_axi_wstrb,
output reg m_axi_wlast,
output reg m_axi_wvalid,
input wire m_axi_wready,
// Write Response Channel
input wire [ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output reg m_axi_bready,
// Read Address Channel
output reg [ID_WIDTH-1:0] m_axi_arid,
output reg [ADDR_WIDTH-1:0] m_axi_araddr,
output reg [7:0] m_axi_arlen,
output reg [2:0] m_axi_arsize,
output reg [1:0] m_axi_arburst,
output reg m_axi_arvalid,
input wire m_axi_arready,
// Read Data Channel
input wire [ID_WIDTH-1:0] m_axi_rid,
input wire [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 reg m_axi_rready,
//=========================================================================
// DMA Descriptor Interface (from PCIe)
//=========================================================================
input wire [63:0] dma_desc_addr, // Source/dest address
input wire [31:0] dma_desc_len, // Transfer length (bytes)
input wire [3:0] dma_desc_channel, // Channel ID
input wire dma_desc_dir, // 0=read, 1=write
input wire dma_desc_valid,
output reg dma_desc_ready,
//=========================================================================
// Channel Stream Interfaces (to ingest lanes)
//=========================================================================
// Channel Write (from lanes to memory)
input wire [NUM_CHANNELS-1:0][DATA_WIDTH-1:0] ch_wr_data,
input wire [NUM_CHANNELS-1:0][DATA_WIDTH/8-1:0] ch_wr_strb,
input wire [NUM_CHANNELS-1:0] ch_wr_valid,
output wire [NUM_CHANNELS-1:0] ch_wr_ready,
// Channel Read (from memory to CPU)
output wire [NUM_CHANNELS-1:0][DATA_WIDTH-1:0] ch_rd_data,
output wire [NUM_CHANNELS-1:0] ch_rd_valid,
input wire [NUM_CHANNELS-1:0] ch_rd_ready,
//=========================================================================
// Status and Control
//=========================================================================
output reg [31:0] status_bytes_written [0:NUM_CHANNELS-1],
output reg [31:0] status_bytes_read [0:NUM_CHANNELS-1],
output reg [NUM_CHANNELS-1:0] status_ch_busy,
output reg [15:0] status_errors,
input wire [NUM_CHANNELS-1:0] ctrl_ch_enable,
input wire ctrl_reset_counters
);
//=========================================================================
// Internal State
//=========================================================================
localparam ST_IDLE = 3'd0;
localparam ST_DESC_PARSE = 3'd1;
localparam ST_ADDR_WRITE = 3'd2;
localparam ST_DATA_WRITE = 3'd3;
localparam ST_ADDR_READ = 3'd4;
localparam ST_DATA_READ = 3'd5;
localparam ST_WAIT_RESP = 3'd6;
reg [2:0] state [0:NUM_CHANNELS-1];
reg [2:0] next_state [0:NUM_CHANNELS-1];
// DMA Descriptor Queue (per channel)
reg [63:0] desc_addr [0:NUM_CHANNELS-1];
reg [31:0] desc_len [0:NUM_CHANNELS-1];
reg desc_dir [0:NUM_CHANNELS-1];
reg desc_valid_internal [0:NUM_CHANNELS-1];
// Transfer State
reg [ADDR_WIDTH-1:0] current_addr [0:NUM_CHANNELS-1];
reg [31:0] bytes_remaining [0:NUM_CHANNELS-1];
reg [7:0] burst_count [0:NUM_CHANNELS-1];
// FIFOs for buffering
wire [NUM_CHANNELS-1:0] wr_fifo_full;
wire [NUM_CHANNELS-1:0] wr_fifo_empty;
wire [NUM_CHANNELS-1:0] rd_fifo_full;
wire [NUM_CHANNELS-1:0] rd_fifo_empty;
reg [NUM_CHANNELS-1:0] wr_fifo_wr_en;
reg [NUM_CHANNELS-1:0] wr_fifo_rd_en;
reg [NUM_CHANNELS-1:0] rd_fifo_wr_en;
reg [NUM_CHANNELS-1:0] rd_fifo_rd_en;
wire [DATA_WIDTH-1:0] wr_fifo_dout [0:NUM_CHANNELS-1];
wire [DATA_WIDTH-1:0] rd_fifo_dout [0:NUM_CHANNELS-1];
// Arbitration
reg [ID_WIDTH-1:0] arb_grant;
reg arb_valid;
//=========================================================================
// DMA Descriptor Parsing
//=========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dma_desc_ready <= 1'b1;
end else begin
if (dma_desc_valid && dma_desc_ready) begin
if (dma_desc_channel < NUM_CHANNELS && ctrl_ch_enable[dma_desc_channel]) begin
desc_addr[dma_desc_channel] <= dma_desc_addr;
desc_len[dma_desc_channel] <= dma_desc_len;
desc_dir[dma_desc_channel] <= dma_desc_dir;
desc_valid_internal[dma_desc_channel] <= 1'b1;
end
end
end
end
//=========================================================================
// Per-Channel State Machines
//=========================================================================
genvar ch;
generate
for (ch = 0; ch < NUM_CHANNELS; ch = ch + 1) begin : channel_sm
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state[ch] <= ST_IDLE;
current_addr[ch] <= {ADDR_WIDTH{1'b0}};
bytes_remaining[ch] <= 32'd0;
burst_count[ch] <= 8'd0;
status_bytes_written[ch] <= 32'd0;
status_bytes_read[ch] <= 32'd0;
status_ch_busy[ch] <= 1'b0;
end else begin
state[ch] <= next_state[ch];
case (state[ch])
ST_IDLE: begin
status_ch_busy[ch] <= 1'b0;
if (desc_valid_internal[ch] && ctrl_ch_enable[ch]) begin
current_addr[ch] <= desc_addr[ch][ADDR_WIDTH-1:0];
bytes_remaining[ch] <= desc_len[ch];
status_ch_busy[ch] <= 1'b1;
end
end
ST_DESC_PARSE: begin
// Calculate burst parameters
// Max burst: 256 beats (AXI4)
if (bytes_remaining[ch] >= (DATA_WIDTH/8 * 256)) begin
burst_count[ch] <= 8'd255; // 256 beats - 1
end else begin
burst_count[ch] <= (bytes_remaining[ch] / (DATA_WIDTH/8)) - 1;
end
end
ST_ADDR_WRITE: begin
if (m_axi_awready && arb_grant == ch && arb_valid) begin
bytes_remaining[ch] <= bytes_remaining[ch] - ((burst_count[ch] + 1) * (DATA_WIDTH/8));
current_addr[ch] <= current_addr[ch] + ((burst_count[ch] + 1) * (DATA_WIDTH/8));
end
end
ST_DATA_WRITE: begin
if (m_axi_wready && m_axi_wlast) begin
status_bytes_written[ch] <= status_bytes_written[ch] + ((burst_count[ch] + 1) * (DATA_WIDTH/8));
end
end
ST_ADDR_READ: begin
if (m_axi_arready && arb_grant == ch && arb_valid) begin
bytes_remaining[ch] <= bytes_remaining[ch] - ((burst_count[ch] + 1) * (DATA_WIDTH/8));
current_addr[ch] <= current_addr[ch] + ((burst_count[ch] + 1) * (DATA_WIDTH/8));
end
end
ST_DATA_READ: begin
if (m_axi_rvalid && m_axi_rlast) begin
status_bytes_read[ch] <= status_bytes_read[ch] + ((burst_count[ch] + 1) * (DATA_WIDTH/8));
end
end
endcase
// Reset counters
if (ctrl_reset_counters) begin
status_bytes_written[ch] <= 32'd0;
status_bytes_read[ch] <= 32'd0;
end
end
end
// Next state logic
always @(*) begin
next_state[ch] = state[ch];
case (state[ch])
ST_IDLE: begin
if (desc_valid_internal[ch] && ctrl_ch_enable[ch]) begin
next_state[ch] = ST_DESC_PARSE;
end
end
ST_DESC_PARSE: begin
if (desc_dir[ch]) begin
next_state[ch] = ST_ADDR_WRITE;
end else begin
next_state[ch] = ST_ADDR_READ;
end
end
ST_ADDR_WRITE: begin
if (m_axi_awready && arb_grant == ch) begin
next_state[ch] = ST_DATA_WRITE;
end
end
ST_DATA_WRITE: begin
if (m_axi_wlast && m_axi_wready) begin
next_state[ch] = ST_WAIT_RESP;
end
end
ST_ADDR_READ: begin
if (m_axi_arready && arb_grant == ch) begin
next_state[ch] = ST_DATA_READ;
end
end
ST_DATA_READ: begin
if (m_axi_rlast && m_axi_rvalid) begin
if (bytes_remaining[ch] > 0) begin
next_state[ch] = ST_DESC_PARSE;
end else begin
next_state[ch] = ST_IDLE;
end
end
end
ST_WAIT_RESP: begin
if (m_axi_bvalid) begin
if (bytes_remaining[ch] > 0) begin
next_state[ch] = ST_DESC_PARSE;
end else begin
next_state[ch] = ST_IDLE;
end
end
end
endcase
end
end
endgenerate
//=========================================================================
// Round-Robin Arbiter for Memory Access
//=========================================================================
reg [ID_WIDTH-1:0] arb_last_grant;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
arb_grant <= {ID_WIDTH{1'b0}};
arb_valid <= 1'b0;
arb_last_grant <= {ID_WIDTH{1'b0}};
end else begin
arb_valid <= 1'b0;
// Find next requester (round-robin)
for (integer i = 0; i < NUM_CHANNELS; i = i + 1) begin
integer idx = (arb_last_grant + i + 1) % NUM_CHANNELS;
if (status_ch_busy[idx] &&
(state[idx] == ST_ADDR_WRITE || state[idx] == ST_ADDR_READ)) begin
arb_grant <= idx[ID_WIDTH-1:0];
arb_valid <= 1'b1;
arb_last_grant <= idx[ID_WIDTH-1:0];
break;
end
end
end
end
//=========================================================================
// AXI Master Write Address
//=========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axi_awvalid <= 1'b0;
end else begin
if (arb_valid && state[arb_grant] == ST_ADDR_WRITE) begin
m_axi_awid <= arb_grant;
m_axi_awaddr <= current_addr[arb_grant];
m_axi_awlen <= burst_count[arb_grant];
m_axi_awsize <= $clog2(DATA_WIDTH/8); // Size = log2(bytes per beat)
m_axi_awburst <= 2'b01; // INCR burst
m_axi_awvalid <= 1'b1;
end else if (m_axi_awready) begin
m_axi_awvalid <= 1'b0;
end
end
end
//=========================================================================
// AXI Master Write Data
//=========================================================================
reg [7:0] wr_beat_count;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axi_wvalid <= 1'b0;
m_axi_wlast <= 1'b0;
wr_beat_count <= 8'd0;
end else begin
if (state[arb_grant] == ST_DATA_WRITE && !wr_fifo_empty[arb_grant]) begin
m_axi_wdata <= wr_fifo_dout[arb_grant];
m_axi_wstrb <= {(DATA_WIDTH/8){1'b1}};
m_axi_wvalid <= 1'b1;
m_axi_wlast <= (wr_beat_count == burst_count[arb_grant]);
if (m_axi_wready) begin
wr_beat_count <= wr_beat_count + 1'b1;
if (m_axi_wlast) begin
wr_beat_count <= 8'd0;
end
end
end else begin
m_axi_wvalid <= 1'b0;
m_axi_wlast <= 1'b0;
end
end
end
//=========================================================================
// AXI Master Read Address
//=========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axi_arvalid <= 1'b0;
end else begin
if (arb_valid && state[arb_grant] == ST_ADDR_READ) begin
m_axi_arid <= arb_grant;
m_axi_araddr <= current_addr[arb_grant];
m_axi_arlen <= burst_count[arb_grant];
m_axi_arsize <= $clog2(DATA_WIDTH/8);
m_axi_arburst <= 2'b01; // INCR burst
m_axi_arvalid <= 1'b1;
end else if (m_axi_arready) begin
m_axi_arvalid <= 1'b0;
end
end
end
//=========================================================================
// AXI Master Read Data
//=========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axi_rready <= 1'b1;
end else begin
// Always ready to receive (buffered in FIFOs)
m_axi_rready <= !rd_fifo_full[m_axi_rid];
end
end
//=========================================================================
// Write Response Handling
//=========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
m_axi_bready <= 1'b1;
status_errors <= 16'd0;
end else begin
if (m_axi_bvalid) begin
if (m_axi_bresp != 2'b00) begin // OKAY response = 2'b00
status_errors <= status_errors + 1'b1;
end
end
end
end
//=========================================================================
// Channel FIFOs (for data buffering)
//=========================================================================
generate
for (ch = 0; ch < NUM_CHANNELS; ch = ch + 1) begin : channel_fifos
// Write FIFO (from ingest lanes to memory)
sync_fifo #(
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(FIFO_DEPTH)
) wr_fifo_inst (
.clk(clk),
.rst_n(rst_n),
.wr_en(ch_wr_valid[ch] && ch_wr_ready[ch]),
.din(ch_wr_data[ch]),
.full(wr_fifo_full[ch]),
.rd_en(wr_fifo_rd_en[ch]),
.dout(wr_fifo_dout[ch]),
.empty(wr_fifo_empty[ch])
);
assign ch_wr_ready[ch] = !wr_fifo_full[ch];
assign wr_fifo_rd_en[ch] = (state[ch] == ST_DATA_WRITE) && m_axi_wready && !wr_fifo_empty[ch];
// Read FIFO (from memory to CPU)
sync_fifo #(
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(FIFO_DEPTH)
) rd_fifo_inst (
.clk(clk),
.rst_n(rst_n),
.wr_en(m_axi_rvalid && m_axi_rid == ch && !rd_fifo_full[ch]),
.din(m_axi_rdata),
.full(rd_fifo_full[ch]),
.rd_en(ch_rd_ready[ch] && !rd_fifo_empty[ch]),
.dout(rd_fifo_dout[ch]),
.empty(rd_fifo_empty[ch])
);
assign ch_rd_data[ch] = rd_fifo_dout[ch];
assign ch_rd_valid[ch] = !rd_fifo_empty[ch];
end
endgenerate
endmodule
//=============================================================================
// Synchronous FIFO (parameterized)
//=============================================================================
module sync_fifo #(
parameter DATA_WIDTH = 256,
parameter DEPTH = 512,
parameter ADDR_WIDTH = $clog2(DEPTH)
)(
input wire clk,
input wire rst_n,
input wire wr_en,
input wire [DATA_WIDTH-1:0] din,
output reg full,
input wire rd_en,
output reg [DATA_WIDTH-1:0] dout,
output reg empty
);
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
reg [ADDR_WIDTH:0] wr_ptr; // Extra bit for full/empty detection
reg [ADDR_WIDTH:0] rd_ptr;
wire [ADDR_WIDTH:0] next_wr_ptr = wr_ptr + 1'b1;
wire [ADDR_WIDTH:0] next_rd_ptr = rd_ptr + 1'b1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= {(ADDR_WIDTH+1){1'b0}};
rd_ptr <= {(ADDR_WIDTH+1){1'b0}};
full <= 1'b0;
empty <= 1'b1;
end else begin
// Write
if (wr_en && !full) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= din;
wr_ptr <= next_wr_ptr;
end
// Read
if (rd_en && !empty) begin
dout <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= next_rd_ptr;
end
// Update flags
full <= (next_wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
(next_wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]);
empty <= (wr_ptr == rd_ptr);
end
end
endmodule