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