Locomotive BASIC
Locomotive Basic is a proprietary dialect of the BASIC programming language written by Locomotive Software. It was modified (many custom features to support the platform) for use on the Amstrad CPC as "Amstrad BASIC" (where it was built-in on ROM). Later Locomotive BASIC-2 was produced for the IBM PC compatibles platform as a GEM application on the Amstrad PC1512 and 1640 and was a descendant of Mallard BASIC,[1] the interpreter for CP/M supplied with the Amstrad PCW. There are two published versions of Amstrad BASIC; 1.0 which only came with the CPC464 (and had a buggy DevelopmentDevelopment was based on existing work recently undertaken writing Mallard BASIC for Acorn Computers Z80 addon for the BBC Micro. It is reported to have taken around 12 weeks to enhance the existing code, and was "very influenced" by BBC BASIC, though adding additional functions to do things that would have required assembly language on the BBC.[1] The "ARNOLD" platform (the CPC464 development codename) was designed to be solid enough to attract the "serious" users Amstrad wanted. Locomotive were engaged to produce the firmware and BASIC for the platform. The mix produced a comprehensive result with technical capabilities almost unheard of in any one contemporary platform - the tidy approach to firmware access with fixed jump blocks, the hypothecation of the firmware into modules, the clever hardware allowing expandability, with multiple pages of RAM and ROM all occupying the same address-space, simultaneously accessible, re-locatable display memory etc. many of which appeared only partially, or not at all on rival platforms. Features of the CPC platform![]() ![]() ![]() If a programmer is concerned only with writing in a rich BASIC dialect they have an excellent machine on which to ply their skills and there is no reliance or expectation the programmer will ultimately have to resort to machine code or study the function of the hardware to produce good quality software. However, to fully comprehend the ethos behind Amstrad BASIC and push the machine to its limits, it is necessary to understand, at least superficially, the design approach to the machine as a whole. Fundamentally, the CPC platform consists of clever hardware with a rich firmware to exploit it; compartmentalised into sub-systems with standardised jump tables to access functionality. Amstrad BASIC was written to expose as much of this platform and firmware as possible to the programmer. Firmware jump blocksAt a machine level on the CPC platform, application software need not be concerned with code moving about in the actual firmware e.g. for different versions and re-assembly. In many contemporary machines, re-assemblies of the firmware and subsequent moving of routines can cause major headaches. A notable example was the disastrous 1983 Timex modified ZX Spectrum (the ROM modified as T/S 2000 BASIC). Due to a lack of structure, many system calls moved in the subsequent re-assembly. The resultant firmware was incapable of running many extant ZX Spectrum programs - instantly denying access to a huge software library and alienating users. With the Locomotive approach to system calls, so long as programs use the documented addresses, this is never an issue. Consider the firmware call $BB5A TXT_OUTPUT (put a single character on the screen), it is ubiquitous - but note from below the firmware vectors are different in BASIC 1.0 and BASIC 1.1 ($9400 vs $93FE). As long as programs use the published function address (i.e. $BB5A), software will run on all CPC platforms with no issues. ![]() The firmware jumps have changed between versions but the address for TXT_OUTPUT remains $BB5A. ![]() The firmware modulesKernel Key Manager Text VDU Graphics VDU Screen Pack Cassette / AMSDOS (AMStrad Disc Operating System) Sound Manager Machine Pack Maths Pack Amstrad BASIC leveraged and exposed the platform being written to take full advantage of the machine, bundling up BASIC code into the requisite calls into the firmware,[2] providing specific commands for functionality rather than reliance on generic *FX or PEEK & POKE statements required to access features on competitor platforms. BASIC and version differencesInternal version numbers of the BASIC ROM differ from the accepted, published versions discussed here. Although not unique, the platform was unusual among contemporaries in that it used the ASCII character set rather than its own idiosyncratic form - an arguable strength as it instantly made the CPC platform a more serious offering, somewhat underpinning Amstrad's marketing claims of it being capable of professional business use. In common with many other dialects, multiple program statements are separated on a single line using the colon
Reserved words (functions, commands, statements etc.) are capitalized in a program by virtue of being tokenized. This reduces program size and accelerates execution. Listing a program then decodes the token to its reserved word which are all in upper case in the token table (it was this method which revealed the presence of DEC$ in BASIC 1.0 - see below). When saving a basic program, the fully tokenized form is saved in a binary format. Alternatively, saving with option "A" creates a fully text compatible ascii file e.g. BASIC 1.0Supplied with the Amstrad CPC464, it was a good release with only a single notable bug, being the ![]() Exploration of the BASIC 1.0 ROM can find the remnants of the function and its crippled token table entry. BASIC 1.1Supplied with the CPC664/6128, besides fixing DEC$, it introduced (among others) the following additional keywords: COPYCHR$, CURSOR, FILL, FRAME, GRAPHICS PAPER, GRAPHICS PEN and MASK - continuing in the vein of BASIC exploiting the firmware and any advancements therein. It also introduced a clumsy but adequate method of trapping disc errors with the Variables and functionsVariable names must begin with a letter and can be up to 40 characters long; made up of Three data-types are supported signified by an identifier suffix on the variable name and can be selectively presumed by use of the
Unlike some dialects, variable names are unique down to type, e.g. Dimensioned variables (arrays) have 0 as their lowest element number(s), and can use square brackets around their elements which helps distinguish them from other parentheses in complex expressions in program code. e.g. Named single-line functions are supported and follow the type and name convention of variables but pre-fixed with The address of a variable in memory can be determined with the @ directive, e.g. Integer and Real variable values are stored in the variable table (see memory map below). String variable contents are stored on the heap. This allows the aggregation of fragmented memory via Garbage Collection. Consequently, for strings, the variable table holds a three byte descriptor made up of the length of the variable and the address in the heap where the actual contents are to be found. Two missed opportunities?BBC Basic uses a clever method for handling some integer variables, which despite claims of its heavy influence on Locomotive BASIC (and by extension Amstrad BASIC), was not replicated in the latter. BBC BASIC has a 54-byte table reserved for the values of the 27 single letter integers For strings, the descriptor is three bytes in the variable table, made up of a length descriptor and a further (little-endian) address of the actual payload. Had the value returned by @ been the two byte address in the heap (and the length prefix moved to the heap also) this would have substantially reduced access time by replacing the two address lookups with just one. ![]() Variable table structure for strings. Graphics and colourHandling of graphics and colour was straightforward with commands such as With Amstrad BASIC V1.1 (CPC664 onwards), the A table giving the numeric codes for the 27 system colors was printed on the casing of the built-in 3" disk drive on the 664 and later machines. Text handlingText moves through the system using a concept of "streams" numbered 0–9, appropriate commands use the hash Streams 0-7 are text windows. The TEXT_VDU firmware pack allows for the creation of multiple text windows each with their own cursor, dimensions, content, colours etc. An individual window is addressed using its stream number, e.g. Stream 8 is the centronics parallel port. To send a line of text to the printer one could use the command Stream 9 is the currently open file (either cassette or disc, input or output) and relevant commands are context sensitive; e.g. it is possible to have both input and output files open simultaneously with Advanced featuresA stand-out feature among almost every other BASIC of the time is a timer-based software interrupt mechanism at 50 ticks per second using the The interrupt ability requires some method to limit its impact when unwanted. Two commands; Amstrad BASIC granted a relatively high level of control over the sound chip, an AY-3-8912 with 3 tone channels and 1 noise channel and interrupt driven sound generation with comprehensive co-ordination of the three audio channels and associated BASIC commands: All disc, tape and file management managed by BASIC is through the firmware and are adequate for simple file management with commands such as ![]() Also available is a parametric Machine code support and RSXsMachine code is well supported (but not to the impressive heights of the BBC Micro's, in-line assembler). There is an easy method of allocating "safe" memory (see below) and once loaded either from disc or cassette or Another method, leveraging the firmware, allows for named sections of machine code using a feature known as Resident System eXtensions (RSX). Although not a purely BASIC feature, Amstrad BASIC embraces this mechanism of RSXs and the names can be used in the BASIC program as if they were reserved keywords - each being prefixed with the bar In UK CPC circles at that time, it was popular to pun words that began with "bar" and name RSXs accordingly, e.g. |BQ, |BARASTREISAND, |STARD etc. Memory allocation and managementGenerally speaking, BASIC programmers do not have to concern themselves too much with the inner workings of their chosen platform to get decent results. Should a programmer wish to ignore them and stick only to BASIC, they are well catered-for with a speedy, rich dialect. For those who want to go beyond and want more control, they are likewise accommodated. In many contemporary systems, allocating a block of memory seems an after-thought with no "proper" method of achieving it. Innovative methods were adopted by programmers which resulted in some, often, highly cryptic and fiddly methods, such as creating Amstrad BASIC program space occupies RAM from $170 extending to somewhere around $A6F0 (varies with BASIC version and other considerations), just under the BASIC system area, AMSDOS area and the high jump blocks - a little over 41KB. Numeric variables and functions etc. are located immediately above the program with the remaining, free memory in between termed "the heap". The contents of string variables are stored in the heap near the very top, with just the string descriptors being stored in similar fashion to numerics in the variable table - just above the program (see Variables and functions above). BASIC program code grew up and strings grew down towards each other in RAM, gradually consuming the heap in between. Amstrad BASIC has a garbage collector which de-fragments the heap to maximise usable memory - as with most computer languages, as strings are created then sliced/deleted, chunks of un-used memory occur between used parts and the heap can become "porous". Notably the BBC Micro did not have garbage collect and manipulation of strings could result in "out of memory" errors simply because a requested block did not exist in one chunk. In common with other dialects, Amstrad BASIC provides the FRE() function to return the amount of free heap. The function has two forms: Amstrad BASIC provides the function, The CPC range makes provision, through the SCREEN_PACK, for User Defined Graphics (UDG) whereby the 8x8 pixel matrix for a character can be redefined allowing for the creation of special characters. By default, the top 16 characters (128 bytes) are "soft" and if that is sufficient, no further adjustment is required. Following on the ethos of exposing the platform capabilities in BASIC, it passes forward this functionality and the memory for UDG is allocated from the heap (i.e. the more characters, the lower The simplified default CPC memory map as it appears to BASIC. ![]() Memory bank switching and a notable omissionAlthough as a BASIC implementation, Amstrad BASIC is fairly complete and goes to great pains to support the CPC platform, one notable omission in all versions is native access to the memory bank switching mechanism used to expand the Z80 memory space; re-using address ranges by overlaying sections of physical ROM or RAM. Through an arrangement of the custom circuitry, switching pages into one of the four 16KB pages in the Z80 memory map ($0xxx, $4xxx, $8xxx, $Cxxx) is possible. For instance, the top page ($C000) is (usually) occupied by both the video RAM, the BASIC ROM and (on disc equipped machines) the AMSDOS ROM with the hardware and firmware providing the necessary control of access. The firmware ROM is bank-switched to the lower 16KB, extra RAM (that beyond the Z80 64KB e.g. the additional 64KB of the CPC6128) and sideways ROMs (containing user machine code or 3rd party software) are mapped to the top page ($C000) - RAM can actually be mapped to any bank as evidenced by the 61KB TPA (Transient Program Area - free program memory when running CP/M+.). Clearly the OS requirements are more than 3KB. ![]() The CRT controller generally maps to the 16KB video RAM at $C000 in the main Z80 address space with the hardware ensuring the video picture is not interrupted when other banks were switched into the same page. As an aside; To facilitate clean CPU and CRTC access to the same memory, the hardware is required to match bus access time to a constant number of clock cycles and any instruction will be "stretched" (utilising the WAIT signal on the Z80 control bus) to the next 4th cycle, so; any instruction running on the Z80 will always be a multiple of 4 T-states, i.e 4, 8, 12 etc. despite published timings for the Z80. This resulted in very slightly slower code performance than the fastest contemporary - the BBC Micro. All CPC models supported this fairly advanced (for the time) bank-switching to increase the potential memory storage - even an un-expanded CPC464 uses fully 96KB of ROM and RAM mapped into the Z80 64KB address space. Memory writes are always applied only to RAM in the main 64KB address space, regardless of switched state, e.g. if the lower ROM ($0-$3FFF) is switched into the memory map, The CPC464/664 hardware can address up to 256KB including up to eight 16KB sideways ROMs, controlled by the large custom chip. One position is used by the BASIC ROM and both the CPC664 and CPC464 expanded with the FDI1, use a further slot for the AMSDOS ROM - leaving six slots. The CPC6128 hardware permits bank switching up to 4MB with increased space for 16 (32 with a PCB hack) 16KB sideways ROMs. Again, two positions are occupied with BASIC and AMSDOS leaving 14 available for user or 3rd parties. The KERNEL provides several methods of accessing banked memory; some involve a pseudo 24bit address via a vector or extending the HL register pair using the C register. For ROMs only the high or low ROM switching is controlled by the top two bits of a 16-bit address. Still others can retrieve data from a bank as if it were in the mainstream Z80 address map or directly from the main 64KB of RAM regardless of the state of the banks. Kernel routines to access banked memory include Prior to "calling sideways", i.e. switching in a bank and jumping to execute machine code at an address there, the kernel assembles structures on the Z80 stack to ensure the safe capture of inbound Despite BASIC not providing support for this kernel functionality, use of banked memory in a BASIC program was certainly possible but required the use of machine code routines to do the switch and take advantage of the result. Banked memory could not be used for BASIC program code. On the bundled CP/M 2.2 and CP/M+ (CPC6128) discs was a two-part program to add primitive-but-adequate bank-switching commands to BASIC. When run, Besides using banked memory to store screen images and rapidly switch between them, some applications implement "RAM Discs" but these are not supported under the cassette/AMSDOS firmware, being quite proprietary. Contemporary rivals
Unlike the Commodore 64's built in BASIC (Commodore BASIC), which had no dedicated commands for graphics or sound, Amstrad BASIC allowed doing pretty much anything that was within the standard capabilities of the machine. This was not unimportant, as some other machines of the era required programmers to use assembler in order to access the full sound and graphics capabilities of their system. MSX, Sinclair Spectrum and some others offered a similar, more or less complete command set for their sound and graphics capabilities. The only things going clearly beyond BASIC capabilities were the overscan modes used in games and demos, 27-color graphics modes, digital sound playback, and smooth scrolling. Unlike Sinclair BASIC or Commodore 64 BASIC, which had various keyboard command shortcuts or specialized keys for choosing symbols or colors, Amstrad BASIC keywords were typed in full and the interpreter parsed, recognized and tokenised them. However, there were abbreviations like " References
External links |