### Author Topic: Simple (16-bit, COM) Helper Macros for Newbies  (Read 11439 times)

#### dreamCoder

• Full Member
• Posts: 107
##### Simple (16-bit, COM) Helper Macros for Newbies
« on: January 07, 2014, 08:21:42 AM »
Hi newbies

Attached is a macro file named lib16.inc that you can use and learn from so that you don't have to start from nothing. It provides many useful utilities like printing string, converting numbers, checking the registers and so on. It also provides simple I/O mostly from the keyboard. This macro file should enable you to learn ASM fast and get to program in NASM in a short time. It consists of 25 macros (+ 2 sub macros).

For example, below is a sample program demonstrating the use of various macros, with their possible switches;

Code: [Select]
`org 100h%include 'lib16.inc'section .text    prts "Enter your name: ",-line             ;print message with no line    gets nm                                           ;get string from kboard    prts "Hello, Welcome to NASM ",-line   ;print welcome and name on the sam line    prts nm    mov ax,100h                                   ;Put something in AX    prtr ax                                            ;confirm it VISUALLY    prtr ax,-b                                        ;AX with binary switch. Prints binary equivalence    prtr ax,-o,-n                                    ;prints AX, with octal, but not the name    shl ax,1                                           ;do something to AX.    prtr ax,-b                                        ;confirm what you just did VISUALLY    prts "Enter an integer: ",-line             ;Prompt user for an integer    geti x                                              ;Get integer string from keyboard    add word[x],10                                ;add 10 to it    prts "The value you entered + 10 is: ",-line    prti [x]    prts "x in binary is: ",-line    prtb [x],-t    prts "x in octal is: ",-line    prto [x]    prts "Evaluating integral expression -34*5/2 (signed)"    prti -34*5/2,-s            ;prti with -s switch (signed)    prts "Evaluating integral expression -34*5/2 (unsigned)"    prti -34*5/2    prts "Converting 56h to Base 32... answer is: ",-line    bconv 56h,32                    ;convert 56h to base 32    prts "Register CX in multiple bases..."    prts "In octal: ",-line    prto cx    prts "In decimal: ",-line    prti cx    prts "In binary: ",-line    prtb cxexit           ;must include this every timesection .datanm: times 30 db '0',0x dw 0`
This is the output:

Code: [Select]
`Enter your name: FrankHello, Welcome to NASM FrankAX:0100AX:0100 [00000001 00000000b]0100 [400o]AX:0200 [00000010 00000000b]Enter an integer: 34The value you entered + 10 is: 44x in binary is: 101100x in octal is: 54Evaluating integral expression -34*5/2 (signed)-85Evaluating integral expression -34*5/2 (unsigned)65451Converting 56h to Base 32... answer is: 2MRegister CX in multiple bases...In octal: 377In decimal: 255In binary: 00000000 11111111`
No restrictions on the usage. Use it until you can come up with your own macros. Some of these macros here are readily convertible to 32-bit.
Read the internal descriptions on how to use the macros and the switches.

Thanks to Frank and Bryant for helping me out with the conversions to NASM.

Hope you can benefit from it.

Regards
Soffian

UPDATE: 13th Feb 2014

I attached another macro file named lib16x.inc which is functionally equivalent to lib16.inc but this time I changed some of the macro files names to more descriptive names such as prtstr (prts), prtreg(prtr), prtchar, getstr, getoct etc. Plus, I also added a few macros (such as getnum, convert etc), removed some hidden bug and did a little optimization. Therefore lib16x.inc is not compatible with lib16.inc. Read the description at the end of the macro file (lib16x.inc). I strongly recommend you use lib16x.inc

Regards.

« Last Edit: February 12, 2014, 05:10:45 PM by dreamCoder »

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #1 on: January 07, 2014, 08:26:20 AM »
This is the list of the macros in lib16.inc

