Close

L O L

A project log for Z80 Reverse-Engineering And Hacking Adventures

What else can I say?

eric-hertzEric Hertz 07/10/2022 at 12:016 Comments

If you read the last log, you'll understand why I'm LOLing about what I have for this one...

Alright, so, I had several epiphanies lately for long-running unsolveds. Though, weirdly (to the point of LOLing) they seem nearly completely opposed to my plans eventually-made in the last log (many of which I guess I'd forgotten).

One was that I recalled once having written a program in C that didn't have all the system-specific stuff included/configured... and yet, it compiled to assembly source-code, which left the unknown function-calls (e.g. printf()) as just i.e. 'call printf' despite there not being anything in that assembly-output called 'printf'.

That was long ago, and a mistake, and I think I chalked it up to the idea that one can compile several separate C files, individually, then I guess the linker must be responsible for linking things like "call printf" in one assembly-output file to the actual printf function in another assembly-output file.

I was intrigued, but I guess it seemed kinda obvious-enough at the time that I didn't really think about it again until just a few days ago, when that memory came to me out of the blue, and I realized that I could compile my code in C, and the assembly output could be merged with the assembly @ziggurat29 wrote for things like configuring devices, and... using the serial port!

Hah! So, in C, I can pretty much simply call the "serpush" and "serpull" he'd written in assembly, as easily as (and essentially the same as) calling stdio.h's getchar() and putchar()!

This is revolutionary.

(just now it occurred to me I could prb do the same for programs on the TI-86(!!?))

Just before writing this, another similar epiphany: I could probably somewhat-easily merge assembly code I'd written /on/ the TI-86, /for/ the TI-86, into our code for the SD-70...

So, somewhere in there I decided to try this mystical idea of compiling C source code that wasn't fully-defined... and... Holy Moly, it worked.

First test was making a front-panel LED blink, by calling a function writen in assembly... Hah! 

Realy, it only takes a *tiny* bit of finagling to literally throw the assembly-output from C into the assembly code we wrote for the replacement firmware. I can even call C functions from the assembly's original "main"-like loop.

I know, I know, it's friggin' obvious, right? Well, it was obvious to me when I made that mistake forgetting a function-definition long ago... I knew from many times compiling the Linux kernel that there were a TON of object-files each compiled from a C file which was aware *of* the others' functions (via declarations) but completely unaware of *where* to find them (the actual *address*). I dunno, I guess I figured there was no way the individual C files' gcc-output could possibly be human-readable, nevermind straight-up-easily-understood assembly that could quite literally be pasted into one's own assembly code.

Really, friggin' amazing.

And it worked like a charm in sdcc, turning my C code into z80 assembly, just like that. Hah!

So, here's where the LOLs come in... I guess I completely forgot my AVR-programmer idea (and many others) from the last log just a few days ago, nevermind the countless thoughts and ramblings on it prior...

And the next thing I know, (well, OK, there was a LOT of "knowing of" things inbetween) I've got an ihex-parser, tested with printfs in linux, in its native ARM (rathern trying to figure out a z80 emulator and whatever hardware emulation it might also need) that could easily be reconfigured to use "serpull" in the (new) firmware-assembly by merely adding 'getnextbyte equ serpull'. HAH!

Then, I wrote and printf-tested the sector-grouper... Because, e.g. the first 128bytes (one flash sector) are very sparse due to the RST vectors, etc... Each is in its own ihex line. So, all those (and everything up to address 0x07ff) have to be combined into a full sector's data-buffer before that sector can be written to flash. Just finished testing that a bit ago... And no chip-pulling-jumper-changing necessary during debugging!

Alright, so, that leaves only two unfinished pieces I can think of: The flash-sector-writing function, and I plan to use hardware-handshaking for serial so I can simply type 'cat newFirmware.hex > /dev/ttyUSB0' to do the whole uploading and flashing procedure.

The former (flash-writing functions) I might just extract from my work last year(!) on #Vintage Z80 palmtop compy hackery (TI-86) . It wouldn't be difficult to rewrite in C, and I do much-prefer the portability of C (like being able to test it on an entirely different and more versatile system!) but it was quite an effort to thumbtype in (then new-to-me) assembly on the TI-86's keyboard and tiny screen... So, since I now know how to mix C and Assembly in this new way, I might decide to reuse that, here, and give it new life.

The hardware-handshaking... well... "That should be easy," but, frankly, aside from modems and desktops I recall *many* an obscure handshaking-scheme, e.g. tying inputs to outputs that have entirely different meanings... So, we'll see. OTOH, I suppose since this whole thing is based on ASCII, xon/xoff might be simpler than I used to imagine (how on earth can you send a *character* to handshake, when it'd look like any other binary data?!). So, I might take a bit to look into that first.

