Close

big learning experience

A project log for Improbable AVR -> 8088 substitution for PC/XT

Probability this can work: 98%, working well: 50% A LOT of work, and utterly ridiculous.

eric-hertzEric Hertz 12/09/2016 at 22:209 Comments

x86 architecture is one of those things that's always been a bit mysterious to me... Even after all these years of what some might consider 1337 h4x0ring, I had no idea what the hizeck 0A:0F80 meant, until last night.

I haven't got my head fully-wrapped-around it (do I of anything?), but it makes a lot of sense, and really isn't even that complicated... And maybe helping me grasp some general CPU-concepts I have managed to get this far in life without understanding, until now. Guess I didn't realize just how "embedded" I was in the simple-uC-realm.

--------

Funny that the way I'm grasping these previously ungraspable-to-me concepts, despite having seen 'em so many times and not really getting it, is by learning about one of amongst the first (and simplest) systems that started it all, and at, I think, a much lower-level than most approach it from (or at least the approach I've seen it explained, prior), kinda coming at it from the opposite direction.

These explanations make sense to me, and they're done in a way that often explicitly compares it to the even-simpler systems that were mainstream prior, rather than treating it like a de-facto concept. That's kinda helpful, seeing as how those "prior" systems are quite a bit more like most uC's in use today.

--------

A weird dichotomy between the extremes of low-level-coding uC's or high-level-programming relying on an OS, wherein the concept of e.g. coding an application in assembly, to run atop an OS, seems like a complete mystery... ("How the heck is assembly going to output anything to my monitor?!")

--------

So, now, some other things I've run-across in my reading... Software-Interrupts. Which, basically, are a really easy way to access chunks of code floating around on a system, already there from e.g. the BIOS, or the OS, or maybe even from TSRs(?), or... What about things like "drive-overlay-software" and such, that basically overrides BIOS limitations... or a SCSI card that auto-detects your drive and makes it show up as C: without having to load a driver... Or even hardware-drivers loaded by the OS (DOS)?

I *think* I get it now. Your [low-level] application needs to know what memory-address your video-card's located at to write pixels? Need to know what format to write them in...? Call a software-interrupt to the de-facto Interrupt-vector where the BIOS stores that info. It's basically no different than calling a function, except that the function is located outside your own code, and outside the executable (with various libraries you didn't code yourself linked-in), and even outside the memory-space your application has access to.

WEIRD. But actually makes sense.

Maybe I'm a bit behind-the-times.

Discussions

greenaum wrote 05/22/2017 at 14:25 point

Most of the stuff you mention, you won't need to know, from the point of view of emulating a CPU. A CPU doesn't need to understand the software or the OS it's running. It just needs to run it!

As long as you're keeping track of the CPU's internal states (mostly the registers, but also stuff like what machine step it's on of it's fetch / execute / store / etc cycle), and the instructions produce the result they ought to, then it'll just work. The rest is for OS programmers.

Yup a software interrupt is a nice idea! Seemed to have entered the world around the time of the 16-bit processors. It's like you say. Hardware interrupts usually finish the current instruction (usually), then read an address from a preset location, then jump to it.

Early computer guys, who probably did some hardware and OS design, realised that this vector jumping thing would be handy in other cases, so software interrupts were decided upon. Same sort of thing, you run a certain specific instruction, and the CPU looks at a preset address then jumps to the location stored there.

Actually the Z80 had it's RST 8, RST 16 etc instructions, so maybe it's a bit before 16-bitters. 16-bit machines really took it and ran with it though, more so than the 8-bits.

Other handy things are what the 68000 calls "traps", not sure if the x86 world calls them the same. Things like "invalid instruction". This can be really handy. It can mean you can implement opcodes that a CPU doesn't have. Even opcodes that only superior models have. Upon trying to execute a non-existing opcode, the CPU calls an invalid-instruction interrupt, and goes off to a preset location routine. That routine checks what the instruction was, and can, if it likes, emulate the effect that instruction would've had. Slower than the real hardware, but means it can be compatible.

Similar to that is how virtual memory works. Whereby when a RAM address that doesn't exist is accessed (say on a 486 with only 4MB RAM), it causes an error. The error is trapped, goes to a routine that looks some stuff up in tables, then loads the correct data from disk into RAM, then places that RAM in the location it should've been in.

So, again, you just use whatever RAM you like, and if it isn't there now, the interrupt routines (in the OS) will fill it in while your program is halted. Effectively you have tons of RAM.

With later machines this got more complex, but that's the principle.

Other stuff is what Windows 3.1 used to emulate hardware that wasn't there, stuff like virtual printer and COM ports. Since newer Windows, I'm not sure.

But for an 8088, it's interesting to know how the future (the future from 1981 onwards or so...) goes. To keep in mind as you go.

But you should be fine. The biggest complaint people had about the 8088 was the bloody segment registers! Nobody outside Intel understood just WHY they did it, and why, if they were going to do it, they did it in such a stupid way! Particularly that several different combinations of segment:offset could refer to the same actual location in RAM. And that's without any virtual memory, which just didn't exist!

Good luck, great idea! I bet programmers of 30-odd years ago would've given their soul for this! There's surely no better debugger than having the entire CPU as software! And with it's own serial port to debug live, too!



  Are you sure? yes | no

Eric Hertz wrote 05/25/2017 at 08:10 point

This looks like a great read, and I can't wait to read it when my brain's back in this realm. Believe me, the email for this message has stars and bolds and all sortsa things on it, and the tab's been open in my browser ever since... so's I don't miss it :)

Thanks, yo!

  Are you sure? yes | no

Eric Hertz wrote 08/17/2017 at 16:41 point

I haven't forgotten ye! Thing's've been weird these past few months, and hackery has been put on the far back-burner :/

This tab is still open!

  Are you sure? yes | no

Yann Guidon / YGDES wrote 12/09/2016 at 23:55 point

So what is 0A:0F80 ? An address or an opcode ?

  Are you sure? yes | no

Eric Hertz wrote 12/10/2016 at 00:21 point

well, shit... you got me there.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 12/10/2016 at 00:23 point

again ? :-D

  Are you sure? yes | no

Eric Hertz wrote 12/10/2016 at 01:15 point

Haha. Nah, I *think* it's: SegmentAddress:LocalAddress or something... 'cause apparently only 64KB is accessible at any one time, but the device can access up to 1MB.

So, I think, 0A:0F80, in terms of a physical address, is basically the same as 0x0F80+(0x0A<<4) = can't-math-right-now.

Still a bit beyond me, but getting there.

I recall seeing addresses like that for PCI devices, and had no friggin' clue what it meant. But 8086/8 is *long* before the PCI era, so who knows.

  Are you sure? yes | no

Yann Guidon / YGDES wrote 12/10/2016 at 01:24 point

I did program TSRs under DOS, I used to know some of Ralph Brown's Interrupt List (RBIL), and I did "some" segment:offset stuff. Why bother with segment 0xA ?...

  Are you sure? yes | no

Eric Hertz wrote 12/10/2016 at 01:30 point

Yeahp, you were way ahead of me... I think I *used* TSRs a few times... maybe MSCDEX.EXE was one?

Why bother with 0A...? Because I was fumbling with trying to keep random-keystrokes limited to Hex-values ;)

But, overlapping segments is a thing, and seems like it could be useful. Maybe you've got a *really small* TSR loaded in segment 0, and don't want to waste 64KB on it. Probably wise to let DOS handle that stuff, in general, but can think of reasons it'd be useful with *really-low-level* coding, e.g. where DOS isn't running (or maybe even writing one's own BIOS).

  Are you sure? yes | no