From 6a0551cea16649e613d6eaae5a0931e26c85cd7e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 21 Feb 2022 23:38:53 +0100 Subject: [PATCH] added 'atari' compiler target beginnings (Atari 800 XL) also default char and string encoding now taken from compiler target --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 4 + .../prog8/codegen/cpu6502/AssemblyProgram.kt | 85 +++- .../src/prog8/codegen/target/AtariTarget.kt | 53 +++ .../src/prog8/codegen/target/C128Target.kt | 7 +- .../src/prog8/codegen/target/C64Target.kt | 7 +- .../src/prog8/codegen/target/Cx16Target.kt | 7 +- .../target/atari/AtariMachineDefinition.kt | 62 +++ .../codegen/target/atari/AtariZeropage.kt | 45 ++ compiler/res/prog8lib/atari/syslib.p8 | 307 +++++++++++++ compiler/res/prog8lib/atari/textio.p8 | 402 ++++++++++++++++++ compiler/src/prog8/CompilerMain.kt | 5 +- compiler/src/prog8/compiler/Compiler.kt | 9 +- .../compiler/astprocessing/AstExtensions.kt | 12 +- .../astprocessing/AstIdentifiersChecker.kt | 2 +- .../compiler/astprocessing/AstPreprocessor.kt | 18 +- .../astprocessing/LiteralsToAutoVars.kt | 3 +- compiler/test/ast/TestAstToSourceText.kt | 4 +- compiler/test/ast/TestProg8Parser.kt | 6 +- compiler/test/helpers/Dummies.kt | 2 + .../src/prog8/ast/AstToSourceTextConverter.kt | 11 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 4 +- .../prog8/ast/expressions/AstExpressions.kt | 7 +- .../compilerinterface/IStringEncoding.kt | 7 +- .../compilerinterface/ICompilationTarget.kt | 2 + docs/source/building.rst | 2 +- docs/source/index.rst | 3 +- docs/source/targetsystem.rst | 3 +- docs/source/todo.rst | 4 + examples/test.p8 | 32 +- 29 files changed, 1022 insertions(+), 93 deletions(-) create mode 100644 codeGenTargets/src/prog8/codegen/target/AtariTarget.kt create mode 100644 codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt create mode 100644 codeGenTargets/src/prog8/codegen/target/atari/AtariZeropage.kt create mode 100644 compiler/res/prog8lib/atari/syslib.p8 create mode 100644 compiler/res/prog8lib/atari/textio.p8 diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index f5ad27311..55796f9cb 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -42,6 +42,10 @@ class AsmGen(internal val program: Program, private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen, allocator) override fun compileToAssembly(): IAssemblyProgram? { + + if(options.compTarget.name=="atari" && options.launcher==LauncherType.BASIC) + throw AssemblyError("atari target cannot use CBM BASIC launcher type") + assemblyLines.clear() loopEndLabels.clear() diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt index 3f8acd54a..34303cc4a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt @@ -17,39 +17,82 @@ internal class AssemblyProgram( private val compTarget: ICompilationTarget) : IAssemblyProgram { private val assemblyFile = outputDir.resolve("$name.asm") - private val prgFile = outputDir.resolve("$name.prg") + private val prgFile = outputDir.resolve("$name.prg") // CBM prg executable program + private val xexFile = outputDir.resolve("$name.xex") // Atari xex executable program private val binFile = outputDir.resolve("$name.bin") private val viceMonListFile = outputDir.resolve(viceMonListName(name)) private val listFile = outputDir.resolve("$name.list") override fun assemble(options: CompilationOptions): Boolean { - // add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently) - val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", - "-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror", - "--dump-labels", "--vice-labels", "--labels=$viceMonListFile", "--no-monitor" - ) - if(options.asmQuiet) - command.add("--quiet") + val assemblerCommand: List - if(options.asmListfile) - command.add("--list=$listFile") + when (compTarget.name) { + in setOf("c64", "c128", "cx16") -> { + // CBM machines .prg generation. + + // add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently) + val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", + "-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror", + "--dump-labels", "--vice-labels", "--labels=$viceMonListFile", "--no-monitor" + ) + + if(options.asmQuiet) + command.add("--quiet") + + if(options.asmListfile) + command.add("--list=$listFile") + + val outFile = when (options.output) { + OutputType.PRG -> { + command.add("--cbm-prg") + println("\nCreating prg for target ${compTarget.name}.") + prgFile + } + OutputType.RAW -> { + command.add("--nostart") + println("\nCreating raw binary for target ${compTarget.name}.") + binFile + } + } + command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString())) + assemblerCommand = command - val outFile = when (options.output) { - OutputType.PRG -> { - command.add("--cbm-prg") - println("\nCreating prg for target ${compTarget.name}.") - prgFile } - OutputType.RAW -> { - command.add("--nostart") - println("\nCreating raw binary for target ${compTarget.name}.") - binFile + "atari" -> { + // Atari800XL .xex generation. + + // TODO are these options okay? + val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", + "-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror", + "--no-monitor" + ) + + if(options.asmQuiet) + command.add("--quiet") + + if(options.asmListfile) + command.add("--list=$listFile") + + val outFile = when (options.output) { + OutputType.PRG -> { + command.add("--atari-xex") + println("\nCreating xex for target ${compTarget.name}.") + xexFile + } + OutputType.RAW -> { + command.add("--nostart") + println("\nCreating raw binary for target ${compTarget.name}.") + binFile + } + } + command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString())) + assemblerCommand = command } + else -> throw AssemblyError("invalid compilation target") } - command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString())) - val proc = ProcessBuilder(command).inheritIO().start() + val proc = ProcessBuilder(assemblerCommand).inheritIO().start() val result = proc.waitFor() if (result == 0) { removeGeneratedLabelsFromMonlist() diff --git a/codeGenTargets/src/prog8/codegen/target/AtariTarget.kt b/codeGenTargets/src/prog8/codegen/target/AtariTarget.kt new file mode 100644 index 000000000..d2550daca --- /dev/null +++ b/codeGenTargets/src/prog8/codegen/target/AtariTarget.kt @@ -0,0 +1,53 @@ +package prog8.codegen.target + +import prog8.ast.base.* +import prog8.ast.expressions.Expression +import prog8.ast.expressions.StringLiteral +import prog8.ast.statements.RegisterOrStatusflag +import prog8.ast.statements.Subroutine +import prog8.ast.statements.VarDecl +import prog8.codegen.target.atari.AtariMachineDefinition +import prog8.codegen.target.cbm.asmsub6502ArgsEvalOrder +import prog8.codegen.target.cbm.asmsub6502ArgsHaveRegisterClobberRisk +import prog8.compilerinterface.* + + +class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { + override val name = NAME + override val machine = AtariMachineDefinition() + override val supportedEncodings = setOf(Encoding.ISO) // TODO + override val defaultEncoding = Encoding.ISO // TODO + override val defaultLauncherType = LauncherType.NONE + + companion object { + const val NAME = "atari" + } + + override fun asmsubArgsEvalOrder(sub: Subroutine): List = + asmsub6502ArgsEvalOrder(sub) + override fun asmsubArgsHaveRegisterClobberRisk(args: List, paramRegisters: List) = + asmsub6502ArgsHaveRegisterClobberRisk(args, paramRegisters) + + override fun memorySize(dt: DataType): Int { + return when(dt) { + in ByteDatatypes -> 1 + in WordDatatypes, in PassByReferenceDatatypes -> 2 + DataType.FLOAT -> 6 + else -> Int.MIN_VALUE + } + } + + override fun memorySize(decl: VarDecl): Int { + return when(decl.type) { + VarDeclType.CONST -> 0 + VarDeclType.VAR, VarDeclType.MEMORY -> { + when(val dt = decl.datatype) { + in NumericDatatypes -> return memorySize(dt) + in ArrayDatatypes -> decl.arraysize!!.constIndex()!! * memorySize(ArrayToElementTypes.getValue(dt)) + DataType.STR -> (decl.value as StringLiteral).value.length + 1 + else -> 0 + } + } + } + } +} diff --git a/codeGenTargets/src/prog8/codegen/target/C128Target.kt b/codeGenTargets/src/prog8/codegen/target/C128Target.kt index eae6a85a4..9ef07f40f 100644 --- a/codeGenTargets/src/prog8/codegen/target/C128Target.kt +++ b/codeGenTargets/src/prog8/codegen/target/C128Target.kt @@ -7,16 +7,15 @@ import prog8.codegen.target.c128.C128MachineDefinition import prog8.codegen.target.cbm.CbmMemorySizer import prog8.codegen.target.cbm.asmsub6502ArgsEvalOrder import prog8.codegen.target.cbm.asmsub6502ArgsHaveRegisterClobberRisk -import prog8.compilerinterface.Encoding -import prog8.compilerinterface.ICompilationTarget -import prog8.compilerinterface.IMemSizer -import prog8.compilerinterface.IStringEncoding +import prog8.compilerinterface.* class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { override val name = NAME override val machine = C128MachineDefinition() override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES) + override val defaultEncoding = Encoding.PETSCII + override val defaultLauncherType = LauncherType.BASIC companion object { const val NAME = "c128" diff --git a/codeGenTargets/src/prog8/codegen/target/C64Target.kt b/codeGenTargets/src/prog8/codegen/target/C64Target.kt index 98e120d28..a160415af 100644 --- a/codeGenTargets/src/prog8/codegen/target/C64Target.kt +++ b/codeGenTargets/src/prog8/codegen/target/C64Target.kt @@ -7,16 +7,15 @@ import prog8.codegen.target.c64.C64MachineDefinition import prog8.codegen.target.cbm.CbmMemorySizer import prog8.codegen.target.cbm.asmsub6502ArgsEvalOrder import prog8.codegen.target.cbm.asmsub6502ArgsHaveRegisterClobberRisk -import prog8.compilerinterface.Encoding -import prog8.compilerinterface.ICompilationTarget -import prog8.compilerinterface.IMemSizer -import prog8.compilerinterface.IStringEncoding +import prog8.compilerinterface.* class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { override val name = NAME override val machine = C64MachineDefinition() override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES) + override val defaultEncoding = Encoding.PETSCII + override val defaultLauncherType = LauncherType.BASIC companion object { const val NAME = "c64" diff --git a/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt b/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt index a0b5aae39..e1208b093 100644 --- a/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt +++ b/codeGenTargets/src/prog8/codegen/target/Cx16Target.kt @@ -7,16 +7,15 @@ import prog8.codegen.target.cbm.CbmMemorySizer import prog8.codegen.target.cbm.asmsub6502ArgsEvalOrder import prog8.codegen.target.cbm.asmsub6502ArgsHaveRegisterClobberRisk import prog8.codegen.target.cx16.CX16MachineDefinition -import prog8.compilerinterface.Encoding -import prog8.compilerinterface.ICompilationTarget -import prog8.compilerinterface.IMemSizer -import prog8.compilerinterface.IStringEncoding +import prog8.compilerinterface.* class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer { override val name = NAME override val machine = CX16MachineDefinition() override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES, Encoding.ISO) + override val defaultEncoding = Encoding.PETSCII + override val defaultLauncherType = LauncherType.BASIC companion object { const val NAME = "cx16" diff --git a/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt b/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt new file mode 100644 index 000000000..13412ec2c --- /dev/null +++ b/codeGenTargets/src/prog8/codegen/target/atari/AtariMachineDefinition.kt @@ -0,0 +1,62 @@ +package prog8.codegen.target.atari + +import prog8.codegen.target.c64.normal6502instructions +import prog8.compilerinterface.* +import java.io.IOException +import java.nio.file.Path + + +class AtariMachineDefinition: IMachineDefinition { + + override val cpu = CpuType.CPU6502 + + override val FLOAT_MAX_POSITIVE = 9.999999999e97 + override val FLOAT_MAX_NEGATIVE = -9.999999999e97 + override val FLOAT_MEM_SIZE = 6 + override val BASIC_LOAD_ADDRESS = 0x2000u + override val RAW_LOAD_ADDRESS = 0x2000u + + // the 2*256 byte evaluation stack (on which bytes, words, and even floats are stored during calculations) + override val ESTACK_LO = 0x1a00u // $1a00-$1aff inclusive // TODO + override val ESTACK_HI = 0x1b00u // $1b00-$1bff inclusive // TODO + + override lateinit var zeropage: Zeropage + + override fun getFloat(num: Number) = TODO("float from number") + + override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { + return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG) + listOf("syslib") + else + emptyList() + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + if(selectedEmulator!=1) { + System.err.println("The atari target only supports the main emulator (atari800).") + return + } + + for(emulator in listOf("atari800")) { + println("\nStarting Atari800XL emulator $emulator...") + val cmdline = listOf(emulator, "-xl", "-nobasic", "-run", "${programNameWithPath}.xex") + 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 isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO + + override fun initializeZeropage(compilerOptions: CompilationOptions) { + zeropage = AtariZeropage(compilerOptions) + } + + override val opcodeNames = normal6502instructions +} diff --git a/codeGenTargets/src/prog8/codegen/target/atari/AtariZeropage.kt b/codeGenTargets/src/prog8/codegen/target/atari/AtariZeropage.kt new file mode 100644 index 000000000..6c4abfe47 --- /dev/null +++ b/codeGenTargets/src/prog8/codegen/target/atari/AtariZeropage.kt @@ -0,0 +1,45 @@ +package prog8.codegen.target.atari + +import prog8.compilerinterface.CompilationOptions +import prog8.compilerinterface.InternalCompilerException +import prog8.compilerinterface.Zeropage +import prog8.compilerinterface.ZeropageType + +class AtariZeropage(options: CompilationOptions) : Zeropage(options) { + + override val SCRATCH_B1 = 0xcbu // temp storage for a single byte + override val SCRATCH_REG = 0xccu // temp storage for a register, must be B1+1 + override val SCRATCH_W1 = 0xcdu // temp storage 1 for a word $cd+$ce + override val SCRATCH_W2 = 0xcfu // temp storage 2 for a word $cf+$d0 TODO is $d0 okay to use? + + + init { + if (options.floats && options.zeropage !in arrayOf( + ZeropageType.FLOATSAFE, + ZeropageType.BASICSAFE, + ZeropageType.DONTUSE + )) + throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'") + + when (options.zeropage) { + ZeropageType.FULL -> { + // TODO all atari usable zero page locations, except the ones used by the system's IRQ routine + free.addAll(0x00u..0xffu) + // TODO atari free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ + } + ZeropageType.KERNALSAFE -> { + free.addAll(0x80u..0xffu) // TODO + } + ZeropageType.BASICSAFE, + ZeropageType.FLOATSAFE -> { + free.addAll(0x80u..0xffu) // TODO + free.removeAll(0xd4u .. 0xefu) // floating point storage + } + ZeropageType.DONTUSE -> { + free.clear() // don't use zeropage at all + } + } + + removeReservedFromFreePool() + } +} \ No newline at end of file diff --git a/compiler/res/prog8lib/atari/syslib.p8 b/compiler/res/prog8lib/atari/syslib.p8 new file mode 100644 index 000000000..68ad51c6a --- /dev/null +++ b/compiler/res/prog8lib/atari/syslib.p8 @@ -0,0 +1,307 @@ +; Prog8 definitions for the Atari800XL +; Including memory registers, I/O registers, Basic and Kernal subroutines. +; +; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0 +; + +atari { + + &uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in + &uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in + &uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in + +; ---- kernal routines ---- +; TODO + + +asmsub init_system() { + ; Initializes the machine to a sane starting state. + ; Called automatically by the loader program logic. + ; TODO + %asm {{ + sei + cld + clc + ; TODO reset screen mode etc etc + clv + cli + rts + }} +} + +asmsub init_system_phase2() { + %asm {{ + rts ; no phase 2 steps on the Atari + }} +} + +} + + +sys { + ; ------- lowlevel system routines -------- + + const ubyte target = 8 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL + + + asmsub reset_system() { + ; Soft-reset the system back to initial power-on Basic prompt. + ; TODO + %asm {{ + sei + jmp (atari.RESET_VEC) + }} + } + + sub wait(uword jiffies) { + ; --- wait approximately the given number of jiffies (1/60th seconds) + ; TODO + } + + asmsub waitvsync() clobbers(A) { + ; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling. + ; TODO + %asm {{ + nop + rts + }} + } + + asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) { + ; note: can't be inlined because is called from asm as well + %asm {{ + ldx cx16.r0 + stx P8ZP_SCRATCH_W1 ; source in ZP + ldx cx16.r0+1 + stx P8ZP_SCRATCH_W1+1 + ldx cx16.r1 + stx P8ZP_SCRATCH_W2 ; target in ZP + ldx cx16.r1+1 + stx P8ZP_SCRATCH_W2+1 + cpy #0 + bne _longcopy + + ; copy <= 255 bytes + tay + bne _copyshort + rts ; nothing to copy + +_copyshort + ; decrease source and target pointers so we can simply index by Y + lda P8ZP_SCRATCH_W1 + bne + + dec P8ZP_SCRATCH_W1+1 ++ dec P8ZP_SCRATCH_W1 + lda P8ZP_SCRATCH_W2 + bne + + dec P8ZP_SCRATCH_W2+1 ++ dec P8ZP_SCRATCH_W2 + +- lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + dey + bne - + rts + +_longcopy + sta P8ZP_SCRATCH_B1 ; lsb(count) = remainder in last page + tya + tax ; x = num pages (1+) + ldy #0 +- lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + iny + bne - + inc P8ZP_SCRATCH_W1+1 + inc P8ZP_SCRATCH_W2+1 + dex + bne - + ldy P8ZP_SCRATCH_B1 + bne _copyshort + rts + }} + } + + asmsub memset(uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers(A,X,Y) { + %asm {{ + ldy cx16.r0 + sty P8ZP_SCRATCH_W1 + ldy cx16.r0+1 + sty P8ZP_SCRATCH_W1+1 + ldx cx16.r1 + ldy cx16.r1+1 + jmp prog8_lib.memset + }} + } + + asmsub memsetw(uword mem @R0, uword numwords @R1, uword value @AY) clobbers(A,X,Y) { + %asm {{ + ldx cx16.r0 + stx P8ZP_SCRATCH_W1 + ldx cx16.r0+1 + stx P8ZP_SCRATCH_W1+1 + ldx cx16.r1 + stx P8ZP_SCRATCH_W2 + ldx cx16.r1+1 + stx P8ZP_SCRATCH_W2+1 + jmp prog8_lib.memsetw + }} + } + + inline asmsub read_flags() -> ubyte @A { + %asm {{ + php + pla + }} + } + + inline asmsub clear_carry() { + %asm {{ + clc + }} + } + + inline asmsub set_carry() { + %asm {{ + sec + }} + } + + inline asmsub clear_irqd() { + %asm {{ + cli + }} + } + + inline asmsub set_irqd() { + %asm {{ + sei + }} + } + + inline asmsub exit(ubyte returnvalue @A) { + ; -- immediately exit the program with a return code in the A register + ; TODO + %asm {{ + ldx prog8_lib.orig_stackpointer + txs + rts ; return to original caller + }} + } + + inline asmsub progend() -> uword @AY { + %asm {{ + lda #prog8_program_end + }} + } + +} + +cx16 { + + ; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage + ; they are simulated on the Atari as well but their location in memory is different + ; TODO + &uword r0 = $1b00 + &uword r1 = $1b02 + &uword r2 = $1b04 + &uword r3 = $1b06 + &uword r4 = $1b08 + &uword r5 = $1b0a + &uword r6 = $1b0c + &uword r7 = $1b0e + &uword r8 = $1b10 + &uword r9 = $1b12 + &uword r10 = $1b14 + &uword r11 = $1b16 + &uword r12 = $1b18 + &uword r13 = $1b1a + &uword r14 = $1b1c + &uword r15 = $1b1e + + &word r0s = $1b00 + &word r1s = $1b02 + &word r2s = $1b04 + &word r3s = $1b06 + &word r4s = $1b08 + &word r5s = $1b0a + &word r6s = $1b0c + &word r7s = $1b0e + &word r8s = $1b10 + &word r9s = $1b12 + &word r10s = $1b14 + &word r11s = $1b16 + &word r12s = $1b18 + &word r13s = $1b1a + &word r14s = $1b1c + &word r15s = $1b1e + + &ubyte r0L = $1b00 + &ubyte r1L = $1b02 + &ubyte r2L = $1b04 + &ubyte r3L = $1b06 + &ubyte r4L = $1b08 + &ubyte r5L = $1b0a + &ubyte r6L = $1b0c + &ubyte r7L = $1b0e + &ubyte r8L = $1b10 + &ubyte r9L = $1b12 + &ubyte r10L = $1b14 + &ubyte r11L = $1b16 + &ubyte r12L = $1b18 + &ubyte r13L = $1b1a + &ubyte r14L = $1b1c + &ubyte r15L = $1b1e + + &ubyte r0H = $1b01 + &ubyte r1H = $1b03 + &ubyte r2H = $1b05 + &ubyte r3H = $1b07 + &ubyte r4H = $1b09 + &ubyte r5H = $1b0b + &ubyte r6H = $1b0d + &ubyte r7H = $1b0f + &ubyte r8H = $1b11 + &ubyte r9H = $1b13 + &ubyte r10H = $1b15 + &ubyte r11H = $1b17 + &ubyte r12H = $1b19 + &ubyte r13H = $1b1b + &ubyte r14H = $1b1d + &ubyte r15H = $1b1f + + &byte r0sL = $1b00 + &byte r1sL = $1b02 + &byte r2sL = $1b04 + &byte r3sL = $1b06 + &byte r4sL = $1b08 + &byte r5sL = $1b0a + &byte r6sL = $1b0c + &byte r7sL = $1b0e + &byte r8sL = $1b10 + &byte r9sL = $1b12 + &byte r10sL = $1b14 + &byte r11sL = $1b16 + &byte r12sL = $1b18 + &byte r13sL = $1b1a + &byte r14sL = $1b1c + &byte r15sL = $1b1e + + &byte r0sH = $1b01 + &byte r1sH = $1b03 + &byte r2sH = $1b05 + &byte r3sH = $1b07 + &byte r4sH = $1b09 + &byte r5sH = $1b0b + &byte r6sH = $1b0d + &byte r7sH = $1b0f + &byte r8sH = $1b11 + &byte r9sH = $1b13 + &byte r10sH = $1b15 + &byte r11sH = $1b17 + &byte r12sH = $1b19 + &byte r13sH = $1b1b + &byte r14sH = $1b1d + &byte r15sH = $1b1f +} diff --git a/compiler/res/prog8lib/atari/textio.p8 b/compiler/res/prog8lib/atari/textio.p8 new file mode 100644 index 000000000..389ddb8cd --- /dev/null +++ b/compiler/res/prog8lib/atari/textio.p8 @@ -0,0 +1,402 @@ +; Prog8 definitions for the Text I/O and Screen routines for the Atari 800XL +; +; Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0 + +%import syslib +%import conv + + +txt { + +const ubyte DEFAULT_WIDTH = 40 +const ubyte DEFAULT_HEIGHT = 25 + + +sub clear_screen() { + txt.chrout(147) ; TODO +} + +sub home() { + txt.chrout(19) ; TODO +} + +sub nl() { + txt.chrout('\n') +} + +sub spc() { + txt.chrout(' ') +} + +asmsub column(ubyte col @A) clobbers(A, X, Y) { + ; ---- set the cursor on the given column (starting with 0) on the current line + ; TODO + %asm {{ + rts + }} +} + +asmsub fill_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { + ; ---- fill the character screen with the given fill character and character color. + ; (assumes screen and color matrix are at their default addresses) + ; TODO + + %asm {{ + rts + }} +} + +asmsub clear_screenchars (ubyte char @ A) clobbers(Y) { + ; ---- clear the character screen with the given fill character (leaves colors) + ; (assumes screen matrix is at the default address) + ; TODO + %asm {{ + rts + }} +} + +asmsub clear_screencolors (ubyte color @ A) clobbers(Y) { + ; ---- clear the character screen colors with the given color (leaves characters). + ; (assumes color matrix is at the default address) + ; TODO + %asm {{ + rts + }} +} + +sub color (ubyte txtcol) { + ; TODO +} + +sub lowercase() { + ; TODO +} + +sub uppercase() { + ; TODO +} + +asmsub scroll_left (ubyte alsocolors @ Pc) clobbers(A, Y) { + ; ---- scroll the whole screen 1 character to the left + ; contents of the rightmost column are unchanged, you should clear/refill this yourself + ; Carry flag determines if screen color data must be scrolled too + ; TODO + + %asm {{ + rts + }} +} + +asmsub scroll_right (ubyte alsocolors @ Pc) clobbers(A) { + ; ---- scroll the whole screen 1 character to the right + ; contents of the leftmost column are unchanged, you should clear/refill this yourself + ; Carry flag determines if screen color data must be scrolled too + ; TODO + %asm {{ + rts + }} +} + +asmsub scroll_up (ubyte alsocolors @ Pc) clobbers(A) { + ; ---- scroll the whole screen 1 character up + ; contents of the bottom row are unchanged, you should refill/clear this yourself + ; Carry flag determines if screen color data must be scrolled too + ; TODO + %asm {{ + rts + }} +} + +asmsub scroll_down (ubyte alsocolors @ Pc) clobbers(A) { + ; ---- scroll the whole screen 1 character down + ; contents of the top row are unchanged, you should refill/clear this yourself + ; Carry flag determines if screen color data must be scrolled too + ; TODO + %asm {{ + rts + }} +} + + +romsub $FFD2 = chrout(ubyte char @ A) ; 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 CHROUT of that single char. + %asm {{ + sta P8ZP_SCRATCH_B1 + sty P8ZP_SCRATCH_REG + ldy #0 +- lda (P8ZP_SCRATCH_B1),y + beq + + jsr 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 + jsr conv.ubyte2decimal + pha + tya + jsr chrout + pla + jsr chrout + txa + jsr chrout + ldx P8ZP_SCRATCH_REG + 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 + jsr conv.ubyte2decimal +_print_byte_digits + pha + cpy #'0' + beq + + tya + jsr chrout + pla + jsr chrout + jmp _ones ++ pla + cmp #'0' + beq _ones + jsr chrout +_ones txa + jsr chrout + ldx P8ZP_SCRATCH_REG + 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 + pha + cmp #0 + bpl + + lda #'-' + jsr chrout ++ pla + jsr conv.byte2decimal + jmp print_ub._print_byte_digits + }} +} + +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 + bcc + + pha + lda #'$' + jsr chrout + pla ++ jsr conv.ubyte2hex + jsr chrout + tya + jsr chrout + ldx P8ZP_SCRATCH_REG + 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 + sta P8ZP_SCRATCH_B1 + bcc + + lda #'%' + jsr chrout ++ ldy #8 +- lda #'0' + asl P8ZP_SCRATCH_B1 + bcc + + lda #'1' ++ jsr chrout + dey + bne - + ldx P8ZP_SCRATCH_REG + 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 + jsr conv.uword2decimal + ldy #0 +- lda conv.uword2decimal.decTenThousands,y + beq + + jsr chrout + iny + bne - ++ ldx P8ZP_SCRATCH_REG + 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 + jsr conv.uword2decimal + ldx P8ZP_SCRATCH_REG + ldy #0 +- lda conv.uword2decimal.decTenThousands,y + beq _allzero + cmp #'0' + bne _gotdigit + iny + bne - + +_gotdigit + jsr chrout + iny + lda conv.uword2decimal.decTenThousands,y + bne _gotdigit + rts +_allzero + lda #'0' + jmp 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 chrout + tya + eor #255 + tay + pla + eor #255 + clc + adc #1 + bcc + + iny ++ jmp print_uw + }} +} + +asmsub input_chars (uword buffer @ AY) clobbers(A) -> ubyte @ Y { + ; ---- Input a string (max. 80 chars) from the keyboard. Returns length in Y. (string is terminated with a 0 byte as well) + ; It assumes the keyboard is selected as I/O channel! + ; TODO + + %asm {{ + ldy #0 + rts + }} +} + +asmsub setchr (ubyte col @X, ubyte row @Y, ubyte character @A) clobbers(A, Y) { + ; ---- sets the character in the screen matrix at the given position + ; TODO + %asm {{ + rts + }} +} + +asmsub getchr (ubyte col @A, ubyte row @Y) clobbers(Y) -> ubyte @ A { + ; ---- get the character in the screen matrix at the given location + ; TODO + %asm {{ + rts + }} +} + +asmsub setclr (ubyte col @X, ubyte row @Y, ubyte color @A) clobbers(A, Y) { + ; ---- set the color in A on the screen matrix at the given position + ; TODO + %asm {{ + rts + }} +} + +asmsub getclr (ubyte col @A, ubyte row @Y) clobbers(Y) -> ubyte @ A { + ; ---- get the color in the screen color matrix at the given location + ; TODO + %asm {{ + rts + }} +} + +sub setcc (ubyte column, ubyte row, ubyte char, ubyte charcolor) { + ; ---- set char+color at the given position on the screen + ; TODO + %asm {{ + rts + }} +} + +asmsub plot (ubyte col @ Y, ubyte row @ A) clobbers(A) { + ; ---- set cursor at specific position + ; TODO + %asm {{ + rts + }} +} + +asmsub width() clobbers(X,Y) -> ubyte @A { + ; -- returns the text screen width (number of columns) + ; TODO + %asm {{ + lda #0 + rts + }} +} + +asmsub height() clobbers(X, Y) -> ubyte @A { + ; -- returns the text screen height (number of rows) + ; TODO + %asm {{ + lda #0 + rts + }} +} + +} diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 1ac676e56..23e812684 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -2,6 +2,7 @@ package prog8 import kotlinx.cli.* import prog8.ast.base.AstException +import prog8.codegen.target.AtariTarget import prog8.codegen.target.C128Target import prog8.codegen.target.C64Target import prog8.codegen.target.Cx16Target @@ -44,7 +45,7 @@ private fun compileMain(args: Array): Boolean { val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results") val asmListfile by cli.option(ArgType.Boolean, fullName = "asmlist", description = "make the assembler produce a listing file as well") val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental codegen") - val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}')").default(C64Target.NAME) + val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler (one of '${C64Target.NAME}', '${C128Target.NAME}', '${Cx16Target.NAME}', '${AtariTarget.NAME}')").default(C64Target.NAME) val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths, separated with ${File.pathSeparator}, to search in for imported modules").multiple().delimiter(File.pathSeparator) val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999) @@ -71,7 +72,7 @@ private fun compileMain(args: Array): Boolean { if(srcdirs.firstOrNull()!=".") srcdirs.add(0, ".") - if (compilationTarget !in setOf(C64Target.NAME, C128Target.NAME, Cx16Target.NAME)) { + if (compilationTarget !in setOf(C64Target.NAME, C128Target.NAME, Cx16Target.NAME, AtariTarget.NAME)) { System.err.println("Invalid compilation target: $compilationTarget") return false } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 9148f0f70..6438ed9f2 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -12,6 +12,7 @@ import prog8.ast.expressions.NumericLiteral import prog8.ast.statements.Directive import prog8.ast.statements.VarDecl import prog8.ast.walk.IAstVisitor +import prog8.codegen.target.AtariTarget import prog8.codegen.target.C128Target import prog8.codegen.target.C64Target import prog8.codegen.target.Cx16Target @@ -59,6 +60,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult { C64Target.NAME -> C64Target() C128Target.NAME -> C128Target() Cx16Target.NAME -> Cx16Target() + AtariTarget.NAME -> AtariTarget() else -> throw IllegalArgumentException("invalid compilation target") } @@ -206,6 +208,9 @@ fun parseImports(filepath: Path, if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG) errors.err("BASIC launcher requires output type PRG", program.toplevelModule.position) + if(compilerOptions.launcher == LauncherType.BASIC && compTarget.name==AtariTarget.NAME) + errors.err("atari target cannot use CBM BASIC launcher, use NONE", program.toplevelModule.position) + errors.report() return Triple(program, compilerOptions, importedFiles) @@ -255,7 +260,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget OutputType.PRG } } - val launcherType = if (launcherTypeStr == null) LauncherType.BASIC else { + val launcherType = if (launcherTypeStr == null) compTarget.defaultLauncherType else { try { LauncherType.valueOf(launcherTypeStr) } catch (x: IllegalArgumentException) { @@ -274,7 +279,7 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget private fun processAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) { println("Analyzing code...") - program.preprocessAst(errors) + program.preprocessAst(errors, compilerOptions.compTarget) program.checkIdentifiers(errors, compilerOptions) errors.report() program.charLiteralsToUByteLiterals(compilerOptions.compTarget, errors) diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index bf9fef66c..27f455edc 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -10,10 +10,7 @@ import prog8.ast.statements.Directive import prog8.ast.statements.VarDeclOrigin import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.compilerinterface.CompilationOptions -import prog8.compilerinterface.ICompilationTarget -import prog8.compilerinterface.IErrorReporter -import prog8.compilerinterface.IVariablesAndConsts +import prog8.compilerinterface.* internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) { @@ -51,7 +48,8 @@ internal fun Program.reorderStatements(errors: IErrorReporter, options: Compilat internal fun Program.charLiteralsToUByteLiterals(target: ICompilationTarget, errors: IErrorReporter) { val walker = object : AstWalker() { override fun after(char: CharLiteral, parent: Node): Iterable { - if(char.encoding !in target.supportedEncodings) { + require(char.encoding != Encoding.DEFAULT) + if(char.encoding != Encoding.DEFAULT && char.encoding !in target.supportedEncodings) { errors.err("compilation target doesn't support this text encoding", char.position) return noModifications } @@ -83,8 +81,8 @@ internal fun Program.verifyFunctionArgTypes() { fixer.visit(this) } -internal fun Program.preprocessAst(errors: IErrorReporter) { - val transforms = AstPreprocessor(this, errors) +internal fun Program.preprocessAst(errors: IErrorReporter, target: ICompilationTarget) { + val transforms = AstPreprocessor(this, errors, target) transforms.visit(this) var mods = transforms.applyModifications() while(mods>0) diff --git a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt index 6c76064cb..064ac1e5b 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt @@ -155,7 +155,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter, else '_' }.joinToString("") - call.args[0] = StringLiteral(processed, Encoding.PETSCII, name.position) + call.args[0] = StringLiteral(processed, compTarget.defaultEncoding, name.position) call.args[0].linkParents(call as Node) } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 44052efb5..98d6249d1 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -9,10 +9,24 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification +import prog8.compilerinterface.Encoding +import prog8.compilerinterface.ICompilationTarget import prog8.compilerinterface.IErrorReporter -class AstPreprocessor(val program: Program, val errors: IErrorReporter) : AstWalker() { +class AstPreprocessor(val program: Program, val errors: IErrorReporter, val compTarget: ICompilationTarget) : AstWalker() { + + override fun before(char: CharLiteral, parent: Node): Iterable { + if(char.encoding==Encoding.DEFAULT) + char.encoding = compTarget.defaultEncoding + return noModifications + } + + override fun before(string: StringLiteral, parent: Node): Iterable { + if(string.encoding==Encoding.DEFAULT) + string.encoding = compTarget.defaultEncoding + return super.before(string, parent) + } override fun after(range: RangeExpression, parent: Node): Iterable { // has to be done before the constant folding, otherwise certain checks there will fail on invalid range sizes @@ -47,7 +61,7 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter) : AstWal return modifications } - override fun before(scope: AnonymousScope, parent: Node): Iterable { + override fun after(scope: AnonymousScope, parent: Node): Iterable { // move vardecls in Anonymous scope up to the containing subroutine // and add initialization assignment in its place if needed diff --git a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt index d889ef0c7..cf5bdc57c 100644 --- a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt +++ b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt @@ -12,6 +12,7 @@ import prog8.ast.statements.VarDecl import prog8.ast.statements.WhenChoice import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification +import prog8.compilerinterface.Encoding import prog8.compilerinterface.ICompilationTarget import prog8.compilerinterface.IErrorReporter @@ -21,7 +22,7 @@ internal class LiteralsToAutoVars(private val program: Program, private val errors: IErrorReporter) : AstWalker() { override fun after(string: StringLiteral, parent: Node): Iterable { - if(string.encoding !in target.supportedEncodings) { + if(string.encoding != Encoding.DEFAULT && string.encoding !in target.supportedEncodings) { errors.err("compilation target doesn't support this text encoding", string.position) return noModifications } diff --git a/compiler/test/ast/TestAstToSourceText.kt b/compiler/test/ast/TestAstToSourceText.kt index a516a595a..cc77ce8c8 100644 --- a/compiler/test/ast/TestAstToSourceText.kt +++ b/compiler/test/ast/TestAstToSourceText.kt @@ -68,7 +68,7 @@ class TestAstToSourceText: AnnotationSpec() { } """) val (txt, _) = roundTrip(parseModule(orig)) - txt shouldContain Regex("str +s += +petscii:\"fooBar\\\\n\"") + txt shouldContain Regex("str +s += +\"fooBar\\\\n\"") } @Test @@ -101,7 +101,7 @@ class TestAstToSourceText: AnnotationSpec() { } """) val (txt, _) = roundTrip(parseModule(orig)) - txt shouldContain Regex("ubyte +c += +petscii:'x'") + txt shouldContain Regex("ubyte +c += +'x'") } @Test diff --git a/compiler/test/ast/TestProg8Parser.kt b/compiler/test/ast/TestProg8Parser.kt index c9b3fdaa8..696aad80b 100644 --- a/compiler/test/ast/TestProg8Parser.kt +++ b/compiler/test/ast/TestProg8Parser.kt @@ -425,7 +425,7 @@ class TestProg8Parser: FunSpec( { .statements.filterIsInstance()[0] val rhs = decl.value as CharLiteral - rhs.encoding shouldBe Encoding.PETSCII + rhs.encoding shouldBe Encoding.DEFAULT rhs.value shouldBe 'x' } @@ -478,7 +478,7 @@ class TestProg8Parser: FunSpec( { val rhs = decl.value as CharLiteral rhs.value shouldBe 'x' - rhs.encoding shouldBe Encoding.PETSCII + rhs.encoding shouldBe Encoding.DEFAULT } test("on rhs of subroutine-level const decl, screencode encoded") { @@ -532,7 +532,7 @@ class TestProg8Parser: FunSpec( { .statements.filterIsInstance()[0] .statements.filterIsInstance()[0] val rhs = decl.value as StringLiteral - rhs.encoding shouldBe Encoding.PETSCII + rhs.encoding shouldBe Encoding.DEFAULT rhs.value shouldBe "name" } diff --git a/compiler/test/helpers/Dummies.kt b/compiler/test/helpers/Dummies.kt index ba6fc1a85..0104632e1 100644 --- a/compiler/test/helpers/Dummies.kt +++ b/compiler/test/helpers/Dummies.kt @@ -52,6 +52,8 @@ internal object DummyCompilationTarget : ICompilationTarget { override val machine: IMachineDefinition get() = throw NotImplementedError("dummy") override val supportedEncodings = setOf(Encoding.PETSCII, Encoding.SCREENCODES, Encoding.ISO) + override val defaultEncoding = Encoding.PETSCII + override val defaultLauncherType = LauncherType.NONE override fun encodeString(str: String, encoding: Encoding): List { throw NotImplementedError("dummy") diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index 4f84b26b2..41b6b99a2 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -7,6 +7,7 @@ import prog8.ast.base.VarDeclType import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.IAstVisitor +import prog8.compilerinterface.Encoding /** @@ -293,11 +294,17 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: } override fun visit(char: CharLiteral) { - output("${char.encoding.prefix}:'${escape(char.value.toString())}'") + if(char.encoding==Encoding.DEFAULT) + output("'${escape(char.value.toString())}'") + else + output("${char.encoding.prefix}:'${escape(char.value.toString())}'") } override fun visit(string: StringLiteral) { - output("${string.encoding.prefix}:\"${escape(string.value)}\"") + if(string.encoding==Encoding.DEFAULT) + output("\"${escape(string.value)}\"") + else + output("${string.encoding.prefix}:\"${escape(string.value)}\"") } override fun visit(array: ArrayLiteral) { diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index dab9e86b3..a01a7174a 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -457,7 +457,7 @@ private fun Prog8ANTLRParser.CharliteralContext.toAst(): CharLiteral { Encoding.values().singleOrNull { it.prefix == enc } ?: throw SyntaxError("invalid encoding", toPosition()) else - Encoding.PETSCII + Encoding.DEFAULT return CharLiteral(unescape(text.substring(1, text.length-1), toPosition())[0], encoding, toPosition()) } @@ -469,7 +469,7 @@ private fun Prog8ANTLRParser.StringliteralContext.toAst(): StringLiteral { Encoding.values().singleOrNull { it.prefix == enc } ?: throw SyntaxError("invalid encoding", toPosition()) else - Encoding.PETSCII + Encoding.DEFAULT return StringLiteral(unescape(text.substring(1, text.length-1), toPosition()), encoding, toPosition()) } diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 0817bca35..a6abb04b3 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -593,7 +593,7 @@ class NumericLiteral(val type: DataType, // only numerical types allowed } class CharLiteral(val value: Char, - val encoding: Encoding, + var encoding: Encoding, override val position: Position) : Expression() { override lateinit var parent: Node @@ -607,7 +607,8 @@ class CharLiteral(val value: Char, throw FatalAstException("can't replace here") } - override fun copy() = CharLiteral(value, encoding, position) + override fun copy() = + CharLiteral(value, encoding, position) override fun referencesIdentifier(nameInSource: List) = false override fun constValue(program: Program): NumericLiteral { val bytevalue = program.encoding.encodeString(value.toString(), encoding).single() @@ -628,7 +629,7 @@ class CharLiteral(val value: Char, } class StringLiteral(val value: String, - val encoding: Encoding, + var encoding: Encoding, override val position: Position) : Expression() { override lateinit var parent: Node diff --git a/compilerAst/src/prog8/compilerinterface/IStringEncoding.kt b/compilerAst/src/prog8/compilerinterface/IStringEncoding.kt index 5c53d3a60..6ba12e32d 100644 --- a/compilerAst/src/prog8/compilerinterface/IStringEncoding.kt +++ b/compilerAst/src/prog8/compilerinterface/IStringEncoding.kt @@ -1,9 +1,10 @@ package prog8.compilerinterface enum class Encoding(val prefix: String) { - PETSCII("petscii"), // c64/c128/cx16 - SCREENCODES("sc"), // c64/c128/cx16 - ISO("iso") // cx16 + DEFAULT("default"), // depends on compilation target + PETSCII("petscii"), // c64/c128/cx16 + SCREENCODES("sc"), // c64/c128/cx16 + ISO("iso") // cx16 } interface IStringEncoding { diff --git a/compilerInterfaces/src/prog8/compilerinterface/ICompilationTarget.kt b/compilerInterfaces/src/prog8/compilerinterface/ICompilationTarget.kt index bf20bd3ac..de5bd6032 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/ICompilationTarget.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/ICompilationTarget.kt @@ -9,6 +9,8 @@ interface ICompilationTarget: IStringEncoding, IMemSizer { val name: String val machine: IMachineDefinition val supportedEncodings: Set + val defaultEncoding: Encoding + val defaultLauncherType: LauncherType override fun encodeString(str: String, encoding: Encoding): List override fun decodeString(bytes: List, encoding: Encoding): String diff --git a/docs/source/building.rst b/docs/source/building.rst index bfa331900..3e2aa4bc2 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -99,7 +99,7 @@ One or more .p8 module files ``-target `` Sets the target output of the compiler, currently 'c64' and 'cx16' are valid targets. - c64 = Commodore 64, c128 = Commodore 128, cx16 = Commander X16. + c64 = Commodore 64, c128 = Commodore 128, cx16 = Commander X16, atari = Atari 800 XL Default = c64 ``-srcdirs `` diff --git a/docs/source/index.rst b/docs/source/index.rst index e20de9596..9b5ebdf37 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,7 +18,8 @@ This CPU is from the late 1970's and early 1980's and was used in many home comp such as the `Commodore-64 `_. The language aims to provide many conveniences over raw assembly code (even when using a macro assembler), while still being low level enough to create high performance programs. -You can compile programs for various machines with this CPU such as the Commodore-64 and Commodore-128, and the Commander X16. +You can compile programs for various machines with this CPU such as the Commodore-64 and Commodore-128, +the Commander X16, and the Atari 800 XL. Prog8 is copyright © Irmen de Jong (irmen@razorvine.net | http://www.razorvine.net). diff --git a/docs/source/targetsystem.rst b/docs/source/targetsystem.rst index 847469ec3..3bf10abbe 100644 --- a/docs/source/targetsystem.rst +++ b/docs/source/targetsystem.rst @@ -12,8 +12,9 @@ Prog8 targets the following hardware: Currently these machines can be selected as a compilation target (via the ``-target`` compiler argument): - 'c64': the Commodore 64 -- 'c128': the Commodore 128 (*limited support only for now*) - 'cx16': the `Commander X16 `_ +- 'c128': the Commodore 128 (*limited support*) +- 'atari': the Atari 800 XL (*experimental support*) This chapter explains some relevant system details of the c64 and cx16 machines. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f7e6b261d..86f439448 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,9 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- move memcopy() logic to prog8_lib and call this from sys.memcopy() the same for all targets (so cx16 now also works when kernal is disabled!) +- same for memset() +- get rid of RAW_LOAD_ADDRESS and make specifying the load address for RAW launcher mode required ... @@ -48,6 +51,7 @@ Compiler: Libraries: - fix the problems in c128 target, and flesh out its libraries. +- fix the problems in atari target, and flesh out its libraries. - c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking) - optimize several inner loops in gfx2 even further? - add modes 2 and 3 to gfx2 (lowres 4 color and 16 color)? diff --git a/examples/test.p8 b/examples/test.p8 index 9031970aa..0aa8d4b90 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,33 +1,11 @@ -%import textio +%launcher none main { sub start() { - ubyte xx = 30 - byte cc + uword @shared names_buffer = memory("filenames", 200, 0) -; cc=0 -; 30 |> sin8u |> cos8u |> cc -; txt.print_ub(cc) -; txt.nl() -; cc=0 -; xx |> sin8u |> cos8u |> cc -; txt.print_ub(cc) -; txt.nl() - 100 |> cc - txt.print_b(cc) - txt.nl() - -100 |> abs |> abs |> cc - txt.print_b(cc) - txt.nl() - cc |> abs |> abs |> cc - txt.print_b(cc) - txt.nl() - cc = -100 - cc |> abs |> abs |> cc - txt.print_b(cc) - txt.nl() - - repeat { - } + do { + ubyte @shared char = '*' + } until true } }