HN user

gp2000

172 karma
Posts0
Comments46
View on HN
No posts found.

It is in the sense that Radio Shack put TRS-80 as a brand on all of their computers up until the mid eighties when they started to move into PC clones. Xroar emulates the Color Computer which was known as the "TRS-80 Color Computer".

Though, to be sure, most often TRS-80 is used to refer to the Model 1, 3, 4 line. But plenty of people will think of the Color Computer when they hear TRS-80. Or, possibly, their line of rebranded pocket and laptop computers like the TRS-80 Model 100 or TRS-80 Pocket Computer 1.

The version for the Model 3 runs on stock hardware as it shipped in 1980. It has a interrupt that fires every second vblank. Thus it is possible to get in sync with the beam but to remain in sync the program must keep track of every cycle it executes.

The Model 1 version does require a hardware mod to get access to vsync.

I wrote those programs and couldn't have done it without something of a virtuous circle of trying stuff on the real hardware and then improving the emulator to more accurately model the hardware and so on.

That isn't a bug. In the original if a guess contains a repeated letter and there is only one occurrence of that letter in the target work then the first (on the left) letter will be yellow and the second black.

You can see this with today's word by guessing MOTTO. The leftmost T will be yellow and the rightmost will be black.

Similarly, if you guess TENET the initial T is black but the final T is green.

Today's word is ZBVFG (rot13).

And it could also save time. The Z-80 conditional return takes 5 cycles (or "T-States" in Zilog terminology) to execute if the condition is not met and 11 cycles otherwise. Quite worthwhile in testing for uncommon cases. Consider this routine to print a message that is terminated by nul or newline:

   PMESS  LD   A,(HL)     ; get character from message
          INC  HL         ; move message pointer to next character
          CP   10         ; newline?
          RET  Z          ; return if so
          OR   A          ; zero?
          RET  Z          ; done if so
          CALL PCHAR      ; print character
          JP   PMESS      ; keep looping
If instead of "RET Z" we had to do a conditional jump to a return it would be 10 cycles for each test instead of 5.
          CP   10
          JP   Z,DONE     ; 10 cycles, jump taken or not
          ...
          JP   PMESS
   DONE:  RET             ; 10 cycles, BTW
The conditional return just happens to be cheaper if not taken because it skips the work of popping the return address off the stack. Though purely an outcome of the implementation you can treat it as sort of a branch prediction.

Incidentally, the Z-80 also has relative branches (JR) that differ in execution time whether they are taken or not. The branch offset is a single byte so JR is only 2 bytes compared to JP's 3. A JR is 7 cycles if not taken, 12 otherwise. Again, we can treat it as a hard-coded branch prediction that predicts the branch is not taken. If space or distance to target is not a problem, a JR is faster if taken less than 60% of the time.

The Z-80 stack pointer (SP) is a full 16 bit register. The stack can be anywhere in memory and be as large as needed.

The 6502 has only an 8 bit stack pointer which points into page 1 only (addresses 0x100 .. 0x1FF).

Yes, enjoyable and good ideas. I feel like I've been on that "project" before. You do a bunch of work, dig into things and then discover a simple answer that, in hindsight, could have been applied immediately and made all the investigation irrelevant.

Usually out of pride or the sunk cost fallacy (or something like it) I'll convince myself there was no other way the problem was going to be solved. Either way the next time around I spend just a little bit longer trying to think of an easy way out.

Although it is a historical (and disavowed) footnote, the Open Text Index launched in April 1995 and sported full text indexing of web pages -- more than 6 months before Alta Vista's launch in December that year.

It did serve as a back-end search for Yahoo! though it never could keep up with the full query volume. It was lambasted by the creators of Google for experimenting with putting clearly-marked ads in search results. That transgression looks hilariously quaint to modern eyes.

https://www.referenceforbusiness.com/history2/72/Open-Text-C...

The original arcade Mortal Kombat (and MK2, MK3 and UMK3) were all written in assembly for the TMS34010 processor. No doubt ports of it to the Sega Genesis did use 68K assembler.

The TMS34010 was something like a CPU and 2D graphics processor combined. It has the ability to change its word size from anywhere between 1 and 32 bits with data addressable on bit boundaries. It's wild.

