<rdrop-exit> the basic mechanism boils down to unwinding the return stack to a previous point
<rdrop-exit> and having a "register" that holds that point
<remexre> er, for CL conditions, the interesting case is being able to say "after the condition was thrown"
<rdrop-exit> what is CL?
<remexre> common lisp
<rdrop-exit> ick
<remexre> ?
<rdrop-exit> I haven't looked at lisp in 30 years, it's not fresh in my memory
<rdrop-exit> The core mechanism of exception handling in Forth is very simple due to Forth having two stacks, ANS adds a little overhead with their throw codes, but it's still very basic
<rdrop-exit> Anything more sophisticated just requires storing extra stuff in the exception frame
<rdrop-exit> and having code that knows what to do with that extra stuff
<rdrop-exit> Whether a more sophisticated mechanism would be worth the trouble, I'm not sure
<remexre> CL's are mainly more useful when you want to express things like "if opening this file fails, create it and retry," or "if a divide by zero occurs, make the result 0"
<remexre> CL's condition mechanism is*
<rdrop-exit> None of that requires an extension of the basic mechanism
<rdrop-exit> try / div/0 cancel
<rdrop-exit> oops
<remexre> where cancel moves control flow back to the place where the exception was thrown?
<rdrop-exit> try / ['] div/0 cancel
<rdrop-exit> doesn't have to
<remexre> what's cancel do, then?
<rdrop-exit> : cancel ( x1 x2 -- x1|0 ) lift <> and ;inline
<remexre> lift?
<rdrop-exit> lift ( x1 x2 -- x1 x1 x2 )
<remexre> hm, ok
<remexre> so what I mean is more like
<remexre> : print-file open-file dup read-file type close-file ;
<remexre> : example-handler ." file didn't exist" restart retry ;
<remexre> : foo ['] file-not-found ['] example-handler ['] print-file call-with-handler ;
<remexre> where call-with-handler ( throw-code handler xt -- )
<rdrop-exit> that's not a fallback handler
<remexre> correct
<rdrop-exit> a fallback handler is what happens when no one has handled the exception and control returns to your system
<remexre> er, yeah, this was me showcasing something you can do w/ conditions that can't be done with ANS-like exceptions (as far as I can tell)
<remexre> sorry if I was unclear
tabemann has quit [Ping timeout: 240 seconds]
<rdrop-exit> but you can make a normal handler as sophisticated as you want
<remexre> sure, but it can't jump back to where the exception was thrown, unless I'm misunderstanding how it works
<rdrop-exit> you end up at the next instruction
<rdrop-exit> try foo zorba
<rdrop-exit> always ends up at zorba
<rdrop-exit> where you go from there doesn't require the exception mechanism
<rdrop-exit> begin try foo ... again
<remexre> yeah, I'm saying in some cases you want to continue where you threw from
<rdrop-exit> you mean in foo ?
<remexre> yeah
<remexre> if somewhere deep in foo there's a recoverable error, it's nice to be able to recover from it and keep executing
<rdrop-exit> that's what the normal mechanism does
<remexre> keep executing as if the throw were a no-op*
<rdrop-exit> some code had to handle the throw
<rdrop-exit> you handle it then you move on
<remexre> sure, but handling it unwinds the stack, no?
<rdrop-exit> yes, you're always catching something that was thrown from a deeper level in the code
<remexre> whereas conditions can choose to, uh, re-wind? (I guess in practice, they're probably implemented by not unwinding until after the handler runs)
<remexre> condition handlers*, that is
<rdrop-exit> you unwind until someone deals with it (and doesn't throw it upstairs)
<rdrop-exit> the level dealing with it is the level that has the required context knowledge to deal with it presumably
<remexre> but that makes the case where e.g. you want to describe how to recover from file-not-found somewhat more annoying
<rdrop-exit> how to recover depends on higher up context knowledge
<remexre> yeah
<rdrop-exit> if it doesn't there's no need to throw
<remexre> but after the higher-up code chooses how to recover (choosing a different path to open, creating the file, etc, etc) it wants to tell the lower code "now continue"
<rdrop-exit> it still needs to open the file, so it would call open again with the new path
<remexre> yeah, that's what the "restart retry" was about in my example
<rdrop-exit> a loop is all that's needed
<remexre> code that knows an exception is potentially about to be thrown can set up (named) restart points, for various actions you want to do
<rdrop-exit> huge overhead, bigger exception frame
<remexre> change my print-file to
<rdrop-exit> sounds unecessary to me
<remexre> : print-file ." this should only be printed once" open-file dup read-file type close-file ;
<remexre> and then a loop no longer suffices
<rdrop-exit> there are only two situations IMO
<rdrop-exit> the code has enough context to deal with the situation, then it doesn't need to throw, or the code doesn't then it throws/
<rdrop-exit> .
<rdrop-exit> exceptions are only for when the code throws up its hands
<rdrop-exit> they are not for normal control flow
<remexre> that's why conditions aren't called exceptions :P
<remexre> I mean, would you make file-not-found an exception?
<rdrop-exit> only if the file is always expected to be there
<remexre> (as a side note, CL has warnings implemented as conditions, since the default handler just continues)
<rdrop-exit> Lisp has a lot of constly abstractions, you can layer those on Forth's more basic mechanism's but then you get the abstraction overhead in Forth as well
<rdrop-exit> you want the banana you get the gorilla
<remexre> no disagreement, though as far as I know, conditions aren't significantly more expensive than normal exceptions would be
<remexre> mainly because CL has stack unwinding implemented separately from either
<rdrop-exit> you could do the same in Forth, not use exceptions for these "conditions"
<remexre> like, in the implementation I've seen, the only difference is that exceptions unwind then run the handler, while conditions run the handler, which itself does the unwind
<remexre> the main reason I haven't implemented them in forth is because any code I write is so dang ugly :P
<remexre> because I'm passing two XTs in, and either a numeric code or another XT as well
<rdrop-exit> down the rabbit hole of complexity
<rdrop-exit> Forth isn't about surface simplicity
<rdrop-exit> unlike other systems
<rdrop-exit> Forth doesn't buy surface simplicity at the expense of more complexity under the hood
<rdrop-exit> Forth is simple all the way down
<remexre> sure, but conditions are very little additional code over exceptions
<rdrop-exit> But exceptions are already expensive
<remexre> yeah, i've avoided implementing them in the past because of that
<rdrop-exit> I've never felt a need for anything more sophisticated
<rdrop-exit> (or more costly)
<rdrop-exit> the definition that throws an exception is basically saying I give up, caller(s) you deal with it
<rdrop-exit> that's all that's needed as far I can tell
<remexre> yeah, and conditions are letting the caller say "I'm done handling it, keep going / retry the last syscall / etc"
<remexre> /shrug
<rdrop-exit> That's definitely going to add complexity
<remexre> since condition handlers run before you unwind, it's minimal
<rdrop-exit> If a division throws a divide by zero, it's done
<rdrop-exit> The caller can do what he wants
<rdrop-exit> there's no need for a predefined menu of options
<remexre> it's defined by the code that calls THROW
<rdrop-exit> I don't want my division primitive to have that overhead
<remexre> isn't it already having the overhead of a branch and potential call to throw, if you're not relying on some hardware exception/interrupt/etc?
<rdrop-exit> how it does it isn't the point, the callee should be as simple as possible, since the caller is the one with the context to best know what to do
<remexre> my point is, you're not adding much more code, you're mostly moving it from CATCH to the handler and THROW
<rdrop-exit> It doesn't make sense to me to burden the lower level with the overhead
<rdrop-exit> Context increases naturally as you go up
<remexre> like, from an aesthetic or a performance perspective? because in the "simple exception" case, it'd be surprising to me if you had >10 extra instructions running
<rdrop-exit> 10 instructions is a lot in low level code, but not much in high level code
<remexre> 10 extra instructions in the throwing case*; should be 0 in the non-throwing case
<rdrop-exit> they're still there all the time even if you only exceptionally use them
<remexre> like in code size? sure, but they're in the THROW word?
<rdrop-exit> People are always claiming that their pet complication has very little overhead, even if the complication isn't needed.
<remexre> /shrug it's not *needed*, but it generalizes exceptions in a very nice way, and it makes some things a lot nicer to express
<rdrop-exit> Exceptions are already a very general mechanism, this seems to impose a menu of predefined options on the lower level code.
<remexre> er, no, the "menu" is presented to the handler, not the thrower
<rdrop-exit> The situation now is that a throw just punts.
<rdrop-exit> Sorry
<rdrop-exit> The situation now is that a thrower just punts.
<rdrop-exit> The smarts on what to do about it are all at a higher level.
<rdrop-exit> Can't get a more general mechanism than that.
<remexre> conditions have a superset of the functionality of exceptions
<remexre> for example, in lisp, you have warnings, which are conditions, where the fallback handler does nothing (or perhaps logs it, I believe it's implementation-specific)
<rdrop-exit> That's not a problem, the fallback is handled at the system-wide context by the outer interpreter.
<remexre> sure, but how does the outer interpreter get control flow back to the code that signalled the warning?
<rdrop-exit> No need
<rdrop-exit> For example
<rdrop-exit> If you're loading source from a file and you get a word not defined exception, you stop the load and print a message.
<rdrop-exit> If you're typing the name interactively, you might just emit a BEEP.
<rdrop-exit> The exception percolates to the level that knows what to do about it because it has the contextual knowledge.
<remexre> for an example of warnings, which I don't believe you can easily do with exceptions:
tabemann has joined #forth
<remexre> I'm writing control code in a loop (e.g. a PID controller), and the sensor I'm reading from gets a value out of the expected range
<rdrop-exit> ok
<tabemann> hey
<rdrop-exit> hey
<remexre> depending on what the sensor is, I might want to clamp it, might want to terminate execution, might want to use the last value; or (let's pretend this is the case), just ignore it
<remexre> hiya
<remexre> er, just ignore it == let the out-of-expected-range value be used
<remexre> the "just ignore it" case can't be done in an exception handler
<rdrop-exit> nor should it
<rdrop-exit> it should be done via a defered word
<rdrop-exit> that you set to how you want to handle it
<rdrop-exit> no one's giving up, therefore no exception
<rdrop-exit> exceptions are a way to punt
<remexre> I guess...
<remexre> though then once I have two sensors, I need two deferred words
<rdrop-exit> (if you always deal with it the same way, you don't even need the deffered word)
<remexre> yeah, the assumption I'm making here is that I'm controlling multiple sensors with a DO-PID-CONTROLLER word or smth
<rdrop-exit> you only need one per sensor, if you want different behaviors vs a global behavior
<rdrop-exit> None of that has to do with exceptions
<remexre> like this is an example of where you can't make the code use exceptions, because they're not general enough
<remexre> signalling a condition (instead of calling the deferred word) would be sufficient, though
<rdrop-exit> No, it's an example where exceptions aren't needed
<rdrop-exit> Exceptions are a heavyweight mechanism that should be avoided in most cases
<remexre> idk, I agree in Java / C++, but ANS Forth exceptions are relatively cheap, and Lisp conditions that are handled w/out unwinding are similarly cheap
<remexre> the major disadvantage I see in Forth and Lisp are that exception-involving control flow is more difficult to read
<rdrop-exit> Relatively cheap is not a reason to use them inappropriately
<remexre> I don't see this case being particularly inappropriate
<rdrop-exit> The only reason to use an exception in real time loop is to bail out completely from the real-time loop
<rdrop-exit> It's not a replacement for run of the mill control flow, it's a punt
<rdrop-exit> it's panic
<remexre> not all uses of conditions are exceptions
<rdrop-exit> but you said they had more overhead than exceptions
<remexre> when you're unwinding
<rdrop-exit> so what are you doing instead of unwinding?
<rdrop-exit> you're not just simply returning to the caller
<remexre> from the PID controller example, I might be clamping the top-of-stack value, I might be doing a no-op, I might be logging and one of the above
<remexre> and then I'd be returning to the caller, yeah
<rdrop-exit> So either a regular word, or a defered word would do the job, how does a condition mechanism differ from the normal solution?
<remexre> I don't need to copy the DO-PID-CONTROLLER code and add an extra deferred word for each sensor (or at least each case)
<rdrop-exit> I don't get it
<remexre> so I've got three sensors, I'd need three deferred words, right?
<remexre> and 3 versions of DO-PID-CONTROLLER, one per deferred word
<rdrop-exit> are you dealing with the out-of-range condition differently depending on the sensor?
<rdrop-exit> or is it a global setting?
<rdrop-exit> If it's global then one defered word, if it depends
<rdrop-exit> then a jump table
<remexre> per sensor; wdym a jump table? like "what a switch() {} statement compiles to" ?
boru` has joined #forth
boru has quit [Disconnected by services]
boru` is now known as boru
<rdrop-exit> an array of XTs
<remexre> one per sensor?
<rdrop-exit> one XT per sensor
<rdrop-exit> assuming you have a setting per sensor, if its a global setting you just need one XT (or a defered word)
<remexre> I guess? seems less elegant than just signalling out of range, though
<rdrop-exit> for example if its sensor #5 that is out of range
<rdrop-exit> 5 extreme-handler perform
<rdrop-exit> the 5 would probably be already on the stack
<remexre> where perform == ANS's execute? yeah
<rdrop-exit> perform is equivalent to a @ EXECUTE
<rdrop-exit> : extreme-handler ( sensor# -- xt ) extreme-handlers cells + ;
<remexre> oh, yeah, forgot the @; yeah
<rdrop-exit> sorry
<remexre> I did mentally I mean
<rdrop-exit> : extreme-handler ( sensor# -- xt ) cells extreme-handlers + ;
<rdrop-exit> corrected
<remexre> yeah, I've got an ARRAY defining word that does that automatically; but sure, makes sense
<rdrop-exit> that's one way of dealing with it, but there are tons of other common ways
<rdrop-exit> PERFORM used to be a common Forth primitive, not sure why they didn't standardize it
<rdrop-exit> (maybe they did, I can't recall)
<remexre> huh, okay
<rdrop-exit> some Forths use the name @EXECUTE
<remexre> I only started using Forth a year ago, and mainly learned it from the 2012 standard
<rdrop-exit> I've always prefered the name PERFORM
<remexre> so I don't know most things that are "used to be", heh
<rdrop-exit> sure :)
<rdrop-exit> I find that most of the baggage that new Forthers try to graft onto Forth from other languages unecessary pure overhead
<rdrop-exit> There's usually a simpler Forth idiom
<rdrop-exit> which doesn't require a new mechanism to be implemented
<rdrop-exit> The problem with the standard is that it's complicating Forth by grafting on a lot of the cruft people are used to from other systems
<remexre> yeah, I kinda feel like the "core" section should be a lot smaller and "core extension" should be larger
<remexre> but for other sections, it's kinda nice that they've already got a solved, well-explored design
<remexre> for if you want that cruft
<rdrop-exit> It's less and less representative of what a Forth should be
<remexre> eh, I'd be fine with these extensions, if they could be ./configure'd out (or equivalent)
<remexre> 'cause for e.g. exceptions or dynamic memory allocation, sometimes they're worth the overhead, and there's basically no reason to implement them yourself
<rdrop-exit> exceptions are simple to implement, much of other stuff is C-oriented, there's some really ugly stuff like recognizers
<rdrop-exit> I've no need for structs, objects, dynamic memory allocation, and the like.
<remexre> oh, huh, yeah, I wouldn't want those... I don't think they're in the 2012 standard, though
<remexre> structs are nice, though I usually just "define them" as a bunch of ( addr -- addr ) words with suggestive names, rather than any language support
<rdrop-exit> I haven't looked at the standard in a while, I sometimes follow discussions on clf and /r/forth
<rdrop-exit> Maybe I'm misrembering what they've added, or confusing what's in the standard with new stuff being discussed
<remexre> I think the latter, though they might've dropped some stuff since ANS? idk tho
<rdrop-exit> I've never implemented a standard compliant Forth, the closest I came was a 83S Forth a long time ago
<rdrop-exit> The only reason for me to keep up with the standard, is to be able to understand what people are talking about in Forth discussions
<remexre> I'm not fully standard-compliant, but I try to be "close enough"
<rdrop-exit> I don't even try, I'm too far gone :)
<rdrop-exit> Even my most basic words like VARIABLE are non-compliant.
<remexre> what're you doing non-compliant there?
<rdrop-exit> I take a size/alignment parameter
<rdrop-exit> 32-bit VARIABLE
<rdrop-exit> 16-bit VARIABLE
<rdrop-exit> 128 VARIABLE
<remexre> oh, huh
<remexre> I'm on ARM, so CREATE aligns for me
<rdrop-exit> 128 bytes on a 128 aligned boundary
<rdrop-exit> My VARIABLE aligns on the size
<rdrop-exit> 64 VARIABLE
<rdrop-exit> creates a 64 byte variable aligned on a 64 byte boundary
<rdrop-exit> 16-bit VARIABLE or 2 VARIABLE
<remexre> huh, any particular reason for that?
<rdrop-exit> creates a 2 byte variable aligned on a 2-byte boundary
<rdrop-exit> The reason is that I used to have BVARIABLE, 16VARIABLE, 32VARIABLE, VARIABLE
<rdrop-exit> then I decided it was just bad factoring to have it that way
<remexre> I meant more for e.g. why 128 VARIABLE aligns to 128
<remexre> instead of to your cell size
<remexre> or some other convenient size
<remexre> e.g. my CREATE aligns to 4 bytes, even though I've got a 64-bit cell size, because code only needs to be aligned to 4 bytes
<remexre> (and the CPU I'm using does unaligned loads and stores, just not unaligned execution)
<rdrop-exit> unaligned loads and stores are still slower, it also makes some other things more convenient
<rdrop-exit> I also have an equivalent to CREATE that takes an alignment without alloting
<remexre> it's only an extra cycle for me /shrug; I'll possibly change it later, but I've got lower-hanging fruit wrt efficiency
<rdrop-exit> It's a factor of VARIABLE just as with typical Forth
<rdrop-exit> It's a freebie, when I'm laying down data I usually know what alignment I'd like it to be at
<rdrop-exit> (and what size)
<rdrop-exit> My equiv
<rdrop-exit> oops
<rdrop-exit> My equivalent to CREATE is ALIGNED
<remexre> yeah, I'd just personally make the alignment and size separate
<rdrop-exit> I use ALIGNED for that
<rdrop-exit> address aligned thingies 8 addresses allot
<remexre> er, is that a code snippet?
<remexre> (forth is the only lang I have to ask that of, heh)
<rdrop-exit> yes, not a real one, just off the top of my head
<rdrop-exit> but that's how I would do it in real code
<rdrop-exit> that line creates an address aligned "thingies" and allots 8 addresses to it
<remexre> addresses == bytes?
<rdrop-exit> No it's the width of an address, 32 bits for example
<remexre> oh, so "cells" in ANS
<rdrop-exit> Not necessarily
<rdrop-exit> It's quite common for a 64-bit Forth (i.e. cell is 8 bytes) to only use 32-bit addresses
<rdrop-exit> @ fetches 64-bits
<rdrop-exit> a@ fetches a 32-bit address
<remexre> huh, I guess
<remexre> I'm a fan of cheeky tricks with page tables, so
<remexre> I usually keep the full width of addresses
<rdrop-exit> My current host PC Forth has 64-bit cells but 32-bit addresses, I've no need at the moment for 64-bit addresses
<rdrop-exit> It would just be overhead for my current needs
<remexre> makes sense, yeah
<remexre> especially since Forth's a language that's relatively immune to "what about when I need >4GB of memory for my program" arguments :)
<rdrop-exit> right :)
<rdrop-exit> So to define an address variable, I would do for example:
<rdrop-exit> address variable thingy
<rdrop-exit> that would give me an address-bits wide variable, aligned on an address-bits wide address
<rdrop-exit> (not it's the address of the variable that's aligned, this has nothing to do with its actual contents)
<rdrop-exit> *(note it's...
<remexre> yeah
<rdrop-exit> it basically accomplishes the same thing as:
<rdrop-exit> address aligned thingy address allot
<rdrop-exit> basically a size-aligned pointer variable
<rdrop-exit> that would give me an address-bits wide variable, aligned
<rdrop-exit> to an address-aligned address
<rdrop-exit> (that's a more correct way of expressing it than what I said earlier)
<rdrop-exit> gotta go, catch you later, nice chat. Keep on Forthin' :)
<remexre> same to you!
dave0 has quit [Quit: dave's not here]
gravicappa has joined #forth
iyzsong has joined #forth
jsoft has joined #forth
jsoft has quit [Ping timeout: 260 seconds]
deesix has quit [Ping timeout: 260 seconds]
dddddd has quit [Ping timeout: 240 seconds]
deesix has joined #forth
dys has quit [Ping timeout: 258 seconds]
rdrop-exit has quit [Quit: Lost terminal]
dys has joined #forth
tp has joined #forth
<tp> gahh C hardware examples are so frustrating!
<tp> mainly as the information needed to understand what the 'special' C syntax does is never in the example
<tp> consider this "TSC->CR = TSC_CR_PGPSC_2 | TSC_CR_PGPSC_0"
<tp> TSC_CR is a documented cortex-m register, no problem there
<tp> TSC_CR_PGPSC is also a documented register with three bits that can be set, i.e. TSC_CR_PGPSC ( %XXX -- )
<tp> so Im guessing that TSC_CR_PGPSC_2 = %010 here ??
<tp> and TSC_CR_PGPSC_0 = %001 here ??
<tp> hmm what's required is TSC_CR_PGPSC = %101
<tp> so TSC_CR_PGPSC_2 means 'bit 2'
<tp> .. just as well they dont have 32 individual bits to define ;-)
<tp> luckily Forth lets me do it in one operation "%101 TSC_CR_PGPSC bis!"
iyzsong has quit [Quit: ZNC 1.7.1 - https://znc.in]
dddddd has joined #forth
X-Scale` has joined #forth
X-Scale has quit [Ping timeout: 240 seconds]
X-Scale` is now known as X-Scale
tp has quit [Remote host closed the connection]
tp has joined #forth
tp has quit [Changing host]
tp has joined #forth
<tabemann> hey
<proteus-guy> Almost have a working basic (very) runtime compiler going for ActorForth!
<tabemann> TSC_CR_PGPSC_2 = %100 I think
<tabemann> hey proteus-guy
<tabemann> for me zeptoforth is awfully functional for something I only began debugging on wednesday and which is my first semi-working project in Thumb assembly
<proteus-guy> tabemann, howdy.
<proteus-guy> nice going!
<tabemann> right now it doesn't execute words properly when you enter them, but it complains when you enter something that it doesn't see as a word or a number
<tabemann> I have to figure out why it's not executing words yet
<tabemann> it took a while to get the last-word-in-flash lookup working properly
<tabemann> YES
<tabemann> I got immediate word execution working
<tabemann> it was a very stupid bug - I switched around the test for interpretation mode and compilation mode by accident
jsoft has joined #forth
<tabemann> okay, gotta get ready for work
tabemann has quit [Ping timeout: 240 seconds]
X-Scale has quit [Ping timeout: 255 seconds]
X-Scale` has joined #forth
X-Scale` is now known as X-Scale
xek_ has joined #forth
xek has quit [Ping timeout: 272 seconds]
dys has quit [Ping timeout: 240 seconds]
dys has joined #forth
WickedShell has joined #forth
<veltas> Hyphens or underscores?
<crc> hyphens
<veltas> Actually I have a real question
<veltas> Do Forths typically use the actual 'stack' for the return stack, or do they tend to put return stack somewhere else?
<crc> two separate stacks, one for data, one for return addresses
<veltas> Yes I get that
<veltas> I mean like the stack maintained by a special register, usually called 'SP'
tp has quit [Read error: Connection reset by peer]
<crc> in terms of hardware, it'd depend on the implementation
<veltas> That is the 'return stack' on many architectures, including Z80 which is what I'm writing for right now
<veltas> I'm just wondering if it's a bad idea to use that stack as my 'return stack'
<crc> in my old x86 system, I used the hardware stack for return addresses
<veltas> Like if I'm going to shoot myself in the foot by doing that
<crc> are you dealing with a host os, or running on the hardware directly?
<veltas> Hardware directly
tp has joined #forth
tp has joined #forth
tp has quit [Changing host]
<crc> i'd think you'd be fine then, as you'll have full control of everything
<veltas> Hmm, okay thanks
<veltas> It can only go so wrong, after all forth implementations aren't meant to be that big
<crc> on a unix host, mine has 497 words, of which 60 are in the kernel, 262 are in the standard library, and 175 are platform-specific
<tp> veltas, I've been disconnected so didnt see CRC's reply. The Forth I use, Mecrisp-Stellaris has two separate stacks, the data stack and the return stack
<siraben> veltas: my z80 Forth uses a simulated stack for the return stack
<siraben> the data stack is just the processor's normal stack
gravicappa has quit [Ping timeout: 258 seconds]
reepca has quit [Ping timeout: 260 seconds]
dave0 has joined #forth
reepca has joined #forth
<veltas> siraben: That makes sense as well because of the PUSH/POP efficiency
<proteus-guy> veltas, if your hardware has another register with addressing options that support a second stack (6809 was good for this) then you take advantage of it, but most CPUs you have to fake it.
<veltas> Even without CALL/RET
<veltas> proteus-guy: On Z80 the byte at (HL) can be treated like a slow 8-bit register
<veltas> So for most purposes (HL) is your good 'second' choice for memory access, but the stack is just far superior in access speed, especially dealing with 16-bit words