[Featured][Beta] API - Why hasn't this been done yet?!

Here you can find side projects of the staff and great projects which we think should get extra support. (Note that featured projects are not projects by staff members of MaxCoderz)

Moderator: MaxCoderz Staff

User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Jim e wrote:Well beyond asking ben to make a SUPER intelligent way of handleing macros...
The issue is more backwards compatibility with TASM than me adding new features to Brass, sadly.
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

Yup, that's something I'm afraid we'll have to live with... Unless someone has a remarkably brilliant idea, I don't think we can simplify this any more than I already did...
Jim e wrote:I wrote most of an interrupt routines like mirageos's that can handle several things, i try to post later today, after I fully test it.
Very nice, thanks :)
And a good idea to add ionRandom by the way. I think I should add all Ion's routines, so you don't need to rely on Ion for them anymore.
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

I have a proposition, which will hopefully retain TASM backwards compatibility and fix a few "lossy algorithm" problems.
Rather than hack in ugly extra directives to switch on/off an optimiser, why not do something like this?

Code: Select all

; Assume a function called 'square_root', which takes acc. as the argument:

#define square_root(value) ld a,value \ call square_root
#ifdef Brass
.define square_root({a}) call square_root
#endif
I use .define (rather than #define) on the Brass defines to make it clearer that they are Brass directives, and also so that TASM users won't accidentally try and use them (it'll throw an error when it hits the .define). Of course, this can be extended:

Code: Select all

; put_s_fixed will display a string: hl->string, b=length

#define draw_string(string, length) ld b,length \ ld hl,string \ call put_s_fixed
#ifdef Brass
.define draw_string({hl}, {b}) call put_s_fixed
.define draw_string(string, {b}) ld hl,string \ call put_s_fixed
.define draw_string({hl}, length) ld b,length \ call put_s_fixed
#endif
TASM users still can get full use of the API, but can suffer redundant code. Brass users can add a ".define Brass" and take advantage of a slightly less brain-dead macro preprocesser.

Apologies for yet another ugly use of curly braces, but as they've been used in other places to force a particular meaning ({-} is the closest label -: behind the current instruction pointer, not subtract, and {*} is the current byte, not the multipication operator).

Brass's macro preprocessor needs a rewrite in any case (slow and hacky), and it's quite a large change - not to mention the run up to Christmas, that I shall be away in the New Year, and that work is keeping me busy away from work as well as at is, so I wouldn't expect a shiny new Brass build until some time in mid-January, sorry.

Brass won't try to do anything special with the thing in curlies other than a basic argument check, so you could also do things like this:

Code: Select all

load(reg, value) ld reg,value
load({a},{0}) xor a
load({a},{a})
load({de},{hl}) ld d,h \ ld e,l
compare(value) cp value
compare({0}) or a
(Bad examples, but that's the sort of thing that I hope that could be done).

Food for thought?
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

Hey, that's a pretty cool idea. Would using macro's withing macro definitions be possible with TASM? Then we could do something like:

Code: Select all

#ifdef brass
   .define load(reg,{reg}) ; makes sure value gets in a if it isn't already
   ; Add your exceptions for double registers / ld a,0 / ld a,a etc..
#else
   #define load(reg,value) ld reg,value
#endif

#define square_root(value) load(a,value) \ call square_root
That would keep the code readable for API users.

You have to explain to me what the curly braces will do exactely though. If I have a macro like load({a},{0}), and I supply it with another register than a for it's first argument, it will load the contents of that register in a? And if I supply some other value than 0 for it's second argument the macro will not be parsed, so it can be taken care of by another macro?

TASM doesn't support having different macro's with the same name and different variables, unfortunately. It would be cool if we could use Brass in this way to provide users with extra functionality (like making it possible to call home.print(>string), or home.print("string"), or home.print(>string,%pos), or home.print("string %d",#value) :excited:). That would also be good advertising for Brass and Latenite ;)

Edit: Sorry, I didn't read careful enough. Curlies do a basic argument check you say, so it would be

Code: Select all

#ifdef brass

   .define load({a},{0}) xor a
   .define load({a},{a})
   .define load({a},value) ld a,value
   .define load({b},{b})
   .define load({b},value) ld b,value
   .define load({c},{c})
   .define load({c},value) ld c,value
   .define load({h},{h})
   .define load({h},value) ld h,value
   .define load({l},{l})
   .define load({l},value) ld l,value
   .define load({d},{d})
   .define load({d},value) ld d,value
   .define load({e},{e})
   .define load({e},value) ld e,value
   .define load({hl},{hl})
   .define load({hl},{de}) ld h,d \ ld l,e
   .define load({hl},{bc}) ld h,b \ ld l,c
   ... etc

#else
   #define load(reg,value) ld reg,value
#endif
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Timendus wrote:Hey, that's a pretty cool idea. Would using macro's withing macro definitions be possible with TASM? Then we could do something like:

Code: Select all

#ifdef brass
   .define load(reg,{reg}) ; makes sure value gets in a if it isn't already
   ; Add your exceptions for double registers / ld a,0 / ld a,a etc..
#else
   #define load(reg,value) ld reg,value
#endif

#define square_root(value) load(a,value) \ call square_root
That would keep the code readable for API users.
Not sure. Brass is, but doesn't support backwards referencing on macros (so load() would have to have been defined before square_root()).
You have to explain to me what the curly braces will do exactely though. If I have a macro like load({a},{0}), and I supply it with another register than a for it's first argument, it will load the contents of that register in a? And if I supply some other value than 0 for it's second argument the macro will not be parsed, so it can be taken care of by another macro?
Brass would do some matching between the different macros and try and find the most specific one it can use. Hence in my examples I don't use an #else block, I always use the TASM macro as the most generic macro definition to fall back on if none of the special cases are matched.

Code: Select all

.define load(reg,{reg}) ; makes sure value gets in a if it isn't already
This would not work, as this macro would only be defined if someone used

Code: Select all

    load (*,reg)
...where * could be anything.

The thing in curlies is a way to catch specific cases.
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

benryves wrote:Not sure. Brass is, but doesn't support backwards referencing on macros (so load() would have to have been defined before square_root()).
Brass would do some matching between the different macros and try and find the most specific one it can use. Hence in my examples I don't use an #else block, I always use the TASM macro as the most generic macro definition to fall back on if none of the special cases are matched.
Okay, those are two things I'll have to test. If I recall correctly TASM will use the first macro with a certain name, and ignore the rest, but I'm not sure about that. If so, we wouldn't even need to #define brass. TASM would use the first macro, and Brass would have more specific macro's that handle optimization cases.

It's so useful to have our own compiler programmer :P I'm glad you decided to write your own assembler, Ben :)
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Timendus wrote:It's so useful to have our own compiler programmer :P I'm glad you decided to write your own assembler, Ben :)
As I said, sorry, this'll take a while to be implemented. :( I'm really busy at the moment...
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

benryves wrote:As I said, sorry, this'll take a while to be implemented. :( I'm really busy at the moment...
Don't worry, that's no problem. I'm really busy myself, so testing this and preparing for the Brass adaption if it turns out to be possible will take quite some time too. And I still haven't added everthing I want to add, I haven't fixed the potential greyscale bug yet, my own thingy is still far from finished... :(
And I think Latenite should have a higher priority ;)
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Timendus wrote:And I think Latenite should have a higher priority ;)
I do have a more up-to-date build as it is, but it's got more bugs than the current release that I haven't got around to fixing (it's got to the "huge, messy, difficult to maintain" stage in places, so a lot of work has just been in invisible refactoring changes). *sighs*
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

Ah yes, that sucks... I know the feeling :(

To get back on topic: I'm going to give this project an even lower priority for a few weeks, because I have exams coming up, and I have to work on a website that's due in januari. Next to that, I will be celebrating Christmas and new years eve with family and friends, which always takes up a lot of time.

So I plan to give you all some time to add your routines now, so that we'll have a nice large API when I upload a stable version to Ticalc.org in about a month.

Lots of thanks to everybody who already added (both ideas, support and code) to this project! I hope you'll all keep up the good work, and spread the word! ;)
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

Wow, it works! It actually works! Ben you rock! And TASM doesn't even complain about the curlies! (As long as you use #define instead of .define)

Here's the set of load macro's that I wrote this weekend (it's quite a long list :)), I hope some of you will take a look at them and run a few tests so I can be sure it works properly with both TASM and Brass (make sure you get the latest version!) before I add it to the API. And please see if I didn't forget any.

Code: Select all

; ***
; [routine]load(reg,val)[/routine]
;
; Loads a value or a register <i>val</i> in register <i>reg</i>.
;
; <i>It is recommended that (within this API) this macro is only used in other macro definitions where the input is variable, not in API routines! The API should stay compatible with TASM as much as possible!</i>
; 
; In TASM, this macro will just compile to
;  <kbd>ld reg,val</kdb>
; but when compiled with Brass, exceptions will assure that things like these work too:
;  <kdb>load(bc,a)
;  load(hl,ix)
;  load(ix,iyh)</kbd>
; and that things like these will be optimized:
;  <kbd>load(h,h)   compiles to nothing
;  load(a,0)   compiles to xor a</kbd>
; 
; <b>Note:</b> In some special cases like these:
;  <kbd>load(h,ixh)
;  load(iy,hl)</kdb>
; the neccessary exception macro's will use register <i>a</i> or the stack as a temporary storage.
;
; Written by:
;  Timendus
;

	;****************************************
	; TASM/default define

#define load(reg,val) ld reg,val

	;****************************************
	; Exceptions for single registers

#define load({a},{0}) xor a

#define load({a},{a})
#define load({b},{b})
#define load({c},{c})
#define load({d},{d})
#define load({e},{e})
#define load({h},{h})
#define load({l},{l})
#define load({ixh},{ixh})
#define load({ixl},{ixl})
#define load({iyh},{iyh})
#define load({iyl},{iyl})

#define load({h},{ixh}) ld a,ixh \ ld h,a
#define load({h},{ixl}) ld a,ixl \ ld h,a
#define load({h},{iyh}) ld a,iyh \ ld h,a
#define load({h},{iyl}) ld a,iyl \ ld h,a

#define load({l},{ixh}) ld a,ixh \ ld l,a
#define load({l},{ixl}) ld a,ixl \ ld l,a
#define load({l},{iyh}) ld a,iyh \ ld l,a
#define load({l},{iyl}) ld a,iyl \ ld l,a

#define load({ixh},{h}) ld a,h \ ld ixh,a
#define load({ixh},{l}) ld a,l \ ld ixh,a
#define load({ixl},{h}) ld a,h \ ld ixl,a
#define load({ixl},{l}) ld a,l \ ld ixl,a

#define load({iyh},{h}) ld a,h \ ld iyh,a
#define load({iyh},{l}) ld a,l \ ld iyh,a
#define load({iyl},{h}) ld a,h \ ld iyl,a
#define load({iyl},{l}) ld a,l \ ld iyl,a

	;****************************************
	; Exceptions for HL

#define load({hl},{hl})

#define load({hl},{a}) ld h,0 \ ld l,a
#define load({hl},{b}) ld h,0 \ ld l,b
#define load({hl},{c}) ld h,0 \ ld l,c
#define load({hl},{d}) ld h,0 \ ld l,d
#define load({hl},{e}) ld h,0 \ ld l,e
#define load({hl},{h}) ld l,h \ ld h,0
#define load({hl},{l}) ld h,0
#define load({hl},{ixh}) load(hl,ix) \ ld l,h \ ld h,0
#define load({hl},{ixl}) load(hl,ix) \ ld h,0
#define load({hl},{iyh}) load(hl,iy) \ ld l,h \ ld h,0
#define load({hl},{iyl}) load(hl,iy) \ ld h,0

#define load({hl},{de}) ld h,d \ ld l,e
#define load({hl},{bc}) ld h,b \ ld l,c
#define load({hl},{ix}) push ix \ pop hl
#define load({hl},{iy}) push iy \ pop hl

	;****************************************
	; Exceptions for DE

#define load({de},{de})

#define load({de},{a}) ld d,0 \ ld e,a
#define load({de},{b}) ld d,0 \ ld e,b
#define load({de},{c}) ld d,0 \ ld e,c
#define load({de},{d}) ld e,d \ ld d,0
#define load({de},{e}) ld d,0
#define load({de},{h}) ld d,0 \ ld e,h
#define load({de},{l}) ld d,0 \ ld e,l
#define load({de},{ixh}) ld d,0 \ ld e,ixh
#define load({de},{ixl}) ld d,0 \ ld e,ixl
#define load({de},{iyh}) ld d,0 \ ld e,iyh
#define load({de},{iyl}) ld d,0 \ ld e,iyl

#define load({de},{hl}) ld d,h \ ld e,l
#define load({de},{bc}) ld d,b \ ld e,c
#define load({de},{ix}) ld d,ixh \ ld e,ixl
#define load({de},{iy}) ld d,iyh \ ld e,iyl

	;****************************************
	; Exceptions for BC

#define load({bc},{bc})

#define load({bc},{a}) ld b,0 \ ld c,a
#define load({bc},{b}) ld c,b \ ld b,0
#define load({bc},{c}) ld b,0
#define load({bc},{d}) ld b,0 \ ld c,d
#define load({bc},{e}) ld b,0 \ ld c,e
#define load({bc},{h}) ld b,0 \ ld c,h
#define load({bc},{l}) ld b,0 \ ld c,l
#define load({bc},{ixh}) ld b,0 \ ld c,ixh
#define load({bc},{ixl}) ld b,0 \ ld c,ixl
#define load({bc},{iyh}) ld b,0 \ ld c,iyh
#define load({bc},{iyl}) ld b,0 \ ld c,iyl

#define load({bc},{hl}) ld b,h \ ld c,l
#define load({bc},{de}) ld b,d \ ld c,e
#define load({bc},{ix}) ld b,ixh \ ld c,ixl
#define load({bc},{iy}) ld b,iyh \ ld c,iyl

	;****************************************
	; Exceptions for IX

#define load({ix},{ix})

#define load({ix},{a}) ld ixh,0 \ ld ixl,a
#define load({ix},{b}) ld ixh,0 \ ld ixl,b
#define load({ix},{c}) ld ixh,0 \ ld ixl,c
#define load({ix},{d}) ld ixh,0 \ ld ixl,d
#define load({ix},{e}) ld ixh,0 \ ld ixl,e
#define load({ix},{ixh}) ld ixl,ixh \ ld ixh,0
#define load({ix},{ixl}) ld ixh,0
#define load({ix},{iyh}) load(ix,iy) \ load(ix,ixh)
#define load({ix},{iyl}) load(ix,iy) \ load(ix,ixl)

#define load({ix},{hl}) push hl \ pop ix
#define load({ix},{de}) ld ixh,d \ ld ixl,e
#define load({ix},{bc}) ld ixh,b \ ld ixl,c
#define load({ix},{iy}) push iy \ pop ix

	;****************************************
	; Exceptions for IY

#define load({iy},{iy})

#define load({iy},{a}) ld iyh,0 \ ld iyl,a
#define load({iy},{b}) ld iyh,0 \ ld iyl,b
#define load({iy},{c}) ld iyh,0 \ ld iyl,c
#define load({iy},{d}) ld iyh,0 \ ld iyl,d
#define load({iy},{e}) ld iyh,0 \ ld iyl,e
#define load({iy},{ixh}) load(iy,ix) \ load(iy,iyh)
#define load({iy},{ixl}) load(iy,ix) \ load(iy,iyl)
#define load({iy},{iyh}) ld iyl,iyh \ ld iyh,0
#define load({iy},{iyl}) ld iyh,0

#define load({iy},{hl}) push hl \ pop iy
#define load({iy},{de}) ld iyh,d \ ld iyl,e
#define load({iy},{bc}) ld iyh,b \ ld iyl,c
#define load({iy},{ix}) push ix \ pop iy

	;****************************************
	;****************************************
The ones that look like this are my absolute favourites :mrgreen::
#define load({ix},{iyh}) load(ix,iy) \ load(ix,ixh)

This is what I tested them with:

Code: Select all

#define sqrt(var) load(a,var)
#defcont \ call sqr_root

.org 0

start:

	; Some examples of macro in macro definition use:
	
	sqrt(10)	; compiles to ld a,10 \ call sqr_root in Brass
	sqrt(a)		; compiles to call sqr_root in Brass
	sqrt(0)		; compiles to xor a \ call sqr_root in Brass
	sqrt(b)		; compiles to ld a,b \ call sqr_root in Brass
	
	; These give errors in TASM, not in Brass:
	
	load(hl,ix)
	load(bc,a)
	
	; These are unoptimized in TASM, not in Brass:
	
	load(c,c)
	load(a,0)
	
sqr_root:
	ret
	
stop:

.echo "*** Binary size: "
.echo stop-start
.echo " bytes\n"
	
.end
(I never tried to run it, just compiled and looked at the lst files)
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
NanoWar
Extreme Poster
Posts: 365
Joined: Fri 17 Dec, 2004 6:39 pm
Location: #$&"%§!
Contact:

Post by NanoWar »

Wow Tim, that looks promising.
You are really the only one that would write all the stuff down and make a GIANT include file ;)
Keep up the good work!
Revolution Software
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

Thanks Robert :mrgreen:
I see you added a routine, nice going! I'm in doubt in what section it belongs though.. :)
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

You should also add that loading 0 to a will destroy your flags.
DarkerLine
Calc Wizard
Posts: 526
Joined: Tue 08 Mar, 2005 1:37 am
Location: who wants to know?
Contact:

Post by DarkerLine »

You wouldn't normally use that by itself though, but rather in a macro such as sqrt(a) (or sqrt(0) ). In that case, flags are going to be destroyed many times over anyway.
just try to be nice to people.
_________________
My TI Blog - http://mpl.unitedti.org/
Post Reply