make %asminclude work, restructure prog8lib into separate asm file

This commit is contained in:
Irmen de Jong 2019-01-21 00:00:26 +01:00
parent ba91ab13d5
commit 5471c5211c
16 changed files with 1814 additions and 1825 deletions

View File

@ -0,0 +1,704 @@
; Prog8 internal Math library routines - always included by the compiler
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
;
; indent format: TABS, size=8
; some more interesting routines can be found here:
; http://6502org.wikidot.com/software-math
; http://codebase64.org/doku.php?id=base:6502_6510_maths
;
multiply_bytes .proc
; -- multiply 2 bytes A and Y, result as byte in A (signed or unsigned)
sta c64.SCRATCH_ZPB1 ; num1
sty c64.SCRATCH_ZPREG ; num2
lda #0
beq _enterloop
_doAdd clc
adc c64.SCRATCH_ZPB1
_loop asl c64.SCRATCH_ZPB1
_enterloop lsr c64.SCRATCH_ZPREG
bcs _doAdd
bne _loop
rts
.pend
multiply_bytes_16 .proc
; -- multiply 2 bytes A and Y, result as word in A/Y (unsigned)
sta c64.SCRATCH_ZPB1
sty c64.SCRATCH_ZPREG
stx c64.SCRATCH_ZPREGX
lda #0
ldx #8
lsr c64.SCRATCH_ZPB1
- bcc +
clc
adc c64.SCRATCH_ZPREG
+ ror a
ror c64.SCRATCH_ZPB1
dex
bne -
tay
lda c64.SCRATCH_ZPB1
ldx c64.SCRATCH_ZPREGX
rts
.pend
multiply_words .proc
; -- multiply two 16-bit words into a 32-bit result (signed and unsigned)
; input: A/Y = first 16-bit number, c64.SCRATCH_ZPWORD1 in ZP = second 16-bit number
; output: multiply_words.result 4-bytes/32-bits product, LSB order (low-to-high)
sta c64.SCRATCH_ZPWORD2
sty c64.SCRATCH_ZPWORD2+1
stx c64.SCRATCH_ZPREGX
mult16 lda #$00
sta multiply_words_result+2 ; clear upper bits of product
sta multiply_words_result+3
ldx #16 ; for all 16 bits...
- lsr c64.SCRATCH_ZPWORD1+1 ; divide multiplier by 2
ror c64.SCRATCH_ZPWORD1
bcc +
lda multiply_words_result+2 ; get upper half of product and add multiplicand
clc
adc c64.SCRATCH_ZPWORD2
sta multiply_words_result+2
lda multiply_words_result+3
adc c64.SCRATCH_ZPWORD2+1
+ ror a ; rotate partial product
sta multiply_words_result+3
ror multiply_words_result+2
ror multiply_words_result+1
ror multiply_words_result
dex
bne -
ldx c64.SCRATCH_ZPREGX
rts
multiply_words_result .byte 0,0,0,0
.pend
divmod_ub .proc
; -- divide A by Y, result quotient in Y, remainder in A (unsigned)
; division by zero will result in quotient = 255 and remainder = original number
sty c64.SCRATCH_ZPREG
sta c64.SCRATCH_ZPB1
stx c64.SCRATCH_ZPREGX
lda #0
ldx #8
asl c64.SCRATCH_ZPB1
- rol a
cmp c64.SCRATCH_ZPREG
bcc +
sbc c64.SCRATCH_ZPREG
+ rol c64.SCRATCH_ZPB1
dex
bne -
ldy c64.SCRATCH_ZPB1
ldx c64.SCRATCH_ZPREGX
rts
.pend
divmod_uw_asm .proc
; -- divide two unsigned words (16 bit each) into 16 bit results
; input: c64.SCRATCH_ZPWORD1 in ZP: 16 bit number, A/Y: 16 bit divisor
; output: c64.SCRATCH_ZPWORD2 in ZP: 16 bit remainder, A/Y: 16 bit division result
; division by zero will result in quotient = 65535 and remainder = divident
dividend = c64.SCRATCH_ZPWORD1
remainder = c64.SCRATCH_ZPWORD2
result = dividend ;save memory by reusing divident to store the result
sta _divisor
sty _divisor+1
stx c64.SCRATCH_ZPREGX
lda #0 ;preset remainder to 0
sta remainder
sta remainder+1
ldx #16 ;repeat for each bit: ...
- asl dividend ;dividend lb & hb*2, msb -> Carry
rol dividend+1
rol remainder ;remainder lb & hb * 2 + msb from carry
rol remainder+1
lda remainder
sec
sbc _divisor ;substract divisor to see if it fits in
tay ;lb result -> Y, for we may need it later
lda remainder+1
sbc _divisor+1
bcc + ;if carry=0 then divisor didn't fit in yet
sta remainder+1 ;else save substraction result as new remainder,
sty remainder
inc result ;and INCrement result cause divisor fit in 1 times
+ dex
bne -
lda result
ldy result+1
ldx c64.SCRATCH_ZPREGX
rts
_divisor .word 0
.pend
randseed .proc
; -- reset the random seeds for the byte and word random generators
; arguments: uword seed in A/Y clobbers A
; (default starting values are: A=$2c Y=$9e)
sta randword._seed
sty randword._seed+1
clc
adc #14
sta randbyte._seed
rts
.pend
randbyte .proc
; -- 8-bit pseudo random number generator into A
lda _seed
beq _eor
asl a
beq _done ; if the input was $80, skip the EOR
bcc _done
_eor eor #$1d ; xor with magic value see below for possible values
_done sta _seed
rts
_seed .byte $3a
; possible 'magic' eor bytes are:
; $1d, $2b, $2d, $4d, $5f, $63, $65, $69
; $71, $87, $8d, $a9, $c3, $cf, $e7, $f5
.pend
randword .proc
; -- 16 bit pseudo random number generator into AY
magic_eor = $3f1d
; possible magic eor words are:
; $3f1d, $3f81, $3fa5, $3fc5, $4075, $409d, $40cd, $4109
; $413f, $414b, $4153, $4159, $4193, $4199, $41af, $41bb
lda _seed
beq _lowZero ; $0000 and $8000 are special values to test for
; Do a normal shift
asl _seed
lda _seed+1
rol a
bcc _noEor
_doEor ; high byte is in A
eor #>magic_eor
sta _seed+1
lda _seed
eor #<magic_eor
sta _seed
ldy _seed+1
rts
_lowZero lda _seed+1
beq _doEor ; High byte is also zero, so apply the EOR
; For speed, you could store 'magic' into 'seed' directly
; instead of running the EORs
; wasn't zero, check for $8000
asl a
beq _noEor ; if $00 is left after the shift, then it was $80
bcs _doEor ; else, do the EOR based on the carry bit as usual
_noEor sta _seed+1
tay
lda _seed
rts
_seed .word $2c9e
.pend
mul_byte_3 .proc
; X + X*2
lda c64.ESTACK_LO+1,x
asl a
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_3 .proc
; W + W*2
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_5 .proc
; X + X*4
lda c64.ESTACK_LO+1,x
asl a
asl a
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_5 .proc
; W + W*4
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_6 .proc
; X*2 + X*4
lda c64.ESTACK_LO+1,x
asl a
sta c64.SCRATCH_ZPREG
asl a
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_6 .proc
; W*2 + W*4
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_7 .proc
; X*8 - X
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
sec
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_7 .proc
; W*8 - W
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sec
lda c64.SCRATCH_ZPWORD1
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
sbc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_9 .proc
; X + X*8
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_9 .proc
; W + W*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_10 .proc
; X + X + X*8
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
clc
adc c64.ESTACK_LO+1,x
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_10 .proc
; W*2 + W*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_11 .proc
; X + X + X + X*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPREG
asl a
asl a
asl a
clc
adc c64.SCRATCH_ZPREG
clc
adc c64.SCRATCH_ZPREG
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
; mul_word_11 is skipped (too much code)
mul_byte_12 .proc
; X*4 + X*8
lda c64.ESTACK_LO+1,x
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_12 .proc
; W*4 + W*8
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_13 .proc
; X*16 - X -X -X
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPREG
asl a
asl a
asl a
asl a
sec
sbc c64.SCRATCH_ZPREG
sec
sbc c64.SCRATCH_ZPREG
sec
sbc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
; mul_word_13 is skipped (too much code)
mul_byte_14 .proc
; X*16 - X -X
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
asl a
sec
sbc c64.ESTACK_LO+1,x
sec
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
; mul_word_14 is skipped (too much code)
mul_byte_15 .proc
; X*16 - X
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPREG
asl a
asl a
asl a
asl a
sec
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_15 .proc
; W*16 - W
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
sec
lda c64.SCRATCH_ZPWORD1
sbc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
sbc c64.ESTACK_HI+1,x
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_20 .proc
; X*4 + X*16
lda c64.ESTACK_LO+1,x
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
asl a
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_20 .proc
; W*4 + W*16
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.SCRATCH_ZPWORD2
lda c64.SCRATCH_ZPWORD1+1
sta c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
asl c64.SCRATCH_ZPWORD2
rol c64.SCRATCH_ZPWORD2+1
clc
lda c64.SCRATCH_ZPWORD1
adc c64.SCRATCH_ZPWORD2
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
adc c64.SCRATCH_ZPWORD2+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_25 .proc
; X + X*8 + X*16
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
clc
adc c64.SCRATCH_ZPREG
clc
adc c64.ESTACK_LO+1,x
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_25 .proc
; W + W*8 + W*16
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
rts
.pend
mul_byte_40 .proc
; X*8 + X*32
lda c64.ESTACK_LO+1,x
asl a
asl a
asl a
sta c64.SCRATCH_ZPREG
asl a
asl a
clc
adc c64.SCRATCH_ZPREG
sta c64.ESTACK_LO+1,x
rts
.pend
mul_word_40 .proc
; W*8 + W*32
lda c64.ESTACK_LO+1,x
sta c64.SCRATCH_ZPWORD1
lda c64.ESTACK_HI+1,x
sta c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
lda c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
asl c64.SCRATCH_ZPWORD1
rol c64.SCRATCH_ZPWORD1+1
clc
lda c64.ESTACK_LO+1,x
adc c64.SCRATCH_ZPWORD1
sta c64.ESTACK_LO+1,x
lda c64.ESTACK_HI+1,x
adc c64.SCRATCH_ZPWORD1+1
sta c64.ESTACK_HI+1,x
rts
.pend

