Vortex 2.0 changes:

+ Microarchitecture optimizations
+ 64-bit support
+ Xilinx FPGA support
+ LLVM-16 support
+ Refactoring and quality control fixes
This commit is contained in:
Blaise Tine
2023-10-19 20:51:22 -07:00
parent d69a64c32c
commit d47cccc157
1300 changed files with 247321 additions and 311189 deletions

View File

@@ -0,0 +1,87 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_allocator #(
parameter SIZE = 1,
parameter ADDRW = `LOG2UP(SIZE)
) (
input wire clk,
input wire reset,
input wire acquire_en,
output wire [ADDRW-1:0] acquire_addr,
input wire release_en,
input wire [ADDRW-1:0] release_addr,
output wire empty,
output wire full
);
reg [SIZE-1:0] free_slots, free_slots_n;
reg [ADDRW-1:0] acquire_addr_r;
reg empty_r, full_r;
wire [ADDRW-1:0] free_index;
wire free_valid;
always @(*) begin
free_slots_n = free_slots;
if (release_en) begin
free_slots_n[release_addr] = 1;
end
if (acquire_en) begin
free_slots_n[acquire_addr_r] = 0;
end
end
VX_lzc #(
.N (SIZE),
.REVERSE (1)
) free_slots_sel (
.data_in (free_slots_n),
.data_out (free_index),
.valid_out (free_valid)
);
always @(posedge clk) begin
if (reset) begin
acquire_addr_r <= ADDRW'(1'b0);
free_slots <= {SIZE{1'b1}};
empty_r <= 1'b1;
full_r <= 1'b0;
end else begin
if (release_en) begin
`ASSERT(0 == free_slots[release_addr], ("%t: releasing invalid addr %d", $time, release_addr));
end
if (acquire_en) begin
`ASSERT(~full_r, ("%t: allocator is full", $time));
end
if (acquire_en || (release_en && full_r)) begin
acquire_addr_r <= free_index;
end
free_slots <= free_slots_n;
empty_r <= (& free_slots_n);
full_r <= ~free_valid;
end
end
assign acquire_addr = acquire_addr_r;
assign empty = empty_r;
assign full = full_r;
endmodule
`TRACING_ON

View File

@@ -0,0 +1,211 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_define.vh"
`TRACING_OFF
module VX_avs_adapter #(
parameter DATA_WIDTH = 1,
parameter ADDR_WIDTH = 1,
parameter BURST_WIDTH = 1,
parameter NUM_BANKS = 1,
parameter TAG_WIDTH = 1,
parameter RD_QUEUE_SIZE = 1,
parameter OUT_REG_REQ = 0,
parameter OUT_REG_RSP = 0
) (
input wire clk,
input wire reset,
// Memory request
input wire mem_req_valid,
input wire mem_req_rw,
input wire [DATA_WIDTH/8-1:0] mem_req_byteen,
input wire [ADDR_WIDTH-1:0] mem_req_addr,
input wire [DATA_WIDTH-1:0] mem_req_data,
input wire [TAG_WIDTH-1:0] mem_req_tag,
output wire mem_req_ready,
// Memory response
output wire mem_rsp_valid,
output wire [DATA_WIDTH-1:0] mem_rsp_data,
output wire [TAG_WIDTH-1:0] mem_rsp_tag,
input wire mem_rsp_ready,
// AVS bus
output wire [DATA_WIDTH-1:0] avs_writedata [NUM_BANKS],
input wire [DATA_WIDTH-1:0] avs_readdata [NUM_BANKS],
output wire [ADDR_WIDTH-1:0] avs_address [NUM_BANKS],
input wire avs_waitrequest [NUM_BANKS],
output wire avs_write [NUM_BANKS],
output wire avs_read [NUM_BANKS],
output wire [DATA_WIDTH/8-1:0] avs_byteenable [NUM_BANKS],
output wire [BURST_WIDTH-1:0] avs_burstcount [NUM_BANKS],
input wire avs_readdatavalid [NUM_BANKS]
);
localparam DATA_SIZE = DATA_WIDTH/8;
localparam RD_QUEUE_ADDR_WIDTH = `CLOG2(RD_QUEUE_SIZE+1);
localparam BANK_ADDRW = `LOG2UP(NUM_BANKS);
localparam LOG2_NUM_BANKS = `CLOG2(NUM_BANKS);
localparam BANK_OFFSETW = ADDR_WIDTH - LOG2_NUM_BANKS;
// Requests handling //////////////////////////////////////////////////////
wire [NUM_BANKS-1:0] req_queue_push, req_queue_pop;
wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] req_queue_tag_out;
wire [NUM_BANKS-1:0] req_queue_going_full;
wire [NUM_BANKS-1:0][RD_QUEUE_ADDR_WIDTH-1:0] req_queue_size;
wire [BANK_ADDRW-1:0] req_bank_sel;
wire [BANK_OFFSETW-1:0] req_bank_off;
wire [NUM_BANKS-1:0] bank_req_ready;
if (NUM_BANKS > 1) begin
assign req_bank_sel = mem_req_addr[BANK_ADDRW-1:0];
end else begin
assign req_bank_sel = '0;
end
assign req_bank_off = mem_req_addr[ADDR_WIDTH-1:LOG2_NUM_BANKS];
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign req_queue_push[i] = mem_req_valid && ~mem_req_rw && bank_req_ready[i] && (req_bank_sel == i);
end
for (genvar i = 0; i < NUM_BANKS; ++i) begin
VX_pending_size #(
.SIZE (RD_QUEUE_SIZE)
) pending_size (
.clk (clk),
.reset (reset),
.incr (req_queue_push[i]),
.decr (req_queue_pop[i]),
.full (req_queue_going_full[i]),
.size (req_queue_size[i]),
`UNUSED_PIN (empty)
);
`UNUSED_VAR (req_queue_size)
VX_fifo_queue #(
.DATAW (TAG_WIDTH),
.DEPTH (RD_QUEUE_SIZE)
) rd_req_queue (
.clk (clk),
.reset (reset),
.push (req_queue_push[i]),
.pop (req_queue_pop[i]),
.data_in (mem_req_tag),
.data_out (req_queue_tag_out[i]),
`UNUSED_PIN (empty),
`UNUSED_PIN (full),
`UNUSED_PIN (alm_empty),
`UNUSED_PIN (alm_full),
`UNUSED_PIN (size)
);
end
for (genvar i = 0; i < NUM_BANKS; ++i) begin
wire valid_out;
wire rw_out;
wire [DATA_SIZE-1:0] byteen_out;
wire [BANK_OFFSETW-1:0] addr_out;
wire [DATA_WIDTH-1:0] data_out;
wire ready_out;
wire valid_out_w = mem_req_valid && ~req_queue_going_full[i] && (req_bank_sel == i);
wire ready_out_w;
VX_elastic_buffer #(
.DATAW (1 + DATA_SIZE + BANK_OFFSETW + DATA_WIDTH),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG_REQ)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG_REQ))
) req_out_buf (
.clk (clk),
.reset (reset),
.valid_in (valid_out_w),
.ready_in (ready_out_w),
.data_in ({mem_req_rw, mem_req_byteen, req_bank_off, mem_req_data}),
.data_out ({rw_out, byteen_out, addr_out, data_out}),
.valid_out (valid_out),
.ready_out (ready_out)
);
assign avs_read[i] = valid_out && ~rw_out;
assign avs_write[i] = valid_out && rw_out;
assign avs_address[i] = ADDR_WIDTH'(addr_out);
assign avs_byteenable[i] = byteen_out;
assign avs_writedata[i] = data_out;
assign avs_burstcount[i] = BURST_WIDTH'(1);
assign ready_out = ~avs_waitrequest[i];
assign bank_req_ready[i] = ready_out_w && ~req_queue_going_full[i];
end
if (NUM_BANKS > 1) begin
assign mem_req_ready = bank_req_ready[req_bank_sel];
end else begin
assign mem_req_ready = bank_req_ready;
end
// Responses handling /////////////////////////////////////////////////////
wire [NUM_BANKS-1:0] rsp_arb_valid_in;
wire [NUM_BANKS-1:0][DATA_WIDTH+TAG_WIDTH-1:0] rsp_arb_data_in;
wire [NUM_BANKS-1:0] rsp_arb_ready_in;
wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] rsp_queue_data_out;
wire [NUM_BANKS-1:0] rsp_queue_empty;
for (genvar i = 0; i < NUM_BANKS; ++i) begin
VX_fifo_queue #(
.DATAW (DATA_WIDTH),
.DEPTH (RD_QUEUE_SIZE)
) rd_rsp_queue (
.clk (clk),
.reset (reset),
.push (avs_readdatavalid[i]),
.pop (req_queue_pop[i]),
.data_in (avs_readdata[i]),
.data_out (rsp_queue_data_out[i]),
.empty (rsp_queue_empty[i]),
`UNUSED_PIN (full),
`UNUSED_PIN (alm_empty),
`UNUSED_PIN (alm_full),
`UNUSED_PIN (size)
);
end
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign rsp_arb_valid_in[i] = !rsp_queue_empty[i];
assign rsp_arb_data_in[i] = {rsp_queue_data_out[i], req_queue_tag_out[i]};
assign req_queue_pop[i] = rsp_arb_valid_in[i] && rsp_arb_ready_in[i];
end
VX_stream_arb #(
.NUM_INPUTS (NUM_BANKS),
.DATAW (DATA_WIDTH + TAG_WIDTH),
.ARBITER ("R"),
.OUT_REG (OUT_REG_RSP)
) rsp_arb (
.clk (clk),
.reset (reset),
.valid_in (rsp_arb_valid_in),
.data_in (rsp_arb_data_in),
.ready_in (rsp_arb_ready_in),
.data_out ({mem_rsp_data, mem_rsp_tag}),
.valid_out (mem_rsp_valid),
.ready_out (mem_rsp_ready),
`UNUSED_PIN (sel_out)
);
endmodule
`TRACING_ON

View File

@@ -1,154 +1,225 @@
`include "VX_define.vh"
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_axi_adapter #(
parameter VX_DATA_WIDTH = 512,
parameter VX_ADDR_WIDTH = (32 - $clog2(VX_DATA_WIDTH/8)),
parameter VX_TAG_WIDTH = 8,
parameter AXI_DATA_WIDTH = VX_DATA_WIDTH,
parameter AXI_ADDR_WIDTH = 32,
parameter AXI_TID_WIDTH = VX_TAG_WIDTH,
parameter VX_BYTEEN_WIDTH = (VX_DATA_WIDTH / 8),
parameter AXI_STROBE_WIDTH = (AXI_DATA_WIDTH / 8)
parameter DATA_WIDTH = 512,
parameter ADDR_WIDTH = 32,
parameter TAG_WIDTH = 8,
parameter NUM_BANKS = 1,
parameter AVS_ADDR_WIDTH = (ADDR_WIDTH - `CLOG2(DATA_WIDTH/8)),
parameter OUT_REG_RSP = 0
) (
input wire clk,
input wire reset,
input wire clk,
input wire reset,
// Vortex request
input wire mem_req_valid,
input wire mem_req_rw,
input wire [VX_BYTEEN_WIDTH-1:0] mem_req_byteen,
input wire [VX_ADDR_WIDTH-1:0] mem_req_addr,
input wire [VX_DATA_WIDTH-1:0] mem_req_data,
input wire [VX_TAG_WIDTH-1:0] mem_req_tag,
input wire mem_req_valid,
input wire mem_req_rw,
input wire [DATA_WIDTH/8-1:0] mem_req_byteen,
input wire [AVS_ADDR_WIDTH-1:0] mem_req_addr,
input wire [DATA_WIDTH-1:0] mem_req_data,
input wire [TAG_WIDTH-1:0] mem_req_tag,
output wire mem_req_ready,
// Vortex response
input wire mem_rsp_ready,
output wire mem_rsp_valid,
output wire [VX_DATA_WIDTH-1:0] mem_rsp_data,
output wire [VX_TAG_WIDTH-1:0] mem_rsp_tag,
output wire mem_req_ready,
// Vortex response
output wire mem_rsp_valid,
output wire [DATA_WIDTH-1:0] mem_rsp_data,
output wire [TAG_WIDTH-1:0] mem_rsp_tag,
input wire mem_rsp_ready,
// AXI write request address channel
output wire [AXI_TID_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 [3:0] m_axi_awqos,
output wire m_axi_awvalid,
input wire m_axi_awready,
// AXI write request address channel
output wire m_axi_awvalid [NUM_BANKS],
input wire m_axi_awready [NUM_BANKS],
output wire [ADDR_WIDTH-1:0] m_axi_awaddr [NUM_BANKS],
output wire [TAG_WIDTH-1:0] m_axi_awid [NUM_BANKS],
output wire [7:0] m_axi_awlen [NUM_BANKS],
output wire [2:0] m_axi_awsize [NUM_BANKS],
output wire [1:0] m_axi_awburst [NUM_BANKS],
output wire [1:0] m_axi_awlock [NUM_BANKS],
output wire [3:0] m_axi_awcache [NUM_BANKS],
output wire [2:0] m_axi_awprot [NUM_BANKS],
output wire [3:0] m_axi_awqos [NUM_BANKS],
output wire [3:0] m_axi_awregion [NUM_BANKS],
// AXI write request data channel
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STROBE_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
// AXI write request data channel
output wire m_axi_wvalid [NUM_BANKS],
input wire m_axi_wready [NUM_BANKS],
output wire [DATA_WIDTH-1:0] m_axi_wdata [NUM_BANKS],
output wire [DATA_WIDTH/8-1:0] m_axi_wstrb [NUM_BANKS],
output wire m_axi_wlast [NUM_BANKS],
// AXI write response channel
input wire [AXI_TID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
input wire m_axi_bvalid [NUM_BANKS],
output wire m_axi_bready [NUM_BANKS],
input wire [TAG_WIDTH-1:0] m_axi_bid [NUM_BANKS],
input wire [1:0] m_axi_bresp [NUM_BANKS],
// AXI read address channel
output wire [AXI_TID_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 [3:0] m_axi_arqos,
output wire m_axi_arvalid,
input wire m_axi_arready,
output wire m_axi_arvalid [NUM_BANKS],
input wire m_axi_arready [NUM_BANKS],
output wire [ADDR_WIDTH-1:0] m_axi_araddr [NUM_BANKS],
output wire [TAG_WIDTH-1:0] m_axi_arid [NUM_BANKS],
output wire [7:0] m_axi_arlen [NUM_BANKS],
output wire [2:0] m_axi_arsize [NUM_BANKS],
output wire [1:0] m_axi_arburst [NUM_BANKS],
output wire [1:0] m_axi_arlock [NUM_BANKS],
output wire [3:0] m_axi_arcache [NUM_BANKS],
output wire [2:0] m_axi_arprot [NUM_BANKS],
output wire [3:0] m_axi_arqos [NUM_BANKS],
output wire [3:0] m_axi_arregion [NUM_BANKS],
// AXI read response channel
input wire [AXI_TID_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
);
localparam AXSIZE = $clog2(VX_DATA_WIDTH/8);
input wire m_axi_rvalid [NUM_BANKS],
output wire m_axi_rready [NUM_BANKS],
input wire [DATA_WIDTH-1:0] m_axi_rdata [NUM_BANKS],
input wire m_axi_rlast [NUM_BANKS],
input wire [TAG_WIDTH-1:0] m_axi_rid [NUM_BANKS],
input wire [1:0] m_axi_rresp [NUM_BANKS]
);
localparam AXSIZE = `CLOG2(DATA_WIDTH/8);
localparam BANK_ADDRW = `LOG2UP(NUM_BANKS);
localparam LOG2_NUM_BANKS = `CLOG2(NUM_BANKS);
`STATIC_ASSERT((AXI_DATA_WIDTH == VX_DATA_WIDTH), ("invalid parameter"))
`STATIC_ASSERT((AXI_TID_WIDTH == VX_TAG_WIDTH), ("invalid parameter"))
wire [BANK_ADDRW-1:0] req_bank_sel;
//`UNUSED_VAR ()
reg awvalid_ack;
reg wvalid_ack;
if (NUM_BANKS > 1) begin
assign req_bank_sel = mem_req_addr[BANK_ADDRW-1:0];
end else begin
assign req_bank_sel = '0;
end
wire mem_req_fire = mem_req_valid && mem_req_ready;
always @(posedge clk) begin
if (reset) begin
awvalid_ack <= 0;
wvalid_ack <= 0;
end else begin
if (mem_req_fire) begin
awvalid_ack <= 0;
wvalid_ack <= 0;
end else begin
awvalid_ack <= m_axi_awvalid && m_axi_awready;
wvalid_ack <= m_axi_wvalid && m_axi_wready;
reg [NUM_BANKS-1:0] m_axi_aw_ack;
reg [NUM_BANKS-1:0] m_axi_w_ack;
for (genvar i = 0; i < NUM_BANKS; ++i) begin
wire m_axi_aw_fire = m_axi_awvalid[i] && m_axi_awready[i];
wire m_axi_w_fire = m_axi_wvalid[i] && m_axi_wready[i];
always @(posedge clk) begin
if (reset) begin
m_axi_aw_ack[i] <= 0;
m_axi_w_ack[i] <= 0;
end else begin
if (mem_req_fire && (req_bank_sel == i)) begin
m_axi_aw_ack[i] <= 0;
m_axi_w_ack[i] <= 0;
end else begin
if (m_axi_aw_fire)
m_axi_aw_ack[i] <= 1;
if (m_axi_w_fire)
m_axi_w_ack[i] <= 1;
end
end
end
end
end
end
wire axi_write_ready = (m_axi_awready || awvalid_ack) && (m_axi_wready || wvalid_ack);
wire axi_write_ready [NUM_BANKS];
// AXI write request address channel
assign m_axi_awvalid = mem_req_valid && mem_req_rw && !awvalid_ack;
assign m_axi_awid = mem_req_tag;
assign m_axi_awaddr = AXI_ADDR_WIDTH'(mem_req_addr) << AXSIZE;
assign m_axi_awlen = 8'b00000000;
assign m_axi_awsize = 3'(AXSIZE);
assign m_axi_awburst = 2'b00;
assign m_axi_awlock = 1'b0;
assign m_axi_awcache = 4'b0;
assign m_axi_awprot = 3'b0;
assign m_axi_awqos = 4'b0;
// AXI write request data channel
assign m_axi_wvalid = mem_req_valid && mem_req_rw && !wvalid_ack;
assign m_axi_wdata = mem_req_data;
assign m_axi_wstrb = mem_req_byteen;
assign m_axi_wlast = 1'b1;
// AXI write response channel
`UNUSED_VAR (m_axi_bid);
`RUNTIME_ASSERT(~m_axi_bvalid || m_axi_bresp == 0, ("%t: *** AXI response error", $time));
assign m_axi_bready = 1'b1;
// AXI read request channel
assign m_axi_arvalid = mem_req_valid && !mem_req_rw;
assign m_axi_arid = mem_req_tag;
assign m_axi_araddr = AXI_ADDR_WIDTH'(mem_req_addr) << AXSIZE;
assign m_axi_arlen = 8'b00000000;
assign m_axi_arsize = 3'(AXSIZE);
assign m_axi_arburst = 2'b00;
assign m_axi_arlock = 1'b0;
assign m_axi_arcache = 4'b0;
assign m_axi_arprot = 3'b0;
assign m_axi_arqos = 4'b0;
// AXI read response channel
assign mem_rsp_valid = m_axi_rvalid;
assign mem_rsp_tag = m_axi_rid;
assign mem_rsp_data = m_axi_rdata;
`RUNTIME_ASSERT(~m_axi_rvalid || m_axi_rresp == 0, ("%t: *** AXI response error", $time));
`UNUSED_VAR (m_axi_rlast);
assign m_axi_rready = mem_rsp_ready;
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign axi_write_ready[i] = (m_axi_awready[i] || m_axi_aw_ack[i])
&& (m_axi_wready[i] || m_axi_w_ack[i]);
end
// Vortex request ack
assign mem_req_ready = mem_req_rw ? axi_write_ready : m_axi_arready;
if (NUM_BANKS > 1) begin
assign mem_req_ready = mem_req_rw ? axi_write_ready[req_bank_sel] : m_axi_arready[req_bank_sel];
end else begin
assign mem_req_ready = mem_req_rw ? axi_write_ready[0] : m_axi_arready[0];
end
endmodule
// AXI write request address channel
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign m_axi_awvalid[i] = mem_req_valid && mem_req_rw && (req_bank_sel == i) && ~m_axi_aw_ack[i];
assign m_axi_awaddr[i] = (ADDR_WIDTH'(mem_req_addr) >> LOG2_NUM_BANKS) << AXSIZE;
assign m_axi_awid[i] = mem_req_tag;
assign m_axi_awlen[i] = 8'b00000000;
assign m_axi_awsize[i] = 3'(AXSIZE);
assign m_axi_awburst[i] = 2'b00;
assign m_axi_awlock[i] = 2'b00;
assign m_axi_awcache[i] = 4'b0000;
assign m_axi_awprot[i] = 3'b000;
assign m_axi_awqos[i] = 4'b0000;
assign m_axi_awregion[i]= 4'b0000;
end
// AXI write request data channel
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign m_axi_wvalid[i] = mem_req_valid && mem_req_rw && (req_bank_sel == i) && ~m_axi_w_ack[i];
assign m_axi_wdata[i] = mem_req_data;
assign m_axi_wstrb[i] = mem_req_byteen;
assign m_axi_wlast[i] = 1'b1;
end
// AXI write response channel (ignore)
for (genvar i = 0; i < NUM_BANKS; ++i) begin
`UNUSED_VAR (m_axi_bvalid[i])
`UNUSED_VAR (m_axi_bid[i])
`UNUSED_VAR (m_axi_bresp[i])
assign m_axi_bready[i] = 1'b1;
`RUNTIME_ASSERT(~m_axi_bvalid[i] || m_axi_bresp[i] == 0, ("%t: *** AXI response error", $time));
end
// AXI read request channel
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign m_axi_arvalid[i] = mem_req_valid && ~mem_req_rw && (req_bank_sel == i);
assign m_axi_araddr[i] = (ADDR_WIDTH'(mem_req_addr) >> LOG2_NUM_BANKS) << AXSIZE;
assign m_axi_arid[i] = mem_req_tag;
assign m_axi_arlen[i] = 8'b00000000;
assign m_axi_arsize[i] = 3'(AXSIZE);
assign m_axi_arburst[i] = 2'b00;
assign m_axi_arlock[i] = 2'b00;
assign m_axi_arcache[i] = 4'b0000;
assign m_axi_arprot[i] = 3'b000;
assign m_axi_arqos[i] = 4'b0000;
assign m_axi_arregion[i]= 4'b0000;
end
// AXI read response channel
wire [NUM_BANKS-1:0] rsp_arb_valid_in;
wire [NUM_BANKS-1:0][DATA_WIDTH+TAG_WIDTH-1:0] rsp_arb_data_in;
wire [NUM_BANKS-1:0] rsp_arb_ready_in;
`UNUSED_VAR (m_axi_rlast)
for (genvar i = 0; i < NUM_BANKS; ++i) begin
assign rsp_arb_valid_in[i] = m_axi_rvalid[i];
assign rsp_arb_data_in[i] = {m_axi_rdata[i], m_axi_rid[i]};
assign m_axi_rready[i] = rsp_arb_ready_in[i];
`RUNTIME_ASSERT(~m_axi_rvalid[i] || m_axi_rlast[i] == 1, ("%t: *** AXI response error", $time));
`RUNTIME_ASSERT(~m_axi_rvalid[i] || m_axi_rresp[i] == 0, ("%t: *** AXI response error", $time));
end
VX_stream_arb #(
.NUM_INPUTS (NUM_BANKS),
.DATAW (DATA_WIDTH + TAG_WIDTH),
.ARBITER ("R"),
.OUT_REG (OUT_REG_RSP)
) rsp_arb (
.clk (clk),
.reset (reset),
.valid_in (rsp_arb_valid_in),
.data_in (rsp_arb_data_in),
.ready_in (rsp_arb_ready_in),
.data_out ({mem_rsp_data, mem_rsp_tag}),
.valid_out (mem_rsp_valid),
.ready_out (mem_rsp_ready),
`UNUSED_PIN (sel_out)
);
endmodule
`TRACING_ON

View File

@@ -1,20 +1,40 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_bits_insert #(
parameter N = 1,
parameter S = 1,
parameter POS = 0
) (
input wire [N-1:0] data_in,
input wire [S-1:0] sel_in,
output wire [N+S-1:0] data_out
input wire [N-1:0] data_in,
input wire [`UP(S)-1:0] sel_in,
output wire [N+S-1:0] data_out
);
if (POS == 0) begin
assign data_out = {data_in, sel_in};
end else if (POS == N) begin
assign data_out = {sel_in, data_in};
if (S == 0) begin
`UNUSED_VAR (sel_in)
assign data_out = data_in;
end else begin
assign data_out = {data_in[N-1:POS], sel_in, data_in[POS-1:0]};
end
if (POS == 0) begin
assign data_out = {data_in, sel_in};
end else if (POS == N) begin
assign data_out = {sel_in, data_in};
end else begin
assign data_out = {data_in[N-1:POS], sel_in, data_in[POS-1:0]};
end
end
endmodule
endmodule
`TRACING_ON

View File

@@ -1,21 +1,38 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_bits_remove #(
parameter N = 1,
parameter N = 2,
parameter S = 1,
parameter POS = 0
) (
input wire [N-1:0] data_in,
input wire [N-1:0] data_in,
output wire [N-S-1:0] data_out
);
`STATIC_ASSERT (((0 == S) || ((POS + S) <= N)), ("invalid parameter"))
if (POS == 0 || S == 0) begin
assign data_out = data_in[N-1:S];
end else if ((POS + S) < N) begin
assign data_out = {data_in[N-1:(POS+S)], data_in[POS-1:0]};
end else begin
assign data_out = data_in[POS-1:0];
end
`UNUSED_VAR (data_in)
if (POS == 0) begin
assign data_out = data_in[N-1:S];
end else if (POS == N) begin
assign data_out = data_in[N-S-1:0];
end else begin
assign data_out = {data_in[N-1:(POS+S)], data_in[POS-1:0]};
end
endmodule
endmodule
`TRACING_ON

View File

@@ -1,5 +1,19 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_bypass_buffer #(
parameter DATAW = 1,
parameter PASSTHRU = 0
@@ -13,7 +27,7 @@ module VX_bypass_buffer #(
input wire ready_out,
output wire valid_out
);
if (PASSTHRU) begin
if (PASSTHRU != 0) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
assign ready_in = ready_out;
@@ -46,4 +60,5 @@ module VX_bypass_buffer #(
assign valid_out = valid_in || buffer_valid;
end
endmodule
endmodule
`TRACING_ON

View File

