This program is a programmable big hexadecimal number calculator, written in x86 assembly language using FASM (the flat assembler). It works with unsigned integers that can be up to 400 bytes (800 hex digits) in length. It looks like this:
Usage
Up to 14 parameters are available to the user of the program, all of which are 400 byte hex numbers. Ten of these parameters can be defined by the user, while the other 4 are built-in.
The edit control on the left allows the user to enter up to ten 400 byte input parameters. Curly brackets are used to define the name of a parameter. A parameter name can be up to 8 characters in length and can include letters, numbers and an underscore. It is case sensitive. The parameter name is followed by a hex value which can be up to 400 bytes (or 800 hex digits) in length. If nothing follows a parameter name definition, the value of that parameter will be initialised to zero. For example:
Define the parameters A = 2, B = 3 and a = 4: {A} 2 {B} 3 {a} 4 Initialise a parameter to a 400 byte value: {Wxyz_123} 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef 01234567 89abcdef Define the parameters a, b, c, d, e ,f, g, h ,i, j and initialise to zero: {a}{b}{c}{d}{e}{f}{g}{h}{i}{j} |
Once the parameters and their values have been entered, press the [Load Parameters] button to read them into memory. To clear all user defined parameters, press the [Clear Parameters] button.
There are also 4 built-in parameters: reg_1, reg_2, reg_3 and reg_4. These are displayed in the edit control on the lower right.
Calculations are implemented by entering instructions into the edit control on the upper right. Up to 40 instructions can be entered and executed at any one time. Instructions are executed by pressing the [Run Instructions] button. Press the [Clear Instructions] button to clear the instructions edit control.
Press the [Reset All] button to clear everything.
Instructions
The instructions used to perform arithmetic operations are like x86 assembly language instructions. But instead of the arguments being registers or memory locations, they are the 400 byte hex number parameters as described above. Some of the instructions also take an immediate value as one of their arguments. Depending on the instruction, the immediate value will be read either as a hex number or a decimal number. The hex number immediate values can be up to 16 bytes (32 hex digits) in length and must not contain any white space or non hex digit characters. The decimal number immediate values can only be up to 4 decimal digits in length and must not be greater than 3200.
The instruction are not case sensitive. So for example, mov can be written as: mov, Mov or MOV. The arguments (the parameter names) are case sensitive.
The instructions and their arguments are white space delimited, and there can also be any amount of leading and trailing white spaces.
A simple example:
Movi reg_1 1234567890abcdef Movi reg_2 abcdef0987654321 Movi reg_3 1234abcd Add reg_2 reg_1 Not reg_1 Mul reg_3 reg_1 Xor reg_3 reg_2 Rotr reg_2 127 |
In other words: move some immediate hex values into reg_1, reg_2 and reg_3. Then add reg_1 to reg_2. Not reg_1 and then multiply reg_3 by reg_1. Xor reg_2 into reg_3 and then right rotate reg_2 by 127 bits.
Single Argument Instructions
Dest is one of the 400 byte hex values.
Not dest | NOT the destination value: dest = not dest |
Neg dest | Negate the destination value: dest = -dest = 1 + not dest |
Clr dest | Clear the destination value: dest = 0 |
Double Argument Instructions
Both dest and src are one of the 400 byte hex values.
Mov dest src | Copy the source value to the destination: dest = src |
Add dest src | Add the source value to the destination: dest = dest + src |
Sub dest src | Subtract the source value from the destination: dest = dest – src |
Mul dest src | Multiply the destination by the source: dest = dest x src |
Div dest src | Divide the destination by the source: dest = dest / src |
Mod dest src | Compute destination modulo source: dest = dest mod src |
And dest src | Bitwise AND of the destination and source: dest = dest AND src |
Or dest src | Bitwise OR of the destination and source: dest = dest OR src |
Xor dest src | Bitwise XOR of the destination and source: dest = dest XOR src |
Xchg dest src | Exchange the destination and source values: swap(dest,src) |
Double Argument Instructions
Dest is one of the 400 byte hex values. The second argument is a 16 byte (128 bit) hex value. There must be no spaces or non hex digits in this argument.
Movi dest immed | Copy the immediate value to the destination: dest = immed |
Addi dest immed | Add the immediate value to the destination: dest = dest + immed |
Subi dest immed | Subtract the immediate value from the destination: dest = dest – immed |
Muli dest immed | Multiply the destination by the immediate value: dest = dest x immed |
Divi dest immed | Divide the destination by the immediate value: dest = dest / immed |
Modi dest immed | Compute the modulo of the destination with the immediate value: dest = dest mod immed |
Andi dest immed | Bitwise AND the immediate value into the destination: dest = dest AND immed |
Ori dest immed | Bitwise OR the immediate value into the destination: dest = dest OR immed |
Xori dest immed | Bitwise XOR the immediate value into the destination: dest = dest XOR immed |
Double Argument Instructions
Dest is one of the 400 byte hex values. The second argument is a decimal number of up to 4 digits. It cannot be greater than 3200.
Shl dest immed | Bitwise left shift of the destination value by the number of bits given by the immediate value. |
Shr dest immed | Bitwise right shift of the destination value by the number of bits given by the immediate value. |
Rotl dest immed | Bitwise left rotation of the destination value by the number of bits given by the immediate value. |
Rotr dest immed | Bitwise right rotation of the destination value by the number of bits given by the immediate value. |
Trunc dest immed | Truncate the destination value to the number of bits given by the immediate value. |
Bset dest immed | Set the number of bits in the destination value as given by the immediate value. |
Single Argument Instructions
The argument is an immediate value which is read as a decimal number of up to 4 digits. It cannot be greater than 3200.
Nbytes immed | When a parameter is shifted or rotated, first truncate it to nbytes as given by the immediate value. |
Repeat immed | Repeat the preceding instructions by the number of times given by the immediate value. |
The Nbytes instruction affects the SHL, SHR, ROTL and ROTR instructions. It sets the word size that these instructions operate on. For example Nbytes 4 sets the word size to 4 bytes, and any parameter which is being shifted or rotated will be treated as a 4 byte value by these operations.
Nbytes must be in the range 1 – 400. Any value outside of this range will cause the nBytes value to be set to the default of 400.
Calculations
Here are some examples showing the sort of calculations that can be done with the program.
GCD – Euclidean Algorithm
To find the greatest common divisor (GCD) of two numbers A and B, the Euclidean Algorithm repeatedly applies the identity:
GCD(A, B) = GCD(B, A mod B)
– until A mod B becomes zero.
To use the calculator to find the GCD of a pair of numbers, first enter the numbers (for example):
{A} BBA56355353BBBF4ADCE523423A {B} 13423234242AC5EFDA3145FCDE3141 |
Then enter the instructions:
Mod A B Xchg A B |
Repeatedly press the [Run Instructions] button to execute these two instructions again and again until B has been reduced to zero. At this point, A will hold the value of the GCD (which in this case is 1).
AES – xtime Function
From the Advanced Encryption Standard, the finite field multiplication function xtime():
========================================================================= xtime - finite field multiplication of the byte b by 2: b' = 2 x b = shl(b,1) and mask mask = 1B or ((shr(b,7) * FF) xor FF) shr(b,7) == 0: mask = 1B or ((0 * FF) xor FF) = FF shr(b,7) == 1: mask = 1B or ((1 * FF) xor FF) = 1B ========================================================================= |
Enter these parameters and press [Load Parameters]:
{bytes} {xtime} {b} {mask} |
Then enter the following instructions and press [Run Instructions]:
shl bytes 8 or bytes b mov reg_1 b shl reg_1 1 mov mask b shr mask 7 muli mask ff xori mask ff ori mask 1b and reg_1 mask shl xtime 8 or xtime reg_1 addi b 1 repeat 255 |
These instructions fill an array with the byte values 0 – FF, and a second array with the byte values after finite field multiplication by 2.
TEA – The Tiny Encryption Algorithm
The algorithm for TEA is:
========================================================================= Input vector (64 bits): v0 v1 Input key (128 bits): k0 k1 k2 k3 sum = 0 delta = 9e3779b9 loop x 32 { sum += delta v0 += (shl(v1,4) + k1) xor (v1 + sum) xor (shr(v1,5) + k1) v1 += (shl(v0,4) + k2) xor (v0 + sum) xor (shr(v0,5) + k3) } ========================================================================= Test Vector: The Key: k0 k1 k2 k3 = 11223344 55667788 9900aabb ccddeeff Plain Text: v0 v1 = 12345678 90abcdef Cipher Text: v0' v1' = 8df5d71f 9c3be43f ========================================================================= |
To encrypt using the above test vector, enter the following parameters and press [Load Parameters]:
{v0} 12345678 {v1} 90abcdef {k0} 11223344 {k1} 55667788 {k2} 9900aabb {k3} ccddeeff {sum} {delta} 9e3779b9 |
Then enter the following instructions and press [Run Instructions]:
nbytes 4 add sum delta mov reg_1 v1 shl reg_1 4 add reg_1 k0 mov reg_2 v1 add reg_2 sum mov reg_3 v1 shr reg_3 5 add reg_3 k1 xor reg_1 reg_2 xor reg_1 reg_3 add v0 reg_1 mov reg_1 v0 shl reg_1 4 add reg_1 k2 mov reg_2 v0 add reg_2 sum mov reg_3 v0 shr reg_3 5 add reg_3 k3 xor reg_1 reg_2 xor reg_1 reg_3 add v1 reg_1 repeat 31 trunc v0 32 trunc v1 32 |
Note the first instruction: nbytes 4. This instruction tells the program that when the SHL and SHR operations are applied, the parameters being shifted are to be treated as 4 byte values (as required by the TEA algorithm).
Executing these instructions should give the result: v0 = 8df5d71f and v1 = 9c3be43f. Note that at the end of the calculation v0 and v1 are truncated to 32 bit (4 byte) values.
SHA-256 Message Schedule
The specifications for the SHA-256 message schedule are:
========================================================================= M = the message = 512 bits = 16 x 32 bit words Wt = the message schedule = 64 x 32 bit words t = 0 to t = 15: W[t] = M[t] t = 16 to t = 63: W[t] = sigma_256_1(W[t-2]) + W[t-7] + sigma_256_0(W[t-15]) + W[t-16] Where: sigma_256_0(W) = rotr(W,7) xor rotr(W,18) xor shr(W,3) sigma_256_1(W) = rotr(W,17) xor rotr(W,19) xor shr(W,10) ========================================================================= Test Vector: The ascii input message 'abc' generates the 512 bit message block M: 61626380 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000018 The message schedule for this M is: 61626380 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000018 61626380 000F0000 7DA86405 600003C6 3E9D7B78 0183FC00 12DCBFDB E2E2C38E C8215C1A B73679A2 E5BC3909 32663C5B 9D209D67 EC8726CB 702138A4 D3B7973B 93F5997F 3B68BA73 AFF4FFC1 F10A5C62 0A8B3996 72AF830A 9409E33E 24641522 9F47BF94 F0A64F5A 3E246A79 27333BA3 0C4763F2 840ABF27 7A290D5D 065C43DA FB3E89CB CC7617DB B9E66C34 A9993667 84BADEDD C21462BC 1487472C B20F7A99 EF57B9CD EBE6B238 9FE3095E 78BC8D4B A43FCF15 668B2FF8 EEABA2CC 12B1EDEB ========================================================================= |
In the calculator program, enter these parameters and press [Load Parameters]:
{Wt} 61626380 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000018 {W_temp} {Wt_2} {Wt_7} {Wt_15} {Wt_16} {s_256_0} {s_256_1} |
Then enter the following instructions and press [Run Instructions]:
nbytes 400 mov Wt_2 Wt shr Wt_2 32 mov Wt_7 Wt shr Wt_7 192 mov Wt_15 Wt shr Wt_15 448 mov Wt_16 Wt shr Wt_16 480 nbytes 4 mov reg_1 Wt_2 rotr reg_1 17 mov reg_2 Wt_2 rotr reg_2 19 mov reg_3 Wt_2 shr reg_3 10 mov s_256_1 reg_1 xor s_256_1 reg_2 xor s_256_1 reg_3 mov reg_1 Wt_15 rotr reg_1 7 mov reg_2 Wt_15 rotr reg_2 18 mov reg_3 Wt_15 shr reg_3 3 mov s_256_0 reg_1 xor s_256_0 reg_2 xor s_256_0 reg_3 mov W_temp Wt_7 add W_temp Wt_16 add W_temp s_256_0 add W_temp s_256_1 trunc W_temp 32 nbytes 400 shl Wt 32 or Wt W_temp repeat 47 |
PRNG – Middle Square Method
Use an adaptation of the middle square method to generate a pseudo random 400 byte value:
========================================================================= Middle Square Method Start with a 32 bit hex number: - Square it to get a 64 bit number. - Right shift by 16 bits. - Truncate to 32 bits. - Repeat. ========================================================================= |
Enter these parameters and press [Load Parameters]:
{seed} 12345678 {rand} |
Then enter the following instructions and press [Run Instructions]:
mov reg_1 seed mul reg_1 reg_1 shr reg_1 16 trunc reg_1 32 mov seed reg_1 shl rand 32 or rand seed repeat 99 |
PRNG – Linear Congruential Generator
Use the Linear Congruential Generator to generate a pseudo random 400 byte value:
========================================================================= Linear Congruential Generator X(n+1) = (aX(n) + c) mod m Use these values: m = 100000000 a = 343FD c = 269EC3 ========================================================================= |
Enter these parameters and press [Load Parameters]:
{a} 343FD {c} 269EC3 {Xn} 12345678 {rand} |
Then enter the following instructions and press [Run Instructions]:
mov reg_1 Xn mul reg_1 a add reg_1 c trunc reg_1 32 mov Xn reg_1 shl rand 32 or rand Xn repeat 99 |
The modulus value m (0x100000000) in this case is just 232, which is equivalent to truncating to 32 bits.
PRNG – Galois LFSR
Use the Galois Linear Feedback Shift Register to generate a pseudo random 400 byte value:
========================================================================= Galois LFSR (Linear Feedback Shift Register) Feedback polynomial = x32 + x31 + x29 + x + 1 Update the LFSR: lfsr = shr(lfsr,1) xor (neg(lfsr and 1) and D0000001) ========================================================================= |
Enter these parameters and press [Load Parameters]:
{lfsr} 12345678 {poly} D0000001 {rand} |
Then enter the following instructions and press [Run Instructions]:
mov reg_1 lfsr shr reg_1 1 mov reg_2 lfsr andi reg_2 1 neg reg_2 and reg_2 poly xor reg_1 reg_2 mov lfsr reg_1 shl rand 32 or rand lfsr repeat 99 |
Modular Exponentiation
Enter instructions to do the modular exponentiation calculation. Note that each of A and C should not be greater than 200 bytes.
========================================================================= Modular Exponentiation - Left To Right Binary Method: mod_exp = AB mod C Initialise: mod_exp = 1 For each bit in B starting from the high order bit: - mod_exp = (mod_exp x mod_exp) mod C Then: - if(bit == 0) mod_exp = (1 x mod_exp) mod C - if(bit == 1) mod_exp = (A x mod_exp) mod C ========================================================================= To turn a bit value of 0 or 1 into a multiplier value of 1 or A: M = (neg(bit) and A) + (bit xor 1) ========================================================================= |
Enter these parameters and press [Load Parameters]:
{A} 12345678 90abcdef {B} 90abcdef {C} 12345678 {mod_exp} 1 |
Then enter the following instructions and press [Run Instructions]:
mul mod_exp mod_exp mod mod_exp C rotl B 1 movi reg_1 1 and reg_1 B movi reg_2 1 xor reg_2 reg_1 neg reg_1 and reg_1 A add reg_1 reg_2 mul mod_exp reg_1 mod mod_exp C repeat 3199 |
Note that for the larger input numbers, it can take a couple of minutes for this calculation to execute.
The FASM x86 Code
To grab this code, select it with the mouse and copy it. It can then be pasted directly into the FASM IDE.
; ------------------------------------------------------------------------------------- format PE GUI 4.0 entry start include 'win32a.inc' ; ------------------------------------------------------------------------------------- IDD_THE_DIALOG = 102 IDC_INPUT = 1000 IDC_CALCS = 1001 IDC_OUTPUT = 1002 IDC_BTN_LOAD_DATA = 1003 IDC_BTN_CALC = 1004 IDC_BTN_CLR_DATA = 1005 IDC_BTN_CLR_INSTR = 1006 IDC_BTN_RESET_ALL = 1007 ; ------------------------------------------------------------------------------------- HEX_LEN = 400 MAX_HEX_DIGITS = 2*HEX_LEN N_CALCS = 40 CALCS_BUFFER_SZ = 20*N_CALCS ; ------------------------------------------------------------------------------------- section '.code' code readable executable start: invoke GetModuleHandle,0 invoke DialogBoxParam,eax,IDD_THE_DIALOG,0,DialogProc,0 exit: invoke ExitProcess,0 ; ------------------------------------------------------------------------------------- proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam cmp [msg],WM_INITDIALOG je .wminitdialog cmp [msg],WM_COMMAND je .wmcommand cmp [msg],WM_CLOSE je .wmclose xor eax,eax jmp .quit .wminitdialog: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputText invoke SetDlgItemText,[hwnddlg],IDC_CALCS,szExprText stdcall ClearRegisterValues stdcall PrintRegisterValues invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .wmcommand: cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_LOAD_DATA je .LOAD cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_CALC je .CALC cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_CLR_DATA je .CLR_DATA cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_CLR_INSTR je .CLR_INSTR cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_RESET_ALL je .RESET jmp .done .LOAD: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,12000 stdcall ValidateParamsBuffer cmp al,0xff je .ERR_8 stdcall ProcessDisplayBuffer stdcall PrintSymbolsParams invoke SetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay stdcall ClearRegisterValues stdcall PrintRegisterValues invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .ERR_8: mov [nErrorCode],byte 8 jmp .ERROR .CALC: invoke GetDlgItemText,[hwnddlg],IDC_CALCS,bfDisplay,12000 stdcall ValidateCalcsBuffer cmp al,0xff je .ERROR stdcall LoadCalculations cmp al,0xff je .ERROR stdcall ExecuteCalculations cmp eax,0xffffffff je .CALC_ERROR stdcall PrintSymbolsParams invoke SetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay stdcall PrintRegisterValues invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .CALC_ERROR: stdcall PrintExeError invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay stdcall PrintSymbolsParams invoke SetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay jmp .done .ERROR: stdcall PrintErrorMessage invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .CLR_DATA: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,"" stdcall ClearSymbolTable stdcall ClearRegisterValues stdcall PrintRegisterValues invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .CLR_INSTR: invoke SetDlgItemText,[hwnddlg],IDC_CALCS,"" jmp .done .RESET: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputText invoke SetDlgItemText,[hwnddlg],IDC_CALCS,szExprText mov [nBytes],HEX_LEN stdcall ClearSymbolTable stdcall ClearRegisterValues stdcall PrintRegisterValues invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .wmclose: invoke EndDialog,[hwnddlg],0 .done: mov eax,1 .quit: ret endp ; ------------------------------------------------------------------------------------- proc ClearRegisterValues lea edi,[Reg_1] stdcall ClearParam lea edi,[Reg_2] stdcall ClearParam lea edi,[Reg_3] stdcall ClearParam lea edi,[Reg_4] stdcall ClearParam ret endp ; ------------------------------------------------------------------------------------- macro PRINT_CRLF { mov [edi],byte 13 inc edi mov [edi],byte 10 inc edi } ; ------------------------------------------------------------------------------------- proc PrintRegisterValues ; print reg_1, reg_2, reg_3, reg_4 lea edi,[bfDisplay] ; reg_1 mov [edi],dword "reg_" add edi,4 mov [edi],dword "1= " add edi,4 PRINT_CRLF PRINT_CRLF lea esi,[Reg_1] stdcall PrintHexValue ; reg_2 mov [edi],dword "reg_" add edi,4 mov [edi],dword "2= " add edi,4 PRINT_CRLF PRINT_CRLF lea esi,[Reg_2] stdcall PrintHexValue ; reg_3 mov [edi],dword "reg_" add edi,4 mov [edi],dword "3= " add edi,4 PRINT_CRLF PRINT_CRLF lea esi,[Reg_3] stdcall PrintHexValue ; reg_4 mov [edi],dword "reg_" add edi,4 mov [edi],dword "4= " add edi,4 PRINT_CRLF PRINT_CRLF lea esi,[Reg_4] stdcall PrintHexValue ; null terminate mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc PrintSymbolsParams ; print the parameter names and their values to the bfDisplay buffer lea edi,[bfDisplay] ; Symbol_1 and Param_1 lea esi,[Symbol_1] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_1] stdcall PrintHexValue ; Symbol_2 and Param_2 lea esi,[Symbol_2] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_2] stdcall PrintHexValue ; Symbol_3 and Param_3 lea esi,[Symbol_3] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_3] stdcall PrintHexValue ; Symbol_4 and Param_4 lea esi,[Symbol_4] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_4] stdcall PrintHexValue ; Symbol_5 and Param_5 lea esi,[Symbol_5] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_5] stdcall PrintHexValue ; Symbol_6 and Param_6 lea esi,[Symbol_6] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_6] stdcall PrintHexValue ; Symbol_7 and Param_7 lea esi,[Symbol_7] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_7] stdcall PrintHexValue ; Symbol_8 and Param_8 lea esi,[Symbol_8] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_8] stdcall PrintHexValue ; Symbol_9 and Param_9 lea esi,[Symbol_9] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_9] stdcall PrintHexValue ; Symbol_10 and Param_10 lea esi,[Symbol_10] cmp [esi],byte 0 je .DONE stdcall PrintSymbol lea esi,[Param_10] stdcall PrintHexValue .DONE: ; null terminate mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc PrintHexValue uses ecx eax ; ESI and EDI set outside of this procedure locals count db 0 endl ; find the first non zero dword in the hex value ; starting from the high dword mov cx,HEX_LEN-4 add esi,HEX_LEN-4 .FIND: mov eax,[esi] cmp eax,0 jne .PRINT sub esi,4 sub cx,4 jcxz .PRINT jmp .FIND .PRINT: mov eax,[esi] ; dword to 8 digits stdcall DWordToStr jcxz .DONE sub cx,4 sub esi,4 inc [count] ; add a CRLF to the output string after every 6 dwords cmp [count],byte 6 je .ADD_CRLF jmp .PRINT .ADD_CRLF: mov [count],byte 0 PRINT_CRLF jmp .PRINT .DONE: PRINT_CRLF PRINT_CRLF ret endp ; ------------------------------------------------------------------------------------- proc WordToStr uses edx ; print a word (2 bytes) to a string ; word passed in AX ; EDI set outside of this function mov dx,ax mov al,ah stdcall ByteToDigits mov [edi],ah inc edi mov [edi],al inc edi mov al,dl stdcall ByteToDigits mov [edi],ah inc edi mov [edi],al inc edi ret endp ; ------------------------------------------------------------------------------------- proc DWordToStr ; print a dword (4 bytes) to a string ; word passed in EAX ; EDI set outside of this function locals tmp dw 0 endl mov word [tmp],ax shr eax,16 stdcall WordToStr mov ax,word [tmp] stdcall WordToStr ; add a space mov [edi],byte 32 inc edi ret endp ; ------------------------------------------------------------------------------------- proc PrintSymbol uses ecx ; ESI and EDI set outside of this procedure mov cx,0 .PRINT: mov al,[esi] cmp al,0 je .DONE mov [edi],al inc esi inc edi inc cx cmp cx,8 jge .DONE jmp .PRINT .DONE: ; '=' mov [edi],byte 61 inc edi PRINT_CRLF PRINT_CRLF ret endp ; ------------------------------------------------------------------------------------- proc ProcessDisplayBuffer ; extract the symbols and hex values from bfDisplay stdcall ClearSymbolTable lea esi,[bfDisplay] ; get Symbol_1 and Param_1 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_1] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_1] stdcall InputBufferToParam ; get Symbol_2 and Param_2 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_2] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_2] stdcall InputBufferToParam ; get Symbol_3 and Param_3 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_3] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_3] stdcall InputBufferToParam ; get Symbol_4 and Param_4 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_4] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_4] stdcall InputBufferToParam ; get Symbol_5 and Param_5 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_5] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_5] stdcall InputBufferToParam ; get Symbol_6 and Param_6 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_6] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_6] stdcall InputBufferToParam ; get Symbol_7 and Param_7 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_7] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_7] stdcall InputBufferToParam ; get Symbol_8 and Param_8 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_8] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_8] stdcall InputBufferToParam ; get Symbol_9 and Param_9 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_9] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_9] stdcall InputBufferToParam ; get Symbol_10 and Param_10 stdcall FindSymbol cmp al,0 je .DONE lea edi,[Symbol_10] stdcall GetSymbol stdcall HexStrToInputBuffer lea edi,[Param_10] stdcall InputBufferToParam .DONE: ret endp ; ------------------------------------------------------------------------------------- proc FindSymbol ; look for the opening brace { (ascii = 123) in bfDisplay ; ESI is set outside of this procedure ; set AL to indicate success mov al,0 .FIND: mov dl,[esi] cmp dl,0 je .DONE cmp dl,123 je .FOUND inc esi jmp .FIND .FOUND: mov al,1 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc GetSymbol uses ecx ; store the symbol in the symbol table ; delimiters = { and } = 123 and 125 ; ESI and EDI set outside of this procedure xor ecx,ecx ; ESI already points to the '{' inc esi .STORE: mov al,[esi] cmp al,0 je .DONE ; '}' cmp al,125 je .DONE mov [edi],al inc esi inc edi inc cx ; read up to 8 chars cmp cx,8 jge .CLOSE jmp .STORE .CLOSE: ; if 8 chars were read, find the closing brace mov al,[esi] cmp al,0 je .DONE cmp al,125 je .DONE inc esi jmp .CLOSE .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ClearSymbolTable uses edi ecx ; clear the symbols lea edi,[Symbol_1] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,100 jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc InputBufferToParam uses esi ecx ; convert the string in InputBuffer to a hex value ; EDI is set outside of this procedure ; EDI points to one of: Param_1, Param_2, etc lea esi,[InputBuffer] ; clear the buffer pointed to by EDI mov edx,edi stdcall ClearParam ; restore EDI mov edi,edx ; count the digits in InputBuffer and save to AX stdcall CountDigits ; check if the input buffer is empty cmp ax,0 je .DONE ; calculate the offset in bytes from the start of EDI ; based on the number of digits in the input buffer (given by AX) xor ecx,ecx mov cx,ax shr cx,1 test ax,1 jnz .ODD .EVEN: ; the input buffer contains an even number of hex digits ; offset = (nDigits/2) - 1 dec cx add edi,ecx jmp .GET_DIGITS .ODD: ; the input buffer contains an odd number of hex digits ; offset = nDigits/2 ; convert the first digit add edi,ecx mov al,[esi] stdcall HexDigitToValue mov [edi],al inc esi dec edi dec cx cmp cx,0 jl .DONE .GET_DIGITS: ; convert 2 hex digits to 1 byte mov al,[esi] stdcall HexDigitToValue shl al,4 mov [edi],al inc esi mov al,[esi] stdcall HexDigitToValue or [edi],al inc esi dec cx cmp cx,0 jl .DONE dec edi jmp .GET_DIGITS .DONE: ret endp ; ------------------------------------------------------------------------------------- proc HexStrToInputBuffer uses edi ecx ; copy a string containing a hex number to the InputBuffer ; filter out any non hex digit characters ; ESI is set outside of this procedure lea edi,[InputBuffer] xor ecx,ecx .FILTER: mov al,[esi] ; 0 = null terminator cmp al,0 je .DONE ; 123 = { cmp al,123 je .DONE cmp al,48 jl .NOT_HEX cmp al,57 jle .COPY cmp al,65 jl .NOT_HEX cmp al,70 jle .COPY cmp al,97 jl .NOT_HEX cmp al,102 jg .NOT_HEX .COPY: mov [edi],al inc edi inc ecx cmp ecx,MAX_HEX_DIGITS jge .DONE .NOT_HEX: inc esi jmp .FILTER .DONE: ; null terminate the new string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc ClearParam uses ecx ; clear the input parameter ; EDI is set outside of this procedure xor ecx,ecx .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,HEX_LEN jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc CountDigits uses esi ecx ; count the number of hex digits in the InputBuffer string mov ax,0 xor ecx,ecx lea esi,[InputBuffer] .COUNT: mov dl,[esi] cmp dl,0 je .DONE inc cx inc esi jmp .COUNT .DONE: ; return the digit count in AX mov ax,cx ret endp ; ------------------------------------------------------------------------------------- proc HexDigitToValue ; convert a hex digit to a 4 bit value ; input in AL - output in AL ; is AL in the range: 48 - 57 (0 - 9) ? cmp al,48 jl .NOT_HEX cmp al,57 jg .A_Z sub al,48 jmp .DONE .A_Z: ; is AL in the range: 65 - 70 (A - B) ? cmp al,65 jl .NOT_HEX cmp al,70 jg .a_z sub al,55 jmp .DONE .a_z: ; is AL in the range: 97 - 102 (a - b) ? cmp al,97 jl .NOT_HEX cmp al,102 jg .NOT_HEX sub al,87 jmp .DONE .NOT_HEX: ; set EAX to 0xffff if input is not a valid hex digit mov eax,0xffff .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ByteToDigits ; convert 1 byte to 2 hex digits ; input in AL - output in AX ; copy AL to AH mov ah,al ; AH: get the upper 4 bits of the byte shr ah,4 ; nibble to hex digit add ah,48 cmp ah,57 jle .NEXT add ah,7 .NEXT: ; AL: get the lower 4 bits of the byte and al,0xf ; nibble to hex digit add al,48 cmp al,57 jle .DONE add al,7 .DONE: ; output is in AX ret endp ; ------------------------------------------------------------------------------------- proc LoadCalculations ; load the calculations from the bfDisplay string stdcall ResetCalculations mov [nErrorCode],byte 0 lea esi,[bfDisplay] .NEXT: ; get the next line lea edi,[CurrentLine] mov al,[esi] cmp al,0 je .DONE .GET_LINE: ; read the line into EDI (don't include CRLF) mov al,[esi] cmp al,13 je .CRLF cmp al,10 je .CRLF cmp al,0 je .PROCESS mov [edi],al inc esi inc edi jmp .GET_LINE .CRLF: ; advance ESI to the first non-CRLF (ready for the next line) inc esi mov al,[esi] cmp al,13 je .CRLF cmp al,10 je .CRLF .PROCESS: ; null terminate EDI mov [edi],byte 0 ; process the line in EDI stdcall ProcessLine cmp al,0xff je .DONE inc [nCalculation] cmp [nCalculation],N_CALCS jge .DONE jmp .NEXT .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ProcessLine uses esi edi ; the current calculation (line) is in the string CurrentLine ; convert to instr and param codes, and store in the Calculations buffer ; structure of Calculations buffer: ; 1 calculation = 20 bytes ; byte 1 = operation code ; byte 2 = arg 1 code ; byte 3 = arg 2 code ; byte 4 = arg 3 code ; byte 5-20 = 16 byte immediate value ; total size of Calculations buffer = 800 bytes = 40 calculations ; set via N_CALCS and CALCS_BUFFER_SZ locals instrcode db 0 endl lea esi,[CurrentLine] lea edi,[Calculations] ; adjust EDI to point to the correct location in the Calculations buffer xor edx,edx ; multiply by 20 = shl(DL,4) + shl(DL,2) mov dl,[nCalculation] shl edx,4 xor eax,eax mov al,[nCalculation] shl eax,2 add edx,eax ; nCalculation has been multiplied by 20, now add to EDI add edi,edx ; skip any leading spaces in the line stdcall SkipSpaces ; get the instruction stdcall GetInstrCode cmp al,0xff je .DONE ; store the instr code in the Calculations buffer mov [edi],al inc edi ; also save to instrcode mov [instrcode],al ; instr codes 1 to 31 - 2 arguments ; instr codes 32 to 63 - 1 argument + 1 immediate ; instr codes 64 to 95 - 1 argument ; instr code 96 to 127 - 1 immediate cmp [instrcode],95 jg .96_127 ; get the first argument stdcall SkipSpaces cmp al,0xff je .DONE stdcall GetNextArgument cmp al,0xff je .DONE ; store the arg code in the Calculations buffer mov [edi],al inc edi .1_31: cmp [instrcode],31 jg .32_63 ; get the second argument stdcall SkipSpaces cmp al,0xff je .DONE stdcall GetNextArgument cmp al,0xff je .DONE ; store the arg code in the Calculations buffer mov [edi],al inc edi jmp .EXTRA_CHARS .32_63: cmp [instrcode],63 jg .64_95 ; EDI points to the location in the Calculations buffer ; where the 128 bit immediate value will be stored inc edi inc edi ; get the immediate value stdcall SkipSpaces cmp al,0xff je .DONE stdcall GetImmediate ; is the Immediate argument in decimal or hex cmp [instrcode],38 jl .HEX_IMMED cmp [instrcode],43 jg .HEX_IMMED .DEC_IMMED: stdcall DecImmediateToHex jmp .NEXT .HEX_IMMED: stdcall ImmediateToHex .NEXT: cmp al,0xff je .DONE stdcall ImmediateToCalcsBuffer jmp .EXTRA_CHARS .64_95: cmp [instrcode],95 jg .96_127 jmp .EXTRA_CHARS .96_127: ; EDI points to the location in the Calculations buffer ; where the 128 bit immediate value will be stored inc edi inc edi inc edi ; get the immediate value stdcall SkipSpaces cmp al,0xff je .DONE stdcall GetImmediate ; immediate value is in decimal stdcall DecImmediateToHex cmp al,0xff je .DONE stdcall ImmediateToCalcsBuffer .EXTRA_CHARS: stdcall CheckExtraChars .DONE: ret endp ; ------------------------------------------------------------------------------------- proc CheckExtraChars ; the instr and args have been read ; are there still unread chars on the line ? ; spaces are OK ; ESI is set outside of this procedure mov al,0 .CHECK: mov dl,[esi] cmp dl,0 je .DONE cmp dl,32 je .NEXT mov al,0xff mov [nErrorCode],byte 1 jmp .DONE .NEXT: inc esi jmp .CHECK .DONE: ret endp ; ------------------------------------------------------------------------------------- proc GetImmediate uses edi ; read the immediate hex value in ESI ; ESI is set outside of this procedure ; read up to 32 hex digits lea edi,[bfImmediate] mov cx,0 ; read until either a space or a NULL is found .READ: mov dl,[esi] cmp dl,0 je .DONE cmp dl,32 je .DONE mov [edi],dl inc esi inc edi inc cx ; read up to 32 digits cmp cx,32 jl .READ .DONE: ; null terminate mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc ImmediateToHex uses esi edi ; convert the string in bfImmediate to a 16 byte hex value lea edi,[Immediate] mov cx,0 ; zero the dest value .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,16 jl .CLEAR ; find the end of the bfImmediate string xor ecx,ecx lea esi,[bfImmediate] .EOS: ; seek the null terminator, or count 32 digits mov dl,[esi] cmp dl,0 je .NEXT inc esi inc cx cmp cx,32 jl .EOS .NEXT: cmp cx,0 je .DONE dec esi lea edi,[Immediate] ; CX contains the digit count .CONVERT: ; read the digits from right to left (in pairs) mov al,[esi] stdcall HexDigitToValue cmp eax,0xffff je .ERROR ; put the first digit into EDI mov [edi],al dec cx cmp cx,0 je .DONE dec esi mov al,[esi] stdcall HexDigitToValue cmp eax,0xffff je .ERROR shl al,4 ; OR the next digit into EDI or [edi],al dec cx cmp cx,0 je .DONE dec esi inc edi jmp .CONVERT mov al,0 jmp .DONE .ERROR: mov [nErrorCode],byte 2 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc DecImmediateToHex uses esi edi ; convert the string in bfImmediate to a hex value ; the value in the string is read as a decimal number ; it cannot be greater than 3200 (4 decimal digits) ; count the number of digits in bfImmediate lea esi,[bfImmediate] mov cx,0 xor eax,eax .COUNT: mov dl,[esi] cmp dl,0 je .NEXT ; check for non decimal digits cmp dl,48 jl .ERROR cmp dl,57 jg .ERROR ; copy to EAX shl eax,8 mov al,dl inc esi inc cx ; check the count cmp cx,4 jg .ERROR jmp .COUNT .NEXT: lea edi,[Immediate] mov cx,0 ; zero the dest value .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,16 jl .CLEAR ; decimal digits are in EAX - convert to a hex number stdcall DecToHex cmp eax,3200 jg .ERROR ; save the result to Immediate lea edi,[Immediate] mov [edi],eax ; don't want to accidently return AL = 0xff xor eax,eax jmp .DONE .ERROR: mov al,0xff mov [nErrorCode],byte 6 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc DecToHex ; convert the decimal digit chars in EAX to a hex value ; result returned in EAX ; swap the bytes bswap eax ; find the most significant digit cmp al,0 jne .NEXT shr eax,8 cmp al,0 jne .NEXT shr eax,8 cmp al,0 jne .NEXT shr eax,8 ; if AL is zero here, there were no digits in EAX cmp al,0 je .DONE .NEXT: ; the most significant digit is now in AL xor edx,edx .CONVERT: ; if AL is zero, there are no more digits cmp al,0 je .HEX ; multiply the existing value in EDX by 10 mov ebx,edx shl edx,3 shl ebx,1 add edx,ebx ; put the next digit into EBX xor ebx,ebx mov bl,al sub bl,48 add edx,ebx shr eax,8 jmp .CONVERT .HEX: mov eax,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ImmediateToCalcsBuffer uses esi ; copy the immediate hex value to the Calculations buffer ; EDI is set outside of this procedure lea esi,[Immediate] mov cx,0 .COPY: mov dl,[esi] mov [edi],dl inc esi inc edi inc cx cmp cx,16 jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc GetNextArgument uses edi ; get the next argument from the string in ESI ; ESI set outside of this procedure ; code for argument returned in AL: ; Param_1 = 1 ; Param_2 = 2 ; Param_3 = 3 ; Param_4 = 4 ; Param_5 = 5 ; Param_6 = 6 ; Param_7 = 7 ; Param_8 = 8 ; Param_9 = 9 ; Param_10 = 10 ; Reg_1 = 11 ; Reg_2 = 12 ; Reg_3 = 13 ; Reg_4 = 14 lea edi,[CurrentArg] mov cx,0 .GET_ARG: ; read into EDI until a space or null is found mov al,[esi] cmp al,0 je .GET_CODE cmp al,32 je .GET_CODE mov [edi],al inc cx cmp cx,8 jge .GET_CODE inc esi inc edi jmp .GET_ARG .GET_CODE: ; null terminate EDI mov [edi],byte 0 cmp cx,0 jl .ERROR ; test the string in EDI to get the argument code stdcall Test_Argument jmp .DONE .ERROR: ; error code mov al,0xff mov [nErrorCode],byte 3 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Test_Argument uses esi edi ; test the argument against the symbols ; symbol 1 lea esi,[CurrentArg] lea edi,[Symbol_1] stdcall MatchSymbol mov dl,1 cmp al,0 je .SET_CODE ; symbol 2 lea esi,[CurrentArg] lea edi,[Symbol_2] stdcall MatchSymbol mov dl,2 cmp al,0 je .SET_CODE ; symbol 3 lea esi,[CurrentArg] lea edi,[Symbol_3] stdcall MatchSymbol mov dl,3 cmp al,0 je .SET_CODE ; symbol 4 lea esi,[CurrentArg] lea edi,[Symbol_4] stdcall MatchSymbol mov dl,4 cmp al,0 je .SET_CODE ; symbol 5 lea esi,[CurrentArg] lea edi,[Symbol_5] stdcall MatchSymbol mov dl,5 cmp al,0 je .SET_CODE ; symbol 6 lea esi,[CurrentArg] lea edi,[Symbol_6] stdcall MatchSymbol mov dl,6 cmp al,0 je .SET_CODE ; symbol 7 lea esi,[CurrentArg] lea edi,[Symbol_7] stdcall MatchSymbol mov dl,7 cmp al,0 je .SET_CODE ; symbol 8 lea esi,[CurrentArg] lea edi,[Symbol_8] stdcall MatchSymbol mov dl,8 cmp al,0 je .SET_CODE ; symbol 9 lea esi,[CurrentArg] lea edi,[Symbol_9] stdcall MatchSymbol mov dl,9 cmp al,0 je .SET_CODE ; symbol 10 lea esi,[CurrentArg] lea edi,[Symbol_10] stdcall MatchSymbol mov dl,10 cmp al,0 je .SET_CODE ; symbol 11 lea esi,[CurrentArg] lea edi,[Symbol_11] stdcall MatchSymbol mov dl,11 cmp al,0 je .SET_CODE ; symbol 12 lea esi,[CurrentArg] lea edi,[Symbol_12] stdcall MatchSymbol mov dl,12 cmp al,0 je .SET_CODE ; symbol 13 lea esi,[CurrentArg] lea edi,[Symbol_13] stdcall MatchSymbol mov dl,13 cmp al,0 je .SET_CODE ; symbol 14 lea esi,[CurrentArg] lea edi,[Symbol_14] stdcall MatchSymbol mov dl,14 cmp al,0 je .SET_CODE ; match not found mov dl,0xff mov [nErrorCode],byte 4 .SET_CODE: ; return the code in AL mov al,dl .DONE: ret endp ; ------------------------------------------------------------------------------------- proc MatchSymbol ; test the name of the argument in ESI against the symbol name in EDI ; ESI and EDI are set outside of this procedure ; result returned in AL ; AL = 0 is a match mov al,0xff mov cx,0 .TEST: mov dl,[esi] cmp [edi],dl jne .DONE cmp [edi],byte 0 je .MATCH inc esi inc edi inc cx cmp cx,8 jl .TEST .MATCH: mov al,0 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc GetInstrCode uses edi ; get the instr code from the string in ESI ; ESI set outside of this procedure ; instr code returned in AL lea edi,[CurrentInstr] mov cx,0 .GET_INSTR: ; read the chars into EDI, stop when a space or null is found mov al,[esi] cmp al,0 je .GET_CODE mov [edi],al inc cx cmp al,32 je .GET_CODE cmp cx,8 jge .GET_CODE inc esi inc edi jmp .GET_INSTR .GET_CODE: cmp cx,3 jl .ERROR ; convert letters in EDI to upper case stdcall InstrToUpper ; test the string in EDI to get an instr code stdcall Test_Instr cmp al,0xff jne .DONE .ERROR: mov [nErrorCode],byte 5 mov al,0xff .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Test_Instr uses edi ; find the instr code for the instr in CurrentInstr ; return in AL ; not found code is FF mov al,0xff lea edi,[CurrentInstr] ; ========================================================================= ; 2 ARGS: ; MOV = 1 ADD = 2 SUB = 3 MUL = 4 DIV = 5 ; MOD = 6 AND = 7 OR = 8 XOR = 9 XCHG = 10 ; ========================================================================= ; MOV = 1 cmp [edi],byte 'M' jne .ADD cmp [edi+1],byte 'O' jne .ADD cmp [edi+2],byte 'V' jne .ADD cmp [edi+3],byte 32 jne .ADD mov al,1 jmp .DONE .ADD: ; ADD = 2 cmp [edi],byte 'A' jne .SUB cmp [edi+1],byte 'D' jne .SUB cmp [edi+2],byte 'D' jne .SUB cmp [edi+3],byte 32 jne .SUB mov al,2 jmp .DONE .SUB: ; SUB = 3 cmp [edi],byte 'S' jne .MUL cmp [edi+1],byte 'U' jne .MUL cmp [edi+2],byte 'B' jne .MUL cmp [edi+3],byte 32 jne .MUL mov al,3 jmp .DONE .MUL: ; MUL = 4 cmp [edi],byte 'M' jne .DIV cmp [edi+1],byte 'U' jne .DIV cmp [edi+2],byte 'L' jne .DIV cmp [edi+3],byte 32 jne .DIV mov al,4 jmp .DONE .DIV: ; DIV = 5 cmp [edi],byte 'D' jne .MOD cmp [edi+1],byte 'I' jne .MOD cmp [edi+2],byte 'V' jne .MOD cmp [edi+3],byte 32 jne .MOD mov al,5 jmp .DONE .MOD: ; MOD = 6 cmp [edi],byte 'M' jne .AND cmp [edi+1],byte 'O' jne .AND cmp [edi+2],byte 'D' jne .AND cmp [edi+3],byte 32 jne .AND mov al,6 jmp .DONE .AND: ; AND = 7 cmp [edi],byte 'A' jne .OR cmp [edi+1],byte 'N' jne .OR cmp [edi+2],byte 'D' jne .OR cmp [edi+3],byte 32 jne .OR mov al,7 jmp .DONE .OR: ; OR = 8 cmp [edi],byte 'O' jne .XOR cmp [edi+1],byte 'R' jne .XOR cmp [edi+2],byte 32 jne .XOR mov al,8 jmp .DONE .XOR: ; XOR = 9 cmp [edi],byte 'X' jne .XCHG cmp [edi+1],byte 'O' jne .XCHG cmp [edi+2],byte 'R' jne .XCHG cmp [edi+3],byte 32 jne .XCHG mov al,9 jmp .DONE .XCHG: ; XCHG = 10 cmp [edi],byte 'X' jne .MOVI cmp [edi+1],byte 'C' jne .MOVI cmp [edi+2],byte 'H' jne .MOVI cmp [edi+3],byte 'G' jne .MOVI cmp [edi+4],byte 32 jne .MOVI mov al,10 jmp .DONE ; ========================================================================= ; 1 ARG + 1 IMMED: ; MOVI = 32 ADDI = 33 SUBI = 34 ANDI = 35 ORI = 36 XORI = 37 ; SHL = 38 SHR = 39 ROTL = 40 ROTR = 41 ; TRUNC = 42 BSET = 43 ; MULI = 44 DIVI = 45 MODI = 46 ; ========================================================================= .MOVI: ; MOVI = 32 cmp [edi],byte 'M' jne .ADDI cmp [edi+1],byte 'O' jne .ADDI cmp [edi+2],byte 'V' jne .ADDI cmp [edi+3],byte 'I' jne .ADDI cmp [edi+4],byte 32 jne .ADDI mov al,32 jmp .DONE .ADDI: ; ADDI = 33 cmp [edi],byte 'A' jne .SUBI cmp [edi+1],byte 'D' jne .SUBI cmp [edi+2],byte 'D' jne .SUBI cmp [edi+3],byte 'I' jne .SUBI cmp [edi+4],byte 32 jne .SUBI mov al,33 jmp .DONE .SUBI: ; SUBI = 34 cmp [edi],byte 'S' jne .ANDI cmp [edi+1],byte 'U' jne .ANDI cmp [edi+2],byte 'B' jne .ANDI cmp [edi+3],byte 'I' jne .ANDI cmp [edi+4],byte 32 jne .ANDI mov al,34 jmp .DONE .ANDI: ; ANDI = 35 cmp [edi],byte 'A' jne .ORI cmp [edi+1],byte 'N' jne .ORI cmp [edi+2],byte 'D' jne .ORI cmp [edi+3],byte 'I' jne .ORI cmp [edi+4],byte 32 jne .ORI mov al,35 jmp .DONE .ORI: ; ORI = 36 cmp [edi],byte 'O' jne .XORI cmp [edi+1],byte 'R' jne .XORI cmp [edi+2],byte 'I' jne .XORI cmp [edi+3],byte 32 jne .XORI mov al,36 jmp .DONE .XORI: ; XORI = 37 cmp [edi],byte 'X' jne .SHL cmp [edi+1],byte 'O' jne .SHL cmp [edi+2],byte 'R' jne .SHL cmp [edi+3],byte 'I' jne .SHL cmp [edi+4],byte 32 jne .SHL mov al,37 jmp .DONE .SHL: ; SHL = 38 cmp [edi],byte 'S' jne .SHR cmp [edi+1],byte 'H' jne .SHR cmp [edi+2],byte 'L' jne .SHR cmp [edi+3],byte 32 jne .SHR mov al,38 jmp .DONE .SHR: ; SHR = 39 cmp [edi],byte 'S' jne .ROTL cmp [edi+1],byte 'H' jne .ROTL cmp [edi+2],byte 'R' jne .ROTL cmp [edi+3],byte 32 jne .ROTL mov al,39 jmp .DONE .ROTL: ; ROTL = 40 cmp [edi],byte 'R' jne .ROTR cmp [edi+1],byte 'O' jne .ROTR cmp [edi+2],byte 'T' jne .ROTR cmp [edi+3],byte 'L' jne .ROTR cmp [edi+4],byte 32 jne .ROTR mov al,40 jmp .DONE .ROTR: ; ROTR = 41 cmp [edi],byte 'R' jne .TRUNC cmp [edi+1],byte 'O' jne .TRUNC cmp [edi+2],byte 'T' jne .TRUNC cmp [edi+3],byte 'R' jne .TRUNC cmp [edi+4],byte 32 jne .TRUNC mov al,41 jmp .DONE .TRUNC: ; TRUNC = 42 cmp [edi],byte 'T' jne .BSET cmp [edi+1],byte 'R' jne .BSET cmp [edi+2],byte 'U' jne .BSET cmp [edi+3],byte 'N' jne .BSET cmp [edi+4],byte 'C' jne .BSET cmp [edi+5],byte 32 jne .BSET mov al,42 jmp .DONE .BSET: ; BSET = 43 cmp [edi],byte 'B' jne .MULI cmp [edi+1],byte 'S' jne .MULI cmp [edi+2],byte 'E' jne .MULI cmp [edi+3],byte 'T' jne .MULI cmp [edi+4],byte 32 jne .MULI mov al,43 jmp .DONE .MULI: ; MULI = 44 cmp [edi],byte 'M' jne .DIVI cmp [edi+1],byte 'U' jne .DIVI cmp [edi+2],byte 'L' jne .DIVI cmp [edi+3],byte 'I' jne .DIVI cmp [edi+4],byte 32 jne .DIVI mov al,44 jmp .DONE .DIVI: ; DIVI = 45 cmp [edi],byte 'D' jne .MODI cmp [edi+1],byte 'I' jne .MODI cmp [edi+2],byte 'V' jne .MODI cmp [edi+3],byte 'I' jne .MODI cmp [edi+4],byte 32 jne .MODI mov al,45 jmp .DONE .MODI: ; MODI = 46 cmp [edi],byte 'M' jne .NOT cmp [edi+1],byte 'O' jne .NOT cmp [edi+2],byte 'D' jne .NOT cmp [edi+3],byte 'I' jne .NOT cmp [edi+4],byte 32 jne .NOT mov al,46 jmp .DONE ; ========================================================================= ; 1 ARG: ; NOT = 64 NEG = 65 CLR = 67 ; ========================================================================= .NOT: ; NOT = 64 cmp [edi],byte 'N' jne .NEG cmp [edi+1],byte 'O' jne .NEG cmp [edi+2],byte 'T' jne .NEG cmp [edi+3],byte 32 jne .NEG mov al,64 jmp .DONE .NEG: ; NEG = 65 cmp [edi],byte 'N' jne .CLR cmp [edi+1],byte 'E' jne .CLR cmp [edi+2],byte 'G' jne .CLR cmp [edi+3],byte 32 jne .CLR mov al,65 jmp .DONE .CLR: ; CLR = 66 cmp [edi],byte 'C' jne .NBYTES cmp [edi+1],byte 'L' jne .NBYTES cmp [edi+2],byte 'R' jne .NBYTES cmp [edi+3],byte 32 jne .NBYTES mov al,66 ; ========================================================================= ; 1 IMMED: ; NBYTES = 96 REPEAT = 97 ; ========================================================================= .NBYTES: ; NBYTES = 96 cmp [edi],byte 'N' jne .REPEAT cmp [edi+1],byte 'B' jne .REPEAT cmp [edi+2],byte 'Y' jne .REPEAT cmp [edi+3],byte 'T' jne .REPEAT cmp [edi+4],byte 'E' jne .REPEAT cmp [edi+5],byte 'S' jne .REPEAT cmp [edi+6],byte 32 jne .REPEAT mov al,96 .REPEAT: ; REPEAT = 97 cmp [edi],byte 'R' jne .DONE cmp [edi+1],byte 'E' jne .DONE cmp [edi+2],byte 'P' jne .DONE cmp [edi+3],byte 'E' jne .DONE cmp [edi+4],byte 'A' jne .DONE cmp [edi+5],byte 'T' jne .DONE cmp [edi+6],byte 32 jne .DONE mov al,97 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc InstrToUpper uses edi ; convert all letters in the instr to upper case lea edi,[CurrentInstr] mov cx,0 .CONVERT: mov al,[edi] cmp al,97 jl .NEXT cmp al,122 jg .NEXT sub al,32 mov [edi],al .NEXT: inc edi inc cx cmp cx,8 jl .CONVERT ret endp ; ------------------------------------------------------------------------------------- proc SkipSpaces ; ESI is set outside of this procedure ; advance ESI to the first non space char mov al,0 .NEXT: mov dl,[esi] cmp dl,32 jne .TEST inc esi jmp .NEXT .TEST: cmp dl,byte 0 jne .DONE ; a non space char was not found mov al,0xff mov [nErrorCode],byte 3 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ValidateParamsBuffer uses esi ; make sure that bfDisplay - when used as the input buffer ; for the parameters - only contains valid chars ; 0-9 = ascii 48-57 ; A-Z = ascii 65-90 ; a-z = ascii 97-122 ; space = ascii 32 ; underscore = ascii 95 ; crlf = 13,10 ; {} = 123,125 ; return the result in AL mov al,0 lea esi,[bfDisplay] .SCAN: mov dl,[esi] cmp dl,0 je .DONE cmp dl,123 je .NEXT cmp dl,125 je .NEXT stdcall ValidateChar cmp al,0xff je .DONE .NEXT: inc esi jmp .SCAN .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ValidateCalcsBuffer uses esi ; make sure that bfDisplay - when used as the input buffer ; for the calculations - only contains valid chars ; 0-9 = ascii 48-57 ; A-Z = ascii 65-90 ; a-z = ascii 97-122 ; space = ascii 32 ; underscore = ascii 95 ; crlf = 13,10 ; return the result in AL mov al,0 lea esi,[bfDisplay] .SCAN: mov dl,[esi] cmp dl,0 je .DONE stdcall ValidateChar cmp al,0xff je .DONE inc esi jmp .SCAN .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ValidateChar ; test the char passed in DL ; set AL to 0xff if invalid ; 0-9 = ascii 48-57 ; A-Z = ascii 65-90 ; a-z = ascii 97-122 ; space = ascii 32 ; underscore = ascii 95 cmp dl,32 je .DONE cmp dl,10 je .DONE cmp dl,13 je .DONE cmp dl,95 je .DONE cmp dl,48 jl .INVALID cmp dl,122 jg .INVALID cmp dl,58 jl .DONE cmp dl,65 jl .INVALID cmp dl,91 jl .DONE cmp dl,96 jg .DONE .INVALID: mov al,0xff mov [nErrorCode],byte 7 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ResetCalculations uses edi ecx ; clear the Calculations buffer mov [nCalculation],byte 0 lea edi,[Calculations] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,CALCS_BUFFER_SZ jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc PrintErrorMessage uses esi edi ; print the error message to bfDisplay lea edi,[bfDisplay] mov dl,[nErrorCode] .ERR_1: cmp dl,1 jne .ERR_2 lea esi,[szError_1] jmp .PRINT .ERR_2: cmp dl,2 jne .ERR_3 lea esi,[szError_2] jmp .PRINT .ERR_3: cmp dl,3 jne .ERR_4 lea esi,[szError_3] jmp .PRINT .ERR_4: cmp dl,4 jne .ERR_5 lea esi,[szError_4] jmp .PRINT .ERR_5: cmp dl,5 jne .ERR_6 lea esi,[szError_5] jmp .PRINT .ERR_6: cmp dl,6 jne .ERR_7 lea esi,[szError_6] jmp .PRINT .ERR_7: cmp dl,7 jne .ERR_8 lea esi,[szError_7] jmp .PRINT .ERR_8: cmp dl,8 jne .ERR_0 lea esi,[szError_8] jmp .PRINT .ERR_0: lea esi,[szError_0] .PRINT: mov dl,[esi] cmp dl,0 je .MORE mov [edi],dl inc esi inc edi jmp .PRINT .MORE: mov dl,[nErrorCode] cmp dl,1 jl .DONE cmp dl,6 jg .DONE ; CRLF x 2 PRINT_CRLF PRINT_CRLF lea esi,[CurrentLine] .PRINTL: mov dl,[esi] cmp dl,0 je .DONE mov [edi],dl inc esi inc edi jmp .PRINTL .DONE: mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc PrintExeError uses esi edi ; print the execution error message to the bfDisplay string locals count db 0 endl lea edi,[bfDisplay] ; execution error codes: ; 0 = unknown error ; 1 = unknown instruction or argument code ; 2 = divide by zero error cmp [nExeErrorCode],byte 1 je .EXE_ERR_1 cmp [nExeErrorCode],byte 2 je .EXE_ERR_2 .EXE_ERR_0: lea esi,[szExeError_0] .SZ_0: mov al,[esi] cmp al,0 je .BF_CALCS mov [edi],al inc esi inc edi jmp .SZ_0 .EXE_ERR_1: lea esi,[szExeError_1] .SZ_1: mov al,[esi] cmp al,0 je .BF_CALCS mov [edi],al inc esi inc edi jmp .SZ_1 .EXE_ERR_2: lea esi,[szExeError_2] .SZ_2: mov al,[esi] cmp al,0 je .DONE mov [edi],al inc esi inc edi jmp .SZ_2 .BF_CALCS: ; print the calculations buffer lea esi,[Calculations] PRINT_CRLF PRINT_CRLF mov cx,CALCS_BUFFER_SZ .PRINT: ; byte to digits mov al,[esi] stdcall ByteToDigits ; add the 2 digits to the string mov [edi],ah inc edi mov [edi],al inc edi inc [count] cmp [count],20 je .CRLF jmp .NEXT .CRLF: mov [count],byte 0 PRINT_CRLF .NEXT: inc esi dec cx cmp cx,0 jg .PRINT .DONE: ; NULL terminate mov [edi],byte 0 ; reset the error flag mov [nExeErrorCode],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc ExecuteCalculations uses esi edi ; execute the instructions in the Calculations buffer lea esi,[Calculations] mov cx,0 .INSTR: mov [nExeErrorCode],byte 0 ; get the next instruction xor eax,eax ; put instr code, arg 1 index, arg 2 index into EAX mov eax,[esi] ; instr code is in AL ; instr code = 0, no more instructions cmp al,0 je .DONE cmp al,32 jge .32_63 .1_31: cmp al,1 je .1 cmp al,2 je .2 cmp al,3 je .3 cmp al,4 je .4 cmp al,5 je .5 cmp al,6 je .6 cmp al,7 je .7 cmp al,8 je .8 cmp al,9 je .9 cmp al,10 je .10 jmp .UI_ERROR .1: ; MOV stdcall Mov_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .2: ; ADD stdcall Add_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .3: ; SUB stdcall Sub_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .4: ; MUL stdcall Mul_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .5: ; DIV stdcall Div_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .6: ; MOD stdcall Mod_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .7: ; AND stdcall And_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .8: ; OR stdcall Or_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .9: ; XOR stdcall Xor_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .10: ; XCHG stdcall Xchg_Dest_Src cmp dl,0xff je .UI_ERROR jmp .NEXT .32_63: cmp al,64 jge .64_95 ; get the immediate value lea edi,[Immediate] mov edx,[esi+4] mov [edi],edx mov edx,[esi+8] mov [edi+4],edx mov edx,[esi+12] mov [edi+8],edx mov edx,[esi+16] mov [edi+12],edx cmp al,32 je .32 cmp al,33 je .33 cmp al,34 je .34 cmp al,35 je .35 cmp al,36 je .36 cmp al,37 je .37 cmp al,38 je .38 cmp al,39 je .39 cmp al,40 je .40 cmp al,41 je .41 cmp al,42 je .42 cmp al,43 je .43 cmp al,44 je .44 cmp al,45 je .45 cmp al,46 je .46 jmp .UI_ERROR .32: ; MOVI stdcall Mov_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .33: ; ADDI stdcall Add_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .34: ; SUBI stdcall Sub_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .35: ; ANDI stdcall And_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .36: ; ORI stdcall Or_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .37: ; XORI stdcall Xor_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .38: ; SHL stdcall Shl_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .39: ; SHR stdcall Shr_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .40: ; ROTL stdcall Rotl_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .41: ; ROTR stdcall Rotr_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .42: ; TRUNC stdcall Trunc_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .43: ; BSET stdcall Bset_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .44: ; MULI stdcall Mul_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .45: ; DIVI stdcall Div_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .46: ; MODI stdcall Mod_Dest_Immed cmp dl,0xff je .UI_ERROR jmp .NEXT .64_95: cmp al,96 jge .96_127 cmp al,64 je .64 cmp al,65 je .65 cmp al,66 je .66 jmp .UI_ERROR .64: ; NOT stdcall Not_Dest cmp dl,0xff je .UI_ERROR jmp .NEXT .65: ; NEG stdcall Neg_Dest cmp dl,0xff je .UI_ERROR jmp .NEXT .66: ; CLR stdcall Clr_Dest cmp dl,0xff je .UI_ERROR jmp .NEXT .96_127: ; get the immediate value mov edx,[esi+4] cmp al,96 je .96 cmp al,97 je .97 jmp .UI_ERROR .96: ; NBYTES mov [nBytes],dx jmp .NEXT .97: ; REPEAT ; immediate value is in EDX ; put iteration number into EAX mov eax,[esi+8] cmp eax,edx jae .END_REPEAT inc eax mov [esi+8],eax lea esi,[Calculations] mov cx,0 jmp .INSTR .END_REPEAT: mov [esi+8],dword 0 .NEXT: cmp [nExeErrorCode],byte 0 jne .EXE_ERROR add esi,20 inc cx cmp cx,N_CALCS jl .INSTR jmp .DONE .UI_ERROR: ; error - unknown instruction or argument code mov [nExeErrorCode],byte 1 .EXE_ERROR: mov eax,0xffffffff .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Mov_Dest_Src uses esi edi ecx ; copy the src value to the dest ; MOV dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; copy the src value to dest mov cx,0 .COPY: mov dl,[esi] mov [edi],dl inc esi inc edi inc cx cmp cx,HEX_LEN jl .COPY .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Add_Dest_Src uses esi edi ecx ; ADD the src value to the dest ; ADD dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; add the src value to dest mov cx,0 ; save CF from iteration to iteration ; init CF = 0 clc ; push flags register to the stack pushf .ADD: mov dl,[esi] ; get the flags register from the stack popf adc [edi],dl ; save the flags register to the stack, for the next iteration pushf inc esi inc edi inc cx cmp cx,HEX_LEN jl .ADD ; clean up the stack popf .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Sub_Dest_Src uses esi edi ecx ; SUB the src value from the dest ; SUB dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; sub the src value from dest mov cx,0 ; save CF from iteration to iteration ; init CF = 0 clc ; push flags register to the stack pushf .SUB: mov dl,[esi] ; get the flags register from the stack popf sbb [edi],dl ; save the flags register to the stack, for the next iteration pushf inc esi inc edi inc cx cmp cx,HEX_LEN jl .SUB ; clean up the stack popf .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Mul_Dest_Src uses esi edi ecx ; Multiply the dest value by the src value ; MUL dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; also need an intermediate value - the temp buffer ; clear the intermediate value stdcall ClearTempBuffer xor ecx,ecx xor edx,edx .MULTIPLY: ; get a byte from ESI and multiply the hex value in EDI ; add the result to the temp buffer mov al,[esi] mov ebx,edi ; the byte is passed in AL, the offset in DL, EDI in EBX stdcall ByteMultiply inc esi inc dx inc cx cmp cx,HEX_LEN jl .MULTIPLY ; copy the result from the temp buffer back to EDI stdcall CopyFromTempBuffer .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ByteMultiply uses ecx edi ; multiply EDI by a byte value and add to TempBf ; EDI is passed in EBX ; byte is passed in AL ; offset is passed in DX locals mbyte db 0 endl ; store the byte mov [mbyte],al ; get EDI mov edi,ebx mov cx,0 xor ebx,ebx ; put the offset into BX (passed to Add_Word) mov bx,dx .B_MULT: ; mul byte [EDI] = [EDI] * AL = |AH|AL| = AX mul byte [edi] ; add AX to the temp buffer stdcall Add_Word ; retore AL for the next iteration mov al,[mbyte] inc edi inc bx cmp bx,HEX_LEN jge .DONE inc cx cmp cx,HEX_LEN jl .B_MULT .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Add_Word uses edi ecx ; add the word in AX to the temp buffer ; at the offset given by BX cmp bx,HEX_LEN jge .DONE lea edi,[TempBf] xor ecx,ecx mov cx,bx cmp bx,HEX_LEN-1 jl .ADD_WD add [edi+ecx],al jmp .DONE .ADD_WD: add [edi+ecx],al inc cx adc [edi+ecx],ah jnc .DONE inc cx .ADD_C: cmp cx,HEX_LEN jge .DONE add byte [edi+ecx],1 jnc .DONE inc cx jmp .ADD_C .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Div_Dest_Src uses esi edi ecx ; Divide the dest value by the src ; DIV dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; reset the quotient and divisor stdcall Zero_Quot_Div ; copy the source (ESI) to the divisor stdcall CopyToDivisor ; do the division stdcall Divide ; copy the quotient to the destination stdcall QuotientToDest .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Mod_Dest_Src uses esi edi ecx ; compute dest mod src ; MOD dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; reset the quotient and divisor stdcall Zero_Quot_Div ; copy the source (ESI) to the divisor stdcall CopyToDivisor ; do the division stdcall Divide ; remainder is in EDI (the destination) .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc And_Dest_Src uses esi edi ecx ; AND the src value into the dest ; AND dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; AND the src value into dest mov cx,0 .AND: mov dl,[esi] and [edi],dl inc esi inc edi inc cx cmp cx,HEX_LEN jl .AND .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Or_Dest_Src uses esi edi ecx ; OR the src value into the dest ; OR dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; OR the src value into dest mov cx,0 .OR: mov dl,[esi] or [edi],dl inc esi inc edi inc cx cmp cx,HEX_LEN jl .OR .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Xor_Dest_Src uses esi edi ecx ; XOR the src value into the dest ; XOR dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; XOR the src value into dest mov cx,0 .XOR: mov dl,[esi] xor [edi],dl inc esi inc edi inc cx cmp cx,HEX_LEN jl .XOR .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Xchg_Dest_Src uses esi edi ecx ; exchange the src value and the dest value ; XCHG dest src shr eax,8 ; dest index is in AL and src index is in AH ; get ESI for the src arg mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE mov esi,edi ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; copy ESI to the TempBf stdcall CopyToTempBuffer ; copy EDI to ESI xor ecx,ecx .COPY: mov dl,[edi+ecx] mov [esi+ecx],dl inc cx cmp cx,HEX_LEN jl .COPY ; copy from TempBf to EDI stdcall CopyFromTempBuffer .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Mov_Dest_Immed uses esi edi ecx ; move the immediate value into the destination: ; MOVI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; clear the destination stdcall ClearParam ; get EDI again mov dl,ah stdcall GetDestPtr ; copy in the 16 byte immediate value lea esi,[Immediate] mov edx,[esi] mov [edi],edx mov edx,[esi+4] mov [edi+4],edx mov edx,[esi+8] mov [edi+8],edx mov edx,[esi+12] mov [edi+12],edx .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Add_Dest_Immed uses esi edi ecx ; add the immediate value to the destination: ; ADDI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; add in the 16 byte immediate value lea esi,[Immediate] mov edx,[esi] add [edi],edx mov edx,[esi+4] adc [edi+4],edx mov edx,[esi+8] adc [edi+8],edx mov edx,[esi+12] adc [edi+12],edx jnc .DL_0 add edi,16 mov cx,16 .ADD_C: add [edi],byte 1 jnc .DL_0 inc edi inc cx cmp cx,HEX_LEN jl .ADD_C .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Sub_Dest_Immed uses esi edi ecx ; subtract the immediate value from the destination: ; SUBI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; subtract the 16 byte immediate value lea esi,[Immediate] mov edx,[esi] sub [edi],edx mov edx,[esi+4] sbb [edi+4],edx mov edx,[esi+8] sbb [edi+8],edx mov edx,[esi+12] sbb [edi+12],edx jnc .DL_0 add edi,16 mov cx,16 .SUB_B: sub [edi],byte 1 jnc .DL_0 inc edi inc cx cmp cx,HEX_LEN jl .SUB_B .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc And_Dest_Immed uses esi edi ecx ; AND the immediate value into the destination: ; ANDI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; AND in the 16 byte immediate value lea esi,[Immediate] mov edx,[esi] and [edi],edx mov edx,[esi+4] and [edi+4],edx mov edx,[esi+8] and [edi+8],edx mov edx,[esi+12] and [edi+12],edx ; clear the rest of EDI xor ecx,ecx mov cx,16 .CLEAR: mov [edi+ecx],byte 0 inc cx cmp cx,HEX_LEN jl .CLEAR .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Or_Dest_Immed uses esi edi ecx ; OR the immediate value into the destination: ; ORI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; OR in the 16 byte immediate value lea esi,[Immediate] mov edx,[esi] or [edi],edx mov edx,[esi+4] or [edi+4],edx mov edx,[esi+8] or [edi+8],edx mov edx,[esi+12] or [edi+12],edx .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Xor_Dest_Immed uses esi edi ecx ; XOR the immediate value into the destination: ; XORI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; XOR in the 16 byte immediate value lea esi,[Immediate] mov edx,[esi] xor [edi],edx mov edx,[esi+4] xor [edi+4],edx mov edx,[esi+8] xor [edi+8],edx mov edx,[esi+12] xor [edi+12],edx .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Shl_Dest_Immed uses esi edi ecx ; shift left dest by the number of bits given in immed ; SHL dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; clear the shift buffer stdcall ClearShiftBuffer ; check that nBytes is in range stdcall Check_nBytes ; the number of bytes to apply the SHL to is now given by nBytes ; get the number of bits to shift by lea esi,[Immediate] mov edx,[esi] ; if the shift is greater or equal to nBytes, the result is zero xor eax,eax mov ax,[nBytes] shl ax,3 cmp dx,ax jge .DL_0 ; copy EDI to the shift buffer ; proc takes ESI mov esi,edi stdcall CopyToShiftBuffer ; do the shift stdcall ShiftLeft .DL_0: stdcall CopyFromShiftBuffer ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ShiftLeft uses esi edi ecx ; for the SHL operation ; SHL the shift buffer by shl_bytes + shl_bits ; size of shift in bits passed in EDX ; ShiftBf is used as the shift buffer locals ncopy dw 0 endl lea esi,[ShiftBf] lea edi,[ShiftBf] mov ebx,edx shr ebx,3 ; EBX now contains shl_bytes cmp bx,0 je .BITS ; ncopy = number of bytes to copy up = nBytes - shl_bytes mov ax,[nBytes] mov [ncopy],ax sub [ncopy],bx .BYTES: sub esi,ebx xor ecx,ecx mov cx,[nBytes] dec cx .COPY: ; copy up the bytes mov bl,[esi+ecx] mov [edi+ecx],bl dec cx dec word [ncopy] cmp [ncopy],word 0 jg .COPY cmp cx,0 jl .BITS .ZERO: ; zero the rest of the buffer mov [edi+ecx],byte 0 dec cx cmp cx,0 jge .ZERO .BITS: ; calculate the size of the remaining bit shift (less than 8 bits) ; calc EDX mod 8 and edx,7 cmp edx,0 ; if bits = 0, nothing more to do je .DONE stdcall SHL_Bits .DONE: ret endp ; ------------------------------------------------------------------------------------- proc SHL_Bits uses edi ecx eax ; shift size in bits is passed in DL lea edi,[ShiftBf] mov cl,dl ; CL contains the shift size, so use AX as the counter xor eax,eax mov ax,[nBytes] dec ax add edi,eax .SHL: mov dh,[edi-1] mov bl,[edi] shld bx,dx,cl mov [edi],bl dec edi dec ax cmp ax,0 jg .SHL .FIRST: shl byte [edi],cl ret endp ; ------------------------------------------------------------------------------------- proc Shr_Dest_Immed uses esi edi ecx ; shift right dest by the number of bits given in immed ; SHR dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; clear the shift buffer stdcall ClearShiftBuffer ; check that nBytes is in range stdcall Check_nBytes ; the number of bytes to apply the SHR to is now given by nBytes ; get the number of bits to shift by lea esi,[Immediate] mov edx,[esi] ; if the shift is greater or equal to nBytes, the result is zero xor eax,eax mov ax,[nBytes] shl ax,3 cmp dx,ax jge .DL_0 ; copy EDI to the shift buffer ; proc takes ESI mov esi,edi stdcall CopyToShiftBuffer ; do the shift stdcall ShiftRight .DL_0: stdcall CopyFromShiftBuffer ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ShiftRight uses esi edi ecx ; for the SHR operation ; SHR the shift buffer by shr_bytes + shr_bits ; size of shift in bits passed in EDX ; ShiftBf is used as the shift buffer locals ncopy dw 0 endl lea esi,[ShiftBf] lea edi,[ShiftBf] mov ebx,edx shr ebx,3 ; EBX now contains shr_bytes cmp bx,0 je .BITS ; ncopy = number of bytes to copy down = nBytes - shr_bytes mov ax,[nBytes] mov [ncopy],ax sub [ncopy],bx .BYTES: xor ecx,ecx add esi,ebx .COPY: ; copy down the bytes mov bl,[esi+ecx] mov [edi+ecx],bl inc cx dec word [ncopy] cmp [ncopy],word 0 jg .COPY cmp cx,[nBytes] jge .BITS .ZERO: ; zero the rest of the buffer mov [edi+ecx],byte 0 inc cx cmp cx,[nBytes] jl .ZERO .BITS: ; calculate the size of the remaining bit shift (less than 8 bits) ; calc EDX mod 8 and edx,7 cmp edx,0 ; if bits = 0, nothing more to do je .DONE stdcall SHR_Bits .DONE: ret endp ; ------------------------------------------------------------------------------------- proc SHR_Bits uses edi ecx eax ; shift size in bits is passed in DL lea edi,[ShiftBf] mov cl,dl ; CL contains the shift size, so use AX as the counter xor eax,eax .SHR: mov dl,[edi+1] mov bh,[edi] shrd bx,dx,cl mov [edi],bh inc edi inc ax inc ax cmp ax,[nBytes] jge .LAST dec ax jmp .SHR .LAST: shr byte [edi],cl ret endp ; ------------------------------------------------------------------------------------- proc Rotl_Dest_Immed uses esi edi ecx ; rot left dest by the number of bits given in immed ; ROTL dest immed locals shift dw 0 endl ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; clear the shift buffer stdcall ClearShiftBuffer ; check that nBytes is in range stdcall Check_nBytes ; the number of bytes to apply the ROTL to is now given by nBytes ; get the number of bits to shift by lea esi,[Immediate] mov edx,[esi] ; if the number of bits to shift by is equal to (8 x nBytes) then no rot needed xor eax,eax mov ax,[nBytes] shl eax,3 cmp eax,edx je .NO_ROT ; if the number of bits to shift by is greater than (8 x nBytes) ; calc EDX = EDX mod EAX .MOD: cmp edx,eax jl .B_COPY sub edx,eax cmp edx,eax ; if (EDX mod EAX) = 0 then no rot needed je .NO_ROT jmp .MOD .B_COPY: mov [shift],dx ; copy EDI to the shift buffer ; ROTL(x) = SHL(x) or SHR(nBytes-x) ; do the left shift ; proc takes ESI mov esi,edi stdcall CopyToShiftBuffer stdcall ShiftLeft lea esi,[ShiftBf] ; copy the result to the temp buffer stdcall CopyToTempBuffer ; ROTL(x) = SHL(x) or SHR(nBytes-x) ; do the right shift ; clear the shift buffer stdcall ClearShiftBuffer ; proc takes ESI mov esi,edi stdcall CopyToShiftBuffer ; put (nBytes - shift) into DX xor eax,eax xor edx,edx mov ax,[nBytes] shl ax,3 sub ax,[shift] mov dx,ax stdcall ShiftRight lea esi,[ShiftBf] stdcall OrIntoTempBuffer stdcall CopyFromTempBuffer jmp .DL_0 .NO_ROT: stdcall TruncToNbytes .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Rotr_Dest_Immed uses esi edi ecx ; rot right dest by the number of bits given in immed ; ROTR dest immed locals shift dw 0 endl ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; clear the shift buffer stdcall ClearShiftBuffer ; check that nBytes is in range stdcall Check_nBytes ; the number of bytes to apply the ROTR to is now given by nBytes ; get the number of bits to shift by lea esi,[Immediate] mov edx,[esi] ; if the number of bits to shift by is equal to (8 x nBytes) then no rot needed xor eax,eax mov ax,[nBytes] shl eax,3 cmp eax,edx je .NO_ROT ; if the number of bits to shift by is greater than (8 x nBytes) ; calc EDX = EDX mod EAX .MOD: cmp edx,eax jl .B_COPY sub edx,eax cmp edx,eax ; if (EDX mod EAX) = 0 then no rot needed je .NO_ROT jmp .MOD .B_COPY: mov [shift],dx ; copy EDI to the shift buffer ; ROTL(x) = SHL(x) or SHR(nBytes-x) ; do the right shift ; proc takes ESI mov esi,edi stdcall CopyToShiftBuffer stdcall ShiftRight lea esi,[ShiftBf] ; copy the result to the temp buffer stdcall CopyToTempBuffer ; ROTL(x) = SHL(x) or SHR(nBytes-x) ; do the left shift ; clear the shift buffer stdcall ClearShiftBuffer ; proc takes ESI mov esi,edi stdcall CopyToShiftBuffer ; put (nBytes - shift) into DX xor eax,eax xor edx,edx mov ax,[nBytes] shl ax,3 sub ax,[shift] mov dx,ax stdcall ShiftLeft lea esi,[ShiftBf] stdcall OrIntoTempBuffer stdcall CopyFromTempBuffer jmp .DL_0 .NO_ROT: stdcall TruncToNbytes .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Check_nBytes uses eax ; check that nBytes is in range mov ax,[nBytes] cmp ax,0 jle .ADJUST cmp ax,HEX_LEN jg .ADJUST jmp .DONE .ADJUST: mov [nBytes],HEX_LEN .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Trunc_Dest_Immed uses esi edi ecx ; truncate dest to the number of bits specified in immed ; TRUNC dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; get immed lea esi,[Immediate] ; EAX gives the size of the trunc in bits mov eax,[esi] cmp eax,HEX_LEN * 8 jge .DL_0 ; convert EAX to a byte index shr eax,3 xor ecx,ecx mov cx,HEX_LEN-1 cmp cx,ax je .BITS .TRUNC: mov [edi+ecx],byte 0 dec cx cmp cx,ax jg .TRUNC .BITS: ; deal with the remaining bits (if any) mov edx,[esi] and edx,7 add edi,ecx mov cl,8 sub cl,dl mov al,0xff shr al,cl and [edi],al .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Bset_Dest_Immed uses esi edi ecx ; in dest - turn on the number of bits specified in immed ; starting from bit 0 ; BSET dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; get immed lea esi,[Immediate] mov eax,[esi] ; convert to bytes shr eax,3 cmp eax,0 je .BITS ; set the bytes mov cx,0 .BSET: mov [edi],byte 0xff inc edi inc cx cmp cx,ax je .BITS cmp cx,HEX_LEN jge .DL_0 jmp .BSET .BITS: mov eax,[esi] and eax,7 cmp eax,0 je .DL_0 mov cl,8 sub cl,al mov al,0xff shr al,cl or [edi],al .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Mul_Dest_Immed uses esi edi ecx ; Multiply the dest by the immediate value: ; MULI dest immed ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; get the 16 byte immediate value lea esi,[Immediate] ; also need an intermediate value - the temp buffer ; clear the intermediate value stdcall ClearTempBuffer xor ecx,ecx xor edx,edx .MULTIPLY: ; get a byte from ESI and multiply the hex value in EDI ; add the result to the temp buffer mov al,[esi] mov ebx,edi ; the byte is passed in AL, the offset in DL, EDI in EBX stdcall ByteMultiply inc esi inc dx inc cx cmp cx,16 jl .MULTIPLY ; copy the result from the temp buffer back to EDI stdcall CopyFromTempBuffer .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Div_Dest_Immed uses esi edi ecx ; Divide the dest value by the immediate value ; DIVI dest immed shr eax,8 ; dest index is in AL ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; reset the quotient and divisor stdcall Zero_Quot_Div ; copy the immediate value to the divisor stdcall ImmediateToDivisor ; do the division stdcall Divide ; copy the quotient to the destination stdcall QuotientToDest .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Mod_Dest_Immed uses esi edi ecx ; compute dest mod immed ; MODI dest immed shr eax,8 ; dest index is in AL ; get EDI for the dest arg mov dl,al stdcall GetDestPtr cmp dl,0xff je .DONE ; reset the quotient and divisor stdcall Zero_Quot_Div ; copy the immediate value to the divisor stdcall ImmediateToDivisor ; do the division stdcall Divide ; remainder is in EDI (the destination) .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Not_Dest uses edi ecx ; NOT the destination value ; NOT dest ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; NOT the destination mov cx,0 .NOT: not byte [edi] inc edi inc cx cmp cx,HEX_LEN jl .NOT .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Neg_Dest uses edi ecx ; NEG the destination value = NOT(dest) + 1 ; NEG dest ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; NOT the destination xor ecx,ecx .NOT: not byte [edi+ecx] inc cx cmp cx,HEX_LEN jl .NOT ; add 1 to the dest xor ecx,ecx .ADD_C: add [edi+ecx],byte 1 jnc .DL_0 inc cx cmp cx,HEX_LEN jl .ADD_C .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Clr_Dest uses edi ; CLR the destination value ; CLR dest ; get EDI for the arg (dest) ; arg index is in AH mov dl,ah stdcall GetDestPtr cmp dl,0xff je .DONE ; clear the destination stdcall ClearParam .DL_0: ; return DL = 0 (success) xor edx,edx .DONE: ret endp ; ------------------------------------------------------------------------------------- proc GetDestPtr ; the index of the arg is passed in DL ; set EDI to point to the arg ; error code returned in DL cmp dl,1 je .1 cmp dl,2 je .2 cmp dl,3 je .3 cmp dl,4 je .4 cmp dl,5 je .5 cmp dl,6 je .6 cmp dl,7 je .7 cmp dl,8 je .8 cmp dl,9 je .9 cmp dl,10 je .10 cmp dl,11 je .11 cmp dl,12 je .12 cmp dl,13 je .13 cmp dl,14 je .14 jmp .ERROR .1: lea edi,[Param_1] jmp .DONE .2: lea edi,[Param_2] jmp .DONE .3: lea edi,[Param_3] jmp .DONE .4: lea edi,[Param_4] jmp .DONE .5: lea edi,[Param_5] jmp .DONE .6: lea edi,[Param_6] jmp .DONE .7: lea edi,[Param_7] jmp .DONE .8: lea edi,[Param_8] jmp .DONE .9: lea edi,[Param_9] jmp .DONE .10: lea edi,[Param_10] jmp .DONE .11: lea edi,[Reg_1] jmp .DONE .12: lea edi,[Reg_2] jmp .DONE .13: lea edi,[Reg_3] jmp .DONE .14: lea edi,[Reg_4] jmp .DONE .ERROR: mov dl,0xff .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ClearShiftBuffer uses edi ecx ; clear ShiftBf lea edi,[ShiftBf] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,HEX_LEN jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc CopyToShiftBuffer uses edi ecx ; copy nBytes from ESI to the shift buffer ; called by the SHL, SHR, ROTL, ROTR functions ; ESI is not modified lea edi,[ShiftBf] xor ecx,ecx .COPY: mov al,[esi+ecx] mov [edi+ecx],al inc cx cmp cx,[nBytes] jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc CopyFromShiftBuffer uses esi ecx ; copy to EDI from the shift buffer ; EDI is not modified lea esi,[ShiftBf] xor ecx,ecx .COPY: mov al,[esi+ecx] mov [edi+ecx],al inc cx cmp cx,HEX_LEN jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc ClearTempBuffer uses edi ecx ; clear TempBf lea edi,[TempBf] xor ecx,ecx .CLEAR: mov [edi+ecx],byte 0 inc cx cmp cx,HEX_LEN jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc CopyToTempBuffer uses edi ecx ; copy from ESI to the temp buffer ; ESI is not modified lea edi,[TempBf] xor ecx,ecx .COPY: mov al,[esi+ecx] mov [edi+ecx],al inc cx cmp cx,HEX_LEN jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc CopyFromTempBuffer uses esi ecx ; copy to EDI from the temp buffer ; EDI is not modified lea esi,[TempBf] xor ecx,ecx .COPY: mov al,[esi+ecx] mov [edi+ecx],al inc cx cmp cx,HEX_LEN jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc OrIntoTempBuffer uses edi ecx ; OR ESI into the temp buffer ; ESI is not modified lea edi,[TempBf] xor ecx,ecx .OR: mov al,[esi+ecx] or [edi+ecx],al inc cx cmp cx,HEX_LEN jl .OR ret endp ; ------------------------------------------------------------------------------------- proc TruncToNbytes uses ecx ; truncate EDI to nBytes xor ecx,ecx mov cx,[nBytes] .TRUNC: cmp cx,HEX_LEN jge .DONE mov [edi+ecx],byte 0 inc cx jmp .TRUNC .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Divide uses ecx ; divide EDI by the divisor ; the result is stored in Quotient ; remainder in EDI ; EDI is set outside of this procedure locals offset dw 0 qdigit db 0 endl stdcall IsDivisorZero cmp al,1 ; divide by zero error je .DIV_BY_ZERO ; is the dividend zero (in EDI) stdcall IsZero cmp al,1 je .DONE stdcall Is_GTE_Divisor cmp al,0 ; do nothing je .DONE ; start the division by aligning the digits in the divisor with the dividend ; put EDI into EAX for the proc mov eax,edi stdcall AlignDivisor ; digit counts returned in EAX ; EAX = |ndigits(src)|ndigits(dest)| cmp ax,0 je .DONE mov [offset],ax shr eax,16 cmp ax,0 je .DONE ; offset = ndigits(src) - ndigits(dest) sub [offset],ax cmp [offset],0 jl .DONE .DIVIDE: mov [qdigit],byte 0 .LT_DIV: ; if EDI is less than the divisor, shift the divisor right by 1 digit stdcall Is_GTE_Divisor cmp al,1 je .SUBTRACT stdcall ShiftDigitsRight dec word [offset] cmp [offset],word 0 jl .DONE jmp .LT_DIV .SUBTRACT: stdcall SubtractDivisor inc byte [qdigit] stdcall Is_GTE_Divisor cmp al,1 je .SUBTRACT mov al,[qdigit] shl eax,16 mov ax,[offset] stdcall AddDigitToQuotient jmp .DIVIDE .DIV_BY_ZERO: mov [nExeErrorCode],byte 2 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc IsZero uses ecx ; is the hex value in EDI zero ? ; EDI set outside of this procedure ; result returned in AL xor eax,eax xor ecx,ecx .TEST: cmp [edi+ecx],byte 0 jne .DONE inc cx cmp cx,HEX_LEN jl .TEST ; number is zero, set AL = 1 mov al,1 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Is_GTE_Divisor uses esi ecx ; compare the hex number in EDI to the divisor ; is EDI greater than or equal to ESI ? ; EDI is set outside of this procedure ; result returned in AL lea esi,[Divisor] xor eax,eax xor ecx,ecx mov cx,HEX_LEN-1 .TEST: mov dl,[esi+ecx] cmp [edi+ecx],dl jb .DONE ja .GTE dec cx cmp cx,0 jge .TEST .GTE: mov al,1 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Get_nDigits uses esi ecx ; get the number of hex digits in ESI ; ESI is passed in EAX ; result returned in AX mov esi,eax xor ecx,ecx mov cx,HEX_LEN-1 xor eax,eax ; AX will be in the range 0 - 800 (800 hex digits in a 400 byte number) mov ax,2*HEX_LEN .TEST: mov dl,[esi+ecx] test dl,0xf0 jnz .DONE dec ax test dl,0x0f jnz .DONE dec ax dec cx cmp cx,0 jge .TEST .DONE: ret endp ; ------------------------------------------------------------------------------------- proc Zero_Quot_Div uses edi ecx ; zero the quotient and divisor ; quotient xor ecx,ecx lea edi,[Quotient] .ZQ: mov [edi+ecx],byte 0 inc cx cmp cx,HEX_LEN jl .ZQ ; divisor xor ecx,ecx lea edi,[Divisor] .ZD: mov [edi+ecx],byte 0 inc cx cmp cx,HEX_LEN jl .ZD ret endp ; ------------------------------------------------------------------------------------- proc AddDigitToQuotient uses edi ecx ; add a digit to the Quotient ; offset and digit passed in EAX ; offset is in nibbles (hex digits) lea edi,[Quotient] xor ecx,ecx ; put the offset into cx mov cx,ax shr eax,16 ; the digit is now in AL test cx,1 jnz .UPPER .LOWER: ; SHR(1) to get the offset in bytes shr ecx,1 or [edi+ecx],al jmp .DONE .UPPER: ; SHR(1) to get the offset in bytes shr ecx,1 shl al,4 or [edi+ecx],al .DONE: ret endp ; ------------------------------------------------------------------------------------- proc IsDivisorZero uses edi ; is the divisor zero ? lea edi,[Divisor] stdcall IsZero ret endp ; ------------------------------------------------------------------------------------- proc CopyToDivisor uses edi ecx ; copy the value in ESI to the divisor ; ESI is set outside of this procedure ; ESI is not modified lea edi,[Divisor] xor ecx,ecx .COPY: mov dl,[esi+ecx] mov [edi+ecx],dl inc cx cmp cx,HEX_LEN jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc ImmediateToDivisor uses esi edi ecx ; copy the immediate value to the divisor lea esi,[Immediate] lea edi,[Divisor] xor ecx,ecx .COPY: mov dl,[esi+ecx] mov [edi+ecx],dl inc cx cmp cx,16 jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc QuotientToDest uses esi ecx ; copy the quotient to EDI ; EDI is set outside of this procedure lea esi,[Quotient] xor ecx,ecx .COPY: mov dl,[esi+ecx] mov [edi+ecx],dl inc cx cmp cx,HEX_LEN jl .COPY ret endp ; ------------------------------------------------------------------------------------- proc SubtractDivisor uses esi ecx ; subtract the divisor from EDI ; EDI is set outside of this procedure lea esi,[Divisor] xor ecx,ecx clc ; push flags register to the stack pushf .SUB: mov dl,[esi+ecx] ; get the flags register from the stack popf sbb [edi+ecx],dl ; save the flags register to the stack, for the next iteration pushf inc cx ; cmp affects the CF cmp cx,HEX_LEN jl .SUB ; clean up the stack popf ret endp ; ------------------------------------------------------------------------------------- proc AlignDivisor uses esi edi ecx ; align the divisor with the number in EDI ; EDI is passed in EAX locals nDigits_Src dw 0 nDigits_Dest dw 0 shift dw 0 ncopy dw 0 endl ; get EDI mov edi,eax xor eax,eax lea esi,[Divisor] mov eax,esi stdcall Get_nDigits mov [nDigits_Src],ax cmp ax,0 ; number in ESI is zero, do nothing je .DONE mov eax,edi stdcall Get_nDigits mov [nDigits_Dest],ax cmp ax,0 ; number in EDI is zero, do nothing je .DONE cmp ax,[nDigits_Src] ; the two numbers are already aligned or the divisor is greater than EDI ; do nothing jle .DONE ; compute the shift (the number of hex digits to shift the Divisor up by) sub ax,[nDigits_Src] mov [shift],ax ; copy up the hex digits lea edi,[Divisor] ; divide AX by 2 to get the number of bytes to shift up by shr ax,1 cmp ax,0 je .DIGIT ; put the shift into EDX and sub from ESI xor edx,edx mov dx,ax sub esi,edx xor ecx,ecx mov cx,HEX_LEN-1 ; number of bytes to copy up mov word [ncopy],HEX_LEN sub [ncopy],dx .BYTES: ; copy up the bytes mov dl,[esi+ecx] mov [edi+ecx],dl dec cx dec word [ncopy] cmp [ncopy],word 0 jg .BYTES cmp cx,0 jl .DIGIT .ZERO: ; zero the rest of the bytes mov [edi+ecx],byte 0 dec cx cmp cx,0 jge .ZERO .DIGIT: mov ax,[shift] test ax,1 jz .DONE ; shift up by 1 more digit (4 bits) stdcall ShiftDigitsLeft .DONE: ; return the digit counts in EAX mov ax,[nDigits_Src] shl eax,16 mov ax,[nDigits_Dest] ret endp ; ------------------------------------------------------------------------------------- proc ShiftDigitsLeft uses esi edi ecx ; shift the Divisor one digit to the left lea esi,[Divisor] lea edi,[Divisor] xor ecx,ecx mov cx,HEX_LEN-1 add esi,ecx add edi,ecx .SHL: mov dl,[esi] shl dl,4 mov [edi],dl cmp cx,0 jle .DONE dec esi mov dl,[esi] shr dl,4 or [edi],dl dec edi dec cx jmp .SHL .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ShiftDigitsRight uses esi edi ecx ; shift the Divisor one digit to the right lea esi,[Divisor] lea edi,[Divisor] mov cx,0 .SHR: mov dl,[esi] shr dl,4 mov [edi],dl inc esi cmp cx,HEX_LEN-1 jge .DONE mov dl,[esi] shl dl,4 or [edi],dl inc edi inc cx jmp .SHR .DONE: ret endp ; ------------------------------------------------------------------------------------- section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess' import user,\ DialogBoxParam,'DialogBoxParamA',\ SetDlgItemText,'SetDlgItemTextA',\ GetDlgItemText,'GetDlgItemTextA',\ EndDialog,'EndDialog' ; ------------------------------------------------------------------------------------- section '.data' readable writeable bfDisplay rb 12000 InputBuffer rb MAX_HEX_DIGITS + 8 Param_1 rb HEX_LEN Param_2 rb HEX_LEN Param_3 rb HEX_LEN Param_4 rb HEX_LEN Param_5 rb HEX_LEN Param_6 rb HEX_LEN Param_7 rb HEX_LEN Param_8 rb HEX_LEN Param_9 rb HEX_LEN Param_10 rb HEX_LEN Reg_1 rb HEX_LEN Reg_2 rb HEX_LEN Reg_3 rb HEX_LEN Reg_4 rb HEX_LEN TempBf rb HEX_LEN ShiftBf rb HEX_LEN Quotient rb HEX_LEN Divisor rb HEX_LEN Symbol_1 rb 10 Symbol_2 rb 10 Symbol_3 rb 10 Symbol_4 rb 10 Symbol_5 rb 10 Symbol_6 rb 10 Symbol_7 rb 10 Symbol_8 rb 10 Symbol_9 rb 10 Symbol_10 rb 10 Calculations rb CALCS_BUFFER_SZ CurrentLine rb 100 CurrentInstr rb 10 CurrentArg rb 10 bfImmediate rb 40 Immediate rb 16 nCalculation db 0 nErrorCode db 0 nExeErrorCode db 0 nBytes dw HEX_LEN szInputText db "Define up to ten 400 byte input parameters here:",0 szExprText db "Enter instructions here:",0 szError_0 db "Unknown error in calculations input buffer.",0 szError_1 db "Extra chars found at the end of the line:",0 szError_2 db "Immediate value argument contains non hex digits in the line:",0 szError_3 db "Missing argument in the line:",0 szError_4 db "Could not match argument to symbol in the line:",0 szError_5 db "Unknown instruction in the line:",0 szError_6 db "Immediate value must be LTE to 3200 (decimal) in the line:",0 szError_7 db "Invalid chars in calculations input buffer.",0 szError_8 db "Invalid chars in hex parameters input buffer.",0 szExeError_0 db "Unknown error - execution failed:",0 szExeError_1 db "Unknown instruction or argument code:",0 szExeError_2 db "Instruction failed - divide by zero error.",0 Symbol_11 db "reg_1",0 Symbol_12 db "reg_2",0 Symbol_13 db "reg_3",0 Symbol_14 db "reg_4",0 ; ------------------------------------------------------------------------------------- section '.rc' resource data readable directory RT_DIALOG,dialogs resource dialogs,IDD_THE_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_dialog dialog the_dialog,\ 'FASM - Hex Calculator',20,50,522,396,\ DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\ 0,0,"Lucida Console",11 dialogitem 'EDIT',0,IDC_INPUT,0,0,260,366,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_CALCS,262,0,260,120,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_OUTPUT,262,122,260,244,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'BUTTON',"Load Parameters",IDC_BTN_LOAD_DATA,7,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Clear Parameters",IDC_BTN_CLR_DATA,89,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Run Instructions",IDC_BTN_CALC,171,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Clear Instructions",IDC_BTN_CLR_INSTR,253,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Reset All",IDC_BTN_RESET_ALL,335,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0 enddialog ; ------------------------------------------------------------------------------------- |