ZXSimulator

Anything QL Software or Programming Related.
User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Tue May 05, 2020 10:22 am

P.S. I'm trying to get permission to post the improved source for Minesweeper since I didn't write the original and don't want to post someone else's code that I modified since it wasn't listed under GPL or anything. Once I get the word I'll put it on here. If anyone wants to give it a try in the meantime PM me and I'll send you the change.


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Tue May 05, 2020 10:10 pm

So for fun I converted the ZX81 Minesweeper game to SuperBASIC. It plays faster than it does on a ZX81 but not by that much (maybe 4-5 times). Clearing out half the screen took a little over 2 minutes and it took a little over 10 on the ZXSimulator running the same game -- so 4-5 times slower is a considerable wait of an extra 7-8 minutes -- but other parts ran at similar speed and I will likely further speed up the ZXSimulator eventually to catch up a bit. After all, I'm writing a BASIC interpreter and SuperBasic is just that as well, though more efficiently implemented. On the actual ZX81 it wasn't quite 10 minutes but I think it was close to that.

Here's a pic of it playing:

Minesweeper.png


Here is the ZX81 version on ZXSimulator which runs slower.

Minesweeper-zx.png


I do like the look of the ZX81 version better. You can get that look on the QL (and even better of course) but you'd have to do some graphics futzing to get to it. I just print out character code 255 to get the stippled patter on the QL but it leaves a gap between boxes...I like how the ZX81 doesn't. The characters aren't as easy to generate on the QL so I didn't bother trying to invert characters, etc. That's the one nice thing about doing quick development on the ZX81...you are limited with graphics but you can do those limited ones quicker.

If I get permission by the author I will post both the ZX81 modified version and the QL converted version.

BTW, so a FOR loop in SuperBasic does not increment beyond the end number. The ZX81 does quite the opposite. So a loop from 1 to 70 on the ZX81 ends at 71 and on the QL it ends at 70. Even weirder when you have this: FOR I=3 TO 10 STEP 5, as it ends at 13 on the ZX81 and at 8 on the QL. Funny because I had it working originally like the QL and had to change it to the ZX81. It's why the value at the top left corner of Minesweeper is 69 on the QL one as the code does a N=N-1 after the loop ends (will need to remove that line). These are the insane idiosyncrasies you have to figure out when simulating an environment and there have been a bunch :-/


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Wed May 06, 2020 10:31 pm

Hi,

I got permission to publish the Minesweeper game. The attached zip file contains these files:

  • minesZX_bas - this is the ZX81 BASIC that can run on ZXSimulator or any ZX81 (emulator or real) if converted into .p or tape file
  • minesZX.p - just the zxtext2p.exe converted file of the first (minesZX_bas) for one of the ZX81 emulators (I use EightyOne)
  • minesSB_bas - this is the converted QL SuperBASIC version that runs a bit faster though the interface is a bit more plain
  • README_txt - repeats this above

It's a really fun game and very playable on the ZXSimulator on an unexpanded QL. If you really want to see it go, use an accelerated QL. It does take a bit of time set up the board but I did add some output that tells you the progress (in addition to letting you choose key mapping - I use the arrow & space so I can use my joystick). Once the ZXSimulator version plays it becomes pretty playable (unless it clears out half the board because of a random clear path, then it'll take some time and sometimes it appears to be stuck but it is just getting out of a long nesting loop which takes time).

minesweeper.zip
(5.94 KiB) Downloaded 18 times


User avatar
pjw
Super Gold Card
Posts: 660
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway
Contact:

Re: ZXSimulator

Postby pjw » Thu May 07, 2020 11:55 am

I briefly tried the SuperBASIC version under SBASIC on SMSQmulator and AFAICS it seemed to work fine. Since I dont have a number pad, it wasnt much fun, but it should be easy enough to change that to using the cursor keys.


Per
Be wary of large West-Coast corporations bearing gifts!
- Ancient Trojan proverb
User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Thu May 07, 2020 7:59 pm

pjw wrote:I briefly tried the SuperBASIC version under SBASIC on SMSQmulator and AFAICS it seemed to work fine. Since I dont have a number pad, it wasnt much fun, but it should be easy enough to change that to using the cursor keys.


It's set up for you to change it on startup. Just hit the "c" key (in reality you can hit any key but "r") and then you can select space and cursor keys.

