4 Replies - 1875 Views - Last Post: 21 June 2011 - 04:02 PM

#1 FranAsm  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 8
  • Joined: 18-June 11

Hardware VGA Text Mode IO in old dos assembly Issue

Posted 18 June 2011 - 04:05 AM

I am new to assembly programming. Finally after reading about at least the first 3 or 4 chapters of about 4 different books I got to a stage where I can put "Hello World" on a dosbox console using MASM 6.11. Imagine my delight!!

The first version of my program used DOS Function 13h.
The second version of my program used BIOS Function 10h

I now want to do the third version using direct hardware output. I have read the parts of the books that explain the screen is divided into 80x25 on a VGA (not bothered about detecting CGA and all that so program uses memory address 0B800h for colour VGA, DOSBox being great and all, and my desire to move to Win Assembler sometime before im 90 years old) monitors. I have read that each character on the hardware screen is 2 bytes (1 for the attribute and one for the character itself, therefore you have 80x25x2=4000 bytes). The odd bytes describe the attribute, and the even bytes the ASCII character.

But my problem is this. No matter how I try, I cant get my program to output a simple black and white (which is just the attribute, I assume I can change this reasonably easily) string (which is just an array of bytes) 5 lines from the top of the screen, and 20 characters in from the left edge (which is just the number of blank characters away from a zero based index with 4000 bytes long). (if my calc is correct that is 5x80=400+20=420x2=840 is the starting position of my string within the array of 4000 bytes)

