转补码,用逻辑运算实现一个全加器,然后级联做成 32 位全加器,这样就有了做加减法的能力,乘除法同理,计算出的结果可以转回原码再求出真值
不过如何实现真值到原码到补码?很简单,利用按位逻辑运算,比如 C++中,一条语句`x=1;`,那么 x 就对应内存中一个存储位置,可以用按位逻辑运算取出每一位,然而非常巧的是,内存中的数值是以补码形式存储的,所以就能够取出补码每一位,也就是说不需要求补码,补码已经躺在内存里了
我写了一个程序来简单说明,只有循环用到了加法`i++`,但是所有循环的次数都是确定的,也就是说**循环可以展开,替换成循环体重复 32 次,相当于没有使用加法**
```
#include <iostream>
using namespace std;
void getComplementCode(bool arr[32], int num) {
int mask = 1;
for (int i = 0; i < 32; i++) {
arr[i] = num & mask;
num = num >> 1;
}
}
int getTrueValue(const bool arr[32]){
int s = 0;
for (int i = 0; i < 32; i++) {
s = s | (arr[i] << i);
}
return s;
}
void add1(bool a, bool b, bool &s, bool c0, bool &c1) {
s = a ^ b ^ c0;
c1 = (a && b) || ((a ^ b) && c0);
}
void add32(bool a[32], bool b[32], bool s[32], bool c = false) {
bool carray[32];
add1(a[0], b[0], s[0], c, carray[0]);
for (int i = 1; i < 32; i++) {
add1(a[i], b[i], s[i], carray[i-1], carray[i]);
}
}
void getTwoComplement(bool arr[32]){
for(int i=0;i<32;i++){
arr[i] = ! arr[i];
}
bool temp[32];
bool one[32];
one[0] = true;
for(int i=1;i<32;i++){
one[i] = false;
}
add32(arr, one, temp);
for(int i=0;i<32;i++){
arr[i] = temp[i];
}
}
int add(int a, int b){
bool A[32], B[32], S[32];
getComplementCode(A, a);
getComplementCode(B, b);
add32(A, B, S);
return getTrueValue(S);
}
int sub(int a, int b){
bool A[32], B[32], S[32];
getComplementCode(A, a);
getComplementCode(B, b);
getTwoComplement(B);
add32(A, B, S);
return getTrueValue(S);
}
int main() {
cout << add(10, 5) << endl;
return 0;
}
```
乘法的话,32 位加 32 位结果是 64 位的,按照这个方式也能够实现
我写的了一个测试用例如下
```
BOOST_AUTO_TEST_CASE(addTest1){
const int times = 10000;
int a = (int)random();
int b = (int)random();
BOOST_TEST(a + b == add(a, b));
}
```
测试通过
除法和浮点数运算,计组课上没讲,不知道具体怎么做,不过道理都是相同的,模拟机器运算,把 C++写成 verilog