Merge pull request #2760 from kugelfuhr/kugelfuhr/fix-2753

Add ".CAPABILITY" to ca65, remove ".MACPACK cpu"
This commit is contained in:
Bob Andrews
2025-07-03 18:43:05 +02:00
committed by GitHub
84 changed files with 717 additions and 361 deletions

View File

@@ -33,7 +33,7 @@ function checkarray_quoted_name
}
for N in `grep -rl "BEGIN SORTED.SH" "$CHECK_DIR"`; do
checkarray_quoted_name $N
find "$CHECK_DIR" -name \*.\[ch\] -print | while read N; do
grep -q "BEGIN SORTED.SH" "$N" && checkarray_quoted_name "$N"
done
exit 0

View File

@@ -64,6 +64,6 @@ function checkarray
find "$CHECK_DIR" -name \*.\[ch\] -print | while read N; do
grep -q "BEGIN DECL SORTED_CODEOPT.SH" "$N" && checkarray $N
grep -q "BEGIN DECL SORTED_CODEOPT.SH" "$N" && checkarray "$N"
done
exit 0
exit 0

View File

@@ -34,7 +34,7 @@ function checkarray_quoted_name
rm -rf .a.tmp
}
for N in `grep -rl "BEGIN SORTED_OPCODES.SH" "$CHECK_DIR"`; do
checkarray_quoted_name $N
find "$CHECK_DIR" -name \*.\[ch\] -print | while read N; do
grep -q "BEGIN SORTED_OPCODES.SH" "$N" && checkarray_quoted_name "$N"
done
exit 0

View File

@@ -1,38 +1,4 @@
; CPU bitmask constants (make sure this matches src/common/cpu.h)
CPU_ISET_NONE = $0001
CPU_ISET_6502 = $0002
CPU_ISET_6502X = $0004
CPU_ISET_6502DTV = $0008
CPU_ISET_65SC02 = $0010
CPU_ISET_65C02 = $0020 ; Rockwell extensions
CPU_ISET_65816 = $0040
CPU_ISET_SWEET16 = $0080
CPU_ISET_HUC6280 = $0100
CPU_ISET_M740 = $0200
CPU_ISET_4510 = $0400
CPU_ISET_45GS02 = $0800
CPU_ISET_W65C02 = $1000 ; WDC extensions
CPU_ISET_65CE02 = $2000 ; CSG extensions
; CPU capabilities
; make sure to only combine the instruction sets that are 100% compatible
CPU_NONE = CPU_ISET_NONE
CPU_6502 = CPU_ISET_6502
CPU_6502X = CPU_ISET_6502X | CPU_ISET_6502
CPU_6502DTV = CPU_ISET_6502DTV | CPU_ISET_6502
CPU_65SC02 = CPU_ISET_65SC02 | CPU_ISET_6502
CPU_65C02 = CPU_ISET_65C02 | CPU_ISET_6502 | CPU_ISET_65SC02
CPU_W65C02 = CPU_ISET_W65C02 | CPU_ISET_6502 | CPU_ISET_65SC02 | CPU_ISET_65C02
; FIXME: CPU_ISET_65SC02 does not apply to the following, because the zp-indirect
; addressing was replaced with zp-indirect,z-indexed in 652SCE02
CPU_HUC6280 = CPU_ISET_HUC6280 | CPU_ISET_6502 | CPU_ISET_65C02
CPU_4510 = CPU_ISET_4510 | CPU_ISET_6502 | CPU_ISET_65C02 | CPU_ISET_65CE02
CPU_45GS02 = CPU_ISET_45GS02 | CPU_ISET_6502 | CPU_ISET_65C02 | CPU_ISET_65CE02 | CPU_ISET_4510
CPU_M740 = CPU_ISET_M740 | CPU_ISET_6502
CPU_65CE02 = CPU_ISET_65CE02 | CPU_ISET_6502 | CPU_ISET_65C02
CPU_65816 = CPU_ISET_65816 | CPU_ISET_6502 | CPU_ISET_65SC02
CPU_SWEET16 = CPU_ISET_SWEET16
; This file is no longer needed as the symbols that were defined here are now
; internal symbols generated by the assembler. It is kept to avoid breaking
; old sources.
.warning "'.macpack cpu' is no longer required"

View File

