Science of Cambridge MK14 simulator

This is an attempt to make a Science of Cambridge MK14 simulator using JavaScipt + SVG that runs in a browser. It is a port of Paul Robson's DOS version. It uses SVG for the LED display. It can also use ascii for the display A timer is used to run some CPU instructions, every timer tick.

References: Paul Robson's page | copy of Paul Robson's pages | Karen Orton's Page techlib.com/area_50/Readers/Karen/micro.htm | more.. | MK_14 Rom listing | My notes | Scmp_Code | Scmp info | Elector Scmp info | ins grid | ins grid | sc/mp datasheet | my web site |


_ _ _ _ _ _ |_||_ | | | _|| |_ |_|| |_||_| | | _| |_ | | |_|| _|| |_ | | _|
For Tablets:

timed press ---___---.

Use the left mouse to press
the buttons below:-
GO MEM ABORT A
7 8 9 B
4 5 6 C
1 2 3 D
TERM 0 F E
RESET
example1:
XOR and store
press
abort 0 F 2 1 Mem
C 4 Mem
A A Mem
E 4 Mem
5 5 Mem
C 8 Mem
0 2 Mem
3 F
;now to execute
abort 0 F 2 2 GO
;you should read:
0F29 FF

 
SCIOS saves
after 3F,
0FF9 p1h
0FFA p1l
0FFB p2h
0FFC p2l
0FFD Acc
0FFE Extension
0FFF Status
The status register:-
  7   6  5  4  3  2  1  0
cy/l,OV,SB,SA,IE,F2,F1,F0
Bit Function 	Notes
0 	F0 	Output Line
1 	F1 	Output Line
2 	F2 	Output Line
3 	IE 	Interrupt Enable
4 	SA 	Input Line + INT,
5 	SB 	Input Line
6 	OV 	Overflow
7 	CY/L Carry / Link bit


display using: SVG: ascii: Simulate Speed: upto CPU instructions every 150 ms ms used. Display update: ms used.

Memory:

@ to P0 disp


Cheat:- Inject @ 0xFF9:

inputs: SIN: SB: SA:

P1h,p1l,P2h,P2l,ACC,Ext,Status,SIO

Cheat:- Inject code @ 0xF20:

Try SIO: 0xC4,0xAA,0x01,0x19,0x3f,0x19,0x3f,0x19,0x3f,0x19,0x3f,0x19,0x3f

Try: 0x90,0x0,0xc4,0x0,0x31,0xc4,0xd,0x35,0xc4,0xaa,0xcd,0x1,0xcd,0x1,0xcd,0x1,0xcd,0x0,0x90,0xec




