Firstly, I haven't looked at Z80 assembly since my childhood back in the late 80's. Whilst I'm quite competent in modern languages, Z80 assembly is something I've never revisited until I recently built a Z80-based single board computer. This runs a version of NASCOM BASIC, which is itself based on Microsoft BASIC from way back in '78.
Now I've got the computer up and running, I'm taking a break from building the next piece of hardware to add to it and instead focusing on the software for the moment. I'd like to make a few (relatively minor) changes to the BASIC interpreter running on the ROM, and in the process learn something about Z80 assembly etc.
What I'm currently trying to do is make the error messages a little more verbose. My first computer was an Amstrad CPC464, so naturally I'm trying to make the BASIC a little more like what I'm used to (already changed the OK prompt to READY.)
I'm hitting a problem with the error messages though. In its untouched form, the error messages are two-character bytes, like so:
ERRORS: .BYTE "NF" ; NEXT without FOR .BYTE "SN" ; Syntax error .BYTE "RG" ; RETURN without GOSUB
Now the following lines of code handles printing a message:
ERROR: CALL CLREG ; Clear registers and stack LD (CTLOFG),A ; Enable output (A is 0) CALL STTLIN ; Start new line LD HL,ERRORS ; Point to error codes LD D,A ; D = 0 (A is 0) LD A,'?' CALL OUTC ; Output '?' ADD HL,DE ; Offset to correct error code LD A,(HL) ; First character CALL OUTC ; Output it CALL GETCHR ; Get next character CALL OUTC ; Output it LD HL,ERRMSG ; "Error" message ERRIN: CALL PRS ; Output message
Now initially (and somewhat naively) I thought I could just change the 2-character bytes in ERRORS: from, e.g. "SN" to "Syntax" - the word " Error" is added after each error message. I soon realised that this wasn't working, as there's a lookup table listing the location of each error message. Once I found that, all seemed to be roses for a while. I changed the code above so that instead of printing 2 characters and then moving on, it would loop through printing characters until it hit a 0.
; BASIC ERROR CODE VALUES NF .EQU 00H ; NEXT without FOR SN .EQU 02H ; Syntax error RG .EQU 04H ; RETURN without GOSUB OD .EQU 06H ; Out of DATA FC .EQU 08H ; Function call error OV .EQU 0AH ; Overflow OM .EQU 0CH ; Out of memory
I added a zero to the end of each message in ERRORS: and changed the 2-char message to a more verbose one (so .BYTE "NF" became .BYTE "NEXT without FOR",0). I then amended the BASIC ERROR CODE VALUES lookup table (above) to take the length of the verbose error messages into account.
Everything was fine for the first few error messages. I'd tested the system and it worked. So I changed the rest of the error messages and updated the lookup table. Some of the values went as high as 124H etc, and I found I had to add a 0 to the lower offsets to avoid errors in TASM. However, I then started getting other errors - unused MS data errors in lines like LD E,(OS). I suspected this was because the offset was too large for a single 8-bit register like E, so where the errors came up I changed the code to LD DE,(<error msg offset label>) to make use of the full 16-bit DE register.
Obviously that didn't work - it stopped my ROM completely and locked the computer up. So, my long-winded question is winding to its conclusion - I don't currently know enough about assembly or the Z80 registers or the BASIC code I'm editing to know what I did wrong and why it was locking up the computer. I suspect this next bit of code is the culprit - taken from the message printing code further up:
LD D,A ; D = 0 (A is 0) LD A,'?' CALL OUTC ; Output '?' ADD HL,DE ; Offset to correct error code
If the error offset is loaded into E, then the first line above doesn't mess with it. But if, after I changed it to load into DE, D is then changed by the above code snippet, then the offset is going to be corrupted. Should I just remove the LD D,A line and the two after it as I'm not bothered about having the ? mark at the start of the error message either…