Vortex 2.0 changes:

+ Microarchitecture optimizations
+ 64-bit support
+ Xilinx FPGA support
+ LLVM-16 support
+ Refactoring and quality control fixes

minor update

minor update

minor update

minor update

minor update

minor update

cleanup

cleanup

cache bindings and memory perf refactory

minor update

minor update

hw unit tests fixes

minor update

minor update

minor update

minor update

minor update

minor udpate

minor update

minor update

minor update

minor update

minor update

minor update

minor update

minor updates

minor updates

minor update

minor update

minor update

minor update

minor update

minor update

minor updates

minor updates

minor updates

minor updates

minor update

minor update
This commit is contained in:
Blaise Tine
2023-10-19 20:51:22 -07:00
parent d69a64c32c
commit c1e168fdbe
1309 changed files with 247412 additions and 311463 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 = 1,
parameter NUM_BANKS = 1,
parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 32,
parameter TAG_WIDTH = 8,
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 = 8,
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