Dynamo 3.1 changes:

I have been busy changing things for no reason at all, and here's where I stand:
(This is a joke.  I had reasons.  I just can't remember what they were.)
((This is a joke.))


1)	BUILDAPP.SYSTEM has changed.  The new build script sample looks like this:

DUMMY							;The default script filename.
0,$0800,SAMPLE.BIN				;Sample app, segment 1 (on server).
0,$8000,SAMPLE.BIN.2			;Sample app, segment 2 (on server).
0,$9000,SAMPLE.BIN.3			;Sample app, segment 3 (on server).
$80,$800						;Starting address.
$								;Display starting address in hex.
$								;Display application size in hex.
N								;Skip save file prompt (and don't save it).
$FF,0,SAMPLE.SYSTEM				;Target filename, filetype, and auxtype.

The difference is the 8th line.  This is new.  You don't have to be prompted from
the keyboard anymore.  You can put a Y,N, or Q here instead of typing it.  If you
don't put one of these letters (lowercase is okay, too), then you will be prompted
from the keyboard.  As a convention, I recommend a ? if you want to be prompted.


2)	The runtime and macros have been revised a few times lately.  One of these
	changes was to optimize _decout, _add, _sub, _mul, _div, _set, _index,
	_getb, _getw, _putb, and _putw.  This was a bad idea, since it makes it
	even more difficult to do Dynamo versions for other assemblers and keep
	them as compatible as possible.  This feature in the MPW version caused
	a greater leel of incompatibility, so I have removed it.  There is a
	benefit that remained.  There were some entry points added for the array
	indexing and accessing routines for the optimizations.  These entry points
	are still there.  Given that _index, _getb, _getw, _putb, and _putw are no
	longer figuring out which entry point to call, there have been some macros
	added.  These are (logically enough) _indexl, _getbl, _getwl, _putbl, and
	_putwl.  These don't load a 2-byte constant into the accumulator and
	y-register.  Rather, they load a one byte value into the accumulator and
	then call the alternate entry point (which loads the accumulator with 0
	and branches to the regular entry point).  If you have a constant in the
	range 0-255, as an optional syntax, you can still call _getb, _getw, _putb,
	and _putw, as long as you put a < in the constant parameter to indicate it
	is a 1-byte value.  For _index, this is the ONLY way to just load the
	accumulator and call the alternate entry point.  There is no _indexl
	macro.  The reason for this is that you can have multiple indexes for
	one instance of _index, so each parameter needs to demonstrate if it is
	a 1-byte or 2-byte value.  Some syntax examples would be:
		_index		#345,,<#3
		_getw		var1,<#3

	A constant parameter can now take these following forms and it produces
	the following code:
		1)	= #constant
				lda #<constant
				ldy #>constant
		2)	= *address
				lda address
				ldy address+1
		3)	= #<constant
				lda #<constant
		4)	= *<address
				lda address

	As a sample we want to calculate the number of bytes necessary to store a
	rectangle of data on the screen.  We have a rectangle stored at $4000, in
	the form x1,y1,x2,y2.  The x-values take two bytes (0-280), and the y-values
	take 1 byte (0-192).  How many bytes do this take?
		First, we calculate which row we are starting in.

		The formula is:  bytes = (int((x2 + 6) / 7) - int(x1 / 7) * (y2 - y1)
		The macros to do this formula would look like:

			rect	equ		$4000
			x1		equ		0
			y1		equ		2
			x2		equ		3
			y2		equ		5

	1)				_set	temp,*rect+x1		;temp = x1
	2)				_div	,#<7				;temp = int(x1 / 7)
	3)				_set	bytes,*rect+x2		;bytes = x2
	4)				_add	,#<6				;temp = x2 + 6
	5)				_div	,#<7				;bytes = int((x2 + 6) / 7)
	6)				_subvar	,temp				;bytes = bytes - temp
												;We now have # of bytes wide (in bytes).
	7)				_set	temp,*<rect+y2		;temp = y2
	8)				_sub	,*<rect+y1			;temp = y2 - y1
	9)				_mul	bytes,temp			;bytes = bytes * temp

		The code for these macros would look like:
	1)				ldx		#temp
					lda		rect+x1
					ldy		rect+x1+1
					jsr		setcon				;Set temp to a 2-byte value.

	2)				lda		#<7
					jsr		divconl				;Divide temp by a 1-byte constant.

	3)				ldx		#bytes
					lda		rect+x2
					ldy		rect+x2+1
					jsr		setcon				;Set bytes to a 2-byte value.

	4)				lda		#<6
					jsr		addconl				;Add a 1-byte constant to bytes.

	5)				lda		#<7
					jsr		divconl				;Divide bytes by a 1-byte constant.

	6)				ldy		#temp
					jsr		subvar				;Subtract temp from bytes.

	7)				ldx		#temp
					lda		rect+y2
					jsr		setconl				;Set temp to a 1-byte value.

	8)				lda		rect+y1
					jsr		subconl				;Subtract a 1-byte value from temp.

	9)				ldx		#bytes
					ldy		#temp
					jsr		mulvar				;bytes = bytes * temp

		Since the y-values are only 1 byte, it is less code to write steps 7-9 like this:
					lda		rect+y2
					sec
					sbc		rect+y1
					_mull
		Note that bytes didn't have to be redeclared for the multiply.  It is still
		around from step 3.  (Steps 4 thru 6 start with a comma, thus leaving the
		x-register alone.)  Also note that we said _mull, NOT _mul.  Since we are
		not stating what we are multiplying by, we aren't telling the macros how
		big the value is.  Since it doesn't know, it has to assume we know what we
		are doing.  If we said _mul, it would assume that we wanted to multiply by
		a 2-byte value, and the y-register would hold the hi-byte.  That isn't what
		we want in this case.  We want to multiply by a 1-byte value, so we have to
		use the _mull macro instead.  This needs to be watched carefully!! 

		So, we used the macros when it helped (readability and/or code size) and wrote
		regular assembly code when it was easy and smaller.  The best of both worlds!!