View File

@ -0,0 +1,11 @@
; Prog8 internal Math library routines - always included by the compiler
;
; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
;
; indent format: TABS, size=8
%import c64lib
~ math {
%asminclude "library:math.asm", ""
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -37,11 +37,13 @@ fun main(args: Array<String>) {
}
private fun compileMain(args: Array<String>) {
var startEmu = false
var emulatorToStart = ""
var moduleFile = ""
for (arg in args) {
if(arg=="--emu")
startEmu = true
emulatorToStart = "x64"
else if(arg=="--emu2")
emulatorToStart = "x64sc"
else if(!arg.startsWith("--"))
moduleFile = arg
}
@ -139,9 +141,9 @@ private fun compileMain(args: Array<String>) {
throw x
}
if(startEmu) {
println("\nStarting C64 emulator...")
val cmdline = listOf("x64sc", "-silent", "-moncommands", "$programname.vice-mon-list",
if(emulatorToStart.isNotEmpty()) {
println("\nStarting C-64 emulator $emulatorToStart...")
val cmdline = listOf(emulatorToStart, "-silent", "-moncommands", "$programname.vice-mon-list",
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programname+".prg")
val process = ProcessBuilder(cmdline).inheritIO().start()
process.waitFor()
@ -184,7 +186,8 @@ fun determineCompilationOptions(moduleAst: Module): CompilationOptions {
private fun usage() {
System.err.println("Missing argument(s):")
System.err.println(" [--emu] auto-start the C64 emulator after successful compilation")
System.err.println(" [--emu] auto-start the 'x64' C-64 emulator after successful compilation")
System.err.println(" [--emu2] auto-start the 'x64sc' C-64 emulator after successful compilation")
System.err.println(" [--vm] launch the prog8 virtual machine instead of the compiler")
System.err.println(" modulefile main module file to compile")
exitProcess(1)

View File

@ -611,8 +611,8 @@ class AstChecker(private val namespace: INameScope,
}
"%asminclude" -> {
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")
if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].name==null)
err("invalid asminclude directive, expected arguments: \"filename\", scopelabel")
if(directive.args.size!=2 || directive.args[0].str==null || directive.args[1].str==null)
err("invalid asminclude directive, expected arguments: \"filename\", \"scopelabel\"")
}
"%asmbinary" -> {
if(directive.parent !is INameScope || directive.parent is Module) err("this directive may only occur in a block")

View File

@ -6,7 +6,12 @@ import prog8.compiler.intermediate.IntermediateProgram
import prog8.compiler.intermediate.Opcode
import prog8.compiler.intermediate.Value
import prog8.optimizing.same
import prog8.parser.tryGetEmbeddedResource
import prog8.stackvm.Syscall
import java.io.File
import java.io.InputStream
import java.io.InputStreamReader
import java.nio.file.Paths
import java.util.*
import kotlin.math.abs
@ -220,8 +225,8 @@ private class StatementTranslator(private val prog: IntermediateProgram,
is Return -> translate(stmt)
is Directive -> {
when(stmt.directive) {
"%asminclude" -> throw CompilerException("can't use %asminclude in stackvm")
"%asmbinary" -> throw CompilerException("can't use %asmbinary in stackvm")
"%asminclude" -> translateAsmInclude(stmt.args)
"%asmbinary" -> translateAsmBinary(stmt.args)
"%breakpoint" -> {
prog.line(stmt.position)
prog.instr(Opcode.BREAKPOINT)
@ -959,6 +964,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
var restoreX = Register.X in subroutine.asmClobbers
if(restoreX)
prog.instr(Opcode.RSAVEX)
// We don't bother about saving A and Y. They're considered expendable.
if(subroutine.isAsmSubroutine) {
if(subroutine.parameters.size!=subroutine.asmParameterRegisters.size)
@ -2185,4 +2191,24 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
}
private fun translateAsmInclude(args: List<DirectiveArg>) {
val scopeprefix = if(args[1].str!!.isNotBlank()) "${args[1].str}\t.proc\n" else ""
val scopeprefixEnd = if(args[1].str!!.isNotBlank()) "\t.pend\n" else ""
val filename=args[0].str!!
val sourcecode =
if(filename.startsWith("library:")) {
val resource = tryGetEmbeddedResource(filename.substring(8)) ?: throw IllegalArgumentException("library file '$filename' not found")
resource.bufferedReader().use { it.readText() }
} else {
// TODO: look in directory of parent source file first
File(filename).readText()
}
prog.instr(Opcode.INLINE_ASSEMBLY, callLabel=scopeprefix+sourcecode+scopeprefixEnd)
}
private fun translateAsmBinary(args: List<DirectiveArg>) {
TODO("asmbinary not implemented $args")
}
}

View File

@ -423,7 +423,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
Opcode.DISCARD_BYTE -> " inx"
Opcode.DISCARD_WORD -> " inx"
Opcode.DISCARD_FLOAT -> " inx | inx | inx"
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel ?: "") // All of the inline assembly is stored in the calllabel property.
Opcode.INLINE_ASSEMBLY -> "@inline@" + (ins.callLabel ?: "") // All of the inline assembly is stored in the calllabel property. the '@inline@' is a special marker to process it.
Opcode.SYSCALL -> {
if (ins.arg!!.numericValue() in syscallsForStackVm.map { it.callNr })
throw CompilerException("cannot translate vm syscalls to real assembly calls - use *real* subroutine calls instead. Syscall ${ins.arg.numericValue()}")
@ -965,18 +965,22 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
}
}
for(pattern in patterns.filter { it.sequence.size <= segment.size || (it.altSequence != null && it.altSequence.size <= segment.size)}) {
val opcodesList = if(pattern.sequence.size<=opcodes.size) opcodes.subList(0, pattern.sequence.size) else null
val opcodesListAlt = if(pattern.altSequence!=null && pattern.altSequence.size<=opcodes.size) opcodes.subList(0, pattern.altSequence.size) else null
// add any matching patterns from the big list
for(pattern in patterns) {
if(pattern.sequence.size > segment.size || (pattern.altSequence!=null && pattern.altSequence.size > segment.size))
continue // don't process patterns that don't fit
val opcodesList = opcodes.subList(0, pattern.sequence.size)
if(pattern.sequence == opcodesList) {
val asm = pattern.asm(segment)
if(asm!=null)
result.add(AsmFragment(asm, pattern.sequence.size))
} else if(opcodesListAlt!=null && pattern.altSequence == opcodesListAlt) {
val asm = pattern.asm(segment)
if(asm!=null)
result.add(AsmFragment(asm, pattern.sequence.size))
} else if(pattern.altSequence!=null) {
val opcodesListAlt = opcodes.subList(0, pattern.altSequence.size)
if(pattern.altSequence == opcodesListAlt) {
val asm = pattern.asm(segment)
if (asm != null)
result.add(AsmFragment(asm, pattern.sequence.size))
}
}
}

View File

@ -5,6 +5,8 @@ import prog8.ast.*
import prog8.compiler.LauncherType
import prog8.compiler.OutputType
import prog8.determineCompilationOptions
import java.io.InputStream
import java.net.URL
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
@ -52,7 +54,9 @@ fun importModule(stream: CharStream, moduleName: String, isLibrary: Boolean): Mo
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "c64utils", null, moduleAst.position)), moduleAst.position))
}
}
// always import the prog8 compiler library
// always import the prog8lib and math compiler libraries
if(!moduleAst.position.file.startsWith("math."))
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "math", null, moduleAst.position)), moduleAst.position))
if(!moduleAst.position.file.startsWith("prog8lib."))
lines.add(0, Directive("%import", listOf(DirectiveArg(null, "prog8lib", null, moduleAst.position)), moduleAst.position))
@ -118,7 +122,6 @@ private fun discoverImportedModuleFile(name: String, importedFrom: Path, positio
throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: $locations)")
}
private fun executeImportDirective(import: Directive, importedFrom: Path): Module? {
if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null)
throw SyntaxError("invalid import directive", import.position)
@ -128,11 +131,11 @@ private fun executeImportDirective(import: Directive, importedFrom: Path): Modul
if(importedModules.containsKey(moduleName))
return null
val resource = import::class.java.getResource("/prog8lib/$moduleName.p8")
val resource = tryGetEmbeddedResource(moduleName+".p8")
val importedModule =
if(resource!=null) {
// load the module from the embedded resource
resource.openStream().use {
resource.use {
println("importing '$moduleName' (embedded library)")
importModule(CharStreams.fromStream(it), moduleName, true)
}
@ -144,3 +147,7 @@ private fun executeImportDirective(import: Directive, importedFrom: Path): Modul
importedModule.checkImportedValid()
return importedModule
}
fun tryGetEmbeddedResource(name: String): InputStream? {
return object{}.javaClass.getResourceAsStream("/prog8lib/$name")
}

View File

@ -120,7 +120,7 @@ Directives
The assembler will include the file as binary bytes at this point, prog8 will not process this at all.
The optional offset and length can be used to select a particular piece of the file.
.. data:: %asminclude "<filename>", scopelabel
.. data:: %asminclude "<filename>", "scopelabel"
Level: block.
This directive can only be used inside a block.
@ -128,6 +128,7 @@ Directives
prog8 will not process this at all, with one exception: the labels.
The scopelabel argument will be used as a prefix to access the labels from the included source code,
otherwise you would risk symbol redefinitions or duplications.
If you know what you are doing you can leave it as an empty string to not have a scope prefix.
.. data:: %breakpoint

View File

@ -44,10 +44,10 @@ sub start() {
sub print_notes(ubyte n1, ubyte n2) {
c64.CHROUT('\n')
c64.PLOT(0, n1/2, 24)
c64scr.PLOT(n1/2, 24)
c64.COLOR=7
c64.CHROUT('Q')
c64.PLOT(0, n2/2, 24)
c64scr.PLOT(n2/2, 24)
c64.COLOR=4
c64.CHROUT('Q')
}

View File

@ -24,7 +24,7 @@
c64scr.clear_screenchars(32)
draw_edges()
time+=0.2
c64.PLOT(0,0,0)
c64scr.PLOT(0,0)
c64scr.print("3d cube! (float) ")
c64scr.print_ub(c64.TIME_LO)
c64scr.print(" jiffies/frame")

View File

@ -89,7 +89,7 @@
anglex-=500
angley+=217
anglez+=452
c64.PLOT(0,0,0)
c64scr.PLOT(0,0)
c64scr.print("3d cube! (sprites) ")
c64scr.print_ub(c64.TIME_LO)
c64scr.print(" jiffies/frame ")

View File

@ -29,7 +29,7 @@
anglex+=1000
angley+=433
anglez+=907
c64.PLOT(0,0,0)
c64scr.PLOT(0,0)
c64scr.print("3d cube! (integer) ")
c64scr.print_ub(c64.TIME_LO)
c64scr.print(" jiffies/frame")

View File

@ -38,7 +38,7 @@
}
float duration = floor(((c64.TIME_LO as float) + 256.0*(c64.TIME_MID as float) + 65536.0*(c64.TIME_HI as float))/60.0)
c64.PLOT(0, 0, 21)
c64scr.PLOT(0, 21)
c64scr.print("finished in ")
c64flt.print_f(duration)
c64scr.print(" seconds!\n")

View File

@ -29,58 +29,9 @@
uword[3] uwa2
word[3] wa2
; ub1 = ub2 & 44
; b1 = b2 & 44
; uw1 = uw2 & 4444
; w1 = w2 & 4444
; ub1 = ub2 | 44
; b1 = b2 | 44
; uw1 = uw2 | 4444
; w1 = w2 | 4444
; ub1 = ub2 ^ 44
; b1 = b2 ^ 44
; uw1 = uw2 ^ 4444
; w1 = w2 ^ 4444
;
; ub1 = ub2 & ub1
; b1 = b2 & b1
; uw1 = uw2 & uw1
; w1 = w2 & w1
; ub1 = ub2 | ub1
; b1 = b2 | b1
; uw1 = uw2 | uw1
; w1 = w2 | w1
; ub1 = ub2 ^ ub1
; b1 = b2 ^ b1
; uw1 = uw2 ^ uw1
; w1 = w2 ^ w1
swap(ub1, ub2)
swap(b1, b2)
swap(uw1, uw2)
swap(w1, w2)
swap(@($d020), @($d021))
swap(mub1, mub2)
swap(muw1, muw2)
swap(mub1, ub2)
swap(muw1, uw2)
ub1=ub2*ub1
swap(uba1[1], uba2[2])
swap(ba1[1], ba2[2])
swap(uwa1[1], uwa2[2])
swap(wa1[1], wa2[2])
ubyte i1
ubyte i2
swap(uba1[i1], uba2[i2])
swap(ba1[i1], ba2[i2])
swap(uwa1[i1], uwa2[i2])
swap(wa1[i1], wa2[i2])
swap(uba1[1], ub1)
swap(uba1[i1], ub1)
swap(uwa1[1], uw1)
swap(uwa1[i1], uw1)
}