/
/                        FIND-MAX
/
/       This is a simple demonstration  program for the
/ simul8 simulator.
/
/       The program is to read from input  a sequence
/ of numbers; it is to find the largest number in this sequence and
/ the number of items in the sequence. These values are then
/ to be printed 
/
/       The input should consist of a sequence of small positive
/ numbers (in decimal) separated by spaces and terminated by
/ a number 0
/
/       The program does not attempt to validate the input, check
/ for overflow or perform and other testing.
/
/ The program contains shift-add multiply and corresoponding divide
/ subroutines
/
*20
char,   0               / next character read or written
nchar,  0               / value as number if character was a digit
num,    0               / number being worked on
max,    0               / maximum found so far
items,  0               / count of numbers processed.
*160
mplr,   0               / multiplier
mpand,  0               / multiplicand
prod,   0               / single length product
temp,   0               / work space used by multiply routine
divsr,  0               / divisor
divdn,  0               / dividend
quot,   0               / quotient
rem,    0               / remainder
kd12,   14              / 12 decimal, the number of bits
kd10,   12              / 10 decimal
kd100,  144             / 100 decimal
kd1000, 1750            / 1000 decimal
cntr,   0               / used when looping as a counter
*200
start,  cla cll
	dca max
	dca items
/ main loop, get next character, echo it
loop,   jms i pget
	jms i pput1
/ test if it's a digit, if so then it starts a number and must read numeric
/ data, if not a digit --- then go back and collect next character input
	jms i pisdig
	jmp loop
	dca nchar
/       have a number, complete reading process
	jms readnm
/       is it zero, if so finished
	tad num
	sna
	jmp quit
/       is it maximum?
	cia
	tad max
	sma cla
	jmp upda                /no, seen bigger
/       yes, replace max
	tad num
	dca max
/       update count of items
upda,   isz items
	nop
/       loop back to get another number
	jmp loop
/       to quit, found the zero at end of input.
quit,   jms i pfinis
	hlt
pisdig, isdig
pfinis, finis
pput1, put
pget,   get
/ - - - - - - - - - - - - -
/       readnm:
/               entered when have read first digit
/               of a number
/               complete reading characters and combining them
/               in to form a number
readnm, 0
/ initialize number to value of digit character just read
	tad nchar
	dca num
/ now main loop of readnumber
lrdnm,  jms i pget      / get next character
	jms i pput1
	jms i pisdig    / is it a digit
	jmp i readnm     / no, so finished
	dca nchar       / yes, so save it
/       now need to multiply current number by 10 decimal
	tad num
	dca mpand
	tad kd10
	dca mplr
	jms i pmult
	tad prod
	tad nchar
	dca num
	jmp lrdnm
pmult,  mult
*400
/       Here we have a "shift and add" multiply routine.
/
/       Several simplifying assumptions:
/       1) its intended only for positive numbers (so not
/               going to worry about two's complement notation
/               for integers).
/       2) its intended only for small numbers (the product
/               of two 12-bit numbers can require 24-bits,
/               that would mean simulating a double length
/               register which is practical but tiresome,
/               so assume that will only be working with
/               small numbers  and that product will be
/               represented in 12-bits; no attempt made
/               to detect overflow).
/       3) note the crude way of passing the arguments (multiplier
/               and multiplicand) via page 0 locations.
mult,   0
	cla cll
/       first, set up a loop that will take us through the
/       12 (decimal) bits of the words to be multiplied.
	tad kd12
	cia
	dca cntr
	tad mpand
	dca temp
/       zero the product
	dca prod
lmult,  cla cll
/       isolate next bit of multiplier
	tad mplr
	rar
	dca mplr
/       test if a 1, for then need to add in another
/       partial product
	snl
	jmp mult1       / that bit was a zero, so ignore
	tad temp
	tad prod
	dca prod
/       to mult1, now  shift temp left as considering next power
/       of 2
mult1,  cla cll
	tad temp
	ral
	dca temp
/       check if have finished the loop
	isz cntr
	jmp lmult
emult,  jmp i mult
/
/       and here is a shift and subtract division routine,
/       much the same limitations as in the multiply
div,    0
	cla cll
	dca quot
	dca rem
	tad divdn
	dca temp
	tad kd12
	cia
	dca cntr
ldiv,   cla cll
/       move next bit into rem
	tad temp
	ral
	dca temp
	tad rem
	ral
	dca rem
/       do subtraction,
	tad divsr
	cia
	tad rem
/       if result -ve, dont't set bit in quotient
	spa
	jmp div1
	dca rem
/       set a 1 in link
	cll cml
	jmp div2
