考虑以下问题。您有一个位串,表示一个热编码中的当前调度从属。例如,“00000100”(最左边的位为#7,最右边的#0)表示调度了从属#2。
现在,我想在循环调度方案中选择下一个预定的从站,并进行扭曲。我有一个“请求掩码”,说明实际上想要安排哪些奴隶。只会从想要的人那里挑选下一个奴隶。
一些例子(假设通过向左旋转完成循环调度)。 例1:
例2:
现在,我知道,这可以很容易地循环编码。但实际上我想通过一个有点笨拙的操作得到我的结果,没有循环。动机:我想用VHDL / Verilog中的硬件(在FPGA中)实现它。
奖励是组成一个对任意数量的奴隶N都是通用的算法。
顺便说一下,这不是一个功课问题。无论何时想要以某种方式安排从属设备,并通过从属设备的请求来调度调度,这都是一个重要的问题。我目前的解决方案有点“沉重”,我想知道我是否遗漏了一些明显的东西。
答案 0 :(得分:6)
循环不一定是坏事。
我只想做
current[i] = current[i-1] & mask[i] | // normal shift logic
mask[i] & current[i-2] & !mask[i-1] | // here build logic
... // expression for
// remaining
然后将其放入生成循环(即它将展开到硬件中),这将为表达式生成并行硬件。
此处提到的其他解决方案使用多个“ - ”。我只能劝阻他们,因为这会给你带来非常昂贵的操作。 ESP。在一个热点,你可以轻松获得超过> 32位,在HW中不容易实现,因为借位必须通过所有位(某些fpgas上的死区进位逻辑使其在少量位时可接近)。
答案 1 :(得分:4)
我在Altera高级综合食谱中找到了以下用于实现该任务的Verilog代码。
// 'base' is a one hot signal indicating the first request
// that should be considered for a grant. Followed by higher
// indexed requests, then wrapping around.
//
module arbiter (
req, grant, base
);
parameter WIDTH = 16;
input [WIDTH-1:0] req;
output [WIDTH-1:0] grant;
input [WIDTH-1:0] base;
wire [2*WIDTH-1:0] double_req = {req,req};
wire [2*WIDTH-1:0] double_grant = double_req & ~(double_req-base);
assign grant = double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH];
endmodule
它使用减法(虽然只有一次),所以在概念上它与Doug的解决方案非常相似。
答案 2 :(得分:3)
以下解决方案适用于任意数量的从设备(K),并且在FPGA中为O(n)。对于现场的每个位,您将需要三个逻辑门和两个逆变器。我用基本的逻辑模拟器测试了这个概念,它可以工作。
当前和掩码之间的逻辑门链实际上创建了一个优先级系统,它有利于链中的“低位”位。这个链在末尾循环,但当前位用于打破链。
为了使操作可视化,假设在当前字段中设置了位 3 ,并在图中向下跟随信号。位 3 的逻辑1在第一个AND门的输入端放置一个逻辑0,这保证了该AND门的输出也为零(这就是OR门链断开的地方) )。第一个AND门输出端的零点在第二个AND门的输入端放置一个。这使得 next 的位 2 直接依赖于掩码的位 2 。
现在,OR门链发挥作用。
如果设置掩码的位 2 ,则直接在其左侧的OR门的逻辑输出也将是1,这将是逻辑输出在当前的位 2 下面的AND门输入端(由于当前中只有一位可以设置为0,因此它将为零)时间)。顶部AND门的输出处的逻辑1在底部AND门的输入处放置逻辑0,因此将 next 的位 1 设置为等于零。
如果掩码的位 2 未设置,则OR门的两个输入都将为零,因此AND门的输出位于 2 < 当前的/ i>将为零,在底部AND门的输入端放置一个,因此将 1 设为 next 依赖于掩码的位 1 。
该逻辑遵循OR门“向上”的位,从左侧向后循环到右侧,确保 next 中只有一位可以设置为1。由于该位被置位,循环一旦返回到当前的位 3 就会停止。这可以防止电路停留在永久循环中。
我没有使用Verilog或VHDL的经验,因此我会将实际代码留给您and the rest of stackoverflow。
alt text http://img145.imageshack.us/img145/5125/bitshifterlogicdiagramkn7.jpg
说明:
答案 3 :(得分:2)
假设两个补码表示,请在C中调用您的两个单词mask
和current
:
mask_lo = (current << 1) - 1; // the bits to the right and including current
mask_hi = ~mask_lo; // the bits to the left of current
// the left bits, otherwise right:
next = (mask & mask_hi) ? (mask & mask_hi) : (mask & mask_lo);
return (next & -next); // the least significant bit set
答案 4 :(得分:2)
减去1是这里的基本想法。它用于级联借位以找到下一个任务。
bits_before_current = ~(current-1) & ~current
bits_after_current = current-1
todo = (mask & bits_before_current)
if todo==0: todo = (mask & bits_after_current) // second part is if we have to wrap around
next = last_bit_of_todo = todo & -todo
这将在内部使用循环...
答案 5 :(得分:2)
有趣的问题!我不禁想知道你是否无法简化你的调度程序操作,所以这种操作是必要的。
鉴于您了解VHDL,我不会详细介绍,但我的建议如下:
使用3位编码器将当前计划的任务转换为数字:
01000000 - &gt; 6
然后使用桶形移位器将掩码旋转数字+ 1(跳过当前任务):
00001010 - &gt; 00010100
然后使用优先级编码器查找第一个可用的“下一个”任务:
00010100 - &gt; 00000100 - &gt; 2
然后通过添加反转桶移位:
(2 + 7)%8 = 1
当重新编码时,将提供下一个计划任务:
00000010
应该是非常快速和直接的,虽然桶状变速器在房地产方面是“昂贵的”,但我目前还没有看到解决这个问题的简单方法。
编辑:Doug的解决方案显得更加优雅......
- 亚当
答案 6 :(得分:1)
这应该做你想要的:
number_of_tasks= <number of tasks, in the example this is 8>
next_mask= current | (current - 1);
next_barrel= next | (next << number_of_tasks);
next_barrel&= ~number_of_tasks;
next_barrel&= -next_barrel;
next_barrel|= next_barrel >> number_of_tasks;
next_task_mask= next_barrel & -next_barrel;
基本上,复制下一个任务掩码的位,屏蔽掉我们不想考虑的位,找到最低设置位,将高位折回,然后取最低位设置。这是在恒定的时间内运行。
编辑:更新以考虑当前== 00010000和next_mask == 00111000
答案 7 :(得分:1)
未经测试,但是如果不能产生合理的合成,我会感到惊讶......相对于典型的比特笨拙的黑客而言,具有相对可读性的优势(无论如何)。< / p>
for i in current'range loop
current := rotate_left(current, 1);
if or_reduce(mask and current) = '1' then
current:= mask and current;
end if;
end loop;