Follow along as we set up the environment and get a Ms-Dos program printing to the console. For a sneak peak of the full game, check out this video:
Part 1 - Get the environment set up
Ok so not the most exciting part of the journey, so let's get it done and move on to the juicy parts.
For compiling, we'll use a Masm version (link below) from 1988!
Source code is copied to a local folder mapped into Dosbox (instructions a bit further down).
Download the asm source file 👇
What else was happening in 1988 you ask?
Time for some coding, here's a starting point to check that everything is set up and working:
;assembly language (EXE) program to print text to console
.model small
; Data segment
DATAS SEGMENT
msg db 'Hello MS-Dos!', 0dh, 0ah, '$' ; $-terminated message
DATAS ENDS
; Stack segment
STACKS SEGMENT STACK
db 100 dup(?)
STACKS ENDS
; Code segment
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
; Our code starts
Main:
; Point DS register to our data segment
mov ax, DATAS
mov ds, ax
; Call Dos services - 09h - Write string to standard output (console)
lea dx, msg ; the address of our message in dx
mov ah, 9 ; "print string" function
int 21h
; call Dos services - 4ch - Terminate
mov ah, 4ch ; "terminate program" function
int 21h
CODES ENDS
END Main
Copy the code above into a local folder, along with the masm files, as 'SayHello.asm'. To make this accessible in DosBox, you can mount (map) a drive in the DosBox console with:
mount d [path-to-local-folder]
I have a folder on my laptop, 'd:\dos', where I put the masm compiler files and SayHello.asm file. After the command 'mount d d:\dos', I can access those files in DosBox on the D: drive. Just edit the command above with your own local folder location and you're all set.
Compile the test program using masm.exe (note I've changed directory to the root of 'd:')
Link the SayHello.obj (output from previous step) using Masm's link.exe
You should now have a file called SayHello.exe, give it a test drive!
Anyone else play Test Drive as a kid?
Ok pretty cool. Not much to look at, but we have a compiled and linked an exe file that is 8086 compatible, runs on MS-Dos in real mode, and goes back in time to 1988! Quicker to build than a flux capacitor.
If you're interested in the content of SayHello.asm, keep reading below - otherwise jump to
Part 2: Drawing pixels in 320x200 with 8 bit color - oooooh [coming soon]
More about SayHello.asm
;assembly language (EXE) program to print text to console .model small ; Example of a comment after code
Comments in assembler can be written either at the start of a line, or after executable code - use the ';' semicolon to start a comment.
Set the memory model to small, we only need 64kb for our data
Read more about the 8086 memory models here ; Data segment
DATAS SEGMENT
msg db 'Hello MS-Dos!', 0dh, 0ah, '$' ; $-terminated message
DATAS ENDS
The data segment is a space in our program for variables, constants and strings. The string above includes a line break pair, to go to the next console line, and is terminated with a $ so Dos knows when to stop. Take it out and see what happens if you're curious.
; Stack segment
STACKS SEGMENT STACK
db 100 dup(?)
STACKS ENDS
The stack segment is a more complex concept, and worthy of further reading. A simple explanation is-> The stack is a temporary storage area, allowing us to save and reload variables. We use it through the push and pop commands in assembler. There is a good explanation here. We have set up a stack segments with a limit of 100 bytes.
; Code segment
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
Where the magic happens! The code segment will contain our assembly code, or instructions.
; Our code starts
Main:
; Point DS register to our data segment
mov ax, DATAS
mov ds, ax
There is a single, main function - I have called it Main but you can rename it to something else if you like.
The DS register is a pointer to our data segment - so we intialise that once at the the start of the program with our data segment definition address.
; Call Dos services - 09h - Write string to standard output (console)
lea dx, msg ; the address of our message in dx
mov ah, 9 ; "print string" function
int 21h
Dos provides functions, much like an API does now days. Like an API, these functions have a contract, or specification. Each function call in the Dos service has a unique Id, this one is 9 - which is the function to print a string to the console. This function requires the message address is loaded into the DX register which we see above.
Once you have the required registers set, calling the interrupt 21h (21 in hex) will request Dos to run the function. Note - msg is defined in our data segment.
; call Dos services - 4ch - Terminate
mov ah, 4ch ; "terminate program" function
int 21h
The next function call we use from Dos, is to terminate our program gracefully. This is function ID 4C (in hex), which we load into the AH 8-bit register, and again we call the 21h Dos interrupt service.
And that's it!
Next up we'll take a look at a popular graphics mode of the time, and a few tips to draw pixels and sprites.
Next episode:
Part 2: Drawing pixels in 320x200 with 8 bit color - oooooh [coming soon]
Comments