@@ -1401,16 +1401,76 @@ writable.
Reading this pseudo variable will give a constant integer value that
tells which CPU is currently enabled. It can also tell which instruction
set the CPU is able to translate. The value read from the pseudo variable
should be further examined by using one of the constants defined by the
"cpu" macro package (see <tt/<ref id=".MACPACK" name=".MACPACK">/).
should be further examined by using one of the following constants:
It may be used to replace the .IFPxx pseudo instructions or to construct
even more complex expressions.
<tscreen><verb>
CPU_6502
CPU_65SC02
CPU_65C02
CPU_65816
CPU_SWEET16
CPU_HUC6280
CPU_4510
CPU_45GS02
CPU_6502DTV
CPU_M740
</verb></tscreen>
Above constants may be used to determine the exact type of the currently
enabled CPU. In addition to that, for each CPU instruction set, another
constant is defined:
<tscreen><verb>
CPU_ISET_6502
CPU_ISET_65SC02
CPU_ISET_65C02
CPU_ISET_65816
CPU_ISET_SWEET16
CPU_ISET_HUC6280
CPU_ISET_4510
CPU_ISET_45GS02
CPU_ISET_6502DTV
CPU_ISET_M740
</verb></tscreen>
<!-- Sorry but explaining these with the changes from #2751 is too cringy for
me - must be done by someone else. The remainder is from the old
".macpack cpu" section"
The value read from the <tt/<ref id=".CPU" name=".CPU">/ pseudo variable may
be checked with <tt/<ref id="operators" name=".BITAND">/ to determine if the
currently enabled CPU supports a specific instruction set. For example the
65C02 supports all instructions of the 65SC02 CPU, so it has the
<tt/CPU_ISET_65SC02/ bit set in addition to its native <tt/CPU_ISET_65C02/
bit. Using
<tscreen><verb>
.if (.cpu .bitand CPU_ISET_65SC02)
lda (c_sp)
.else
ldy #$00
lda (c_sp),y
.endif
</verb></tscreen>
it is possible to determine if the
<tscreen><verb>
lda (c_sp)
</verb></tscreen>
instruction is supported, which is the case for the 65SC02, 65C02 and 65816
CPUs (the latter two are upwards compatible to the 65SC02).
see section <ref id="6502-mode" name="6502 format"> and following.
-->
<tt/.CPU/ may be used to replace the .IFPxx pseudo instructions or to
construct even more complex expressions.
Example:
<tscreen><verb>
.macpack cpu
.if (.cpu .bitand CPU_ISET_65816)
phx
phy
@@ -1422,6 +1482,9 @@ writable.
.endif
</verb></tscreen>
See also: <tt><ref id=".CAP" name=".CAP"></tt>
<sect1><tt>.ISIZE</tt><label id=".ISIZE"><p>
@@ -1594,6 +1657,61 @@ either a string or an expression value.
<sect1><tt>.CAP, .CAPABILITY</tt><label id=".CAP"><p>
Builtin function. The function allows to check for capabilities of the
currently selected CPU or target system. It must be called with a comma
separated list of identifiers and returns non zero if all of the given
capabilities are available. Otherwise it returns zero.
Existing capabilities are:
<descrip>
<tag><tt>CPU_HAS_BITIMM</tt></tag>
Checks for the availability of the "bit #imm" instruction.
<tag><tt>CPU_HAS_BRA8</tt></tag>
Checks for the availability of a short (8 bit) branch.
<tag><tt>CPU_HAS_INA</tt></tag>
Checks for the availability of accu inc/dec instructions.
<tag><tt>CPU_HAS_PUSHXY</tt></tag>
Checks for the capability to push and pop the X and Y registers.
<tag><tt>CPU_HAS_ZPIND</tt></tag>
Checks for the availability of the "zeropage indirect" addressing mode as it
is implemented in the 65SC02 CPU.
<tag><tt>CPU_HAS_STZ</tt></tag>
Checks for the availability of the "store zero" instruction as it is
implemented in the 65SC02 CPU.
</descrip>
Case is ignored when checking the identifiers. The <tt/.cap/ function is
easier to use than checking <tt/.cpu/ and requires no intimate knowledge
of all instruction sets. For more detailed checking <tt/.cpu/ is still
available.
Example:
<tscreen><verb>
.if .cap(CPU_HAS_BRA, CPU_HAS_PUSHXY)
phx
bra L1
.else
txa
pha
jmp L1
.endif
</verb></tscreen>
See also: <tt><ref id=".CPU" name=".CPU"></tt>
<sect1><tt>.CONCAT</tt><label id=".CONCAT"><p>
Builtin string function. The function allows to concatenate a list of string
@@ -4985,69 +5103,6 @@ This macro package defines a macro named <tt/scrcode/. It takes a string
as argument and places this string into memory translated into screen codes.
<sect1><tt>.MACPACK cpu</tt><p>
This macro package does not define any macros but constants used to examine
the value read from the <tt/<ref id=".CPU" name=".CPU">/ pseudo variable. For
each supported CPU a constant similar to
<tscreen><verb>
CPU_6502
CPU_65SC02
CPU_65C02
CPU_65816
CPU_SWEET16
CPU_HUC6280
CPU_4510
CPU_45GS02
CPU_6502DTV
CPU_M740
</verb></tscreen>
is defined. These constants may be used to determine the exact type of the
currently enabled CPU. In addition to that, for each CPU instruction set,
another constant is defined:
<tscreen><verb>
CPU_ISET_6502
CPU_ISET_65SC02
CPU_ISET_65C02
CPU_ISET_65816
CPU_ISET_SWEET16
CPU_ISET_HUC6280
CPU_ISET_4510
CPU_ISET_45GS02
CPU_ISET_6502DTV
CPU_ISET_M740
</verb></tscreen>
The value read from the <tt/<ref id=".CPU" name=".CPU">/ pseudo variable may
be checked with <tt/<ref id="operators" name=".BITAND">/ to determine if the
currently enabled CPU supports a specific instruction set. For example the
65C02 supports all instructions of the 65SC02 CPU, so it has the
<tt/CPU_ISET_65SC02/ bit set in addition to its native <tt/CPU_ISET_65C02/
bit. Using
<tscreen><verb>
.if (.cpu .bitand CPU_ISET_65SC02)
lda (c_sp)
.else
ldy #$00
lda (c_sp),y
.endif
</verb></tscreen>
it is possible to determine if the
<tscreen><verb>
lda (c_sp)
</verb></tscreen>
instruction is supported, which is the case for the 65SC02, 65C02 and 65816
CPUs (the latter two are upwards compatible to the 65SC02).
see section <ref id="6502-mode" name="6502 format"> and following.
<sect1><tt>.MACPACK module</tt><p>
This macro package defines a macro named <tt/module_header/. It takes an

View File

@@ -18,8 +18,6 @@
.include "zeropage.inc"
.include "apple2.inc"
.macpack cpu
.segment "ONCE"
initconio:

View File

@@ -6,7 +6,6 @@
.export _lseek
.import popax, popptr1
.macpack cpu
.include "zeropage.inc"
.include "errno.inc"

View File

@@ -26,7 +26,6 @@
.include "ser-error.inc"
.macpack module
.macpack cpu
; ------------------------------------------------------------------------
; Header. Includes jump table

View File

