Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Twisty little passages
Page 1 of 2 | |||||
Author | Message | ||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Hey folks, My CMM2 has arrived, thanks to the WhiteWizard and micromite.org. Under the current conditions my free time to play with it will be very limited but for the sake of a smoke test I've updated and executed my (incomplete) Z-Machine implementation: Best wishes, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
MustardMan Senior Member Joined: 30/08/2019 Location: AustraliaPosts: 175 |
I think your signature line is very appropriate in this situation |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 3422 |
Wow, The CMM2 should allow you to run full ZORK 1. You don't need a mini version. Is there a thread about your ZORK port (I guess you started on CMM).??? I volunteer if you need help, either testing, or coding. Volhout PicomiteVGA PETSCII ROBOTS |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Thanks it's 50-75% done I think ... But it has been in that state for several months whilst I have been flashing LEDs. Quite right. The original CMM should be capable of running full Zork too as my code implements virtual memory paged from the SD. Speed is the main issue with the CMM implementation. One reason for testing with the mini version is that it is freeware so there is no issue with having it in my GitHub repository. This is now that thread. I have mentioned it in passing a couple of times in the past but nobody expressed interest so I didn't push it. Note it is not Zork that I am porting it is an implementation of the Zmachine. Once complete it will run all the Infocom Z3 format adventure games. Yes and I am still targeting it. However I am hoping the improved speed and editor on the CMM2 will allow me to develop faster. As long as I am careful about which language features I use a back port should then be relatively painless. I'm happy to add you as a contributor to the project on GitHub even if you just want to lurk. It might even encourage me to work more proactively on it. Best wishes, Tom Edited 2020-05-15 17:59 by thwill Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
cosmic frog Senior Member Joined: 09/02/2012 Location: United KingdomPosts: 277 |
I have been looking forward to this but thought you had lost interest in it. It's good to see you are still progressing with it. Cannot wait. Dave. |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Hi folks, Just a quick picture to show that progress is being made: What this shows is a Z-machine monitor/debugger that I've built into the implementation to help me track down a bug in the parser that has been stymying further progress. Best wishes, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Just in case you were getting tired of looking at all the impressive graphics demos and really felt the need for some serial terminal action here is video evidence of the latest progress: Zork on Colour Maximite 2 Obviously there's a bug causing the cryptic message when I try to examine the leaflet, that's next on the TODO list. Performance is ... adequate. Undoubtedly there is some room for optimisation but I suspect that implementing a reasonably complex virtual machine in BASIC was always going to be a stretch even on the CMM2; my understanding is that some of the more complex modern Z-machine games can cause a Z-machine VM written in "C" to creak a bit on a Raspberry Pi. I still hope to produce a version capable of running on the CMM "Classic" but I suspect it will be a bit like playing "Adventure" back in the 70's on a teletype. Best wishes, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Moved from its original thread The Z-Machine doesn't do anything particularly algorithmically complex. The body of the code is just a simple fetch, decode, execute instruction loop and the instructions are for the most part analagous to simple assembler and individually execute quite quickly: ADD, SUB, STOREB, STOREW, LOADB, LOADW, POP, PUSH, that sort of thing. It has some more complex CISC instructions concerned with writing Strings, reading input and manipulating a tree of game objects but they don't form a significant percentage of the instructions actually called in any given execution. The obvious target for optimisation is of course what the machine does most often, i.e. read from its 128K memory: The CMM2 implementation just uses an array of 128K floats, with each float just storing a byte, horrendously memory inefficient, but simple, and memory isn't a limiting factor on the CMM2. - one thing I will experiment with is whether I can use the screen memory of the additional PAGEs as the Z-Machine memory. Is it possible that peeking and poking that will be faster than array variable access? The CMM1 implementation uses a much smaller float array accessing the individual bytes with PEEK and POKE. This float array only contains a subset of the Z-Machine memory with pages being read into it and discarded as required from the SD card, i.e. it uses an implementation of file backed virtual memory. The next target is probably the execute functions, e.g. for the 2-operand instructions: Function execute_2op() Local a, b, x, y, z, _ a = oa(0) b = oa(1) ' JE If oc = &h1 Then x = (a = b) If (Not x) And (onum > 2) Then x = (a = oa(2)) If (Not x) And (onum > 3) Then x = (a = oa(3)) _branch(x, br) ' JL ElseIf oc = &h2 Then If a > 32767 Then a = a - 65536 If b > 32767 Then b = b - 65536 _branch(a < b, br) ' JG ElseIf oc = &h3 Then If a > 32767 Then a = a - 65536 If b > 32767 Then b = b - 65536 _branch(a > b, br) ' DEC_CHK ElseIf oc = &h4 Then x = vget(a) If x > 32767 Then x = x - 65536 If b > 32767 Then b = b - 65536 x = x - 1 y = x < b If x < 0 Then x = 65536 + x vset(a, x) _branch(y, br) ' INC_CHK ElseIf oc = &h5 Then x = vget(a) If x > 32767 Then x = x - 65536 If b > 32767 Then b = b - 65536 x = x + 1 y = x > b If x < 0 Then x = 65536 + x vset(a, x) _branch(y, br) ' JIN ElseIf oc = &h6 Then x = orel(a, PARENT) _branch(x = b, br) ' TEST ElseIf oc = &h7 Then _branch((a And b) = b, br) ' OR ElseIf oc = &h8 Then vset(st, a Or b) ' AND ElseIf oc = &h9 Then vset(st, a And b) ' TEST_ATTR: a = object, b = attribute ElseIf oc = &hA Then x = oattr(a, b) _branch(x = 1, br) ' SET_ATTR ElseIf oc = &hB Then _ = oattr(a, b, 1, 1) ' CLEAR_ATTR ElseIf oc = &hC Then _ = oattr(a, b, 1, 0) ' STORE ElseIf oc = &hD Then vset(a, b) ' INSERT_OBJ: a = object, b = destination ElseIf oc = &hE Then x = orel(b, CHILD) ' original child of destination y = orel(a, SIBLING) ' original sibling of object z = orel(a, PARENT) ' original parent of object _ = orel(b, CHILD, 1, a) ' object is new child of destination _ = orel(a, PARENT, 1, b) ' destination is new parent of object _ = orel(a, SIBLING, 1, x) ' original child of destination is new sibling of object _ = orel(z, CHILD, 1, y) ' original sibling of object is new child of original parent ' LOADW ElseIf oc = &hF Then x = rw(a + 2 * b) vset(st, x) ' LOADB ElseIf oc = &h10 Then x = rb(a + b) vset(st, x) ' GET_PROP ElseIf oc = &h11 Then x = get_prop(a, b) vset(st, x) ' GET_PROP_ADDR ElseIf oc = &h12 Then x = get_prop_addr(a, b) vset(st, x) ' GET_NEXT_PROP ElseIf oc = &h13 Then execute_2op = E_UNIMPLEMENTED ElseIf oc < &h19 Then If a > 32767 Then a = a - 65536 If b > 32767 Then b = b - 65536 If oc = &h14 Then ' ADD x = a + b ElseIf oc = &h15 Then ' SUB x = a - b ElseIf oc = &h16 Then ' MUL x = a * b ElseIf oc = &h17 Then ' DIV x = a \ b Else ' MOD x = a Mod b EndIf If x < 0 Then x = 65536 + x vset(st, x) Else execute_2op = E_UNKNOWN EndIf End Function Note that oc, oa(0..3), br and st are global variables containing the instruction code, operands, branch target and store location for the currently executing instruction. Hunting through that IF block is presumably expensive. I don't know if SELECT CASE is more efficient, but it's not an option if the code is to run on the CMM1. I also can't extract individual operations into their own SUB/FUNCTION because of the 60 SUB/FUNCTION limit on the CMM1 ... I didn't notice the same limitation documented for the CMM2. I'm assuming this could be optimised as a CFunction, but can CFunctions call BASIC functions or will I end up needing to convert the whole implementation into one huge CFunction? Speaking of which do you know if a CFunction is literally a "C" function or could it be multiple functions calling each other without stepping back into BASIC? Is that enough for now, or would you like to know more? Of course this is all hypothetical at the moment since neither CMM1 nor 2 have CFunctions. Best regards, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 8517 |
FWIW I would read the entire z file into an integer array using LONGSTRING APPEND. Then access the individual bytes addr%=peek(varaddr array%()) opcode%=peek(byte addr%+offset%) Then rather than a huge "if then else" or "switch" statement I would binary chop the opcodes in some intelligent way, possibly in two chops, and then have separate "if then else" for each sub group. And of course prioritise the most common opcodes at the top of the clauses |
||||
MauroXavier Guru Joined: 06/03/2016 Location: BrazilPosts: 303 |
In my games and demos, the SELECT CASE was proved to be much faster to use for comparisons with the same variable, at least in a 10ms interrupt routine (SN76489 and 2A03 register simulation and VGM player). |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Thank you, it's worth a lot. Excellent! Not options I had on the CMM1 and my skim of the CMM2 manual hadn't picked up the possibility of using LONGSTRING. Especially pleased to see PEEK(VARADDR ...) I was going to ask for that at some point. Exactly what I was planning on when I got to the optimisation stage. Thanks again, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Good to know, if/when I give up on CMM1 support I will definitely benchmark this. Thanks, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 8517 |
The other thing you could look at is using the EVAL$ function. If you converted the binary opcodes to a string opcode$="F"+str$(op%) then you could use eval$ as a subroutine dispatcher a%=eval$(opcode$) function F01 'handle opcode 01 ...... end function function F02 'handle opcode 02 ...... end function function F03 'handle opcode 03 ...... end function haven't tried this but looks interesting Edited 2020-06-03 21:11 by matherp |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Nice, though again CMM2 specific and requiring support for more than 60 subroutines so perhaps for a later version. EVAL$ is an interesting addition because I believe a BASIC that includes it is uncompilable ... not that you are writing a BASIC compiler. Thanks, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 8517 |
maximum subroutines on the CMM2 is 500! |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
More than enough. I meant a later version of my code when I drop the idea of CMM1 support. Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3641 |
Thanks, Tom & Peter. Eval does look promising but for sure a binary search/chop, or any check that finds the common opcodes quickly, will be far faster than the current linear list of IFs. Just that change might be a speed-up of (say) a factor of 5. John |
||||
cosmic frog Senior Member Joined: 09/02/2012 Location: United KingdomPosts: 277 |
More than enough. I meant a later version of my code when I drop the idea of CMM1 support. Tom I hope you don't drop the idea of CMM1 support. |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3807 |
Dear CF, Thanks for your interest and worry not. There will be at least one CMM1 compatible release, though I won't speak as to whether it will be fast enough to play. This will probably be about a month after the CMM2 release (in a fortnight all being well). I want to automate the process that will create the CMM1 source from the CMM2 source which means writing a rudimentary preprocessor to handle the #Include statements in the CMM2 source and also provide some support for conditional exclusion/inclusion of blocks of code. What happens beyond that depends on the level of interest, if any. Ideally I would like to extend support from stories in .z3 format to cover the other text-based story versions .z4, .z5 and .z8 but if I do that it may be necessary to switch to just targetting CMM2. Regards, Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
cosmic frog Senior Member Joined: 09/02/2012 Location: United KingdomPosts: 277 |
That's brilliant! Thanks. |
||||
Page 1 of 2 |
Print this page |