Welcome

Palm Keygenz HandBook ...

by saerdna ... memberz of Palmwarez

version 1.0 12/27/2000

send comments to keygenz@palm.as

writing Keygenz is the highest Level of
Reverse Engineering

If you want create a Keygen (PSNG Plugin)

for a PalmOS Application, i hope

this Tutorial will help you ;-)

You can reach us on IRC #palmwarez

http://pilotwarez.com
http://pilotwarez.org
http://pilotwarez.net


Tools you need !

  • CodeWarrior6 for Palm

    To create a PSNG Plugin you need CodeWarrior6 for PalmOS

    Sorry, CodeWarrior5 does NOT work with PSNG SDK 2.0....

  • PSNG SDK2

    This is a great Framework for CodeWarrior6 to create Keygens for PalmOS Applications..

    The only stuff you must do is write the DoCalc Routine ...

  • PRCEdit (much easier with this GREAT Tool)

    Thanks to DrFunk ... another member of Palmwarez ;-)

  • Debuffer 1.2

    To analyze the code, we need a good Debugger..


Step by Step

You are ready to go ?

let’s start...

Þ | Get the Target you want use and analyze the code
Þ | Get a real serial with Debuffer for your HotSyncID sometimes..the Keygen Routine also use ROMID to generate the serial.
Þ | Get the serial for few HotSyncID's with length > 10, special characters like äöü (german umlaut)...
Þ | Trace through the Keygen Routine(s) with Debuffer and analyze the code.
Þ | If you have experience in programming in C, you can write the Keygen Routine directly in CodeWarrior.. but for me, i prefer to first write a "Prototype" in Delphi or VB...
Þ | When you have tested your Keygen with few HotSyncID's generate the PSNG Plugin with CodeWarrior..
& | And now... publish your Keygen in Palmwarez


The PSNG SDK2

Palm Serial Number Generator - version 2.0

...brought to you by the SPC...

This is our second release (2.0) of our PSNG application for the Palm platform. This will allow you to generate codes based based on things like the HotSync User Name, ROM ID (probably not really used since it isn't supported on all the Palm models), or User ID. If some other input is required, the plugin author will provide a custom dialog box to get the input.

It is a good idea to hit the "Get Plugin Info" button to see if anything special needs to be entered. It should also tell you where you can get the warez and more...

There are many new features in version 2. It now has Categories so that plugin developers can create plugins for the Palm, Mac, PC or Other platforms. Another great feature is the ability to generate a list of serial numbers. The list will be generated according to the Category you have set. It will be stored in the Memo Pad and split into chunks of 4k if you have a lot of plugins (for support of old units).

The PSNGPlug SDK is available for you hacking types to develop new plugins. We used (and suggest) "CodeWarrior for Palm OS R6" or newer. There are two SDK templates. A simple SDK for when you only need basic info like the HotSync Name. It is the preferred method because there will be no need for any specialized input. If a generator needs specialized info, say for a Mac SNG, then it will prompt the user for information.

Have fun,

a couple SPC krackers.

P.S. and rememeber.. PSNG is for educational and entertainment purposes only.

if you truly enjoy any of the fine apps that you create numbers for.. purchase them..

To paraphrase one of our friends: We believe in supporting shareware authors when we decide to keep an application. We just hate being limited or bothered during testing. Others have told us the same.

This app is Shareware: If you like it and use it, then buy some shareware (any platform will do!)


PSNG SDK2 Installation

Installation is easy...

Extract the PSNG into a directory

below CW for Palm OS

Now you can load the PSNGPlug.mcp

Project with CodeWarrior6


first Target SuperList2

Target1 -> SuperList2

OK, now let’s start with our first Target... SuperList2 v2.2a from Tapnese

First Step

  • We start PRCEdit and analyze the Code and search the Keygen Routine(s)

  • hmmm there a 2 parts we need to calculate the code..


SuperList2 Part1

Part1 ... the changes on our HotsyncName

To fully understand this code i used Debuffer and traced
Step by Step through this Routine, with few HotsyncNames ;)

000069ba
000069be
000069c2
000069c6
000069c8
000069ca
000069cc
000069ce
000069d2
000069d4
000069d8
000069da
000069de
000069de
000069e0
000069e2
000069e6
000069e8
000069ec
000069ee
000069f0
000069f2
000069f4
000069f8
000069fa
000069fe
00006a00
00006a04
00006a08
00006a0c
00006a12
00006a14
00006a18
00006a1a
00006a1c
00006a22
00006a24
00006a2a
00006a2c
00006a30
00006a36
00006a38
00006a3c
00006a3e
00006a42
00006a44
00006a48
00006a4a
00006a4c
00006a4e
00006a50
00006a54
00006a58
00006a5a
00006a5c
00006a5e
00006a60
00006a64
00006a6a
00006a6c
00006a6e
00006a70
00006a76
00006a7a
00006a7e
00006a82
00006a86
00006a88
00006a8c
00006a90
00006a94
00006a9a
00006a9c

4e56fffc
48e71f30
266e0008
4243
4245
4244
4207
b6fc0000
6604
47faa6ec
2f0b
4e4fa0c7

3200
4246
426efffe
3001
0c410006
6f02
7006
b046
6f60
43ec0930
3444
1032b800
e808
1d40ffff
41ec0453
342efffe
13b020003000
5243
1032b800
740f
c082
13b008003000
5243
13bc003a3000
5243
41ec0470
11b2b8005000
5245
de32b800
5244
0c410006
6f0a
0c440003
6604
3801
5744
5246
6000ff94
41ec0930
1007
e808
740f
c082
43ec0453
11b108003000
5243
700f
c087
11b108003000
42303001
41ec0470
42305000
4a2e000c
6608
41ec0930
60000006
41ec0470
4cee0cf8ffe0
4e5e
4e75

L735

L736

L737

L738

L739

L740

L741
L742

LINK A6,#-4
MOVEM.L D3-D7/A2/A3,-(A7)
MOVEA.L 8(A6),A3
CLR.W D3
CLR.W D5
CLR.W D4
CLR.B D7
CMPA.W #0,A3 <- A3 our full HotsyncName
BNE L736
LEA L143,A3
MOVE.L A3,-(A7)
TRAP #15
DC.W sysTrapStrLen
MOVE.W D0,D1 <- length of full HotsyncName
CLR.W D6
CLR.W -2(A6)
MOVE.W D1,D0
CMPI.W #6,D1 <- check length HotsyncName with 6
BLE L738
MOVEQ #6,D0
CMP.W D6,D0
BLE L740
LEA 2352(A4),A1
MOVEA.W D4,A2
MOVE.B 0(A2,A3.L),D0 <- D0 = 1 char of HotsyncName
LSR.B #4,D0
MOVE.B D0,-1(A6)
LEA 1107(A4),A0
MOVE.W -2(A6),D2
MOVE.B 0(A0,D2.W),0(A1,D3.W)
ADDQ.W #1,D3
MOVE.B 0(A2,A3.L),D0
MOVEQ #15,D2
AND.L D2,D0
MOVE.B 0(A0,D0.L),0(A1,D3.W)
ADDQ.W #1,D3
MOVE.B #58!$3a,0(A1,D3.W)
ADDQ.W #1,D3
LEA 1136(A4),A0
MOVE.B 0(A2,A3.L),0(A0,D5.W)
ADDQ.W #1,D5
ADD.B 0(A2,A3.L),D7
ADDQ.W #1,D4 <- D4 = D4 + 1 ..counter
CMPI.W #6,D1 <- D1 length of full HotsyncName
BLE L739 <- hmm check if HotsyncName <= 6
CMPI.W #3,D4 <- D4 .. counter <> 3 hmm
BNE L739
MOVE.W D1,D4 <- D4 = length of HotsyncName
SUBQ.W #3,D4 <- D4 = length(HotsyncNme)-3
ADDQ.W #1,D6
BRA L737 <- jump
LEA 2352(A4),A0 <-3first & 3last char in Hex
MOVE.B D7,D0
LSR.B #4,D0
MOVEQ #15,D2
AND.L D2,D0
LEA 1107(A4),A1
MOVE.B 0(A1,D0.L),0(A0,D3.W)
ADDQ.W #1,D3
MOVEQ #15,D0
AND.L D7,D0
MOVE.B 0(A1,D0.L),0(A0,D3.W)
CLR.B 1(A0,D3.W)
LEA 1136(A4),A0 <-3first & 3last char ! of our HotsyncName
CLR.B 0(A0,D5.W)
TST.B 12(A6)
BNE L741
LEA 2352(A4),A0
BRA L742
LEA 1136(A4),A0 <-3first & 3last char ! of our HotsyncName
MOVEM.L -32(A6),D3-D7/A2/A3
UNLK A6
RTS

Conclusion

This Routine takes our HotsyncName and check if length(HotsynName) > 6, if this is true it generates a new HotsyncName with the 3first and 3last characters, otherwise it takes the original HotsyncName!


SuperList2 Part2

Part2 ... the Calcualtion Routine

00006e06
00006e0a
00006e0c
00006e0e
00006e12
00006e14
00006e16
00006e1a
00006e1a
00006e1c
00006e1e
00006e20
00006e22
00006e24
00006e26
00006e2a
00006e2c
00006e2e
00006e30
00006e32
00006e34
00006e38
00006e3a
00006e3c
00006e3e
00006e42
00006e46
00006e48

4e560000
2f0a
2f03
246e000a
4243
2f0a
4e4fa0c7

3040
4241
b648
6412
7400
3401
10322800
4880
d640
5241
b248
65f0
b66e0008
57c0
4880
4440
262efff8
246efffc
4e5e
4e75

L760

L761 I->
I
I
I loop
I
I
I-------
L762

LINK A6,#0
MOVE.L A2,-(A7)
MOVE.L D3,-(A7)
MOVEA.L 10(A6),A2 <- our "cleaned" HotsyncName
CLR.W D3 <- D3 = 0
MOVE.L A2,-(A7)
TRAP #15
DC.W sysTrapStrLen
MOVEA.W D0,A0 <- length to A0
CLR.W D1 <- D1 = 0
CMP.W A0,D3 <- length > D3 ?
BCC L762 <- Equal then jump
MOVEQ #0,D2 <- D2 = 0
MOVE.W D1,D2 <- D2 = D1
MOVE.B 0(A2,D2.L),D0 <- D0 = HotsyncName[D2]
EXT.W D0
ADD.W D0,D3 <- add ascii val to D3
ADDQ.W #1,D1 <- D1 = D1+1
CMP.W A0,D1 <- D1 = length ?
BCS L761 <- Not Equal then jump
CMP.W 8(A6),D3 <- compare fakeSerial with realSerial
SEQ D0 <- $0000FFFF if equal, else 0
EXT.W D0
NEG.W D0 <- 1 if equal, else 0
MOVE.L -8(A6),D3
MOVEA.L -4(A6),A2
UNLK A6
RTS

Conclusion

This Routine calculates the Sum(HotsyncName)


SuperList2 C-Prototype

Keygen C-Prototype

This is a very easy KeygenCode J

If you are not a C-Programmer (like me) it’s a good idea to code the first version of a Keygen in a programming Language you have experience.

// generate theName first3 and last3 characters

if (StrLen(hsname) > 6)
{
theName[0] = hsname[0];
theName[1] = hsname[1];
theName[2] = hsname[2];
theName[3] = hsname[StrLen(hsname)-3];
theName[4] = hsname[StrLen(hsname)-2];
theName[5] = hsname[StrLen(hsname)-1];
theName[6] = '\0';
}
else
{
for (i=0;i<StrLen(hsname);i++)
{
theName[i]=hsname[i];
theName[i+1]='\0';
}
}
// calculate sum of theName
 for (i=0;i<StrLen(theName);i++)
theNum = theNum + theName[i];


second Target WorldMate5

Target2 -> WorldMate5

OK, now let’s start with our second Target... WorldMate 5.0 from Mobimate

First Step

  • We start PRCEdit and analyze the Code and search the Keygen Routine

  • Hmm.. it’s only a single and short Routine


WorldMate5 CodePart

the KeygenRoutine

To fully understand all part of this code you can use Debuffer and trace Step by Step through this Routine, with few HotsyncNames ;)

00006fde
00006fe2
00006fe6
00006fe8
00006fec
00006fee
00006ff0
00006ff4
00006ff6
00006ff8
00006ffa
00006ffe
00006ffe
00007002
00007006
00007006
00007008
0000700a
0000700e
00007010
00007014
00007018
0000701a
0000701e
00007020
00007022
00007024
00007026
00007028
0000702a
0000702c
0000702e
00007030
00007032
00007034
00007036
00007038
0000703c
00007040
00007042
00007044
00007046
0000704a
0000704c
00007050
00007054
00007058
0000705e

4e56ffd6
48e71e00
7a00
422effd6
42a7
42a7
486effd6
42a7
42a7
42a7
4e4fa2a9

