I'm new to assembly and i am fooling around with DOS and bios interrupts. My problem is that when you accept get a character from an interrupt (Dos or Bios) then is the value given to you in ASCII or is it a string like in C. Also when I accept an integer and try to display it on the screen I get some weird looking things. I would like help with a few things
1. How to accept an integer from a user and display the integer
2. How to accept a character and display the character to the screen
3. How to accept individual characters and use them to build a string of characters that can be later displayed
4. How do I initialize an uninitialized variable in declared in
I am using the nasm assembler and fooling around with real mode flat and real mode segmented models. The book that i'm reading are Jeff Dunteman: Step by Step Programming with DOS and Linux, and Michael Abrash's Blackbook of Graphics programming. I already read the entire content of Dunteman's book but am now trying to apply them and I want to learn how to assembly code in order to be able to tackle Michael's Book.

This is what i got so far, it is supposed to read in a character and display it to the screen.
But when it displays it I see some weird symbols and not the character I typed.




mov dx,welcome
call Write
mov dx,CRLF
call Write
call Input
sub ah,ah
mov dx,ax
call Write

mov ax,04C00h
int 21h

Write:
mov ah,09
int 21h
ret

Input:
mov ah,07
int 10h
ret


welcome db "Please enter an integer: ",0Dh,OAh,"$"
CRLF db 0Dh,0Ah,"$"

num1 resb 1
Posted on 2013-01-28 19:11:51 by Snake4eva
Hi Snake4eva,

My sincere apologies. I wrote up an extensive reply yesterday, but the Forum dropped it in the bit-bucket. I think I exceeded my login time. In any case, I've been too demoralized to repeat it. Wasn't very good, but it was long. Sorry. But you've edited your post, and that gives me something to work with...






mov dx,welcome
call Write
mov dx,CRLF
call Write
; so far, so good
; but what's this supposed to do?
call Input
sub ah,ah
; dx needs to point to a $-terminated string
; this wouldn't point to a $-terminated string
; regardless of your input subroutine
mov dx,ax
call Write

mov ax,04C00h
int 21h

Write:
mov ah,09
int 21h
ret

Input:
mov ah,07 ; say what?
int 10h
ret


welcome db "Please enter an integer: ,0Dh,OAh,"$"
CRLF db 0Dh,0Ah,"$"

num1 resb 1

It's been a while since I ran dos, but the BIOS interrupt int 10h/7 scrolls the screen, last I knew. Did you mean int 21h/7? That would get you a character.

In any case, to get to your question 1.) We really can't "get an integer" from the keyboard - we get ascii codes. The ascii codes for characters representing decimal digits are '0' or 30h or 48 greater than the number they represent. Simple for a single digit - more complicated for multi-digit numbers. Lemme try a slight re-work of your code...





mov dx,welcome
call Write
mov dx,CRLF
call Write
call Input
; here we initialize that uninitialized variable
mov , al
; and $-terminate it
mov byte , '$'
mov dx, num1 ; address of our $-terminated string
call Write

mov ax,04C00h
int 21h

Write:
mov ah,09
int 21h
ret

Input:
mov ah,07
int 21h
ret


welcome db "Please enter an integer: ,0Dh,OAh,"$"
CRLF db 0Dh,0Ah,"$"

num1 resb 2 ; note space for the '$'!

That's untested, but "ought" to be pretty close. At this point, we aren't dealing with a "number" (integer), but merely repeating the character that was entered. To make it a number...

;...
call input
sub al, '0'
mov , al
mov byte , '$'
;...

At this point, we're not ready to print the number... try it with '7', that should produce the number 7, which is the ascii code for the "beep" (called "BEL"). You won't see anything, but should hear it! To convert it back to a character we can print...

;...
add byte , '0'
mov dx, num1
call Write
;...

We haven't accomplished much - just converted a character to the number and then back into a character. It's a start. You can do some "arithmetic" on the number, if you want. Obviously, if the result is greater than 9, it's going to take more than one character to represent it. You should be able to come up with an example of that - it's about the most frequently asked question of all time! We can come up with something if you need help (not right now... sorry).

Best,
Frank

Posted on 2013-01-30 09:47:08 by fbkotler
Thank you fbkotler for answering my question I've moved on quite a bit since I last edited this post. I have learn how to use mov ah,0 int 10h and mov ah,09 int 10h to read and display character which brings me to another question. If only ascii values can be obtained from the keyboard input then how do you construct a multi-digit number from individual ascii digits? This question is very important because I would like to start doing some basic arithmetic with assembly. Also can you explain
sub al, '0'
mov , al
mov byte , '$'

what is the purpose of the sub al,'0' and how does it help to convert the ascii code back into a digit. Please give me the complicated technical explanation even if it involves boolean algebra on the bits. 
Posted on 2013-01-30 19:09:39 by Snake4eva
Well... we can discuss where the bits are, but there's really no mystery to it: the ascii codes for the characters representing the decimal digits 0 thru 9 are 30h thru 39h. You could do it this way, if you wanna bash bits...

