Dark Bit Factory & Gravity
PROGRAMMING => Other languages => ASM => Topic started by: boogop on August 14, 2018
-
I'm working on a small plasma in TASM. It's very vanilla and not very interesting except for the sine generator. I was struggling with a big list of sine constants (originally I'd exported them from c#, double d = 32 + 32 * Math.Cos((i * 6.28) / 256)) when I came upon this generator in a prod by insomniac/matrix. But I'm not good enough at asm to tell exactly how it's working, except that wally/rage (??) was pretty darn clever. 188 bytes but I'm also getting some annoying color banding from stosw
; tasm /m2
; tlink /t
cseg segment
assume cs:cseg
org 0100h
.286
start:
mov ax,13h ; set mode 13
int 10h
push 0a000h ; stick video segment in es
pop es
mov dx,3c8h ; set color index port
xor ax,ax
out dx,al ; output color index 0
inc dx ; inc dx = 3C9h, color write port
@redup: ; Set colors 0-62, ramp up red
out dx,al ; set red to value in al
xchg al,ah ; ah is 0, so exchange it with al
out dx,al ; set green and blue = 0
out dx,al
xchg al,ah ; swap ah/al so al is again non-zero
inc al ; al +=1
cmp al,63
jne @redup
@reddn: ;set colors 63-127, ramp down red
out dx,al
xchg al,ah
out dx,al
out dx,al
xchg al,ah
dec al
jnz @reddn
@blueup: ;set colors 127-194, ramp up blue
xchg al,ah
out dx,al
out dx,al
xchg al,ah
out dx,al
inc al
cmp al,63
jne @blueup
@bluedn: ;set 194-256, ramp down blue
xchg al,ah
out dx,al
out dx,al
xchg al,ah
out dx,al
dec al
jnz @bluedn
; sin generator from argon by insomnia/matrix
; who got it from Wally/Rage, but I'm not sure
; who that was. There was a Rage demogroup
; in the amiga scene. Anyway, credit to the
; original author. My big list of sin constants
; was taking up ~200 bytes
mov cx,783Fh ; [30783]
xor si,si
sin1:
mov ax,65497
imul cx ;[2016194151]
add si,dx ; results of imul are stored in dx:ax [782C AE67, si+=30764]
add cx,si ; [783F + 782C,cx=30783+30764=61547=F06B]
mov [bx],ch ; [[bx]=F0=240]
sar byte ptr [bx],1 ; divide the value by 2, only store a byte [bx=120?]
dec bx
cmp bx,16383
jne sin1
; inc bx ; BX points to the sine/cos-values [comment by insomnia but this step isn't needed and saves a byte]
mov si,bx ; move it to SI since I need BX
main:
;------- main program ------------
xor di,di ; Reset vga position
mov cl,[p_pos1] ; stick plasma position values into ch,cl
mov ch,[p_pos2]
mov ah,200 ; 200 rows in mode 13
Y_LOOP:
push ax ; ax is also our x counter, so save
; the y vals to test later
mov dl,[p_pos3] ; the other position values in dh,dl
mov dh,[p_pos4] ; now the plasma position vals are in cx/dx
mov ah,160 ; X counter. since we're using stosw we only have to loop 320/2 times
X_LOOP:
xor al,al ; al holds the color, so clear it
; x = SinTable[p_pos1] + SinTable[p_pos2] + SinTable[p_pos3] + SinTable[p_pos4]
mov bl,dl ; mov p_pos3 into bl
add al,si[bx] ; x += Sin[p_pos3]
mov bl,dh ; mov p_pos4 into bl
add al,si[bx] ; x += Sin[p_pos4]
mov bl,cl ; mov p_pos1 into bl
add al,si[bx] ; x += Sin[p_pos1]
mov bl,ch ; mov p_pos2 into bl
add al,si[bx] ; x += Sin[p_pos2]
; push cx ; save the position vals
; mov cx,4 ; write 4 pixels at a time
; rep stosb ; put pixel cx times in es:di, advancing the screen pointer
; pop cx ; restore position vals
stosw ; stosw is smaller than that noise
add dl,2 ; add movement var to p_pos3
add dh,1 ; add movement var to p_pos4
dec ah ; decrement the x counter
jnz X_LOOP ; test for 0
add cl,2 ; add movement var to p_pos1
add ch,3 ; add movement var to p_pos2
pop ax ; restore the y counter
dec ah ; Next vertical line
jnz Y_LOOP ; test for 0
add [p_pos1],2 ; add some vals to the position vars
add [p_pos2],3 ; speed up/slow down the plasma
sub [p_pos3],1
add [p_pos4],4
jmp main ; do it all again
p_pos1 db 0
p_pos2 db 0
p_pos3 db 0
p_pos4 db 0
; SinTable db 64,63,63,63,63,63,63,63,63,63
; db 63,62,62,62,62,61,61,61,60,60
; db 60,59,59,59,58,58,57,57,56,56
; db 55,55,54,54,53,52,52,51,51,50
; db 49,49,48,47,47,46,45,44,44,43
; db 42,42,41,40,39,39,38,37,36,35
; db 35,34,33,32,32,31,30,29,28,28
; db 27,26,25,25,24,23,22,21,21,20
; db 19,19,18,17,16,16,15,14,14,13
; db 12,12,11,11,10,9,9,8,8,7
; db 7,6,6,5,5,4,4,4,3,3
; db 3,2,2,2,1,1,1,1,0,0
; db 0,0,0,0,0,0,0,0,0,0
; db 0,0,0,0,0,0,0,0,0,1
; db 1,1,1,2,2,2,3,3,3,4
; db 4,4,5,5,6,6,7,7,8,8
; db 9,9,10,11,11,12,12,13,14,14
; db 15,16,16,17,18,18,19,20,21,21
; db 22,23,24,24,25,26,27,28,28,29
; db 30,31,31,32,33,34,35,35,36,37
; db 38,38,39,40,41,41,42,43,44,44
; db 45,46,47,47,48,49,49,50,50,51
; db 52,52,53,54,54,55,55,56,56,57
; db 57,58,58,58,59,59,60,60,60,61
; db 61,61,62,62,62,62,63,63,63,63
; db 63,63,63,63,63,63
cseg ends
End Start
-
nvm the color banding. That's caused by the counter value in ah. duh
push ax
xor ah,ah
stosw
pop ax
-
And here is the Freebasic port for the sine generator part, for anyone who wants to investigate how it works.
Keep in mind that this generator was done for old computers without FPU (old PC 286 computers I believe), but it's an interesting piece of code that shows how those old coders did their stuff, might be useful for someone making demos for other kinds of old school computers ofcourse.
' CALCULATE SINE/COS - VALUES (Wally/Rage)
dim shared bx(16384) as short
dim as short cx = &h783F
dim as byte ch = 0
dim as short si = 0
dim as short ax = 0
dim as short dx = 0
dim as short b = 0
width 80, 25
cls
dim as integer i = 0
for i = 0 to 16383
ax = -39 '65497
dx = (cx * ax) shr 16
si += dx
cx += si
ch = (cx shr 8 ) and &hFF
bx( i ) = ch
b = bx( i )
bx( i ) = b shr 1
print bx( i ); " ";
next
print
print
print "press any key to exit..."
sleep
dim as string clearkey = inkey
-
Cool stuff, Rbz!
I probably have all the effect source from Hornet Archive and I've never seen a sine generator like that one. Mostly people seemed to be generating them externally and using a list of constants. There are a few that use fi[blah] commands to produce one.
Starport II (1993) had an interesting one but didn't create a table, it calculated it on the fly. SHRD was a 386 instruction, not sure it was available on the 286?
;北北北北北北北北 sin/cos 北北北北北北北北
;entry: ax=angle (0..65535)
; exit: ax=muller (-127..127)
addwcos:add ax,ds:[bx] ;optimized entry for wavesets
mov ds:[bx],ax
cos: add ax,16384
sin: mov bx,ax
mov cx,bx
and cx,1023
neg cx
add cx,1023
shr bx,10
mov ah,ds:sintable[bx]
xor al,al
imul cx
push ax
push dx
mov ah,ds:sintable[bx+1]
xor al,al
neg cx
add cx,1023
imul cx
pop bx
pop cx
add ax,cx
adc dx,bx
shrd ax,dx,11
ret
but SPII also included a sine table, so further investigation is needed
sintable LABEL BYTE ;sine table (circle is 64 units)
db 0,12,24,36,48,59,70,80,89,98,105,112,117,121,124,126,127,126
db 124,121,117,112,105,98,89,80,70,59,48,36,24,12,0,-12,-24,-36
db -48,-59,-70,-80,-89,-98,-105,-112,-117,-121,-124,-126,-127
db -126,-124,-121,-117,-112,-105,-98,-89,-80,-70,-59,-48,-36
db -24,-12,0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54
db 57,59,62,65,67,70