## compile with gas as follows: ## as -R morecircles.s -o morecircles.o ## objcopy -O binary morecircles.o morecircles.com.0 ## dd if=morecircles.com.0 of=morecircles.com bs=256 skip=1 ## I've only tested it in DOSBox and in QEMU with FreeDOS; ## hope it works elsewhere! ## registers are used as follows: ## %ax: X-coordinate from center of circle, sin theta ## %bx: scratch space ## %cx: loop counter ## %dx: Y-coordinate from center of circle, cos theta ## %di: scratch space used to compute address of pixel ## %si: center of circle (as pixel address) ## %bp: PRNG state ## %cs, %ds, %ss, %sp, %ip: the usual ## %es: the video RAM segment ## the top stack item: the current color and a counter .code16 .org 0x100 ## set video mode 13h start: mov $0x13, %al int $0x10 ## load video segment into %es #mov $seg-2, %bx # if we leave this out, it actually still mostly works les (%bx), %bp # we don't care what goes into %bp as long as it's not 0 init: ## change radius and position pseudorandomly mov %bp, %ax # random seed is in %bp imulw (start+1) # 0xcd13**n % 65536 has period 16384 mov %ax, %bp xor %ax, %si # get some "randomness" into the position xor %dx, %dx # set angle to 90 degrees mov %ax, %cx # number of iterations: (scaled) radius loop: ## turn coordinates in %ax, %dx into offset in %di ## first, put %dx/256 * 320 into %di ## sin and cos are scaled by 16 so the circle is round, not octagonal xor %bx, %bx mov %dh, %bh mov %bx, %di sar $2, %bx add %bx, %di ## now add x-coordinate, %ax/256 mov %ax, %bx sar $8, %bx add %bx, %di ## now offset them both by the center of circle add %si, %di #mov %si, %di # to see the centers only, to see how bad the RNG is ## now set a pixel pop %bx # we're using whatever was on the stack... movb %bh, %es:(%di) # change color every 256 pixels by using %bh inc %bx push %bx ## this is the circle-drawing trick from HAKMEM ## to update sin and cos: ## cos += sin * scale mov %ax, %bx sar $4, %bx add %bx, %dx ## sin -= cos * scale mov %dx, %bx sar $4, %bx sub %bx, %ax loop loop ## now that we've drawn a circle, let's go to the next one jmp init #seg: .short 0xa000 # (see above about "it actually still mostly works")