• Please review our updated Terms and Rules here

Epson HX-20 - FORTH ROM

Great! Good progress - maybe one more example: just knowing the CFA's doesn't help if we wanted to do the patching from "within" Forth.
See, as @GeoffB17 already explained, the definitions are in the parameter fields. To illustrate - say you have (acutally performed on the HX-20 Forth ):

: test + ;

How do we peek inside the definition of test?

' TEST @ U. -> 25798 OK

And as we already know, this is indeed the CFA of "+":

' + CFA U. -> 25798

How do we know when a definition ends? By checking for some EXIT word in the definition (EXIT does not seem to be defined, but there ought to be something equivalent):

' TEST DUP 2 + @ U. @ U. -> 25668 25798

So, the "EXIT" word in the definition of TEST is at CFA 25668. For all definitions (e.g., if you define

: test2 - ;

you'll also find

' TEST2 DUP 2 + @ U. @ U . -> 25668 26649

(where 26649 is the CFA of '-')

So in the "Forth disassembler" that @GeoffB17 describes, you'll have to go through the parameter field of each word you encounter until you find the 25668 address)

And now what I don't know - for BEEP, we obviously have a valid CFA and WORD - but within the definition of BEEP, we will probably find the "firmware routine":

' BEEP DUP DUP DUP 2+ @ U. @ U. -> 12850 13107

Now, THAT might either be MACHINE code (you can define words also in machine code directly), or it might be the BEEP firmware routine somehwere.

EDIT: So, after all, it might be easier to just edit that stuff in the ROM directly.
 
Last edited:
OK, I think I may have identified most of the subroutine calls:

6087: calls $d715. Unknown. Outputs a message of some description from address $d735 (length 5 characters)?
70F2: calls $d715. Part of the 'Warm?' question to output the message string.

6112: calls $e2ef. Unknown.

74A9: calls $d310. Part of MON word.

7BFF: calls $e3f2. Part of BEEP word.
7EA1: calls $e3f2. Part of TAPCNT word.

7C0E: calls $e34d. Part of COPY word.

7C31: calls $e2a5. Part of FEED word.

7C51: calls $d957. Part of PSET word.

7C6D: calls $d977. Part of PGET word.

7C90: calls d9d6. Part of PLOT word.

7CB8: calls $da07. Part of DRAW word.

7CEC: calls $e1ff: Part of (CLK) word.

7EB0: calls $eb8f. Part of SEEK word.

Most of the subroutines are (clearly) Epson-specific words...

I will have a look and see if I can decipher some of these from the firmware listing. Disassembling the BASIC keyword table may lead to working out where the V 1.1 could call.

EDIT:

I see there is a SOUND function available by calling $ff64. The parameters expected appear to be the same as the FORTH word BEEP - so I wonder if changing the $e3f2 at ROM addresses 7BFF and 7EA1 to $ff64 will work?

I also disassembled the FORTH word PSET - and I can see it constructing what I think is a parameter list to the virtual screen function $C7 to plot a point (i.e. taking the X and Y coordinate from the stack along with the 'colour' and storing them in the parameter block). The only thing I can't see it doing is to actually place the $C7 function code into indexed address X,0. The subroutine address appears to be $ff5e for this - but it may require a small piece of 'helper' code somewhere to store the $C7 before calling the function.

PGET is similar. It sets up the parameter block for a call to virtual screen function $8F (but doesn't store the actual function code itself within the parameter block). The returned pixel colour is read out of the block on return and (presumably) pushed onto the stack for subsequent processing.

PLOT appears to construct another parameter block for a virtual screen function - but I was expecting an additional set of coordinates to be there; but they are not. Just wondering whether the additional set of coordinates (finish X and Y) are processed within the subroutine that is called ($d9d6).

DRAW (on the other hand) appears to fully populate the parameter block with the starting X and Y coordinates, the ending X and Y coordinates and the colour.

All of the parameter blocks appear to start in RAM at address $009C - but none of the FORTH word code itself sets up the virtual screen function code in X,0.

I suspect all of this 'magic' is undertaken within the BASIC helper function (or utility). I tried looking at the BASIC reserved word table - but (unfortunately) it is not the same as the BASICs I know where the subroutine address is stored within the table itself. The table is just a list of reserved words with bit 7 set on the last character of the name. I assume there is a parallel table somewhere of addresses. It can't, however, be too far away from the reserved word table itself. Perhaps that gives me somewhere to look tomorrow?!

It may help if we had the manual and Version 1.0 of the ROMs available - but we are getting there :)...

Dave
 
Last edited:
I have found some of the equivalent commands in the BASIC manual.

I have also identified what I think is the BASIC address table that matches with the reserved word table. I will see tomorrow... It is definitely getting lateen the UK - and I would like to get a quick walk in before I go to bed...

EDIT: I spoke too soon regarding the address table!

Dave
 
Last edited:
When you're doing this sort of thing, it might be useful to use HEX.

That word changes the number base from the default decimal to hex, so the addresses etc will display more usefully?

DECIMAL sets it back.

Worth including HEX in the VLIST2 definition?

I would certainly expect that for many functions involving the hardware, the BASIC code and the FORTH code will be VERY similar, and both will access the same code in the system ROM. There are a number of packages that add new commands to the BASIC, I'm sure there's a table somewhere?

Geoff
 
Last edited:
>>> I'm sure there's a table somewhere?

There will be - it is a matter of finding it of course!

>>> The BASIC code and the FORTH code will be VERY similar, and both will access the same code in the system ROM.

This doesn't actually seem to be true. It seems that the FORTH code unstacks the parameters etc. (as only a FORTH program can of course) and seems to either call the BASIC code to perform the actual action - or a helper function provided by BASIC - or in the utility section of the ROM. From what I have seen, this does approximate to the library routines that are documented - but I see some subtle functionality that is missing from the FORTH implementation to the documented library routines.

If I can get the V1.0 ROM images, I can disassemble the subroutine that is called and we can develop the equivalent code for the FORTH implementation (if we can find some spare ROM space somewhere) so it is ROM independent.

However, tracking down the ROM image is proving tricky. I assume you have a version of the 1.0 ROM - as you have FORTH running? Is there any way of getting a hex dump of your V1.0 ROM in some way? Either that, or can you dump a section of your ROM if I can specify the area(s) of interest?

Dave
 
Yes, I'm trying.

My printer isn't working, so there's a problem there. If I try to use it, there's the sound of it trying then I get a 'Charge Battery' message and the HX goes. Restart and all OK again. My assumption is that some parts of the printer need some lubrication? Not been used for a LOT of years.

My internal tape drive doesn't work either, the drive band is gone. Not got around to trying to fix this, although I have the info to do so, once I can source a suitable repl band.

External tape drive works fine (CAS1:). Also, I can connect to laptop and SAVE as a .WAV file, and reload from there, so actually can get by OK.

I have done a fair bit of work messing with the .WAV files, I have the 'hxtape' utility and I've got this working inder WinDoze (with a lot of help from the author in Italy). This will work if volume levels etc are within bounds, but it's all rather temperamental. This has the added benefit that I can save the file, then use hxtape to convert the .WAV data to ASCII text, edit the text, then use the other part of the software to convert back to .WAV and then LOAD.

I'm trying to do the same thing using the SAVEM command, which basically takes a memory dump and saves it. Currently trying 8000-9FFF which is the first ROM. I've got the initial dump as a .WAV, but it may not be quite right (the laptop was misbehaving at the time, busy doing something else, and of course for this job timing may be critical). Then I tried the conversion, I got a mass of errors and no data. I'll try to get the laptop stable, and try again. I have got a result with SAVEM data before. But only with small amounts.

I'll report when I start to get some results - it's just a latter of getting levels OK

Geoff
 
One thought.

Rather than try to mess with ALL the ROMs.

I suspect that the difference between 1.0 and 1.1 may be fairly minor, but just where, and what?

As I understand it from other info, where the character data is stored the difference is about 8 bytes. By the time we get to the D715 the difference seems to be 15 bytes. I guess that the vast bulk of the code is the same, the addresses are just a few bytes out.

Would there be any value in trying to map the differences. Say every xx bytes, I note what my ROMS give me. I could run a little prog that stores the data to a file, even as a .WAV that I can then 'translate', and this would be a lot more viable than a solid 8k data dump?

In fact, thinking about this, it might be more reliable to do something like that re the bulk data dump. Get a larger .WAV, but that's no big deal. The prog running would mean that the data being sent to the laptop would be slower, so the integrity of the .WAV would be better. I could add a CHK into the data to verify? I'd need another prog to reconstruct the binary ROM image afterwards, but that's no big deal.

I'll experiments with that if my try with the laptop and SAVEM doesn't help?

Geoff
 
My logic was to identify the first 8 bytes or so at the beginning of the subroutine call target within the BASIC 1.0 ROM and then locate those 8 bytes in the 1.1 ROM (as a first approximation).

However, without the 1.0 ROM, I am sunk before I have started...

I have already posted the first tranch of subroutine targets back in post #62.

Dave
 
Last edited:
Right, I'm getting somewhere.

The recording to .WAV is OK, but something with the initial adjustment needed for hxtape was wrong. I needed to remove the .WAV header, but the result needed to be unsigned and I did it as signed. Once I did it as signed, hxtape produced a binary file.

But.

It's not the right size. It's a bit too big, and I'm trying to work out why.

The 8k ROM file for FORTH is 8192, which is correct for 8k raw data.

The file I've got for the 8000-9FFF ROM is 8960. This is still the SAVEM data though, and the SAVEM data includes some block overhead. Allowing for this, the file is still a bit too big, but I don't YET see why.

If I compare the first few bytes with the &H8000 Monitor Dump on the HX, this agrees. If I compare the last few bytes in my file with the &H9FF1 Dump on the HX, this agrees. The header for each block includes the memory address, the last block in the file shows the correct address. So where's the extra data coming from?

However, I attach the file I've got, as you might be able to do something with it. You can see the Command Table data. You might be able to find other things. You might spot my problem.

The record structure here (different to prev SAVEM data I've looked at) comprises a 1 byte record size , followed by a two byte start address, followed by 64 bytes data to go into ROM, followed by 1 byte (I assume a CHK). To create a plain memory image file I need to read the data 68 bytes at a time, discard the first 3 bytes and the last byte and put the remaining 64 bytes to the new file.

I'm still looking at this.

Geoff
 

Attachments

  • 8000A.ZIP
    7.3 KB · Views: 3
Aha - I've found the problem with my file.

The file should be 0000-21FF, this is 128 x 68 byte records, which with the header info removed will give the correct size.

BUT, the file is actually 8960, and occupies 0000-22FF. The last 100 (hex) bytes is actually a repeat of the previous data, and needs to be discarded. Maybe all down to buffering somewhere in the file manipulation process. When I write my prog to process the file to the raw ROM data (no SAVEM headers) then I just read the 128 records and forget the extra ones and the new file should be correct.

Then do the same with the other ROMs (A000-BFFF, C000-DFFF, E000-FFFF).

I've not done so, data may be all OK, but might need to check the CHKs?? I'd leave this unless we find some oddities in the ROM data, OK?

Geoff
 
New file attached. This one has block headers removed, and is correct size for 8k ROM.

This one is for HX Memory Range 8000-9FFF.

If this seems OK, I'll get the rest done. Should be no problem now everything is clear.

Geoff
 

Attachments

  • 8000B.ZIP
    6.8 KB · Views: 12
Michael - I've just checked on the Stardot forum and I see that you were asking there about this as well.

We should get somewhere here, I hope you will update the other forum with any result to keep things tidy there too?

Geoff
 
@GeoffB17 and all, IT WORKS! Just "downgraded" to your 1.0 OS - THANK YOU SO MUCH!
Whereas it would be GREAT if FORTH also worked with 1.1, for me, this is good enough! Wonderful! THANK YOU!

Regarding the other forum - absolutely, I'll post a thank you note there as well!

20220327_154152.jpg20220327_154200.jpg20220327_154208.jpg20220327_154210.jpg
 
Great, but not so much the 'thanks', much more to explain that the problem is that the HCCS FORTH works with the 1.0 system ONLY, and fails with he 1.1, owing to the use of direct calls into the ROM code.

If you (we ?) can do some sort of 'fix' for this, it would be a big help. We could do something via changes to the FORTH ROM code, that do not involve the system getting any bigger, as the 8K space is fully used. Otherwise might not be possible. Just need to see what the eventual extent of the problem is?

Geoff
 
Ok, I think I have a preliminary list of patches to the FORTH ROM itself to convert from V1.0 ROMS to V1.1 ROMS.

I have one (1) subroutine call 'in the wind' at the moment. This is part of the MON word, and I suspect that the monitor itself has been completely moved in the V1.1 ROMS. As we suspected, most of the other locations have been 'shifted' - although the number of bytes doesn't appear to be wholly fixed - and sometimes the offset is negative (indicating some code has been moved/removed).

FORTH Address $6087 calls $D715. Patch to $D724. Outputs a message "Error".

FORTH Address $6082 points to a message string "Error". Patch to $D744. This is the "Error" message referred to above.

FORTH Address $70F2 calls $D715. Patch to $D724. Outputs the message "Warm?"

FORTH Address $6112 calls $E2EF. Patch to $E2C0. Usage unknown.

FORTH Address $74A9 calls $D310. Part of MON word. Unidentified patch at the moment. The FORTH word MON will still TRAP as a result.

FORTH Address $7BFF calls $E3F2. Patch to $E3C6. Part of BEEP word.
FORTH Address $7EA1 calls $E3F2. Patch to $E3C6. Part of TAPCNT word? Not too sure why TAPCNT would output a sound though? Perhaps I will disasseble TAPCNT later to see!

FORTH Address $7C0E calls $E34D. Patch to $E31E. Part of COPY word.

FORTH Address $7C31 calls $E2A5. Patch to $E276. Part of FEED word.

FORTH Address $7C51: calls $D957. Patch to $D967. Part of PSET word.

FORTH Address $7C6D calls $D977. Patch to $D987. Part of PGET word.

FORTH Address $7C90 calls $D9D6. Patch to $D9E6. Part of PLOT word.

FORTH Address $7CB8 calls $DA07. Patch to $DA17. Part of DRAW word.

FORTH Address $7CEC calls $E1FF. Patch to $E1E0. Part of (CLK) word.

FORTH Address $7EB0 calls $EB8F. Patch to $EB57. Part of SEEK word.

This addresses any subroutine calls (JSR) - and the odd message pointer I have identified during my disassembling - but this may not address everything of course! There may be jumps (JMP) instructions that I will have a look at next. Other instructions may also refer to locations within the 1.0 ROM set as well.

Let's see how far this gets us first shall we?

Dave
 
Last edited:
Back
Top