486effd6
4e4fa0c7

3c00
7600
4fef001c
6020
41eeffd6
10303000
4880
0640ff9f
3800
4a40
6c06
3004
4440
6002
3004
da40
5243
b646
65dc
700b
c1c5
0640001b
b06e0008
6604
7001
601e
486db97c
42a7
3f2e0008
487a000e
487a0004
0697ffffa13c
4e75

L974

L975------I>
I
I
I
I
I loop
I
I
I
I
I L976
I L977
I
I L978
----------------

L979

LINK A6,#-42
MOVEM.L D3-D6,-(A7)
MOVEQ #0,D5
CLR.B -42(A6)
CLR.L -(A7)
CLR.L -(A7)
PEA -42(A6)
CLR.L -(A7)
CLR.L -(A7)
CLR.L -(A7)
TRAP #15
DC.W sysTrapDlkGetSyncInfo
PEA -42(A6)
TRAP #15
DC.W sysTrapStrLen
MOVE.W D0,D6 <- D6 = length(HotSyncName)
MOVEQ #0,D3 <- counter
LEA 28(A7),A7
BRA L978
LEA -42(A6),A0
MOVE.B 0(A0,D3.W),D0 <- D0 = HotSyncName[counter]
EXT.W D0
ADDI.W #-97!-$61,D0 <- D0 = D0 – 97 hmmm
MOVE.W D0,D4 what, if D0 < 97 ?
TST.W D0
BGE L976 <- D0 >= 0 jump
MOVE.W D4,D0
NEG.W D0
BRA L977
MOVE.W D4,D0
ADD.W D0,D5 <- D5 = D5 + D0
ADDQ.W #1,D3 <- counter = counter + 1
CMP.W D6,D3 <- end of length(HotSyncName) ?
BCS L975
MOVEQ #11,D0
MULS.W D5,D0 <- D0 = D0 * 11
ADDI.W #27!$1b,D0 <- D0 = D0 + 27
CMP.W 8(A6),D0 <- compare fakeSerial with realSerial !
BNE L979
MOVEQ #1,D0
BRA L982
PEA -18052(A5)
CLR.L -(A7)
MOVE.W 8(A6),-(A7)
PEA L981
PEA L980
ADDI.L #-24260!-$5ec4,(A7)
RTS

Conclusion

Maybe the only critical Part of this Routine could be the Part 00007018 - 00007018
when D0 < 97 ... but if you trace through the Code with Debuffer,
you will see there is a easy solution J


WorldMate5 C-Prototype

Keygen C-Prototype

Ok.. here is my C-Prototype of the Keygen Routine..

int counter = 0;
unsigned int theNum=0;

// calculate serial..
 for (counter=0;counter<StrLen(hsname);counter++)
{
if (hsname[counter] > 97)
theNum=theNum + (hsname[counter] - 97);
else
theNum=theNum + (97 - hsname[counter]);
}

theNum=theNum * 11;
theNum=theNum + 27;


third Target SafeInHand

Target3 -> SafeInHand by drFunk

OK, now let’s start with our third Target... SafeInHand from PalmInHand

First Step

  • We start PRCEdit and analyze the Code and search the Keygen Routine(s)

  • hmmm the UnLock Key is based on ROM ID
    for details read     Fishing serial where Keygen is based on ROM ID


SafeInHand CodePart

the KeygenRoutine
be aware, this calculation is based on the ROM ID !

000000be
000000c2
000000c6
000000ca
000000cc
000000ce
000000d2
000000d2
000000d4
000000d6
000000d8
000000da
000000dc
000000de
000000e2
000000e4
000000e6
000000e8
000000ea
000000ec
000000f0
000000f2
000000f4
000000f6
000000f8
000000fa
000000fe
00000100
00000102
00000106
00000108
0000010a
0000010b

4e560000
48e71e20
246e000a
7800
2f0a
4e4fa0c7

3c00
7600
584f
601c
7000
3003
1a320800
702a
9044
d043
1205
4881
0641000d
c2c0
3801
5243
b646
65e0
b86e0008
57c0
4400
4cdf0478
4e5e
4e75
87
4576616c4b6579

L8

L9à
|
|
|
|
|
|Loop
|
|
|
|
|
L10
-----

LINK A6,#0
MOVEM.L D3-D6/A2,-(A7)
MOVEA.L 10(A6),A2
MOVEQ #0,D4 <-D4 = result
MOVE.L A2,-(A7)
TRAP #15
DC.W sysTrapStrLen
MOVE.W D0,D6 <-D6 is length of RomID
MOVEQ #0,D3 <-clear Loop counter
ADDQ.W #4,A7
BRA L10
MOVEQ #0,D0
MOVE.W D3,D0
MOVE.B 0(A2,D0.L),D5 <-D5 = char
MOVEQ #42,D0 <-D0 = 42
SUB.W D4,D0 <-D0 = 42 - D4
ADD.W D3,D0 <-D0 = (42 - D4) + Loop counter
MOVE.B D5,D1 <-D1 = char
EXT.W D1
ADDI.W #13!$d,D1 <-D1 = char + 13
MULU.W D0,D1<-D1=(cha +13)*((42-D4)+loop counter)
MOVE.W D1,D4<-D4=(cha +13)*((42-D4)+loop counter)
ADDQ.W #1,D3
CMP.W D6,D3 <-D6 = len, D3 = loop counter
BCS L9
CMP.W 8(A6),D4 <-compare Key with typed value
SEQ D0
NEG.B D0
MOVEM.L (A7)+,D3-D6/A2
UNLK A6
RTS
DC.B #135
'EvalKey'


SafeInHand C-Prototype

Keygen C-Prototype

Ok.. here is the C-Prototype of the Keygen Routine..

x = StrLen( romid ); // string length of our complete text string.

if (x > 10) {

for ( i = 1 ; i < 6 ; i++) {

romid[5+i] = romid[x-5+i];

romid[11] = '\0';

x = 10;

}

for ( i = 0 ; i < x ; i++ ) {

ch = romid[i];

theNum = (unsigned long) ((ch + 13) * (unsigned int)((42 - theNum) + i));


use the application self as keygen

In this Part of the Keygenz Handbook we use the Target self as Keygen !!

  • The idea
    – modify the bad guy message to a Alertbox which show us the real serial

Ok.. let’s start with our Target Triv 3.0 from http://www.rjen.com


Triv 3.0 overview

hmm.. first we must replace the bad guy message AlertResource through a CustomAlert Resource, so we can show the real serial in this dialog!

Let’s take a look into the PalmOS API definitions...

Alert Resource

Example

Overview

The alert resource defines a modal dialog that displays a message, an icon, and one or more buttons. A small icon indicates the category of the dialog box; for example, an exclamation mark for an error message. The icon appears on the left side of the dialog. The text is justified left but placed to the right of the dialog icon.

Type | Icon | Definition | Button | Example
Information | i | Lowest-level warning. Action shouldn't or can't be completed but doesn't generate an error or risk data loss. | OK | An alarm setting must be between 1 and 99.
Confirmation | ? | Confirm an action or suggest options. | OK, Cancel | Change settings before switching applications? (For example, when pressing an application key with an open dialog box.)
Warning | ! | Ask if user wishes to continue a potentially dangerous action. | OK, Cancel | Are you sure you want to delete this entry?
Error | (stop sign) | Attempted action generated error and/or cannot be completed. | OK | Disk full.

The Alert resource has the following attributes.

Attributes

Alert Type

Determines the sound played and the icon displayed when the alert is drawn. There are four possible icons:

  • InformationAlert (Alert Number 0)

  • ConfirmationAlert (Alert Number 1)

  • WarningAlert (Alert Number 2)

  • ErrorAlert (Alert Number 3)

Help ID

The ID of a String resource that's the help text for the alert dialog box. If you provide a value, the system displays an "i" in the top right corner of the alert box.

Default Button ID

The number of a button that the system assumes is selected if the user switches to another application, forcing the form to go away without making a selection.

Title

Title of the alert form.

Message

Message displayed by the alert dialog. May contain ^1, ^2, ^3 as substitution variables for use in conjunction with FrmCustomAlert.

Button Text

Text of the button (e.g. OK or Cancel), determined by an entry in the resource of each button.
To add a button, select Item Text 0, and type Cmd-K.

FrmCustomAlert

Purpose

Create a modal dialog from an alert resource and display the dialog until the user taps a button in the alert dialog.

Prototype

Word FrmCustomAlert (Word alertId, CharPtr s1, CharPtr s2, CharPtr s3)

Parameters

-> alertId

Resource ID of the alert.

-> s1, s2, s3

Strings to replace ^1, ^2, and ^3 (see Comments).

Result

Returns the number of the button the user tapped (the first button is zero).
Comments

A button's item number is determined by its order in the alert template; the first button has the item number zero. Up to three strings can be passed to this routine. They are used to replace the variables ^1, ^2 and ^3 that are contained in the message string of the alert resource.

If the variables ^1, ^2, and ^3 occur in the message string, do not pass NULL for the arguments s1, s2, and s3. If you want an argument to be ignored, pass the empty string (""). In Palm OS 2.0 or below, pass a string containing a space (" ") instead of the empty string.


Triv 3.0 find and change AlertResource

Now we must first disasm our Target with pilotdis..
then search for the AlertResource with our bad guy message..

you can easy find it when you search for the title of our bad guy message..

now we modify this AlertResource to a CustomAlertResource....

modify following
– Title
– AlertString Text and include a variable ^1
– Type of the Icon if you want..

original AlertResource

00016b18
00016b1b
00016b25
00016b2e
00016b2f
00016b39
00016b43
00016b4d
00016b57
00016b61
00016b6b
00016b75
00016b7f
00016b89
00016b91

010000
52656769737472617469
6f6e204661696c6564
00
536f7272792c20796f75
72207265676973747261
74696f6e20636f646520
646964206e6f74206d61
74636820796f75722075
736572206e616d652e20
506c6561736520636865
636b20746865206e756d
62657220616e64207472
7920616761696e2e
004f4b00

DC.B
DC.B

DC.B
DC.B

DC.B

DC.W

#1,#0,#0
'Registration Failed'

#0
'Sorry, your registration code did not match your user name. Please check the num'

'ber and try again.'

#79,#19200

modified AlertResource

00016b18
00016b1b
00016b25
00016b2e
00016b2f
00016b39
00016b43
00016b4d
00016b57
00016b61
00016b6b
00016b75
00016b7f
00016b89
00016b91

010000
4772656574696e677a20
3b2d29202020202020
00
2350616c776172657a20
70726573656e74732079
6f7572207265616c2073
657269616c3a205e3120
20202020202020202020
20202020202020202020
20202020202020202020
20202020202020202020
20202020202020202020
2020202020202020
004f4b00

DC.B
DC.B

DC.B
DC.B

DC.B

DC.W

#1,#0,#0
'Greetingz ;-) '

#0
'#Palwarez presents your real serial: ^1

' '

#79,#19200


Triv 3.0 change call of AlertResource

now, after changing the AlertResource to a CustomAlertResource we need to change the
call of this AlertResource and pass the real serial to this Routine..

original call of the AlertResource

00003d62
00003d64
00003d66
00003d6a
00003d6e
00003d6e
00003d70
00003d74
00003d76
00003d7c
00003d80
00003d82
00003d86
00003d88
00003d8c
00003d8e
00003d90
00003d94
00003d94
00003d98
00003d9a
00003d9c
00003da0
00003da4
00003da8
00003da8
00003daa
00003dac
00003db0
00003db4
00003db8
00003db8

2648
2f0b
486dfba4
4e4fa0c8

4a40
4fef000c
6636
1b7c0001e8fa
4eba4c68
42a7
3f3c089e
2f0a
4eba2a42
5c4f
2f08
4e4fa158

4a2de8ab
504f
6704
4eba2be2
3f2dfea4
4e4fa19e

544f
6044
422de8fa
3f3c0514
4e4fa192

544f

L486

L487

MOVEA.L A0,A3
MOVE.L A3,-(A7)
PEA -1116(A5) pointer to real serial string
TRAP #15
DC.W sysTrapStrCompare
TST.W D0
LEA 12(A7),A7
BNE L487
MOVE.B #1,-5894(A5)
JSR L1142
CLR.L -(A7)
MOVE.W #2206!$89e,-(A7)
MOVE.L A2,-(A7)
JSR L835
ADDQ.W #6,A7
MOVE.L A0,-(A7)
TRAP #15
DC.W sysTrapFldSetTextHandle
TST.B -5973(A5)
ADDQ.W #8,A7
BEQ L486
JSR L847
MOVE.W -348(A5),-(A7)
TRAP #15
DC.W sysTrapFrmReturnToForm
ADDQ.W #2,A7
BRA L490
CLR.B -5894(A5)
MOVE.W #1300!$514,-(A7)
TRAP #15
DC.W sysTrapFrmAlert //bad guy message
ADDQ.W #2,A7

call of our modified AlertResource

00003d62
00003d62
00003d64
00003d66
00003d6a
00003d6e
00003d6e
00003d70
00003d74
00003d78
00003d7a
00003d7c
00003d80
00003d82
00003d86
00003d88
00003d8c
00003d8e
00003d90
00003d94
00003d94
00003d98
00003d9a
00003d9c
00003da0
00003da4
00003da8
00003da8
00003daa
00003dac
00003db0
00003db4
00003db8
00003db8

2648
2f0b
486dfba4
4e4fa0c8

4a40
4fef000c
486dfba4
6032
4e71
4eba4c68
42a7
3f3c089e
2f0a
4eba2a42
5c4f
2f08
4e4fa158

4a2de8ab
504f
6704
4eba2be2
3f2dfea4
4e4fa19e

544f
6044
422de8fa
3f3c0514
4e4fa19 4

544f

L486

L487

DC.W sysTrapFldGetTextPtr
MOVEA.L A0,A3
MOVE.L A3,-(A7)
PEA -1116(A5) pointer to real serial string
TRAP #15
DC.W sysTrapStrCompare
TST.W D0
LEA 12(A7),A7
PEA -1116(A5) load pointer to real serial string
BRA L487 jump to modified AlertMsg
NOP
JSR L1142
CLR.L -(A7)
MOVE.W #2206!$89e,-(A7)
MOVE.L A2,-(A7)
JSR L835
ADDQ.W #6,A7
MOVE.L A0,-(A7)
TRAP #15
DC.W sysTrapFldSetTextHandle
TST.B -5973(A5)
ADDQ.W #8,A7
BEQ L486
JSR L847
MOVE.W -348(A5),-(A7)
TRAP #15
DC.W sysTrapFrmReturnToForm
ADDQ.W #2,A7
BRA L490
CLR.B -5894(A5)
MOVE.W #1300!$514,-(A7)
TRAP #15
DC.W sysTrapFrmCustomAlert show our modified AlertBox!
ADDQ.W #2,A7

Ok, now our target will work like a keygen J
when we enter any serial, the modified AlertBox will present us the real serial!


CodeWarrior6 generate PSNG Plugin

Now we would create the PalmOS PSNG Plugin with CodeWarrior6

Let’s start CodeWarrior6 and load the original PSNG Project..

set the Project Properties to our Traget..

Replace the DoCalc Function with our Code ...

This is the DoCalc Function for SuperList2...

Now we need to change the Function PlugEntry ...

yeahh.. now we can MAKE our Project... press the make Button

Load the Psng2.prc and our new created Plugin into POSE

and calculate your serial... ;-)


Keygenz Code Snippes

Dear Reader... be aware... i’m not a C-programmer ;-)
If you can do it better.... do it !