How do I separate the attribute from the character (I got it to work partially but it only shows every second character, then a bunch of random junk (thats how I figured I need some sort of byte pair for the attribute and text), or how do I set it up such that both are recognised together or how is that done. How do I control he position of the text on the screen once the calcs are made. Where am I going wrong.

I have tried looking around the web for this seemingly simple question but am unable to find a solution. Is there anyone who used to program in DOS and x86 Assembly that can tell me how to do this easy little program by not using BIOS or DOS functions, just with the hardware.

I would really appreicate a simple code snippet if possible. Or a refrence to some site or free e-book. I dont want buying a big book on dos console programming which will end up useless when I move to windows shortly. The only reason I am focused on this is because I want to learn true assembly, not some macro language or some pretensious high level language that claims to be assembly.

I am trying to build a library of routines that will make Assembly easier to learn so people dont have to work though all the 3 to 6 chapters across 10 books of theory esentially explaining again and again the same stuff when really all that is needed is enough to know how to get some output, assign values to variables, get some input, and do some loops and decisions. The theory can come along later, and by the time they get to loops and decisions most people will have done enough assembler to have all the theory anyway. I beleive assembly should be taught no different than any other language starting with a simple hello world program then getting input ect. I want to make this possible.

One other note, I know for a fact the problem is NOT with DOSBox as I have a very old PC running true MS-DOS V6.2 and the program still doesnt work (but gives almost identical output). In fact, DOSBox actually runs some of my old programs even better than True dos. Gem desktop being one example. Just wanted to get that cleared before people try suggesting its a problem with the emulator. It cant be, not with such simple programs. No im afraid the problem is with my little brain not fully understanding what is needed.

Can anyone out there please help!!

------------------------------------------------------------------------

Below is the program I used (MASM 6.1 Under DOSBox on Win 7 64-bit). It uses BIOS Intrrupt 10h Function 13h sub function 0. I want to do the same stuff using direct hardware IO.

.model small
.stack
.data				;part of the program containing data
    ;Constants - None
    ;Variables
    MyMsg   db	  'Hello World'

.code
Main:
GetAddress:
	mov ax,@data		;Gets address of data segment
	mov es,ax		;Loads segment address into es regrister
	mov bp,OFFSET MyMsg	;Load Offset into DX

SetAttributes:
	mov bl,01001111b	;BG/FG Colour attributes
	mov cx,11		;Length of string in data segment

SetRowAndCol:
	mov dh,24		;Set the row to start printing at
	mov dl,68		;Set the column to start printing at

GetFunctionAndSub:
	mov ah,13h		;BIOS Function 10h - String Output
	mov al,0		;BIOS Sub-Function (0-3)

Execute:
	int 10h 		;BIOS Interrupt 10h

EndProg:
	mov ax,4c00h		;Terminate program return 0 to OS
	int 21h 		;DOS Interrupt 21h

end Main
end



----------------------------------------------------------------------------

Below is what I currently have done re hardware IO. Obviously its not complete, but I am trying to get the same effect as the above program.

.model small
.stack
.data
CR		equ		13h
LF		equ		10h
MyMsg	db		'Hello World'
;MyMsg	db		00001111b,'H' ;Was just trying something diff here
;		db		00001111b,'E' ;thinking attribute / character byte pair might work.
;		db		00001111b,'L' ;but it didnt.
;		db		00001111b,'L'
;		db		00001111b,'O'
;		db		00001111b,' '
;		db		00001111b,'W'
;		db		00001111b,'O'
;		db		00001111b,'R'
;		db		00001111b,'L'
;		db		00001111b,'D'

ScreenSeg	dw		0B800h

.code
Main:
SetupSource:
	mov dx,@data
	mov ds,dx ;src seg
	mov dx,offset MyMsg
	mov si,dx ;src ofset (eol 22)

SetupTarget:
	mov es,MyMsg ;tar seg (video buffer)
	mov di,3     ;tar ofset (eol 23)

	mov cx,22*80 ;wrds to be scrolled (80x22) (22 lines)
	std ;direction - down
	rep movsw ;write char and attr
	cld ;direction - up

;Below are some alternates I was trying
;	mov dx,@data  
;	lea si,MyMsg

;	mov ax,@data
;	lea di,MyMsg

;	mov cx,22
;	cld
;	rep movsb

;Some more alternates here
;;	mov	ax, 40h
;;	mov	ds, ax

;;	mov	cx, 22
;;	mov	si, cs
;;	mov	ds, si
;;	lea	si, MyMsg
;;	mov	di, ScreenSeg
;;	mov	es, di
;;	xor	di, di

DoMove:
;	cld
;	rep	movsw

EndPrg:
	mov	ax, 4C00h
	int	21h
end Main




So given all the above where am I going wrong.

Is This A Good Question/Topic? 0
  • +

Replies To: Hardware VGA Text Mode IO in old dos assembly Issue

#2 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10595
  • View blog
  • Posts: 39,236
  • Joined: 27-December 08

Re: Hardware VGA Text Mode IO in old dos assembly Issue

Posted 18 June 2011 - 05:28 AM

Moved to Assembly.
Was This Post Helpful? 0
  • +
  • -

#3 FranAsm  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 8
  • Joined: 18-June 11

Re: Hardware VGA Text Mode IO in old dos assembly Issue

Posted 18 June 2011 - 07:16 AM

View Postmacosxnerd101, on 18 June 2011 - 05:28 AM, said:

Moved to Assembly.


Sincere apologies! My first time reading DIC. Will be more careful in future thanks.
Was This Post Helpful? 0
  • +
  • -

#4 GenHornet18  Icon User is offline

  • Darken the Radar

Reputation: 36
  • View blog
  • Posts: 629
  • Joined: 19-October 09

Re: Hardware VGA Text Mode IO in old dos assembly Issue

Posted 21 June 2011 - 06:55 AM

I thought the VGA memory was at address 0xB8000 (by the looks of it you did as well). Your attribute is a unique solution albeit redundant (if maintaining the same attribute consistently), basically you could easily make this more efficient later.

Issues:
i.) This line here:
mov es,MyMsg



If we look at the syntax of the "movsw" instruction (Move word at address DS:(E)SI to address ES:(E)DI), it can be shown that the segment:offset pair ES:DI should resolve to the destination address (in your case VGA memory).

Try:
mov ES, 0xB800   ;start of VGA memory 
mov DI, 0x06E0   ;22*80 (offset into VGA memory)




ii.) Next your data is only half the story (literally):
MyMsg   db      'Hello World'