But, really... this whole epiphany was such a "wow!" that I completely forgot my other ideas. And, having just reread them, I see that this whole scenario could lend itself to many of those goals, anyhow. E.G. the AVR-based plug-in in-system flash-programmer idea is great because it could be used with basically any system that has a firmware-ROM I can replace with a flash... BUT, now it doesn't /have/ to be an AVR... C's portable. And sdcc does 8051's, and I have some 89C52's I'd probably otherwise never get around to using... This might just be a good use for them. And, then, the idea is, any such system in the future could be "brought-up" with the flash's being programmed by that external in-system programmer, *until* (and if necessitated) the very sourcecode running on it gets ported to it, directly. Whew!

...fading, quick... sun's rising.

Discussions

ziggurat29 wrote 07/11/2022 at 22:49 point

you're doing it!
One thing to check out is whatever Application Binary Interface (ABI) SDCC uses. I.e., it is expecting registers to be used/preserved in a specific way when calls are made.  I know it has opinions about IX and IY (I think it uses one of them for the frame pointer).
If you adhere to those, then it should be quite easy to link the board support stuff in assembler to the application stuff in C. This includes the higher level C stdlib stuff; so notionally you could support things like a full printf() implementation that spews to the LCD or out the serial line, without having to code actual printf().
Hardware handshaking is going to be easier in this case I think, and you'll be happier that you can exchange arbitrary binary instead of having to consider the need to escape XON and XOFF for arbitrary streams.
Since there now is a systick, then maybe a future adventure will be a thread scheduler? lol

  Are you sure? yes | no

Ken Yap wrote 07/13/2022 at 08:05 point

You can do nearly all of it in C, even the assembly language snippets. SDCC supports inline ASM. Also look at page 40 of the 4.1.0 manual which shows you how to define an I/O port as a SFR variable. Reading this "variable" will do an IN and writing an OUT.

  Are you sure? yes | no

ziggurat29 wrote 07/13/2022 at 13:50 point

very good point; will check out those pages. If nothing else, it could/would streamline the build process to stay in one tool.

  Are you sure? yes | no

Eric Hertz wrote 07/16/2022 at 02:24 point

Great points, Ken Yap and @ziggurat29, thanks!

I am /definitely/ overwhelmed by the idea of trying to learn what's necessary to get it 100% C-ready, to the extent of printfs, etc. But this intermediate stage is nice in that many low-level things can be done in C. Our keyboard-scanning, for instance... Could be added to the already-written portions of otherwise-Assembly "BIOS".

If I were doing this all myself, AND knew of this sorta intermediate C-technique, I probably would've done most all of it in C, then hand-linked it at the assembly-level. Surely a lot of work compared to using a full C "toolchain" as I think you're both alluding to, but creating the necessary components for that toolchain seemed to me like a tremendous hurdle...

Here I can literally write "while (1) { _asm_("nop"); }" plug it into sdcc (out of the box) and copy-paste it into a blank assembly file, add a couple extra lines (like ".org 0") and watch as LEDs on the address bus count up and reset. 

The exact same process (and C code) could be thrown at an 8051, without knowing anything of its assembly language nor its register-set nor peripherals... And if there's a 6502 C compiler, the same...

I guess my draw to this "epiphany" is to see how simple it can be to get started at the lowest level in some architecture-independent way.

....

