Assembly Lib
A 16-bits x86 DOS Assembly library that provides many useful functions for developing programs. It has both VGA grapics functions as well as general purpose utilities. The main purpose of this library was to be able to implement simple DOS games (in Assembly) using VGA (320x200, 256 colors) display.
A 16-bits x86 DOS Assembly library that provides many useful functions for developing programs. It has both VGA grapics functions as well as general purpose utilities. The main purpose of this library was to be able to implement simple DOS games (in Assembly) using VGA (320x200, 256 colors) display. The project is written primarily in Assembly, first published in 2018. Key topics include: 16-bit, asm, assembler, assembly, game.
Assembly Library
For more projects, click here
A 16-bits x86 DOS Assembly library that provides many useful functions for developing programs. It has both VGA grapics functions as well as general purpose utilities. The main purpose of this library was to be able to implement simple DOS games (in Assembly) using VGA (320x200, 256 colors) display.
Note The library was developed and tested using TASM 4.1 and DosBox
Graphics
The library provides the following graphics capabilities:
- General purpose graphics utilities
- Manipulate color palettes
- Draw lines
- Draw rectangles (outline and filled)
- Draw closed polygons (outline only)
- Draw circles (outline and filled)
- Draw Bitmaps
- Images & screen manipulations
- Draw sprites and animation
- Support for Double buffering
Utilities
The library contains an utility package with many useful macros and procedures such as:
- File management
- Keyboard management, including ISR support
- Mouse input
- Several Math and randomizer functions
- Memory management (allocation and deallocation on the heap)
- String operations
- Printing to the screen
- Support for playing sound
- Time functions for delays
Using the library
To use the libraries, include the files in your code as follows:
shCODESEG include "UtilLib.inc" include "GrLib.inc"
Note that UtilLib.inc MUST come before GrLib.inc
Here is a sample program that draws a line and waits for a key press, using double buffering:
sh.486 IDEAL MODEL small STACK 256 DATASEG CODESEG include "UtilLib.inc" include "GrLib.inc" start: mov ax, @data mov ds,ax ; Init library with double buffering flag on mov ax, TRUE ut_init_lib ax ; Allocate double buffering memory space call AllocateDblBuffer ; set display to VGA mode gr_set_video_mode_vga ; Set initial pen color gr_set_color GR_COLOR_GREEN ; your code here - we will draw a line... grm_DrawLine 10, 10, 200, 200 exit: call WaitForKeypress call ReleaseDblBuffer gr_set_video_mode_txt return 0 END start
Build the program using
shtasm /zi main.asm tlink /v main
PROCs and MACROs
The library provides many Procedures and Macros that you can use directly in your code. To make life easier (and have the code look more like a high level language), a wrapper MACRO was provided to many of the PROCs. Both options yield the same outcome.
For example, you can draw a line using the PROC
shpush x1 push y1 push x2 push y2 call GR_DrawLine
or using a wrapper MACRO
shgrm_DrawLine x1, y1, x2, y2
Make sure you pass the arguments in the right order. All procedures preserve register values, unless stated otherwise.
Macros (not including wrapper macros), on the other hand, may alter register values. Check out their documentation for details.
Initializing the library
At the beginning of your code, you need to initialize the library by calling:
shCODESEG ; Init library mov ax, FALSE ut_init_lib ax
The flag shoule be set to TRUE if you intend to dynamically allocate memory in your program. See memory management
Note that TRUE and FALSE are defined by the library as 1 and 0.
Testing the library and code samples
The Tests folder includes a testing file that demonstrates the use of various parts of the library. the test program itself
can be found at the root and is called main.asm
TicTac Game
A simple TicTac game that uses many of the library's features, was added to the library. You can compile and run the game using:
shtasm /zi tictac.asm tlink /v tictac
The game itself can be found under Tests/tic folder and the main file is tictac.asm
---------------------------------------------------------------
Graphics Library
Drawing a pixel
The most basic macros handle drawing a single pixel on the screen, using direct memory access (not interrupt).
shgr_set_pixel x, y, color - draws a pixel in the given (x,y) coordinates with the given color gr_set_pixel_xy x,y - draws a pixel in the given (x,y) coordinates with the set color
Note that x, y and color cannot use the following registers: ax, bx, di, dx
This macro takes into account double buffering and will draw to the buffer (if set) instead of the video display. See
Double Buffering for details.
It is highly recommended to use this macro whenever you want to draw to the VGA screen.
Clearing the screen
There are 3 ways to clear the screen, or a portion of the screen
shclear_screen_vga - macro that very efficiently clears the entire screen (VGA mode) GR_ClearRect - procedure that clears a rectangle on the screen (VGA mode) clear_screen_txt - macro that very efficiently clears the entire screen (TXT mode)
Drawing Shapes
Drawing Lines
Drawing a line using a PROC:
shpush 50 ; x1 push 60 ; y1 push 120 ; x2 push 180 ; y2 call GR_DrawLine
or using a MACRO:
shgrm_DrawLine 50, 60, 120, 180
Drawing Rectangles
You can either draw a rectangle outline or a filled one.
Outline using a PROC:
shpush 50 ; x (top) push 60 ; y (top) push 120 ; width push 180 ; height call GR_DrawRect
or using a MACRO:
shgrm_DrawRect 50, 60, 120, 180
Filled using a PROC:
shpush 50 ; x (top) push 60 ; y (top) push 120 ; width push 180 ; height call GR_FillRect
or using a MACRO:
shgrm_FillRect 50, 60, 120, 180
Drawing Circles
You can either draw a circle outline or a filled one.
Outline using a PROC:
shpush 150 ; X center push 100 ; Y center push 40 ; Radius call GR_DrawCircle
or using a MACRO:
shgrm_DrawCircle 150, 100, 40
Filled using a PROC:
shpush 150 ; X center push 100 ; Y center push 40 ; Radius call GR_FillCircle
or using a MACRO:
shgrm_FillCircle 150, 100, 40
Drawing Polygons
To draw a polygon, you need to define an array and pass its pointer along with the number of points in the array.
The array should contain points (x and y) as follows:
shDATASEG _poly dw 5,30,100,50,200,100
This is an array with the following points:
- _poly[0] = (5,30)
- _poly[1] = (100,50)
- _poly[2] = (200,100)
Using a PROC:
shpush 3 ; there are 3 points push offset _poly ; pointer to _poly array call GR_DrawPolygon
or using a MACRO:
shmov ax, offset _poly grm_DrawPolygon 3, ax
Using Bitmaps
The library support only 8-bit bitmaps in v3. To load a bitmap, you need to define the following variable:
sh_bmp_file db "asset\\b.bmp",0 _bmp db BMP_STRUCT_SIZE dup(0)
This will allocate the memory for the BMP headers (struct). Memory allocation for the pixels' data will be
allocated in RAM when loading the data.
You must use "call FreeProgramMem" before trying to load images or you will get an out of memory situation and the allocation will fail.
Note that you can implicitly call it by passing TRUE to ut_init_lib:
shmov ax, TRUE ut_init_lib TRUE
To load a BMP image, call:
shmov dx, offset _bmp_file mov cx, offset _bmp push dx ; path offset push ds ; path segment push cx ; bitmap struct offset push ds ; bitmap struct segment call LoadBMPImage
or using a MACRO
shmov dx, offset _bmp_file mov cx, offset _bmp grm_LoadBMPImage dx, ds, cx, ds
After loading the bitmap, you can draw it on the screen
shmov cx, offset _bmp push cx ; bitmap struct offset push ds ; bitmap struct segment push 000Ah ; xTop = 10 push 000Bh ; yTop = 11 call DisplayBMP ; instead, you can tile the image on the screen using push cx push ds call TileBmp
or using MACROS:
shmov cx, offset _bmp grm_DisplayBMP cx, ds, 000Ah, 000Bh ; or grm_TileBmp cx, ds
You must free the bitmap memory (when it is not needed anymore) by calling
shmov cx, offset _bmp push cx ; bitmap struct offset push ds ; bitmap struct segment call FreeBmp
or using MACROS:
shgrm_FreeBmp cx, ds
Saving and Loading Palettes
The library provides methods for extracting color palettes of BMP files and storing them in a new file (binary) as well as load a palette file into
a buffer (possibly the palette of a BMP structure).
Here is an example of saving a palette to a file:
shmov dx, offset _bmp_file mov ax, offset _bmp grm_LoadBMPImage dx, [_dss], ax, [_dss] mov ax, offset _bmp mov bx, offset _paletteFile grm_SavePalette ax, [_dss], bx
and loading it to a buffer:
shpush offset _paletteFile push ds push offset _palette push ds call LoadPalette
Sprites
The library supports sprites, which is an image with multiple frames. Sprites are a great way to create animation or to hold multiple variants of an image.
See an example.
Since sprites are standard BMP files, you load them normally and then can display any frame you select.
shDATASEG _sprite_w equ 30 _sprite_frames equ 6 _sprite_file db "asset\\sprite1.bmp",0 _sprite db BMP_STRUCT_SIZE dup(0) CODESEG mov dx, offset _sprite_file mov ax, offset _sprite push dx ; path address push ds ; path segment push ax ; struct address push ds ; struct segment call LoadBMPImage push 0 ; frame index push ax ; BMP struct address push ds ; BMP struct segment push 0064h ; x coordinate push 0064h ; y coordinate push _sprite_w ; width of a single frame push _sprite_frames ; number of frames in BMP call PlaySpriteInPlace
or using macros:
shCODESEG mov dx, offset _sprite_file mov ax, offset _sprite grm_LoadBMPImage dx, ds, ax, ds grm_PlaySpriteInPlace 0, ax, ds, 0064h, 0064h, _sprite_w, _sprite_frames
Take a look at TestMySprite function as an example for playing animation using sprites.
Here is an example of a sprite image
Copy screen to buffer and visa versa
The library provide functions for copying a portion of the screen to a buffer and visa versa (from a buffer to the screen).
shgrm_SaveScreen memAddress, memSeg, x, y, w, h
shgrm_WriteScreen memAddress, memSeg, x, y, w, h
---------------------------------------------------------------
Utility Library
The library includes other utilities that help developing assembly programs.
shstore_sp_bp - macro that stores and sets BP value. Called at the beginning of PROC restore_sp_bp - macro that restores BP, SP values. Called at the end of PROC return - macro for returning control to DOS with a code cmpv - macro that compare two memory variables movv - moves a WORD from one memory to another via the stack
Data Segment
The library stores the original data segment (DS register) using a global variable _dss that you can access at any time if you need to restore its value.
shpush [_dss] pop ds
Time and Delays
The library provides 3 different ways to delay your program:
Sleep
If you want your program to halt for a given number of seconds call the Sleep procedure
shpush 3 ; sleeps for 3 seconds call Sleep
or using MACROS:
shutm_Sleep 3
Delay
Delay program execution by X number of milliseconds. Actually, the argument is the number of
1/18 of a second
shpush 3 ; Delay for 3 * 1/18 of a sec call Delay
Or:
shutm_Delay 3
DelayMS
This function delays execution for given number of microseconds which are specified in 2 variables, one for the high order and one for the low order.
For example, a 1 second delay (1 * 1,000,000 msec) is 000F 4240 and therfore the values will be
shpush 000Fh push 4240h call DelayMS
Or
shutm_DelayMS 000Fh, 4240h
Another example, a 2 seconds delay is equal to (21,000,000) 001E 8480 and a 1 millisecond is (11000) 0000 03EB
Keyboard
Most keyboard functions are accessible via interrupts and the library focuses on some less trivial parts of handling the keyboard.
A list of keyboard scan codes can be found at keymap.asm
Repeat Rate
Setting keyboard yypematic rate to defalt (repeat delay and rate)
shcall SetKeyboardRateDefault
Wait for keypress
Hold program execution until a key is pressed
shcall WaitForKeypress
Keyboard Status
Getting keyboard status
shcall GetKeyboardStatus
Returns:
ZF = 0 if a _Key pressed (even Ctrl-Break)
AX = 0 if no scan code is available
AH = scan code
AL = ASCII character or zero if special function _Key
Consume Key
Taking the pressed key out of the keyboard buffer
shcall ConsumeKey
Get keyboard flags
shcall GetKeyboardFlags
Returns AL:
|7|6|5|4|3|2|1|0| AL or BIOS Data Area 40:17
| | | | | | | ---- right shift key depressed | | | | | | ----- left shift key depressed
| | | | | ------ CTRL key depressed | | | | ------- ALT key depressed
| | | -------- scroll-lock is active | | --------- num-lock is active
| ---------- caps-lock is active ----------- insert is active
Install & Restore a Keyboard ISR
You can replace the default keyboard interrupt with your own by calling this procedure
shpush isr_address call InstallKeyboardInterrupt
For example:
shlea dx,[my_interr] push dx call InstallKeyboardInterrupt
You must restore the interrupt at the end of the program by calling
shcall RestoreKeyboardInterrupt
Sample Keyboard Interrupts
The library contains 2 sample implementations of a keyboard ISR.
- KeyboardSampleISR - implements a FIFO buffer and allows retrieving keys using getcISR. Note that this is not
a complete implementation but merely an example. For instance, it does not convert the scancode to ASCII and does not
treat SHIFT, CTRL and ALT combinations. - KeyboardISREvents - a simple implementation that illustrates how to call the default keyboard handler
See TestKeyboardISR and TestSimpleISR
Mouse
Most mouse functions are accessible via interrupts and the library focuses on some less trivial parts of handling the mouse.
Show and Hide the mouse
Use these macros to show / hide the mouse
shShowMouse HideMouse
Get Mouse Status
Mouse position and button status can be retrieved by
shGetMouseStatus
On return:
CX = horizontal (X) position (0..639)
DX = vertical (Y) position (0..199)
BX = button status:
|F-8|7|6|5|4|3|2|1|0| Button Status
| | | | | | | | `---- left button (1 = pressed)
| | | | | | | `----- right button (1 = pressed)
`------------------- unused
Translate Mouse Coordinates
After getting mouse coordinates from GetMouseStatus, you can translate them to VGA coordinates by calling
shTranslateMouseCoords
Set Mouse Cursor Position
shmov cx, 3 ; horizontal mov dx, 5 ; vertical SetMousePosition
Installing and Restoring Mouse ISR
You can replace the default mouse interrupt with your own by calling this procedure
shpush ISR address push ISR segment push mask call InstallMouseInterrupt
You must restore the interrupt at the end of the program by calling
shcall UninstallMouseInterrupt
File System
The library provide a set of functions to access and manipulate files. The library was designed to handle a single file at any time using the global variables
sh_fHandle - stores the handle of the openned file _fErr - stores the error value
Open a File
shpush address_of_file_name push segment_of_file_name call fopen
or using MACROS:
shutm_fopen address_of_file_name, segment_of_file_name
Create a New File
shpush address_of_file_name push segment_of_file_name call fnew
or using MACROS:
shutm_fnew address_of_file_name, segment_of_file_name
Close a File
shcall fclose
or using MACROS:
shutm_fclose
Get File Size
shpush address_of_file_name push segment_of_file_name call fsize
or using MACROS:
shutm_fsize address_of_file_name, segment_of_file_name
Read from a File
shpush length push address_of_buffer push segment_of_buffer call fread
or using MACROS:
shutm_fread address_of_buffer, segment_of_buffer
Write to a File
shpush length push address_of_buffer push segment_of_buffer call fwrite
or using MACROS:
shutm_fwrite address_of_buffer, segment_of_buffer
Delete a File
shpush address_of_file_name push segment_of_file_name call fdelete
or using MACROS:
shutm_fdelete address_of_file_name, segment_of_file_name
Change File Attributes
shpush attribute push address_of_file_name push segment_of_file_name call fchangeAttr
or using MACROS:
shutm_fchangeAttr attribute, address_of_file_name, segment_of_file_name
File Seek
You can do a fseek in a file very similar to the C function
shgrm_fseek SEEK_SET, 0, 40
Or:
shpush SEEK_SET push 0 push 40 call fseek
The first parameter can be SEEK_CUR, SEEK_SET or SEEK_END.
The second parameter is the high order of the offset and the third is the low order.
Directory Services
The library provides a few directory services, including:
shmkdir OR utm_mkdir - create a directory rmdir OR utm_rmdir - delete a directory chdir OR utm_chdir - change a directory
Math
The library provide some basic math related functions and macros
Random Numbers
Before generating a random number, you need to initialize the number generator by calling
shcall RandomSeed
and then you can use
shcall RandomWord or call RandomByte
to get a random number in AX or AL
Abs(x)
You can get the absoilute value of a number
shgr_absolute number
Memory Management
The library allows managing (allocating, releasing) RAM memory. If you need to allocate dynamic memory, you must free unused memory at the
beginning of your program by calling:
shcall FreeProgramMem
If you forget to call it, all memory allocations will fail on "out of memory".
Note that you can implicitly call it by passing TRUE to ut_init_lib:
shmov ax, TRUE ut_init_lib TRUE
Allocating a block
Allocating a memory block is done by calling:
shpush size call malloc
Note that the size is measured in Paragraphs and therefore need to be divided by 16 (bytes)
Return value:
AX = segment address of allocated memory block (MCB + 1para)
0 on error
BX = size in paras of the largest block of memory available
0 on error
CF = 0 if successful
= 1 if error
Allocated memory is at AX:0000
Release an allocated memory block
Pass the segment address of the allocated memory block to release it
shpush segment call mfree
Releasing all allocated blocks
The library maintains an internal list of up to 50 allocated blocks that can be freed by calling
shcall mfreeAll
Memory Copy
Copies memory from one address to another
shpush from_address push from_seg push to_address push to_seg push length_in_bytes call MemCpy
Initialize memory block
You can set a byte or word value to an entire memory block
shmov ax, offset _blcok push 10 ; length_in_bytes push ds ; block_segment push ax ; block_offset push 0 ; value call SetMemByte
and
shmov ax, offset _blcok push 5 ; length_in_words push ds ; block_segment push ax ; block_offset push 0 ; value call SetMemWord
Sound
You can make a beep with the following procedure. Note that the sound will continue until you stop it
shpush frequency call Beep utm_Sleep 2 ; wait 2 seconds call StopBeep
Or with macros:
shutm_Beep freq utm_Sleep 2 utm_StopBeep
This part of the library supports writting text to the screen
Printing to the screeb
shcall PrintDecimal - prints a value as a decimal number call PrintChar - prints DL as a char PrintCharNewLine - macro to print a char with new line call PrintByte - prints DL (number between 0 and 15) PrintByteNewLine - macro to print a byte with a new line call PrintStr - prints a string. DS:DX pointer to string ending in "$" PrintStrNewLine - macro to print a string with a new line call PrintNewLine - prints a new line call PrintSpace - prints a space char call PrintHexByte - prints the LSB BYTE in HEX call PrintHexByte - prints the WORD in HEX
Printing in VGA
shcall PrintCharVGA - prints a character on VGA display (DL: char, BL: color) call PrintStrVGA - prints a string to the VGA screen
Setting cursor position
shpush x push y call SetCursorPosition
String Manipulations
The library contains several basic string manipulations functions that accept null terminating string
shStrlen - Calculates length of string ending with NULL StrlenDollar - Calculates length of string ending with '$' Strcpy - Copies string s2 into string s1 Strncpy - Copies given number of chars from string s2 into string s1. Strcat - concatenate 2 strings Strchr - Searches for the first occurrence of the character in the given string Strcmp - Compares the string pointed to, by str1 to the string pointed to by str2.
License
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Credits
- Some ideas were taken from https://github.com/itay-grudev/assembly-dos-gx
- README file created using Dillinger
Contributors
Showing top 1 contributor by commit count.