@@ -9,14 +9,13 @@
.importzp sreg
.include "cbm.inc"
.macpack cpu
.proc _clock
; Some accelerator adaptors have CMOS ICs.
.if (.cpu & ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg + 1
.else
lda #$00 ; Byte 3 always is zero

View File

@@ -7,8 +7,6 @@
.include "errno.inc"
.macpack cpu
; ----------------------------------------------------------------------------
; int __fastcall__ __directerrno (unsigned char code);
; /* Set errno to a specific error code, clear __oserror, and return -1. Used
@@ -18,7 +16,7 @@
___directerrno:
jsr ___seterrno ; Set errno (returns with .A = 0)
sta ___oserror ; Clear ___oserror
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_INA)
dec a
.else
lda #$FF ; Return -1

View File

@@ -12,7 +12,6 @@
.include "_heap.inc"
.macpack generic
.macpack cpu
;-----------------------------------------------------------------------------
; Code
@@ -39,7 +38,7 @@ ___heapblocksize:
ldy #usedblock::size+1
lda (ptr2),y
tax
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (ptr2)
.else
dey

View File

@@ -8,7 +8,6 @@
.include "errno.inc"
.macpack generic
.macpack cpu
; ----------------------------------------------------------------------------
; int __fastcall__ __mappederrno (unsigned char code);
@@ -24,7 +23,7 @@ ___mappederrno:
bze ok ; Branch if no
jsr ___osmaperrno ; Map OS error into errno code
jsr ___seterrno ; Save in errno (returns with .A = 0)
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_INA)
dec a
.else
lda #$FF ; Return -1 if error

View File

@@ -13,7 +13,6 @@
.import _strlower, _strlen
.macpack generic
.macpack cpu
; ----------------------------------------------------------------------------
; We will store variables into the register bank in the zeropage. Define
@@ -38,7 +37,7 @@ FCount = ptr2
GetFormatChar:
ldy #0
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (Format)
.else
lda (Format),y
@@ -115,7 +114,7 @@ GetIntArg:
lda (ArgList),y
tax
dey
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (ArgList)
.else
lda (ArgList),y
@@ -274,7 +273,7 @@ Save: lda regbank,y
; Initialize the output counter in the output descriptor to zero
lda #0
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (OutData)
ldy #$01
sta (OutData),y
@@ -353,7 +352,7 @@ MainLoop:
sta (c_sp),y
dey
lda FCount
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (c_sp)
.else
sta (c_sp),y
@@ -570,7 +569,7 @@ CheckCount:
jsr GetIntArg
sta ptr1
stx ptr1+1 ; Get user supplied pointer
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (OutData) ; Low byte of OutData->ccount
sta (ptr1)
ldy #1

View File

@@ -16,8 +16,6 @@
.include "time.inc"
.macpack cpu
__time_t_to_tm:
; Divide number of seconds since epoch, in ptr1:sreg,
; by 86400 to get the number of days since epoch, and
@@ -80,7 +78,7 @@ __time_t_to_tm:
; Zero the two high bytes of the divisor and the high byte
; of the dividend.
.if .cpu .bitand CPU_ISET_65SC02
.if .cap(CPU_HAS_STZ)
stz ptr4
stz ptr4+1
stz sreg+1

View File

@@ -9,8 +9,6 @@
.importzp ptr1
.include "time.inc"
.macpack cpu
; ------------------------------------------------------------------------
; Special values
@@ -24,7 +22,7 @@ MAX_BUF_LEN = 38
_asctime:
; Backup timep
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_PUSHXY)
pha
phx
.else
@@ -48,7 +46,7 @@ _asctime:
jsr pushax
; Restore timep
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_PUSHXY)
plx
pla
.else

View File

@@ -10,8 +10,6 @@
.include "errno.inc"
.macpack cpu
; ---------------------------------------------------------------------------
.proc _atexit
@@ -41,7 +39,7 @@
jsr ___seterrno
ldx #$FF ; Return -1
txa
rts
Exit: rts
.endproc
@@ -54,7 +52,7 @@
.proc doatexit
ldy exitfunc_index ; Get index
beq @L9 ; Jump if done
beq _atexit::Exit ; Jump if done
dey
lda exitfunc_table,y
tax
@@ -62,14 +60,12 @@
lda exitfunc_table,y
sty exitfunc_index
jsr callax ; Call the function
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_BRA8)
bra doatexit
.else
jmp doatexit ; Next one
.endif
@L9: rts
.endproc

View File

@@ -12,8 +12,6 @@
.include "stdio.inc"
.include "_file.inc"
.macpack cpu
_fgetc:
sta ptr1
stx ptr1+1
@@ -22,7 +20,7 @@ _fgetc:
jsr checkferror
bne ret_eof
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_BITIMM)
bit #_FPUSHBACK ; Check for pushed back char
beq do_read
.else

View File

@@ -14,12 +14,10 @@
.include "stdio.inc"
.include "_file.inc"
.macpack cpu
terminate_ptr:
lda #$00
tax
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (ptr4)
.else
tay
@@ -41,7 +39,7 @@ _fgets:
sta buf
stx buf+1
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz didread
.else
lda #$00 ; We have read nothing yet
@@ -79,7 +77,7 @@ read_loop:
ldy #$01
sty didread ; We read at least one char
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (ptr4)
.else
dey

View File

@@ -20,7 +20,6 @@
.include "_file.inc"
.macpack generic
.macpack cpu
; ------------------------------------------------------------------------
; Code
@@ -48,7 +47,7 @@
ldy #_FILE::f_flags
lda (file),y
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_BITIMM)
bit #_FOPEN ; Is the file open?
.else
and #_FOPEN ; Is the file open?
@@ -57,7 +56,7 @@
; Check if the stream is in an error state
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_BITIMM)
bit #_FERROR
.else
lda (file),y ; get file->f_flags again
@@ -74,17 +73,15 @@
; Remember if we have a pushed back character and reset the flag.
@L2: .if (.cpu .bitand ::CPU_ISET_65SC02)
@L2: .if .cap(CPU_HAS_BITIMM)
ldx #$00
bit #_FPUSHBACK
beq @L3
.else
tax ; X = 0
lda (file),y
and #_FPUSHBACK
.endif
beq @L3
.if (.not .cpu .bitand ::CPU_ISET_65SC02)
lda (file),y
.endif
and #<~_FPUSHBACK
@@ -135,7 +132,7 @@
; Copy the buffer pointer into ptr1, and increment the pointer value passed
; to read() by one, so read() starts to store data at buf+1.
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
sta ptr1
add #1
@@ -159,7 +156,7 @@
ldy #_FILE::f_pushback
lda (file),y
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (ptr1) ; *buf = file->f_pushback;
.else
ldy #0

View File

@@ -16,8 +16,6 @@
.include "errno.inc"
.include "_file.inc"
.macpack cpu
; ------------------------------------------------------------------------
; Code
@@ -34,7 +32,7 @@
ldy #_FILE::f_flags
lda (ptr1),y
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_BITIMM)
bit #_FOPEN
.else
and #_FOPEN ; Is the file open?
@@ -50,7 +48,7 @@
; Check if the stream is in an error state
@L2: .if (.not .cpu .bitand ::CPU_ISET_65SC02)
@L2: .if .not .cap(CPU_HAS_BITIMM)
lda (ptr1),y ; get file->f_flags again
.endif
and #_FERROR

View File

@@ -10,8 +10,6 @@
.import __hextab, __longminstr
.importzp sreg, ptr1, ptr2, ptr3, tmp1
.macpack cpu
.code
;
@@ -64,7 +62,7 @@ L2: txa ; get high byte
bpl ultoa
lda #'-'
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (ptr2)
.else
ldy #0

View File

@@ -8,7 +8,6 @@
.export _strcat
.import popax
.importzp ptr1, ptr2, tmp3
.macpack cpu
_strcat:
sta ptr1 ; Save src
@@ -16,7 +15,7 @@ _strcat:
jsr popax ; Get dest
sta tmp3 ; Remember for function return
tay
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz ptr2
.else
lda #0

View File

@@ -8,14 +8,13 @@
.export _strchr
.import popax
.importzp ptr1, tmp1
.macpack cpu
_strchr:
sta tmp1 ; Save c
jsr popax ; get s
tay ; low byte of pointer to y
stx ptr1+1
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz ptr1
.else
lda #0

View File

@@ -12,8 +12,6 @@
.import _strlen_ptr4, _malloc, _memcpy, pushax
.export _strdup
.macpack cpu
_strdup:
; Get length (and store source in ptr4)
sta ptr4
@@ -22,7 +20,7 @@ _strdup:
jsr _strlen_ptr4 ; strlen may increment
; Add null byte for terminator
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_INA)
inc a
.else
clc

View File

@@ -10,7 +10,6 @@
.export _strlen, _strlen_ptr4
.importzp ptr4
.macpack cpu
_strlen:
sta ptr4 ; Save s

View File

@@ -8,64 +8,63 @@
.export _strncat
.import popax, popptr1
.importzp ptr1, ptr2, ptr3, tmp1, tmp2
.macpack cpu
_strncat:
inx
stx tmp2
tax
inx
stx tmp1 ; save count with each byte incremented separately
inx
stx tmp2
tax
inx
stx tmp1 ; save count with each byte incremented separately
jsr popptr1 ; get src
jsr popptr1 ; get src
jsr popax ; get dest
sta ptr3 ; remember for function return
stx ptr3+1
stx ptr2+1
tay ; low byte as offset in Y
.if (.cpu .bitand ::CPU_ISET_65SC02)
stz ptr2
jsr popax ; get dest
sta ptr3 ; remember for function return
stx ptr3+1
stx ptr2+1
tay ; low byte as offset in Y
.if .cap(CPU_HAS_STZ)
stz ptr2
.else
ldx #0
stx ptr2 ; destination on page boundary
ldx #0
stx ptr2 ; destination on page boundary
.endif
; find end of dest
L1: lda (ptr2),y
beq L2
iny
bne L1
inc ptr2+1
bne L1
L1: lda (ptr2),y
beq L2
iny
bne L1
inc ptr2+1
bne L1
; end found, apply offset to dest ptr and reset y
L2: sty ptr2
L2: sty ptr2
; copy src. We've put the ones complement of the count into the counter, so
; we'll increment the counter on top of the loop
L3: ldy #0
ldx tmp1 ; low counter byte
L3: ldy #0
ldx tmp1 ; low counter byte
L4: dex
bne L5
dec tmp2
beq L6 ; jump if done
L5: lda (ptr1),y
sta (ptr2),y
beq L7
iny
bne L4
inc ptr1+1
inc ptr2+1
bne L4
L4: dex
bne L5
dec tmp2
beq L6 ; jump if done
L5: lda (ptr1),y
sta (ptr2),y
beq L7
iny
bne L4
inc ptr1+1
inc ptr2+1
bne L4
; done, set the trailing zero and return pointer to dest
L6: lda #0
sta (ptr2),y
L7: lda ptr3
ldx ptr3+1
rts
L6: lda #0
sta (ptr2),y
L7: lda ptr3
ldx ptr3+1
rts

View File

@@ -8,13 +8,12 @@
.export _cputsxy, _cputs
.import gotoxy, _cputc
.importzp ptr1, tmp1
.macpack cpu
_cputsxy:
sta ptr1 ; Save s for later
stx ptr1+1
jsr gotoxy ; Set cursor, pop x and y
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_BRA8)
bra L0 ; Same as cputs...
.else
jmp L0 ; Same as cputs...
@@ -24,7 +23,7 @@ _cputs: sta ptr1 ; Save s
stx ptr1+1
L0:
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (ptr1) ; (5)
.else
ldy #0 ; (2)

View File

@@ -10,8 +10,6 @@
.import screensize
.importzp ptr1, ptr2
.macpack cpu
.proc _screensize
sta ptr2 ; Store the y pointer
@@ -20,7 +18,7 @@
jsr screensize ; Get screensize into X/Y
tya ; Get Y size into A
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (ptr2)
txa
sta (ptr1)

View File

@@ -10,7 +10,6 @@
.importzp c_sp, ptr1, ptr2, ptr3, tmp1
.macpack generic
.macpack cpu
.data
@@ -74,7 +73,7 @@ out: jsr popax ; count
; Loop outputting characters
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND, CPU_HAS_BRA8)
@L1: dec outdesc+6
beq @L4

View File

@@ -11,14 +11,12 @@
.export tosadda0, tosaddax
.importzp c_sp, tmp1
.macpack cpu
tosadda0:
ldx #0
tosaddax:
clc ; (2)
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
adc (c_sp) ; (7)
tay ; (9)

View File

@@ -8,12 +8,10 @@
.import addysp1
.importzp c_sp, ptr4
.macpack cpu
tosanda0:
ldx #$00
tosandax:
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
and (c_sp) ; 65SC02 version, saves 2 cycles and 1 byte
ldy #1
.else

View File

@@ -18,8 +18,6 @@
.import __CONSTRUCTOR_TABLE__, __CONSTRUCTOR_COUNT__
.import __DESTRUCTOR_TABLE__, __DESTRUCTOR_COUNT__
.macpack cpu
; --------------------------------------------------------------------------
; Initialize library modules

View File

@@ -7,11 +7,10 @@
.export incax1
.macpack generic
.macpack cpu
.proc incax1
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_INA)
ina ; 65C02 version
bne @L9
.else

View File

@@ -7,8 +7,6 @@
.export popax, incsp2
.importzp c_sp
.macpack cpu
; Pop a/x from stack. This function will run directly into incsp2
.proc popax
@@ -16,7 +14,7 @@
ldy #1
lda (c_sp),y ; get hi byte
tax ; into x
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp) ; get lo byte
.else
dey

View File

@@ -8,8 +8,6 @@
.import addysp1
.importzp c_sp, sreg, tmp1
.macpack cpu
; EAX = TOS + EAX
tosadd0ax:
@@ -19,7 +17,7 @@ tosadd0ax:
tosaddeax:
clc
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
adc (c_sp) ; 65SC02 version - saves 2 cycles
ldy #1
.else

View File

@@ -11,8 +11,6 @@
.export laddeq1, laddeqa, laddeq
.importzp sreg, ptr1, tmp1
.macpack cpu
laddeq1:
lda #$01
@@ -24,7 +22,7 @@ laddeqa:
laddeq: sty ptr1+1 ; Store high byte of address
clc
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
adc (ptr1)
sta (ptr1)
ldy #$01 ; Address byte 1

View File

@@ -9,10 +9,8 @@
.import addysp1
.importzp c_sp, sreg, tmp1
.macpack cpu
tosand0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -22,7 +20,7 @@ tosand0ax:
.endif
tosandeax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
and (c_sp) ; byte 0
ldy #1
.else

View File

@@ -7,8 +7,6 @@
.export ldau00sp, ldau0ysp
.importzp c_sp, ptr1
.macpack cpu
ldau00sp:
ldy #1
ldau0ysp:
@@ -18,7 +16,7 @@ ldau0ysp:
lda (c_sp),y
sta ptr1
ldx #0
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (ptr1) ; Save one cycle for the C02
.else
lda (ptr1,x)

View File

@@ -14,8 +14,6 @@
.import addysp
.importzp c_sp
.macpack cpu
leave00:
lda #0
leave0: ldx #0
@@ -28,7 +26,7 @@ leavey0:
leavey:
jsr addysp ; drop stack frame
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
leave: tay ; save A a sec
lda (c_sp) ; that's the pushed arg size

View File

@@ -11,10 +11,8 @@
.import poplsargs, udiv32, negeax
.importzp sreg, ptr1, ptr2, tmp1, tmp3, tmp4
.macpack cpu
tosmod0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else

View File

@@ -9,11 +9,9 @@
.import addysp1
.importzp c_sp, sreg, tmp1, tmp2, tmp3, tmp4, ptr1, ptr3, ptr4
.macpack cpu
tosmul0ax:
tosumul0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -26,7 +24,7 @@ tosmuleax:
tosumuleax:
mul32: sta ptr1
stx ptr1+1 ; op2 now in ptr1/sreg
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
ldy #1
.else

View File

@@ -9,10 +9,8 @@
.import addysp1
.importzp c_sp, sreg, tmp1
.macpack cpu
tosor0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -22,7 +20,7 @@ tosor0ax:
.endif
tosoreax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
ora (c_sp)
ldy #1
.else

View File

@@ -9,8 +9,6 @@
.import incsp4
.importzp c_sp, sreg
.macpack cpu
popeax: ldy #3
lda (c_sp),y
sta sreg+1
@@ -20,7 +18,7 @@ popeax: ldy #3
dey
lda (c_sp),y
tax
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
.else
dey

View File

@@ -12,13 +12,11 @@
.import decsp4
.importzp c_sp, sreg
.macpack cpu
pushl0:
lda #0
tax
push0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -39,7 +37,7 @@ pusheax:
txa
sta (c_sp),y
pla
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (c_sp)
.else
dey

View File

@@ -12,10 +12,8 @@
.import addysp1
.importzp c_sp, sreg, tmp1
.macpack cpu
tosrsub0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -26,7 +24,7 @@ tosrsub0ax:
tosrsubeax:
sec
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sbc (c_sp)
ldy #1
.else

View File

@@ -11,10 +11,8 @@
.import addysp1
.importzp c_sp, sreg
.macpack cpu
tossub0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -26,7 +24,7 @@ tossub0ax:
tossubeax:
sec
eor #$FF
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
adc (c_sp) ; 65SC02 version - saves 2 cycles
ldy #1
.else

View File

@@ -11,8 +11,6 @@
.export lsubeq1, lsubeqa, lsubeq
.importzp sreg, ptr1
.macpack cpu
lsubeq1:
lda #$01
@@ -25,7 +23,7 @@ lsubeq: sty ptr1+1 ; Store high byte of address
sec
eor #$FF
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
adc (ptr1) ; Subtract byte 0
sta (ptr1)
ldy #$01 ; Address byte 1

View File

@@ -9,10 +9,8 @@
.import addysp1
.importzp c_sp, sreg, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
.macpack cpu
tosudiv0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -38,7 +36,7 @@ getlop: sta ptr3 ; Put right operand in place
lda sreg+1
sta ptr4+1
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
ldy #1
.else

View File

@@ -9,10 +9,8 @@
.import getlop, udiv32
.importzp sreg, tmp3, tmp4, ptr2
.macpack cpu
tosumod0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else

View File

@@ -9,10 +9,8 @@
.import addysp1
.importzp c_sp, sreg, tmp1
.macpack cpu
tosxor0ax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz sreg
stz sreg+1
.else
@@ -22,7 +20,7 @@ tosxor0ax:
.endif
tosxoreax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
eor (c_sp) ; byte 0
ldy #1
.else

View File

@@ -9,12 +9,10 @@
.import addysp1
.importzp c_sp, tmp1
.macpack cpu
tosora0:
ldx #$00
tosorax:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
ora (c_sp)
ldy #1
.else

View File

@@ -7,11 +7,9 @@
.export popa
.importzp c_sp
.macpack cpu
.proc popa
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
.else
ldy #0 ; (2)

View File

@@ -8,14 +8,12 @@
.import incsp2
.importzp c_sp, ptr1
.macpack cpu
.proc popptr1 ; 14 bytes (four usages = at least 2 bytes saved)
ldy #1
lda (c_sp),y ; get hi byte
sta ptr1+1 ; into ptr hi
dey ; dey even for for 65C02 here to have Y=0 at exit!
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp) ; get lo byte
.else
lda (c_sp),y ; get lo byte

View File

@@ -8,14 +8,12 @@
.import incsp2
.importzp c_sp, sreg
.macpack cpu
popsreg:
pha ; save A
ldy #1
lda (c_sp),y ; get hi byte
sta sreg+1 ; store it
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp) ; get lo byte
.else
dey

View File

@@ -7,8 +7,6 @@
.export pusha0sp, pushaysp, pusha
.importzp c_sp
.macpack cpu
; Beware: The optimizer knows about this function!
pusha0sp:

View File

@@ -7,8 +7,6 @@
.export push0, pusha0, pushax
.importzp c_sp
.macpack cpu
push0: lda #0
pusha0: ldx #0
@@ -31,7 +29,7 @@ pusha0: ldx #0
sta (c_sp),y ; (27)
pla ; (31)
dey ; (33)
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (c_sp) ; (37)
.else
sta (c_sp),y ; (38)

View File

@@ -8,8 +8,6 @@
.import pushax
.importzp ptr1
.macpack cpu
pushbidx:
sty ptr1
clc
@@ -19,7 +17,7 @@ pushbidx:
pushb: sta ptr1
stx ptr1+1
ldx #0 ; Load index/high byte
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (ptr1) ; Save one cycle for the C02
.else
lda (ptr1,x)

View File

@@ -9,8 +9,6 @@
.import addysp1
.importzp c_sp, tmp1
.macpack cpu
;
; AX = AX - TOS
;
@@ -19,7 +17,7 @@ tosrsuba0:
ldx #0
tosrsubax:
sec
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sbc (c_sp)
ldy #1
.else

View File

@@ -15,8 +15,6 @@
.import popax
.importzp tmp1
.macpack cpu
tosshlax:
tosaslax:
sta tmp1 ; Save shift count
@@ -55,7 +53,7 @@ L2: pla
; Shift count is exactly 8
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_PUSHXY)
L3: plx ; Low byte from stack into X
rts ; A is already zero
.else

View File

@@ -9,8 +9,6 @@
.import incsp2
.importzp c_sp, tmp1, ptr1
.macpack cpu
.proc staxspidx
sty tmp1 ; Save Y
@@ -18,7 +16,7 @@
ldy #1
lda (c_sp),y
sta ptr1+1
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
.else
dey

View File

@@ -21,7 +21,6 @@
; Use macros for better readability
.macpack generic
.macpack cpu
; ----------------------------------------------------------------------------
@@ -39,7 +38,7 @@
lda c_sp+1
sta initialsp+1
sbc #>__STACKSIZE__
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_INA)
ina ; Add 256 bytes safety area
.else
add #1 ; Add 256 bytes safety area

View File

@@ -8,8 +8,6 @@
.import addysp1
.importzp c_sp
.macpack cpu
; AX = TOS - AX
tossuba0:
@@ -17,7 +15,7 @@ tossuba0:
tossubax:
sec
eor #$FF
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
adc (c_sp)
ldy #1
.else

View File

@@ -8,8 +8,6 @@
.export swapstk
.importzp c_sp, ptr4
.macpack cpu
swapstk:
sta ptr4
stx ptr4+1
@@ -18,7 +16,7 @@ swapstk:
tax
lda ptr4+1
sta (c_sp),y
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
tay
lda ptr4

View File

@@ -8,14 +8,12 @@
.import incsp2
.importzp c_sp
.macpack cpu
; Convert TOS from long to int by cutting of the high 16bit
.proc tosint
pha
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
lda (c_sp)
.else
ldy #0

View File

@@ -8,8 +8,6 @@
.import decsp2
.importzp c_sp
.macpack cpu
; Convert TOS from int to long
tosulong:
@@ -17,7 +15,7 @@ tosulong:
jsr decsp2 ; Make room
ldy #2
lda (c_sp),y
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (c_sp) ; 65C02 version
iny ; Y = 3
.else
@@ -43,7 +41,7 @@ toslong:
jsr decsp2 ; Make room
ldy #2
lda (c_sp),y
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
sta (c_sp) ; 65C02 version
iny ; Y = 3
.else

View File

@@ -9,8 +9,6 @@
.include "zeropage.inc"
.macpack cpu
;---------------------------------------------------------------------------
; 8x16 => 24 unsigned multiplication routine. Because the overhead for a
; 8x16 => 16 unsigned multiplication routine is small, we will tag it with
@@ -31,7 +29,7 @@ umul8x16r16:
umul8x16r24m:
umul8x16r16m:
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_STZ)
stz ptr1+1
stz sreg
.else

View File

@@ -9,12 +9,10 @@
.import addysp1
.importzp c_sp, tmp1
.macpack cpu
tosxora0:
ldx #$00
tosxorax:
.if (.cpu .bitand CPU_ISET_65SC02)
.if .cap(CPU_HAS_ZPIND)
eor (c_sp)
ldy #1
.else

View File

@@ -9,8 +9,6 @@
.import __MAIN_START__
.import startup
.macpack cpu
.segment "EXEHDR"
.byte $73, $69, $6D, $36, $35 ; 'sim65'

View File

@@ -9,8 +9,6 @@
.import umul8x16r24
.import popa, popax
.macpack cpu
;-----------------------------------------------------------------------------
; void __fastcall__ tgi_settextstyle (unsigned width, unsigned height,
; unsigned char dir, unsigned char font);
@@ -82,7 +80,7 @@ process_onedim:
; Disallowing characters larger than 256 pixels, we just drop the high byte
; and remember the low 16 bit as size in 8.8 format.
.if (.cpu .bitand ::CPU_ISET_65SC02)
.if .cap(CPU_HAS_PUSHXY)
phy ; Save Y
jsr umul8x16r24
ply ; Restore Y

View File

@@ -37,6 +37,7 @@
#include <time.h>
/* common */
#include "capability.h"
#include "check.h"
#include "cpu.h"
#include "exprdefs.h"
@@ -60,6 +61,7 @@
#include "studyexpr.h"
#include "symbol.h"
#include "symtab.h"
#include "target.h"
#include "toklist.h"
#include "ulabel.h"
#include "macro.h"
@@ -405,6 +407,66 @@ static ExprNode* FuncBlank (void)
static ExprNode* FuncCapability (void)
/* Handle the .CAPABILITY builtin function */
{
int Result = 1;
/* What follows is a comma separated list of identifiers. An empty list is
** not allowed.
*/
while (1) {
const char* Name;
capability_t Cap;
/* We must have an identifier */
if (CurTok.Tok != TOK_IDENT) {
Error ("Arguments to .CAPABILITY must be identifiers");
/* Skip tokens until closing paren or end of line */
while (CurTok.Tok != TOK_RPAREN && !TokIsSep (CurTok.Tok)) {
NextTok ();
}
return GenLiteral0 ();
}
/* Search for the capability that matches this identifier. Ignore case
** on the specified capabilities.
*/
UpcaseSVal ();
SB_Terminate (&CurTok.SVal);
Name = SB_GetConstBuf (&CurTok.SVal);
Cap = FindCapability (Name);
/* Check if the capability is supported */
if (Cap == CAP_INVALID) {
Error ("Not a valid capability name: %s", Name);
Result = 0;
} else {
/* The pseudo function result is the logical AND of all capabilities
** given.
*/
if (!CPUHasCap (Cap) && !TargetHasCap (Cap)) {
Result = 0;
}
}
/* Skip the capability name */
NextTok ();
/* Handle end of list or next capability */
if (CurTok.Tok != TOK_COMMA) {
break;
}
NextTok ();
}
/* Done */
return GenLiteralExpr (Result);
}
static ExprNode* FuncConst (void)
/* Handle the .CONST builtin function */
{
@@ -484,9 +546,10 @@ static ExprNode* FuncIsMnemonic (void)
if (FindMacro (&CurTok.SVal) == 0) {
Instr = FindInstruction (&CurTok.SVal);
}
}
else {
/* Macros and symbols may NOT use the names of instructions, so just check for the instruction */
} else {
/* Macros and symbols may NOT use the names of instructions, so
** just check for the instruction.
*/
Instr = FindInstruction (&CurTok.SVal);
}
}
@@ -532,7 +595,7 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
token_t Term = GetTokListTerm (TOK_COMMA);
while (CurTok.Tok != Term) {
/* We may not end-of-line of end-of-file here */
/* We may not end-of-line or end-of-file here */
if (TokIsSep (CurTok.Tok)) {
Error ("Unexpected end of line");
return GenLiteral0 ();
@@ -570,7 +633,7 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
Node = Root;
while (CurTok.Tok != Term) {
/* We may not end-of-line of end-of-file here */
/* We may not end-of-line or end-of-file here */
if (TokIsSep (CurTok.Tok)) {
Error ("Unexpected end of line");
return GenLiteral0 ();
@@ -1129,6 +1192,10 @@ static ExprNode* Factor (void)
N = Function (FuncBlank);
break;
case TOK_CAP:
N = Function (FuncCapability);
break;
case TOK_CONST:
N = Function (FuncConst);
break;

View File

@@ -192,6 +192,45 @@ static void CBMSystem (const char* Sys)
static void DefineCpuSymbols (void)
/* Define all the symbols to evaluate .cpu. These were previously in cpu.mac. */
{
NewSymbol ("CPU_ISET_NONE", CPU_ISET_NONE);
NewSymbol ("CPU_ISET_6502", CPU_ISET_6502);
NewSymbol ("CPU_ISET_6502X", CPU_ISET_6502X);
NewSymbol ("CPU_ISET_6502DTV", CPU_ISET_6502DTV);
NewSymbol ("CPU_ISET_65SC02", CPU_ISET_65SC02);
NewSymbol ("CPU_ISET_65C02", CPU_ISET_65C02);
NewSymbol ("CPU_ISET_65816", CPU_ISET_65816);
NewSymbol ("CPU_ISET_SWEET16", CPU_ISET_SWEET16);
NewSymbol ("CPU_ISET_HUC6280", CPU_ISET_HUC6280);
NewSymbol ("CPU_ISET_M740", CPU_ISET_M740);
NewSymbol ("CPU_ISET_4510", CPU_ISET_4510);
NewSymbol ("CPU_ISET_45GS02", CPU_ISET_45GS02);
NewSymbol ("CPU_ISET_W65C02", CPU_ISET_W65C02);
NewSymbol ("CPU_ISET_65CE02", CPU_ISET_65CE02);
/* Additional ones from cpu.mac. Not sure how useful they are after the
** changes from #2751.
*/
NewSymbol ("CPU_NONE", CPUIsets[CPU_NONE]);
NewSymbol ("CPU_6502", CPUIsets[CPU_6502]);
NewSymbol ("CPU_6502X", CPUIsets[CPU_6502X]);
NewSymbol ("CPU_6502DTV", CPUIsets[CPU_6502DTV]);
NewSymbol ("CPU_65SC02", CPUIsets[CPU_65SC02]);
NewSymbol ("CPU_65C02", CPUIsets[CPU_65C02]);
NewSymbol ("CPU_65816", CPUIsets[CPU_65816]);
NewSymbol ("CPU_SWEET16", CPUIsets[CPU_SWEET16]);
NewSymbol ("CPU_HUC6280", CPUIsets[CPU_HUC6280]);
NewSymbol ("CPU_M740", CPUIsets[CPU_M740]);
NewSymbol ("CPU_4510", CPUIsets[CPU_4510]);
NewSymbol ("CPU_45GS02", CPUIsets[CPU_45GS02]);
NewSymbol ("CPU_W65C02", CPUIsets[CPU_W65C02]);
NewSymbol ("CPU_65CE02", CPUIsets[CPU_65CE02]);
}
static void SetSys (const char* Sys)
/* Define a target system */
{
@@ -363,6 +402,9 @@ static void SetSys (const char* Sys)
}
/* Define the symbols for evaluating .cpu */
DefineCpuSymbols ();
/* Initialize the translation tables for the target system */
TgtTranslateInit ();
}

View File

@@ -2114,7 +2114,8 @@ struct CtrlDesc {
};
/* NOTE: .AND, .BITAND, .BITNOT, .BITOR, .BITXOR, .MOD, .NOT, .OR, .SHL, .SHR
and .XOR do NOT go into this table */
** and .XOR do NOT go into this table.
*/
#define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoA16 }, /* .A16 */
@@ -2132,6 +2133,7 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoUnexpected }, /* .BLANK */
{ ccNone, DoBss }, /* .BSS */
{ ccNone, DoByte }, /* .BYT, .BYTE */
{ ccNone, DoUnexpected }, /* .CAP */
{ ccNone, DoCase }, /* .CASE */
{ ccNone, DoCharMap }, /* .CHARMAP */
{ ccNone, DoCode }, /* .CODE */

View File

@@ -158,6 +158,8 @@ struct DotKeyword {
{ ".BSS", TOK_BSS },
{ ".BYT", TOK_BYTE },
{ ".BYTE", TOK_BYTE },
{ ".CAP", TOK_CAP },
{ ".CAPABILITY", TOK_CAP },
{ ".CASE", TOK_CASE },
{ ".CHARMAP", TOK_CHARMAP },
{ ".CODE", TOK_CODE },

View File

@@ -137,6 +137,7 @@ typedef enum token_t {
TOK_BLANK,
TOK_BSS,
TOK_BYTE,
TOK_CAP,
TOK_CASE,
TOK_CHARMAP,
TOK_CODE,

View File

@@ -80,6 +80,7 @@
<ClInclude Include="common\assertion.h" />
<ClInclude Include="common\attrib.h" />
<ClInclude Include="common\bitops.h" />
<ClInclude Include="common\capability.h" />
<ClInclude Include="common\cddefs.h" />
<ClInclude Include="common\chartype.h" />
<ClInclude Include="common\check.h" />
@@ -133,6 +134,7 @@
<ClCompile Include="common\alignment.c" />
<ClCompile Include="common\assertion.c" />
<ClCompile Include="common\bitops.c" />
<ClCompile Include="common\capability.c" />
<ClCompile Include="common\chartype.c" />
<ClCompile Include="common\check.c" />
<ClCompile Include="common\cmdline.c" />
@@ -171,4 +173,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

91
src/common/capability.c Normal file
View File

@@ -0,0 +1,91 @@
/*****************************************************************************/
/* */
/* capability.c */
/* */
/* Handle CPU or target capabilities */
/* */
/* */
/* */
/* (C) 2026, Kugelfuhr */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdlib.h>
/* ca65 */
#include "capability.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* List of dot keywords with the corresponding ids. */
/* CAUTION: table must be sorted for bsearch. */
struct Capability {
const char* Key;
capability_t Cap;
} Capabilities [] = {
/* BEGIN SORTED.SH */
{ "CPU_HAS_BITIMM", CAP_CPU_HAS_BITIMM },
{ "CPU_HAS_BRA8", CAP_CPU_HAS_BRA8 },
{ "CPU_HAS_INA", CAP_CPU_HAS_INA },
{ "CPU_HAS_PUSHXY", CAP_CPU_HAS_PUSHXY },
{ "CPU_HAS_STZ", CAP_CPU_HAS_STZ },
{ "CPU_HAS_ZPIND", CAP_CPU_HAS_ZPIND },
/* END SORTED.SH */
};
#define CAP_TABLE_SIZE (sizeof (Capabilities) / sizeof (Capabilities [0]))
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static int CmpCapability (const void* K1, const void* K2)
/* Compare function for the capability search */
{
return strcmp (((struct Capability*)K1)->Key, ((struct Capability*)K2)->Key);
}
capability_t FindCapability (const char* Name)
/* Find the capability with the given name. Returns CAP_INVALID if there is no
** capability with the given name and a capability code >= 0 instead. The
** capability name is expected in upper case.
*/
{
const struct Capability K = { Name, 0 };
const struct Capability* C = bsearch (&K, Capabilities, CAP_TABLE_SIZE,
sizeof (Capabilities [0]),
CmpCapability);
return (C == 0)? CAP_INVALID : C->Cap;
}

79
src/common/capability.h Normal file
View File

@@ -0,0 +1,79 @@
/*****************************************************************************/
/* */
/* capability.h */
/* */
/* Handle CPU or target capabilities */
/* */
/* */
/* */
/* (C) 2026, Kugelfuhr */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef CAPABILITY_H
#define CAPABILITY_H
/* common */
#include "strbuf.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Numeric codes for capabilities */
enum capability_t {
CAP_INVALID = -1,
CAP_CPU_HAS_BRA8 = 0, /* CPU has a BRA 8-bit instruction */
CAP_CPU_HAS_INA = 1, /* CPU has DEA/INA */
CAP_CPU_HAS_PUSHXY = 2, /* CPU has PHX/PHY/PLX/PLY */
CAP_CPU_HAS_ZPIND = 3, /* CPU has "(zp)" mode (no offset) */
CAP_CPU_HAS_STZ = 4, /* CPU has "store zero" (!) instruction */
CAP_CPU_HAS_BITIMM = 5, /* CPU has "bit #imm" instruction */
};
typedef enum capability_t capability_t;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
capability_t FindCapability (const char* Name);
/* Find the capability with the given name. Returns CAP_INVALID if there is no
** capability with the given name and a capability code >= 0 instead. The
** capability name is expected in upper case.
*/
/* End of capability.h */
#endif

View File

@@ -33,6 +33,8 @@
#include <stdint.h>
/* common */
#include "addrsize.h"
#include "check.h"
@@ -72,24 +74,112 @@ const char* CPUNames[CPU_COUNT] = {
* NOTE: make sure to only combine the instruction sets that are 100% compatible
*/
const unsigned CPUIsets[CPU_COUNT] = {
/* CPU_NONE */
CPU_ISET_NONE,
/* CPU_6502 */
CPU_ISET_6502,
/* CPU_6502X */
CPU_ISET_6502X | CPU_ISET_6502,
/* CPU_6502DTV */
CPU_ISET_6502DTV | CPU_ISET_6502,
/* CPU_65SC02 */
CPU_ISET_65SC02 | CPU_ISET_6502,
/* CPU_65C02 */
CPU_ISET_65C02 | CPU_ISET_6502 | CPU_ISET_65SC02,
/* 65816 has wai/stp and NO bit manipulation */
/* CPU_65816. 65816 has wai/stp and NO bit manipulation. */
CPU_ISET_65816 | CPU_ISET_6502 | CPU_ISET_65SC02,
/* CPU_SWEET16 */
CPU_ISET_SWEET16,
/* CPU_HUC6280 */
CPU_ISET_HUC6280 | CPU_ISET_6502 | CPU_ISET_65SC02 | CPU_ISET_65C02,
/* CPU_M740 */
CPU_ISET_M740 | CPU_ISET_6502,
/* 4510 does NOT have indirect-zp (without z), so we can not use 65SC02 */
/* CPU_4510. 4510 does NOT have indirect-zp (without z), so we can not use 65SC02 */
CPU_ISET_4510 | CPU_ISET_6502 | CPU_ISET_65C02 | CPU_ISET_65CE02,
/* CPU_45GS02 */
CPU_ISET_45GS02 | CPU_ISET_6502 | CPU_ISET_65C02 | CPU_ISET_65CE02 | CPU_ISET_4510,
/* CPU_W65C02 */
CPU_ISET_W65C02 | CPU_ISET_6502 | CPU_ISET_65SC02 | CPU_ISET_65C02,
/* CPU_65CE02 */
CPU_ISET_65CE02 | CPU_ISET_6502 | CPU_ISET_65C02,
};
/* Defines for capabilities. Currently the entries are uint32_ts but the table
** is deliberately hidden from the outside so it can be extended to 64 bit or
** even more.
*/
#define CAP_BIT(Cap) (UINT32_C (1) << (Cap))
#define CAP_NONE UINT32_C (0)
#define CAP_6502 CAP_NONE
#define CAP_6502X CAP_NONE
#define CAP_6502DTV CAP_NONE
#define CAP_65SC02 \
(CAP_BIT (CAP_CPU_HAS_BITIMM) | \
CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY) | \
CAP_BIT (CAP_CPU_HAS_ZPIND) | \
CAP_BIT (CAP_CPU_HAS_STZ))
#define CAP_65C02 \
(CAP_BIT (CAP_CPU_HAS_BITIMM) | \
CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY) | \
CAP_BIT (CAP_CPU_HAS_ZPIND) | \
CAP_BIT (CAP_CPU_HAS_STZ))
#define CAP_65816 \
(CAP_BIT (CAP_CPU_HAS_BITIMM) | \
CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY) | \
CAP_BIT (CAP_CPU_HAS_ZPIND) | \
CAP_BIT (CAP_CPU_HAS_STZ))
#define CAP_SWEET16 CAP_NONE
#define CAP_HUC6280 \
(CAP_BIT (CAP_CPU_HAS_BITIMM) | \
CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY) | \
CAP_BIT (CAP_CPU_HAS_ZPIND) | \
CAP_BIT (CAP_CPU_HAS_STZ))
#define CAP_M740 \
(CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA))
#define CAP_4510 \
(CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY))
#define CAP_45GS02 \
(CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY))
#define CAP_W65C02 \
(CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY))
#define CAP_65CE02 \
(CAP_BIT (CAP_CPU_HAS_BRA8) | \
CAP_BIT (CAP_CPU_HAS_INA) | \
CAP_BIT (CAP_CPU_HAS_PUSHXY))
/* Table containing one capability entry per CPU */
static const uint32_t CPUCaps[CPU_COUNT] = {
CAP_NONE, /* CPU_NONE */
CAP_6502, /* CPU_6502 */
CAP_6502X, /* CPU_6502X */
CAP_6502DTV, /* CPU_6502DTV */
CAP_65SC02, /* CPU_65SC02 */
CAP_65C02, /* CPU_65C02 */
CAP_65816, /* CPU_65816 */
CAP_SWEET16, /* CPU_SWEET16 */
CAP_HUC6280, /* CPU_HUC6280 */
CAP_M740, /* CPU_M740 */
CAP_4510, /* CPU_4510 */
CAP_45GS02, /* CPU_45GS02 */
CAP_W65C02, /* CPU_W65C02 */
CAP_65CE02, /* CPU_65CE02 */
};
/*****************************************************************************/
@@ -148,3 +238,12 @@ cpu_t FindCPU (const char* Name)
/* Not found */
return CPU_UNKNOWN;
}
int CPUHasCap (capability_t Cap)
/* Check if the current CPU has the given capability */
{
PRECONDITION (CPU >= 0 && CPU < CPU_COUNT);
return (CPUCaps[CPU] & CAP_BIT (Cap)) != 0;
}

