Retour


The machine language of SC-61860

This page's trying to cover SC-61860's machine language used on most Sharp pocket computers (series PC-12??, PC-13??, PC-14?? and PC-2500)

Some french words :
Cette page est uniquement en anglais car je n'ai le temps de créer qu'une seule documentation, et puis, je fais beaucoup moins de fautes dans la langue de Shakespear. L'anglais n'est pas très recherché (car c'est le mien ;-D).

Please note : in this page

What is a SC-61860

The SC-61860 is a 8 bits CPU based on CMOS technology used by most 80' Sharp Pocket computer : PC-12??, 13?? and 14??. PC-15??, PC-1600 and all 4 bits powered pocket are excluded.
In fact this CPU should really called a 'Micro Controller' as it contains also some part of the LCD drivers (it's why it has so many pins).
It has also 8k of ROM embedded, named the "internal ROM", which is different between PC models, and 96 bytes internal memory. Notez bien : the internal ram is very very faster than the external one. Using this memory save lof of CPU cycles, and as the system clock is very slow, it will improve noticeably critical stuffs.

The Internal memory (96 bytes)

$00 I   Indexes
$01 J
$02 A   Accumulators
$03 B
$04 Xl X 16 bits register X
X = Xh * 256 + Xl
$05 Xh
$06 Yl Y 16 bits register Y
Y = Yh * 256 + Yl
$07 Yh
$08 K   General use registers
$09 L
$0a M
$0b N
$0c     Working area
...
$0f
$10 Xreg   BCD pseudo registers
Used by mathematicals calls
...
$17
$18 Yreg  
...
$1f
$20 Zreg  
...
$27
$28 Wreg  
...
$2f
$30     Working area

...
 

...
 
Stack
$5b
$5c Port A I/O Keyboard
$5d Port B I/O SD + SIO
$5e Port F O SD + SIO or Keyboard
$5f Port C O Control port

Internal RAM pointers (7 bits each)

16 bits external RAM pointer (16 bits)

Accumulators (8 bits)

Indexes (8 bits)

  • I ($00)
  • J ($01)
indexes is the official name of these registers but, in fact they are used mainly for repeated instructions. J is always set to '1' so instructions using this register are almost used for 16 bits manipulations (EXBD, ...?).

General use registers (8 bits)

  • K ($08),
  • L ($09),
  • M ($0a),
  • N ($0b)
Even if all bytes of the internal memory should be considered as a 'general use register', K,L,M,N have some special instructions to use them : INC? and DEC?.
Please also note that many mnemonics have 'M' in there names. It stand for (P), only INCM and DECM use directly the M register.

I/O ports

BCD pseudo registers

Some instructions can compute BCD numbers but, unlike mathematical processing unit of moderns CPU, they use normals registers in the "internal working memory".
So, in this memory, some groups of 8 bytes are commonly used for BCD computation by ROM functions :

(but you can use other parts of the memory for BCD computation, or use this memory for other task w/o any gain or loose).

Working area

This memory hold temporary objects :

The CPU stack

The stack start at $5b and increases downward. In fact, there is no real limit on stack expention and no check is done.

Unlike most other systems, the CPU stack is not intensively used.
For exemple, on 68000 systems, stacks are used to reserve working area, to pass parameters between functions, to store scrach registers and to store program environment when an interruption occurs, ... On SC61860's machine this stack is only used to stock return address of sub routines and eventually, to save some registers. And as this CPU doesn't have any interrupts capability, a very small stack is enough.

Mnemonics

Immediate loading

LIr n : r <- #n
The parameter is loaded into the register r.

LII n (&00), LIJ n (&01), LIA n (&02), LIB n (&03), LIP n (&12), LIQ n (&13)
LIDP nn (&10), LIDL n (&11)

For small values, LIP n can be shorted by LP n, coded in only one byte (LP 3F - &80 - to LP 3F - &BF -)

Loading

LDr : A <- r
The value of the register is loaded into A.

LDP (&20), LDQ (&21), LDR (&22),
and
LDD (&57) : A <- (DP)
LDM (&59) : A <- (P)

Storing

STr : r <- A
The value of A is loaded into the register.

STP (&30), STQ (&31), STR (&32),
and
STD (&52) : (DP) <- A

Please note : STM doesn't exist. Use EXAM instead.

Moving

MVW (&08) : [(P++) <- (Q++)] * I
MVB (&0A) : [(P++) <- (Q++)] * J (as J is usualy 1, perfect for 16 bits move)
MVWD (&18) : [(P++) <- (DP++)] * I
MVBD (&1A) : [(P++) <- (DP++)] * J (as J is usualy 1, perfect for 16 bits move)

MVDM (&53) : (DP) <- (P)
MVMD (&55) : (P) <- (DP)

DATA (&35) : [(P++) <- ({B,A}++);] * I
This instruction is the ONLY ONE for reading protected memory (i.e. first 8k ROM).

Exchange

EXW (&09) : [(P++) <-> (Q++)] * I
EXB (&0B) : [(P++) <-> (Q++)] * J (as J is usualy 1, perfect for 16 bits move)
EXWD (&19) : [(P++) <-> (DP++)] * I
EXBD (&1B) : [(P++) <-> (DP++)] * J (as J is usualy 1, perfect for 16 bits move)

EXAB : A <-> B (&DA)
EXAM : A <- (P) (&DB)

Increment / Decrement

INCr : r <- r+1
DECr : r <- r-1
Add or substract 1 to a register.
Flags (C and Z) are affected and Q is modified (INCP and DECP don't modify anything but P).

INCI (&40), DECI (&41), INCJ (&C0), DECJ (&C1), INCA (&42), DECA (&43), INCB (&C2), DECB (&C3), INCK (&48), DECK (&49), INCL (&C8), DECL (&C9), INCM (&4A), DECM (&4B), INCN (&CA), DECN (&CB), INCP (&50), DECP (&51)

Increment / Decrement on 16 bits registers

Ir : r <- r+1; DP <- r
Dr : r <- r-1; DP <- r
Add or substract 1 to a register and load DP

IX (&04), DX (&05), IY (&06), DY (&07),

X and Y registers allow blocs memory moves using following instructions :

IXL (&24): X <- X+1; DP <- X; A <- (DP)
DXL (&25): X <- X-1; DP <- X; A <- (DP)
IYS (&26): Y <- Y+1; DP <- Y; (DP) <- A
DYS (&27): Y <- Y-1; DP <- Y; (DP) <- A

So the following listing are equivalent
Normal listing Optimized listing
{start_loop}
	IX
	LDD
	IY
	STD
	DECI
	JRNZ {start_loop}
{start_loop}
	IXL
	IYS
	DECI
	JRNZ {start_loop}
and a ROM function implement this.

Arithmetics

Adding Subtracting
Binary

ADIA n (&74): A <- A + #n
ADIM n (&70): (P) <- (P) + #n

ADM (&44): (P) <- (P) + A
ADCM (&C4): (P) <- (P) + A + C

ADB (&14): (P+1,P) <- (P+1,P) + (B,A); P++

SBIA n (&75): A <- A - #n
SBIM n (&71): (P) <- (P) - #n

SBM (&45): (P) <- (P) - A
SBCM (&C5): (P) <- (P) - A - C

SBB (&15): (P+1,P) <- (P+1,P) - (B,A); P++

BCD
ADN n (&0C): [(P) <- (P) + A; P--; ] * I
ADW n (&0E): [(P) <- (P) + (Q); P--; Q-- ] * I
SBN n (&0D): [(P) <- (P) - A; P--; ] * I
SBW n (&0F): [(P) <- (P) - (Q); P--; Q-- ] * I

Logical operations

code AN
Logical AND
OR
Logical OR
TS
Test
CP
Compare
opIA n
A <- A op #n
&64 &65 &66 &67
opIM n
(P) <- (P) op #n
&60 &61 &62 &63
opID n
(P) <- (P) op #n
&D4 &D5 &D6 &D7
opMA n
(P) <- (P) op #n
&46 &47 &C6 &C7

for all operations, Z=1 if the result is null or Z=0 otherwise.
C is only affected by an CP instuction.

  • AN operations performs a logical AND : bits set in the results are bits set in both operands
  • OR operations performs a logical OR : bits set in the results are bits set at last in one operand
LIA  &12
ANIA &42
-> A = &02
LIA  &12
ORIA &42
-> A = &52
  • TS performs a virtual AND : the result is not stocked and only Z is touched.
  • CP compares 2 values and set flags using the following rules.
    CPIA n
    C Z
    A < n
    1 0
    A = n
    0 1
    A > n
    0 0

Jumping

  1. Unconditionnal jump :
    JRP n (&2C): PC <- PC + #n
    JRM n (&2D): PC <- PC - #n
    JP nn (&79): PC <- #nn

    For relative jump, JRP and JRM, the reference is the address of the argument. So

  2. Conditionnal jump :

    JRcP n, JRcM n, JPc nn does the same thing but with a condition :
    • Z : done if Z is set,
    • NZ : done if Z is not set,
    • C : done if C is set,
    • NC : done if C is not set,
    NZ Z NC C
    JRcP &28 &38 &2A &3A
    JRcM &29 &39 &2B &3B
    JPc &7C &7E &7D &7F

Sub routines

CALL nn (&78): (R-1,R) <- PC; R <- R-2; PC <- #nn
RTN (&37): PC <- (R-1,R); R <- R+2

CALL saves the current PC value and jump to a sub routine. RTN ends this sub routine and returns to the saved PC value (PC is now on the instruction following the CALL).
CAL 00 n (&E0) to CAL 1F n (&E0) does the same thing but saves one byte and some CPU cycle and are reserved for function in the first 8k memorie (the internal ROM).

Jump table

CASE1 nb rtn@dr
CASE2 val1 @dr1 val2 @dr2 ... valn @drn def@dr

Using theses instructions, it is very very easy to call a sub routine associated to a value of A (same as switch() / case structure in C.
Parameters :

  • nb : number of cases,
  • rtn@adr : return adress of functions,
  • vali & @dri : call @dri if A = vali.
  • def@dr : function to call if A doesn't match any value.

	CASE1 2 {rtn}
	CASE2
		31	{func1}
		32	{func2}
		{func_notfound}
{rtn}
		...

Stack management

PUSH (&34): (R) <- A; R <- R-1
POP (&5B): A <- (R); R <- R+1

Looping

LOOP n (&2F): (R) <- (R)-1; if c=0 then PC <- PC + 1 - #n else PC <- PC + 2; R <- R+1
LEAVE (&D8): (R) <- 0

With these instructions, a loop can be easily made, and LEAVE is an easy way to exit from a loop.
How to use LOOP
	LIA 5
	PUSH
	LIB 0
{lbl}
	INCB
	LOOP {lbl}
	LIDP &6c30
	EXAB
	STD
	RTN
	02 05
	34
	03 00
	
	C2
	2F 03
	10 6C 30
	DA
	52
	37
(&6C30) => 6

Port Instructions

INA (&4C): A <- PortA
OUTA (&5D): PortA <- ($5c)
INB (&CC): A <- PortB
OUTB (&5D): PortB <- ($5d)
OUTF (&5F): PortF <- ($5e)
OUTC (&DF): PortC <- ($5f)

Filling memory

FILM (&1E): [(P) <- A; P++] * I
FILD (&1F): [(DP) <- A; DP++] * I

Shifting

SL (&5A): Shift A left
SR (&5D): Shift A Right
RC
LIA &12
SL
SC
LIA &12
SL
RC
LIA &12
SR
SC
LIA &12
SR
RC
LIA &80
SL
RC
LIA &01
SR
=> &24
C = 0
=> &25
C = 0
=> &09
C = 0
=> &89
C = 0
=> &00
C = 1
=> &00
C = 1

SLW (&1D): Shift 4 bits left starting P and on I bytes.([SHIFT4LEFT(P); P <- P-1] * I)
SRW (&1C): Shift 4 bits right starting P and on I bytes.([SHIFT4RIGHT(P); P <- P+1] * I)

Waiting

WAIT n (&4E): Wait 6 + n cycles
NOPW (&4D): Wait 2 cycles
NOPT (&CE): Wait 3 cycles

Tape specialised functions

CUP (&4F): Wait if xin is not high
CDN (&6F): Wait if xin is not low

	d <- I;
	repeat
		d--;
	until (d==&ff or Xin=condition);

These instructions are mainly used to synchronize loading procedure with bits flows from tape.
C = false if the loop ends because of Xin = condition or C = false otherwise.

TEST

TEST n (&6B)

This instruction acts as if we TS a system port of the CPU.
bit number Name meaning
0 CT1 True if 512ms spent since the last counter reset.
1 CT2 True if 2ms spent since the last counter reset.
2
3 Kon True if [BRK] key is pressed.
4
5
6 RST True if we are reseting (False in case of powerup, True otherwise)
7 Xin Value of Xin
Example

{loop}
	TEST 08
	JRZM {loop}
Loops until [BRK] is pressed.

Miscellaneous

SWP (&58): Swap A7-4, A3-0 (LIA &ab; SWP => A=&ba).

SC (&D0): C=1, Z=1
RC (&D1): C=0, Z=1

Hum, I realy don't know what should be the useness of such instructions ;-D
READ (&56): A <- (PC + 1)
READM (&54): (P) <- (PC + 1)

WRIT (&D3): ????