什么可能是 C 中 SystemVerilog 的 casex 语句的等效方法
What could be an equivalent approach to a casex statement from SystemVerilog in C
一些背景信息:我目前正在编写一个模拟器。我正在尝试实现具有类似行为的解码器,例如 SystemVerilog 上的 'casex' 语句。
为了举例说明,这些是一些说明。
BNE_ENCODING 0b100011xx
BRK_ENCODING 0b10101100
CMP_ENCODING 0b01110000
DEC_ENCODING 0b1001xxxx
我尝试了什么:我尝试用零替换 x。但是那没有用。
我不明白如何在不创建冲突的 case 语句的情况下忽略 C 语言的最后一位。 x 代表忽略的位。我试图通过查看 Quartus 生成的 RTL 输出来了解一些实现(我知道 RTL 与 C 无关,它只是让我了解我可以实现的布尔表达式)。译码器是用或非门实现的。
System Verilog 上的部分解码器。
casex(op)
8'b100011xx: /* Do something */;
8'b10101100: /* Do something */;
8'b01110000: /* Do something */;
8'b1001xxxx: /* Do something */;
endcase
问题:用 C 语言实现这种解码器的正确方法是什么?我所说的解码器是指与 Verilog casex
语句具有相似行为的 switch 语句。
忽略某些位可以通过按位与操作屏蔽它们来完成。
if ((op & 0xFC) == 0x8C) {
/* 8'b100011xx */
} else if ((op & 0xFF) == 0xAC) {
/* 8'b10101100 */
} else if ((op & 0xFF) == 0x70) {
/* 8'b01110000 */
} else if ((op & 0xF0) == 0x90) {
/* 8'b1001xxxx */
}
如果你坚持使用switch
语句,你可以使用多级的。
switch (op & 0xF0) {
case 0x80: /* 8'b1000xxxx */
switch (op & 0x0C) {
case 0x0C: /* 8'bxxxx11xx (8'b100011xx) */
break;
}
break;
case 0xA0: /* 8'b1010xxxx */
switch (op & 0x0F) {
case 0x0C: /* 8'bxxxx1100 (8'b10101100) */
break;
}
break;
case 0x70: /* 8'b0111xxxx */
switch (op & 0x0F) {
case 0x00: /* 8'bxxxx0000 (8'b01110000) */
break;
}
break;
case 0x90: /* 8'b1001xxxx */
break;
}
由于您需要实现通配符,您可以使用 if-else
链,在其中以某种方式屏蔽输入,使比较忽略 不关心 位:
if((op & 0xFC) == 0x8C) // 0x8C = 8'b10001100
{
/* Do something */;
}
else if(op == 0xAC) // 0xAC = 8'b10101100
{
/* Do something */;
}
else if(op == 0x70) // 0x70 = 8'b01110000
{
/* Do something */;
}
else if((op & 0xF0) == 0x90) // 0x90 = 8'b1001xxxx
{
/* ... */
}
- 在第一个条件中,你将输入
op
与 0xFC,即 b11111100
进行运算,以便将两个 LSB 设置为 0,并将其与你输入的值进行比较 casex
无关位设置为 0 (0x8C)
- 第二个和第三个条件是直接比较
- 在最后一个条件中,你将输入
op
与0xF0,即b11110000
进行AND运算,以便将四个LSB设置为0,并将其与你输入的值进行比较casex
无关位设置为 0 (0x90)
您可以使用右移运算符 (>>)。
int x = 10; // 1010 in binary
switch(x >> 1) // this would have switched 101, getting rid of the 0 at the end
switch(x >> 2) // this would have switched 10, getting rid of the 10 at the end
如果您使用 gcc
系列编译器(gcc
、clang
、icc
等),您可以使用 switch ... case
中的范围,这将准确地执行操作你想要:
void foo(uint8_t val)
{
switch(val)
{
case 0b10001100 ... 0b10001111:
/* do something */
break;
case 0b10101100:
/* do something */
break;
case 0b01110000:
/* do something */
break;
case 0b10010000 ... 0b10011111:
/* do something */
break;
default:
/* do something */
break;
}
}
作为额外的奖励,gcc
也有二进制常量扩展。
一些背景信息:我目前正在编写一个模拟器。我正在尝试实现具有类似行为的解码器,例如 SystemVerilog 上的 'casex' 语句。
为了举例说明,这些是一些说明。
BNE_ENCODING 0b100011xx
BRK_ENCODING 0b10101100
CMP_ENCODING 0b01110000
DEC_ENCODING 0b1001xxxx
我尝试了什么:我尝试用零替换 x。但是那没有用。
我不明白如何在不创建冲突的 case 语句的情况下忽略 C 语言的最后一位。 x 代表忽略的位。我试图通过查看 Quartus 生成的 RTL 输出来了解一些实现(我知道 RTL 与 C 无关,它只是让我了解我可以实现的布尔表达式)。译码器是用或非门实现的。
System Verilog 上的部分解码器。
casex(op)
8'b100011xx: /* Do something */;
8'b10101100: /* Do something */;
8'b01110000: /* Do something */;
8'b1001xxxx: /* Do something */;
endcase
问题:用 C 语言实现这种解码器的正确方法是什么?我所说的解码器是指与 Verilog casex
语句具有相似行为的 switch 语句。
忽略某些位可以通过按位与操作屏蔽它们来完成。
if ((op & 0xFC) == 0x8C) {
/* 8'b100011xx */
} else if ((op & 0xFF) == 0xAC) {
/* 8'b10101100 */
} else if ((op & 0xFF) == 0x70) {
/* 8'b01110000 */
} else if ((op & 0xF0) == 0x90) {
/* 8'b1001xxxx */
}
如果你坚持使用switch
语句,你可以使用多级的。
switch (op & 0xF0) {
case 0x80: /* 8'b1000xxxx */
switch (op & 0x0C) {
case 0x0C: /* 8'bxxxx11xx (8'b100011xx) */
break;
}
break;
case 0xA0: /* 8'b1010xxxx */
switch (op & 0x0F) {
case 0x0C: /* 8'bxxxx1100 (8'b10101100) */
break;
}
break;
case 0x70: /* 8'b0111xxxx */
switch (op & 0x0F) {
case 0x00: /* 8'bxxxx0000 (8'b01110000) */
break;
}
break;
case 0x90: /* 8'b1001xxxx */
break;
}
由于您需要实现通配符,您可以使用 if-else
链,在其中以某种方式屏蔽输入,使比较忽略 不关心 位:
if((op & 0xFC) == 0x8C) // 0x8C = 8'b10001100
{
/* Do something */;
}
else if(op == 0xAC) // 0xAC = 8'b10101100
{
/* Do something */;
}
else if(op == 0x70) // 0x70 = 8'b01110000
{
/* Do something */;
}
else if((op & 0xF0) == 0x90) // 0x90 = 8'b1001xxxx
{
/* ... */
}
- 在第一个条件中,你将输入
op
与 0xFC,即b11111100
进行运算,以便将两个 LSB 设置为 0,并将其与你输入的值进行比较casex
无关位设置为 0 (0x8C) - 第二个和第三个条件是直接比较
- 在最后一个条件中,你将输入
op
与0xF0,即b11110000
进行AND运算,以便将四个LSB设置为0,并将其与你输入的值进行比较casex
无关位设置为 0 (0x90)
您可以使用右移运算符 (>>)。
int x = 10; // 1010 in binary
switch(x >> 1) // this would have switched 101, getting rid of the 0 at the end
switch(x >> 2) // this would have switched 10, getting rid of the 10 at the end
如果您使用 gcc
系列编译器(gcc
、clang
、icc
等),您可以使用 switch ... case
中的范围,这将准确地执行操作你想要:
void foo(uint8_t val)
{
switch(val)
{
case 0b10001100 ... 0b10001111:
/* do something */
break;
case 0b10101100:
/* do something */
break;
case 0b01110000:
/* do something */
break;
case 0b10010000 ... 0b10011111:
/* do something */
break;
default:
/* do something */
break;
}
}
作为额外的奖励,gcc
也有二进制常量扩展。