Duck Shoot: run from 0f23, increase nuber of instructions per timer tick as well!


    2 0000:             ; duck shoot
    4 0000:             ; rcasm \D puts PC relative addresses out by one.
    8 0000:
            8060{
   11 0000:             Disp:	equ 0d00H
   12 0000:             ChRom:	equ 010bH
   13 0000:             Duck:	equ 061h
   15 0000:             ;	org	0f0fh
   17 0000:             	org	0f20h
   19 0f20: 00          Row:	db 0
   20 0f21: 00          Count:	db 0
   21 0f22: 00          Sum:	db 0
   24 0f23:             Shoot:
   25 0f23:             	; reload display pointer.
   26 0f23: c4 0d       	LDI	Disp.1
   27 0f25: 35          	XPAH	1
   28 0f26: c4 00       	LDI	Disp.0
   29 0f28: 31          	XPAL	1
   30 0f29: c4 01       	LDI	1
   31 0f2b: c8 f4       	STR	Row
   32 0f2d:             React:
   33 0f2d: c4 10       	LDI 	16	; speed of flight
   34 0f2f: c8 f1       	STR	Count
   35 0f31: c4 00       	LDI	0
   36 0f33: c8 ee       	STR	Sum
   44 0f35: c4 08       Shift:	LDI	8	;Move ducks this time
   47 0f37:             	; scan each digit and key
   48 0f37: 01          Ndig:	XAE
   49 0f38:             	; row contains bit map of ducks
   50 0f38:             	; rotate and test MSB
   51 0f38:             	; to see if duck present
   52 0f38: c0 e7       	LDR	Row
   53 0f3a:             			; rotate and check if duck in msb
   54 0f3a: 1e          	RR
   55 0f3b: c8 e4       	STR	Row
   56 0f3d: 94 04       	JP	No
   58 0f3f: c4 61       	LDI	Duck
   59 0f41: 90 02       	JMP	Go
   61 0f43:             No:
   62 0f43:             	; msb no set so no duck
   63 0f43: c4 00       	LDI 	0	;No duck
   66 0f45:             Go:
   67 0f45:             	; store at display using e
   68 0f45: c9 80       	ST	-128(1)
   69 0f47:             	;DLY	01
   70 0f47: 8f 01       	DLY	01
   72 0f49: c0 d8       	LDR	Sum
   74 0f4b: 9c 0e       	JNZ	Nok	;No Key
   77 0f4d:             	; load key E contains off set
   79 0f4d: c1 80       	LD	-128(1)
   80 0f4f: e4 ff       	XRI	0FFh
   81 0f51: 98 08       	JZ	Nok	; no key pressed
   85 0f53:             	;
   86 0f53:             	;ldi	0ffh
   87 0f53: c8 ce       	STR	Sum
   88 0f55: c0 ca       	LDR	Row
   90 0f57: e4 80       	XRI	080h
   92 0f59: c8 c6       	STR	Row	;Change top bit
   93 0f5b:             Nok:
   94 0f5b: 40          	LDE
   95 0f5c: 03          	SCL
   96 0f5d: fc 01       	CAI	1	; Subtract 1
   97 0f5f: 94 d6       	JP	Ndig	;Do next digit
   99 0f61:
  100 0f61: b8 bf       	DLDR	Count
  101 0f63: 98 c8       	JZ	React	;Start new position
  103 0f65:             	;	dle 	30
  104 0f65: c4 07       	LDI	7
  105 0f67:
  106 0f67: 90 ce       	JMP	Ndig 	;Another sweep
            }
  108 0f69:
;
;       Converts decimal number from keyboard to hex and displays in
;       'MEM' = minus, 'TERM' clears display
;		run from 0F50h
;
:180F5000C40F36C40032C400CA12CA0CCA0EC40137C459333F9028C435
:180F68000ACA1103C212016078014078019002C21302F20CCA1340F2AC
:180F80000E01BA119CF140CA0EC213CA0C90CFE40398C3C4FFCA12905F
:010F9800C593
:00000001FF