; character in al from keyboard (or ???)
; convert from character to number
and al, 0FFh ; strip off the 3 from 3?h
;....
; do something with it, if you want
; but still a single decimal digit, please
; convert number to character
or al, 30h ; add (or "or") the 30h back on
; print it
; ...

But add/sub '0' is clearer to read, IMO.

You asked a similar question about a year ago...
http://www.asmcommunity.net/board/index.php?topic=30843.msg215714#msg215714
Maybe you didn't "get" the way we tried to explain it. We can try again...

First get some text from the victim ("user", I mean) - say "1234". You can get this with int 21h/0Ah, or with "file-read" on stdin, or you can get it byte-by-byte yourself. If you use dos interrupts, there's a good chance your "string" (C defines "string" as zero-terminated, so not a "string" in the C sense) is terminated with a carriage return (ascii 0Dh or 13). In addition, we know how many characters were entered (probably includes the CR).

Zero out a register to use as "result so far". Get a character. Make sure it's valid. Subtract '0' to convert to a number. Multiply the "result so far" by ten. Add the new number to "result so far". Repeat until done.

You could arrange to start at the end of the string - at the "one's place" - and multiply each digit by increasing powers of ten, or figure out what power of ten to multiply by from the length of the string... but I think it's easier to just multiply a "result so far"...

mov si, buffer ; buffer + 2 for int 21h/0Ah
; call this if you like
atoi: ; to reuse a name...
mov di, 10 ; multiply by ten
xor ax, ax ; "result so far"
.top:
xor bx, bx ; or use movzx
mov bl,
inc si
cmp bl, 13 ; CR - must be done
jz .done
cmp bl, 0 ; zero-terminated?
jz .done
cmp bl, '0'
jb .done ; or ".invalid" if you care
cmp bl, '9'
ja .done
sub bl, '0'
; note that now the full bx is our number
mul di ; multiply "result so far" by ten
; jc .overflow?
add ax, bx
; jc .overflow
jmp .top
.done:
; number is in ax
; ret?

That could be improved, no doubt, if it's even right, but should get you an integer to play with.

To print a number, you want to divide it repeatedly by ten and keep the remainders. We get 'em in the "wrong order" to print 'em right away. I like to push 'em on the stack, but if you don't like excessive pushing and popping, you can start at the "end" of the buffer and store 'em right to left. Either pad the left end with spaces (looks nice for numbers printed in a column), or keep track of how far left you got and start your print position there. Or just put 'em in the buffer in the "wrong" order and do a "string reverse" at the end.

Here's an "easy" way...

; prints the value of ax as decimal, hex, and binary ascii
; nasm -f bin -o showax.com showax.asm

org 100h

section .text
    mov ax, 12345

    call ax2dec
    call newline
    call ax2hex
    call newline
    call ax2bin

    mov ah, 4Ch
    int 21h
;--------------

;--------------
ax2dec:
    push ax
    push bx
    push cx
    push dx

    mov bx, 10          ; divide by ten
    xor cx, cx          ; zero our counter
.push_digit:
    xor dx, dx          ; clear dx for the div
    div bx              ; dx:ax/bx -> ax quotient, dx remainder
    push dx            ; save remainder
    inc cx              ; bump digit counter
    or ax, ax          ; is quotient zero?
    jnz .push_digit    ; no, do more

    mov ah, 2          ; print character subfunction
.pop_digit:
    pop dx              ; get remainder back
    add dl, '0'        ; convert to ascii character
    int 21h            ; print it
    loop .pop_digit    ; cx times

    pop dx
    pop cx
    pop bx
    pop ax
    ret
;-------------------

;-------------------
ax2hex:
    push cx
    push dx

    mov cx, 4          ; four digits to show

.top
    rol ax, 4          ; rotate one digit into position
    mov dl, al          ; make a copy to process
    and dl, 0Fh        ; mask off a single (hex) digit
    cmp dl, 9          ; is it in the 'A' to 'F' range?
    jbe .dec_dig        ; no, skip it
    add dl, 7          ; adjust
.dec_dig:
    add dl, 30h        ; convert to character

    push ax
    mov ah, 2          ; print the character
    int 21h
    pop ax

    loop .top

    pop dx
    pop cx
    ret
;--------------------------

;--------------------------
ax2bin:
    push cx
    push dx
    mov cx, 16
.top
    rcl ax, 1    ; rotate and set/clear carry
    mov dl, '0'
    adc dl, 0    ; make it '1' if carry set

    push ax
    mov ah, 2    ; print it
    int 21h
    pop ax

    loop .top

    pop dx
    pop cx
    ret
;----------------------------

;----------------------------
newline:
    push ax
    push dx

    mov ah, 2      ; print character in dl
    mov dl, 13      ; carriage return
    int 21h
    mov dl, 10      ; and linefeed
    int 21h

    pop dx
    pop ax
    ret
;----------------------------

