mirror of
https://github.com/irmen/prog8.git
synced 2024-09-30 00:55:52 +00:00
added preliminary CommanderX16 machine target support. Fixed nullpointer when importing a missing file.
This commit is contained in:
parent
256781bba5
commit
b939562062
@ -11,10 +11,6 @@
|
|||||||
|
|
||||||
c64utils {
|
c64utils {
|
||||||
|
|
||||||
const uword ESTACK_LO = $ce00
|
|
||||||
const uword ESTACK_HI = $cf00
|
|
||||||
|
|
||||||
|
|
||||||
; ----- number conversions to decimal strings
|
; ----- number conversions to decimal strings
|
||||||
|
|
||||||
asmsub ubyte2decimal (ubyte value @ A) -> ubyte @ Y, ubyte @ A, ubyte @ X {
|
asmsub ubyte2decimal (ubyte value @ A) -> ubyte @ Y, ubyte @ A, ubyte @ X {
|
||||||
|
79
compiler/res/prog8lib/cx16lib.p8
Normal file
79
compiler/res/prog8lib/cx16lib.p8
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
; Prog8 definitions for the CommanderX16
|
||||||
|
; Including memory registers, I/O registers, Basic and Kernal subroutines.
|
||||||
|
;
|
||||||
|
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
|
;
|
||||||
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
|
|
||||||
|
cx16 {
|
||||||
|
|
||||||
|
; ---- C64 kernal routines ----
|
||||||
|
|
||||||
|
romsub $FF81 = CINT() clobbers(A,X,Y) ; (alias: SCINIT) initialize screen editor and video chip
|
||||||
|
romsub $FF84 = IOINIT() clobbers(A, X) ; initialize I/O devices (CIA, SID, IRQ)
|
||||||
|
romsub $FF87 = RAMTAS() clobbers(A,X,Y) ; initialize RAM, tape buffer, screen
|
||||||
|
romsub $FF8A = RESTOR() clobbers(A,X,Y) ; restore default I/O vectors
|
||||||
|
romsub $FF8D = VECTOR(uword userptr @ XY, ubyte dir @ Pc) clobbers(A,Y) ; read/set I/O vector table
|
||||||
|
romsub $FF90 = SETMSG(ubyte value @ A) ; set Kernal message control flag
|
||||||
|
romsub $FF93 = SECOND(ubyte address @ A) clobbers(A) ; (alias: LSTNSA) send secondary address after LISTEN
|
||||||
|
romsub $FF96 = TKSA(ubyte address @ A) clobbers(A) ; (alias: TALKSA) send secondary address after TALK
|
||||||
|
romsub $FF99 = MEMTOP(uword address @ XY, ubyte dir @ Pc) -> uword @ XY ; read/set top of memory pointer
|
||||||
|
romsub $FF9C = MEMBOT(uword address @ XY, ubyte dir @ Pc) -> uword @ XY ; read/set bottom of memory pointer
|
||||||
|
romsub $FF9F = SCNKEY() clobbers(A,X,Y) ; scan the keyboard
|
||||||
|
romsub $FFA2 = SETTMO(ubyte timeout @ A) ; set time-out flag for IEEE bus
|
||||||
|
romsub $FFA5 = ACPTR() -> ubyte @ A ; (alias: IECIN) input byte from serial bus
|
||||||
|
romsub $FFA8 = CIOUT(ubyte databyte @ A) ; (alias: IECOUT) output byte to serial bus
|
||||||
|
romsub $FFAB = UNTLK() clobbers(A) ; command serial bus device to UNTALK
|
||||||
|
romsub $FFAE = UNLSN() clobbers(A) ; command serial bus device to UNLISTEN
|
||||||
|
romsub $FFB1 = LISTEN(ubyte device @ A) clobbers(A) ; command serial bus device to LISTEN
|
||||||
|
romsub $FFB4 = TALK(ubyte device @ A) clobbers(A) ; command serial bus device to TALK
|
||||||
|
romsub $FFB7 = READST() -> ubyte @ A ; read I/O status word
|
||||||
|
romsub $FFBA = SETLFS(ubyte logical @ A, ubyte device @ X, ubyte address @ Y) ; set logical file parameters
|
||||||
|
romsub $FFBD = SETNAM(ubyte namelen @ A, str filename @ XY) ; set filename parameters
|
||||||
|
romsub $FFC0 = OPEN() clobbers(A,X,Y) ; (via 794 ($31A)) open a logical file
|
||||||
|
romsub $FFC3 = CLOSE(ubyte logical @ A) clobbers(A,X,Y) ; (via 796 ($31C)) close a logical file
|
||||||
|
romsub $FFC6 = CHKIN(ubyte logical @ X) clobbers(A,X) ; (via 798 ($31E)) define an input channel
|
||||||
|
romsub $FFC9 = CHKOUT(ubyte logical @ X) clobbers(A,X) ; (via 800 ($320)) define an output channel
|
||||||
|
romsub $FFCC = CLRCHN() clobbers(A,X) ; (via 802 ($322)) restore default devices
|
||||||
|
romsub $FFCF = CHRIN() clobbers(Y) -> ubyte @ A ; (via 804 ($324)) input a character (for keyboard, read a whole line from the screen) A=byte read.
|
||||||
|
romsub $FFD2 = CHROUT(ubyte char @ A) ; (via 806 ($326)) output a character
|
||||||
|
romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> ubyte @Pc, ubyte @ A, ubyte @ X, ubyte @ Y ; (via 816 ($330)) load from device
|
||||||
|
romsub $FFD8 = SAVE(ubyte zp_startaddr @ A, uword endaddr @ XY) -> ubyte @ Pc, ubyte @ A ; (via 818 ($332)) save to a device
|
||||||
|
romsub $FFDB = SETTIM(ubyte low @ A, ubyte middle @ X, ubyte high @ Y) ; set the software clock
|
||||||
|
romsub $FFDE = RDTIM() -> ubyte @ A, ubyte @ X, ubyte @ Y ; read the software clock
|
||||||
|
romsub $FFE1 = STOP() clobbers(A,X) -> ubyte @ Pz, ubyte @ Pc ; (via 808 ($328)) check the STOP key
|
||||||
|
romsub $FFE4 = GETIN() clobbers(X,Y) -> ubyte @ A ; (via 810 ($32A)) get a character
|
||||||
|
romsub $FFE7 = CLALL() clobbers(A,X) ; (via 812 ($32C)) close all files
|
||||||
|
romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock
|
||||||
|
romsub $FFED = SCREEN() -> ubyte @ X, ubyte @ Y ; read number of screen rows and columns
|
||||||
|
romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, ubyte dir @ Pc) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use c64scr.plot for a 'safe' wrapper that preserves X.
|
||||||
|
romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices
|
||||||
|
|
||||||
|
|
||||||
|
; ---- end of kernal routines ----
|
||||||
|
|
||||||
|
asmsub init_system() {
|
||||||
|
; Initializes the machine to a sane starting state.
|
||||||
|
; Called automatically by the loader program logic.
|
||||||
|
%asm {{
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
;lda #%00101111
|
||||||
|
;sta $00
|
||||||
|
;lda #%00100111
|
||||||
|
;sta $01
|
||||||
|
jsr cx16.IOINIT
|
||||||
|
jsr cx16.RESTOR
|
||||||
|
jsr cx16.CINT
|
||||||
|
lda #0
|
||||||
|
tax
|
||||||
|
tay
|
||||||
|
clc
|
||||||
|
clv
|
||||||
|
cli
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
604
compiler/res/prog8lib/cx16utils.p8
Normal file
604
compiler/res/prog8lib/cx16utils.p8
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
; Prog8 definitions for the CommanderX16
|
||||||
|
; These are the utility subroutines.
|
||||||
|
;
|
||||||
|
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
|
;
|
||||||
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
|
|
||||||
|
%import cx16lib
|
||||||
|
|
||||||
|
|
||||||
|
cx16utils {
|
||||||
|
|
||||||
|
; ----- 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
|
||||||
|
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
; ----- utility functions ----
|
||||||
|
|
||||||
|
|
||||||
|
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_X
|
||||||
|
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_X
|
||||||
|
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)
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub str2uword(str string @ AY) -> uword @ AY {
|
||||||
|
; -- returns the unsigned word value of the string number argument in AY
|
||||||
|
; the number may NOT be preceded by a + sign and may NOT contain spaces
|
||||||
|
; (any non-digit character will terminate the number string that is parsed)
|
||||||
|
%asm {{
|
||||||
|
_result = P8ZP_SCRATCH_W2
|
||||||
|
sta _mod+1
|
||||||
|
sty _mod+2
|
||||||
|
ldy #0
|
||||||
|
sty _result
|
||||||
|
sty _result+1
|
||||||
|
_mod lda $ffff,y ; modified
|
||||||
|
sec
|
||||||
|
sbc #48
|
||||||
|
bpl +
|
||||||
|
_done ; return result
|
||||||
|
lda _result
|
||||||
|
ldy _result+1
|
||||||
|
rts
|
||||||
|
+ cmp #10
|
||||||
|
bcs _done
|
||||||
|
; add digit to result
|
||||||
|
pha
|
||||||
|
jsr _result_times_10
|
||||||
|
pla
|
||||||
|
clc
|
||||||
|
adc _result
|
||||||
|
sta _result
|
||||||
|
bcc +
|
||||||
|
inc _result+1
|
||||||
|
+ iny
|
||||||
|
bne _mod
|
||||||
|
; never reached
|
||||||
|
|
||||||
|
_result_times_10 ; (W*4 + W)*2
|
||||||
|
lda _result+1
|
||||||
|
sta P8ZP_SCRATCH_REG
|
||||||
|
lda _result
|
||||||
|
asl a
|
||||||
|
rol P8ZP_SCRATCH_REG
|
||||||
|
asl a
|
||||||
|
rol P8ZP_SCRATCH_REG
|
||||||
|
clc
|
||||||
|
adc _result
|
||||||
|
sta _result
|
||||||
|
lda P8ZP_SCRATCH_REG
|
||||||
|
adc _result+1
|
||||||
|
asl _result
|
||||||
|
rol a
|
||||||
|
sta _result+1
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub str2word(str string @ AY) -> word @ AY {
|
||||||
|
; -- returns the signed word value of the string number argument in AY
|
||||||
|
; the number may be preceded by a + or - sign but may NOT contain spaces
|
||||||
|
; (any non-digit character will terminate the number string that is parsed)
|
||||||
|
%asm {{
|
||||||
|
_result = P8ZP_SCRATCH_W2
|
||||||
|
sta P8ZP_SCRATCH_W1
|
||||||
|
sty P8ZP_SCRATCH_W1+1
|
||||||
|
ldy #0
|
||||||
|
sty _result
|
||||||
|
sty _result+1
|
||||||
|
sty _negative
|
||||||
|
lda (P8ZP_SCRATCH_W1),y
|
||||||
|
cmp #'+'
|
||||||
|
bne +
|
||||||
|
iny
|
||||||
|
+ cmp #'-'
|
||||||
|
bne _parse
|
||||||
|
inc _negative
|
||||||
|
iny
|
||||||
|
_parse lda (P8ZP_SCRATCH_W1),y
|
||||||
|
sec
|
||||||
|
sbc #48
|
||||||
|
bpl _digit
|
||||||
|
_done ; return result
|
||||||
|
lda _negative
|
||||||
|
beq +
|
||||||
|
sec
|
||||||
|
lda #0
|
||||||
|
sbc _result
|
||||||
|
sta _result
|
||||||
|
lda #0
|
||||||
|
sbc _result+1
|
||||||
|
sta _result+1
|
||||||
|
+ lda _result
|
||||||
|
ldy _result+1
|
||||||
|
rts
|
||||||
|
_digit cmp #10
|
||||||
|
bcs _done
|
||||||
|
; add digit to result
|
||||||
|
pha
|
||||||
|
jsr str2uword._result_times_10
|
||||||
|
pla
|
||||||
|
clc
|
||||||
|
adc _result
|
||||||
|
sta _result
|
||||||
|
bcc +
|
||||||
|
inc _result+1
|
||||||
|
+ iny
|
||||||
|
bne _parse
|
||||||
|
; never reached
|
||||||
|
_negative .byte 0
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} ; ------ end of block cx16utils
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
screen {
|
||||||
|
|
||||||
|
; ---- this block contains (character) Screen and text I/O related functions ----
|
||||||
|
|
||||||
|
|
||||||
|
asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) {
|
||||||
|
; ---- clear the character screen with the given fill character and character color.
|
||||||
|
; (assumes screen and color matrix are at their default addresses)
|
||||||
|
|
||||||
|
%asm {{
|
||||||
|
brk ; TODO
|
||||||
|
}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print (str text @ AY) clobbers(A,Y) {
|
||||||
|
; ---- print null terminated string from A/Y
|
||||||
|
; note: the compiler contains an optimization that will replace
|
||||||
|
; a call to this subroutine with a string argument of just one char,
|
||||||
|
; by just one call to cx16.CHROUT of that single char.
|
||||||
|
%asm {{
|
||||||
|
sta P8ZP_SCRATCH_B1
|
||||||
|
sty P8ZP_SCRATCH_REG
|
||||||
|
ldy #0
|
||||||
|
- lda (P8ZP_SCRATCH_B1),y
|
||||||
|
beq +
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
iny
|
||||||
|
bne -
|
||||||
|
+ rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_ub0 (ubyte value @ A) clobbers(A,Y) {
|
||||||
|
; ---- print the ubyte in A in decimal form, with left padding 0s (3 positions total)
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
jsr cx16utils.ubyte2decimal
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
pla
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
txa
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_ub (ubyte value @ A) clobbers(A,Y) {
|
||||||
|
; ---- print the ubyte in A in decimal form, without left padding 0s
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
jsr cx16utils.ubyte2decimal
|
||||||
|
_print_byte_digits
|
||||||
|
pha
|
||||||
|
cpy #'0'
|
||||||
|
beq +
|
||||||
|
tya
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
pla
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
jmp _ones
|
||||||
|
+ pla
|
||||||
|
cmp #'0'
|
||||||
|
beq _ones
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
_ones txa
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_b (byte value @ A) clobbers(A,Y) {
|
||||||
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
pha
|
||||||
|
cmp #0
|
||||||
|
bpl +
|
||||||
|
lda #'-'
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
+ pla
|
||||||
|
jsr cx16utils.byte2decimal
|
||||||
|
jsr print_ub._print_byte_digits
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_ubhex (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||||
|
; ---- print the ubyte in A in hex form (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
bcc +
|
||||||
|
pha
|
||||||
|
lda #'$'
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
pla
|
||||||
|
+ jsr cx16utils.ubyte2hex
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
tya
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_ubbin (ubyte value @ A, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||||
|
; ---- print the ubyte in A in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
sta P8ZP_SCRATCH_B1
|
||||||
|
bcc +
|
||||||
|
lda #'%'
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
+ ldy #8
|
||||||
|
- lda #'0'
|
||||||
|
asl P8ZP_SCRATCH_B1
|
||||||
|
bcc +
|
||||||
|
lda #'1'
|
||||||
|
+ jsr cx16.CHROUT
|
||||||
|
dey
|
||||||
|
bne -
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_uwbin (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||||
|
; ---- print the uword in A/Y in binary form (if Carry is set, a radix prefix '%' is printed as well)
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
jsr print_ubbin
|
||||||
|
pla
|
||||||
|
clc
|
||||||
|
jmp print_ubbin
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_uwhex (uword value @ AY, ubyte prefix @ Pc) clobbers(A,Y) {
|
||||||
|
; ---- print the uword in A/Y in hexadecimal form (4 digits)
|
||||||
|
; (if Carry is set, a radix prefix '$' is printed as well)
|
||||||
|
%asm {{
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
jsr print_ubhex
|
||||||
|
pla
|
||||||
|
clc
|
||||||
|
jmp print_ubhex
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_uw0 (uword value @ AY) clobbers(A,Y) {
|
||||||
|
; ---- print the uword in A/Y in decimal form, with left padding 0s (5 positions total)
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
jsr cx16utils.uword2decimal
|
||||||
|
ldy #0
|
||||||
|
- lda cx16utils.uword2decimal.decTenThousands,y
|
||||||
|
beq +
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
iny
|
||||||
|
bne -
|
||||||
|
+ ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_uw (uword value @ AY) clobbers(A,Y) {
|
||||||
|
; ---- print the uword in A/Y in decimal form, without left padding 0s
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
jsr cx16utils.uword2decimal
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
ldy #0
|
||||||
|
- lda cx16utils.uword2decimal.decTenThousands,y
|
||||||
|
beq _allzero
|
||||||
|
cmp #'0'
|
||||||
|
bne _gotdigit
|
||||||
|
iny
|
||||||
|
bne -
|
||||||
|
|
||||||
|
_gotdigit
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
iny
|
||||||
|
lda cx16utils.uword2decimal.decTenThousands,y
|
||||||
|
bne _gotdigit
|
||||||
|
rts
|
||||||
|
_allzero
|
||||||
|
lda #'0'
|
||||||
|
jmp cx16.CHROUT
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub print_w (word value @ AY) clobbers(A,Y) {
|
||||||
|
; ---- print the (signed) word in A/Y in decimal form, without left padding 0's
|
||||||
|
%asm {{
|
||||||
|
cpy #0
|
||||||
|
bpl +
|
||||||
|
pha
|
||||||
|
lda #'-'
|
||||||
|
jsr cx16.CHROUT
|
||||||
|
tya
|
||||||
|
eor #255
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
eor #255
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
bcc +
|
||||||
|
iny
|
||||||
|
+ jmp print_uw
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) {
|
||||||
|
; ---- safe wrapper around PLOT kernel routine, to save the X register.
|
||||||
|
%asm {{
|
||||||
|
stx P8ZP_SCRATCH_REG_X
|
||||||
|
tax
|
||||||
|
clc
|
||||||
|
jsr cx16.PLOT
|
||||||
|
ldx P8ZP_SCRATCH_REG_X
|
||||||
|
rts
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} ; ---- end block screen
|
@ -4,8 +4,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%import c64lib
|
|
||||||
|
|
||||||
math {
|
math {
|
||||||
%asminclude "library:math.asm", ""
|
%asminclude "library:math.asm", ""
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
;
|
;
|
||||||
; indent format: TABS, size=8
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
%import c64lib
|
|
||||||
|
|
||||||
prog8_lib {
|
prog8_lib {
|
||||||
%asminclude "library:prog8lib.asm", ""
|
%asminclude "library:prog8lib.asm", ""
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import prog8.compiler.target.CompilationTarget
|
|||||||
import prog8.compiler.target.c64.C64MachineDefinition
|
import prog8.compiler.target.c64.C64MachineDefinition
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import prog8.compiler.target.c64.codegen.AsmGen
|
import prog8.compiler.target.c64.codegen.AsmGen
|
||||||
|
import prog8.compiler.target.cx16.CX16MachineDefinition
|
||||||
import prog8.parser.ParsingFailedError
|
import prog8.parser.ParsingFailedError
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.file.FileSystems
|
import java.nio.file.FileSystems
|
||||||
@ -52,7 +53,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
when(compilationTarget) {
|
when(compilationTarget) {
|
||||||
"c64" -> {
|
"c64" -> {
|
||||||
with(CompilationTarget) {
|
with(CompilationTarget) {
|
||||||
name = "c64"
|
name = "Commodore-64"
|
||||||
machine = C64MachineDefinition
|
machine = C64MachineDefinition
|
||||||
encodeString = { str, altEncoding ->
|
encodeString = { str, altEncoding ->
|
||||||
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
||||||
@ -63,8 +64,21 @@ private fun compileMain(args: Array<String>) {
|
|||||||
asmGenerator = ::AsmGen
|
asmGenerator = ::AsmGen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"cx16" -> {
|
||||||
|
with(CompilationTarget) {
|
||||||
|
name = "Commander X16"
|
||||||
|
machine = CX16MachineDefinition
|
||||||
|
encodeString = { str, altEncoding ->
|
||||||
|
if(altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
|
||||||
|
}
|
||||||
|
decodeString = { bytes, altEncoding ->
|
||||||
|
if(altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||||
|
}
|
||||||
|
asmGenerator = ::AsmGen
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
System.err.println("invalid compilation target")
|
System.err.println("invalid compilation target. Available are: c64, cx16")
|
||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,20 +135,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
if (compilationResult.programName.isEmpty())
|
if (compilationResult.programName.isEmpty())
|
||||||
println("\nCan't start emulator because no program was assembled.")
|
println("\nCan't start emulator because no program was assembled.")
|
||||||
else if(startEmulator) {
|
else if(startEmulator) {
|
||||||
for(emulator in listOf("x64sc", "x64")) {
|
CompilationTarget.machine.launchEmulator(compilationResult.programName)
|
||||||
println("\nStarting C-64 emulator $emulator...")
|
|
||||||
val cmdline = listOf(emulator, "-silent", "-moncommands", "${compilationResult.programName}.vice-mon-list",
|
|
||||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", compilationResult.programName + ".prg")
|
|
||||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
|
||||||
val process: Process
|
|
||||||
try {
|
|
||||||
process=processb.start()
|
|
||||||
} catch(x: IOException) {
|
|
||||||
continue // try the next emulator executable
|
|
||||||
}
|
|
||||||
process.waitFor()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,11 +90,8 @@ private fun parseImports(filepath: Path, errors: ErrorReporter): Triple<Program,
|
|||||||
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG)
|
||||||
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.")
|
||||||
|
|
||||||
// if we're producing a PRG or BASIC program, include the c64utils and c64lib libraries
|
// depending on the mach9ine and compiler options we may have to include some libraries
|
||||||
if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) {
|
CompilationTarget.machine.importLibs(compilerOptions, importer, programAst)
|
||||||
importer.importLibraryModule(programAst, "c64lib")
|
|
||||||
importer.importLibraryModule(programAst, "c64utils")
|
|
||||||
}
|
|
||||||
|
|
||||||
// always import prog8lib and math
|
// always import prog8lib and math
|
||||||
importer.importLibraryModule(programAst, "math")
|
importer.importLibraryModule(programAst, "math")
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package prog8.compiler.target
|
package prog8.compiler.target
|
||||||
|
|
||||||
|
import prog8.ast.Program
|
||||||
import prog8.compiler.CompilationOptions
|
import prog8.compiler.CompilationOptions
|
||||||
import prog8.compiler.Zeropage
|
import prog8.compiler.Zeropage
|
||||||
|
import prog8.parser.ModuleImporter
|
||||||
|
|
||||||
|
|
||||||
interface IMachineFloat {
|
internal interface IMachineFloat {
|
||||||
fun toDouble(): Double
|
fun toDouble(): Double
|
||||||
fun makeFloatFillAsm(): String
|
fun makeFloatFillAsm(): String
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMachineDefinition {
|
internal interface IMachineDefinition {
|
||||||
val FLOAT_MAX_NEGATIVE: Double
|
val FLOAT_MAX_NEGATIVE: Double
|
||||||
val FLOAT_MAX_POSITIVE: Double
|
val FLOAT_MAX_POSITIVE: Double
|
||||||
val FLOAT_MEM_SIZE: Int
|
val FLOAT_MEM_SIZE: Int
|
||||||
@ -22,8 +24,11 @@ interface IMachineDefinition {
|
|||||||
val opcodeNames: Set<String>
|
val opcodeNames: Set<String>
|
||||||
var zeropage: Zeropage
|
var zeropage: Zeropage
|
||||||
val initSystemProcname: String
|
val initSystemProcname: String
|
||||||
|
val cpu: String
|
||||||
|
|
||||||
fun initializeZeropage(compilerOptions: CompilationOptions)
|
fun initializeZeropage(compilerOptions: CompilationOptions)
|
||||||
fun getFloat(num: Number): IMachineFloat
|
fun getFloat(num: Number): IMachineFloat
|
||||||
fun getFloatRomConst(number: Double): String?
|
fun getFloatRomConst(number: Double): String?
|
||||||
|
fun importLibs(compilerOptions: CompilationOptions, importer: ModuleImporter, program: Program)
|
||||||
|
fun launchEmulator(programName: String)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class AssemblyProgram(override val name: String, outputDir: Path) : IAssemblyPro
|
|||||||
val outFile = when (options.output) {
|
val outFile = when (options.output) {
|
||||||
OutputType.PRG -> {
|
OutputType.PRG -> {
|
||||||
command.add("--cbm-prg")
|
command.add("--cbm-prg")
|
||||||
println("\nCreating C-64 prg.")
|
println("\nCreating prg.")
|
||||||
prgFile
|
prgFile
|
||||||
}
|
}
|
||||||
OutputType.RAW -> {
|
OutputType.RAW -> {
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package prog8.compiler.target.c64
|
package prog8.compiler.target.c64
|
||||||
|
|
||||||
import prog8.compiler.CompilationOptions
|
import prog8.ast.Program
|
||||||
import prog8.compiler.CompilerException
|
import prog8.compiler.*
|
||||||
import prog8.compiler.Zeropage
|
|
||||||
import prog8.compiler.ZeropageType
|
|
||||||
import prog8.compiler.target.IMachineDefinition
|
import prog8.compiler.target.IMachineDefinition
|
||||||
import prog8.compiler.target.IMachineFloat
|
import prog8.compiler.target.IMachineFloat
|
||||||
|
import prog8.parser.ModuleImporter
|
||||||
|
import java.io.IOException
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
internal object C64MachineDefinition: IMachineDefinition {
|
internal object C64MachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
|
override val cpu = "6502"
|
||||||
|
|
||||||
// 5-byte cbm MFLPT format limitations:
|
// 5-byte cbm MFLPT format limitations:
|
||||||
override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
|
override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
|
||||||
override val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
|
override val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
|
||||||
@ -64,6 +66,31 @@ internal object C64MachineDefinition: IMachineDefinition {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun importLibs(compilerOptions: CompilationOptions, importer: ModuleImporter, program: Program) {
|
||||||
|
// if we're producing a PRG or BASIC program, include the c64utils and c64lib libraries
|
||||||
|
if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) {
|
||||||
|
importer.importLibraryModule(program, "c64lib")
|
||||||
|
importer.importLibraryModule(program, "c64utils")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun launchEmulator(programName: String) {
|
||||||
|
for(emulator in listOf("x64sc", "x64")) {
|
||||||
|
println("\nStarting C-64 emulator $emulator...")
|
||||||
|
val cmdline = listOf(emulator, "-silent", "-moncommands", "$programName.vice-mon-list",
|
||||||
|
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programName + ".prg")
|
||||||
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
|
val process: Process
|
||||||
|
try {
|
||||||
|
process=processb.start()
|
||||||
|
} catch(x: IOException) {
|
||||||
|
continue // try the next emulator executable
|
||||||
|
}
|
||||||
|
process.waitFor()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
||||||
zeropage = C64Zeropage(compilerOptions)
|
zeropage = C64Zeropage(compilerOptions)
|
||||||
}
|
}
|
||||||
@ -143,11 +170,11 @@ internal object C64MachineDefinition: IMachineDefinition {
|
|||||||
free.clear()
|
free.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(SCRATCH_B1 !in free)
|
require(SCRATCH_B1 !in free)
|
||||||
assert(SCRATCH_REG !in free)
|
require(SCRATCH_REG !in free)
|
||||||
assert(SCRATCH_REG_X !in free)
|
require(SCRATCH_REG_X !in free)
|
||||||
assert(SCRATCH_W1 !in free)
|
require(SCRATCH_W1 !in free)
|
||||||
assert(SCRATCH_W2 !in free)
|
require(SCRATCH_W2 !in free)
|
||||||
|
|
||||||
for (reserved in options.zpReserved)
|
for (reserved in options.zpReserved)
|
||||||
reserve(reserved)
|
reserve(reserved)
|
||||||
|
@ -78,11 +78,13 @@ internal class AsmGen(private val program: Program,
|
|||||||
|
|
||||||
private fun header() {
|
private fun header() {
|
||||||
val ourName = this.javaClass.name
|
val ourName = this.javaClass.name
|
||||||
out("; 6502 assembly code for '${program.name}'")
|
val cpu = CompilationTarget.machine.cpu
|
||||||
|
|
||||||
|
out("; $cpu assembly code for '${program.name}'")
|
||||||
out("; generated by $ourName on ${LocalDateTime.now().withNano(0)}")
|
out("; generated by $ourName on ${LocalDateTime.now().withNano(0)}")
|
||||||
out("; assembler syntax is for the 64tasm cross-assembler")
|
out("; assembler syntax is for the 64tasm cross-assembler")
|
||||||
out("; output options: output=${options.output} launcher=${options.launcher} zp=${options.zeropage}")
|
out("; output options: output=${options.output} launcher=${options.launcher} zp=${options.zeropage}")
|
||||||
out("\n.cpu '6502'\n.enc 'none'\n")
|
out("\n.cpu '$cpu'\n.enc 'none'\n")
|
||||||
|
|
||||||
program.actualLoadAddress = program.definedLoadAddress
|
program.actualLoadAddress = program.definedLoadAddress
|
||||||
if (program.actualLoadAddress == 0) // fix load address
|
if (program.actualLoadAddress == 0) // fix load address
|
||||||
|
125
compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt
Normal file
125
compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
package prog8.compiler.target.cx16
|
||||||
|
|
||||||
|
import prog8.ast.Program
|
||||||
|
import prog8.compiler.*
|
||||||
|
import prog8.compiler.target.IMachineDefinition
|
||||||
|
import prog8.compiler.target.c64.C64MachineDefinition
|
||||||
|
import prog8.parser.ModuleImporter
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
internal object CX16MachineDefinition: IMachineDefinition {
|
||||||
|
|
||||||
|
override val cpu = "65c02"
|
||||||
|
|
||||||
|
// 5-byte cbm MFLPT format limitations:
|
||||||
|
override val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
|
||||||
|
override val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
|
||||||
|
override val FLOAT_MEM_SIZE = 5
|
||||||
|
override val POINTER_MEM_SIZE = 2
|
||||||
|
override val BASIC_LOAD_ADDRESS = 0x0801
|
||||||
|
override val RAW_LOAD_ADDRESS = 0x8000
|
||||||
|
|
||||||
|
// the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations)
|
||||||
|
// and some heavily used string constants derived from the two values above
|
||||||
|
override val ESTACK_LO = 0x0400 // $0400-$04ff inclusive
|
||||||
|
override val ESTACK_HI = 0x0500 // $0500-$05ff inclusive
|
||||||
|
|
||||||
|
override lateinit var zeropage: Zeropage
|
||||||
|
override val initSystemProcname = "cx16.init_system"
|
||||||
|
|
||||||
|
override fun getFloat(num: Number) = C64MachineDefinition.Mflpt5.fromNumber(num)
|
||||||
|
|
||||||
|
override fun getFloatRomConst(number: Double): String? = null // TODO Does Cx16 have ROM float locations?
|
||||||
|
override fun importLibs(compilerOptions: CompilationOptions, importer: ModuleImporter, program: Program) {
|
||||||
|
// if we're producing a PRG or BASIC program, include the cx16utils and cx16lib libraries
|
||||||
|
if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) {
|
||||||
|
importer.importLibraryModule(program, "cx16lib")
|
||||||
|
importer.importLibraryModule(program, "cx16utils")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun launchEmulator(programName: String) {
|
||||||
|
for(emulator in listOf("x16emu")) {
|
||||||
|
println("\nStarting Commander X16 emulator $emulator...")
|
||||||
|
val cmdline = listOf(emulator, "-rom", "/usr/share/x16-rom/rom.bin", "-scale", "2",
|
||||||
|
"-run", "-prg", programName + ".prg")
|
||||||
|
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||||
|
val process: Process
|
||||||
|
try {
|
||||||
|
process=processb.start()
|
||||||
|
} catch(x: IOException) {
|
||||||
|
continue // try the next emulator executable
|
||||||
|
}
|
||||||
|
process.waitFor()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initializeZeropage(compilerOptions: CompilationOptions) {
|
||||||
|
zeropage = CX16Zeropage(compilerOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6502 opcodes (including aliases and illegal opcodes), these cannot be used as variable or label names
|
||||||
|
// TODO add 65C02 opcodes
|
||||||
|
override val opcodeNames = setOf("adc", "ahx", "alr", "anc", "and", "ane", "arr", "asl", "asr", "axs", "bcc", "bcs",
|
||||||
|
"beq", "bge", "bit", "blt", "bmi", "bne", "bpl", "brk", "bvc", "bvs", "clc",
|
||||||
|
"cld", "cli", "clv", "cmp", "cpx", "cpy", "dcm", "dcp", "dec", "dex", "dey",
|
||||||
|
"eor", "gcc", "gcs", "geq", "gge", "glt", "gmi", "gne", "gpl", "gvc", "gvs",
|
||||||
|
"inc", "ins", "inx", "iny", "isb", "isc", "jam", "jmp", "jsr", "lae", "las",
|
||||||
|
"lax", "lda", "lds", "ldx", "ldy", "lsr", "lxa", "nop", "ora", "pha", "php",
|
||||||
|
"pla", "plp", "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", "sbx",
|
||||||
|
"sec", "sed", "sei", "sha", "shl", "shr", "shs", "shx", "shy", "slo", "sre",
|
||||||
|
"sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa")
|
||||||
|
|
||||||
|
|
||||||
|
internal class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||||
|
|
||||||
|
override val SCRATCH_B1 = 0x79 // temp storage for a single byte
|
||||||
|
override val SCRATCH_REG = 0x7a // temp storage for a register
|
||||||
|
override val SCRATCH_REG_X = 0x7b // temp storage for register X (the evaluation stack pointer)
|
||||||
|
override val SCRATCH_W1 = 0x7c // temp storage 1 for a word $7c+$7d
|
||||||
|
override val SCRATCH_W2 = 0x7e // temp storage 2 for a word $7e+$7f
|
||||||
|
|
||||||
|
|
||||||
|
override val exitProgramStrategy: ExitProgramStrategy = when (options.zeropage) {
|
||||||
|
ZeropageType.BASICSAFE, ZeropageType.DONTUSE -> ExitProgramStrategy.CLEAN_EXIT
|
||||||
|
ZeropageType.KERNALSAFE, ZeropageType.FULL -> ExitProgramStrategy.SYSTEM_RESET
|
||||||
|
else -> ExitProgramStrategy.SYSTEM_RESET
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (options.floats && options.zeropage !in setOf(ZeropageType.BASICSAFE, ZeropageType.DONTUSE ))
|
||||||
|
throw CompilerException("when floats are enabled, zero page type should be 'basicsafe' or 'dontuse'")
|
||||||
|
|
||||||
|
when (options.zeropage) {
|
||||||
|
ZeropageType.FULL -> {
|
||||||
|
free.addAll(0x02..0xff)
|
||||||
|
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||||
|
}
|
||||||
|
ZeropageType.KERNALSAFE -> {
|
||||||
|
free.addAll(0x02..0x7f)
|
||||||
|
free.addAll(0xa9..0xff)
|
||||||
|
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||||
|
}
|
||||||
|
ZeropageType.BASICSAFE -> {
|
||||||
|
free.addAll(0x02..0x7f)
|
||||||
|
free.removeAll(listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_REG_X, SCRATCH_W1, SCRATCH_W1 + 1, SCRATCH_W2, SCRATCH_W2 + 1))
|
||||||
|
}
|
||||||
|
ZeropageType.DONTUSE -> {
|
||||||
|
free.clear() // don't use zeropage at all
|
||||||
|
}
|
||||||
|
else -> throw CompilerException("for this machine target, zero page type 'floatsafe' is not available. ${options.zeropage}")
|
||||||
|
}
|
||||||
|
|
||||||
|
require(SCRATCH_B1 !in free)
|
||||||
|
require(SCRATCH_REG !in free)
|
||||||
|
require(SCRATCH_REG_X !in free)
|
||||||
|
require(SCRATCH_W1 !in free)
|
||||||
|
require(SCRATCH_W2 !in free)
|
||||||
|
|
||||||
|
for (reserved in options.zpReserved)
|
||||||
|
reserve(reserved)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -94,7 +94,7 @@ internal class ModuleImporter {
|
|||||||
|
|
||||||
private fun discoverImportedModuleFile(name: String, source: Path, position: Position?): Path {
|
private fun discoverImportedModuleFile(name: String, source: Path, position: Position?): Path {
|
||||||
val fileName = "$name.p8"
|
val fileName = "$name.p8"
|
||||||
val locations = mutableListOf(source.parent)
|
val locations = if(source.toString().isEmpty()) mutableListOf<Path>() else mutableListOf(source.parent)
|
||||||
|
|
||||||
val propPath = System.getProperty("prog8.libdir")
|
val propPath = System.getProperty("prog8.libdir")
|
||||||
if(propPath!=null)
|
if(propPath!=null)
|
||||||
@ -109,7 +109,7 @@ internal class ModuleImporter {
|
|||||||
if (Files.isReadable(file)) return file
|
if (Files.isReadable(file)) return file
|
||||||
}
|
}
|
||||||
|
|
||||||
throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: $locations)")
|
throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: embedded libs and $locations)")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeImportDirective(program: Program, import: Directive, source: Path): Module? {
|
private fun executeImportDirective(program: Program, import: Directive, source: Path): Module? {
|
||||||
@ -128,9 +128,6 @@ internal class ModuleImporter {
|
|||||||
if(resource!=null) {
|
if(resource!=null) {
|
||||||
// load the module from the embedded resource
|
// load the module from the embedded resource
|
||||||
resource.use {
|
resource.use {
|
||||||
if(import.args[0].int==42)
|
|
||||||
println("importing '$moduleName' (library, auto)")
|
|
||||||
else
|
|
||||||
println("importing '$moduleName' (library)")
|
println("importing '$moduleName' (library)")
|
||||||
importModule(program, CharStreams.fromStream(it), Paths.get("@embedded@/$moduleName"), true)
|
importModule(program, CharStreams.fromStream(it), Paths.get("@embedded@/$moduleName"), true)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
%import c64utils
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -8,25 +7,25 @@ main {
|
|||||||
uword xx = $ef34
|
uword xx = $ef34
|
||||||
|
|
||||||
xx &= $00f0
|
xx &= $00f0
|
||||||
c64scr.print_uwhex(xx, 1)
|
screen.print_uwhex(xx, 1)
|
||||||
c64.CHROUT('\n')
|
cx16.CHROUT('\n')
|
||||||
xx |= $000f
|
xx |= $000f
|
||||||
c64scr.print_uwhex(xx, 1)
|
screen.print_uwhex(xx, 1)
|
||||||
c64.CHROUT('\n')
|
cx16.CHROUT('\n')
|
||||||
xx ^= $0011
|
xx ^= $0011
|
||||||
c64scr.print_uwhex(xx, 1)
|
screen.print_uwhex(xx, 1)
|
||||||
c64.CHROUT('\n')
|
cx16.CHROUT('\n')
|
||||||
|
|
||||||
xx = $ef34
|
xx = $ef34
|
||||||
xx &= $f000
|
xx &= $f000
|
||||||
c64scr.print_uwhex(xx, 1)
|
screen.print_uwhex(xx, 1)
|
||||||
c64.CHROUT('\n')
|
cx16.CHROUT('\n')
|
||||||
xx |= $0f00
|
xx |= $0f00
|
||||||
c64scr.print_uwhex(xx, 1)
|
screen.print_uwhex(xx, 1)
|
||||||
c64.CHROUT('\n')
|
cx16.CHROUT('\n')
|
||||||
xx ^= $1100
|
xx ^= $1100
|
||||||
c64scr.print_uwhex(xx, 1)
|
screen.print_uwhex(xx, 1)
|
||||||
c64.CHROUT('\n')
|
cx16.CHROUT('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user