;       Mastermind      (MK14 Manual)
;
;       run from 0F1Ch
;
;       Term new game
;       Mem clear
;       Go process
;
:180F1C00C400C8EDC8ED32C40F36C40137C40B33C404CA10C40F35C4E8
:180F3400143103C104EC90C904D40F01C380CD01BA109CEFC40D35C43B
:180F4C000031C103E4FF98D8C4FFCA0FC400CA00CA0102C40137C45935
:180F6400333F900B40F4F694F1C41A333F90E5E4039A1BE4059CD9C436
:180F7C000BCA00CA01C40F35C41431C48001C404CA11C1F0E5019C0C85
:180F9400AA01C1FF58C9FFC1EF58C9EFBA119CEAC404CA11C404CA1064
:180FAC00C40F37C40833C5FF940ABA119CEE9013BA1098F6C100E7FFCB
:180FC4009CF6AA00C30058CB0090E7C404CA11C100D47FCD01BA119C90
:180FDC00F6C40135C20031C100CA00C20131C100CA01C4FFCA0F925D84
:00000001FF
;       Moon landing (MK14 Manual)
;
;       Keys 1-7 control the thrust
;
;       Major display problems on the old emulator
;		run from 0f52
;	0f08	Alt,
;	0f0B	Vel,
;	0f0E	Acceleration,
;	0f10	Thrust,
;	0f12	Fuel
;
:180F14000850009980009998000258003EC8E3C40135C8DFC40B31C877
:180F2C00DBC0D702D40F01C180CF01C4008F04C0C91C1C1C1C010603EA
:180F440094EDC400CF01C0BB35C0B93190CEC40F35C41431C40F36C4EA
:180F5C002032C40CCAE4C10BCDFFBAE49CF8C40C37C4FF33C401CAE473
:180F7400C5069404C5049032C402CAE302C5FFE902C900BAE39CF6C19A
:180F8C00029402C499EDFFC900BAE494E3C50CAAE303C5FFF9FEC900A9
:180FA40008BAE394F50694029004C400C9FFC1FF03EC94C9FDC499ECF9
:180FBC0000C9FCC1003EC1F9940AC49903F9FA03EC009002C1FA3EC173
:180FD400F73EC7FFC5F63EC40ACAE4C7FF940AE4DF9A31BAE49CF492E3
:0A0FEC0049C109980333C90992496D
:00000001FF
;       Reaction Timer from the MK14 Manual
;
;       after display lights up press 'MEM'
;		run from 0f20
;
:180F2000C40D35C40031C40F36C40032C40137C45933C205018F7D029D
:180F38007094F9C90340CA0CCA0EC4A88F0003C20C68CA0CC20E68CADE
:0C0F50000E4002F90398EB3F90FD90D09A
:00000001FF
;       Five silver dollars - machine plays against you moving five
;       silver dollars along a track - player unable to move loses
;		run from     0F28h
;
:060F1200FF0305080900C1
:180F2800C40F36C40032C40F35C41831C406CA24C1FACD01BA249CF8EA
:180F4000C400CA25C40F35C41931C40901C408CA8040FC0194F6C4055C
:180F5800CA24C5011E940BD47F01C280DC30CA80900701C280DC06CA9E
:180F700080BA249CE5C40137C484333F902A4098F403FC0694EFC40FF3
:180F880035C418027031C10002F4FF02F9FF940290DBC2259C0340CA5C
:180FA00025609E43B9009243C2259A43C403CA24C40F35C41831C400F3
:180FB80001C10102FD02C9046001BA249CF340980EE10003FD0294F66F
:180FD00002F1F9C9F9923FC405CA24C5FF02F4FF02F9FF9406BA249C0C
:070FE800F29307B900923FEC
:00000001FF
;
;       multiply two unsigned 8 bit numbers
;
;       P2->0   = A
;       P2->1   = B
;       P2->2   = Result(H)
;       P2->3   = Result(L)
;       P2->-1  = Temp
;
;       .org    0F50h
:180F5000C408CAFFC400CA02CA03C201021ECA019413C202F2001FCAA3
:110F680002C2031FCA03BAFF9CE83F90DBC20290ED9D
:00000001FF
;       divide 16 bit by 8 bit, both unsigned
;
;
;       P2->-1                  Quotient (temp)
;       P2->0   Divisor         Quotient (high)
;       P2->1   Dividend(High)  Quotient (low)
;       P2->2   Dividend(Low)   Remainder
;	 .org    0F80h
:180F8000C20001C400CA00CAFFC2010378CA011D9404AA0090F3C20191
:180F980070CA01C2020378CA02C201FC00CA011D9404AAFF90EDC202D2
:0A0FB00070CA02C2FFCA013F90C6DA
:00000001FF
;       16 bit Square Root
;
;       P2 points to number on entry (Hi,Lo) -1(2) is temporary
;
Hi      = 0
Lo      = 1
Temp    = -1

        .org    0F20h

:180F2000C400CAFF03BAFFF2FF01C4FEF40001F201CA0140F200CA000D
:100F38001D940290E7C400CA00FAFFCA013F90D886
:00000001FF
;       moves block of memory.
;
;       From = start address
;       To = end address
;       Length = no bytes
;
#define DatPtr(x)       ((x)+1)

E       = 80h

From    = DatPtr(0F1Bh)
To      = DatPtr(0F1Dh)
Length  = DatPtr(0F1Fh)

        .org    0F20h
:180F2000C4000103C0F9F8F5C0F4F8F01D9403C0EF0102C0E87031C040
:180F3800E3F4003502C0E07032C0DBF4003602409C02C4027801C58028
:070F5000CE80B8CC9CF83FF5
:00000001FF

example 1: XOR and store

Some very simple hex to type in to the MK 14. It works out 0xAA xor 0x55 which equals 0xFF. It stores the result in memory just after the return to the monitor.
abort 0F22 Term