@@ -0,0 +1,73 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_cyclic_arbiter #(
parameter NUM_REQS = 1,
parameter LOCK_ENABLE = 0,
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire [NUM_REQS-1:0] requests,
input wire unlock,
output wire [LOG_NUM_REQS-1:0] grant_index,
output wire [NUM_REQS-1:0] grant_onehot,
output wire grant_valid
);
`UNUSED_PARAM (LOCK_ENABLE)
`UNUSED_VAR (unlock)
if (NUM_REQS == 1) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
assign grant_index = '0;
assign grant_onehot = requests;
assign grant_valid = requests[0];
end else begin
localparam IS_POW2 = (1 << LOG_NUM_REQS) == NUM_REQS;
reg [LOG_NUM_REQS-1:0] grant_index_r;
always @(posedge clk) begin
if (reset) begin
grant_index_r <= '0;
end else begin
if (!IS_POW2 && grant_index_r == LOG_NUM_REQS'(NUM_REQS-1)) begin
grant_index_r <= '0;
end else begin
grant_index_r <= grant_index_r + LOG_NUM_REQS'(1);
end
end
end
reg [NUM_REQS-1:0] grant_onehot_r;
always @(*) begin
grant_onehot_r = '0;
grant_onehot_r[grant_index_r] = 1'b1;
end
assign grant_index = grant_index_r;
assign grant_onehot = grant_onehot_r;
assign grant_valid = requests[grant_index_r];
end
endmodule
`TRACING_ON

View File

@@ -1,27 +1,40 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_divider #(
parameter WIDTHN = 1,
parameter WIDTHD = 1,
parameter WIDTHQ = 1,
parameter WIDTHR = 1,
parameter NSIGNED = 0,
parameter DSIGNED = 0,
parameter LATENCY = 0
parameter N_WIDTH = 1,
parameter D_WIDTH = 1,
parameter Q_WIDTH = 1,
parameter R_WIDTH = 1,
parameter N_SIGNED = 0,
parameter D_SIGNED = 0,
parameter LATENCY = 0
) (
input wire clk,
input wire enable,
input wire [WIDTHN-1:0] numer,
input wire [WIDTHD-1:0] denom,
output wire [WIDTHQ-1:0] quotient,
output wire [WIDTHR-1:0] remainder
input wire clk,
input wire enable,
input wire [N_WIDTH-1:0] numer,
input wire [D_WIDTH-1:0] denom,
output wire [Q_WIDTH-1:0] quotient,
output wire [R_WIDTH-1:0] remainder
);
`ifdef QUARTUS
wire [WIDTHN-1:0] quotient_unqual;
wire [WIDTHD-1:0] remainder_unqual;
wire [N_WIDTH-1:0] quotient_unqual;
wire [D_WIDTH-1:0] remainder_unqual;
lpm_divide divide (
.clock (clk),
@@ -34,32 +47,32 @@ module VX_divider #(
defparam
divide.lpm_type = "LPM_DIVIDE",
divide.lpm_widthn = WIDTHN,
divide.lpm_widthd = WIDTHD,
divide.lpm_nrepresentation = NSIGNED ? "SIGNED" : "UNSIGNED",
divide.lpm_drepresentation = DSIGNED ? "SIGNED" : "UNSIGNED",
divide.lpm_widthn = N_WIDTH,
divide.lpm_widthd = D_WIDTH,
divide.lpm_nrepresentation = N_SIGNED ? "SIGNED" : "UNSIGNED",
divide.lpm_drepresentation = D_SIGNED ? "SIGNED" : "UNSIGNED",
divide.lpm_hint = "MAXIMIZE_SPEED=6,LPM_REMAINDERPOSITIVE=FALSE",
divide.lpm_pipeline = LATENCY;
assign quotient = quotient_unqual [WIDTHQ-1:0];
assign remainder = remainder_unqual [WIDTHR-1:0];
assign quotient = quotient_unqual [Q_WIDTH-1:0];
assign remainder = remainder_unqual [R_WIDTH-1:0];
`else
reg [WIDTHN-1:0] quotient_unqual;
reg [WIDTHD-1:0] remainder_unqual;
reg [N_WIDTH-1:0] quotient_unqual;
reg [D_WIDTH-1:0] remainder_unqual;
always @(*) begin
begin
if (NSIGNED && DSIGNED) begin
if (N_SIGNED && D_SIGNED) begin
quotient_unqual = $signed(numer) / $signed(denom);
remainder_unqual = $signed(numer) % $signed(denom);
end
else if (NSIGNED && !DSIGNED) begin
else if (N_SIGNED && !D_SIGNED) begin
quotient_unqual = $signed(numer) / denom;
remainder_unqual = $signed(numer) % denom;
end
else if (!NSIGNED && DSIGNED) begin
else if (!N_SIGNED && D_SIGNED) begin
quotient_unqual = numer / $signed(denom);
remainder_unqual = numer % $signed(denom);
end
@@ -71,13 +84,13 @@ module VX_divider #(
end
if (LATENCY == 0) begin
assign quotient = quotient_unqual [WIDTHQ-1:0];
assign remainder = remainder_unqual [WIDTHR-1:0];
assign quotient = quotient_unqual [Q_WIDTH-1:0];
assign remainder = remainder_unqual [R_WIDTH-1:0];
end else begin
reg [WIDTHN-1:0] quotient_pipe [LATENCY-1:0];
reg [WIDTHD-1:0] remainder_pipe [LATENCY-1:0];
reg [N_WIDTH-1:0] quotient_pipe [LATENCY-1:0];
reg [D_WIDTH-1:0] remainder_pipe [LATENCY-1:0];
for (genvar i = 0; i < LATENCY; i++) begin
for (genvar i = 0; i < LATENCY; ++i) begin
always @(posedge clk) begin
if (enable) begin
quotient_pipe[i] <= (0 == i) ? quotient_unqual : quotient_pipe[i-1];
@@ -86,11 +99,11 @@ module VX_divider #(
end
end
assign quotient = quotient_pipe[LATENCY-1][WIDTHQ-1:0];
assign remainder = remainder_pipe[LATENCY-1][WIDTHR-1:0];
assign quotient = quotient_pipe[LATENCY-1][Q_WIDTH-1:0];
assign remainder = remainder_pipe[LATENCY-1][R_WIDTH-1:0];
end
`endif
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,252 +1,314 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_dp_ram #(
parameter DATAW = 1,
parameter SIZE = 1,
parameter BYTEENW = 1,
parameter WRENW = 1,
parameter OUT_REG = 0,
parameter NO_RWCHECK = 0,
parameter LUTRAM = 0,
parameter ADDRW = $clog2(SIZE),
parameter LUTRAM = 0,
parameter INIT_ENABLE = 0,
parameter INIT_FILE = "",
parameter [DATAW-1:0] INIT_VALUE = 0
parameter [DATAW-1:0] INIT_VALUE = 0,
parameter ADDRW = `LOG2UP(SIZE)
) (
input wire clk,
input wire [BYTEENW-1:0] wren,
input wire read,
input wire write,
input wire [WRENW-1:0] wren,
input wire [ADDRW-1:0] waddr,
input wire [DATAW-1:0] wdata,
input wire [ADDRW-1:0] raddr,
output wire [DATAW-1:0] rdata
);
localparam WSELW = DATAW / WRENW;
`STATIC_ASSERT((WRENW * WSELW == DATAW), ("invalid parameter"))
`STATIC_ASSERT((1 == BYTEENW) || ((BYTEENW > 1) && 0 == (BYTEENW % 4)), ("invalid parameter"))
`define RAM_INITIALIZATION \
if (INIT_ENABLE) begin \
if (INIT_FILE != "") begin \
initial $readmemh(INIT_FILE, ram); \
end else begin \
initial \
for (integer i = 0; i < SIZE; ++i)\
ram[i] = INIT_VALUE; \
end \
`define RAM_INITIALIZATION \
if (INIT_ENABLE != 0) begin \
if (INIT_FILE != "") begin \
initial $readmemh(INIT_FILE, ram); \
end else begin \
initial \
for (integer i = 0; i < SIZE; ++i) \
ram[i] = INIT_VALUE; \
end \
end
`UNUSED_VAR (read)
`ifdef SYNTHESIS
if (LUTRAM) begin
if (OUT_REG) begin
reg [DATAW-1:0] rdata_r;
if (BYTEENW > 1) begin
`USE_FAST_BRAM reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
if (WRENW > 1) begin
`ifdef QUARTUS
if (LUTRAM != 0) begin
if (OUT_REG != 0) begin
reg [DATAW-1:0] rdata_r;
`USE_FAST_BRAM reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
end
rdata_r <= ram[raddr];
end
end else begin
`USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
if (BYTEENW > 1) begin
`USE_FAST_BRAM reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
end
end
assign rdata = ram[raddr];
end else begin
`USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
end
assign rdata = ram[raddr];
end
end
end else begin
if (OUT_REG) begin
reg [DATAW-1:0] rdata_r;
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
end
rdata_r <= ram[raddr];
end
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
if (NO_RWCHECK) begin
if (BYTEENW > 1) begin
`NO_RW_RAM_CHECK reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
ram[waddr][i] <= wdata[i * WSELW +: WSELW];
end
end
if (read) begin
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
`USE_FAST_BRAM reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i] <= wdata[i * WSELW +: WSELW];
end
end
end
assign rdata = ram[raddr];
end
end else begin
if (OUT_REG != 0) begin
reg [DATAW-1:0] rdata_r;
reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i] <= wdata[i * WSELW +: WSELW];
end
end
if (read) begin
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
if (NO_RWCHECK != 0) begin
`NO_RW_RAM_CHECK reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i] <= wdata[i * WSELW +: WSELW];
end
end
end
assign rdata = ram[raddr];
end else begin
`NO_RW_RAM_CHECK reg [DATAW-1:0] ram [SIZE-1:0];
reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i] <= wdata[i * WSELW +: WSELW];
end
end
end
assign rdata = ram[raddr];
end
end else begin
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
end
end
`else
// default synthesis
if (LUTRAM != 0) begin
`USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
if (OUT_REG != 0) begin
reg [DATAW-1:0] rdata_r;
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW];
end
end
if (read) begin
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW];
end
end
end
assign rdata = ram[raddr];
end
end else begin
if (OUT_REG != 0) begin
reg [DATAW-1:0] ram [SIZE-1:0];
reg [DATAW-1:0] rdata_r;
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW];
end
end
if (read) begin
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
if (NO_RWCHECK != 0) begin
`NO_RW_RAM_CHECK reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW];
end
end
end
assign rdata = ram[raddr];
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
if (write) begin
for (integer i = 0; i < WRENW; ++i) begin
if (wren[i])
ram[waddr][i * WSELW +: WSELW] <= wdata[i * WSELW +: WSELW];
end
end
end
assign rdata = ram[raddr];
end
end
end
end
end
`else
if (OUT_REG) begin
reg [DATAW-1:0] rdata_r;
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`endif
end else begin
// (WRENW == 1)
if (LUTRAM != 0) begin
`USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
if (OUT_REG != 0) begin
reg [DATAW-1:0] rdata_r;
always @(posedge clk) begin
if (write) begin
ram[waddr] <= wdata;
end
if (read) begin
rdata_r <= ram[raddr];
end
end
rdata_r <= ram[raddr];
assign rdata = rdata_r;
end else begin
always @(posedge clk) begin
if (write) begin
ram[waddr] <= wdata;
end
end
assign rdata = ram[raddr];
end
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
if (OUT_REG != 0) begin
reg [DATAW-1:0] ram [SIZE-1:0];
reg [DATAW-1:0] rdata_r;
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
ram[waddr] <= wdata;
end
if (read) begin
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
if (NO_RWCHECK != 0) begin
`NO_RW_RAM_CHECK reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
ram[waddr] <= wdata;
end
end
assign rdata = ram[raddr];
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (write) begin
ram[waddr] <= wdata;
end
end
assign rdata = ram[raddr];
end
end
end
end
`else
// RAM emulation
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
`RAM_INITIALIZATION
wire [DATAW-1:0] ram_n;
for (genvar i = 0; i < WRENW; ++i) begin
assign ram_n[i * WSELW +: WSELW] = ((WRENW == 1) | wren[i]) ? wdata[i * WSELW +: WSELW] : ram[waddr][i * WSELW +: WSELW];
end
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
if (OUT_REG != 0) begin
reg [DATAW-1:0] rdata_r;
always @(posedge clk) begin
if (write) begin
ram[waddr] <= ram_n;
end
if (read) begin
rdata_r <= ram[raddr];
end
end
assign rdata = rdata_r;
end else begin
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
reg [DATAW-1:0] prev_data;
reg [ADDRW-1:0] prev_waddr;
reg prev_write;
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[waddr][i] <= wdata[i * 8 +: 8];
end
prev_write <= (| wren);
prev_data <= ram[waddr];
prev_waddr <= waddr;
end
if (LUTRAM || !NO_RWCHECK) begin
`UNUSED_VAR (prev_write)
`UNUSED_VAR (prev_data)
`UNUSED_VAR (prev_waddr)
assign rdata = ram[raddr];
end else begin
assign rdata = (prev_write && (prev_waddr == raddr)) ? prev_data : ram[raddr];
end else begin
reg [DATAW-1:0] prev_data;
reg [ADDRW-1:0] prev_waddr;
reg prev_write;
always @(posedge clk) begin
if (write) begin
ram[waddr] <= ram_n;
end
prev_write <= (| wren);
prev_data <= ram[waddr];
prev_waddr <= waddr;
end
if (LUTRAM || !NO_RWCHECK) begin
`UNUSED_VAR (prev_write)
`UNUSED_VAR (prev_data)
`UNUSED_VAR (prev_waddr)
assign rdata = ram[raddr];
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
reg [DATAW-1:0] prev_data;
reg [ADDRW-1:0] prev_waddr;
reg prev_write;
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[waddr] <= wdata;
prev_write <= wren;
prev_data <= ram[waddr];
prev_waddr <= waddr;
end
if (LUTRAM || !NO_RWCHECK) begin
`UNUSED_VAR (prev_write)
`UNUSED_VAR (prev_data)
`UNUSED_VAR (prev_waddr)
assign rdata = ram[raddr];
end else begin
assign rdata = (prev_write && (prev_waddr == raddr)) ? prev_data : ram[raddr];
end
assign rdata = (prev_write && (prev_waddr == raddr)) ? prev_data : ram[raddr];
end
end
`endif
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -0,0 +1,53 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_elastic_adapter (
input wire clk,
input wire reset,
input wire valid_in,
output wire ready_in,
input wire ready_out,
output wire valid_out,
input wire busy,
output wire strobe
);
wire push = valid_in && ready_in;
wire pop = valid_out && ready_out;
reg loaded;
always @(posedge clk) begin
if (reset) begin
loaded <= 0;
end else begin
if (push) begin
loaded <= 1;
end
if (pop) begin
loaded <= 0;
end
end
end
assign ready_in = ~loaded;
assign valid_out = loaded && ~busy;
assign strobe = push;
endmodule
`TRACING_ON

View File

@@ -1,9 +1,22 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_elastic_buffer #(
parameter DATAW = 1,
parameter SIZE = 2,
parameter SIZE = 1,
parameter OUT_REG = 0,
parameter LUTRAM = 0
) (
@@ -18,8 +31,6 @@ module VX_elastic_buffer #(
input wire ready_out,
output wire valid_out
);
`STATIC_ASSERT (SIZE != 1, ("invalid value"))
if (SIZE == 0) begin
`UNUSED_VAR (clk)
@@ -29,19 +40,36 @@ module VX_elastic_buffer #(
assign data_out = data_in;
assign ready_in = ready_out;
end else if (SIZE == 1) begin
wire stall = valid_out && ~ready_out;
VX_pipe_register #(
.DATAW (1 + DATAW),
.RESETW (1)
) pipe_register (
.clk (clk),
.reset (reset),
.enable (~stall),
.data_in ({valid_in, data_in}),
.data_out ({valid_out, data_out})
);
assign ready_in = ~stall;
end else if (SIZE == 2) begin
VX_skid_buffer #(
.DATAW (DATAW),
.OUT_REG (OUT_REG)
) queue (
) skid_buffer (
.clk (clk),
.reset (reset),
.valid_in (valid_in),
.data_in (data_in),
.ready_in (ready_in),
.valid_out (valid_out),
.valid_in (valid_in),
.ready_in (ready_in),
.data_in (data_in),
.data_out (data_out),
.valid_out (valid_out),
.ready_out (ready_out)
);
@@ -49,21 +77,24 @@ module VX_elastic_buffer #(
wire empty, full;
wire [DATAW-1:0] data_out_t;
wire ready_out_t;
wire push = valid_in && ready_in;
wire pop = valid_out && ready_out;
wire pop = ~empty && ready_out_t;
VX_fifo_queue #(
.DATAW (DATAW),
.SIZE (SIZE),
.OUT_REG (OUT_REG),
.DEPTH (SIZE),
.OUT_REG (OUT_REG == 1),
.LUTRAM (LUTRAM)
) queue (
) fifo_queue (
.clk (clk),
.reset (reset),
.push (push),
.pop (pop),
.data_in(data_in),
.data_out(data_out),
.data_out(data_out_t),
.empty (empty),
.full (full),
`UNUSED_PIN (alm_empty),
@@ -71,10 +102,23 @@ module VX_elastic_buffer #(
`UNUSED_PIN (size)
);
assign ready_in = ~full;
assign valid_out = ~empty;
assign ready_in = ~full;
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (OUT_REG == 2)
) out_buf (
.clk (clk),
.reset (reset),
.valid_in (~empty),
.ready_in (ready_out_t),
.data_in (data_out_t),
.data_out (data_out),
.valid_out (valid_out),
.ready_out (ready_out)
);
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,60 +1,72 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_fair_arbiter #(
parameter NUM_REQS = 1,
parameter LOCK_ENABLE = 0,
parameter LOG_NUM_REQS = $clog2(NUM_REQS)
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire enable,
input wire unlock,
input wire [NUM_REQS-1:0] requests,
output wire [LOG_NUM_REQS-1:0] grant_index,
output wire [NUM_REQS-1:0] grant_onehot,
output wire grant_valid
);
);
if (NUM_REQS == 1) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
assign grant_index = 0;
`UNUSED_VAR (reset)
`UNUSED_VAR (unlock)
assign grant_index = '0;
assign grant_onehot = requests;
assign grant_valid = requests[0];
end else begin
reg [NUM_REQS-1:0] buffer;
reg use_buffer;
wire [NUM_REQS-1:0] requests_qual = use_buffer ? buffer : requests;
wire [NUM_REQS-1:0] buffer_n = requests_qual & ~grant_onehot;
wire [NUM_REQS-1:0] buffer_qual = buffer & requests;
wire [NUM_REQS-1:0] requests_qual = (| buffer) ? buffer_qual : requests;
wire [NUM_REQS-1:0] buffer_n = requests_qual & ~grant_onehot;
always @(posedge clk) begin
if (reset) begin
use_buffer <= 0;
end else if (!LOCK_ENABLE || enable) begin
use_buffer <= (buffer_n != 0);
end
if (!LOCK_ENABLE || enable) begin
buffer <= '0;
end else if (!LOCK_ENABLE || unlock) begin
buffer <= buffer_n;
end
end
VX_fixed_arbiter #(
VX_priority_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) fixed_arbiter (
) priority_arbiter (
.clk (clk),
.reset (reset),
.enable (enable),
.unlock (unlock),
.requests (requests_qual),
.grant_index (grant_index),
.grant_onehot (grant_onehot),
.grant_valid (grant_valid)
);
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,15 +1,27 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_fifo_queue #(
parameter DATAW = 1,
parameter SIZE = 2,
parameter ALM_FULL = (SIZE - 1),
parameter DEPTH = 2,
parameter ALM_FULL = (DEPTH - 1),
parameter ALM_EMPTY = 1,
parameter ADDRW = $clog2(SIZE),
parameter SIZEW = $clog2(SIZE+1),
parameter OUT_REG = 0,
parameter LUTRAM = 1
parameter LUTRAM = 1,
parameter SIZEW = `CLOG2(DEPTH+1)
) (
input wire clk,
input wire reset,
@@ -23,26 +35,33 @@ module VX_fifo_queue #(
output wire alm_full,
output wire [SIZEW-1:0] size
);
`STATIC_ASSERT(`ISPOW2(SIZE), ("must be 0 or power of 2!"))
if (SIZE == 1) begin
localparam ADDRW = `CLOG2(DEPTH);
`STATIC_ASSERT(ALM_FULL > 0, ("alm_full must be greater than 0!"))
`STATIC_ASSERT(ALM_FULL < DEPTH, ("alm_full must be smaller than size!"))
`STATIC_ASSERT(ALM_EMPTY > 0, ("alm_empty must be greater than 0!"))
`STATIC_ASSERT(ALM_EMPTY < DEPTH, ("alm_empty must be smaller than size!"))
`STATIC_ASSERT(`ISPOW2(DEPTH), ("size must be a power of 2!"))
if (DEPTH == 1) begin
reg [DATAW-1:0] head_r;
reg size_r;
always @(posedge clk) begin
if (reset) begin
head_r <= 0;
size_r <= 0;
head_r <= '0;
size_r <= '0;
end else begin
`ASSERT(!push || !full, ("runtime error"));
`ASSERT(!pop || !empty, ("runtime error"));
`ASSERT(~push || ~full, ("runtime error: writing to a full queue"));
`ASSERT(~pop || ~empty, ("runtime error: reading an empty queue"));
if (push) begin
if (!pop) begin
if (~pop) begin
size_r <= 1;
end
end else if (pop) begin
size_r <= 0;
size_r <= '0;
end
if (push) begin
head_r <= data_in;
@@ -62,6 +81,7 @@ module VX_fifo_queue #(
reg empty_r, alm_empty_r;
reg full_r, alm_full_r;
reg [ADDRW-1:0] used_r;
wire [ADDRW-1:0] used_n;
always @(posedge clk) begin
if (reset) begin
@@ -69,43 +89,40 @@ module VX_fifo_queue #(
alm_empty_r <= 1;
full_r <= 0;
alm_full_r <= 0;
used_r <= 0;
used_r <= '0;
end else begin
`ASSERT(!push || !full, ("runtime error"));
`ASSERT(!pop || !empty, ("runtime error"));
`ASSERT(~(push && ~pop) || ~full, ("runtime error: incrementing full queue"));
`ASSERT(~(pop && ~push) || ~empty, ("runtime error: decrementing empty queue"));
if (push) begin
if (!pop) begin
if (~pop) begin
empty_r <= 0;
if (used_r == ADDRW'(ALM_EMPTY))
alm_empty_r <= 0;
if (used_r == ADDRW'(SIZE-1))
if (used_r == ADDRW'(DEPTH-1))
full_r <= 1;
if (used_r == ADDRW'(ALM_FULL-1))
alm_full_r <= 1;
end
end else if (pop) begin
full_r <= 0;
full_r <= 0;
if (used_r == ADDRW'(ALM_FULL))
alm_full_r <= 0;
if (used_r == ADDRW'(1))
empty_r <= 1;
if (used_r == ADDRW'(ALM_EMPTY+1))
alm_empty_r <= 1;
end
if (SIZE > 2) begin
used_r <= used_r + ADDRW'($signed(2'(push) - 2'(pop)));
end else begin
// (SIZE == 2);
used_r[0] <= used_r[0] ^ (push ^ pop);
end
used_r <= used_n;
end
end
if (SIZE == 2) begin
if (DEPTH == 2) begin
assign used_n = used_r ^ (push ^ pop);
if (0 == OUT_REG) begin
reg [DATAW-1:0] shift_reg [1:0];
reg [1:0][DATAW-1:0] shift_reg;
always @(posedge clk) begin
if (push) begin
@@ -137,6 +154,8 @@ module VX_fifo_queue #(
end
end else begin
assign used_n = $signed(used_r) + ADDRW'($signed(2'(push) - 2'(pop)));
if (0 == OUT_REG) begin
@@ -145,8 +164,8 @@ module VX_fifo_queue #(
always @(posedge clk) begin
if (reset) begin
rd_ptr_r <= 0;
wr_ptr_r <= 0;
rd_ptr_r <= '0;
wr_ptr_r <= '0;
end else begin
wr_ptr_r <= wr_ptr_r + ADDRW'(push);
rd_ptr_r <= rd_ptr_r + ADDRW'(pop);
@@ -154,13 +173,14 @@ module VX_fifo_queue #(
end
VX_dp_ram #(
.DATAW (DATAW),
.SIZE (SIZE),
.OUT_REG (0),
.LUTRAM (LUTRAM)
.DATAW (DATAW),
.SIZE (DEPTH),
.LUTRAM (LUTRAM)
) dp_ram (
.clk(clk),
.wren (push),
.read (1'b1),
.write (push),
`UNUSED_PIN (wren),
.waddr (wr_ptr_r),
.wdata (data_in),
.raddr (rd_ptr_r),
@@ -177,8 +197,8 @@ module VX_fifo_queue #(
always @(posedge clk) begin
if (reset) begin
wr_ptr_r <= 0;
rd_ptr_r <= 0;
wr_ptr_r <= '0;
rd_ptr_r <= '0;
rd_ptr_n_r <= 1;
end else begin
if (push) begin
@@ -186,23 +206,31 @@ module VX_fifo_queue #(
end
if (pop) begin
rd_ptr_r <= rd_ptr_n_r;
if (SIZE > 2) begin
if (DEPTH > 2) begin
rd_ptr_n_r <= rd_ptr_r + ADDRW'(2);
end else begin // (SIZE == 2);
end else begin // (DEPTH == 2);
rd_ptr_n_r <= ~rd_ptr_n_r;
end
end
end
end
wire going_empty;
if (ALM_EMPTY == 1) begin
assign going_empty = alm_empty_r;
end else begin
assign going_empty = (used_r == ADDRW'(1));
end
VX_dp_ram #(
.DATAW (DATAW),
.SIZE (SIZE),
.OUT_REG (0),
.LUTRAM (LUTRAM)
.DATAW (DATAW),
.SIZE (DEPTH),
.LUTRAM (LUTRAM)
) dp_ram (
.clk (clk),
.wren (push),
.read (1'b1),
.write (push),
`UNUSED_PIN (wren),
.waddr (wr_ptr_r),
.wdata (data_in),
.raddr (rd_ptr_n_r),
@@ -210,7 +238,7 @@ module VX_fifo_queue #(
);
always @(posedge clk) begin
if (push && (empty_r || ((used_r == ADDRW'(1)) && pop))) begin
if (push && (empty_r || (going_empty && pop))) begin
dout_r <= data_in;
end else if (pop) begin
dout_r <= dout;
@@ -229,4 +257,4 @@ module VX_fifo_queue #(
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,19 +1,32 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_find_first #(
parameter N = 1,
parameter DATAW = 1,
parameter REVERSE = 0,
parameter LOGN = $clog2(N)
parameter REVERSE = 0
) (
input wire [N-1:0][DATAW-1:0] data_i,
input wire [N-1:0] valid_i,
output wire [DATAW-1:0] data_o,
output wire valid_o
input wire [N-1:0][DATAW-1:0] data_in,
input wire [N-1:0] valid_in,
output wire [DATAW-1:0] data_out,
output wire valid_out
);
localparam TL = (1 << LOGN) - 1;
localparam TN = (1 << (LOGN+1)) - 1;
localparam LOGN = `CLOG2(N);
localparam TL = (1 << LOGN) - 1;
localparam TN = (1 << (LOGN+1)) - 1;
`IGNORE_WARNINGS_BEGIN
wire [TN-1:0] s_n;
@@ -21,13 +34,13 @@ module VX_find_first #(
`IGNORE_WARNINGS_END
for (genvar i = 0; i < N; ++i) begin
assign s_n[TL+i] = REVERSE ? valid_i[N-1-i] : valid_i[i];
assign d_n[TL+i] = REVERSE ? data_i[N-1-i] : data_i[i];
assign s_n[TL+i] = REVERSE ? valid_in[N-1-i] : valid_in[i];
assign d_n[TL+i] = REVERSE ? data_in[N-1-i] : data_in[i];
end
for (genvar i = TL+N; i < TN; ++i) begin
assign s_n[i] = 0;
assign d_n[i] = 'x;
assign d_n[i] = '0;
end
for (genvar j = 0; j < LOGN; ++j) begin
@@ -37,8 +50,8 @@ module VX_find_first #(
end
end
assign valid_o = s_n[0];
assign data_o = d_n[0];
assign valid_out = s_n[0];
assign data_out = d_n[0];
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -0,0 +1,113 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_generic_arbiter #(
parameter NUM_REQS = 1,
parameter LOCK_ENABLE = 0,
parameter `STRING TYPE = "P",
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire unlock,
input wire [NUM_REQS-1:0] requests,
output wire [LOG_NUM_REQS-1:0] grant_index,
output wire [NUM_REQS-1:0] grant_onehot,
output wire grant_valid
);
if (TYPE == "P") begin
VX_priority_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) priority_arbiter (
.clk (clk),
.reset (reset),
.unlock (unlock),
.requests (requests),
.grant_valid (grant_valid),
.grant_index (grant_index),
.grant_onehot (grant_onehot)
);
end else if (TYPE == "R") begin
VX_rr_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) rr_arbiter (
.clk (clk),
.reset (reset),
.unlock (unlock),
.requests (requests),
.grant_valid (grant_valid),
.grant_index (grant_index),
.grant_onehot (grant_onehot)
);
end else if (TYPE == "F") begin
VX_fair_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) fair_arbiter (
.clk (clk),
.reset (reset),
.unlock (unlock),
.requests (requests),
.grant_valid (grant_valid),
.grant_index (grant_index),
.grant_onehot (grant_onehot)
);
end else if (TYPE == "M") begin
VX_matrix_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) matrix_arbiter (
.clk (clk),
.reset (reset),
.unlock (unlock),
.requests (requests),
.grant_valid (grant_valid),
.grant_index (grant_index),
.grant_onehot (grant_onehot)
);
end else if (TYPE == "C") begin
VX_cyclic_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) cyclic_arbiter (
.clk (clk),
.reset (reset),
.unlock (unlock),
.requests (requests),
.grant_valid (grant_valid),
.grant_index (grant_index),
.grant_onehot (grant_onehot)
);
end else begin
`ERROR(("invalid parameter"));
end
endmodule
`TRACING_ON

View File

@@ -1,3 +1,16 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
@@ -7,82 +20,48 @@ module VX_index_buffer #(
parameter LUTRAM = 1,
parameter ADDRW = `LOG2UP(SIZE)
) (
input wire clk,
input wire reset,
input wire clk,
input wire reset,
output wire [ADDRW-1:0] write_addr,
input wire [DATAW-1:0] write_data,
input wire acquire_slot,
input wire acquire_en,
input wire [ADDRW-1:0] read_addr,
output wire [DATAW-1:0] read_data,
input wire [ADDRW-1:0] release_addr,
input wire release_slot,
input wire release_en,
output wire empty,
output wire full
output wire empty,
output wire full
);
reg [SIZE-1:0] free_slots, free_slots_n;
reg [ADDRW-1:0] write_addr_r;
reg empty_r, full_r;
wire free_valid;
wire [ADDRW-1:0] free_index;
VX_lzc #(
.N (SIZE)
) free_slots_sel (
.in_i (free_slots_n),
.cnt_o (free_index),
.valid_o (free_valid)
);
always @(*) begin
free_slots_n = free_slots;
if (release_slot) begin
free_slots_n[release_addr] = 1;
end
if (acquire_slot) begin
free_slots_n[write_addr_r] = 0;
end
end
always @(posedge clk) begin
if (reset) begin
write_addr_r <= ADDRW'(1'b0);
free_slots <= {SIZE{1'b1}};
empty_r <= 1'b1;
full_r <= 1'b0;
end else begin
if (release_slot) begin
`ASSERT(0 == free_slots[release_addr], ("%t: releasing invalid slot at port %d", $time, release_addr));
end
if (acquire_slot) begin
`ASSERT(1 == free_slots[write_addr], ("%t: acquiring used slot at port %d", $time, write_addr));
end
write_addr_r <= free_index;
free_slots <= free_slots_n;
empty_r <= (& free_slots_n);
full_r <= ~free_valid;
end
end
VX_allocator #(
.SIZE (SIZE)
) allocator (
.clk (clk),
.reset (reset),
.acquire_en (acquire_en),
.acquire_addr (write_addr),
.release_en (release_en),
.release_addr (read_addr),
.empty (empty),
.full (full)
);
VX_dp_ram #(
.DATAW (DATAW),
.SIZE (SIZE),
.LUTRAM (LUTRAM)
) data_table (
.clk (clk),
.wren (acquire_slot),
.waddr (write_addr_r),
.clk (clk),
.read (1'b1),
.write (acquire_en),
`UNUSED_PIN (wren),
.waddr (write_addr),
.wdata (write_data),
.raddr (read_addr),
.rdata (read_data)
);
assign write_addr = write_addr_r;
assign empty = empty_r;
assign full = full_r;
);
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,20 +1,33 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_index_queue #(
parameter DATAW = 1,
parameter SIZE = 1
parameter SIZE = 1
) (
input wire clk,
input wire reset,
input wire [DATAW-1:0] write_data,
input wire clk,
input wire reset,
input wire [DATAW-1:0] write_data,
output wire [`LOG2UP(SIZE)-1:0] write_addr,
input wire push,
input wire pop,
output wire full,
output wire empty,
input wire push,
input wire pop,
output wire full,
output wire empty,
input wire [`LOG2UP(SIZE)-1:0] read_addr,
output wire [DATAW-1:0] read_data
output wire [DATAW-1:0] read_data
);
reg [DATAW-1:0] entries [SIZE-1:0];
reg [SIZE-1:0] valid;
@@ -36,9 +49,9 @@ module VX_index_queue #(
always @(posedge clk) begin
if (reset) begin
rd_ptr <= 0;
wr_ptr <= 0;
valid <= 0;
rd_ptr <= '0;
wr_ptr <= '0;
valid <= '0;
end else begin
if (enqueue) begin
valid[wr_a] <= 1;
@@ -61,4 +74,4 @@ module VX_index_queue #(
assign read_data = entries[read_addr];
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,31 +1,55 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_lzc #(
parameter N = 2,
parameter MODE = 0, // 0 -> trailing zero, 1 -> leading zero
parameter LOGN = $clog2(N)
parameter N = 2,
parameter REVERSE = 0, // 0 -> leading zero, 1 -> trailing zero,
parameter LOGN = `LOG2UP(N)
) (
input wire [N-1:0] in_i,
output wire [LOGN-1:0] cnt_o,
output wire valid_o
input wire [N-1:0] data_in,
output wire [LOGN-1:0] data_out,
output wire valid_out
);
wire [N-1:0][LOGN-1:0] indices;
if (N == 1) begin
`UNUSED_PARAM (REVERSE)
assign data_out = '0;
assign valid_out = data_in;
end else begin
wire [N-1:0][LOGN-1:0] indices;
for (genvar i = 0; i < N; ++i) begin
assign indices[i] = REVERSE ? LOGN'(i) : LOGN'(N-1-i);
end
VX_find_first #(
.N (N),
.DATAW (LOGN),
.REVERSE (!REVERSE)
) find_first (
.data_in (indices),
.valid_in (data_in),
.data_out (data_out),
.valid_out (valid_out)
);
for (genvar i = 0; i < N; ++i) begin
assign indices[i] = MODE ? LOGN'(N-1-i) : LOGN'(i);
end
VX_find_first #(
.N (N),
.DATAW (LOGN),
.REVERSE (MODE)
) find_first (
.data_i (indices),
.valid_i (in_i),
.data_o (cnt_o),
.valid_o (valid_o)
);
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,26 +1,39 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_matrix_arbiter #(
parameter NUM_REQS = 1,
parameter LOCK_ENABLE = 0,
parameter LOG_NUM_REQS = $clog2(NUM_REQS)
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire enable,
input wire unlock,
input wire [NUM_REQS-1:0] requests,
output wire [LOG_NUM_REQS-1:0] grant_index,
output wire [NUM_REQS-1:0] grant_onehot,
output wire grant_valid
);
);
if (NUM_REQS == 1) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
`UNUSED_VAR (unlock)
assign grant_index = 0;
assign grant_index = '0;
assign grant_onehot = requests;
assign grant_valid = requests[0];
@@ -30,8 +43,8 @@ module VX_matrix_arbiter #(
wire [NUM_REQS-1:0] pri [NUM_REQS-1:0];
wire [NUM_REQS-1:0] grant_unqual;
for (genvar i = 0; i < NUM_REQS; i++) begin
for (genvar j = 0; j < NUM_REQS; j++) begin
for (genvar i = 0; i < NUM_REQS; ++i) begin
for (genvar j = 0; j < NUM_REQS; ++j) begin
if (j > i) begin
assign pri[j][i] = requests[i] && state[i][j];
end
@@ -45,11 +58,11 @@ module VX_matrix_arbiter #(
assign grant_unqual[i] = requests[i] && !(| pri[i]);
end
for (genvar i = 0; i < NUM_REQS; i++) begin
for (genvar j = i + 1; j < NUM_REQS; j++) begin
for (genvar i = 0; i < NUM_REQS; ++i) begin
for (genvar j = i + 1; j < NUM_REQS; ++j) begin
always @(posedge clk) begin
if (reset) begin
state[i][j] <= 0;
state[i][j] <= '0;
end else begin
state[i][j] <= (state[i][j] || grant_unqual[j]) && !grant_unqual[i];
end
@@ -58,18 +71,18 @@ module VX_matrix_arbiter #(
end
if (LOCK_ENABLE == 0) begin
`UNUSED_VAR (enable)
`UNUSED_VAR (unlock)
assign grant_onehot = grant_unqual;
end else begin
reg [NUM_REQS-1:0] grant_unqual_prev;
always @(posedge clk) begin
if (reset) begin
grant_unqual_prev <= 0;
end else if (enable) begin
grant_unqual_prev <= '0;
end else if (unlock) begin
grant_unqual_prev <= grant_unqual;
end
end
assign grant_onehot = enable ? grant_unqual : grant_unqual_prev;
assign grant_onehot = unlock ? grant_unqual : grant_unqual_prev;
end
VX_onehot_encoder #(
@@ -85,4 +98,4 @@ module VX_matrix_arbiter #(
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -0,0 +1,240 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_mem_adapter #(
parameter SRC_DATA_WIDTH = 1,
parameter SRC_ADDR_WIDTH = 1,
parameter DST_DATA_WIDTH = 1,
parameter DST_ADDR_WIDTH = 1,
parameter SRC_TAG_WIDTH = 1,
parameter DST_TAG_WIDTH = 1,
parameter OUT_REG_REQ = 0,
parameter OUT_REG_RSP = 0
) (
input wire clk,
input wire reset,
input wire mem_req_valid_in,
input wire [SRC_ADDR_WIDTH-1:0] mem_req_addr_in,
input wire mem_req_rw_in,
input wire [SRC_DATA_WIDTH/8-1:0] mem_req_byteen_in,
input wire [SRC_DATA_WIDTH-1:0] mem_req_data_in,
input wire [SRC_TAG_WIDTH-1:0] mem_req_tag_in,
output wire mem_req_ready_in,
output wire mem_rsp_valid_in,
output wire [SRC_DATA_WIDTH-1:0] mem_rsp_data_in,
output wire [SRC_TAG_WIDTH-1:0] mem_rsp_tag_in,
input wire mem_rsp_ready_in,
output wire mem_req_valid_out,
output wire [DST_ADDR_WIDTH-1:0] mem_req_addr_out,
output wire mem_req_rw_out,
output wire [DST_DATA_WIDTH/8-1:0] mem_req_byteen_out,
output wire [DST_DATA_WIDTH-1:0] mem_req_data_out,
output wire [DST_TAG_WIDTH-1:0] mem_req_tag_out,
input wire mem_req_ready_out,
input wire mem_rsp_valid_out,
input wire [DST_DATA_WIDTH-1:0] mem_rsp_data_out,
input wire [DST_TAG_WIDTH-1:0] mem_rsp_tag_out,
output wire mem_rsp_ready_out
);
`STATIC_ASSERT ((DST_TAG_WIDTH >= SRC_TAG_WIDTH), ("oops!"))
localparam DST_DATA_SIZE = (DST_DATA_WIDTH / 8);
localparam DST_LDATAW = `CLOG2(DST_DATA_WIDTH);
localparam SRC_LDATAW = `CLOG2(SRC_DATA_WIDTH);
localparam D = `ABS(DST_LDATAW - SRC_LDATAW);
localparam P = 2**D;
wire mem_req_valid_out_w;
wire [DST_ADDR_WIDTH-1:0] mem_req_addr_out_w;
wire mem_req_rw_out_w;
wire [DST_DATA_WIDTH/8-1:0] mem_req_byteen_out_w;
wire [DST_DATA_WIDTH-1:0] mem_req_data_out_w;
wire [DST_TAG_WIDTH-1:0] mem_req_tag_out_w;
wire mem_req_ready_out_w;
wire mem_rsp_valid_in_w;
wire [SRC_DATA_WIDTH-1:0] mem_rsp_data_in_w;
wire [SRC_TAG_WIDTH-1:0] mem_rsp_tag_in_w;
wire mem_rsp_ready_in_w;
`UNUSED_VAR (mem_rsp_tag_out)
if (DST_LDATAW > SRC_LDATAW) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
wire [D-1:0] req_idx = mem_req_addr_in[D-1:0];
wire [D-1:0] rsp_idx = mem_rsp_tag_out[D-1:0];
wire [SRC_ADDR_WIDTH-D-1:0] mem_req_addr_in_qual = mem_req_addr_in[SRC_ADDR_WIDTH-1:D];
wire [P-1:0][SRC_DATA_WIDTH-1:0] mem_rsp_data_out_w = mem_rsp_data_out;
if (DST_ADDR_WIDTH < (SRC_ADDR_WIDTH - D)) begin
`UNUSED_VAR (mem_req_addr_in_qual)
assign mem_req_addr_out_w = mem_req_addr_in_qual[DST_ADDR_WIDTH-1:0];
end else if (DST_ADDR_WIDTH > (SRC_ADDR_WIDTH - D)) begin
assign mem_req_addr_out_w = DST_ADDR_WIDTH'(mem_req_addr_in_qual);
end else begin
assign mem_req_addr_out_w = mem_req_addr_in_qual;
end
assign mem_req_valid_out_w = mem_req_valid_in;
assign mem_req_rw_out_w = mem_req_rw_in;
assign mem_req_byteen_out_w = DST_DATA_SIZE'(mem_req_byteen_in) << ((DST_LDATAW-3)'(req_idx) << (SRC_LDATAW-3));
assign mem_req_data_out_w = DST_DATA_WIDTH'(mem_req_data_in) << ((DST_LDATAW'(req_idx)) << SRC_LDATAW);
assign mem_req_tag_out_w = DST_TAG_WIDTH'({mem_req_tag_in, req_idx});
assign mem_req_ready_in = mem_req_ready_out_w;
assign mem_rsp_valid_in_w = mem_rsp_valid_out;
assign mem_rsp_data_in_w = mem_rsp_data_out_w[rsp_idx];
assign mem_rsp_tag_in_w = SRC_TAG_WIDTH'(mem_rsp_tag_out[SRC_TAG_WIDTH+D-1:D]);
assign mem_rsp_ready_out = mem_rsp_ready_in_w;
end else if (DST_LDATAW < SRC_LDATAW) begin
reg [D-1:0] req_ctr, rsp_ctr;
reg [P-1:0][DST_DATA_WIDTH-1:0] mem_rsp_data_out_r, mem_rsp_data_out_n;
wire mem_req_out_fire = mem_req_valid_out && mem_req_ready_out;
wire mem_rsp_in_fire = mem_rsp_valid_out && mem_rsp_ready_out;
wire [P-1:0][DST_DATA_WIDTH-1:0] mem_req_data_in_w = mem_req_data_in;
wire [P-1:0][DST_DATA_SIZE-1:0] mem_req_byteen_in_w = mem_req_byteen_in;
always @(*) begin
mem_rsp_data_out_n = mem_rsp_data_out_r;
if (mem_rsp_in_fire) begin
mem_rsp_data_out_n[rsp_ctr] = mem_rsp_data_out;
end
end
always @(posedge clk) begin
if (reset) begin
req_ctr <= '0;
rsp_ctr <= '0;
end else begin
if (mem_req_out_fire) begin
req_ctr <= req_ctr + 1;
end
if (mem_rsp_in_fire) begin
rsp_ctr <= rsp_ctr + 1;
end
end
mem_rsp_data_out_r <= mem_rsp_data_out_n;
end
reg [DST_TAG_WIDTH-1:0] mem_rsp_tag_in_r;
wire [DST_TAG_WIDTH-1:0] mem_rsp_tag_in_x;
always @(posedge clk) begin
if (mem_rsp_in_fire) begin
mem_rsp_tag_in_r <= mem_rsp_tag_out;
end
end
assign mem_rsp_tag_in_x = (rsp_ctr != 0) ? mem_rsp_tag_in_r : mem_rsp_tag_out;
`RUNTIME_ASSERT(!mem_rsp_in_fire || (mem_rsp_tag_in_x == mem_rsp_tag_out),
("%t: *** out-of-order memory reponse! cur=%d, expected=%d", $time, mem_rsp_tag_in_x, mem_rsp_tag_out))
wire [SRC_ADDR_WIDTH+D-1:0] mem_req_addr_in_qual = {mem_req_addr_in, req_ctr};
if (DST_ADDR_WIDTH < (SRC_ADDR_WIDTH + D)) begin
`UNUSED_VAR (mem_req_addr_in_qual)
assign mem_req_addr_out_w = mem_req_addr_in_qual[DST_ADDR_WIDTH-1:0];
end else if (DST_ADDR_WIDTH > (SRC_ADDR_WIDTH + D)) begin
assign mem_req_addr_out_w = DST_ADDR_WIDTH'(mem_req_addr_in_qual);
end else begin
assign mem_req_addr_out_w = mem_req_addr_in_qual;
end
assign mem_req_valid_out_w = mem_req_valid_in;
assign mem_req_rw_out_w = mem_req_rw_in;
assign mem_req_byteen_out_w = mem_req_byteen_in_w[req_ctr];
assign mem_req_data_out_w = mem_req_data_in_w[req_ctr];
assign mem_req_tag_out_w = DST_TAG_WIDTH'(mem_req_tag_in);
assign mem_req_ready_in = mem_req_ready_out_w && (req_ctr == (P-1));
assign mem_rsp_valid_in_w = mem_rsp_valid_out && (rsp_ctr == (P-1));
assign mem_rsp_data_in_w = mem_rsp_data_out_n;
assign mem_rsp_tag_in_w = SRC_TAG_WIDTH'(mem_rsp_tag_out);
assign mem_rsp_ready_out = mem_rsp_ready_in_w;
end else begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
if (DST_ADDR_WIDTH < SRC_ADDR_WIDTH) begin
`UNUSED_VAR (mem_req_addr_in)
assign mem_req_addr_out_w = mem_req_addr_in[DST_ADDR_WIDTH-1:0];
end else if (DST_ADDR_WIDTH > SRC_ADDR_WIDTH) begin
assign mem_req_addr_out_w = DST_ADDR_WIDTH'(mem_req_addr_in);
end else begin
assign mem_req_addr_out_w = mem_req_addr_in;
end
assign mem_req_valid_out_w = mem_req_valid_in;
assign mem_req_rw_out_w = mem_req_rw_in;
assign mem_req_byteen_out_w = mem_req_byteen_in;
assign mem_req_data_out_w = mem_req_data_in;
assign mem_req_tag_out_w = DST_TAG_WIDTH'(mem_req_tag_in);
assign mem_req_ready_in = mem_req_ready_out_w;
assign mem_rsp_valid_in_w = mem_rsp_valid_out;
assign mem_rsp_data_in_w = mem_rsp_data_out;
assign mem_rsp_tag_in_w = SRC_TAG_WIDTH'(mem_rsp_tag_out);
assign mem_rsp_ready_out = mem_rsp_ready_in_w;
end
VX_elastic_buffer #(
.DATAW (1 + DST_DATA_SIZE + DST_ADDR_WIDTH + DST_DATA_WIDTH + DST_TAG_WIDTH),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG_REQ)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG_REQ))
) req_out_buf (
.clk (clk),
.reset (reset),
.valid_in (mem_req_valid_out_w),
.ready_in (mem_req_ready_out_w),
.data_in ({mem_req_rw_out_w, mem_req_byteen_out_w, mem_req_addr_out_w, mem_req_data_out_w, mem_req_tag_out_w}),
.data_out ({mem_req_rw_out, mem_req_byteen_out, mem_req_addr_out, mem_req_data_out, mem_req_tag_out}),
.valid_out (mem_req_valid_out),
.ready_out (mem_req_ready_out)
);
VX_elastic_buffer #(
.DATAW (SRC_DATA_WIDTH + SRC_TAG_WIDTH),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG_RSP)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG_RSP))
) rsp_in_buf (
.clk (clk),
.reset (reset),
.valid_in (mem_rsp_valid_in_w),
.ready_in (mem_rsp_ready_in_w),
.data_in ({mem_rsp_data_in_w, mem_rsp_tag_in_w}),
.data_out ({mem_rsp_data_in, mem_rsp_tag_in}),
.valid_out (mem_rsp_valid_in),
.ready_out (mem_rsp_ready_in)
);
endmodule
`TRACING_ON

