Hisofts Basic Compiler

======================

There is more than one way to produce machine code programs. If you do not want to learn Z80 assembly language, then why not just continue writing in Basic - get a program to translate your work into machine code for you! Hisoft have a vary powerful Basic compiler, with versions for all Spectrums including the +3.

The compiler, once loaded, occupies 11K of memory - although 128K versions store themselves in the RamDisk, so occupying very little main memory; they also support the PLAY command (and the resulting code can be run on 48K machines, where the PLAY code is simply ignored). The Spectrum+3 version also implements additional Basic commands (only for compiled code) which can read & write serial-type data files on disk.

All interaction with the compiler is via a number of commands; on 48K machines you type a * followed by a single letter (C for compile, etc). 128K machines have a menu called up by pressing TRUE VIDEO & INV VIDEO together; then C or whichever letter is pressed. Functions allow for compilation of the Basic program in memory (which remains for further editing unless the code created is very large), variable type-testing (more on this later), Ramtop resetting (each compilation lowers Ramtop to allow space for the latest code), erasing of the Basic program and separate compilation of the Basic program & Data (if the program is really large).

The compiler supports normal floating point variables as well as integers (-32768 to 32767) and positive-only integers (0 to 65535) and strings, by default up to 255 characters in length. Special compiler instructions (e.g. REM : LEN A$ < 20) specify the maximum length of any individual string, as well as starting and stopping compilation, specifying which variables are to be integers, etc.

An integer variable takes up less memory (2 bytes instead of 5) and can be processed much quicker than a normal one (leading to faster code). However, the accuracy of a normal variable is sometimes needed - examining the code to identify which variables can be integers is often difficult; so the compiler has a function (INFO) which allows the program to be run un-compiled (somewhat slower than normal) and a report obtained indicating what variables were used, and what type they can be. This mode also reports the maximum length of strings used.

Spectrum Compilers are normally very limited as to what code can be translated - that is how they get the code to run faster than Basic. The Hisoft compiler, however, acccepts almost any Basic program (not CLEAR, LOAD/SAVE, RUN and a few other commands that will cause few problems). Some programs need special treatment - for example, if any GOSUB or GOTO commands have computed line numbers (e.g. GOSUB 100*N) then the compiler can be told to produce slightly slower code rather than just giving up!

======================

Other limitations are that DATA statements cannot reference variables (DATA 100*3 is OK, DATA 100*X is not) - this allows the compiler to convert the DATA to a table of values once, instead of every time the program is run. Also, the compiler only supports 1 and 2 dimensional arrays (you cannot have A(1,2,3) for example); and the VAL"..." function must be of the VAL"123" form, so VAL"N*N" cannot be processed (however, the 128K compiler has a way of dealing with this problem).

As a result of the power of this compiler, most programs can be compiled without any alteration - speed improvements will only be of the order of 2 to 5 times, however. If the code is 'tweaked', making if more efficient once compiled, then improvements of 10 to 20 times (or more) are possible - the major benefit of this way of writing programs is that the code can be debugged in the normal way (i.e. very easily) then compiled once it is working fully.

To give an idea of the power of this program, I wrote two short programs which do 'really useful' things - they compute the first 100 prime numbers! All testing was on a Spectrum+3. PRIMES1 is a simple program that calculated each prime by dividing by all previous primes up to the square root of the number being checked - if nothing divides exactly (obviously, the number has to be odd) then the number is a new prime. The program stops after printing the 100th one. PRIMES2 is more complex, and is based on the 'Sieve of Erastosthenes' - it is a program version of crossing out the multiples of each prime; numbers not crossed out must themselves be prime. Again, the program stops after printing the 100th primes (which, incidentally, is 541).

In theory, PRIMES2 is the faster (it is a well worn test of the speed of compilers) - the table shows that +3Basic has trouble running PRIMES2, but straight compilation speeds PRIMES1 2.8 times, and PRIMES2 5.4 times. Note, too, that 48Basic is quite a bit faster than +3Basic ...

Both programs use only integers, so inserting a 'REM: INT+' statement further speeds the programs - PRIMES2 is now 7.8 times faster. It is unfair, however, to compare the programs when so much displaying is occurring; the true speed of the program is held back by the display. So removing the PRINT line is PRIMES2 speeds up from 62seconds in +3Basic to 1.4seconds using integer compilation - an increase of FORTY FOUR times!