I was unaware that the SFR thing was common; I recall seeing that early-on in my AVR endeavors and thinking it was something specific to them. I'll definitely look into that.

I think I also recall seeing some ROM function stuff like you described, Ken. without really getting it at the time. That'll definitely beat my "equ" statements and hand-finagling in the future.

I imagine, as Ziggurat29 alluded to, that for more complicated functions, there might be some difficulty determining/assigning info like where it expects its arguments (registers, stack?) or where to expect return values. Those sorts of things are where my eyes start to cross. Heh. And where hand-finagling seems easier to me. I've no doubt I'll eventually tire of that and be glad for these insights and direction when I get there!

Thanks, again, both of you.

  Are you sure? yes | no

Ken Yap wrote 07/13/2022 at 21:58 point

And if you have routines in ROM you want to call, try this:

typedef void (voidfn)();

#define LINEFEED        ((voidfn)0xfeed)

main() {
       LINEFEED();
       return 42;

}

Compile and read the ASM. Naturally any side effects on registers in LINEFEED should be catered for.

The return 42 is just to prevent SDCC from optimising the call to a jump (tail call optimisation) in this demo.

  Are you sure? yes | no

Eric Hertz wrote 07/15/2022 at 08:48 point

Ugh... I'm friggin beat. Thought I'd be done with this DAYS ago, so have been going at it nearly non-stop, meaning to read/respond to this as soon as I finished

I friggin' thought XON/XOFF would be MORE likely to be well-supported by USB adapters, not less! Remember the graphlink bitbanging ordeal? 100 bits/sec, as I recall, trying to read those handshaking lines. The USB bandwidth was maxed-out due to packet overhead. I had no high hopes for hardware handshaking working well.

Finally got this thing running pretty durn well, XONs/OFFs sending at the right times, etc. Even created 'cbinject' to put them next-to-send in the circular FIFOs, but reception starts getting corrupted after about a dozen lines (far more than our 128B buffers). On a whim I looked up my serial adapter... I don't even recall why... but it wasn't in thinking that XON/OFF just flat-out wasn't supported, and worse, that the driver *lies* about supporting it, and worse still, not because it can't support it but doesn't because most other USB adapters don't/can't, and worse still that NUMEROUS folk have submitted patches to either A) enable the hardware-level support that the chip actually has in it, or B) At Least Warn the user that support is non-functional when selected, and yet all seem to have been dismissed, again, on the basis of "most /USB/ chips don't support it"... And, worse still, the shear arrogance and pedantry of the responses! "Weird indenting" was repeatedly brought up over several days' messages for all to read in the mailing-lists! 

Holy Shit. It's a wonder we have ANYTHING that works. And maybe as much wonder programmers don't "go postal" on a regular basis.

...

All that to say, if I hadn't thought I was only a few hours away from complete in implementing XON/OFF when I got your message, days ago, and if I hadn't thought "Only a few more hours" for days on end, I'd've read your message then and maybe been the wiser than to try it.

Too beat to read/respond more deeply tonight. I guess I'll find out if I missed other such warnings from you and @Ken Yap tomorrow... if I can ever look at this project again without seeing red! Heh.

(BTW, this is the <s>second</s> *Third!* thing I've come across, now, standard for decades, that this chip has hardware support and detailed documentation for, that they haven't bothered, if not flat-out refused, to support in the mainline driver despite numerous patches submitted. I'm really starting to lose faith in this era).

(Oh, right, I went searching to see if there was a way to reduce the size of the output buffer thinking the xoff would be responded-to faster... Which, frankly, would be one way to implement software Xon/off flow-control for *all* serial ports, USB or otherwise... if, yahknow, Xon/off might be important for some old hardware... important-enough to be an [the default] option in stty!)

(I think I'll try out my handiwork on the 486 and hyperterminal, just to see it working. ... Ten minutes later, mostly due to moving stuff out of the way. Lo and behold, it works perfectly. AAARRRGGGHHH! Anyhow, I do love giving these old things purpose...)

Thanks, both, for your responses, I'll catcha soon.

  Are you sure? yes | no