If your moving data in WORD size from this data then your forgetting about the attribute byte and replacing it with another character byte. As you've said VGA memory works with one character and attribute byte for every character shown on screen, therefore would it not be prudent to provide the data in this manner?

Try:
MyMsg   db      'H', 0x07        ;displayed in a nice grey
        db      'e', 0x07
        db      'l', 0x07
        db      'l', 0x07
        db      'o', 0x07
        db      ' ', 0x07
        db      'W', 0x07
        db      'o', 0x07
        db      'r', 0x07 
        db      'l', 0x07
        db      'd', 0x07



This is however extremely redundant (assuming a consistent attribute) and could be modified programatically to add the same attribute everytime.


iii.) Be sure to update your repetition counter (CX) to properly account for the amount of memory transferred:
mov cx,22*80 ;wrds to be scrolled (80x22) (22 lines)



Try:
mov CX, 0x16         ;22 bytes (character and attribute)





Best of luck, and welcome to the wonderful world of assembly (Hello World!)


Hornet

EDIT:
Grammatical error

This post has been edited by GenHornet18: 21 June 2011 - 06:59 AM

Was This Post Helpful? 1
  • +
  • -

#5 FranAsm  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 8
  • Joined: 18-June 11

Re: Hardware VGA Text Mode IO in old dos assembly Issue

Posted 21 June 2011 - 04:02 PM

Thank you for your reply.

As you have been kind enough to reply I decided to go back a few days and modify my old code as you suggested to see if it worked. (Sadly not). However...Stay tuned...

I have been working (quite hard) on this little post of mine. Because I beleive that the way I did it before is too messy (both technically (to explain to others) and in terms of redundancy (making it harder to explain and justify) as you said).

I want to have this in a format that is easy to explain. So here is my current workings. I've almost got it. But it only prints the attributes, getting the characters on screen is a problem. (Ocasionally when I modify it slightly, I get every second character with random attributes (I know the technicalities of why, but dont know enough assembler to fix it)). But if I can get it to work like this it would be much less redundant, technical, and by definition easier to explain, justify, and work with later (if I want to make an output procedure that takes parameters for example, too much right now).

Anyway, enough waffle... I will let my code talk so you can see what I am aiming for.

.model small
.stack
.data
	;Constants
	ScreenSeg	equ		0B800h

	;Variables
	MyMsg	db	'Hello World'
	StrLen	equ	$-MyMsg

.code
Main:				

SetSeg:
	mov	ax, ScreenSeg	;set segment register:
	mov	ds, ax

InitializeStringLoop:		;Display all characters: - Not working :(/> Y!
	mov cx, StrLen		;number of characters.
	mov di, 00h		;start from byte 'h'

OutputString:
	mov [di], offset byte ptr MyMsg[di]
	add di, 2		;skip over next attribute code in vga memory.
	loop OutputString

InitializeAttributeLoop:	;Color all characters: - Atributes are working fine.
	mov cx, StrLen		;number of characters.
	mov di, 01h		;start from byte after 'h'
;Assuming I have all chars with same attributes - fine for now - later I would make this
;into a procedure that I will just pass the details into. - But for now I just want a
;basic output tutorial.

OutputAttributes:
	mov [di], 11101100b	;light red(1100) on yellow(1110)
	add di, 2		;skip over next ascii code in vga memory.
	loop OutputAttributes

EndPrg:
	mov	ax, 4C00h
	int	21h
end Main




Of course I want to reduce the instructions used to the bare bones essentials. (for proper tuition purposes, less to cover when teaching others). Hense the reason I did not use MOVSB/W/D ect with REP. I opted instead for an easy to explain manual loop using standard MOV, INC, ADD ect. These are instructions that are basic enough and easy to explain to newcommers. So if possible I would like to keep it as close to this as possible.

I know esentially all that is wrong is the loop for the actual string handler. Its not letting me increment the address the way I want it to. Its killing me cause I know its something really silly now. (Honestly, I am actually quite a good progammer using C++, C#, VB, and Delphi (way back when)). I know you wouldnt think that given I cant even get a good loop right!! :bigsmile:
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1