View File

@@ -38,6 +38,11 @@
/* common */
#include "capability.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
@@ -64,7 +69,7 @@ typedef enum {
CPU_COUNT /* Number of different CPUs */
} cpu_t;
/* CPU instruction sets (make sure this matches asminc/cpu.mac) */
/* CPU instruction sets */
enum {
CPU_ISET_NONE = 1 << CPU_NONE,
CPU_ISET_6502 = 1 << CPU_6502,
@@ -107,6 +112,9 @@ cpu_t FindCPU (const char* Name);
** the given name is no valid target.
*/
int CPUHasCap (capability_t Cap);
/* Check if the current CPU has the given capability */
/* End of cpu.h */

View File

@@ -37,6 +37,7 @@
#include <string.h>
/* common */
#include "attrib.h"
#include "chartype.h"
#include "check.h"
#include "target.h"
@@ -302,3 +303,12 @@ const char* GetTargetName (target_t Target)
/* Return the array entry */
return GetTargetProperties (Target)->Name;
}
int TargetHasCap (capability_t Cap attribute((unused)))
/* Check if the current target has the given capability */
{
/* Currently unused */
return 0;
}

View File

@@ -39,6 +39,7 @@
/* common */
#include "capability.h"
#include "cpu.h"
@@ -131,6 +132,9 @@ const TargetProperties* GetTargetProperties (target_t Target);
const char* GetTargetName (target_t Target);
/* Return the name of a target */
int TargetHasCap (capability_t Cap);
/* Check if the current target has the given capability */
/* End of target.h */