View File

@@ -0,0 +1,111 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_mem_rsp_sel #(
parameter NUM_REQS = 1,
parameter DATA_WIDTH = 1,
parameter TAG_WIDTH = 1,
parameter TAG_SEL_BITS = 0,
parameter OUT_REG = 0
) (
input wire clk,
input wire reset,
// input response
input wire [NUM_REQS-1:0] rsp_valid_in,
input wire [NUM_REQS-1:0][DATA_WIDTH-1:0] rsp_data_in,
input wire [NUM_REQS-1:0][TAG_WIDTH-1:0] rsp_tag_in,
output wire [NUM_REQS-1:0] rsp_ready_in,
// output responses
output wire rsp_valid_out,
output wire [NUM_REQS-1:0] rsp_mask_out,
output wire [NUM_REQS-1:0][DATA_WIDTH-1:0] rsp_data_out,
output wire [TAG_WIDTH-1:0] rsp_tag_out,
input wire rsp_ready_out
);
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
localparam LOG_NUM_REQS = `CLOG2(NUM_REQS);
if (NUM_REQS > 1) begin
wire [LOG_NUM_REQS-1:0] grant_index;
wire grant_valid;
wire rsp_fire;
VX_priority_arbiter #(
.NUM_REQS (NUM_REQS)
) arbiter (
.clk (clk),
.reset (reset),
.unlock (rsp_fire),
.requests (rsp_valid_in),
.grant_valid (grant_valid),
.grant_index (grant_index),
`UNUSED_PIN (grant_onehot)
);
reg [NUM_REQS-1:0] rsp_valid_sel;
reg [NUM_REQS-1:0] rsp_ready_sel;
wire rsp_ready_unqual;
wire [TAG_WIDTH-1:0] rsp_tag_sel = rsp_tag_in[grant_index];
always @(*) begin
rsp_valid_sel = '0;
rsp_ready_sel = '0;
for (integer i = 0; i < NUM_REQS; ++i) begin
if (rsp_tag_in[i][TAG_SEL_BITS-1:0] == rsp_tag_sel[TAG_SEL_BITS-1:0]) begin
rsp_valid_sel[i] = rsp_valid_in[i];
rsp_ready_sel[i] = rsp_ready_unqual;
end
end
end
assign rsp_fire = grant_valid && rsp_ready_unqual;
VX_elastic_buffer #(
.DATAW (NUM_REQS + TAG_WIDTH + (NUM_REQS * DATA_WIDTH)),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (reset),
.valid_in (grant_valid),
.data_in ({rsp_valid_sel, rsp_tag_sel, rsp_data_in}),
.ready_in (rsp_ready_unqual),
.valid_out (rsp_valid_out),
.data_out ({rsp_mask_out, rsp_tag_out, rsp_data_out}),
.ready_out (rsp_ready_out)
);
assign rsp_ready_in = rsp_ready_sel;
end else begin
assign rsp_valid_out = rsp_valid_in;
assign rsp_mask_out = 1'b1;
assign rsp_tag_out = rsp_tag_in;
assign rsp_data_out = rsp_data_in;
assign rsp_ready_in = rsp_ready_out;
end
endmodule
`TRACING_ON

View File

@@ -0,0 +1,578 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_mem_scheduler #(
parameter `STRING INSTANCE_ID = "",
parameter NUM_REQS = 4,
parameter NUM_BANKS = 4,
parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 32,
parameter TAG_WIDTH = 32,
parameter MEM_TAG_ID = 0, // upper section of the tag sent to the memory interface
parameter UUID_WIDTH = 0, // upper section of the mem_tag_id containing the UUID
parameter QUEUE_SIZE = 16,
parameter RSP_PARTIAL = 0,
parameter CORE_OUT_REG = 0,
parameter MEM_OUT_REG = 0,
parameter BYTEENW = DATA_WIDTH / 8,
parameter NUM_BATCHES = (NUM_REQS + NUM_BANKS - 1) / NUM_BANKS,
parameter QUEUE_ADDRW = `CLOG2(QUEUE_SIZE),
parameter BATCH_SEL_BITS = `CLOG2(NUM_BATCHES),
parameter MEM_TAGW = MEM_TAG_ID + QUEUE_ADDRW + BATCH_SEL_BITS
) (
input wire clk,
input wire reset,
// Input request
input wire req_valid,
input wire req_rw,
input wire [NUM_REQS-1:0] req_mask,
input wire [NUM_REQS-1:0][BYTEENW-1:0] req_byteen,
input wire [NUM_REQS-1:0][ADDR_WIDTH-1:0] req_addr,
input wire [NUM_REQS-1:0][DATA_WIDTH-1:0] req_data,
input wire [TAG_WIDTH-1:0] req_tag,
output wire req_empty,
output wire req_ready,
output wire write_notify,
// Output response
output wire rsp_valid,
output wire [NUM_REQS-1:0] rsp_mask,
output wire [NUM_REQS-1:0][DATA_WIDTH-1:0] rsp_data,
output wire [TAG_WIDTH-1:0] rsp_tag,
output wire rsp_sop,
output wire rsp_eop,
input wire rsp_ready,
// Memory request
output wire [NUM_BANKS-1:0] mem_req_valid,
output wire [NUM_BANKS-1:0] mem_req_rw,
output wire [NUM_BANKS-1:0][BYTEENW-1:0] mem_req_byteen,
output wire [NUM_BANKS-1:0][ADDR_WIDTH-1:0] mem_req_addr,
output wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_req_data,
output wire [NUM_BANKS-1:0][MEM_TAGW-1:0]mem_req_tag,
input wire [NUM_BANKS-1:0] mem_req_ready,
// Memory response
input wire [NUM_BANKS-1:0] mem_rsp_valid,
input wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_rsp_data,
input wire [NUM_BANKS-1:0][MEM_TAGW-1:0] mem_rsp_tag,
output wire [NUM_BANKS-1:0] mem_rsp_ready
);
localparam MEM_TAG_WIDTH = `UP(MEM_TAG_ID);
localparam BATCH_SEL_WIDTH = `UP(BATCH_SEL_BITS);
localparam TAG_ONLY_WIDTH = TAG_WIDTH - MEM_TAG_ID;
localparam STALL_TIMEOUT = 10000000;
`STATIC_ASSERT ((MEM_TAG_ID >= UUID_WIDTH), ("invalid parameter"))
`STATIC_ASSERT (DATA_WIDTH == 8 * (DATA_WIDTH / 8), ("invalid parameter"))
`STATIC_ASSERT ((0 == RSP_PARTIAL) || (1 == RSP_PARTIAL), ("invalid parameter"))
`RUNTIME_ASSERT ((~req_valid || req_mask != 0), ("invalid request mask"));
wire [NUM_BANKS-1:0] mem_req_valid_s;
wire [NUM_BANKS-1:0] mem_req_mask_s;
wire [NUM_BANKS-1:0] mem_req_rw_s;
wire [NUM_BANKS-1:0][BYTEENW-1:0] mem_req_byteen_s;
wire [NUM_BANKS-1:0][ADDR_WIDTH-1:0] mem_req_addr_s;
wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_req_data_s;
wire [MEM_TAGW-1:0] mem_req_tag_s;
wire [NUM_BANKS-1:0] mem_req_ready_s;
wire mem_rsp_valid_s;
wire [NUM_BANKS-1:0] mem_rsp_mask_s;
wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_rsp_data_s;
wire [MEM_TAGW-1:0] mem_rsp_tag_s;
wire mem_rsp_ready_s;
wire mem_rsp_fire_s;
wire reqq_push;
wire reqq_pop;
wire reqq_full;
wire reqq_empty;
wire reqq_rw;
wire [NUM_REQS-1:0] reqq_mask;
wire [NUM_REQS-1:0][BYTEENW-1:0] reqq_byteen;
wire [NUM_REQS-1:0][ADDR_WIDTH-1:0] reqq_addr;
wire [NUM_REQS-1:0][DATA_WIDTH-1:0] reqq_data;
wire [QUEUE_ADDRW-1:0] reqq_tag;
wire [MEM_TAG_WIDTH-1:0] reqq_mtid;
wire ibuf_push;
wire ibuf_pop;
wire [QUEUE_ADDRW-1:0] ibuf_waddr;
wire [QUEUE_ADDRW-1:0] ibuf_raddr;
wire ibuf_full;
wire ibuf_empty;
wire [TAG_ONLY_WIDTH-1:0] ibuf_din;
wire [TAG_ONLY_WIDTH-1:0] ibuf_dout;
wire crsp_valid;
wire [NUM_REQS-1:0] crsp_mask;
wire [NUM_REQS-1:0][DATA_WIDTH-1:0] crsp_data;
wire [TAG_WIDTH-1:0] crsp_tag;
wire crsp_sop;
wire crsp_eop;
wire crsp_ready;
// Request queue //////////////////////////////////////////////////////////
wire req_sent_all;
assign reqq_push = req_valid && req_ready;
assign reqq_pop = ~reqq_empty && req_sent_all;
wire [MEM_TAG_WIDTH-1:0] req_mtid;
if (MEM_TAG_ID != 0) begin
assign req_mtid = req_tag[TAG_WIDTH-1 -: MEM_TAG_ID];
end else begin
assign req_mtid = '0;
end
wire [`CLOG2(QUEUE_SIZE+1)-1:0] reqq_size;
`UNUSED_VAR (reqq_size)
VX_fifo_queue #(
.DATAW (1 + NUM_REQS * (1 + BYTEENW + ADDR_WIDTH + DATA_WIDTH) + MEM_TAG_WIDTH + QUEUE_ADDRW),
.DEPTH (QUEUE_SIZE),
.OUT_REG (1)
) req_queue (
.clk (clk),
.reset (reset),
.push (reqq_push),
.pop (reqq_pop),
.data_in ({req_rw, req_mask, req_byteen, req_addr, req_data, req_mtid, ibuf_waddr}),
.data_out ({reqq_rw, reqq_mask, reqq_byteen, reqq_addr, reqq_data, reqq_mtid, reqq_tag}),
.full (reqq_full),
.empty (reqq_empty),
`UNUSED_PIN (alm_full),
`UNUSED_PIN (alm_empty),
.size (reqq_size)
);
// can accept another request?
assign req_ready = ~reqq_full && (req_rw || ~ibuf_full);
// no pending requests
assign req_empty = reqq_empty && ibuf_empty;
// notify write submisison
assign write_notify = reqq_pop && reqq_rw;
// Index buffer ///////////////////////////////////////////////////////////
wire rsp_complete;
assign ibuf_push = reqq_push && ~req_rw;
assign ibuf_pop = crsp_valid && crsp_ready && rsp_complete;
assign ibuf_raddr = mem_rsp_tag_s[0 +: QUEUE_ADDRW];
assign ibuf_din = req_tag[TAG_ONLY_WIDTH-1:0];
VX_index_buffer #(
.DATAW (TAG_ONLY_WIDTH),
.SIZE (QUEUE_SIZE)
) req_ibuf (
.clk (clk),
.reset (reset),
.acquire_en (ibuf_push),
.write_addr (ibuf_waddr),
.write_data (ibuf_din),
.read_data (ibuf_dout),
.read_addr (ibuf_raddr),
.release_en (ibuf_pop),
.full (ibuf_full),
.empty (ibuf_empty)
);
`UNUSED_VAR (ibuf_empty)
// Handle memory requests /////////////////////////////////////////////////
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0] mem_req_mask_b;
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0] mem_req_rw_b;
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0][BYTEENW-1:0] mem_req_byteen_b;
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0][ADDR_WIDTH-1:0] mem_req_addr_b;
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_req_data_b;
wire [BATCH_SEL_WIDTH-1:0] req_batch_idx;
for (genvar i = 0; i < NUM_BATCHES; ++i) begin
for (genvar j = 0; j < NUM_BANKS; ++j) begin
localparam r = i * NUM_BANKS + j;
if (r < NUM_REQS) begin
assign mem_req_mask_b[i][j] = reqq_mask[r];
assign mem_req_rw_b[i][j] = reqq_rw;
assign mem_req_byteen_b[i][j] = reqq_byteen[r];
assign mem_req_addr_b[i][j] = reqq_addr[r];
assign mem_req_data_b[i][j] = reqq_data[r];
end else begin
assign mem_req_mask_b[i][j] = 0;
assign mem_req_rw_b[i][j] = '0;
assign mem_req_byteen_b[i][j] = '0;
assign mem_req_addr_b[i][j] = '0;
assign mem_req_data_b[i][j] = '0;
end
end
end
assign mem_req_mask_s = mem_req_mask_b[req_batch_idx];
assign mem_req_rw_s = mem_req_rw_b[req_batch_idx];
assign mem_req_byteen_s = mem_req_byteen_b[req_batch_idx];
assign mem_req_addr_s = mem_req_addr_b[req_batch_idx];
assign mem_req_data_s = mem_req_data_b[req_batch_idx];
reg [NUM_BANKS-1:0] batch_sent_mask;
wire [NUM_BANKS-1:0] batch_sent_mask_n = batch_sent_mask | mem_req_ready_s;
wire batch_sent_all = (mem_req_mask_s & ~batch_sent_mask_n) == 0;
always @(posedge clk) begin
if (reset) begin
batch_sent_mask <= '0;
end else begin
if (~reqq_empty) begin
if (batch_sent_all) begin
batch_sent_mask <= '0;
end else begin
batch_sent_mask <= batch_sent_mask_n;
end
end
end
end
if (NUM_BATCHES > 1) begin
reg [BATCH_SEL_BITS-1:0] req_batch_idx_r;
always @(posedge clk) begin
if (reset) begin
req_batch_idx_r <= '0;
end else begin
if (~reqq_empty && batch_sent_all) begin
if (req_sent_all) begin
req_batch_idx_r <= '0;
end else begin
req_batch_idx_r <= req_batch_idx_r + BATCH_SEL_BITS'(1);
end
end
end
end
wire [NUM_BATCHES-1:0] req_batch_valids;
wire [NUM_BATCHES-1:0][BATCH_SEL_BITS-1:0] req_batch_idxs;
wire [BATCH_SEL_BITS-1:0] req_batch_idx_last;
for (genvar i = 0; i < NUM_BATCHES; ++i) begin
assign req_batch_valids[i] = (| mem_req_mask_b[i]);
assign req_batch_idxs[i] = BATCH_SEL_BITS'(i);
end
VX_find_first #(
.N (NUM_BATCHES),
.DATAW (BATCH_SEL_BITS),
.REVERSE (1)
) find_last (
.valid_in (req_batch_valids),
.data_in (req_batch_idxs),
.data_out (req_batch_idx_last),
`UNUSED_PIN (valid_out)
);
assign req_batch_idx = req_batch_idx_r;
assign req_sent_all = batch_sent_all && (req_batch_idx_r == req_batch_idx_last);
if (MEM_TAG_ID != 0) begin
assign mem_req_tag_s = {reqq_mtid, req_batch_idx, reqq_tag};
end else begin
`UNUSED_VAR (reqq_mtid)
assign mem_req_tag_s = {req_batch_idx, reqq_tag};
end
end else begin
assign req_batch_idx = '0;
assign req_sent_all = batch_sent_all;
if (MEM_TAG_ID != 0) begin
assign mem_req_tag_s = {reqq_mtid, reqq_tag};
end else begin
`UNUSED_VAR (reqq_mtid)
assign mem_req_tag_s = reqq_tag;
end
end
assign mem_req_valid_s = {NUM_BANKS{~reqq_empty}} & mem_req_mask_s & ~batch_sent_mask;
for (genvar i = 0; i < NUM_BANKS; ++i) begin
VX_elastic_buffer #(
.DATAW (1 + BYTEENW + ADDR_WIDTH + DATA_WIDTH + MEM_TAGW),
.SIZE (`OUT_REG_TO_EB_SIZE(MEM_OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(MEM_OUT_REG))
) mem_req_buf (
.clk (clk),
.reset (reset),
.valid_in (mem_req_valid_s[i]),
.ready_in (mem_req_ready_s[i]),
.data_in ({mem_req_rw_s[i], mem_req_byteen_s[i], mem_req_addr_s[i], mem_req_data_s[i], mem_req_tag_s}),
.data_out ({mem_req_rw[i], mem_req_byteen[i], mem_req_addr[i], mem_req_data[i], mem_req_tag[i]}),
.valid_out (mem_req_valid[i]),
.ready_out (mem_req_ready[i])
);
end
// Handle memory responses ////////////////////////////////////////////////
reg [QUEUE_SIZE-1:0][NUM_REQS-1:0] rsp_rem_mask;
wire [NUM_REQS-1:0] rsp_rem_mask_n, curr_mask;
wire [BATCH_SEL_WIDTH-1:0] rsp_batch_idx;
// Select memory response
VX_mem_rsp_sel #(
.NUM_REQS (NUM_BANKS),
.DATA_WIDTH (DATA_WIDTH),
.TAG_WIDTH (MEM_TAGW),
.TAG_SEL_BITS (MEM_TAGW - MEM_TAG_ID),
.OUT_REG (2)
) mem_rsp_sel (
.clk (clk),
.reset (reset),
.rsp_valid_in (mem_rsp_valid),
.rsp_data_in (mem_rsp_data),
.rsp_tag_in (mem_rsp_tag),
.rsp_ready_in (mem_rsp_ready),
.rsp_valid_out (mem_rsp_valid_s),
.rsp_mask_out (mem_rsp_mask_s),
.rsp_data_out (mem_rsp_data_s),
.rsp_tag_out (mem_rsp_tag_s),
.rsp_ready_out (mem_rsp_ready_s)
);
for (genvar r = 0; r < NUM_REQS; ++r) begin
localparam i = r / NUM_BANKS;
localparam j = r % NUM_BANKS;
assign curr_mask[r] = (BATCH_SEL_WIDTH'(i) == rsp_batch_idx) && mem_rsp_mask_s[j];
end
assign rsp_rem_mask_n = rsp_rem_mask[ibuf_raddr] & ~curr_mask;
if (NUM_BATCHES > 1) begin
assign rsp_batch_idx = mem_rsp_tag_s[QUEUE_ADDRW +: BATCH_SEL_BITS];
end else begin
assign rsp_batch_idx = '0;
end
assign rsp_complete = ~(| rsp_rem_mask_n);
always @(posedge clk) begin
if (ibuf_push) begin
rsp_rem_mask[ibuf_waddr] <= req_mask;
end
if (mem_rsp_fire_s) begin
rsp_rem_mask[ibuf_raddr] <= rsp_rem_mask_n;
end
end
assign mem_rsp_fire_s = mem_rsp_valid_s && mem_rsp_ready_s;
if (RSP_PARTIAL == 1) begin
reg [QUEUE_SIZE-1:0] rsp_sop_r;
always @(posedge clk) begin
if (ibuf_push) begin
rsp_sop_r[ibuf_waddr] <= 1;
end
if (mem_rsp_fire_s) begin
rsp_sop_r[ibuf_raddr] <= 0;
end
end
assign mem_rsp_ready_s = crsp_ready;
assign crsp_valid = mem_rsp_valid_s;
assign crsp_mask = curr_mask;
assign crsp_sop = rsp_sop_r[ibuf_raddr];
for (genvar r = 0; r < NUM_REQS; ++r) begin
localparam j = r % NUM_BANKS;
assign crsp_data[r] = mem_rsp_data_s[j];
end
end else begin
reg [NUM_BATCHES*NUM_BANKS*DATA_WIDTH-1:0] rsp_store [QUEUE_SIZE-1:0];
reg [NUM_BATCHES*NUM_BANKS*DATA_WIDTH-1:0] rsp_store_n;
reg [NUM_REQS-1:0] rsp_orig_mask [QUEUE_SIZE-1:0];
always @(*) begin
rsp_store_n = rsp_store[ibuf_raddr];
for (integer i = 0; i < NUM_BANKS; ++i) begin
if ((NUM_BANKS == 1) || mem_rsp_mask_s[i]) begin
rsp_store_n[(rsp_batch_idx * NUM_BANKS + i) * DATA_WIDTH +: DATA_WIDTH] = mem_rsp_data_s[i];
end
end
end
always @(posedge clk) begin
if (ibuf_push) begin
rsp_orig_mask[ibuf_waddr] <= req_mask;
end
if (mem_rsp_valid_s) begin
rsp_store[ibuf_raddr] <= rsp_store_n;
end
end
assign mem_rsp_ready_s = crsp_ready || ~rsp_complete;
assign crsp_valid = mem_rsp_valid_s && rsp_complete;
assign crsp_mask = rsp_orig_mask[ibuf_raddr];
assign crsp_sop = 1'b1;
for (genvar r = 0; r < NUM_REQS; ++r) begin
localparam i = r / NUM_BANKS;
localparam j = r % NUM_BANKS;
assign crsp_data[r] = rsp_store_n[(i * NUM_BANKS + j) * DATA_WIDTH +: DATA_WIDTH];
end
end
if (MEM_TAG_ID != 0) begin
assign crsp_tag = {mem_rsp_tag_s[MEM_TAGW-1 -: MEM_TAG_ID], ibuf_dout};
end else begin
assign crsp_tag = ibuf_dout;
end
assign crsp_eop = ibuf_pop;
// Send response to caller
VX_elastic_buffer #(
.DATAW (NUM_REQS + 1 + 1 + (NUM_REQS * DATA_WIDTH) + TAG_WIDTH),
.SIZE (`OUT_REG_TO_EB_SIZE(CORE_OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(CORE_OUT_REG))
) rsp_buf (
.clk (clk),
.reset (reset),
.valid_in (crsp_valid),
.ready_in (crsp_ready),
.data_in ({crsp_mask, crsp_sop, crsp_eop, crsp_data, crsp_tag}),
.data_out ({rsp_mask, rsp_sop, rsp_eop, rsp_data, rsp_tag}),
.valid_out (rsp_valid),
.ready_out (rsp_ready)
);
`ifdef SIMULATION
wire [`UP(UUID_WIDTH)-1:0] req_dbg_uuid;
wire [`UP(UUID_WIDTH)-1:0] rsp_dbg_uuid;
wire [`UP(UUID_WIDTH)-1:0] mem_req_dbg_uuid;
wire [`UP(UUID_WIDTH)-1:0] mem_rsp_dbg_uuid;
if (UUID_WIDTH != 0) begin
assign req_dbg_uuid = req_tag[TAG_WIDTH-1 -: UUID_WIDTH];
assign rsp_dbg_uuid = rsp_tag[TAG_WIDTH-1 -: UUID_WIDTH];
assign mem_req_dbg_uuid = reqq_mtid[MEM_TAG_ID-1 -: UUID_WIDTH];
assign mem_rsp_dbg_uuid = mem_rsp_tag_s[MEM_TAGW-1 -: UUID_WIDTH];
end else begin
assign req_dbg_uuid = '0;
assign rsp_dbg_uuid = '0;
assign mem_req_dbg_uuid = '0;
assign mem_rsp_dbg_uuid = '0;
end
`UNUSED_VAR (req_dbg_uuid)
`UNUSED_VAR (rsp_dbg_uuid)
`UNUSED_VAR (mem_req_dbg_uuid)
`UNUSED_VAR (mem_rsp_dbg_uuid)
reg [(`UP(UUID_WIDTH) + TAG_ONLY_WIDTH + 64)-1:0] pending_reqs [QUEUE_SIZE-1:0];
reg [QUEUE_SIZE-1:0] pending_req_valids;
always @(posedge clk) begin
if (reset) begin
pending_req_valids <= '0;
end else begin
if (ibuf_push) begin
pending_req_valids[ibuf_waddr] <= 1'b1;
end
if (ibuf_pop) begin
pending_req_valids[ibuf_raddr] <= 1'b0;
end
end
if (ibuf_push) begin
pending_reqs[ibuf_waddr] <= {req_dbg_uuid, ibuf_din, $time};
end
for (integer i = 0; i < QUEUE_SIZE; ++i) begin
if (pending_req_valids[i]) begin
`ASSERT(($time - pending_reqs[i][0 +: 64]) < STALL_TIMEOUT,
("%t: *** %s response timeout: remaining=%b, tag=0x%0h (#%0d)",
$time, INSTANCE_ID, rsp_rem_mask[i], pending_reqs[i][64 +: TAG_ONLY_WIDTH], pending_reqs[i][64+TAG_ONLY_WIDTH +: `UP(UUID_WIDTH)]));
end
end
end
`endif
///////////////////////////////////////////////////////////////////////////
`ifndef NDEBUG
wire [NUM_BANKS-1:0] mem_req_fire_s = mem_req_valid_s & mem_req_ready_s;
always @(posedge clk) begin
if (req_valid && req_ready) begin
if (req_rw) begin
`TRACE(1, ("%d: %s-core-req-wr: valid=%b, addr=", $time, INSTANCE_ID, req_mask));
`TRACE_ARRAY1D(1, req_addr, NUM_REQS);
`TRACE(1, (", byteen="));
`TRACE_ARRAY1D(1, req_byteen, NUM_REQS);
`TRACE(1, (", data="));
`TRACE_ARRAY1D(1, req_data, NUM_REQS);
end else begin
`TRACE(1, ("%d: %s-core-req-rd: valid=%b, addr=", $time, INSTANCE_ID, req_mask));
`TRACE_ARRAY1D(1, req_addr, NUM_REQS);
end
`TRACE(1, (", tag=0x%0h (#%0d)\n", req_tag, req_dbg_uuid));
end
if (rsp_valid && rsp_ready) begin
`TRACE(1, ("%d: %s-rsp: valid=%b, sop=%b, eop=%b, data=", $time, INSTANCE_ID, rsp_mask, rsp_sop, rsp_eop));
`TRACE_ARRAY1D(1, rsp_data, NUM_REQS);
`TRACE(1, (", tag=0x%0h (#%0d)\n", rsp_tag, rsp_dbg_uuid));
end
if (| mem_req_fire_s) begin
if (| mem_req_rw_s) begin
`TRACE(1, ("%d: %s-mem-req-wr: valid=%b, addr=", $time, INSTANCE_ID, mem_req_fire_s));
`TRACE_ARRAY1D(1, mem_req_addr_s, NUM_BANKS);
`TRACE(1, (", byteen="));
`TRACE_ARRAY1D(1, mem_req_byteen_s, NUM_BANKS);
`TRACE(1, (", data="));
`TRACE_ARRAY1D(1, mem_req_data_s, NUM_BANKS);
end else begin
`TRACE(1, ("%d: %s-mem-req-rd: valid=%b, addr=", $time, INSTANCE_ID, mem_req_fire_s));
`TRACE_ARRAY1D(1, mem_req_addr_s, NUM_BANKS);
end
`TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_waddr, req_batch_idx, mem_req_dbg_uuid));
end
if (mem_rsp_fire_s) begin
`TRACE(1, ("%d: %s-mem-rsp: valid=%b, data=", $time, INSTANCE_ID, mem_rsp_mask_s));
`TRACE_ARRAY1D(1, mem_rsp_data_s, NUM_BANKS);
`TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_raddr, rsp_batch_idx, mem_rsp_dbg_uuid));
end
end
`endif
endmodule
`TRACING_ON