// generate cleanName strip special characters

count=0;
for (i=0;i<StrLen(hsname);i++)
{
if ((hsname[i]>64 && hsname[i]<91) || (hsname[i]>96 && hsname[i]<123 ))
{
cleanName[count]=hsname[i];
count=count+1;
}
}
cleanName [count]='\0';

// lowercase hsname

StrToLower(theName, hsname); //convert to LowerCase

// calculate sum(hsname)

for (i=0;i<StrLen(hsname);i++)
{
theSum=theSum+hsname[i];
}

// create UserName for compute the serial..

// first 5 char and last 5 character

if (StrLen(hsname)>10)
{
for(i=0;i<5;i++)
{
computename[i]=hsname[i];
computename[9-i]=hsname[StrLen(hsname)-i-1];
}
computename[10]='\0';
}
else
{
for(i=0;i<StrLen(hsname);i++)
{
computename[i]=hsname[i];
computename[StrLen(hsname)]='\0';
}
}

// generate theName .. replace special characters with "Space"

count=0;
for (i=0;i<StrLen(hsname);i++)
{
if (hsname[i]<123 && hsname[i]>31 ) // no special character
{
theName[count]=hsname[i];
theName[count+1]='\0';
count=count+1;
}
else
{
theName[count]=' '; // special char = "Space"
theName[count+1]='\0';
count=count+1;
}
}


Palm Debuffer 1.2 Summary

Trap into Debuffer
place OPCODE 4E48 into the prc-file.

Quitting
Type "bye" (no quotes) to exit. If you do not have a prompt because
the debugger is waiting for a debug event, hit "Ctrl+C".

Syntax
The arguments to each command are specified in the stack-effect comment immediately following the command. Since the Debuffer command language is FORTH, type the arguments first (in the order listed) before the command word. For example, to disassemble the next 10 commands at the current program counter, type "pc @ 10 dis".

Registers
.regs ( -- ) Print all registers.

DragonBall registers are mapped to FORTH variables in the debuffer.
Access each using the register name: d0, d1, d2, d3, d4, d5, d6, d7,
a0, a1, a2, a3, a4, a5, a6, usp, ssp, pc, and sr. fp is an alias for a6.
All registers except sr are 32-bits. sr is 16-bits.

Examining and Modifying Memory
@byte ( addr -- n ) Fetch the 8-bit value at the given address.
@word ( addr -- n ) Fetch the 16-bit value at the given address.
@long ( addr -- n ) Fetch the 32-bit value at the given address.
!byte ( byte addr -- ) Store the 8-bit value to the given address.
!word ( word addr -- ) Store the 16-bit value to the given address.
!long ( long addr -- ) Store the 32-bit value to the given address.
da ( addr count -- ) Dump ASCII.
db ( addr count -- ) Dump bytes.
dd ( addr count -- ) Dump double-words (longs).
dw ( addr count -- ) Dump words.
dis ( addr count -- ) Disassemble count instructions at the given address.

Breakpoints
bc ( bpid -- ) Clear breakpoint.
bd ( bpid -- ) Disable breakpoint.
be ( bpid -- ) Enable breakpoint.
bl ( -- ) List breakpoints.
bp ( addr -- ) Set a breakpoint.
bp takes an optional string argument to execute when the breakpoint is hit.

Controlling Execution
go ( -- ) Resume execution.
next ( -- ) Step to the next instruction, over branches.
nospy ( -- ) Remove any installed step-spy.
out ( -- ) Step out of the current routine.
spy ( addr value -- ) Install a step-spy for *addr == value.
step ( -- ) Step to the next instruction, into branches.
to ( addr -- ) Run to the specified address.
wait ( -- ) Wait for something to happen.

Miscellaneous
bt ( -- ) Backtrace.
ln ( addr -- ) Lookup the name for the given address.


Fishing serial out from a StrCompare

Debuffer Tips

Fishing serial out from a StrCompare

Part with StrCompare from a Keycheck Routine

000037f4
000037f4
000037f6
000037f8
000037fc
00003800
00003800
00003802
00003806

2648
2f0b
486dfba4
4e4fa0c8

4a40
4fef000c
6636

DC.W sysTrapFldGetTextPtr
MOVEA.L A0,A3
MOVE.L A3,-(A7)
PEA -1116(A5)
TRAP #15
DC.W sysTrapStrCompare
TST.W D0 <- break here!
LEA 12(A7),A7
BNE L488

How can we read the values with Debuffer ?
Ok, first let’s take a look into the PalmOS API definitions...

PalmOS API StrCompare Routine

StrCompare
 Purpose
Compare two strings.
Prototype
Int StrCompare (CharPtr s1, CharPtr s2)
Parameters
s1, s2 Two string pointers.
Result
Returns 0 if the strings match.
Returns a positive number if s1 sorts after s2 alphabetically.
Returns a negative number if s1 sorts before s2 alphabetically.
Comments
Use this function instead of the standard strcmp routine.
This function is case sensitive. Use it to sort strings but not to find them.
This function performs a character-by-character comparison of s1 and s2 and returns
as soon as it finds two unequal characters. For example, if you are comparing the string
"celery" with the string "Cauliflower," StrCompare returns that "celery" should appear
before "Cauliflower" because it sorts the letter "c" before "C."

The Debugging Session

OK, set the Debuffer Break OPCODE 4E48 just below the StrCompare and start Debuffer..

and now we must get the 2 Pointers to the Strings....
we can do it with the Debuffer command: ssp @ 8 db
this will show us the 2 Pointers to the Strings as hex value..
Pointer to String1: 0001804e Pointer tp String2: 00002750

To see the Strings we need to convert the Hex values to decimal addresses....
0001804e -> dec: 98382 and 00002750 -> dec: 10064
with the Debug command: 98382 20 db we can see 20 bytes of the first String J
hey.... that’s the real Serial for our HotsyncName !
The second String shows my fake Serial..


Fishing serial where Keygen is based on ROM ID

Debuffer Tips

Fishing serial where Keygen is based on ROM ID

If we have a target with a Keyroutine based on the ROM ID we have a problem to fish the real serial with Debuffer for our PalmDevice...

hmmm... how can we set the ROM ID in POSE ?

let’s take a look into the PalmOS API definitions...

PalmOS Reference Guide
Some Palm devices, beginning with the Palm III product, hold a 12-digit serial number that
identifies the device uniquely. However not all PalmOS Platform devices (Handspring, IIIe and m100) contain flash ROM memory chips. They contain what is known as mask ROM chips, which do not have this serial number and are not upgradeable.
The serial number is held in a displayable text buffer with no null terminator.
The user can view the serial number in the Application Launcher application.
(The pop-up version of the Launcher does not display the serial number.)
The Application Launcher also displays to the user a checksum digit that you can use
to validate user entry of the serial number.

first we look at POSE with Application Launcher for our ROM ID

On POSE..no ROM ID will be displayed... ! | what on a real Palm device ?

ok, i have found a cool utility SetNewSerial that should do this for us.
You can get it on http://klyatskin.da.ru

but first we must edit the SetNewSerial.prc and insert our ROM ID from
the real device, so POSE will use our ROM ID.
Use a HEX Editor and open the file SetNewSerial.prc

you need to enter (your) ROM ID from a real Palm device..

now save this modified SetNewSerial.prc as mySetNewSerial.prc

then install Hackmaster and our new mySetNewSerial on POSE

After enable SetNewSerial on POSE, look for the ROM ID with Application Launcher...

yeah... we are now ready for our Debug session :)

The Debugging Session

we use our Target SafeInHand as sample..
OK, set the Debuffer Break OPCODE 4E48 just below the StrCompare and start Debuffer..

Keygen Routine of SafeInHand

000000be
000000c2
000000c6
000000ca
000000cc
000000ce
000000d2
000000d2
000000d4
000000d6
000000d8
000000da
000000dc
000000de
000000e2
000000e4
000000e6
000000e8
000000ea
000000ec
000000f0
000000f2
000000f4
000000f6
000000f8
000000fa
000000fe
00000100
00000102
00000106
00000108
0000010a
0000010b

4e560000
48e71e20
246e000a
7800
2f0a
4e4fa0c7

3c00
7600
584f
601c
7000
3003
1a320800
702a
9044
d043
1205
4881
0641000d
c2c0
3801
5243
b646
65e0
b86e0008
57c0
4400
4cdf0478
4e5e
4e75
87
4576616c4b6579

L8

L9à
|
|
|
|
|
|Loop
|
|
|
|
|
L10
-----

LINK A6,#0
MOVEM.L D3-D6/A2,-(A7)
MOVEA.L 10(A6),A2
MOVEQ #0,D4
MOVE.L A2,-(A7)
TRAP #15
DC.W sysTrapStrLen
MOVE.W D0,D6
MOVEQ #0,D3
ADDQ.W #4,A7
BRA L10
MOVEQ #0,D0
MOVE.W D3,D0
MOVE.B 0(A2,D0.L),D5
MOVEQ #42,D0
SUB.W D4,D0
ADD.W D3,D0
MOVE.B D5,D1
EXT.W D1
ADDI.W #13!$d,D1
MULU.W D0,D1
MOVE.W D1,D4
ADDQ.W #1,D3
CMP.W D6,D3
BCS L9
CMP.W 8(A6),D4 <-compare Key with typed value
SEQ D0 <- break here!
NEG.B D0
MOVEM.L (A7)+,D3-D6/A2
UNLK A6
RTS
DC.B #135
'EvalKey'

After break into Debuffer, D4 should have the real serial !
convert hex 77BC to dec -> 30652


68K ASM Instructions Part1

68000 Instruction Set