Code: [Select]
`;================== LIST OF MACROS ======================;;prtr     - Display 16-bit register;dumpreg  - Dump register;flags    - Display Flags register;geti     - Get and save decimal from kboard;prti     - Display Decimal string;geto     - Get and save Octal string from kboard.;prto     - Display Oct string;getb     - Get and save Bin string from kboard.;prtb     - Display Bin string (formatted);pbin     - Display Bin string (raw format);geth     - Get and save Hex string from kboard.;prth     - Display Hex string;getc     - Get a character from kboard and put in var;getch    - Get character from kboard and put in AL;prtc     - Display a character to screen;gets     - Get string from keyboard;prts     - Print string using 2 sub macros;lines    - Print line(s);line     - Alternative to line - Print single line;exit     - Pause and quit to OS;pause    - Pause the screen;bitf     - Extract bit field from a word, with copy;bconv    - Base converter (16-bit) to any base up to 36;pow      - 16-bit power function;cls      - Clear 80x25 console screen;TOTAL 25 macros + 2 sub macros(prtCStr/prtStr);;============================;Recommended Skeleton for COM;============================;       org 100h;       %include 'lib16.inc';       section .text;               <your codes here>;       exit;       section .data;               <your data here>  ;================= GUIDES ON USAGE ======================;;-Save this file in the same dir as your source file.    ;;-To use lib16 in your source, use %include directive.   ;;-Use a macro by typing the name of the macro and        ;; supply parameters if necessary. Read descriptions.     ;;-Strictly 16-bit. For COM.                              ;;-Macro names,switches and parameters are lower-cased    ;;-Distribute freely for educational purposes only.       ;;-Use at own risk. NOT for critical systems. Unoptimized.;;-Use for small tasks only. Tends to get larger easily   ;;-Use exit at the end of source to exit properly.        ;;PARAMETERS:                                             ;;- [db],[dw]  = mem variable in square bracket           ;;- db,dw      = Variable without bracket                 ;;- imm16/8    = Size of immediate (word/byte)            ;;- r16/r8     = 16-bit register / 8-bit register         ;;- (opt)      = Optional                                 ;;ERROR CODES: '#','!'                                    ;;--------------------------------------------------------;`

« Last Edit: January 07, 2014, 08:28:49 AM by dreamCoder »

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #2 on: January 07, 2014, 08:51:35 AM »
Sorry if it is not perfect though. My knowledge of NASM is very limited at this time. And if you found a bug or have a way of redefining the macros, please modify it and share with us your modifications in this thread. But try to keep it simple and descriptive (simple instructions etc). Optimization may not be the main purpose of this macro file. I developed this solely for newbies seeking speedy entry to NASM/ASM programming particularly those starting up from 16-bit COM environment. That may be old, but the educational values provided by 16-bit programming will never grow old.

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #3 on: January 08, 2014, 05:40:59 PM »
A slight modification to macro geti. Reason: to get rid of the macro's local data and replace it with dx as the signess marker.

Code: [Select]
`;GET DECIMAL STRING FROM KBOARD;And convert to its true value;Five digits only. Max: 65535;Don't supply suffix 'd';Valid digits from '0' to '9' only;%1 = dw;============%macro geti 1;============        pusha        mov word[ds:%1],0         ;initialize variable        xor si,si                 ;si=0 or mov si,0. For the loop        xor di,di                 ;di=0 or mov di,0. For the exponent        xor dx,dx             ;**%%get:          getch                     ;get character from kboard (in AL)        cmp al,'-'                ;if negative sign            je %%sign        cmp al,0dh                ;if <ENTER>            je %%line        cmp al,39h                ;if bigger than '9'            jg %%inv        sub al,30h                ;convert chars to digits        xor ah,ah                 ;clear AH. We want AL only        push ax                   ;now save AX (AL=digit. AH cleared)        inc si                    ;Loop up        cmp si,6                  ;5 digits only (for 16-bit)            je %%inv        jmp %%get                 ;get next char from kboard%%sign:         test si,si                ;if invalid negative form            jnz %%inv             ;equals cmp si,0/je %%inv        mov dx,1               ;**        push dx                 ;**        jmp %%get                 ;get next chars%%inv:          prtc '!'        jmp %%exit%%line:        line                      ;after ENTERed%%first:        pop ax                    ;Restore digit off the stack,save in AX        add word[ds:%1],ax        ;add first digit, to sent var        cmp si,1                  ;if single digit input            je %%done             ;done%%second:                         ;Second digit        inc di                    ;Power up        mov ax,10                 ;10^1 = 10        pop bx                    ;restore digit off the stack,save in BX        mul bx                    ;AX=AX(10)* BX(digit). Answer in AX        add word[ds:%1],ax        ;add up second digit, to sent var        cmp si,2                  ;if two digits input            je %%done             ;done        sub si,2                  ;next loop is to ignore two digits%%next:         inc di                    ;power up (exponent)        push di                   ;save exponent onto stack        mov ax,10                 ;for MUL        mov bx,10                 ;for MUL%%pow:          mul bx                    ;Generate pow, final answer in AX        cmp di,2                  ;off-by-one adjustment. If power is completed            je %%ok        dec di                    ;else, exponent down        jmp %%pow                 ;next pow for the same digit%%ok:           pop di                    ;restore exponent        pop bx                    ;restore the digit        mul bx                    ;AX=AX(from pow) * BX (digit)        add word[ds:%1],ax        ;add up to sent var        dec si                    ;loop down        test si,si                ;loop check if si=0            jz %%done        jmp %%next                ;process next digit%%done:         pop dx                 ;**        cmp dx,1             ;**            je %%signs        jmp %%exit%%signs:        neg word[ds:%1]           ;negate it%%exit:         popa                      ;restore general registers%endmacro `
Just replace the entire macro with this one above. Usage:

Code: [Select]
`geti x        ;get a 16-bit decimal from keyboard. Sign or unsignedprti [x],-s    ;Display sign integer (-s switch)......x dw 0`
« Last Edit: January 09, 2014, 08:09:39 AM by dreamCoder »

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #4 on: February 08, 2014, 02:25:55 AM »
Hi again Frank and Bryant

This time it's a 32-bit macro that's giving me problem. I wrote this macro that converts to integer:

Code: [Select]
`extern _printfextern _scanfextern _putcharextern _getcharextern _exit%macro prtint 1-3        pushad        mov eax,%1        xor esi,esi        mov ecx,10        xor edx,edx        test eax,80000000h           js %%sign        jmp %%start%%sign:        %ifidn %2,-s           prtchar '-'           neg eax        %endif%%start:        div ecx        push edx        xor edx,edx        inc esi        test eax,eax            jz %%prt        jmp %%start%%prt:        dec esi        pop eax        add al,30h        prtchar eax        test esi,esi            jz %%done        jmp %%prt%%done:        %ifnidn %3,-line           line        %endif        popad%endmacro%macro prtchar 1        pushad        push dword %1        call _putchar        popad%endmacro%macro line 0        prtchar 0dh        prtchar 0ah%endmacro`
And can be called from like:
Code: [Select]
`%include 'lib32.mac'global _mainsection .text_main:prtint [x] ;problem buddy?push 0call _exitsection .datax: dd 35h`
The macro works but it prints garbage endlessly. Just like the 16-bit version, this is translated from another ASM language. Is there anything that I missed? Thanks for your replies.

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #5 on: February 08, 2014, 02:51:05 AM »
As a wild guess...
Code: [Select]
`%macro prtchar 1        pushad        push dword %1        call _putchar        add esp, 4 ; <- clean up stack!        popad%endmacro`
Best,
Frank

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #6 on: February 08, 2014, 03:35:25 AM »
Thanks Frank. It works now. Question: Do I have to clean up the stack after calling printf as well?

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #7 on: February 08, 2014, 03:40:46 AM »
ok I get it. Its all about different calling conventions. Oh one more question Frank, do these macros work in Linux as well? Because I have no access to Linux-based computers, just wondering if this could work without int 80h calls. Thanks.
« Last Edit: February 08, 2014, 03:45:27 AM by dreamCoder »

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #8 on: February 08, 2014, 05:21:56 AM »
Well... yeah, it should work in Linux. It won't work on my machine at the moment because I (still!) haven't got the 32-bit C libraries installed. You'd think they would be installed by default, but nooo. I've pretty much decided that this distro's broken and I'm going to have to install something else, but I haven't gotten around to doing it yet.

One difference is that Linux doesn't use underscores on "main", "printf", etc. The way I like to deal with this is to spell 'em without underscores and tell Nasm "--prefix _"  if it's to be assembled as "-f win32". ("--postfix _" for OpenWatcom C - yeah, they use a trailing underscore) If you've got code with underscores in it, and you want to assemble it for Linux, you can do:
Code: [Select]
`%define _main main%define _printf printf; etc...`or similar.

There are some differences (strnicmp vs strncasecmp for example) but 32-bit code that depends on the C libraries should "mostly" work on Windows or Linux. Dr. Carter's tutorial depends on it.

When it comes to 64-bit code, even "just call printf" is completely different. IMO they've screwed things up completely, but I suppose they have reasons... I do not envy the NASMX crew having to deal with this! Fortunately, I like int 80h...

Best,
Frank

#### dreamCoder

• Full Member
• Posts: 107
##### Re: Simple (16-bit, COM) Helper Macros for Newbies
« Reply #9 on: February 12, 2014, 05:16:44 PM »
Thanks Frank. I am still working on the 32-bit file. Btw I also added lib16x.inc to the attachment (refer to first post). Hope this can help somebody out there.