or
abort 0F21 Mem
C4 Mem
AA Mem
E4 Mem
55 Mem
C8 Mem
02 Mem
3F
;now go and execute
abort 0F22
G
;
you should read:
0F29 FF

The code assembled using rcasm or asm:
   32 0f22:
   33 0f22:             	; load accumulator with 0xAA eor with 0x55 and store
   34 0f22: c4 aa       	ldi	0aah
   35 0f24: e4 55       	xri	055h
   36 0f26:
   37 0f26: c8 02       	st	2 (0)
   38 0f28:             	; return to the monitor
   39 0f28: 3f          	xppc	3
   40 0f29:
   41 0f29:
   42 0f29:             	; next code is overwritten by result.

example 2: write to display

execute from 0F20. Jmp to routine. set up P1 to point to the display. load 0xAA and write to display.
   31 0f20: 90 00       	jmp	main0
   32 0f22:
   33 0f22:             main0:
   34 0f22:             	; reload display pointer.
   35 0f22: c4 00       	LDI	Disp.0
   36 0f24: 31          	XPAL	1
   37 0f25: c4 0d       	LDI	Disp.1
   38 0f27: 35          	XPAH	1
   39 0f28:
   40 0f28: c4 aa       	ldi	0aah
   41 0f2a: cd 00       	st	@0(1)
   42 0f2c:
   43 0f2c: 90 f4       	jmp	main0
   44 0f2e:
   45 0f2e:

Instruction set

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 dddddddd18/10AC := (EA)
ST 11001mpp dddddddd18/10(EA) := ACOR
AND/ANI11010mpp dddddddd18/10AC := AC & (EA)
OR/ORI 11011mpp dddddddd18/10AC := AC | (EA)
XOR/XRI11100mpp dddddddd18/10AC := AC ^ (EA)
DAD/DAI (1)11101mpp dddddddd23/15AC,CYL := AC+(EA)+CY/L, base 10
ADD/ADI11110mpp dddddddd19/11AC,CYL := AC+(EA)+CY/L
CAD/CAI (2)11111mpp dddddddd20/12AC,CYL := AC+~(EA)+CY/L
ILD 101010pp dddddddd22AC,(EA) := (EA)+1
DLD 101110pp dddddddd22AC,(EA) := (EA)-1
JMP 100100pp dddddddd9PC := EA
JP 100101pp dddddddd9/11if AC > 0 PC := EA
JZ 100110pp dddddddd9/11if AC = 0 PC := EA
JNZ 100111pp dddddddd9/11if AC <> 0 PC := EA
DLY 10001111 dddddddd(3)Delay

