From a50400b7d153e4c3c21c647c3e17e82358b0e89e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 25 Apr 2024 01:17:44 +0200 Subject: [PATCH] initial neo6502 target --- codeCore/src/prog8/code/target/C64Target.kt | 4 +- .../src/prog8/code/target/Neo6502Target.kt | 30 ++ .../neo6502/Neo6502MachineDefinition.kt | 52 ++ .../code/target/neo6502/Neo6502Zeropage.kt | 48 ++ .../prog8/codegen/cpu6502/AssemblyProgram.kt | 40 +- compiler/res/prog8lib/atari/syslib.p8 | 2 +- compiler/res/prog8lib/c128/syslib.p8 | 2 +- compiler/res/prog8lib/c64/syslib.p8 | 2 +- compiler/res/prog8lib/cx16/syslib.p8 | 4 +- compiler/res/prog8lib/neo/neo6502.asm | 500 ++++++++++++++++++ compiler/res/prog8lib/neo/syslib.p8 | 439 +++++++++++++++ compiler/res/prog8lib/pet32/syslib.p8 | 2 +- compiler/res/prog8lib/virtual/syslib.p8 | 2 +- compiler/src/prog8/CompilerMain.kt | 2 +- compiler/src/prog8/compiler/Compiler.kt | 11 +- docs/source/compiling.rst | 2 +- docs/source/libraries.rst | 1 + docs/source/targetsystem.rst | 1 + examples/test.p8 | 128 ++++- 19 files changed, 1241 insertions(+), 31 deletions(-) create mode 100644 codeCore/src/prog8/code/target/Neo6502Target.kt create mode 100644 codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt create mode 100644 codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt create mode 100644 compiler/res/prog8lib/neo/neo6502.asm create mode 100644 compiler/res/prog8lib/neo/syslib.p8 diff --git a/codeCore/src/prog8/code/target/C64Target.kt b/codeCore/src/prog8/code/target/C64Target.kt index cec4c4090..c00615a9a 100644 --- a/codeCore/src/prog8/code/target/C64Target.kt +++ b/codeCore/src/prog8/code/target/C64Target.kt @@ -27,6 +27,7 @@ val CompilationTargets = listOf( Cx16Target.NAME, PETTarget.NAME, AtariTarget.NAME, + Neo6502Target.NAME, VMTarget.NAME ) @@ -37,5 +38,6 @@ fun getCompilationTargetByName(name: String) = when(name.lowercase()) { PETTarget.NAME -> PETTarget() AtariTarget.NAME -> AtariTarget() VMTarget.NAME -> VMTarget() + Neo6502Target.NAME -> Neo6502Target() else -> throw IllegalArgumentException("invalid compilation target") -} \ No newline at end of file +} diff --git a/codeCore/src/prog8/code/target/Neo6502Target.kt b/codeCore/src/prog8/code/target/Neo6502Target.kt new file mode 100644 index 000000000..1b14a4164 --- /dev/null +++ b/codeCore/src/prog8/code/target/Neo6502Target.kt @@ -0,0 +1,30 @@ +package prog8.code.target + +import prog8.code.core.* +import prog8.code.target.neo6502.Neo6502MachineDefinition + + +class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer { + override val name = NAME + override val machine = Neo6502MachineDefinition() + override val defaultEncoding = Encoding.ISO + + companion object { + const val NAME = "neo" + } + + override fun memorySize(dt: DataType): Int { + return when(dt) { + in ByteDatatypesWithBoolean -> 1 + in WordDatatypes, in PassByReferenceDatatypes -> 2 + DataType.FLOAT -> machine.FLOAT_MEM_SIZE + else -> throw IllegalArgumentException("invalid datatype") + } + } + + override fun memorySize(arrayDt: DataType, numElements: Int) = + if(arrayDt== DataType.UWORD) + numElements // pointer to bytes. + else + memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements +} diff --git a/codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt b/codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt new file mode 100644 index 000000000..d067ea43b --- /dev/null +++ b/codeCore/src/prog8/code/target/neo6502/Neo6502MachineDefinition.kt @@ -0,0 +1,52 @@ +package prog8.code.target.neo6502 + +import prog8.code.core.* +import java.nio.file.Path + + +class Neo6502MachineDefinition: IMachineDefinition { + + override val cpu = CpuType.CPU65c02 + + override val FLOAT_MAX_POSITIVE = 9.999999999e97 + override val FLOAT_MAX_NEGATIVE = -9.999999999e97 + override val FLOAT_MEM_SIZE = 6 + override val PROGRAM_LOAD_ADDRESS = 0x0800u + + override val BSSHIGHRAM_START = 0u // TODO + override val BSSHIGHRAM_END = 0u // TODO + override val BSSGOLDENRAM_START = 0u // TODO + override val BSSGOLDENRAM_END = 0u // TODO + + override lateinit var zeropage: Zeropage + override lateinit var golden: GoldenRam + + override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number") + override fun convertFloatToBytes(num: Double): List = TODO("atari float to bytes") + override fun convertBytesToFloat(bytes: List): Double = TODO("atari bytes to float") + + override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List { + return listOf("syslib") + } + + override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) { + if(selectedEmulator!=1) { + System.err.println("The neo target only supports the main emulator (neo).") + return + } + + val cmdline = listOf("neo", "${programNameWithPath}.bin@800", "cold") + + println("\nStarting Neo6502 emulator...") + val processb = ProcessBuilder(cmdline).inheritIO() + val process: Process = processb.start() + process.waitFor() + } + + override fun isIOAddress(address: UInt): Boolean = address in 0xff00u..0xff0fu + + override fun initializeMemoryAreas(compilerOptions: CompilationOptions) { + zeropage = Neo6502Zeropage(compilerOptions) + golden = GoldenRam(compilerOptions, UIntRange.EMPTY) + } +} diff --git a/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt b/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt new file mode 100644 index 000000000..77c1350d4 --- /dev/null +++ b/codeCore/src/prog8/code/target/neo6502/Neo6502Zeropage.kt @@ -0,0 +1,48 @@ +package prog8.code.target.neo6502 + +import prog8.code.core.* + +class Neo6502Zeropage(options: CompilationOptions) : Zeropage(options) { + + override val SCRATCH_B1 = 0xfau // temp storage for a single byte + override val SCRATCH_REG = 0xfbu // temp storage for a register, must be B1+1 + override val SCRATCH_W1 = 0xfcu // temp storage 1 for a word $fc+$fd + override val SCRATCH_W2 = 0xfeu // temp storage 2 for a word $fe+$ff + + init { + if (options.floats) { + throw InternalCompilerException("Neo6502 target doesn't support floating point routines") + } + + when (options.zeropage) { + ZeropageType.DONTUSE -> { + free.clear() // don't use zeropage at all + } + else -> { + free.addAll(0x22u..0xffu) + } + } + + val distinctFree = free.distinct() + free.clear() + free.addAll(distinctFree) + + removeReservedFromFreePool() + allocateCx16VirtualRegisters() + retainAllowed() + } + + override fun allocateCx16VirtualRegisters() { + // Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses. + // However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well. + // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer) + for(reg in 0..15) { + allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2) // cx16.r0 .. cx16.r15 + allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.WORD, 2) // cx16.r0s .. cx16.r15s + allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0L .. cx16.r15L + allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.UBYTE, 1) // cx16.r0H .. cx16.r15H + allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sL .. cx16.r15sL + allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.BYTE, 1) // cx16.r0sH .. cx16.r15sH + } + } +} \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt index d471b87b7..7395b1782 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AssemblyProgram.kt @@ -1,7 +1,9 @@ package prog8.codegen.cpu6502 import prog8.code.core.* +import prog8.code.target.AtariTarget import prog8.code.target.C64Target +import prog8.code.target.Neo6502Target import java.nio.file.Path @@ -16,6 +18,7 @@ internal class AssemblyProgram( private val binFile = outputDir.resolve("$name.bin") private val viceMonListFile = outputDir.resolve(C64Target.viceMonListName(name)) private val listFile = outputDir.resolve("$name.list") + private val targetWithoutBreakpointsForEmulator = setOf(AtariTarget.NAME, Neo6502Target.NAME) override fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean { @@ -96,12 +99,47 @@ internal class AssemblyProgram( command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString())) assemblerCommand = command } + "neo" -> { + // Neo6502 raw program generation. + + if(options.output!=OutputType.RAW || options.loadAddress!=0x0800u || options.launcher!=CbmPrgLauncherType.NONE) { + throw AssemblyError("invalid program compilation options. Neo6502 requires %output raw, %launcher none, %address $0800") + } + + // TODO are these options okay for neo? + val command = mutableListOf("64tass", "--case-sensitive", "--long-branch", + "-Wall", // "-Werror", "-Wno-strict-bool" + "--no-monitor" + ) + + if(options.warnSymbolShadowing) + command.add("-Wshadow") + else + command.add("-Wno-shadow") + + if(options.asmQuiet) + command.add("--quiet") + + if(options.asmListfile) + command.add("--list=$listFile") + + val outFile = when (options.output) { + OutputType.RAW -> { + command.add("--nostart") + println("\nCreating raw binary for target ${compTarget.name}.") + binFile + } + else -> throw AssemblyError("invalid output type, need 'raw'") + } + command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString())) + assemblerCommand = command + } else -> throw AssemblyError("invalid compilation target") } val proc = ProcessBuilder(assemblerCommand).inheritIO().start() val result = proc.waitFor() - if (result == 0 && compTarget.name!="atari") { + if (result == 0 && compTarget.name !in targetWithoutBreakpointsForEmulator) { removeGeneratedLabelsFromMonlist() generateBreakpointList() } diff --git a/compiler/res/prog8lib/atari/syslib.p8 b/compiler/res/prog8lib/atari/syslib.p8 index b0779f0f4..07e6d638e 100644 --- a/compiler/res/prog8lib/atari/syslib.p8 +++ b/compiler/res/prog8lib/atari/syslib.p8 @@ -21,7 +21,7 @@ atari { sys { ; ------- lowlevel system routines -------- - const ubyte target = 8 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL + const ubyte target = 8 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index 710d37b3c..aebe365d9 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -402,7 +402,7 @@ asmsub x16jsrfar() { sys { ; ------- lowlevel system routines -------- - const ubyte target = 128 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16. + const ubyte target = 128 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index c3c3142ac..385e9c4df 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -432,7 +432,7 @@ _jmpfar jmp $0000 ; modified sys { ; ------- lowlevel system routines -------- - const ubyte target = 64 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16. + const ubyte target = 64 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 10eb5900f..3459f2518 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -332,7 +332,7 @@ cx16 { &ubyte VERA_FX_X_POS_S = VERA_BASE + $0009 &ubyte VERA_FX_Y_POS_S = VERA_BASE + $000a &ubyte VERA_FX_POLY_FILL_L = VERA_BASE + $000b - &ubyte VERA_FX_POLY_FILL_H = VERA_BASE + $000c + &ubyte VERA_FX_POLY_FILL_H = VERA_BASE + $000cF &uword VERA_FX_POLY_FILL = VERA_BASE + $000b &ubyte VERA_FX_CACHE_L = VERA_BASE + $0009 &ubyte VERA_FX_CACHE_M = VERA_BASE + $000a @@ -1372,7 +1372,7 @@ _continue iny sys { ; ------- lowlevel system routines -------- - const ubyte target = 16 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16. + const ubyte target = 16 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 diff --git a/compiler/res/prog8lib/neo/neo6502.asm b/compiler/res/prog8lib/neo/neo6502.asm new file mode 100644 index 000000000..ad292ace5 --- /dev/null +++ b/compiler/res/prog8lib/neo/neo6502.asm @@ -0,0 +1,500 @@ +; Convenience macros for Neo6502 applications programming +; SPDX-License-Identifier: CC0-1.0 +; obtained from https://github.com/paulscottrobson/neo6502-firmware + +;-----------------------------------------------------; +; Neo6502 Kernel jump vectors (see kernel/kernel.asm) ; +;-----------------------------------------------------; + +ChainBasicOnlyProgram = $ffdf +ChainBasicProgram = $ffe2 +WriteCharacterInline = $ffe5 +LoadExtended = $ffe8 +ReadLine = $FFEB +ReadCharacter = $FFEE +WriteCharacter = $FFF1 +WaitMessage = $FFF4 +SendMessage = $FFF7 + + +;--------------------------------------; +; Neo6502 Kernel API control addresses ; +;--------------------------------------; + +ControlPort = $FF00 +API_COMMAND = ControlPort + 0 ; function group address +API_FUNCTION = ControlPort + 1 ; function address +API_ERROR = ControlPort + 2 ; function error codes +API_STATUS = ControlPort + 3 ; misc hardware status codes (bit-field) +API_PARAMETERS = ControlPort + 4 ; function parameters base address (+0-7) + + +;------------------------------------------------; +; Neo6502 Kernel API control codes (see api.pdf) ; +;------------------------------------------------; + +; Status Information +API_ERROR_NONE = #$00 ; error code +API_STATUS_ESC = #$07 ; flag + +; System functions (Group 1) +API_GROUP_SYSTEM = #$01 ; API function group +API_FN_TIMER = #$01 ; API function +API_FN_KEY_STATUS = #$02 ; API function +API_FN_BASIC = #$03 ; API function +API_FN_CREDITS = #$04 ; API function +API_FN_SERIAL_STATUS = #$05 ; API function +API_FN_LOCALE = #$06 ; API function +API_FN_RESET = #$07 ; API function +API_FN_MOS = #$08 ; API function +API_FN_SWEET16 = #$09 ; API function + +; Console functions (Group 2) +API_GROUP_CONSOLE = #$02 ; API function group +API_FN_READ_CHAR = #$01 ; API function +API_FN_CONSOLE_STATUS = #$02 ; API function +API_FN_READ_LINE = #$03 ; API function +API_FN_DEFINE_HOTKEY = #$04 ; API function +API_FN_DEFINE_CHAR = #$05 ; API function +API_FN_WRITE_CHAR = #$06 ; API function +API_FN_SET_CURSOR_POS = #$07 ; API function +API_FN_LIST_HOTKEYS = #$08 ; API function +API_FN_SCREEN_SIZE = #$09 ; API function +API_FN_INSERT_LINE = #$0A ; API function +API_FN_DELETE_LINE = #$0B ; API function +API_FN_CLEAR_SCREEN = #$0C ; API function +API_FN_CURSOR_POS = #$0D ; API function +API_FN_CLEAR_REGIION = #$0E ; API function +API_FN_SET_TEXT_COLOR = #$0F ; API function +API_FN_CURSOR_INVERSE = #$10 ; API function + +; Console results (Group 2 Function 2) +API_QUEUE_EMPTY = #$FF ; API result (status code) + +; File I/O functions (Group 3) +API_GROUP_FILEIO = #$03 ; API function group +API_FN_LIST_DIRECTORY = #$01 ; API function +API_FN_LOAD_FILENAME = #$02 ; API function +API_FN_STORE_FILENAME = #$03 ; API function +API_FN_FILE_OPEN = #$04 ; API function +API_FN_FILE_CLOSE = #$05 ; API function +API_FN_FILE_SEEK = #$06 ; API function +API_FN_FILE_TELL = #$07 ; API function +API_FN_FILE_READ = #$08 ; API function +API_FN_FILE_WRITE = #$09 ; API function +API_FN_FILE_SIZE = #$0A ; API function +API_FN_FILE_SET_SIZE = #$0B ; API function +API_FN_FILE_RENAME = #$0C ; API function +API_FN_FILE_DELETE = #$0D ; API function +API_FN_DIR_CHDIR = #$0E ; API function +API_FN_DIR_MKDIR = #$0F ; API function +API_FN_FILE_STAT = #$10 ; API function +API_FN_DIR_OPEN = #$11 ; API function +API_FN_DIR_READ = #$12 ; API function +API_FN_DIR_CLOSE = #$13 ; API function +API_FN_FILE_COPY = #$14 ; API function +API_FN_SET_ATTR = #$15 ; API function +API_FN_LIST_FILTERED = #$20 ; API function + +; File I/O parameters (Group 3 Function 2) +API_FILE_TO_SCREEN = #$FFFF ; API parameter + +; Mathematics functions (Group 4) +API_GROUP_MATH = #$04 ; API function group +API_FN_ADD = #$00 ; API function +API_FN_SUB = #$01 ; API function +API_FN_MUL = #$02 ; API function +API_FN_DIV_DEC = #$03 ; API function +API_FN_DIV_INT = #$04 ; API function +API_FN_MOD = #$05 ; API function +API_FN_COMP = #$06 ; API function +API_FN_NEG = #$10 ; API function +API_FN_FLOOR = #$11 ; API function +API_FN_SQRT = #$12 ; API function +API_FN_SINE = #$13 ; API function +API_FN_COS = #$14 ; API function +API_FN_TAN = #$15 ; API function +API_FN_ATAN = #$16 ; API function +API_FN_EXP = #$17 ; API function +API_FN_LOG = #$18 ; API function +API_FN_ABS = #$19 ; API function +API_FN_SIGN = #$1A ; API function +API_FN_RND_DEC = #$1B ; API function +API_FN_RND_INT = #$1C ; API function +API_FN_INT_TO_DEC = #$20 ; API function +API_FN_STR_TO_NUM = #$21 ; API function +API_FN_NUM_TO_STR = #$22 ; API function +API_FN_SET_DEG_RAD_MODE = #$23 ; API function + +; Graphics functions (Group 5) +API_GROUP_GRAPHICS = #$05 ; API function group +API_FN_SET_GFX = #$01 ; API function +API_FN_DRAW_LINE = #$02 ; API function +API_FN_DRAW_RECT = #$03 ; API function +API_FN_DRAW_ELLIPSE = #$04 ; API function +API_FN_DRAW_PIXEL = #$05 ; API function +API_FN_DRAW_TEXT = #$06 ; API function +API_FN_DRAW_IMG = #$07 ; API function +API_FN_DRAW_TILEMAP = #$08 ; API function +API_FN_SET_PALETTE = #$20 ; API function +API_FN_READ_PIXEL = #$21 ; API function +API_FN_RESET_PALETTE = #$22 ; API function +API_FN_SET_TILEMAP = #$23 ; API function +API_FN_READ_SPRITE_PXL = #$24 ; API function +API_FN_FRAME_COUNT = #$25 ; API function +API_FN_GET_PALETTE = #$26 ; API function +API_FN_WRITE_PIXEL = #$27 ; API function +API_FN_SET_COLOR = #$40 ; API function +API_FN_SET_SOLID = #$41 ; API function +API_FN_SET_DRAW_SIZE = #$42 ; API function +API_FN_SET_FLIP = #$43 ; API function + +; Graphics parameters (Group 5, Function 1 - Group 6, Function 2) +API_FLIP_HORZ = #$00 ; API parameter (flag) +API_FLIP_VERT = #$01 ; API parameter (flag) + +; Graphics results (Group 5, Functions 33,36) +API_PIXEL_TRANSPARENT = #$00 ; API result (flag) + +; Sprites functions (Group 6) +API_GROUP_SPRITES = #$06 ; API function group +API_FN_SPRITE_RESET = #$01 ; API function +API_FN_SPRITE_SET = #$02 ; API function +API_FN_SPRITE_HIDE = #$03 ; API function +API_FN_SPRITE_COLLISION = #$04 ; API function +API_FN_SPRITE_POS = #$05 ; API function + +; Sprites parameters (Group 6, Function 2) +API_SPRITE_TURTLE = #$00 ; API parameter (sprite index) +API_SPRITE_32BIT = #$40 ; API parameter (bit-mask) +API_SPRITE_CLEAR = #$80 ; API parameter (bit-mask) +API_ANCHOR_BL = #$01 ; API parameter (anchor position) +API_ANCHOR_B = #$02 ; API parameter (anchor position) +API_ANCHOR_BR = #$03 ; API parameter (anchor position) +API_ANCHOR_L = #$04 ; API parameter (anchor position) +API_ANCHOR_C = #$05 ; API parameter (anchor position) +API_ANCHOR_R = #$06 ; API parameter (anchor position) +API_ANCHOR_TL = #$07 ; API parameter (anchor position) +API_ANCHOR_T = #$08 ; API parameter (anchor position) +API_ANCHOR_TR = #$09 ; API parameter (anchor position) + +; Sprites results (Group 6, Function 4) +API_COLLISION_NONE = #$00 ; API result (flag) + +; Controller functions (Group 7) +API_GROUP_CONTROLLER = #$07 ; API function group +API_FN_READ_DEFAULT_CONTROLLER = #$01 ; API function +API_FN_READ_CONTROLLER_COUNT = #$02 ; API function +API_FN_READ_CONTROLLER = #$03 ; API function + +; Controller results (Group 7, Function 1) +API_CONTROLLER_LEFT = #$01 ; API result (status bit-mask) +API_CONTROLLER_RIGHT = #$02 ; API result (status bit-mask) +API_CONTROLLER_UP = #$04 ; API result (status bit-mask) +API_CONTROLLER_DOWN = #$08 ; API result (status bit-mask) +API_CONTROLLER_BTNA = #$10 ; API result (status bit-mask) +API_CONTROLLER_BTNB = #$20 ; API result (status bit-mask) + +; Sound functions (Group 8) +API_GROUP_SOUND = #$08 ; API function group +API_FN_RESET_SOUND = #$01 ; API function +API_FN_RESET_CHANNEL = #$02 ; API function +API_FN_BEEP = #$03 ; API function +API_FN_QUEUE_SOUND = #$04 ; API function +API_FN_PLAY_SOUND = #$05 ; API function +API_FN_SOUND_STATUS = #$06 ; API function + +; Sound parameters (Group 8, Functions 2,4,5) +API_SOUND_CH_00 = #$00 ; API parameter (channel index) + +; Sound parameters (Group 8, Function 4) +API_NOTE_REST = #$0000 ; API parameter (musical rest) +API_NOTE_C0 = #$0010 ; API parameter (musical note) +API_NOTE_Cs0 = #$0011 ; API parameter (musical note) +API_NOTE_Df0 = #$0011 ; API parameter (musical note) +API_NOTE_D0 = #$0012 ; API parameter (musical note) +API_NOTE_Ds0 = #$0013 ; API parameter (musical note) +API_NOTE_Ef0 = #$0013 ; API parameter (musical note) +API_NOTE_E0 = #$0015 ; API parameter (musical note) +API_NOTE_F0 = #$0016 ; API parameter (musical note) +API_NOTE_Fs0 = #$0017 ; API parameter (musical note) +API_NOTE_Gf0 = #$0017 ; API parameter (musical note) +API_NOTE_G0 = #$0018 ; API parameter (musical note) +API_NOTE_Af0 = #$001A ; API parameter (musical note) +API_NOTE_Gs0 = #$001A ; API parameter (musical note) +API_NOTE_A0 = #$001C ; API parameter (musical note) +API_NOTE_As0 = #$001D ; API parameter (musical note) +API_NOTE_Bf0 = #$001D ; API parameter (musical note) +API_NOTE_B0 = #$001F ; API parameter (musical note) +API_NOTE_C1 = #$0021 ; API parameter (musical note) +API_NOTE_Cs1 = #$0023 ; API parameter (musical note) +API_NOTE_Df1 = #$0023 ; API parameter (musical note) +API_NOTE_D1 = #$0025 ; API parameter (musical note) +API_NOTE_Ds1 = #$0027 ; API parameter (musical note) +API_NOTE_Ef1 = #$0027 ; API parameter (musical note) +API_NOTE_E1 = #$0029 ; API parameter (musical note) +API_NOTE_F1 = #$002C ; API parameter (musical note) +API_NOTE_Fs1 = #$002E ; API parameter (musical note) +API_NOTE_Gf1 = #$002E ; API parameter (musical note) +API_NOTE_G1 = #$0031 ; API parameter (musical note) +API_NOTE_Af1 = #$0034 ; API parameter (musical note) +API_NOTE_Gs1 = #$0034 ; API parameter (musical note) +API_NOTE_A1 = #$0037 ; API parameter (musical note) +API_NOTE_As1 = #$003A ; API parameter (musical note) +API_NOTE_Bf1 = #$003A ; API parameter (musical note) +API_NOTE_B1 = #$003E ; API parameter (musical note) +API_NOTE_C2 = #$0041 ; API parameter (musical note) +API_NOTE_Cs2 = #$0045 ; API parameter (musical note) +API_NOTE_Df2 = #$0045 ; API parameter (musical note) +API_NOTE_D2 = #$0049 ; API parameter (musical note) +API_NOTE_Ds2 = #$004E ; API parameter (musical note) +API_NOTE_Ef2 = #$004E ; API parameter (musical note) +API_NOTE_E2 = #$0052 ; API parameter (musical note) +API_NOTE_F2 = #$0057 ; API parameter (musical note) +API_NOTE_Fs2 = #$005C ; API parameter (musical note) +API_NOTE_Gf2 = #$005C ; API parameter (musical note) +API_NOTE_G2 = #$0062 ; API parameter (musical note) +API_NOTE_Af2 = #$0068 ; API parameter (musical note) +API_NOTE_Gs2 = #$0068 ; API parameter (musical note) +API_NOTE_A2 = #$006E ; API parameter (musical note) +API_NOTE_As2 = #$0075 ; API parameter (musical note) +API_NOTE_Bf2 = #$0075 ; API parameter (musical note) +API_NOTE_B2 = #$007B ; API parameter (musical note) +API_NOTE_C3 = #$0083 ; API parameter (musical note) +API_NOTE_Cs3 = #$008B ; API parameter (musical note) +API_NOTE_Df3 = #$008B ; API parameter (musical note) +API_NOTE_D3 = #$0093 ; API parameter (musical note) +API_NOTE_Ds3 = #$009C ; API parameter (musical note) +API_NOTE_Ef3 = #$009C ; API parameter (musical note) +API_NOTE_E3 = #$00A5 ; API parameter (musical note) +API_NOTE_F3 = #$00AF ; API parameter (musical note) +API_NOTE_Fs3 = #$00B9 ; API parameter (musical note) +API_NOTE_Gf3 = #$00B9 ; API parameter (musical note) +API_NOTE_G3 = #$00C4 ; API parameter (musical note) +API_NOTE_Af3 = #$00D0 ; API parameter (musical note) +API_NOTE_Gs3 = #$00D0 ; API parameter (musical note) +API_NOTE_A3 = #$00DC ; API parameter (musical note) +API_NOTE_As3 = #$00E9 ; API parameter (musical note) +API_NOTE_Bf3 = #$00E9 ; API parameter (musical note) +API_NOTE_B3 = #$00F7 ; API parameter (musical note) +API_NOTE_C4 = #$0106 ; API parameter (musical note) +API_NOTE_Cs4 = #$0115 ; API parameter (musical note) +API_NOTE_Df4 = #$0115 ; API parameter (musical note) +API_NOTE_D4 = #$0126 ; API parameter (musical note) +API_NOTE_Ds4 = #$0137 ; API parameter (musical note) +API_NOTE_Ef4 = #$0137 ; API parameter (musical note) +API_NOTE_E4 = #$014A ; API parameter (musical note) +API_NOTE_F4 = #$015D ; API parameter (musical note) +API_NOTE_Fs4 = #$0172 ; API parameter (musical note) +API_NOTE_Gf4 = #$0172 ; API parameter (musical note) +API_NOTE_G4 = #$0188 ; API parameter (musical note) +API_NOTE_Af4 = #$019F ; API parameter (musical note) +API_NOTE_Gs4 = #$019F ; API parameter (musical note) +API_NOTE_A4 = #$01B8 ; API parameter (musical note) +API_NOTE_As4 = #$01D2 ; API parameter (musical note) +API_NOTE_Bf4 = #$01D2 ; API parameter (musical note) +API_NOTE_B4 = #$01EE ; API parameter (musical note) +API_NOTE_C5 = #$020B ; API parameter (musical note) +API_NOTE_Cs5 = #$022A ; API parameter (musical note) +API_NOTE_Df5 = #$022A ; API parameter (musical note) +API_NOTE_D5 = #$024B ; API parameter (musical note) +API_NOTE_Ds5 = #$026E ; API parameter (musical note) +API_NOTE_Ef5 = #$026E ; API parameter (musical note) +API_NOTE_E5 = #$0293 ; API parameter (musical note) +API_NOTE_F5 = #$02BA ; API parameter (musical note) +API_NOTE_Fs5 = #$02E4 ; API parameter (musical note) +API_NOTE_Gf5 = #$02E4 ; API parameter (musical note) +API_NOTE_G5 = #$0310 ; API parameter (musical note) +API_NOTE_Af5 = #$033F ; API parameter (musical note) +API_NOTE_Gs5 = #$033F ; API parameter (musical note) +API_NOTE_A5 = #$0370 ; API parameter (musical note) +API_NOTE_As5 = #$03A4 ; API parameter (musical note) +API_NOTE_Bf5 = #$03A4 ; API parameter (musical note) +API_NOTE_B5 = #$03DC ; API parameter (musical note) +API_NOTE_C6 = #$0417 ; API parameter (musical note) +API_NOTE_Cs6 = #$0455 ; API parameter (musical note) +API_NOTE_Df6 = #$0455 ; API parameter (musical note) +API_NOTE_D6 = #$0497 ; API parameter (musical note) +API_NOTE_Ds6 = #$04DD ; API parameter (musical note) +API_NOTE_Ef6 = #$04DD ; API parameter (musical note) +API_NOTE_E6 = #$0527 ; API parameter (musical note) +API_NOTE_F6 = #$0575 ; API parameter (musical note) +API_NOTE_Fs6 = #$05C8 ; API parameter (musical note) +API_NOTE_Gf6 = #$05C8 ; API parameter (musical note) +API_NOTE_G6 = #$0620 ; API parameter (musical note) +API_NOTE_Af6 = #$067D ; API parameter (musical note) +API_NOTE_Gs6 = #$067D ; API parameter (musical note) +API_NOTE_A6 = #$06E0 ; API parameter (musical note) +API_NOTE_As6 = #$0749 ; API parameter (musical note) +API_NOTE_Bf6 = #$0749 ; API parameter (musical note) +API_NOTE_B6 = #$07B8 ; API parameter (musical note) +API_NOTE_C7 = #$082D ; API parameter (musical note) +API_NOTE_Cs7 = #$08A9 ; API parameter (musical note) +API_NOTE_Df7 = #$08A9 ; API parameter (musical note) +API_NOTE_D7 = #$092D ; API parameter (musical note) +API_NOTE_Ds7 = #$09B9 ; API parameter (musical note) +API_NOTE_Ef7 = #$09B9 ; API parameter (musical note) +API_NOTE_E7 = #$0A4D ; API parameter (musical note) +API_NOTE_F7 = #$0AEA ; API parameter (musical note) +API_NOTE_Fs7 = #$0B90 ; API parameter (musical note) +API_NOTE_Gf7 = #$0B90 ; API parameter (musical note) +API_NOTE_G7 = #$0C40 ; API parameter (musical note) +API_NOTE_Af7 = #$0CFA ; API parameter (musical note) +API_NOTE_Gs7 = #$0CFA ; API parameter (musical note) +API_NOTE_A7 = #$0DC0 ; API parameter (musical note) +API_NOTE_As7 = #$0E91 ; API parameter (musical note) +API_NOTE_Bf7 = #$0E91 ; API parameter (musical note) +API_NOTE_B7 = #$0F6F ; API parameter (musical note) +API_NOTE_C8 = #$105A ; API parameter (musical note) +API_NOTE_Cs8 = #$1153 ; API parameter (musical note) +API_NOTE_Df8 = #$1153 ; API parameter (musical note) +API_NOTE_D8 = #$125B ; API parameter (musical note) +API_NOTE_Ds8 = #$1372 ; API parameter (musical note) +API_NOTE_Ef8 = #$1372 ; API parameter (musical note) +API_NOTE_E8 = #$149A ; API parameter (musical note) +API_NOTE_F8 = #$15D4 ; API parameter (musical note) +API_NOTE_Fs8 = #$1720 ; API parameter (musical note) +API_NOTE_Gf8 = #$1720 ; API parameter (musical note) +API_NOTE_G8 = #$1880 ; API parameter (musical note) +API_NOTE_Af8 = #$19F5 ; API parameter (musical note) +API_NOTE_Gs8 = #$19F5 ; API parameter (musical note) +API_NOTE_A8 = #$1B80 ; API parameter (musical note) +API_NOTE_As8 = #$1D23 ; API parameter (musical note) +API_NOTE_Bf8 = #$1D23 ; API parameter (musical note) +API_NOTE_B8 = #$1EDE ; API parameter (musical note) +API_NOTE_C9 = #$20B4 ; API parameter (musical note) +API_NOTE_Cs9 = #$22A6 ; API parameter (musical note) +API_NOTE_Df9 = #$22A6 ; API parameter (musical note) +API_NOTE_D9 = #$24B5 ; API parameter (musical note) +API_NOTE_Ds9 = #$26E4 ; API parameter (musical note) +API_NOTE_Ef9 = #$26E4 ; API parameter (musical note) +API_NOTE_E9 = #$2934 ; API parameter (musical note) +API_NOTE_F9 = #$2BA7 ; API parameter (musical note) +API_NOTE_Fs9 = #$2E40 ; API parameter (musical note) +API_NOTE_Gf9 = #$2E40 ; API parameter (musical note) +API_NOTE_G9 = #$3100 ; API parameter (musical note) +API_NOTE_Af9 = #$33EA ; API parameter (musical note) +API_NOTE_Gs9 = #$33EA ; API parameter (musical note) +API_NOTE_A9 = #$3700 ; API parameter (musical note) +API_NOTE_As9 = #$3A45 ; API parameter (musical note) +API_NOTE_Bf9 = #$3A45 ; API parameter (musical note) +API_NOTE_B9 = #$3DBC ; API parameter (musical note) +API_NOTE_C10 = #$4168 ; API parameter (musical note) +API_NOTE_Cs10 = #$454C ; API parameter (musical note) +API_NOTE_Df10 = #$454C ; API parameter (musical note) +API_NOTE_D10 = #$496B ; API parameter (musical note) +API_NOTE_Ds10 = #$4DC8 ; API parameter (musical note) +API_NOTE_Ef10 = #$4DC8 ; API parameter (musical note) +API_TEMPO_60 = #$0064 ; API parameter (musical note duration, 60BPM) +API_TEMPO_80 = #$004B ; API parameter (musical note duration, 80BPM) +API_TEMPO_90 = #$0042 ; API parameter (musical note duration, 90BPM) +API_TEMPO_120 = #$0032 ; API parameter (musical note duration, 120BPM) +API_SLIDE_NONE = #$0000 ; API parameter (slide value) +API_SLIDE_SLOW = #$0004 ; API parameter (slide range) +API_SLIDE_MED = #$0008 ; API parameter (slide range) +API_SLIDE_FAST = #$0010 ; API parameter (slide range) +API_SOUND_SRC_BEEP = #$00 ; API parameter (sound generator) + +; Sound parameters (Group 8, Function 5) +API_SFX_POSITIVE = #$00 ; API parameter (sound effect) +API_SFX_NEGATIVE = #$01 ; API parameter (sound effect) +API_SFX_ERROR = #$02 ; API parameter (sound effect) +API_SFX_CONFIRM = #$03 ; API parameter (sound effect) +API_SFX_REJECT = #$04 ; API parameter (sound effect) +API_SFX_SWEEP = #$05 ; API parameter (sound effect) +API_SFX_COIN = #$06 ; API parameter (sound effect) +API_SFX_LASER_LONG = #$07 ; API parameter (sound effect) +API_SFX_POWERUP = #$08 ; API parameter (sound effect) +API_SFX_VICTORY = #$09 ; API parameter (sound effect) +API_SFX_DEFEAT = #$0A ; API parameter (sound effect) +API_SFX_FANFARE = #$0B ; API parameter (sound effect) +API_SFX_ALARM1 = #$0C ; API parameter (sound effect) +API_SFX_ALARM2 = #$0D ; API parameter (sound effect) +API_SFX_ALARM3 = #$0E ; API parameter (sound effect) +API_SFX_RING1 = #$0F ; API parameter (sound effect) +API_SFX_RING2 = #$10 ; API parameter (sound effect) +API_SFX_RING3 = #$11 ; API parameter (sound effect) +API_SFX_DANGER = #$12 ; API parameter (sound effect) +API_SFX_EXPL_LONG = #$13 ; API parameter (sound effect) +API_SFX_EXPL_MEDIUM = #$14 ; API parameter (sound effect) +API_SFX_EXPL_SHORT = #$15 ; API parameter (sound effect) +API_SFX_LASER_MEDIUM = #$16 ; API parameter (sound effect) +API_SFX_LASER_SHORT = #$17 ; API parameter (sound effect) + +; Turtle Graphics functions (Group 9) +API_GROUP_TURTLE = #$09 ; API function group +API_FN_TURTLE_INIT = #$01 ; API function +API_FN_TURTLE_TURN = #$02 ; API function +API_FN_TURTLE_MOVE = #$03 ; API function +API_FN_TURTLE_HIDE = #$04 ; API function +API_FN_TURTLE_HOME = #$05 ; API function + +; Turtle Graphics parameters (Group 9, Function 2) +API_TURTLE_LEFT = #$010E ; API parameter (turn -90 degrees) +API_TURTLE_RIGHT = #$005A ; API parameter (turn +90 degrees) +API_TURTLE_FLIP = #$00B4 ; API parameter (turn 180 degrees) + +; Turtle Graphics parameters (Group 9, Function 3) +API_PEN_UP = #$00 ; API parameter (turtle tracks on) +API_PEN_DOWN = #$01 ; API parameter (turtle tracks off) + +; UExt functions (Group 10) +API_GROUP_UEXT = #$09 ; API function group +API_FN_UEXT_INIT = #$01 ; API function +API_FN_GPIO_WRITE = #$02 ; API function +API_FN_GPIO_READ = #$03 ; API function +API_FN_SET_PORT_DIR = #$04 ; API function +API_FN_I2C_WRITE = #$05 ; API function +API_FN_I2C_READ = #$06 ; API function +API_FN_ANALOG_READ = #$07 ; API function +API_FN_I2C_STATUS = #$08 ; API function +API_FN_I2C_READ_BLOCK = #$09 ; API function +API_FN_I2C_WRITE_BLCOK = #$0a ; API function +API_FN_SPI_READ_BLOCK = #$0b ; API function +API_FN_SPI_WRITE_BLOCK = #$0c ; API function +API_FN_UART_READ_BLOCK = #$0d ; API function +API_FN_UART_WRITE_BLOPCK= #$0e ; API function +API_FN_UART_SET_SPEED = #$0f ; API function +API_FN_UART_WRITE = #$10 ; API function +API_FN_UART_READ = #$11 ; API function +API_FN_UART_CHECK_BYTE_AVAILABLE = #$12 ; API function + +; TODO group 11 MOUSE +; TODO group 12 BLITTER +; TODO group 13 EDITOR + + +;--------; +; colors ; +;--------; + +COLOR_BLACK = #$80 +COLOR_RED = #$81 +COLOR_GREEN = #$82 +COLOR_YELLOW = #$83 +COLOR_BLUE = #$84 +COLOR_MAGENTA = #$85 +COLOR_CYAN = #$86 +COLOR_WHITE = #$87 +COLOR_ALT_BLACK = #$88 +COLOR_DARK_GREY = #$89 +COLOR_DARK_GREEN = #$8A +COLOR_ORANGE = #$8B +COLOR_DARK_ORANGE = #$8C +COLOR_BROWN = #$8D +COLOR_PINK = #$8E +COLOR_LIGHT_GREY = #$8F + + +;---------------------------------; +; limited-case convenience macros ; +;---------------------------------; + +DoSendMessage .macro + jsr neo.SendMessage + .endm + +DoWaitMessage .macro + jsr neo.WaitMessage + .endm + diff --git a/compiler/res/prog8lib/neo/syslib.p8 b/compiler/res/prog8lib/neo/syslib.p8 new file mode 100644 index 000000000..22eedf790 --- /dev/null +++ b/compiler/res/prog8lib/neo/syslib.p8 @@ -0,0 +1,439 @@ +; Prog8 definitions for the Neo6502 + +%option no_symbol_prefixing, ignore_unused + +neo { + &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 + + %asminclude "library:neo/neo6502.asm" +} + +sys { + ; ------- lowlevel system routines -------- + + const ubyte target = 7 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 + + asmsub init_system() { + ; Initializes the machine to a sane starting state. + ; Called automatically by the loader program logic. + %asm {{ + sei + cld + clc + ; TODO reset screen mode etc etc? + clv + ; TODO what about IRQ handler? cli + rts + }} + } + + asmsub init_system_phase2() { + %asm {{ + rts ; no phase 2 steps on the Neo6502 + }} + } + + asmsub reset_system() { + ; Soft-reset the system back to initial power-on status + ; TODO + %asm {{ + sei + jmp (neo.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 internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) { + ; Called when the compiler wants to assign a string value to another string. + %asm {{ + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda cx16.r0 + ldy cx16.r0+1 + jmp prog8_lib.strcpy + }} + } + + asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) { + ; note: only works for NON-OVERLAPPING memory regions! + ; 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 + dey + beq + +- lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + dey + bne - ++ lda (P8ZP_SCRATCH_W1),y + sta (P8ZP_SCRATCH_W2),y + 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 irqsafe_set_irqd() { + %asm {{ + php + sei + }} + } + + inline asmsub irqsafe_clear_irqd() { + %asm {{ + plp + }} + } + + sub disable_caseswitch() { + ; no-op + } + + sub enable_caseswitch() { + ; no-op + } + + asmsub save_prog8_internals() { + %asm {{ + lda P8ZP_SCRATCH_B1 + sta save_SCRATCH_ZPB1 + lda P8ZP_SCRATCH_REG + sta save_SCRATCH_ZPREG + lda P8ZP_SCRATCH_W1 + sta save_SCRATCH_ZPWORD1 + lda P8ZP_SCRATCH_W1+1 + sta save_SCRATCH_ZPWORD1+1 + lda P8ZP_SCRATCH_W2 + sta save_SCRATCH_ZPWORD2 + lda P8ZP_SCRATCH_W2+1 + sta save_SCRATCH_ZPWORD2+1 + rts +save_SCRATCH_ZPB1 .byte 0 +save_SCRATCH_ZPREG .byte 0 +save_SCRATCH_ZPWORD1 .word 0 +save_SCRATCH_ZPWORD2 .word 0 + }} + } + + asmsub restore_prog8_internals() { + %asm {{ + lda save_prog8_internals.save_SCRATCH_ZPB1 + sta P8ZP_SCRATCH_B1 + lda save_prog8_internals.save_SCRATCH_ZPREG + sta P8ZP_SCRATCH_REG + lda save_prog8_internals.save_SCRATCH_ZPWORD1 + sta P8ZP_SCRATCH_W1 + lda save_prog8_internals.save_SCRATCH_ZPWORD1+1 + sta P8ZP_SCRATCH_W1+1 + lda save_prog8_internals.save_SCRATCH_ZPWORD2 + sta P8ZP_SCRATCH_W2 + lda save_prog8_internals.save_SCRATCH_ZPWORD2+1 + sta P8ZP_SCRATCH_W2+1 + rts + }} + } + + asmsub exit(ubyte returnvalue @A) { + ; -- immediately exit the program with a return code in the A register + ; TODO where to store A as exit code? + %asm {{ + ldx prog8_lib.orig_stackpointer + txs + rts ; return to original caller + }} + } + + asmsub exit2(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y) { + ; -- immediately exit the program with result values in the A, X and Y registers. + ; TODO where to store A,X,Y as exit code? + %asm {{ + jmp exit + }} + } + + asmsub exit3(ubyte resulta @A, ubyte resultx @X, ubyte resulty @Y, bool carry @Pc) { + ; -- immediately exit the program with result values in the A, X and Y registers, and the Carry flag in the status register. + ; TODO where to store A,X,Y,Carry as exit code? + %asm {{ + jmp exit + }} + } + + inline asmsub progend() -> uword @AY { + %asm {{ + lda #prog8_program_end + }} + } + + inline asmsub push(ubyte value @A) { + %asm {{ + pha + }} + } + + inline asmsub pushw(uword value @AY) { + %asm {{ + pha + tya + pha + }} + } + + inline asmsub pop() -> ubyte @A { + %asm {{ + pla + }} + } + + inline asmsub popw() -> uword @AY { + %asm {{ + pla + tay + pla + }} + } + +} + +cx16 { + ; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage +; the sixteen virtual 16-bit registers in both normal unsigned mode and signed mode (s) + &uword r0 = $0002 + &uword r1 = $0004 + &uword r2 = $0006 + &uword r3 = $0008 + &uword r4 = $000a + &uword r5 = $000c + &uword r6 = $000e + &uword r7 = $0010 + &uword r8 = $0012 + &uword r9 = $0014 + &uword r10 = $0016 + &uword r11 = $0018 + &uword r12 = $001a + &uword r13 = $001c + &uword r14 = $001e + &uword r15 = $0020 + + &word r0s = $0002 + &word r1s = $0004 + &word r2s = $0006 + &word r3s = $0008 + &word r4s = $000a + &word r5s = $000c + &word r6s = $000e + &word r7s = $0010 + &word r8s = $0012 + &word r9s = $0014 + &word r10s = $0016 + &word r11s = $0018 + &word r12s = $001a + &word r13s = $001c + &word r14s = $001e + &word r15s = $0020 + + &ubyte r0L = $0002 + &ubyte r1L = $0004 + &ubyte r2L = $0006 + &ubyte r3L = $0008 + &ubyte r4L = $000a + &ubyte r5L = $000c + &ubyte r6L = $000e + &ubyte r7L = $0010 + &ubyte r8L = $0012 + &ubyte r9L = $0014 + &ubyte r10L = $0016 + &ubyte r11L = $0018 + &ubyte r12L = $001a + &ubyte r13L = $001c + &ubyte r14L = $001e + &ubyte r15L = $0020 + + &ubyte r0H = $0003 + &ubyte r1H = $0005 + &ubyte r2H = $0007 + &ubyte r3H = $0009 + &ubyte r4H = $000b + &ubyte r5H = $000d + &ubyte r6H = $000f + &ubyte r7H = $0011 + &ubyte r8H = $0013 + &ubyte r9H = $0015 + &ubyte r10H = $0017 + &ubyte r11H = $0019 + &ubyte r12H = $001b + &ubyte r13H = $001d + &ubyte r14H = $001f + &ubyte r15H = $0021 + + &byte r0sL = $0002 + &byte r1sL = $0004 + &byte r2sL = $0006 + &byte r3sL = $0008 + &byte r4sL = $000a + &byte r5sL = $000c + &byte r6sL = $000e + &byte r7sL = $0010 + &byte r8sL = $0012 + &byte r9sL = $0014 + &byte r10sL = $0016 + &byte r11sL = $0018 + &byte r12sL = $001a + &byte r13sL = $001c + &byte r14sL = $001e + &byte r15sL = $0020 + + &byte r0sH = $0003 + &byte r1sH = $0005 + &byte r2sH = $0007 + &byte r3sH = $0009 + &byte r4sH = $000b + &byte r5sH = $000d + &byte r6sH = $000f + &byte r7sH = $0011 + &byte r8sH = $0013 + &byte r9sH = $0015 + &byte r10sH = $0017 + &byte r11sH = $0019 + &byte r12sH = $001b + &byte r13sH = $001d + &byte r14sH = $001f + &byte r15sH = $0021 + + asmsub save_virtual_registers() clobbers(A,Y) { + %asm {{ + ldy #31 + - lda cx16.r0,y + sta _cx16_vreg_storage,y + dey + bpl - + rts + + _cx16_vreg_storage + .word 0,0,0,0,0,0,0,0 + .word 0,0,0,0,0,0,0,0 + }} + } + + asmsub restore_virtual_registers() clobbers(A,Y) { + %asm {{ + ldy #31 + - lda save_virtual_registers._cx16_vreg_storage,y + sta cx16.r0,y + dey + bpl - + rts + }} + } + + sub cpu_is_65816() -> bool { + ; Returns true when you have a 65816 cpu, false when it's a 6502. + return false + } + +} diff --git a/compiler/res/prog8lib/pet32/syslib.p8 b/compiler/res/prog8lib/pet32/syslib.p8 index 059050363..dbcd04650 100644 --- a/compiler/res/prog8lib/pet32/syslib.p8 +++ b/compiler/res/prog8lib/pet32/syslib.p8 @@ -96,7 +96,7 @@ asmsub kbdbuf_clear() { sys { ; ------- lowlevel system routines -------- - const ubyte target = 32 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 32=PET + const ubyte target = 32 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 diff --git a/compiler/res/prog8lib/virtual/syslib.p8 b/compiler/res/prog8lib/virtual/syslib.p8 index 396791dc5..30813efee 100644 --- a/compiler/res/prog8lib/virtual/syslib.p8 +++ b/compiler/res/prog8lib/virtual/syslib.p8 @@ -5,7 +5,7 @@ sys { ; ------- lowlevel system routines -------- - const ubyte target = 255 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16, 8 = atari800XL, 255 = virtual + const ubyte target = 255 ; compilation target specifier. 255=virtual, 128=C128, 64=C64, 32=PET, 16=CommanderX16, 8=atari800XL, 7=Neo6502 const ubyte sizeof_bool = 1 const ubyte sizeof_byte = 1 diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index e9cad5b62..5637d1b9d 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -292,7 +292,7 @@ private fun compileMain(args: Array): Boolean { val programNameInPath = outputPath.resolve(compilationResult.compilerAst.name) if(startEmulator1==true || startEmulator2==true) { - if (compilationResult.compilationOptions.launcher != CbmPrgLauncherType.NONE || compilationTarget=="atari") { + if (compilationResult.compilationOptions.launcher != CbmPrgLauncherType.NONE || compilationTarget=="atari" || compilationTarget=="neo") { if (startEmulator1 == true) compilationResult.compilationOptions.compTarget.machine.launchEmulator(1, programNameInPath) else if (startEmulator2 == true) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 77ac98b24..4fb469810 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -15,10 +15,7 @@ import prog8.code.ast.printAst import prog8.code.ast.verifyFinalAstBeforeAsmGen import prog8.code.core.* import prog8.code.optimize.optimizeIntermediateAst -import prog8.code.target.AtariTarget -import prog8.code.target.Cx16Target -import prog8.code.target.VMTarget -import prog8.code.target.getCompilationTargetByName +import prog8.code.target.* import prog8.codegen.vm.VmCodeGen import prog8.compiler.astprocessing.* import prog8.optimizer.* @@ -236,7 +233,11 @@ internal fun determineProgramLoadAddress(program: Program, options: CompilationO } else { when(options.output) { - OutputType.RAW -> { /* no predefined load address */ } + OutputType.RAW -> { + if(options.compTarget.name==Neo6502Target.NAME) + loadAddress = options.compTarget.machine.PROGRAM_LOAD_ADDRESS + // for all other targets, RAW has no predefined load address. + } OutputType.PRG -> { if(options.launcher==CbmPrgLauncherType.BASIC) { loadAddress = options.compTarget.machine.PROGRAM_LOAD_ADDRESS diff --git a/docs/source/compiling.rst b/docs/source/compiling.rst index e78f92b34..1d013392f 100644 --- a/docs/source/compiling.rst +++ b/docs/source/compiling.rst @@ -136,7 +136,7 @@ One or more .p8 module files ``-target `` Sets the target output of the compiler. This option is required. ``c64`` = Commodore 64, ``c128`` = Commodore 128, ``cx16`` = Commander X16, ``pet32`` - Commodore PET model 4032, - ``atari`` = Atari 800 XL, ``virtual`` = builtin virtual machine. + ``atari`` = Atari 800 XL, ``neo`` = Neo6502, ``virtual`` = builtin virtual machine. ``-srcdirs `` Specify a list of extra paths (separated with ':'), to search in for imported modules. diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 8aced3e37..d3a13b4fb 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -235,6 +235,7 @@ Grouped per compilation target. * `c128 <_static/symboldumps/skeletons-c128.txt>`_ * `cx16 <_static/symboldumps/skeletons-cx16.txt>`_ * `pet32 <_static/symboldumps/skeletons-pet32.txt>`_ +* `neo <_static/symboldumps/skeletons-neo.txt>`_ * `virtual <_static/symboldumps/skeletons-virtual.txt>`_ diff --git a/docs/source/targetsystem.rst b/docs/source/targetsystem.rst index ac2f4147a..88cadc944 100644 --- a/docs/source/targetsystem.rst +++ b/docs/source/targetsystem.rst @@ -16,6 +16,7 @@ Currently these machines can be selected as a compilation target (via the ``-tar - 'c128': the Commodore 128 (*limited support*) - 'pet32': the Commodore PET 4032 (*limited support*) - 'atari': the Atari 800 XL (*experimental support*) +- 'neo': the `Neo6502 `_ (*experimental*) - 'virtual': a builtin virtual machine This chapter explains some relevant system details of the c64 and cx16 machines. diff --git a/examples/test.p8 b/examples/test.p8 index 6c3f0b805..b52f77b32 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,20 +1,118 @@ -%import textio -%import floats -%option no_sysinit -%zeropage basicsafe +%output raw +%launcher none main { sub start() { - float @shared fl1 = 4444.234 - float @shared fl2 = -9999.111 - float @shared fl3 = fl1+fl2 - floats.print(fl1) - txt.spc() - floats.print(fl2) - txt.spc() - floats.print(fl3) - txt.nl() - txt.print_w(fl3 as word) - txt.nl() + romsub $fff1 = WriteCharacter(ubyte character @A) + + for cx16.r0L in "\n\n\n.... Hello from Prog8 :-)" + WriteCharacter(cx16.r0L) + + repeat { + } + } + + + sub start2() { + + %asm {{ + +; Program constants +CURSOR_POS_X = #0 ; character display 'X' coordinate +CURSOR_POS_Y = #21 ; character display 'Y' coordinate +NEWLINE_CHAR = #13 ; ASCII character code + + +;--------------; +; Main Program ; +;--------------; + +start: + ;-----------------------------------------------; + ; Play sound effect - (API Group 8, Function 5) ; + ;-----------------------------------------------; + + lda neo.API_SOUND_CH_00 ; sound channel (API::sound->play->channel) + sta neo.API_PARAMETERS + 0 ; set API 'Parameter0' (API::sound->play->channel) + lda neo.API_SFX_COIN ; sound effect index (API::sound->play->effect) + sta neo.API_PARAMETERS + 1 ; set API 'Parameter1' (API::sound->play->effect) + lda neo.API_FN_PLAY_SOUND ; sound effect function (API::sound->play) + sta neo.API_FUNCTION ; set API 'Function' (API::sound->play) + lda neo.API_GROUP_SOUND ; 'Sound' API function group (API::sound) + sta neo.API_COMMAND ; trigger 'Sound' API routine (API::sound) + + + ;--------------------------------------------------; + ; Set cursor position - (API Group 2, Function 7) ; + ;--------------------------------------------------; + + ; reposition the cursor to overwrite the default welcome text + lda neo.API_FN_SET_CURSOR_POS ; set cursor position function (API::console->cursor) + sta neo.API_FUNCTION ; set API 'Function' (API::console->cursor) + lda CURSOR_POS_X ; cursor 'X' coordinate (API::console->cursor->x) + sta neo.API_PARAMETERS + 0 ; set API 'Parameter0' (API::console->cursor->x) + lda CURSOR_POS_Y ; cursor 'Y' coordinate (API::console->cursor->y) + sta neo.API_PARAMETERS + 1 ; set API 'Parameter1' (API::console->cursor->y) + lda neo.API_GROUP_CONSOLE ; 'Console' API function group (API::console) + sta neo.API_COMMAND ; trigger 'Console' API routine (API::console) + + ; this simply repeats the same routine as the previous block, + ; but using the generic convenience macro, for the sake of demonstration + lda CURSOR_POS_X + sta neo.API_PARAMETERS + 0 + lda CURSOR_POS_Y + sta neo.API_PARAMETERS + 1 + #neo.DoSendMessage ; send command 2,7 + .byte 2,7 + + + ;--------------------------------------------------------; + ; Write character to console - (API Group 2, Function 6) ; + ;--------------------------------------------------------; + + ; first, write a single newline character, using the special convenience macro + lda NEWLINE_CHAR + jsr neo.WriteCharacter + ; the text foreground color can also be set by injecting a control character + lda neo.COLOR_DARK_GREEN + jsr neo.WriteCharacter + + ; next, print the welcome message (a string of characters), using the API + ldx #0 ; initialize string iteration index + lda neo.API_FN_WRITE_CHAR ; console write function (API::console->write) + sta neo.API_FUNCTION ; set API 'Function' (API::console->write) +print_next_char: + lda neo.API_COMMAND ; previous API routine status + bne print_next_char ; wait for previous API routine to complete + + lda hello_msg , x ; next character of 'hello_msg' (API::console->write->char) + beq end ; test for string end null byte + sta neo.API_PARAMETERS + 0 ; set API 'Parameter0' (API::console->write->char) + lda neo.API_GROUP_CONSOLE ; 'Console' API function group (API::console) + sta neo.API_COMMAND ; trigger 'Console' API routine (API::console) + + inx ; increment iteration index + jmp print_next_char ; continue 'hello_msg' print loop + +end: + jmp end ; infinite loop + + +;--------------; +; Program data ; +;--------------; + +hello_msg: + .text " Hello Neo6502" ; line 1 to display + .text 13 ; newline + .text " " ; 53 blanks + .text 13 ; newline + .text " Now you're playing with Neo Power!" ; line 2 to display + .text 13 ; newline + .text " (Some assembly required)" ; line 3 to display + .text 0 ; null-terminated + + + }} } }