This is extracted from the National Semiconductor Data Sheet dated March 1977. Specific details are available via email (firstname.lastname@example.org). Special thanks to Grant Searle for copying his documentation on the SC/MP and MK14
Whilst an SC/MP can address 64k , it does so rather ineffectively. Pointers do not wrap around above 4k, and there is no A12-A15 bus lines. They are multiplexed onto the data lines instead.
The SC/MP has a single interrupt input, which is also connected to the 'Sense A' line.
The accumulator is a standard 8 bit register. It is used in most data manipulation operations. Unlike most modern CPUs, the 'test & jump' operations do not operate on a 'flag register' but on the actual value in the accumulator itself.
The extension register provides a further 8 bit register. ALU operations are possible using this register as an operand, and it can also be used in indexing to provide a 2-level index register. The Extension register also has the facility to shift data in and out to hardware pins using the SIO command.
The status register provides storage for arithmetic, control and software status flags. There are 3 'output' flags which connect directly to pins on the IC, called F0,F1 and F2. There are two input flags , Sense A and Sense B, also connecting to the IC. Sense A has a dual function, as the interrupt line. The other 3 flags are system status flags
|3||IE||Interrupt Enable (set to 1 when enabled)|
|4||SA||Input Line, causes interrupt when SA = 1 and IE = 1|
|6||OV||Overflow on Add, or Complement and Add instructions|
|7||CY/L||Carry / Link bit|
On the MK14, cassette out is connected to F0, and cassette in to SIN. An interrupt is raised when IE = 1 and SA = 1
Program Counter (P0)
The program counter register P0 is a 16 bit program counter. It will not increment the 4 upper bits automatically, so an increment from 0FFF would go to 0000.
IMPORTANT: The SC/MP "fetch" is backwards. It increments the program counter, then fetches the instruction. This means that if you wish to 'jump' by setting the Program Counter, you must set it to one less than the actual address. This also means in the ROM at 0000 the first byte isn't used. The PC is set to 0000 on reset, then incremented, then fetched, so the first instruction is at 0001.
Pointer Registers (P1,P2,P3)
These are functionally equivalent to the Program Counter, except that they aren't used for the fetch/execute routines. They are all 16 bit. If Interrupts are being used, P3 contains the address of the routine. (an interrupt call just does XPPC 3 and clears IE)
The following address modes are available :-
These are functionally equivalent. The effective address is the current value of the PC or pointer register added to the displacement, which can range from -128..127. If the displacement is -128 then the displacement value used is in the Extension register.
Because of the backwards fetch/execute cycle most offsets are one out from what you might expect. This is because when the address is calculated the Program Counter still points at the displacement byte, not the next instruction.
0010 C0 04 This instruction is load indexed on 0 (the program counter). The effective address is 15 (the address of the displacement added to the displacement)
The data is in the next byte. There is no 'effective address' as such.
This is like the indexing mode except that the pointer register is pre-decremented or post-incremented by the displacement - if the displacement is -2 the pointer register has 2 subtracted before the data is fetched, if it is +2 it has 2 added after.
m is the mode bit. If 1 the instruction is auto-indexed, if 0 it is indexed. pp refers to a pointer register, P0..P3
If mpp is 100 (you can't auto index on the program counter), this is immediate mode. The data is in the next byte ( ). There is, of course, no store immediate.
Double Byte Instructions
|LD/LDI||11000mpp dddddddd||18/10||AC := (EA)|
|ST||11001mpp dddddddd||18/10||(EA) := ACOR|
|AND/ANI||11010mpp dddddddd||18/10||AC := AC & (EA)|
|OR/ORI||11011mpp dddddddd||18/10||AC := AC | (EA)|
|XOR/XRI||11100mpp dddddddd||18/10||AC := AC ^ (EA)|
|DAD/DAI (1)||11101mpp dddddddd||23/15||AC,CYL := AC+(EA)+CY/L, base 10|
|ADD/ADI||11110mpp dddddddd||19/11||AC,CYL := AC+(EA)+CY/L|
|CAD/CAI (2)||11111mpp dddddddd||20/12||AC,CYL := AC+~(EA)+CY/L|
|ILD||101010pp dddddddd||22||AC,(EA) := (EA)+1|
|DLD||101110pp dddddddd||22||AC,(EA) := (EA)-1|
|JMP||100100pp dddddddd||9||PC := EA|
|JP||100101pp dddddddd||9/11||if AC > 0 PC := EA|
|JZ||100110pp dddddddd||9/11||if AC = 0 PC := EA|
|JNZ||100111pp dddddddd||9/11||if AC <> 0 PC := EA|
(1) DAD and DAI are decimal add instructions. These do not affect the overflow
(2) CAD and CAI are complement and add instructions, these are used to subtract.
(3) Delays for 13 + 2 * AC + 2 * dddddddd + 2^9 * dddddddd cycles. (13-131,593), AC is set to -1 afterwards.
Single Byte Instructions
|lde||01000000||6||AC := E|
|xae||00000001||7||AC <-> E|
|ane||01010000||6||AC := AC & E|
|ore||01011000||6||AC := AC | E|
|xre||01100000||6||AC := AC ^ E|
|dae||01101000||11||AC := AC + E + CY/L base 10|
|ade||01101000||7||AC := AC + E + CY/L|
|cae||01111000||8||AC := AC + ~E + CY/L|
|xpal||001100pp||8||AC <-> P.Low|
|xpah||001101pp||8||AC <-> P.High|
|xppc||011111pp||7||P <-> P0|
|sio||00011001||5||Sout := E0,E := E >> 1, E7 := Sin|
|sr||00011100||5||AC := AC >> 1|
|srl||00011101||5||AC := AC >> 1,AC7 := CY/L|
|rr||00011110||5||rotate right AC|
|rrl||00011111||5||rotate right AC,CY/L|
|halt||00000000||8||Pulse 'H' (doesn't stop the CPU)|
|ccl||00000010||5||CY/L := 0|
|scl||00000011||5||CY/L := 1|
|dint||00000100||6||IEN := 0|
|ien||00000101||6||IEN := 1|
|csa||00000110||5||AC := S|
|cas||00000111||6||S := AC (not SA or SB)|
Double byte instructions are represented as follows :-
|Immediate||ldi 4Ch||(immediate mode)|
|Indexed||ld 41(0)||EAC := 42 + P0|
|Auto Indexed||ld @4(1)||EAC := P1 then P1 := P1 + 4|
|Direct||ld 42h||EAC := 42 (see below)|
There is no actual 'direct' mode. It is converted by the assembler into a PC-relative instruction.
Because of the pre-increment fetch problem, TASM in its normal form will assemble data references one out. So if you are going to use a data area, do it as follows :-
This will 'fudge' TASM by fixing the value so it can assemble properly. However it is not then possible to use this address by putting it into a Pointer Register and using indexing.
"Calls" via xppc need to be done with the address - 1, again. To call to address 0F40 use the following code :-
This will make the PC equal to 0F3Fh , and P1 equal to the address of the XPPC command after it has been executed. The prefetch increment makes the address 'correct'. On return (via XPPC 1 again) the prefetch increment before the next instruction will fix the program counter correctly.