]> git.sur5r.net Git - cc65/blob - doc/smc.sgml
remote TABs in doc/ and test/
[cc65] / doc / smc.sgml
1 <!doctype linuxdoc system>
2
3 <article>
4 <title>ca65 Macros for Self Modifying Code
5 <author>Christian Kr&uuml;ger
6
7 <abstract>
8 The 'smc.inc' macro package for ca65 eases the use, increases the safeness and
9 self-explanation of 'self-modifying-code' (SMC).
10 </abstract>
11
12 <!-- Table of contents -->
13 <toc>
14
15 <!-- Begin the document -->
16
17 <sect>Overview<p>
18 When reading assembler sources, self modifying code is often hard to identify
19 and applying it needs a lot of discipline.
20
21 Since the cacheless 6502 is a thankful target of such kind of code, the macro
22 package will not only reduce this complexness, but also document the use. The
23 resulting source is more self-explanatory and so easier to maintain.
24
25 While for general purposes SMC is not a desired form for implementations, it
26 can be quite useful for a small range of scenarios. Normally SMC will be
27 introduced when optimizing code in respect to:
28
29 <itemize>
30 <item>speed and/or
31 <item>size.
32 </itemize>
33
34 Please mind that SMC can only be applied for code in RAM, which means that a
35 general purpose library with SMC excludes ROM targets!
36
37 The ca65 SMC macro package consists of two files:
38
39 <itemize>
40 <item><tt>smc.inc</tt>
41 <item><tt>opcodes.inc</tt>
42 </itemize>
43
44 The latter is only needed if you also plan to modify opcodes and not only data
45 within your code.
46
47 <sect>Usage<p>
48 The use of the macros is quite simple:
49
50 Original:
51
52 <tscreen><verb>
53     PHA
54     JSR SUBROUTINE
55     PLA
56 </verb></tscreen>
57
58 By applying SMC, the speed will now be increased by once cycle:
59
60 SMC:
61
62 <tscreen><verb>
63     SMC_StoreValue RestoreAccu
64     JSR SUBROUTINE
65 SMC RestoreAccu, { LDA #SMC_Value }
66 </verb></tscreen>
67
68 The first line stores the value of the accu into the '<tt>RestoreAccu</tt>'
69 labeled SMC target.
70
71 Please note:
72 <enum>
73 <item>  for all SMC store or transfer operations, a second argument can be
74         given. This determines the register for the operation:
75         '<tt>SMC_StoreValue Label, y</tt>' will store the value of the
76         Y-register.
77
78         If the second argument is missing, the accu will be used automatically.
79
80 <item>  The label targets a 'special SMC namespace'. It fits only to
81         destinations which are introduced with the macro '<tt>SMC</tt>'. A
82         normal label '<tt>RestoreAccu</tt>' wouldn't match and could even
83         coexist (even if you should abstain from doing so).
84
85 <item>  The macro '<tt>SMC_StoreValue</tt>' takes care, that the store
86         operation will occur on the value-position of a SMC-instruction. As
87         you will see, other macros influence other instruction part positions.
88         There is no consistency check, if the targeted SMC instruction acually
89         contains a value. Storing a 'value' on an immplied SMC instruction
90         would corrupt the following memory cell!
91 </enum>
92
93 The second line needs no further explanation, this is just a placeholder for
94 some code in the example.
95
96 The third line is the code line which is about to be modified. It has to start
97 with the '<tt>SMC</tt>' macro and must be labeled, so that the modification
98 can be designated. Then the unmodified code is given in curly braces.
99
100 Please note the usage of the value placeholder 'SMC_Value'. Using such a
101 placeholder has two advantages:
102
103 <enum>
104 <item> The code is better documented. It is clearly visible that the given
105        value is about to be changed.
106 <item> When examining an (initial) disassembly (e.g. in a debugger), these
107        placegolders can be better identified: They are fixed and, you may
108        notice that below, quite eye catching defined.
109 </enum>
110
111 <sect1>Argument placeholders<p>
112
113 There are four kinds of placeholders:
114
115 <descrip>
116
117   <label id="Address placeholder">
118   <tag><tt>SMC_AbsAdr</tt></tag>
119
120   Used to indicate an address. The value is '<tt>$FADE</tt>'.
121
122   Example: <tt>STA SMC_AbsAdr</tt>
123
124
125   <label id="Zero-Page-Address placeholder">
126   <tag><tt>SMC_ZpAdr</tt></tag>
127
128   Used to indicate a zero-page-address. The value is '<tt>$00</tt>'.
129
130   Example: <tt>LDA SMC_ZpAdr</tt>
131
132
133   <label id="Opcode placeholder">
134   <tag><tt>SMC_Opcode</tt></tag>
135
136   Used to indicate an instruction. The value is '<tt>NOP</tt>'.
137
138   Example: <tt>SMC_Opcode</tt>
139
140
141   <label id="Immediate value placeholder">
142   <tag><tt>SMC_Value</tt></tag>
143
144   Used to indicate a value. The value is '<tt>$42</tt>'.
145
146   Example: <tt>LDX #SMC_Value</tt>
147 </descrip>
148
149 Attention: Often code is modified after the initial use - where using the
150 placeholders does not makes sense. Please mind also, that in very variable
151 expressions (e.g. opcode and argument is about to be changed), placeholders
152 can lead to unidentifyable code for a debugger/disassembler:
153
154 <tt>SMC Example, { SMC_Opcode SMC_AbsAdr } </tt>
155
156 Since the opcode is '<tt/NOP/', the value '<tt/$DE/' from '<tt/$FADE/' will
157 interpreted as opcode in a disassembler too. This breaks the correct
158 disassembly, because '<tt/$DE/' is interpreted as '<tt/DEC abx/'. Establishing
159 a valid placeholder instruction may be better:
160
161 <tt>SMC Example, { sta SMC_AbsAdr }     ; Note: Opcode will be modified too!</tt>
162
163 <sect1>Accessing opcodes<p>
164
165 Some macros are designed to access the instruction of a code line. To increase
166 readability, please use the opcodes as defined in the '<tt>opcodes.inc</tt>'
167 file.
168
169 <descrip>
170
171   <label id="Transfer opcode">
172   <tag><tt>SMC_TransferOpcode label, opcode (, register)</tt></tag>
173   Loads and store an opcode to given SMC instruction.
174
175   Example:
176
177 <tscreen><verb>
178 SMC SumRegister, { LDA #10 }
179     JSR OUTPUT
180     SMC_TransferOpcode SumRegister, OPC_ADC_imm, x
181 </verb></tscreen>
182
183 The macro above will load the opcode '<tt>ADC #</tt>' into the x - register
184 and stores it at the place of the '<tt>LDA #</tt>'.
185
186  <label id="Load opcode">
187   <tag><tt>SMC_LoadOpcode label (, register)</tt></tag>
188   Loads the opcode of a SMC line to the given register.
189
190   Example:
191 <tscreen><verb>
192 SMC ShiftOrNothing, { LSL }
193     SMC_LoadOpcode ShiftOrNothing, y
194     CPY #OPC_NOP
195     BEQ Exit
196 </verb></tscreen>
197
198  <label id="Store opcode">
199   <tag><tt>SMC_StoreOpcode label (, register)</tt></tag>
200   Stores the value of the given register at the opcode place of a SMC line.
201
202   Example:
203 <tscreen><verb>
204 SetBoldMode:
205     LDA #OPC_INX
206     SMC_StoreOpcode AdaptCharWidth
207     SMC_StoreOpcode AdaptUnderlineWidth
208     RTS
209     ...
210 SMC AdaptCharWidth, { NOP }
211     ...
212 SMC AdaptUnderlineWidth, { NOP }
213 </verb></tscreen>
214
215 </descrip>
216
217 <sect1>Accessing arguments<p>
218
219 These marcos are determined to get, set and change arguments of instructions:
220
221 <descrip>
222
223   <label id="Change branch">
224   <tag><tt>SMC_ChangeBranch label, destination (, register)</tt></tag>
225
226   Used to modify the destination of a branch instruction. If the address offset
227   exceeds the supported range of 8-bit of the 6502, a error will be thrown.
228
229   Example:
230 <tscreen><verb>
231 Disable Handler:
232     SMC_ChangeBranch BranchToHandler, Exit
233     RTS
234     ...
235     LDA warning
236 SMC BranchToHandler, { BNE Handler }
237 Exit:
238     RTS
239 </verb></tscreen>
240
241
242   <label id="Transfer value">
243   <tag><tt>SMC_TransferValue label, value (, register)</tt></tag>
244
245   Changes the value of a SMC line.
246
247   Example:
248 <tscreen><verb>
249 ClearDefault:
250     SMC_TransferValue LoadDefault, 0
251     RTS
252     ...
253 SMC LoadDefault, { LDX #25 }
254 </verb></tscreen>
255
256
257   <label id="Load value">
258   <tag><tt>SMC_LoadValue label (, register)</tt></tag>
259
260   Retreives the value of a SMC line.
261
262   Example:
263 <tscreen><verb>
264 ShowDefault:
265     SMC_LoadValue LoadDefault
266     JSR PrintValue
267     RTS
268     ...
269 SMC LoadDefault, { LDX #25 }
270 </verb></tscreen>
271
272
273   <label id="Store value">
274   <tag><tt>SMC_StoreValue label (, register)</tt></tag>
275
276   Stores the value in the register to given SMC line.
277
278   Example:
279 <tscreen><verb>
280 InitCounters:
281     LDY #0
282     SMC_StoreValue GetI, y
283     SMC_StoreValue GetJ, y
284     SMC_StoreValue GetK, y
285     ...
286 SMC GetI, { LDX #SMC_Value      }
287     ...
288 SMC GetJ, { LDX #SMC_Value      }
289     ...
290 SMC GetK, { LDX #SMC_Value      }
291 </verb></tscreen>
292
293
294   <label id="Transfer low-byte">
295   <tag><tt>SMC_TransferLowByte label, value (, register)</tt></tag>
296
297   Does the same as '<tt>SMC_TransferValue</tt>' but should be used for
298   low-bytes of addresses for better readability.
299
300   Example:
301 <tscreen><verb>
302 ActivateSecondDataSet:
303     SMC_TransferLowByte LoadData, $40
304         RTS
305     ...
306 SMC LoadData, { LDA $2000 }
307 </verb></tscreen>
308
309
310   <label id="Load low-byte">
311   <tag><tt>SMC_LoadLowByte label (, register)</tt></tag>
312
313   Does the same as '<tt>SMC_LoadValue</tt>' but should be used for low-bytes
314   of addresses for better readability.
315
316   Example:
317 <tscreen><verb>
318 IsSecondDataSetActive:
319         SMC_LoadLowByte LoadData, y
320         CPY #$40
321         BNE NotActive
322     ...
323 SMC LoadData, { LDA $2000 }
324 </verb></tscreen>
325
326
327   <label id="Store low-byte">
328   <tag><tt>SMC_StoreLowByte label (, register)</tt></tag>
329
330   Does the same as '<tt>SMC_StoreValue</tt>' but should be used for low-bytes
331   of addresses for better readability.
332
333   Example:
334 <tscreen><verb>
335 InitStructureBaseAddresses:
336     LDX #0
337     SMC_StoreLowByte GetPlayerGraphic, x
338     SMC_StoreLowByte GetObjectGraphic, x
339     SMC_StoreLowByte StoreCollisionData, x
340     RTS
341     ...
342 SMC GetPlayerGraphic, { LDX $2000 }
343     ...
344 SMC GetObjectGraphic, { LDA $2100,x }
345     ...
346 SMC StoreCollisionData, { STY $2200 }
347 </verb></tscreen>
348
349
350   <label id="Transfer high-byte">
351   <tag><tt>SMC_TransferHighByte label, value (, register)</tt></tag>
352
353   Loads and stores the given value via the named register to the high-byte
354   address portion of an SMC-instruction.
355
356   Example:
357 <tscreen><verb>
358 PlaySFX:
359 SMC GetVolume { LDA $3200,x }
360     STA SoundOut
361     INX
362     BNE PlaySFX
363     ...
364 PlayOtherSound:
365     SMC_TransferHighByte GetVolume, $34
366 </verb></tscreen>
367
368
369   <label id="Load high-byte">
370   <tag><tt>SMC_LoadHighByte label (, register)</tt></tag>
371
372   Loads the high-byte part of an SMC-instruction address to the given register.
373
374   Example:
375 <tscreen><verb>
376 PlaySFX:
377 SMC GetVolume { LDA $3200,x }
378     ...
379     SMC_LoadHighByte GetVolume
380     cmp #$34
381     beq OtherSoundPlaying
382     ...
383 </verb></tscreen>
384
385
386   <label id="Store high-byte">
387   <tag><tt>SMC_StoreHighByte label (, register)</tt></tag>
388
389   Stores the high-byte address part of an SMC-instruction from the given
390   register.
391
392   Example:
393 <tscreen><verb>
394 SetupLevel2:
395     LDX #(>Level2Base)
396     SMC_StoreHighByte GetLevelData, x
397     SMC_StoreHighByte GetScreenData, x
398     SMC_StoreHighByte GetSoundData, x
399     RTS
400     ...
401 SMC GetLevelData, { LDA Level1Base+Data }
402     ...
403 SMC GetScreenData, { LDA Level1Base+Screen, x }
404     ...
405 SMC GetSoundData, { LDA Level1Base+Sound, y }
406 </verb></tscreen>
407
408
409   <label id="Transfer single address">
410   <tag><tt>SMC_TransferAddressSingle label, address (, register)</tt></tag>
411
412   Transfers the contents of the given address via the given register to the
413   designated SMC instruction.
414
415   Example:
416 <tscreen><verb>
417 PrintHello:
418     SMC_TransferAddressSingle GetChar, #HelloMsg
419     ...
420     LDX #0
421 NextChar:
422 SMC GetChar, { LDA  SMC_AbsAdr, x }
423     BEQ leave
424     JSR CharOut
425     INX
426     BNE NextChar
427 </verb></tscreen>
428
429
430   <label id="Transfer address">
431   <tag><tt>SMC_TransferAddress label, address</tt></tag>
432
433   Loads contents of given address to A/X and stores the result to SMC
434   instruction. Allows reuse of register contents by using
435   '<tt>SMC_StoreAddress</tt>' for multiple SMC instruction modifications.
436
437   Example:
438 <tscreen><verb>
439     SMC_TransferAddress JumpTo, #CloseChannel
440     ...
441 SMC JumpTo, { JMP OpenChannel }
442 </verb></tscreen>
443
444
445   <label id="Store address">
446   <tag><tt>SMC_StoreAddress label</tt></tag>
447
448   Stores the address value in a/x to a SMC instruction address position.
449
450   Example:
451 <tscreen><verb>
452     SMC_StoreAddress GetData
453     ...
454 SMC GetData, { LDA SMC_AbsAdr }
455 </verb></tscreen>
456
457 </descrip>
458
459 <sect1>Operational macros<p>
460
461 These marcos are determined to let read/modify/write opcodes work on parts of
462 SMC instructions.
463
464 <descrip>
465
466  <label id="Operate on value">
467   <tag><tt>SMC_OperateOnValue opcode, label</tt></tag>
468
469   Let given opcode work on the value part of a SMC instruction.
470
471   Example:
472 <tscreen><verb>
473     SMC_OperateOnValue ASL, LoadMask    ; shift mask to left
474     ...
475 SMC LoadMask, { LDA #$20 }
476 </verb></tscreen>
477
478   <label id="Operate on low-byte">
479   <tag><tt>SMC_OperateOnLowByte opcode, label</tt></tag>
480
481   Same as '<tt/SMC_OperateOnValue/' but renamed for better readability when
482   accessing low-bytes of address.
483
484   Example:
485 <tscreen><verb>
486     SMC_OperateOnLowByte DEC, AccessData
487     ...
488 SMC AccessData, { LDX Data }
489 </verb></tscreen>
490
491   <label id="Operate on high-byte">
492   <tag><tt>SMC_OperateOnHighByte opcode, label</tt></tag>
493
494   Let the given opcode work on the high-byte part on a SMC-instruction.
495
496   Example:
497 <tscreen><verb>
498 NextPage:
499     SMC_OperateOnHighByte INC, GetPageData
500     ...
501 SMC GetPageData, { LDA SourceData, X }
502 </verb></tscreen>
503 </descrip>
504
505 <sect1>Scope macros<p>
506
507 These marcos are determined to export and import SMC labels out of the current
508 file scope. Please handle with care! If you cannot abstain from leaving the
509 file scope, you should at least document the exported SMC lines very well. On
510 import side no checking is available if the SMC line is correct accessed (e.g.
511 invalid access to the value of an implied instruction)!
512
513 <descrip>
514   <label id="Export SMC line under given name">
515   <tag><tt>SMC_Export alias, label</tt></tag>
516
517   SMC label will be exported under given alias.
518
519   Example:
520 <tscreen><verb>
521 .proc GetValue
522 SMC LoadValue, { LDA #12 }
523     rts
524 .endproc
525
526 SMC_Export GetValueLoader, GetValue::LoadValue
527 </verb></tscreen>
528
529   <label id="Import SMC alias">
530   <tag><tt>SMC_Import alias</tt></tag>
531
532   SMC line is made accessible under given alias.
533
534   Example:
535 <tscreen><verb>
536 SMC_Import GetValueLoader
537     ...
538     SMC_TransferValue GetValueLoader, #47
539     ...
540 </verb></tscreen>
541 </descrip>
542
543 <sect>A complex example<p>
544 Let's have a look on a quite sophisticated example for the usage of SMC. It
545 not only modifies code, but also the modification of the code is modified -
546 allowing reuse of some instructions.
547
548 <descrip>
549 <tag/The code is from my 'memset()'implementation:/
550 <tscreen><verb>
551  1:     ...
552  2:     SMC_StoreAddress StoreAccuFirstSection
553  3:
554  4: StoreToFirstSection:
555  5:     SMC StoreAccuFirstSection, { sta SMC_AbsAdr, Y }
556  6:             ...
557  7: RestoreCodeBranchBaseAdr:
558  8:     SMC FirstIncHighByte, { SMC_OperateOnHighByte inc, StoreAccuFirstSection }              ; code will be overwritten to 'beq RestoreCode' (*)
559  9:     ...
560 10:     SMC_TransferOpcode FirstIncHighByte, OPC_BEQ , x                                        ; change code marked above with (*)
561 11:     SMC_TransferValue FirstIncHighByte, #(restoreCode - RestoreCodeBranchBaseAdr-2), x      ; set relative address to 'RestoreCode'
562 12:     ...
563 13: restoreCode:
564 14:     SMC_TransferOpcode FirstIncHighByte, OPC_INC_abs , x                                    ; restore original code...
565 15:     SMC_TransferValue FirstIncHighByte, #(<(StoreToFirstSection+2)), x                      ; (second byte of inc contained low-byte of address)
566 16:             ...
567 </verb></tscreen>
568
569 <tag/Some explanation:/
570 Line 2: The register pair A/X contains an address, which is stored on the
571 address location of a SMC line called 'StoreAccuFirstSection'. According to
572 cc65's calling convention, the low-byte is in accu while the high-byte is in
573 the X-register.
574
575 Line 5: The (modified) address is accessed.
576
577 Line 8: We have a line here, which is about to be modified (it begins with
578 SMC), but itself modifies code. Please note: Contrary to the rest of SMC-line
579 modifying macros, the 'OperateOn'-macros just expand their given arguments
580 into a single instruction line. These can be changed of course too.
581
582 Line 10,11: These lines construct a branch operation for line 8: The
583 X-register will be used to change it from 'inc StoreAccuFirstSection+2'
584 (high-byte operation) to 'beq restoreCode'. Please note: To calculate the
585 relaive branch offset, we introduced a second label
586 ('RestoreCodeBranchBaseAdr') for to calculate it. Some could also use the
587 internal name of the SMC label, but you should abstain to do so - it may be
588 changed in the future...
589
590 Line 14,15: The original code from line 8 is reestablished.
591 </descrip>
592 </article>