Yes, the 8086 wanted to be mechanically translatable from the 8080, but
devblogs.microsoft.com
devblogs.microsoft.com
• the address calculation would be simple enough to do hardwired even on the original 8086, instead of using slow microcode. The 8086 actually took a different amount of clock cycles depending on the registers used for base and index, because there wasn't enough ROM space to duplicate the code for every combination without using jumps!
• you could use [SP+xxxx] to access local variables (frame pointer omission)
• would be able to emulate the 8080's LDAX/STAX and XTHL in a single instruction
• with so few registers, you really want every one available for memory addressing. Especially AX which is used implicitly by instructions like LODSW and MUL.
The 8086 was designed under harsh technical constraints by moderns standards. Don't forget that.
The giant Kyocera printer at work has a little screen where it shows you it not only loading up the print buffer, but purging the information from the disk afterward so there is no trace of PII remaining.
Those were the days my friend.
1982 Victor 9000 / Sirius 1 designed by Chuck Peddle of Commodore/MOS 6502 fame had floppy capacity extended from standard IBM PC 180KB all the way up to 600KB per side. 1.2MB floppy in 1982 using same magnetic medium! How? Software controlled drive with 6502 doing GCR combined with Zoned Constant Linear Velocity and Zone bit recording. There were still hard drives being manufactured not using ZBR 8 years later (Seagate ST-157A)!
It also did 25x80 text using 10x16 font or 800x400 bitmap graphics at 76Hz. https://en.wikipedia.org/wiki/Sirius_Systems_Technology http://oldcomputers.net/victor9000.html
There was also an IBM PC 8088 clone in ~1984 with "dedicated Video DMA" implemented by Intel MCS-48 microcontroller (8042/8048, same chip as keyboard controllers at the time), sadly I cant remember the name and google fails me :( I do remember nobody used it for anything and the only coding example I could find at the time was a singular YT video where someone reverse engineered manufacturer demo and reused it for its own sprite engine.
As a programmer, and I've heard this sentiment from others too, I also think the 6502 was also the last "fun" assembly language to write directly without a higher level language, which adds to its legacy.
Yes, the 8086 was simple, but all the parts needed to do this should be present: whether an instruction uses register or memory operands is entirely under the control of hardwired logic, the microcode is the same for both (the address calculation subroutine runs first, but is invoked automatically by the hardware).
I would say Intel chose to make addressing more complicated in order to add a feature that complicated register allocation for very little usefulness. If you see something like [BX+SI] in disassembled code, in 99% of cases it's not an actual instruction, but data or misaligned code.
(I know, they didn't have address pins on the 40-pin package. Still, an architecturally guaranteed 16MB of room to play in would have changed the face of the software industry in the 1980s).
I don't think it would have, because such amounts of RAM were prohibitively expensive into the late 80s. It would have changed the way software accessed the available RAM, made life easier for developers and improved compatibility be removing various kludges, but largely computers would have looked and behaved similarly, having largely similar specs.
Telling their corporate customers, "Buy another 512K of RAM" would probably have saved their company and let them ship a number of world-class productivity products, and given Windows some interesting competition.
It's easy to second guess this stuff, on the other hand 512K of RAM was about $120 in 1985. We shipped the Atari ST with that much, when having that amount of memory on a Mac was pretty rare.
You are right that doesn't have to be a limitation on internal architecture: The 386SX internally had the 386's 32-bit data bus only 24 bits were carried out to the external pins. This, along with squeezing the 32-bit data lines through a 16-bit data bus by doubling up requests, made it able to be used on cheaper motherboards based on 286 designs.
I'm not sure that this would have made enough difference to be worth the cost of the extra silicon at that time of the 8086's design though. While a flatter and more roomy address space would have been convenient to developers there would be little or no benefit for end users. The 386SX was a success because it could run software intended for the original 386 (then renamed 386DX) on cheaper hardware (and had the same MMU allowing virtual memory so could run larger software then it's 16Mb physical RAM limit made possible, at a further performance cost). Also the extra silicon requirements were not as expensive at the time the 386SX was being designed as when the 8086 was.
In fact there was a chip that did similar for the 8086: the 8088. It had an 8-but external address bus and broke up 16-bit requests to make them over it. Though unlike the 386SX it maintained the same address bus of its relative.
I did write an 8086 assembly based Z80 emulator (in the late 80's) that was surprisingly compact and had acceptable Z80 performance on a 12MhZ AMD 80286. It passed CP/M system calls to Concurrent DOS.
I should see if I still have the code and run an emulator torture test to see how bad it was.
Even if translating code ahead of time, "LD (BC), A" needs to be emulated as something like "MOV DI,CX; MOV [DI],AL".
Yes, I agree. I also used SI as the PC so I could use "lodsb" (cute HN name BTW) and "lodsw" for 2 byte args.
My register use was
286 Z80
--- ---
BX HL
CX BC
DX DE
DI A
SI PC
When emulating the DD, FD and CB prefixes I pre-loaded BP with either IX+d, IY+d (IX, IY were stored in memory) or BX and jumping to common code.Basic structure was like
OP_00:
XOR AH,AH
LODSB
SHL AX,1
MOV BP,AX
JMP CS:OP_table[BP]
For OP_02 - "LD (BC),A" I used, OP_02:
XCHG CX,DI
MOV [DI], CL
XCHG CX,DI
JMP OP_00
I did see some opportunities for additional code-golf. Also noticed that EX AF,AF' did not properly exchange the flags (so that will need to get fixed!).I was mostly only running m80, l80 and mload.
Fascinating! Does anyone have links to more information about this? What purpose might one have for this fingerprinting?
Similar fingerprinting techniques were also used by assembly coders as proof of copyright. When reverse-engineering to a spec, it's not unusual for routines, even long routines, as well as lookup tables, etc. to end up being coded the same, or nearly so, as the original software. This isn't necessarily infringing of copyright -- for example there are only a few sensible ways to check if a character is uppercase in ASCII. It can be hard to tell reverse-engineered and re-implemented code, from disassembled and reshuffled code (which is copyright infringement). If the suspect routine incorporates something like an idiosyncratic sequence of NOPs that serve no particular purpose, coincidence is a lot harder to argue.
To prove some program was made with A86, there would have to be a more specific signature that wouldn't match any other assembler, like a copyright message encoded bit-by-bit in the opcode choice.
02 C0 ADD AL,AL
02 C1 ADD AL,CL
00 D0 ADD AL,DL
00 D8 ADD AL,BL
02 C4 ADD AL,AH
02 C5 ADD AL,CH
00 F0 ADD AL,DH
00 F8 ADD AL,BH
Don't know if this would hold up in court for proving that some code was assembled with A86...edit: other ALU ops are the same; for MOV the "direction bit" is inverted.
$ zasm -Mx86 -='add al al;add al dl;add dl al'
000000 - 02 C0 00 D0 02 D0 |...... |
$ hex C3 | ndisasm -au -
00000000 C3 ret
0: C2, C3, CA, or CB, so modrm (ax/cx) (dx/bx) A86 assembler package V4.05 January 14, 2000
The entire package is Copyright 2000 Eric Isaacson. All
rights reserved.I was extremely frustrated because my textbook's later chapters used MASM as the assembler, which at the time cost some ghastly amount of money (somewhere around $180 if I recall correctly, which was a truly staggering number of birthday and Christmas presents).
Anyway, my point is, in 2022 everyone takes for granted that an assembler for any system that matters can be downloaded for free from the Internet -- or if it doesn't, one will soon be written by some enthusiast and posted on Gitlab.
But back in the 1980's and well into the 1990's, assemblers were expensive products that companies actually got away with charging a lot of money for. Presumably they made a significant amount of revenue from those sales.
So the use case that immediately springs to my mind is being able to prove a particular commercial binary was assembled by your assembler, in order to make a successful accusation of software piracy and extract a monetary settlement from its developer.
Time was worth relatively little in comparison and I figured I will at least know the instruction set inside-out.
Did you bootstrap it with hand-assembled code or some Basic? Did you assemble the assembler with itself?
(Had to Google to remember this bit of trivia again -- funnily enough turned up this [2] HN comment I replied to 9 years ago with nearly the exact same comment I made above.)
[1] https://support.apple.com/kb/TA39083?locale=en_US&viewlocale...
But Woz's trick is far more impressive.
https://www.amazon.nl/Assembly-Language-Programming-Lance-Le...
Memory management was a tricky part and macro expansion only got done after the whole thing worked (that would have saved a lot of time but I couldn't see the wood for the trees at that point).
The nasty part was that instructions were variable length so you could get into these weird errors where your initial guess for a jump target was too small, which would then move everything else as well, which might lead to other jumps becoming too small. I don't have the code any more but I think I fixed that by making all the jumps long jumps initially. A bit wasteful but that way I could at least get it to work in one pass. Later on when I got better at assembly that sort of thing got fixed.
The end product was endless 'data' statements that were poked into memory at 48K and up, right over the basic interpreter, which we had figured out a way to page out and replace from software. This later led to an annotated version of the basic that came with that computer (a version of MS Basic) and subsequently a replacement interpreter with a lot of built in goodies (double speed tape interface, a whole raft of new statements and functions). Good times!
Shout out to my friend Henri G. who did at least half of that work, we had identical home computers (Dragon 32) and worked together a lot on this. He probably still has his in working order :)
Ye that one is annoying.
I am making a VM compiler right now, and I have the same problem. I would probably have to make some intermediate tree to solve it without making every jump a "far jump".
Moving instructions is a headache :)
I had the same problems, only I was programming a Laser 128 (an Apple II clone) that had a built in System Monitor, which let you directly change memory addresses, but no assembler.
So I photocopied the Assembly to Machine Language chart in a book I got from the library, and did it manually - I learned quite a lot. I remember writing a layout and edge detection routine for a Tetris clone I tried to write (never finished it). Basic was too slow for those critical parts, so I called out to the routine, but did most of the code in Basic.
I remember been utterly wowed that Linux came with a free compiler - I could only dream of having software like that back then.
Before that it was a case of writing code on graph paper, looking up the opcodes in the manual, and assembling by hand. Needless to say that writing programs was slow and difficult.
I think I jumped straight from paper -> A86, without using debug.com. Not sure why.
As incentive, he'd send you enhanced versions of the software (with 386 opcode support iirc... or was it 32-bit support?), and a ringbound hardcopy of the manuals.
I remember companies forking out $500-$800 ($3,300 in today's money) for Pascal compilers.
And not just for one title, but $3,300 for each version — per user, per year.
But at least you got a box, and nice thick manuals and tutorials.
My partner was impressed with it, and sent it along to me to evaluate.
My tests showed close compatibility. A bit too good. It didn't take me too long to figure out it was the Microsoft MASM program with the copyright notice patched out.
Dodged a bullet with that one.
The reason assemblers were expensive in those days is they were written in assembler, which is far more expensive than writing in C.
https://www.mail-archive.com/freedos-user@lists.sourceforge....
① The number of customers was smaller than it is today, so to remain profitable the NRE cost had to be paid by a smaller number of sales.
② Legal proprietary PC software distribution was competing with user group meetings, Hamvention, and 1200-baud underground BBSes where people used names like "Warlord of Chaos", not pop-up PC repair shops, anonymous FTP sites, Eggdrop, Napster, BitTorrent, Debian, and GitHub. Faster and cheaper ways of sharing software both made it cheaper for enthusiasts to collaborate on writing free software and made illegal copies cheaper and more accessible. It's easier to stomach paying US$180 (say, US$500 today) for MASM when your alternative is to spend your weekend and US$60 making long-distance calls to BBSes that might or might not have a copy.
https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ba...
The cool thing to do with it is add it to your favorite text editor as a command - highlight some of your text and disassemble it! Great party game - what is your name disassembled? Valid code, or are you a seg fault?
rex.WXB jb 0x6050b4 ; jb offset here is 0x61, 'a'
outsb %gs:(%esi),(%dx)I was just reading a book called “Almost Perfect”, a first-hand history of WordPerfect by one of the founders. He mentions that they bought an IBM PC when it came out and wanted to port their word processor (over from the Data General minis that had been their initial platform). But they had to wait five months for an assembler to become available.
Imagine buying a $5,000 computer and you can’t even get an assembler for it for any money.
(WordPerfect was written entirely in x86 assembly, even when it was a billion-dollar product.)
In fact, if memory serves, RDOS had FORTRAN, ALGOL, and BASIC available, even if most of the system software was written in assembler.
Writing an assembler in BASIC on either the Nova or the IBM PC would have been considerably less hassle than writing it in assembly and hand-assembling it.
[1]: https://github.com/woodruffw/steg86
[2]: https://blog.yossarian.net/2020/08/16/Hiding-messages-in-x86...
It was sold under a shareware model, and if you used it commercially you were supposed to buy the licence. I guess they randomly sampled other people's software to see if it looked like it was built with a86 or not, but honestly I'd never actually heard of them doing that and suspected that it was just enough of a threat to know it was possible that they hoped people would pay up.
I am looking into writing some basic compiler(s) but I really want to emphasize micro-optimizations, maybe even the stochastic ones -- don't ask why, it's just an obsession.
Question: is there an Arduino-like hardware that allows FULL visibility into the efficiency of every piece of code ran on it? On my first job, 20 years ago, there was a team working on embedded boards that maybe did something similar.
But again, I am looking for a piece of hardware -- and a software stack for it -- where you say "here's this chunk of assembly / machine code, run it and give me detailed statistics which instruction got ran the most times, which one took the longest time" etc.?
Is there something like that out there?
They were saving it for 286, 386, ... MMX, AVX, SSE, ...
On the plus side that means common instructions are still actually compact so reducing icache pressure.
Using 64-bit registers, or any of R8-R15, requires a prefix byte. The single-byte INC/DEC opcodes have been repurposed for this. And for performance reasons having to do with how it affects the flags, you don't want to use INC/DEC (now two bytes) at all.
So now the very common operation of incrementing a register takes at least three bytes, four if it needs the prefix. Legacy instructions have been made invalid - depending more on the whims of Intel/AMD than whether they are actually useful - but still clutter up the opcode space.
But while talking about ISA size and compactness, we need to compare to the real world alternative: the various ARM or RISC-V ISAs, etc are all 4byte per instruction with the occasional 2 byte variable length extensions*. 4 byte does seem to have been what has been selected for.
My experience with code size is wrapped up in jitting JS so I could believe my experience isn't as reflective of real world code size as it could be :D
* fun story: thumb2 had an early bug/errata where a 4 byte branch spanning a page boundary would jump to the wrong page.
And if 8080 backwards compatibility is really necessary, we can write an emulator in Rust, compiled to WebAssembly and running on RISC-V. /s
Why do Windows functions all begin with a pointless MOV EDI, EDI instruction?
https://devblogs.microsoft.com/oldnewthing/20110921-00/?p=95...
For this specific blog post there's an HN discussion¹ and archive.today² (beware!?³) did grab comments while the Internet Archive does not load them:
¹ https://news.ycombinator.com/item?id=3022224
² http://archive.today/2015.07.08-134638/http://blogs.msdn.com...
Side note: Michael Kaplan’s blog, which Microsoft took down in a remarkably shameful manner, has also been archived[3], while Eric Lippert reposted (most of?) his old articles on his personal WordPress instance[4].
[1] http://bytepointer.com/resources/old_new_thing/index.htm
[2] http://bytepointer.com/resources/old_new_thing/20110921_226_...
At the time that seemed like a good way of getting low-level code-related posts.
[1] https://docs.microsoft.com/en-us/archive/blogs/larryosterman...
Wouldn't it be the same to have a single 5-byte effectless operation to patch a single long jump instead of needing space for two jumps?
I thought that multibyte NOPs were executed in a single instruction?
Besides, it sounds like premature optimization. This isn’t the 1980s; An extra clock cycle per function call is not going to make or break your program.
There is a very good chance this dates back to 16-bit Windows. Even Windows 98 supported the 486 which was not capable of independent execution (that’s P5) or separate decode from execution (P5Pro there).
Those processors weren’t dead until Windows XP.
Or is it that when you get to assembly-level instructions, you can have total confidence that everything you’re reading will be executed as-is ?