(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 010000006AC := E
xae 000000017AC <-> E
ane 010100006AC := AC & E
ore 010110006AC := AC | E
xre 011000006AC := AC ^ E
dae 0110100011AC := AC + E + CY/L base 10 
ade 011010007AC := AC + E + CY/L
cae 011110008AC := AC + ~E + CY/L
xpal001100pp8AC <-> P.Low
xpah001101pp8AC <-> P.High
xppc011111pp7P <-> P0
sio 000110015Sout := E0,E := E >> 1, E7 := Sin
sr 000111005AC := AC >> 1
srl 000111015AC := AC >> 1,AC7 := CY/L
rr 000111105rotate right AC
rrl 000111115rotate right AC,CY/L
halt000000008Pulse 'H' (doesn't stop the CPU)
ccl 000000105CY/L := 0
scl 000000115CY/L := 1
dint000001006IEN := 0
ien 000001016IEN := 1
csa 000001105AC := S
cas 000001116S := AC (not SA or SB)
nop 000010005no operation

Assembler notes

Double byte instructions are represented as follows :-

Immediateldi 4Ch(immediate mode)
Indexedld 41(0)EAC := 42 + P0
Auto Indexedld @4(1)EAC := P1 then P1 := P1 + 4
Directld 42hEAC := 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 :-

  1. define the DatPtr macro as #define DatPtr(a) ((a)+1)
  2. allocate variables by address if they are being used in direct mode MyVar .equ DatPtr(0FE0h)

Requirements

My MK14 that I sold:

The MK14 had ram, rom, a National SC/MP cpu, display, keyboard, glue logic, and power supply This simulation has an array called Memory[], and the cpu is simulated. The display and keyboard have to be emulated, so that the code the SC/MP cpu runs works. One of the nice things was the SC/MP had "microcontroller" features with the three outputs and two inputs to the chip. It would be nice to have cheats as well. Poke bytes into memory. Offset calculators. LEDs on port pins. Switches on SIO input.

The Display

For a good idea, see: Karen Orton's Page http://techlib.com/area_50/Readers/Karen/micro.htm#PIC14 |

The display is at 0x0900+x where x is the digit. It is also at 0xd00+x. The MK14 had a 4 bit latch and binary decoder 74LS154 mux. The display lit one digit at a time. To illumiate the LED segments, the bit pattern is written into the address, and latch. The MK14 keeps displaying until the next write to the display. (* This simulation does not do this yet! *) Update display() when CPU writes to the display memory. This clobbers the speed, so only update webpage display every 150ms tick. This program uses SVG graphics and innerHTML to render the 7-segment display. It reads Memory[ 0x900 ] to Memory[ 0x909 ] at the moment.

The keyboard

The MK14 keyboard is scanned. The keyboard is a 4x8 matrix sharing the display logic. When a key is pressed a connection is made between the column and row. When the cpu reads from the Keyboard addresses, the display decoder pulls a column low. If a key is pressed, the accumulator has a low in the apropriate bit if the key is pressed. In a web page you can either track key up and down. Difficult:- Could use the mousedown() and mouseup() events. Buttons have different events to other tags. onclick(). The JavaScipt uses onmousedown() and onmouseUp() to set and reset a bit in an array called KeyPressesdA[] indexed by the button. This does not work on tablets, so the buttons use onclick(), which starts a timer that is clocked when the keys are scanned, and releases all keys on timeout. This is consulted when the sc/mp reads the keyboard address. This is 'dualport' Ram, accessed by the webpage and simulated CPU.
Buttons:-

reset

GO	MEM	Abort	A
7	8	9	B
4	5	6	C
1	2	3	D
term 	0	F	E

Layout:-
-----------------------------------
bit	|	7	6	5	4	3	2	1	0
-----------------------------------
ra3	|	7	6	5	4	3	2	1	0
ra2	|							9	8
ra1	|	Te			Ab 	Me	Go
ra0	|	F	E			D	C	B	A

http://www.javascript-coder.com/button/javascript-button-p1.phtml

The CPU


This ports Paul Robson's C code.

It needs the registers:
	ACC
	E
	status
	p0,p1,p2,p3

Functions:
	reset
	instructionInterpreter -  See Paul Robinson - I used his code.
	helper functions

The Memory map

Only the first 12 bits of the program counter are decoded

000-1FF  512 byte SCIOS ROM  Decoded by 0xxx
200-3FF  ROM Shadow / Expansion RAM
400-5FF  ROM Shadow / Expansion RAM
600-7FF  ROM Shadow / Expansion RAM
800-87F  128 bytes I/O chip RAM  Decoded by 1xx0
880-8FF  I/O Ports  Decoded by 1xx0
900-9FF  Keyboard & Display  Decoded by 1x01
A00-AFF  I/O Port & RAM Shadow
B00-BFF  256 bytes RAM (Extended) / VDU RAM  Decoded by 1011
C00-CFF  I/O Port & RAM Shadow
D00-DFF  Keyboard & Display Shadow
E00-EFF  I/O Port & RAM Shadow
F00-FFF  256 bytes RAM (Standard) / VDU RAM  Decoded by 1111

The ROM

Memory[] is populated with values from the ROM. MK_14 Rom listing | Karen Orton's Page http://techlib.com/area_50/Readers/Karen/micro.htm#PIC14 |

Conclusion

This webpage allows you to exprience the MK14. It allows you to use a mouse to press buttons on the keypad, enter hex and run it.

References to other pages provide enough information. It also allows me to provide a sandpit for playing with machine code

/********************************************************************/
/*																	*/
/*		Portable MK14 emulator in 'C' by Paul Robson	1998		*/
/*																	*/
/*        ported to JavaScript by Doug Rice , June 2016, March2017  */
/*																	*/
/*				I built a kit in 1977 or 78								*/
/*																	*/
/*								CPU Emulator						*/
/*																	*/
/********************************************************************/