https://en.wikipedia.org/wiki/TMS34010

The bug is explained by Dave Theurer himself in this video: https://www.youtube.com/watch?v=41TbGi7u598&t=168

Like many games at the time the code in the ROMs had tamper protection. The basic idea is to detect if the ROM has been altered and if so assume it is a pirated copy and do something to cause the game to fail. Pirates could still make exact copies but they'd have to retain copyright notices and trademarks which makes them more vulnerable to detection and prosecution.

At the last minute Dave changed the position of some logos on screen but forgot to update the copy protection. When an illegal copy was detected the game would use some of the digits of the score obtained at the end of the game to zap bytes in memory if the overall score itself was within some range. This kind of random scrambling that only happens semi-randomly is better than copy protection that triggers deterministically. Imagine if the game did a checksum of its ROM and immediately said "Illegal Copy Detected - Program Halted". It would make it easier to find the copy protection routines and disable them.

So the first version that shipped thought it was an illegal copy and triggered the random scrambling. It so happens that sometimes the random scrambling would result in giving the player 40 credits.

There were other effects which players discovered and are listed here: https://forums.arcade-museum.com/archive/index.php/t-79058.h...

I imagine the original labels would have been in English. The assembly source code I've seen for Japanese games has variables and labels in English with Japanese comments in Shift-JIS. I would guess the choice was forced because the assembler, linker, debugger or other tools did not support Shift-JIS properly. Often labels are restricted to 6 bytes which would be 3 Japanese characters. Perhaps such a limit was also a factor.

This hybrid approach was used for a series of arcade games on XArcade for the Xbox 360. Frogger, Gauntlet, Joust, Gyruss and a bunch of others. I think we referred to it as "reskinning".

Mostly it was applying higher-resolution tiles and sprites but some had particle effects added. For instance, some exhaust smoke on the cars in Frogger.

My favorite was Gyruss which is somewhat like Space Invaders of Galaxian but with a 3rd person view from behind the player's ship so you see enemies come toward you in pseudo-3D. We found that the game internally used polar coordinates and had a fair bit of code that converted those 2D and chose the right sized sprites. Replaced all that with 3D models rendered at the same spot in space.

I view these techniques along a continuum where you're essentially changing the porting layer. An emulation puts that layer at the hardware. A hybrid approach pushes it some ways into the game. A source code port is above the binary but some ways into the code. A remake is at the "game design" level.

Yes, for better or worse ugly is definitely a 2nd-order predictor of success.

I guess "ugly" is a fair assessment of the 8086 at the time. Certainly the 68000 was a much cleaner and orthogonal architecture. On the other hand, I'd rate the 8086 at least as good as if not better than other contemporary microprocessors such as the Z-80 and 6502. The 6809 was sweet but a 16 bit address space rooted it in the previous direction and the 68000 make it clear that the 6809 wasn't in Motorola's future plans. Sure, had IBM chosen the 6809 there surely would have been a compatible follow-on but I can't imagine even the stanchest IBMer to have that kind of hubris.

But calling MS-DOS ugly at the time would have been unfair. It was as capable as any other microcomputer OS at the time in the home computer space. It was widely proclaimed to be a rip-off of CP/M so we might take that as a compliment and if you look at TRS-DOS, Apple DOS or whatever PET's used it was just fine. It'd be unrealistic to suggest and mini or mainframe OS was an option and Unix just wasn't there yet. If IBM had given Microsoft more lead time they might have went with Xenix which they did have out in 1981 for the Z-8001. I'm not so sure IBM would have been interested, though, as they wouldn't have an exclusive license to the OS.

Not to mention that the overhead of the operating system was an important consideration. The machines didn't have much capacity to waste and whatever you picked it still had to perform well on a system with only floppy drives. Maybe that in itself doesn't rule out Unix but it sure cramps the design space.

In both cases, CPU and OS, the ugliness really took off with backward compatibility to maintain. The 80286 was already being designed so it drove that deeper into the weeds and there was no way of bypassing MS-DOS compatibility once it anchored the marketplace. The only way forward was to improve the OS while keeping MS-DOS programs running and the whole OS/2 debacle only helped to delay that upward path.

I mean, fair enough to say "ugly won" but some consideration should be given to the lay of the land when these long-term trends were set in motion.

