A long, long time ago, there was a little firm called CURRAH, and the people at CURRAH had a dream ... They dreamt that they could create a magic box that would give the mysterious ‘Spectrum User’ powers beyond imagination.
Unfortunately, CURRAH went bust before their dream became reality, but their black box that gives you FORTH, an Assembler and a debugging tool, all from within BASIC, is now available from Quadhouse Computers. At £19.50 Paul Gardner finds it hard to resist.
Back in early 1984, MicroSource was conceived as an idea. It was originally to be a ROM based BASIC compiler and assembler package. It soon became apparent though, with the prices of ROM chips as they were, that the BASIC compiler would either have to be quite limited or expensive to produce. The next idea was to offer a Forth compiler and an assembler. That was possible because of the compact nature of Forth code. It was finally designed and tested but then CURRAH went into liquidation. MicroSource was not forgotten, however, and the rights to the package were bought by DK’tronics in mid 1984. Then it was forgotten. Now, more than a year after it was finally completed, Quadhouse Computers have negotiated the rights to distribute MicroSource, and at a much lower price than was originally intended.
The final MicroSource package is a plug-in ROM based module that gives you access to Forth, an Assembler and a ‘Software Front Panel’ debugging tool. The box itself is similar to the CURRAH MicroSpeech package, but smaller. It is another ‘last in the line’ add-on for the Spectrum, so you will need a motherboard of sorts if you want to plug in any other products that don’t have a through connector.
The MicroSource circuit holds two chips, a 4K masked ROM and a small ULA. The ROM is switched in whenever a new variable is created. Because of this it is necessary to make sure that the Interface 1 variables are installed first if you have an Interface 1 attached — either cause an error or do a CAT of your microdrive.
The assembler is a full Z80 assembler that supports macros with local labels, conditional assembly, powerful pseudo-ops, various number bases and an expression evaluator that allows you to import the contents of pre-defined BASIC variables into machine code. The assembler is invoked by a statement:
and the assembly routine then follows this statement as a list of REM ! lines eg:
810 LET assemble=0 820 REM ! org 3200 830 REM !start ld a,2 840 REM ! defm a$ 850 REM ! ret 860 — (basic program continued) —
The contents of the variable a$ are imported onto the assembly routine during assembly and occupy the bytes reserved by the DEFM pseudo op.
Any labels used in the assembly routine are set up as BASIC variables and can be used directly in a BASIC program. So for the above routine, RANDOMISE USR start would call the routine.
The assembler outputs the machine code it produces either directly into memory, or to any opened channel if you have an Interface 1 fitted. Object code produced can be saved onto microdrive files or event sent over the network. For non microdrive owners the assembler will print a ‘map’ of the object code locations, so that you can save it to tape using the usual SAVE "name" CODE routine.
As your source code is assembled, the assembly listing produced can be output to screen, printer or again, to any opened channel. Listing 2 is an assembly listing of the routine contained in the demonstrated program.
Three subroutines in different languages achieve the same thing: turning lower case characters into upper case characters — a tedious example, maybe, but it shows how you can take a BASIC variable (Z$ here) and use it in three separate languages!
10 REM demo program for micro source 20 CLEAR 63000 30 GO SUB 500: REM define forth words 40 GO SUB 900: REM assemble m/c 50 REM set up test string 60 PRINT "Please wait" 70 PRINT " - setting up string" 80 LET s$="" 90 FOR i=32 TO 127 95 LET s$=s$+CHR$ (i) 100 NEXT i 105 REM lengthen the string 110 LET s$=s$+s$ 120 LET s$=s$+s$ 130 LET s$=s$+s$ 140 LET s$=s$+s$ 150 LET s$=s$+s$ 160 PRINT "Length of string is ";LEN s$;" chars" 170 INPUT "Press enter to continue";n$: CLS 180 LET z$=s$: PRINT "Basic start" 190 GO SUB 400: REM basic routine 200 PRINT "Basic end" 210 INPUT "Press enter to continue";n$: CLS 220 LET z$=s$: PRINT "Forth start" 230 GO SUB 700: REM forth routine 240 PRINT "Forth end" 250 INPUT "Press enter to continue";n$ 260 LET z$=s$: PRINT "M/C start" 270 GO SUB 1300: REM forth into m/c 280 PRINT "M/C end" 290 STOP 300 REM subroutines in different languages 310 REM to change a string to upper case 320 REM 400 REM Basic subroutine 410 REM 420 FOR i=1 TO LEN (z$) 430 LET y$=z$(i) 440 IF y$>="a" AND y$<="z" THEN LET y$=CHR$(CODE (y$)-32): LET z$(i)=y$ 450 NEXT i 460 RETURN 470 REM 500 REM Forth definitions 510 LET forth=0 520 REM # % upcase 530 REM # OVER * SWAP 540 REM # DO 550 REM # I C@ 560 REM # DUP DUP 96 > 570 REM # SWAP 128 < AND 580 REM # IF 590 REM # 1101111B AND 600 REM # I C! 610 REM # ELSE 620 REM # DROP 630 REM # THEN 640 REM # LOOP : 650 REM # 660 RETURN 670 REM 700 REM actual run time call 710 LET forth=1 720 REM # COPY Z$ upcase 730 RETURN 740 REM 900 REM m/c routine definition 910 LET assemble=1 920 REM ! list 3 930 REM ! opt 2+4+16+32+64 940 REM ! org 63000 950 REM !mcr push af 960 REM ! push hl 970 REM !save push bc 980 REM ! push bc 990 REM ! pop hl 1000 REM ! dec hl 1010 REM ! ld b,(hl) 1020 REM ! dec hl 1030 REM ! ld c,(hl) 1040 REM ! pop hl 1050 REM !loop ld a,(hl) 1060 REM ! cp 97 1070 REM ! jp m,notlo 1080 REM ! cp 123 1090 REM ! jp p,notlo 1100 REM ! res 5,(hl) 1110 REM !notlo inc hl 1120 REM ! dec bl 1130 REM ! ld a,b 1140 REM ! or c 1150 REM ! jp nz,loop 1160 REM !resto pop hl 1170 REM ! pop af 1180 REM ! ret 1190 RETURN : REM back to basic 1200 REM 1300 REM forth interface to m/c 1310 LET forth=0 1320 REM # COPY Z$ DROP GET mcr USR DROP 1330 RETURN : REM back to basic
The Assembly listing produced when MicroSource assembles lines 920 to 1180 of the first listing.
MicroSource CURRAH 1984 920 0000 list 3 930 0000 opt 2+4+16+32+64 940 F618 org 63000 950 F618 F5 mor push af 960 F619 E5 push hl 970 F61A C5 save push bc 980 F61B C5 push bc 990 F61C E1 pop hl 1000 F61D 2B dec hl 1010 F61E 46 ld b,(hl) 1020 F61F 2B dec hl 1030 F620 4E ld c,(hl) 1040 F621 E1 pop hl 1050 F622 7E loop ld a,(hl) 1060 F623 FE 61 cp 97 1070 F625 FA 2F F6 jp m,notlo 1080 F628 FE 7B cp 123 1090 F62A F2 2F F6 jp p,notlo 1100 F62D CB AE res 5,(hl) 1110 F62F 23 notlo inc hl 1120 F630 0B dec bl 1130 F631 78 ld a,b 1140 F632 B1 or c 1150 F633 C2 22 F6 jp nz,loop 1160 F636 E1 resto pop hl 1170 F637 F1 pop af 1180 F638 C9 ret 0 Total Errors mor F618 save F61A loop F622 notlo F62F resto F636 Start Length 63000 (F618H) 33 (0021H)
Forth Vocabulary: SWAP DUP ?DUP DROP OVER ROT PICK(*) RP(*) . ? U. H.(*) C.(*) TYPE ."(*) EMIT CR SP + - 1+ 1- 2* 2/ * / MOD /MOD NEG MAX MIN ABS AND OR(*) XOR(*) RL(*) RR(*) @ ! +! C@ C! ' CONST VAR = <> > < O< NOT >= <= I I' J >R R> RP(*) IF ELSE THEN DO LOOP +LOOP BEGIN UNTIL WHILE REPEAT ABORT(*) HERE ALLOT , C, H(*) FORGET EMPTY LAST(*) #(*) STACK(*) LINK(*) ( MOVE USR(*) GET(*) PUT(*) COPY(*) TOK(*)
Those words followed by (*) are different to the Forth ’79 standard in some way.
The Forth is invoked from BASIC by the statement:
after which the Forth system will execute or compile the following lines as Forth code. Like the assembler, the Forth lines in a program start with a REM statement:
890 LET forth=1 900 REM # 2 DUP + 32000 C! 910 REM # % newword 100 10 DO I, LOOP ; 920 REM # newword 930 — (basic program continued) —
For technical reasons, any Forth definitions are started with a % (percent) sign instead of the usual : (colon).
Forth definitions are compiled into a dictionary which can be saved to tape or microdrive and later re-loaded and linked into the dictionary, although only if loaded back into the original memory locations.
The Forth language supported is a small subset of Forth ’79. Most of the omissions cover virtual memory, double length number handling and most of the useful commands for creating your own data and language structures. Some useful additions include the ability to pass variables between BASIC and Forth and the ability to pass parameters into, and then call, machine code routines. Listing 3 gives the full list of Forth words supported. Those marked with an asterisk differ from the standard in some way.
A=00 F=SZ0H0PNC M=F618 BC=0000> FC AF 11 FF FF C3 CB 11 DE=0000> FC AF 11 FF FF C3 CB 11 HL=0000> FC AF 11 FF FF C3 CB 11 IX=0000> FC AF 11 FF FF C3 CB 11 IY=5C3A> FF CD 00 B1 F5 6B AD 00 F558> 00 00 00 00 00 00 00 00 SP=F560> 00 00 00 00 00 00 00 00 F568> 00 00 00 00 00 00 00 00 F570> 00 00 00 00 00 00 00 00 F600> 71 15 F6 21 17 9B 36 98 F608> 03 00 05 00 00 49 71 44 F610> 71 52 1C 76 1B 03 13 00 PC=F618> F5 E5 C5 C5 E1 2B 46 2B F620> 4E E1 7E FE 61 FA 2F F6 F628> FE 7B F2 2F F6 CB AE 23 F630> 0B 78 B1 C2 22 F6 E1 F1 F638> C9 00 00 00 00 00 00 00 F640> 00 00 00 00 00 00 00 00
The screendump of a typical Debug Front Panel display — in this instance, displaying the machine code routine, again derived from lines 920 to 1180 of Listing 1.
The debugging part of the package is a ‘software front panel’ that allows you to step through machine code routines while displaying the contents of all, or some of the Z80 registers and a section of memory. Listing 4 shows a screen dump of the form panel, as it views the machine code that was assembled from the demonstration program. Debug also allows you to display memory contents as screens full of hex bytes or ASCII characters. There are a number of commands that allow you to selectively step through machine code routines, with the option of following, or not following, subroutine calls as you wish.
For all the potential of Debug as a tool it is badly let down in two respects. It is very difficult to follow a machine code routine that is simply displayed as hex bytes. If only the current instructions were displayed as the Z80 assembly mnemonics it would be easier to use. The other problem concerns print-outs. I use an old Kempston printer interface and when Debug tries to send the display output to my printer the entire system crashes! However, I have been assured that Debug works perfectly with Interface 1 and any serial port printer, or the original Sinclair printer.
The simple demonstration has a main BASIC part that sets up a string of 3072 characters of mixed character codes. The program contains three ‘subroutines’, one in BASIC, one in Forth and one in assembly language. These routines are functionally identical in that they will convert the string in Z$ so that all the lower case letters are changed to upper case ones. Before any of the routines are called, the Forth lines need to be compiled and the assembly code needs to be assembled. After that, the test string is set up and each routine is used to convert a copy of the test string. The retrospective timings for the routines are some indication of the speed advantage to be gained by not using BASIC for the repetitive or slow sections of a program:
It is unfortunate but there are some. Given the history of this product, we are unlikely to see a bug free ROM being released. Apart from the error in Debug which stops it printing out to a Kempston printer interface, there seems to be no serious bug in the Assembler-Debug part of the package. The most serious bug I have found is in the Forth. Contrary to the Forth ’79 standard, in this version you can use the word ." (dot-quote) outside word definitions but not inside word definitions! For you BASIC fans, that’s like having a version of BASIC that won’t let you PRINT text strings written as part of the program... For similar reasons you may as well not include comments in your Forth programs because if you’re not careful they cause some very spurious errors that you will never find.
One other ‘bug’ is that you can only transport the values and addresses of simple variables between the BASIC, Forth and assembly language. This means that you cannot easily get Forth to do processing on BASIC arrays. This is a real pity, as array processing is one of the most time-consuming elements of BASIC programming.
The assembler itself is worth the £19.50 that is being asked for the whole package. If you are aware of the bugs in the Forth then it is easy to evade or avoid them. The manual is very good and explains things in just the right amount of detail. The program listed in this article should show you some of the power the MicroSource offers you. I shall certainly buy this one! (High praise indeed — ED)