View File

@@ -1,70 +1,54 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_multiplier #(
parameter WIDTHA = 1,
parameter WIDTHB = 1,
parameter WIDTHP = 1,
parameter A_WIDTH = 1,
parameter B_WIDTH = A_WIDTH,
parameter R_WIDTH = A_WIDTH + B_WIDTH,
parameter SIGNED = 0,
parameter LATENCY = 0
) (
input wire clk,
input wire enable,
input wire [WIDTHA-1:0] dataa,
input wire [WIDTHB-1:0] datab,
output wire [WIDTHP-1:0] result
input wire [A_WIDTH-1:0] dataa,
input wire [B_WIDTH-1:0] datab,
output wire [R_WIDTH-1:0] result
);
wire [R_WIDTH-1:0] prod_w;
`ifdef QUARTUS
lpm_mult mult (
.clock (clk),
.clken (enable),
.dataa (dataa),
.datab (datab),
.result (result),
.aclr (1'b0),
.sclr (1'b0),
.sum (1'b0)
);
defparam mult.lpm_type = "LPM_MULT",
mult.lpm_widtha = WIDTHA,
mult.lpm_widthb = WIDTHB,
mult.lpm_widthp = WIDTHP,
mult.lpm_representation = SIGNED ? "SIGNED" : "UNSIGNED",
mult.lpm_pipeline = LATENCY,
mult.lpm_hint = "DEDICATED_MULTIPLIER_CIRCUITRY=YES,MAXIMIZE_SPEED=9";
`else
wire [WIDTHP-1:0] result_unqual;
if (SIGNED) begin
assign result_unqual = $signed(dataa) * $signed(datab);
if (SIGNED != 0) begin
assign prod_w = R_WIDTH'($signed(dataa) * $signed(datab));
end else begin
assign result_unqual = dataa * datab;
assign prod_w = R_WIDTH'(dataa * datab);
end
if (LATENCY == 0) begin
assign result = result_unqual;
assign result = prod_w;
end else begin
reg [WIDTHP-1:0] result_pipe [LATENCY-1:0];
reg [LATENCY-1:0][R_WIDTH-1:0] prod_r;
always @(posedge clk) begin
if (enable) begin
result_pipe[0] <= result_unqual;
end
end
for (genvar i = 1; i < LATENCY; i++) begin
always @(posedge clk) begin
if (enable) begin
result_pipe[i] <= result_pipe[i-1];
prod_r[0] <= prod_w;
for (integer i = 1; i < LATENCY; ++i) begin
prod_r[i] <= prod_r[i-1];
end
end
end
assign result = result_pipe[LATENCY-1];
end
assign result = prod_r[LATENCY-1];
end
`endif
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,10 +1,23 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_mux #(
parameter DATAW = 1,
parameter N = 1,
parameter LN = $clog2(N)
parameter LN = `LOG2UP(N)
) (
input wire [N-1:0][DATAW-1:0] data_in,
input wire [LN-1:0] sel_in,
@@ -18,4 +31,4 @@ module VX_mux #(
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,3 +1,16 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
// Fast encoder using parallel prefix computation
@@ -5,7 +18,7 @@
`TRACING_OFF
module VX_onehot_encoder #(
parameter N = 1,
parameter N = 1,
parameter REVERSE = 0,
parameter MODEL = 1,
parameter LN = `LOG2UP(N)
@@ -24,53 +37,50 @@ module VX_onehot_encoder #(
assign data_out = data_in[!REVERSE];
assign valid_out = (| data_in);
end else if (MODEL == 1) begin
`IGNORE_WARNINGS_BEGIN
localparam levels_lp = $clog2(N);
localparam aligned_width_lp = 1 << $clog2(N);
wire [levels_lp:0][aligned_width_lp-1:0] addr;
wire [levels_lp:0][aligned_width_lp-1:0] v;
end else if (MODEL == 1) begin
localparam M = 1 << LN;
`IGNORE_UNOPTFLAT_BEGIN
wire [LN-1:0][M-1:0] addr;
wire [LN:0][M-1:0] v;
`IGNORE_UNOPTFLAT_END
// base case, also handle padding for non-power of two inputs
assign v[0] = REVERSE ? (data_in << (aligned_width_lp - N)) : ((aligned_width_lp)'(data_in));
assign addr[0] = 'x;
assign v[0] = REVERSE ? (M'(data_in) << (M - N)) : M'(data_in);
for (genvar level = 1; level < levels_lp+1; level=level+1) begin
localparam segments_lp = 2**(levels_lp-level);
localparam segment_slot_lp = aligned_width_lp/segments_lp;
localparam segment_width_lp = level; // how many bits are needed at each level
for (genvar lvl = 1; lvl < (LN+1); ++lvl) begin
localparam SN = 1 << (LN - lvl);
localparam SI = M / SN;
localparam SW = lvl;
for (genvar segment = 0; segment < segments_lp; segment=segment+1) begin
wire [1:0] vs = {
v[level-1][segment*segment_slot_lp+(segment_slot_lp >> 1)],
v[level-1][segment*segment_slot_lp]
};
assign v[level][segment*segment_slot_lp] = (| vs);
for (genvar s = 0; s < SN; ++s) begin
`IGNORE_UNOPTFLAT_BEGIN
wire [1:0] vs = {v[lvl-1][s*SI+(SI>>1)], v[lvl-1][s*SI]};
`IGNORE_UNOPTFLAT_END
assign v[lvl][s*SI] = (| vs);
if (level == 1) begin
assign addr[level][(segment*segment_slot_lp)+:segment_width_lp] = vs[!REVERSE];
if (lvl == 1) begin
assign addr[lvl-1][s*SI +: SW] = vs[!REVERSE];
end else begin
assign addr[level][(segment*segment_slot_lp)+:segment_width_lp] = {
assign addr[lvl-1][s*SI +: SW] = {
vs[!REVERSE],
addr[level-1][segment*segment_slot_lp+:segment_width_lp-1] | addr[level-1][segment*segment_slot_lp+(segment_slot_lp >> 1)+:segment_width_lp-1]
addr[lvl-2][s*SI +: SW-1] | addr[lvl-2][s*SI+(SI>>1) +: SW-1]
};
end
end
end
assign data_out = addr[levels_lp][`LOG2UP(N)-1:0];
assign valid_out = v[levels_lp][0];
`IGNORE_WARNINGS_END
end else if (MODEL == 2) begin
assign data_out = addr[LN-1][LN-1:0];
assign valid_out = v[LN][0];
end else if (MODEL == 2 && REVERSE == 0) begin
for (genvar j = 0; j < LN; ++j) begin
wire [N-1:0] mask;
for (genvar i = 0; i < N; ++i) begin
assign mask[i] = i[j];
end
assign data_out[j] = |(mask & data_in);
assign data_out[j] = | (mask & data_in);
end
assign valid_out = (| data_in);
@@ -79,21 +89,21 @@ module VX_onehot_encoder #(
reg [LN-1:0] index_r;
if (REVERSE) begin
if (REVERSE != 0) begin
always @(*) begin
index_r = 'x;
for (integer i = N-1; i >= 0; --i) begin
if (data_in[i]) begin
index_r = `LOG2UP(N)'(i);
index_r = LN'(N-1-i);
end
end
end
end else begin
always @(*) begin
index_r = 'x;
for (integer i = 0; i < N; i++) begin
for (integer i = 0; i < N; ++i) begin
if (data_in[i]) begin
index_r = `LOG2UP(N)'(i);
index_r = LN'(i);
end
end
end
@@ -104,4 +114,4 @@ module VX_onehot_encoder #(
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,3 +1,16 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
@@ -10,11 +23,105 @@ module VX_onehot_mux #(
input wire [N-1:0] sel_in,
output wire [DATAW-1:0] data_out
);
if (N > 1) begin
if (N == 1) begin
`UNUSED_VAR (sel_in)
assign data_out = data_in;
end else if (N == 2) begin
`UNUSED_VAR (sel_in)
assign data_out = sel_in[0] ? data_in[0] : data_in[1];
end else if (N == 3) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
case (sel_in)
3'b001: data_out_r = data_in[0];
3'b010: data_out_r = data_in[1];
3'b100: data_out_r = data_in[2];
default: data_out_r = 'x;
endcase
end
assign data_out = data_out_r;
end else if (N == 4) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
case (sel_in)
4'b0001: data_out_r = data_in[0];
4'b0010: data_out_r = data_in[1];
4'b0100: data_out_r = data_in[2];
4'b1000: data_out_r = data_in[3];
default: data_out_r = 'x;
endcase
end
assign data_out = data_out_r;
end else if (N == 5) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
case (sel_in)
5'b00001: data_out_r = data_in[0];
5'b00010: data_out_r = data_in[1];
5'b00100: data_out_r = data_in[2];
5'b01000: data_out_r = data_in[3];
5'b10000: data_out_r = data_in[4];
default: data_out_r = 'x;
endcase
end
assign data_out = data_out_r;
end else if (N == 6) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
case (sel_in)
6'b000001: data_out_r = data_in[0];
6'b000010: data_out_r = data_in[1];
6'b000100: data_out_r = data_in[2];
6'b001000: data_out_r = data_in[3];
6'b010000: data_out_r = data_in[4];
6'b100000: data_out_r = data_in[5];
default: data_out_r = 'x;
endcase
end
assign data_out = data_out_r;
end else if (N == 7) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
case (sel_in)
7'b0000001: data_out_r = data_in[0];
7'b0000010: data_out_r = data_in[1];
7'b0000100: data_out_r = data_in[2];
7'b0001000: data_out_r = data_in[3];
7'b0010000: data_out_r = data_in[4];
7'b0100000: data_out_r = data_in[5];
7'b1000000: data_out_r = data_in[6];
default: data_out_r = 'x;
endcase
end
assign data_out = data_out_r;
end else if (N == 8) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
case (sel_in)
8'b00000001: data_out_r = data_in[0];
8'b00000010: data_out_r = data_in[1];
8'b00000100: data_out_r = data_in[2];
8'b00001000: data_out_r = data_in[3];
8'b00010000: data_out_r = data_in[4];
8'b00100000: data_out_r = data_in[5];
8'b01000000: data_out_r = data_in[6];
8'b10000000: data_out_r = data_in[7];
default: data_out_r = 'x;
endcase
end
assign data_out = data_out_r;
end else begin
if (MODEL == 1) begin
for (genvar i = 0; i < N; ++i) begin
assign data_out = sel_in[i] ? data_in[i] : 'z;
reg [DATAW-1:0] data_out_r;
always @(*) begin
data_out_r = 'x;
for (integer i = 0; i < N; ++i) begin
if (sel_in[i]) begin
data_out_r = data_in[i];
end
end
end
assign data_out = data_out_r;
end else if (MODEL == 2) begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
@@ -36,22 +143,8 @@ module VX_onehot_mux #(
end
assign data_out[i] = (| gather);
end
end else begin
reg [DATAW-1:0] data_out_r;
always @(*) begin
data_out_r = 'x;
for (integer i = N-1; i >= 0; --i) begin
if (sel_in[i]) begin
data_out_r = data_in[i];
end
end
end
assign data_out = data_out_r;
end
end else begin
`UNUSED_VAR (sel_in)
assign data_out = data_in;
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,49 +1,102 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_pending_size #(
parameter SIZE = 1,
parameter SIZEW = $clog2(SIZE+1)
parameter INCRW = 1,
parameter DECRW = 1,
parameter SIZEW = `CLOG2(SIZE+1)
) (
input wire clk,
input wire reset,
input wire incr,
input wire decr,
input wire [INCRW-1:0] incr,
input wire [DECRW-1:0] decr,
output wire empty,
output wire full,
output wire [SIZEW-1:0] size
);
localparam ADDRW = $clog2(SIZE);
`STATIC_ASSERT(INCRW <= SIZEW, ("invalid parameter"))
`STATIC_ASSERT(DECRW <= SIZEW, ("invalid parameter"))
localparam ADDRW = `LOG2UP(SIZE);
reg [ADDRW-1:0] used_r;
reg empty_r;
reg full_r;
reg empty_r;
reg full_r;
always @(posedge clk) begin
if (reset) begin
used_r <= 0;
empty_r <= 1;
full_r <= 0;
end else begin
`ASSERT(!incr || !full, ("runtime error"));
if (incr) begin
if (!decr) begin
empty_r <= 0;
if (used_r == ADDRW'(SIZE-1))
full_r <= 1;
end
end else if (decr) begin
full_r <= 0;
if (used_r == ADDRW'(1))
empty_r <= 1;
if (INCRW != 1 || DECRW != 1) begin
reg [SIZEW-1:0] size_r;
wire [SIZEW-1:0] size_n;
assign size_n = size_r + SIZEW'(incr) - SIZEW'(decr);
always @(posedge clk) begin
if (reset) begin
size_r <= '0;
empty_r <= 1;
full_r <= 0;
end else begin
size_r <= size_n;
empty_r <= (size_n == SIZEW'(0));
full_r <= (size_n == SIZEW'(SIZE));
end
used_r <= used_r + ADDRW'($signed(2'(incr && !decr) - 2'(decr && !incr)));
end
assign size = size_r;
end else begin
reg [ADDRW-1:0] used_r;
always @(posedge clk) begin
if (reset) begin
used_r <= '0;
empty_r <= 1;
full_r <= 0;
end else begin
`ASSERT(~(incr && ~decr) || ~full, ("runtime error: incrementing full counter"));
`ASSERT(~(decr && ~incr) || ~empty, ("runtime error: decrementing empty counter"));
if (incr) begin
if (~decr) begin
empty_r <= 0;
if (used_r == ADDRW'(SIZE-1))
full_r <= 1;
end
end else if (decr) begin
full_r <= 0;
if (used_r == ADDRW'(1))
empty_r <= 1;
end
used_r <= $signed(used_r) + ADDRW'($signed(2'(incr) - 2'(decr)));
end
end
if (SIZE > 1) begin
if (SIZEW > ADDRW) begin
assign size = {full_r, used_r};
end else begin
assign size = used_r;
end
end else begin
assign size = full_r;
end
end
assign empty = empty_r;
assign full = full_r;
assign size = {full_r, used_r};
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,9 +1,22 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_pipe_register #(
parameter DATAW = 1,
parameter RESETW = DATAW,
parameter RESETW = 0,
parameter DEPTH = 1
) (
input wire clk,
@@ -12,7 +25,6 @@ module VX_pipe_register #(
input wire [DATAW-1:0] data_in,
output wire [DATAW-1:0] data_out
);
if (DEPTH == 0) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
@@ -60,18 +72,22 @@ module VX_pipe_register #(
assign data_out = {value_r, value_d};
end
end else begin
VX_shift_register #(
.DATAW (DATAW),
.RESETW (RESETW),
.DEPTH (DEPTH)
) shift_reg (
.clk (clk),
.reset (reset),
.enable (enable),
.data_in (data_in),
.data_out (data_out)
);
wire [DEPTH:0][DATAW-1:0] data_delayed;
assign data_delayed[0] = data_in;
for (genvar i = 1; i <= DEPTH; ++i) begin
VX_pipe_register #(
.DATAW (DATAW),
.RESETW (RESETW)
) pipe_reg (
.clk (clk),
.reset (reset),
.enable (enable),
.data_in (data_delayed[i-1]),
.data_out (data_delayed[i])
);
end
assign data_out = data_delayed[DEPTH];
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,49 +1,209 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_popcount63(
input wire [5:0] data_in,
output wire [2:0] data_out
);
reg [2:0] sum;
always @(*) begin
case (data_in)
6'd0: sum=3'd0; 6'd1: sum=3'd1; 6'd2: sum=3'd1; 6'd3: sum=3'd2;
6'd4: sum=3'd1; 6'd5: sum=3'd2; 6'd6: sum=3'd2; 6'd7: sum=3'd3;
6'd8: sum=3'd1; 6'd9: sum=3'd2; 6'd10: sum=3'd2; 6'd11: sum=3'd3;
6'd12: sum=3'd2; 6'd13: sum=3'd3; 6'd14: sum=3'd3; 6'd15: sum=3'd4;
6'd16: sum=3'd1; 6'd17: sum=3'd2; 6'd18: sum=3'd2; 6'd19: sum=3'd3;
6'd20: sum=3'd2; 6'd21: sum=3'd3; 6'd22: sum=3'd3; 6'd23: sum=3'd4;
6'd24: sum=3'd2; 6'd25: sum=3'd3; 6'd26: sum=3'd3; 6'd27: sum=3'd4;
6'd28: sum=3'd3; 6'd29: sum=3'd4; 6'd30: sum=3'd4; 6'd31: sum=3'd5;
6'd32: sum=3'd1; 6'd33: sum=3'd2; 6'd34: sum=3'd2; 6'd35: sum=3'd3;
6'd36: sum=3'd2; 6'd37: sum=3'd3; 6'd38: sum=3'd3; 6'd39: sum=3'd4;
6'd40: sum=3'd2; 6'd41: sum=3'd3; 6'd42: sum=3'd3; 6'd43: sum=3'd4;
6'd44: sum=3'd3; 6'd45: sum=3'd4; 6'd46: sum=3'd4; 6'd47: sum=3'd5;
6'd48: sum=3'd2; 6'd49: sum=3'd3; 6'd50: sum=3'd3; 6'd51: sum=3'd4;
6'd52: sum=3'd3; 6'd53: sum=3'd4; 6'd54: sum=3'd4; 6'd55: sum=3'd5;
6'd56: sum=3'd3; 6'd57: sum=3'd4; 6'd58: sum=3'd4; 6'd59: sum=3'd5;
6'd60: sum=3'd4; 6'd61: sum=3'd5; 6'd62: sum=3'd5; 6'd63: sum=3'd6;
endcase
end
assign data_out = sum;
endmodule
module VX_popcount32(
input wire [2:0] data_in,
output wire [1:0] data_out
);
reg [1:0] sum;
always @(*) begin
case (data_in)
3'd0: sum=2'd0; 3'd1: sum=2'd1; 3'd2: sum=2'd1; 3'd3: sum=2'd2;
3'd4: sum=2'd1; 3'd5: sum=2'd2; 3'd6: sum=2'd2; 3'd7: sum=2'd3;
endcase
end
assign data_out = sum;
endmodule
module VX_sum33(
input wire [2:0] data_in1,
input wire [2:0] data_in2,
output wire [3:0] data_out
);
reg [3:0] sum;
always @(*) begin
case ({data_in1, data_in2})
6'd0: sum=4'd0; 6'd1: sum=4'd1; 6'd2: sum=4'd2; 6'd3: sum=4'd3;
6'd4: sum=4'd4; 6'd5: sum=4'd5; 6'd6: sum=4'd6; 6'd7: sum=4'd7;
6'd8: sum=4'd1; 6'd9: sum=4'd2; 6'd10: sum=4'd3; 6'd11: sum=4'd4;
6'd12: sum=4'd5; 6'd13: sum=4'd6; 6'd14: sum=4'd7; 6'd15: sum=4'd8;
6'd16: sum=4'd2; 6'd17: sum=4'd3; 6'd18: sum=4'd4; 6'd19: sum=4'd5;
6'd20: sum=4'd6; 6'd21: sum=4'd7; 6'd22: sum=4'd8; 6'd23: sum=4'd9;
6'd24: sum=4'd3; 6'd25: sum=4'd4; 6'd26: sum=4'd5; 6'd27: sum=4'd6;
6'd28: sum=4'd7; 6'd29: sum=4'd8; 6'd30: sum=4'd9; 6'd31: sum=4'd10;
6'd32: sum=4'd4; 6'd33: sum=4'd5; 6'd34: sum=4'd6; 6'd35: sum=4'd7;
6'd36: sum=4'd8; 6'd37: sum=4'd9; 6'd38: sum=4'd10; 6'd39: sum=4'd11;
6'd40: sum=4'd5; 6'd41: sum=4'd6; 6'd42: sum=4'd7; 6'd43: sum=4'd8;
6'd44: sum=4'd9; 6'd45: sum=4'd10; 6'd46: sum=4'd11; 6'd47: sum=4'd12;
6'd48: sum=4'd6; 6'd49: sum=4'd7; 6'd50: sum=4'd8; 6'd51: sum=4'd9;
6'd52: sum=4'd10; 6'd53: sum=4'd11; 6'd54: sum=4'd12; 6'd55: sum=4'd13;
6'd56: sum=4'd7; 6'd57: sum=4'd8; 6'd58: sum=4'd9; 6'd59: sum=4'd10;
6'd60: sum=4'd11; 6'd61: sum=4'd12; 6'd62: sum=4'd13; 6'd63: sum=4'd14;
endcase
end
assign data_out = sum;
endmodule
module VX_popcount #(
parameter MODEL = 1,
parameter N = 1,
parameter M = $clog2(N+1)
parameter M = `CLOG2(N+1)
) (
input wire [N-1:0] in_i,
output wire [M-1:0] cnt_o
input wire [N-1:0] data_in,
output wire [M-1:0] data_out
);
`UNUSED_PARAM (MODEL)
`UNUSED_PARAM (MODEL)
`ifndef SYNTHESIS
assign cnt_o = $countones(in_i);
`else
`ifdef QUARTUS
assign cnt_o = $countones(in_i);
assign data_out = $countones(data_in);
`elsif QUARTUS
assign data_out = $countones(data_in);
`else
if (N == 1) begin
assign cnt_o = in_i;
assign data_out = data_in;
end else if (N <= 3) begin
reg [2:0] t_in;
wire [1:0] t_out;
always @(*) begin
t_in = '0;
t_in[N-1:0] = data_in;
end
VX_popcount32 pc32(t_in, t_out);
assign data_out = t_out[M-1:0];
end else if (N <= 6) begin
reg [5:0] t_in;
wire [2:0] t_out;
always @(*) begin
t_in = '0;
t_in[N-1:0] = data_in;
end
VX_popcount63 pc63(t_in, t_out);
assign data_out = t_out[M-1:0];
end else if (N <= 9) begin
reg [8:0] t_in;
wire [4:0] t1_out;
wire [3:0] t2_out;
always @(*) begin
t_in = '0;
t_in[N-1:0] = data_in;
end
VX_popcount63 pc63(t_in[5:0], t1_out[2:0]);
VX_popcount32 pc32(t_in[8:6], t1_out[4:3]);
VX_sum33 sum33(t1_out[2:0], {1'b0, t1_out[4:3]}, t2_out);
assign data_out = t2_out[M-1:0];
end else if (N <= 12) begin
reg [11:0] t_in;
wire [5:0] t1_out;
wire [3:0] t2_out;
always @(*) begin
t_in = '0;
t_in[N-1:0] = data_in;
end
VX_popcount63 pc63a(t_in[5:0], t1_out[2:0]);
VX_popcount63 pc63b(t_in[11:6], t1_out[5:3]);
VX_sum33 sum33(t1_out[2:0], t1_out[5:3], t2_out);
assign data_out = t2_out[M-1:0];
end else if (N <= 18) begin
reg [17:0] t_in;
wire [8:0] t1_out;
wire [5:0] t2_out;
always @(*) begin
t_in = '0;
t_in[N-1:0] = data_in;
end
VX_popcount63 pc63a(t_in[5:0], t1_out[2:0]);
VX_popcount63 pc63b(t_in[11:6], t1_out[5:3]);
VX_popcount63 pc63c(t_in[17:12], t1_out[8:6]);
VX_popcount32 pc32a({t1_out[0], t1_out[3], t1_out[6]}, t2_out[1:0]);
VX_popcount32 pc32b({t1_out[1], t1_out[4], t1_out[7]}, t2_out[3:2]);
VX_popcount32 pc32c({t1_out[2], t1_out[5], t1_out[8]}, t2_out[5:4]);
assign data_out = {2'b0,t2_out[1:0]} + {1'b0,t2_out[3:2],1'b0} + {t2_out[5:4],2'b0};
end else if (MODEL == 1) begin
`IGNORE_WARNINGS_BEGIN
localparam PN = 1 << $clog2(N);
localparam LOGPN = $clog2(PN);
wire [M-1:0] tmp [0:PN-1] [0:PN-1];
for (genvar i = 0; i < N; ++i) begin
assign tmp[0][i] = in_i[i];
end
for (genvar i = N; i < PN; ++i) begin
assign tmp[0][i] = '0;
end
localparam PN = 1 << `CLOG2(N);
localparam LOGPN = `CLOG2(PN);
`IGNORE_UNOPTFLAT_BEGIN
wire [M-1:0] tmp [LOGPN-1:0][PN-1:0];
`IGNORE_UNOPTFLAT_END
for (genvar j = 0; j < LOGPN; ++j) begin
for (genvar i = 0; i < (1 << (LOGPN-j-1)); ++i) begin
assign tmp[j+1][i] = tmp[j][i*2] + tmp[j][i*2+1];
localparam D = j + 1;
localparam Q = (D < LOGPN) ? (D + 1) : M;
for (genvar i = 0; i < (1 << (LOGPN-j-1)); ++i) begin
localparam l = i * 2;
localparam r = i * 2 + 1;
wire [Q-1:0] res;
if (j == 0) begin
if (r < N) begin
assign res = data_in[l] + data_in[r];
end else if (l < N) begin
assign res = 2'(data_in[l]);
end else begin
assign res = 2'b0;
end
end else begin
assign res = D'(tmp[j-1][l]) + D'(tmp[j-1][r]);
end
assign tmp[j][i] = M'(res);
end
end
assign cnt_o = tmp[LOGPN][0];
`IGNORE_WARNINGS_END
assign data_out = tmp[LOGPN-1][0];
end else begin
reg [M-1:0] cnt_r;
@@ -51,17 +211,14 @@ module VX_popcount #(
always @(*) begin
cnt_r = '0;
for (integer i = 0; i < N; ++i) begin
`IGNORE_WARNINGS_BEGIN
cnt_r = cnt_r + in_i[i];
`IGNORE_WARNINGS_END
cnt_r = cnt_r + M'(data_in[i]);
end
end
assign cnt_o = cnt_r;
assign data_out = cnt_r;
end
`endif
`endif
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,28 +1,40 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_fixed_arbiter #(
module VX_priority_arbiter #(
parameter NUM_REQS = 1,
parameter LOCK_ENABLE = 0,
parameter LOG_NUM_REQS = $clog2(NUM_REQS)
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire [NUM_REQS-1:0] requests,
input wire enable,
input wire unlock,
output wire [LOG_NUM_REQS-1:0] grant_index,
output wire [NUM_REQS-1:0] grant_onehot,
output wire grant_valid
);
);
`UNUSED_PARAM (LOCK_ENABLE)
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
`UNUSED_VAR (enable)
`UNUSED_VAR (unlock)
if (NUM_REQS == 1) begin
assign grant_index = 0;
assign grant_index = '0;
assign grant_onehot = requests;
assign grant_valid = requests[0];
@@ -30,7 +42,7 @@ module VX_fixed_arbiter #(
VX_priority_encoder #(
.N (NUM_REQS)
) tid_select (
) priority_encoder (
.data_in (requests),
.index (grant_index),
.onehot (grant_onehot),
@@ -40,4 +52,4 @@ module VX_fixed_arbiter #(
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,3 +1,16 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
@@ -14,7 +27,7 @@ module VX_priority_encoder #(
);
wire [N-1:0] reversed;
if (REVERSE) begin
if (REVERSE != 0) begin
for (genvar i = 0; i < N; ++i) begin
assign reversed[N-i-1] = data_in[i];
end
@@ -25,7 +38,7 @@ module VX_priority_encoder #(
if (N == 1) begin
assign onehot = reversed;
assign index = 0;
assign index = '0;
assign valid_out = reversed;
end else if (N == 2) begin
@@ -47,11 +60,12 @@ module VX_priority_encoder #(
);
VX_lzc #(
.N (N)
.N (N),
.REVERSE (1)
) lzc (
.in_i (reversed),
.cnt_o (index),
`UNUSED_PIN (valid_o)
.data_in (reversed),
.data_out (index),
`UNUSED_PIN (valid_out)
);
assign onehot = scan_lo & {(~scan_lo[N-2:0]), 1'b1};
@@ -67,23 +81,25 @@ module VX_priority_encoder #(
assign onehot[N-1:0] = reversed[N-1:0] & ~higher_pri_regs[N-1:0];
VX_lzc #(
.N (N)
.N (N),
.REVERSE (1)
) lzc (
.in_i (reversed),
.cnt_o (index),
.valid_o (valid_out)
.data_in (reversed),
.data_out (index),
.valid_out (valid_out)
);
end else if (MODEL == 3) begin
assign onehot = reversed & ~(reversed-1);
assign onehot = reversed & -reversed;
VX_lzc #(
.N (N)
.N (N),
.REVERSE (1)
) lzc (
.in_i (reversed),
.cnt_o (index),
.valid_o (valid_out)
.data_in (reversed),
.data_out (index),
.valid_out (valid_out)
);
end else begin
@@ -97,7 +113,7 @@ module VX_priority_encoder #(
for (integer i = N-1; i >= 0; --i) begin
if (reversed[i]) begin
index_r = LN'(i);
onehot_r = 0;
onehot_r = '0;
onehot_r[i] = 1'b1;
end
end
@@ -110,4 +126,4 @@ module VX_priority_encoder #(
end
endmodule
`TRACING_ON
`TRACING_ON

