home   |   the links mine   |   6502 primer   |   large math look-up tables   |   65c02 assembly structure macros   |   simple multitask   |   6502 interrupts   |   zero-overhead Forth interrupts   |   RS-232 primer   |   assembly relevant today   |   NMOS-CMOS 6502 differences   |   6502 stacks treatise   |   workbench computers   |   self-modifying code   |   65816 misunderstandings

Self-modifying code on 65xx

On this page:

I was looking around to see what others have done with self-modifying code (SMC), toying with the idea of writing a 6502/816-oriented article on it.  The more I look, the more I think there is significant capability there that most of us have been neglecting.  Not much of this article is of my own invention.  Please help me improve it, by emailing me more ideas, links, short pieces of SMC, etc., at wilsonminesBdslextremeBcom (replacing the B's with @ and .).  I'll give you credit of course.

Before you get started in SMC:  A recent comment from a newbie prompts me to recommend that you first get cozy with the 65xx processors' existing instructions' offerings in indirection, indexing, and pre- and post-indexed indirects.  If you're new to the 6502 family, it's likely that there's already a built-in way to do what you want.

Definition and purpose of SMC:

Self-modifying code (SMC) is where the program writes bytes to its own instructions' op codes or operands.  This article is, so far, about SMC done in 65xx assembly language, not high-level languages (HLLs).  Possible reasons for using SMC include, but are not limited to, the following: SMC is simple to do on the 65xx processors and various others of its era, because an instruction's op code and operand are in separate bytes, not merged, and all op codes are one byte long.  These processors also have their instructions and data on the same bus, having a Von Neumann architecture, not a Harvard architecture.  There is no problem storing to instructions.

If you're resorting to SMC for speed, its greatest value might be where you have a loop with one or more instructions that get modified from outside the loop before the loop is started.  Then, a couple of cycles saved per iteration may result in hundreds of cycles saved by the time the loop finishes.



This last part goes beyond SMC, as it involves discrete or programmable logic to fool the processor in order to make new instructions.  With this hardware, a single WDM instruction can do multiple simultaneous output and input functions, and based on what was found at the specified input, artificially modify the next instruction as it gets delivered to the processor, sometimes adding an extra operand byte (by using RDY along with the special hardware logic).  The subject is too involved to detail it here, and I hope to have an article later on how to do it; but for now, maybe the following will stimulate the reader's imagination.

Twiddling bit 5 of op codes is particularly interesting, and Jeff Laughton has devised circuits that do that, depending on inputs during an immediately preceding WDM instruction which he uses to do input and output at the same time.  Which input and output bits to use are both specified in the WDM instruction's operand's bit fields.  Depending on the state of a specified input, the circuit intercepts bit 5 of the next op code and optionally inverts it before handing it to the processor, giving a lot of options to do one thing or another without the time-consuming branches around the unwanted parts of the code.  The circuit knows when an op code is being fetched (as opposed to operand or data or a dead-bus cycle) by both VDA and VPA are high (on the 65816), or SYNC is high (on the 6502).

Following are some noteworthy '816 opcode pairs which differ only in bit 5.  (Many could be applied to the '02 as well.)  All op codes are in hex.

He also had this kind of option for inverting an operand byte, the second byte of the next instruction following a WDM instruction!  (although the usefulness there takes more brain-twisting to grasp).  Following are some examples:

In our discussion as he was developing the circuit, we ran into a difficulty in that depending on when an interrupt hit, the next op code fetched might not be the next one executed.  Fortunately he figured out a solution, so that keeping the relevant instruction pairs together in execution time won't require disabling interrupts.

This would take programming into new territory.  Clearly some good macros would be in order, to take advantage.  (you still need to know what's in the macros—it's just that you don't have to keep seeing the ugly internal details every time you invoke one.)

outside links:

Codebase64 search results for SMC
Self modifying code forum topic from 2008
Bruce Clark's post on using SMC to shorten Forth's AND, OR, XOR, -, and +
Software - 65816 - Memory move, on the 6502.org wiki
token threading, on the 6502.org wiki
Fast block move on 65816 in bank 0 (using PEI) forum topic
Strotmann Atari wiki SMC page (archived)
Using BIT to skip 2 bytes (forum topic) Not quite SMC, but related.  Also discussed is using BIT ZP or BIT # to skip a single byte.  This strange use of BIT is usually for jumping around an instruction intended to be the first one at an entry point, such that the instruction doesn't get executed unless you branch or jump to it from outside.  It saves a byte compared to branching around the instruction.  See also this forum post.
Wikipedia article on SMC
gardners' comments on SMC, in the context of his GS4502B attempt to create a high-performance 6502-compatible CPU

last updated Feb 21, 2022