mirror of
https://github.com/cc65/cc65.git
synced 2025-02-03 22:32:24 +00:00
commit
e5b08baf56
@ -172,7 +172,7 @@ ExprNode* FuncHiByte (void);
|
||||
/* Handle the .HIBYTE builtin function */
|
||||
|
||||
ExprNode* MakeBoundedExpr (ExprNode* Expr, unsigned Size);
|
||||
/* Force the given expression into a specific size of ForceRange is true */
|
||||
/* Force the given expression into a specific size if ForceRange is true */
|
||||
|
||||
ExprNode* BoundedExpr (ExprNode* (*ExprFunc) (void), unsigned Size);
|
||||
/* Parse an expression and force it within a given size if ForceRange is true */
|
||||
|
@ -417,7 +417,7 @@ void SegDone (void)
|
||||
if ((F->Len == 1 && ED.AddrSize > ADDR_SIZE_ZP) ||
|
||||
(F->Len == 2 && ED.AddrSize > ADDR_SIZE_ABS) ||
|
||||
(F->Len == 3 && ED.AddrSize > ADDR_SIZE_FAR)) {
|
||||
LIError (&F->LI, "Range error");
|
||||
LIError (&F->LI, "Range error (Address size %u does not match fragment size %u)", ED.AddrSize, F->Len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
|
||||
/* ca65 */
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "segment.h"
|
||||
#include "studyexpr.h"
|
||||
#include "symtab.h"
|
||||
@ -187,6 +188,70 @@ static void ED_MergeAddrSize (ExprDesc* ED, const ExprDesc* Right)
|
||||
}
|
||||
|
||||
|
||||
static void ED_MergeAddrSizeAND (ExprNode* Expr, ExprDesc* ED, const ExprDesc* Right)
|
||||
/* Merge the address sizes of two expressions into ED, special case for AND operator */
|
||||
{
|
||||
int ConstL, ConstR;
|
||||
int Size, ConstSize;
|
||||
long Val, ValR;
|
||||
|
||||
if (ED->AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* If ED is valid, ADDR_SIZE_DEFAULT gets always overridden, otherwise
|
||||
** it takes precedence over anything else.
|
||||
*/
|
||||
if (ED_IsValid (ED)) {
|
||||
ED->AddrSize = Right->AddrSize;
|
||||
}
|
||||
} else if (Right->AddrSize == ADDR_SIZE_DEFAULT) {
|
||||
/* If Right is valid, ADDR_SIZE_DEFAULT gets always overridden,
|
||||
** otherwise it takes precedence over anything else.
|
||||
*/
|
||||
if (!ED_IsValid (Right)) {
|
||||
ED->AddrSize = Right->AddrSize;
|
||||
}
|
||||
} else {
|
||||
/* Neither ED nor Right has a default address size, use the smaller of
|
||||
** the two.
|
||||
*/
|
||||
if (Right->AddrSize < ED->AddrSize) {
|
||||
ED->AddrSize = Right->AddrSize;
|
||||
}
|
||||
}
|
||||
/* Check if either side of the expression is constant */
|
||||
ConstL = IsConstExpr (Expr->Left, &Val);
|
||||
ConstR = IsConstExpr (Expr->Right, &ValR);
|
||||
if (!ConstL && !ConstR) {
|
||||
/* If neither part of the expression is constant, the above is all we can do */
|
||||
return;
|
||||
}
|
||||
/* We start assuming the left side is constant, left value is in Val, right
|
||||
size in Size */
|
||||
Size = Right->AddrSize;
|
||||
/* Now check if the right side is constant, and if so put the right value
|
||||
into Val and the Left size into Size. */
|
||||
if (ConstR) {
|
||||
Val = ValR;
|
||||
Size = ED->AddrSize;
|
||||
}
|
||||
/* Figure out the size of the constant value */
|
||||
if (IsByteRange (Val)) {
|
||||
ConstSize = ADDR_SIZE_ZP;
|
||||
} else if (IsWordRange (Val)) {
|
||||
ConstSize = ADDR_SIZE_ABS;
|
||||
} else if (IsFarRange (Val)) {
|
||||
ConstSize = ADDR_SIZE_FAR;
|
||||
} else {
|
||||
ConstSize = ADDR_SIZE_LONG;
|
||||
}
|
||||
|
||||
if (Size == ADDR_SIZE_DEFAULT) {
|
||||
ED->AddrSize = ConstSize;
|
||||
} else {
|
||||
/* use the smaller of the two sizes */
|
||||
ED->AddrSize = (ConstSize < Size) ? ConstSize : Size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ED_SymRef* ED_FindSymRef (ExprDesc* ED, SymEntry* Sym)
|
||||
/* Find a symbol reference and return it. Return NULL if the reference does
|
||||
@ -489,7 +554,11 @@ static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
|
||||
|
||||
/* Merge references and update address size */
|
||||
ED_MergeRefs (D, &Right);
|
||||
ED_MergeAddrSize (D, &Right);
|
||||
if (Expr->Op == EXPR_AND) {
|
||||
ED_MergeAddrSizeAND (Expr, D, &Right);
|
||||
} else {
|
||||
ED_MergeAddrSize (D, &Right);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ endif
|
||||
|
||||
WORKDIR = ../testwrk/asm
|
||||
|
||||
SUBDIRS = cpudetect opcodes listing
|
||||
SUBDIRS = cpudetect opcodes listing val err
|
||||
|
||||
.PHONY: all continue mostlyclean clean
|
||||
|
||||
|
45
test/asm/err/Makefile
Normal file
45
test/asm/err/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
# Makefile for the tests that MUST NOT compile
|
||||
|
||||
ifneq ($(shell echo),)
|
||||
CMD_EXE = 1
|
||||
endif
|
||||
|
||||
ifdef CMD_EXE
|
||||
S = $(subst /,\,/)
|
||||
NOT = - # Hack
|
||||
NULLDEV = nul:
|
||||
MKDIR = mkdir $(subst /,\,$1)
|
||||
RMDIR = -rmdir /s /q $(subst /,\,$1)
|
||||
else
|
||||
S = /
|
||||
NOT = !
|
||||
NULLDEV = /dev/null
|
||||
MKDIR = mkdir -p $1
|
||||
RMDIR = $(RM) -r $1
|
||||
endif
|
||||
|
||||
ifdef QUIET
|
||||
.SILENT:
|
||||
NULLERR = 2>$(NULLDEV)
|
||||
endif
|
||||
|
||||
CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
|
||||
|
||||
WORKDIR = ../../../testwrk/asm/err
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
SOURCES := $(wildcard *.s)
|
||||
TESTS = $(patsubst %.s,$(WORKDIR)/%.prg,$(SOURCES))
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
$(WORKDIR):
|
||||
$(call MKDIR,$(WORKDIR))
|
||||
|
||||
$(WORKDIR)/%.prg: %.s | $(WORKDIR)
|
||||
$(if $(QUIET),echo asm/err/$*.s)
|
||||
$(NOT) $(CA65) -o $@ $< $(NULLERR)
|
||||
|
||||
clean:
|
||||
@$(call RMDIR,$(WORKDIR))
|
3
test/asm/err/bug1538-1.s
Normal file
3
test/asm/err/bug1538-1.s
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
; this should produce a range error
|
||||
.byte $1234 & $ffff
|
@ -17,3 +17,16 @@ Overall tests:
|
||||
--------------
|
||||
|
||||
These go into listing/. Refer to listing/readme.txt
|
||||
|
||||
val:
|
||||
----
|
||||
|
||||
Works very much like the /val directory used to test the compiler - individual
|
||||
tests are run in the simulator and should exit with an exit code of 0 when they
|
||||
pass, or either -1 or a number indicating what part of the test failed on error.
|
||||
|
||||
err:
|
||||
----
|
||||
|
||||
Works very much like the /err directory used to test the compiler - individual
|
||||
tests are assembled and MUST NOT assemble without error.
|
||||
|
58
test/asm/val/Makefile
Normal file
58
test/asm/val/Makefile
Normal file
@ -0,0 +1,58 @@
|
||||
# Makefile for the regression tests that return an error code on failure
|
||||
|
||||
ifneq ($(shell echo),)
|
||||
CMD_EXE = 1
|
||||
endif
|
||||
|
||||
ifdef CMD_EXE
|
||||
S = $(subst /,\,/)
|
||||
NULLDEV = nul:
|
||||
MKDIR = mkdir $(subst /,\,$1)
|
||||
RMDIR = -rmdir /s /q $(subst /,\,$1)
|
||||
else
|
||||
S = /
|
||||
NULLDEV = /dev/null
|
||||
MKDIR = mkdir -p $1
|
||||
RMDIR = $(RM) -r $1
|
||||
endif
|
||||
|
||||
ifdef QUIET
|
||||
.SILENT:
|
||||
NULLOUT = >$(NULLDEV)
|
||||
NULLERR = 2>$(NULLDEV)
|
||||
endif
|
||||
|
||||
SIM65FLAGS = -x 5000000000
|
||||
|
||||
CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
|
||||
LD65 := $(if $(wildcard ../../../bin/ld65*),..$S..$S..$Sbin$Sld65,ld65)
|
||||
SIM65 := $(if $(wildcard ../../../bin/sim65*),..$S..$S..$Sbin$Ssim65,sim65)
|
||||
|
||||
WORKDIR = ../../../testwrk/asm/val
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
SOURCES := $(wildcard *.s)
|
||||
TESTS = $(SOURCES:%.s=$(WORKDIR)/%.6502.prg)
|
||||
TESTS += $(SOURCES:%.s=$(WORKDIR)/%.65c02.prg)
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
$(WORKDIR):
|
||||
$(call MKDIR,$(WORKDIR))
|
||||
|
||||
define PRG_template
|
||||
|
||||
$(WORKDIR)/%.$1.prg: %.s | $(WORKDIR)
|
||||
$(if $(QUIET),echo asm/val/$$*.$1.prg)
|
||||
$(CA65) -t sim$1 -o $$(@:.prg=.o) $$< $(NULLERR)
|
||||
$(LD65) -C sim6502-asmtest.cfg -o $$@ $$(@:.prg=.o) sim$1.lib $(NULLERR)
|
||||
$(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT)
|
||||
|
||||
endef # PRG_template
|
||||
|
||||
$(eval $(call PRG_template,6502))
|
||||
$(eval $(call PRG_template,65c02))
|
||||
|
||||
clean:
|
||||
@$(call RMDIR,$(WORKDIR))
|
122
test/asm/val/bug1538.s
Normal file
122
test/asm/val/bug1538.s
Normal file
@ -0,0 +1,122 @@
|
||||
|
||||
.macpack longbranch
|
||||
|
||||
.import _exit
|
||||
.export _main
|
||||
|
||||
offset1 = ($123456 + ((.bank(_main)) * $2345)) ; should produce $123456 + ($23 * $2345) = 1706c5
|
||||
|
||||
_main:
|
||||
ldx #1 ; test counter
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
; first check if we can still force an 16bit address although we are
|
||||
; ANDing with a 8bit value
|
||||
test1:
|
||||
test1a: bit a:$1234 & $ff ; should produce 00 34
|
||||
lda test1a+1
|
||||
cmp #$34
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test1a+2
|
||||
cmp #$00
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
test1b: bit a:$34 & $ff ; should produce 00 34
|
||||
lda test1b+1
|
||||
cmp #$34
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test1b+2
|
||||
cmp #$00
|
||||
jne exiterror
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
; the original bug report, use an expression that contains a non constant
|
||||
; part (.bank(_main)) and limit it to 8bit size by ANDing with $ff
|
||||
test2:
|
||||
inx
|
||||
lda #(offset1 >> 0) & $ff
|
||||
cmp #$c5
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda #(offset1 >> 8) & $ff
|
||||
cmp #$06
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda #(offset1 >> 16) & $ff
|
||||
cmp #$17
|
||||
jne exiterror
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
; import a zeropage symbol (1 byte size) and then AND with a constant
|
||||
; 16bit value - it should not turn into a 16bit address
|
||||
test3:
|
||||
jmp test3chk
|
||||
.importzp tmp1
|
||||
test3a: .byte tmp1 ; verify its 8bit
|
||||
test3b: .byte tmp1 & $ff ; AND with $ff should work of course
|
||||
test3c: .byte tmp1 & $ffff ; AND with $ffff should not change size
|
||||
test3d: .byte tmp1 & $ffffff ; AND with $ffffff should not change size
|
||||
test3e: .byte tmp1 & $ffffffff ; AND with $ffffffff should not change size
|
||||
test3f: .word tmp1 & $ffffff ; AND with $ffffff should not change size
|
||||
test3g: .word tmp1 & $ffffffff ; AND with $ffffffff should not change size
|
||||
test3chk:
|
||||
inx
|
||||
lda test3a
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3b
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3c
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3d
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3e
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3f
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3f+1
|
||||
cmp #$00
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3g
|
||||
cmp #tmp1
|
||||
jne exiterror
|
||||
|
||||
inx
|
||||
lda test3g+1
|
||||
cmp #$00
|
||||
jne exiterror
|
||||
|
||||
;---------------------------------------------------------------------
|
||||
; exit OK
|
||||
ldx #0
|
||||
exiterror:
|
||||
txa
|
||||
ldx #0
|
||||
jmp _exit
|
||||
|
35
test/asm/val/sim6502-asmtest.cfg
Normal file
35
test/asm/val/sim6502-asmtest.cfg
Normal file
@ -0,0 +1,35 @@
|
||||
SYMBOLS {
|
||||
__EXEHDR__: type = import;
|
||||
__STACKSIZE__: type = weak, value = $0800; # 2k stack
|
||||
}
|
||||
MEMORY {
|
||||
ZP: file = "", start = $0000, size = $0100;
|
||||
HEADER: file = %O, start = $0000, size = $000C;
|
||||
MAIN: file = %O, define = yes, start = $0200, size = $FDF0 - __STACKSIZE__, BANK = $23;
|
||||
}
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
EXEHDR: load = HEADER, type = ro;
|
||||
STARTUP: load = MAIN, type = ro;
|
||||
LOWCODE: load = MAIN, type = ro, optional = yes;
|
||||
ONCE: load = MAIN, type = ro, optional = yes;
|
||||
CODE: load = MAIN, type = ro;
|
||||
RODATA: load = MAIN, type = ro;
|
||||
DATA: load = MAIN, type = rw;
|
||||
BSS: load = MAIN, type = bss, define = yes;
|
||||
}
|
||||
FEATURES {
|
||||
CONDES: type = constructor,
|
||||
label = __CONSTRUCTOR_TABLE__,
|
||||
count = __CONSTRUCTOR_COUNT__,
|
||||
segment = ONCE;
|
||||
CONDES: type = destructor,
|
||||
label = __DESTRUCTOR_TABLE__,
|
||||
count = __DESTRUCTOR_COUNT__,
|
||||
segment = RODATA;
|
||||
CONDES: type = interruptor,
|
||||
label = __INTERRUPTOR_TABLE__,
|
||||
count = __INTERRUPTOR_COUNT__,
|
||||
segment = RODATA,
|
||||
import = __CALLIRQ__;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user