minesSB.png


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Thu May 07, 2020 10:13 pm

I realized the QL version of Minesweeper had a bug. I had to comment out line 3310 since the QL's FOR loop ends at "no greater than" the end condition whereas the ZX81 FOR loop goes past it. So in a FOR I=1 TO 70 loop the QL ends at 70 and the ZX81 ends at 71 (and tries to correct it at line 3310).

Code: Select all

3310 REMark  QL FOR LOOP DIFFERENT FROM ZX, SO IGNORE: LET N=N-1


The issue comes up when you are about to win since you'll have 2 mines left but it only shows 1 and if you "mark" the penultimate one it will say you didn't get them all. Fixed. I didn't catch it on the QL version because I kept screwing up when playing it since with text-only graphics it's really hard to see sometimes when a number is next to a marked mine (i.e. when diagonal) and so it's easier to make a mistake and accidentally try and clear a space when it shouldn't be.

Perhaps someone that's got some experience with SuperBASIC graphics can fix the game so it looks more like it does on the ZX81 with inverted graphics for marking the mines. The only two Minesweeper games I've seen on Dilwyn's site are executable that require some other library to get it to run so having a SuperBASIC-only version might be nice and the algorithm that Bodo Wenzel created is solid.

Of course if you have an accelerated QL then by all means, use my ZXSimulator with minesZX_bas :-) It works on an unexpanded QL but it is slower than the SuperBASIC version. I just learned about Chroma 81 so I might eventually add in color compatibility for those games that are in BASIC and have been colorized so they can be played in full color on the QL. There are a good bit of BASIC games on the ZX81 and those should all eventually run on the ZXSimulator.

minesweeper.zip
(5.96 KiB) Downloaded 13 times


Enjoy!


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Sat May 09, 2020 10:36 am

Latest version of ZXSimulator:

zx.zip
(29.11 KiB) Downloaded 11 times


New:

  • DIM now is multi-dimensional (currently up to 6 dimensions) for numbers. Strings still only a single dimension
  • FOR loop fixed to match ZX81 so it ignores extra NEXT and skips to next if loop is zero.
  • Code generally cleaned up and these changes, which were significant, only netted an extra 200 bytes so not bad.

Took me a bit to figure out how to take multiple dimensions and flatten them out but I exhaustively looked at a 3x3x3 matrix of 27 values and finally came up with:

((index_1-1)*dim_1+(index_2-1))*dim_2+index_3

So if you are getting at index A(3,2,1) then that yields the 22'nd entry in a linear array of 27.

Which translated out more generally to:

(((...((index_1-1)*dim_1+ ... + (index_m-1))...)))*dim_m+index_n { where n = m-1, i.e. m is the second-to-last one }

I'm sure I could have found the formula online but it was more fun coming up with it.

Still has issues, including not reading lines exceeding more than 128 bytes so some long lines need to be split up to work within it but that's usually easy to do. Also, still integer-only though I started looking at the upgrade. It's not hard to do but I want to keep it fast so I may want to only switch to floating point when needed and stick with integer otherwise. Digital 'C' SE uses function calls for all its floating point operations and stores numbers in 48 byte values (i.e. int num[3]).

And with integer-only I still have the hack for RND where it looks for the * operator right after and then the next value. So if someone writes INT (10*RND) then you get huge integer values since RND returns a number between 0 and 32768, but if you flip it to INT (RND*10) you get what you expect: a number between 0 and 9...(temporary hack).
Last edited by bwinkel67 on Tue May 12, 2020 12:42 am, edited 8 times in total.


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Sat May 09, 2020 9:22 pm

So here is a working idea I've come up with to integrate floating point into the ZXSimulator but keeping it integer focused. I want to create integer values with optional decimal values (i.e. I'm not trying to create a true single-precision floating point value specified by existing formats -- like say IEEE 754). I don't like that Digital 'C" SE forces 48 bits (i.e. 6 bytes) on you via an integer array of 3 (with short integers being 16 bits). It doesn't give a 32 bit option unfortunately. Plus I want to keep the speed of integers for things like loops that don't use floating points, etc. Presently I have three arrays associated with variables:

  • long integer (i.e. 32 bit address) array for names containing pointer to each character string (i.e. the variable names)
  • integer (i.e. 16 bit) array for value (i.e. the integer value of the variable)
  • long integer (i.e 32 bit address) array for either strings (pointer to 8 bit char array) or DIM''ed number (pointer to 16 bit integer array)

