Printing register values problem

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
atilali
Posts: 9
Joined: Sun Feb 26, 2017 7:52 am

Printing register values problem

Post by atilali »

Hi i am trying to print register values on the screen. at line 14 if i set ax manually like "mov ax,0xffff;" it works fine. but when i type "mov ax,bx" it fills screen with random characters. im trying to find problem over 2 hours :cry:

Code: Select all

mov ax,0xb800;
mov es,ax;

mov ax,0x07c0;
mov ds,ax;

xor ax,ax;
mov di,ax;

mov ax,disk_drive_number;
mov si,ax;
call printStr;

mov ax,bx;
call printInt;
call jmp;

;prints ax to screen
printInt:
	mov cx,0x0000;
divide:	
	mov dx,0x0000;
	mov bx,0x000A;
	div bx;
	inc cx;
	add dx,48;
	mov dh,0x4e;
	push dx;
	cmp ax,0x0000;
	jne divide;
print:	
	pop dx;
	mov di,[video_memory_index];
	mov [es:di], dx;
	inc di;
	inc di;
	mov [video_memory_index],di;
	dec cx;
	cmp cx,0x0000;
	jne print;
	ret;
	
;prints string in [ds:si] to screen	
printStr:
	cld;inc si after lodsb
loadchr:
	lodsb;
	cmp al,0x00;
	je printStrFinish;
	cmp al,0x0A;
	je newline;
	mov ah,0x4e;
	mov di,[video_memory_index];
	mov [es:di],ax;
	inc di;
	inc di;
	mov [video_memory_index],di;
	jmp loadchr;
newline:
	push dx;
	push bx;
	push ax;
	mov bx,0x00A0;
	add [video_memory_index],bx;
	mov dx,0;
	mov ax,[video_memory_index];
	div bx;
	sub [video_memory_index],dx;
	pop ax;
	pop bx;
	pop dx;
	jmp loadchr;
printStrFinish:
	ret;
	


jmp: 
	nop
	call jmp



video_memory_index dw 0x00A0;
disk_drive_number db 'drivenumber:',0x00;
ax_str db 'ax:',0x0A,0x00;
bx_str db 'bx:',0x00;
cx_str db 'cx:',0x00;
dx_str db 'dx:',0x00;
sp_str db 'sp:',0x00;
bp_str db 'bp:',0x00;
si_str db 'si:',0x00;
di_str db 'di:',0x00;

times 510-($-$$) db 0
db 0x55
db 0xAA
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Printing register values problem

Post by Octacone »

atilali wrote:

Code: Select all

mov ax,0xb800;
Just a hint.
If this indicates your video memory, it is wrong. It should be 0xB8000.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
atilali
Posts: 9
Joined: Sun Feb 26, 2017 7:52 am

Re: Printing register values problem

Post by atilali »

octacone wrote:
atilali wrote:

Code: Select all

mov ax,0xb800;
Just a hint.
If this indicates your video memory, it is wrong. It should be 0xB8000.
Hi, i am in real mode. using ax to load es with 0xb800. when i write to video memory i use [es:di] so i think its not wrong.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Printing register values problem

Post by BrightLight »

octacone wrote:
atilali wrote:

Code: Select all

mov ax,0xb800;
Just a hint.
If this indicates your video memory, it is wrong. It should be 0xB8000.
That code is correct. He's obviously running in real mode, and he loads the ES segment with 0xB800, which would allow him to access 0xB8000 through DI register (or any other register/instruction with ES prefix.)

OP: While I haven't reviewed the code, what exactly happens when your code is run? Try different values and tell us what is printed, for example, try 0x1234, 0x1A2B and 0xFFFF.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Printing register values problem

Post by Octocontrabass »

atilali wrote:

Code: Select all

jmp: 
	nop
	call jmp
What does this do?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Printing register values problem

Post by Octacone »

omarrx024 wrote:
octacone wrote:
atilali wrote:

Code: Select all

mov ax,0xb800;
Just a hint.
If this indicates your video memory, it is wrong. It should be 0xB8000.
That code is correct. He's obviously running in real mode, and he loads the ES segment with 0xB800, which would allow him to access 0xB8000 through DI register (or any other register/instruction with ES prefix.)