View File

@@ -0,0 +1,39 @@
; Error: Arguments to .CAPABILITY must be identifiers
.if .cap()
.endif
; Error: Arguments to .CAPABILITY must be identifiers
; Error: ')' expected
.if .cap(
.endif
; Error: Not a valid capability name: CPU_HAS_BR
.if .cap(cpu_has_br)
.endif
; Error: ')' expected
; Error: Unexpected trailing garbage characters
.if .cap(cpu_has_bra8 cpu_has_bra8)
.endif
; Ok
.if .cap(cpu_has_bra8, CPU_HAS_PUSHXY, CPU_HAS_STZ, CPU_HAS_INA)
.endif
.setcpu "65SC02"
.if !.cap(cpu_has_bra8)
.error "Assembler says 65SC02 has no 8 bit bra"
.endif
.if !.cap(cpu_has_PUSHXY)
.error "Assembler says 65SC02 has no phx"
.endif
.if !.cap(cpu_has_STZ)
.error "Assembler says 65SC02 has no stz"
.endif
.if !.cap(cpu_has_INA)
.error "Assembler says 65SC02 has no ina"
.endif

View File

@@ -0,0 +1,6 @@
110-capabilities.s:3: Error: Arguments to .CAPABILITY must be identifiers
110-capabilities.s:8: Error: Arguments to .CAPABILITY must be identifiers
110-capabilities.s:8: Error: ')' expected
110-capabilities.s:12: Error: Not a valid capability name: CPU_HAS_BR
110-capabilities.s:17: Error: ')' expected
110-capabilities.s:17: Error: Unexpected trailing garbage characters