72
hw/rtl/libs/VX_reduce.sv Normal file
View File

@@ -0,0 +1,72 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_reduce #(
parameter DATAW_IN = 1,
parameter DATAW_OUT = DATAW_IN,
parameter N = 1,
parameter `STRING OP = "+"
) (
input wire [N-1:0][DATAW_IN-1:0] data_in,
output wire [DATAW_OUT-1:0] data_out
);
if (N == 1) begin
assign data_out = DATAW_OUT'(data_in[0]);
end else begin
localparam int N_A = N / 2;
localparam int N_B = N - N_A;
wire [N_A-1:0][DATAW_IN-1:0] in_A;
wire [N_B-1:0][DATAW_IN-1:0] in_B;
wire [DATAW_OUT-1:0] out_A, out_B;
for (genvar i = 0; i < N_A; i++) begin
assign in_A[i] = data_in[i];
end
for (genvar i = 0; i < N_B; i++) begin
assign in_B[i] = data_in[N_A + i];
end
VX_reduce #(
.DATAW_IN (DATAW_IN),
.DATAW_OUT (DATAW_OUT),
.N (N_A),
.OP (OP)
) reduce_A (
.data_in (in_A),
.data_out (out_A)
);
VX_reduce #(
.DATAW_IN (DATAW_IN),
.DATAW_OUT (DATAW_OUT),
.N (N_B),
.OP (OP)
) reduce_B (
.data_in (in_B),
.data_out (out_B)
);
if (OP == "+") assign data_out = out_A + out_B;
else if (OP == "^") assign data_out = out_A ^ out_B;
else if (OP == "&") assign data_out = out_A & out_B;
else if (OP == "|") assign data_out = out_A | out_B;
else `ERROR(("invalid parameter"));
end
endmodule
`TRACING_ON

View File

@@ -1,31 +1,43 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_reset_relay #(
parameter N = 1,
parameter DEPTH = 1
parameter N = 1,
parameter MAX_FANOUT = 0
) (
input wire clk,
input wire reset,
input wire clk,
input wire reset,
output wire [N-1:0] reset_o
);
if (DEPTH > 1) begin
`PRESERVE_REG `DISABLE_BRAM reg [N-1:0] reset_r [DEPTH-1:0];
always @(posedge clk) begin
for (integer i = DEPTH-1; i > 0; --i)
reset_r[i] <= reset_r[i-1];
reset_r[0] <= {N{reset}};
end
assign reset_o = reset_r[DEPTH-1];
end else if (DEPTH == 1) begin
`PRESERVE_REG reg [N-1:0] reset_r;
always @(posedge clk) begin
reset_r <= {N{reset}};
);
if (MAX_FANOUT >= 0 && N > (MAX_FANOUT + MAX_FANOUT/2)) begin
localparam F = `UP(MAX_FANOUT);
localparam R = N / F;
`PRESERVE_NET reg [R-1:0] reset_r;
for (genvar i = 0; i < R; ++i) begin
always @(posedge clk) begin
reset_r[i] <= reset;
end
end
for (genvar i = 0; i < N; ++i) begin
assign reset_o[i] = reset_r[i / F];
end
assign reset_o = reset_r;
end else begin
`UNUSED_VAR (clk)
assign reset_o = {N{reset}};
end
endmodule
endmodule
`TRACING_ON

