mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
added 'atari' compiler target beginnings (Atari 800 XL)
also default char and string encoding now taken from compiler target
This commit is contained in:
parent
553f3b45d2
commit
6a0551cea1
@ -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()
|
||||
|
||||
|
@ -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<String>
|
||||
|
||||
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()
|
||||
|
53
codeGenTargets/src/prog8/codegen/target/AtariTarget.kt
Normal file
53
codeGenTargets/src/prog8/codegen/target/AtariTarget.kt
Normal file
@ -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<Int> =
|
||||
asmsub6502ArgsEvalOrder(sub)
|
||||
override fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>, paramRegisters: List<RegisterOrStatusflag>) =
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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<String> {
|
||||
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
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
307
compiler/res/prog8lib/atari/syslib.p8
Normal file
307
compiler/res/prog8lib/atari/syslib.p8
Normal file
@ -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
|
||||
ldy #>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
|
||||
}
|
402
compiler/res/prog8lib/atari/textio.p8
Normal file
402
compiler/res/prog8lib/atari/textio.p8
Normal file
@ -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
|
||||
}}
|
||||
}
|
||||
|
||||
}
|
@ -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<String>): 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<String>): 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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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<IAstModification> {
|
||||
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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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<IAstModification> {
|
||||
if(char.encoding==Encoding.DEFAULT)
|
||||
char.encoding = compTarget.defaultEncoding
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun before(string: StringLiteral, parent: Node): Iterable<IAstModification> {
|
||||
if(string.encoding==Encoding.DEFAULT)
|
||||
string.encoding = compTarget.defaultEncoding
|
||||
return super.before(string, parent)
|
||||
}
|
||||
|
||||
override fun after(range: RangeExpression, parent: Node): Iterable<IAstModification> {
|
||||
// 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<IAstModification> {
|
||||
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
|
||||
|
||||
// move vardecls in Anonymous scope up to the containing subroutine
|
||||
// and add initialization assignment in its place if needed
|
||||
|
@ -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<IAstModification> {
|
||||
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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -425,7 +425,7 @@ class TestProg8Parser: FunSpec( {
|
||||
.statements.filterIsInstance<VarDecl>()[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<Block>()[0]
|
||||
.statements.filterIsInstance<VarDecl>()[0]
|
||||
val rhs = decl.value as StringLiteral
|
||||
rhs.encoding shouldBe Encoding.PETSCII
|
||||
rhs.encoding shouldBe Encoding.DEFAULT
|
||||
rhs.value shouldBe "name"
|
||||
}
|
||||
|
||||
|
@ -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<UByte> {
|
||||
throw NotImplementedError("dummy")
|
||||
|
@ -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) {
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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<String>) = 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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -9,6 +9,8 @@ interface ICompilationTarget: IStringEncoding, IMemSizer {
|
||||
val name: String
|
||||
val machine: IMachineDefinition
|
||||
val supportedEncodings: Set<Encoding>
|
||||
val defaultEncoding: Encoding
|
||||
val defaultLauncherType: LauncherType
|
||||
|
||||
override fun encodeString(str: String, encoding: Encoding): List<UByte>
|
||||
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String
|
||||
|
@ -99,7 +99,7 @@ One or more .p8 module files
|
||||
|
||||
``-target <compilation 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 <pathlist>``
|
||||
|
@ -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 <https://en.wikipedia.org/wiki/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).
|
||||
|
@ -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 <https://www.commanderx16.com/>`_
|
||||
- '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.
|
||||
|
||||
|
@ -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)?
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user