Hello Brian, Steve,
There is a very limited space in RAM on the TPDD1 to load the
dumping program into and I needed to make it as small and usable as
possible, and for me it was easier to dump to a formatted HEX output and
capture that in a terminal program.
I'll poke around and try updating the up-loadable assembly program to
dump the data in binary and put in some spots where a start word and
length byte can be modified this weekend. And you're right, I made up a
simple RS-232 cable with only RX, TX, and GND when I was working on
dumping the ROM. I should have used the hardware flow control lines too,
but thinking back I wasn't sure if the hardware flow control bits for
the UART in the 6301 would have been set. But looking at the source now,
they were. Also, at the end of my code I jump into an infinite loop,
I've not played around with returning to the running firmware, but this
might be possible too. That could allow for running multiple 'external'
programs without power cycling the TPPD1.
I'm glad you put the TPPD2 firmware on the web too. I've been poking
around the firmware that Steve supplied and there are some things that
weren't making sense and I thought there might have been some dumping
errors still, but your copy is exactly the same.
But now looking the the stuff that didn't make sense again, it's
actually a pretty cool implementation of some code compaction tricks.
*Weird thing #1 - the array of CPX statements.*
[FD77] [26 1D ] [& ] BNE A_FD96
[FD79] [DE 99 ] [ ] A_FD79: LDX A_99
[FD7B] [A6 02 ] [ ] LDA A 0x02, X
[FD7D] [97 89 ] [ ] A_FD7D: STA A A_89
[FD7F] [C6 B2 ] [ ] A_FD7F: LDA B #0xB2
[FD81] [F7 40 00 ] [ @ ] STA B (CPLD)4000
[FD84] [71 BF 02 ] [q ] AIM #0xBF, (register)PORT1Data
[FD87] [39 ] [9 ] A_FD87: RTS
[FD88] [C6 40 ] [ @ ] A_FD88: LDA B #0x40
*[FD8A] [8C C6 4B ] [ K ] CPX #0xC64B*
[FD8D] [9E 81 ] [ ] LDS A_81
*[FD8F] [8C C6 42 ] [ B ] CPX #0xC642
[FD92] [8C C6 41 ] [ A ] CPX #0xC641
[FD95] [8C C6 49 ] [ I ] CPX #0xC649
[FD98] [8C C6 4A ] [ J ] CPX #0xC64A*
[FD9B] [D7 8E ] [ ] STA B A_8E
[FD9D] [86 FF ] [ ] A_FD9D: LDA A #0xFF
[FD9F] [20 DC ] [ ] BRA A_FD7D
These just didn't make sense at first, and also the branches and jumps
pointed to the middle of the opcoode (the C6 in the middle). But this is
just code compaction. What makes this cool is C6 is a load accumulator B
command that takes 2 bytes. So what is really happening? Since in this
part of the code we're not concerned with the index register, those
commands are just superfluous.
What the code is doing is loading acc B with 0x40, 0x4B, 0x42, 0x49, or
0x4A without a lot of extra branches or jumps between opcodes. Looking
at line FD77 there is a BNE (branch if not equal) to address FD96, the
middle of the CPX #0xC649 opcode, which turns out to be C6 49, or LDA B
#0x49. The next opcode is CPX #0xC64A, which does nothing in this code,
but hides C6 AA, or LDA B #0x49 (there is other code that jumps to
that). Seems a little complicated, but the author saved 5 bytes by not
having 2 byte branch opcodes between each LDA in this section alone. And
when you only have 4K of space, every byte counts. Especially if you
want to put your name in the code, you need to do what you can!
*Weird thing #2 - Software interrupts and invalid opcodes.*
[FD73] [3F ] [? ] SWI
[FD74] [13 ] [ ] INVALID
When de-compiling I often look for invalid opcodes to locate issues or
data tables. What I noted was just before many of the invalid opcodes
was a SWI, or software interrupt. This is cool because the software
interrupt jumps to a block of code that gets the SWI address out of of
the stack and gets the next byte after that address, which is the
invalid or nonsensical opcodes after the SWI. I still need to dig deeper
into what these are all doing, but it's a neat way to pass a parameter
to a function without using a register.
*Weird thing #3 - Other standalone invalid opcodes.
*
The 6301 traps invalid opcodes, and I see that there are many standalone
invalid opcodes that make no sense. But when using the TRAP, the invalid
opcodes become a 1 byte call to a subroutine instead of a 3 byte call.
Another form of code compaction.
So thank you Steve and Brian for helping out with this! There are some
really cool things to discover in these ancient devices.
This firmware is completely different form the TPPD1, and a lot more
complicated. It'll take a while to decipher and figure out the little
tricks that were used to save space, and also decode the functionality.
As i figure out more I'll update my GitHub and this list.
Darren Clark
On 1/24/24 19:36, Brian K. White wrote:
I'm currently parsing the returned ascii hex dump to generate the
binary, but could you possibly make a version that just sends the raw
binary bytes? Even better one that can take parameters or even just
have a few bytes edited on the fly to dump an arbitrary address & length?