NanoWar wrote:It's always good to know the problems of a programming language and what you really hate about it. Then you can try to change that.

What I dislike about ASM is the register poverty. I really want to abtract these away. And the nonexistence of function parameters (or lack of methods of documentation/discovery) annoys me.

HASM should introduce functions and implement register spilling.

We can make this a collaborative project on github since we now have an organization on github.What I'm thinking right now is very much a C-like language, but I'm very unsure.Some constructions just don't feel necessary/relevant that are in C, so it's likely to be a Bare-Minimum-C if anything like C at all..What do we want and/or need?

Functions

Register Spilling

Macros

Speed/Size Optimizations

Good code readability

With more to come.

I guess we'll need to consider a lot/few more things before we start working on HASM, like what language we are implementing this in, cross-compilation, libraries and so forth.

Last edited by add on 09 November 2017, 13:26, edited 1 time in total.

I'll leave this to you all, C makes my head spin... I agree though on the register poverty. You really do need to use the shadows more. exx and ex af,af' only take up 4 t-states and give you a whole new set of registers to work with. Still, working with ARM and other processors is like a dream with all the registers (and easy manipulation of the stack). I do wish the z80 had more registers, but it really wouldn't fit in the instruction set, at least not without adding more 2-byte/prefixed instructions which wouldn't make them as fast.

chickendude wrote:I'll leave this to you all, C makes my head spin... I agree though on the register poverty. You really do need to use the shadows more. exx and ex af,af' only take up 4 t-states and give you a whole new set of registers to work with. Still, working with ARM and other processors is like a dream with all the registers (and easy manipulation of the stack). I do wish the z80 had more registers, but it really wouldn't fit in the instruction set, at least not without adding more 2-byte/prefixed instructions which wouldn't make them as fast.

I didn't mean that it was going to be a C clone language, that'd be boring, and also probably done already.No, a layer of convenience for programming is the goal, I think we will need your input also chickendude.

Well i think you can really use the Funk Library as a starting point. There was also EZAsm which had some cool stuff, too. I helped Joel out with some of the (simpler) assembly routines back in the day. We used to talk on AIM

*Sigh*, never ask friends for advice regarding languages that advertise themselves as a "C/C++ replacement".I guess I'm sticking to C for now, and probably forever if this keeps up.Why can't a good system programming language be made...I highly doubt I'd make a good programming language designer..

Your add offset could probably be optimized a bit for speed with an actual multiplication routine (base += width*Y), at least if your offset will generally be more than about 15 or so. The delay would also be more consistent How would you return 2 bytes from that area? Eg. if you had a table of pointers to strings. "return *base+*(base+1)<<8?" that seems harder to optimize into a ld a,(hl) \ inc hl \ ld h,(hl) \ ld l,a.

chickendude wrote:How would you return 2 bytes from that area? Eg. if you had a table of pointers to strings. "return *base+*(base+1)<<8?" that seems harder to optimize into a ld a,(hl) \ inc hl \ ld h,(hl) \ ld l,a.

In SPASM I have ld hl, (hl) for that. But I guess you would just change the return register from a to hl.

I haven't tested these and i haven't touched asm in a bit (everything's been in annoying C the past couple months ), but here's my take on these, though i can't really think of a situation where i would actually want to do any of these :hl = [bc] + hl + [de] + [hl]

Does your code for "de = *hl - a + bc" work? it looks like you just pop the original values hl and de back. For "de = 0x4000 + *hl + *hl", you can move the load to de (ld de,$4000) before the ld l,0 and load the zero from e, it'll save a byte and 3 t-states. And restoring registers will slow things down a bit, push/pops are pretty expensive...And i dunno if this'd work:

adda,6cp(hl);(hl) == a+6jrnz,skipsub6;offset the a+6, later we overwrite a anyway so we don't need to worry about restoring a if the if is falseinchladda,(hl)ldc,a;c = a + (hl+1)dechl;restore hl from the (hl+1) bit, acc gets overwritten so no need to restoreskip:lda,(de)adda,cadda,b;a = b + c + (de)

if (*hl == a + 6){c = a + *(hl+1); a is not a+6, but the value before the if}; byte comparison => save apushAF; Prepare longer statement: a+6addA, 6; Second statement is comparable without further ado; Comparecp(HL); Fork; Could be jr instead, maybe optimize later? but then _if1_end's address changes... how?jpnz, _if1_end; Is a needed in loop as statement? => yes => restore apopAF; byte addition => save apushAF; Load first parameter in a; ld a, a ; remove; Prepare bracket; >> register savepoint for hl (maybe add push/pop hl later)incHL; parameter is addable without using further registersadda, (hl); << restore savepoint; hl restoring is easier by undoing by dec for 1dechl; Move to targetldc, a; Clean stack (inside loop stack frame only) => done; a will be popped after loop; Check if there is an else clause, if so, jump to end of if => no else_if1_end; Clean stackpopAF

It takes the same amount of bytes, but using a register to back up a instead of the stack takes less than half as many t-states. Push/pop is 21 t-states, the register loads are only 4 each. But i guess again you'd have to know that a's value could get thrown away (ie. it's not used again).

And i believe that's the fastest way to do add a,(de). You could do something like ld a,c \ ld a,(de) \ add a,c, but that's not faster or smaller and wastes a register. I don't think it's that bad though, for example it's still faster than adding to an index register. I guess you generally just try to use HL when you can or use DE for multiple thing. I often use the shadows for that, though (eg. ld hl,tileMap \ ld de,(mapWidth) \ exx \ ld hl,gbuf \ ld de,WIDTH and pass data through a).

If you could variably name registers for different usages, what syntax would you use?

I like let/var/def name:type = value with valuebeing always optional and type being optional for var and def.

Examples:let number:a = 6 will just do ld a, 6 but also do a registration for a as variable named "number". This will later be used for references and in the SSA-form.var OLD_PEN:System::Pen being a ram variable at a free saferam point depending on earlier vars with type Pen which is 2 bytes => .var OLD_PEN, 2 (funk syntax).def MAX_ITEMS = 50 => #define MAX_ITEMS 50

mod System{ struct Pen { byte y byte x} def PEN:Pen = penCol ; this is a bit weird, when I do "let pen:de = System::PEN" I know that de is of type System::Pen which holds y and x, so I can do pen.x to access penRow