Vortex 2.0 changes:
+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes minor update minor update minor update minor update minor update minor update cleanup cleanup cache bindings and memory perf refactory minor update minor update hw unit tests fixes minor update minor update minor update minor update minor update minor udpate minor update minor update minor update minor update minor update minor update minor update minor updates minor updates minor update minor update minor update minor update minor update minor update minor updates minor updates minor updates minor updates minor update minor update
This commit is contained in:
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 = 1,
|
||||
parameter NUM_BANKS = 1,
|
||||
parameter ADDR_WIDTH = 32,
|
||||
parameter DATA_WIDTH = 32,
|
||||
parameter TAG_WIDTH = 8,
|
||||
parameter MEM_TAG_ID = 0, // upper section of the tag sent to the memory interface
|
||||
parameter UUID_WIDTH = 0, // upper section of the mem_tag_id containing the UUID
|
||||
parameter QUEUE_SIZE = 8,
|
||||
parameter RSP_PARTIAL = 0,
|
||||
parameter CORE_OUT_REG = 0,
|
||||
parameter MEM_OUT_REG = 0,
|
||||
|
||||
parameter BYTEENW = DATA_WIDTH / 8,
|
||||
parameter NUM_BATCHES = (NUM_REQS + NUM_BANKS - 1) / NUM_BANKS,
|
||||
parameter QUEUE_ADDRW = `CLOG2(QUEUE_SIZE),
|
||||
parameter BATCH_SEL_BITS = `CLOG2(NUM_BATCHES),
|
||||
parameter MEM_TAGW = MEM_TAG_ID + QUEUE_ADDRW + BATCH_SEL_BITS
|
||||
) (
|
||||
input wire clk,
|
||||
input wire reset,
|
||||
|
||||
// Input request
|
||||
input wire req_valid,
|
||||
input wire req_rw,
|
||||
input wire [NUM_REQS-1:0] req_mask,
|
||||
input wire [NUM_REQS-1:0][BYTEENW-1:0] req_byteen,
|
||||
input wire [NUM_REQS-1:0][ADDR_WIDTH-1:0] req_addr,
|
||||
input wire [NUM_REQS-1:0][DATA_WIDTH-1:0] req_data,
|
||||
input wire [TAG_WIDTH-1:0] req_tag,
|
||||
output wire req_empty,
|
||||
output wire req_ready,
|
||||
output wire write_notify,
|
||||
|
||||
// Output response
|
||||
output wire rsp_valid,
|
||||
output wire [NUM_REQS-1:0] rsp_mask,
|
||||
output wire [NUM_REQS-1:0][DATA_WIDTH-1:0] rsp_data,
|
||||
output wire [TAG_WIDTH-1:0] rsp_tag,
|
||||
output wire rsp_sop,
|
||||
output wire rsp_eop,
|
||||
input wire rsp_ready,
|
||||
|
||||
// Memory request
|
||||
output wire [NUM_BANKS-1:0] mem_req_valid,
|
||||
output wire [NUM_BANKS-1:0] mem_req_rw,
|
||||
output wire [NUM_BANKS-1:0][BYTEENW-1:0] mem_req_byteen,
|
||||
output wire [NUM_BANKS-1:0][ADDR_WIDTH-1:0] mem_req_addr,
|
||||
output wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_req_data,
|
||||
output wire [NUM_BANKS-1:0][MEM_TAGW-1:0]mem_req_tag,
|
||||
input wire [NUM_BANKS-1:0] mem_req_ready,
|
||||
|
||||
// Memory response
|
||||
input wire [NUM_BANKS-1:0] mem_rsp_valid,
|
||||
input wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_rsp_data,
|
||||
input wire [NUM_BANKS-1:0][MEM_TAGW-1:0] mem_rsp_tag,
|
||||
output wire [NUM_BANKS-1:0] mem_rsp_ready
|
||||
);
|
||||
|
||||
localparam MEM_TAG_WIDTH = `UP(MEM_TAG_ID);
|
||||
localparam BATCH_SEL_WIDTH = `UP(BATCH_SEL_BITS);
|
||||
localparam TAG_ONLY_WIDTH = TAG_WIDTH - MEM_TAG_ID;
|
||||
localparam STALL_TIMEOUT = 10000000;
|
||||
|
||||
`STATIC_ASSERT ((MEM_TAG_ID >= UUID_WIDTH), ("invalid parameter"))
|
||||
`STATIC_ASSERT (DATA_WIDTH == 8 * (DATA_WIDTH / 8), ("invalid parameter"))
|
||||
`STATIC_ASSERT ((0 == RSP_PARTIAL) || (1 == RSP_PARTIAL), ("invalid parameter"))
|
||||
`RUNTIME_ASSERT ((~req_valid || req_mask != 0), ("invalid request mask"));
|
||||
|
||||
wire [NUM_BANKS-1:0] mem_req_valid_s;
|
||||
wire [NUM_BANKS-1:0] mem_req_mask_s;
|
||||
wire [NUM_BANKS-1:0] mem_req_rw_s;
|
||||
wire [NUM_BANKS-1:0][BYTEENW-1:0] mem_req_byteen_s;
|
||||
wire [NUM_BANKS-1:0][ADDR_WIDTH-1:0] mem_req_addr_s;
|
||||
wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_req_data_s;
|
||||
wire [MEM_TAGW-1:0] mem_req_tag_s;
|
||||
wire [NUM_BANKS-1:0] mem_req_ready_s;
|
||||
|
||||
wire mem_rsp_valid_s;
|
||||
wire [NUM_BANKS-1:0] mem_rsp_mask_s;
|
||||
wire [NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_rsp_data_s;
|
||||
wire [MEM_TAGW-1:0] mem_rsp_tag_s;
|
||||
wire mem_rsp_ready_s;
|
||||
wire mem_rsp_fire_s;
|
||||
|
||||
wire reqq_push;
|
||||
wire reqq_pop;
|
||||
wire reqq_full;
|
||||
wire reqq_empty;
|
||||
wire reqq_rw;
|
||||
wire [NUM_REQS-1:0] reqq_mask;
|
||||
wire [NUM_REQS-1:0][BYTEENW-1:0] reqq_byteen;
|
||||
wire [NUM_REQS-1:0][ADDR_WIDTH-1:0] reqq_addr;
|
||||
wire [NUM_REQS-1:0][DATA_WIDTH-1:0] reqq_data;
|
||||
wire [QUEUE_ADDRW-1:0] reqq_tag;
|
||||
wire [MEM_TAG_WIDTH-1:0] reqq_mtid;
|
||||
|
||||
wire ibuf_push;
|
||||
wire ibuf_pop;
|
||||
wire [QUEUE_ADDRW-1:0] ibuf_waddr;
|
||||
wire [QUEUE_ADDRW-1:0] ibuf_raddr;
|
||||
wire ibuf_full;
|
||||
wire ibuf_empty;
|
||||
wire [TAG_ONLY_WIDTH-1:0] ibuf_din;
|
||||
wire [TAG_ONLY_WIDTH-1:0] ibuf_dout;
|
||||
|
||||
wire crsp_valid;
|
||||
wire [NUM_REQS-1:0] crsp_mask;
|
||||
wire [NUM_REQS-1:0][DATA_WIDTH-1:0] crsp_data;
|
||||
wire [TAG_WIDTH-1:0] crsp_tag;
|
||||
wire crsp_sop;
|
||||
wire crsp_eop;
|
||||
wire crsp_ready;
|
||||
|
||||
// Request queue //////////////////////////////////////////////////////////
|
||||
|
||||
wire req_sent_all;
|
||||
|
||||
assign reqq_push = req_valid && req_ready;
|
||||
assign reqq_pop = ~reqq_empty && req_sent_all;
|
||||
|
||||
wire [MEM_TAG_WIDTH-1:0] req_mtid;
|
||||
if (MEM_TAG_ID != 0) begin
|
||||
assign req_mtid = req_tag[TAG_WIDTH-1 -: MEM_TAG_ID];
|
||||
end else begin
|
||||
assign req_mtid = '0;
|
||||
end
|
||||
|
||||
wire [`CLOG2(QUEUE_SIZE+1)-1:0] reqq_size;
|
||||
`UNUSED_VAR (reqq_size)
|
||||
|
||||
VX_fifo_queue #(
|
||||
.DATAW (1 + NUM_REQS * (1 + BYTEENW + ADDR_WIDTH + DATA_WIDTH) + MEM_TAG_WIDTH + QUEUE_ADDRW),
|
||||
.DEPTH (QUEUE_SIZE),
|
||||
.OUT_REG (1)
|
||||
) req_queue (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.push (reqq_push),
|
||||
.pop (reqq_pop),
|
||||
.data_in ({req_rw, req_mask, req_byteen, req_addr, req_data, req_mtid, ibuf_waddr}),
|
||||
.data_out ({reqq_rw, reqq_mask, reqq_byteen, reqq_addr, reqq_data, reqq_mtid, reqq_tag}),
|
||||
.full (reqq_full),
|
||||
.empty (reqq_empty),
|
||||
`UNUSED_PIN (alm_full),
|
||||
`UNUSED_PIN (alm_empty),
|
||||
.size (reqq_size)
|
||||
);
|
||||
|
||||
// can accept another request?
|
||||
assign req_ready = ~reqq_full && (req_rw || ~ibuf_full);
|
||||
|
||||
// no pending requests
|
||||
assign req_empty = reqq_empty && ibuf_empty;
|
||||
|
||||
// notify write submisison
|
||||
assign write_notify = reqq_pop && reqq_rw;
|
||||
|
||||
// Index buffer ///////////////////////////////////////////////////////////
|
||||
|
||||
wire rsp_complete;
|
||||
|
||||
assign ibuf_push = reqq_push && ~req_rw;
|
||||
assign ibuf_pop = crsp_valid && crsp_ready && rsp_complete;
|
||||
assign ibuf_raddr = mem_rsp_tag_s[0 +: QUEUE_ADDRW];
|
||||
assign ibuf_din = req_tag[TAG_ONLY_WIDTH-1:0];
|
||||
|
||||
VX_index_buffer #(
|
||||
.DATAW (TAG_ONLY_WIDTH),
|
||||
.SIZE (QUEUE_SIZE)
|
||||
) req_ibuf (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.acquire_en (ibuf_push),
|
||||
.write_addr (ibuf_waddr),
|
||||
.write_data (ibuf_din),
|
||||
.read_data (ibuf_dout),
|
||||
.read_addr (ibuf_raddr),
|
||||
.release_en (ibuf_pop),
|
||||
.full (ibuf_full),
|
||||
.empty (ibuf_empty)
|
||||
);
|
||||
|
||||
`UNUSED_VAR (ibuf_empty)
|
||||
|
||||
// Handle memory requests /////////////////////////////////////////////////
|
||||
|
||||
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0] mem_req_mask_b;
|
||||
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0] mem_req_rw_b;
|
||||
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0][BYTEENW-1:0] mem_req_byteen_b;
|
||||
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0][ADDR_WIDTH-1:0] mem_req_addr_b;
|
||||
wire [NUM_BATCHES-1:0][NUM_BANKS-1:0][DATA_WIDTH-1:0] mem_req_data_b;
|
||||
|
||||
wire [BATCH_SEL_WIDTH-1:0] req_batch_idx;
|
||||
|
||||
for (genvar i = 0; i < NUM_BATCHES; ++i) begin
|
||||
for (genvar j = 0; j < NUM_BANKS; ++j) begin
|
||||
localparam r = i * NUM_BANKS + j;
|
||||
if (r < NUM_REQS) begin
|
||||
assign mem_req_mask_b[i][j] = reqq_mask[r];
|
||||
assign mem_req_rw_b[i][j] = reqq_rw;
|
||||
assign mem_req_byteen_b[i][j] = reqq_byteen[r];
|
||||
assign mem_req_addr_b[i][j] = reqq_addr[r];
|
||||
assign mem_req_data_b[i][j] = reqq_data[r];
|
||||
end else begin
|
||||
assign mem_req_mask_b[i][j] = 0;
|
||||
assign mem_req_rw_b[i][j] = '0;
|
||||
assign mem_req_byteen_b[i][j] = '0;
|
||||
assign mem_req_addr_b[i][j] = '0;
|
||||
assign mem_req_data_b[i][j] = '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign mem_req_mask_s = mem_req_mask_b[req_batch_idx];
|
||||
assign mem_req_rw_s = mem_req_rw_b[req_batch_idx];
|
||||
assign mem_req_byteen_s = mem_req_byteen_b[req_batch_idx];
|
||||
assign mem_req_addr_s = mem_req_addr_b[req_batch_idx];
|
||||
assign mem_req_data_s = mem_req_data_b[req_batch_idx];
|
||||
|
||||
reg [NUM_BANKS-1:0] batch_sent_mask;
|
||||
|
||||
wire [NUM_BANKS-1:0] batch_sent_mask_n = batch_sent_mask | mem_req_ready_s;
|
||||
|
||||
wire batch_sent_all = (mem_req_mask_s & ~batch_sent_mask_n) == 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
batch_sent_mask <= '0;
|
||||
end else begin
|
||||
if (~reqq_empty) begin
|
||||
if (batch_sent_all) begin
|
||||
batch_sent_mask <= '0;
|
||||
end else begin
|
||||
batch_sent_mask <= batch_sent_mask_n;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (NUM_BATCHES > 1) begin
|
||||
reg [BATCH_SEL_BITS-1:0] req_batch_idx_r;
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
req_batch_idx_r <= '0;
|
||||
end else begin
|
||||
if (~reqq_empty && batch_sent_all) begin
|
||||
if (req_sent_all) begin
|
||||
req_batch_idx_r <= '0;
|
||||
end else begin
|
||||
req_batch_idx_r <= req_batch_idx_r + BATCH_SEL_BITS'(1);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire [NUM_BATCHES-1:0] req_batch_valids;
|
||||
wire [NUM_BATCHES-1:0][BATCH_SEL_BITS-1:0] req_batch_idxs;
|
||||
wire [BATCH_SEL_BITS-1:0] req_batch_idx_last;
|
||||
|
||||
for (genvar i = 0; i < NUM_BATCHES; ++i) begin
|
||||
assign req_batch_valids[i] = (| mem_req_mask_b[i]);
|
||||
assign req_batch_idxs[i] = BATCH_SEL_BITS'(i);
|
||||
end
|
||||
|
||||
VX_find_first #(
|
||||
.N (NUM_BATCHES),
|
||||
.DATAW (BATCH_SEL_BITS),
|
||||
.REVERSE (1)
|
||||
) find_last (
|
||||
.valid_in (req_batch_valids),
|
||||
.data_in (req_batch_idxs),
|
||||
.data_out (req_batch_idx_last),
|
||||
`UNUSED_PIN (valid_out)
|
||||
);
|
||||
|
||||
assign req_batch_idx = req_batch_idx_r;
|
||||
|
||||
assign req_sent_all = batch_sent_all && (req_batch_idx_r == req_batch_idx_last);
|
||||
|
||||
if (MEM_TAG_ID != 0) begin
|
||||
assign mem_req_tag_s = {reqq_mtid, req_batch_idx, reqq_tag};
|
||||
end else begin
|
||||
`UNUSED_VAR (reqq_mtid)
|
||||
assign mem_req_tag_s = {req_batch_idx, reqq_tag};
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
assign req_batch_idx = '0;
|
||||
assign req_sent_all = batch_sent_all;
|
||||
|
||||
if (MEM_TAG_ID != 0) begin
|
||||
assign mem_req_tag_s = {reqq_mtid, reqq_tag};
|
||||
end else begin
|
||||
`UNUSED_VAR (reqq_mtid)
|
||||
assign mem_req_tag_s = reqq_tag;
|
||||
end
|
||||
end
|
||||
|
||||
assign mem_req_valid_s = {NUM_BANKS{~reqq_empty}} & mem_req_mask_s & ~batch_sent_mask;
|
||||
|
||||
for (genvar i = 0; i < NUM_BANKS; ++i) begin
|
||||
VX_elastic_buffer #(
|
||||
.DATAW (1 + BYTEENW + ADDR_WIDTH + DATA_WIDTH + MEM_TAGW),
|
||||
.SIZE (`OUT_REG_TO_EB_SIZE(MEM_OUT_REG)),
|
||||
.OUT_REG (`OUT_REG_TO_EB_REG(MEM_OUT_REG))
|
||||
) mem_req_buf (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.valid_in (mem_req_valid_s[i]),
|
||||
.ready_in (mem_req_ready_s[i]),
|
||||
.data_in ({mem_req_rw_s[i], mem_req_byteen_s[i], mem_req_addr_s[i], mem_req_data_s[i], mem_req_tag_s}),
|
||||
.data_out ({mem_req_rw[i], mem_req_byteen[i], mem_req_addr[i], mem_req_data[i], mem_req_tag[i]}),
|
||||
.valid_out (mem_req_valid[i]),
|
||||
.ready_out (mem_req_ready[i])
|
||||
);
|
||||
end
|
||||
|
||||
// Handle memory responses ////////////////////////////////////////////////
|
||||
|
||||
reg [QUEUE_SIZE-1:0][NUM_REQS-1:0] rsp_rem_mask;
|
||||
wire [NUM_REQS-1:0] rsp_rem_mask_n, curr_mask;
|
||||
wire [BATCH_SEL_WIDTH-1:0] rsp_batch_idx;
|
||||
|
||||
// Select memory response
|
||||
VX_mem_rsp_sel #(
|
||||
.NUM_REQS (NUM_BANKS),
|
||||
.DATA_WIDTH (DATA_WIDTH),
|
||||
.TAG_WIDTH (MEM_TAGW),
|
||||
.TAG_SEL_BITS (MEM_TAGW - MEM_TAG_ID),
|
||||
.OUT_REG (2)
|
||||
) mem_rsp_sel (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.rsp_valid_in (mem_rsp_valid),
|
||||
.rsp_data_in (mem_rsp_data),
|
||||
.rsp_tag_in (mem_rsp_tag),
|
||||
.rsp_ready_in (mem_rsp_ready),
|
||||
.rsp_valid_out (mem_rsp_valid_s),
|
||||
.rsp_mask_out (mem_rsp_mask_s),
|
||||
.rsp_data_out (mem_rsp_data_s),
|
||||
.rsp_tag_out (mem_rsp_tag_s),
|
||||
.rsp_ready_out (mem_rsp_ready_s)
|
||||
);
|
||||
|
||||
for (genvar r = 0; r < NUM_REQS; ++r) begin
|
||||
localparam i = r / NUM_BANKS;
|
||||
localparam j = r % NUM_BANKS;
|
||||
assign curr_mask[r] = (BATCH_SEL_WIDTH'(i) == rsp_batch_idx) && mem_rsp_mask_s[j];
|
||||
end
|
||||
|
||||
assign rsp_rem_mask_n = rsp_rem_mask[ibuf_raddr] & ~curr_mask;
|
||||
|
||||
if (NUM_BATCHES > 1) begin
|
||||
assign rsp_batch_idx = mem_rsp_tag_s[QUEUE_ADDRW +: BATCH_SEL_BITS];
|
||||
end else begin
|
||||
assign rsp_batch_idx = '0;
|
||||
end
|
||||
|
||||
assign rsp_complete = ~(| rsp_rem_mask_n);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (ibuf_push) begin
|
||||
rsp_rem_mask[ibuf_waddr] <= req_mask;
|
||||
end
|
||||
if (mem_rsp_fire_s) begin
|
||||
rsp_rem_mask[ibuf_raddr] <= rsp_rem_mask_n;
|
||||
end
|
||||
end
|
||||
|
||||
assign mem_rsp_fire_s = mem_rsp_valid_s && mem_rsp_ready_s;
|
||||
|
||||
if (RSP_PARTIAL == 1) begin
|
||||
|
||||
reg [QUEUE_SIZE-1:0] rsp_sop_r;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (ibuf_push) begin
|
||||
rsp_sop_r[ibuf_waddr] <= 1;
|
||||
end
|
||||
if (mem_rsp_fire_s) begin
|
||||
rsp_sop_r[ibuf_raddr] <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
assign mem_rsp_ready_s = crsp_ready;
|
||||
|
||||
assign crsp_valid = mem_rsp_valid_s;
|
||||
|
||||
assign crsp_mask = curr_mask;
|
||||
assign crsp_sop = rsp_sop_r[ibuf_raddr];
|
||||
|
||||
for (genvar r = 0; r < NUM_REQS; ++r) begin
|
||||
localparam j = r % NUM_BANKS;
|
||||
assign crsp_data[r] = mem_rsp_data_s[j];
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
reg [NUM_BATCHES*NUM_BANKS*DATA_WIDTH-1:0] rsp_store [QUEUE_SIZE-1:0];
|
||||
reg [NUM_BATCHES*NUM_BANKS*DATA_WIDTH-1:0] rsp_store_n;
|
||||
reg [NUM_REQS-1:0] rsp_orig_mask [QUEUE_SIZE-1:0];
|
||||
|
||||
always @(*) begin
|
||||
rsp_store_n = rsp_store[ibuf_raddr];
|
||||
for (integer i = 0; i < NUM_BANKS; ++i) begin
|
||||
if ((NUM_BANKS == 1) || mem_rsp_mask_s[i]) begin
|
||||
rsp_store_n[(rsp_batch_idx * NUM_BANKS + i) * DATA_WIDTH +: DATA_WIDTH] = mem_rsp_data_s[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (ibuf_push) begin
|
||||
rsp_orig_mask[ibuf_waddr] <= req_mask;
|
||||
end
|
||||
if (mem_rsp_valid_s) begin
|
||||
rsp_store[ibuf_raddr] <= rsp_store_n;
|
||||
end
|
||||
end
|
||||
|
||||
assign mem_rsp_ready_s = crsp_ready || ~rsp_complete;
|
||||
|
||||
assign crsp_valid = mem_rsp_valid_s && rsp_complete;
|
||||
|
||||
assign crsp_mask = rsp_orig_mask[ibuf_raddr];
|
||||
assign crsp_sop = 1'b1;
|
||||
|
||||
for (genvar r = 0; r < NUM_REQS; ++r) begin
|
||||
localparam i = r / NUM_BANKS;
|
||||
localparam j = r % NUM_BANKS;
|
||||
assign crsp_data[r] = rsp_store_n[(i * NUM_BANKS + j) * DATA_WIDTH +: DATA_WIDTH];
|
||||
end
|
||||
end
|
||||
|
||||
if (MEM_TAG_ID != 0) begin
|
||||
assign crsp_tag = {mem_rsp_tag_s[MEM_TAGW-1 -: MEM_TAG_ID], ibuf_dout};
|
||||
end else begin
|
||||
assign crsp_tag = ibuf_dout;
|
||||
end
|
||||
|
||||
assign crsp_eop = ibuf_pop;
|
||||
|
||||
// Send response to caller
|
||||
|
||||
VX_elastic_buffer #(
|
||||
.DATAW (NUM_REQS + 1 + 1 + (NUM_REQS * DATA_WIDTH) + TAG_WIDTH),
|
||||
.SIZE (`OUT_REG_TO_EB_SIZE(CORE_OUT_REG)),
|
||||
.OUT_REG (`OUT_REG_TO_EB_REG(CORE_OUT_REG))
|
||||
) rsp_buf (
|
||||
.clk (clk),
|
||||
.reset (reset),
|
||||
.valid_in (crsp_valid),
|
||||
.ready_in (crsp_ready),
|
||||
.data_in ({crsp_mask, crsp_sop, crsp_eop, crsp_data, crsp_tag}),
|
||||
.data_out ({rsp_mask, rsp_sop, rsp_eop, rsp_data, rsp_tag}),
|
||||
.valid_out (rsp_valid),
|
||||
.ready_out (rsp_ready)
|
||||
);
|
||||
|
||||
`ifdef SIMULATION
|
||||
wire [`UP(UUID_WIDTH)-1:0] req_dbg_uuid;
|
||||
wire [`UP(UUID_WIDTH)-1:0] rsp_dbg_uuid;
|
||||
wire [`UP(UUID_WIDTH)-1:0] mem_req_dbg_uuid;
|
||||
wire [`UP(UUID_WIDTH)-1:0] mem_rsp_dbg_uuid;
|
||||
|
||||
if (UUID_WIDTH != 0) begin
|
||||
assign req_dbg_uuid = req_tag[TAG_WIDTH-1 -: UUID_WIDTH];
|
||||
assign rsp_dbg_uuid = rsp_tag[TAG_WIDTH-1 -: UUID_WIDTH];
|
||||
assign mem_req_dbg_uuid = reqq_mtid[MEM_TAG_ID-1 -: UUID_WIDTH];
|
||||
assign mem_rsp_dbg_uuid = mem_rsp_tag_s[MEM_TAGW-1 -: UUID_WIDTH];
|
||||
end else begin
|
||||
assign req_dbg_uuid = '0;
|
||||
assign rsp_dbg_uuid = '0;
|
||||
assign mem_req_dbg_uuid = '0;
|
||||
assign mem_rsp_dbg_uuid = '0;
|
||||
end
|
||||
|
||||
`UNUSED_VAR (req_dbg_uuid)
|
||||
`UNUSED_VAR (rsp_dbg_uuid)
|
||||
`UNUSED_VAR (mem_req_dbg_uuid)
|
||||
`UNUSED_VAR (mem_rsp_dbg_uuid)
|
||||
|
||||
reg [(`UP(UUID_WIDTH) + TAG_ONLY_WIDTH + 64)-1:0] pending_reqs [QUEUE_SIZE-1:0];
|
||||
reg [QUEUE_SIZE-1:0] pending_req_valids;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
pending_req_valids <= '0;
|
||||
end else begin
|
||||
if (ibuf_push) begin
|
||||
pending_req_valids[ibuf_waddr] <= 1'b1;
|
||||
end
|
||||
if (ibuf_pop) begin
|
||||
pending_req_valids[ibuf_raddr] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
if (ibuf_push) begin
|
||||
pending_reqs[ibuf_waddr] <= {req_dbg_uuid, ibuf_din, $time};
|
||||
end
|
||||
|
||||
for (integer i = 0; i < QUEUE_SIZE; ++i) begin
|
||||
if (pending_req_valids[i]) begin
|
||||
`ASSERT(($time - pending_reqs[i][0 +: 64]) < STALL_TIMEOUT,
|
||||
("%t: *** %s response timeout: remaining=%b, tag=0x%0h (#%0d)",
|
||||
$time, INSTANCE_ID, rsp_rem_mask[i], pending_reqs[i][64 +: TAG_ONLY_WIDTH], pending_reqs[i][64+TAG_ONLY_WIDTH +: `UP(UUID_WIDTH)]));
|
||||
end
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`ifndef NDEBUG
|
||||
wire [NUM_BANKS-1:0] mem_req_fire_s = mem_req_valid_s & mem_req_ready_s;
|
||||
always @(posedge clk) begin
|
||||
if (req_valid && req_ready) begin
|
||||
if (req_rw) begin
|
||||
`TRACE(1, ("%d: %s-core-req-wr: valid=%b, addr=", $time, INSTANCE_ID, req_mask));
|
||||
`TRACE_ARRAY1D(1, req_addr, NUM_REQS);
|
||||
`TRACE(1, (", byteen="));
|
||||
`TRACE_ARRAY1D(1, req_byteen, NUM_REQS);
|
||||
`TRACE(1, (", data="));
|
||||
`TRACE_ARRAY1D(1, req_data, NUM_REQS);
|
||||
end else begin
|
||||
`TRACE(1, ("%d: %s-core-req-rd: valid=%b, addr=", $time, INSTANCE_ID, req_mask));
|
||||
`TRACE_ARRAY1D(1, req_addr, NUM_REQS);
|
||||
end
|
||||
`TRACE(1, (", tag=0x%0h (#%0d)\n", req_tag, req_dbg_uuid));
|
||||
end
|
||||
if (rsp_valid && rsp_ready) begin
|
||||
`TRACE(1, ("%d: %s-rsp: valid=%b, sop=%b, eop=%b, data=", $time, INSTANCE_ID, rsp_mask, rsp_sop, rsp_eop));
|
||||
`TRACE_ARRAY1D(1, rsp_data, NUM_REQS);
|
||||
`TRACE(1, (", tag=0x%0h (#%0d)\n", rsp_tag, rsp_dbg_uuid));
|
||||
end
|
||||
if (| mem_req_fire_s) begin
|
||||
if (| mem_req_rw_s) begin
|
||||
`TRACE(1, ("%d: %s-mem-req-wr: valid=%b, addr=", $time, INSTANCE_ID, mem_req_fire_s));
|
||||
`TRACE_ARRAY1D(1, mem_req_addr_s, NUM_BANKS);
|
||||
`TRACE(1, (", byteen="));
|
||||
`TRACE_ARRAY1D(1, mem_req_byteen_s, NUM_BANKS);
|
||||
`TRACE(1, (", data="));
|
||||
`TRACE_ARRAY1D(1, mem_req_data_s, NUM_BANKS);
|
||||
end else begin
|
||||
`TRACE(1, ("%d: %s-mem-req-rd: valid=%b, addr=", $time, INSTANCE_ID, mem_req_fire_s));
|
||||
`TRACE_ARRAY1D(1, mem_req_addr_s, NUM_BANKS);
|
||||
end
|
||||
`TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_waddr, req_batch_idx, mem_req_dbg_uuid));
|
||||
end
|
||||
if (mem_rsp_fire_s) begin
|
||||
`TRACE(1, ("%d: %s-mem-rsp: valid=%b, data=", $time, INSTANCE_ID, mem_rsp_mask_s));
|
||||
`TRACE_ARRAY1D(1, mem_rsp_data_s, NUM_BANKS);
|
||||
`TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_raddr, rsp_batch_idx, mem_rsp_dbg_uuid));
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
`TRACING_ON
|
||||
@@ -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