Copy single byte to multiple memory locations in XV6 8086 Assembly 0x13 VGA (Real Mode)

120 Views Asked by At

Before anybody tells me that this technology is outdated, I am aware however the scope of the project is very specific.

My requirement is to print a filled rectangle to the output by writing directly to the video memory (0x13 in real mode). I have achieved this by plotting each line along the x axis and storing the colour byte (in this case 11) to VGA memory 0xa0000 + offset. The requirements for this project however ask for a more efficient method than a loop plotting each pixel as I'm directly addressing video memory.

I can't seem to work out if there's a way to copy a single byte (value: 11) across multiple memory locations. As an experiment, I tried to copy the byte across a register by multiplying it by 0x01010... and then moving the entire two bytes to memory. That experiment was successful, it produced a horizontal line the length of two pixels starting at memory location defined by 0xa0000 + offset.

The issue I have, is this is only two bits. The resolution for 0x13 mode is 320x200, making the use of registers in such a way inefficient. I had considered the use of .string etc however that is also against the requirements of the scope. Plotting an array and allocating a size that totals 64kb on the off chance that some of those pixels may be used also sounds massively inefficient, if even possible in real mode. So that ruled that out for me.

Another factor of this not working is also the fact that sometimes lines may need to be drawn downwards rather than horizontal and won't be as simple as storing a block of bytes starting at the memory address.

Having said that however, if I can figure out a way of copying a dynamic number of the same byte to a block of memory starting at a given location then it's huge progress I can work off, so that's my current goal.

Is there any way to do this without previously allocating crazy amounts of space? Say I want to draw a line that's 18 pixels long, I want to copy a byte of value 11 into 18 bytes of a segment starting at the given offset.

Thanks in advance, I hope I've been descriptive enough.

1

There are 1 best solutions below

0
Sep Roland On

My requirement is to print a filled rectangle to the output by writing directly to the video memory (0x13 in real mode).
The requirements for this project however ask for a more efficient method than a loop plotting each pixel as I'm directly addressing video memory.

Plotting each pixel would indeed be inefficient. The code that I show below:

  • calculates only the address for the upperleft pixel
  • writes 2 pixels at once
  • avoids writing a word at an odd address

I chose to pass the arguments in registers, but if you prefer you can change it so it uses the stack. This is pure 8086 code. If you target the real mode of the later cpus, then outputting at least 4 pixels at once is possible.

; BL is color [0,255]
; CX is X [0,319]
; DX is Y [0,199]
; SI is width [1,320]
; DI is height [1,200]
; IN (bl,cx,dx,si,di) OUT () MOD (ax,bx,cx,dx)
PaintRectangle:
  push es           ; DirectionFlag (DF) assumed 0
  push di

  mov  ax, 0A000h   ; Video buffer for 256-color mode 13h (320 x 200)
  mov  es, ax
  mov  ax, 320      ; BytesPerScanline (BPS)
  mul  dx           ; Y * 320
  add  ax, cx       ; Y * 320 + X
  xchg ax, di       ; DI is address, AX is height
  xchg ax, bx       ; BX is height, AL is color
  mov  ah, al       ; AH is color too

.loop:
  mov  cx, si       ; Width 1+
  test di, 1
  jz   .even
  stosb             ; First/only pixel on an odd offset address
  dec  cx
.even:
  shr  cx, 1
  rep stosw         ; Two pixels together on an even offset address
  jnc  .done
  stosb             ; Last pixel on an even offset address
.done:
  sub  di, si       ; Back to left side of rectangle
  add  di, 320      ; Descending one scanline
  dec  bx           ; Height--
  jnz  .loop

  pop  di
  pop  es
  ret