OP: While I haven't reviewed the code, what exactly happens when your code is run? Try different values and tell us what is printed, for example, try 0x1234, 0x1A2B and 0xFFFF.
:oops: Oops! Sorry, forgot about segment:offset.
Octocontrabass wrote:
atilali wrote:

Code: Select all

jmp: 
	nop
	call jmp
What does this do?
I tried running his code and it crashed. When I removed that part crashes were gone.
Last edited by Octacone on Sat Mar 11, 2017 7:31 am, edited 1 time in total.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
atilali
Posts: 9
Joined: Sun Feb 26, 2017 7:52 am

Re: Printing register values problem

Post by atilali »

Octocontrabass wrote:
atilali wrote:

Code: Select all

jmp: 
	nop
	call jmp
What does this do?
Does nothing i suppose :D its called after printing on screen to keep cpu busy.
atilali
Posts: 9
Joined: Sun Feb 26, 2017 7:52 am

Re: Printing register values problem

Post by atilali »

omarrx024 wrote:
OP: While I haven't reviewed the code, what exactly happens when your code is run? Try different values and tell us what is printed, for example, try 0x1234, 0x1A2B and 0xFFFF.
outputs for 0x1234, 0xFFF and mov ax,bx : http://imgur.com/a/2i6hj
Last edited by atilali on Sat Mar 11, 2017 7:42 am, edited 1 time in total.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Printing register values problem

Post by Brendan »

Hi,

Some tips:
  • Often debugging is best done by splitting the code in some way and figuring out which piece is causing the problem; then repeating this until you know exactly where the problem is caused. One way to do this is to choose individual pieces (e.g. "printString" and "printInt") and test them in isolation to prove that they are (or aren't) fine. Another way is to put a breakpoint in the middle of a piece of code and check everything is right before the breakpoint (to determine if the problem is before or after the breakpoint).
  • Assembly uses one instruction per line (and doesn't allow multiple instructions on a line), so there's no need for any "end of statement character" like there is in languages like C. Instead, the ';' character is used (by some assemblers) to start a comment. Appending an empty comment at the end of the every line is pointless and ugly (it's like doing "variable = 123; //" in C or C++).
  • The most effective way to write assembly is to describe the logic on the right hand side in comments. This allows you to read the comments in "top to bottom" order (and ignore the instructions) to verify that the logic is correct; and then compare the instruction with the comment to ensure that the instruction correctly implements that piece of logic. This practice makes it extremely easy to find bugs, but also makes it far less likely that you'll create bugs.
  • It's a very bad idea to give a label the same name as an instruction or keyword (e.g. "jmp:").
  • The "call" instruction pushes a return address on the stack. A loop like "jmp: call jmp" would never remove these return addresses from the stack, and will quickly fill the stack with worthless trash until bad things happen (until useful data is overwritten or you get some kind of stack fault or exception). You would need a loop like "jmp: jmp jmp" (which also serves as a nice example of why you shouldn't give a label the same name as an instruction).
  • You can use 32-bit registers in real mode.
  • Assembly isn't restricted by a "standard calling convention", which has advantages (performance) and disadvantages (can be confusing/bad for code maintenance). To avoid most of the disadvantages you need to document how each routine uses registers. Example:

    Code: Select all

    ;Print 16-bit integer in decimal
    ;
    ;Inputs:
    ; ax    Value to display
    ; ds    Normal data segment
    ;
    ;Outputs:
    ; none
    ;
    ;Trashed:
    ; bx, cx, dx, di
    ;_______________________________________________
    
    printInt:
    This also helps to avoid bugs (e.g. forgetting that something gets trashed by a routine).

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
atilali
Posts: 9
Joined: Sun Feb 26, 2017 7:52 am

Re: Printing register values problem

Post by atilali »

Brendan wrote: [*]The "call" instruction pushes a return address on the stack. A loop like "jmp: call jmp" would never remove these return addresses from the stack, and will quickly fill the stack with worthless trash until bad things happen (until useful data is overwritten or you get some kind of stack fault or exception). You would need a loop like "jmp: jmp jmp" (which also serves as a nice example of why you shouldn't give a label the same name as an instruction).
i guess this was the problem. stack has been overriding video memory. i have changed jmp to

Code: Select all

jmp:
       jmp jmp 
and it worked. thanks
Post Reply