These tests shows very clearly what the Hisoft compiler is capable of, with the right Basic program. The compilation process is also quite quick. I compiled a program which took 18secs to poke some code into memory - compilation took 2.6secs and the resulting code executed in 2.2secs, so compiling & running was still 3 times faster than the Basic (this doesn't include the loading time of the compiler, however).

======================

Another area of consideration, however, is the size of the program - compilation will normally increase the size of the program. I tested this using the example programs that came with the compiler. A PACMAN-style program compiled in 8secs from 6150bytes of Basic to 9635bytes of code, and the resulting program was too fast for me to beat. Removing the BREAK option (which means, on 128K machines, that the code cannot be broken into) reduced the code size by 1300bytes. A FROGGER-style game compiled in 7.6secs from 7387bytes of Basic to 8853bytes of code (with the BREAK-in option removed). However, the all-integer version of PRIMES2 actually went down from 381bytes of Basic to 359bytes of code - this is a very impressive result!

One final test, which indicates that 'miracles' may not always occur. I took a GLOBALPLOT program (from Chezron Softwares OUTLET disk magazine, No.18) which takes 50minuutes to run in Basic. With no tuning, the compiled version ran more than twice as fast - in 22minutes!

In summary, Hisofts Basic Compiler is an excellent piece of software for those wanting to write faster than Basic programs without having to learn any new languages - a bonus is that the code is protected (it is almost impossible to take a compiled program and recreate the Basic). The manual is very well presented (no index but good appendices) and has a tutorial section as well as a complete reference of differences between Basic & compiled code. The manual also discusses ways of 'tweaking' the code to improve execution speed. The resulting machine code can be compiled to run at any address, and the compiler does not need to be loaded to run the code. The only bad point is the price - #24.95 on tape or #29.95 for the improved Spectrum+3 version.

Contact Hisoft at The Old School, Greenfield, Bedford MK45 5DE (or telephone 0525 718181).

<<< Please box these programs for reference ...

<<< 10 REM PRIMES1 in Basic. Ian Cull. 18/4/89.

<<< 20 DIM P(1000)

<<< 30 LET P(1)=2: LET PTOP=1

<<< 40 LET PP=1: LET PPS=P(PP)*P(PP)

<<< 50 LET P=3

<<< 100 IF PPS<P THEN LET PP=PP+1: LET PPS=P(PP)*P(PP): GOTO 100

<<< 110 FOR X=1 TO PP

<<< 120 IF INT(P/P(X)+.5)*P(X)=P THEN LET P=P+2:GOTO 100

<<< 130 NEXT X

<<< 140 LET PTOP=PTOP+1

<<< 150 LET P(PTOP)=P

<<< 160 PRINT PTOP,P: INPUT;

<<< 170 IF PTOP<100 THEN LET P=P+2: GOTO 100

<<< 180 STOP

<<<

<<< 10 REM PRIMES2 in Basic. Ian Cull. 18/4/89.

<<< 20 DIM P(1000)

<<< 30 LET P(1)=1

<<< 40 LET PTOP=1

<<< 50 LET PCNT=1

<<< 100 IF PCNT>100 THEN GOTO 200

<<< 110 IF P(PTOP)<>0 THEN LET PTOP=PTOP+1: GOTO 100

<<< 120 LET P=PTOP: LET X=P

<<< 130 PRINT PCNT,P: INPUT;:REM Remove this for speed

<<< 140 LET PCNT=PCNT+1

<<< 150 LET P(X)=1: LET X=X+P

<<< 160 IF X<=1000 THEN GOTO 150

<<< 170 GOTO 100

<<< 200 STOP

<<<

<<< PROGRAM PRIMES

<<< C PRIMES2 rewritten in Fortran

<<< INTEGER P(1000),PCNT,PTOP,PRIME

<<< DO 35 I=1,1000

<<< 35 P(I)=0

<<< P(1)=1

<<< PTOP=1

<<< PCNT=1

<<< 100 IF (PCNT.GT.100) GOTO 200

<<< IF (P(TOP).NE.0) THEN

<<< PTOP=PTOP+1

<<< GOTO 100

<<< ENDIF

<<< PRIME=PTOP

<<< WRITE (2,135) PCNT,PRIME

<<< 135 FORMAT(I3,'=',I3)

<<< PCNT=PCNT+1

<<< DO 150 I=PRIME,1000,PRIME

<<< 150 P(I)=1

<<< GOTO 100

<<< 200 CONTINUE

<<< END

<<<

<<< Continued ...

<<<

<<< PROGRAM primes(input,output);

<<< { PRIMES2 rewritten in Pascal }

<<< CONST top=100;

<<< VAR i,j,ptop:INTEGER;

<<< p:PACKED ARRAY [1..1000] OF BOOLEAN;

<<< pcnt:0..top;

<<< BEGIN

<<< FOR i:=1 TO 1000 DO p[i]:=false;

<<< pcnt:=0;

<<< ptop:=1;

<<< p[ptop]:=true;

<<< WHILE pcnt<top DO

<<< BEGIN

<<< WHILE p[ptop] DO

<<< ptop:=ptop+1;

<<< j:=ptop;

<<< pcnt:=pcnt+1;

<<< WRITELN('prime ',pcnt,' is ',ptop);

<<< WHILE j<1000 DO

<<< BEGIN

<<< p[j]:=true;

<<< j:=j+ptop

<<< END

<<< END;

<<< END.

<<<

<<< End of programs to be boxed for reference.

<<<

<<<

<<< Please also box the following table of timings ...

PRIMES1 PRIMES2 PRIMES2 (No PRINTing)

+3Basic 46.7 67.4 62.0

48Basic 41 50

Hisoft Basic 16.5 12.5

Hisoft Basic (ints) 13.9 8.6 1.4

MIRA Fortran (ints) 0.57

MIRA Pascal (logicals) 1.5

========================

If you feel that it is cheating to use a Basic Compiler (no need to learn anything new) then why not learn a language other than Assembly Code - Hisoft offer a 'C' Compiler (the 'yuppie' of programming languages - no review copy as yet) but MIRA Software (24 Home Close, Kibworth, Leicestershire LE8 0JT) offer Pascal & Fortran Compilers - Pascal was designed as a good teaching language, and Fortran is one of the oldest languages around, and is also quite similar to Basic.

MIRA do not support the Spectrum+3 (and why not?), but both their compilers support both 48K and 128K Spectrums with tape, Sinclair Microdrives, Plus D, Beta and Opus disk interfaces and even Wafadrives. The 128K versions also fully support the RamDisk. Both compilers were reviewed in their 48K tape-only versions by Simon N. Goodwin in Crash issue 45 (Page 118/119). NOTE: The 128K versions are unlikely to run on the Spectrum+2A!

The MIRA Compilers both have a rather unusual user interface. The program source is listed in a similar way to Basic (i.e. in the top screen) but without line numbers. The cursor keys can be used to move up and down the source 1 or 8 lines at a time, or to move to the top or bottom of the program. Pressing ENTER allows new text to be inserted after the current line (until CAPS-SHIFT 6 is pressed), or E allows entry of a single line before the current one. Keys B and K mark the beginning and end of a block and 'cut it' out, the P key allows the block to be 'Pasted' back as many time as necessary. A block can also be deleted completely.

There is a find function (F specifies the search text, N continues through the text) and the source can be SAVEd or LOADed to tape, RamDisk (with the 128K version) or to any available drive (according to the version being run). LOADed text is always merged with what is already in memory - this must therefore first be deletedt (using the memorable (!) sequence SYM-SHIFT 7 B SYM-SHIFT 6 CAPS-SHIFT 0). An option byte allows setting of where the SAVE/LOAD commands are directed to.

Compilation of loaded source is begun by pressing the X key; after a successful compilation both the source and the compiler are lost - 128K versions save to RamDisk first and 48K disk versions save to disk. The 48K tape-only compilers are almost unusable because of this. In addition, there is no access to Basic in the 48K versions once the compiler has been loaded (except a reset) so if a disk/cartridge is full, a new one cannot be formatted or files erased without losing the current source (though you could always save to tape!).

========================

FORTRAN

======

Fortran is easier to pick up for Basic programmers - its layout is similar (apart from needing 6 spaces at the start of every line) and offers named functions & subroutines (but only 6 character names). Fortrans main capability is in its Maths functions (Fortran is an abbreviation of Formula Translation), though the MIRA compiler omits Double Precision and Complex variables, offering REAL, INTEGER & LOGICAL. CHARACTER variables are very poorly supported - stick to Basic if you want to process text.

Fortrans Maths functions include Logs (to base e or base 10) normal & hyperbolic trig. functions (SIN, COS, etc) & the Fortran MAX & MIN functions. The Fortran DO loop is very similar to Basics FOR/NEXT loop, and Fortran also offers block, logical & arithmetic IF statements - enough power for most programs. MIRA have also implemented COMMON & EQUIVALENCE, allowing sharing of variables between subroutines.

Spectrum specific routines include CIRCLE, DRAW, PLOT, BEEP and USR. Fortrans input/output functions are also well implemented, files must be OPENed to streams in Basic before running the program and most FORMAT codes are available for displaying results.

The MIRA Fortran compiler gives very fast code - the non-displaying PRIMES2 program rewritten in integer Fortran was 109 times faster than +3Basic (but the code occupied more than 5K). I did find some bugs in the MIRA Compiler - IMPLICIT declarations do not work, and using LOGICAL variables gives a lot of trouble. The 128K compiler also crashed when I tried to save a new version of a file to Plus D disk.

I also tried the 48K Wafadrive version of the MIRA Fortran compiler - you are very aware that it is a two pass compiler, as a second block of code is loaded in partway through every compilation. In addition, the automatic saving of source before compilation (even if you have just saved it) becomes very annoying. Note: there is also a simple error in the loader program which transfer the files to Wafadrive.

========================

PASCAL

======

Pascal is a very strict language and the MIRA Compiler (which apparently conforms to BS6192 level 1) is no exception. A Basic programmer new to Pascal has little chance of success without buying additional books. Pascal was designed (by Nicklaus Wirth) as a teaching language and there is little chance of mistakes not being spotted during compilation. However, learning where and where not to put semi-colons is a tedious process for Basic programmers.

Pascal offers a wide range of variable types including ordinals (integers), reals, characters and sets (a variable containing one or more items from a defined list). Character processing is much better than Fortran - one of the example programs is a Spelling Checker! MIRA have again implemented Spectrum specific functions including all those available for Fortran. Also TAN, ARCSIN and ARCCOS are implemented, as well as being available in the Pascal definition - this is not clarified in the manual.

Files are again implemented by OPENing them to streams in Basic - however 'internal files' can also be created and destroyed by the compiler (on disk versions only) while the program runs.

The compiled Pascal code is not as fast as Fortran - the non-displaying PRIMES2 program is 'only' 41 times quicker than +3Basic; this is to be expected since the strictness of the language means that a lot of checks have to be made (Range errors - if a variable is given a value it should not have, Type mismatches etc). Again, I found the odd bug in the compiler - the 128K version of PRIMES2 crashed whenever it finished running.

The 48K Wafadrive version of the Pascal compiler was easier to use - compilation does not need to load in extra blocks of code (though the source is still automatically saved every time). In addition the PRIMES2 program did not result in a crash!

SUMMARY

=======

Both the Fortran & Pascal compilers are available from MIRA Software for #15 each - the tape contains all 48K & 128K versions and a few example programs. However, you may have to budget for additional books (only a Pascal book is recommended). Using either compiler in the 48K tape-only version would be very trying (128K tape only use is, however, fine if you save the source before testing it, as you should do with any programming language). Both compilers are good value and offer Spectrum users the chance to learn alternative programming skills. All I want now is a Spectrum+3 version!

=========================

Continuing our look at hacking programs, we now review LIFEGUARD from Romantic Robot (54 Deanscroft Ave, London NW9 8EN) which is an Infinite Lives Finder program that will run on ANY Spectrum fitted with one of RomRobs MULTIFACE devices. These devices are all hardware add-ons which give a games player the ability to halt almost any game, AT ANY TIME, and store the current position to tape or almost any add-on storage device. MULTIFACE ONE will save to tape, microdrive cartridge, Opus, Beta, Disciple/Plus D or Kempston disk interface or Wafadrive (certain interaces require a special version of MULTIFACE). MULTIFACE 128 supports the extra memory of the original 128K Spectrum (and the grey +2) and offers hyperspeed tape saving as well (but loses the Wafadrive option). MULTIFACE THREE works with the 'unusual' hardware of the Spectrum+3 (and the +2A) and can save to tape or the 3inch disk - you can also LOAD disk games from the 'Magic Button' allowing 48K games to be stored on disk.

Except for the +3, all SAVEd games can be reloaded without using the MULTIFACE, which means that its internal RAM can be used to store special programs - GENIE and LIFEGUARD are two such. LOADing LIFEGUARD from tape takes less than one minute, and the program automatically identifies which MULTIFACE is fitted and installs itself. The program is then completely invisible to the Spectrum until the Magic Button is pressed.

You can now LOAD a game and begin playing. At some point, note how many lives you are left, and press the Magic Button. The game stops and the LIFEGUARD menu appears. The first step is to tell LIFEGUARD how many lives you have - press L(ives) then 1(up) or 2(down) to set the counter; 3(set) finishes that part of the procedure.

Next you press S(earch) and LIFEGUARD hunts through the stopped program for possible infinite life pokes. Below the menu is shown how many pokes were found and how many have been tried, and the last poke address. You now press N(ext) to return to the program with the next (first) poke installed, and die. If you lose a life then press the Magic Button again and try N(ext) until you get a poke which stops your lives going down. Then press the Magic Button one final time and note the address shown (SPACE returns you to the game); next time you can use the simple MULTIFACE Tools function to poke this address with zero - you have completed your first hack!

Now, finding infinite life pokes is not always this easy (if it was, we wouldn't have a Playing Tips section!); lives can be counted in Z80 code in many different ways, and LIFEGUARD cannot automatically try every possible way. However, an additional menu option, F(lip), allows different methods to be tried. LIFEGUARD offers two common instructions types (if the first gives no luck, try the second AFTER resetting the lives counter). There is also an option for C(ustom) setting, but you need to know what you're doing - you might be better with GENIE & brainpower!

=========================

However, LIFEGUARD can often find pokes and is very simple to use. I tried few games to test how successful it can be.

First I tried it on EXOLON on a 128K Spectrum. I began playing and immediately got show by the cannon - so I blew this up then pressed the Magic Button. I set the lives counter to 8 and pressed S (using the initial 'DEC A' flip mode) - LIFEGUARD found three possible pokes so I pressed N to try the first. Instant Success! Lots more death, but no more loss of life - I pressed the Button again to reveal the poke address as 40221,0.

I now loaded PACMANIA on my Spectrum+3. This time I set lives to 4 and pressed S - no pokes found! So I Flipped to the 'DEC HL' mode and tried S again; three pokes were found. Again, the first worked - 35141,0.

I tried an older game, NEBULUS, and found a poke of 32921,0. I then loaded up TREASURE ISLAND DIZZY but drew a blank - there is no lives counter (your first death is your last).

LIFEGUARD can be used to find other pokes too. On EXOLON again I found pokes for infinite Ammo (33646,0) and grenades (37456,0) by setting the lives counter to the number of bullets/grenades remaining.

I did not have good luck every time, however. ZYNAPS was one game for which I could find no useful poke - one displayed 6 lives but still ended the game after three. Other pokes did nothing or caused strange behaviour (including a crash).

In summary, LIFEGUARD is a clever program which does very well attempting a nearly impossible task - automatic hacking of games! Anyone owning a MULTIFACE will find LIFEGUARD a useful investment, allowing pokes to be found before they appear in Crash Playing Tips - but not every game is breakable. MULTIFACE itself is a very useful Spectrum add-on in its own right (especially for anyone using faster storage than tape) and is almost essential for Spectrum+3 owners. The Tools function allows pokes to be easily put into any game without having to use massive listings.

LIFEGUARD costs #6.95 but you need a MULTIFACE too (#35...#45) - you should take advantage of last months Crash offer!

Next Month

==========

A look at Animator II, re-released for the Spectrum+3. Also a look at 'free' software - for CP/M on the +3. And more ways to hack games ...

Remember, not every letter can be answered in these pages (due to lack of space!) but an SAE will guarantee a reply if I can help you.