That's pretty simple-minded (but at least it's tested - used to work!), but it'll print a number. You can save the characters to a string and print 'em all at once. Don't forget to terminate your string with a '$' or a zero... or keep track of the length - whichever your print routine expects. Don't forget to leave room in your buffer for the terminator... and maybe a minus sign, if you get to that...

Best,
Frank


Posted on 2013-01-30 22:46:56 by fbkotler
I am learning assembly in a systematic way in order to do some VGA programming. I am familiar with high level languages C and C++ but really enjoy more low level stuff. This is the format that I plan to progress my assembly language practice
1. Input/Output
2. Storage/Variable(declaration, type creation, initialization etc)
3. File access
4. Communicating with Hardware (printer, floppy disk, hard drive)
5. High level concepts (Arrays, heap, link list, class etc)
6. Advanced Mathematics and algorithm implementation

I am currently learning I/O and Storage through Dos and Bios services int 21h and int 10h and with your posts i am becoming more comfortable with variables but I think i may need considerable help with 3,4 and 6. So please look forward for a lot more questions from me as I progress through the list.

Also for the I got the sub al, '0' bitwise operation to convert to number
Eg:
al = 31h
sub al,'0'
Gives
00110001
-00110000
=00000001

But I don't get the
and al,0ffh
Suppose al = 30h
When I do the bitwise and i don't see how the three is stripped off
11111111
00110000
= 00110000 which is the original Ascii character 30h am I doing something wrong?
Posted on 2013-01-31 09:52:26 by Snake4eva
Nope, you're not doing anything wrong, I am:

and al, 0FFh ; strip off the 3 from 3?h

meant:

and al, 0Fh ; strip off the 3 from 3?h

Sorry 'bout that!

VGA programming, eh? Well I guess it's good if someone preserves the ancient wisdom. :)

Best,
Frank

Posted on 2013-01-31 14:34:52 by fbkotler
That's my job :)
Posted on 2013-01-31 16:45:31 by Scali
What do you mean ancient wisdom? I know that there are newer graphics standards after VGA but isn't it the basis for all the new analogue video standards. I know DVI uses a different standard.
Posted on 2013-01-31 16:49:07 by Snake4eva

What do you mean ancient wisdom? I know that there are newer graphics standards after VGA but isn't it the basis for all the new analogue video standards. I know DVI uses a different standard.


DVI is merely a connection between videocard and display device. VGA is a display adapter, whose 15-pin analog connector has become known as 'VGA' as well, but other than that, DVI and VGA have little to do with eachother.

You mentioned VGA programming, which would mean programming the display adapter. Which is indeed ancient technology, and completely irrelevant in today's world.
VGA is not exactly the 'basis' for newer standards. It is an ancient standard, with a weird ALU on board, and a planar oriented display memory, with a palettized RAMDAC.
These days we either use truecolour linear framebuffers or we use hardware-accelerated drawing, based on triangles.

That's why VGA is 'ancient wisdom'. It's cool to play around with VGA and all... but it's completely meaningless in today's world.
Posted on 2013-02-07 09:47:35 by Scali
I am an electronics student and for my final year project I would like to build a simple GPU that addresses some of the problems involved with 3D animations. My approach is to avoid the transistor and conquer method used in most modern GPU's. I was initially considering building it to work with the VGA standard but in light of your revelation it seems that I need to reconsider my design model. Can you please explain the operation of DVI and how it differs from analogue VGA standards. What's confusing me is that colours are continuous analogue signals so I wonder how DVI display monitors work in the digital domain if they are representing analogue information.
Posted on 2013-02-11 10:00:09 by Snake4eva
In the world of computers, nothing is analog.
In fact, before VGA, monitors used a TTL connection, with separate R, G, B signals, and intensity. With CGA, you had a global intensity, so you basically just had R, G, B and I, totalling 2^4 possibilities: 16 colours.
EGA introduced separate intensities for R, G and B, so you had 2^6 possibilities: 64 colours.

Since VGA had a total palette of 2^18 colours (6 bits for R, G and B each), it would have required a lot of complex wiring if they would stick with TTL. So instead, they moved to analog RGB signals, where the RAMDAC would just translate each 6-bit value to analog voltages. This way the intensity was implicit in the R, G, B signals, and only 3 wires were required.
These analog signals could be used to drive the CRT circuitry.

But once LCD screens arrived, the signals had to be processed in digital form anyway, so analog VGA signals were run through an ADC again inside the monitor, to get an internal framebuffer, which would then feed the pixels continuously (most LCD monitors only have 18 to 20-bit colour precision anyway, and they often use a form of dithering to simulate the full 24-bit that most videocards output... some can even do 30-bit (10:10:10)).

Since digital technology had progressed a lot anyway, it became feasible to just have a high-speed digital link between the videocard and the screen directly. So the RAMDAC on the videocard could be skipped, as well as the ADC inside the monitor. The framebuffer is just transferred digitally.

None of this really matters if you want to build a GPU though. You can just use standard components for VGA and/or DVI signals. The important part of a GPU is how you fill that framebuffer.
Posted on 2013-02-12 06:09:45 by Scali