MZX 2.81h+lua Lua support in MZX
#91
Posted 23 May 2008 - 04:02 AM
I got tired of writing search-and-replace code for the editor, and it'd be so much simpler to use a fast well-tested string library.
#92
Posted 23 May 2008 - 09:10 AM
#93
Posted 23 May 2008 - 11:18 AM
Debian's AMD64 shared library is 198160 bytes, which seems pretty large. I ran through this auto-generation script you mentioned simply with "replace" and it pulls in code for handling with utf8, which MZX explicitly does not need. It still compiles to about 140KB of object code in a shared library. If this kind of dependency could be mitigated I'd be happier.
If we do care about using the editor on PSP/NDS/GP2X, I would say we're already at risk of bloating MZX pretty considerably -- an "all disabled" binary for NDS is currently only 460KB statically linked -- and if binary size increases by more than 40% (overall) I'd probably start asking questions about these new features. On platforms with XIP it's not too big a deal, but a larger program is still significantly slower. On a platform that caches the binary, it could mean the difference between being able to play a world and not.
If you do import it, please make sure you stick it in contrib/ and integrate it into MZX's build system. The directory should presumably only be built if CONFIG_EDITOR is enabled. I can give you a hand with this if you need it.
--ajs.
#94
Posted 23 May 2008 - 05:58 PM
ajs, on May 23 2008, 12:18 PM, said:
But if utf8 isn't being used then won't it be stripped as dead code? I guess I can run some tests on binary size with and without statically linked ustr to see what happens.
All of the libraries I've been using (Lua, and now ustr) have been explicitly designed to be as small as possible. Exo asked a while back why Perl or Python was a crazy idea while Lua is workable: this is the reason. I'm definitely conscious of the size restrictions.
I went through my editor and replaced the string functions with ustr and it simplified the code tremendously. Syntax coloring on a purely textual basis (i.e. without the aid of bytecode) is incredibly annoying without a string library, because of the necessity of inserting tags. It'll also come in very handy in the recompiler, because that manipulates text a lot.
Quote
Ok, I'll do this. I'll make sure dead stripping happens too.
#95
Posted 23 May 2008 - 06:34 PM
Nightwatch, on May 23 2008, 01:58 PM, said:
All of the libraries I've been using (Lua, and now ustr) have been explicitly designed to be as small as possible. Exo asked a while back why Perl or Python was a crazy idea while Lua is workable: this is the reason. I'm definitely conscious of the size restrictions.
I went through my editor and replaced the string functions with ustr and it simplified the code tremendously. Syntax coloring on a purely textual basis (i.e. without the aid of bytecode) is incredibly annoying without a string library, because of the necessity of inserting tags. It'll also come in very handy in the recompiler, because that manipulates text a lot.
Ok, I'll do this. I'll make sure dead stripping happens too.
Two questions:
- Is your editor being done with Robotic in mind as well as Lua?
- Is it being made reminiscent of the original editor as much as possible?
Please conform to both as much as you can.
"The fact that I say I've one of the best, is called honesty." -Akwende
"Megazeux is not ment to be just ASCII, it is ANSI!" - T-bone6
"I hate it when you get all exo on me." - emalkay
Exophase can what Rubi-cant.
exoware is ware ur ware is exoware
ps. not loking 4 new membrs kthx
#96
Posted 23 May 2008 - 07:12 PM
Nightwatch, on May 23 2008, 06:58 PM, said:
I doubt it. The linker will only remove the code if it's unused (not necessarily unreachable) and the compiler will only remove unreachable code in some cases, specifically something like if (zero_const_or_literal) {} which I doubt is the case here. Of course, this is just a guess. Like you say it's definitely worth running a test for this; unfortunately that could be hard.
Nightwatch, on May 23 2008, 06:58 PM, said:
I'm aware of Lua's small footprint myself, which is why I've not been too concerned about it. But Pluto is pretty big, certainly proportionately big, and ustr could be too. Obviously you can't ever get cool new features for free, so some increase in size is inevitable, and your cleanups may reduce LOC in some cases. Fortunately we've got all the forensics necessary to find and fix areas of bloat.
Nightwatch, on May 23 2008, 06:58 PM, said:
Maybe, but in this case you'll place a dependency on it outside of CONFIG_EDITOR. This is the kind of bloat I care most about.
--ajs.
#97
Posted 23 May 2008 - 07:38 PM
Exophase, on May 23 2008, 06:34 PM, said:
- Is your editor being done with Robotic in mind as well as Lua?
Yes, that's why parsing Robotic is such a big priority.
Quote
Please conform to both as much as you can.
Yes, modulo a bit of "modernization". For instance, selecting will be done with shift+direction like most editors do instead of alt+s, alt+e. Cut/copy/paste will be ctrl+x, ctrl+c, ctrl+v. The line being edited isn't always in the center, rather the editor scrolls as the user requests it (this is done already).
And, in general, the feel will be unavoidably different as a result of being text based instead of bytecode based - this is a change that you wanted to make anyway though, so I doubt that's of much concern.
Oh, and I just integrated ustr into MZX's build system and ran a test, calling ustr_dup_empty() in main and seeing how much it affected the size. It increased the MZX size by 100k in a *debug* build, which doesn't seem like much to me (2745955 bytes versus 2842436 bytes, x86-64 linux system).
This post has been edited by Nightwatch: 23 May 2008 - 07:40 PM
#98
Posted 23 May 2008 - 08:24 PM
Nightwatch, on May 23 2008, 03:38 PM, said:
Yes, modulo a bit of "modernization". For instance, selecting will be done with shift+direction like most editors do instead of alt+s, alt+e. Cut/copy/paste will be ctrl+x, ctrl+c, ctrl+v. The line being edited isn't always in the center, rather the editor scrolls as the user requests it (this is done already).
And, in general, the feel will be unavoidably different as a result of being text based instead of bytecode based - this is a change that you wanted to make anyway though, so I doubt that's of much concern.
Oh, and I just integrated ustr into MZX's build system and ran a test, calling ustr_dup_empty() in main and seeing how much it affected the size. It increased the MZX size by 100k in a *debug* build, which doesn't seem like much to me (2745955 bytes versus 2842436 bytes, x86-64 linux system).
OK, that all sounds good. I hope this isn't too much work for you. Please try not to overlook any of the little features I've added though :> (like alt + direction for word moving, alt + backspace to delete a line, ctrl + backspace to delete previous word, etc - these are not especially non-standard, I think)
I doubt the "feel" will have to be much different, aside from not adding connector words, which I think people will just have to get used to anyway (it's an option as it is, I think.. I've never turned it on myself)
It'll be good to finally have an editor not stuck with some of the old cruft, honestly.
"The fact that I say I've one of the best, is called honesty." -Akwende
"Megazeux is not ment to be just ASCII, it is ANSI!" - T-bone6
"I hate it when you get all exo on me." - emalkay
Exophase can what Rubi-cant.
exoware is ware ur ware is exoware
ps. not loking 4 new membrs kthx
#99
Posted 23 May 2008 - 08:38 PM
Like I said on IRC, this would be pretty much the most welcome change to MZX (at least for stability purposes). The current problems left with MZX are mostly related to the Robotic editor, and are almost all uniformly nasty (either to fix, in themselves, or both).
<Exophase> HES STEALING MAH AIRSHIP!!!!!!11111111
#100
Posted 24 May 2008 - 02:17 AM
Nightwatch, on May 23 2008, 08:38 PM, said:
I guess this begs the question; what about a non-debug build? Also, calling one function obviously isn't a good enough test; we need to see what the size increase is like doing something realistic. Nobody doubts code elimination for unused functions, the question is what can be eliminated in used functions.
Don't be too concerned by this; you should get it working, then we can worry about size. If needs be, we can fork the code in question, or re-implement it.
--ajs.
#101
Posted 26 May 2008 - 08:32 AM
#102
Posted 26 May 2008 - 02:57 PM
Also you might get less resistance from people if either a) you try to match the old editor colour scheme as closely as possible or b) you let people redefine it (I think this latter option is pointless bloat, myself). At the moment you're placing emphasis on the commands themselves, which in the case of * is kind of distracting. Maybe I'm just too used to the old way.
--ajs.
#103
Posted 26 May 2008 - 06:55 PM