You could choose that the memory accesses be at any bit size from 1 to 32 with both unsigned and sign-extended register loads. In fact, I think you got to pick two sizes and for most normal operation you'd choose 16 and 32 bits. There were some load/store operations that always operated at 8 bits so you'd get the usual complement of data sizes. Pretty useful feature for something that was intended to be a graphics processor. I've also seen the different bit sizes used for fast and simple Huffman decoding in gzip decompression.

The auto-increment/decrement addressing modes were aware of the bit size. Thus you could have polymorphic subroutines where the same code could be used to sum an array of bytes, words, 13 bit quantities or whatever size word you wanted (up to 32 bits).

Since the processor had built-in circuitry to help drive graphics displays it took a high input frequency of something like 40 or 50 MHz and actually divided that down to run the processor at around 10 MHz or so. The opposite of what we're used to now and made the darn things look scary (well, scarier) from an emulation programmer's perspective.

The memory interface was designed to work with shift-register VRAM. The idea there being that the VRAM chips had a built-in shift register 512 pixels wide. The display circuitry would make use of it by having each line from the frame buffer dumped into the shift register as the raster was moving down the screen. And then the shift register would clock out the pixels as the raster moved across each line.

During VBLANK (when the video circuitry is waiting for the raster to return to the top of the screen) you could use special instructions to load and store the shift register which would be as fast as any load/store operation. The entire frame buffer could be filled very quickly with any repetitive pattern or erased entirely by copying some fixed line to all the others.

Lotta cool stuff in that beast.

Emulation of that processor was a bit of a challenge. Fortunately the fully general bit addressibility was only used in gzip decompression and the drawing instructions (circles, rectangles, that sort of thing) only came up in test mode. So not all of it had to be implemented and only the normal 8/16/32 bit addressing modes had to be fast.

In command contexts "." refers to the current line (e.g., :.,$s/a/b/ will perform the a -> b substitution from the current line to the last line of the file). That comes from ex which likely copied that from ed. I've seen "." used similarly in other contexts. 8-bit Microsoft BASIC used "." for the current line -- "LIST ." would list the last line that had been listed or edited. A number of assemblers use "." for the current assembly address.

The point being that there is a bit of a tradition of using "." for "the current thing" so there's a sort of sense in using it for the most recent command.

If you're really curious get in touch with Bill Joy.

It is difficult to take a binary program and establish intent. I'd rather call these "interesting and unusual programming tricks" than "anti-emulation measures" until more evidence is presented.

Mirrored memory is a side effect of unconnected lines on the address bus thus making the content of those bits irrelevant. Code can take advantage of this to run faster or put tag values into addresses.

On a GBA, VRAM is faster than ordinary RAM. Programs can do well to use it for tight inner loops.

Using STM (store multiple) to DMA registers? Again, go faster.

Save type masquerading might be code that helps when running on a development kit, but I admit that I can't think of what use it might have.

Self-modifying code that depends on the pre-fetch queue might be the best place to look for intent. Might be easy to tell if the program is doing it for some larger purpose or simply to fail subtly or overtly if it sees unrealistic processor behavior.

Any why would a program do extra work writing to an audio FIFO than need be?

I, too, am curious though I suspect I'm imagining worse than it is. My best guess is vitriolic raging against the modern state of technology and/or particular individuals. Though it could just as easily be sordid tales of his exploits or maybe just semi-incoherent ramblings going nowhere in particular.

I don't have a 6502-specific example, but scaling an image with point sampling is one place I've seen it done. The inner-loop to scale a line might look like this:

  frac = 0;
  while (len > 0) {
    for (frac += scale; frac >= 1; frac--)
      *dst++ = *src;
    src++;
  }
Instead of repeating the work of the inner loop every time, generate the code that has the scale baked in. For instance, doubling the image would output this code fragment repeated for the width of the source image:
  *dst++ = *src; *dst++ = *src; src++;
And scaling down by half would be:
  *dst++ = *src; src++; src++;
Though whether this is faster or the best technique really depends on the processor. It might be just as easy to pre-compute a lookup table pointing to the offset of the source pixel for each destination one. That's something an 8086 could do fairly easily and maybe a 6502, but not so much for a Z-80.