View File

@@ -1,3 +1,16 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
@@ -5,23 +18,23 @@ module VX_rr_arbiter #(
parameter NUM_REQS = 1,
parameter LOCK_ENABLE = 0,
parameter MODEL = 1,
parameter LOG_NUM_REQS = $clog2(NUM_REQS)
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire enable,
input wire unlock,
input wire [NUM_REQS-1:0] requests,
output wire [LOG_NUM_REQS-1:0] grant_index,
output wire [NUM_REQS-1:0] grant_onehot,
output wire grant_valid
);
);
if (NUM_REQS == 1) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
`UNUSED_VAR (unlock)
assign grant_index = 0;
assign grant_index = '0;
assign grant_onehot = requests;
assign grant_valid = requests[0];
@@ -41,8 +54,8 @@ module VX_rr_arbiter #(
always @(posedge clk) begin
if (reset) begin
state <= 0;
end else if (!LOCK_ENABLE || enable) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
@@ -51,7 +64,37 @@ module VX_rr_arbiter #(
assign grant_onehot = grant_onehot_r;
assign grant_valid = (| requests);
end else if (NUM_REQS == 4) begin
end /*else if (NUM_REQS == 3) begin
reg [LOG_NUM_REQS-1:0] grant_index_r;
reg [NUM_REQS-1:0] grant_onehot_r;
reg [LOG_NUM_REQS-1:0] state;
always @(*) begin
casez ({state, requests})
5'b00_001,
5'b01_0?1,
5'b10_??1: begin grant_onehot_r = 3'b001; grant_index_r = LOG_NUM_REQS'(0); end
5'b00_?1?,
5'b01_010,
5'b10_?10: begin grant_onehot_r = 3'b010; grant_index_r = LOG_NUM_REQS'(1); end
default: begin grant_onehot_r = 3'b100; grant_index_r = LOG_NUM_REQS'(2); end
endcase
end
always @(posedge clk) begin
if (reset) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
assign grant_index = grant_index_r;
assign grant_onehot = grant_onehot_r;
assign grant_valid = (| requests);
end */else if (NUM_REQS == 4) begin
reg [LOG_NUM_REQS-1:0] grant_index_r;
reg [NUM_REQS-1:0] grant_onehot_r;
@@ -77,8 +120,8 @@ module VX_rr_arbiter #(
always @(posedge clk) begin
if (reset) begin
state <= 0;
end else if (!LOCK_ENABLE || enable) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
@@ -87,7 +130,171 @@ module VX_rr_arbiter #(
assign grant_onehot = grant_onehot_r;
assign grant_valid = (| requests);
end else if (NUM_REQS == 8) begin
end /*else if (NUM_REQS == 5) begin
reg [LOG_NUM_REQS-1:0] grant_index_r;
reg [NUM_REQS-1:0] grant_onehot_r;
reg [LOG_NUM_REQS-1:0] state;
always @(*) begin
casez ({state, requests})
8'b000_00001,
8'b001_000?1,
8'b010_00??1,
8'b011_0???1,
8'b100_????1: begin grant_onehot_r = 5'b00001; grant_index_r = LOG_NUM_REQS'(0); end
8'b000_???1?,
8'b001_00010,
8'b010_00?10,
8'b011_0??10,
8'b100_???10: begin grant_onehot_r = 5'b00010; grant_index_r = LOG_NUM_REQS'(1); end
8'b000_??10?,
8'b001_??1??,
8'b010_00100,
8'b011_0?100,
8'b100_??100: begin grant_onehot_r = 5'b00100; grant_index_r = LOG_NUM_REQS'(2); end
8'b000_?100?,
8'b001_?10??,
8'b010_?1???,
8'b011_01000,
8'b100_?1000: begin grant_onehot_r = 5'b01000; grant_index_r = LOG_NUM_REQS'(3); end
default: begin grant_onehot_r = 5'b10000; grant_index_r = LOG_NUM_REQS'(4); end
endcase
end
always @(posedge clk) begin
if (reset) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
assign grant_index = grant_index_r;
assign grant_onehot = grant_onehot_r;
assign grant_valid = (| requests);
end else if (NUM_REQS == 6) begin
reg [LOG_NUM_REQS-1:0] grant_index_r;
reg [NUM_REQS-1:0] grant_onehot_r;
reg [LOG_NUM_REQS-1:0] state;
always @(*) begin
casez ({state, requests})
9'b000_000001,
9'b001_0000?1,
9'b010_000??1,
9'b011_00???1,
9'b100_0????1,
9'b101_?????1: begin grant_onehot_r = 6'b000001; grant_index_r = LOG_NUM_REQS'(0); end
9'b000_????1?,
9'b001_000010,
9'b010_000?10,
9'b011_00??10,
9'b100_0???10,
9'b101_????10: begin grant_onehot_r = 6'b000010; grant_index_r = LOG_NUM_REQS'(1); end
9'b000_???10?,
9'b001_???1??,
9'b010_000100,
9'b011_00?100,
9'b100_0??100,
9'b101_???100: begin grant_onehot_r = 6'b000100; grant_index_r = LOG_NUM_REQS'(2); end
9'b000_??100?,
9'b001_??10??,
9'b010_??1???,
9'b011_001000,
9'b100_0?1000,
9'b101_??1000: begin grant_onehot_r = 6'b001000; grant_index_r = LOG_NUM_REQS'(3); end
9'b000_?1000?,
9'b001_?100??,
9'b010_?10???,
9'b011_?1????,
9'b100_010000,
9'b101_?10000: begin grant_onehot_r = 6'b010000; grant_index_r = LOG_NUM_REQS'(4); end
default: begin grant_onehot_r = 6'b100000; grant_index_r = LOG_NUM_REQS'(5); end
endcase
end
always @(posedge clk) begin
if (reset) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
assign grant_index = grant_index_r;
assign grant_onehot = grant_onehot_r;
assign grant_valid = (| requests);
end else if (NUM_REQS == 7) begin
reg [LOG_NUM_REQS-1:0] grant_index_r;
reg [NUM_REQS-1:0] grant_onehot_r;
reg [LOG_NUM_REQS-1:0] state;
always @(*) begin
casez ({state, requests})
10'b000_000001,
10'b001_0000?1,
10'b010_000??1,
10'b011_00???1,
10'b100_00???1,
10'b101_0????1,
10'b110_?????1: begin grant_onehot_r = 7'b0000001; grant_index_r = LOG_NUM_REQS'(0); end
10'b000_?????1?,
10'b001_0000010,
10'b010_0000?10,
10'b011_000??10,
10'b100_00???10,
10'b101_0????10,
10'b110_?????10: begin grant_onehot_r = 7'b0000010; grant_index_r = LOG_NUM_REQS'(1); end
10'b000_????10?,
10'b001_????1??,
10'b010_0000100,
10'b011_000?100,
10'b100_00??100,
10'b101_0???100,
10'b110_????100: begin grant_onehot_r = 7'b0000100; grant_index_r = LOG_NUM_REQS'(2); end
10'b000_???100?,
10'b001_???10??,
10'b010_???1???,
10'b011_0001000,
10'b100_00?1000,
10'b101_0??1000,
10'b110_???1000: begin grant_onehot_r = 7'b0001000; grant_index_r = LOG_NUM_REQS'(3); end
10'b000_??1000?,
10'b001_??100??,
10'b010_??10???,
10'b011_??1????,
10'b100_0010000,
10'b101_0?10000,
10'b110_??10000: begin grant_onehot_r = 7'b0010000; grant_index_r = LOG_NUM_REQS'(4); end
10'b000_?10000?,
10'b001_?1000??,
10'b010_?100???,
10'b011_?10????,
10'b100_?1?????,
10'b101_0100000,
10'b110_?100000: begin grant_onehot_r = 7'b0100000; grant_index_r = LOG_NUM_REQS'(5); end
default: begin grant_onehot_r = 7'b1000000; grant_index_r = LOG_NUM_REQS'(6); end
endcase
end
always @(posedge clk) begin
if (reset) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
assign grant_index = grant_index_r;
assign grant_onehot = grant_onehot_r;
assign grant_valid = (| requests);
end */else if (NUM_REQS == 8) begin
reg [LOG_NUM_REQS-1:0] grant_index_r;
reg [NUM_REQS-1:0] grant_onehot_r;
@@ -157,8 +364,8 @@ module VX_rr_arbiter #(
always @(posedge clk) begin
if (reset) begin
state <= 0;
end else if (!LOCK_ENABLE || enable) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
@@ -169,9 +376,9 @@ module VX_rr_arbiter #(
end else if (MODEL == 1) begin
`IGNORE_WARNINGS_BEGIN
`IGNORE_UNOPTFLAT_BEGIN
wire [NUM_REQS-1:0] mask_higher_pri_regs, unmask_higher_pri_regs;
`IGNORE_WARNINGS_END
`IGNORE_UNOPTFLAT_END
wire [NUM_REQS-1:0] grant_masked, grant_unmasked;
reg [NUM_REQS-1:0] pointer_reg;
@@ -192,7 +399,7 @@ module VX_rr_arbiter #(
always @(posedge clk) begin
if (reset) begin
pointer_reg <= {NUM_REQS{1'b1}};
end else if (!LOCK_ENABLE || enable) begin
end else if (!LOCK_ENABLE || unlock) begin
if (|req_masked) begin
pointer_reg <= mask_higher_pri_regs;
end else if (|requests) begin
@@ -235,8 +442,8 @@ module VX_rr_arbiter #(
always @(posedge clk) begin
if (reset) begin
state <= 0;
end else if (!LOCK_ENABLE || enable) begin
state <= '0;
end else if (!LOCK_ENABLE || unlock) begin
state <= grant_index_r;
end
end
@@ -247,4 +454,4 @@ module VX_rr_arbiter #(
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,3 +1,16 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
// Fast Paralllel scan using Kogge-Stone style prefix tree with configurable operator
@@ -12,14 +25,14 @@ module VX_scan #(
input wire [N-1:0] data_in,
output wire [N-1:0] data_out
);
`IGNORE_WARNINGS_BEGIN
localparam LOGN = $clog2(N);
localparam LOGN = `CLOG2(N);
`IGNORE_UNOPTFLAT_BEGIN
wire [LOGN:0][N-1:0] t;
`IGNORE_UNOPTFLAT_END
// reverses bits
if (REVERSE) begin
if (REVERSE != 0) begin
assign t[0] = data_in;
end else begin
assign t[0] = {<<{data_in}};
@@ -35,7 +48,7 @@ module VX_scan #(
end else begin
// general case
wire [N-1:0] fill;
for (genvar i = 0; i < LOGN; i++) begin
for (genvar i = 0; i < LOGN; ++i) begin
wire [N-1:0] shifted = N'({fill, t[i]} >> (1<<i));
if (OP == 0) begin
assign fill = {N{1'b0}};
@@ -51,14 +64,13 @@ module VX_scan #(
end
// reverse bits
if (REVERSE) begin
if (REVERSE != 0) begin
assign data_out = t[LOGN];
end else begin
for (genvar i = 0; i < N; i++) begin
for (genvar i = 0; i < N; ++i) begin
assign data_out[i] = t[LOGN][N-1-i];
end
end
`IGNORE_WARNINGS_END
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,244 +0,0 @@
`include "VX_platform.vh"
`TRACING_OFF
module VX_scope #(
parameter DATAW = 64,
parameter BUSW = 64,
parameter SIZE = 16,
parameter UPDW = 1,
parameter DELTAW = 16
) (
input wire clk,
input wire reset,
input wire start,
input wire stop,
input wire changed,
input wire [DATAW-1:0] data_in,
input wire [BUSW-1:0] bus_in,
output wire [BUSW-1:0] bus_out,
input wire bus_write,
input wire bus_read
);
localparam UPDW_ENABLE = (UPDW != 0);
localparam MAX_DELTA = (2 ** DELTAW) - 1;
localparam CMD_GET_VALID = 3'd0;
localparam CMD_GET_DATA = 3'd1;
localparam CMD_GET_WIDTH = 3'd2;
localparam CMD_GET_COUNT = 3'd3;
localparam CMD_SET_START = 3'd4;
localparam CMD_SET_STOP = 3'd5;
localparam CMD_GET_OFFSET= 3'd6;
localparam GET_VALID = 3'd0;
localparam GET_DATA = 3'd1;
localparam GET_WIDTH = 3'd2;
localparam GET_COUNT = 3'd3;
localparam GET_OFFSET = 3'd6;
`NO_RW_RAM_CHECK reg [DATAW-1:0] data_store [SIZE-1:0];
`NO_RW_RAM_CHECK reg [DELTAW-1:0] delta_store [SIZE-1:0];
reg [UPDW-1:0] prev_trigger_id;
reg [DELTAW-1:0] delta;
reg [BUSW-1:0] bus_out_r;
reg [63:0] timestamp, start_time;
reg [`CLOG2(SIZE)-1:0] raddr, waddr, waddr_end;
reg [`LOG2UP(DATAW)-1:0] read_offset;
reg cmd_start, started, start_wait, recording, data_valid, read_delta, delta_flush;
reg [BUSW-3:0] delay_val, delay_cntr;
reg [2:0] get_cmd;
wire [2:0] cmd_type;
wire [BUSW-4:0] cmd_data;
assign {cmd_data, cmd_type} = bus_in;
wire [UPDW-1:0] trigger_id = data_in[UPDW-1:0];
always @(posedge clk) begin
if (reset) begin
get_cmd <= $bits(get_cmd)'(CMD_GET_VALID);
raddr <= 0;
waddr <= 0;
waddr_end <= $bits(waddr)'(SIZE-1);
cmd_start <= 0;
started <= 0;
start_wait <= 0;
recording <= 0;
delay_val <= 0;
delay_cntr <= 0;
delta <= 0;
delta_flush <= 0;
prev_trigger_id <= 0;
read_offset <= 0;
read_delta <= 0;
data_valid <= 0;
timestamp <= 0;
start_time <= 0;
end else begin
timestamp <= timestamp + 1;
if (bus_write) begin
case (cmd_type)
CMD_GET_VALID,
CMD_GET_DATA,
CMD_GET_WIDTH,
CMD_GET_OFFSET,
CMD_GET_COUNT: get_cmd <= $bits(get_cmd)'(cmd_type);
CMD_SET_START: begin
delay_val <= $bits(delay_val)'(cmd_data);
cmd_start <= 1;
`ifdef DBG_TRACE_SCOPE
dpi_trace("%d: *** scope: CMD_SET_START: delay_val=%0d\n", $time, $bits(delay_val)'(cmd_data));
`endif
end
CMD_SET_STOP: begin
waddr_end <= $bits(waddr)'(cmd_data);
`ifdef DBG_TRACE_SCOPE
dpi_trace("%d: *** scope: CMD_SET_STOP: waddr_end=%0d\n", $time, $bits(waddr)'(cmd_data));
`endif
end
default:;
endcase
end
if (!started && (start || cmd_start)) begin
started <= 1;
delta_flush <= 1;
if (0 == delay_val) begin
start_wait <= 0;
recording <= 1;
delta <= 0;
delay_cntr <= 0;
start_time <= timestamp;
`ifdef DBG_TRACE_SCOPE
dpi_trace("%d: *** scope: recording start - start_time=%0d\n", $time, timestamp);
`endif
end else begin
start_wait <= 1;
delay_cntr <= delay_val;
end
end
if (start_wait) begin
delay_cntr <= delay_cntr - 1;
if (1 == delay_cntr) begin
start_wait <= 0;
recording <= 1;
delta <= 0;
start_time <= timestamp;
`ifdef DBG_TRACE_SCOPE
dpi_trace("%d: *** scope: recording start - start_time=%0d\n", $time, timestamp);
`endif
end
end
if (recording) begin
if (UPDW_ENABLE) begin
if (delta_flush
|| changed
|| (trigger_id != prev_trigger_id)) begin
delta_store[waddr] <= delta;
data_store[waddr] <= data_in;
waddr <= waddr + $bits(waddr)'(1);
delta <= 0;
delta_flush <= 0;
end else begin
delta <= delta + DELTAW'(1);
delta_flush <= (delta == (MAX_DELTA-1));
end
prev_trigger_id <= trigger_id;
end else begin
delta_store[waddr] <= 0;
data_store[waddr] <= data_in;
waddr <= waddr + 1;
end
if (stop
|| (waddr >= waddr_end)) begin
`ifdef DBG_TRACE_SCOPE
dpi_trace("%d: *** scope: recording stop - waddr=(%0d, %0d)\n", $time, waddr, waddr_end);
`endif
waddr <= waddr; // keep last address
recording <= 0;
data_valid <= 1;
read_delta <= 1;
end
end
if (bus_read
&& (get_cmd == GET_DATA)
&& data_valid) begin
if (read_delta) begin
read_delta <= 0;
end else begin
if (DATAW > BUSW) begin
if (read_offset < $bits(read_offset)'(DATAW-BUSW)) begin
read_offset <= read_offset + $bits(read_offset)'(BUSW);
end else begin
raddr <= raddr + $bits(raddr)'(1);
read_offset <= 0;
read_delta <= 1;
if (raddr == waddr) begin
data_valid <= 0;
end
end
end else begin
raddr <= raddr + 1;
read_delta <= 1;
if (raddr == waddr) begin
data_valid <= 0;
end
end
end
end
end
if (recording) begin
if (UPDW_ENABLE) begin
if (delta_flush
|| changed
|| (trigger_id != prev_trigger_id)) begin
delta_store[waddr] <= delta;
data_store[waddr] <= data_in;
end
end else begin
delta_store[waddr] <= 0;
data_store[waddr] <= data_in;
end
end
end
always @(*) begin
case (get_cmd)
GET_VALID : bus_out_r = BUSW'(data_valid);
GET_WIDTH : bus_out_r = BUSW'(DATAW);
GET_COUNT : bus_out_r = BUSW'(waddr) + BUSW'(1);
GET_OFFSET: bus_out_r = BUSW'(start_time);
/* verilator lint_off WIDTH */
GET_DATA : bus_out_r = read_delta ? BUSW'(delta_store[raddr]) : BUSW'(data_store[raddr] >> read_offset);
/* verilator lint_on WIDTH */
default : bus_out_r = 0;
endcase
end
assign bus_out = bus_out_r;
`ifdef DBG_TRACE_SCOPE
always @(posedge clk) begin
if (bus_read) begin
dpi_trace("%d: scope-read: cmd=%0d, addr=%0d, value=%0h\n", $time, get_cmd, raddr, bus_out);
end
if (bus_write) begin
dpi_trace("%d: scope-write: cmd=%0d, value=%0d\n", $time, cmd_type, cmd_data);
end
end
`endif
endmodule
`TRACING_ON

View File

@@ -0,0 +1,63 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_scope_switch #(
parameter N = 0
) (
input wire clk,
input wire reset,
input wire req_in,
output wire req_out [N],
input wire rsp_in [N],
output wire rsp_out
);
if (N > 1) begin
reg req_out_r [N];
reg rsp_out_r;
always @(posedge clk) begin
if (reset) begin
for (integer i = 0; i < N; ++i) begin
req_out_r[i] <= 0;
end
rsp_out_r <= 0;
end else begin
for (integer i = 0; i < N; ++i) begin
req_out_r[i] <= req_in;
end
rsp_out_r <= 0;
for (integer i = 0; i < N; ++i) begin
if (rsp_in[i])
rsp_out_r <= 1;
end
end
end
assign req_out = req_out_r;
assign rsp_out = rsp_out_r;
end else begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
assign req_out[0] = req_in;
assign rsp_out = rsp_in[0];
end
endmodule
`TRACING_ON

313
hw/rtl/libs/VX_scope_tap.sv Normal file
View File

@@ -0,0 +1,313 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_scope_tap #(
parameter SCOPE_ID = 0, // scope identifier
parameter SCOPE_IDW = 8, // scope identifier width
parameter TRIGGERW = 0, // trigger signals width
parameter PROBEW = 0, // probe signal width
parameter SIZE = 256, // trace buffer size
parameter IDLE_CTRW = 16 // idle time between triggers counter width
) (
input wire clk,
input wire reset,
input wire start,
input wire stop,
input wire [TRIGGERW-1:0] triggers,
input wire [PROBEW-1:0] probes,
input wire bus_in,
output wire bus_out
);
localparam TX_DATAW = 64;
localparam TX_DATA_BITS = `LOG2UP(TX_DATAW);
localparam DATAW = PROBEW + TRIGGERW;
localparam DATA_BITS = `LOG2UP(DATAW);
localparam ADDRW = `CLOG2(SIZE);
localparam TRIGGER_ENABLE = (TRIGGERW != 0);
localparam MAX_IDLE_CTR = (2 ** IDLE_CTRW) - 1;
localparam CTRL_STATE_IDLE = 2'd0;
localparam CTRL_STATE_RECV = 2'd1;
localparam CTRL_STATE_CMD = 2'd2;
localparam CTRL_STATE_SEND = 2'd3;
localparam CTRL_STATE_BITS = 2;
localparam TAP_STATE_IDLE = 2'd0;
localparam TAP_STATE_WAIT = 2'd1;
localparam TAP_STATE_RUN = 2'd2;
localparam TAP_STATE_BITS = 2;
localparam CMD_GET_WIDTH = 3'd0;
localparam CMD_GET_COUNT = 3'd1;
localparam CMD_GET_START = 3'd2;
localparam CMD_GET_DATA = 3'd3;
localparam CMD_SET_START = 3'd4;
localparam CMD_SET_STOP = 3'd5;
localparam CMD_TYPE_BITS = 3;
localparam GET_TYPE_WIDTH = 2'd0;
localparam GET_TYPE_COUNT = 2'd1;
localparam GET_TYPE_START = 2'd2;
localparam GET_TYPE_DATA = 2'd3;
localparam GET_TYPE_BITS = 2;
`NO_RW_RAM_CHECK reg [DATAW-1:0] data_store [SIZE-1:0];
`NO_RW_RAM_CHECK reg [IDLE_CTRW-1:0] delta_store [SIZE-1:0];
reg [TRIGGERW-1:0] prev_triggers;
reg [IDLE_CTRW-1:0] delta;
reg [63:0] timestamp, start_time;
reg [ADDRW-1:0] waddr, waddr_end;
reg cmd_start, delta_flush;
reg [63:0] start_delay, delay_cntr;
reg [TAP_STATE_BITS-1:0] tap_state;
reg [CTRL_STATE_BITS-1:0] ctrl_state;
reg [GET_TYPE_BITS-1:0] get_type;
reg [TX_DATA_BITS-1:0] ser_tx_ctr;
reg [DATA_BITS-1:0] read_offset;
reg [ADDRW-1:0] raddr;
reg read_data;
//
// trace capture
//
wire [ADDRW-1:0] raddr_n = raddr + 1;
wire [ADDRW:0] count = (ADDRW+1)'(waddr) + 1;
always @(posedge clk) begin
if (reset) begin
tap_state <= TAP_STATE_IDLE;
raddr <= '0;
waddr <= '0;
delta <= '0;
prev_triggers <= '0;
read_offset <= '0;
read_data <= 0;
timestamp <= '0;
end else begin
timestamp <= timestamp + 1;
case (tap_state)
TAP_STATE_IDLE: begin
if (start || cmd_start) begin
delta <= '0;
delta_flush <= 1;
if (0 == start_delay) begin
tap_state <= TAP_STATE_RUN;
start_time <= timestamp;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: recording start - time=%0d\n", $time, SCOPE_ID, timestamp));
`endif
end else begin
tap_state <= TAP_STATE_WAIT;
delay_cntr <= start_delay;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: delayed start - time=%0d\n", $time, SCOPE_ID, start_delay));
`endif
end
end
end
TAP_STATE_WAIT: begin
delay_cntr <= delay_cntr - 1;
if (1 == delay_cntr) begin
tap_state <= TAP_STATE_RUN;
start_time <= timestamp;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: recording start - time=%0d\n", $time, SCOPE_ID, timestamp));
`endif
end
end
TAP_STATE_RUN: begin
if (TRIGGER_ENABLE != 0) begin
if (delta_flush || (triggers != prev_triggers)) begin
data_store[waddr] <= {probes, triggers};
delta_store[waddr] <= delta;
waddr <= waddr + 1;
delta <= '0;
delta_flush <= 0;
end else begin
delta <= delta + 1;
delta_flush <= (delta == (MAX_IDLE_CTR-1));
end
prev_triggers <= triggers;
end else begin
data_store[waddr] <= {probes, triggers};
delta_store[waddr] <= '0;
waddr <= waddr + 1;
end
if (stop || (waddr >= waddr_end)) begin
waddr <= waddr;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: recording stop - waddr=(%0d, %0d)\n", $time, SCOPE_ID, waddr, waddr_end));
`endif
tap_state <= TAP_STATE_IDLE;
end
end
default:;
endcase
if (ctrl_state == CTRL_STATE_SEND
&& get_type == GET_TYPE_DATA
&& ser_tx_ctr == 0) begin
if (~read_data) begin
read_data <= 1;
end else begin
if (DATAW > TX_DATAW) begin
`IGNORE_WARNINGS_BEGIN
if (read_offset < DATA_BITS'(DATAW-TX_DATAW)) begin
read_offset <= read_offset + DATA_BITS'(TX_DATAW);
end else begin
raddr <= raddr_n;
read_data <= 0;
read_offset <= '0;
end
`IGNORE_WARNINGS_END
end else begin
raddr <= raddr_n;
read_data <= 0;
end
if (raddr_n == waddr) begin
raddr <= 0;
end
end
end
end
end
//
// command controller
//
reg bus_out_r;
reg [TX_DATAW-1:0] ser_buf_in;
wire [TX_DATAW-1:0] ser_buf_in_n = {ser_buf_in[TX_DATAW-2:0], bus_in};
`UNUSED_VAR (ser_buf_in)
wire [CMD_TYPE_BITS-1:0] cmd_type = ser_buf_in[CMD_TYPE_BITS-1:0];
wire [SCOPE_IDW-1:0] cmd_scope_id = ser_buf_in_n[CMD_TYPE_BITS +: SCOPE_IDW];
wire [TX_DATAW-CMD_TYPE_BITS-SCOPE_IDW-1:0] cmd_data = ser_buf_in[TX_DATAW-1:CMD_TYPE_BITS+SCOPE_IDW];
wire [TX_DATAW-1:0] data_chunk = TX_DATAW'(DATAW'(data_store[raddr] >> read_offset));
wire [TX_DATAW-1:0] get_data = read_data ? data_chunk : TX_DATAW'(delta_store[raddr]);
always @(posedge clk) begin
if (reset) begin
ctrl_state <= CTRL_STATE_IDLE;
cmd_start <= 0;
start_delay <= '0;
waddr_end <= ADDRW'(SIZE-1);
bus_out_r <= 0;
end else begin
bus_out_r <= 0;
cmd_start <= 0;
case (ctrl_state)
CTRL_STATE_IDLE: begin
if (bus_in) begin
ctrl_state <= CTRL_STATE_RECV;
end
ser_tx_ctr <= TX_DATA_BITS'(TX_DATAW-1);
end
CTRL_STATE_RECV: begin
ser_tx_ctr <= ser_tx_ctr - 1;
ser_buf_in <= ser_buf_in_n;
if (ser_tx_ctr == 0) begin
ctrl_state <= (cmd_scope_id == SCOPE_ID) ? CTRL_STATE_CMD : CTRL_STATE_IDLE;
end
end
CTRL_STATE_CMD: begin
ctrl_state <= CTRL_STATE_IDLE;
case (cmd_type)
CMD_SET_START: begin
start_delay <= 64'(cmd_data);
cmd_start <= 1;
end
CMD_SET_STOP: begin
waddr_end <= ADDRW'(cmd_data);
end
CMD_GET_WIDTH,
CMD_GET_START,
CMD_GET_COUNT,
CMD_GET_DATA: begin
ctrl_state <= CTRL_STATE_SEND;
get_type <= GET_TYPE_BITS'(cmd_type);
ser_tx_ctr <= TX_DATA_BITS'(TX_DATAW-1);
bus_out_r <= 1;
end
default:;
endcase
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: CMD: type=%0d\n", $time, SCOPE_ID, cmd_type));
`endif
end
CTRL_STATE_SEND: begin
ser_tx_ctr <= ser_tx_ctr - 1;
case (get_type)
GET_TYPE_WIDTH: begin
bus_out_r <= 1'(DATAW >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND width=%0d\n", $time, SCOPE_ID, DATAW));
end
`endif
end
GET_TYPE_COUNT: begin
bus_out_r <= 1'(count >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND count=%0d\n", $time, SCOPE_ID, count));
end
`endif
end
GET_TYPE_START: begin
bus_out_r <= 1'(start_time >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND start=%0d\n", $time, SCOPE_ID, start_time));
end
`endif
end
GET_TYPE_DATA: begin
bus_out_r <= 1'(get_data >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND data=%0d\n", $time, SCOPE_ID, get_data));
end
`endif
end
default:;
endcase
if (ser_tx_ctr == 0) begin
ctrl_state <= CTRL_STATE_IDLE;
end
end
default:;
endcase
end
end
assign bus_out = bus_out_r;
endmodule
`TRACING_ON