Why-Fi: but I'M MATURE ENOUGH TO BE A MODERATOR!!!!!!!!!!
#104
Posted 26 May 2008 - 06:57 PM
--ajs.
#105
Posted 26 May 2008 - 07:42 PM
It's really hard to design a good-looking editor when you're limited to the default character set and default palette and trying to preserve as much screen space for editing as possible. I really like having a large 80x22 space for editing, but that leaves little room for other bells and whistles.
#106
Posted 26 May 2008 - 08:10 PM
#107
Posted 26 May 2008 - 08:16 PM
To be honest I'm not that bothered about losing the border around the editor, just as long as it's CLEAR what line I'm currently on. You definitely need to restore the line/column indicator though, they'll be genuinely useful when you get round to the validating the robotic. Not sure what to do about Size, I guess this new way we won't need to care about the world limit any more, but we'll surely have a limit on program size and somewhere this will be checked (??). This could probably go in the same place as the validation logic, and just not let you leave the editor with a faulty program.
--ajs.
#108
Posted 27 May 2008 - 06:29 PM
I created a new bug-fixes branch for really general bug fixes. ajs, you might want to take a look.
#109
Posted 27 May 2008 - 08:13 PM
Other fixes look fine, surprising I didn't pick them up here. I reworked the getcwd() fix slightly because you forgot about the OS X special case. SVN 625 tracks all these fixes except the exit(0) hack. You can drop all but that from your branch.
--ajs.
#110
Posted 27 May 2008 - 08:55 PM
Nightwatch, on May 27 2008, 01:29 PM, said:
I created a new bug-fixes branch for really general bug fixes. ajs, you might want to take a look.
Simple, rasm really doesn't handle that. Extras and join words are not potential candidates as identifier strings. It'd be great if you could make it so they are, but that might go beyond the scope of simple lexing. It'd also be good to have a distinction between ID strings and literal strings. I actually wanted the ID string delimiter to be changed to a different character like ` (they shouldn't be necessary anymore most of the time anyway, do people really need to put spaces in their names?), but that'd really confuse some people.
Having lex as a compile-time dependency isn't that big of a deal though, since it won't be required as extra stuff added to the runtime (although I don't know how size optimal the code it generates is)
"The fact that I say I've one of the best, is called honesty." -Akwende
"Megazeux is not ment to be just ASCII, it is ANSI!" - T-bone6
"I hate it when you get all exo on me." - emalkay
Exophase can what Rubi-cant.
exoware is ware ur ware is exoware
ps. not loking 4 new membrs kthx
#111
Posted 29 May 2008 - 06:03 PM
Originally, I was going to have two options in the editor branch (without Lua): "Basic Robotic" and "Formatted Robotic", the latter of which is stored as text in addition to bytecode. I ended up renaming them "Robotic" and "Exotic" respectively, though, because the storing of Robotic in text form was intended to be the first step along the way to Exo's Robotic overhaul. I redid the robot parameter editor so that you can select a language from a dialog box whenever you edit a robot.
#112
Posted 11 June 2008 - 12:18 AM
Exo's previous implementation, which just created a secondary board buffer and copied there, allowed you to implement move by not directly utilising the board for both source and destination. Since your new code does not accommodate for this, move is currently not possible. I would suggest that we implement move as copy and slow-erase (without creating a secondary buffer), it can be slow because only the editor needs it. That would be better than the old buffer method and allow me to finally remove the old copy_block..() routines.
What do you think? It would be nice to do this for 2.82b.
(Oh and BTW inmate's been working on optimising the counter/string lookups using your hashtable code instead of binary searching lists. So that's a second user of it. He's got some changes to make to the hashtable stuff, but it's non final so I'll try to pass them on to you later.)
--ajs.
#113
Posted 13 June 2008 - 06:39 AM
ajs, on Jun 11 2008, 01:18 AM, said:
Exo's previous implementation, which just created a secondary board buffer and copied there, allowed you to implement move by not directly utilising the board for both source and destination. Since your new code does not accommodate for this, move is currently not possible. I would suggest that we implement move as copy and slow-erase (without creating a secondary buffer), it can be slow because only the editor needs it. That would be better than the old buffer method and allow me to finally remove the old copy_block..() routines.
What do you think? It would be nice to do this for 2.82b.
I'll take a look at what the editor requires when I get a chance.
I've almost finished moving Lua to the language-neutral robot backend. It's been a lot more work than I anticipated, having required pretty much a complete rewrite of the entire MZX Lua core except for the freeze/thaw protection table logic. I bumped the version number, but that'll probably have to be changed to coincide with whatever version starts to phase the new language backend in.
The idea is that when the top bit of "status" is set (in the world file only, not in memory), the robot is running a language other than Robotic. This is also set when the robot is running "bytecode-free" Robotic, a.k.a. Exotic. In this case, the program size and program are ignored, and instead MegaZeux reads a language ID and a blob of language-specific data. MZX looks in its language table to see whether it has routines to handle that language, and, if so, passes the data off to the thaw_robot_language_data routine that the language implements. In the case of Lua, this data is the code that the robot is running, plus a snapshot of the state of the Lua VM if it's a saved game. In the case of Exotic, the code is currently just stubs, but it should be the Exotic code in plain text format.
This should allow languages to be easily compiled in or left out as desired, easing the transition. It might be a bit overengineered - I don't want to encourage MZX to support every language under the sun - but better too flexible than too rigid, I think. It also keeps Lua intrusion onto the existing codebase to a minimum.
This post has been edited by Nightwatch: 13 June 2008 - 06:40 AM
#114
Posted 13 June 2008 - 10:06 AM
LOADING WORLDS
- If loading from world <= 2.82, disassemble all robotic bytecode into source, flag in memory as "Type 1" (see below), discard bytecode:
- If loading from world > 2.82, check language version which can be one of three things. [There might also be an optimisation here to see if Lua bytecode is present; if it is, load that and skip to step 5]. You are loading source only, at this point:
- Type 1: Robotic
- Type 2: Exotic
- Type 3: Lua
- Type 1: Robotic
- If type is 1 or 2, translate program to Lua. Additionally, repeat this step if the robot is loaded programmatically (at runtime via LOAD_ROBOT). You never throw away the original Robotic/Exotic source, you just additionally translate to Lua.
- Compile the robot to Lua bytecode (don't fully understand how this works atm but I assume it's basically automatic). After this point, the source representation can be discarded from memory.
- Rules for runtime are "do as few checks as possible", "don't retain anything in memory we don't need" and "representation is unified (as Lua bytecode)"
EDIT: Removed garbage about SAV files.
ROBOT EDITOR HANDLING
- Regardless of type, load source (which should now be available in native language).
- On exit, validate program (for Robotic/Exotic, this would ideally be a subset of RASM, not an assembler but a very GOOD validator, something better than what we have right now; part of translating expressions et al. to Lua would require better validation);
- No need to translate/compile at this stage, as Alt-T's loader would do this, but you could do it anyway to find other kinds of mistakes (expression bugs or whatever).
- Rule in the editor is "do all the expensive checks, we don't care about performance"
SUMMARY
This approach lets us drop the assembler parts of RASM and supplant it entirely with Lua. Lua is at the core of MZX; LOAD_BC would handle Lua bytecode (of course translating older robotic bytecode programs as necessary). SAVE_BC automatically exports Lua, not Robotic, bytecode. At runtime, everything would internally be Lua bytecode, and all source could be discarded. Robotic/Exotic bytecode is never, ever saved to the MZX/SAV file by 2.83.
This approach would also eventually allow Robotic (or even Exotic, eh??) to no longer be presented to the user as an option in the robot editor, without unduly breaking backwards compatibility. It also provides a smooth way of eventually deprecating support at the world-loader level (say MZX 3 or similar, where an external translator might be used).
I think my approach is more of a "total conversion" than your current implementation, but I think it will be necessary if we're ever to get this 100% right. It can be roughly broken down into the following pieces of work:
- Routine for converting robotic bytecode to source (done already by RASM, but it'll need pulling out)
- Robotic and Exotic program validator (partially done by RASM, but more work is required IMO)
- Convertors for Robotic and Exotic to Lua
- runrobo2 dies in current form, Lua interpreter implicitly invokes C routines (this has all kinds of unresolved issues WRT cross-robot sends and other timing issues, I think, but maybe I'm wrong here)
--ajs.
#115
Posted 13 June 2008 - 06:17 PM
- I thought the policy was to ignore backwards compatibility for saves, for simplicity.
- Compiling the robot to Lua bytecode is done using luaL_loadstring, which pushes a closure onto the world's Lua stack. There's no difference between Lua programs and closures (i.e. functions) from an internal standpoint. The closure is then stored in the world registry so that it doesn't get garbage collected, and a key to retrieve it later is stored with the robot.
- Lua bytecode can never be stored in the world files, because it's specific to the endianness and word size of the machine that compiled it.
- The Lua is compiled when leaving the robot editor at the moment. It's just simpler to always maintain the invariant that the Lua is available in compiled form with a Lua-running robot at all times. There is an API routine to check syntax only, but since we're only talking about the editor I doubt it matters much.
- Lua timings and Robotic timings are different, there's just no way around it short of cycle counting (God, I hope we don't have to do that). It is possible to register a "hook", which is a function that is called every time the Lua VM steps one instruction. There is special case code in the Lua source to allow the hook to yield execution, so it seems the Lua developers had situations like ours in mind, in which the Lua VM is only allowed to execute some N instructions before it gets preempted. The only gotcha is that while the Lua interpreter is re-entrant, yielding is not. That is, if the C stack looks something like:
Main program -> Lua interpreter -> C function called by Lua -> Lua interpreter
you cannot yield control back to the main program, because that would involve swizzling C stacks, which can't be done in a portable way (there *is* a Lua module that implements this on many platforms, but it'd be best to avoid it). So a Robotic program executing Lua must never be re-entrant. This shouldn't be a problem as long as we're careful with the recompiler.
#116
Posted 13 June 2008 - 07:09 PM
Nightwatch, on Jun 13 2008, 07:17 PM, said:
Thinko on my part, you're quite right.
Nightwatch, on Jun 13 2008, 07:17 PM, said:
This is unfortunate, but it does make sense for the reasons you've specified. It'll mean we can't support LOAD_BC and SAVE_BC in a Lua context (of course backwards compatibility is fine). Maybe there's some extension for Lua that allows program bytecode serialization in a platform neutral way?
Nightwatch, on Jun 13 2008, 07:17 PM, said:
This, I don't understand. What possible use is compiled Lua in the editor? The world is saved and re-loaded when it's tested anyway, so the robot is never executed in the editor. Why would you want the Lua bytecode to be saved?
Nightwatch, on Jun 13 2008, 07:17 PM, said:
Main program -> Lua interpreter -> C function called by Lua -> Lua interpreter
you cannot yield control back to the main program, because that would involve swizzling C stacks, which can't be done in a portable way (there *is* a Lua module that implements this on many platforms, but it'd be best to avoid it). So a Robotic program executing Lua must never be re-entrant. This shouldn't be a problem as long as we're careful with the recompiler.
You know what's possible better than I do, but games will break if we don't keep time _between_ robots. Robotic has this mantra of "these commands end the cycle" and "these commands do not". As a result, I'd GUESS most of the time we're fine, since we don't need to rely on the VM for preemption, we can just preempt execution of a given robot when a native call to C is made (and it matches some criteria). Undoubtedly there are some troublesome exceptions to this rule, but I can't think of any atm.
(Calling subroutines on other robots is probably one case to consider?)
All sounds pretty good, but it is a lot of work. If need any help please let me know.
--ajs.
#117
Posted 13 June 2008 - 08:18 PM
A lot of old games use idle loops without any kind of cycle ending commands. To get arround needing to preempt the VM specifically I think that the Robotic to Lua conversion will need to scan for these kinds of loops and insert yielding explicitly, or possibly decrementing a counter that eventually yields based on the size of the loop. I don't think getting the timing anywhere close to correct is a big deal.
"The fact that I say I've one of the best, is called honesty." -Akwende
"Megazeux is not ment to be just ASCII, it is ANSI!" - T-bone6
"I hate it when you get all exo on me." - emalkay
Exophase can what Rubi-cant.
exoware is ware ur ware is exoware
ps. not loking 4 new membrs kthx
#118
Posted 13 June 2008 - 08:27 PM
Maybe as you suggest explicit yield points can be inserted to precisely duplicate the old way. I actually think this will end up being worth doing. If we're too dismissive of the timing issue it'll end up biting us when we do break games. Ideally, converted robotic programs (in Lua) _would_ precisely emulate robotic timing, so that it's possible to write a bunch of tests and/or prove why games break and how to fix them. Of course, I don't really care at all if things change when you use "pure Lua".
IOW I don't think the casual "Lua runs X insn and breaks" will be sufficient.
--ajs
[1] WALK incidentally being very dependent on cycle frequency to be processed accurately, without explicit code points enabling this via preemption.
#119
Posted 14 June 2008 - 12:41 AM
If you need to do cycle counting at the very least you can do it block-wise, before labels and flow control changes (but then it'll be off by a few cycles)
This is not emulating hardware.. and even then most game consoles past a certain point don't need especially precise timing for just about any game. If a one in a thousand game somehow freakishly relies on this then it's probably worth fixing because it'd probably be the result of some really awful coding.
As far as relying on timing for comparison testing goes, I don't think this would be a great way to go about debugging problems anyway. MZX games are sufficiently high level enough (and open source) and usually simple enough to analyze directly.
"The fact that I say I've one of the best, is called honesty." -Akwende
"Megazeux is not ment to be just ASCII, it is ANSI!" - T-bone6
"I hate it when you get all exo on me." - emalkay
Exophase can what Rubi-cant.
exoware is ware ur ware is exoware
ps. not loking 4 new membrs kthx
#120
Posted 14 June 2008 - 03:07 AM
Quite frankly, it was a fairly academic point anyway -- let's get things working first, then we can refine it if necessary. It doesn't sound like it would be impossible to provide 99% accurate cycles even with the Lua translation. It sounds like we could just emit these so called "yield points" on every other line and programmatically determine whether or not to yield. Unless robotic has a way to spin that requires 0 LOC this works :-)
--ajs.

Help









