1 <!doctype linuxdoc system>
4 <title>Defining a Custom cc65 Target
5 <author>Bruce Reidenbach
9 This section provides step-by-step instructions on how to use the cc65
10 toolset for a custom hardware platform (a target system not currently
11 supported by the cc65 library set).
14 <!-- Table of contents -->
18 <!-- Begin the document -->
22 The cc65 toolset provides a set of pre-defined libraries that allow the
23 user to target the executable image to a variety of hardware platforms.
24 In addition, the user can create a customized environment so that the
25 executable can be targeted to a custom platform. The following
26 instructions provide step-by-step instructions on how to customize the
27 toolset for a target that is not supported by the standard cc65
30 The platform used in this example is a Xilinx Field Programmable Gate
31 Array (FPGA) with an embedded 65C02 core. The processor core supports
32 the additional opcodes/addressing modes of the 65SC02, along with the
33 STP and WAI instructions. These instructions will create a set of files
34 to create a custom target, named SBC, for <bf>S</bf>ingle <bf>B</bf>oard
37 <sect>System Memory Map Definition<p>
39 The targeted system uses block RAM contained on the XILINX FPGA for the
40 system memory (both RAM and ROM). The block RAMs are available in
41 various aspect ratios, and they will be used in this system as 2K*8
42 devices. There will be two RAMs used for data storage, starting at
43 location $0000 and growing upwards. There will be one ROM (realized as
44 initialized RAM) used code storage, starting at location $FFFF and
47 The cc65 toolset requires a memory configuration file to define the
48 memory that is available to the cc65 run-time environment, which is
53 ZP: start = $0, size = $100, type = rw, define = yes;
54 RAM: start = $200, size = $0E00, define = yes;
55 ROM: start = $F800, size = $0800, file = %O;
59 ZP defines the available zero page locations, which in this case starts
60 at $0 and has a length of $100. Keep in mind that certain systems may
61 require access to some zero page locations, so the starting address may
62 need to be adjusted accordingly to prevent cc65 from attempting to reuse
63 those locations. Also, at a minimum, the cc65 run-time environment uses
64 26 zero page locations, so the smallest zero page size that can be
65 specified is $1A. The usable RAM memory area begins after the 6502
66 stack storage in page 1, so it is defined as starting at location $200
67 and filling the remaining 4K of space (4096 - 2 *
68 256 = 3584 = $0E00). The 2K of ROM space begins at
69 address $F800 and goes to $FFFF (size = $0800).
71 Next, the memory segments within the memory devices need to be defined.
72 A standard segment definition is used, with one notable exception. The
73 interrupt and reset vector locations need to be defined at locations
74 $FFFA through $FFFF. A special segment named VECTORS is defined that
75 resides at these locations. Later, the interrupt vector map will be
76 created and placed in the VECTORS segment, and the linker will put these
77 vectors at the proper memory locations. The segment definition is:
81 ZEROPAGE: load = ZP, type = zp, define = yes;
82 DATA: load = ROM, type = rw, define = yes, run = RAM;
83 BSS: load = RAM, type = bss, define = yes;
84 HEAP: load = RAM, type = bss, optional = yes;
85 STARTUP: load = ROM, type = ro;
86 INIT: load = ROM, type = ro, optional = yes;
87 CODE: load = ROM, type = ro;
88 RODATA: load = ROM, type = ro;
89 VECTORS: load = ROM, type = ro, start = $FFFA;
93 The meaning of each of these segments is as follows.
95 <p><tt> ZEROPAGE: </tt>Data in page 0, defined by ZP as starting at $0 with length $100
96 <p><tt> DATA: </tt>Initialized data that can be modified by the program, stored in RAM
97 <p><tt> BSS: </tt>Uninitialized data stored in RAM (used for variable storage)
98 <p><tt> HEAP: </tt>Uninitialized C-level heap storage in RAM, optional
99 <p><tt> STARTUP: </tt>The program initialization code, stored in ROM
100 <p><tt> INIT: </tt>The code needed to initialize the system, stored in ROM
101 <p><tt> CODE: </tt>The program code, stored in ROM
102 <p><tt> RODATA: </tt>Initialized data that cannot be modified by the program, stored in ROM
103 <p><tt> VECTORS: </tt>The interrupt vector table, stored in ROM at location $FFFA
105 A note about initialized data: any variables that require an initial
106 value, such as external (global) variables, require that the initial
107 values be stored in the ROM code image. However, variables stored in
108 ROM cannot change; therefore the data must be moved into variables that
109 are located in RAM. Specifying <tt>run = RAM</tt> as part of
110 the DATA segment definition will indicate that those variables will
111 require their initialization value to be copied via a call to the
112 <tt>copydata</tt> routine in the startup assembly code. In addition,
113 there are system level variables that will need to be initialized as
114 well, especially if the heap segment is used via a C-level call to
115 <tt>malloc ()</tt>.
117 The final section of the definition file contains the data constructors
118 and destructors used for system startup. In addition, if the heap is
119 used, the maximum C-level stack size needs to be defined in order for
120 the system to be able to reliably allocate blocks of memory. The stack
121 size selection must be greater than the maximum amount of storage
122 required to run the program, keeping in mind that the C-level subroutine
123 call stack and all local variables are stored in this stack. The
124 <tt>FEATURES</tt> section defines the required constructor/destructor
125 attributes and the <tt>SYMBOLS</tt> section defines the stack size. The
126 constructors will be run via a call to <tt>initlib</tt> in the startup
127 assembly code and the destructors will be run via an assembly language
128 call to <tt>donelib</tt> during program termination.
132 CONDES: segment = STARTUP,
134 label = __CONSTRUCTOR_TABLE__,
135 count = __CONSTRUCTOR_COUNT__;
136 CONDES: segment = STARTUP,
138 label = __DESTRUCTOR_TABLE__,
139 count = __DESTRUCTOR_COUNT__;
143 # Define the stack size for the application
144 __STACKSIZE__: value = $0200, weak = yes;
148 These definitions are placed in a file named "sbc.cfg"
149 and are referred to during the ld65 linker stage.
151 <sect>Startup Code Definition<p>
153 In the cc65 toolset, a startup routine must be defined that is executed
154 when the CPU is reset. This startup code is marked with the STARTUP
155 segment name, which was defined in the system configuration file as
156 being in read only memory. The standard convention used in the
157 predefined libraries is that this code is resident in the crt0 module.
158 For this custom system, all that needs to be done is to perform a little
159 bit of 6502 housekeeping, set up the C-level stack pointer, initialize
160 the memory storage, and call the C-level routine <tt>main ()</tt>.
161 The following code was used for the crt0 module, defined in the file
165 ; ---------------------------------------------------------------------------
167 ; ---------------------------------------------------------------------------
169 ; Startup code for cc65 (Single Board Computer version)
174 .export __STARTUP__ : absolute = 1 ; Mark as startup
175 .import __RAM_START__, __RAM_SIZE__ ; Linker generated
177 .import copydata, zerobss, initlib, donelib
179 .include "zeropage.inc"
181 ; ---------------------------------------------------------------------------
182 ; Place the startup code in a special segment
184 .segment "STARTUP"
186 ; ---------------------------------------------------------------------------
187 ; A little light 6502 housekeeping
189 _init: LDX #$FF ; Initialize stack pointer to $01FF
191 CLD ; Clear decimal mode
193 ; ---------------------------------------------------------------------------
194 ; Set cc65 argument stack pointer
196 LDA #<(__RAM_START__ + __RAM_SIZE__)
198 LDA #>(__RAM_START__ + __RAM_SIZE__)
201 ; ---------------------------------------------------------------------------
202 ; Initialize memory storage
204 JSR zerobss ; Clear BSS segment
205 JSR copydata ; Initialize DATA segment
206 JSR initlib ; Run constructors
208 ; ---------------------------------------------------------------------------
213 ; ---------------------------------------------------------------------------
214 ; Back from main (this is also the _exit entry): force a software break
216 _exit: JSR donelib ; Run destructors
220 The following discussion explains the purpose of several important
221 assembler level directives in this file.
227 This line instructs the assembler that the symbols <tt>_init</tt> and
228 <tt>_exit</tt> are to be accessible from other modules. In this
229 example, <tt>_init</tt> is the location that the CPU should jump to when
230 reset, and <tt>_exit</tt> is the location that will be called when the
237 This line instructs the assembler to import the symbol <tt>_main</tt>
238 from another module. cc65 names all C-level routines as
239 {underscore}{name} in assembler, thus the <tt>main ()</tt> routine
240 in C is named <tt>_main</tt> in the assembler. This is how the startup
241 code will link to the C-level code.
244 .export __STARTUP__ : absolute = 1 ; Mark as startup
247 This line marks this code as startup code (code that is executed when
248 the processor is reset), which will then be automatically linked into
252 .import __RAM_START__, __RAM_SIZE__ ; Linker generated
255 This line imports the RAM starting address and RAM size constants, which
256 are used to initialize the cc65 C-level argument stack pointer.
259 .segment "STARTUP"
262 This line instructs the assembler that the code is to be placed in the
263 STARTUP segment of memory.
266 JSR zerobss ; Clear BSS segment
267 JSR copydata ; Initialize DATA segment
268 JSR initlib ; Run constructors
271 These three lines initialize the external (global) and system
272 variables. The first line sets the BSS segment -- the memory locations
273 used for external variables -- to 0. The second line copies the
274 initialization value stored in ROM to the RAM locations used for
275 initialized external variables. The last line runs the constructors
276 that are used to initialize the system run-time variables.
282 This is the actual call to the C-level <tt>main ()</tt> routine,
283 which is called after the startup code completes.
286 _exit: JSR donelib ; Run destructors
290 This is the code that will be executed when <tt>main ()</tt>
291 terminates. The first thing that must be done is run the destructors
292 via a call to <tt>donelib</tt>. Then the program can terminate. In
293 this example, the program is expected to run forever. Therefore, there
294 needs to be a way of indicating when something has gone wrong and the
295 system needs to be shut down, requiring a restart only by a hard reset.
296 The BRK instruction will be used to indicate a software fault. This is
297 advantageous because cc65 uses the BRK instruction as the fill byte in
298 the final binary code. In addition, the hardware has been designed to
299 force the data lines to $00 for all illegal memory accesses, thereby
300 also forcing a BRK instruction into the CPU.
302 <sect>Custom Run-Time Library Creation<p>
304 The next step in customizing the cc65 toolset is creating a run-time
305 library for the targeted hardware. The easiest way to do this is to
306 modify a standard library from the cc65 distribution. In this example,
307 there is no console I/O, mouse, joystick, etc. in the system, so it is
308 most appropriate to use the simplest library as the base, which is for
309 the Watara Supervision and is named "supervision.lib" in the
310 lib directory of the distribution.
312 The only modification required is to replace the <tt>crt0</tt> module in
313 the supervision.lib library with custom startup code. This is simply
314 done by first copying the library and giving it a new name, compiling
315 the startup code with ca65, and finally using the ar65 archiver to
316 replace the module in the new library. The steps are shown below:
319 $ copy "C:\Program Files\cc65\lib\supervision.lib" sbc.lib
321 $ ar65 a sbc.lib crt0.o
324 <sect>Interrupt Service Routine Definition<p>
326 For this system, the CPU is put into a wait condition prior to allowing
327 interrupt processing. Therefore, the interrupt service routine is very
328 simple: return from all valid interrupts. However, as mentioned
329 before, the BRK instruction is used to indicate a software fault, which
330 will call the same interrupt service routine as the maskable interrupt
331 signal IRQ. The interrupt service routine must be able to tell the
332 difference between the two, and act appropriately.
334 The interrupt service routine shown below includes code to detect when a
335 BRK instruction has occurred and stops the CPU from further processing.
336 The interrupt service routine is in a file named
337 "interrupt.s".
340 ; ---------------------------------------------------------------------------
342 ; ---------------------------------------------------------------------------
346 ; Checks for a BRK instruction and returns from all valid interrupts.
349 .export _irq_int, _nmi_int
351 .segment "CODE"
353 .PC02 ; Force 65C02 assembly mode
355 ; ---------------------------------------------------------------------------
356 ; Non-maskable interrupt (NMI) service routine
358 _nmi_int: RTI ; Return from all NMI interrupts
360 ; ---------------------------------------------------------------------------
361 ; Maskable interrupt (IRQ) service routine
363 _irq_int: PHX ; Save X register contents to stack
364 TSX ; Transfer stack pointer to X
365 PHA ; Save accumulator contents to stack
366 INX ; Increment X so it points to the status
367 INX ; register value saved on the stack
368 LDA $100,X ; Load status register contents
369 AND #$10 ; Isolate B status bit
370 BNE break ; If B = 1, BRK detected
372 ; ---------------------------------------------------------------------------
373 ; IRQ detected, return
375 irq: PLA ; Restore accumulator contents
376 PLX ; Restore X register contents
377 RTI ; Return from all IRQ interrupts
379 ; ---------------------------------------------------------------------------
382 break: JMP _stop ; If BRK is detected, something very bad
383 ; has happened, so stop running
386 The following discussion explains the purpose of several important
387 assembler level directives in this file.
393 This line instructs the assembler to import the symbol <tt>_stop</tt>
394 from another module. This routine will be called if a BRK instruction
395 is encountered, signaling a software fault.
398 .export _irq_int, _nmi_int
401 This line instructs the assembler that the symbols <tt>_irq_int</tt> and
402 <tt>_nmi_int</tt> are to be accessible from other modules. In this
403 example, the address of these symbols will be placed in the interrupt
407 .segment "CODE"
410 This line instructs the assembler that the code is to be placed in the
411 CODE segment of memory. Note that because there are 65C02 mnemonics in
412 the assembly code, the assembler is forced to use the 65C02 instruction
413 set with the <tt>.PC02</tt> directive.
415 The final step is to define the interrupt vector memory locations.
416 Recall that a segment named VECTORS was defined in the memory
417 configuration file, which started at location $FFFA. The addresses of
418 the interrupt service routines from "interrupt.s" along with
419 the address for the initialization code in crt0 are defined in a file
420 named "vectors.s". Note that these vectors will be placed in
421 memory in their proper little-endian format as:
423 <p><tt> $FFFA - $FFFB:</tt> NMI interrupt vector (low byte, high byte)
424 <p><tt> $FFFC - $FFFD:</tt> Reset vector (low byte, high byte)
425 <p><tt> $FFFE - $FFFF:</tt> IRQ/BRK interrupt vector (low byte, high byte)
427 using the <tt>.addr</tt> assembler directive. The contents of the file are:
430 ; ---------------------------------------------------------------------------
432 ; ---------------------------------------------------------------------------
434 ; Defines the interrupt vector table.
437 .import _nmi_int, _irq_int
439 .segment "VECTORS"
441 .addr _nmi_int ; NMI vector
442 .addr _init ; Reset vector
443 .addr _irq_int ; IRQ/BRK vector
446 The cc65 toolset will replace the address symbols defined here with the
447 actual addresses of the routines during the link process.
449 <sect>Adding Custom Instructions<p>
451 The cc65 instruction set only supports the WAI (Wait for Interrupt) and
452 STP (Stop) instructions when used with the 65816 CPU (accessed via the
453 --cpu command line option of the ca65 macro assembler). The 65C02 core
454 used in this example supports these two instructions, and in fact the
455 system benefits from the use of both the WAI and STP instructions.
457 In order to use the WAI instruction in this case, a C routine named
458 "wait" was created that consists of the WAI opcode followed by
459 a subroutine return. It was convenient in this example to put the IRQ
460 interrupt enable in this subroutine as well, since interrupts should
461 only be enabled when the code is in this wait condition.
463 For both the WAI and STP instructions, the assembler is
464 "fooled" into placing those opcodes into memory by inserting a
465 single byte of data that just happens to be the opcode for those
466 instructions. The assembly code routines are placed in a file, named
467 "wait.s", which is shown below:
470 ; ---------------------------------------------------------------------------
472 ; ---------------------------------------------------------------------------
474 ; Wait for interrupt and return
478 ; ---------------------------------------------------------------------------
479 ; Wait for interrupt: Forces the assembler to emit a WAI opcode ($CB)
480 ; ---------------------------------------------------------------------------
482 .segment "CODE"
486 CLI ; Enable interrupts
487 .byte $CB ; Inserts a WAI opcode
488 RTS ; Return to caller
492 ; ---------------------------------------------------------------------------
493 ; Stop: Forces the assembler to emit a STP opcode ($DB)
494 ; ---------------------------------------------------------------------------
498 .byte $DB ; Inserts a STP opcode
503 The label <tt>_wait</tt>, when exported, can be called by using the
504 <tt>wait ()</tt> subroutine call in C. The section is marked as
505 code so that it will be stored in read-only memory, and the procedure is
506 tagged for 16-bit absolute addressing via the "near"
507 modifier. Similarly, the <tt>_stop</tt> routine can be called from
508 within the C-level code via a call to <tt>stop ()</tt>. In
509 addition, the routine can be called from assembly code by calling
510 <tt>_stop</tt> (as was done in the interrupt service routine).
512 <sect>Hardware Drivers<p>
514 Oftentimes, it can be advantageous to create small application helpers
515 in assembly language to decrease codespace and increase execution speed
516 of the overall program. An example of this would be the transfer of
517 characters to a FIFO (<bf>F</bf>irst-<bf>I</bf>n,
518 <bf>F</bf>irst-<bf>O</bf>ut) storage buffer for transmission over a
519 serial port. This simple action could be performed by an assembly
520 language driver which would execute much quicker than coding it in C.
521 The following discussion outlines a method of interfacing a C program
522 with an assembly language subroutine.
524 The first step in creating the assembly language code for the driver is
525 to determine how to pass the C arguments to the assembly language
526 routine. The cc65 toolset allows the user to specify whether the data
527 is passed to a subroutine via the stack or by the processor registers by
528 using the <tt/__fastcall__/ and <tt/__cdecl__/ function qualifiers (note that
529 there are two underscore characters in front of and two behind each
530 qualifier). <tt/__fastcall__/ is the default. When <tt/__cdecl__/ <em/isn't/
531 specified, and the function isn't variadic (i.e., its prototype doesn't have
532 an ellipsis), the rightmost argument in the function call is passed to the
533 subroutine using the 6502 registers instead of the stack. Note that if
534 there is only one argument in the function call, the execution overhead
535 required by the stack interface routines is completely avoided.
537 With <tt/__cdecl__</tt>, the last argument is loaded into the A and X
538 registers and then pushed onto the stack via a call to <tt>pushax</tt>.
539 The first thing the subroutine does is retrieve the argument from the
540 stack via a call to <tt>ldax0sp</tt>, which copies the values into the A
541 and X. When the subroutine is finished, the values on the stack must be
542 popped off and discarded via a jump to <tt>incsp2</tt>, which includes
543 the RTS subroutine return command. This is shown in the following code
549 lda #<(L0001) ; Load A with the high order byte
550 ldx #>(L0001) ; Load X with the low order byte
551 jsr pushax ; Push A and X onto the stack
552 jsr _foo ; Call foo, i.e., foo (arg)
558 _foo: jsr ldax0sp ; Retrieve A and X from the stack
559 sta ptr ; Store A in ptr
560 stx ptr+1 ; Store X in ptr+1
561 ... ; (more subroutine code goes here)
562 jmp incsp2 ; Pop A and X from the stack (includes return)
565 If <tt/__cdecl__/ isn't specified, then the argument is loaded into the A
566 and X registers as before, but the subroutine is then called
567 immediately. The subroutine does not need to retrieve the argument
568 since the value is already available in the A and X registers.
569 Furthermore, the subroutine can be terminated with an RTS statement
570 since there is no stack cleanup which needs to be performed. This is
571 shown in the following code sample.
576 lda #<(L0001) ; Load A with the high order byte
577 ldx #>(L0001) ; Load X with the low order byte
578 jsr _foo ; Call foo, i.e., foo (arg)
584 _foo: sta ptr ; Store A in ptr
585 stx ptr+1 ; Store X in ptr+1
586 ... ; (more subroutine code goes here)
587 rts ; Return from subroutine
590 The hardware driver in this example writes a string of character data to
591 a hardware FIFO located at memory location $1000. Each character is
592 read and is compared to the C string termination value ($00), which will
593 terminate the loop. All other character data is written to the FIFO.
594 For convenience, a carriage return/line feed sequence is automatically
595 appended to the serial stream. The driver defines a local pointer
596 variable which is stored in the zero page memory space in order to allow
597 for retrieval of each character in the string via the indirect indexed
600 The assembly language routine is stored in a file names
601 "rs232_tx.s" and is shown below:
604 ; ---------------------------------------------------------------------------
606 ; ---------------------------------------------------------------------------
608 ; Write a string to the transmit UART FIFO
611 .exportzp _rs232_data: near
613 .define TX_FIFO $1000 ; Transmit FIFO memory location
617 _rs232_data: .res 2, $00 ; Reserve a local zero page pointer
619 .segment "CODE"
621 .proc _rs232_tx: near
623 ; ---------------------------------------------------------------------------
624 ; Store pointer to zero page memory and load first character
626 sta _rs232_data ; Set zero page pointer to string address
627 stx _rs232_data+1 ; (pointer passed in via the A/X registers)
628 ldy #00 ; Initialize Y to 0
629 lda (_rs232_data) ; Load first character
631 ; ---------------------------------------------------------------------------
632 ; Main loop: read data and store to FIFO until \0 is encountered
634 loop: sta TX_FIFO ; Loop: Store character in FIFO
635 iny ; Increment Y index
636 lda (_rs232_data),y ; Get next character
637 bne loop ; If character == 0, exit loop
639 ; ---------------------------------------------------------------------------
640 ; Append CR/LF to output stream and return
651 <sect>Hello World! Example<p>
653 The following short example demonstrates programming in C using the cc65
654 toolset with a custom run-time environment. In this example, a Xilinx
655 FPGA contains a UART which is connected to a 65c02 processor with FIFO
656 (<bf>F</bf>irst-<bf>I</bf>n, <bf>F</bf>irst-<bf>O</bf>ut) storage to
657 buffer the data. The C program will wait for an interrupt generated by
658 the receive UART and then respond by transmitting the string "Hello
659 World! " every time a question mark character is received via a
660 call to the hardware driver <tt>rs232_tx ()</tt>. The driver
661 prototype uses the <tt>__fastcall__</tt> extension to indicate that the
662 driver does not use the stack. The FIFO data interface is at address
663 $1000 and is defined as the symbolic constant <tt>FIFO_DATA</tt>.
664 Writing to <tt>FIFO_DATA</tt> transfers a byte of data into the transmit
665 FIFO for subsequent transmission over the serial interface. Reading
666 from <tt>FIFO_DATA</tt> transfers a byte of previously received data out
667 of the receive FIFO. The FIFO status data is at address $1001 and is
668 defined as the symbolic constant <tt>FIFO_STATUS</tt>. For convenience,
669 the symbolic constants <tt>TX_FIFO_FULL</tt> (which isolates bit 0 of
670 the register) and <tt>RX_FIFO_EMPTY</tt> (which isolates bit 1 of the
671 register) have been defined to read the FIFO status.
673 The following C code is saved in the file "main.c". As this
674 example demonstrates, the run-time environment has been set up such that
675 all of the behind-the-scene work is transparent to the user.
678 #define FIFO_DATA (*(unsigned char *) 0x1000)
679 #define FIFO_STATUS (*(unsigned char *) 0x1001)
681 #define TX_FIFO_FULL (FIFO_STATUS & 0x01)
682 #define RX_FIFO_EMPTY (FIFO_STATUS & 0x02)
685 extern void __fastcall__ rs232_tx (char *str);
688 while (1) { // Run forever
689 wait (); // Wait for an RX FIFO interrupt
691 while (RX_FIFO_EMPTY == 0) { // While the RX FIFO is not empty
692 if (FIFO_DATA == '?') { // Does the RX character = '?'
693 rs232_tx ("Hello World!"); // Transmit "Hello World!"
694 } // Discard any other RX characters
698 return (0); // We should never get here!
702 <sect>Putting It All Together<p>
704 The following commands will create a ROM image named "a.out"
705 that can be used as the initialization data for the Xilinx Block RAM
706 used for code storage:
709 $ cc65 -t none -O --cpu 65sc02 main.c
710 $ ca65 --cpu 65sc02 main.s
711 $ ca65 --cpu 65sc02 rs232_tx.s
712 $ ca65 --cpu 65sc02 interrupt.s
713 $ ca65 --cpu 65sc02 vectors.s
714 $ ca65 --cpu 65sc02 wait.s
715 $ ld65 -C sbc.cfg -m main.map interrupt.o vectors.o wait.o rs232_tx.o
719 During the C-level code compilation phase (<tt>cc65</tt>), assumptions
720 about the target system are disabled via the <tt>-t none</tt> command
721 line option. During the object module linker phase (<tt>ld65</tt>), the
722 target customization is enabled via inclusion of the <tt>sbc.lib</tt>
723 file and the selection of the configuration file via the <tt>-C
724 sbc.cfg</tt> command line option.
726 The 65C02 core used most closely matches the cc65 toolset processor
727 named 65SC02 (the 65C02 extensions without the bit manipulation
728 instructions), so all the commands specify the use of that processor via
729 the <tt>--cpu 65sc02</tt> option.