I only consider a processor to be computer if it can support self-hosted programming, so I wondered what it would take to manually toggle in a program on an MCU with no computer and minimal logic. I've produced a video based on this blog here.
I chose a primitive 8-bit PIC, because it has a simple programming algorithm, but even so, I have to enter 56 bits per instruction flashed. It was so tedious I printed out the entire sequence and used a ruler to make sure I didn't lose my position. Here's the 11-instruction program itself:
0 Bsf Status,5 ;01 0110 1000 0011
1 Bcf Trisc,4 ;01 0010 0000 0111
2 Bcf Status,5 ;01 0010 1000 0011
3 Movlw 53 ;11 0000 0011 0101
4 Movwf T1con ;00 0000 1001 0000 65536 cycles at 8us/cycle=
5 Btfss Pir1,0 ;01 1100 0000 1100 3.8s per full blink.
6 Goto 5 ;10 1000 0000 0101
7 Movlw 16 ;11 0000 0001 0000
8 Xorwf PortC,f;00 0110 1000 0111 (Don't care about RMW issues)
9 Bcf Pir1,0 ;01 0000 0000 1100
10 Goto 5 ;10 1000 0000 0101
You don't need a GOTO start at address 0: if you don't have any interrupt code you can just start your program at address 0.
The reason why it's so tedious is that programming each instruction involves four command sequences:
- Load the instruction into (I presume) an internal buffer.
- Burn the instruction into flash memory.
- Verify the flash memory instruction you've just programmed (always worthwhile as it's so easy to make a mistake).
- Increment the address of the PC. Unlike many MCU flash programming algorithms, the 8-bit PICs can only have their programming address reset (by unpowering the MCU, connecting the PIC's /MCLR signal to 12V, then powering the rest of the MCU at 5V) and then incremented. Thus making a mistake (most likely because you've left out a bit or duplicated one) means you have to start again.
In addition, each programming command expects all the data to be entered from the LSB to the MSB, so in fact I toggled in all the commands backwards, reading each line from right to left. So, the first full command really looked as follows (with '|' separating individual fields):
Bsf Status,5 |0|01 0110 1000 0011|0|000010 Bit 5 is RP0, status is 3
(Prog) | |001000 Bsf is 01 01bb bfff ffff.
(ReadBack) |0|-- ---- ---- ----|0|000100
(Inc) | |000110
The PIC needs just two signals to program it: a clock input and data signal. My hardware is (relatively speaking) super simple.
I use an astoundingly primitive 555 timer chip in its monostable (one shot) mode to debounce the clock. All I needed was a couple of capacitors and resistors to give a 0.2s delay and it would eliminate bounce. All the information I needed came from the wikipedia page on the 555 timer.
The data button was a bit more challenging. I used a few resistors and a red LED as I needed Vdd when I pressed the button, less than 0.8V when I let go, but I also needed to enable the DAT line to drive the LED when verifying data and not exceed current limits even if I accidentally pressed the button when the DAT was trying to output. One of the downsides to this approach is that the LED is barely visible on the video, though in retrospect I think I could have halved the resistor values and it would have been fine.
Finally, I needed a 12V programming voltage for the PIC, and then used a basic 7805 voltage regulator to generate the 5V Vdd voltage for the 555 and PIC. The currents are so small I didn't need to worry about a heatsink for the 7805.
On a PIC it's not good enough just to program the flash, I needed to change the internal configuration to stop the Watchdog from resetting the PIC after 4ms and to use the internal oscillator instead of an external RC oscillator. The spec on programming the configuration is rather confusing, because the sequence to go into config mode requires the full 14-bit configuration setting, and then you have to enter it again as a normal programming instruction.
With some experimentation I got it right in the end! With a bit more detail, I started off by finding out how I could enter one instruction (after running the erase command), and then two instructions. I made two attempts to program the entire program - in the first attempt I made a mistake on the last-but-one instruction and had to start again, I videoed both of them so although the toggling sequence is complete and not spliced from multiple attempts, it wasn't the first attempt.
I had a similar problem with the configuration. It took a few attempts at that to get it right and at one point I thought I had configured it to use an external oscillator and couldn't read the flash anymore. In fact I had mis-inserted the VPP to the right of the 7805's IN pin.
So, it's possible, but not very practical to manually toggle program an MCU, but perhaps survivalist geeks might find it useful in some post-apocolyptic dystopia!