0

I'm using emu8086 on Windows 10 with VGA mode and 8-bit fixed RGBA pixel format, learning the basics of graphics and ASM just for fun. I found a way to draw one pixel at a time as shown in the code below:

org 100h       
mov ax, 13h 
int 10h       
mov ax, 40960
mov ds, ax
mov ax, 2Fh         
mov bx, 0 ; will hold addr of pxl to paint in.   
pntLnClr: 
mov [bx],ax ; paint color in ax into pixel at bx. 
inc bx
cmp bx, 40
JL pntLnClr
mov ah, 0 
int 16h 
ret

I want to write an ASM program that would paint multiple pixels at the same time instead of looping from pixel to pixel, making it look like a trail. I've been bouncing around SO and the rest of the Web trying to find a base code for accomplishing the objective but couldn't find anything. The accepted answer here seems like the closest thing to an answer, although it is unclear to me whether I actually need something like an extra segment and techniques like pushing and popping to access and write to multiple pixel addresses. Not only that, I tried the code from the answer, and the assembler told me that BITS is an illegal instruction and that the parameters in mov [es:di],dx are wrong.

[EDIT:] This question is coming from the idea of satisfying the goal of creating a 2D game-like demo with low resolution, something as simple as a board where the sprites and the background are on the same flat layer.

  • see [Graphics mode in assembly 8086](https://stackoverflow.com/a/48664419/2521214) and all the sublinks in there (especially the `VESA+PCX in TASM` and `What is the best way to move an object on the screen` as there you got asm examples for rendering sprites and images... what do you mean color multiple pixels at the same time? you can only color neighboring pixels up o used transfer instruction bitwidth ... if you want more pixels then use loops or stuff like `rep movsb/stosb/movsw/stosw` ... what video mode you are using? is it CGA/EGA/VEGA or VESA/VBE ? what pixelformat ? – Spektre Nov 13 '21 at 10:58
  • @Spektre The top bar of my emu window says "(40x25 chars)(320x200 pixels)". Going off of [this page](http://www.columbia.edu/~em36/wpdos/videomodes.txt) I'm assuming that just means I'm in the VGA mode. Also, coming from [this](https://derivative.ca/UserGuide/Pixel_Formats#/Supported_Pixel_Formats), it looks like I'm using the 8-bit fixed RGBA format since I have two hex-chars (4 bits each x 2 hex-chars = 8 bits) and nothing more, nothing fancy. My whole idea is to have the blank prompt with more than one dot getting colored at a time, not like one after another. – AndrewGreen Nov 14 '21 at 07:11
  • Ah yes I overlooked `mov ax, 13h int 10h` in your code ... its 320x200x8bpp 256 color palette so single segment no paging the examples in the link from my first comment use the same mode. What asm compiler you use? TASM/MASM/NASM ? each has its own syntax for addressing memory and other stuff. my favourite is NASM however I started with TASM as it was integrated in ancient turbo pascal and turbo C++ from borland. if you look through my asm answers some are in TASM some in NASM so just check the syntax. – Spektre Nov 14 '21 at 08:16
  • IIRC NASM and TASM uses `mov [es:di],al` syntax however there are other compilers that uses different formats like `mov es:[di],al` or `mov es[di],al` and other weird combinations. however there are other quirqs between compilers like different format of `org/equ/db/dw/dq/bits/code/segment` .... so you should first check what compiler you use and then search for any asm example so you can use the correct syntax. Also the code structure differs between `*.com` and `*.exe` and `*.ovl` so you have to take that in mind too – Spektre Nov 14 '21 at 08:24
  • @Spektre According to [this](https://stackoverflow.com/questions/44853636/how-to-know-if-an-assembly-code-has-particular-syntax-emu8086-nasm-tasm), emu8086 falls under the TASM/MASM umbrella. As someone who is to some degree interested in the history of ASM's evolution (more old-school -oriented), I think I'd better do a very thorough, comprehensive research on what came before what (even if it is obsolete but still works on modern-architecture machines). Also, by looking at your comments I can tell: I would have to do some research on the different kinds of compilers out there. – AndrewGreen Nov 14 '21 at 08:54
  • Update: After going over the answer [here](https://stackoverflow.com/questions/38268762/write-graphics-pixels-in-16-bit-assembly), I just found out that in my case syntax for accessing the extra segment register does matter. It's not ```mov [es:di],ax```, but ```mov es:[di],ax```. But I still can't paint more than one pixel at a time. No clue why. – AndrewGreen Nov 15 '21 at 06:59
  • instruction `mov es:[di],ax` will place 16bit ax value onto es:di address if `es=A000h` and `di=320*y+x` it will color 2 pixels once at `(x,y)` and the other at `(x+1,y)` or `(0,y+1)` depending on the fact if the x is on the boundary `(x=319)` or not ... you can use 32bit eax (if 386+) to color 4 consequent pixels at once however that is it ... in order to color more pixels you need to use loop and updating the `di` inside it ... or use block instructions like `rep stosw` which is more or less the same as `l0: moc es:[di],ax; inc di; inc di; djnz l0;` ... so it repeats cx times .... – Spektre Nov 15 '21 at 09:14
  • btw before your app exit you should also set the videomode back to usual console 80x25 text mode `mov ax, 3 int 10h` ... also the `BITS 16` is not instruction but compiler directive telling NASM its a 16bit code ... as you have clearly different compiler you need to find out how its done in it .. usually older compilers uses switches instead of in code keywords the `ORG 100h` tells compiler where to place the code the address is common start of `*.com` executables ... – Spektre Nov 15 '21 at 09:22
  • Update: I did some research and figured out how to use REP(eated) STOSB instruction, but what that does is the same old thing - painting pixels one by one. What I don't understand is how game developers back in the MS-DOS days could make all image pixels appear and disappear at the same time (sort of like page flipping). There has to be some kind of an instruction that allows for loading hex color code from ACC into one group of memory addresses at the same time or over the same time interval in the background for all pixels to show their colors at the same moment. – AndrewGreen Nov 17 '21 at 03:32
  • What you are describing is using Sprite engine ... there is no Sprite processor on old PC / MS-DOS (they where used in some 8bit computers and game consoles but not on PC) the old games really did render pixel by pixel ... the only page flipping that can be done is using VBE and swap pages (like double buffernig) however the individual pages still need to be rendered pixel by pixel ... only gfx accelerators did something like that virtually ... other possibility is that you are searching for some crazy EGA/VGA I/O port technique that I do not know of as I used BIOS and VRAM access instead – Spektre Nov 17 '21 at 08:54
  • The best you can try to do is to use DMA for sprite transfer however I never used DMA on PC for gfx (only for sound) so try to look at this: [PC Game Programmer Encyklopedia 1.0](https://www.pcorner.com/list/UPLOAD/PCGPE.ZIP/INFO/) that should cover DMA too (I think the DMA_VLA.TXT is what you seek) beware the PCGPE is a MSDOS executable so you need to run it in DOSBox in order to read the files. There was also win help version out there but all my links are broken try to google it that is viewable directly in windows if you have the `*.hlp` extention installed – Spektre Nov 17 '21 at 08:56
  • After much research, I'm embarrassed to say that I actually remember learning that you can only raster one pixel at a time; otherwise, stuttering and tearing wouldn't be possible. With all that being said, after writing an ASM code where I'm creating a sprite and "moving" it by erasing it with black in one place and drawing it somewhere else with its own color, I'm getting flicker. That is because the rewriting isn't happening fast enough. How do I achieve faster rasterization to avoid flicker? How do I employ a gfx-card accelerator in Assembly? Or are there other ways? – AndrewGreen Nov 24 '21 at 11:30
  • You got 2 options... 1. use VGA sync signal and redraw pixels before they are copied onto VGA signal 2. use backbuffer instead of overwriting with background of sprite, so render to memory and when done copy it to VRAM (you might use the #1 for the copy) ... in both case no need for faster pixel access ... – Spektre Nov 24 '21 at 15:42
  • @Spektre Just did a bit more research. I think I understand now why the redrawing is so slow. When running my assembly code with the `mov [bx], ax` instruction for painting pixels, every time this instruction is to be executed, my machine is using the CPU - already burdened with other tasks - to access and write to the screen memory (VRAM at A000H) all by itself, which takes up too much time. This is where the peripheral DMA controller (PDC) comes in, relieving the CPU of the accessing/writing operations. And this is before graphics accelerators w/ GPUs came in in the early 90's. Am I correct? – AndrewGreen Nov 24 '21 at 20:00
  • Even on old machines the 320x200x256color mode is just 64KByte per frame the old CPUs wehre still fast enough to render whole screen without any problems no DMA nor gfx accelerators needed.... You are running in some emulator so may be you just have it wrongly set up to too low speed ... or you are doing something wrong – Spektre Nov 24 '21 at 22:42
  • There appears to be no way to adjust the speed on emu8086, and I don't know what I'm doing wrong as the code shown in OP is fairly basic. Also, I tried using MASM in DOSBox as an alternative, only to be obstructed with nonsense like prompting for source listing and cross reference when compiling and linking my .asm file. Not sure that video game developers in the 80s and 90s had to put up with as much technical nuisance just to quickly move a sprite on a prompt. It's been 11 days, so it looks like I'll have to try to provide an answer to this question myself with all the findings that I got. – AndrewGreen Nov 25 '21 at 08:44
  • DOSbox has natively set the speed for really low IIRC using CTRL+F12 increasesthe cycles ... in DOSBox use VC (Volkov comander) and its associations to quickly compile and link asm files just by hitting enter in the asm file see [Is there a way to link object files for DOS from Linux?](https://retrocomputing.stackexchange.com/a/5366/6868) its example of *.com app compilation by nasm and linked by tasm's tlink (in extention format for volkov comander but you can easily adapt it for commandline ...) ...also move sprite like that is not hard... novadyas gfx apis are way more complicated – Spektre Nov 25 '21 at 09:05
  • 1
    `inc bx` only increments the pointer by 1 byte, but you're storing two bytes with each `mov` from AX. So you're doing overlapping stores. Also, you could be using `rep stosw` which was faster on 8086, and potentially *much* faster on modern CPUs with "fast strings" microcode, potentially generating wider bus transactions instead of multiple 2-byte stores over a PCIe bus. (Especially if VGA RAM is mapped in a WC write-combining region). Actual 8086 only had a 16-bit bus, so that wasn't a downside; `rep` avoiding instruction fetch cycles was all the speedup you could get. – Peter Cordes Nov 25 '21 at 09:41
  • @PeterCordes I see what you are doing. `rep stosw` enables you to draw a 2pxl-by-2pxl square. And if we do away with the idea of refreshing the entire screen and just move individual sprites around on the "foreground", we will get a better game performance. I will go ahead and look into the different buses, bus sizes, and how `mov` and `sto` make an impact on the memory. – AndrewGreen Nov 25 '21 at 20:15
  • 1
    Each `rep stosw` stores a contiguous range of bytes / words. A square on a larger screen is multiple separate rows. You'd need `mov cx, square_width` / `rep stosw` / `add di, row_stride - sqare_width` in a loop to draw a square. – Peter Cordes Nov 25 '21 at 22:03
  • @PeterCordes and @Spektre : If you guys want to, you can contribute an answer yourselves. It appears that there is no way to access/write to multiple pixels at the same time other than by addressing two contiguous Bytes/pixels (a.k.a. one word string) with `rep stosw`. I tried painting one word/two pixels per row for 40 rows and it took way too long to paint that. Perhaps there is a workaround. The idea for me is to quickly display and image in my emulator graphics prompt in emu8086. After that I want to figure out how to preserve a chunk of an image for side-scrolling purposes. – AndrewGreen Nov 27 '21 at 07:46

1 Answers1

0

To iterate one of my comments from this thread:

When running my assembly code with the mov [bx], ax instruction for painting pixels, every time this instruction is to be executed, my machine is using the CPU - already burdened with other tasks - to access and write to the screen memory (VRAM at A000H or B000H) all by itself, which takes up too much time. (See Refresh Rates, V-Sync Settings and Frame Buffers Explained on YouTube and 'Framebuffer' on Wiki.)

[EDIT:] While you can access two bytes / one word at a time with rep stosw, that is still not enough to paint a whole image screen-size in a flash.

In order to fulfill the goal of creating a 2D game-like demo (with or without scrolling ability), you would have to learn to capture a 320x200 part of a very large image. But to do that you have to learn to capture at least any 320x200 image. And to do that you would have to tap into the hardware directly or indirectly to store an image in a chunk of its memory. To do something like accessing the hardware indirectly you would need to write your own video driver. It was pointed out by a number of people that reinventing the wheel by way of doing all of this in Assembly is a tedious practice (as argued here). You are better off doing all of this in C unless there is a particular specialized task that cannot be accomplished in C.

There may not be a need for a DMA to relieve the CPU of the accessing/writing operations. And in the '80s there were no graphics accelerators with graphics libraries and GPUs, which came in only in the early 90's to make animation much more fluid in worlds of higher definition. (See 'DMA' on Wiki.)