ABCD - Add Binary Coded Decimal
This instruction is a specialized arithmetic instruction that adds together two bytes (and only bytes) containing binary-coded decimal numbers. The addition can either be done between two data registers or between two memory locations. If performed on bytes in memory, only address register indirect with predecrement addressing can be used. This facilitates easy manipulation of multiple-precision BCD numbers. The extend bit is added along with the BCD bytes to allow this multiprecision data manipulation. Also note that the Zero flag is only changed if the result becomes non-zero. Therefore, both the Extend and Zero bits in the condition code register should be preset before the operation is performed. The Extend bit would normally be preset to a zero (to prevent extension on the first addition), and the Zero bit to a one (to preset a zero result prior to the first addition). A MOVE #4,CCR would setup these flags correctly. Syntax: ABCD Dn, Dn or ABCD -(An), -(An). Flags affected: The Extend, Zero, and Carry flags are affected as per the result of the operation. The state of the Negative and Ovreflow flags is undefined.
ADD - Add Binary
The ADD instruction adds the source to the destination operand with the result appearing in the destination. It is possible to add bytes, words, or long words with this opcode. Either the source or destination (or both) must be a data register. The source operand can be any memory location or data register, and the destination operand can also be any memory location or data register. Syntax: ADD Dn, Dn or ADD address, Dn or ADD Dn, address. Flags affected: The Extend, Negative, Zero, Overflow, and Carry flags are all affected as per the result of the addition.
ADDA - Add Address
This variant of the ADD instruction only differs from ADD in that an address register is specified as the destination. As an address rather than data is being manipulated, the condition code flags are left unaltered. Only sign-extended words or long words can be added.
ADDI - Add Immediate
This variant of the ADD instruction is used to add a constant value to the destination. The immediate operand can be any 8-, 16-, or 32-bit value as specified by the .B, .W, or .L opcode suffix. The destination can not be an address register or a program counter relative address. Syntax: ADDI #imm, Dn or ADDI #imm, address where address is any memory addressing mode except program counter relative. Flags affected: The Extend, Negative, Zero, Overflow, and Carry flags are all set as per the result of the addition.
ADDQ - Add Quick
This variant of the ADD instruction is used to add a small positive integer between one and eight to the destination. The destination can be a memory location, a data register, or an address register. If it is an address register, the condition code flags are unaffected and the operand length can not be a byte. This operation takes the place of the increment instruction found on other processors. Syntax: ADDQ #imm, Rn or ADDQ #imm, address. Flags affected: The Extend, Negative, Zero, Overflow, and Carry flags are all set as per the result of the addition unless the destination is an address register.
ADDX - Add Extended
This variant of the ADD instruction adds two numbers plus the Extend bit from the condition code register. This allows multiple-precision additions to be performed. For this reason, the Zero flag is only affected when a non-zero result is obtained. This means that if multiple numbers are added together using ADDX, the Zero flag will stay reset if any of those numbers were non-zero. Syntax: ADDX Dn, Dn or ADDX -(An), -(An).
AND - Logical AND
This instruction logically ANDs bits in the source operand with the same number of bits in the destination operand were the result is left. The number of bits can be 8, 16, or 32 as per the .B, .W, or .L opcode suffix. One or both operands must be a data register. Syntax: AND Dn, Dn or AND Dn, memory or AND memory, Dn.
ANDI - Logical AND Immediate
This instruction logically ANDs an immediate byte, word, or long word value with the destination. The destination can be a data register, memory, or one of two special cases: the condition code register, only a byte-length immediate value is allowed. If the destination is the status register, only a word-length immediate value is allowed, and the processor must be in supervisor mode or a priviledge voilation will occur. Syntax: ANDI #imm, Dn or ANDI #imm, memory or ANDI.B #imm 8-bit value, CCR or ANDI.W #imm 16-bit value, SR (Privileged). Flags affected: The Overflow and Carry bits are reset, the Negative and Zero bits set as per the result, and the Extend bit is unaffected.
ASL - Arithmetic Shift Left
This instruction shifts the destination operand left by a specified number of bits. If you are shifting a data register, the number of bits to be shifted can be specified as an immediate value or as a value in another data register. The immediate value can be 1 to 8, whereas the data register can be 1 to 64 (where zero acts as the 64 count). Data registers may be shifted as 8, 16, or 32 bit quantities. Only 16-bit word values can be shifted in memory and then only by one bit. As shown below zeroes are shifted in at the right hand side of the operand. As each bit is shifted out of the left of an operand, it is placed in the Carry and Extend bits of the condition code register. If the sign of the operand changes during the shift, the Owerflow bit is set in the condition code register. C < < | <<< ASL <<< | < 0 X < Syntax: ASL Dn, Dn or ASL #imm 3-bit value, Dn or ASL memory (1 bit shift only).
ASR - Arithmetic Shift Right
This instruction shifts the destination operand right by a specified number of bits. If you are shifting a data register, the number of bits to be shifted can be specified as an immediate value or as a value in another data register. The immediate value can specify a shift of 1 to 8, while the data register can specify a shift of 1 to 64 (where zero acts as the 64 count). Data registers may be shifted as 8, 16, or 32 bit quantities. Only 16-bit word values can be shifted in memory and then only by one bit. Each bit shifted out of the right hand side of an operand is placed in the Carry and Extend bits of the condition code register. As shown below the bit shifted in at the left hand side is the current sign bit (the most significant bit is therefore preserved throughout the shift). > C Current MSB > | >>> ASR >>> | > > X Syntax: ASR Dn, Dn or ASR #imm 3-bit value, Dn or ASR memory (1 bit shift only).
BRA - Branch Always
This instruction changes the program counter register so execution continues at a different point in the program code. The destination of the jump is specified as a signed displacement to the program counter. This signed displacement can be an 8- or 16- bit quantity. With a bit 8-bit quantities, this allows branches of +126 to -128 bytes; 16-bit quantities can specify branches of +32766 to -32768 bytes. The value of the program counter when the displacement is added is taken to be the first word after the BRA opcode. This is the actual opcode address plus two. Normally an assembler will assume a 16-bit quantity as the displacement, but if an opcode suffix of .S is appended th the BRA, a short 8-bit displacement will be used instead. Syntax: BRA label (16-bit displacement) or BRA.S label (8-bit displacement). Flags affected: None.
Bcc - Branch Conditionally
Other variants of the BRA instruction allow a branch to be made only if a certain condition is met in the condition code register. These Bcc instructions can be divided into three different categories. Whether or not this instruction is actually executed depends on the required condition, which is verified by means of the flags. A minus sign before a flag indicates that it must be cleared to satisfy the condition. Logical operations are indicated with "*" for AND and "/" for OR. Branches depending on flag status:
BCC - Branch if carry clear -C
BCS - Branch if carry set C
BNE - Branch if zero clear -Z
BEQ - Branch if zero set Z
BVC - Branch if overflow clear -V
BVS - Branch if overflow set V
BPL - Branch if negative clear -N
BMI - Branch if negative set N Branches after unsigned comparison:
BHI - Branch if higher than -C * -Z
BHS - Branch if higher than or same as
BLO - Branch if lower than
BLS - Branch if lower than or same as C / Z
BEQ - Branch if equal to Z
BNE - Branch if not equal to -Z Branches after signed comparison:
BGT - Branch if greater than N * V * -Z / -N * -V * -Z
BGE - Branch if greater than or equal to N * V / -N * -V
BLT - Branch if less than N * -V / -N * V
BLE - Branch if less than or equal to Z / N * -V / -N * V
BEQ - Branch if equal to Z
BNE - Branch if not equal to -Z Syntax: Bcc label (16-bit displacement) or Bcc.S label (8-bit displacement). Flags affected: None.
BSR - Branch to Subroutine
This instruction causes control to be passed unconditionally to the specified program counter displacement as in the BRA opcode. However, before the branch is made, the address of the opcode following the BSR is saved on the stack so return can later be made to that address to continue processing at that point. This is achived as follows: 1. The 24-bit address following the opcode is pushed on the stack as two words. 2. The program counter is loaded with its new value and processing continues at the new address. Syntax: BSR label (16-bit displacement) or BSR.S label (8-bit displacement). Flags affected: None.
BCHG, BCLR, BSET, BTST - Bit Test and Change, Clear, Set
These instructions allow the manipulation and testing of single bits. The bits are numbered from the right to the left starting with bit no zero. Thus a byte contains bits 0 to 7; a word bits 0 to 15; and a long word bits 0 to 31. The number of the bit to be tested is specified in a data register or as an immediate value. The value of the bit is reflected in the Zero flag of the condition code register. This means that the if the bit tested was zero, the Zero flag will be set (Z=1). Therefore the Zero flag is always the opposite of the bit being tested. Once the test is made and the Zero flag is set up, the tested bit is manipulated as follows:
BCHG - The bit is reversed.
BCLR - The bit is cleared to zero.
BSET - The bit is set to a one.
BTST - The bit is unchanged. Syntax: Bxxx Dn, address or Bxxx #imm, address. Flags affected: Zero flag only.
CHK - Check Against Bounds
This instruction checks its first operand against a data register's word contents. If the data register contains less than zero or greater than its first operand, a trap to the address specified by vector 6 occurs. Thus, CHK can be used to ensure that an element of an array is neither below nor above its boundaries. Syntax: CHK bounds, Dn where bounds is anything except an address register. Flags affected: All flags are undefined after this operation.
CLR - Clear Destination to Zero
This instruction allows a byte, a word or a long word to be cleared to a zero according to the operand suffix .B, .W, or .L. The destination can be either a data register or memory. Address registers cannot be cleared with the CLR instruction (Use MOVE.L #0, An). Syntax: CLR Dn or CLR address. Flags affected: Negative, Overflow, and Carry are all set to zero, the Zero flag is set to a one, and the Extend flag is unaffected.
CMP - Compare
This instruction compares two operands and sets flags in the condition code register according to the result. Except for the Extend flag, the flags are set as if the source operand were subtracted from the destination. However, the result of this subtraction is not actually retained so the destination remains unchanged. The information about the comparison that is stored in the condition flags can then be acted upon by a Bcc-instruction. CMP may be used with byte, word, or long word source operands. Note that although any addressing mode can be used to specify the source operand, an address register can only be used if a word or long word comparison is performed. Syntax: CMP address, Dn.
CMPA - Compare Address
This variation of the CMP instruction is used to compare a source operand with an address register as destination operand. Only word or long word compares are allowed with CMPA. If a word is used as source, if is sign-extended to 32 bits before the comparison is made. Syntax: CMPA address, An. Flags affected: Same as CMP instruction.
CMPI - Compare Immediate
This variation of the CMP instruction is used to compare a source operand consisting of an immediate value with either a data register or memory. The comparison length can be byte, word, or long word as specified by the .B, .W, or .L opcode suffix. Syntax: CMPI #imm, Dn or CMPI #imm, memory. CMPM - Compare Memory
This variation of the CMP opcode is used to compare sequential memory locations. These locations can be of type byte, word, or long word as specified by the .B, .W, or .L opcode suffix. To perform the sequencing automatically through memory, both source and destination operands must be specified using address register indirect with postincrement. Thus, after the compare is made, the address registers of both source and destination operands will be incremented by the length of data compared. Syntax: CMPM (An)+, (An)+. Flags affected: Same as the CMP opcode.
DBRA - Decrement and Branch
This instruction is used to control the program counter register in much the same way as BRA instruction is except that this allows greater power and versatility. By using DBRA, a specified data register is decremented and the branch made only if that register goes past zero. Thus, the count from a positive number will count down until zero and branch one more time. This allows loops where an index of zero is the last element. Note that as a result of this, the value left in the register will be -1 when an exit is made at the end of the loop. As an example, if eight locations were to be accessed, the data register specified in the DBRA instruction would be loaded with seven. The countdown, including the final zero, would go through eight cycles. The program counter register is modified as in the BRA instruction whereby a sign-extended 16-bit displacement is added to the program counter. No short 8 bit form is available. only bits 0 to 15 (that is, one word) of the data register is used. The destination of the branch is usually supplied as a label from which the assembler automatically calculates the displacement needed to that label. Syntax: DBRA Dn, label.
DBcc - Decrement and Branch Conditionally
This is a whole series of instruction that resemble the conditional versions of the BRA opcode. Conditional decrement and branch instruction work in a similar manner to the DBRA instruction except that one step is added to the execution process. Before the decrement is performed as in DBRA, the condition specified in the mnemonic is tested (in the opposite order to that suggested by the opcode name). If the condition is true, control drops through to the next instruction - the branch is not made. This is the opposite to the normal branch instruction where the conditional branch is made if the condition is true. Thus this mnemonic might more accurately be read as "decrement and branch if the condition is not fulfilled". Powerful loops can be constructed using the decrement and branch conditional instruction; an exit can be made from the loop either if the data register passes zero or if a pretested condition is met. The following list displays the conditions available for testing before the decrement and possible branch is made. This list is similar to that for the Bcc opcode with the addition of the F (false) and T (true) conditions, which specify an always false or always true precondition. Therefore a DBF is always false, so it will never drop through to the following opcode. Thus, the branch after the decrement will always be performed. Conversely, a DBT is always true, so it will always drop through and never perform the decrement. (This would only be likely to be of use during program development.)
DBEQ - Decrement, branch equal.
DBF - Decrement, branch false. (Same as DBRA.)
DBGE - Decrement, branch greater than or equal.
DBGT - Decrement, branch graeter than.
DBHI - Decrement, branch higher.
DBLE - Decrement, branch less than or equal.
DBLS - Decrement, branch lower than or same.
DBLT - Decrement, branch less than.
DBMI - Decrement, branch minus.
DBNE - Decrement, branch not equal.
DBPL - Decrement, branch plus.
DBRA - Decrement, branch unconditionally.
DBT - Decrement, branch true. (Branch never taken.) Syntax: DBcc Dn, label.
DIVS, DIVU - Divide Signed, Unsigned
These instructions allow a 16-bit divisor (n"mnare) to be used as a source and a 32-bit destination to be specified as dividend (t"ljare) in a divide operation. DIVS assumes both mubers are signed, whereas DIVU assumes both to be unsigned. The destination must be a data register. The source can be a memory location or another data register. The result is stored in the low word of the destination data register and the remainder in the high word of the same register. If the result will not fit in the 16 bits of the low half, the Overflow flag is set in the condition code register. It is possible that the overflow condition can occur during the internal processing of the divide, in which case the Negative and Zero flags will be undefined as will be the result. Either a conditional branch on overflow or a TRAPV can be placed after the divide opcode to act upon the error. Another problem occurs if a divisor of zero is specified. In this case a division-by-zero exception processing sequence is automatically initiated which causes a trap through vector 5. Syntax: DIVx Dn, Dn or DIVx address, Dn. Flags affected: The Carry flag is always set to zero. The Zero, Overflow, and Negative flags are set as per the result. The Extend flag is unaffected.
EOR - Logical Exclusive OR
This instruction performs a logical exclusive OR of the source operand with the same number of bits in the destination operand where the result is left. The number if bits can be 8, 16, or 32 as specified by the .B, .W, or .L opcode suffix. Syntax: EOR Dn, Dn or EOR Dn, address or EOR address, Dn. Flags affected: The Overflow and Carry flags are reset. The Negative and Zero flags are set as per the result, and the Extend flag is unaffected.
EORI - Logical Exclusive OR Immediate
This instruction performs a logical exclusive OR on a length of byte, word or long word between an immediate value and a destination. The destination can be a data register, memory or one of two special cases: the condition code register or the status register. If the destination is the the condition code register, only a byte-length immediate value is allowed. If the destination is the status register, only a word-length immediate value is allowed, and the processor must be in supervisor mode or else a priviledge voilation will occur causing a trap through vector 8. Syntax: EORI #imm, Dn or EORI #imm, memory or EORI.B #imm 8-bit value, CCR or EORI.W #imm 16-bit value, SR (Privileged). Flags affected: Same as the EOR instruction.
EXG - Exchange registers
This instruction allows the sign bit (the most significant bit) to be extended up to the next higher size. Thus if an opcode modifier of .W is used, the bit in position 7 of the lower-order byte will be extended into the rest of the word (in bits 8 to 15). If an opcode modifier of .L is used, the bit in position 15 of the low-order word will be extended into the rest of the long word (bits 16 to 31). If a byte value has to sign-extended to a long word, both an EXT.W and an EXT.L have to be performed on the data register. Syntax: EXT Dn. Flags affected: The Negative and Zero flags are set as per the result. The Overflow and Carry are reset to zero, and the Extend flag is unaffected.


68K ASM Instructions Part2

JMP - Jump
This instruction allows execution of the program to be transferred anywhere within the entire addressing space of the 68000. The jump address can be specified using any memory mode except register indirect with postincrement or predecrement. It should be borne in mind that an absolute address specified in a jump instruction will load the program counter immediately with that value. Because absolute addresses are not position- independent. If the program is moved in memory it has to be reassembled if the label is contained within the program. The JMP instruction with an absolute address is more properly used for jumps to static locations such as ROM routines. To keep the jump position-independent, a program-counter-relative address should be specified. Syntax: JMP address where address is any addressing mode except (An)+ and -(An). Flags affected: None.
JSR - Jump to Subroutine
This instruction allows control to be redirected in a similar manner to the JMP instruction; however, before the jump is made, the address of the following opcode is pushed onto the stack. (See BSR for a description of the stack save process.) Thus a subroutine can perform a task, and when it finishes, it can execute a Return instruction to return to the address saved on the stack. As far as the destination address of the JSR instruction is concerned, the same caveats apply as for the JMP instruction. Absolute addresses, even as labels inside your program, should be avoided where possible to avoid a program which is not position-independent. Unless using such things as ROM routines or memory-mapped hardware locations, which have absolute addresses, use program counter relative or address register indirect addressing. Syntax: JSR address where address is any addressing mode except (An)+ and -(An). Flags affected: None.
LEA - Load Effective Address
This instruction provides a simple way of loading any address register with the address resulting from nearly any addressing mode. Only two such modes are excluded from the list of possibilities. Due to the fact that address register indirect with postincrement or predecrement represent a dynamically increasing or decreasing addresses, these two modes cannot be used with LEA. But any other address, no matter how complicated, (including address register indirect with displacement and index) can be loaded into the specified address register. This saves performing the address arithmetic within the program. The processor will automatically take the same value as the calculated address - or in other words "the effective address". Only address registers can be used with this instruction, and the destination address register is loaded with a 32-bit long value even though the address will only be 24 bits long. Syntax: LEA address, An where address is any addressing mode except postincrement and predecrement. Flags affected: None.
LINK - Link Subroutine
This instruction is a specialized data area allocation opcode for use by subroutines that require a temporary work area that will be relinguished after use. Normally, when a subroutine has been entered from a JSR or BSR instruction, the return address (that is, the address of the instruction after the JSR or BSR) has automatically been saved on the stack by the processor before transferring control to the subroutine. This is part of the regular linkage for a subroutine call, which is automatically performed by any computer processor. The LINK instruction adds another automatic-linkage option after control has been handed to the subroutine. Assume the subroutine nedds ten bytes of temporary storage in order to perform its function. The ideal place for this would be on the stack, which is the usual place for dynamic registers saves during a program's operation. As the stack pointer saves numbers in a downward direction in memory, simply subtracting ten from the stack pointer register A7 would reserve ten bytes of the stack space with A7 pointing at it. However, A7 may not point to the ten bytes for long, as other items may subsequently be pushed onto the stack changing A7 to point lower in memory. So ideally, another address register should be loaded with the contents of A7 before it was decremented by ten so we have a firm pointer to the stack before it is changed. This is exactly what the LINK instruction does. An address register is elected to save the current pointer to the stack in A7; this assigned will become the pointer to the temporary reserved stack space. The stack pointer A7 is then decremented by however many bytes needed, but before being decremented, the assigned register itself is saved on the stack. This way, the called subroutine can perform a LINK to reserve space, knowing that it can call yet another subroutine, which can also perform a LINK with no registers being corrupted. The diagram shows what happens.
LINK A0,#-10
Before: After: Low memory | | |----------------| Low memory A7 > | | | | | 10 bytes | |----------------| | | A7 > | Return address | |----------------| |----------------| A0 > | Previous A0 | | | |----------------| High memory | Return Address | |----------------| | | High memory Note that because ten bytes are required on stack going downwards in memory (as per normal stack practice), a negative displacement is specified in the LINK instruction. As the displacement is a signed 16-bit immediate value, a stack displacement of plus or minus 32K can be specified. The address register assigned to point to the top of the reserved space, or stack frame, is generally known as a frame pointer when used in this way. Note that as this register will be used with predecrement instructions, it initially points to one word above the frame. Syntax: LINK An, #imm where #imm is plus or minus 32K. Flags affected: None.
LSL - Logical Shift Left
This instruction shifts the destination operand left by a specified number of bits. If you are shifting a data register, the number of bits to be shifted can be specified as an immediate value or as a value in another data register. The immediate value can be 1 to 8, whereas the data register value can be 1 to 64 (where zero acts as the 64 count). Data registers may be shifted as 8, 16 or 32 bit quantities. Only 16-bit word values can be shifted in memory and then only by one bit. Each bit shifted out of the left-hand side of an operand is placed in the Carry and Extend bits in the condition code register. As shown below, the bit shifted in at the right hand side is always a zero. C < < | <<< LSL <<< | < 0 X < Syntax: LSL Dn, Dn or LSL #imm 3-bit value, Dn or LSL memory (1 bit shift only). Flags affected: The Carry and Extend bits are set as per the most significant operand bit before the shift. The Overflow flag is reset to zero. The Negative and Zero flags are set as per result.
LSR Logical Shift Right
This instruction shifts the destination operand right by a specified number of bits. If you are shifting a data register, the number of bits to be shifted can be specified as an immediate value or as a value in another data register. The immediate value can specify a shift of 1 to 8, while the data register value can specify a shift of 1 to 64 (where zero acts as the 64 count). Data registers may be shifted as 8, 16, or 32 bit quantities. Only 16-bit word values can be shifted in memory and then only by one bit. Each bit shifted out of the right hand side of an operand is placed in the Carry and Extend bits of the condition code register. As shown below, the bit shifted in at the left hand side is always a zero. > C 0 MSB > | >>> ASR >>> | > > X Syntax: LSR Dn, Dn or LSR #imm 3-bit value, Dn or LSR memory (1 bit shift only). Flags affected: The Carry and Extend bits are set as per the least significant operand bit before the shift. The Overflow flag is reset to zero. The Negative and Zero flags are set as per result.
MOVE - Move Data
This is the 68000's general purpose data-transfer instruction. Using one single opcode, data can be moved from register to register, register to memory, memory to register and memory to memory. The MOVE instruction can also be used to move data to (but not from) the condition code register, thus explicitly setting a particular set of conditions. If you are in privileged (or supervisor) mode, the MOVE instruction can be used to move data to the status register and to or from the user stack pointer. (Privileged mode is not required to move data from the status register.) With so many potential sources and destinations of data moves, the 68000 makes life easier by allowing all addressing modes to be used for the source. For destination, all except program counter relative addressing modes may be used. With data transfers involving memory and / or data registers, the data transfer can be made using 8, 16, or 32 bit quantities and is specified by appending .B, .W, or .L to the MOVE mnemonic. If the high-order bits of a data register are not involved in the data move, those bits remain unaffected by the transfer. Care should be used when mixing length of operands during routines using MOVE; if a byte is moved from a location using MOVE.B and then stored back again using MOVE.W, it will be stored in a memory location one byte higher than it was fetched from. Similary, storing it back with MOVE.L would store it three bytes higher than its original location. If the destination operand of the MOVE is the condition code register, the length of the source operand can only be eight bits. If the status register is involved as either source or destination of the move, only 16-bit transfers allowed. The instruction involving the user stack pointer is the only circumstance under which the 68000 allows optional access to either the user or the system stack pointer. Normally, the stack pointer is accessed as register A7. Whichever of two A7 registers is in effect depends on whether the processor is in supervisor or user mode. However, the supervisor mode may have a need to access the user stack pointer even though it would normally only access the system stack pointer. This is why the privileged mode is required to access a normally unprotected register. Syntax: MOVE source, destination where source can be any addressing mode destination can be any addressing mode except program counter relative and immediate. Either of the above can be CCR, SR and USP (privileged mode only). Flags affected: When the MOVE source, destination format is used, the Negative and Zero flags are set as per the data moved, the Overflow and Carry flags are reset to zero and the Extend flag is unaffected. When the MOVE source, CCR / SR formats are used, the flags are set directly from the data. When the MOVE is done with the USP as an operand, no flags are affected.
MOVEA - Move Address
This specialized version of the MOVE command is used when the destination is an address register. The instruction only allows transfers of 16 or 32 bits in length. Byte transfers are not allowed with an address register as the destination. Also note that unlike the normal MOVE command, no flag bits are affected. Syntax: MOVEA source, An where source is any addressing mode. Flags affected: None. MOVEM - Move Multiple
This variation of the MOVE instruction allows multiple registers to be saved and restored using a single operation. Any of the 16 data or address registers can be moved this way. At the source code level, the registers chosen to be saved or restored are specified to the assembler in a list separated by slashes. Thus, to save D0, D3 and A1, the register list would be specified as D0/D3/A1. If a consecutive number of registers are included in the list, they can be idetified as such by a hyphen. So to save D0, D1, D2, D5 and A1, the register list can be specified as D5/D0-D2/A1. Notice that the order of register between slashes is unimportant; however, when the 68000 saves these registers, it does so in a definite order. It also retrives them in a definite (but opposite) order, so that if the registers are saved on the stack, they can be pulled off in a typical stack-like fashion (that is, last in first out). The order in which the 68000 saves registers is first A7 through A0, and then D7 through D0. Then in reverse order, D0 is restored first, and restoration continues all the way through to A7. As the registers are most often saved in a stack formation, normally an address register is chosen to point to that stack. Then a predecrement addressing mode is used to push the registers down onto the stack. Conversely, when registers are being restored, a postincrement addressing mode is used. As an example, to save two registers at a memory location pointed to by A3, the instruction MOVEM D1/A1, -(A3) might be used. To restore them at another point in program, MOVEM (A3)+, D1/A1 would be correct. Note that registers can only be saved as words or long words. If they are saved as 16-bit words, then when they are restored, the upper half of the register is automtically sign-extended so that bit 15 fills the upper half of the register. Although less memory is used to save registers this way, such a loss of control of the upper 16 bits of every restored register may present problems unless you remain acutely aware of the possible corruption of an upper register half. the MOVEM instruction may be used with addressing modes other than predecrement and postincrement. By specifying other addressing modes as the source or destination of the multiple transfer, registers can be saved and restored in ascending locations in memory. The same register order is used, but they will not be stacked in at last in, first out order. Note that no flags are affected by this operation. Thus a subroutine can affect the condition code register, restore multiple registers with MOVEM, and return with the condition code register still intact. Syntax: MOVEM register list, destination address or MOVEM source address, register list or MOVEM register list, -(An) or MOVEM (An)+, register list. Flags affected: None.
MOVEP - Move Peripheral Data
This variation of the MOVE instruction is used to transfer data between the 68000 and certain peripherals. As input and output on the 68000 is memory-mapped, certain addresses will not actually be memory at all but will instead be external devices. The 68000 has a special design to allow it to use the many hardware interfaces that exist for 8-bit microprocessors, in particular the 6800. What this means to the programmer is that if a peripheral is interfaced to the 68000 and is normally addressed at consecutive address on an 8-bit microprocessor, it will be addressed at every other address on the 68000 due to the design of its peripheral hardware bus. Thus the MOVEP instruction was included to address such peripherals. A long word of data from a data register can be transferred high byte first to every alternate memory (pheripheral) address with a single MOVEP to the first address. This also works the other way round in that every other word will be addressed starting with the source address specified in the MOVEP instruction. Only word or long word transfers are allowed. (A normal MOVE would be used for a single byte.) The only addressing mode allowed to specify the memory location is address register indirect with displacement, and only a data register can be used as the other operand. Syntax: MOVEP Dn, disp(An) or MOVEP disp(An), Dn where disp is a 16-bit displacement.
MOVEQ - Move Quick
This variation on the MOVE instruction allows the quick loading of a data register with an immediate value. The MOVEQ variant works like a MOVE immediate value to the data register except that MOVEQ is much faster and only takes up two bytes in memory. The immediate value that is moved into a data register can only be in the range -128 to +127. This value is sign- extended into the entire 32 bits of the data register, so it is always of type .L despite the small immediate value. As this instruction works so fast, it is quicker to clear a data register with a MOVE #0, Dn than to use CLR Dn. MOVEQ cannot, however, be used with address registers or numbers larger than eight bits. Syntax: MOVEQ #imm 8-bit signed value, Dn. Flags affected: The Negative and Zero flags are set as per the immediate value; the Overflow and Carry flags are reset to zero, and the Extent flag is unaffected.
MULS, MULU - Multiply Signed, Unsigned
This instruction allow a multiplication to take place between a 16-bit source operand and the low order 16 bits of a data register. MULS assumes both numbers are signed, whereas MULU assumes both to be unsigned. The source can be a word from any memory location or the low-order 16 bits of a data register. The destination has to be a data register. The result is stored as a 32-bit signed or unsigned value in the destination register. The Negative flag in the condition code register is affected whether or not the operands are signed, and reflects the most significant bit of the result. Syntax: MULx Dn, Dn or MULx address, Dn where address is any addressing mode. Flags affected: The Negative and Zero flags are set as per the result. The Overflow and Carry flags are reset to zero. The Extend flag is unaffected.
NBCD - Negate Binary Coded Decimal
This specialized arithmetic instruction allows a single byte containing two binary coded decimal digits to be negated. The byte can be contained in the low portion of a data register or in memory. If the number is in memory, any memory addressing mode except program counter relative may be used. If the number is in data register, bits 8 to 31 are not affected. Syntax: NBCD Dn or NBCD address. Flags affected: The Negative and Overflow flag is undefined. The Zero flag is set per the contents of register. Carry and Extend are set as per the result of operation.
NEG, NEGX - Negate Binary, Negate with Extend
This instruction negates its operand. The result is the same as if the operand were subtracted from zero. The operand may be 8, 16, or 32 bits long as specified by the .B, .W, or .L mnemonic suffix. All flags are affected by this operation. A variation of this instruction exists to facilitate the manipulation of multiple-precision quantities where data is handled in segments. This is achived by using the Extend flag as set or reset from a previous arithmetic operation. The NEGX instruction works by subtracting its operand from zero then subtracting the Extend bit. All flags are affected by the result of the NEGX operation, but the Zero flag is only changed if the result becomes non-zero thus reflecting the nonzero state of a segmented number. For this reason, the Zero flag should be reset before performing code involving multiple use of NEGX. Syntax: NEG Dn or NEG address where address is any addressing mode except program counter relative. Flags affected: All.
NOP - No Operation
This instruction is a do-nothing opcode. It is used during program developement to leave room in a section of code. This space can be patched with machine-code instruction as necessary during debugging to test new routines within a previously written machine code level by substituting NOP instruction for the instructions and operands. Syntax: NOP. Flags affected: None.
NOT - Logical NOT
This instruction takes its operand and simply inverts all of its bits. (Each one-bit becomes zero and each zero-bit becomes one.) The operand can either be in a data register or memory and can be 8, 16, or 32 bits in length as per the .B, .W, or .L operand suffix. Syntax: NOT Dn or NOT address where address is any memory addressing mode except program counter relative.
OR - Logical OR
The OR opcode performs a logical OR operation. A number of bits in the source operand are ORed with the same number of bits in the destination operand where the result is left. The number of bits can be 8, 16, or 32 as the .B, .W, or .L opcode suffix. One or both operands must be a data register. Syntax: OR Dn, Dn or OR Dn, address or OR address, Dn where address is any addressing mode with the proviso that program counter relative may not be used as destination.
ORI - Logical OR Immediate
This instruction logically ORs a byte, word, or long word immediate value with the destination. The destination address can be a data register, memory, or one of two special cases: the condition code register and the status register. If the destination is the condition code register, only a byte-length immediate value is allowed. If the destination is the status register, only a word-length immediate value is allowed, and the processor must be in supervisor mode or else a privilege voilation will occur. Syntax: ORI #imm, Dn or ORI #imm, address or ORI.B #imm 8-bit value, CCR or ORI.W #imm 16-bit value, SR (Privileged). Flags affected: The Overflow and Carry bits are reset, the Negative and Zero bits set as per the result, and the Extend bit is unaffected.
PEA - Push Effective Address
This instruction takes the effective address of its operands and pushes it onto the stack as pointed to by the stack pointer A7. The operand can be nearly any addressing mode and is represented as a 32-bit long word. Only two addressing modes are excluded from the list of possibilities. Due to the fact that address register indirect with postincrement or predecrement represent a dynamically increasing or decreasing address, these two modes cannot be used with PEA. But any other address, no matter how complicated, (including address register indirect with displacement and index) can be pushed onto the stack. This saves performing the address arithmetic within the program. The processor will automatically push the same value as the calculated address - or in other words "the effective address". The destination address on the stack is loaded with a 32-bit long value even though the address will only be 24 bits long. No flags are affected by the result of the address calculation. Syntax: PEA address where address is any memory addressing mode except postincrement and predecrement. Flags affected: None.
RESET - Reset External Devices
This instruction sends out a pulse from the RESET pin of the 68000. It is normally used when a system is first powered up to reset all devices to a known state. It is only likely to be used after that if a hardware fault-condition developes. Because it is such a powerful opcode, it is restricted to use in supervisor mode only. Syntax: RESET Flags affected: None.
ROL, ROXL - Rotate Left, Rotate Extended Left
These two instructions both rotate the destination operand left by a specified number of bits. If you are rotating a data register, the number of bits can be specified as an immediate value or as a value in another data register. The immediate value can be 1 to 8, whereas the data register value can be 1 to 64 (where zero acts as the 64 count). Data registers may be rotated as 8, 16, or 32 bit quantities. Only 16-bit word values can be rotated im memory and then only by one bit. As shown, each bit rotated out of the left hand side of the operand is placed in the Carry bit of the condition code register, and in case of ROXL, also in the Extend bit. The bit rotated in at the right is the most significant bit for ROL or the Extend bit for ROXL. Thus, one more bit is involved in the ROXL rotate than in the ROL rotate. Note that ROL does not affect the Extend flag in the condition code register. C < | <<< ROL <<< | < C < > > > > > > > > > < | <<< ROXL <<< | < < X < > > > > > > > > > > > > > Syntax: ROL Dn, Dn or ROL #imm, Dn or ROL address. Flags affected: The Negative flag is set as per most significant bit before the rotate. The Zero flag is set as per resultant operand. The Overflow flag is reset to zero. The Extend flag is unaffected by ROL, but contains the previous most significant bit for ROXL.
ROR, ROXL - Rotate Right, Rotate Extended Right
These two instructions both rotate the destination operand right by a specified number of bits. If you are rotating a data register, the number of bits can be specified as an immediate value or as a value in another data register. The immediate value can be 1 to 8, whereas the data register value can be 1 to 64 (where zero acts as the 64 count). Data registers may be rotated as 8, 16, or 32 bit quantities. Only 16-bit word values can be rotated im memory and then only by one bit. As shown, each bit rotated out of the right hand side of the operand is placed in the Carry bit of the condition code register and in case of ROXR, also in the Extend bit. The bit rotated in at the left is the least significant bit for ROR or the Extend bit for ROXR. Thus, one more bit is involved in the ROXR rotate than in the ROR rotate. Note that ROR does not affect the Extend flag in the condition code register. > | >>> ROR >>> | > C > C < < < < < < < < < > | >>> ROXR >>> | > > X > < < < < < < < < < < < < < Syntax: ROR Dn, Dn or ROR #imm, Dn or ROR address. Flags affected: The Negative flag is set as per most significant bit before the rotate. The Zero flag is set as per resultant operand. The Overflow flag is reset to zero. The Extend flag is unaffected by ROR, but contains the previous most significant bit for ROXR.
RTE - Return from Exception, RTR - Return and Restore CCR, RTS - Return from Subroutine
These instructions change program control by loading the program counter with an execution address previously saved on the stack. The most common version is RTS, which simply pulls the saved address from the stack, increments A7 to allow reuse of the stack space, and reloads the program counter. RTE excepts to find a previously saved status register word on the stack, which it pulls and restores prior to reloading the program counter. As RTE accesses the privileged byte of the status register, it can only be executed in supervisor mode or else a privilege voilation trap will occur. RTR expects to find a previously saved condition code register word on the stack, which it pulls and restores prior to reloading the program counter. Syntax: RTS or RTE or RTR. Flags affected: No flags are affected by RTS. All flags are reloaded by RTE and RTR.
SBCD - Subtract Binary Coded Decimal
This instruction a specialized arithmetic instruction that subtracts one bytes from another (only bytes) when each byte containis binary-coded decimal numbers. The subtraction can be performed either on two data registers or between two memory locations. If performed on bytes in memory, only address register indirect with predecrement can be used. This facilitates easy manipulation of multiple-precision BCD numbers. The extend bit is subtracted along with the BCD bytes to allow this multiprecision data manipulation. Also note that the zero flag is only changed if the result becomes nonzero. Therefore, both the Extend and Zero bits in the condition code register should be perset before the operation is performed. The Extend bit would normally be preset to a zero (to prevent extension on the first subtraction) and the Zero bit to a one (to signify a zero result prior to the first subtraction). A MOVE #4, CCR would preset these flags correctly. Syntax: SBCD Dn, Dn or SBCD -(An), -(An) Flags affected: The Zero flag is cleared if the result becomes nonzero. The Carry and Extend flags are set if a decimal borrow is generated. The Negative and Overflow bits are undefined.
Scc - Set from Conditions Codes
This instruction sets a single byte specified in the operand to all zeroes or all ones according to the condition codes. The condition codes which may be used are the same as for the decrement and branch opcode. If the specified condition is true as reflected in the condition code register, the destination byte is set to all ones ($FF). If it is not true, the destination byte is set to zero. The destination can be the low-order byte of a data register or a byte in memory. This instruction is of particular value saving status of a specific condition code. EQ - Equal to NE - Not equal to MI - Minus PL - Plus CS - Carry set CC - Carry clear VS - Overflow set VC - Overflow clear HI - Higher LS - Less than or same HS - Higher or same LO - Lower GT - Greater GE - Greater than or equal to LE - Less than or equal to LT - Less than F - False Always false => MOVE #$0 T - True Always true => MOVE #$FF Syntax: Scc Dn or Scc address where address is any addressing mode except program counter relative. Flags affected: None.
STOP - Stop processor and wait
This is a privileged instruction that first copies its operand (which is an immediate word value) into the status register and then halts the processor. The processor will remain in this state until it receives an interrupt that is not masked by the interrupt mask into the status register. Syntax: STOP #imm 16-bit value (Privileged). Flags affected: All flags are set as per the immediate value.
SUB - Subtract Binary
The SUB instruction subtracts the source operand from the destination operand with the result appearing in the destination. It is possible to subtract bytes, words, or long words with this opcode by appending .B, .W, or .L to the mnemonic. Either the source or destination (or both) must be a data register. The source operand can be any memory location or data register, and the destination operand can also be any memory location or data register. Syntax: SUB Dn, Dn or SUB address, Dn or SUB Dn, address Flags affected: The Extend, Negative, Zero, Overflow, and Carry flags are all affected as per the result of the subtraction.
SUBA - Subtract Address
This variant of the SUB instruction only differs in that an address register is specified as the destination. As an address rather than data is being manipulated, the condition code flags are left unaffected. Only sign-extended words or long words can be subtracted.
SUBI - Subtract Immediate
This variant of the SUB instruction is used to subtract a constant value from the destination. The immediate operand can be any 8-, 16-, or 32-bit value as specified by the .B, .W, or .L opcode suffix. The destination cannot be an address register or a program counter relative address. Syntax: SUBI #imm, Dn or SUBI #imm, address where address is any memory addressing mode except program counter relative. Flags affected: The Extend, Negative, Zero, Overflow, and Carry flags are all set as per the result of the subtraction.
SUBQ - Subtract Quick
This variant of the SUB instruction is used to subtract a small integer between one and eight from the destination. The destination can be a memory location, a data register, or an address register. If it is an address register, the condition code flags are unaffected and the operand length cannot be a byte. This operation takes the place of the decrement instruction found on other processors. Syntax: SUBQ #imm, Rn or SUBQ #imm, address. Flags affected: The Extend, Negative, Zero, Overflow, and Carry flags are all set as per the result of the subtraction unless the destination is an address register.
SUBX - Subtract Extended
This variant of the SUB instruction subtracts two numbers and the Extend bit of the condition code register. This allows multiple-precision subtractions to be performed. For this reason, the Zero flag is only affected when a non-zero result is obtained. This means that if multiple numbers are subtracted using SUBX, the Zero flag will stay reset if any of those numbers were non-zero. Syntax: SUBX Dn, Dn or SUBX -(An), -(An).
SWAP - Swap Data register halves
This instruction takes the lower 16 bits of the specified data register and swaps it with the upper 16 bits. It can only be used with data registers and only on the fixed word length in each half. Syntax: SWAP Dn. Flags affected: The Negative and Zero flags are set to reflect the 32-bit result. The Overflow and Carry flags are reset to zero. The Extend flag is unaffected.
TAS - Test and Set
This is a highly specialized instruction that is used to test a byte in memory or in a data register. When the condition codes are set as per the byte's contents, bit 7 (the most significant bit) of the byte is set to a one. This operation is achived in an uninterruptible read-modify-write cycle. It is the only instruction on the 68000 that uses this method. Its importance lies in the fact that no interrupt can cause a read of the accessed byte before the operation is finished. If the operation were done in two steps, an interrupt could occur before the byte was changed, which would allow the interrupting routine to scan the byte and draw an erroneous conclution as to its status. Syntax: TAS Dn or TAS address where address is any addressing mode except program counter relative. Flags affected: The Negative and Zero flags are set as per the byte before modification. The Overflow and Carry flags are reset to zero. The Extend flag is unaffected.
TRAP - Software Trap
This instruction causes a trap to occur in the same manner as if it had been caused by a hardware-detected condition. The processor will jump to one of the 16 special addresses set up in the first 1024 bytes of memory. The actual address that will be jumped to is determined by the operand supplied with the opcode. This will be a number from 0 to 15. The software trap vectors are 32-bit addresses stored in memory starting at location #128. Before the specified vector is taken, the status register and program counter are pushed onto the stack to facilitate a return via an RTE instruction. Syntax: TRAP #imm where #imm is an immediate value from 0 to 15. Flags affected: None.
TRAPV - Trap if Overflow
This instruction causes a trap to occur to the address in location #28 in low memory if the Overflow flag is set in the condition code register. Before the overflow vector is taken, the status register and program counter are pushed onto the stack to facilitate a return via an RTE instruction. Syntax: TRAPV Flags affected: None.
TST - Test Operand
This instruction causes the processor to scan the operand and set the condition code flags according to the contents. The operand can be 8, 16, or 32 bytes as specified in the .B, .W, or .L opcode modifier. No registers other than the condition code register are changed. The operand can be either a data register or a memory location. Syntax: TST Dn or TST address where address is any addressing mode except program counter relative.
UNLK - Unlink
This instruction is the reverse of the LINK opcode. It takes the address in the specified address register and loads the stack pointer (A7) with it. This removes any space allocated on the stack for temporary storage. The stack pointer then points at the previous contents of the address register (the frame pointer). This contents would have been placed there by a previous LINK instruction. The frame pointer is automatically reloaded by pulling the value from the stack. Both the frame pointer and the stack pointer are therefore returned to their values before the last LINK. This entire operation is performed automatically by a single UNLK instruction. Syntax: UNLK An Flags affected: None.


common ASM to C

ASM statement | C translation | description
ANDI.W #31!$1f,D0 | D0 = D0 & 31 | Logical AND
EORI.L #424986326!$7fffffff,D4 | D4 = D4 ^ 424986326 | Exclusiv OR
LSL.L #5,D0 | D0 = D0 << 5 | Logical Shift Left
LSR.L #5,D0 | D0 = D0 >> 5 | Logical Shift Left
DIVS.W #23,!$17,D6 SWAP D6 | D6 = D6 % 23 | Modulus


C-Language Overview

This part is for C-newbies (like me) and should help you create a Keygen for PSNG


C-Language Variable Types

C's numeric data types.

Variable Type | Keyword | Bytes Required | Range
Character | char | 1 | -128 to 127
Integer | int | 2 | -32768 to 32767
Short integer | short | 2 | -32768 to 32767
Long integer | long | 4 | -2,147,483,648 to 2,147,438,647
Unsigned character | unsigned char | 1 | 0 to 255
Unsigned integer | unsigned int | 2 | 0 to 65535
Unsigned short integer | unsigned short | 2 | 0 to 65535
Unsigned long integer | unsigned long | 4 | 0 to 4,294,967,295
Single-precision | float | 4 | 1.2E-38 to
floating-point |  |  | 3.4E381
Double-precision | double | 8 | 2.2E-308 to
floating-point |  |  | 1.8E3082
1Approximate range; precision = 7 digits. |  |  |
2Approximate range; precision = 19 digits. |  |  |


C-Language Strings and Pointers

Strings and Pointers: A Review

This is a good time to review some material from Day 10 regarding string allocation and initialization. One way to allocate and initialize a string is to declare an array of type char as follows:

char message[] = "This is the message.";

You could accomplish the same thing by declaring a pointer to type char:

char *message = "This is the message.";

Both declarations are equivalent. In each case, the compiler allocates enough space to hold the string along with its terminating null character, and the expression message is a pointer to the start of the string. But what about the following two declarations?

char message1[20];

char *message2;

The first line declares an array of type char that is 20 characters long, with message1 being a pointer to the first array position. Although the array space is allocated, it isn't initialized, and the array contents are undetermined. The second line declares message2, a pointer to type char. No storage space for a string is allocated by this statement--only space to hold the pointer. If you want to create a string and then have message2 point to it, you must allocate space for the string first. On Day 10, you learned how to use the malloc() memory allocation function for this purpose. Remember that any string must have space allocated for it, whether at compilation in a declaration or at runtime with malloc() or a related memory allocation function.

Array of Pointers to Type char

Now that you're done with the review, how do you declare an array of pointers? The following statement declares an array of 10 pointers to type char:

char *message[10];

Each element of the array message[] is an individual pointer to type char. As you might have guessed, you can combine the declaration with initialization and allocation of storage space for the strings:

char *message[10] = { "one", "two", "three" };

This declaration does the following:

  • It allocates a 10-element array named message; each element of message is a pointer to type char.

  • It allocates space somewhere in memory (exactly where doesn't concern you) and stores the three initialization strings, each with a terminating null character.

  • It initializes message[0] to point to the first character of the string "one", message[1] to point to the first character of the string "two", and message[2] to point to the first character of the string "three".


C-Language Arrays of Character

Arrays of Characters

To hold a string of six characters, for example, you need to declare an array of type char with seven elements. Arrays of type char are declared like arrays of other data types. For example, the statement char string[10]; declares a 10-element array of type char. This array could be used to hold a string of nine or fewer characters.

"But wait," you might be saying. "It's a 10-element array, so why can it hold only nine characters? In C, a string is defined as a sequence of characters ending with the null character, a special character represented by \0. Although it's represented by two characters (backslash and zero), the null character is interpreted as a single character and has the ASCII value of 0. It's one of C's escape sequences, covered on Day 7.

When a C program stores the string Alabama, for example, it stores the seven characters A, l, a, b, a, m, and a, followed by the null character \0, for a total of eight characters. Thus, a character array can hold a string of characters numbering one less than the total number of elements in the array.

A type char variable is one byte in size, so the number of bytes in an array of type char variables is the same as the number of elements in the array.

Initializing Character Arrays

Like other C data types, character arrays can be initialized when they are declared. Character arrays can be assigned values element by element, as shown here:

char string[10] = { `A', `l', `a', `b', `a', `m', `a', `\0' };

It's more convenient, however, to use a literal string, which is a sequence of characters enclosed in double quotes:

char string[10] = "Alabama";

When you use a literal string in your program, the compiler automatically adds the terminating null character at the end of the string. If you don't specify the number of subscripts when you declare an array, the compiler calculates the size of the array for you. Thus, the following line creates and initializes an eight-element array:

char string[] = "Alabama";

Remember that strings require a terminating null character. The C functions that manipulate strings (covered on Day 17, "Manipulating Strings") determine string length by looking for the null character. These functions have no other way of recognizing the end of the string. If the null character is missing, your program thinks that the string extends until the next null character in memory. Pesky program bugs can result from this sort of error


C-Language mathematical Operators

C's unary mathematical operators.

Operator | Symbol | Action | Examples
Increment | ++ | Increments the operand by one | ++x, x++
Decrement | -- | Decrements the operand by one | --x, x--

C's binary mathematical operators.

Operator | Symbol | Action | Example
Addition | + | Adds two operands | x + y
Subtraction | - | Subtracts the second operand from the first operand | x - y
Multiplication | * | Multiplies two operands | x * y
Division | / | Divides the first operand by the second operand | x / y
Modulus | % | Gives the remainder when the first operand is divided by the second operand | x % y


C-Language Logical Operators

C's logical operators.

Operator | Symbol | Example
AND | && | exp1 && exp2
OR | || | exp1 || exp2
NOT | ! | !exp1

The way these logical operators work is explained in Table 4.8.

C's logical operators in use.

Expression | What It Evaluates To
(exp1 && exp2) | True (1) only if both exp1 and exp2 are true; false (0) otherwise
(exp1 || exp2) | True (1) if either exp1 or exp2 is true; false (0) only if both are false
(!exp1) | False (0) if exp1 is true; true (1) if exp1 is false

Code examples of C's logical operators.

Expression | What It Evaluates To
(5 == 5) && (6 != 2) | True (1), because both operands are true
(5 > 1) || (6 < 1) | True (1), because one operand is true
(2 == 1) && (5 == 5) | False (0), because one operand is false
!(5 == 4) | True (1), because the operand is false


C-Language relational Operators

C's relational operators.

Operator | Symbol | Question Asked | Example
Equal | == | Is operand 1 equal to operand 2? | x == y
Greater than | > | Is operand 1 greater than operand 2? | x > y
Less than | < | Is operand 1 less than operand 2? | x < y
Greater than or equal to | >= | Is operand 1 greater than or equal to operand 2? | x >= y
Less than or equal to | <= | Is operand 1 less than or equal to operand 2? | x <= y
Not equal | != | Is operand 1 not equal to operand 2? | x != y

Relational operators in use.

Expression | How It Reads | What It Evaluates To
5 == 1 | Is 5 equal to 1? | 0 (false)
5 > 1 | Is 5 greater than 1? | 1 (true)
5 != 1 | Is 5 not equal to 1? | 1 (true)
(5 + 10) == (3 * 5) | Is (5 + 10) equal to (3 * 5)? | 1 (true)

When working with relational operators, true is equal to 1, and false is equal to 0.


C-Language Operator precedence

C operator precedence.

Level | Operators
1 | () [] -> .
2 | ! ~ ++ -- * (indirection) & (address-of) (type)
 | sizeof + (unary) - (unary)
3 | * (multiplication) / %
4 | + -
5 | << >>
6 | < <= > >=
7 | == !=
8 | & (bitwise AND)
9 | ^
10 | |
11 | &&
12 | ||
13 | ?:
14 | = += -= *= /= %= &= ^= |= <<= >>=
15 | ,
() is the function operator; [] is the array operator. |


C-Language Compound assignement Operators

Examples of compound assignment operators.

When You Write This... | It Is Equivalent To This
x *= y | x = x * y
y -= z + 1 | y = y - z + 1
a /= b | a = a / b
x += y / 8 | x = x + y / 8
y %= 3 | y = y % 3


C-Language Statements

The if Statement

Form 1

if( expression )

statement1;

next_statement;

This is the if statement in its simplest form. If expression is true, statement1 is executed. If expression is not true, statement1 is ignored.

Form 2

if( expression )

statement1;

else

statement2;

next_statement;

This is the most common form of the if statement. If expression is true, statement1 is executed; otherwise, statement2 is executed.

Form 3

if( expression1 )

statement1;

else if( expression2 )

statement2;

else

statement3;

next_statement;

This is a nested if. If the first expression, expression1, is true, statement1 is executed before the program continues with the next_statement. If the first expression is not true, the second expression, expression2, is checked. If the first expression is not true, and the second is true, statement2 is executed. If both expressions are false, statement3 is executed. Only one of the three statements is executed.

The for Statement

for (initial; condition; increment)

statement(s)

initial is any valid C expression. It is usually an assignment statement that sets a variable to a particular value.

condition is any valid C expression. It is usually a relational expression. When condition evaluates to false (zero), the for statement terminates, and execution passes to the first statement following statement(s); otherwise, the C statement(s) in statement(s) are executed.

increment is any valid C expression. It is usually an expression that increments a variable initialized by the initial expression.

statement(s) are the C statements that are executed as long as the condition remains true.

A for statement is a looping statement. It can have an initialization, test condition, and increment as parts of its command. The for statement executes the initial expression first. It then checks the condition. If the condition is true, the statements execute. Once the statements are completed, the increment expression is evaluated. The for statement then rechecks the condition and continues to loop until the condition is false.

The while Statement

The while statement, also called the while loop, executes a block of statements as long as a specified condition is true. The while statement has the following form:

while (condition)

statement

condition is any C expression, and statement is a single or compound C statement. When program execution reaches a while statement, the following events occur:

1. The expression condition is evaluated.

2. If condition evaluates to false (that is, zero), the while statement terminates, and execution passes to the first statement following statement.

3. If condition evaluates to true (that is, nonzero), the C statement(s) in statement are executed.

4. Execution returns to step 1.

The do...while Loop

C's third loop construct is the do...while loop, which executes a block of statements as long as a specified condition is true. The do...while loop tests the condition at the end of the loop rather than at the beginning, as is done by the for loop and the while loop.

The structure of the do...while loop is as follows:

do

statement

while (condition);

condition is any C expression, and statement is a single or compound C statement. When program execution reaches a do...while statement, the following events occur:

1. The statements in statement are executed.

2. condition is evaluated. If it's true, execution returns to step 1. If it's false, the loop terminates.


C-Language Advanced Program Control

The break Statement

The break statement can be placed only in the body of a for loop, while loop, or do...while loop. (It's valid in a switch statement too, but that topic isn't covered until later in this chapter.) When a break statement is encountered, execution exits the loop. The following is an example:

for ( count = 0; count < 10; count++ )

{

if ( count == 5 )

break;

}

Left to itself, the for loop would execute 10 times. On the sixth iteration, however, count is equal to 5, and the break statement executes, causing the for loop to terminate. Execution then passes to the statement immediately following the for loop's closing brace. When a break statement is encountered inside a nested loop, it causes the program to exit the innermost loop only.

The continue Statement

continue;

continue is used inside a loop. It causes the control of a program to skip the rest of the current iteration of a loop and start the next iteration.

Example

int x;

printf("Printing only the even numbers from 1 to 10\n");

for( x = 1; x <= 10; x++ )

{

if( x % 2 != 0 ) /* See if the number is NOT even */

continue; /* Get next instance x */

printf( "\n%d", x );

}

The goto Statement

goto location;

location is a label statement that identifies the program location where execution is to branch. A label statement consists of an identifier followed by a colon and a C statement:

location: a C statement;

If you want the label by itself on a line, you can follow it with the null statement (a semicolon by itself):

location: ;

The switch Statement

switch (expression)

{

case template_1: statement(s);

case template_2: statement(s);

...

case template_n: statement(s);

default: statement(s);

}

The switch statement allows for multiple branches from a single expression. It's more efficient and easier to follow than a multileveled if statement. A switch statement evaluates an expression and then branches to the case statement that contains the template matching the expression's result. If no template matches the expression's result, control goes to the default statement. If there is no default statement, control goes to the end of the switch statement.

Program flow continues from the case statement down unless a break statement is encountered. In that case, control goes to the end of the switch statement.

Example 1

switch( letter )

{

case `A':

case `a':

printf( "You entered A" );

break;

case `B':

case `b':

printf( "You entered B");

break;

...

...

default:

printf( "I don't have a case for %c", letter );

}


C-Language printf() conversion_characters

The conversion_char is the only required part of a conversion command (other than the %). Table 14.5 lists the conversion characters and their meanings.

The printf() and fprintf() conversion characters.

Conversion Character | Meaning
d, i | Display a signed integer in decimal notation.
u | Display an unsigned integer in decimal notation.
o | Display an integer in unsigned octal notation.
x, X | Display an integer in unsigned hexadecimal notation. Use x for lowercase output and X for uppercase output.
c | Display a single character (the argument gives the character's ASCII code).
e, E | Display a float or double in scientific notation (for example, 123.45 is displayed as 1.234500e+002). Six digits are displayed to the right of the decimal point unless another precision is specified with the f specifier. Use e or E to control the case of output.
f | Display a float or double in decimal notation (for example, 123.45 is displayed as 123.450000). Six digits are displayed to the right of the decimal point unless another precision is specified.
g, G | Use e, E, or f format. The e or E format is used if the exponent is less than -3 or greater than the precision (which defaults to 6). f format is used otherwise. Trailing zeros are truncated.
n | Nothing is displayed. The argument corresponding to an n conversion command is a pointer to type int. The printf() function assigns to this variable the number of characters output so far.
s | Display a string. The argument is a pointer to char. Characters are displayed until a null character is encountered or the number of characters specified by precision (which defaults to 32767) is displayed. The terminating null character is not output.
% | Display the % character.

You can place the l modifier just before the conversion character. This modifier applies only to the conversion characters o, u, x, X, i, d, and b. When applied, this modifier specifies that the argument is a type long rather than a type int. If the l modifier is applied to the conversion characters e, E, f, g, or G, it specifies that the argument is a type double. If an l is placed before any other conversion character, it is ignored.

The precision specifier consists of a decimal point (.) by itself or followed by a number. A precision specifier applies only to the conversion characters e, E, f, g, G, and s. It specifies the number of digits to display to the right of the decimal point or, when used with s, the number of characters to output. If the decimal point is used alone, it specifies a precision of 0.

The field-width specifier determines the minimum number of characters output.
The field-width specifier can be the following:

  • A decimal integer not starting with 0. The output is padded on the left with spaces to fill the designated field width.

  • A decimal integer starting with 0. The output is padded on the left with zeros to fill the designated field width.

  • The * character. The value of the next argument (which must be an int) is used as the field width. For example, if w is a type int with a value of 10, the statement printf("%*d", w, a); prints the value of a with a field width of 10.

If no field width is specified, or if the specified field width is narrower than the output, the output field is just as wide as needed.

The last optional part of the printf() format string is the flag, which immediately follows the % character. There are four available flags:

- This means that the output is left-justified in its field rather than right-justified, which is the default.

+ This means that signed numbers are always displayed with a leading + or -.

` ` A space means that positive numbers are preceded by a space.

# This applies only to x, X, and o conversion characters. It specifies that nonzero numbers are displayed with a leading 0X or 0x (for x and X) or a leading 0 (for o).

When you use printf(), the format string can be a string literal enclosed in double quotes in the printf() argument list. It can also be a null-terminated string stored in memory, in which case you pass a pointer to the string to printf().

For example, this statement:

char *fmt = "The answer is %f.";

printf(fmt, x);

is equivalent to this statement:

printf("The answer is %f.", x);

the printf() format string can contain escape sequences that provide special control over the output. For example, including the newline sequence (\n) in a format string causes subsequent output to appear starting on the next screen line.


C-Language Reserved Words

Reserved C Keywords.

Keyword | Description
asm | Keyword that denotes inline assembly language code.
auto | The default storage class.
break | Command that exits for, while, switch, and do...while statements unconditionally.
case | Command used within the switch statement.
char | The simplest C data type.
const | Data modifier that prevents a variable from being changed. See volatile.
continue | Command that resets a for, while, or do...while statement to the next iteration.
default | Command used within the switch statement to catch any instances not specified with a case statement.
do | Looping command used in conjunction with the while statement. The loop will always execute at least once.
double | Data type that can hold double-precision floating-point values.
else | Statement signaling alternative statements to be executed when an if statement evaluates to FALSE.
enum | Data type that allows variables to be declared that accept only certain values.
extern | Data modifier indicating that a variable will be declared in another area of the program.
float | Data type used for floating-point numbers.
for | Looping command that contains initialization, incrementation, and conditional sections.
goto | Command that causes a jump to a predefined label.
if | Command used to change program flow based on a TRUE/FALSE decision.
int | Data type used to hold integer values.
long | Data type used to hold larger integer values than int.
register | Storage modifier that specifies that a variable should be stored in a register if possible.
return | Command that causes program flow to exit from the current function and return to the calling function. It can also be used to return a single value.
short | Data type used to hold integers. It isn't commonly used, and it's the same size as an int on most computers.
signed | Modifier used to signify that a variable can have both positive and negative values. See unsigned.
sizeof | Operator that returns the size of the item in bytes.
static | Modifier used to signify that the compiler should retain the variable's value.
struct | Keyword used to combine C variables of any data type into a group.
switch | Command used to change program flow in a multitude of directions. Used in conjunction with the case statement.
typedef | Modifier used to create new names for existing variable and function types.
union | Keyword used to allow multiple variables to share the same memory space.
unsigned | Modifier used to signify that a variable will contain only positive values. See signed.
void | Keyword used to signify either that a function doesn't return anything or that a pointer being used is considered generic or able to point to any data type.
volatile | Modifier that signifies that a variable can be changed. See const.
while | Looping statement that executes a section of code as long as a condition remains TRUE.


ascii / hex / dec Table

Hex | Dec | char | Hex | Dec | char
20 | 32 |  | 21 | 33 | !
22 | 34 | " | 23 | 35 | #
24 | 36 | $ | 25 | 37 | %
26 | 38 | & | 27 | 39 | ‘
28 | 40 | ( | 29 | 41 | )
2A | 42 | * | 2B | 43 | +
2C | 44 | , | 2D | 45 | -
2E | 46 | . | 2F | 47 | /
30 | 48 | 0 | 31 | 49 | 1
32 | 50 | 2 | 33 | 51 | 3
34 | 52 | 4 | 35 | 53 | 5
36 | 54 | 6 | 37 | 55 | 7
38 | 56 | 8 | 39 | 57 | 9
3A | 58 | : | 3B | 59 | ;
3C | 60 | < | 3D | 61 | =
3E | 62 | > | 3F | 63 | ?
40 | 64 | @ | 41 | 65 | A
42 | 66 | B | 43 | 67 | C
44 | 68 | D | 45 | 69 | E
46 | 70 | F | 47 | 71 | G
48 | 72 | H | 49 | 73 | I
4A | 74 | J | 4B | 75 | K
4C | 76 | L | 4D | 77 | M
4E | 78 | N | 4F | 79 | O
50 | 80 | P | 51 | 81 | Q
52 | 82 | R | 53 | 83 | S
54 | 84 | T | 55 | 85 | U
56 | 86 | V | 57 | 87 | W
58 | 88 | X | 59 | 89 | Y
5A | 90 | Z | 5B | 91 | [
5C | 92 | \ | 5E | 93 | ]
5E | 94 | ^ | 5F | 95 | _
60 | 96 | ` | 61 | 97 | a
62 | 98 | b | 63 | 99 | c
64 | 100 | d | 65 | 101 | e
66 | 102 | f | 67 | 103 | g
68 | 104 | h | 69 | 105 | i
6A | 106 | j | 6B | 107 | k
6C | 108 | l | 6D | 109 | m
6E | 110 | n | 6F | 111 | o
70 | 112 | p | 71 | 113 | q
72 | 114 | r | 73 | 115 | s
74 | 116 | t | 75 | 117 | u
76 | 118 | v | 77 | 119 | w
78 | 120 | x | 79 | 121 | y
7A | 122 | z | 7B | 123 | {
7C | 124 | ¦ | 7D | 125 | }
7E | 126 | ~ |  |  |