I am currently trying to learn assembly (Intel x86) and I've made a program that simulates bit stuffing on 32bit words -> every 5 consecutive identical bits (5 0's or 5 1's), an opposite bit is inserted. In order to keep the word to its original 32bit size, the less significant bits are truncated if stuffing bits are added.
Here are a few examples:
0000 1111 0000 1111 0000 1111 0000 1111 -> 0000 1111 0000 1111 0000 1111 0000 1111
0000 1111 0000 1111 0000 1111 0000 0000 -> 0000 1111 0000 1111 0000 1111 0000 0100
0000 1111 0000 1111 0000 0000 0000 0000 -> 0000 1111 0000 1111 0000 0100 0001 0000
So this is my C++ program that tests if everything works correctly, but the last two don't work, and I can't figure out why. I ran it several times by following every step the program doesn with the IDE Debugger, and it seems to do exactly what I want it to do, but the results don't follow...
#include <iostream>
using namespace std;
extern "C" {unsigned int bitstuffing(unsigned int a);}
int main () {
unsigned int in = 0xFFFFFFFF;
unsigned int verif = 0xFBEFBEFB;
unsigned int out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
in = 0x00000000;
verif = 0x04104104;
out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
in = 0xF0F0F0F; // 0000 1111 0000 1111 0000 1111 0000 1111
verif = 0xF0F0F0F; // 0000 1111 0000 1111 0000 1111 0000 1111
out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
in = 0xF0F0F00; // 0000 1111 0000 1111 0000 1111 0000 0000
verif = 0xF0F0F04; // 0000 1111 0000 1111 0000 1111 0000 0100
out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
in = 0xF0F0000; // 0000 1111 0000 1111 0000 0000 0000 0000
verif = 0xF0F0410; // 0000 1111 0000 1111 0000 0100 0001 0000
out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
in = 0xAAAA0000; // 1010 1010 1010 1010 0000 0000 0000 0000
verif = 0xAAAA0820; // 1010 1010 1010 1010 0000 1000 0010 0000
out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
in = 0x7878000; // 0000 0111 1000 0111 1000 0000 0000 0000
verif = 0x7C1F041; // 0000 0111 1100 0001 1111 0000 0100 0001
// out = 0000 0111 1100 0111 1101 0000 0100 0001
out = bitstuffing(in);
if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;
return 0;
}
And this is the ASM program, which is the most important
CPU 386
%include "io.inc"
section .text
global CMAIN
;0FFFFFFFFh - 0xFBEFBEFB ok
;000000000h - 0x04104104 ok
;0F0F0F0Fh - 0xF0F0F0F ok
;0F0F0F00h - 0xF0F0F04 ok
;0F0F0000h - 0xF0F0410 ok
;0AAAA0000h - 0xAAAA0820 DOESNT WORK
;07878000h - 0x7878000 DOESNT WORK
CMAIN:
mov ebp, esp; for correct debugging
PUSH EBP
MOV EBP, ESP
MOV EAX, 07878000h;[EBP+8] ; places message (parameter) in EAX
MOV ECX, 32
MOV BL, 0 ; counts number of "0" bits
MOV BH, 0 ; counts number of "1" bits
loop1:
ROL EAX, 1
JC carry
JNC no_carry
carry:
XOR BL, BL ; resets "0" counter to 0
INC BH ; increments "1" counter
CMP BH, 5 ; if we get 5 consecutive bits of the same sign -> bitstuffing
JE stuffing_0
DEC ECX ; Decrementing ECX for loop
JNZ loop1
JZ end
no_carry:
XOR BH, BH ; resets "1" counter to 0
INC BL ; increments "0" counter
CMP BL, 5 ; if we get 5 consecutive bits of the same sign -> bitstuffing
JE stuffing_1
DEC ECX ; Decrementing ECX for loop
JNZ loop1
JZ end
stuffing_0:
XOR EDX, EDX
XOR EBX, EBX
MOV EDX, 2 ; Putting 2 in EDX for MUL operation
MUL EDX ; Multiplying EAX by 2 is like adding a 0 at the end
XOR EDX, EDX ; Resetting EDX register
DEC ECX ; Decrementing ECX twice for loop (in order to truncate bits)
DEC ECX
CMP ECX, 0
JG loop1
JLE end
stuffing_1:
XOR EDX, EDX
XOR EBX, EBX
MOV EDX, 2 ; Putting 2 in EDX for MUL operation
MUL EDX ; Multiplying EAX by 2 is like adding a 0 at the end
ADD EAX, 1 ; Adding 1 to EAX when the last bit is the zero we added is the same is adding 1 instead of zero
XOR EDX, EDX ; Resetting EDX register
DEC ECX ; Decrementing ECX twice for loop (in order to truncate bits)
DEC ECX
CMP ECX, 0
JG loop1
JLE end
end:
LEAVE
RET
So when I run this program, it works very well with the following values (they are all put in EAX)
;0FFFFFFFFh - 0xFBEFBEFB ok
;000000000h - 0x04104104 ok
;0F0F0F0Fh - 0xF0F0F0F ok
;0F0F0F00h - 0xF0F0F04 ok
;0F0F0000h - 0xF0F0410 ok
But doesn't work with the following
;0AAAA0000h - 0xAAAA0820 DOESNT WORK
;07878000h - 0x7878000 DOESNT WORK
If anyone can spot the problem it would be of great help!