mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 20:02:27 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4bca5fe47 | ||
|
|
a1729b65ab | ||
|
|
2950d26c8e | ||
|
|
4f8d4a9585 | ||
|
|
d787795759 | ||
|
|
cf74e73e27 | ||
|
|
2770254fd9 | ||
|
|
de04bd8cfa | ||
|
|
076a547f91 | ||
|
|
dffd0a2706 | ||
|
|
6c66f86103 | ||
|
|
26502c949a | ||
|
|
8dfe510883 | ||
|
|
96ba9f5902 | ||
|
|
3a6ba0ab71 | ||
|
|
32d894d6b6 | ||
|
|
543efa4299 | ||
|
|
eba0708099 | ||
|
|
51e6bf0d45 | ||
|
|
07b5c44a54 | ||
|
|
9fe32c1c34 | ||
|
|
0e0278c84a | ||
|
|
dea775a9cd | ||
|
|
7e3e18a5c7 | ||
|
|
8e3ebc84f0 |
No files matched your search
@@ -23,13 +23,14 @@ https://prog8.readthedocs.io/
|
||||
What does Prog8 provide?
|
||||
------------------------
|
||||
|
||||
- big reduction of source code length over raw assembly
|
||||
- reduction of source code length over raw assembly
|
||||
- modularity, symbol scoping, subroutines
|
||||
- various data types other than just bytes (16-bit words, floats, strings)
|
||||
- automatic variable allocations, automatic string and array variables and string sharing
|
||||
- subroutines with an input- and output parameter signature
|
||||
- no stack frame allocations because parameters and local variables are automatically allocated statically
|
||||
- constant folding in expressions and other high-level program optimizations
|
||||
- subroutines with input parameters and result values
|
||||
- high-level program optimizations
|
||||
- small program boilerplate/compilersupport overhead
|
||||
- sane variable initialization, programs can be restarted again just fine after exiting to basic
|
||||
- conditional branches
|
||||
- floating point operations (requires the C64 Basic ROM routines for this)
|
||||
- 'when' statement to provide a concise jump table alternative to if/elseif chains
|
||||
@@ -38,8 +39,10 @@ What does Prog8 provide?
|
||||
- various powerful built-in libraries to do I/O, number conversions, graphics and more
|
||||
- convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses
|
||||
- fast execution speed due to compilation to native assembly code
|
||||
- variables are allocated statically
|
||||
- inline assembly allows you to have full control when every cycle or byte matters
|
||||
- supports the sixteen 'virtual' 16-bit registers R0 .. R15 from the Commander X16, and provides them also on the C64.
|
||||
- encode strings and characters into petscii or screencodes as desired (C64/Cx16)
|
||||
|
||||
*Rapid edit-compile-run-debug cycle:*
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
%import textio
|
||||
|
||||
; bitmap pixel graphics module for the C64
|
||||
; only black/white monchrome 320x200 for now
|
||||
; only black/white monochrome 320x200 for now
|
||||
; assumes bitmap screen memory is $2000-$3fff
|
||||
|
||||
graphics {
|
||||
|
||||
+435
-222
@@ -7,239 +7,213 @@ conv {
|
||||
|
||||
; ----- number conversions to decimal strings ----
|
||||
|
||||
asmsub ubyte2decimal (ubyte value @A) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||
; ---- A to decimal string in Y/A/X (100s in Y, 10s in A, 1s in X)
|
||||
str string_out = "????????????????" ; result buffer for the string conversion routines
|
||||
|
||||
asmsub str_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||
; ---- convert the ubyte in A in decimal string form, with left padding 0s (3 positions total)
|
||||
%asm {{
|
||||
ldy #uword2decimal.ASCII_0_OFFSET
|
||||
bne uword2decimal.hex_try200
|
||||
rts
|
||||
phx
|
||||
jsr conv.ubyte2decimal
|
||||
sty string_out
|
||||
sta string_out+1
|
||||
stx string_out+2
|
||||
lda #0
|
||||
sta string_out+3
|
||||
plx
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub uword2decimal (uword value @AY) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||
; ---- convert 16 bit uword in A/Y to decimal
|
||||
; output in uword2decimal.decTenThousands, decThousands, decHundreds, decTens, decOnes
|
||||
; (these are terminated by a zero byte so they can be easily printed)
|
||||
; also returns Y = 100's, A = 10's, X = 1's
|
||||
|
||||
asmsub str_ub (ubyte value @ A) clobbers(A,Y) {
|
||||
; ---- convert the ubyte in A in decimal string form, without left padding 0s
|
||||
%asm {{
|
||||
|
||||
;Convert 16 bit Hex to Decimal (0-65535) Rev 2
|
||||
;By Omegamatrix Further optimizations by tepples
|
||||
; routine from http://forums.nesdev.com/viewtopic.php?f=2&t=11341&start=15
|
||||
|
||||
;HexToDec99
|
||||
; start in A
|
||||
; end with A = 10's, decOnes (also in X)
|
||||
|
||||
;HexToDec255
|
||||
; start in A
|
||||
; end with Y = 100's, A = 10's, decOnes (also in X)
|
||||
|
||||
;HexToDec999
|
||||
; start with A = high byte, Y = low byte
|
||||
; end with Y = 100's, A = 10's, decOnes (also in X)
|
||||
; requires 1 extra temp register on top of decOnes, could combine
|
||||
; these two if HexToDec65535 was eliminated...
|
||||
|
||||
;HexToDec65535
|
||||
; start with A/Y (low/high) as 16 bit value
|
||||
; end with decTenThousand, decThousand, Y = 100's, A = 10's, decOnes (also in X)
|
||||
; (irmen: I store Y and A in decHundreds and decTens too, so all of it can be easily printed)
|
||||
|
||||
|
||||
ASCII_0_OFFSET = $30
|
||||
temp = P8ZP_SCRATCH_B1 ; byte in zeropage
|
||||
hexHigh = P8ZP_SCRATCH_W1 ; byte in zeropage
|
||||
hexLow = P8ZP_SCRATCH_W1+1 ; byte in zeropage
|
||||
|
||||
|
||||
HexToDec65535; SUBROUTINE
|
||||
sty hexHigh ;3 @9
|
||||
sta hexLow ;3 @12
|
||||
tya
|
||||
tax ;2 @14
|
||||
lsr a ;2 @16
|
||||
lsr a ;2 @18 integer divide 1024 (result 0-63)
|
||||
|
||||
cpx #$A7 ;2 @20 account for overflow of multiplying 24 from 43,000 ($A7F8) onward,
|
||||
adc #1 ;2 @22 we can just round it to $A700, and the divide by 1024 is fine...
|
||||
|
||||
;at this point we have a number 1-65 that we have to times by 24,
|
||||
;add to original sum, and Mod 1024 to get a remainder 0-999
|
||||
|
||||
|
||||
sta temp ;3 @25
|
||||
asl a ;2 @27
|
||||
adc temp ;3 @30 x3
|
||||
tay ;2 @32
|
||||
lsr a ;2 @34
|
||||
lsr a ;2 @36
|
||||
lsr a ;2 @38
|
||||
lsr a ;2 @40
|
||||
lsr a ;2 @42
|
||||
tax ;2 @44
|
||||
tya ;2 @46
|
||||
asl a ;2 @48
|
||||
asl a ;2 @50
|
||||
asl a ;2 @52
|
||||
clc ;2 @54
|
||||
adc hexLow ;3 @57
|
||||
sta hexLow ;3 @60
|
||||
txa ;2 @62
|
||||
adc hexHigh ;3 @65
|
||||
sta hexHigh ;3 @68
|
||||
ror a ;2 @70
|
||||
lsr a ;2 @72
|
||||
tay ;2 @74 integer divide 1,000 (result 0-65)
|
||||
|
||||
lsr a ;2 @76 split the 1,000 and 10,000 digit
|
||||
tax ;2 @78
|
||||
lda ShiftedBcdTab,x ;4 @82
|
||||
tax ;2 @84
|
||||
rol a ;2 @86
|
||||
and #$0F ;2 @88
|
||||
ora #ASCII_0_OFFSET
|
||||
sta decThousands ;3 @91
|
||||
txa ;2 @93
|
||||
lsr a ;2 @95
|
||||
lsr a ;2 @97
|
||||
lsr a ;2 @99
|
||||
ora #ASCII_0_OFFSET
|
||||
sta decTenThousands ;3 @102
|
||||
|
||||
lda hexLow ;3 @105
|
||||
cpy temp ;3 @108
|
||||
bmi _doSubtract ;2³ @110/111
|
||||
beq _useZero ;2³ @112/113
|
||||
adc #23 + 24 ;2 @114
|
||||
_doSubtract
|
||||
sbc #23 ;2 @116
|
||||
sta hexLow ;3 @119
|
||||
_useZero
|
||||
lda hexHigh ;3 @122
|
||||
sbc #0 ;2 @124
|
||||
|
||||
Start100s
|
||||
and #$03 ;2 @126
|
||||
tax ;2 @128 0,1,2,3
|
||||
cmp #2 ;2 @130
|
||||
rol a ;2 @132 0,2,5,7
|
||||
ora #ASCII_0_OFFSET
|
||||
tay ;2 @134 Y = Hundreds digit
|
||||
|
||||
lda hexLow ;3 @137
|
||||
adc Mod100Tab,x ;4 @141 adding remainder of 256, 512, and 256+512 (all mod 100)
|
||||
bcs hex_doSub200 ;2³ @143/144
|
||||
|
||||
hex_try200
|
||||
cmp #200 ;2 @145
|
||||
bcc hex_try100 ;2³ @147/148
|
||||
hex_doSub200
|
||||
iny ;2 @149
|
||||
iny ;2 @151
|
||||
sbc #200 ;2 @153
|
||||
hex_try100
|
||||
cmp #100 ;2 @155
|
||||
bcc HexToDec99 ;2³ @157/158
|
||||
iny ;2 @159
|
||||
sbc #100 ;2 @161
|
||||
|
||||
HexToDec99; SUBROUTINE
|
||||
lsr a ;2 @163
|
||||
tax ;2 @165
|
||||
lda ShiftedBcdTab,x ;4 @169
|
||||
tax ;2 @171
|
||||
rol a ;2 @173
|
||||
and #$0F ;2 @175
|
||||
ora #ASCII_0_OFFSET
|
||||
sta decOnes ;3 @178
|
||||
txa ;2 @180
|
||||
lsr a ;2 @182
|
||||
lsr a ;2 @184
|
||||
lsr a ;2 @186
|
||||
ora #ASCII_0_OFFSET
|
||||
|
||||
; irmen: load X with ones, and store Y and A too, for easy printing afterwards
|
||||
sty decHundreds
|
||||
sta decTens
|
||||
ldx decOnes
|
||||
rts ;6 @192 Y=hundreds, A = tens digit, X=ones digit
|
||||
|
||||
|
||||
HexToDec999; SUBROUTINE
|
||||
sty hexLow ;3 @9
|
||||
jmp Start100s ;3 @12
|
||||
|
||||
Mod100Tab
|
||||
.byte 0,56,12,56+12
|
||||
|
||||
ShiftedBcdTab
|
||||
.byte $00,$01,$02,$03,$04,$08,$09,$0A,$0B,$0C
|
||||
.byte $10,$11,$12,$13,$14,$18,$19,$1A,$1B,$1C
|
||||
.byte $20,$21,$22,$23,$24,$28,$29,$2A,$2B,$2C
|
||||
.byte $30,$31,$32,$33,$34,$38,$39,$3A,$3B,$3C
|
||||
.byte $40,$41,$42,$43,$44,$48,$49,$4A,$4B,$4C
|
||||
|
||||
decTenThousands .byte 0
|
||||
decThousands .byte 0
|
||||
decHundreds .byte 0
|
||||
decTens .byte 0
|
||||
decOnes .byte 0
|
||||
.byte 0 ; zero-terminate the decimal output string
|
||||
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||
; ---- A (signed byte) to decimal string in Y/A/X (100s in Y, 10s in A, 1s in X)
|
||||
; note: if the number is negative, you have to deal with the '-' yourself!
|
||||
%asm {{
|
||||
cmp #0
|
||||
bpl +
|
||||
eor #255
|
||||
clc
|
||||
adc #1
|
||||
+ jmp ubyte2decimal
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub ubyte2hex (ubyte value @A) -> ubyte @A, ubyte @Y {
|
||||
; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG
|
||||
phx
|
||||
ldy #0
|
||||
sty P8ZP_SCRATCH_B1
|
||||
jsr conv.ubyte2decimal
|
||||
_output_byte_digits
|
||||
; hundreds?
|
||||
cpy #'0'
|
||||
beq +
|
||||
pha
|
||||
and #$0f
|
||||
tax
|
||||
ldy _hex_digits,x
|
||||
tya
|
||||
ldy P8ZP_SCRATCH_B1
|
||||
sta string_out,y
|
||||
pla
|
||||
lsr a
|
||||
lsr a
|
||||
lsr a
|
||||
lsr a
|
||||
tax
|
||||
lda _hex_digits,x
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
|
||||
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||
inc P8ZP_SCRATCH_B1
|
||||
; tens?
|
||||
+ ldy P8ZP_SCRATCH_B1
|
||||
cmp #'0'
|
||||
beq +
|
||||
sta string_out,y
|
||||
iny
|
||||
+ ; ones.
|
||||
txa
|
||||
sta string_out,y
|
||||
iny
|
||||
lda #0
|
||||
sta string_out,y
|
||||
plx
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub uword2hex (uword value @AY) clobbers(A,Y) {
|
||||
; ---- convert 16 bit uword in A/Y into 4-character hexadecimal string 'uword2hex.output' (0-terminated)
|
||||
asmsub str_b (byte value @ A) clobbers(A,Y) {
|
||||
; ---- convert the byte in A in decimal string form, without left padding 0s
|
||||
%asm {{
|
||||
sta P8ZP_SCRATCH_REG
|
||||
tya
|
||||
jsr ubyte2hex
|
||||
sta output
|
||||
sty output+1
|
||||
lda P8ZP_SCRATCH_REG
|
||||
jsr ubyte2hex
|
||||
sta output+2
|
||||
sty output+3
|
||||
rts
|
||||
output .text "0000", $00 ; 0-terminated output buffer (to make printing easier)
|
||||
phx
|
||||
ldy #0
|
||||
sty P8ZP_SCRATCH_B1
|
||||
cmp #0
|
||||
bpl +
|
||||
pha
|
||||
lda #'-'
|
||||
sta string_out
|
||||
inc P8ZP_SCRATCH_B1
|
||||
pla
|
||||
+ jsr conv.byte2decimal
|
||||
bra str_ub._output_byte_digits
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_ubhex (ubyte value @ A) clobbers(A,Y) {
|
||||
; ---- convert the ubyte in A in hex string form
|
||||
%asm {{
|
||||
jsr conv.ubyte2hex
|
||||
sta string_out
|
||||
sty string_out+1
|
||||
lda #0
|
||||
sta string_out+2
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_ubbin (ubyte value @ A) clobbers(A,Y) {
|
||||
; ---- convert the ubyte in A in binary string form
|
||||
%asm {{
|
||||
sta P8ZP_SCRATCH_B1
|
||||
ldy #0
|
||||
sty string_out+8
|
||||
ldy #7
|
||||
- lsr P8ZP_SCRATCH_B1
|
||||
bcc +
|
||||
lda #'1'
|
||||
bne _digit
|
||||
+ lda #'0'
|
||||
_digit sta string_out,y
|
||||
dey
|
||||
bpl -
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_uwbin (uword value @ AY) clobbers(A,Y) {
|
||||
; ---- convert the uword in A/Y in binary string form
|
||||
%asm {{
|
||||
sta P8ZP_SCRATCH_REG
|
||||
tya
|
||||
jsr str_ubbin
|
||||
ldy #0
|
||||
sty string_out+16
|
||||
ldy #7
|
||||
- lsr P8ZP_SCRATCH_REG
|
||||
bcc +
|
||||
lda #'1'
|
||||
bne _digit
|
||||
+ lda #'0'
|
||||
_digit sta string_out+8,y
|
||||
dey
|
||||
bpl -
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_uwhex (uword value @ AY) clobbers(A,Y) {
|
||||
; ---- convert the uword in A/Y in hexadecimal string form (4 digits)
|
||||
%asm {{
|
||||
pha
|
||||
tya
|
||||
jsr conv.ubyte2hex
|
||||
sta string_out
|
||||
sty string_out+1
|
||||
pla
|
||||
jsr conv.ubyte2hex
|
||||
sta string_out+2
|
||||
sty string_out+3
|
||||
lda #0
|
||||
sta string_out+4
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||
; ---- convert the uword in A/Y in decimal string form, with left padding 0s (5 positions total)
|
||||
%asm {{
|
||||
phx
|
||||
jsr conv.uword2decimal
|
||||
ldy #0
|
||||
- lda conv.uword2decimal.decTenThousands,y
|
||||
sta string_out,y
|
||||
beq +
|
||||
iny
|
||||
bne -
|
||||
+ plx
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_uw (uword value @ AY) clobbers(A,Y) {
|
||||
; ---- convert the uword in A/Y in decimal string form, without left padding 0s
|
||||
%asm {{
|
||||
phx
|
||||
jsr conv.uword2decimal
|
||||
ldx #0
|
||||
_output_digits
|
||||
ldy #0
|
||||
- lda conv.uword2decimal.decTenThousands,y
|
||||
beq _allzero
|
||||
cmp #'0'
|
||||
bne _gotdigit
|
||||
iny
|
||||
bne -
|
||||
_gotdigit sta string_out,x
|
||||
inx
|
||||
iny
|
||||
lda conv.uword2decimal.decTenThousands,y
|
||||
bne _gotdigit
|
||||
_end lda #0
|
||||
sta string_out,x
|
||||
plx
|
||||
rts
|
||||
|
||||
_allzero lda #'0'
|
||||
sta string_out,x
|
||||
inx
|
||||
bne _end
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub str_w (word value @ AY) clobbers(A,Y) {
|
||||
; ---- convert the (signed) word in A/Y in decimal string form, without left padding 0's
|
||||
%asm {{
|
||||
cpy #0
|
||||
bpl str_uw
|
||||
phx
|
||||
pha
|
||||
lda #'-'
|
||||
sta string_out
|
||||
tya
|
||||
eor #255
|
||||
tay
|
||||
pla
|
||||
eor #255
|
||||
clc
|
||||
adc #1
|
||||
bcc +
|
||||
iny
|
||||
+ jsr conv.uword2decimal
|
||||
ldx #1
|
||||
bne str_uw._output_digits
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -520,4 +494,243 @@ _stop
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
; ----- low level number conversions to decimal strings ----
|
||||
|
||||
asmsub ubyte2decimal (ubyte value @A) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||
; ---- A to decimal string in Y/A/X (100s in Y, 10s in A, 1s in X)
|
||||
%asm {{
|
||||
ldy #uword2decimal.ASCII_0_OFFSET
|
||||
bne uword2decimal.hex_try200
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub uword2decimal (uword value @AY) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||
; ---- convert 16 bit uword in A/Y to decimal
|
||||
; output in uword2decimal.decTenThousands, decThousands, decHundreds, decTens, decOnes
|
||||
; (these are terminated by a zero byte so they can be easily printed)
|
||||
; also returns Y = 100's, A = 10's, X = 1's
|
||||
|
||||
%asm {{
|
||||
|
||||
;Convert 16 bit Hex to Decimal (0-65535) Rev 2
|
||||
;By Omegamatrix Further optimizations by tepples
|
||||
; routine from http://forums.nesdev.com/viewtopic.php?f=2&t=11341&start=15
|
||||
|
||||
;HexToDec99
|
||||
; start in A
|
||||
; end with A = 10's, decOnes (also in X)
|
||||
|
||||
;HexToDec255
|
||||
; start in A
|
||||
; end with Y = 100's, A = 10's, decOnes (also in X)
|
||||
|
||||
;HexToDec999
|
||||
; start with A = high byte, Y = low byte
|
||||
; end with Y = 100's, A = 10's, decOnes (also in X)
|
||||
; requires 1 extra temp register on top of decOnes, could combine
|
||||
; these two if HexToDec65535 was eliminated...
|
||||
|
||||
;HexToDec65535
|
||||
; start with A/Y (low/high) as 16 bit value
|
||||
; end with decTenThousand, decThousand, Y = 100's, A = 10's, decOnes (also in X)
|
||||
; (irmen: I store Y and A in decHundreds and decTens too, so all of it can be easily printed)
|
||||
|
||||
|
||||
ASCII_0_OFFSET = $30
|
||||
temp = P8ZP_SCRATCH_B1 ; byte in zeropage
|
||||
hexHigh = P8ZP_SCRATCH_W1 ; byte in zeropage
|
||||
hexLow = P8ZP_SCRATCH_W1+1 ; byte in zeropage
|
||||
|
||||
|
||||
HexToDec65535; SUBROUTINE
|
||||
sty hexHigh ;3 @9
|
||||
sta hexLow ;3 @12
|
||||
tya
|
||||
tax ;2 @14
|
||||
lsr a ;2 @16
|
||||
lsr a ;2 @18 integer divide 1024 (result 0-63)
|
||||
|
||||
cpx #$A7 ;2 @20 account for overflow of multiplying 24 from 43,000 ($A7F8) onward,
|
||||
adc #1 ;2 @22 we can just round it to $A700, and the divide by 1024 is fine...
|
||||
|
||||
;at this point we have a number 1-65 that we have to times by 24,
|
||||
;add to original sum, and Mod 1024 to get a remainder 0-999
|
||||
|
||||
|
||||
sta temp ;3 @25
|
||||
asl a ;2 @27
|
||||
adc temp ;3 @30 x3
|
||||
tay ;2 @32
|
||||
lsr a ;2 @34
|
||||
lsr a ;2 @36
|
||||
lsr a ;2 @38
|
||||
lsr a ;2 @40
|
||||
lsr a ;2 @42
|
||||
tax ;2 @44
|
||||
tya ;2 @46
|
||||
asl a ;2 @48
|
||||
asl a ;2 @50
|
||||
asl a ;2 @52
|
||||
clc ;2 @54
|
||||
adc hexLow ;3 @57
|
||||
sta hexLow ;3 @60
|
||||
txa ;2 @62
|
||||
adc hexHigh ;3 @65
|
||||
sta hexHigh ;3 @68
|
||||
ror a ;2 @70
|
||||
lsr a ;2 @72
|
||||
tay ;2 @74 integer divide 1,000 (result 0-65)
|
||||
|
||||
lsr a ;2 @76 split the 1,000 and 10,000 digit
|
||||
tax ;2 @78
|
||||
lda ShiftedBcdTab,x ;4 @82
|
||||
tax ;2 @84
|
||||
rol a ;2 @86
|
||||
and #$0F ;2 @88
|
||||
ora #ASCII_0_OFFSET
|
||||
sta decThousands ;3 @91
|
||||
txa ;2 @93
|
||||
lsr a ;2 @95
|
||||
lsr a ;2 @97
|
||||
lsr a ;2 @99
|
||||
ora #ASCII_0_OFFSET
|
||||
sta decTenThousands ;3 @102
|
||||
|
||||
lda hexLow ;3 @105
|
||||
cpy temp ;3 @108
|
||||
bmi _doSubtract ;2³ @110/111
|
||||
beq _useZero ;2³ @112/113
|
||||
adc #23 + 24 ;2 @114
|
||||
_doSubtract
|
||||
sbc #23 ;2 @116
|
||||
sta hexLow ;3 @119
|
||||
_useZero
|
||||
lda hexHigh ;3 @122
|
||||
sbc #0 ;2 @124
|
||||
|
||||
Start100s
|
||||
and #$03 ;2 @126
|
||||
tax ;2 @128 0,1,2,3
|
||||
cmp #2 ;2 @130
|
||||
rol a ;2 @132 0,2,5,7
|
||||
ora #ASCII_0_OFFSET
|
||||
tay ;2 @134 Y = Hundreds digit
|
||||
|
||||
lda hexLow ;3 @137
|
||||
adc Mod100Tab,x ;4 @141 adding remainder of 256, 512, and 256+512 (all mod 100)
|
||||
bcs hex_doSub200 ;2³ @143/144
|
||||
|
||||
hex_try200
|
||||
cmp #200 ;2 @145
|
||||
bcc hex_try100 ;2³ @147/148
|
||||
hex_doSub200
|
||||
iny ;2 @149
|
||||
iny ;2 @151
|
||||
sbc #200 ;2 @153
|
||||
hex_try100
|
||||
cmp #100 ;2 @155
|
||||
bcc HexToDec99 ;2³ @157/158
|
||||
iny ;2 @159
|
||||
sbc #100 ;2 @161
|
||||
|
||||
HexToDec99; SUBROUTINE
|
||||
lsr a ;2 @163
|
||||
tax ;2 @165
|
||||
lda ShiftedBcdTab,x ;4 @169
|
||||
tax ;2 @171
|
||||
rol a ;2 @173
|
||||
and #$0F ;2 @175
|
||||
ora #ASCII_0_OFFSET
|
||||
sta decOnes ;3 @178
|
||||
txa ;2 @180
|
||||
lsr a ;2 @182
|
||||
lsr a ;2 @184
|
||||
lsr a ;2 @186
|
||||
ora #ASCII_0_OFFSET
|
||||
|
||||
; irmen: load X with ones, and store Y and A too, for easy printing afterwards
|
||||
sty decHundreds
|
||||
sta decTens
|
||||
ldx decOnes
|
||||
rts ;6 @192 Y=hundreds, A = tens digit, X=ones digit
|
||||
|
||||
|
||||
HexToDec999; SUBROUTINE
|
||||
sty hexLow ;3 @9
|
||||
jmp Start100s ;3 @12
|
||||
|
||||
Mod100Tab
|
||||
.byte 0,56,12,56+12
|
||||
|
||||
ShiftedBcdTab
|
||||
.byte $00,$01,$02,$03,$04,$08,$09,$0A,$0B,$0C
|
||||
.byte $10,$11,$12,$13,$14,$18,$19,$1A,$1B,$1C
|
||||
.byte $20,$21,$22,$23,$24,$28,$29,$2A,$2B,$2C
|
||||
.byte $30,$31,$32,$33,$34,$38,$39,$3A,$3B,$3C
|
||||
.byte $40,$41,$42,$43,$44,$48,$49,$4A,$4B,$4C
|
||||
|
||||
decTenThousands .byte 0
|
||||
decThousands .byte 0
|
||||
decHundreds .byte 0
|
||||
decTens .byte 0
|
||||
decOnes .byte 0
|
||||
.byte 0 ; zero-terminate the decimal output string
|
||||
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub byte2decimal (byte value @A) -> ubyte @Y, ubyte @A, ubyte @X {
|
||||
; ---- A (signed byte) to decimal string in Y/A/X (100s in Y, 10s in A, 1s in X)
|
||||
; note: if the number is negative, you have to deal with the '-' yourself!
|
||||
%asm {{
|
||||
cmp #0
|
||||
bpl +
|
||||
eor #255
|
||||
clc
|
||||
adc #1
|
||||
+ jmp ubyte2decimal
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub ubyte2hex (ubyte value @A) -> ubyte @A, ubyte @Y {
|
||||
; ---- A to hex petscii string in AY (first hex char in A, second hex char in Y)
|
||||
%asm {{
|
||||
stx P8ZP_SCRATCH_REG
|
||||
pha
|
||||
and #$0f
|
||||
tax
|
||||
ldy _hex_digits,x
|
||||
pla
|
||||
lsr a
|
||||
lsr a
|
||||
lsr a
|
||||
lsr a
|
||||
tax
|
||||
lda _hex_digits,x
|
||||
ldx P8ZP_SCRATCH_REG
|
||||
rts
|
||||
|
||||
_hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as well
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub uword2hex (uword value @AY) clobbers(A,Y) {
|
||||
; ---- convert 16 bit uword in A/Y into 4-character hexadecimal string 'uword2hex.output' (0-terminated)
|
||||
%asm {{
|
||||
sta P8ZP_SCRATCH_REG
|
||||
tya
|
||||
jsr ubyte2hex
|
||||
sta output
|
||||
sty output+1
|
||||
lda P8ZP_SCRATCH_REG
|
||||
jsr ubyte2hex
|
||||
sta output+2
|
||||
sty output+3
|
||||
rts
|
||||
output .text "0000", $00 ; 0-terminated output buffer (to make printing easier)
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ gfx2 {
|
||||
sub screen_mode(ubyte mode) {
|
||||
when mode {
|
||||
1 -> {
|
||||
; lores monchrome
|
||||
; lores monochrome
|
||||
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1
|
||||
cx16.VERA_DC_HSCALE = 64
|
||||
cx16.VERA_DC_VSCALE = 64
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
; Bitmap pixel graphics module for the CommanderX16
|
||||
; wraps the graphics functions that are in ROM.
|
||||
; only black/white monchrome 320x200 for now. (i.e. truncated at the bottom)
|
||||
; only black/white monochrome 320x200 for now. (i.e. truncated at the bottom)
|
||||
; For full-screen 640x480 or 320x240 graphics, use the "gfx2" module instead. (but that is Cx16-specific)
|
||||
; Note: there is no color palette manipulation here, you have to do that yourself or use the "palette" module.
|
||||
|
||||
|
||||
@@ -420,7 +420,7 @@ _print_byte_digits
|
||||
jsr c64.CHROUT
|
||||
pla
|
||||
jsr c64.CHROUT
|
||||
jmp _ones
|
||||
bra _ones
|
||||
+ pla
|
||||
cmp #'0'
|
||||
beq _ones
|
||||
@@ -443,7 +443,7 @@ asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||
jsr c64.CHROUT
|
||||
+ pla
|
||||
jsr conv.byte2decimal
|
||||
jmp print_ub._print_byte_digits
|
||||
bra print_ub._print_byte_digits
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ asmsub print_uwbin (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
jsr print_ubbin
|
||||
pla
|
||||
clc
|
||||
jmp print_ubbin
|
||||
bra print_ubbin
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ asmsub print_uwhex (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||
jsr print_ubhex
|
||||
pla
|
||||
clc
|
||||
jmp print_ubhex
|
||||
bra print_ubhex
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -570,7 +570,7 @@ asmsub print_w (word value @ AY) clobbers(A,Y) {
|
||||
adc #1
|
||||
bcc +
|
||||
iny
|
||||
+ jmp print_uw
|
||||
+ bra print_uw
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,8 +244,8 @@ randseed .proc
|
||||
.pend
|
||||
|
||||
|
||||
randbyte .proc
|
||||
; -- 8-bit pseudo random number generator into A
|
||||
fast_randbyte .proc
|
||||
; -- fast but bad 8-bit pseudo random number generator into A
|
||||
lda _seed
|
||||
beq _eor
|
||||
asl a
|
||||
@@ -263,6 +263,10 @@ _seed .byte $3a
|
||||
|
||||
.pend
|
||||
|
||||
randbyte .proc
|
||||
; -- 8 bit pseudo random number generator into A (by just reusing randword)
|
||||
jmp randword
|
||||
.pend
|
||||
|
||||
randword .proc
|
||||
; -- 16 bit pseudo random number generator into AY
|
||||
|
||||
@@ -387,6 +387,14 @@ func_sqrt16_into_A .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_fastrnd8_stack .proc
|
||||
; -- put a random ubyte on the estack (using fast but bad RNG)
|
||||
jsr math.fast_randbyte
|
||||
sta P8ESTACK_LO,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_rnd_stack .proc
|
||||
; -- put a random ubyte on the estack
|
||||
jsr math.randbyte
|
||||
@@ -432,6 +440,7 @@ func_min_ub_stack .proc
|
||||
func_min_b_into_A .proc
|
||||
; -- min(barray) -> A. (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #127
|
||||
sta P8ZP_SCRATCH_B1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
@@ -548,6 +557,7 @@ func_min_w_stack .proc
|
||||
func_max_ub_into_A .proc
|
||||
; -- max(ubarray) -> A (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #0
|
||||
sta P8ZP_SCRATCH_B1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.2
|
||||
6.3
|
||||
@@ -218,13 +218,13 @@ internal class AstChecker(private val program: Program,
|
||||
err("subroutines can only have one return value")
|
||||
|
||||
// subroutine must contain at least one 'return' or 'goto'
|
||||
// (or if it has an asm block, that must contain a 'rts' or 'jmp')
|
||||
// (or if it has an asm block, that must contain a 'rts' or 'jmp' or 'bra')
|
||||
if(subroutine.statements.count { it is Return || it is Jump } == 0) {
|
||||
if (subroutine.amountOfRtsInAsm() == 0) {
|
||||
if (subroutine.returntypes.isNotEmpty()) {
|
||||
// for asm subroutines with an address, no statement check is possible.
|
||||
if (subroutine.asmAddress == null && !subroutine.inline)
|
||||
err("non-inline subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or 'rts' / 'jmp' in case of %asm)")
|
||||
err("non-inline subroutine has result value(s) and thus must have at least one 'return' or 'goto' in it (or rts/jmp/bra in case of %asm)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,32 +268,23 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
override fun before(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
val valueType = assignment.value.inferType(program)
|
||||
val targetType = assignment.target.inferType(program)
|
||||
var assignments = emptyList<Assignment>()
|
||||
|
||||
if(targetType.istype(DataType.STRUCT) && (valueType.istype(DataType.STRUCT) || valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes )) {
|
||||
assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenStructAssignmentFromStructLiteral(assignment) // 'structvar = [ ..... ] '
|
||||
if (assignment.value is ArrayLiteralValue) {
|
||||
errors.err("cannot assign non-const array value, use separate assignment per field", assignment.position)
|
||||
} else {
|
||||
flattenStructAssignmentFromIdentifier(assignment) // 'structvar1 = structvar2'
|
||||
return copyStructValue(assignment)
|
||||
}
|
||||
}
|
||||
|
||||
if(targetType.typeOrElse(DataType.STRUCT) in ArrayDatatypes && valueType.typeOrElse(DataType.STRUCT) in ArrayDatatypes ) {
|
||||
assignments = if (assignment.value is ArrayLiteralValue) {
|
||||
flattenArrayAssignmentFromArrayLiteral(assignment) // 'arrayvar = [ ..... ] '
|
||||
if (assignment.value is ArrayLiteralValue) {
|
||||
errors.err("cannot assign non-const array value, use separate assignment per element", assignment.position)
|
||||
} else {
|
||||
flattenArrayAssignmentFromIdentifier(assignment) // 'arrayvar1 = arrayvar2'
|
||||
return copyArrayValue(assignment)
|
||||
}
|
||||
}
|
||||
|
||||
if(assignments.isNotEmpty()) {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val scope = assignment.definingScope()
|
||||
assignments.reversed().mapTo(modifications) { IAstModification.InsertAfter(assignment, it, scope) }
|
||||
modifications.add(IAstModification.Remove(assignment, scope))
|
||||
return modifications
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
@@ -346,114 +337,94 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun flattenArrayAssignmentFromArrayLiteral(assign: Assignment): List<Assignment> {
|
||||
private fun copyArrayValue(assign: Assignment): List<IAstModification> {
|
||||
val identifier = assign.target.identifier!!
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
val alv = assign.value as? ArrayLiteralValue
|
||||
return flattenArrayAssign(targetVar, alv, identifier, assign.position)
|
||||
}
|
||||
|
||||
private fun flattenArrayAssignmentFromIdentifier(assign: Assignment): List<Assignment> {
|
||||
val identifier = assign.target.identifier!!
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
if(targetVar.arraysize==null)
|
||||
errors.err("array has no defined size", assign.position)
|
||||
|
||||
val sourceIdent = assign.value as IdentifierReference
|
||||
val sourceVar = sourceIdent.targetVarDecl(program)!!
|
||||
if(!sourceVar.isArray) {
|
||||
errors.err("value must be an array", sourceIdent.position)
|
||||
return emptyList()
|
||||
errors.err("value must be an array", sourceIdent.position)
|
||||
} else {
|
||||
if (sourceVar.arraysize!!.constIndex() != targetVar.arraysize!!.constIndex())
|
||||
errors.err("element count mismatch", assign.position)
|
||||
if (sourceVar.datatype != targetVar.datatype)
|
||||
errors.err("element type mismatch", assign.position)
|
||||
}
|
||||
val alv = sourceVar.value as? ArrayLiteralValue
|
||||
return flattenArrayAssign(targetVar, alv, identifier, assign.position)
|
||||
|
||||
if(!errors.isEmpty())
|
||||
return emptyList()
|
||||
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assign.position),
|
||||
mutableListOf(
|
||||
AddressOf(sourceIdent, assign.position),
|
||||
AddressOf(identifier, assign.position),
|
||||
NumericLiteralValue.optimalInteger(targetVar.arraysize!!.constIndex()!!, assign.position)
|
||||
),
|
||||
true,
|
||||
assign.position
|
||||
)
|
||||
return listOf(IAstModification.ReplaceNode(assign, memcopy, assign.parent))
|
||||
}
|
||||
|
||||
private fun flattenArrayAssign(targetVar: VarDecl, alv: ArrayLiteralValue?, identifier: IdentifierReference, position: Position): List<Assignment> {
|
||||
if(targetVar.arraysize==null) {
|
||||
errors.err("array has no defined size", identifier.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
if(alv==null || alv.value.size != targetVar.arraysize!!.constIndex()) {
|
||||
errors.err("element count mismatch", position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// TODO use memcopy instead of individual assignments after certain amount of elements
|
||||
// TODO what does assigning a struct var use?
|
||||
return alv.value.mapIndexed { index, value ->
|
||||
val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, position), position), position)
|
||||
Assignment(AssignTarget(null, idx, null, position), value, value.position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromStructLiteral(structAssignment: Assignment): List<Assignment> {
|
||||
private fun copyStructValue(structAssignment: Assignment): List<IAstModification> {
|
||||
val identifier = structAssignment.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
val struct = targetVar.struct!!
|
||||
|
||||
val slv = structAssignment.value as? ArrayLiteralValue
|
||||
if(slv==null || slv.value.size != struct.numberOfElements) {
|
||||
errors.err("element count mismatch", structAssignment.position)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return struct.statements.zip(slv.value).map { (targetDecl, sourceValue) ->
|
||||
targetDecl as VarDecl
|
||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val assign = Assignment(AssignTarget(idref, null, null, structAssignment.position),
|
||||
sourceValue, sourceValue.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
}
|
||||
}
|
||||
|
||||
private fun flattenStructAssignmentFromIdentifier(structAssignment: Assignment): List<Assignment> {
|
||||
// TODO use memcopy beyond a certain number of elements
|
||||
val identifier = structAssignment.target.identifier!!
|
||||
val identifierName = identifier.nameInSource.single()
|
||||
val targetVar = identifier.targetVarDecl(program)!!
|
||||
val struct = targetVar.struct!!
|
||||
when (structAssignment.value) {
|
||||
is IdentifierReference -> {
|
||||
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program)!!
|
||||
val memsize = struct.memsize(program.memsizer)
|
||||
when {
|
||||
sourceVar.struct!=null -> {
|
||||
// struct memberwise copy
|
||||
val sourceStruct = sourceVar.struct!!
|
||||
if(sourceStruct!==targetVar.struct) {
|
||||
// structs are not the same in assignment
|
||||
return listOf() // error will be printed elsewhere
|
||||
errors.err("struct type mismatch", structAssignment.position)
|
||||
return listOf()
|
||||
}
|
||||
if(struct.statements.size!=sourceStruct.statements.size)
|
||||
return listOf() // error will be printed elsewhere
|
||||
return struct.statements.zip(sourceStruct.statements).map { member ->
|
||||
val targetDecl = member.first as VarDecl
|
||||
val sourceDecl = member.second as VarDecl
|
||||
if(targetDecl.name != sourceDecl.name)
|
||||
throw FatalAstException("struct member mismatch")
|
||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val sourcemangled = mangledStructMemberName(sourceVar.name, sourceDecl.name)
|
||||
val sourceIdref = IdentifierReference(listOf(sourcemangled), structAssignment.position)
|
||||
val assign = Assignment(AssignTarget(idref, null, null, structAssignment.position), sourceIdref, member.second.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
if(struct.statements.size!=sourceStruct.statements.size) {
|
||||
errors.err("struct element count mismatch", structAssignment.position)
|
||||
return listOf()
|
||||
}
|
||||
if(memsize!=sourceStruct.memsize(program.memsizer)) {
|
||||
errors.err("memory size mismatch", structAssignment.position)
|
||||
return listOf()
|
||||
}
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), structAssignment.position),
|
||||
mutableListOf(
|
||||
AddressOf(structAssignment.value as IdentifierReference, structAssignment.position),
|
||||
AddressOf(identifier, structAssignment.position),
|
||||
NumericLiteralValue.optimalInteger(memsize, structAssignment.position)
|
||||
),
|
||||
true,
|
||||
structAssignment.position
|
||||
)
|
||||
return listOf(IAstModification.ReplaceNode(structAssignment, memcopy, structAssignment.parent))
|
||||
}
|
||||
sourceVar.isArray -> {
|
||||
val array = (sourceVar.value as ArrayLiteralValue).value
|
||||
if(struct.statements.size!=array.size)
|
||||
return listOf() // error will be printed elsewhere
|
||||
return struct.statements.zip(array).map {
|
||||
val decl = it.first as VarDecl
|
||||
val mangled = mangledStructMemberName(identifierName, decl.name)
|
||||
val targetName = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||
val target = AssignTarget(targetName, null, null, structAssignment.position)
|
||||
val assign = Assignment(target, it.second, structAssignment.position)
|
||||
assign.linkParents(structAssignment)
|
||||
assign
|
||||
val array = sourceVar.value as ArrayLiteralValue
|
||||
if(struct.statements.size!=array.value.size) {
|
||||
errors.err("struct element count mismatch", structAssignment.position)
|
||||
return listOf()
|
||||
}
|
||||
if(memsize!=array.memsize(program.memsizer)) {
|
||||
errors.err("memory size mismatch", structAssignment.position)
|
||||
return listOf()
|
||||
}
|
||||
val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), structAssignment.position),
|
||||
mutableListOf(
|
||||
AddressOf(structAssignment.value as IdentifierReference, structAssignment.position),
|
||||
AddressOf(identifier, structAssignment.position),
|
||||
NumericLiteralValue.optimalInteger(memsize, structAssignment.position)
|
||||
),
|
||||
true,
|
||||
structAssignment.position
|
||||
)
|
||||
return listOf(IAstModification.ReplaceNode(structAssignment, memcopy, structAssignment.parent))
|
||||
}
|
||||
else -> {
|
||||
throw FatalAstException("can only assign arrays or structs to structs")
|
||||
@@ -461,7 +432,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
}
|
||||
}
|
||||
is ArrayLiteralValue -> {
|
||||
throw IllegalArgumentException("not going to flatten a structLv assignment here")
|
||||
throw IllegalArgumentException("not going to do a structLv assignment here")
|
||||
}
|
||||
else -> throw FatalAstException("strange struct value")
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ private val functionSignatures: List<FSignature> = listOf(
|
||||
FSignature("peekw" , true, listOf(FParam("address", setOf(DataType.UWORD))), DataType.UWORD),
|
||||
FSignature("poke" , false, listOf(FParam("address", setOf(DataType.UWORD)), FParam("value", setOf(DataType.UBYTE))), null),
|
||||
FSignature("pokew" , false, listOf(FParam("address", setOf(DataType.UWORD)), FParam("value", setOf(DataType.UWORD))), null),
|
||||
FSignature("fastrnd8" , false, emptyList(), DataType.UBYTE),
|
||||
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
|
||||
FSignature("rndw" , false, emptyList(), DataType.UWORD),
|
||||
FSignature("rndf" , false, emptyList(), DataType.FLOAT),
|
||||
@@ -320,8 +321,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
|
||||
val target = (args[0] as IdentifierReference).targetStatement(program)
|
||||
?: throw CannotEvaluateException("sizeof", "no target")
|
||||
|
||||
fun structSize(target: StructDecl) =
|
||||
NumericLiteralValue(DataType.UBYTE, target.statements.map { memsizer.memorySize((it as VarDecl).datatype) }.sum(), position)
|
||||
fun structSize(target: StructDecl) = NumericLiteralValue(DataType.UBYTE, target.memsize(memsizer), position)
|
||||
|
||||
return when {
|
||||
dt.typeOrElse(DataType.STRUCT) in ArrayDatatypes -> {
|
||||
|
||||
@@ -12,7 +12,7 @@ import prog8.compiler.IErrorReporter
|
||||
import prog8.compiler.Zeropage
|
||||
import prog8.compiler.target.c64.C64MachineDefinition
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
||||
import prog8.compiler.target.cx16.CX16MachineDefinition
|
||||
import java.nio.file.Path
|
||||
|
||||
@@ -114,5 +114,6 @@ internal fun asmGeneratorFor(
|
||||
outputDir: Path
|
||||
): IAssemblyGenerator
|
||||
{
|
||||
// at the moment we only have one code generation backend (for 6502 and 65c02)
|
||||
return AsmGen(program, errors, zp, options, compTarget, outputDir)
|
||||
}
|
||||
+53
-77
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.*
|
||||
import prog8.ast.antlr.escape
|
||||
@@ -11,8 +11,8 @@ import prog8.compiler.functions.FSignature
|
||||
import prog8.compiler.target.*
|
||||
import prog8.compiler.target.c64.AssemblyProgram
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.compiler.target.c64.codegen.assignment.AsmAssignment
|
||||
import prog8.compiler.target.c64.codegen.assignment.AssignmentAsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
|
||||
import java.io.CharConversionException
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
@@ -157,7 +157,7 @@ internal class AsmGen(private val program: Program,
|
||||
pha""")
|
||||
}
|
||||
|
||||
out(" jmp main.start ; start program / force start proc to be included")
|
||||
jmp("main.start")
|
||||
}
|
||||
|
||||
private fun slaballocations() {
|
||||
@@ -695,7 +695,7 @@ internal class AsmGen(private val program: Program,
|
||||
is Break -> {
|
||||
if(loopEndLabels.isEmpty())
|
||||
throw AssemblyError("break statement out of context ${stmt.position}")
|
||||
out(" jmp ${loopEndLabels.peek()}")
|
||||
jmp(loopEndLabels.peek())
|
||||
}
|
||||
is WhileLoop -> translate(stmt)
|
||||
is RepeatLoop -> translate(stmt)
|
||||
@@ -930,7 +930,7 @@ internal class AsmGen(private val program: Program,
|
||||
val endLabel = makeLabel("if_end")
|
||||
expressionsAsmGen.translateComparisonExpressionWithJumpIfFalse(booleanCondition, elseLabel)
|
||||
translate(stmt.truepart)
|
||||
out(" jmp $endLabel")
|
||||
jmp(endLabel)
|
||||
out(elseLabel)
|
||||
translate(stmt.elsepart)
|
||||
out(endLabel)
|
||||
@@ -952,7 +952,7 @@ internal class AsmGen(private val program: Program,
|
||||
// endless loop
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
out(" jmp $repeatLabel")
|
||||
jmp(repeatLabel)
|
||||
out(endLabel)
|
||||
}
|
||||
is NumericLiteralValue -> {
|
||||
@@ -976,10 +976,12 @@ internal class AsmGen(private val program: Program,
|
||||
val name = asmVariableName(stmt.iterations as IdentifierReference)
|
||||
when(vardecl.datatype) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
repeatByteCountVar(name, repeatLabel, endLabel, stmt.body)
|
||||
assignVariableToRegister(name, RegisterOrPair.A)
|
||||
repeatByteCountInA(null, repeatLabel, endLabel, stmt.body)
|
||||
}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
repeatWordCountVar(name, repeatLabel, endLabel, stmt.body)
|
||||
assignVariableToRegister(name, RegisterOrPair.AY)
|
||||
repeatWordCountInAY(null, repeatLabel, endLabel, stmt.body)
|
||||
}
|
||||
else -> throw AssemblyError("invalid loop variable datatype $vardecl")
|
||||
}
|
||||
@@ -1006,10 +1008,11 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
private fun repeatWordCountInAY(constIterations: Int?, repeatLabel: String, endLabel: String, body: AnonymousScope) {
|
||||
// note: A/Y must have been loaded with the number of iterations!
|
||||
if(constIterations==0)
|
||||
return
|
||||
// note: A/Y must have been loaded with the number of iterations already!
|
||||
// TODO can be even more optimized by iterating over pages
|
||||
// no need to explicitly test for 0 iterations as this is done in the count down logic below
|
||||
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
out("""
|
||||
sta $counterVar
|
||||
@@ -1018,80 +1021,48 @@ $repeatLabel lda $counterVar
|
||||
bne +
|
||||
lda $counterVar+1
|
||||
beq $endLabel
|
||||
+ lda $counterVar
|
||||
lda $counterVar
|
||||
bne +
|
||||
dec $counterVar+1
|
||||
+ dec $counterVar
|
||||
""")
|
||||
translate(body)
|
||||
out(" jmp $repeatLabel")
|
||||
if(constIterations!=null && constIterations>=16 && zeropage.available() > 1) {
|
||||
// allocate count var on ZP
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UWORD, body.position, errors)
|
||||
out("""$counterVar = $zpAddr ; auto zp UWORD""")
|
||||
} else {
|
||||
out("""
|
||||
$counterVar .word 0""")
|
||||
}
|
||||
out(endLabel)
|
||||
jmp(repeatLabel)
|
||||
|
||||
if(constIterations!=null && constIterations>=16 && zeropage.available() > 1) {
|
||||
// allocate count var on ZP TODO can be shared with countervars from other subroutines
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UWORD, body.position, errors)
|
||||
out("$counterVar = $zpAddr ; auto zp UWORD")
|
||||
} else {
|
||||
out("$counterVar .word 0")
|
||||
}
|
||||
|
||||
out(endLabel)
|
||||
}
|
||||
|
||||
private fun repeatByteCountInA(constIterations: Int?, repeatLabel: String, endLabel: String, body: AnonymousScope) {
|
||||
// note: A must have been loaded with the number of iterations!
|
||||
if(constIterations==0)
|
||||
return
|
||||
// note: A must have been loaded with the number of iterations already!
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
if(constIterations==null)
|
||||
out(" beq $endLabel")
|
||||
out(" beq $endLabel ; skip loop if zero iters")
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
out(" sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(body)
|
||||
out("""
|
||||
dec $counterVar
|
||||
bne $repeatLabel
|
||||
beq $endLabel
|
||||
$counterVar .byte 0""")
|
||||
out(endLabel)
|
||||
}
|
||||
beq $endLabel""")
|
||||
|
||||
private fun repeatByteCountVar(repeatCountVar: String, repeatLabel: String, endLabel: String, body: AnonymousScope) {
|
||||
// note: cannot use original counter variable because it should retain its original value
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
out(" lda $repeatCountVar | beq $endLabel | sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(body)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
// inline countervar:
|
||||
out("""
|
||||
beq $endLabel
|
||||
$counterVar .byte 0""")
|
||||
out(endLabel)
|
||||
}
|
||||
if(constIterations!=null && constIterations>=16 && zeropage.available() > 0) {
|
||||
// allocate count var on ZP TODO can be shared with countervars from other subroutines
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UBYTE, body.position, errors)
|
||||
out("$counterVar = $zpAddr ; auto zp UBYTE")
|
||||
} else {
|
||||
out("$counterVar .byte 0")
|
||||
}
|
||||
|
||||
private fun repeatWordCountVar(repeatCountVar: String, repeatLabel: String, endLabel: String, body: AnonymousScope) {
|
||||
// TODO can be even more optimized by iterating over pages
|
||||
// note: cannot use original counter variable because it should retain its original value
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
out("""
|
||||
lda $repeatCountVar
|
||||
sta $counterVar
|
||||
ora $repeatCountVar+1
|
||||
beq $endLabel
|
||||
lda $repeatCountVar+1
|
||||
sta $counterVar+1""")
|
||||
out(repeatLabel)
|
||||
translate(body)
|
||||
out("""
|
||||
lda $counterVar
|
||||
bne +
|
||||
dec $counterVar+1
|
||||
+ dec $counterVar
|
||||
lda $counterVar
|
||||
ora $counterVar+1
|
||||
bne $repeatLabel
|
||||
beq $endLabel
|
||||
$counterVar .word 0""")
|
||||
out(endLabel)
|
||||
}
|
||||
|
||||
@@ -1104,7 +1075,7 @@ $counterVar .word 0""")
|
||||
out(whileLabel)
|
||||
expressionsAsmGen.translateComparisonExpressionWithJumpIfFalse(booleanCondition, endLabel)
|
||||
translate(stmt.body)
|
||||
out(" jmp $whileLabel")
|
||||
jmp(whileLabel)
|
||||
out(endLabel)
|
||||
loopEndLabels.pop()
|
||||
}
|
||||
@@ -1138,7 +1109,7 @@ $counterVar .word 0""")
|
||||
if(choice.values==null) {
|
||||
// the else choice
|
||||
translate(choice.statements)
|
||||
out(" jmp $endLabel")
|
||||
jmp(endLabel)
|
||||
} else {
|
||||
choiceBlocks.add(choiceLabel to choice.statements)
|
||||
for (cv in choice.values!!) {
|
||||
@@ -1157,11 +1128,11 @@ $counterVar .word 0""")
|
||||
}
|
||||
}
|
||||
}
|
||||
out(" jmp $endLabel")
|
||||
jmp(endLabel)
|
||||
for(choiceBlock in choiceBlocks) {
|
||||
out(choiceBlock.first)
|
||||
translate(choiceBlock.second)
|
||||
out(" jmp $endLabel")
|
||||
jmp(endLabel)
|
||||
}
|
||||
out(endLabel)
|
||||
}
|
||||
@@ -1220,7 +1191,7 @@ $counterVar .word 0""")
|
||||
val endLabel = makeLabel("branch_end")
|
||||
out(" $instruction $elseLabel")
|
||||
translate(stmt.truepart)
|
||||
out(" jmp $endLabel")
|
||||
jmp(endLabel)
|
||||
out(elseLabel)
|
||||
translate(stmt.elsepart)
|
||||
out(endLabel)
|
||||
@@ -1277,14 +1248,12 @@ $label nop""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(jmp: Jump) {
|
||||
out(" jmp ${getJumpTarget(jmp)}")
|
||||
}
|
||||
private fun translate(jump: Jump) = jmp(getJumpTarget(jump))
|
||||
|
||||
private fun getJumpTarget(jmp: Jump): String {
|
||||
val ident = jmp.identifier
|
||||
val label = jmp.generatedLabel
|
||||
val addr = jmp.address
|
||||
private fun getJumpTarget(jump: Jump): String {
|
||||
val ident = jump.identifier
|
||||
val label = jump.generatedLabel
|
||||
val addr = jump.address
|
||||
return when {
|
||||
ident!=null -> {
|
||||
val target = ident.targetStatement(program)
|
||||
@@ -1378,6 +1347,13 @@ $label nop""")
|
||||
return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables
|
||||
}
|
||||
|
||||
internal fun jmp(asmLabel: String) {
|
||||
if(isTargetCpu(CpuType.CPU65c02))
|
||||
out(" bra $asmLabel") // note: 64tass will convert this automatically to a jmp if the relative distance is too large
|
||||
else
|
||||
out(" jmp $asmLabel")
|
||||
}
|
||||
|
||||
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: Expression): Pair<Expression, Expression>? {
|
||||
if(pointerOffsetExpr is BinaryExpression && pointerOffsetExpr.operator=="+") {
|
||||
val leftDt = pointerOffsetExpr.left.inferType(program)
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
|
||||
// note: see https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations
|
||||
+25
-12
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
@@ -13,7 +13,12 @@ import prog8.ast.toHex
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.functions.FSignature
|
||||
import prog8.compiler.target.CpuType
|
||||
import prog8.compiler.target.c64.codegen.assignment.*
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.*
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignSource
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.SourceStorageKind
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind
|
||||
import prog8.compiler.target.subroutineFloatEvalResultVar2
|
||||
|
||||
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) {
|
||||
@@ -51,7 +56,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
"ln", "log2", "sqrt", "rad",
|
||||
"deg", "round", "floor", "ceil",
|
||||
"rndf" -> funcVariousFloatFuncs(fcall, func, resultToStack, resultRegister, sscope)
|
||||
"rnd", "rndw" -> funcRnd(func, resultToStack, resultRegister, sscope)
|
||||
"fastrnd8", "rnd", "rndw" -> funcRnd(func, resultToStack, resultRegister, sscope)
|
||||
"sqrt16" -> funcSqrt16(fcall, func, resultToStack, resultRegister, sscope)
|
||||
"rol" -> funcRol(fcall)
|
||||
"rol2" -> funcRol2(fcall)
|
||||
@@ -478,11 +483,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
asmgen.out(" jsr prog8_lib.func_${function.name}_uw_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
asmgen.out(" jsr floats.func_${function.name}_f_fac1")
|
||||
@@ -509,19 +514,19 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
when (dt.typeOrElse(DataType.STRUCT)) {
|
||||
DataType.ARRAY_UB, DataType.STR -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_ub_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_b_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_uw_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_w_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
asmgen.out(" jsr floats.func_sum_f_fac1")
|
||||
@@ -924,15 +929,15 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
when (dt) {
|
||||
in ByteDatatypes -> {
|
||||
asmgen.out(" jsr prog8_lib.abs_b_into_A")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister!!, scope, program, asmgen), CpuRegister.A)
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), CpuRegister.A)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
asmgen.out(" jsr prog8_lib.abs_w_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister!!, scope, program, asmgen), RegisterOrPair.AY)
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
asmgen.out(" jsr floats.abs_f_fac1")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister!!, scope, program, asmgen), RegisterOrPair.FAC1)
|
||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, scope, program, asmgen))
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
@@ -941,6 +946,14 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
|
||||
private fun funcRnd(func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
|
||||
when(func.name) {
|
||||
"fastrnd8" -> {
|
||||
if(resultToStack)
|
||||
asmgen.out(" jsr prog8_lib.func_fastrnd8_stack")
|
||||
else {
|
||||
asmgen.out(" jsr math.fast_randbyte")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, scope, program, asmgen), CpuRegister.A)
|
||||
}
|
||||
}
|
||||
"rnd" -> {
|
||||
if(resultToStack)
|
||||
asmgen.out(" jsr prog8_lib.func_rnd_stack")
|
||||
+26
-26
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
@@ -370,7 +370,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -381,7 +381,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
cmp #${rightConstVal.number}
|
||||
bcs $jumpIfFalseLabel""")
|
||||
else
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
}
|
||||
else if (left is DirectMemoryRead) {
|
||||
@@ -390,7 +390,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
asmgen.out(" cmp #${rightConstVal.number} | bcs $jumpIfFalseLabel")
|
||||
}
|
||||
else
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -405,7 +405,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -439,7 +439,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -455,7 +455,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
bcs $jumpIfFalseLabel
|
||||
+""")
|
||||
else
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -470,7 +470,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -500,7 +500,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -538,7 +538,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -576,7 +576,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -611,7 +611,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -647,7 +647,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -693,7 +693,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -731,7 +731,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -765,7 +765,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal>leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -801,7 +801,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -831,7 +831,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -868,7 +868,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -897,7 +897,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal<leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -928,7 +928,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal!=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -959,7 +959,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal==leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -990,7 +990,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal!=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -1027,7 +1027,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal==leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -1067,7 +1067,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal!=leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
@@ -1151,7 +1151,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
if(rightConstVal!=null) {
|
||||
if(leftConstVal!=null) {
|
||||
if(rightConstVal==leftConstVal)
|
||||
asmgen.out(" jmp $jumpIfFalseLabel")
|
||||
asmgen.jmp(jumpIfFalseLabel)
|
||||
return
|
||||
} else {
|
||||
if (left is IdentifierReference) {
|
||||
+39
-38
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ArrayElementTypes
|
||||
@@ -57,9 +57,9 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
|
||||
lda $varname
|
||||
$modifiedLabel cmp #0 ; modified
|
||||
beq $endLabel
|
||||
$incdec $varname
|
||||
jmp $loopLabel
|
||||
$endLabel""")
|
||||
$incdec $varname""")
|
||||
asmgen.jmp(loopLabel)
|
||||
asmgen.out(endLabel)
|
||||
|
||||
} else {
|
||||
|
||||
@@ -117,16 +117,15 @@ $modifiedLabel2 cmp #0 ; modified
|
||||
asmgen.out("""
|
||||
+ inc $varname
|
||||
bne $loopLabel
|
||||
inc $varname+1
|
||||
jmp $loopLabel
|
||||
""")
|
||||
inc $varname+1""")
|
||||
asmgen.jmp(loopLabel)
|
||||
} else {
|
||||
asmgen.out("""
|
||||
+ lda $varname
|
||||
bne +
|
||||
dec $varname+1
|
||||
+ dec $varname
|
||||
jmp $loopLabel""")
|
||||
+ dec $varname""")
|
||||
asmgen.jmp(loopLabel)
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
@@ -386,23 +385,25 @@ $loopLabel""")
|
||||
}
|
||||
-2 -> {
|
||||
when (range.last) {
|
||||
0 -> asmgen.out("""
|
||||
lda $varname
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
dec $varname
|
||||
jmp $loopLabel""")
|
||||
0 -> {
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
dec $varname""")
|
||||
asmgen.jmp(loopLabel)
|
||||
}
|
||||
1 -> asmgen.out("""
|
||||
dec $varname
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
bne $loopLabel""")
|
||||
dec $varname
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
bne $loopLabel""")
|
||||
else -> asmgen.out("""
|
||||
dec $varname
|
||||
dec $varname
|
||||
lda $varname
|
||||
cmp #${range.last-2}
|
||||
bne $loopLabel""")
|
||||
dec $varname
|
||||
dec $varname
|
||||
lda $varname
|
||||
cmp #${range.last-2}
|
||||
bne $loopLabel""")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@@ -413,8 +414,8 @@ $loopLabel""")
|
||||
beq $endLabel
|
||||
clc
|
||||
adc #${range.step}
|
||||
sta $varname
|
||||
jmp $loopLabel""")
|
||||
sta $varname""")
|
||||
asmgen.jmp(loopLabel)
|
||||
}
|
||||
}
|
||||
asmgen.out(endLabel)
|
||||
@@ -450,9 +451,9 @@ $loopLabel""")
|
||||
sta $varname
|
||||
lda $varname+1
|
||||
adc #>${range.step}
|
||||
sta $varname+1
|
||||
jmp $loopLabel
|
||||
$endLabel""")
|
||||
sta $varname+1""")
|
||||
asmgen.jmp(loopLabel)
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -502,9 +503,9 @@ $loopLabel""")
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
jmp $loopLabel
|
||||
$endLabel""")
|
||||
dec $varname""")
|
||||
asmgen.jmp(loopLabel)
|
||||
asmgen.out(endLabel)
|
||||
}
|
||||
1 -> {
|
||||
asmgen.out("""
|
||||
@@ -545,9 +546,9 @@ $loopLabel""")
|
||||
beq $endLabel
|
||||
+ inc $varname
|
||||
bne $loopLabel
|
||||
inc $varname+1
|
||||
jmp $loopLabel
|
||||
$endLabel""")
|
||||
inc $varname+1""")
|
||||
asmgen.jmp(loopLabel)
|
||||
asmgen.out(endLabel)
|
||||
asmgen.loopEndLabels.pop()
|
||||
}
|
||||
|
||||
@@ -573,9 +574,9 @@ $loopLabel""")
|
||||
+ lda $varname
|
||||
bne +
|
||||
dec $varname+1
|
||||
+ dec $varname
|
||||
jmp $loopLabel
|
||||
$endLabel""")
|
||||
+ dec $varname""")
|
||||
asmgen.jmp(loopLabel)
|
||||
asmgen.out(endLabel)
|
||||
asmgen.loopEndLabels.pop()
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
@@ -8,10 +8,10 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.target.CpuType
|
||||
import prog8.compiler.target.c64.codegen.assignment.AsmAssignSource
|
||||
import prog8.compiler.target.c64.codegen.assignment.AsmAssignTarget
|
||||
import prog8.compiler.target.c64.codegen.assignment.AsmAssignment
|
||||
import prog8.compiler.target.c64.codegen.assignment.TargetStorageKind
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignSource
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment
|
||||
import prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind
|
||||
|
||||
|
||||
internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
package prog8.compiler.target.cpu6502.codegen
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen.assignment
|
||||
package prog8.compiler.target.cpu6502.codegen.assignment
|
||||
|
||||
import prog8.ast.IMemSizer
|
||||
import prog8.ast.Program
|
||||
@@ -6,7 +6,7 @@ import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
||||
|
||||
|
||||
internal enum class TargetStorageKind {
|
||||
+6
-5
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen.assignment
|
||||
package prog8.compiler.target.cpu6502.codegen.assignment
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
@@ -9,12 +9,13 @@ import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.functions.BuiltinFunctions
|
||||
import prog8.compiler.functions.builtinFunctionReturnType
|
||||
import prog8.compiler.target.CpuType
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.c64.codegen.ExpressionsAsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.ExpressionsAsmGen
|
||||
|
||||
|
||||
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen,
|
||||
private val exprAsmgen: ExpressionsAsmGen) {
|
||||
private val exprAsmgen: ExpressionsAsmGen
|
||||
) {
|
||||
|
||||
private val augmentableAsmGen = AugmentableAssignmentAsmGen(program, this, exprAsmgen, asmgen)
|
||||
|
||||
@@ -356,7 +357,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
|
||||
|
||||
// special case optimizations
|
||||
if(target.kind==TargetStorageKind.VARIABLE) {
|
||||
if(target.kind== TargetStorageKind.VARIABLE) {
|
||||
if(value is IdentifierReference && valueDt != DataType.STRUCT)
|
||||
return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt)
|
||||
|
||||
+5
-4
@@ -1,4 +1,4 @@
|
||||
package prog8.compiler.target.c64.codegen.assignment
|
||||
package prog8.compiler.target.cpu6502.codegen.assignment
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
@@ -7,13 +7,14 @@ import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.toHex
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.target.CpuType
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.compiler.target.c64.codegen.ExpressionsAsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
||||
import prog8.compiler.target.cpu6502.codegen.ExpressionsAsmGen
|
||||
|
||||
internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
private val assignmentAsmGen: AssignmentAsmGen,
|
||||
private val exprAsmGen: ExpressionsAsmGen,
|
||||
private val asmgen: AsmGen) {
|
||||
private val asmgen: AsmGen
|
||||
) {
|
||||
fun translate(assign: AsmAssignment) {
|
||||
require(assign.isAugmentable)
|
||||
require(assign.source.kind== SourceStorageKind.EXPRESSION)
|
||||
@@ -19,7 +19,7 @@ private val alwaysKeepSubroutines = setOf(
|
||||
Pair("main", "start")
|
||||
)
|
||||
|
||||
private val asmJumpRx = Regex("""[\-+a-zA-Z0-9_ \t]+(jmp|jsr)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE)
|
||||
private val asmJumpRx = Regex("""[\-+a-zA-Z0-9_ \t]+(jmp|jsr|bra)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE)
|
||||
private val asmRefRx = Regex("""[\-+a-zA-Z0-9_ \t]+(...)[ \t]+(\S+).*""", RegexOption.IGNORE_CASE)
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ class CallGraph(private val program: Program, private val asmFileLoader: (filena
|
||||
}
|
||||
|
||||
override fun visit(inlineAssembly: InlineAssembly) {
|
||||
// parse inline asm for subroutine calls (jmp, jsr)
|
||||
// parse inline asm for subroutine calls (jmp, jsr, bra)
|
||||
val scope = inlineAssembly.definingSubroutine()
|
||||
scanAssemblyCode(inlineAssembly.assembly, inlineAssembly, scope)
|
||||
super.visit(inlineAssembly)
|
||||
|
||||
@@ -9,28 +9,32 @@ import kotlin.math.pow
|
||||
class ConstExprEvaluator {
|
||||
|
||||
fun evaluate(left: NumericLiteralValue, operator: String, right: NumericLiteralValue): Expression {
|
||||
return when(operator) {
|
||||
"+" -> plus(left, right)
|
||||
"-" -> minus(left, right)
|
||||
"*" -> multiply(left, right)
|
||||
"/" -> divide(left, right)
|
||||
"%" -> remainder(left, right)
|
||||
"**" -> power(left, right)
|
||||
"&" -> bitwiseand(left, right)
|
||||
"|" -> bitwiseor(left, right)
|
||||
"^" -> bitwisexor(left, right)
|
||||
"and" -> logicaland(left, right)
|
||||
"or" -> logicalor(left, right)
|
||||
"xor" -> logicalxor(left, right)
|
||||
"<" -> NumericLiteralValue.fromBoolean(left < right, left.position)
|
||||
">" -> NumericLiteralValue.fromBoolean(left > right, left.position)
|
||||
"<=" -> NumericLiteralValue.fromBoolean(left <= right, left.position)
|
||||
">=" -> NumericLiteralValue.fromBoolean(left >= right, left.position)
|
||||
"==" -> NumericLiteralValue.fromBoolean(left == right, left.position)
|
||||
"!=" -> NumericLiteralValue.fromBoolean(left != right, left.position)
|
||||
"<<" -> shiftedleft(left, right)
|
||||
">>" -> shiftedright(left, right)
|
||||
else -> throw FatalAstException("const evaluation for invalid operator $operator")
|
||||
try {
|
||||
return when(operator) {
|
||||
"+" -> plus(left, right)
|
||||
"-" -> minus(left, right)
|
||||
"*" -> multiply(left, right)
|
||||
"/" -> divide(left, right)
|
||||
"%" -> remainder(left, right)
|
||||
"**" -> power(left, right)
|
||||
"&" -> bitwiseand(left, right)
|
||||
"|" -> bitwiseor(left, right)
|
||||
"^" -> bitwisexor(left, right)
|
||||
"and" -> logicaland(left, right)
|
||||
"or" -> logicalor(left, right)
|
||||
"xor" -> logicalxor(left, right)
|
||||
"<" -> NumericLiteralValue.fromBoolean(left < right, left.position)
|
||||
">" -> NumericLiteralValue.fromBoolean(left > right, left.position)
|
||||
"<=" -> NumericLiteralValue.fromBoolean(left <= right, left.position)
|
||||
">=" -> NumericLiteralValue.fromBoolean(left >= right, left.position)
|
||||
"==" -> NumericLiteralValue.fromBoolean(left == right, left.position)
|
||||
"!=" -> NumericLiteralValue.fromBoolean(left != right, left.position)
|
||||
"<<" -> shiftedleft(left, right)
|
||||
">>" -> shiftedright(left, right)
|
||||
else -> throw FatalAstException("const evaluation for invalid operator $operator")
|
||||
}
|
||||
} catch (ax: FatalAstException) {
|
||||
throw ExpressionError(ax.message, left.position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import prog8.ast.base.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import java.util.*
|
||||
import java.util.Objects
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
@@ -542,6 +542,14 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
|
||||
return type==other.type && value.contentEquals(other.value)
|
||||
}
|
||||
|
||||
fun memsize(memsizer: IMemSizer): Int {
|
||||
if(type.isKnown) {
|
||||
val eltType = ArrayElementTypes.getValue(type.typeOrElse(DataType.STRUCT))
|
||||
return memsizer.memorySize(eltType) * value.size
|
||||
}
|
||||
else throw IllegalArgumentException("array datatype is not yet known")
|
||||
}
|
||||
|
||||
fun guessDatatype(program: Program): InferredTypes.InferredType {
|
||||
// Educated guess of the desired array literal's datatype.
|
||||
// If it's inside a for loop, assume the data type of the loop variable is what we want.
|
||||
|
||||
@@ -728,7 +728,7 @@ class Subroutine(override val name: String,
|
||||
.asSequence()
|
||||
.filter { it is InlineAssembly }
|
||||
.map { (it as InlineAssembly).assembly }
|
||||
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it }
|
||||
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it || " bra" in it || "\tbra" in it}
|
||||
}
|
||||
|
||||
|
||||
@@ -1000,6 +1000,9 @@ class StructDecl(override val name: String,
|
||||
val numberOfElements: Int
|
||||
get() = this.statements.size
|
||||
|
||||
fun memsize(memsizer: IMemSizer) =
|
||||
statements.map { memsizer.memorySize((it as VarDecl).datatype) }.sum()
|
||||
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
||||
|
||||
@@ -50,8 +50,9 @@ Language features
|
||||
- Provide high level programming constructs but at the same time stay close to the metal;
|
||||
still able to directly use memory addresses and ROM subroutines,
|
||||
and inline assembly to have full control when every register, cycle or byte matters
|
||||
- Arbitrary number of subroutine parameters, Complex nested expressions are possible
|
||||
- No stack frame allocations because parameters and local variables are automatically allocated statically
|
||||
- Subroutines with parameters and return values
|
||||
- complex nested expressions are possible
|
||||
- Variables are allocated statically
|
||||
- Nested subroutines can access variables from outer scopes to avoids the overhead to pass everything via parameters
|
||||
- Variable data types include signed and unsigned bytes and words, arrays, strings and floats.
|
||||
- High-level code optimizations, such as const-folding, expression and statement simplifications/rewriting.
|
||||
|
||||
@@ -105,7 +105,7 @@ conv
|
||||
Routines to convert strings to numbers or vice versa.
|
||||
|
||||
- numbers to strings, in various formats (binary, hex, decimal)
|
||||
- strings in decimal, hex and binary format into numbers
|
||||
- strings in decimal, hex and binary format into numbers (bytes, words)
|
||||
|
||||
|
||||
textio (txt.*)
|
||||
|
||||
@@ -757,11 +757,12 @@ all(x)
|
||||
1 ('true') if all of the values in the array value x are 'true' (not zero), else 0 ('false')
|
||||
|
||||
len(x)
|
||||
Number of values in the array value x, or the number of characters in a string (excluding the size or 0-byte).
|
||||
Number of values in the array value x, or the number of characters in a string (excluding the 0-byte).
|
||||
Note: this can be different from the number of *bytes* in memory if the datatype isn't a byte. See sizeof().
|
||||
Note: lengths of strings and arrays are determined at compile-time! If your program modifies the actual
|
||||
length of the string during execution, the value of len(string) may no longer be correct!
|
||||
(use strlen function if you want to dynamically determine the length)
|
||||
length of the string during execution, the value of len(s) may no longer be correct!
|
||||
(use the ``string.length`` routine if you want to dynamically determine the length by counting to the
|
||||
first 0-byte)
|
||||
|
||||
max(x)
|
||||
Maximum of the values in the array value x
|
||||
@@ -824,6 +825,9 @@ rndw()
|
||||
rndf()
|
||||
returns a pseudo-random float between 0.0 and 1.0
|
||||
|
||||
fastrnd8()
|
||||
returns a pseudo-random byte from 0..255 (using a fast but not very good rng)
|
||||
|
||||
rol(x)
|
||||
Rotate the bits in x (byte or word) one position to the left.
|
||||
This uses the CPU's rotate semantics: bit 0 will be set to the current value of the Carry flag,
|
||||
|
||||
@@ -592,7 +592,7 @@ flag such as Carry (Pc).
|
||||
Asmsubs can also be tagged as ``inline asmsub`` to make trivial pieces of assembly inserted
|
||||
directly instead of a call to them. Note that it is literal copy-paste of code that is done,
|
||||
so make sure the assembly is actually written to behave like such - which probably means you
|
||||
don't want a ``rts`` or ``jmp`` in it!
|
||||
don't want a ``rts`` or ``jmp`` or ``bra`` in it!
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- optimize assigning array and struct variables (multi-element assings -> memcopy)
|
||||
- optimize several inner loops in gfx2
|
||||
- fix the bresenham line routines in graphics and gfx2 (sometimes they're a pixel 'off') (or maybe finally just replace them with a proper all-assembly implementation)
|
||||
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
|
||||
- optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2))
|
||||
- optimize several inner loops in gfx2
|
||||
- try to fix the bresenham line routines in graphics and gfx2 (sometimes they're a pixel 'off')
|
||||
- add modes 2 and 3 to gfx2 (lowres 4 color and 16 color)
|
||||
- add a flood fill routine to gfx2?
|
||||
- add modes 2 and 3 to gfx2 (lowres 4 color and 16 color) ?
|
||||
- add a f_seek() routine for the Cx16 that uses its seek dos api?
|
||||
- refactor the asmgen into their own submodule?
|
||||
- refactor the compiler optimizers into their own submodule?
|
||||
|
||||
@@ -42,7 +42,7 @@ main {
|
||||
active_height--
|
||||
upwards = false
|
||||
} else {
|
||||
target_height = 8 + rnd() % 16
|
||||
target_height = 8 + fastrnd8() % 16
|
||||
if upwards
|
||||
mountain = 233
|
||||
else
|
||||
@@ -57,7 +57,7 @@ main {
|
||||
txt.scroll_left(true)
|
||||
|
||||
; float the balloon
|
||||
if rnd() & %10000
|
||||
if fastrnd8() & %10000
|
||||
c64.SPXY[1] ++
|
||||
else
|
||||
c64.SPXY[1] --
|
||||
@@ -71,10 +71,10 @@ main {
|
||||
txt.setcc(39, yy, 160, 8) ; draw mountain
|
||||
}
|
||||
|
||||
yy = rnd()
|
||||
yy = fastrnd8()
|
||||
if yy > 100 {
|
||||
; draw a star
|
||||
txt.setcc(39, yy % (active_height-1), '.', rnd())
|
||||
txt.setcc(39, yy % (active_height-1), '.', fastrnd8())
|
||||
}
|
||||
|
||||
if yy > 200 {
|
||||
@@ -85,7 +85,7 @@ main {
|
||||
tree = 88
|
||||
else if yy & %00100000 != 0
|
||||
tree = 65
|
||||
if rnd() > 130
|
||||
if fastrnd8() > 130
|
||||
treecolor = 13
|
||||
txt.setcc(39, active_height, tree, treecolor)
|
||||
}
|
||||
|
||||
+6
-6
@@ -24,12 +24,12 @@ main {
|
||||
; Setup Starting Ball Positions
|
||||
ubyte lp
|
||||
for lp in 0 to ballCount-1 {
|
||||
BX[lp] = rnd() % txt.DEFAULT_WIDTH
|
||||
BY[lp] = rnd() % txt.DEFAULT_HEIGHT
|
||||
BC[lp] = rnd() & 15
|
||||
DX[lp] = rnd() & 1
|
||||
DY[lp] = rnd() & 1
|
||||
void rnd()
|
||||
BX[lp] = fastrnd8() % txt.DEFAULT_WIDTH
|
||||
BY[lp] = fastrnd8() % txt.DEFAULT_HEIGHT
|
||||
BC[lp] = fastrnd8() & 15
|
||||
DX[lp] = fastrnd8() & 1
|
||||
DY[lp] = fastrnd8() & 1
|
||||
void fastrnd8()
|
||||
}
|
||||
|
||||
; start clock
|
||||
|
||||
@@ -406,14 +406,18 @@ galaxy {
|
||||
sub init(ubyte galaxynum) {
|
||||
number = 1
|
||||
planet.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxynum-1 {
|
||||
nextgalaxy()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -587,7 +591,10 @@ galaxy {
|
||||
planet.species_kind = (planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet.goatsoup_seed[1] = msb(seed[1])
|
||||
planet.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy10 {
|
||||
sub init(ubyte galaxy10num) {
|
||||
number = 1
|
||||
planet10.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy10num-1 {
|
||||
nextgalaxy10()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy10() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -576,8 +580,10 @@ galaxy10 {
|
||||
planet10.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
|
||||
planet10.species_kind = (planet10.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet10.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet10.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet10.goatsoup_seed[1] = msb(seed[1])
|
||||
planet10.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet10.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy2 {
|
||||
sub init(ubyte galaxy2num) {
|
||||
number = 1
|
||||
planet2.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy2num-1 {
|
||||
nextgalaxy2()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy2() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy2 {
|
||||
planet2.species_kind = (planet2.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet2.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet2.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet2.goatsoup_seed[1] = msb(seed[1])
|
||||
planet2.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet2.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy3 {
|
||||
sub init(ubyte galaxy3num) {
|
||||
number = 1
|
||||
planet3.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy3num-1 {
|
||||
nextgalaxy3()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy3() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy3 {
|
||||
planet3.species_kind = (planet3.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet3.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet3.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet3.goatsoup_seed[1] = msb(seed[1])
|
||||
planet3.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet3.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy4 {
|
||||
sub init(ubyte galaxy4num) {
|
||||
number = 1
|
||||
planet4.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy4num-1 {
|
||||
nextgalaxy4()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy4() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy4 {
|
||||
planet4.species_kind = (planet4.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet4.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet4.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet4.goatsoup_seed[1] = msb(seed[1])
|
||||
planet4.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet4.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy5 {
|
||||
sub init(ubyte galaxy5num) {
|
||||
number = 1
|
||||
planet5.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy5num-1 {
|
||||
nextgalaxy5()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy5() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy5 {
|
||||
planet5.species_kind = (planet5.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet5.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet5.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet5.goatsoup_seed[1] = msb(seed[1])
|
||||
planet5.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet5.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy6 {
|
||||
sub init(ubyte galaxy6num) {
|
||||
number = 1
|
||||
planet6.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy6num-1 {
|
||||
nextgalaxy6()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy6() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy6 {
|
||||
planet6.species_kind = (planet6.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet6.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet6.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet6.goatsoup_seed[1] = msb(seed[1])
|
||||
planet6.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet6.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy7 {
|
||||
sub init(ubyte galaxy7num) {
|
||||
number = 1
|
||||
planet7.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy7num-1 {
|
||||
nextgalaxy7()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy7() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy7 {
|
||||
planet7.species_kind = (planet7.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet7.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet7.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet7.goatsoup_seed[1] = msb(seed[1])
|
||||
planet7.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet7.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy8 {
|
||||
sub init(ubyte galaxy8num) {
|
||||
number = 1
|
||||
planet8.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy8num-1 {
|
||||
nextgalaxy8()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy8() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -577,7 +581,10 @@ galaxy8 {
|
||||
planet8.species_kind = (planet8.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet8.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet8.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet8.goatsoup_seed[1] = msb(seed[1])
|
||||
planet8.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet8.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -396,14 +396,18 @@ galaxy9 {
|
||||
sub init(ubyte galaxy9num) {
|
||||
number = 1
|
||||
planet9.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxy9num-1 {
|
||||
nextgalaxy9()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy9() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -576,8 +580,10 @@ galaxy9 {
|
||||
planet9.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
|
||||
planet9.species_kind = (planet9.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet9.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet9.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet9.goatsoup_seed[1] = msb(seed[1])
|
||||
planet9.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet9.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
%target cx16
|
||||
%import palette
|
||||
%import conv
|
||||
%import textio
|
||||
|
||||
; "unlimited sprites / bobs" demo effect.
|
||||
; Note that everything is prog8, no inline assembly used/required.
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
cx16.screen_set_mode(0)
|
||||
txt.print("\n\n how many sprites does\n the commander x16 have?\n")
|
||||
sys.wait(180)
|
||||
txt.print("\n\n the manual says: '128'.\n")
|
||||
sys.wait(80)
|
||||
txt.print("\n\n but that's just a manual...\n")
|
||||
sys.wait(80)
|
||||
txt.print("\n\n let's find out for ourselves,\n shall we?")
|
||||
sys.wait(180)
|
||||
|
||||
; enable bitmap mode 320x240, 1 bpp, only layer 1
|
||||
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000
|
||||
cx16.VERA_DC_HSCALE = 64
|
||||
cx16.VERA_DC_VSCALE = 64
|
||||
cx16.VERA_L1_CONFIG = %00000100
|
||||
cx16.VERA_L1_MAPBASE = 0
|
||||
cx16.VERA_L1_TILEBASE = 0
|
||||
|
||||
; limit display heigth to 200 pixels to have enough vram for 14 backbuffers
|
||||
const ubyte vstart = 20
|
||||
const ubyte vheight = 200
|
||||
cx16.VERA_CTRL = %00000010
|
||||
cx16.VERA_DC_VSTART = vstart
|
||||
cx16.VERA_DC_VSTOP = vstart + vheight - 1
|
||||
|
||||
init_buffers()
|
||||
palette.set_color(0, $000)
|
||||
palette.set_color(1, $af8)
|
||||
|
||||
cx16.set_rasterirq(&irq, 340) ; time it so that the page flip occurs near the bottom of the screen to avoid tearing
|
||||
|
||||
repeat {
|
||||
; don't exit
|
||||
}
|
||||
}
|
||||
|
||||
const ubyte num_backbuffers = 12 ; there is vram space for 14 backbuffers. reduce to make tighter "loops"
|
||||
uword num_bobs = 0
|
||||
ubyte backbuffer = num_backbuffers-1
|
||||
ubyte blitbuffer = 0
|
||||
uword anim1 = $0432
|
||||
uword anim2 = $0123
|
||||
uword anim3 = $4321
|
||||
uword anim4 = $8500
|
||||
|
||||
sub irq() {
|
||||
|
||||
; palette.set_color(0, $f00) ; debug rastertime
|
||||
|
||||
; draw 2 bobs per frame to speed up bob count
|
||||
ubyte vmembase = blitbuffer*4 ; 2048 * 4 per backbuffer
|
||||
blit(vmembase)
|
||||
blitbuffer++
|
||||
if blitbuffer==num_backbuffers
|
||||
blitbuffer=0
|
||||
vmembase = blitbuffer*4 ; 2048 * 4 per backbuffer
|
||||
blit(vmembase)
|
||||
blitbuffer++
|
||||
if blitbuffer==num_backbuffers
|
||||
blitbuffer=0
|
||||
|
||||
backbuffer++
|
||||
if backbuffer==num_backbuffers {
|
||||
backbuffer=0
|
||||
num_bobs+=2
|
||||
}
|
||||
|
||||
vmembase = backbuffer*4 ; 2048 * 4 per backbuffer
|
||||
draw_number(vmembase, num_bobs)
|
||||
cx16.VERA_L1_TILEBASE = vmembase << 2 ; flip to next backbuffer
|
||||
|
||||
; palette.set_color(0, $000)
|
||||
}
|
||||
|
||||
sub init_buffers() {
|
||||
; erase all vram
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_L = 0
|
||||
cx16.VERA_ADDR_M = 0
|
||||
cx16.VERA_ADDR_H = %00010000 ; auto incr 1
|
||||
repeat $ffff
|
||||
cx16.VERA_DATA0 = 0
|
||||
repeat $f960
|
||||
cx16.VERA_DATA0 = 0
|
||||
}
|
||||
|
||||
sub blit(ubyte vmembase) {
|
||||
ubyte bank = vmembase>=32
|
||||
uword vmem = vmembase * 2048 ; mkword(vmembase,0) * 8
|
||||
uword blit_x = (cos8u(msb(anim1)) as uword) + sin8u(msb(anim2))/5
|
||||
ubyte blit_y = sin8u(msb(anim3))/2 + cos8u(msb(anim4))/5
|
||||
vmem += blit_x/8 + (blit_y as uword) * 40
|
||||
|
||||
bitshift(lsb(blit_x) & 7)
|
||||
|
||||
; left column of the (shifted)sprite
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
cx16.VERA_ADDR_H = bank | %10110000 ; increment 40 for read (next line)
|
||||
cx16.VERA_CTRL = 1
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
cx16.VERA_ADDR_H = bank | %10110000 ; increment 40 for read (next line)
|
||||
ubyte ix
|
||||
for ix in 0 to len(shifted_sprite)-1 step 3
|
||||
cx16.VERA_DATA1 = cx16.VERA_DATA0 & shifted_mask[ix] | shifted_sprite[ix]
|
||||
|
||||
; middle column of the (shifted)sprite
|
||||
vmem++
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
cx16.VERA_CTRL = 1
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
for ix in 1 to len(shifted_sprite)-1 step 3
|
||||
cx16.VERA_DATA1 = cx16.VERA_DATA0 & shifted_mask[ix] | shifted_sprite[ix]
|
||||
|
||||
; right column of the (shifted)sprite
|
||||
vmem++
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
cx16.VERA_CTRL = 1
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
for ix in 2 to len(shifted_sprite)-1 step 3
|
||||
cx16.VERA_DATA1 = cx16.VERA_DATA0 & shifted_mask[ix] | shifted_sprite[ix]
|
||||
|
||||
anim1 += 217
|
||||
anim2 += 190
|
||||
anim3 += 222
|
||||
anim4 += 195
|
||||
}
|
||||
|
||||
sub bitshift(ubyte shift) {
|
||||
ubyte yix
|
||||
ubyte yy
|
||||
for yy in 0 to 15 {
|
||||
uword @zp sprw = sprite[yy]
|
||||
uword @zp maskw = mask[yy]
|
||||
ubyte @zp sprite_3 = 0
|
||||
ubyte @zp mask_3 = 255
|
||||
repeat shift {
|
||||
sprw >>= 1
|
||||
ror(sprite_3)
|
||||
sys.set_carry()
|
||||
ror(maskw)
|
||||
ror(mask_3)
|
||||
}
|
||||
shifted_sprite[yix] = msb(sprw)
|
||||
shifted_mask[yix] = msb(maskw)
|
||||
yix++
|
||||
shifted_sprite[yix] = lsb(sprw)
|
||||
shifted_mask[yix] = lsb(maskw)
|
||||
yix++
|
||||
shifted_sprite[yix] = sprite_3
|
||||
shifted_mask[yix] = mask_3
|
||||
yix++
|
||||
}
|
||||
}
|
||||
|
||||
sub draw_number(ubyte vmembase, uword number) {
|
||||
uword vmem = vmembase * 2048 ; mkword(vmembase,0) * 8
|
||||
ubyte bank = vmembase>=32
|
||||
vmem += 35
|
||||
conv.str_uw0(number)
|
||||
uword pixelsptr = &numberpixels + (conv.string_out[1] & 15)*7
|
||||
ubyte pix
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
cx16.VERA_ADDR_H = bank | %10110000 ; increment 40 for read (next line)
|
||||
for pix in 0 to 6
|
||||
cx16.VERA_DATA0 = pixelsptr[pix]
|
||||
vmem++
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
pixelsptr = &numberpixels + (conv.string_out[2] & 15)*7
|
||||
for pix in 0 to 6
|
||||
cx16.VERA_DATA0 = pixelsptr[pix]
|
||||
vmem++
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
pixelsptr = &numberpixels + (conv.string_out[3] & 15)*7
|
||||
for pix in 0 to 6
|
||||
cx16.VERA_DATA0 = pixelsptr[pix]
|
||||
vmem++
|
||||
cx16.VERA_ADDR_L = lsb(vmem)
|
||||
cx16.VERA_ADDR_M = msb(vmem)
|
||||
pixelsptr = &numberpixels + (conv.string_out[4] & 15)*7
|
||||
for pix in 0 to 6
|
||||
cx16.VERA_DATA0 = pixelsptr[pix]
|
||||
}
|
||||
|
||||
ubyte[10*7] numberpixels = [
|
||||
%00111000,
|
||||
%01000100,
|
||||
%10000100,
|
||||
%10000100,
|
||||
%10000100,
|
||||
%01111000,
|
||||
%00000000,
|
||||
|
||||
%00010000,
|
||||
%00110000,
|
||||
%01010000,
|
||||
%00010000,
|
||||
%00010000,
|
||||
%01111100,
|
||||
%00000000,
|
||||
|
||||
%01111000,
|
||||
%10000100,
|
||||
%00011000,
|
||||
%00110000,
|
||||
%01100000,
|
||||
%11111100,
|
||||
%00000000,
|
||||
|
||||
%01111000,
|
||||
%00000100,
|
||||
%00111000,
|
||||
%00000100,
|
||||
%00000100,
|
||||
%11111000,
|
||||
%00000000,
|
||||
|
||||
%00010100,
|
||||
%00100100,
|
||||
%01000100,
|
||||
%11111100,
|
||||
%00000100,
|
||||
%00000100,
|
||||
%00000000,
|
||||
|
||||
%11111000,
|
||||
%10000000,
|
||||
%11111000,
|
||||
%00000100,
|
||||
%00000100,
|
||||
%11111000,
|
||||
%00000000,
|
||||
|
||||
%01111000,
|
||||
%10000000,
|
||||
%11111000,
|
||||
%10000100,
|
||||
%10000100,
|
||||
%01111000,
|
||||
%00000000,
|
||||
|
||||
%11111100,
|
||||
%00001000,
|
||||
%00010000,
|
||||
%00010000,
|
||||
%00010000,
|
||||
%00010000,
|
||||
%00000000,
|
||||
|
||||
%01111000,
|
||||
%10000100,
|
||||
%01111000,
|
||||
%10000100,
|
||||
%10000100,
|
||||
%01111000,
|
||||
%00000000,
|
||||
|
||||
%01111000,
|
||||
%10000100,
|
||||
%01111100,
|
||||
%00000100,
|
||||
%10000100,
|
||||
%01111000,
|
||||
%00000000
|
||||
]
|
||||
|
||||
uword[16] sprite = [
|
||||
%0000000000000000,
|
||||
%0110001110000000,
|
||||
%0101001001000000,
|
||||
%0100111001000000,
|
||||
%0100000000100000,
|
||||
%0101001000100000,
|
||||
%0101001000110000,
|
||||
%0100100000101000,
|
||||
%0101111000101000,
|
||||
%0010000001010100,
|
||||
%0001111110010100,
|
||||
%0001000000010000,
|
||||
%0001000000010000,
|
||||
%0001010111010000,
|
||||
%0001101100110000,
|
||||
%0000000000000000
|
||||
]
|
||||
|
||||
uword[16] mask = [
|
||||
%1111111111111111,
|
||||
%1000000001111111,
|
||||
%1000000000111111,
|
||||
%1000000000111111,
|
||||
%1000000000011111,
|
||||
%1000000000011111,
|
||||
%1000000000001111,
|
||||
%1000000000000111,
|
||||
%1000000000000111,
|
||||
%1100000000001011,
|
||||
%1110000000001011,
|
||||
%1110000000001111,
|
||||
%1110000000001111,
|
||||
%1110000000001111,
|
||||
%1110010011001111,
|
||||
%1111111111111111
|
||||
]
|
||||
|
||||
ubyte[16*3] shifted_sprite
|
||||
ubyte[16*3] shifted_mask
|
||||
}
|
||||
@@ -64,25 +64,25 @@ main {
|
||||
|
||||
asmsub print_number_gfx(ubyte num @ A) clobbers(A,Y) {
|
||||
%asm {{
|
||||
phx
|
||||
jsr conv.ubyte2decimal
|
||||
phx
|
||||
pha
|
||||
cpy #'0'
|
||||
beq +
|
||||
tya
|
||||
jsr cx16.GRAPH_put_char
|
||||
pla
|
||||
jsr cx16.GRAPH_put_char
|
||||
jmp _ones
|
||||
+ pla
|
||||
phx
|
||||
jsr conv.ubyte2decimal
|
||||
phx
|
||||
pha
|
||||
cpy #'0'
|
||||
beq +
|
||||
tya
|
||||
jsr cx16.GRAPH_put_char
|
||||
pla
|
||||
jsr cx16.GRAPH_put_char
|
||||
bra _ones
|
||||
+ pla
|
||||
cmp #'0'
|
||||
beq _ones
|
||||
jsr cx16.GRAPH_put_char
|
||||
_ones pla
|
||||
jsr cx16.GRAPH_put_char
|
||||
plx
|
||||
rts
|
||||
_ones pla
|
||||
jsr cx16.GRAPH_put_char
|
||||
plx
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
%target cx16
|
||||
%import palette
|
||||
%option no_sysinit
|
||||
|
||||
; Vertical rasterbars a.k.a. "Kefren bars"
|
||||
; also see: rasterbars.p8
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
uword[32] colors = [
|
||||
$000,
|
||||
$011, $112, $213, $214,
|
||||
$315, $316, $417, $418,
|
||||
$519, $51a, $62b, $62c,
|
||||
$73d, $73e, $84f, $94f,
|
||||
$93e, $83d, $82c, $72b,
|
||||
$71a, $619, $618, $517,
|
||||
$516, $415, $414, $313,
|
||||
$312, $211, $100
|
||||
]
|
||||
|
||||
; Not yet implemented in ROM: cx16.FB_set_palette(&colors, 0, len(colors)*3)
|
||||
palette.set_rgb(&colors, len(colors))
|
||||
cx16.screen_set_mode(128) ; low-res bitmap 256 colors
|
||||
cx16.FB_init()
|
||||
cx16.VERA_DC_VSCALE = 0 ; display trick spoiler.......: stretch display all the way to the bottom
|
||||
cx16.set_rasterirq(&irq.irq, 0)
|
||||
|
||||
repeat {
|
||||
; don't exit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
irq {
|
||||
uword next_irq_line = 0
|
||||
ubyte anim1 = 0
|
||||
ubyte av1 = 0
|
||||
ubyte anim2 = 0
|
||||
ubyte av2 = 0
|
||||
|
||||
ubyte[32] pixels = 0 to 31
|
||||
|
||||
sub irq() {
|
||||
next_irq_line += 6
|
||||
anim1 += 4
|
||||
anim2 += 6
|
||||
if next_irq_line > 400 {
|
||||
av1++
|
||||
av2 += 2
|
||||
anim1 = av1
|
||||
anim2 = av2
|
||||
next_irq_line = 0
|
||||
; erase the bars
|
||||
cx16.FB_cursor_position(0, 0)
|
||||
cx16.FB_fill_pixels(320, 1, 0)
|
||||
} else {
|
||||
; add new bar
|
||||
cx16.FB_cursor_position(sin8u(anim1)/2 + cos8u(anim2)/2 + $0010, 0)
|
||||
cx16.FB_set_pixels(pixels, len(pixels))
|
||||
}
|
||||
|
||||
cx16.set_rasterline(next_irq_line)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
%import textio
|
||||
%import palette
|
||||
|
||||
; horizontal raster bars
|
||||
; also see: kefrenbars.p8
|
||||
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
@@ -9,7 +13,6 @@ main {
|
||||
txt.plot(14,14)
|
||||
txt.print("raster bars!")
|
||||
|
||||
cx16.rombank(0) ; switch to kernal rom for faster irq handling
|
||||
cx16.set_rasterirq(&irq.irq, 0)
|
||||
|
||||
repeat {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
%import gfx2
|
||||
%import textio
|
||||
%import test_stack
|
||||
%zeropage dontuse
|
||||
|
||||
main {
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
; todo feedback: new routines at the end of the jump table so existing jump vectors remain unchanged
|
||||
|
||||
txt.lowercase()
|
||||
|
||||
vtui.initialize()
|
||||
|
||||
@@ -14,4 +14,3 @@ main {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ main {
|
||||
ubyte @zp ii
|
||||
for ii in 0 to 7 {
|
||||
; use 16 bit rng for a bit more randomness instead of the 8-bit rng
|
||||
if lsb(rndw()) > s {
|
||||
if rnd() > s {
|
||||
b |= bittab[ii]
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ main {
|
||||
for i in 0 to 7 {
|
||||
c64.SPRPTR[i] = $0a00 / 64
|
||||
c64.SPXY[i*2] = 50+25*i
|
||||
c64.SPXY[i*2+1] = rnd()
|
||||
c64.SPXY[i*2+1] = fastrnd8()
|
||||
}
|
||||
|
||||
c64.SPENA = 255 ; enable all sprites
|
||||
@@ -60,7 +60,7 @@ irq {
|
||||
ubyte @zp i
|
||||
for i in 0 to 14 step 2 {
|
||||
c64.SPXY[i+1]--
|
||||
ubyte @zp r = rnd()
|
||||
ubyte @zp r = fastrnd8()
|
||||
if r>200
|
||||
c64.SPXY[i]++
|
||||
else if r<40
|
||||
|
||||
+2
-11
@@ -1,18 +1,9 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
uword screen = 2000
|
||||
ubyte i = 1
|
||||
uword w = 33
|
||||
str derp ="derp"
|
||||
ubyte[] array = [1,2,3]
|
||||
|
||||
@(screen+i) = 128
|
||||
@(i+screen) = 129
|
||||
|
||||
txt.print("done\n")
|
||||
txt.print("hello")
|
||||
}
|
||||
}
|
||||
+10
-3
@@ -414,14 +414,18 @@ galaxy {
|
||||
sub init(ubyte galaxynum) {
|
||||
number = 1
|
||||
planet.number = 255
|
||||
seed = [base0, base1, base2]
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxynum-1 {
|
||||
nextgalaxy()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy() {
|
||||
seed = [twist(seed[0]), twist(seed[1]), twist(seed[2])]
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
@@ -658,7 +662,10 @@ galaxy {
|
||||
planet.species_kind = (planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet.goatsoup_seed = [lsb(seed[1]), msb(seed[1]), lsb(seed[2]), seed2_msb]
|
||||
planet.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet.goatsoup_seed[1] = msb(seed[1])
|
||||
planet.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<keywords keywords="&;->;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
|
||||
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%target;%zeropage;%zpreserved" />
|
||||
<keywords3 keywords="byte;const;float;str;struct;ubyte;uword;void;word;zp" />
|
||||
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;ceil;cos;cos16;cos16u;cos8;cos8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;offsetof;peek;peekw;poke;pokew;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
|
||||
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;ceil;cos;cos16;cos16u;cos8;cos8u;deg;fastrnd8;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;offsetof;peek;peekw;poke;pokew;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
<mapping ext="p8" />
|
||||
|
||||
Reference in new issue
Block a user