View File

@@ -1,32 +1,41 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_serial_div #(
parameter WIDTHN = 1,
parameter WIDTHD = 1,
parameter WIDTHQ = 1,
parameter WIDTHR = 1,
parameter LANES = 1,
parameter TAGW = 1
parameter WIDTHN = 32,
parameter WIDTHD = 32,
parameter WIDTHQ = 32,
parameter WIDTHR = 32,
parameter LANES = 1
) (
input wire clk,
input wire reset,
input wire clk,
input wire reset,
input wire valid_in,
output wire ready_in,
input wire strobe,
output wire busy,
input wire is_signed,
input wire [LANES-1:0][WIDTHN-1:0] numer,
input wire [LANES-1:0][WIDTHD-1:0] denom,
input wire signed_mode,
input wire [TAGW-1:0] tag_in,
input wire [LANES-1:0][WIDTHD-1:0] denom,
output wire [LANES-1:0][WIDTHQ-1:0] quotient,
output wire [LANES-1:0][WIDTHR-1:0] remainder,
input wire ready_out,
output wire valid_out,
output wire [TAGW-1:0] tag_out
output wire [LANES-1:0][WIDTHR-1:0] remainder
);
localparam MIN_ND = (WIDTHN < WIDTHD) ? WIDTHN : WIDTHD;
localparam CNTRW = $clog2(WIDTHN+1);
localparam CNTRW = `CLOG2(WIDTHN);
reg [LANES-1:0][WIDTHN + MIN_ND:0] working;
reg [LANES-1:0][WIDTHD-1:0] denom_r;
@@ -38,18 +47,11 @@ module VX_serial_div #(
reg [LANES-1:0] inv_quot, inv_rem;
reg [CNTRW-1:0] cntr;
reg is_busy;
reg [TAGW-1:0] tag_r;
wire done = ~(| cntr);
wire push = valid_in && ready_in;
wire pop = valid_out && ready_out;
reg busy_r;
for (genvar i = 0; i < LANES; ++i) begin
wire negate_numer = signed_mode && numer[i][WIDTHN-1];
wire negate_denom = signed_mode && denom[i][WIDTHD-1];
wire negate_numer = is_signed && numer[i][WIDTHN-1];
wire negate_denom = is_signed && denom[i][WIDTHD-1];
assign numer_qual[i] = negate_numer ? -$signed(numer[i]) : numer[i];
assign denom_qual[i] = negate_denom ? -$signed(denom[i]) : denom[i];
assign sub_result[i] = working[i][WIDTHN + MIN_ND : WIDTHN] - denom_r[i];
@@ -57,46 +59,40 @@ module VX_serial_div #(
always @(posedge clk) begin
if (reset) begin
cntr <= 0;
is_busy <= 0;
busy_r <= 0;
end else begin
if (push) begin
cntr <= WIDTHN;
is_busy <= 1;
end else if (!done) begin
cntr <= cntr - CNTRW'(1);
if (strobe) begin
busy_r <= 1;
end
if (pop) begin
is_busy <= 0;
if (busy && cntr == 0) begin
busy_r <= 0;
end
end
if (push) begin
for (integer i = 0; i < LANES; ++i) begin
working[i] <= {{WIDTHD{1'b0}}, numer_qual[i], 1'b0};
denom_r[i] <= denom_qual[i];
inv_quot[i] <= (denom[i] != 0) && signed_mode && (numer[i][31] ^ denom[i][31]);
inv_rem[i] <= signed_mode && numer[i][31];
end
tag_r <= tag_in;
end else if (!done) begin
for (integer i = 0; i < LANES; ++i) begin
working[i] <= sub_result[i][WIDTHD] ? {working[i][WIDTHN+MIN_ND-1:0], 1'b0} :
{sub_result[i][WIDTHD-1:0], working[i][WIDTHN-1:0], 1'b1};
end
cntr <= cntr - CNTRW'(1);
if (strobe) begin
cntr <= CNTRW'(WIDTHN-1);
end
end
for (genvar i = 0; i < LANES; ++i) begin
always @(posedge clk) begin
if (strobe) begin
working[i] <= {{WIDTHD{1'b0}}, numer_qual[i], 1'b0};
denom_r[i] <= denom_qual[i];
inv_quot[i] <= (denom[i] != 0) && is_signed && (numer[i][31] ^ denom[i][31]);
inv_rem[i] <= is_signed && numer[i][31];
end else if (busy_r) begin
working[i] <= sub_result[i][WIDTHD] ? {working[i][WIDTHN+MIN_ND-1:0], 1'b0} :
{sub_result[i][WIDTHD-1:0], working[i][WIDTHN-1:0], 1'b1};
end
end
wire [WIDTHQ-1:0] q = working[i][WIDTHQ-1:0];
wire [WIDTHR-1:0] r = working[i][WIDTHN+WIDTHR:WIDTHN+1];
assign quotient[i] = inv_quot[i] ? -$signed(q) : q;
assign remainder[i] = inv_rem[i] ? -$signed(r) : r;
end
assign ready_in = !is_busy;
assign tag_out = tag_r;
assign valid_out = is_busy && done;
assign busy = busy_r;
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -0,0 +1,107 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
// Iterative integer multiplier
// An adaptation of ZipCPU algorithm for a multi-lane elastic architecture.
// https://zipcpu.com/zipcpu/2021/07/03/slowmpy.html
`TRACING_OFF
module VX_serial_mul #(
parameter A_WIDTH = 32,
parameter B_WIDTH = A_WIDTH,
parameter R_WIDTH = A_WIDTH + B_WIDTH,
parameter SIGNED = 0,
parameter LANES = 1
) (
input wire clk,
input wire reset,
input wire strobe,
output wire busy,
input wire [LANES-1:0][A_WIDTH-1:0] dataa,
input wire [LANES-1:0][B_WIDTH-1:0] datab,
output wire [LANES-1:0][R_WIDTH-1:0] result
);
localparam X_WIDTH = SIGNED ? `MAX(A_WIDTH, B_WIDTH) : A_WIDTH;
localparam Y_WIDTH = SIGNED ? `MAX(A_WIDTH, B_WIDTH) : B_WIDTH;
localparam P_WIDTH = X_WIDTH + Y_WIDTH;
localparam CNTRW = `CLOG2(X_WIDTH);
reg [LANES-1:0][X_WIDTH-1:0] a;
reg [LANES-1:0][Y_WIDTH-1:0] b;
reg [LANES-1:0][P_WIDTH-1:0] p;
reg [CNTRW-1:0] cntr;
reg busy_r;
always @(posedge clk) begin
if (reset) begin
busy_r <= 0;
end else begin
if (strobe) begin
busy_r <= 1;
end
if (busy_r && cntr == 0) begin
busy_r <= 0;
end
end
cntr <= cntr - CNTRW'(1);
if (strobe) begin
cntr <= CNTRW'(X_WIDTH-1);
end
end
for (genvar i = 0; i < LANES; ++i) begin
wire [X_WIDTH-1:0] axb = b[i][0] ? a[i] : '0;
always @(posedge clk) begin
if (strobe) begin
if (SIGNED) begin
a[i] <= X_WIDTH'($signed(dataa[i]));
b[i] <= Y_WIDTH'($signed(datab[i]));
end else begin
a[i] <= dataa[i];
b[i] <= datab[i];
end
p[i] <= 0;
end else if (busy_r) begin
b[i] <= (b[i] >> 1);
p[i][Y_WIDTH-2:0] <= p[i][Y_WIDTH-1:1];
if (SIGNED) begin
if (cntr == 0) begin
p[i][P_WIDTH-1:Y_WIDTH-1] <= {1'b0, p[i][P_WIDTH-1:Y_WIDTH]} + {1'b0, axb[X_WIDTH-1], ~axb[X_WIDTH-2:0]};
end else begin
p[i][P_WIDTH-1:Y_WIDTH-1] <= {1'b0, p[i][P_WIDTH-1:Y_WIDTH]} + {1'b0, ~axb[X_WIDTH-1], axb[X_WIDTH-2:0]};
end
end else begin
p[i][P_WIDTH-1:Y_WIDTH-1] <= {1'b0, p[i][P_WIDTH-1:Y_WIDTH]} + ((b[i][0]) ? {1'b0, a[i]} : 0);
end
end
end
if (SIGNED) begin
assign result[i] = R_WIDTH'(p[i][P_WIDTH-1:0] + {1'b1, {(X_WIDTH-2){1'b0}}, 1'b1, {(Y_WIDTH){1'b0}}});
end else begin
assign result[i] = R_WIDTH'(p[i]);
end
end
`UNUSED_VAR (p)
assign busy = busy_r;
endmodule
`TRACING_ON

View File

@@ -1,141 +1,58 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_shift_register_nr #(
parameter DATAW = 1,
parameter DEPTH = 1,
parameter NTAPS = 1,
parameter DEPTHW = $clog2(DEPTH),
parameter [(DEPTHW*NTAPS)-1:0] TAPS = {NTAPS{DEPTHW'(DEPTH-1)}}
) (
input wire clk,
input wire enable,
input wire [DATAW-1:0] data_in,
output wire [(NTAPS*DATAW)-1:0] data_out
);
reg [DEPTH-1:0][DATAW-1:0] entries;
always @(posedge clk) begin
if (enable) begin
for (integer i = DEPTH-1; i > 0; --i)
entries[i] <= entries[i-1];
entries[0] <= data_in;
end
end
for (genvar i = 0; i < NTAPS; ++i) begin
assign data_out [i*DATAW+:DATAW] = entries [TAPS[i*DEPTHW+:DEPTHW]];
end
endmodule
module VX_shift_register_wr #(
parameter DATAW = 1,
parameter DEPTH = 1,
parameter NTAPS = 1,
parameter DEPTHW = $clog2(DEPTH),
parameter [(DEPTHW*NTAPS)-1:0] TAPS = {NTAPS{DEPTHW'(DEPTH-1)}}
) (
input wire clk,
input wire reset,
input wire enable,
input wire [DATAW-1:0] data_in,
output wire [(NTAPS*DATAW)-1:0] data_out
);
reg [DEPTH-1:0][DATAW-1:0] entries;
always @(posedge clk) begin
if (reset) begin
entries <= '0;
end else if (enable) begin
for (integer i = DEPTH-1; i > 0; --i)
entries[i] <= entries[i-1];
entries[0] <= data_in;
end
end
for (genvar i = 0; i < NTAPS; ++i) begin
assign data_out [i*DATAW+:DATAW] = entries [TAPS[i*DEPTHW+:DEPTHW]];
end
endmodule
module VX_shift_register #(
parameter DATAW = 1,
parameter RESETW = 0,
parameter DEPTH = 1,
parameter NTAPS = 1,
parameter DEPTHW = $clog2(DEPTH),
parameter [(DEPTHW*NTAPS)-1:0] TAPS = {NTAPS{DEPTHW'(DEPTH-1)}}
parameter DATAW = 1,
parameter RESETW = 0,
parameter DEPTH = 1,
parameter NUM_TAPS = 1,
parameter TAP_START = 0,
parameter TAP_STRIDE = 1
) (
input wire clk,
input wire reset,
input wire enable,
input wire [DATAW-1:0] data_in,
output wire [(NTAPS*DATAW)-1:0] data_out
input wire clk,
input wire reset,
input wire enable,
input wire [DATAW-1:0] data_in,
output wire [NUM_TAPS-1:0][DATAW-1:0] data_out
);
if (RESETW != 0) begin
if (RESETW == DATAW) begin
VX_shift_register_wr #(
.DATAW (DATAW),
.DEPTH (DEPTH),
.NTAPS (NTAPS),
.TAPS (TAPS)
) sr (
.clk (clk),
.reset (reset),
.enable (enable),
.data_in (data_in),
.data_out (data_out)
);
end else begin
VX_shift_register_wr #(
.DATAW (RESETW),
.DEPTH (DEPTH),
.NTAPS (NTAPS),
.TAPS (TAPS)
) sr_wr (
.clk (clk),
.reset (reset),
.enable (enable),
.data_in (data_in[DATAW-1:DATAW-RESETW]),
.data_out (data_out[DATAW-1:DATAW-RESETW])
);
VX_shift_register_nr #(
.DATAW (DATAW-RESETW),
.DEPTH (DEPTH),
.NTAPS (NTAPS),
.TAPS (TAPS)
) sr_nr (
.clk (clk),
.enable (enable),
.data_in (data_in[DATAW-RESETW-1:0]),
.data_out (data_out[DATAW-RESETW-1:0])
);
if (DEPTH != 0) begin
reg [DEPTH-1:0][DATAW-1:0] entries;
always @(posedge clk) begin
for (integer i = 0; i < DATAW; ++i) begin
if ((i >= (DATAW-RESETW)) && reset) begin
for (integer j = 0; j < DEPTH; ++j)
entries[j][i] <= 0;
end else if (enable) begin
for (integer j = 1; j < DEPTH; ++j)
entries[j-1][i] <= entries[j][i];
entries[DEPTH-1][i] <= data_in[i];
end
end
end
end else begin
for (genvar i = 0; i < NUM_TAPS; ++i) begin
assign data_out[i] = entries[i * TAP_STRIDE + TAP_START];
end
end else begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
VX_shift_register_nr #(
.DATAW (DATAW),
.DEPTH (DEPTH),
.NTAPS (NTAPS),
.TAPS (TAPS)
) sr (
.clk (clk),
.enable (enable),
.data_in (data_in),
.data_out (data_out)
);
end
`UNUSED_VAR (enable)
assign data_out = data_in;
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,11 +1,23 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_skid_buffer #(
parameter DATAW = 1,
parameter PASSTHRU = 0,
parameter NOBACKPRESSURE = 0,
parameter OUT_REG = 0
parameter DATAW = 32,
parameter PASSTHRU = 0,
parameter OUT_REG = 0
) (
input wire clk,
input wire reset,
@@ -18,8 +30,9 @@ module VX_skid_buffer #(
input wire ready_out,
output wire valid_out
);
`STATIC_ASSERT ((OUT_REG <= 2), ("invalid parameter"))
if (PASSTHRU) begin
if (PASSTHRU != 0) begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
@@ -28,107 +41,114 @@ module VX_skid_buffer #(
assign data_out = data_in;
assign ready_in = ready_out;
end else if (NOBACKPRESSURE) begin
end else if (OUT_REG == 0) begin
`RUNTIME_ASSERT(ready_out, ("%t: *** ready_out should always be asserted", $time))
reg [1:0][DATAW-1:0] shift_reg;
reg valid_out_r, ready_in_r, rd_ptr_r;
wire stall = valid_out && ~ready_out;
wire push = valid_in && ready_in;
wire pop = valid_out_r && ready_out;
VX_pipe_register #(
.DATAW (1 + DATAW),
.RESETW (1)
) pipe_reg (
.clk (clk),
.reset (reset),
.enable (!stall),
.data_in ({valid_in, data_in}),
.data_out ({valid_out, data_out})
);
always @(posedge clk) begin
if (reset) begin
valid_out_r <= 0;
ready_in_r <= 1;
rd_ptr_r <= 1;
end else begin
if (push) begin
if (!pop) begin
ready_in_r <= rd_ptr_r;
valid_out_r <= 1;
end
end else if (pop) begin
ready_in_r <= 1;
valid_out_r <= rd_ptr_r;
end
rd_ptr_r <= rd_ptr_r ^ (push ^ pop);
end
end
always @(posedge clk) begin
if (push) begin
shift_reg[1] <= shift_reg[0];
shift_reg[0] <= data_in;
end
end
assign ready_in = ready_in_r;
assign valid_out = valid_out_r;
assign data_out = shift_reg[rd_ptr_r];
end else if (OUT_REG == 1) begin
// Full-bandwidth operation: input is consummed every cycle.
// However, data_out register has an additional multiplexer.
reg [DATAW-1:0] data_out_r;
reg [DATAW-1:0] buffer;
reg valid_out_r;
reg use_buffer;
wire push = valid_in && ready_in;
wire stall_out = valid_out_r && ~ready_out;
always @(posedge clk) begin
if (reset) begin
valid_out_r <= 0;
use_buffer <= 0;
end else begin
if (ready_out) begin
use_buffer <= 0;
end else if (valid_in && valid_out) begin
use_buffer <= 1;
end
if (~stall_out) begin
valid_out_r <= valid_in || use_buffer;
end
end
end
always @(posedge clk) begin
if (push) begin
buffer <= data_in;
end
if (~stall_out) begin
data_out_r <= use_buffer ? buffer : data_in;
end
end
assign ready_in = ~use_buffer;
assign valid_out = valid_out_r;
assign data_out = data_out_r;
assign ready_in = ~stall;
end else begin
if (OUT_REG) begin
// Half-bandwidth operation: input is consummed every other cycle.
// However, data_out register has no additional multiplexer.
reg [DATAW-1:0] data_out_r;
reg [DATAW-1:0] buffer;
reg valid_out_r;
reg use_buffer;
wire push = valid_in && ready_in;
wire pop = !valid_out_r || ready_out;
always @(posedge clk) begin
if (reset) begin
valid_out_r <= 0;
use_buffer <= 0;
end else begin
if (ready_out) begin
use_buffer <= 0;
end else if (valid_in && valid_out_r) begin
use_buffer <= 1;
end
if (pop) begin
valid_out_r <= valid_in || use_buffer;
end
end
end
reg [DATAW-1:0] data_out_r;
reg has_data;
always @(posedge clk) begin
if (push) begin
buffer <= data_in;
end
if (pop && !use_buffer) begin
data_out_r <= data_in;
always @(posedge clk) begin
if (reset) begin
has_data <= 0;
end else begin
if (~has_data) begin
has_data <= valid_in;
end else if (ready_out) begin
data_out_r <= buffer;
end
has_data <= 0;
end
end
assign ready_in = !use_buffer;
assign valid_out = valid_out_r;
assign data_out = data_out_r;
end else begin
reg [DATAW-1:0] shift_reg [1:0];
reg valid_out_r, ready_in_r, rd_ptr_r;
wire push = valid_in && ready_in;
wire pop = valid_out_r && ready_out;
always @(posedge clk) begin
if (reset) begin
valid_out_r <= 0;
ready_in_r <= 1;
rd_ptr_r <= 1;
end else begin
if (push) begin
if (!pop) begin
ready_in_r <= rd_ptr_r;
valid_out_r <= 1;
end
end else if (pop) begin
ready_in_r <= 1;
valid_out_r <= rd_ptr_r;
end
rd_ptr_r <= rd_ptr_r ^ (push ^ pop);
end
if (~has_data) begin
data_out_r <= data_in;
end
always @(posedge clk) begin
if (push) begin
shift_reg[1] <= shift_reg[0];
shift_reg[0] <= data_in;
end
end
assign ready_in = ready_in_r;
assign valid_out = valid_out_r;
assign data_out = shift_reg[rd_ptr_r];
end
assign ready_in = ~has_data;
assign valid_out = has_data;
assign data_out = data_out_r;
end
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -1,252 +1,60 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_sp_ram #(
parameter DATAW = 1,
parameter SIZE = 1,
parameter BYTEENW = 1,
parameter WRENW = 1,
parameter OUT_REG = 0,
parameter NO_RWCHECK = 0,
parameter LUTRAM = 0,
parameter ADDRW = $clog2(SIZE),
parameter LUTRAM = 0,
parameter INIT_ENABLE = 0,
parameter INIT_FILE = "",
parameter [DATAW-1:0] INIT_VALUE = 0
parameter [DATAW-1:0] INIT_VALUE = 0,
parameter ADDRW = `LOG2UP(SIZE)
) (
input wire clk,
input wire clk,
input wire read,
input wire write,
input wire [WRENW-1:0] wren,
input wire [ADDRW-1:0] addr,
input wire [BYTEENW-1:0] wren,
input wire [DATAW-1:0] wdata,
output wire [DATAW-1:0] rdata
);
`STATIC_ASSERT((1 == BYTEENW) || ((BYTEENW > 1) && 0 == (BYTEENW % 4)), ("invalid parameter"))
`define RAM_INITIALIZATION \
if (INIT_ENABLE) begin \
if (INIT_FILE != "") begin \
initial $readmemh(INIT_FILE, ram); \
end else begin \
initial \
for (integer i = 0; i < SIZE; ++i)\
ram[i] = INIT_VALUE; \
end \
end
`ifdef SYNTHESIS
if (LUTRAM) begin
if (OUT_REG) begin
reg [DATAW-1:0] rdata_r;
if (BYTEENW > 1) begin
`USE_FAST_BRAM reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
rdata_r <= ram[addr];
end
end else begin
`USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
rdata_r <= ram[addr];
end
end
assign rdata = rdata_r;
end else begin
if (BYTEENW > 1) begin
`USE_FAST_BRAM reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
end
assign rdata = ram[addr];
end else begin
`USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
end
assign rdata = ram[addr];
end
end
end else begin
if (OUT_REG) begin
reg [DATAW-1:0] rdata_r;
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
rdata_r <= ram[addr];
end
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
rdata_r <= ram[addr];
end
end
assign rdata = rdata_r;
end else begin
if (NO_RWCHECK) begin
if (BYTEENW > 1) begin
`NO_RW_RAM_CHECK reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
end
assign rdata = ram[addr];
end else begin
`NO_RW_RAM_CHECK reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
end
assign rdata = ram[addr];
end
end else begin
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
end
assign rdata = ram[addr];
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
end
assign rdata = ram[addr];
end
end
end
end
`else
if (OUT_REG) begin
reg [DATAW-1:0] rdata_r;
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
rdata_r <= ram[addr];
end
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
rdata_r <= ram[addr];
end
end
assign rdata = rdata_r;
end else begin
if (BYTEENW > 1) begin
reg [BYTEENW-1:0][7:0] ram [SIZE-1:0];
reg [DATAW-1:0] prev_data;
reg [ADDRW-1:0] prev_addr;
reg prev_write;
`RAM_INITIALIZATION
always @(posedge clk) begin
for (integer i = 0; i < BYTEENW; i++) begin
if (wren[i])
ram[addr][i] <= wdata[i * 8 +: 8];
end
prev_write <= (| wren);
prev_data <= ram[addr];
prev_addr <= addr;
end
if (LUTRAM || !NO_RWCHECK) begin
`UNUSED_VAR (prev_write)
`UNUSED_VAR (prev_data)
`UNUSED_VAR (prev_addr)
assign rdata = ram[addr];
end else begin
assign rdata = (prev_write && (prev_addr == addr)) ? prev_data : ram[addr];
end
end else begin
reg [DATAW-1:0] ram [SIZE-1:0];
reg [DATAW-1:0] prev_data;
reg [ADDRW-1:0] prev_addr;
reg prev_write;
`RAM_INITIALIZATION
always @(posedge clk) begin
if (wren)
ram[addr] <= wdata;
prev_write <= wren;
prev_data <= ram[addr];
prev_addr <= addr;
end
if (LUTRAM || !NO_RWCHECK) begin
`UNUSED_VAR (prev_write)
`UNUSED_VAR (prev_data)
`UNUSED_VAR (prev_addr)
assign rdata = ram[addr];
end else begin
assign rdata = (prev_write && (prev_addr == addr)) ? prev_data : ram[addr];
end
end
end
`endif
VX_dp_ram #(
.DATAW (DATAW),
.SIZE (SIZE),
.WRENW (WRENW),
.OUT_REG (OUT_REG),
.NO_RWCHECK (NO_RWCHECK),
.LUTRAM (LUTRAM),
.INIT_ENABLE (INIT_ENABLE),
.INIT_FILE (INIT_FILE),
.INIT_VALUE (INIT_VALUE),
.ADDRW (ADDRW)
) dp_ram (
.clk (clk),
.read (read),
.write (write),
.wren (wren),
.waddr (addr),
.wdata (wdata),
.raddr (addr),
.rdata (rdata)
);
endmodule
`TRACING_ON
`TRACING_ON

View File

