User:Ashmanskas/p364/prime.sasm

From LaPET electronics

Jump to: navigation, search

prime.sasm

	#
	# prime.sasm
	# coded 2010-11-11 by Bill Ashmanskas, ashmansk@hep.upenn.edu
	#
	# The purpose of this program is to demonstrate that the CPU
	# implemented in simple_cpu.v is capable of carrying out a
	# non-trivial computation.
	#
	# This is probably the dumbest imaginable algorithm to compute
	# prime numbers.  Its execution time scales as the third power
	# of the number of candidates to evaluate.  For every candidate i,
	# loop over possible factors j and k, testing whether i==j*k.  If
	# no such j and k are found, then display i on the LEDs.
	#
	# Note that with storage for a mere 5000 boolean values (which
	# I could have easily cooked up), one can use a much more efficient
	# algorithm, the Sieve of Eratosthenes.  It scales (with number of
	# candidate integers N) as N*log(N)*log(log(N)), while my algorithm 
	# scales as N**3.  I point this out only so that you don't think
	# that I think the N**3 algorithm is a good way to compute primes.
	#
start:	load	one	#
	store	i	#  i := 1
iloop:	load	i	#  loop i from 2 to 32767
	add	one	#
	store	i	#    i := i+1
	jumpn	done	#    if (i>=32768) goto done
	load	zero	#
	store	j	#    j := 0
jloop:	load	j	#    loop j from 1 to i-1
	add	one	#
	store	j	#      j := j+1
	load	i	#
	sub	j	#
	jumpz	jdone	#      if (i==j) goto jdone
	load	zero	#
	store	k	#      k := 0
kloop:	load	k	#      loop k from 1 to i-1
	add	one	#
	store	k	#        k := k+1
	sub	i	#
	jumpz	jloop	#        if (k==i) goto jloop
	load	j	#
	mul	k	#
	store	prod	#        product := j*k
	sub	i	#        // if j*k==i then i is not prime
	jumpz	iloop	#        if (product==i) goto iloop  // skip to next i
	jumpn	kloop	#        if (product<i)  goto kloop  // keep looping k
			#        // k exceeds i/j, so skip to next j
	jump	jloop	#        goto jloop
	#
	# If we reach here, then i is a prime number.  The only purpose
	# of the code below is to convert i from binary into decimal so
	# that the LED display can be understood by human observers.
	#
jdone:	load	zero	#  'outnum' will hold the binary-coded decimal result
	store	outnum	#  outnum := 0
	load	i	#
	store	remain	#  remainder := i
	sub	d10000	#
	jumpn	thsnds	#  jump out of entire i loop if i too big to display
	jump	done	#  if (i>10000) goto done
thsnds:	load	zero	#  initialize 1000's digit to 0
	store	hdigit	#  digit := 0
nx1000:	load	remain	#  loop over values for 1000's digit
	sub	d1000	#
	jumpn	hndrds	#    if (remainder<1000) goto hundreds
	store	remain	#    remainder := remainder-1000
	load	hdigit	#
	add	h1000	#
	store	hdigit	#    digit := digit+0x1000
	jump	nx1000	#    keep looping over values for 1000's digit
hndrds:	load	hdigit	#  add the 1000's digit to 'outnum' total
	add	outnum	#
	store	outnum	#  outnum := outnum+digit
	load	zero	#
	store	hdigit	#  digit := 0
nxt100:	load	remain	#  loop over values for 100's digit
	sub	d100	#
	jumpn	tens	#    if (remainder<100) goto tens
	store	remain	#    remainder := remainder-100
	load	hdigit	#
	add	h100	#
	store	hdigit	#    digit := digit+0x100
	jump	nxt100	#    keep looping over values for 100's digit
tens:	load	hdigit	#  add the 100's digit to 'outnum' total
	add	outnum	#
	store	outnum	#  outnum := outnum+digit
	load	zero	#
	store	hdigit	#  digit := 0
nxt10:	load	remain	#  loop over values for 10's digit
	sub	d10	#
	jumpn	ones	#    if (remainder<10) goto ones
	store	remain	#    remainder := remainder-10
	load	hdigit	#
	add	h10	#
	store	hdigit	#    digit := digit+0x10
	jump	nxt10	#    keep looping over values for 10's digit
ones:	load	hdigit	#  add the 10's digit to 'outnum' total
	add	outnum	#
	add	remain	#  now the remainder equals the ones digit
	store	outnum	#  outnum := outnum+digit+remainder
	out		#  copy 'outnum' to LED display
	#
	# This block is here to delay O(1 second) after displaying
	# each new prime number, so that (especially early in the
	# sequence, when the loop over factors goes quickly) the
	# observer has time to see each number display.
	#
	# Since the largest value we can hold in a register is 65535,
	# and we need about ten times longer delay than that, we make
	# a double loop using both j and k as loop counters.
	#
	load	zero	#
	sub	one	#
	store	j	#  j := 65535
jdelay:	load	j	#  loop j from 65535 downto 1
	sub	one	#
	store	j	#    j := j-1
	jumpz	iloop	#    if (j==0) goto iloop  // try next candididate i
	load	d10	#
	store	k	#    k := 10
kdelay:	load	k	#    loop k from 10 downto 1
	sub	one	#
	store	k	#    k := k-1
	jumpz	jdelay	#    if (k==0) goto jdelay // break out out to j loop
	jump	kdelay	#    keep looping over k values
done:	jump	start	#  go back and start counting again from i==2
zero:	.data	0	#  store the constant '0'
one:	.data	1	#  store the constant '1'
i:	.data	0	#  store the loop variable 'i' (prime number cand.)
j:	.data	0	#  store the loop variable 'j'
k:	.data	0	#  store the loop variable 'k'
prod:	.data	0	#  store the product 'prod' = j*k
outnum:	.data	0	#  compute/store binary-coded-decimal conversion of i
remain:	.data	0	#  store remainder used in BCD computation
hdigit:	.data	0	#  store hex value used to display one decimal digit
h1000:	.data	1000	#  store hexadecimal constant 0x1000
h100:	.data	100	#  store hexadecimal constant 0x100
h10:	.data	10	#  store hexadecimal constant 0x10
d10000:	.data	2710	#  store decimal constant 10000
d1000:	.data	3e8	#  store decimal constant 1000
d100:	.data	64	#  store decimal constant 100
d10:	.data	a	#  store decimal constant 10
Personal tools