3)	Another runtime change that stayed in is a value called strvalcount.  This
	value is calculated by _strval and _midstrval.  strvalcount is the number
	of characters involved in the evaluation of the string value.  Some examples:

		_strval of:  -$100FG							returns -4111 (or 61425) 
														and sets strvalcount to 6.

		_midstrval(from char 4) of:  ------345.6789		returns 345 (two minuses
														cancel each other out) and
														sets strvalcount to 5.

	This addition is very useful when parsing a string.  If you pull an integer
	value from a string, you may want to know how many characters the runtime
	routine used.  If this value wasn't set, you would have to know all of the
	rules that the runtime used to evaluate the integer and walk through the
	string again yourself.  This is wasteful, and also can be a problem if the
	evaluation method is ever changed.  If that occured, you would have to change
	code in more than one place.  strvalcount is not returned in any register.
	The registers are all used already.  Also, you commonly don't care about this
	value.  (When you do care, you need it badly.)  strvalcount is simply a byte
	value that you have external access to.  If you want it, just load it.


4)	Another _strval or _midstrval calculated value is strvaldigit.  This tells
	you if the string evaluation routine actually found any digits.  When you
	are returned a value of 0, you don't know if this was because there was a
	value of 0 (or -$0000 for that matter), or because the routine ran into a
	non-integer character before it could find any characters to evaluate.  The
	strvaldigit value tells you which occured.  It holds the number of digit
	characters encountered.  (If strvaldigit is 0, then the integer result must
	also be 0.)  Note that strvalcount can be greater than 0 even if strvaldigit
	is 0.  This would occur in the string: -$G  In this case strvalcount would be
	2 (the - and the $) and strvaldigit would be 0 (there were no legal digits).


5)	Another change (kind of big, kind of small) is how the variable space is
	defined.  It used to be that varstart was equated in app.config.  If it
	changed, the runtime has to be reassembled and turned into a library again.
	This has been leading to errors that are time consuming to trace.  Instead,
	what is being done is to let the linker worry about it.  There now needs to
	be a varspace space (256 bytes) for the linker to link in.  Once this is
	done, varspace can be kept, or you can use LinkIIGS and MakeBigIIGS to throw
	it away.  The runtime doesn't demand that varspace be part of your program.
	All it cares about is that there are 256 bytes somewhere in memory that it
	will access.  So, it isn't necessary that the application carry these 256
	bytes around.  (Save disk space -- just say no!!)  It is necessary to have
	something for the linker to work with, however.  So, the sample application
	now has an additional segment called varspace.  It is thrown away in this
	example.  This is done by linking it into a separate segment that we don't
	care about.  Check out the make file for exactly how this is done.
	It is worth noting that if you wish to move where the 256-byte varspace
	area is, all you need to do is change the makefile.  Just change the -org
	value for the segment "trash".

6)	More support for indirection and dereferencing has been added.  There are now
	an additional macro for dereferencing, as well as syntax extensions to handle
	multi-level-dereferencing in conjunction with other macros.  Here is some code
	from sample.a that demonstrates the extent of the indirection capabilities:

		_set	var1,**@ptr1		;Set var1 to double-dereferenced @ptr1.
									;var1 has address @ptr3 now.
		_add	,#<2				;Add 2 to the pointer.
		_vderef						;Dereference var1 again (into itself).
									;var1 has address @ptr4 now.
		_vderef						;Dereference var1 again (into itself).
									;var1 has address @ptr5 now.
		_vderef						;Dereference var1 again (into itself).
									;var1 has value from @ptr5 now.
		_vhexout					;Output the variable value (which is $1234)
		jmp		@past

@ptr1		dc.w	@ptr2
@ptr2		dc.w	@ptr3
@ptr3		dc.w	0,@ptr4
@ptr4		dc.w	@ptr5
@ptr5		dc.w	$1234

@past		equ		*




Well, this ought to be enough arbitrary changes for version 3.1 -- have fun.



Eric Soldan, Apple II DTS
