Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 71 additions & 77 deletions data/verilog/arith/select.v
Original file line number Diff line number Diff line change
@@ -1,92 +1,86 @@
`timescale 1ns/1ps
module antitokens (
// inputs
input clk,
input reset,
input pvalid1,
input pvalid0,
input generate_at1,
input generate_at0,
// outputs
output kill1,
output kill0,
output stop_valid
);

wire reg_in0;
wire reg_in1;
reg reg_out0 = 1'b0;
reg reg_out1 = 1'b0;

always @(posedge clk) begin
if (reset) begin
reg_out0 <= 1'b0;
reg_out1 <= 1'b0;
end else begin
reg_out0 <= reg_in0;
reg_out1 <= reg_in1;
end
end

assign reg_in0 = !pvalid0 & (generate_at0 | reg_out0);
assign reg_in1 = !pvalid1 & (generate_at1 | reg_out1);
module selector #(
parameter DATA_TYPE = 8
)(
// Inputs
input wire clk,
input wire rst,
input wire [0:0] condition,
input wire condition_valid,
input wire [DATA_TYPE-1:0] trueValue,
input wire trueValue_valid,
input wire [DATA_TYPE-1:0] falseValue,
input wire falseValue_valid,
input wire result_ready,
// Outputs
output wire [DATA_TYPE-1:0] result,
output wire result_valid,
output wire condition_ready,
output wire trueValue_ready,
output wire falseValue_ready
);

assign stop_valid = reg_out0 | reg_out1;
// Parameters
localparam discard_depth = 4;
localparam counter_width = $clog2(discard_depth);

assign kill0 = generate_at0 | reg_out0;
assign kill1 = generate_at1 | reg_out1;
// Internal signals
reg [counter_width-1:0] num_token_to_discard_true = 0;
reg [counter_width-1:0] num_token_to_discard_false = 0;

endmodule
wire can_propagate_true;
wire can_propagate_false;
wire can_discard_true;
wire can_discard_false;
wire still_need_to_discard_true;
wire still_need_to_discard_false;

// ----------------------
// Internal signal logic
// ----------------------
assign can_discard_true = (trueValue_valid || (num_token_to_discard_true < discard_depth)) ? 1'b1 : 1'b0;
assign can_discard_false = (falseValue_valid || (num_token_to_discard_false < discard_depth)) ? 1'b1 : 1'b0;

module selector #(
parameter DATA_TYPE = 32
)(
// inputs
input clk,
input rst,
input condition,
input condition_valid,
input [DATA_TYPE-1 : 0] trueValue,
input trueValue_valid,
input [DATA_TYPE-1 : 0] falseValue,
input falseValue_valid,
input result_ready,
// outputs
output [DATA_TYPE-1 : 0] result,
output result_valid,
output condition_ready,
output trueValue_ready,
output falseValue_ready
);
assign can_propagate_true = (condition_valid && condition[0] && trueValue_valid &&
(num_token_to_discard_true == 0) && can_discard_false) ? 1'b1 : 1'b0;

wire ee, validInternal, kill0, kill1, antitokenStop, g0, g1;
assign can_propagate_false = (condition_valid && !condition[0] && falseValue_valid &&
(num_token_to_discard_false == 0) && can_discard_true) ? 1'b1 : 1'b0;

// condition and one input
assign ee = condition_valid & ( ( !condition & falseValue_valid) | (condition & trueValue_valid) );
// propagate ee if not stopped antitoken
assign validInternal = ee & !antitokenStop;
assign still_need_to_discard_true = (num_token_to_discard_true > 0) ? 1'b1 : 1'b0;
assign still_need_to_discard_false = (num_token_to_discard_false > 0) ? 1'b1 : 1'b0;

assign g0 = !trueValue_valid & validInternal & result_ready;
assign g1 = !falseValue_valid & validInternal & result_ready;
// ----------------------
// Handshake signals
// ----------------------
assign result_valid = can_propagate_true || can_propagate_false;
assign result = condition[0] ? trueValue : falseValue;

assign result_valid = validInternal;
assign trueValue_ready = !trueValue_valid | (validInternal & result_ready) | kill0; // normal join or antitoken
assign falseValue_ready = !falseValue_valid | (validInternal & result_ready) | kill1; // normal join or antitoken
assign condition_ready = !condition_valid | (validInternal & result_ready); // normal join
assign trueValue_ready = (~trueValue_valid) || (result_valid && result_ready) || still_need_to_discard_true;
assign falseValue_ready = (~falseValue_valid) || (result_valid && result_ready) || still_need_to_discard_false;
assign condition_ready = (~condition_valid) || (result_valid && result_ready);

assign result = condition ? trueValue : falseValue;
// ----------------------
// Discard counters
// ----------------------
always @(posedge clk) begin
if (rst) begin
num_token_to_discard_true <= 0;
num_token_to_discard_false <= 0;
end else begin
// True counter update
if (result_valid && result_ready && !trueValue_valid)
num_token_to_discard_true <= num_token_to_discard_true + 1;
else if (still_need_to_discard_true && trueValue_valid)
num_token_to_discard_true <= num_token_to_discard_true - 1;

antitokens antitokens (
.clk(clk),
.reset(rst),
.pvalid0(trueValue_valid),
.pvalid1(falseValue_valid),
.generate_at0(g0),
.generate_at1(g1),
.kill0(kill0),
.kill1(kill1),
.stop_valid(antitokenStop)
);
// False counter update
if (result_valid && result_ready && !falseValue_valid)
num_token_to_discard_false <= num_token_to_discard_false + 1;
else if (still_need_to_discard_false && falseValue_valid)
num_token_to_discard_false <= num_token_to_discard_false - 1;
end
end

endmodule
167 changes: 95 additions & 72 deletions data/vhdl/arith/select.vhd
Original file line number Diff line number Diff line change
@@ -1,55 +1,7 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity antitokens is
port (
clk, rst : in std_logic;
pvalid1, pvalid0 : in std_logic;
kill1, kill0 : out std_logic;
generate_at1, generate_at0 : in std_logic;
stop_valid : out std_logic
);
end antitokens;

architecture arch of antitokens is
signal reg_in0, reg_in1, reg_out0, reg_out1 : std_logic;
begin

reg0 : process (clk)
begin
if (rising_edge(clk)) then
if (rst = '1') then
reg_out0 <= '0';
else
reg_out0 <= reg_in0;
end if;
end if;
end process reg0;

reg1 : process (clk)
begin
if (rising_edge(clk)) then
if (rst = '1') then
reg_out1 <= '0';
else
reg_out1 <= reg_in1;
end if;
end if;
end process reg1;

reg_in0 <= not pvalid0 and (generate_at0 or reg_out0);
reg_in1 <= not pvalid1 and (generate_at1 or reg_out1);

stop_valid <= reg_out0 or reg_out1;

kill0 <= generate_at0 or reg_out0;
kill1 <= generate_at1 or reg_out1;
end architecture;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

entity selector is
generic (
Expand All @@ -76,33 +28,104 @@ entity selector is
end entity;

architecture arch of selector is
signal ee, validInternal : std_logic;
signal kill0, kill1 : std_logic;
signal antitokenStop : std_logic;
signal g0, g1 : std_logic;
begin
-- One side can run ahead of the other for "discard_depth - 1" times
-- NOTE: discard_depth > 1
constant discard_depth : integer := 4;
constant counter_width : positive := positive(ceil(log2(real(discard_depth))));

ee <= condition_valid and ((not condition(0) and falseValue_valid) or (condition(0) and trueValue_valid)); --condition(0) and one input
validInternal <= ee and not antitokenStop; -- propagate ee if not stopped by antitoken
-- number of tokens to discard for the true side
signal num_token_to_discard_true : std_logic_vector(counter_width - 1 downto 0) := (others => '0');
-- number of tokens to discard for the false side
signal num_token_to_discard_false : std_logic_vector(counter_width - 1 downto 0) := (others => '0');

g0 <= not trueValue_valid and validInternal and result_ready;
g1 <= not falseValue_valid and validInternal and result_ready;
signal can_propagate_true : std_logic;
signal can_propagate_false : std_logic;

result_valid <= validInternal;
trueValue_ready <= (not trueValue_valid) or (validInternal and result_ready) or kill0; -- normal join or antitoken
falseValue_ready <= (not falseValue_valid) or (validInternal and result_ready) or kill1; --normal join or antitoken
condition_ready <= (not condition_valid) or (validInternal and result_ready); --like normal join
signal can_discard_true : std_logic;
signal can_discard_false : std_logic;

signal still_need_to_discard_true : std_logic;
signal still_need_to_discard_false : std_logic;
begin

result <= falseValue when (condition(0) = '0') else
trueValue;

Antitokens : entity work.antitokens
port map(
clk, rst,
falseValue_valid, trueValue_valid,
kill1, kill0,
g1, g0,
antitokenStop
);
-- [START internal signal configuration]
-- Select can discard more true if we are currently discarding a true or the counter hasn't reached the limit
can_discard_true <= '1' when ((trueValue_valid = '1') or (unsigned(num_token_to_discard_true) < discard_depth)) else '0';
-- Select can discard more false if we are currently discarding a true or the counter hasn't reached the limit
can_discard_false <= '1' when ((falseValue_valid = '1') or (unsigned(num_token_to_discard_false) < discard_depth)) else '0';

can_propagate_true <= '1' when
((condition_valid = '1') and
(condition(0) = '1') and
(trueValue_valid = '1') and
(unsigned(num_token_to_discard_true) = 0) and
(can_discard_false = '1'))
else '0';

can_propagate_false <= '1' when
((condition_valid = '1') and
(condition(0) = '0') and
(falseValue_valid = '1') and
(unsigned(num_token_to_discard_false) = 0) and
(can_discard_true = '1'))
else '0';

still_need_to_discard_true <= '1' when (unsigned(num_token_to_discard_true) > 0) else '0';
still_need_to_discard_false <= '1' when (unsigned(num_token_to_discard_false) > 0) else '0';
-- [END internal signal configuration]

-- [START handshake configuration]
-- true (false) token is valid to send if
-- 1. there is nothing to discard for true (false)
-- 2. the data is valid
-- 3. the counter for false (true) is less than maximum
result_valid <= can_propagate_true or can_propagate_false;
result <= falseValue when (condition(0) = '0') else trueValue;

-- Conditions:
-- 1. "not trueValue_valid": prevent deadlocking.
-- 2. "result_valid and result_ready": all three inputs are valid. In this case, take all of them and discard the unselected one.
-- 3. "discard_true": false input and condition are passed without the true input in a previous cycle. Here we need to discard that one.
trueValue_ready <= (not trueValue_valid) or (result_valid and result_ready) or (still_need_to_discard_true);
falseValue_ready <= (not falseValue_valid) or (result_valid and result_ready) or (still_need_to_discard_false);
condition_ready <= (not condition_valid) or (result_valid and result_ready);
-- [END handshake configuration]

-- [START updating the discard counters]
proc_counter_true : process (clk)
begin
if (rising_edge(clk)) then
if (rst = '1') then
num_token_to_discard_true <= (others => '0');
else
-- false token transfered without discarding true token
if (result_valid and result_ready and (not trueValue_valid)) then
num_token_to_discard_true <= std_logic_vector(unsigned(num_token_to_discard_true) + 1);
-- discarding the true token while not taking any new false token
elsif (still_need_to_discard_true and trueValue_valid) then
num_token_to_discard_true <= std_logic_vector(unsigned(num_token_to_discard_true) - 1);
end if;
end if;
end if;
end process proc_counter_true;

proc_counter_false : process (clk)
begin
if (rising_edge(clk)) then
if (rst = '1') then
num_token_to_discard_false <= (others => '0');
else
-- false token transfered without discarding true token
if (result_valid and result_ready and (not falseValue_valid)) then
num_token_to_discard_false <= std_logic_vector(unsigned(num_token_to_discard_false) + 1);
-- discarding the false token while not taking any new false token
elsif (still_need_to_discard_false and falseValue_valid) then
num_token_to_discard_false <= std_logic_vector(unsigned(num_token_to_discard_false) - 1);
end if;
end if;
end if;
end process proc_counter_false;
-- [END updating the discard counters]

end architecture;
Loading