JGH Spectrum ROM Modifications ============================== J.G.Harston - jgh@arcade.demon.co.uk http://www.mdfs.net/Software/Spectrum/Harston This is a patched Spectrum 48K ROM which fixes many bugs and adds some useful extensions. JGHROM is the ROM image, and Patch/src is the source code, written in BBC BASIC Z80 assembler. The Spectrum ROM is copyright Amstrad. Amstrad have kindly given their permission for the redistribution of their copyrighted material but retain that copyright. The extra code is copyright J.G.Harston and may be redistributed, and may be extracted and used in other code, with attribution. This ROM is compatible with the Interface 1. As many entry points as possible are preserved, but it may not work with systems that depend on code being in particular places. Bugs fixed ========== The following bugs listed in the Complete Spectrum ROM disassembly are fixed: * NMI routine, CHR$8, CHR$9, scroll?/press any key, CLOSE#, SCREEN$, "X"+STR$Y, -65536, Divide bit34. Note, the bugfix code in the CSRD for the -65536 bug is wrong. This ROM is patched with a correct bugfix. The following bugs are also fixed: * SKIP_CONS writing to ROM, INKEY#0, screen scrolling writing to ROM. * The 'Out of Memory' code at &1F15 now calls the ERROR restart. This should allow the Interface 1 to switch off microdrives when it hits the out of memory bug. * DEC_TO_FP divides by 10 instead of multiplying them by 1/10, as per Geoff Wearmouth [http://www.wearmouth.demon.co.uk/Features.htm]. * The current line cursor error is fixed, as per Geoff Wearmouth [http://www.wearmouth.demon.co.uk/gw03/gw03page.htm]. * Colour and drawing commands select channel "S" to avoid colour codes being sent to microdrive channels, as per Geoff Wearmouth [http://www.wearmouth.demon.co.uk/gw03/gw03page.htm]. Changed preferences =================== On startup, the screen is set to black border and paper, and white ink and CAPS is on. The startup message says ", JGH" at the end. Extensions ========== Once all the bugs were fixed, I added the following additional features: * Lines entered character by character, and tokenised into Basic. As a consequence of this, there is no extended mode. All symbols entered with Symbol-Shift, the copyright symbol is Symbol-Shift-I. By default, tokens must be in upper case, and may be abbreviated with a '.'. This can be changed by changing FLAGS2 at &5C6A. * When CAPS is on, pressing Shift produces lower case. * An additional ASCII keyboard on port &FD/&F9 is scanned. * New "P" and "C" channels that write to a Centronics port on port &FB. If b1 of FLAGS at &5C3B is zero, then channel "P" expands tokens and sends after . If b1 of FLAGS is set, channel "P" acts like channel "C". Channel "C" writes raw data to the centronic port without interpreting it as text. By default stream 4 is attached to channel "C" and closing stream 4 will reattach it to channel "C". * INK/PAPER/BRIGHT/INVERSE/AT/TAB out of range is ignored. * CHR$12 performs a CLS. * Integers can be entered in hexadecimal with &, ie PRINT &4000, and can be output in hexadecimal with PRINT~ and STR$~. * CAT[#s] will catalogue from tape, ended by pressing SPACE or an error. The display lists the files' type and name, followed by the length, start address and extra (execution) address in hex. * SAVE s$ CODE extended to SAVE s$ CODE start,length[,extra[,reload[,type]]] * CALL numeric will call an address. The CALL token replaces the COPY token. * Replacement font, based on the BBC font. * INPUT can use channel "S", but the effects are rather strange at the moment. * RUN s$ or *filename will load and execute a CODE file from tape or microdrive as machine code, for instance RUN "MDump" or *MDump. The code is entered at the address in the 'extra' field, with DE pointing to any command line parameters. When running from tape a temporary stack is used, so code that never returns can safely overwrite the existing stack without CLEAR having to be used first. Running from microdrive should also use a temporary stack and may do in future. * *d: or RUN "d:" will set the default device for running machine code to the specified device: T: for tape, or 1: to 8: for microdrive. If an Interface 1 is present 1: is initially selected on NEW/RESET, otherwise T: is selected. * RST &08 out of range gives "Unknown command" error, so using Interface 1 hook codes without the Interface 1 present gives a sensible error message. * Calculator literal &3C which calls e_to_fp is unusable as e_to_fp expects a parameter in the A register, and calling it via the calculator corrupts A. Consequently, e_to_fp is only ever called directly. Literal &3C has been used to give STR$~. * OPEN can attach a stream to any non-extended channel. You can even open a stream to channel "R"! An extended channel is detected by it's output address being &00xx. If you create new channels they must be in the following format similar to Interface 1 channels: entry+0,1 : output address - must not be &00xx or &xx80. entry+2,3 : input address - must not be &00xx entry+4 : channel character entry+5,6 : &0000 entry+7,8 : &0000 entry+9,10: channel length, eg 11 for this example. * RAMTOP defaults to &F7FF to reserve memory for transient commands to be loaded at &F800. * On RESET, if Symbol-Shift is pressed, extra memory for transient commands and channel "C" is not claimed. Entry points to new routines ============================ Some of the additional routines are accessible through extra fixed entry points in zero page. &0005 RESTART - Restart spectrum with specified maximum memory -------------------------------------------------------------- On entry: DE=highest memory location to use A must be zero and INTs disabled before calling On exit: never exits Not really an additional entry, but documented for completeness. &0013 PRHEX0 - Print byte in B with leading zero ------------------------------------------------- On entry: B=byte to print On exit: A,B,D corrupted &0015 PRHEX - Print byte in B ------------------------------- On entry: B=byte to print D=0 for no leading zeros, D=ASC"0" for leading zeros On exit: A,B,D corrupted &0025 SCANHEX - Scan hexadecimal -------------------------------- On entry: CH_ADD=>first character of hexadecimal string On exit: CH_ADD=>first non-hex character DE=hex value A corrupted &002B PR2HEX0 - Print word in BC with leading zeros --------------------------------------------------- On entry: BC=word to print On exit: A,B,C,D corrupted &002D PR2HEX - Print word in BC -------------------------------- On entry: BC=word to print D=0 for no leading zeros, D=ASC"0" for leading zeros On exit: A,B,C,D corrupted &0060 SRCHTABLE - Search a token table -------------------------------------- On entry: DE=table start (no prefix byte) HL=string to decode C=token value to start with. Stops when C=0 B=flags, b7=IgnoreCase b6=NoAbbrs b5=Termination type If b7=0, the case must match If b7=1, case is ignored If b6=0, tokens can be abbreviated with '.' If b6=1, tokens must be entered in full If b5=0, tokens don't need to be seperated by, eg spaces If b5=1, tokens must be followed by nonalphanumeric character When lines are entered in command mode, the default settings of b7-b5 are taken from b7-b5 of FLAGS2 at &5C6A. On exit: If token found, A=token value, F=NC If not found, A=first byte of string, F=C BC,DE,HL corrupted &0063 TOKENISE - Tokenise a BASIC line -------------------------------------- On entry: HL=source string DE=destination B=flags to pass to SRCHTABLE On exit: Source string has been tokenised AF,BC,DE,HL corrupted Access to new hardware ====================== The modified ROM allows access to extra hardware. New printer port at &FB ----------------------- The "P" printer stream and "C" centronics stream access a Centronics parallel printer on port &FB. OUT &FB,n writes data and strobes the printer. IN &FB returns a busy/ready signal in bit 7. If b7=1, printer is ready (or absent). If b7=0, printer is not ready. This also releases &5B00-&5BFF for other uses. Additional ASCII keyboard port at &F9/&FD ----------------------------------------- The keyboard routines scan for an external ASCII keyboard as well as the Spectrum ULA matrix keyboard. IN &FD should return the ASCII data and IN &F9 should return the keyboard status, b0=shift, b1=control, b4=control codes need translating. The ASCII codes are translated to Spectrum keypresses: Ctrl-letter -> UDG characters Ctrl-@ -> CHR$127 for copyright ASCII 127 -> CHR$12 for delete &80+ -> (key AND &8F)+16*shift+32*ctrl Memory locations ================ &5C3B FLAGS b1=0 Text output, b1=1 raw output on printer channel "P". Was flag for ZX Printer, but the ZX Printer has been replaced. &5C6A FLAGS2 b7/b6/b5 holds tokeniser flags, zero by default. &5C7F CURDRV Current default device, ie "T" for tape or "1"-"8" for microdrive. Was P_POSN, but the ZX Printer has been replaced. &5C80/1 NMIADD As the Interface 1 uses the old NMIADD at &5CB0, the NMI now uses &5C80 instead. This used to be PR_CC, used by the ZX printer routines. The ZX printer had been replaced by the parallel printer code, so PR_CC is now free &5CB0 PRCOL This was NMIADD, but is now used by the Interface 1 to hold the current RS232 text output column. &5CB1 WIDTH Width of RS232 text output stream. The following memory locations are spare: &5C3B FLAGS b4 - Indicates 128K mode on Spectrum 128. &5C3C TVFLAG b7,b6,b2,b1 - spare &5C6A FLAGS2 b1 - was "Printer buffer not empty" &5C71 FLAGX b4,b3,b2 - spare Executing machine code ====================== When machine code is run with *command or RUN s$, it is loaded to it's load address, and entered at its execution address, stored in the 'extra' field. [[If the 'extra' field is &FFFF, then the code is entered at its load address.]] Code is entered with registers set to the following: If Cy=0 Entered via USR x or CALL x. BC=entry address, A, DE, HL undefined. If Cy=1 Entered via *command or RUN s$. BC=entry address, DE points to command tail, A, HL undefined. *commands have stream 2 selected. CALL/USR have whichever previously selected stream selected, so if called from the direct mode, will have stream 0 (Keyboard) selected. The code should finish with a RET. The contents of BC will be returned to the user if called with USR. *command and CALL can trash all registers, but USR must preserve HL' to return successfully. History ======= 28-Sep-2004 v0.74 Running machine code from tape is silent. 26-Sep-2004 v0.73 Running machine code from microdrive finally works! Needs tidying up a little bit. CHR$12 gives CLS, RST &08 out of range trapped. Sets default drive if Interface 1 present. 18-Sep-2004 v0.72 Channel "C" causing Interface 1 to fall over, added length to channel information. NEW was forgetting channel "C" and Interface 1 was clearing #4 and channel "C". Added Geoff Wearmouth's changes to make INPUT use stream 1, fix current line cursor bug, colours select stream &FE. 15-Sep-2004 v0.71 Added Geoff Wearmouth's DEC_TO_FP bugfix and scrolling to ROM bugfix. RUN was incorrrectly calling SYNTAX_Z instead of CHECK_END. Added "C" channel, OPEN and CLOSE deal with any short channel. "P" and "C" actually act on BREAK. 18-Nov-2003 v0.70 RUN "filename" and *command. Fixed tokeniser bug where PRINT INK 2 became PRINT IN K 2. "P" printer channel defaults to "text" output, where tokens are expanded and a is added after a . Calculator literal &3C used for STR$~. 27-Oct-2003 v0.60 Fixed bugs where CAT d would catalogue from tape, and then from microdrive, and SAVE "x"CODE s,l,e tried to save during syntax check phase. 02-Sep-2003 v0.50 Rewrote the source code. The original source was a text file of hand-assembled code, cut up into pieces and glued into place, and modifications written over. The code was 'assembled' by poking the byte values into the ROM image in memory. This worked, but was very difficult to extend, so the source now exists as the file 'Patch/src'. By doing this I managed to get STR$~ working. The startup message has been returned to the original as per Amstrad requirements, with "JGH" at the end to indicate the modified ROM. 13-May-1985 v0.50 Started trying to get STR$~ working. xx-xxx-1985 v0.40 Fixed entry points for additional routines. Hex input with &xxxx and output with PRINT~. CAT from tape and extended SAVE. xx-xxx-1985 v0.30 Looks for Ascii keyboard, "P" stream goes to parallel printer. xx-xxx-1985 v0.20 -65536 bugfix corrected. Lines tokenised. 12-Jan-1985 v0.10 Bugs fixed, new startup colours and message, but -65536 bugfix wrong. Future extensions ================= When I get around to it, I intend to add the following additional features: Bus in the extended ROM: * If PRHEX or PR2HEX are called to print 0 with no leading zeros, nothing is printed! PRINT~ and STR$~ use a workaround to avoid this, but it needs fixing properly. * Code running from tape should be a silent search. Extensions I would like to complete: * Extend LOAD/SAVE to allow "d:filename", auto-translating LOAD "1:filename" to LOAD *"m";1;"filename", etc. * Check Shift on RESET and do something with it. * |name to execute memory-resident RSX command, kept above RAMTOP. * Fix INPUT from "S" problems.