The 1802 (actually, a specialized version of the architecture) was the first CPU (vs processors made from discrete components) to enter space (if it's a space probe from the 80's, it probably had an 1802 onboard). It also helped run the Magellan probe that mapped and then crashed (intentionally!) into Venus^. The 1802 also entered space in control of the Galileo probe^ and as a display controller on the Space Shuttle and on MAGSAT, OSCAR 9-11, UoSAT-1, UoSAT-2, later DMSP, Dynamics Explorer A & B. Note: It did NOT travel on the Viking or Voyagers, as is often claimed.^
It's just an 8 bit uC, with 64K address space, a slow 2.5Mhz clock and really poor efficiency (most instructions take 16 to 24 clock cycles), 91 instructions, 1 interrupt level and a wierd external DMA.
The 1802 is unusual for two reasons: It was made as static core CMOS called COSMOS (COmplementary Silicon/Metal-Oxide Semiconductor) so the clock could run as slowly as you like, all the way down to stopped. This allows for very low power operation and instant low power mode... just stop the clock. The architecture is also unusual with 16 general purpose registers, any one of which can become the program counter.
Name | Width | Description |
D | 8 | Accumulator |
P | 4 | PC Pointer. This register is NOT the Program Counter, but points to one of the 16 Address registers, which then becomes the PC. The next instruction to excecute comes from the memory address pointed to by the Address Register pointed to by P. Each instruction cycle loads that value into the I and N Control Registers, then excecutes those values. M(R(P)) -> I,N. As a result, there are effecivly 16 PC's, any one of which can become active by loading P via the SEP instruction. Of course, then you wouldn't have any data pointers... or a stack pointer, DMA, INT, etc... |
X | 4 | Address Pointer. Like the P register, X points to one of the 16 Address registers, but that memory value is then used in arithmetic, logic, and I/O instructions. X is loaded with the SEX (!) instruction. |
R(0)-R(F) | 16x16 | Address registers. There are 16, and each is 16 bits wide. R(0) is the DMA pointer. R(1) is used as the interrupt routine PC an interrupt sets P to 1. R(2) is used as the stack pointer (as required by the MARK instruction), R(3) is used as the primary Program Counter although, as noted, the PC is really R(P). |
DF | 1 | Carry bit |
IE | 1 | Interrupt Enable |
I,N | 4 | Instruction registers. Internal registers which hold the instruction currently being excecuted. |
T | 8 | Temporary register. An internal register used to hold the values of P and X when they are being saved via the MARK instruction. |
# | Op | Description | Action |
0 | IDL | IDLE | WAIT FOR DMA OR INTERRUPT; M(R(0)) -> BUS (Note 3) |
0N | LDN | LOAD VIA N | M(R(N)) -> D; FOR N |
1N | INC | INCREMENT REG N | R(N) + 1 -> R(N) |
2N | DEC | DECREMENT REG N | R(N) - 1 -> R(N) |
30 | BR | SHORT BRANCH | M(R(P)) -> R(P).0 |
31 | BQ | SHORT BRANCH IF Q = 1 | "IF Q = 1, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
32 | BZ | SHORT BRANCH IF D = 0 | "IF D = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
33 | BDF | SHORT BRANCH IF DF = 1 | "IF DF = 1, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P) (Note 2)" |
34 | B1 | SHORT BRANCH IF EF1 = 1 (EF1 = VSS) | "IF EF1 =1, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
35 | B2 | SHORT BRANCH IF EF2 = 1 (EF2 = VSS) | "IF EF2 = 1, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
36 | B3 | SHORT BRANCH IF EF3 = 1 (EF3 = VSS) | "IF EF3 = 1, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
37 | B4 | SHORT BRANCH IF EF4 = 1 (EF4 = VSS) | "IF EF4 = 1, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
38 | NBR | NO SHORT BRANCH (See SKP) | R(P) + 1 -> R(P) (Note 2) |
38 | SKP | SHORT SKIP (See NBR) | R(P) + 1 -> R(P) (Note 2) |
39 | BNQ | SHORT BRANCH IF Q = 0 | "IF Q = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
3A | BNZ | SHORT BRANCH IF D NOT 0 | "IF D NOT 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
3B | BNF | SHORT BRANCH IF DF = 0 | "IF DF = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P) (Note 2)" |
3C | BN1 | SHORT BRANCH IF EF1 = 0 (EF1 = VCC) | "IF EF1 = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
3D | BN2 | SHORT BRANCH IF EF2 = 0 (EF2 = VCC) | "IF EF2 = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
3E | BN3 | SHORT BRANCH IF EF3 = 0 (EF3 = VCC) | "IF EF3 = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
3F | BN4 | SHORT BRANCH IF EF4 = 0 (EF4 = VCC) | "IF EF4 = 0, M(R(P)) -> R(P).0, ELSE R(P) + 1 -> R(P)" |
4N | LDA | LOAD ADVANCE | M(R(N)) -> D; R(N) + 1 -> R(N) |
5N | STR | STORE VIA N | D -> M(R(N)) |
60 | IRX | INCREMENT REG X | R(X) + 1 -> R(X) |
61 | OUT 1 | OUTPUT 1 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 1 |
62 | OUT 2 | OUTPUT 2 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 2 |
63 | OUT 3 | OUTPUT 3 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 3 |
64 | OUT 4 | OUTPUT 4 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 4 |
65 | OUT 5 | OUTPUT 5 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 5 |
66 | OUT 6 | OUTPUT 6 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 6 |
67 | OUT 7 | OUTPUT 7 | M(R(X)) -> BUS; R(X) + 1 -> R(X); N LINES = 7 |
68 | not assigned | ||
69 | INP 1 | INPUT 1 | BUS -> M(R(X)); BUS -> D; N LINES = 1 |
6A | INP 2 | INPUT 2 | BUS -> M(R(X)); BUS -> D; N LINES = 2 |
6B | INP 3 | INPUT 3 | BUS -> M(R(X)); BUS -> D; N LINES = 3 |
6C | INP 4 | INPUT 4 | BUS -> M(R(X)); BUS -> D; N LINES = 4 |
6D | INP 5 | INPUT 5 | BUS -> M(R(X)); BUS -> D; N LINES = 5 |
6E | INP 6 | INPUT 6 | BUS -> M(R(X)); BUS -> D; N LINES = 6 |
6F | INP 7 | INPUT 7 | BUS -> M(R(X)); BUS -> D; N LINES = 7 |
70 | RET | RETURN | "M(R(X)) -> (X, P); R(X) + 1 -> R(X), 1 -> IE" |
71 | DIS | DISABLE | "M(R(X)) -> (X, P); R(X) + 1 -> R(X), 0 -> IE" |
72 | LDXA | LOAD VIA X AND ADVANCE | M(R(X)) -> D; R(X) + 1 -> R(X) |
73 | STXD | STORE VIA X AND DECREMENT | D -> M(R(X)); R(X) - 1 -> R(X) |
74 | ADC | ADD WITH CARRY | "M(R(X)) + D + DF -> DF, D" |
75 | SDB | SUBTRACT D WITH BORROW | "M(R(X)) - D - (NOT DF) -> DF, D" |
76 | SHRC | SHIFT RIGHT WITH CARRY | "SHIFT D RIGHT, LSB(D) -> DF, DF -> MSB(D) (Note 2)" |
76 | RSHR | RING SHIFT RIGHT | "SHIFT D RIGHT, LSB(D) -> DF, DF -> MSB(D) (Note 2)" |
77 | SMB | SUBTRACT MEMORY WITH BORROW | "D-M(R(X))-(NOT DF) -> DF, D" |
78 | SAV | SAVE | T -> M(R(X)) |
79 | MARK | "PUSH X, P TO STACK" | "(X, P)-> T; (X, P)-> M(R(2)), THEN P-> X; R(2) - 1-> R(2)" |
7A | REQ | RESET Q | 0 -> Q |
7B | SEQ | SET Q | 1 -> Q |
7C | ADCI | "ADD WITH CARRY, IMMEDIATE" | "M(R(P)) + D + DF -> DF, D; R(P) + 1 -> R(P)" |
7D | SDBI | "SUBTRACT D WITH BORROW, IMMEDIATE" | "M(R(P)) - D - (Not DF) -> DF, D; R(P) + 1 -> R(P)" |
7E | SHLC | SHIFT LEFT WITH CARRY | "SHIFT D LEFT, MSB(D) -> DF, DF -> LSB(D) (Note 2)" |
7E | RSHL | RING SHIFT LEFT | "SHIFT D LEFT, MSB(D) -> DF, DF -> LSB(D) (Note 2)" |
7F | SMBI | "SUBTRACT MEMORY WITH BORROW, IMMEDIATE" | "D-M(R(P))-(NOT DF) -> DF, D; R(P) + 1 -> R(P)" |
8N | GLO | GET LOW REG N | R(N).0 -> D |
9N | GHI | GET HIGH REG N | R(N).1 -> D |
AN | PLO | PUT LOW REG N | D -> R(N).0 |
BN | PHI | PUT HIGH REG N | D -> R(N).1 |
C0 | LBR | LONG BRANCH | "M(R(P)) -> R(P). 1, M(R(P) + 1) -> R(P).0" |
C1 | LBQ | LONG BRANCH IF Q = 1 | "IF Q = 1, M(R(P)) -> R(P).1, M(R(P) + 1) -> R(P).0, ELSE R(P) + 2 -> R(P)" |
C2 | LBZ | LONG BRANCH IF D = 0 | "IF D = 0, M(R(P)) -> R(P).1, M(R(P) +1) -> R(P).0, ELSE R(P) + 2 -> R(P)" |
C3 | LBDF | LONG BRANCH IF DF = 1 | "IF DF = 1, M(R(P))-> R(P).1, M(R(P) + 1)-> R(P).0, ELSE R(P) + 2 -> R(P)" |
C4 | NOP | NO OPERATION | CONTINUE |
C5 | LSNQ | LONG SKIP IF Q = 0 | "IF Q = 0, R(P) + 2 -> R(P), ELSE CONTINUE" |
C6 | LSNZ | LONG SKIP IF D NOT 0 | "IF D Not 0, R(P) + 2 -> R(P), ELSE CONTINUE" |
C7 | LSNF | LONG SKIP IF DF = 0 | "IF DF = 0, R(P) + 2 -> R(P), ELSE CONTINUE" |
C8 | NLBR | NO LONG BRANCH (See LSKP) | R(P) = 2 -> R(P) (Note 2) |
C8 | LSKP | LONG SKIP (See NLBR) | R(P) + 2 -> R(P) (Note 2) |
C9 | LBNQ | LONG BRANCH IF Q = 0 | "IF Q = 0, M(R(P)) -> R(P).1, M(R(P) + 1) -> R(P).0 EISE R(P) + 2 -> R(P)" |
CA | LBNZ | LONG BRANCH IF D NOT 0 | "IF D Not 0, M(R(P))-> R(P).1, M(R(P) + 1)-> R(P).0, ELSE R(P) + 2 -> R(P)" |
CB | LBNF | LONG BRANCH IF DF = 0 | "IF DF = 0, M(R(P))-> R(P).1, M(R(P) + 1)-> R(P).0, ELSE R(P) + 2 -> R(P)" |
CC | LSIE | LONG SKIP IF IE = 1 | "IF IE = 1, R(P) + 2 -> R(P), ELSE CONTINUE" |
CD | LSQ | LONG SKIP IF Q = 1 | "IF Q = 1, R(P) + 2 -> R(P), ELSE CONTINUE" |
CE | LSZ | LONG SKIP IF D = 0 | "IF D = 0, R(P) + 2 -> R(P), ELSE CONTINUE" |
CF | LSDF | LONG SKIP IF DF = 1 | "IF DF = 1, R(P) + 2 -> R(P), ELSE CONTINUE" |
DN | SEP | SET P | N -> P |
EN | SEX | SET X | N -> X |
F0 | LDX | LOAD VIA X | M(R(X)) -> D |
F1 | OR | OR | M(R(X)) OR D -> D |
F2 | AND | AND | M(R(X)) AND D -> D |
F3 | XOR | EXCLUSIVE OR | M(R(X)) XOR D -> D |
F4 | ADD | ADD | "M(R(X)) + D -> DF, D" |
F5 | SD | SUBTRACT D | "M(R(X)) - D -> DF, D" |
F6 | SHR | SHIFT RIGHT | "SHIFT D RIGHT, LSB(D) -> DF, 0 -> MSB(D)" |
F7 | SM | SUBTRACT MEMORY | "D-M(R(X)) -> DF, D" |
F8 | LDI | LOAD IMMEDIATE | M(R(P)) -> D; R(P) + 1 -> R(P) |
F9 | ORI | OR IMMEDIATE | M(R(P)) OR D -> D; R(P) + 1 -> R(P) |
FA | ANI | AND IMMEDIATE | M(R(P)) AND D -> D; R(P) + 1 -> R(P) |
FB | XRI | EXCLUSIVE OR IMMEDIATE | M(R(P)) XOR D -> D; R(P) + 1 -> R(P) |
FC | ADI | ADD IMMEDIATE | "M(R(P)) + D -> DF, D; R(P) + 1 -> R(P)" |
FD | SDI | SUBTRACT D IMMEDIATE | "M(R(P)) - D -> DF, D; R(P) + 1 -> R(P)" |
FE | SHL | SHIFT LEFT | "SHIFT D LEFT, MSB(D) -> DF, 0 -> LSB(D)" |
FF | SMI | SUBTRACT MEMORY IMMEDIATE | "D-M(R(P)) -> DF, D; R(P) + 1 -> R(P)" |
NOTES
* 0. Nomenclature / register summary:
D : data register, accumulator (16 bits). DF : data flag, carry (1 bit). P : program-counter register designator (4 bits). X : index register designator (4 bits). I : high nibble of instruction (4-bits) N : low nibble of instruction (4 bits). R(d) : 1 of 16 16-bit registers as designated by d. Q : Q flag (1 bit). IE : interrupt enable flag (1 bit). T : saved-state register (X,P) on interrupt (8 bits). M(a) : memory location addressed by a (8 bits).
* 1. The arithmetic operations and the shift instructions are the only instructions that can alter the DF.
After an add instruction: DF = 1 denotes a carry has occurred DF = 0 Denotes a carry has not occurred After a subtract instruction: DF = 1 denotes no borrow. D is a true positive number DF = 0 denotes a borrow. D is twoÕs complement The syntax Ò-(not DF)Ó denotes the subtraction of the borrow.
* 2. This instruction is associated with more than one mnemonic. Each mnemonic is individually listed.
* 3. An idle instruction initiates a repeating S1 cycle. The processor will continue to idle until an I/O request (INTERRUPT, DMA-lN, or DMA- OUT) is activated. When the request is acknowledged, the idle cycle is terminated and the I/O request is serviced, and then normal operation is resumed.
* 4. Long-Branch, Long-Skip and No Op instructions require three cycles to complete (1 fetch + 2 execute). Long-Branch instructions are three bytes long. The first byte specifies the condition to be tested; and the second and third byte, the branching address.
If the tested condition is met, then branching takes place; the branching
address bytes are loaded in the high-and-low order bytes of the current program
counter, respectively. This operation effects a branch to any memory location.
If the tested condition is not met, the branching address bytes are skipped
over, and the next instruction in sequence is fetched and executed.
This operation is taken for the case of unconditional no branch (NLBR).
* 5. The short-branch instructions are two bytes long. The first byte specifies the condition to be tested, and the second specifies the branching address.
If the tested condition is met, then branching takes place; the branching address byte is loaded into the low-order byte position of the current program counter. This effects a branch within the current 256-byte page of the memory, i.e., the page which holds the branching address. If the tested condition is not met, the branching address byte is skipped over, and the next instruction in sequence is fetched and executed. This same action is taken in the case of unconditional no branch (NBR).
* 6. The skip instructions are one byte long. There is one Unconditional
Short-Skip (SKP) and eight Long-Skip instructions. The Unconditional Short-Skip
instruction takes 2 cycles to complete (1 fetch + 1 execute). Its action
is to skip over the byte following it.
Then the next instruction in sequence is fetched and executed. This SKP
instruction is identical to the unconditional no-branch instruction (NBR)
except that the skipped-over byte is not considered part of the program.
The Long-Skip instructions take three cycles to complete (1 fetch + 2
execute).
If the tested condition is met, then Long Skip takes place; the current program counter is incremented twice. Thus two bytes are skipped over, and the next instruction in sequence is fetched and executed. If the tested condition is not met, then no action is taken. Execution is continued by fetching the next instruction in sequence.
Note that although there is a return from interrupt instruction, there is no standard call and return. Or standard stack push or pop. The MARK instruction uses R(2) as a stack pointer to save X and P but since those are 4 bits each, and P must point to the register used as the program counter, that can't be used to push data. As the MARK instruction and P hint, call / return and data stacks are built from multiple instructions and clever program layout.
To call a routine, we first load the starting address of the code into the Register which will become the PC. Then we set the P register to point to that register. The code is then executed. To return, we need to set P back to whatever register it was before. At this point, the Register used for the subroutine points to the end of the routine, and will need to be reloaded for the next call.
This is fine for a general call to subroutine, but for something we will do repeatedly, like an interrupt, we can avoid this by setting up the subroutine with the entry point in the middle, and at the end, branch back up to the start, where we set P back to the original Register. That leaves our subroutine register pointing to the entry point of the subroutine; ready for the next call. Because interrupts simply save P and X to T then set them to 1 and 2 (respectivly), we can set R(1) to the entry point of our interrupt routine, and as long as we do this branch to the top, and do a RET to restore P and X from T just before the entry point, we can set it and forget it.
A data stack can be implemented by setting X to a Register which points to empty memory. Then Push by loading the value to push into D (e.g. GLO or GHI) then using STXD to store D to the memory location pointed to by the Register pointed to by X, and decrementing that Register. Pop is the opposite, but the Register used is hard coded using LDA #, to move a byte into D from the memory value pointed to by the register pointed to in the LDA instruction (the #, so LDA 2 uses R(2)). But... LDA increments the Register after loading the value, so you have the INC 2 (or INC whichever Register is your stack pointer) first, then LDA, then store the value from D to wherever, THEN... INC 2 so the stack is ready for a new value. Yike. But it works. And you can have multiple stacks, which is cool.
1821 (1024×1 RAM), 1822 (256×4 RAM), 1823 (128×8 RAM), 1824 (32×8 RAM), 1826 (64×8 RAM), 1831/2 (512×8 ROM), 1833/4 (1024×8 ROM), 1835/6/7 (2048×8 ROM), 1851 (Programmable I/O Interface, 1852 (8-bit I/O Port), 1853 (n-bit Decoder I/O Interface), 1854 (UART), 1855 (multiply/divide coprocessor), 1856 (4-bit memory buffer), 1857 (4-bit I/O buffer), 1858 (4-bit latch w decoder), 1859 (4-bit latch w dual decoder), 1861 (Video display controller), 1862 (color generator), 1863 (Programmable tone generator), 1864 (PAL interface), 1866, 1867, 1868 (latch/decoder memory interface), 1869 (Video Interface System, Address and Sound Generator), 1870, 1876 (Video Interface System), 1871 (Keyboard encoder), 1872, 1874, 1875 (8-bit I/O Port), 1877 (Programmable Interrupt Controller), 1878 (Dual Timer), 1879 (Timer), 1881, 1882, 1883 (Latch w Decoder Memory Interface)
See also:
file: /Techref/1802/index.htm, 26KB, , updated: 2023/6/20 20:21, local time: 2024/11/5 06:41,
18.226.88.151:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/Techref/1802/index.htm"> 1802 Processor</A> |
Did you find what you needed? |