So at minimum 10 bytes per variable plus the number of bytes the variable name is and presently, for integer variables, I keep a string equivalent numeric value. However, it' s not that bad because these are only single values, so if you have 10 variables you multiply that by 10 and add the size of the character string for the integer value (I may get rid of that in the future and zero it out). Note that for DIM'ed arrays I don't associate the second long integer array with it so only the 16 bit numeric values are stored.

So my thinking is that I want to avoid tripling the integer value, which doesn't seem bad as you only add 4 more bytes per value for single variables but becomes a problem for DIM'ed arrays. Minesweeper has a single dimensioned array of 672 values and that would grow from a 1.3K to 4K just to hold those values which only encompass a total of 30 small numbers per array entry.

The plan is to add a second integer array that holds the decimal value. I was thinking of making it a character array and trimming my floating point to 255 (may still try that) but three digit precision might not be so great (in fact it's really 2 digit since you can't get 999). With 16 bits unsigned I could get 5 digit precision up to 65536 (ok really 4 digit for 9999). More importantly, if the floating point array value is 0 then I can ignore it and use the integer portion only as is, so if I'm running a loop and my start, step, and increment are all integers I avoid the other array's value in the computation (no use adding 0's). I can do this by keeping a global flag around that gets turned on if any computation yields a non-zero value in the second array and if it does then a few routines that deal with math will have to switch to the floating point math functions (i.e. add a switch into a few functions).

Now doing this and not blowing up the code will be tricky but I don't think it will. So if you only program in integer values then the flag doesn't get flipped and the code should run pretty close to the speed of what it does now (except the extra time to do the switch which is pretty fast). And for memory, it will only double arrays so Minesweeper's array of 672 values will go form 1.3K to 2.6K. But will 4-5 point precision be enough to get close to what most BASIC programs on the ZX81 do? One alternative hybrid approach would be to keep the full 48 bit floating point at the variable level but trim DIM'ed arrays to 32 bits (or even 24 bits) so that any variable computations not involving arrays can be full precision. I can still split it and ignore the decimal when doing integer calculations. So maybe this 48/32 (or 48/24) bit hybrid approach may be my final solution.


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Tue May 12, 2020 6:48 am

Finalized an initial design for floating point in ZXSimulator (with the restrictions that Digital 'C' SE puts into place). Floating point values will be stored in 32 bits. Addition and Subtraction will now be 32 bit operations, compared to 16 bit presently. Not sure if that will slow things down but the 68008 is a 32 bit processor with 8 bit data bus so I'm guessing it has to grab twice as much data (4 reads vs 2) and put that back into memory; so slightly slower. All numeric arrays will be 32 bit as well. Multiplication and division will likely take longer since the 32 bit values need to be converted to 48 bits and adjusted to work within Digital 'C" SE's floating point libraries.

The largest positive number to be represented will be 214,748 and only 4 decimal precision will be available. The largest number seems much smaller than what the ZX81 can do but that's a tradeoff (same with decimal precision). The goal is to keep the speed as fast as possible especially with the most common operation of addition and subtraction (i.e. many programs do this to move loops along, etc). With this implementation, floating point addition and subtraction will actually be done as integer addition and subtraction so the only speed loss here is the extra two bytes on the data bus. That was the key of me choosing this initial design since there are floating point library functions in Digital 'C' SE that would do this for me in that weird 48 bit representation (i.e. fadd and fsub), but I wanted to stick with the operators (+ and -) since by their nature they'll be faster.

The idea is to basically multiply all numbers by 10000 (I'll have to see if shifting and adding by 13, 11, 8, 4 is faster) which will then store in a 32 bit integer with 4 lower digits representing the decimal. So a loop that goes from 1 to 5 by step 1 will now go from 10000 to 50000 by step 10000 internally and the addition of larger numbers shouldn't really change things. When displaying to screen, basically you put a decimal point between 4th and 5th digit (and not show the decimal if all 0's). When doing multiplication and division, with use of the floating point conversation routines from 32 bit integer to 48 bit internal pseudo-floating point (3-int array) an additional divide (by 10000) is needed to generate the floating point number for the 48 bit representation. That will, unfortunately, take time, so multiplication and division will be slower. But I'm fine with that. Most games I've tried so far use +/- much more to compute what they are doing (even implicitly in FOR loops).


User avatar
bwinkel67
Gold Card
Posts: 330
Joined: Thu Oct 03, 2019 2:09 am

Re: ZXSimulator

Postby bwinkel67 » Tue May 12, 2020 10:00 am

I've been compiling ZXSimulator on a fast PC running QLAY2 on Windows. Being at the 8-week mark of this project I wanted to be a bit authentic and create an executable that was actually compiled on my QL, close to the way I would have done it with the original interpreter in the 90's. Back in the day I didn't have extra memory but did eventually get a Kempston disk-interface expansion card and a 3.5 inch floppy. I initially developed the interpreter with Digital 'C' SE using MDV drives before I upgraded to the floppy.

Now I don't own a floppy anymore and I wanted to avoid sitting through failed MDV cartridges so I stuck with vDrive which doesn't really add anything else and just emulates MDV's with 128KB of data capacity (so that was pretty close). If I had good MDV cartridges, after a lot of whirring, I'd get to the same place (instead of the soothing whirring I get the beeping of vDrive, which isn't quite the same). I don't think vDrive actually speeds up the data reading/writing part.

My setup had MDV3 holding the source (zx_c) and MDV4 holding Digital 'C' SE containing the following (I don't have vMap so MDV1 and MDV2 aren't available to me for the SD card). Note this only leaves 13K free.

  • cc - parser
  • cg - code generator
  • lg - linker (not needed)
  • config - used to configure above three for MDV3/MDV4 -- set to MDV4
  • stdio_h - base header file
  • std_lib - base library
  • mc_obj - base obj fiel
  • trap1_c - not sure if needed
  • vutil_c - not sure if needed
  • arc_exe - my favorite archiver back in the 90's by Ralf Biedermann

So with only 2 MDV's you basically have to move cc from MDV4 to MDV3 to clear out space for the generated object file needed on MDV4. Then you type:

exec mdv3_cc

...and when prompted you enter -p -m mdv3_zx_c and wait about 23 minutes (it took a while) and voila, it compiled. Ironically, I was watching Babylon 5, a mid 90's scifi show on TV, while doing this (we get about 3 hours a night here on Comet TV).

Then you delete the source off of MDV3 and copy zx_obj from MDV4 to MDV3 (deleting it off of MDV4 when done) and copy cc from MDV3 back to MDV4 and delete it off of MDV3...so you basically swap the two files. You then type:

exec mdv4_cg

...and when prompted you enter mdv3_zx mdv3_zx -nc and wait about 6-7 minutes and then you have the executable. BTW, in the 90's I divided my source code up into 4 files but haven't gotten it to work since (haven't tried on the QL so it may be an emulator issue and how it deals with media or maybe MDV vs FLP).

I then used arc_exe to compress it (via Huffman). What's nice with arc_exe is that it creates a text file that can be transported to another machine and when unarchived it keeps the executable information (like zip/unzip) but only takes up 4K of space for the archiver itself (zip can't run on an unexpanded QL).

So attached are two files. The first is zx_arc.zip which contains zx_arc, the archived executable compiled 1990's style (sans vDrive) on my QL. I really wanted to just attach the archive file since it doesn't need to be ZIP compressed but qlforum won't let you so I had to use Window's ZIP. To use it, just grab zx_arc and dump it into a directory on an SD card (if using real hardware) or a WIN directory on an emulator and use qlayt.exe to add it (but no need to worry about data space for executables since it's a data file) and then use arc_exe to expand it.

zx_arc.zip
(20.39 KiB) Downloaded 9 times


...and I included my version of arc_exe which is 4 bytes larger than what's on Dilwyn's site. You'll need unzip to expand it into a runnable executable. I got this back in the early 90's and I have no idea how since this was before the worldwide-web and I didn't use bulletin board systems. Maybe a member from our local user's group (NESQLUG) gave it to me along with the text editor (QED) I used to write the original version of the BASIC interpreter. Funny to think back on how information was shared in the 90's.

arc_exe.zip
(2.57 KiB) Downloaded 8 times


Enjoy. The ZXSimulator executable isn't really any different form the last version though it has improved syntax error handling (i.e. displaying a more accurate message when BASIC gets into trouble).
Last edited by bwinkel67 on Wed May 13, 2020 3:28 am, edited 3 times in total.



Who is online

Users browsing this forum: No registered users and 2 guests