Background
Back in mid-May I disconnected the Ardino Mega from BEN2 and subsequently I didn't have any process to update BEN2 ROM. This meant that I was totally dependent on the existing ROM monitor program at address $8000 (called xmodem-2-shell-1 or mon2 for short) for loading any code I wanted to test or run.
In mid-June I successfully implemented a program (write-romx) which enables me to write code into ROM. This gave me the potential capability to upgrade the ROM monitor code. (to lib-3-mon or mon3 for short).
Copy mon2
I made a copy of the mon2 source program to form the basis for the new monitor. The aim was to make sure it worked in RAM then load it into ROM. Unfortunately, for reasons I didn't understand at the time, the copy didn't work. It appeared to download correctly but then wouldnt run.
As is usual in these circumstances, my approach is to cut down the program until I have at least a small part that is working. Eventually I cut the monitor down so that it just displayed a menu. The code was only about 300 bytes.
Create a symbol table
I started to embark on work to add functionality / subroutines gradually.
However I had a little flash of inspiration. I realised that all the subroutines I needed were already part of mon2 and resided in ROM. For example, the subroutine to display a menu is called cmdline_menu and looking at the link-map for mon2 I can see that it can be found in ROM starting at address $815A.
So all I need to do is replace my subroutine names with suitable ROM addresses and I can implement functionality with almost no extra code.
In fact, what I doing here is using mon2 code as a library. This is similar to what was done on old home computers. The vendors would, if you were lucky, would give you a list of ROM addresses for various functions you might want to use and you could then use them in your programs.
When I implemented libraries for my previous 6502 boards I ran into big problems with change control. It was very easy to not update addresses when a routine moved to a different location and took much work to maintain a (somewhat flaky) list. For this system to suceed I needed a better approach.
What I need is a symbol table showing subroutine names and their associated ROM addresses. As I will only update ROM occasionally, when a new version of the monitor is released, this table wont change frequently. The first change will occur when I cutover to a new monitor version.
My programming environment is now on WSL and I can easily access the ld65 link map which is created during the assembly - link procedure.
Using nifty linux tools like sed, awk, cut and column it didn't take long to process the link map, extracting all lines containing labels and their associated addresses. Some of these addresses are for branch statements but it doesn't matter as long as I have all the subroutine names. I could remove them manually, but so far I haven't needed to.
For example within mon2 in ROM the subroutine which displays a newline on the terminal is term_newline and it resides in the monitor at location $852B
If I want to use this ROM routine in my program I simply include the header file symbol_table.h and use "jsr LIBterm_newline".
If I want to I can incorporate the code within my program by copying the source in and issuing "jsr term_newline".
Generally, I want to use "LIB" subroutines unless I new an updated version of a routine, either for extra functionality or error correction.
Create a small mon3
Rather than add all the functions I implement into the monitor I aim to keep it compact.
Initially I have restricted myself to m (memory dump), s(call subroutine), x(xmodem download), p(clear memory range) and I have added an extra function z which I use when testing a new monitor version, it exits the RAM test monitor and returns control to the ROM version.
Other options which I dont think are vital were removed: c (clear screen), j(jump to address),l(sticky key), o(blink LED), r(reset)
All the functions I am using (m,s,x,p) were already in mon2 so it is easy to add them to mon3, mainly a question of using the LIB version of subroutines. The assembly download procedure for mon3 is setup to download it to $3000. Typically the programs I download will reside at $1000 and the write-romx program will work at $2000 so I aim to avoid mixups over memory.
The addition of a z option is very important as it allows exit from the test monitor to the ROM monitor. The terminal prompt was changed from '>' in mon2 to '$' in mon3 so you can always tell which version you are using.
Also I removed the stack initialisation code from mon3 for a couple of reasons.
Firstly, although stack initialisation allows us to check how the stack has built up and what it contains more easily, I never use this functionality. Secondly if I initialise the stack within mon3 I cant issue a RTS opcode to return to mon2 as I have overwritten the stack entry containing a return address. I dont forsee a need to put stack initialisation back.
Update ROM monitor
Once I was happy that the monitor was working in RAM I wanted to check that I could save it in ROM and use it to start up my system.
I connected the ROM Output Enable and Write Enable wires to the VIA chip to facilitate update of ROM contents and ran my write-romx script to assemble and download mon3 to RAM and ran write-romx to copy mon3 to ROM at $9000.
The results were underwhelming. The program did not run properly at $9000 and I wasted some time mindlessly tinkering with scripts and download program changes.
I knew that mon3 was about 400 bytes long and worked when loaded at $3000 in RAM. I looked at memory locations to compare this with the version loaded at $9000 in ROM. I saw that the new code was 12 bytes longer!
For writing to ROM we download write-romx (about 120 bytes) to $2000 and mon3 code follows on immediately after write-romx in RAM. I checked this code and found that it was also 12 bytes longer than the original, indicating that 12 bytes had been added during download.
As my download package (write-romx + mon3) was just over $200 bytes I guessed, correctly, that the error was caused by my program not working with bigger downloads.
I managed to cut out some more bytes from the mon3 executable to make the total download package less than $200 bytes.
When I tried the download + copy-to-ROM again, I found that the executable was the correct size and tmon3 ran correctly in ROM.
The process of putting mon3 in ROM has a number of very rough edges but this represents a good step forward.
Although we are not ready to cutover to the new monitor I did a quick test cutover.
I removed the ROM chip from BEN2 and inserted it in the EEPROM programmer.
I then changed the reset vector in $FFFC and $FFFD, using the xgpro software, from $8000 to $9000.
I reinserted the chip in BEN2, powered up and reset the computer and my new monitor appeared😀
I then reset the ROM since mon3 is not yet ready for "production" use.
Fix programs larger than 512 bytes
My previous text display subroutine could only show 255 bytes so I amended it to be able print larger blocks of text.
Rather than inserting newline codes in my text I amended the subroutine so that a tilde character '~' in the text indicates a newline. The display subroutine replaces it with a newline ($0A, $0D).
I noticed that the extra characters were printable, and in fact they read "Minicom2.7.1". Clearly my terminal emulation program, which is conveniently left running during a download, inserts these characters. I realised that this is the Answerback message that minicom must insert when it receives an ENQ ($05) character. I looked at the hex values for the program I was downloading but there was no $05 value there. With a small flash of inspiration I realised that my xmodem download sends data in 128 byte blocks the download goes wrong near the start of the fifth block after 512 bytes have been sent. The xmodem protocol specifies that a block number, in this case $05, is inserted in the header for each block, thus causing the error.
Next I tried out PICOcom, which promises to be a basic emulator, based on minicom, but with fewer features. It works a treat, there is no answerback and my downloads are a lot more reliable😀😀
Change individual ROM bytes
It occured to me that the payload could be one or two bytes long and I could use a script to put the bytes into the payload.
An irritating glitch
The existing byte at the problem location remains unchanged (i.e. the copy program isn't inserting a duff value).
There is a single byte which isn't copied even if the program is 1k in size.
$9000, $9100, $9200, $A000, $A200, $A100, $9040, $9080 all have an error after 256 ($100) bytes
$9001, $9203, $A001, $9010, $9020 dont have an error.
I can then change the reset vector to $9001 or $A001 to use the new monitor by default.
No comments:
Post a Comment