@@ -0,0 +1,375 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_stream_arb #(
parameter NUM_INPUTS = 1,
parameter NUM_OUTPUTS = 1,
parameter DATAW = 1,
parameter `STRING ARBITER = "P",
parameter LOCK_ENABLE = 1,
parameter MAX_FANOUT = `MAX_FANOUT,
parameter OUT_REG = 0 ,
parameter NUM_REQS = (NUM_INPUTS + NUM_OUTPUTS - 1) / NUM_OUTPUTS,
parameter LOG_NUM_REQS = `CLOG2(NUM_REQS),
parameter NUM_REQS_W = `UP(LOG_NUM_REQS)
) (
input wire clk,
input wire reset,
input wire [NUM_INPUTS-1:0] valid_in,
input wire [NUM_INPUTS-1:0][DATAW-1:0] data_in,
output wire [NUM_INPUTS-1:0] ready_in,
output wire [NUM_OUTPUTS-1:0] valid_out,
output wire [NUM_OUTPUTS-1:0][DATAW-1:0] data_out,
output wire [NUM_OUTPUTS-1:0][NUM_REQS_W-1:0] sel_out,
input wire [NUM_OUTPUTS-1:0] ready_out
);
if (NUM_INPUTS > NUM_OUTPUTS) begin
if (NUM_OUTPUTS > 1) begin
// (#inputs > #outputs) and (#outputs > 1)
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
localparam BATCH_BEGIN = i * NUM_REQS;
localparam BATCH_END = `MIN(BATCH_BEGIN + NUM_REQS, NUM_INPUTS);
localparam BATCH_SIZE = BATCH_END - BATCH_BEGIN;
`RESET_RELAY (slice_reset, reset);
VX_stream_arb #(
.NUM_INPUTS (BATCH_SIZE),
.NUM_OUTPUTS (1),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) arb_slice (
.clk (clk),
.reset (slice_reset),
.valid_in (valid_in[BATCH_END-1: BATCH_BEGIN]),
.ready_in (ready_in[BATCH_END-1: BATCH_BEGIN]),
.data_in (data_in[BATCH_END-1: BATCH_BEGIN]),
.data_out (data_out[i]),
.sel_out (sel_out[i]),
.valid_out (valid_out[i]),
.ready_out (ready_out[i])
);
end
end else if (MAX_FANOUT != 0 && (NUM_INPUTS > (MAX_FANOUT + MAX_FANOUT/2))) begin
// (#inputs > max_fanout) and (#outputs == 1)
localparam NUM_BATCHES = (NUM_INPUTS + MAX_FANOUT - 1) / MAX_FANOUT;
localparam LOG_NUM_REQS2 = `CLOG2(MAX_FANOUT);
localparam LOG_NUM_REQS3 = `CLOG2(NUM_BATCHES);
wire [NUM_BATCHES-1:0] valid_tmp;
wire [NUM_BATCHES-1:0][DATAW+LOG_NUM_REQS2-1:0] data_tmp;
wire [NUM_BATCHES-1:0] ready_tmp;
for (genvar i = 0; i < NUM_BATCHES; ++i) begin
localparam BATCH_BEGIN = i * MAX_FANOUT;
localparam BATCH_END = `MIN(BATCH_BEGIN + MAX_FANOUT, NUM_INPUTS);
localparam BATCH_SIZE = BATCH_END - BATCH_BEGIN;
wire [DATAW-1:0] data_tmp_u;
wire [`LOG2UP(BATCH_SIZE)-1:0] sel_tmp_u;
`RESET_RELAY (slice_reset, reset);
if (MAX_FANOUT != 1) begin
VX_stream_arb #(
.NUM_INPUTS (BATCH_SIZE),
.NUM_OUTPUTS (1),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) fanout_slice_arb (
.clk (clk),
.reset (slice_reset),
.valid_in (valid_in[BATCH_END-1: BATCH_BEGIN]),
.data_in (data_in[BATCH_END-1: BATCH_BEGIN]),
.ready_in (ready_in[BATCH_END-1: BATCH_BEGIN]),
.valid_out (valid_tmp[i]),
.data_out (data_tmp_u),
.sel_out (sel_tmp_u),
.ready_out (ready_tmp[i])
);
end
assign data_tmp[i] = {data_tmp_u, LOG_NUM_REQS2'(sel_tmp_u)};
end
wire [DATAW+LOG_NUM_REQS2-1:0] data_out_u;
wire [LOG_NUM_REQS3-1:0] sel_out_u;
VX_stream_arb #(
.NUM_INPUTS (NUM_BATCHES),
.NUM_OUTPUTS (1),
.DATAW (DATAW + LOG_NUM_REQS2),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) fanout_join_arb (
.clk (clk),
.reset (reset),
.valid_in (valid_tmp),
.ready_in (ready_tmp),
.data_in (data_tmp),
.data_out (data_out_u),
.sel_out (sel_out_u),
.valid_out (valid_out),
.ready_out (ready_out)
);
assign data_out = data_out_u[LOG_NUM_REQS2 +: DATAW];
assign sel_out = {sel_out_u, data_out_u[0 +: LOG_NUM_REQS2]};
end else begin
// (#inputs <= max_fanout) and (#outputs == 1)
wire valid_in_r;
wire [DATAW-1:0] data_in_r;
wire ready_in_r;
wire arb_valid;
wire [NUM_REQS_W-1:0] arb_index;
wire [NUM_REQS-1:0] arb_onehot;
wire arb_unlock;
VX_generic_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE),
.TYPE (ARBITER)
) arbiter (
.clk (clk),
.reset (reset),
.requests (valid_in),
.unlock (arb_unlock),
.grant_valid (arb_valid),
.grant_index (arb_index),
.grant_onehot (arb_onehot)
);
assign valid_in_r = arb_valid;
assign data_in_r = data_in[arb_index];
assign arb_unlock = | (valid_in_r & ready_in_r);
for (genvar i = 0; i < NUM_REQS; ++i) begin
assign ready_in[i] = ready_in_r & arb_onehot[i];
end
VX_elastic_buffer #(
.DATAW (LOG_NUM_REQS + DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (reset),
.valid_in (valid_in_r),
.ready_in (ready_in_r),
.data_in ({arb_index, data_in_r}),
.data_out ({sel_out, data_out}),
.valid_out (valid_out),
.ready_out (ready_out)
);
end
end else if (NUM_OUTPUTS > NUM_INPUTS) begin
if (NUM_INPUTS > 1) begin
// (#inputs > 1) and (#outputs > #inputs)
for (genvar i = 0; i < NUM_INPUTS; ++i) begin
localparam BATCH_BEGIN = i * NUM_REQS;
localparam BATCH_END = `MIN(BATCH_BEGIN + NUM_REQS, NUM_OUTPUTS);
localparam BATCH_SIZE = BATCH_END - BATCH_BEGIN;
`RESET_RELAY (slice_reset, reset);
VX_stream_arb #(
.NUM_INPUTS (1),
.NUM_OUTPUTS (BATCH_SIZE),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) arb_slice (
.clk (clk),
.reset (slice_reset),
.valid_in (valid_in[i]),
.ready_in (ready_in[i]),
.data_in (data_in[i]),
.data_out (data_out[BATCH_END-1: BATCH_BEGIN]),
.valid_out (valid_out[BATCH_END-1: BATCH_BEGIN]),
.ready_out (ready_out[BATCH_END-1: BATCH_BEGIN]),
`UNUSED_PIN (sel_out)
);
for (genvar j = BATCH_BEGIN; j < BATCH_END; ++j) begin
assign sel_out[j] = i;
end
end
end else if (MAX_FANOUT != 0 && (NUM_OUTPUTS > (MAX_FANOUT + MAX_FANOUT/2))) begin
// (#inputs == 1) and (#outputs > max_fanout)
localparam NUM_BATCHES = (NUM_OUTPUTS + MAX_FANOUT - 1) / MAX_FANOUT;
wire [NUM_BATCHES-1:0] valid_tmp;
wire [NUM_BATCHES-1:0][DATAW-1:0] data_tmp;
wire [NUM_BATCHES-1:0] ready_tmp;
VX_stream_arb #(
.NUM_INPUTS (1),
.NUM_OUTPUTS (NUM_BATCHES),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) fanout_fork_arb (
.clk (clk),
.reset (reset),
.valid_in (valid_in),
.ready_in (ready_in),
.data_in (data_in),
.data_out (data_tmp),
.valid_out (valid_tmp),
.ready_out (ready_tmp),
`UNUSED_PIN (sel_out)
);
for (genvar i = 0; i < NUM_BATCHES; ++i) begin
localparam BATCH_BEGIN = i * MAX_FANOUT;
localparam BATCH_END = `MIN(BATCH_BEGIN + MAX_FANOUT, NUM_OUTPUTS);
localparam BATCH_SIZE = BATCH_END - BATCH_BEGIN;
`RESET_RELAY (slice_reset, reset);
VX_stream_arb #(
.NUM_INPUTS (1),
.NUM_OUTPUTS (BATCH_SIZE),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) fanout_slice_arb (
.clk (clk),
.reset (slice_reset),
.valid_in (valid_tmp[i]),
.ready_in (ready_tmp[i]),
.data_in (data_tmp[i]),
.data_out (data_out[BATCH_END-1: BATCH_BEGIN]),
.valid_out (valid_out[BATCH_END-1: BATCH_BEGIN]),
.ready_out (ready_out[BATCH_END-1: BATCH_BEGIN]),
`UNUSED_PIN (sel_out)
);
end
end else begin
// (#inputs == 1) and (#outputs <= max_fanout)
wire [NUM_OUTPUTS-1:0] ready_in_r;
wire [NUM_OUTPUTS-1:0] arb_requests;
wire arb_valid;
wire [NUM_OUTPUTS-1:0] arb_onehot;
wire arb_unlock;
VX_generic_arbiter #(
.NUM_REQS (NUM_OUTPUTS),
.LOCK_ENABLE (LOCK_ENABLE),
.TYPE (ARBITER)
) arbiter (
.clk (clk),
.reset (reset),
.requests (arb_requests),
.unlock (arb_unlock),
.grant_valid (arb_valid),
`UNUSED_PIN (grant_index),
.grant_onehot (arb_onehot)
);
assign arb_requests = ready_in_r;
assign arb_unlock = | (valid_in & ready_in);
assign ready_in = arb_valid;
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (reset),
.valid_in (valid_in && arb_onehot[i]),
.ready_in (ready_in_r[i]),
.data_in (data_in),
.data_out (data_out[i]),
.valid_out (valid_out[i]),
.ready_out (ready_out[i])
);
end
end
assign sel_out = 0;
end else begin
// #Inputs == #Outputs
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
`RESET_RELAY_EN (out_buf_reset, reset, (NUM_OUTPUTS > 1));
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (out_buf_reset),
.valid_in (valid_in[i]),
.ready_in (ready_in[i]),
.data_in (data_in[i]),
.data_out (data_out[i]),
.valid_out (valid_out[i]),
.ready_out (ready_out[i])
);
assign sel_out[i] = NUM_REQS_W'(i);
end
end
endmodule
`TRACING_ON

View File

@@ -1,148 +0,0 @@
`include "VX_platform.vh"
module VX_stream_arbiter #(
parameter NUM_REQS = 1,
parameter LANES = 1,
parameter DATAW = 1,
parameter TYPE = "P",
parameter LOCK_ENABLE = 1,
parameter BUFFERED = 0
) (
input wire clk,
input wire reset,
input wire [NUM_REQS-1:0][LANES-1:0] valid_in,
input wire [NUM_REQS-1:0][LANES-1:0][DATAW-1:0] data_in,
output wire [NUM_REQS-1:0][LANES-1:0] ready_in,
output wire [LANES-1:0] valid_out,
output wire [LANES-1:0][DATAW-1:0] data_out,
input wire [LANES-1:0] ready_out
);
localparam LOG_NUM_REQS = `CLOG2(NUM_REQS);
if (NUM_REQS > 1) begin
wire sel_valid;
wire sel_ready;
wire [LOG_NUM_REQS-1:0] sel_index;
wire [NUM_REQS-1:0] sel_onehot;
wire [NUM_REQS-1:0] valid_in_any;
wire [LANES-1:0] ready_in_sel;
if (LANES > 1) begin
for (genvar i = 0; i < NUM_REQS; i++) begin
assign valid_in_any[i] = (| valid_in[i]);
end
assign sel_ready = (| ready_in_sel);
end else begin
for (genvar i = 0; i < NUM_REQS; i++) begin
assign valid_in_any[i] = valid_in[i];
end
assign sel_ready = ready_in_sel;
end
if (TYPE == "P") begin
VX_fixed_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) sel_arb (
.clk (clk),
.reset (reset),
.requests (valid_in_any),
.enable (sel_ready),
.grant_valid (sel_valid),
.grant_index (sel_index),
.grant_onehot (sel_onehot)
);
end else if (TYPE == "R") begin
VX_rr_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) sel_arb (
.clk (clk),
.reset (reset),
.requests (valid_in_any),
.enable (sel_ready),
.grant_valid (sel_valid),
.grant_index (sel_index),
.grant_onehot (sel_onehot)
);
end else if (TYPE == "F") begin
VX_fair_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) sel_arb (
.clk (clk),
.reset (reset),
.requests (valid_in_any),
.enable (sel_ready),
.grant_valid (sel_valid),
.grant_index (sel_index),
.grant_onehot (sel_onehot)
);
end else if (TYPE == "M") begin
VX_matrix_arbiter #(
.NUM_REQS (NUM_REQS),
.LOCK_ENABLE (LOCK_ENABLE)
) sel_arb (
.clk (clk),
.reset (reset),
.requests (valid_in_any),
.enable (sel_ready),
.grant_valid (sel_valid),
.grant_index (sel_index),
.grant_onehot (sel_onehot)
);
end else begin
`ERROR(("invalid parameter"));
end
wire [LANES-1:0] valid_in_sel;
wire [LANES-1:0][DATAW-1:0] data_in_sel;
if (LANES > 1) begin
wire [NUM_REQS-1:0][(LANES * (1 + DATAW))-1:0] valid_data_in;
for (genvar i = 0; i < NUM_REQS; i++) begin
assign valid_data_in[i] = {valid_in[i], data_in[i]};
end
assign {valid_in_sel, data_in_sel} = valid_data_in[sel_index];
`UNUSED_VAR (sel_valid)
end else begin
assign data_in_sel = data_in[sel_index];
assign valid_in_sel = sel_valid;
end
for (genvar i = 0; i < NUM_REQS; i++) begin
assign ready_in[i] = ready_in_sel & {LANES{sel_onehot[i]}};
end
for (genvar i = 0; i < LANES; ++i) begin
VX_skid_buffer #(
.DATAW (DATAW),
.PASSTHRU (0 == BUFFERED),
.OUT_REG (2 == BUFFERED)
) out_buffer (
.clk (clk),
.reset (reset),
.valid_in (valid_in_sel[i]),
.data_in (data_in_sel[i]),
.ready_in (ready_in_sel[i]),
.valid_out (valid_out[i]),
.data_out (data_out[i]),
.ready_out (ready_out[i])
);
end
end else begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
assign valid_out = valid_in;
assign data_out = data_in;
assign ready_in = ready_out;
end
endmodule

View File

@@ -1,68 +0,0 @@
`include "VX_platform.vh"
module VX_stream_demux #(
parameter NUM_REQS = 1,
parameter LANES = 1,
parameter DATAW = 1,
parameter BUFFERED = 0,
parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire [LANES-1:0][LOG_NUM_REQS-1:0] sel_in,
input wire [LANES-1:0] valid_in,
input wire [LANES-1:0][DATAW-1:0] data_in,
output wire [LANES-1:0] ready_in,
output wire [NUM_REQS-1:0][LANES-1:0] valid_out,
output wire [NUM_REQS-1:0][LANES-1:0][DATAW-1:0] data_out,
input wire [NUM_REQS-1:0][LANES-1:0] ready_out
);
if (NUM_REQS > 1) begin
for (genvar j = 0; j < LANES; ++j) begin
reg [NUM_REQS-1:0] valid_in_sel;
wire [NUM_REQS-1:0] ready_in_sel;
always @(*) begin
valid_in_sel = '0;
valid_in_sel[sel_in[j]] = valid_in[j];
end
assign ready_in[j] = ready_in_sel[sel_in[j]];
for (genvar i = 0; i < NUM_REQS; i++) begin
VX_skid_buffer #(
.DATAW (DATAW),
.PASSTHRU (0 == BUFFERED),
.OUT_REG (2 == BUFFERED)
) out_buffer (
.clk (clk),
.reset (reset),
.valid_in (valid_in_sel[i]),
.data_in (data_in[j]),
.ready_in (ready_in_sel[i]),
.valid_out (valid_out[i][j]),
.data_out (data_out[i][j]),
.ready_out (ready_out[i][j])
);
end
end
end else begin
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
`UNUSED_VAR (sel_in)
assign valid_out = valid_in;
assign data_out = data_in;
assign ready_in = ready_out;
end
endmodule

View File

@@ -0,0 +1,164 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_stream_switch #(
parameter NUM_INPUTS = 1,
parameter NUM_OUTPUTS = 1,
parameter DATAW = 1,
parameter OUT_REG = 0,
parameter NUM_REQS = (NUM_INPUTS > NUM_OUTPUTS) ? ((NUM_INPUTS + NUM_OUTPUTS - 1) / NUM_OUTPUTS) : ((NUM_OUTPUTS + NUM_INPUTS - 1) / NUM_INPUTS),
parameter SEL_COUNT = `MIN(NUM_INPUTS, NUM_OUTPUTS),
parameter LOG_NUM_REQS = `CLOG2(NUM_REQS)
) (
input wire clk,
input wire reset,
input wire [SEL_COUNT-1:0][`UP(LOG_NUM_REQS)-1:0] sel_in,
input wire [NUM_INPUTS-1:0] valid_in,
input wire [NUM_INPUTS-1:0][DATAW-1:0] data_in,
output wire [NUM_INPUTS-1:0] ready_in,
output wire [NUM_OUTPUTS-1:0] valid_out,
output wire [NUM_OUTPUTS-1:0][DATAW-1:0] data_out,
input wire [NUM_OUTPUTS-1:0] ready_out
);
if (NUM_INPUTS > NUM_OUTPUTS) begin
wire [NUM_OUTPUTS-1:0][NUM_REQS-1:0] valid_in_r;
wire [NUM_OUTPUTS-1:0][NUM_REQS-1:0][DATAW-1:0] data_in_r;
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
for (genvar j = 0; j < NUM_REQS; ++j) begin
localparam ii = i * NUM_REQS + j;
if (ii < NUM_INPUTS) begin
assign valid_in_r[i][j] = valid_in[ii];
assign data_in_r[i][j] = data_in[ii];
end else begin
assign valid_in_r[i][j] = 0;
assign data_in_r[i][j] = '0;
end
end
end
wire [NUM_OUTPUTS-1:0] valid_out_r;
wire [NUM_OUTPUTS-1:0][DATAW-1:0] data_out_r;
wire [NUM_OUTPUTS-1:0] ready_out_r;
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
assign valid_out_r[i] = valid_in_r[i][sel_in[i]];
assign data_out_r[i] = data_in_r[i][sel_in[i]];
end
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
for (genvar j = 0; j < NUM_REQS; ++j) begin
localparam ii = i * NUM_REQS + j;
if (ii < NUM_INPUTS) begin
assign ready_in[ii] = ready_out_r[i] & (sel_in[i] == LOG_NUM_REQS'(j));
end
end
end
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
`RESET_RELAY_EN (out_buf_reset, reset, (NUM_OUTPUTS > 1));
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (out_buf_reset),
.valid_in (valid_out_r[i]),
.ready_in (ready_out_r[i]),
.data_in (data_out_r[i]),
.data_out (data_out[i]),
.valid_out (valid_out[i]),
.ready_out (ready_out[i])
);
end
end else if (NUM_OUTPUTS > NUM_INPUTS) begin
wire [NUM_INPUTS-1:0][NUM_REQS-1:0] valid_out_r;
wire [NUM_INPUTS-1:0][NUM_REQS-1:0] ready_out_r;
for (genvar i = 0; i < NUM_INPUTS; ++i) begin
for (genvar j = 0; j < NUM_REQS; ++j) begin
assign valid_out_r[i][j] = valid_in[i] & (sel_in[i] == LOG_NUM_REQS'(j));
end
assign ready_in[i] = ready_out_r[i][sel_in[i]];
end
for (genvar i = 0; i < NUM_INPUTS; ++i) begin
for (genvar j = 0; j < NUM_REQS; ++j) begin
localparam ii = i * NUM_REQS + j;
if (ii < NUM_OUTPUTS) begin
`RESET_RELAY (out_buf_reset, reset);
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (out_buf_reset),
.valid_in (valid_out_r[i][j]),
.ready_in (ready_out_r[i][j]),
.data_in (data_in[i]),
.data_out (data_out[ii]),
.valid_out (valid_out[ii]),
.ready_out (ready_out[ii])
);
end else begin
`UNUSED_VAR (valid_out_r[i][j])
assign ready_out_r[i][j] = '0;
end
end
end
end else begin
// #Inputs == #Outputs
`UNUSED_VAR (sel_in)
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
`RESET_RELAY_EN (out_buf_reset, reset, (NUM_OUTPUTS > 1));
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (out_buf_reset),
.valid_in (valid_in[i]),
.ready_in (ready_in[i]),
.data_in (data_in[i]),
.data_out (data_out[i]),
.valid_out (valid_out[i]),
.ready_out (ready_out[i])
);
end
end
endmodule
`TRACING_ON

View File

@@ -0,0 +1,207 @@
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_define.vh"
`TRACING_OFF
module VX_stream_xbar #(
parameter NUM_INPUTS = 4,
parameter NUM_OUTPUTS = 4,
parameter DATAW = 4,
parameter IN_WIDTH = `LOG2UP(NUM_INPUTS),
parameter OUT_WIDTH = `LOG2UP(NUM_OUTPUTS),
parameter ARBITER = "P",
parameter LOCK_ENABLE = 0,
parameter OUT_REG = 0,
parameter MAX_FANOUT = `MAX_FANOUT,
parameter PERF_CTR_BITS = `CLOG2(NUM_INPUTS+1)
) (
input wire clk,
input wire reset,
output wire [PERF_CTR_BITS-1:0] collisions,
input wire [NUM_INPUTS-1:0] valid_in,
input wire [NUM_INPUTS-1:0][DATAW-1:0] data_in,
input wire [NUM_INPUTS-1:0][OUT_WIDTH-1:0] sel_in,
output wire [NUM_INPUTS-1:0] ready_in,
output wire [NUM_OUTPUTS-1:0] valid_out,
output wire [NUM_OUTPUTS-1:0][DATAW-1:0] data_out,
output wire [NUM_OUTPUTS-1:0][IN_WIDTH-1:0] sel_out,
input wire [NUM_OUTPUTS-1:0] ready_out
);
`UNUSED_VAR (clk)
`UNUSED_VAR (reset)
if (NUM_INPUTS != 1) begin
if (NUM_OUTPUTS != 1) begin
// (#inputs > 1) and (#outputs > 1)
wire [NUM_OUTPUTS-1:0][NUM_INPUTS-1:0] per_output_ready_in;
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
wire [NUM_INPUTS-1:0] valid_in_q;
for (genvar j = 0; j < NUM_INPUTS; ++j) begin
assign valid_in_q[j] = valid_in[j] && (sel_in[j] == i);
end
`RESET_RELAY (slice_reset, reset);
VX_stream_arb #(
.NUM_INPUTS (NUM_INPUTS),
.NUM_OUTPUTS (1),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) xbar_arb (
.clk (clk),
.reset (slice_reset),
.valid_in (valid_in_q),
.data_in (data_in),
.ready_in (per_output_ready_in[i]),
.valid_out (valid_out[i]),
.data_out (data_out[i]),
.sel_out (sel_out[i]),
.ready_out (ready_out[i])
);
end
for (genvar i = 0; i < NUM_INPUTS; ++i) begin
assign ready_in[i] = per_output_ready_in[sel_in[i]][i];
end
end else begin
// (#inputs >= 1) and (#outputs == 1)
VX_stream_arb #(
.NUM_INPUTS (NUM_INPUTS),
.NUM_OUTPUTS (1),
.DATAW (DATAW),
.ARBITER (ARBITER),
.LOCK_ENABLE (LOCK_ENABLE),
.MAX_FANOUT (MAX_FANOUT),
.OUT_REG (OUT_REG)
) xbar_arb (
.clk (clk),
.reset (reset),
.valid_in (valid_in),
.data_in (data_in),
.ready_in (ready_in),
.valid_out (valid_out),
.data_out (data_out),
.sel_out (sel_out),
.ready_out (ready_out)
);
`UNUSED_VAR (sel_in)
end
end else if (NUM_OUTPUTS != 1) begin
// (#inputs == 1) and (#outputs > 1)
logic [NUM_OUTPUTS-1:0] valid_out_r, ready_out_r;
logic [NUM_OUTPUTS-1:0][DATAW-1:0] data_out_r;
always @(*) begin
valid_out_r = '0;
valid_out_r[sel_in] = valid_in;
end
assign data_out_r = {NUM_OUTPUTS{data_in}};
assign ready_in = ready_out_r[sel_in];
for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin
`RESET_RELAY (out_buf_reset, reset);
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (out_buf_reset),
.valid_in (valid_out_r[i]),
.ready_in (ready_out_r[i]),
.data_in (data_out_r[i]),
.data_out (data_out[i]),
.valid_out (valid_out[i]),
.ready_out (ready_out[i])
);
end
assign sel_out = 0;
end else begin
// (#inputs == 1) and (#outputs == 1)
VX_elastic_buffer #(
.DATAW (DATAW),
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
) out_buf (
.clk (clk),
.reset (reset),
.valid_in (valid_in),
.ready_in (ready_in),
.data_in (data_in),
.data_out (data_out),
.valid_out (valid_out),
.ready_out (ready_out)
);
`UNUSED_VAR (sel_in)
assign sel_out = 0;
end
// compute inputs collision
// we have a collision when there exists a valid transfer with mutiple input candicates
// we caount the unique duplicates each cycle.
reg [PERF_CTR_BITS-1:0] collisions_r;
reg [NUM_INPUTS-1:0] per_cycle_collision;
always @(*) begin
per_cycle_collision = 0;
for (integer i = 0; i < NUM_INPUTS; ++i) begin
for (integer j = 1; j < (NUM_INPUTS-i); ++j) begin
if (valid_in[i] && valid_in[j+i] && sel_in[i] == sel_in[j+i]) begin
per_cycle_collision[i] |= ready_in[i] | ready_in[j+i];
end
end
end
end
wire [`CLOG2(NUM_INPUTS+1)-1:0] collision_count;
`POP_COUNT(collision_count, per_cycle_collision);
always @(posedge clk) begin
if (reset) begin
collisions_r <= '0;
end else begin
collisions_r <= collisions_r + PERF_CTR_BITS'(collision_count);
end
end
assign collisions = collisions_r;
endmodule
`TRACING_ON