Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 21:48 29 Mar 2024 Privacy Policy
Jump to

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 Kingdom
Posts: 3807
Posted: 11:44am 14 May 2020
Copy link to clipboard 
Print this post

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: Australia
Posts: 175
Posted: 02:09am 15 May 2020
Copy link to clipboard 
Print this post

I think your signature line is very appropriate in this situation  
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3422
Posted: 06:36am 15 May 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3807
Posted: 07:44am 15 May 2020
Copy link to clipboard 
Print this post

  Volhout said  Wow,


Thanks it's 50-75% done I think ... But it has been in that state for several months whilst I have been flashing LEDs.

  Quote  The CMM2 should allow you to run full ZORK 1. You don't need a mini version.


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.

  Quote  Is there a thread about your ZORK port


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.

  Quote  I guess you started on CMM).???


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.

  Quote  I volunteer if you need help, either testing, or coding.


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 Kingdom
Posts: 277
Posted: 09:30pm 15 May 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3807
Posted: 03:18pm 23 May 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3807
Posted: 07:18pm 30 May 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3807
Posted: 10:37am 03 Jun 2020
Copy link to clipboard 
Print this post

Moved from its original thread

  JohnS said  Do you have a list of the kinds of things you'd likely get a fair speed increase from?  (Not sure I'll understand your list as I don't know the Z M so a sort of simplified high-level short list may be the best?  Skip it if that's not meaningful, of course.)


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 Kingdom
Posts: 8517
Posted: 10:54am 03 Jun 2020
Copy link to clipboard 
Print this post

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: Brazil
Posts: 303
Posted: 10:55am 03 Jun 2020
Copy link to clipboard 
Print this post

  thwill said  I don't know if SELECT CASE is more efficient


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 Kingdom
Posts: 3807
Posted: 11:00am 03 Jun 2020
Copy link to clipboard 
Print this post

  matherp said  FWIW


Thank you, it's worth a lot.

  Quote  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%)


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.

  Quote  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


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 Kingdom
Posts: 3807
Posted: 11:01am 03 Jun 2020
Copy link to clipboard 
Print this post

  MauroXavier said  
  thwill said  I don't know if SELECT CASE is more efficient


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).


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 Kingdom
Posts: 8517
Posted: 11:08am 03 Jun 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 3807
Posted: 11:15am 03 Jun 2020
Copy link to clipboard 
Print this post

  matherp said  The other thing you could look at is using the EVAL$ function ...


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 Kingdom
Posts: 8517
Posted: 11:18am 03 Jun 2020
Copy link to clipboard 
Print this post

maximum subroutines on the CMM2 is 500!
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3807
Posted: 11:21am 03 Jun 2020
Copy link to clipboard 
Print this post

  matherp said  maximum subroutines on the CMM2 is 500!


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 Kingdom
Posts: 3641
Posted: 02:37pm 03 Jun 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 277
Posted: 09:29pm 03 Jun 2020
Copy link to clipboard 
Print this post

  thwill said  
  matherp said  maximum subroutines on the CMM2 is 500!


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 Kingdom
Posts: 3807
Posted: 09:42am 04 Jun 2020
Copy link to clipboard 
Print this post

  cosmic frog said  I hope you don't drop the idea of CMM1 support.  


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 Kingdom
Posts: 277
Posted: 09:48am 04 Jun 2020
Copy link to clipboard 
Print this post

That's brilliant!

Thanks.
 
     Page 1 of 2    
Print this page
© JAQ Software 2024