/       set a 0 in link
div1,   cla cll
/       now move bit into quotient
div2,   tad quot
	ral
	dca quot
	cla cll
/       check if have finished loop
	isz cntr
	jmp ldiv
ediv,   jmp i div
*600
/       Basic flag-driven i/o
/
/       get: read character from keyboard (normal wait for key stroke)
/               and store in "char"
get,    0
	cla cll
lget,   ksf
	jmp lget
	krb
	dca char
	jmp i get
/       put: print character held in "char"
/               (send the character, wait till notified that it got off
/               safely)
put,    0
	cla cll
	tad char
	tls
lput,   tsf
	jmp lput
	cla cll
	jmp i put
/
/
/       msg: print a message,
/               on entry, acc should contain address of where
/               some characters forming message are stored
/               characters should be stored one per word
/               and terminated by a word containing zero.
msg,    0
	dca mptr
lmsg,   tad i mptr
	sna
	jmp i msg
	dca char
	jms put
	isz mptr
	nop
	jmp lmsg
mptr,    0
/
/
/       isdig:
/               check on character in "char"
/               is it a digit, (i.e. >= '0', <='9'),
/               if so return its numeric value in acc
/                       and MODIFY RETURN address
/
/       so, will be returning to address immediately
/               following call if its not a digit (and acc will be zero)
/           but returning to address subsequent to that if it
/               is a digit
/
isdig,  0
	cla cll
	tad zero
	cia
	tad char
	spa cla
	jmp i isdig             / its less than zero character
	tad char
	cia
	tad nine
	spa cla
	jmp i isdig
/       its a digit as in correct range of character values
/       convert from character form to numeric
	tad zero
	cia
	tad char
	isz isdig
	nop
	jmp i isdig
zero,   60              / value representing '0'
nine,   71              / value representing '9'
*1000
/       finis:
/               end marker in input encountered
/
/               put some newlines after the echoed input
/               print message "# read : "
/               then print item-count
/               then print message representing couple of newlines
/               then print "Largest : "
/               print max
/               print newlines
finis,  0
	tad amsg2
	jms i pmsg
	tad amsg1
	jms i pmsg
/       now print count
	tad items
	jms i pprnum
	tad amsg2
	jms i pmsg
	tad amsg3
	jms i pmsg
/       largest value
	tad max
	jms i pprnum
	tad amsg2
	jms i pmsg
	jmp i finis
pprnum, prnum
pmsg,   msg
amsg1,  msg1
amsg2,  msg2
amsg3,  msg3
msg1,   43              / #
	40              / space
	162             / r
	145             / e
	141             / a
	144             / d
	40
	40
	72              / :
	40
	0
msg2,   15
	15
	12
	0
msg3,   114             / L
	141             / a
	162             / r
	147             / g
	145             / e
	163             / s
	164             / t
	40
	72
	40
	0
*1200
/       An oversimplified number printing routine
/
/       Its a bit specific to this problem,
/       numbers can be assumed to be smallish positive
/       values.
/
/       will divide by 1000 (decimal) and convert quotient
/       to character representing number of thousands
/
/       take remainder, divide by 100 (decimal) print result
/
/       and so forth,
/
/
prnum,  0
	dca divdn
  dca chflag
/ do the divides by 1000
	tad kd1000
	dca divsr
	jms i pdiv
/ look at result, if zero don't want to print anything
	tad quot
	sna
	jmp prn1  
/ but if have a thousands digit, then convert value to character form
/ and print
	tad przero
	dca char
	jms i pput
/ and note that we have printed some characters
  isz chflag
  nop
/
/ now deal with the hundreds
prn1,   tad rem
	dca divdn
	tad kd100
	dca divsr
	jms i pdiv
/ again do we have a hundreds digit, or have we already printed a
/ thousands digit
/ if we've already printed a thousands digit, best print hundreds digit
/ even if its a zero
  tad chflag
  sza cla
  jmp prn1c 
/ if no characters printed so far, again check to see if this is a zero
/ in which case will omit
	tad quot
	sna cla
	jmp prn2
/ prn1c, convert hundreds digit to character form and print
prn1c,	tad quot
  tad przero
	dca char
	jms i pput
  isz chflag
  nop
/ deal with tens in like manner
prn2,   tad rem
	dca divdn
	tad kd10
	dca divsr
	jms i pdiv
/ usual checks regarding printing of leading zeros
  tad chflag
  sza cla
  jmp prn2c
	tad quot
	sna cla
	jmp prn3
prn2c,	tad quot
  tad przero
	dca char
	jms i pput
prn3,   tad rem
	tad przero
	dca char
	jms i pput
	jmp i prnum
pput,  put
pdiv,   div
przero, 60
chflag,0
$


