mirror of
https://github.com/irmen/prog8.git
synced 2025-06-14 11:23:37 +00:00
Compare commits
76 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f09784b55 | |||
e7a3a89bfb | |||
7ea7e63f44 | |||
1d2ce2cbeb | |||
06cf2e0bd7 | |||
9d219ae4b9 | |||
71f5a6c50e | |||
90b2be2bf4 | |||
db1aa8fcbd | |||
11c000f764 | |||
4d6dcbd173 | |||
0da117efd2 | |||
533c368e32 | |||
8883513b0e | |||
dcc9a71455 | |||
1a56743bb1 | |||
387a4b7c35 | |||
1d65d63bd9 | |||
dda19c29fe | |||
ca41669f4f | |||
0e1886e6bd | |||
c26e116f0e | |||
5c9c7f2c5e | |||
ca2fb6cef3 | |||
46dac909ef | |||
b1e4347e10 | |||
97aa91c75e | |||
4f8fb32136 | |||
e0fbce0087 | |||
fb22f78fb3 | |||
d6393cdbe5 | |||
5167fdb3f0 | |||
ab00822764 | |||
b4352ad38b | |||
d07d00fa41 | |||
11d87e4725 | |||
627ed51a1b | |||
c8f3bfa726 | |||
3091e3a1c8 | |||
2f3e7d1c27 | |||
0e831d4b92 | |||
7294ec9a3c | |||
e34bab9585 | |||
7dd14955c1 | |||
6428ced157 | |||
30a42ec1bd | |||
aacea3e9db | |||
6886b61186 | |||
0744c9fa29 | |||
502a665ffc | |||
3c315703c0 | |||
12ed07a607 | |||
101b33c381 | |||
97f4316653 | |||
b0704e86f0 | |||
a182b13e5a | |||
80b630a1e4 | |||
475efbe007 | |||
3ab5e5ac48 | |||
c6c5ff2089 | |||
176ec8ac7d | |||
dcdd4b3255 | |||
fc0a0105b3 | |||
f3960d21a8 | |||
a44d853c1b | |||
6b41734d6a | |||
c33dc0f3be | |||
bb5ffb24a8 | |||
a878c9a61d | |||
6454bf8ec4 | |||
40aa733ea7 | |||
f37a822725 | |||
f249ccd414 | |||
7ef4ddf0f3 | |||
d8e18df3a1 | |||
78d3d9d27d |
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -19,7 +19,7 @@
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<type id="Python" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
3
.idea/modules.xml
generated
3
.idea/modules.xml
generated
@ -2,10 +2,10 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/codeAst/codeAst.iml" filepath="$PROJECT_DIR$/codeAst/codeAst.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenIntermediate/codeGenIntermediate.iml" filepath="$PROJECT_DIR$/codeGenIntermediate/codeGenIntermediate.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenVirtual/codeGenVirtual.iml" filepath="$PROJECT_DIR$/codeGenVirtual/codeGenVirtual.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" filepath="$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
|
||||
@ -14,6 +14,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" filepath="$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
|
||||
</modules>
|
||||
|
@ -5,7 +5,7 @@ import prog8.code.core.*
|
||||
|
||||
/**
|
||||
* Tree structure containing all symbol definitions in the program
|
||||
* (blocks, subroutines, variables (all types) and labels).
|
||||
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
|
||||
*/
|
||||
class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
||||
fun print() = printIndented(0)
|
||||
@ -54,6 +54,10 @@ class SymbolTable : StNode("", StNodeType.GLOBAL, Position.DUMMY) {
|
||||
vars
|
||||
}
|
||||
|
||||
val allMemorySlabs: Collection<StMemorySlab> by lazy {
|
||||
children.mapNotNull { if (it.value.type == StNodeType.MEMORYSLAB) it.value as StMemorySlab else null }
|
||||
}
|
||||
|
||||
override fun lookup(scopedName: List<String>) = flat[scopedName]
|
||||
}
|
||||
|
||||
@ -68,7 +72,8 @@ enum class StNodeType {
|
||||
STATICVAR,
|
||||
MEMVAR,
|
||||
CONSTANT,
|
||||
BUILTINFUNC
|
||||
BUILTINFUNC,
|
||||
MEMORYSLAB
|
||||
}
|
||||
|
||||
|
||||
@ -142,6 +147,7 @@ open class StNode(val name: String,
|
||||
StNodeType.LABEL -> print("(L) ")
|
||||
StNodeType.STATICVAR -> print("(V) ")
|
||||
StNodeType.MEMVAR -> print("(M) ")
|
||||
StNodeType.MEMORYSLAB -> print("(MS) ")
|
||||
StNodeType.CONSTANT -> print("(C) ")
|
||||
StNodeType.BUILTINFUNC -> print("(F) ")
|
||||
StNodeType.ROMSUB -> print("(R) ")
|
||||
@ -163,26 +169,26 @@ open class StNode(val name: String,
|
||||
|
||||
class StStaticVariable(name: String,
|
||||
val dt: DataType,
|
||||
val initialNumericValue: Double?,
|
||||
val initialStringValue: StString?,
|
||||
val initialArrayValue: StArray?,
|
||||
val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments
|
||||
val onetimeInitializationStringValue: StString?,
|
||||
val onetimeInitializationArrayValue: StArray?,
|
||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
val zpwish: ZeropageWish,
|
||||
position: Position) : StNode(name, StNodeType.STATICVAR, position) {
|
||||
|
||||
init {
|
||||
if(length!=null) {
|
||||
require(initialNumericValue == null)
|
||||
if(initialArrayValue!=null)
|
||||
require(length == initialArrayValue.size)
|
||||
require(onetimeInitializationNumericValue == null)
|
||||
if(onetimeInitializationArrayValue!=null)
|
||||
require(length == onetimeInitializationArrayValue.size)
|
||||
}
|
||||
if(initialNumericValue!=null)
|
||||
if(onetimeInitializationNumericValue!=null)
|
||||
require(dt in NumericDatatypes)
|
||||
if(initialArrayValue!=null)
|
||||
if(onetimeInitializationArrayValue!=null)
|
||||
require(dt in ArrayDatatypes)
|
||||
if(initialStringValue!=null) {
|
||||
if(onetimeInitializationStringValue!=null) {
|
||||
require(dt == DataType.STR)
|
||||
require(length == initialStringValue.first.length+1)
|
||||
require(length == onetimeInitializationStringValue.first.length+1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,6 +217,17 @@ class StMemVar(name: String,
|
||||
}
|
||||
}
|
||||
|
||||
class StMemorySlab(
|
||||
name: String,
|
||||
val size: UInt,
|
||||
val align: UInt,
|
||||
position: Position
|
||||
):
|
||||
StNode(name, StNodeType.MEMORYSLAB, position) {
|
||||
override fun printProperties() {
|
||||
print("$name size=$size align=$align")
|
||||
}
|
||||
}
|
||||
|
||||
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, position: Position) :
|
||||
StNode(name, StNodeType.SUBROUTINE, position) {
|
||||
@ -220,7 +237,11 @@ class StSub(name: String, val parameters: List<StSubroutineParameter>, val retur
|
||||
}
|
||||
|
||||
|
||||
class StRomSub(name: String, val address: UInt, val parameters: List<StSubroutineParameter>, val returnTypes: List<DataType>, position: Position) :
|
||||
class StRomSub(name: String,
|
||||
val address: UInt,
|
||||
val parameters: List<StRomSubParameter>,
|
||||
val returns: List<RegisterOrStatusflag>,
|
||||
position: Position) :
|
||||
StNode(name, StNodeType.ROMSUB, position) {
|
||||
override fun printProperties() {
|
||||
print("$name address=${address.toHex()}")
|
||||
@ -229,6 +250,7 @@ class StRomSub(name: String, val address: UInt, val parameters: List<StSubroutin
|
||||
|
||||
|
||||
class StSubroutineParameter(val name: String, val type: DataType)
|
||||
class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType)
|
||||
class StArrayElement(val number: Double?, val addressOf: List<String>?)
|
||||
|
||||
typealias StString = Pair<String, Encoding>
|
@ -3,7 +3,7 @@ package prog8.code.ast
|
||||
import prog8.code.core.*
|
||||
import java.nio.file.Path
|
||||
|
||||
// New (work-in-progress) simplified AST for the code generator.
|
||||
// New simplified AST for the code generator.
|
||||
|
||||
|
||||
sealed class PtNode(val position: Position) {
|
@ -173,8 +173,7 @@ class PtPrefix(val operator: String, type: DataType, position: Position): PtExpr
|
||||
|
||||
init {
|
||||
// note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0
|
||||
if(operator !in setOf("+", "-", "~"))
|
||||
throw IllegalArgumentException("invalid prefix operator: $operator")
|
||||
require(operator in setOf("+", "-", "~")) { "invalid prefix operator: $operator" }
|
||||
}
|
||||
|
||||
override fun printProperties() {
|
@ -8,7 +8,7 @@ class PtAsmSub(
|
||||
val address: UInt?,
|
||||
val clobbers: Set<CpuRegister>,
|
||||
val parameters: List<Pair<PtSubroutineParameter, RegisterOrStatusflag>>,
|
||||
val returnTypes: List<DataType>,
|
||||
val returnTypes: List<DataType>, // TODO join with register as Pairs ?
|
||||
val retvalRegisters: List<RegisterOrStatusflag>,
|
||||
val inline: Boolean,
|
||||
position: Position
|
||||
@ -29,6 +29,14 @@ class PtSub(
|
||||
override fun printProperties() {
|
||||
print(name)
|
||||
}
|
||||
|
||||
init {
|
||||
// params and return value should not be str
|
||||
if(parameters.any{ it.type !in NumericDatatypes })
|
||||
throw AssemblyError("non-numeric parameter")
|
||||
if(returntype!=null && returntype !in NumericDatatypes)
|
||||
throw AssemblyError("non-numeric returntype $returntype")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ class CompilationOptions(val output: OutputType,
|
||||
var asmQuiet: Boolean = false,
|
||||
var asmListfile: Boolean = false,
|
||||
var experimentalCodegen: Boolean = false,
|
||||
var keepIR: Boolean = false,
|
||||
var evalStackBaseAddress: UInt? = null,
|
||||
var outputDir: Path = Path(""),
|
||||
var symbolDefs: Map<String, String> = emptyMap()
|
||||
|
@ -106,7 +106,7 @@ sealed class SourceCode {
|
||||
* [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
|
||||
*/
|
||||
class Resource(pathString: String): SourceCode() {
|
||||
private val normalized = "/" + Path.of(pathString).normalize().toMutableList().joinToString("/")
|
||||
private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
|
||||
|
||||
override val isFromResources = true
|
||||
override val isFromFilesystem = false
|
||||
@ -125,7 +125,7 @@ sealed class SourceCode {
|
||||
}
|
||||
val stream = object {}.javaClass.getResourceAsStream(normalized)
|
||||
text = stream!!.reader().use { it.readText() }
|
||||
name = Path.of(pathString).toFile().nameWithoutExtension
|
||||
name = Path(pathString).toFile().nameWithoutExtension
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,10 @@ import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.CpuType
|
||||
import prog8.code.core.IMachineDefinition
|
||||
import prog8.code.core.Zeropage
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
import kotlin.io.path.isReadable
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.readText
|
||||
|
||||
class VirtualMachineDefinition: IMachineDefinition {
|
||||
|
||||
@ -30,10 +31,18 @@ class VirtualMachineDefinition: IMachineDefinition {
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
println("\nStarting Virtual Machine...")
|
||||
// to not have external module dependencies we launch the virtual machine via reflection
|
||||
// to not have external module dependencies in our own module, we launch the virtual machine via reflection
|
||||
val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
|
||||
val source = File("$programNameWithPath.p8virt").readText()
|
||||
vm.runProgram(source, true)
|
||||
val filename = programNameWithPath.name
|
||||
if(programNameWithPath.isReadable()) {
|
||||
vm.runProgram(programNameWithPath.readText())
|
||||
} else {
|
||||
val withExt = programNameWithPath.resolveSibling("$filename.p8ir")
|
||||
if(withExt.isReadable())
|
||||
vm.runProgram(withExt.readText())
|
||||
else
|
||||
throw NoSuchFileException(withExt.toFile(), reason="not a .p8ir file")
|
||||
}
|
||||
}
|
||||
|
||||
override fun isIOAddress(address: UInt): Boolean = false
|
||||
@ -44,5 +53,5 @@ class VirtualMachineDefinition: IMachineDefinition {
|
||||
}
|
||||
|
||||
interface IVirtualMachineRunner {
|
||||
fun runProgram(source: String, throttle: Boolean)
|
||||
fun runProgram(irSource: CharSequence)
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ compileTestKotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':codeAst')
|
||||
implementation project(':codeCore')
|
||||
implementation project(':compilerAst')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
|
@ -9,7 +9,6 @@
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="module" module-name="codeAst" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
<orderEntry type="module" module-name="compilerAst" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
|
@ -41,7 +41,7 @@ class AsmGen(internal val program: Program,
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this, allocator)
|
||||
private val programGen = ProgramAndVarsGen(program, options, errors, symbolTable, functioncallAsmGen, this, allocator, zeropage)
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, this, allocator)
|
||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen, allocator)
|
||||
private val builtinFunctionsAsmGen = BuiltinFunctionsAsmGen(program, this, assignmentAsmGen)
|
||||
|
||||
override fun compileToAssembly(): IAssemblyProgram? {
|
||||
|
||||
@ -77,7 +77,7 @@ class AsmGen(internal val program: Program,
|
||||
}
|
||||
|
||||
internal fun out(str: String, splitlines: Boolean = true) {
|
||||
val fragment = (if(splitlines && " | " in str) str.replace("|", "\n") else str).trim('\n')
|
||||
val fragment = (if(splitlines && " | " in str) str.replace("|", "\n") else str).trim('\r', '\n')
|
||||
if (splitlines) {
|
||||
for (line in fragment.splitToSequence('\n')) {
|
||||
val trimmed = if (line.startsWith(' ')) "\t" + line.trim() else line
|
||||
@ -838,7 +838,7 @@ $repeatLabel lda $counterVar
|
||||
if(stmt.definingModule.source is SourceCode.Generated)
|
||||
throw AssemblyError("%asminclude inside non-library/non-filesystem module not yet supported")
|
||||
loadAsmIncludeFile(includedName, stmt.definingModule.source).fold(
|
||||
success = { assemblyLines.add(it.trimEnd().trimStart('\n')) },
|
||||
success = { assemblyLines.add(it.trimEnd().trimStart('\r', '\n')) },
|
||||
failure = { errors.err(it.toString(), stmt.position) }
|
||||
)
|
||||
}
|
||||
@ -909,7 +909,7 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
private fun translate(asm: InlineAssembly) {
|
||||
val assembly = asm.assembly.trimEnd().trimStart('\n')
|
||||
val assembly = asm.assembly.trimEnd().trimStart('\r', '\n')
|
||||
assemblyLines.add(assembly)
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,13 @@ internal fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefin
|
||||
numberOfOptimizations++
|
||||
}
|
||||
|
||||
mods = optimizeSamePointerIndexing(linesByFourteen, machine, program)
|
||||
if(mods.isNotEmpty()) {
|
||||
apply(mods, lines)
|
||||
linesByFourteen = getLinesBy(lines, 14)
|
||||
numberOfOptimizations++
|
||||
}
|
||||
|
||||
// TODO more assembly peephole optimizations
|
||||
|
||||
return numberOfOptimizations
|
||||
@ -320,6 +327,48 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
|
||||
return mods
|
||||
}
|
||||
|
||||
private fun optimizeSamePointerIndexing(linesByFourteen: List<List<IndexedValue<String>>>, machine: IMachineDefinition, program: Program): List<Modification> {
|
||||
|
||||
// Optimize same pointer indexing where for instance we load and store to the same ptr index in Y
|
||||
// if Y isn't modified in between we can omit the second LDY:
|
||||
// ldy #0
|
||||
// lda (ptr),y
|
||||
// ora #3 ; <-- instruction(s) that don't modify Y
|
||||
// ldy #0 ; <-- can be removed
|
||||
// sta (ptr),y
|
||||
|
||||
val mods = mutableListOf<Modification>()
|
||||
for (lines in linesByFourteen) {
|
||||
val first = lines[0].value.trimStart()
|
||||
val second = lines[1].value.trimStart()
|
||||
val third = lines[2].value.trimStart()
|
||||
val fourth = lines[3].value.trimStart()
|
||||
val fifth = lines[4].value.trimStart()
|
||||
val sixth = lines[5].value.trimStart()
|
||||
|
||||
if(first.startsWith("ldy") && second.startsWith("lda") && fourth.startsWith("ldy") && fifth.startsWith("sta")) {
|
||||
val firstvalue = first.substring(4)
|
||||
val secondvalue = second.substring(4)
|
||||
val fourthvalue = fourth.substring(4)
|
||||
val fifthvalue = fifth.substring(4)
|
||||
if("y" !in third && firstvalue==fourthvalue && secondvalue==fifthvalue && secondvalue.endsWith(",y") && fifthvalue.endsWith(",y")) {
|
||||
mods.add(Modification(lines[3].index, true, null))
|
||||
}
|
||||
}
|
||||
if(first.startsWith("ldy") && second.startsWith("lda") && fifth.startsWith("ldy") && sixth.startsWith("sta")) {
|
||||
val firstvalue = first.substring(4)
|
||||
val secondvalue = second.substring(4)
|
||||
val fifthvalue = fifth.substring(4)
|
||||
val sixthvalue = sixth.substring(4)
|
||||
if("y" !in third && "y" !in fourth && firstvalue==fifthvalue && secondvalue==sixthvalue && secondvalue.endsWith(",y") && sixthvalue.endsWith(",y")) {
|
||||
mods.add(Modification(lines[4].index, true, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mods
|
||||
}
|
||||
|
||||
private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>, machine: IMachineDefinition, program: Program): List<Modification> {
|
||||
// sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can OFTEN be eliminated
|
||||
val mods = mutableListOf<Modification>()
|
||||
|
@ -15,8 +15,7 @@ import prog8.compiler.FSignature
|
||||
|
||||
internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
private val asmgen: AsmGen,
|
||||
private val assignAsmGen: AssignmentAsmGen,
|
||||
private val allocations: VariableAllocator) {
|
||||
private val assignAsmGen: AssignmentAsmGen) {
|
||||
|
||||
internal fun translateFunctioncallExpression(fcall: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single())
|
||||
@ -309,14 +308,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||
val name = (fcall.args[0] as StringLiteral).value
|
||||
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
|
||||
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
|
||||
|
||||
val existing = allocations.getMemorySlab(name)
|
||||
if(existing!=null && (existing.first!=size || existing.second!=align))
|
||||
throw AssemblyError("memory slab '$name' already exists with a different size or alignment at ${fcall.position}")
|
||||
|
||||
val slabname = IdentifierReference(listOf("prog8_slabs", name), fcall.position)
|
||||
val slabname = IdentifierReference(listOf("prog8_slabs", "prog8_memoryslab_$name"), fcall.position)
|
||||
slabname.linkParents(fcall)
|
||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UWORD, expression = AddressOf(slabname, fcall.position))
|
||||
val target =
|
||||
@ -326,7 +318,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, null, asmgen)
|
||||
val assign = AsmAssignment(src, target, false, program.memsizer, fcall.position)
|
||||
asmgen.translateNormalAssignment(assign)
|
||||
allocations.allocateMemorySlab(name, size, align)
|
||||
}
|
||||
|
||||
private fun funcSqrt16(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
|
||||
|
@ -170,10 +170,10 @@ internal class ProgramAndVarsGen(
|
||||
private fun memorySlabs() {
|
||||
asmgen.out("; memory slabs")
|
||||
asmgen.out("prog8_slabs\t.block")
|
||||
for((name, info) in allocator.memorySlabs) {
|
||||
if(info.second>1u)
|
||||
asmgen.out("\t.align ${info.second.toHex()}")
|
||||
asmgen.out("$name\t.fill ${info.first}")
|
||||
for(slab in symboltable.allMemorySlabs) {
|
||||
if(slab.align>1u)
|
||||
asmgen.out("\t.align ${slab.align.toHex()}")
|
||||
asmgen.out("${slab.name}\t.fill ${slab.size}")
|
||||
}
|
||||
asmgen.out("\t.bend")
|
||||
}
|
||||
@ -450,8 +450,8 @@ internal class ProgramAndVarsGen(
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
|
||||
for (variable in vars) {
|
||||
val svar = symboltable.flat.getValue(variable.key) as StStaticVariable
|
||||
if(svar.initialStringValue!=null)
|
||||
result.add(ZpStringWithInitial(variable.key, variable.value, svar.initialStringValue!!))
|
||||
if(svar.onetimeInitializationStringValue!=null)
|
||||
result.add(ZpStringWithInitial(variable.key, variable.value, svar.onetimeInitializationStringValue!!))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -461,8 +461,8 @@ internal class ProgramAndVarsGen(
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
|
||||
for (variable in vars) {
|
||||
val svar = symboltable.flat.getValue(variable.key) as StStaticVariable
|
||||
if(svar.initialArrayValue!=null)
|
||||
result.add(ZpArrayWithInitial(variable.key, variable.value, svar.initialArrayValue!!))
|
||||
if(svar.onetimeInitializationArrayValue!=null)
|
||||
result.add(ZpArrayWithInitial(variable.key, variable.value, svar.onetimeInitializationArrayValue!!))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -481,7 +481,7 @@ internal class ProgramAndVarsGen(
|
||||
asmgen.out("; non-zeropage variables")
|
||||
val (stringvars, othervars) = variables.partition { it.dt==DataType.STR }
|
||||
stringvars.forEach {
|
||||
outputStringvar(it.name, it.initialStringValue!!.second, it.initialStringValue!!.first)
|
||||
outputStringvar(it.name, it.onetimeInitializationStringValue!!.second, it.onetimeInitializationStringValue!!.first)
|
||||
}
|
||||
othervars.sortedBy { it.type }.forEach {
|
||||
staticVariable2asm(it)
|
||||
@ -491,11 +491,11 @@ internal class ProgramAndVarsGen(
|
||||
private fun staticVariable2asm(variable: StStaticVariable) {
|
||||
val name = variable.name
|
||||
val initialValue: Number =
|
||||
if(variable.initialNumericValue!=null) {
|
||||
if(variable.onetimeInitializationNumericValue!=null) {
|
||||
if(variable.dt== DataType.FLOAT)
|
||||
variable.initialNumericValue!!
|
||||
variable.onetimeInitializationNumericValue!!
|
||||
else
|
||||
variable.initialNumericValue!!.toInt()
|
||||
variable.onetimeInitializationNumericValue!!.toInt()
|
||||
} else 0
|
||||
|
||||
when (variable.dt) {
|
||||
@ -514,7 +514,7 @@ internal class ProgramAndVarsGen(
|
||||
DataType.STR -> {
|
||||
throw AssemblyError("all string vars should have been interned into prog")
|
||||
}
|
||||
in ArrayDatatypes -> arrayVariable2asm(name, variable.dt, variable.initialArrayValue, variable.length)
|
||||
in ArrayDatatypes -> arrayVariable2asm(name, variable.dt, variable.onetimeInitializationArrayValue, variable.length)
|
||||
else -> {
|
||||
throw AssemblyError("weird dt")
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
) {
|
||||
|
||||
private val zeropage = options.compTarget.machine.zeropage
|
||||
private val memorySlabsInternal = mutableMapOf<String, Pair<UInt, UInt>>()
|
||||
internal val memorySlabs: Map<String, Pair<UInt, UInt>> = memorySlabsInternal
|
||||
internal val globalFloatConsts = mutableMapOf<Double, String>() // all float values in the entire program (value -> varname)
|
||||
internal val zeropageVars: Map<List<String>, Zeropage.ZpAllocation> = zeropage.allocatedVariables
|
||||
|
||||
@ -24,12 +22,6 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
|
||||
allocateZeropageVariables()
|
||||
}
|
||||
|
||||
internal fun getMemorySlab(name: String) = memorySlabsInternal[name]
|
||||
|
||||
internal fun allocateMemorySlab(name: String, size: UInt, align: UInt) {
|
||||
memorySlabsInternal[name] = Pair(size, align)
|
||||
}
|
||||
|
||||
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropage.allocatedVariables
|
||||
|
||||
internal fun getFloatAsmConst(number: Double): String {
|
||||
|
@ -974,6 +974,9 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
} else if(valueDt in ByteDatatypes && targetDt in ByteDatatypes) {
|
||||
// byte to byte, just assign
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.BYTE || targetDt==DataType.WORD)
|
||||
} else if(valueDt in ByteDatatypes && targetDt in WordDatatypes) {
|
||||
// byte to word, just assign
|
||||
assignExpressionToRegister(value, target.register!!, targetDt==DataType.WORD)
|
||||
}
|
||||
else
|
||||
throw AssemblyError("can't cast $valueDt to $targetDt, this should have been checked in the astchecker")
|
||||
|
@ -24,8 +24,9 @@ compileTestKotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':codeAst')
|
||||
implementation project(':codeCore')
|
||||
implementation project(':intermediate')
|
||||
implementation project(':codeGenIntermediate')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
||||
|
@ -10,7 +10,8 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="codeAst" />
|
||||
<orderEntry type="module" module-name="codeGenIntermediate" />
|
||||
<orderEntry type="module" module-name="intermediate" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
</component>
|
||||
</module>
|
@ -1,39 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyGenerator
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.code.core.IErrorReporter
|
||||
|
||||
/*
|
||||
|
||||
NOTE: The goal is to keep the dependencies as lean as possible! For now, we depend only on:
|
||||
- codeAst (the 'lean' new AST and the SymbolTable)
|
||||
- codeCore (various base enums and interfaces)
|
||||
|
||||
This *should* be enough to build a complete code generator with. But we'll see :)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class AsmGen(internal val program: PtProgram,
|
||||
internal val symbolTable: SymbolTable,
|
||||
internal val options: CompilationOptions,
|
||||
internal val errors: IErrorReporter
|
||||
): IAssemblyGenerator {
|
||||
|
||||
override fun compileToAssembly(): IAssemblyProgram? {
|
||||
|
||||
println("\n** experimental code generator **\n")
|
||||
|
||||
println("Writing AST into XML form...")
|
||||
val xmlConv = AstToXmlConverter(program, symbolTable, options)
|
||||
xmlConv.writeXml()
|
||||
|
||||
println("..todo: create assembly program into ${options.outputDir.toAbsolutePath()}..")
|
||||
|
||||
return AssemblyProgram("dummy")
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
|
||||
|
||||
internal class AssemblyProgram(override val name: String) : IAssemblyProgram
|
||||
{
|
||||
override fun assemble(options: CompilationOptions): Boolean {
|
||||
println("..todo: assemble code into binary..")
|
||||
return true
|
||||
}
|
||||
}
|
@ -1,668 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.*
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import javax.xml.stream.XMLOutputFactory
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.div
|
||||
|
||||
/*
|
||||
|
||||
NOTE: The goal is to keep the dependencies as lean as possible! For now, we depend only on:
|
||||
- codeAst (the 'lean' new AST and the SymbolTable)
|
||||
- codeCore (various base enums and interfaces)
|
||||
|
||||
This *should* be enough to build a complete code generator with. But we'll see :)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class AstToXmlConverter(internal val program: PtProgram,
|
||||
internal val symbolTable: SymbolTable,
|
||||
internal val options: CompilationOptions
|
||||
) {
|
||||
|
||||
private lateinit var xml: IndentingXmlWriter
|
||||
|
||||
fun writeXml() {
|
||||
val writer = (options.outputDir / Path(program.name+"-ast.xml")).toFile().printWriter()
|
||||
xml = IndentingXmlWriter(XMLOutputFactory.newFactory().createXMLStreamWriter(writer))
|
||||
xml.doc()
|
||||
xml.elt("program")
|
||||
xml.attr("name", program.name)
|
||||
xml.startChildren()
|
||||
writeOptions(options)
|
||||
program.children.forEach { writeNode(it) }
|
||||
writeSymboltable(symbolTable)
|
||||
xml.endElt()
|
||||
xml.endDoc()
|
||||
xml.close()
|
||||
}
|
||||
|
||||
private fun writeSymboltable(st: SymbolTable) {
|
||||
xml.elt("symboltable")
|
||||
xml.startChildren()
|
||||
st.flat.forEach{ (name, entry) ->
|
||||
xml.elt("entry")
|
||||
xml.attr("name", name.joinToString("."))
|
||||
xml.attr("type", entry.type.name)
|
||||
xml.startChildren()
|
||||
writeStNode(entry)
|
||||
xml.endElt()
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun writeStNode(node: StNode) {
|
||||
when(node.type) {
|
||||
StNodeType.GLOBAL,
|
||||
StNodeType.LABEL,
|
||||
StNodeType.BLOCK,
|
||||
StNodeType.BUILTINFUNC,
|
||||
StNodeType.SUBROUTINE -> {/* no additional info*/}
|
||||
StNodeType.ROMSUB -> {
|
||||
node as StRomSub
|
||||
xml.elt("romsub")
|
||||
xml.attr("address", node.address.toString())
|
||||
xml.endElt()
|
||||
}
|
||||
StNodeType.STATICVAR -> {
|
||||
node as StStaticVariable
|
||||
xml.elt("var")
|
||||
xml.attr("type", node.dt.name)
|
||||
xml.attr("zpwish", node.zpwish.name)
|
||||
if(node.length!=null)
|
||||
xml.attr("length", node.length.toString())
|
||||
if(node.initialNumericValue!=null || node.initialArrayValue!=null || node.initialStringValue!=null) {
|
||||
xml.startChildren()
|
||||
if(node.initialNumericValue!=null) {
|
||||
writeNumber(node.dt, node.initialNumericValue!!)
|
||||
}
|
||||
if(node.initialStringValue!=null) {
|
||||
xml.writeTextNode(
|
||||
"string",
|
||||
listOf(Pair("encoding", node.initialStringValue!!.second.name)),
|
||||
node.initialStringValue!!.first,
|
||||
false
|
||||
)
|
||||
}
|
||||
if(node.initialArrayValue!=null) {
|
||||
xml.elt("array")
|
||||
xml.startChildren()
|
||||
val eltDt = ArrayToElementTypes.getValue(node.dt)
|
||||
node.initialArrayValue!!.forEach {
|
||||
if(it.number!=null) {
|
||||
writeNumber(eltDt, it.number!!)
|
||||
}
|
||||
if(it.addressOf!=null) {
|
||||
xml.elt("addressof")
|
||||
xml.attr("symbol", it.addressOf!!.joinToString("."))
|
||||
xml.endElt()
|
||||
}
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
StNodeType.MEMVAR -> {
|
||||
node as StMemVar
|
||||
xml.writeTextNode("memvar",
|
||||
listOf(Pair("type", node.dt.name)),
|
||||
node.address.toString(),
|
||||
false)
|
||||
}
|
||||
StNodeType.CONSTANT -> {
|
||||
node as StConstant
|
||||
xml.writeTextNode("const",
|
||||
listOf(Pair("type", node.dt.name)),
|
||||
intOrDouble(node.dt, node.value).toString(),
|
||||
false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeOptions(options: CompilationOptions) {
|
||||
xml.elt("options")
|
||||
xml.attr("target", options.compTarget.name)
|
||||
xml.attr("output", options.output.name)
|
||||
xml.attr("launcher", options.launcher.name)
|
||||
xml.attr("zeropage", options.zeropage.name)
|
||||
xml.attr("loadaddress", options.loadAddress.toString())
|
||||
xml.attr("floatsenabled", options.floats.toString())
|
||||
xml.attr("nosysinit", options.noSysInit.toString())
|
||||
xml.attr("dontreinitglobals", options.dontReinitGlobals.toString())
|
||||
xml.attr("optimize", options.optimize.toString())
|
||||
if(options.evalStackBaseAddress!=null)
|
||||
xml.attr("evalstackbase", options.evalStackBaseAddress!!.toString())
|
||||
if(options.zpReserved.isNotEmpty()) {
|
||||
xml.startChildren()
|
||||
options.zpReserved.forEach {
|
||||
xml.elt("zpreserved")
|
||||
xml.attr("from", it.first.toString())
|
||||
xml.attr("to", it.last.toString())
|
||||
xml.endElt()
|
||||
}
|
||||
}
|
||||
if(options.symbolDefs.isNotEmpty()) {
|
||||
xml.startChildren()
|
||||
options.symbolDefs.forEach { name, value ->
|
||||
xml.elt("symboldef")
|
||||
xml.attr("name", name)
|
||||
xml.attr("value", value)
|
||||
xml.endElt()
|
||||
}
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun writeNode(it: PtNode) {
|
||||
when(it) {
|
||||
is PtBlock -> write(it)
|
||||
is PtSub -> write(it)
|
||||
is PtVariable -> write(it)
|
||||
is PtAssignment -> write(it)
|
||||
is PtConstant -> write(it)
|
||||
is PtAsmSub -> write(it)
|
||||
is PtAddressOf -> write(it)
|
||||
is PtArrayIndexer -> write(it)
|
||||
is PtArray -> write(it)
|
||||
is PtBinaryExpression -> write(it)
|
||||
is PtBuiltinFunctionCall -> write(it)
|
||||
is PtConditionalBranch -> write(it)
|
||||
is PtContainmentCheck -> write(it)
|
||||
is PtForLoop -> write(it)
|
||||
is PtFunctionCall -> write(it)
|
||||
is PtIdentifier -> write(it)
|
||||
is PtIfElse -> write(it)
|
||||
is PtInlineAssembly -> write(it)
|
||||
is PtIncludeBinary -> write(it)
|
||||
is PtJump -> write(it)
|
||||
is PtMemoryByte -> write(it)
|
||||
is PtMemMapped -> write(it)
|
||||
is PtNumber -> write(it)
|
||||
is PtPostIncrDecr -> write(it)
|
||||
is PtPrefix -> write(it)
|
||||
is PtRange -> write(it)
|
||||
is PtRepeatLoop -> write(it)
|
||||
is PtReturn -> write(it)
|
||||
is PtString -> write(it)
|
||||
is PtTypeCast -> write(it)
|
||||
is PtWhen -> write(it)
|
||||
is PtWhenChoice -> write(it)
|
||||
is PtLabel -> write(it)
|
||||
is PtNop -> {}
|
||||
is PtBreakpoint -> write(it)
|
||||
is PtScopeVarsDecls -> write(it)
|
||||
is PtNodeGroup -> it.children.forEach { writeNode(it) }
|
||||
else -> TODO("$it")
|
||||
}
|
||||
}
|
||||
|
||||
private fun write(vars: PtScopeVarsDecls) {
|
||||
xml.elt("vars")
|
||||
xml.startChildren()
|
||||
vars.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(breakPt: PtBreakpoint) {
|
||||
xml.elt("breakpoint")
|
||||
xml.pos(breakPt.position)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(array: PtArray) {
|
||||
xml.elt("array")
|
||||
xml.attr("type", array.type.name)
|
||||
xml.startChildren()
|
||||
array.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(prefix: PtPrefix) {
|
||||
xml.elt("prefix")
|
||||
xml.attr("op", prefix.operator)
|
||||
xml.attr("type", prefix.type.name)
|
||||
xml.startChildren()
|
||||
xml.elt("value")
|
||||
xml.startChildren()
|
||||
writeNode(prefix.value)
|
||||
xml.endElt()
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(string: PtString) =
|
||||
xml.writeTextNode("string", listOf(Pair("encoding", string.encoding.name)), string.value, false)
|
||||
|
||||
private fun write(rept: PtRepeatLoop) {
|
||||
xml.elt("repeat")
|
||||
xml.pos(rept.position)
|
||||
xml.startChildren()
|
||||
xml.elt("count")
|
||||
xml.startChildren()
|
||||
writeNode(rept.count)
|
||||
xml.endElt()
|
||||
writeNode(rept.statements)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(branch: PtConditionalBranch) {
|
||||
xml.elt("conditionalbranch")
|
||||
xml.attr("condition", branch.condition.name)
|
||||
xml.pos(branch.position)
|
||||
xml.startChildren()
|
||||
xml.elt("true")
|
||||
xml.startChildren()
|
||||
writeNode(branch.trueScope)
|
||||
xml.endElt()
|
||||
if(branch.falseScope.children.isNotEmpty()) {
|
||||
xml.elt("false")
|
||||
xml.startChildren()
|
||||
writeNode(branch.falseScope)
|
||||
xml.endElt()
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(check: PtContainmentCheck) {
|
||||
xml.elt("containment")
|
||||
xml.attr("type", check.type.name)
|
||||
xml.startChildren()
|
||||
xml.elt("element")
|
||||
xml.startChildren()
|
||||
writeNode(check.children[0])
|
||||
xml.endElt()
|
||||
xml.elt("iterable")
|
||||
xml.startChildren()
|
||||
writeNode(check.children[1])
|
||||
xml.endElt()
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(range: PtRange) {
|
||||
xml.elt("range")
|
||||
xml.attr("type", range.type.name)
|
||||
xml.startChildren()
|
||||
xml.elt("from")
|
||||
xml.startChildren()
|
||||
writeNode(range.from)
|
||||
xml.endElt()
|
||||
xml.elt("to")
|
||||
xml.startChildren()
|
||||
writeNode(range.to)
|
||||
xml.endElt()
|
||||
xml.elt("step")
|
||||
xml.startChildren()
|
||||
writeNode(range.step)
|
||||
xml.endElt()
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(forLoop: PtForLoop) {
|
||||
xml.elt("for")
|
||||
xml.attr("loopvar", strTargetName(forLoop.variable))
|
||||
xml.pos(forLoop.position)
|
||||
xml.startChildren()
|
||||
xml.elt("iterable")
|
||||
xml.startChildren()
|
||||
writeNode(forLoop.iterable)
|
||||
xml.endElt()
|
||||
writeNode(forLoop.statements)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(membyte: PtMemoryByte) {
|
||||
xml.elt("membyte")
|
||||
xml.attr("type", membyte.type.name)
|
||||
xml.startChildren()
|
||||
xml.elt("address")
|
||||
xml.startChildren()
|
||||
writeNode(membyte.address)
|
||||
xml.endElt()
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(whenStmt: PtWhen) {
|
||||
xml.elt("when")
|
||||
xml.pos(whenStmt.position)
|
||||
xml.startChildren()
|
||||
xml.elt("value")
|
||||
xml.startChildren()
|
||||
writeNode(whenStmt.value)
|
||||
xml.endElt()
|
||||
xml.elt("choices")
|
||||
xml.startChildren()
|
||||
writeNode(whenStmt.choices)
|
||||
xml.endElt()
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(choice: PtWhenChoice) {
|
||||
xml.elt("choice")
|
||||
if(choice.isElse) {
|
||||
xml.attr("else", "true")
|
||||
xml.startChildren()
|
||||
} else {
|
||||
xml.startChildren()
|
||||
xml.elt("values")
|
||||
xml.startChildren()
|
||||
writeNode(choice.values)
|
||||
xml.endElt()
|
||||
}
|
||||
writeNode(choice.statements)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(inlineAsm: PtInlineAssembly) {
|
||||
xml.elt("assembly")
|
||||
xml.pos(inlineAsm.position)
|
||||
xml.startChildren()
|
||||
xml.writeTextNode("code", emptyList(), inlineAsm.assembly)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(inlineBinary: PtIncludeBinary) {
|
||||
xml.elt("binary")
|
||||
xml.attr("filename", inlineBinary.file.absolutePathString())
|
||||
if(inlineBinary.offset!=null)
|
||||
xml.attr("offset", inlineBinary.offset!!.toString())
|
||||
if(inlineBinary.length!=null)
|
||||
xml.attr("length", inlineBinary.length!!.toString())
|
||||
xml.pos(inlineBinary.position)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(fcall: PtBuiltinFunctionCall) {
|
||||
xml.elt("builtinfcall")
|
||||
xml.attr("name", fcall.name)
|
||||
if(fcall.void)
|
||||
xml.attr("type", "VOID")
|
||||
else
|
||||
xml.attr("type", fcall.type.name)
|
||||
xml.startChildren()
|
||||
fcall.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(cast: PtTypeCast) {
|
||||
xml.elt("cast")
|
||||
xml.attr("type", cast.type.name)
|
||||
xml.startChildren()
|
||||
writeNode(cast.value)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(aix: PtArrayIndexer) {
|
||||
xml.elt("arrayindexed")
|
||||
xml.attr("type", aix.type.name)
|
||||
xml.startChildren()
|
||||
write(aix.variable)
|
||||
writeNode(aix.index)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(binexpr: PtBinaryExpression) {
|
||||
xml.elt("binexpr")
|
||||
xml.attr("op", binexpr.operator)
|
||||
xml.attr("type", binexpr.type.name)
|
||||
xml.startChildren()
|
||||
writeNode(binexpr.left)
|
||||
writeNode(binexpr.right)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(addrof: PtAddressOf) {
|
||||
xml.elt("addressof")
|
||||
xml.attr("symbol", strTargetName(addrof.identifier))
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(fcall: PtFunctionCall) {
|
||||
xml.elt("fcall")
|
||||
xml.attr("name", strTargetName(fcall))
|
||||
if(fcall.void)
|
||||
xml.attr("type", "VOID")
|
||||
else
|
||||
xml.attr("type", fcall.type.name)
|
||||
xml.pos(fcall.position)
|
||||
xml.startChildren()
|
||||
fcall.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(number: PtNumber) = writeNumber(number.type, number.number)
|
||||
|
||||
private fun writeNumber(type: DataType, number: Double) =
|
||||
xml.writeTextNode("number", listOf(Pair("type", type.name)), intOrDouble(type, number).toString(), false)
|
||||
|
||||
private fun write(symbol: PtIdentifier) {
|
||||
xml.elt("symbol")
|
||||
xml.attr("name", strTargetName(symbol))
|
||||
xml.attr("type", symbol.type.name)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(assign: PtAssignment) {
|
||||
xml.elt("assign")
|
||||
xml.pos(assign.position)
|
||||
xml.startChildren()
|
||||
write(assign.target)
|
||||
writeNode(assign.value)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(ifElse: PtIfElse) {
|
||||
xml.elt("ifelse")
|
||||
xml.pos(ifElse.position)
|
||||
xml.startChildren()
|
||||
xml.elt("condition")
|
||||
xml.startChildren()
|
||||
writeNode(ifElse.condition)
|
||||
xml.endElt()
|
||||
xml.elt("true")
|
||||
xml.pos(ifElse.ifScope.position)
|
||||
xml.startChildren()
|
||||
writeNode(ifElse.ifScope)
|
||||
xml.endElt()
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
xml.elt("false")
|
||||
xml.pos(ifElse.elseScope.position)
|
||||
xml.startChildren()
|
||||
writeNode(ifElse.elseScope)
|
||||
xml.endElt()
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(ret: PtReturn) {
|
||||
xml.elt("return")
|
||||
if(ret.hasValue) {
|
||||
xml.startChildren()
|
||||
writeNode(ret.value!!)
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(incdec: PtPostIncrDecr) {
|
||||
if(incdec.operator=="++") xml.elt("inc") else xml.elt("dec")
|
||||
xml.startChildren()
|
||||
write(incdec.target)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(label: PtLabel) {
|
||||
xml.elt("label")
|
||||
xml.attr("name", label.scopedName.joinToString("."))
|
||||
xml.pos(label.position)
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(block: PtBlock) {
|
||||
xml.elt("block")
|
||||
xml.attr("name", block.scopedName.joinToString("."))
|
||||
if(block.address!=null)
|
||||
xml.attr("address", block.address!!.toString())
|
||||
xml.attr("library", block.library.toString())
|
||||
xml.pos(block.position)
|
||||
xml.startChildren()
|
||||
block.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(memMapped: PtMemMapped) {
|
||||
xml.writeTextNode("memvar",
|
||||
listOf(
|
||||
Pair("name", memMapped.scopedName.joinToString(".")),
|
||||
Pair("type", memMapped.type.name)
|
||||
),
|
||||
memMapped.address.toString(),
|
||||
false)
|
||||
}
|
||||
|
||||
private fun write(target: PtAssignTarget) {
|
||||
xml.elt("target")
|
||||
xml.startChildren()
|
||||
if(target.identifier!=null) {
|
||||
writeNode(target.identifier!!)
|
||||
} else if(target.memory!=null) {
|
||||
writeNode(target.memory!!)
|
||||
} else if(target.array!=null) {
|
||||
writeNode(target.array!!)
|
||||
} else
|
||||
throw InternalCompilerException("weird assign target")
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(jump: PtJump) {
|
||||
xml.elt("jump")
|
||||
if(jump.identifier!=null) xml.attr("symbol", strTargetName(jump.identifier!!))
|
||||
else if(jump.address!=null) xml.attr("address", jump.address!!.toString())
|
||||
else if(jump.generatedLabel!=null) xml.attr("label", jump.generatedLabel!!)
|
||||
else
|
||||
throw InternalCompilerException("weird jump target")
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(sub: PtSub) {
|
||||
xml.elt("sub")
|
||||
xml.attr("name", sub.scopedName.joinToString("."))
|
||||
if(sub.inline)
|
||||
xml.attr("inline", "true")
|
||||
xml.attr("returntype", sub.returntype?.toString() ?: "VOID")
|
||||
xml.pos(sub.position)
|
||||
xml.startChildren()
|
||||
if(sub.parameters.isNotEmpty()) {
|
||||
xml.elt("parameters")
|
||||
xml.startChildren()
|
||||
sub.parameters.forEach { write(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
sub.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(parameter: PtSubroutineParameter, registerOrStatusflag: RegisterOrStatusflag? = null) {
|
||||
xml.elt("param")
|
||||
xml.attr("name", parameter.name)
|
||||
xml.attr("type", parameter.type.name)
|
||||
if(registerOrStatusflag?.statusflag!=null) {
|
||||
xml.attr("statusflag", registerOrStatusflag.statusflag!!.toString())
|
||||
}
|
||||
if(registerOrStatusflag?.registerOrPair!=null){
|
||||
xml.attr("registers", registerOrStatusflag.registerOrPair!!.name)
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
private fun write(asmSub: PtAsmSub) {
|
||||
if(asmSub.address!=null) {
|
||||
xml.elt("romsub")
|
||||
xml.attr("name", asmSub.scopedName.joinToString("."))
|
||||
xml.attr("address", asmSub.address!!.toString())
|
||||
if(asmSub.inline)
|
||||
xml.attr("inline", "true")
|
||||
xml.pos(asmSub.position)
|
||||
xml.startChildren()
|
||||
paramsEtcetera(asmSub)
|
||||
xml.endElt()
|
||||
}
|
||||
else {
|
||||
xml.elt("asmsub")
|
||||
xml.attr("name", asmSub.scopedName.joinToString("."))
|
||||
if(asmSub.inline)
|
||||
xml.attr("inline", "true")
|
||||
xml.pos(asmSub.position)
|
||||
xml.startChildren()
|
||||
paramsEtcetera(asmSub)
|
||||
xml.elt("code")
|
||||
xml.startChildren()
|
||||
asmSub.children.forEach { writeNode(it) }
|
||||
xml.endElt()
|
||||
xml.endElt()
|
||||
}
|
||||
}
|
||||
|
||||
private fun paramsEtcetera(asmSub: PtAsmSub) {
|
||||
if(asmSub.parameters.isNotEmpty()) {
|
||||
xml.elt("parameters")
|
||||
xml.startChildren()
|
||||
asmSub.parameters.forEach { (param, reg) -> write(param, reg) }
|
||||
xml.endElt()
|
||||
}
|
||||
if(asmSub.clobbers.isNotEmpty()) {
|
||||
xml.elt("clobbers")
|
||||
xml.attr("registers", asmSub.clobbers.joinToString(",") { it.name })
|
||||
xml.endElt()
|
||||
}
|
||||
if(asmSub.retvalRegisters.isNotEmpty()) {
|
||||
xml.elt("returns")
|
||||
xml.startChildren()
|
||||
asmSub.retvalRegisters.forEach {
|
||||
xml.elt("register")
|
||||
if(it.statusflag!=null)
|
||||
xml.attr("statusflag", it.statusflag!!.toString())
|
||||
if(it.registerOrPair!=null)
|
||||
xml.attr("registers", it.registerOrPair!!.toString())
|
||||
xml.endElt()
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
}
|
||||
|
||||
private fun write(constant: PtConstant) {
|
||||
xml.writeTextNode("const",
|
||||
listOf(
|
||||
Pair("name", constant.scopedName.joinToString(".")),
|
||||
Pair("type", constant.type.name)
|
||||
),
|
||||
intOrDouble(constant.type, constant.value).toString(), false)
|
||||
}
|
||||
|
||||
private fun write(variable: PtVariable) {
|
||||
// the variable declaration nodes are still present in the Ast,
|
||||
// but the Symboltable should be used look up their details.
|
||||
xml.elt("vardecl")
|
||||
xml.attr("name", variable.scopedName.joinToString("."))
|
||||
xml.attr("type", variable.type.name)
|
||||
if(variable.arraySize!=null)
|
||||
xml.attr("arraysize", variable.arraySize.toString())
|
||||
if(variable.value!=null) {
|
||||
// static initialization value
|
||||
xml.startChildren()
|
||||
writeNode(variable.value!!)
|
||||
}
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun strTargetName(ident: PtIdentifier): String = ident.targetName.joinToString(".")
|
||||
|
||||
private fun strTargetName(call: PtFunctionCall): String = call.functionName.joinToString(".")
|
||||
|
||||
private fun intOrDouble(type: DataType, value: Double): Number =
|
||||
if(type in IntegerDatatypes) value.toInt() else value
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyGenerator
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.codegen.intermediate.IRCodeGen
|
||||
import prog8.intermediate.IRFileWriter
|
||||
|
||||
class CodeGen(private val program: PtProgram,
|
||||
private val symbolTable: SymbolTable,
|
||||
private val options: CompilationOptions,
|
||||
private val errors: IErrorReporter
|
||||
): IAssemblyGenerator {
|
||||
override fun compileToAssembly(): IAssemblyProgram? {
|
||||
|
||||
// you could write a code generator directly on the PtProgram AST,
|
||||
// but you can also use the Intermediate Representation to build a codegen on:
|
||||
val irCodeGen = IRCodeGen(program, symbolTable, options, errors)
|
||||
val irProgram = irCodeGen.generate()
|
||||
|
||||
// this stub only writes the IR program to disk but doesn't generate anything else.
|
||||
IRFileWriter(irProgram, null).write()
|
||||
|
||||
println("** experimental codegen stub: no assembly generated **")
|
||||
return null
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package prog8.codegen.experimental
|
||||
|
||||
import prog8.code.core.Position
|
||||
import java.util.*
|
||||
import javax.xml.stream.XMLStreamWriter
|
||||
|
||||
class IndentingXmlWriter(val xml: XMLStreamWriter): XMLStreamWriter by xml {
|
||||
private var indent = 0
|
||||
private var content = Stack<Boolean>()
|
||||
|
||||
fun doc(version: String? = null) = if(version==null) writeStartDocument() else writeStartDocument(version)
|
||||
fun endDoc() = writeEndDocument()
|
||||
fun elt(name: String) = writeStartElement(name)
|
||||
fun attr(name: String, value: String) = writeAttribute(name, value)
|
||||
fun attrs(attributes: List<Pair<String, String>>) = attributes.forEach { writeAttribute(it.first, it.second) }
|
||||
fun startChildren() {
|
||||
xml.writeCharacters("\n")
|
||||
content.pop()
|
||||
content.push(true)
|
||||
}
|
||||
fun endElt(writeIndent: Boolean=true) = writeEndElement(writeIndent)
|
||||
fun pos(pos: Position) = writeAttribute("src", pos.toString())
|
||||
fun comment(text: String) {
|
||||
writeComment(text)
|
||||
writeCharacters("\n")
|
||||
}
|
||||
|
||||
override fun writeStartDocument() {
|
||||
xml.writeStartDocument()
|
||||
xml.writeCharacters("\n")
|
||||
content.push(true)
|
||||
}
|
||||
|
||||
override fun writeStartDocument(version: String) {
|
||||
xml.writeStartDocument(version)
|
||||
xml.writeCharacters("\n")
|
||||
content.push(true)
|
||||
}
|
||||
|
||||
override fun writeEndDocument() {
|
||||
xml.writeEndDocument()
|
||||
xml.writeCharacters("\n")
|
||||
require(indent==0)
|
||||
require(content.size==1)
|
||||
}
|
||||
|
||||
override fun writeStartElement(name: String) {
|
||||
xml.writeCharacters(" ".repeat(indent))
|
||||
xml.writeStartElement(name)
|
||||
indent++
|
||||
content.push(false)
|
||||
}
|
||||
|
||||
override fun writeStartElement(name: String, ns: String) {
|
||||
xml.writeCharacters(" ".repeat(indent))
|
||||
xml.writeStartElement(name, ns)
|
||||
indent++
|
||||
content.push(false)
|
||||
}
|
||||
|
||||
fun writeEndElement(writeIndents: Boolean) {
|
||||
indent--
|
||||
if(content.pop() && writeIndents)
|
||||
xml.writeCharacters(" ".repeat(indent))
|
||||
xml.writeEndElement()
|
||||
xml.writeCharacters("\n")
|
||||
}
|
||||
|
||||
override fun writeEndElement() = writeEndElement(true)
|
||||
|
||||
override fun writeStartElement(name: String, ns: String, p2: String) {
|
||||
xml.writeCharacters(" ".repeat(indent))
|
||||
xml.writeStartElement(name, ns, p2)
|
||||
indent++
|
||||
content.push(false)
|
||||
}
|
||||
|
||||
fun writeTextNode(name: String, attrs: List<Pair<String, String>>, text: String, cdata: Boolean = true) {
|
||||
xml.writeCharacters(" ".repeat(indent))
|
||||
xml.writeStartElement(name)
|
||||
attrs.forEach { (name, value) -> xml.writeAttribute(name, value) }
|
||||
if(cdata)
|
||||
xml.writeCData(text)
|
||||
else
|
||||
xml.writeCharacters(text)
|
||||
xml.writeEndElement()
|
||||
xml.writeCharacters("\n")
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ plugins {
|
||||
id 'java'
|
||||
id 'application'
|
||||
id "org.jetbrains.kotlin.jvm"
|
||||
id "io.kotest" version "0.3.9"
|
||||
}
|
||||
|
||||
java {
|
||||
@ -25,9 +24,8 @@ compileTestKotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':codeAst')
|
||||
implementation project(':codeCore')
|
||||
implementation project(':virtualmachine')
|
||||
implementation project(':intermediate')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.16"
|
||||
@ -62,4 +60,4 @@ test {
|
||||
testLogging {
|
||||
events "skipped", "failed"
|
||||
}
|
||||
}
|
||||
}
|
@ -5,15 +5,14 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
<orderEntry type="module" module-name="intermediate" />
|
||||
<orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
|
||||
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
||||
<orderEntry type="module" module-name="codeAst" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
<orderEntry type="module" module-name="virtualmachine" />
|
||||
</component>
|
||||
</module>
|
@ -1,13 +1,18 @@
|
||||
package prog8.codegen.virtual
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.core.SignedDatatypes
|
||||
import prog8.intermediate.IRCodeChunk
|
||||
import prog8.intermediate.IRInstruction
|
||||
import prog8.intermediate.Opcode
|
||||
import prog8.intermediate.VmDataType
|
||||
|
||||
internal class AssignmentGen(private val codeGen: CodeGen, private val expressionEval: ExpressionGen) {
|
||||
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
||||
|
||||
internal fun translate(assignment: PtAssignment): VmCodeChunk {
|
||||
internal fun translate(assignment: PtAssignment): IRCodeChunk {
|
||||
if(assignment.target.children.single() is PtMachineRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
|
||||
@ -17,17 +22,16 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
translateRegularAssign(assignment)
|
||||
}
|
||||
|
||||
private fun translateInplaceAssign(assignment: PtAssignment): VmCodeChunk {
|
||||
private fun translateInplaceAssign(assignment: PtAssignment): IRCodeChunk {
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
|
||||
return if(ident!=null) {
|
||||
val address = codeGen.allocations.get(ident.targetName)
|
||||
assignSelfInMemory(address, assignment.value, assignment)
|
||||
assignSelfInMemory(ident.targetName.joinToString("."), assignment.value, assignment)
|
||||
} else if(memory != null) {
|
||||
if(memory.address is PtNumber)
|
||||
assignSelfInMemory((memory.address as PtNumber).number.toInt(), assignment.value, assignment)
|
||||
assignSelfInMemoryKnownAddress((memory.address as PtNumber).number.toInt(), assignment.value, assignment)
|
||||
else
|
||||
fallbackAssign(assignment)
|
||||
} else if(array!=null) {
|
||||
@ -40,35 +44,56 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
}
|
||||
}
|
||||
|
||||
private fun assignSelfInMemory(
|
||||
private fun assignSelfInMemoryKnownAddress(
|
||||
address: Int,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): VmCodeChunk {
|
||||
): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(origAssign.position)
|
||||
when(value) {
|
||||
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, address)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, origAssign)
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, address, null, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, address, null, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
return if (!codeGen.options.compTarget.machine.isIOAddress(address.toUInt()))
|
||||
code // do nothing, mem=mem null assignment.
|
||||
else {
|
||||
// read and write a (i/o) memory location to itself.
|
||||
val tempReg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, value = address)
|
||||
code
|
||||
}
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun fallbackAssign(origAssign: PtAssignment): VmCodeChunk {
|
||||
private fun assignSelfInMemory(
|
||||
symbol: String,
|
||||
value: PtExpression,
|
||||
origAssign: PtAssignment
|
||||
): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(value.type)
|
||||
val code = IRCodeChunk(origAssign.position)
|
||||
when(value) {
|
||||
is PtIdentifier -> return code // do nothing, x=x null assignment.
|
||||
is PtMachineRegister -> return code // do nothing, reg=reg null assignment
|
||||
is PtPrefix -> return inplacePrefix(value.operator, vmDt, null, symbol, value.position)
|
||||
is PtBinaryExpression -> return inplaceBinexpr(value.operator, value.right, vmDt, value.type in SignedDatatypes, null, symbol, origAssign)
|
||||
is PtMemoryByte -> {
|
||||
val tempReg = codeGen.vmRegisters.nextFree()
|
||||
code += IRInstruction(Opcode.LOADM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = tempReg, labelSymbol = symbol)
|
||||
return code
|
||||
}
|
||||
else -> return fallbackAssign(origAssign)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fallbackAssign(origAssign: PtAssignment): IRCodeChunk {
|
||||
if (codeGen.options.slowCodegenWarnings)
|
||||
codeGen.errors.warn("indirect code for in-place assignment", origAssign.position)
|
||||
return translateRegularAssign(origAssign)
|
||||
@ -79,50 +104,73 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
operand: PtExpression,
|
||||
vmDt: VmDataType,
|
||||
signed: Boolean,
|
||||
address: Int,
|
||||
knownAddress: Int?,
|
||||
symbol: String?,
|
||||
origAssign: PtAssignment
|
||||
): VmCodeChunk {
|
||||
when(operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(address, vmDt, operand)
|
||||
"-" -> return expressionEval.operatorMinusInplace(address, vmDt, operand)
|
||||
"*" -> return expressionEval.operatorMultiplyInplace(address, vmDt, operand)
|
||||
"/" -> return expressionEval.operatorDivideInplace(address, vmDt, signed, operand)
|
||||
"|" -> return expressionEval.operatorOrInplace(address, vmDt, operand)
|
||||
"&" -> return expressionEval.operatorAndInplace(address, vmDt, operand)
|
||||
"^" -> return expressionEval.operatorXorInplace(address, vmDt, operand)
|
||||
"<<" -> return expressionEval.operatorShiftLeftInplace(address, vmDt, operand)
|
||||
">>" -> return expressionEval.operatorShiftRightInplace(address, vmDt, signed, operand)
|
||||
else -> {}
|
||||
): IRCodeChunk {
|
||||
if(knownAddress!=null) {
|
||||
when (operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(knownAddress, null, vmDt, operand)
|
||||
"-" -> return expressionEval.operatorMinusInplace(knownAddress, null, vmDt, operand)
|
||||
"*" -> return expressionEval.operatorMultiplyInplace(knownAddress, null, vmDt, operand)
|
||||
"/" -> return expressionEval.operatorDivideInplace(knownAddress, null, vmDt, signed, operand)
|
||||
"|" -> return expressionEval.operatorOrInplace(knownAddress, null, vmDt, operand)
|
||||
"&" -> return expressionEval.operatorAndInplace(knownAddress, null, vmDt, operand)
|
||||
"^" -> return expressionEval.operatorXorInplace(knownAddress, null, vmDt, operand)
|
||||
"<<" -> return expressionEval.operatorShiftLeftInplace(knownAddress, null, vmDt, operand)
|
||||
">>" -> return expressionEval.operatorShiftRightInplace(knownAddress, null, vmDt, signed, operand)
|
||||
else -> {}
|
||||
}
|
||||
} else {
|
||||
symbol!!
|
||||
when (operator) {
|
||||
"+" -> return expressionEval.operatorPlusInplace(null, symbol, vmDt, operand)
|
||||
"-" -> return expressionEval.operatorMinusInplace(null, symbol, vmDt, operand)
|
||||
"*" -> return expressionEval.operatorMultiplyInplace(null, symbol, vmDt, operand)
|
||||
"/" -> return expressionEval.operatorDivideInplace(null, symbol, vmDt, signed, operand)
|
||||
"|" -> return expressionEval.operatorOrInplace(null, symbol, vmDt, operand)
|
||||
"&" -> return expressionEval.operatorAndInplace(null, symbol, vmDt, operand)
|
||||
"^" -> return expressionEval.operatorXorInplace(null, symbol, vmDt, operand)
|
||||
"<<" -> return expressionEval.operatorShiftLeftInplace(null, symbol, vmDt, operand)
|
||||
">>" -> return expressionEval.operatorShiftRightInplace(null, symbol, vmDt, signed, operand)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return fallbackAssign(origAssign)
|
||||
}
|
||||
|
||||
private fun inplacePrefix(operator: String, vmDt: VmDataType, address: Int): VmCodeChunk {
|
||||
val code= VmCodeChunk()
|
||||
private fun inplacePrefix(operator: String, vmDt: VmDataType, knownAddress: Int?, addressSymbol: String?, position: Position): IRCodeChunk {
|
||||
val code= IRCodeChunk(position)
|
||||
when(operator) {
|
||||
"+" -> { }
|
||||
"-" -> {
|
||||
code += VmCodeInstruction(Opcode.NEGM, vmDt, value = address)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.NEGM, vmDt, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.NEGM, vmDt, labelSymbol = addressSymbol)
|
||||
}
|
||||
"~" -> {
|
||||
val regMask = codeGen.vmRegisters.nextFree()
|
||||
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||
code += VmCodeInstruction(Opcode.XORM, vmDt, reg1=regMask, value = address)
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=regMask, value = mask)
|
||||
code += if(knownAddress!=null)
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=regMask, value = knownAddress)
|
||||
else
|
||||
IRInstruction(Opcode.XORM, vmDt, reg1=regMask, labelSymbol = addressSymbol)
|
||||
}
|
||||
else -> throw AssemblyError("weird prefix operator")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translateRegularAssign(assignment: PtAssignment): VmCodeChunk {
|
||||
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunk {
|
||||
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
|
||||
val ident = assignment.target.identifier
|
||||
val memory = assignment.target.memory
|
||||
val array = assignment.target.array
|
||||
val vmDt = codeGen.vmType(assignment.value.type)
|
||||
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(assignment.position)
|
||||
var resultRegister = -1
|
||||
var resultFpRegister = -1
|
||||
val zero = codeGen.isZero(assignment.value)
|
||||
@ -142,19 +190,18 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
}
|
||||
}
|
||||
if(ident!=null) {
|
||||
val address = codeGen.allocations.get(ident.targetName)
|
||||
val symbol = ident.targetName.joinToString(".")
|
||||
code += if(zero) {
|
||||
VmCodeInstruction(Opcode.STOREZM, vmDt, value = address)
|
||||
IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = symbol)
|
||||
} else {
|
||||
if (vmDt == VmDataType.FLOAT)
|
||||
VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value = address)
|
||||
IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = symbol)
|
||||
else
|
||||
VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value = address)
|
||||
IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = symbol)
|
||||
}
|
||||
}
|
||||
else if(array!=null) {
|
||||
val variable = array.variable.targetName
|
||||
var variableAddr = codeGen.allocations.get(variable)
|
||||
val variable = array.variable.targetName.joinToString(".")
|
||||
val itemsize = codeGen.program.memsizer.memorySize(array.type)
|
||||
|
||||
if(array.variable.type==DataType.UWORD) {
|
||||
@ -168,40 +215,40 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
if(zero) {
|
||||
// there's no STOREZIX instruction
|
||||
resultRegister = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
||||
code += IRInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0)
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, value = variableAddr)
|
||||
code += IRInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, labelSymbol = variable)
|
||||
return code
|
||||
}
|
||||
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
if(zero) {
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=variableAddr)
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg)
|
||||
code += VmCodeInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, value=variableAddr)
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable)
|
||||
}
|
||||
} else {
|
||||
if(vmDt== VmDataType.FLOAT) {
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, value=variableAddr)
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = resultFpRegister, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg)
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
}
|
||||
} else {
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, value=variableAddr)
|
||||
val offset = fixedIndex*itemsize
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultRegister, labelSymbol = "$variable+$offset")
|
||||
} else {
|
||||
val indexReg = codeGen.vmRegisters.nextFree()
|
||||
code += loadIndexReg(array, itemsize, indexReg)
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, value=variableAddr)
|
||||
code += loadIndexReg(array, itemsize, indexReg, array.position)
|
||||
code += IRInstruction(Opcode.STOREX, vmDt, reg1 = resultRegister, reg2=indexReg, labelSymbol = variable)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -210,19 +257,19 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
require(vmDt== VmDataType.BYTE)
|
||||
if(zero) {
|
||||
if(memory.address is PtNumber) {
|
||||
code += VmCodeInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||
code += IRInstruction(Opcode.STOREZM, vmDt, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||
code += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg)
|
||||
}
|
||||
} else {
|
||||
if(memory.address is PtNumber) {
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
code += IRInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
code += IRInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,8 +278,8 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio
|
||||
return code
|
||||
}
|
||||
|
||||
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int, indexReg: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
if(itemsize==1) {
|
||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
package prog8.codegen.virtual
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.Syscall
|
||||
import prog8.vm.VmDataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.intermediate.*
|
||||
|
||||
internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen: ExpressionGen) {
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGen: ExpressionGen) {
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
return when(call.name) {
|
||||
"any" -> funcAny(call, resultRegister)
|
||||
"all" -> funcAll(call, resultRegister)
|
||||
@ -25,9 +25,9 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
"rsave",
|
||||
"rsavex",
|
||||
"rrestore",
|
||||
"rrestorex" -> VmCodeChunk() // vm doesn't have registers to save/restore
|
||||
"rnd" -> funcRnd(resultRegister)
|
||||
"rndw" -> funcRndw(resultRegister)
|
||||
"rrestorex" -> IRCodeChunk(call.position) // vm doesn't have registers to save/restore
|
||||
"rnd" -> funcRnd(resultRegister, call.position)
|
||||
"rndw" -> funcRndw(resultRegister, call.position)
|
||||
"callfar" -> throw AssemblyError("callfar() is for cx16 target only")
|
||||
"callrom" -> throw AssemblyError("callrom() is for cx16 target only")
|
||||
"msb" -> funcMsb(call, resultRegister)
|
||||
@ -37,7 +37,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
"peekw" -> funcPeekW(call, resultRegister)
|
||||
"poke" -> funcPoke(call)
|
||||
"pokew" -> funcPokeW(call)
|
||||
"pokemon" -> VmCodeChunk()
|
||||
"pokemon" -> IRCodeChunk(call.position)
|
||||
"mkword" -> funcMkword(call, resultRegister)
|
||||
"sort" -> funcSort(call)
|
||||
"reverse" -> funcReverse(call)
|
||||
@ -49,85 +49,85 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val leftRegister = codeGen.vmRegisters.nextFree()
|
||||
val rightRegister = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], leftRegister, -1)
|
||||
code += exprGen.translateExpression(call.args[1], rightRegister, -1)
|
||||
code += VmCodeInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
code += IRInstruction(Opcode.CMP, codeGen.vmType(call.args[0].type), reg1=leftRegister, reg2=rightRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(call.position)
|
||||
val syscall =
|
||||
when (array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
DataType.ARRAY_B -> Syscall.ANY_BYTE
|
||||
DataType.ARRAY_B -> IMSyscall.ANY_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.ANY_WORD
|
||||
DataType.ARRAY_F -> Syscall.ANY_FLOAT
|
||||
DataType.ARRAY_W -> IMSyscall.ANY_WORD
|
||||
DataType.ARRAY_F -> IMSyscall.ANY_FLOAT
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1 = 1, value = array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if (resultRegister != 0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
private fun funcAll(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
DataType.ARRAY_B -> Syscall.ALL_BYTE
|
||||
DataType.ARRAY_B -> IMSyscall.ALL_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.ALL_WORD
|
||||
DataType.ARRAY_F -> Syscall.ALL_FLOAT
|
||||
DataType.ARRAY_W -> IMSyscall.ALL_WORD
|
||||
DataType.ARRAY_F -> IMSyscall.ALL_FLOAT
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcAbs(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val sourceDt = call.args.single().type
|
||||
if(sourceDt!=DataType.UWORD) {
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
when (sourceDt) {
|
||||
DataType.UBYTE -> {
|
||||
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += VmCodeInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += VmCodeLabel(notNegativeLabel)
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.BYTE, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=compareReg, value=0x80)
|
||||
code += IRInstruction(Opcode.BZ, VmDataType.BYTE, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRInstruction(Opcode.EXT, VmDataType.BYTE, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
}
|
||||
DataType.WORD -> {
|
||||
val notNegativeLabel = codeGen.createLabelName()
|
||||
val compareReg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
code += VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += VmCodeInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||
code += VmCodeLabel(notNegativeLabel)
|
||||
code += IRInstruction(Opcode.LOADR, VmDataType.WORD, reg1=compareReg, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.AND, VmDataType.WORD, reg1=compareReg, value=0x8000)
|
||||
code += IRInstruction(Opcode.BZ, VmDataType.WORD, reg1=compareReg, labelSymbol = notNegativeLabel)
|
||||
code += IRInstruction(Opcode.NEG, VmDataType.WORD, reg1=resultRegister)
|
||||
code += IRCodeLabel(notNegativeLabel)
|
||||
}
|
||||
else -> throw AssemblyError("weird type")
|
||||
}
|
||||
@ -135,236 +135,225 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += VmCodeInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
|
||||
code += IRInstruction(Opcode.SGN, codeGen.vmType(call.type), reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcSqrt16(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += VmCodeInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
code += IRInstruction(Opcode.SQRT, VmDataType.WORD, reg1=resultRegister, reg2=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPop(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPop(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
|
||||
code += IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPopw(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPopw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
|
||||
code += IRInstruction(Opcode.POP, VmDataType.WORD, reg1=reg)
|
||||
code += assignRegisterTo(call.args.single(), reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPush(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
|
||||
code += IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPushw(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
val reg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), reg, -1)
|
||||
code += VmCodeInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
|
||||
code += IRInstruction(Opcode.PUSH, VmDataType.WORD, reg1=reg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val sortSyscall =
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS
|
||||
DataType.ARRAY_F -> Syscall.REVERSE_FLOATS
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> IMSyscall.REVERSE_BYTES
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> IMSyscall.REVERSE_WORDS
|
||||
DataType.ARRAY_F -> IMSyscall.REVERSE_FLOATS
|
||||
else -> throw IllegalArgumentException("weird type to reverse")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSort(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
private fun funcSort(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val sortSyscall =
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB -> Syscall.SORT_UBYTE
|
||||
DataType.ARRAY_B -> Syscall.SORT_BYTE
|
||||
DataType.ARRAY_UW -> Syscall.SORT_UWORD
|
||||
DataType.ARRAY_W -> Syscall.SORT_WORD
|
||||
DataType.STR -> Syscall.SORT_UBYTE
|
||||
DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE
|
||||
DataType.ARRAY_B -> IMSyscall.SORT_BYTE
|
||||
DataType.ARRAY_UW -> IMSyscall.SORT_UWORD
|
||||
DataType.ARRAY_W -> IMSyscall.SORT_WORD
|
||||
DataType.STR -> IMSyscall.SORT_UBYTE
|
||||
DataType.ARRAY_F -> throw IllegalArgumentException("sorting a floating point array is not supported")
|
||||
else -> throw IllegalArgumentException("weird type to sort")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], 0, -1)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += IRInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
private fun funcMkword(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val msbReg = codeGen.vmRegisters.nextFree()
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], msbReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], resultRegister, -1)
|
||||
code += VmCodeInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
code += IRInstruction(Opcode.CONCAT, VmDataType.BYTE, reg1=resultRegister, reg2=msbReg)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPokeW(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPokeW(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
||||
code += IRInstruction(Opcode.STOREZM, VmDataType.WORD, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREZI, VmDataType.WORD, reg2 = addressReg)
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, VmDataType.WORD, reg1 = valueReg, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPoke(call: PtBuiltinFunctionCall): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPoke(call: PtBuiltinFunctionCall): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(codeGen.isZero(call.args[1])) {
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
||||
code += IRInstruction(Opcode.STOREZM, VmDataType.BYTE, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREZI, VmDataType.BYTE, reg2 = addressReg)
|
||||
}
|
||||
} else {
|
||||
val valueReg = codeGen.vmRegisters.nextFree()
|
||||
if (call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
||||
code += IRInstruction(Opcode.STOREM, VmDataType.BYTE, reg1 = valueReg, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args[0], addressReg, -1)
|
||||
code += exprGen.translateExpression(call.args[1], valueReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2 = addressReg)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPeekW(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
||||
code += IRInstruction(Opcode.LOADM, VmDataType.WORD, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcPeek(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
if(call.args[0] is PtNumber) {
|
||||
val address = (call.args[0] as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
code += IRInstruction(Opcode.LOADM, VmDataType.BYTE, reg1 = resultRegister, value = address)
|
||||
} else {
|
||||
val addressReg = codeGen.vmRegisters.nextFree()
|
||||
code += exprGen.translateExpression(call.args.single(), addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
code += IRInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2 = addressReg)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRnd(resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
||||
private fun funcRnd(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
code += IRInstruction(Opcode.RND, VmDataType.BYTE, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRndw(resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
||||
private fun funcRndw(resultRegister: Int, position: Position): IRCodeChunk {
|
||||
val code = IRCodeChunk(position)
|
||||
code += IRInstruction(Opcode.RND, VmDataType.WORD, reg1=resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
private fun funcMemory(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val name = (call.args[0] as PtString).value
|
||||
val size = (call.args[1] as PtNumber).number.toUInt()
|
||||
val align = (call.args[2] as PtNumber).number.toUInt()
|
||||
val existing = codeGen.allocations.getMemorySlab(name)
|
||||
val address = if(existing==null)
|
||||
codeGen.allocations.allocateMemorySlab(name, size, align)
|
||||
else if(existing.second!=size || existing.third!=align) {
|
||||
codeGen.errors.err("memory slab '$name' already exists with a different size or alignment", call.position)
|
||||
return VmCodeChunk()
|
||||
}
|
||||
else
|
||||
existing.first
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, value=address.toInt())
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += IRInstruction(Opcode.LOAD, VmDataType.WORD, reg1=resultRegister, labelSymbol = "prog8_slabs.prog8_memoryslab_$name")
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun funcMsb(call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args.single(), resultRegister, -1)
|
||||
code += VmCodeInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||
code += IRInstruction(Opcode.MSIG, VmDataType.BYTE, reg1 = resultRegister, reg2=resultRegister)
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
private fun funcRolRor(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int): IRCodeChunk {
|
||||
val vmDt = codeGen.vmType(call.args[0].type)
|
||||
val code = VmCodeChunk()
|
||||
val code = IRCodeChunk(call.position)
|
||||
code += exprGen.translateExpression(call.args[0], resultRegister, -1)
|
||||
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
code += IRInstruction(opcode, vmDt, reg1=resultRegister)
|
||||
code += assignRegisterTo(call.args[0], resultRegister)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunk {
|
||||
val code = IRCodeChunk(target.position)
|
||||
val assignment = PtAssignment(target.position)
|
||||
val assignTarget = PtAssignTarget(target.position)
|
||||
assignTarget.children.add(target)
|
File diff suppressed because it is too large
Load Diff
1039
codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt
Normal file
1039
codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,180 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.intermediate.*
|
||||
|
||||
internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
fun optimize() {
|
||||
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
|
||||
sub.chunks.forEach { chunk ->
|
||||
// we don't optimize Inline Asm chunks here.
|
||||
if(chunk is IRCodeChunk) {
|
||||
do {
|
||||
val indexedInstructions = chunk.lines.withIndex()
|
||||
.filter { it.value is IRInstruction }
|
||||
.map { IndexedValue(it.index, it.value as IRInstruction) }
|
||||
val changed = removeNops(chunk, indexedInstructions)
|
||||
|| removeDoubleLoadsAndStores(chunk, indexedInstructions) // TODO not yet implemented
|
||||
|| removeUselessArithmetic(chunk, indexedInstructions)
|
||||
|| removeWeirdBranches(chunk, indexedInstructions)
|
||||
|| removeDoubleSecClc(chunk, indexedInstructions)
|
||||
|| cleanupPushPop(chunk, indexedInstructions)
|
||||
// TODO other optimizations:
|
||||
// more complex optimizations such as unused registers
|
||||
} while (changed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
// push followed by pop to same target, or different target->replace with load
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode== Opcode.PUSH) {
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val insAfter = chunk.lines[idx+1] as? IRInstruction
|
||||
if(insAfter!=null && insAfter.opcode == Opcode.POP) {
|
||||
if(ins.reg1==insAfter.reg1) {
|
||||
chunk.lines.removeAt(idx)
|
||||
chunk.lines.removeAt(idx)
|
||||
} else {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOADR, ins.type, reg1=insAfter.reg1, reg2=ins.reg1)
|
||||
chunk.lines.removeAt(idx+1)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeDoubleSecClc(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
// double sec, clc
|
||||
// sec+clc or clc+sec
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode== Opcode.SEC || ins.opcode== Opcode.CLC) {
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val insAfter = chunk.lines[idx+1] as? IRInstruction
|
||||
if(insAfter?.opcode == ins.opcode) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
else if(ins.opcode== Opcode.SEC && insAfter?.opcode== Opcode.CLC) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
else if(ins.opcode== Opcode.CLC && insAfter?.opcode== Opcode.SEC) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeWeirdBranches(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
// jump/branch to label immediately below
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
val labelSymbol = ins.labelSymbol
|
||||
if(ins.opcode== Opcode.JUMP && labelSymbol!=null) {
|
||||
// if jumping to label immediately following this
|
||||
if(idx < chunk.lines.size-1) {
|
||||
val label = chunk.lines[idx+1] as? IRCodeLabel
|
||||
if(label?.name == labelSymbol) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
when (ins.opcode) {
|
||||
Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> {
|
||||
if (ins.value == 1) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.ADD, Opcode.SUB -> {
|
||||
if (ins.value == 1) {
|
||||
chunk.lines[idx] = IRInstruction(
|
||||
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
|
||||
ins.type,
|
||||
ins.reg1
|
||||
)
|
||||
changed = true
|
||||
} else if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.AND -> {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
||||
changed = true
|
||||
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
} else if (ins.value == 65535 && ins.type == VmDataType.WORD) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.OR -> {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
|
||||
chunk.lines[idx] = IRInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.XOR -> {
|
||||
if (ins.value == 0) {
|
||||
chunk.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeNops(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if (ins.opcode == Opcode.NOP) {
|
||||
changed = true
|
||||
chunk.lines.removeAt(idx)
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeDoubleLoadsAndStores(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||
var changed = false
|
||||
indexedInstructions.forEach { (idx, ins) ->
|
||||
|
||||
// TODO: detect multiple loads to the same target registers, only keep first (if source is not I/O memory)
|
||||
// TODO: detect multiple stores to the same target, only keep first (if target is not I/O memory)
|
||||
// TODO: detect multiple float ffrom/fto to the same target, only keep first
|
||||
// TODO: detect multiple sequential rnd with same reg1, only keep one
|
||||
// TODO: detect subsequent same xors/nots/negs, remove the pairs completely as they cancel out
|
||||
// TODO: detect multiple same ands, ors; only keep first
|
||||
// TODO: (hard) detect multiple registers being assigned the same value (and not changed) - use only 1 of them
|
||||
// ...
|
||||
}
|
||||
return changed
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.core.AssemblyError
|
||||
|
||||
internal class RegisterPool {
|
||||
private var firstFree: Int=3 // integer registers 0,1,2 are reserved
|
||||
private var firstFreeFloat: Int=0
|
||||
|
||||
fun peekNext() = firstFree
|
||||
fun peekNextFloat() = firstFreeFloat
|
||||
|
||||
fun nextFree(): Int {
|
||||
val result = firstFree
|
||||
firstFree++
|
||||
if(firstFree>65535)
|
||||
throw AssemblyError("out of virtual registers (int)")
|
||||
return result
|
||||
}
|
||||
|
||||
fun nextFreeFloat(): Int {
|
||||
val result = firstFreeFloat
|
||||
firstFreeFloat++
|
||||
if(firstFreeFloat>65535)
|
||||
throw AssemblyError("out of virtual registers (fp)")
|
||||
return result
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
package prog8tests.vm.helpers
|
||||
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.IMemSizer
|
177
codeGenIntermediate/test/TestIRPeepholeOpt.kt
Normal file
177
codeGenIntermediate/test/TestIRPeepholeOpt.kt
Normal file
@ -0,0 +1,177 @@
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8.codegen.intermediate.IRPeepholeOptimizer
|
||||
import prog8.intermediate.*
|
||||
|
||||
class TestIRPeepholeOpt: FunSpec({
|
||||
fun makeIRProgram(lines: List<IRCodeLine>): IRProgram {
|
||||
val block = IRBlock("main", null, IRBlock.BlockAlignment.NONE, Position.DUMMY)
|
||||
val sub = IRSubroutine("main.start", emptyList(), null, Position.DUMMY)
|
||||
val chunk = IRCodeChunk(Position.DUMMY)
|
||||
for(line in lines)
|
||||
chunk += line
|
||||
sub += chunk
|
||||
block += sub
|
||||
val target = VMTarget()
|
||||
val options = CompilationOptions(
|
||||
OutputType.RAW,
|
||||
CbmPrgLauncherType.NONE,
|
||||
ZeropageType.DONTUSE,
|
||||
emptyList(),
|
||||
floats = false,
|
||||
noSysInit = true,
|
||||
compTarget = target,
|
||||
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||
)
|
||||
val prog = IRProgram("test", IRSymbolTable(null), options, target)
|
||||
prog.addBlock(block)
|
||||
return prog
|
||||
}
|
||||
|
||||
fun IRProgram.lines(): List<IRCodeLine> = this.blocks.flatMap { it.subroutines }.flatMap { it.chunks }.flatMap { it.lines }
|
||||
|
||||
test("remove nops") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "dummy"),
|
||||
IRInstruction(Opcode.NOP),
|
||||
IRInstruction(Opcode.NOP)
|
||||
))
|
||||
irProg.lines().size shouldBe 3
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
irProg.lines().size shouldBe 1
|
||||
}
|
||||
|
||||
test("remove jmp to label below") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label"), // removed
|
||||
IRCodeLabel("label"),
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label2"), // removed
|
||||
IRInstruction(Opcode.NOP), // removed
|
||||
IRCodeLabel("label2"),
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = "label3"),
|
||||
IRInstruction(Opcode.INC, VmDataType.BYTE, reg1=1),
|
||||
IRCodeLabel("label3")
|
||||
))
|
||||
irProg.lines().size shouldBe 8
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 5
|
||||
(lines[0] as IRCodeLabel).name shouldBe "label"
|
||||
(lines[1] as IRCodeLabel).name shouldBe "label2"
|
||||
(lines[2] as IRInstruction).opcode shouldBe Opcode.JUMP
|
||||
(lines[3] as IRInstruction).opcode shouldBe Opcode.INC
|
||||
(lines[4] as IRCodeLabel).name shouldBe "label3"
|
||||
}
|
||||
|
||||
test("remove double sec/clc") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.SEC),
|
||||
IRInstruction(Opcode.SEC),
|
||||
IRInstruction(Opcode.SEC),
|
||||
IRInstruction(Opcode.CLC),
|
||||
IRInstruction(Opcode.CLC),
|
||||
IRInstruction(Opcode.CLC)
|
||||
))
|
||||
irProg.lines().size shouldBe 6
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.CLC
|
||||
}
|
||||
|
||||
test("push followed by pop") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=42),
|
||||
IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=42),
|
||||
IRInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=99),
|
||||
IRInstruction(Opcode.POP, VmDataType.BYTE, reg1=222)
|
||||
))
|
||||
irProg.lines().size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOADR
|
||||
(lines[0] as IRInstruction).reg1 shouldBe 222
|
||||
(lines[0] as IRInstruction).reg2 shouldBe 99
|
||||
}
|
||||
|
||||
test("remove useless div/mul, add/sub") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 2),
|
||||
IRInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 0)
|
||||
))
|
||||
irProg.lines().size shouldBe 10
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 4
|
||||
}
|
||||
|
||||
test("replace add/sub 1 by inc/dec") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.lines().size shouldBe 2
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 2
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.INC
|
||||
(lines[1] as IRInstruction).opcode shouldBe Opcode.DEC
|
||||
}
|
||||
|
||||
test("remove useless and/or/xor") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 65535),
|
||||
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 200),
|
||||
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 60000),
|
||||
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 1),
|
||||
IRInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
irProg.lines().size shouldBe 8
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 4
|
||||
}
|
||||
|
||||
test("replace and/or/xor by constant number") {
|
||||
val irProg = makeIRProgram(listOf(
|
||||
IRInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 0),
|
||||
IRInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 255),
|
||||
IRInstruction(Opcode.OR, VmDataType.WORD, reg1=42, value = 65535)
|
||||
))
|
||||
irProg.lines().size shouldBe 4
|
||||
val opt = IRPeepholeOptimizer(irProg)
|
||||
opt.optimize()
|
||||
val lines = irProg.lines()
|
||||
lines.size shouldBe 4
|
||||
(lines[0] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[1] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[2] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[3] as IRInstruction).opcode shouldBe Opcode.LOAD
|
||||
(lines[0] as IRInstruction).value shouldBe 0
|
||||
(lines[1] as IRInstruction).value shouldBe 0
|
||||
(lines[2] as IRInstruction).value shouldBe 255
|
||||
(lines[3] as IRInstruction).value shouldBe 65535
|
||||
}
|
||||
})
|
@ -1,138 +0,0 @@
|
||||
package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.IAssemblyProgram
|
||||
import prog8.vm.Instruction
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.OpcodesWithAddress
|
||||
import prog8.vm.VmDataType
|
||||
import java.io.BufferedWriter
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.bufferedWriter
|
||||
import kotlin.io.path.div
|
||||
|
||||
|
||||
class AssemblyProgram(override val name: String, private val allocations: VariableAllocator
|
||||
) : IAssemblyProgram {
|
||||
|
||||
private val globalInits = mutableListOf<VmCodeLine>()
|
||||
private val blocks = mutableListOf<VmCodeChunk>()
|
||||
|
||||
override fun assemble(options: CompilationOptions): Boolean {
|
||||
val outfile = options.outputDir / ("$name.p8virt")
|
||||
println("write code to $outfile")
|
||||
outfile.bufferedWriter().use { out ->
|
||||
allocations.asVmMemory().forEach { (name, alloc) ->
|
||||
out.write("; ${name.joinToString(".")}\n")
|
||||
out.write(alloc + "\n")
|
||||
}
|
||||
out.write("------PROGRAM------\n")
|
||||
|
||||
if(!options.dontReinitGlobals) {
|
||||
out.write("; global var inits\n")
|
||||
globalInits.forEach { out.writeLine(it) }
|
||||
}
|
||||
|
||||
out.write("; actual program code\n")
|
||||
blocks.asSequence().flatMap { it.lines }.forEach { line->out.writeLine(line) }
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun BufferedWriter.writeLine(line: VmCodeLine) {
|
||||
when(line) {
|
||||
is VmCodeComment -> write("; ${line.comment}\n")
|
||||
is VmCodeInstruction -> {
|
||||
write(line.ins.toString() + "\n")
|
||||
}
|
||||
is VmCodeLabel -> write("_" + line.name.joinToString(".") + ":\n")
|
||||
is VmCodeInlineAsm -> {
|
||||
val asm = line.assembly.replace("""\{[a-zA-Z\d_\.]+\}""".toRegex()) { matchResult ->
|
||||
val name = matchResult.value.substring(1, matchResult.value.length-1).split('.')
|
||||
allocations.get(name).toString() }
|
||||
write(asm+"\n")
|
||||
}
|
||||
is VmCodeInlineBinary -> {
|
||||
write("incbin \"${line.file}\"")
|
||||
if(line.offset!=null)
|
||||
write(",${line.offset}")
|
||||
if(line.length!=null)
|
||||
write(",${line.length}")
|
||||
write("\n")
|
||||
}
|
||||
else -> throw AssemblyError("invalid vm code line")
|
||||
}
|
||||
}
|
||||
|
||||
fun addGlobalInits(chunk: VmCodeChunk) = globalInits.addAll(chunk.lines)
|
||||
fun addBlock(block: VmCodeChunk) = blocks.add(block)
|
||||
fun getBlocks(): List<VmCodeChunk> = blocks
|
||||
}
|
||||
|
||||
sealed class VmCodeLine
|
||||
|
||||
class VmCodeInstruction(
|
||||
opcode: Opcode,
|
||||
type: VmDataType?=null,
|
||||
reg1: Int?=null, // 0-$ffff
|
||||
reg2: Int?=null, // 0-$ffff
|
||||
fpReg1: Int?=null, // 0-$ffff
|
||||
fpReg2: Int?=null, // 0-$ffff
|
||||
value: Int?=null, // 0-$ffff
|
||||
fpValue: Float?=null,
|
||||
labelSymbol: List<String>?=null // alternative to value for branch/call/jump labels
|
||||
): VmCodeLine() {
|
||||
val ins = Instruction(opcode, type, reg1, reg2, fpReg1, fpReg2, value, fpValue, labelSymbol)
|
||||
|
||||
init {
|
||||
if(reg1!=null && (reg1<0 || reg1>65536))
|
||||
throw IllegalArgumentException("reg1 out of bounds")
|
||||
if(reg2!=null && (reg2<0 || reg2>65536))
|
||||
throw IllegalArgumentException("reg2 out of bounds")
|
||||
if(fpReg1!=null && (fpReg1<0 || fpReg1>65536))
|
||||
throw IllegalArgumentException("fpReg1 out of bounds")
|
||||
if(fpReg2!=null && (fpReg2<0 || fpReg2>65536))
|
||||
throw IllegalArgumentException("fpReg2 out of bounds")
|
||||
|
||||
if(value!=null && opcode !in OpcodesWithAddress) {
|
||||
when (type) {
|
||||
VmDataType.BYTE -> {
|
||||
if (value < -128 || value > 255)
|
||||
throw IllegalArgumentException("value out of range for byte: $value")
|
||||
}
|
||||
VmDataType.WORD -> {
|
||||
if (value < -32768 || value > 65535)
|
||||
throw IllegalArgumentException("value out of range for word: $value")
|
||||
}
|
||||
VmDataType.FLOAT, null -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VmCodeLabel(val name: List<String>): VmCodeLine()
|
||||
internal class VmCodeComment(val comment: String): VmCodeLine()
|
||||
|
||||
class VmCodeChunk(initial: VmCodeLine? = null) {
|
||||
val lines = mutableListOf<VmCodeLine>()
|
||||
|
||||
init {
|
||||
if(initial!=null)
|
||||
lines.add(initial)
|
||||
}
|
||||
|
||||
operator fun plusAssign(line: VmCodeLine) {
|
||||
lines.add(line)
|
||||
}
|
||||
|
||||
operator fun plusAssign(chunk: VmCodeChunk) {
|
||||
lines.addAll(chunk.lines)
|
||||
}
|
||||
}
|
||||
|
||||
internal class VmCodeInlineAsm(asm: String): VmCodeLine() {
|
||||
val assembly: String = asm.trimIndent()
|
||||
}
|
||||
|
||||
internal class VmCodeInlineBinary(val file: Path, val offset: UInt?, val length: UInt?): VmCodeLine()
|
@ -1,814 +0,0 @@
|
||||
package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
internal class VmRegisterPool {
|
||||
private var firstFree: Int=3 // integer registers 0,1,2 are reserved
|
||||
private var firstFreeFloat: Int=0
|
||||
|
||||
fun peekNext() = firstFree
|
||||
fun peekNextFloat() = firstFreeFloat
|
||||
|
||||
fun nextFree(): Int {
|
||||
val result = firstFree
|
||||
firstFree++
|
||||
if(firstFree>65535)
|
||||
throw AssemblyError("out of virtual registers (int)")
|
||||
return result
|
||||
}
|
||||
|
||||
fun nextFreeFloat(): Int {
|
||||
val result = firstFreeFloat
|
||||
firstFreeFloat++
|
||||
if(firstFreeFloat>65535)
|
||||
throw AssemblyError("out of virtual registers (fp)")
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CodeGen(internal val program: PtProgram,
|
||||
internal val symbolTable: SymbolTable,
|
||||
internal val options: CompilationOptions,
|
||||
internal val errors: IErrorReporter
|
||||
): IAssemblyGenerator {
|
||||
|
||||
internal val allocations = VariableAllocator(symbolTable, program)
|
||||
private val expressionEval = ExpressionGen(this)
|
||||
private val builtinFuncGen = BuiltinFuncGen(this, expressionEval)
|
||||
private val assignmentGen = AssignmentGen(this, expressionEval)
|
||||
internal val vmRegisters = VmRegisterPool()
|
||||
|
||||
override fun compileToAssembly(): IAssemblyProgram? {
|
||||
val vmprog = AssemblyProgram(program.name, allocations)
|
||||
|
||||
if(!options.dontReinitGlobals) {
|
||||
// collect global variables initializers
|
||||
program.allBlocks().forEach {
|
||||
val code = VmCodeChunk()
|
||||
it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += assignmentGen.translate(assign) }
|
||||
vmprog.addGlobalInits(code)
|
||||
}
|
||||
}
|
||||
|
||||
if(options.symbolDefs.isNotEmpty())
|
||||
throw AssemblyError("virtual target doesn't support symbols defined on the commandline")
|
||||
if(options.evalStackBaseAddress!=null)
|
||||
throw AssemblyError("virtual target doesn't use eval-stack")
|
||||
|
||||
for (block in program.allBlocks()) {
|
||||
vmprog.addBlock(translate(block))
|
||||
}
|
||||
|
||||
if(options.optimize) {
|
||||
val optimizer = VmPeepholeOptimizer(vmprog)
|
||||
optimizer.optimize()
|
||||
}
|
||||
|
||||
println("Vm codegen: virtual registers=${vmRegisters.peekNext()} memory usage=${allocations.freeMem}")
|
||||
|
||||
return vmprog
|
||||
}
|
||||
|
||||
|
||||
internal fun translateNode(node: PtNode): VmCodeChunk {
|
||||
val code = when(node) {
|
||||
is PtBlock -> translate(node)
|
||||
is PtSub -> translate(node)
|
||||
is PtAsmSub -> translate(node)
|
||||
is PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table
|
||||
is PtVariable -> VmCodeChunk() // var should be looked up via symbol table
|
||||
is PtMemMapped -> VmCodeChunk() // memmapped var should be looked up via symbol table
|
||||
is PtConstant -> VmCodeChunk() // constants have all been folded into the code
|
||||
is PtAssignment -> assignmentGen.translate(node)
|
||||
is PtNodeGroup -> translateGroup(node.children)
|
||||
is PtBuiltinFunctionCall -> translateBuiltinFunc(node, 0)
|
||||
is PtFunctionCall -> expressionEval.translate(node, 0, 0)
|
||||
is PtNop -> VmCodeChunk()
|
||||
is PtReturn -> translate(node)
|
||||
is PtJump -> translate(node)
|
||||
is PtWhen -> translate(node)
|
||||
is PtForLoop -> translate(node)
|
||||
is PtIfElse -> translate(node)
|
||||
is PtPostIncrDecr -> translate(node)
|
||||
is PtRepeatLoop -> translate(node)
|
||||
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
|
||||
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
|
||||
is PtConditionalBranch -> translate(node)
|
||||
is PtInlineAssembly -> VmCodeChunk(VmCodeInlineAsm(node.assembly))
|
||||
is PtIncludeBinary -> VmCodeChunk(VmCodeInlineBinary(node.file, node.offset, node.length))
|
||||
is PtAddressOf,
|
||||
is PtContainmentCheck,
|
||||
is PtMemoryByte,
|
||||
is PtProgram,
|
||||
is PtArrayIndexer,
|
||||
is PtBinaryExpression,
|
||||
is PtIdentifier,
|
||||
is PtWhenChoice,
|
||||
is PtPrefix,
|
||||
is PtRange,
|
||||
is PtAssignTarget,
|
||||
is PtTypeCast,
|
||||
is PtSubroutineParameter,
|
||||
is PtNumber,
|
||||
is PtArray,
|
||||
is PtString -> throw AssemblyError("should not occur as separate statement node ${node.position}")
|
||||
else -> TODO("missing codegen for $node")
|
||||
}
|
||||
if(code.lines.isNotEmpty() && node.position.line!=0)
|
||||
code.lines.add(0, VmCodeComment(node.position.toString()))
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(branch: PtConditionalBranch): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val elseLabel = createLabelName()
|
||||
// note that the branch opcode used is the opposite as the branch condition, because the generated code jumps to the 'else' part
|
||||
code += when(branch.condition) {
|
||||
BranchCondition.CS -> VmCodeInstruction(Opcode.BSTCC, labelSymbol = elseLabel)
|
||||
BranchCondition.CC -> VmCodeInstruction(Opcode.BSTCS, labelSymbol = elseLabel)
|
||||
BranchCondition.EQ, BranchCondition.Z -> VmCodeInstruction(Opcode.BSTNE, labelSymbol = elseLabel)
|
||||
BranchCondition.NE, BranchCondition.NZ -> VmCodeInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
|
||||
BranchCondition.MI, BranchCondition.NEG -> VmCodeInstruction(Opcode.BSTPOS, labelSymbol = elseLabel)
|
||||
BranchCondition.PL, BranchCondition.POS -> VmCodeInstruction(Opcode.BSTNEG, labelSymbol = elseLabel)
|
||||
BranchCondition.VC,
|
||||
BranchCondition.VS -> throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu V flag ${branch.position}")
|
||||
}
|
||||
code += translateNode(branch.trueScope)
|
||||
if(branch.falseScope.children.isNotEmpty()) {
|
||||
val endLabel = createLabelName()
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(branch.falseScope)
|
||||
code += VmCodeLabel(endLabel)
|
||||
} else {
|
||||
code += VmCodeLabel(elseLabel)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(whenStmt: PtWhen): VmCodeChunk {
|
||||
if(whenStmt.choices.children.isEmpty())
|
||||
return VmCodeChunk()
|
||||
val code = VmCodeChunk()
|
||||
val valueReg = vmRegisters.nextFree()
|
||||
val choiceReg = vmRegisters.nextFree()
|
||||
val valueDt = vmType(whenStmt.value.type)
|
||||
code += expressionEval.translateExpression(whenStmt.value, valueReg, -1)
|
||||
val choices = whenStmt.choices.children.map {it as PtWhenChoice }
|
||||
val endLabel = createLabelName()
|
||||
for (choice in choices) {
|
||||
if(choice.isElse) {
|
||||
code += translateNode(choice.statements)
|
||||
} else {
|
||||
val skipLabel = createLabelName()
|
||||
val values = choice.values.children.map {it as PtNumber}
|
||||
if(values.size==1) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=values[0].number.toInt())
|
||||
code += VmCodeInstruction(Opcode.BNE, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = skipLabel)
|
||||
code += translateNode(choice.statements)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
} else {
|
||||
val matchLabel = createLabelName()
|
||||
for (value in values) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, valueDt, reg1=choiceReg, value=value.number.toInt())
|
||||
code += VmCodeInstruction(Opcode.BEQ, valueDt, reg1=valueReg, reg2=choiceReg, labelSymbol = matchLabel)
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = skipLabel)
|
||||
code += VmCodeLabel(matchLabel)
|
||||
code += translateNode(choice.statements)
|
||||
if(choice.statements.children.last() !is PtReturn)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
}
|
||||
code += VmCodeLabel(skipLabel)
|
||||
}
|
||||
}
|
||||
code += VmCodeLabel(endLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(forLoop: PtForLoop): VmCodeChunk {
|
||||
val loopvar = symbolTable.lookup(forLoop.variable.targetName) as StStaticVariable
|
||||
val iterable = forLoop.iterable
|
||||
val code = VmCodeChunk()
|
||||
when(iterable) {
|
||||
is PtRange -> {
|
||||
if(iterable.from is PtNumber && iterable.to is PtNumber)
|
||||
code += translateForInConstantRange(forLoop, loopvar)
|
||||
else
|
||||
code += translateForInNonConstantRange(forLoop, loopvar)
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val arrayAddress = allocations.get(iterable.targetName)
|
||||
val iterableVar = symbolTable.lookup(iterable.targetName) as StStaticVariable
|
||||
val loopvarAddress = allocations.get(loopvar.scopedName)
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val tmpReg = vmRegisters.nextFree()
|
||||
val loopLabel = createLabelName()
|
||||
val endLabel = createLabelName()
|
||||
if(iterableVar.dt==DataType.STR) {
|
||||
// iterate over a zero-terminated string
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Opcode.LOADX, VmDataType.BYTE, reg1=tmpReg, reg2=indexReg, value = arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.BZ, VmDataType.BYTE, reg1=tmpReg, labelSymbol = endLabel)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.BYTE, reg1=tmpReg, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=indexReg)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
code += VmCodeLabel(endLabel)
|
||||
} else {
|
||||
// iterate over array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
val elementSize = program.memsizer.memorySize(elementDt)
|
||||
val lengthBytes = iterableVar.length!! * elementSize
|
||||
if(lengthBytes<256) {
|
||||
val lengthReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=lengthReg, value=lengthBytes)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
|
||||
code += VmCodeInstruction(Opcode.BNE, VmDataType.BYTE, reg1=indexReg, reg2=lengthReg, labelSymbol = loopLabel)
|
||||
} else if(lengthBytes==256) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=indexReg, value=0)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmType(elementDt), reg1=tmpReg, reg2=indexReg, value=arrayAddress)
|
||||
code += VmCodeInstruction(Opcode.STOREM, vmType(elementDt), reg1=tmpReg, value = loopvarAddress)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstReg(VmDataType.BYTE, indexReg, elementSize)
|
||||
code += VmCodeInstruction(Opcode.BNZ, VmDataType.BYTE, reg1=indexReg, labelSymbol = loopLabel)
|
||||
} else {
|
||||
throw AssemblyError("iterator length should never exceed 256")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird for iterable")
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translateForInNonConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk {
|
||||
val iterable = forLoop.iterable as PtRange
|
||||
val step = iterable.step.number.toInt()
|
||||
if (step==0)
|
||||
throw AssemblyError("step 0")
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val endvalueReg = vmRegisters.nextFree()
|
||||
val loopvarAddress = allocations.get(loopvar.scopedName)
|
||||
val loopvarDt = vmType(loopvar.dt)
|
||||
val loopLabel = createLabelName()
|
||||
val code = VmCodeChunk()
|
||||
|
||||
code += expressionEval.translateExpression(iterable.to, endvalueReg, -1)
|
||||
code += expressionEval.translateExpression(iterable.from, indexReg, -1)
|
||||
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step)
|
||||
code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
||||
val branchOpcode = if(loopvar.dt in SignedDatatypes) Opcode.BLES else Opcode.BLE
|
||||
code += VmCodeInstruction(branchOpcode, loopvarDt, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk {
|
||||
val loopLabel = createLabelName()
|
||||
val loopvarAddress = allocations.get(loopvar.scopedName)
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
val loopvarDt = vmType(loopvar.dt)
|
||||
val iterable = forLoop.iterable as PtRange
|
||||
val step = iterable.step.number.toInt()
|
||||
val rangeStart = (iterable.from as PtNumber).number.toInt()
|
||||
val rangeEndUntyped = (iterable.to as PtNumber).number.toInt() + step
|
||||
if(step==0)
|
||||
throw AssemblyError("step 0")
|
||||
if(step>0 && rangeEndUntyped<rangeStart || step<0 && rangeEndUntyped>rangeStart)
|
||||
throw AssemblyError("empty range")
|
||||
val rangeEndWrapped = if(loopvarDt==VmDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535
|
||||
val code = VmCodeChunk()
|
||||
val endvalueReg: Int
|
||||
if(rangeEndWrapped!=0) {
|
||||
endvalueReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped)
|
||||
} else {
|
||||
endvalueReg = -1 // not used
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart)
|
||||
code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress)
|
||||
code += VmCodeLabel(loopLabel)
|
||||
code += translateNode(forLoop.statements)
|
||||
code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step)
|
||||
code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress)
|
||||
code += if(rangeEndWrapped==0) {
|
||||
VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, labelSymbol = loopLabel)
|
||||
} else {
|
||||
VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, labelSymbol = loopLabel)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun addConstReg(dt: VmDataType, reg: Int, value: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
when(value) {
|
||||
0 -> { /* do nothing */ }
|
||||
1 -> {
|
||||
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||
}
|
||||
2 -> {
|
||||
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||
code += VmCodeInstruction(Opcode.INC, dt, reg1=reg)
|
||||
}
|
||||
-1 -> {
|
||||
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
||||
}
|
||||
-2 -> {
|
||||
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
||||
code += VmCodeInstruction(Opcode.DEC, dt, reg1=reg)
|
||||
}
|
||||
else -> {
|
||||
code += if(value>0) {
|
||||
VmCodeInstruction(Opcode.ADD, dt, reg1 = reg, value=value)
|
||||
} else {
|
||||
VmCodeInstruction(Opcode.SUB, dt, reg1 = reg, value=-value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun addConstMem(dt: VmDataType, address: UInt, value: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
when(value) {
|
||||
0 -> { /* do nothing */ }
|
||||
1 -> {
|
||||
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
|
||||
}
|
||||
2 -> {
|
||||
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
|
||||
code += VmCodeInstruction(Opcode.INCM, dt, value=address.toInt())
|
||||
}
|
||||
-1 -> {
|
||||
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
|
||||
}
|
||||
-2 -> {
|
||||
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
|
||||
code += VmCodeInstruction(Opcode.DECM, dt, value=address.toInt())
|
||||
}
|
||||
else -> {
|
||||
val valueReg = vmRegisters.nextFree()
|
||||
if(value>0) {
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=value)
|
||||
code += VmCodeInstruction(Opcode.ADDM, dt, reg1=valueReg, value=address.toInt())
|
||||
}
|
||||
else {
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=valueReg, value=-value)
|
||||
code += VmCodeInstruction(Opcode.SUBM, dt, reg1=valueReg, value=address.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun multiplyByConstFloat(fpReg: Int, factor: Float): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1f)
|
||||
return code
|
||||
code += if(factor==0f) {
|
||||
VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = 0f)
|
||||
} else {
|
||||
VmCodeInstruction(Opcode.MUL, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun multiplyByConstFloatInplace(address: Int, factor: Float): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1f)
|
||||
return code
|
||||
if(factor==0f) {
|
||||
code += VmCodeInstruction(Opcode.STOREZM, VmDataType.FLOAT, value = address)
|
||||
} else {
|
||||
val factorReg = vmRegisters.nextFreeFloat()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
code += VmCodeInstruction(Opcode.MULM, VmDataType.FLOAT, fpReg1 = factorReg, value = address)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal val powersOfTwo = (0..16).map { 2.0.pow(it.toDouble()).toInt() }
|
||||
|
||||
internal fun multiplyByConst(dt: VmDataType, reg: Int, factor: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
if(pow2==1) {
|
||||
// just shift 1 bit
|
||||
code += VmCodeInstruction(Opcode.LSL, dt, reg1=reg)
|
||||
}
|
||||
else if(pow2>=1) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += VmCodeInstruction(Opcode.LSLN, dt, reg1=reg, reg2=pow2reg)
|
||||
} else {
|
||||
code += if (factor == 0) {
|
||||
VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0)
|
||||
} else {
|
||||
VmCodeInstruction(Opcode.MUL, dt, reg1=reg, value=factor)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun multiplyByConstInplace(dt: VmDataType, address: Int, factor: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
if(pow2==1) {
|
||||
// just shift 1 bit
|
||||
code += VmCodeInstruction(Opcode.LSLM, dt, value = address)
|
||||
}
|
||||
else if(pow2>=1) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += VmCodeInstruction(Opcode.LSLNM, dt, reg1=pow2reg, value=address)
|
||||
} else {
|
||||
if (factor == 0) {
|
||||
code += VmCodeInstruction(Opcode.STOREZM, dt, value=address)
|
||||
}
|
||||
else {
|
||||
val factorReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value = factor)
|
||||
code += VmCodeInstruction(Opcode.MULM, dt, reg1=factorReg, value = address)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConstFloat(fpReg: Int, factor: Float): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1f)
|
||||
return code
|
||||
code += if(factor==0f) {
|
||||
VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = fpReg, fpValue = Float.MAX_VALUE)
|
||||
} else {
|
||||
VmCodeInstruction(Opcode.DIVS, VmDataType.FLOAT, fpReg1 = fpReg, fpValue=factor)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConstFloatInplace(address: Int, factor: Float): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1f)
|
||||
return code
|
||||
if(factor==0f) {
|
||||
val maxvalueReg = vmRegisters.nextFreeFloat()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1 = maxvalueReg, fpValue = Float.MAX_VALUE)
|
||||
code += VmCodeInstruction(Opcode.STOREM, VmDataType.FLOAT, fpReg1 = maxvalueReg, value=address)
|
||||
} else {
|
||||
val factorReg = vmRegisters.nextFreeFloat()
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.FLOAT, fpReg1=factorReg, fpValue = factor)
|
||||
code += VmCodeInstruction(Opcode.DIVSM, VmDataType.FLOAT, fpReg1 = factorReg, value=address)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConst(dt: VmDataType, reg: Int, factor: Int, signed: Boolean): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
if(pow2==1 && !signed) {
|
||||
code += VmCodeInstruction(Opcode.LSR, dt, reg1=reg) // simple single bit shift
|
||||
}
|
||||
else if(pow2>=1 &&!signed) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += if(signed)
|
||||
VmCodeInstruction(Opcode.ASRN, dt, reg1=reg, reg2=pow2reg)
|
||||
else
|
||||
VmCodeInstruction(Opcode.LSRN, dt, reg1=reg, reg2=pow2reg)
|
||||
} else {
|
||||
code += if (factor == 0) {
|
||||
VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||
} else {
|
||||
if(signed)
|
||||
VmCodeInstruction(Opcode.DIVS, dt, reg1=reg, value=factor)
|
||||
else
|
||||
VmCodeInstruction(Opcode.DIV, dt, reg1=reg, value=factor)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
internal fun divideByConstInplace(dt: VmDataType, address: Int, factor: Int, signed: Boolean): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(factor==1)
|
||||
return code
|
||||
val pow2 = powersOfTwo.indexOf(factor)
|
||||
if(pow2==1 && !signed) {
|
||||
code += VmCodeInstruction(Opcode.LSRM, dt, value=address) // just simple bit shift
|
||||
}
|
||||
else if(pow2>=1 && !signed) {
|
||||
// just shift multiple bits
|
||||
val pow2reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=pow2reg, value=pow2)
|
||||
code += if(signed)
|
||||
VmCodeInstruction(Opcode.ASRNM, dt, reg1=pow2reg, value=address)
|
||||
else
|
||||
VmCodeInstruction(Opcode.LSRNM, dt, reg1=pow2reg, value=address)
|
||||
} else {
|
||||
if (factor == 0) {
|
||||
val reg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=reg, value=0xffff)
|
||||
code += VmCodeInstruction(Opcode.STOREM, dt, reg1=reg, value=address)
|
||||
}
|
||||
else {
|
||||
val factorReg = vmRegisters.nextFree()
|
||||
code += VmCodeInstruction(Opcode.LOAD, dt, reg1=factorReg, value= factor)
|
||||
code += if(signed)
|
||||
VmCodeInstruction(Opcode.DIVSM, dt, reg1=factorReg, value=address)
|
||||
else
|
||||
VmCodeInstruction(Opcode.DIVM, dt, reg1=factorReg, value=address)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(ifElse: PtIfElse): VmCodeChunk {
|
||||
if(ifElse.condition.operator !in ComparisonOperators)
|
||||
throw AssemblyError("if condition should only be a binary comparison expression")
|
||||
|
||||
val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||
val vmDt = vmType(ifElse.condition.left.type)
|
||||
val code = VmCodeChunk()
|
||||
|
||||
fun translateNonZeroComparison(): VmCodeChunk {
|
||||
val elseBranch = when(ifElse.condition.operator) {
|
||||
"==" -> Opcode.BNE
|
||||
"!=" -> Opcode.BEQ
|
||||
"<" -> if(signed) Opcode.BGES else Opcode.BGE
|
||||
">" -> if(signed) Opcode.BLES else Opcode.BLE
|
||||
"<=" -> if(signed) Opcode.BGTS else Opcode.BGT
|
||||
">=" -> if(signed) Opcode.BLTS else Opcode.BLT
|
||||
else -> throw AssemblyError("invalid comparison operator")
|
||||
}
|
||||
|
||||
val leftReg = vmRegisters.nextFree()
|
||||
val rightReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
code += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
fun translateZeroComparison(): VmCodeChunk {
|
||||
fun equalOrNotEqualZero(elseBranch: Opcode): VmCodeChunk {
|
||||
val leftReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1)
|
||||
if(ifElse.elseScope.children.isNotEmpty()) {
|
||||
// if and else parts
|
||||
val elseLabel = createLabelName()
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = elseLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeInstruction(Opcode.JUMP, labelSymbol = afterIfLabel)
|
||||
code += VmCodeLabel(elseLabel)
|
||||
code += translateNode(ifElse.elseScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
} else {
|
||||
// only if part
|
||||
val afterIfLabel = createLabelName()
|
||||
code += VmCodeInstruction(elseBranch, vmDt, reg1=leftReg, labelSymbol = afterIfLabel)
|
||||
code += translateNode(ifElse.ifScope)
|
||||
code += VmCodeLabel(afterIfLabel)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
return when (ifElse.condition.operator) {
|
||||
"==" -> {
|
||||
// if X==0 ... so we just branch on left expr is Not-zero.
|
||||
equalOrNotEqualZero(Opcode.BNZ)
|
||||
}
|
||||
"!=" -> {
|
||||
// if X!=0 ... so we just branch on left expr is Zero.
|
||||
equalOrNotEqualZero(Opcode.BZ)
|
||||
}
|
||||
else -> {
|
||||
// another comparison against 0, just use regular codegen for this.
|
||||
translateNonZeroComparison()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if(constValue(ifElse.condition.right)==0.0)
|
||||
translateZeroComparison()
|
||||
else
|
||||
translateNonZeroComparison()
|
||||
}
|
||||
|
||||
|
||||
private fun translate(postIncrDecr: PtPostIncrDecr): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val operationMem: Opcode
|
||||
val operationRegister: Opcode
|
||||
when(postIncrDecr.operator) {
|
||||
"++" -> {
|
||||
operationMem = Opcode.INCM
|
||||
operationRegister = Opcode.INC
|
||||
}
|
||||
"--" -> {
|
||||
operationMem = Opcode.DECM
|
||||
operationRegister = Opcode.DEC
|
||||
}
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
val ident = postIncrDecr.target.identifier
|
||||
val memory = postIncrDecr.target.memory
|
||||
val array = postIncrDecr.target.array
|
||||
val vmDt = vmType(postIncrDecr.target.type)
|
||||
if(ident!=null) {
|
||||
val address = allocations.get(ident.targetName)
|
||||
code += VmCodeInstruction(operationMem, vmDt, value = address)
|
||||
} else if(memory!=null) {
|
||||
if(memory.address is PtNumber) {
|
||||
val address = (memory.address as PtNumber).number.toInt()
|
||||
code += VmCodeInstruction(operationMem, vmDt, value = address)
|
||||
} else {
|
||||
val incReg = vmRegisters.nextFree()
|
||||
val addressReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(memory.address, addressReg, -1)
|
||||
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1 = incReg, reg2 = addressReg)
|
||||
code += VmCodeInstruction(operationRegister, vmDt, reg1 = incReg)
|
||||
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1 = incReg, reg2 = addressReg)
|
||||
}
|
||||
} else if (array!=null) {
|
||||
val variable = array.variable.targetName
|
||||
var variableAddr = allocations.get(variable)
|
||||
val itemsize = program.memsizer.memorySize(array.type)
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
if(fixedIndex!=null) {
|
||||
variableAddr += fixedIndex*itemsize
|
||||
code += VmCodeInstruction(operationMem, vmDt, value=variableAddr)
|
||||
} else {
|
||||
val incReg = vmRegisters.nextFree()
|
||||
val indexReg = vmRegisters.nextFree()
|
||||
code += expressionEval.translateExpression(array.index, indexReg, -1)
|
||||
code += VmCodeInstruction(Opcode.LOADX, vmDt, reg1=incReg, reg2=indexReg, value=variableAddr)
|
||||
code += VmCodeInstruction(operationRegister, vmDt, reg1=incReg)
|
||||
code += VmCodeInstruction(Opcode.STOREX, vmDt, reg1=incReg, reg2=indexReg, value=variableAddr)
|
||||
}
|
||||
} else
|
||||
throw AssemblyError("weird assigntarget")
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(repeat: PtRepeatLoop): VmCodeChunk {
|
||||
when (constIntValue(repeat.count)) {
|
||||
0 -> return VmCodeChunk()
|
||||
1 -> return translateGroup(repeat.children)
|
||||
256 -> {
|
||||
// 256 iterations can still be done with just a byte counter if you set it to zero as starting value.
|
||||
repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position)
|
||||
}
|
||||
}
|
||||
|
||||
val code = VmCodeChunk()
|
||||
val counterReg = vmRegisters.nextFree()
|
||||
val vmDt = vmType(repeat.count.type)
|
||||
code += expressionEval.translateExpression(repeat.count, counterReg, -1)
|
||||
val repeatLabel = createLabelName()
|
||||
code += VmCodeLabel(repeatLabel)
|
||||
code += translateNode(repeat.statements)
|
||||
code += VmCodeInstruction(Opcode.DEC, vmDt, reg1=counterReg)
|
||||
code += VmCodeInstruction(Opcode.BNZ, vmDt, reg1=counterReg, labelSymbol = repeatLabel)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(jump: PtJump): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
if(jump.address!=null)
|
||||
throw AssemblyError("cannot jump to memory location in the vm target")
|
||||
code += if(jump.generatedLabel!=null)
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf(jump.generatedLabel!!))
|
||||
else if(jump.identifier!=null)
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.targetName)
|
||||
else
|
||||
throw AssemblyError("weird jump")
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translateGroup(group: List<PtNode>): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
group.forEach { code += translateNode(it) }
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(ret: PtReturn): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
val value = ret.value
|
||||
if(value!=null) {
|
||||
// Call Convention: return value is always returned in r0 (or fr0 if float)
|
||||
code += if(value.type==DataType.FLOAT)
|
||||
expressionEval.translateExpression(value, -1, 0)
|
||||
else
|
||||
expressionEval.translateExpression(value, 0, -1)
|
||||
}
|
||||
code += VmCodeInstruction(Opcode.RETURN)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(sub: PtSub): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
|
||||
code += VmCodeLabel(sub.scopedName)
|
||||
for (child in sub.children) {
|
||||
code += translateNode(child)
|
||||
}
|
||||
code += VmCodeComment("SUB-END '${sub.name}'")
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(sub: PtAsmSub): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeComment("ASMSUB: ${sub.scopedName}")
|
||||
code += VmCodeLabel(sub.scopedName)
|
||||
for (child in sub.children) {
|
||||
code += translateNode(child)
|
||||
}
|
||||
code += VmCodeComment("ASMSUB-END '${sub.name}'")
|
||||
return code
|
||||
}
|
||||
|
||||
private fun translate(block: PtBlock): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += VmCodeComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
|
||||
for (child in block.children) {
|
||||
if(child !is PtAssignment) // global variable initialization is done elsewhere
|
||||
code += translateNode(child)
|
||||
}
|
||||
code += VmCodeComment("BLOCK-END '${block.name}'")
|
||||
return code
|
||||
}
|
||||
|
||||
|
||||
internal fun vmType(type: DataType): VmDataType {
|
||||
return when(type) {
|
||||
DataType.BOOL,
|
||||
DataType.UBYTE,
|
||||
DataType.BYTE -> VmDataType.BYTE
|
||||
DataType.UWORD,
|
||||
DataType.WORD -> VmDataType.WORD
|
||||
DataType.FLOAT -> VmDataType.FLOAT
|
||||
in PassByReferenceDatatypes -> VmDataType.WORD
|
||||
else -> throw AssemblyError("no vm datatype for $type")
|
||||
}
|
||||
}
|
||||
|
||||
private var labelSequenceNumber = 0
|
||||
internal fun createLabelName(): List<String> {
|
||||
labelSequenceNumber++
|
||||
return listOf("prog8_label_gen_$labelSequenceNumber")
|
||||
}
|
||||
|
||||
internal fun translateBuiltinFunc(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk =
|
||||
builtinFuncGen.translate(call, resultRegister)
|
||||
|
||||
internal fun isZero(expression: PtExpression): Boolean = expression is PtNumber && expression.number==0.0
|
||||
|
||||
internal fun isOne(expression: PtExpression): Boolean = expression is PtNumber && expression.number==1.0
|
||||
}
|
||||
|
@ -1,122 +0,0 @@
|
||||
package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.*
|
||||
|
||||
class VariableAllocator(private val st: SymbolTable, private val program: PtProgram) {
|
||||
|
||||
private val allocations = mutableMapOf<List<String>, Int>()
|
||||
private var freeMemoryStart: Int
|
||||
|
||||
val freeMem: Int
|
||||
get() = freeMemoryStart
|
||||
|
||||
init {
|
||||
var nextLocation = 0
|
||||
for (variable in st.allVariables) {
|
||||
val memsize =
|
||||
when (variable.dt) {
|
||||
DataType.STR -> variable.initialStringValue!!.first.length + 1 // include the zero byte
|
||||
in NumericDatatypes -> program.memsizer.memorySize(variable.dt)
|
||||
in ArrayDatatypes -> program.memsizer.memorySize(variable.dt, variable.length!!)
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
|
||||
allocations[variable.scopedName] = nextLocation
|
||||
nextLocation += memsize
|
||||
}
|
||||
for (memvar in st.allMemMappedVariables) {
|
||||
// TODO virtual machine doesn't have memory mapped variables, so treat them as regular allocated variables for now
|
||||
val memsize =
|
||||
when (memvar.dt) {
|
||||
in NumericDatatypes -> program.memsizer.memorySize(memvar.dt)
|
||||
in ArrayDatatypes -> program.memsizer.memorySize(memvar.dt, memvar.length!!)
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
|
||||
allocations[memvar.scopedName] = nextLocation
|
||||
nextLocation += memsize
|
||||
}
|
||||
|
||||
freeMemoryStart = nextLocation
|
||||
}
|
||||
|
||||
fun get(name: List<String>) = allocations.getValue(name)
|
||||
|
||||
fun asVmMemory(): List<Pair<List<String>, String>> {
|
||||
val mm = mutableListOf<Pair<List<String>, String>>()
|
||||
for (variable in st.allVariables) {
|
||||
val location = allocations.getValue(variable.scopedName)
|
||||
val typeStr = when(variable.dt) {
|
||||
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
|
||||
DataType.BYTE, DataType.ARRAY_B -> "byte"
|
||||
DataType.UWORD, DataType.ARRAY_UW -> "uword"
|
||||
DataType.WORD, DataType.ARRAY_W -> "word"
|
||||
DataType.FLOAT, DataType.ARRAY_F -> "float"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
val value = when(variable.dt) {
|
||||
DataType.FLOAT -> (variable.initialNumericValue ?: 0.0).toString()
|
||||
in NumericDatatypes -> (variable.initialNumericValue ?: 0).toHex()
|
||||
DataType.STR -> {
|
||||
val encoded = program.encoding.encodeString(variable.initialStringValue!!.first, variable.initialStringValue!!.second) + listOf(0u)
|
||||
encoded.joinToString(",") { it.toInt().toHex() }
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
if(variable.initialArrayValue!=null) {
|
||||
variable.initialArrayValue!!.joinToString(",") { it.number!!.toString() }
|
||||
} else {
|
||||
(1..variable.length!!).joinToString(",") { "0" }
|
||||
}
|
||||
}
|
||||
in ArrayDatatypes -> {
|
||||
if(variable.initialArrayValue!==null) {
|
||||
variable.initialArrayValue!!.joinToString(",") { it.number!!.toHex() }
|
||||
} else {
|
||||
(1..variable.length!!).joinToString(",") { "0" }
|
||||
}
|
||||
}
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
mm.add(Pair(variable.scopedName, "$location $typeStr $value"))
|
||||
}
|
||||
for (variable in st.allMemMappedVariables) {
|
||||
val location = allocations.getValue(variable.scopedName)
|
||||
val typeStr = when(variable.dt) {
|
||||
DataType.UBYTE, DataType.ARRAY_UB, DataType.STR -> "ubyte"
|
||||
DataType.BYTE, DataType.ARRAY_B -> "byte"
|
||||
DataType.UWORD, DataType.ARRAY_UW -> "uword"
|
||||
DataType.WORD, DataType.ARRAY_W -> "word"
|
||||
DataType.FLOAT, DataType.ARRAY_F -> "float"
|
||||
else -> throw InternalCompilerException("weird dt")
|
||||
}
|
||||
val value = when(variable.dt) {
|
||||
DataType.FLOAT -> "0.0"
|
||||
in NumericDatatypes -> "0"
|
||||
DataType.ARRAY_F -> (1..variable.length!!).joinToString(",") { "0.0" }
|
||||
in ArrayDatatypes -> (1..variable.length!!).joinToString(",") { "0" }
|
||||
else -> throw InternalCompilerException("weird dt for mem mapped var")
|
||||
}
|
||||
mm.add(Pair(variable.scopedName, "$location $typeStr $value"))
|
||||
}
|
||||
return mm
|
||||
}
|
||||
|
||||
private val memorySlabsInternal = mutableMapOf<String, Triple<UInt, UInt, UInt>>()
|
||||
internal val memorySlabs: Map<String, Triple<UInt, UInt, UInt>> = memorySlabsInternal
|
||||
|
||||
fun allocateMemorySlab(name: String, size: UInt, align: UInt): UInt {
|
||||
val address =
|
||||
if(align==0u || align==1u)
|
||||
freeMemoryStart.toUInt()
|
||||
else
|
||||
(freeMemoryStart.toUInt() + align-1u) and (0xffffffffu xor (align-1u))
|
||||
|
||||
memorySlabsInternal[name] = Triple(address, size, align)
|
||||
freeMemoryStart = (address + size).toInt()
|
||||
return address
|
||||
}
|
||||
|
||||
fun getMemorySlab(name: String): Triple<UInt, UInt, UInt>? = memorySlabsInternal[name]
|
||||
}
|
@ -1,188 +0,0 @@
|
||||
package prog8.codegen.virtual
|
||||
|
||||
import prog8.vm.Instruction
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
|
||||
|
||||
class VmPeepholeOptimizer(private val vmprog: AssemblyProgram) {
|
||||
fun optimize() {
|
||||
vmprog.getBlocks().forEach { block ->
|
||||
do {
|
||||
val indexedInstructions = block.lines.withIndex()
|
||||
.filter { it.value is VmCodeInstruction }
|
||||
.map { IndexedValue(it.index, (it.value as VmCodeInstruction).ins) }
|
||||
val changed = removeNops(block, indexedInstructions)
|
||||
|| removeDoubleLoadsAndStores(block, indexedInstructions) // TODO not yet implemented
|
||||
|| removeUselessArithmetic(block, indexedInstructions)
|
||||
|| removeWeirdBranches(block, indexedInstructions)
|
||||
|| removeDoubleSecClc(block, indexedInstructions)
|
||||
|| cleanupPushPop(block, indexedInstructions)
|
||||
// TODO other optimizations:
|
||||
// more complex optimizations such as unused registers
|
||||
} while(changed)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanupPushPop(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
||||
// push followed by pop to same target, or different target->replace with load
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode==Opcode.PUSH) {
|
||||
if(idx < block.lines.size-1) {
|
||||
val insAfter = block.lines[idx+1] as? VmCodeInstruction
|
||||
if(insAfter!=null && insAfter.ins.opcode ==Opcode.POP) {
|
||||
if(ins.reg1==insAfter.ins.reg1) {
|
||||
block.lines.removeAt(idx)
|
||||
block.lines.removeAt(idx)
|
||||
} else {
|
||||
block.lines[idx] = VmCodeInstruction(Opcode.LOADR, ins.type, reg1=insAfter.ins.reg1, reg2=ins.reg1)
|
||||
block.lines.removeAt(idx+1)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
|
||||
private fun removeDoubleSecClc(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
||||
// double sec, clc
|
||||
// sec+clc or clc+sec
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode==Opcode.SEC || ins.opcode==Opcode.CLC) {
|
||||
if(idx < block.lines.size-1) {
|
||||
val insAfter = block.lines[idx+1] as? VmCodeInstruction
|
||||
if(insAfter?.ins?.opcode == ins.opcode) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
else if(ins.opcode==Opcode.SEC && insAfter?.ins?.opcode==Opcode.CLC) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
else if(ins.opcode==Opcode.CLC && insAfter?.ins?.opcode==Opcode.SEC) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeWeirdBranches(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
||||
// jump/branch to label immediately below
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if(ins.opcode==Opcode.JUMP && ins.labelSymbol!=null) {
|
||||
// if jumping to label immediately following this
|
||||
if(idx < block.lines.size-1) {
|
||||
val label = block.lines[idx+1] as? VmCodeLabel
|
||||
if(label?.name == ins.labelSymbol) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeUselessArithmetic(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
||||
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
when (ins.opcode) {
|
||||
Opcode.DIV, Opcode.DIVS, Opcode.MUL, Opcode.MOD -> {
|
||||
if (ins.value == 1) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.ADD, Opcode.SUB -> {
|
||||
if (ins.value == 1) {
|
||||
block.lines[idx] = VmCodeInstruction(
|
||||
if (ins.opcode == Opcode.ADD) Opcode.INC else Opcode.DEC,
|
||||
ins.type,
|
||||
ins.reg1
|
||||
)
|
||||
changed = true
|
||||
} else if (ins.value == 0) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.AND -> {
|
||||
if (ins.value == 0) {
|
||||
block.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = 0)
|
||||
changed = true
|
||||
} else if (ins.value == 255 && ins.type == VmDataType.BYTE) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
} else if (ins.value == 65535 && ins.type == VmDataType.WORD) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.OR -> {
|
||||
if (ins.value == 0) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
} else if ((ins.value == 255 && ins.type == VmDataType.BYTE) || (ins.value == 65535 && ins.type == VmDataType.WORD)) {
|
||||
block.lines[idx] = VmCodeInstruction(Opcode.LOAD, ins.type, reg1 = ins.reg1, value = ins.value)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
Opcode.XOR -> {
|
||||
if (ins.value == 0) {
|
||||
block.lines.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeNops(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
||||
var changed = false
|
||||
indexedInstructions.reversed().forEach { (idx, ins) ->
|
||||
if (ins.opcode == Opcode.NOP) {
|
||||
changed = true
|
||||
block.lines.removeAt(idx)
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun removeDoubleLoadsAndStores(block: VmCodeChunk, indexedInstructions: List<IndexedValue<Instruction>>): Boolean {
|
||||
var changed = false
|
||||
indexedInstructions.forEach { (idx, ins) ->
|
||||
|
||||
// TODO: detect multiple loads to the same target registers, only keep first (if source is not I/O memory)
|
||||
// TODO: detect multiple stores to the same target, only keep first (if target is not I/O memory)
|
||||
// TODO: detect multiple float ffrom/fto to the same target, only keep first
|
||||
// TODO: detect multiple sequential rnd with same reg1, only keep one
|
||||
// TODO: detect subsequent same xors/nots/negs, remove the pairs completely as they cancel out
|
||||
// TODO: detect multiple same ands, ors; only keep first
|
||||
// TODO: (hard) detect multiple registers being assigned the same value (and not changed) - use only 1 of them
|
||||
// ...
|
||||
}
|
||||
return changed
|
||||
}
|
||||
}
|
||||
|
||||
private interface ICodeChange { // TODO not used? remove?
|
||||
fun perform(block: VmCodeChunk)
|
||||
|
||||
class Remove(val idx: Int): ICodeChange {
|
||||
override fun perform(block: VmCodeChunk) {
|
||||
block.lines.removeAt(idx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
package prog8tests.vm
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.codegen.virtual.*
|
||||
import prog8.vm.Opcode
|
||||
import prog8.vm.VmDataType
|
||||
import prog8tests.vm.helpers.DummyMemsizer
|
||||
import prog8tests.vm.helpers.DummyStringEncoder
|
||||
|
||||
class TestVmPeepholeOpt: FunSpec({
|
||||
fun makeVmProgram(lines: List<VmCodeLine>): Pair<AssemblyProgram, VariableAllocator> {
|
||||
val st = SymbolTable()
|
||||
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
||||
val allocations = VariableAllocator(st, program)
|
||||
val asm = AssemblyProgram("test", allocations)
|
||||
val block = VmCodeChunk()
|
||||
for(line in lines)
|
||||
block += line
|
||||
asm.addBlock(block)
|
||||
return Pair(asm, allocations)
|
||||
}
|
||||
|
||||
fun AssemblyProgram.lines(): List<VmCodeLine> = this.getBlocks().flatMap { it.lines }
|
||||
|
||||
test("remove nops") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("dummy")),
|
||||
VmCodeInstruction(Opcode.NOP),
|
||||
VmCodeInstruction(Opcode.NOP)
|
||||
))
|
||||
asm.lines().size shouldBe 3
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
asm.lines().size shouldBe 1
|
||||
}
|
||||
|
||||
test("remove jmp to label below") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("label")), // removed
|
||||
VmCodeLabel(listOf("label")),
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("label2")), // removed
|
||||
VmCodeInstruction(Opcode.NOP), // removed
|
||||
VmCodeLabel(listOf("label2")),
|
||||
VmCodeInstruction(Opcode.JUMP, labelSymbol = listOf("label3")),
|
||||
VmCodeInstruction(Opcode.INC, VmDataType.BYTE, reg1=1),
|
||||
VmCodeLabel(listOf("label3"))
|
||||
))
|
||||
asm.lines().size shouldBe 8
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 5
|
||||
(lines[0] as VmCodeLabel).name shouldBe listOf("label")
|
||||
(lines[1] as VmCodeLabel).name shouldBe listOf("label2")
|
||||
(lines[2] as VmCodeInstruction).ins.opcode shouldBe Opcode.JUMP
|
||||
(lines[3] as VmCodeInstruction).ins.opcode shouldBe Opcode.INC
|
||||
(lines[4] as VmCodeLabel).name shouldBe listOf("label3")
|
||||
}
|
||||
|
||||
test("remove double sec/clc") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.SEC),
|
||||
VmCodeInstruction(Opcode.SEC),
|
||||
VmCodeInstruction(Opcode.SEC),
|
||||
VmCodeInstruction(Opcode.CLC),
|
||||
VmCodeInstruction(Opcode.CLC),
|
||||
VmCodeInstruction(Opcode.CLC)
|
||||
))
|
||||
asm.lines().size shouldBe 6
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as VmCodeInstruction).ins.opcode shouldBe Opcode.CLC
|
||||
}
|
||||
|
||||
test("push followed by pop") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=42),
|
||||
VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=42),
|
||||
VmCodeInstruction(Opcode.PUSH, VmDataType.BYTE, reg1=99),
|
||||
VmCodeInstruction(Opcode.POP, VmDataType.BYTE, reg1=222)
|
||||
))
|
||||
asm.lines().size shouldBe 4
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 1
|
||||
(lines[0] as VmCodeInstruction).ins.opcode shouldBe Opcode.LOADR
|
||||
(lines[0] as VmCodeInstruction).ins.reg1 shouldBe 222
|
||||
(lines[0] as VmCodeInstruction).ins.reg2 shouldBe 99
|
||||
}
|
||||
|
||||
test("remove useless div/mul, add/sub") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 1),
|
||||
VmCodeInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 1),
|
||||
VmCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 1),
|
||||
VmCodeInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 1),
|
||||
VmCodeInstruction(Opcode.DIV, VmDataType.BYTE, reg1=42, value = 2),
|
||||
VmCodeInstruction(Opcode.DIVS, VmDataType.BYTE, reg1=42, value = 2),
|
||||
VmCodeInstruction(Opcode.MUL, VmDataType.BYTE, reg1=42, value = 2),
|
||||
VmCodeInstruction(Opcode.MOD, VmDataType.BYTE, reg1=42, value = 2),
|
||||
VmCodeInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 0),
|
||||
VmCodeInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 0)
|
||||
))
|
||||
asm.lines().size shouldBe 10
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 4
|
||||
}
|
||||
|
||||
test("replace add/sub 1 by inc/dec") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.ADD, VmDataType.BYTE, reg1=42, value = 1),
|
||||
VmCodeInstruction(Opcode.SUB, VmDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
asm.lines().size shouldBe 2
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 2
|
||||
(lines[0] as VmCodeInstruction).ins.opcode shouldBe Opcode.INC
|
||||
(lines[1] as VmCodeInstruction).ins.opcode shouldBe Opcode.DEC
|
||||
}
|
||||
|
||||
test("remove useless and/or/xor") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 255),
|
||||
VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 65535),
|
||||
VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 0),
|
||||
VmCodeInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 0),
|
||||
VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 200),
|
||||
VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 60000),
|
||||
VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 1),
|
||||
VmCodeInstruction(Opcode.XOR, VmDataType.BYTE, reg1=42, value = 1)
|
||||
))
|
||||
asm.lines().size shouldBe 8
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 4
|
||||
}
|
||||
|
||||
test("replace and/or/xor by constant number") {
|
||||
val(asm, _) = makeVmProgram(listOf(
|
||||
VmCodeInstruction(Opcode.AND, VmDataType.BYTE, reg1=42, value = 0),
|
||||
VmCodeInstruction(Opcode.AND, VmDataType.WORD, reg1=42, value = 0),
|
||||
VmCodeInstruction(Opcode.OR, VmDataType.BYTE, reg1=42, value = 255),
|
||||
VmCodeInstruction(Opcode.OR, VmDataType.WORD, reg1=42, value = 65535)
|
||||
))
|
||||
asm.lines().size shouldBe 4
|
||||
val opt = VmPeepholeOptimizer(asm)
|
||||
opt.optimize()
|
||||
val lines = asm.lines()
|
||||
lines.size shouldBe 4
|
||||
(lines[0] as VmCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
||||
(lines[1] as VmCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
||||
(lines[2] as VmCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
||||
(lines[3] as VmCodeInstruction).ins.opcode shouldBe Opcode.LOAD
|
||||
(lines[0] as VmCodeInstruction).ins.value shouldBe 0
|
||||
(lines[1] as VmCodeInstruction).ins.value shouldBe 0
|
||||
(lines[2] as VmCodeInstruction).ins.value shouldBe 255
|
||||
(lines[3] as VmCodeInstruction).ins.value shouldBe 65535
|
||||
}
|
||||
})
|
@ -6,7 +6,10 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.maySwapOperandOrder
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.statements.AnonymousScope
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.IfElse
|
||||
import prog8.ast.statements.Jump
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
|
@ -27,13 +27,12 @@ compileTestKotlin {
|
||||
def prog8version = rootProject.file('compiler/res/version.txt').text.trim()
|
||||
|
||||
dependencies {
|
||||
implementation project(':codeAst')
|
||||
implementation project(':codeCore')
|
||||
implementation project(':codeOptimizers')
|
||||
implementation project(':compilerAst')
|
||||
implementation project(':codeGenCpu6502')
|
||||
implementation project(':codeGenVirtual')
|
||||
implementation project(':codeGenExperimental')
|
||||
implementation project(':virtualmachine')
|
||||
implementation 'org.antlr:antlr4-runtime:4.10.1'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
|
@ -17,11 +17,10 @@
|
||||
<orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
|
||||
<orderEntry type="library" name="antlr.antlr4" level="project" />
|
||||
<orderEntry type="module" module-name="codeCore" />
|
||||
<orderEntry type="module" module-name="codeAst" />
|
||||
<orderEntry type="module" module-name="compilerAst" />
|
||||
<orderEntry type="module" module-name="codeOptimizers" />
|
||||
<orderEntry type="module" module-name="codeGenCpu6502" />
|
||||
<orderEntry type="module" module-name="codeGenExperimental" />
|
||||
<orderEntry type="module" module-name="codeGenVirtual" />
|
||||
<orderEntry type="module" module-name="virtualmachine" />
|
||||
</component>
|
||||
</module>
|
||||
</module>
|
||||
|
@ -844,25 +844,28 @@ _done
|
||||
}
|
||||
6 -> {
|
||||
; hires 4c
|
||||
; we're going to use a few cx16 registers to make sure every variable is in zeropage in the inner loop.
|
||||
cx16.r11L = color
|
||||
cx16.r8 = y
|
||||
while @(sctextptr) {
|
||||
chardataptr = charset_addr + (@(sctextptr) as uword)*8
|
||||
repeat 8 {
|
||||
; TODO rewrite this inner loop partly in assembly
|
||||
; requires expanding the charbits to 2-bits per pixel (based on color)
|
||||
; also it's way more efficient to draw whole horizontal spans instead of per-character
|
||||
ubyte charbits = cx16.vpeek(charset_bank, chardataptr)
|
||||
cx16.r9L = cx16.vpeek(charset_bank, chardataptr) ; get the 8 horizontal character bits
|
||||
cx16.r7 = x
|
||||
repeat 8 {
|
||||
charbits <<= 1
|
||||
cx16.r9L <<= 1
|
||||
if_cs
|
||||
plot(x, y, color)
|
||||
x++
|
||||
plot(cx16.r7, cx16.r8, cx16.r11L)
|
||||
cx16.r7++
|
||||
}
|
||||
x-=8
|
||||
chardataptr++
|
||||
y++
|
||||
cx16.r8++
|
||||
}
|
||||
x+=8
|
||||
y-=8
|
||||
cx16.r8-=8
|
||||
sctextptr++
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,12 @@ psg {
|
||||
const ubyte RIGHT = %10000000
|
||||
|
||||
sub voice(ubyte voice_num, ubyte channel, ubyte volume, ubyte waveform, ubyte pulsewidth) {
|
||||
; -- Enables a 'voice' on the PSG.
|
||||
; voice_num = 0-15, the voice number.
|
||||
; channel = either LEFT or RIGHT or (LEFT|RIGHT). Specifies the stereo channel(s) to use.
|
||||
; volume = 0-63, the starting volume for the voice
|
||||
; waveform = one of PULSE,SAWTOOTH,TRIANGLE,NOISE.
|
||||
; pulsewidth = 0-63. Specifies the pulse width for waveform=PULSE.
|
||||
envelope_states[voice_num] = 255
|
||||
cx16.r0 = $f9c2 + voice_num * 4
|
||||
cx16.VERA_CTRL = 0
|
||||
@ -30,12 +36,15 @@ psg {
|
||||
|
||||
; sub freq_hz(ubyte voice_num, float hertz) {
|
||||
; ; this would rely on floating point math to convert hertz to vera frequency
|
||||
; ; TODO should be replaced by integer math maybe with a lookup table?
|
||||
; ; could be replaced by integer math maybe with a lookup table?
|
||||
; uword vera_freq = (hertz / 0.3725290298461914) as uword
|
||||
; freq(voice_num, vera_freq)
|
||||
; }
|
||||
|
||||
sub freq(ubyte voice_num, uword vera_freq) {
|
||||
; -- Changes the frequency of the voice's sound.
|
||||
; voice_num = 0-15, vera_freq = 0-65535 calculate this via the formula given in the Vera's PSG documentation.
|
||||
; (https://github.com/commanderx16/x16-docs/blob/master/VERA%20Programmer's%20Reference.md)
|
||||
cx16.r0 = $f9c0 + voice_num * 4
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_L = lsb(cx16.r0)
|
||||
@ -47,6 +56,8 @@ psg {
|
||||
}
|
||||
|
||||
sub volume(ubyte voice_num, ubyte vol) {
|
||||
; -- Modifies the volume of this voice.
|
||||
; voice_num = 0-15, vol = 0-63 where 0=silent, 63=loudest.
|
||||
cx16.r0 = $f9c2 + voice_num * 4
|
||||
cx16.vpoke(1, cx16.r0, cx16.vpeek(1, cx16.r0) & %11000000 | vol)
|
||||
envelope_volumes[voice_num] = mkword(vol, 0)
|
||||
@ -54,11 +65,18 @@ psg {
|
||||
}
|
||||
|
||||
sub pulse_width(ubyte voice_num, ubyte pw) {
|
||||
; -- Modifies the pulse width of this voice (when waveform=PULSE)
|
||||
; voice_num = 0-15, pw = 0-63 where 0=narrow, 63=50%cycle so square wave.
|
||||
cx16.r0 = $f9c3 + voice_num * 4
|
||||
cx16.vpoke(1, cx16.r0, cx16.vpeek(1, cx16.r0) & %11000000 | pw)
|
||||
}
|
||||
|
||||
sub envelope(ubyte voice_num, ubyte maxvolume, ubyte attack, ubyte sustain, ubyte release) {
|
||||
; -- Enables AttackSustainRelease volume envelope for a voice.
|
||||
; Note: this requires setting up envelopes_irq() as well, read its description.
|
||||
; voice_num = 0-15 maxvolume = 0-63
|
||||
; attack, sustain, release = 0-255 that determine the speed of the A/D/R.
|
||||
; TODO describe how the speeds are calculated. For now, experiment. Higher values means *slower* enveloping.
|
||||
envelope_states[voice_num] = 255
|
||||
envelope_attacks[voice_num] = attack
|
||||
envelope_sustains[voice_num] = sustain
|
||||
@ -73,6 +91,7 @@ psg {
|
||||
}
|
||||
|
||||
sub silent() {
|
||||
; -- Shut down all PSG voices.
|
||||
for cx16.r1L in 0 to 15 {
|
||||
envelope_states[cx16.r1L] = 255
|
||||
envelope_volumes[cx16.r1L] = 0
|
||||
|
@ -369,6 +369,7 @@ romsub $ff4d = clock_set_date_time(uword yearmonth @R0, uword dayhours @R1, uwor
|
||||
romsub $ff50 = clock_get_date_time() clobbers(A, X, Y) -> uword @R0, uword @R1, uword @R2, ubyte @R3 ; result registers see clock_set_date_time()
|
||||
|
||||
; keyboard, mouse, joystick
|
||||
; note: also see the kbdbuf_clear() helper routine below!
|
||||
romsub $febd = kbdbuf_peek() -> ubyte @A, ubyte @X ; key in A, queue length in X
|
||||
romsub $febd = kbdbuf_peek2() -> uword @AX ; alternative to above to not have the hassle to deal with multiple return values
|
||||
romsub $fec0 = kbdbuf_get_modifiers() -> ubyte @A
|
||||
@ -380,6 +381,15 @@ romsub $ff53 = joystick_scan() clobbers(A, X, Y)
|
||||
romsub $ff56 = joystick_get(ubyte joynr @A) -> ubyte @A, ubyte @X, ubyte @Y
|
||||
romsub $ff56 = joystick_get2(ubyte joynr @A) clobbers(Y) -> uword @AX ; alternative to above to not have the hassle to deal with multiple return values
|
||||
|
||||
asmsub kbdbuf_clear() {
|
||||
; -- convenience helper routine to clear the keyboard buffer
|
||||
%asm {{
|
||||
- jsr c64.GETIN
|
||||
bne -
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub mouse_config2(ubyte shape @A) clobbers (A, X, Y) {
|
||||
; -- convenience wrapper function that handles the screen resolution for mouse_config() for you
|
||||
%asm {{
|
||||
|
@ -37,60 +37,6 @@ _sinecos8 .char trunc(127.0 * sin(range(256+64) * rad(360.0/256.0)))
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub sin16(ubyte angle @A) -> word @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda _sinecos8lo,y
|
||||
pha
|
||||
lda _sinecos8hi,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
_ := trunc(32767.0 * sin(range(256+64) * rad(360.0/256.0)))
|
||||
_sinecos8lo .byte <_
|
||||
_sinecos8hi .byte >_
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub cos16(ubyte angle @A) -> word @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda sin16._sinecos8lo+64,y
|
||||
pha
|
||||
lda sin16._sinecos8hi+64,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub sin16u(ubyte angle @A) -> uword @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda _sinecos8ulo,y
|
||||
pha
|
||||
lda _sinecos8uhi,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
_ := trunc(32768.0 + 32767.5 * sin(range(256+64) * rad(360.0/256.0)))
|
||||
_sinecos8ulo .byte <_
|
||||
_sinecos8uhi .byte >_
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub cos16u(ubyte angle @A) -> uword @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda sin16u._sinecos8ulo+64,y
|
||||
pha
|
||||
lda sin16u._sinecos8uhi+64,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub sinr8u(ubyte radians @A) clobbers(Y) -> ubyte @A {
|
||||
%asm {{
|
||||
tay
|
||||
@ -125,57 +71,4 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub sinr16(ubyte radians @A) -> word @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda _sinecosR8lo,y
|
||||
pha
|
||||
lda _sinecosR8hi,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
_ := trunc(32767.0 * sin(range(180+45) * rad(360.0/180.0)))
|
||||
_sinecosR8lo .byte <_
|
||||
_sinecosR8hi .byte >_
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub cosr16(ubyte radians @A) -> word @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda sinr16._sinecosR8lo+45,y
|
||||
pha
|
||||
lda sinr16._sinecosR8hi+45,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub sinr16u(ubyte radians @A) -> uword @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda _sinecosR8ulo,y
|
||||
pha
|
||||
lda _sinecosR8uhi,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
_ := trunc(32768.0 + 32767.5 * sin(range(180+45) * rad(360.0/180.0)))
|
||||
_sinecosR8ulo .byte <_
|
||||
_sinecosR8uhi .byte >_
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub cosr16u(ubyte radians @A) -> uword @AY {
|
||||
%asm {{
|
||||
tay
|
||||
lda sinr16u._sinecosR8ulo+45,y
|
||||
pha
|
||||
lda sinr16u._sinecosR8uhi+45,y
|
||||
tay
|
||||
pla
|
||||
rts
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -224,6 +224,29 @@ _done rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub lowerchar(ubyte char @A) -> ubyte @A {
|
||||
%asm {{
|
||||
and #$7f
|
||||
cmp #97
|
||||
bcc +
|
||||
cmp #123
|
||||
bcs +
|
||||
and #%11011111
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub upperchar(ubyte char @A) -> ubyte @A {
|
||||
%asm {{
|
||||
cmp #65
|
||||
bcc +
|
||||
cmp #91
|
||||
bcs +
|
||||
ora #%00100000
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub startswith(str st, str prefix) -> bool {
|
||||
ubyte prefix_len = length(prefix)
|
||||
ubyte str_len = length(st)
|
||||
|
@ -196,7 +196,7 @@ sub str2uword(str string) -> uword {
|
||||
; the number may NOT be preceded by a + sign and may NOT contain spaces
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%asm {{
|
||||
loadm.w r0, {conv.str2uword.string}
|
||||
loadm.w r0,conv.str2uword.string
|
||||
syscall 11
|
||||
return
|
||||
}}
|
||||
@ -207,7 +207,7 @@ sub str2word(str string) -> word {
|
||||
; the number may be preceded by a + or - sign but may NOT contain spaces
|
||||
; (any non-digit character will terminate the number string that is parsed)
|
||||
%asm {{
|
||||
loadm.w r0, {conv.str2word.string}
|
||||
loadm.w r0,conv.str2word.string
|
||||
syscall 12
|
||||
return
|
||||
}}
|
||||
|
@ -10,7 +10,7 @@ floats {
|
||||
sub print_f(float value) {
|
||||
; ---- prints the floating point value (without a newline).
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.print_f.value}
|
||||
loadm.f fr0,floats.print_f.value
|
||||
syscall 25
|
||||
return
|
||||
}}
|
||||
@ -18,8 +18,8 @@ sub print_f(float value) {
|
||||
|
||||
sub pow(float value, float power) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.pow.value}
|
||||
loadm.f fr1,{floats.pow.power}
|
||||
loadm.f fr0,floats.pow.value
|
||||
loadm.f fr1,floats.pow.power
|
||||
fpow.f fr0,fr1
|
||||
return
|
||||
}}
|
||||
@ -27,7 +27,7 @@ sub pow(float value, float power) -> float {
|
||||
|
||||
sub fabs(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.fabs.value}
|
||||
loadm.f fr0,floats.fabs.value
|
||||
fabs.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -35,7 +35,7 @@ sub fabs(float value) -> float {
|
||||
|
||||
sub sin(float angle) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.sin.angle}
|
||||
loadm.f fr0,floats.sin.angle
|
||||
fsin.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -43,7 +43,7 @@ sub sin(float angle) -> float {
|
||||
|
||||
sub cos(float angle) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.cos.angle}
|
||||
loadm.f fr0,floats.cos.angle
|
||||
fcos.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -51,7 +51,7 @@ sub cos(float angle) -> float {
|
||||
|
||||
sub tan(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.tan.value}
|
||||
loadm.f fr0,floats.tan.value
|
||||
ftan.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -59,7 +59,7 @@ sub tan(float value) -> float {
|
||||
|
||||
sub atan(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.atan.value}
|
||||
loadm.f fr0,floats.atan.value
|
||||
fatan.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -67,7 +67,7 @@ sub atan(float value) -> float {
|
||||
|
||||
sub ln(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.ln.value}
|
||||
loadm.f fr0,floats.ln.value
|
||||
fln.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -75,7 +75,7 @@ sub ln(float value) -> float {
|
||||
|
||||
sub log2(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.log2.value}
|
||||
loadm.f fr0,floats.log2.value
|
||||
flog.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -83,7 +83,7 @@ sub log2(float value) -> float {
|
||||
|
||||
sub sqrt(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.sqrt.value}
|
||||
loadm.f fr0,floats.sqrt.value
|
||||
sqrt.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -101,7 +101,7 @@ sub deg(float angle) -> float {
|
||||
|
||||
sub round(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.round.value}
|
||||
loadm.f fr0,floats.round.value
|
||||
fround.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -109,7 +109,7 @@ sub round(float value) -> float {
|
||||
|
||||
sub floor(float value) -> float {
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.floor.value}
|
||||
loadm.f fr0,floats.floor.value
|
||||
ffloor.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
@ -118,7 +118,7 @@ sub floor(float value) -> float {
|
||||
sub ceil(float value) -> float {
|
||||
; -- ceil: tr = int(f); if tr==f -> return else return tr+1
|
||||
%asm {{
|
||||
loadm.f fr0,{floats.ceil.value}
|
||||
loadm.f fr0,floats.ceil.value
|
||||
fceil.f fr0,fr0
|
||||
return
|
||||
}}
|
||||
|
@ -19,7 +19,7 @@ math {
|
||||
$0f, $11, $12, $14, $15, $17, $19, $1b, $1d, $1f, $21, $23, $25, $28, $2a, $2c,
|
||||
$2f, $31, $34, $36, $39, $3b, $3e, $41, $43, $46, $49, $4c, $4f, $52, $55, $58,
|
||||
$5a, $5d, $61, $64, $67, $6a, $6d, $70, $73, $76, $79, $7c]
|
||||
return sintab[angle]
|
||||
return sintab[angle]
|
||||
}
|
||||
|
||||
sub cos8u(ubyte angle) -> ubyte {
|
||||
@ -40,31 +40,53 @@ math {
|
||||
$bc, $be, $c1, $c4, $c6, $c9, $cb, $ce, $d0, $d3, $d5, $d7, $da, $dc, $de, $e0,
|
||||
$e2, $e4, $e6, $e8, $ea, $eb, $ed, $ee, $f0, $f1, $f3, $f4, $f5, $f6, $f8, $f9,
|
||||
$fa, $fa, $fb, $fc, $fd, $fd, $fe, $fe, $fe, $ff, $ff, $ff ]
|
||||
return costab[angle]
|
||||
return costab[angle]
|
||||
}
|
||||
|
||||
sub sin8(ubyte angle) -> byte {
|
||||
return 42 ; TODO
|
||||
ubyte[256] sintab = [
|
||||
$00, $03, $06, $09,
|
||||
$0c, $0f, $12, $15, $18, $1b, $1e, $21, $24, $27, $2a, $2d, $30, $33, $36, $39,
|
||||
$3b, $3e, $41, $43, $46, $49, $4b, $4e, $50, $52, $55, $57, $59, $5b, $5e, $60,
|
||||
$62, $64, $66, $67, $69, $6b, $6c, $6e, $70, $71, $72, $74, $75, $76, $77, $78,
|
||||
$79, $7a, $7b, $7b, $7c, $7d, $7d, $7e, $7e, $7e, $7e, $7e, $7f, $7e, $7e, $7e,
|
||||
$7e, $7e, $7d, $7d, $7c, $7b, $7b, $7a, $79, $78, $77, $76, $75, $74, $72, $71,
|
||||
$70, $6e, $6c, $6b, $69, $67, $66, $64, $62, $60, $5e, $5b, $59, $57, $55, $52,
|
||||
$50, $4e, $4b, $49, $46, $43, $41, $3e, $3b, $39, $36, $33, $30, $2d, $2a, $27,
|
||||
$24, $21, $1e, $1b, $18, $15, $12, $0f, $0c, $09, $06, $03, $00, $fd, $fa, $f7,
|
||||
$f4, $f1, $ee, $eb, $e8, $e5, $e2, $df, $dc, $d9, $d6, $d3, $d0, $cd, $ca, $c7,
|
||||
$c5, $c2, $bf, $bd, $ba, $b7, $b5, $b2, $b0, $ae, $ab, $a9, $a7, $a5, $a2, $a0,
|
||||
$9e, $9c, $9a, $99, $97, $95, $94, $92, $90, $8f, $8e, $8c, $8b, $8a, $89, $88,
|
||||
$87, $86, $85, $85, $84, $83, $83, $82, $82, $82, $82, $82, $81, $82, $82, $82,
|
||||
$82, $82, $83, $83, $84, $85, $85, $86, $87, $88, $89, $8a, $8b, $8c, $8e, $8f,
|
||||
$90, $92, $94, $95, $97, $99, $9a, $9c, $9e, $a0, $a2, $a5, $a7, $a9, $ab, $ae,
|
||||
$b0, $b2, $b5, $b7, $ba, $bd, $bf, $c2, $c5, $c7, $ca, $cd, $d0, $d3, $d6, $d9,
|
||||
$dc, $df, $e2, $e5, $e8, $eb, $ee, $f1, $f4, $f7, $fa, $fd
|
||||
]
|
||||
return sintab[angle] as byte
|
||||
}
|
||||
|
||||
sub cos8(ubyte angle) -> byte {
|
||||
return 42 ; TODO
|
||||
}
|
||||
|
||||
sub sin16(ubyte angle) -> word {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
|
||||
sub cos16(ubyte angle) -> word {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
|
||||
sub sin16u(ubyte angle) -> uword {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
|
||||
sub cos16u(ubyte angle) -> uword {
|
||||
return 4242 ; TODO
|
||||
ubyte[256] costab = [
|
||||
$7f, $7e, $7e, $7e,
|
||||
$7e, $7e, $7d, $7d, $7c, $7b, $7b, $7a, $79, $78, $77, $76, $75, $74, $72, $71,
|
||||
$70, $6e, $6c, $6b, $69, $67, $66, $64, $62, $60, $5e, $5b, $59, $57, $55, $52,
|
||||
$50, $4e, $4b, $49, $46, $43, $41, $3e, $3b, $39, $36, $33, $30, $2d, $2a, $27,
|
||||
$24, $21, $1e, $1b, $18, $15, $12, $0f, $0c, $09, $06, $03, $00, $fd, $fa, $f7,
|
||||
$f4, $f1, $ee, $eb, $e8, $e5, $e2, $df, $dc, $d9, $d6, $d3, $d0, $cd, $ca, $c7,
|
||||
$c5, $c2, $bf, $bd, $ba, $b7, $b5, $b2, $b0, $ae, $ab, $a9, $a7, $a5, $a2, $a0,
|
||||
$9e, $9c, $9a, $99, $97, $95, $94, $92, $90, $8f, $8e, $8c, $8b, $8a, $89, $88,
|
||||
$87, $86, $85, $85, $84, $83, $83, $82, $82, $82, $82, $82, $81, $82, $82, $82,
|
||||
$82, $82, $83, $83, $84, $85, $85, $86, $87, $88, $89, $8a, $8b, $8c, $8e, $8f,
|
||||
$90, $92, $94, $95, $97, $99, $9a, $9c, $9e, $a0, $a2, $a5, $a7, $a9, $ab, $ae,
|
||||
$b0, $b2, $b5, $b7, $ba, $bd, $bf, $c2, $c5, $c7, $ca, $cd, $d0, $d3, $d6, $d9,
|
||||
$dc, $df, $e2, $e5, $e8, $eb, $ee, $f1, $f4, $f7, $fa, $fd, $00, $03, $06, $09,
|
||||
$0c, $0f, $12, $15, $18, $1b, $1e, $21, $24, $27, $2a, $2d, $30, $33, $36, $39,
|
||||
$3b, $3e, $41, $43, $46, $49, $4b, $4e, $50, $52, $55, $57, $59, $5b, $5e, $60,
|
||||
$62, $64, $66, $67, $69, $6b, $6c, $6e, $70, $71, $72, $74, $75, $76, $77, $78,
|
||||
$79, $7a, $7b, $7b, $7c, $7d, $7d, $7e, $7e, $7e, $7e, $7e
|
||||
]
|
||||
return costab[angle] as byte
|
||||
}
|
||||
|
||||
sub sinr8u(ubyte radians) -> ubyte {
|
||||
@ -102,26 +124,39 @@ math {
|
||||
}
|
||||
|
||||
sub sinr8(ubyte radians) -> byte {
|
||||
return 42 ; TODO
|
||||
ubyte[180] sintab = [
|
||||
$00, $04, $08, $0d,
|
||||
$11, $16, $1a, $1e, $23, $27, $2b, $2f, $33, $37, $3b, $3f, $43, $47, $4a, $4e,
|
||||
$51, $54, $58, $5b, $5e, $61, $64, $66, $69, $6b, $6d, $70, $72, $74, $75, $77,
|
||||
$78, $7a, $7b, $7c, $7d, $7d, $7e, $7e, $7e, $7f, $7e, $7e, $7e, $7d, $7d, $7c,
|
||||
$7b, $7a, $78, $77, $75, $74, $72, $70, $6d, $6b, $69, $66, $64, $61, $5e, $5b,
|
||||
$58, $54, $51, $4e, $4a, $47, $43, $3f, $3b, $37, $33, $2f, $2b, $27, $23, $1e,
|
||||
$1a, $16, $11, $0d, $08, $04, $00, $fc, $f8, $f3, $ef, $ea, $e6, $e2, $dd, $d9,
|
||||
$d5, $d1, $cd, $c9, $c5, $c1, $bd, $b9, $b6, $b2, $af, $ac, $a8, $a5, $a2, $9f,
|
||||
$9c, $9a, $97, $95, $93, $90, $8e, $8c, $8b, $89, $88, $86, $85, $84, $83, $83,
|
||||
$82, $82, $82, $81, $82, $82, $82, $83, $83, $84, $85, $86, $88, $89, $8b, $8c,
|
||||
$8e, $90, $93, $95, $97, $9a, $9c, $9f, $a2, $a5, $a8, $ac, $af, $b2, $b6, $b9,
|
||||
$bd, $c1, $c5, $c9, $cd, $d1, $d5, $d9, $dd, $e2, $e6, $ea, $ef, $f3, $f8, $fc
|
||||
]
|
||||
return sintab[radians] as byte
|
||||
}
|
||||
|
||||
sub cosr8(ubyte radians) -> byte {
|
||||
return 42 ; TODO
|
||||
ubyte[180] costab = [
|
||||
$7f, $7e, $7e, $7e, $7d, $7d, $7c,
|
||||
$7b, $7a, $78, $77, $75, $74, $72, $70, $6d, $6b, $69, $66, $64, $61, $5e, $5b,
|
||||
$58, $54, $51, $4e, $4a, $47, $43, $3f, $3b, $37, $33, $2f, $2b, $27, $23, $1e,
|
||||
$1a, $16, $11, $0d, $08, $04, $00, $fc, $f8, $f3, $ef, $ea, $e6, $e2, $dd, $d9,
|
||||
$d5, $d1, $cd, $c9, $c5, $c1, $bd, $b9, $b6, $b2, $af, $ac, $a8, $a5, $a2, $9f,
|
||||
$9c, $9a, $97, $95, $93, $90, $8e, $8c, $8b, $89, $88, $86, $85, $84, $83, $83,
|
||||
$82, $82, $82, $81, $82, $82, $82, $83, $83, $84, $85, $86, $88, $89, $8b, $8c,
|
||||
$8e, $90, $93, $95, $97, $9a, $9c, $9f, $a2, $a5, $a8, $ac, $af, $b2, $b6, $b9,
|
||||
$bd, $c1, $c5, $c9, $cd, $d1, $d5, $d9, $dd, $e2, $e6, $ea, $ef, $f3, $f8, $fc,
|
||||
$00, $04, $08, $0d, $11, $16, $1a, $1e, $23, $27, $2b, $2f, $33, $37, $3b, $3f,
|
||||
$43, $47, $4a, $4e, $51, $54, $58, $5b, $5e, $61, $64, $66, $69, $6b, $6d, $70,
|
||||
$72, $74, $75, $77, $78, $7a, $7b, $7c, $7d, $7d, $7e, $7e, $7e
|
||||
]
|
||||
return costab[radians] as byte
|
||||
}
|
||||
|
||||
sub sinr16(ubyte radians) -> word {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
|
||||
sub cosr16(ubyte radians) -> word {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
|
||||
sub sinr16u(ubyte radians) -> uword {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
|
||||
sub cosr16u(ubyte radians) -> uword {
|
||||
return 4242 ; TODO
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ prog8_lib {
|
||||
; Note that you can also directly compare strings and string values with eachother using
|
||||
; comparison operators ==, < etcetera (it will use strcmp for you under water automatically).
|
||||
%asm {{
|
||||
loadm.w r0, {prog8_lib.string_compare.st1}
|
||||
loadm.w r1, {prog8_lib.string_compare.st2}
|
||||
loadm.w r0,prog8_lib.string_compare.st1
|
||||
loadm.w r1,prog8_lib.string_compare.st2
|
||||
syscall 29
|
||||
return
|
||||
}}
|
||||
|
@ -114,6 +114,18 @@ string {
|
||||
}
|
||||
}
|
||||
|
||||
sub lowerchar(ubyte char) -> ubyte {
|
||||
if char >= 'A' and char <= 'Z'
|
||||
char |= %00100000
|
||||
return char
|
||||
}
|
||||
|
||||
sub upperchar(ubyte char) -> ubyte {
|
||||
if char >= 'a' and char <= 'z'
|
||||
char &= %11011111
|
||||
return char
|
||||
}
|
||||
|
||||
sub startswith(str st, str prefix) -> bool {
|
||||
ubyte prefix_len = length(prefix)
|
||||
ubyte str_len = length(st)
|
||||
|
@ -15,7 +15,7 @@ sys {
|
||||
sub wait(uword jiffies) {
|
||||
; --- wait approximately the given number of jiffies (1/60th seconds)
|
||||
%asm {{
|
||||
loadm.w r0, {sys.wait.jiffies}
|
||||
loadm.w r0,sys.wait.jiffies
|
||||
syscall 13
|
||||
}}
|
||||
}
|
||||
@ -62,7 +62,7 @@ sys {
|
||||
sub exit(ubyte returnvalue) {
|
||||
; -- immediately exit the program with a return code in the A register
|
||||
%asm {{
|
||||
loadm.b r0,{sys.exit.returnvalue}
|
||||
loadm.b r0,sys.exit.returnvalue
|
||||
syscall 1
|
||||
}}
|
||||
}
|
||||
@ -82,24 +82,31 @@ sys {
|
||||
|
||||
sub gfx_enable(ubyte mode) {
|
||||
%asm {{
|
||||
loadm.b r0, {sys.gfx_enable.mode}
|
||||
loadm.b r0,sys.gfx_enable.mode
|
||||
syscall 8
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_clear(ubyte color) {
|
||||
%asm {{
|
||||
loadm.b r0,sys.gfx_clear.color
|
||||
syscall 9
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_plot(uword xx, uword yy, ubyte color) {
|
||||
%asm {{
|
||||
loadm.w r0, {sys.gfx_plot.xx}
|
||||
loadm.w r1, {sys.gfx_plot.yy}
|
||||
loadm.b r2, {sys.gfx_plot.color}
|
||||
loadm.w r0,sys.gfx_plot.xx
|
||||
loadm.w r1,sys.gfx_plot.yy
|
||||
loadm.b r2,sys.gfx_plot.color
|
||||
syscall 10
|
||||
}}
|
||||
}
|
||||
|
||||
sub gfx_getpixel(uword xx, uword yy) -> ubyte {
|
||||
%asm {{
|
||||
loadm.w r0, {sys.gfx_getpixel.xx}
|
||||
loadm.w r1, {sys.gfx_getpixel.yy}
|
||||
loadm.w r0,sys.gfx_getpixel.xx
|
||||
loadm.w r1,sys.gfx_getpixel.yy
|
||||
syscall 30
|
||||
return
|
||||
}}
|
||||
@ -110,105 +117,105 @@ cx16 {
|
||||
|
||||
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
||||
; they are simulated on the VirtualMachine as well but their location in memory is different
|
||||
&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
|
||||
&uword r0 = $ff02
|
||||
&uword r1 = $ff04
|
||||
&uword r2 = $ff06
|
||||
&uword r3 = $ff08
|
||||
&uword r4 = $ff0a
|
||||
&uword r5 = $ff0c
|
||||
&uword r6 = $ff0e
|
||||
&uword r7 = $ff10
|
||||
&uword r8 = $ff12
|
||||
&uword r9 = $ff14
|
||||
&uword r10 = $ff16
|
||||
&uword r11 = $ff18
|
||||
&uword r12 = $ff1a
|
||||
&uword r13 = $ff1c
|
||||
&uword r14 = $ff1e
|
||||
&uword r15 = $ff20
|
||||
|
||||
&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
|
||||
&word r0s = $ff02
|
||||
&word r1s = $ff04
|
||||
&word r2s = $ff06
|
||||
&word r3s = $ff08
|
||||
&word r4s = $ff0a
|
||||
&word r5s = $ff0c
|
||||
&word r6s = $ff0e
|
||||
&word r7s = $ff10
|
||||
&word r8s = $ff12
|
||||
&word r9s = $ff14
|
||||
&word r10s = $ff16
|
||||
&word r11s = $ff18
|
||||
&word r12s = $ff1a
|
||||
&word r13s = $ff1c
|
||||
&word r14s = $ff1e
|
||||
&word r15s = $ff20
|
||||
|
||||
&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 r0L = $ff02
|
||||
&ubyte r1L = $ff04
|
||||
&ubyte r2L = $ff06
|
||||
&ubyte r3L = $ff08
|
||||
&ubyte r4L = $ff0a
|
||||
&ubyte r5L = $ff0c
|
||||
&ubyte r6L = $ff0e
|
||||
&ubyte r7L = $ff10
|
||||
&ubyte r8L = $ff12
|
||||
&ubyte r9L = $ff14
|
||||
&ubyte r10L = $ff16
|
||||
&ubyte r11L = $ff18
|
||||
&ubyte r12L = $ff1a
|
||||
&ubyte r13L = $ff1c
|
||||
&ubyte r14L = $ff1e
|
||||
&ubyte r15L = $ff20
|
||||
|
||||
&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
|
||||
&ubyte r0H = $ff03
|
||||
&ubyte r1H = $ff05
|
||||
&ubyte r2H = $ff07
|
||||
&ubyte r3H = $ff09
|
||||
&ubyte r4H = $ff0b
|
||||
&ubyte r5H = $ff0d
|
||||
&ubyte r6H = $ff0f
|
||||
&ubyte r7H = $ff11
|
||||
&ubyte r8H = $ff13
|
||||
&ubyte r9H = $ff15
|
||||
&ubyte r10H = $ff17
|
||||
&ubyte r11H = $ff19
|
||||
&ubyte r12H = $ff1b
|
||||
&ubyte r13H = $ff1d
|
||||
&ubyte r14H = $ff1f
|
||||
&ubyte r15H = $ff21
|
||||
|
||||
&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 r0sL = $ff02
|
||||
&byte r1sL = $ff04
|
||||
&byte r2sL = $ff06
|
||||
&byte r3sL = $ff08
|
||||
&byte r4sL = $ff0a
|
||||
&byte r5sL = $ff0c
|
||||
&byte r6sL = $ff0e
|
||||
&byte r7sL = $ff10
|
||||
&byte r8sL = $ff12
|
||||
&byte r9sL = $ff14
|
||||
&byte r10sL = $ff16
|
||||
&byte r11sL = $ff18
|
||||
&byte r12sL = $ff1a
|
||||
&byte r13sL = $ff1c
|
||||
&byte r14sL = $ff1e
|
||||
&byte r15sL = $ff20
|
||||
|
||||
&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
|
||||
&byte r0sH = $ff03
|
||||
&byte r1sH = $ff05
|
||||
&byte r2sH = $ff07
|
||||
&byte r3sH = $ff09
|
||||
&byte r4sH = $ff0b
|
||||
&byte r5sH = $ff0d
|
||||
&byte r6sH = $ff0f
|
||||
&byte r7sH = $ff11
|
||||
&byte r8sH = $ff13
|
||||
&byte r9sH = $ff15
|
||||
&byte r10sH = $ff17
|
||||
&byte r11sH = $ff19
|
||||
&byte r12sH = $ff1b
|
||||
&byte r13sH = $ff1d
|
||||
&byte r14sH = $ff1f
|
||||
&byte r15sH = $ff21
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ txt {
|
||||
sub clear_screen() {
|
||||
str @shared sequence = "\x1b[2J\x1B[H"
|
||||
%asm {{
|
||||
load.w r0, {txt.clear_screen.sequence}
|
||||
load.w r0,txt.clear_screen.sequence
|
||||
syscall 3
|
||||
}}
|
||||
}
|
||||
@ -30,14 +30,14 @@ sub uppercase() {
|
||||
|
||||
sub chrout(ubyte char) {
|
||||
%asm {{
|
||||
loadm.b r0, {txt.chrout.char}
|
||||
loadm.b r0,txt.chrout.char
|
||||
syscall 2
|
||||
}}
|
||||
}
|
||||
|
||||
sub print (str text) {
|
||||
%asm {{
|
||||
loadm.w r0, {txt.print.text}
|
||||
loadm.w r0,txt.print.text
|
||||
syscall 3
|
||||
}}
|
||||
}
|
||||
@ -114,10 +114,25 @@ sub input_chars (uword buffer) -> ubyte {
|
||||
; ---- Input a string (max. 80 chars) from the keyboard. Returns length of input. (string is terminated with a 0 byte as well)
|
||||
; It assumes the keyboard is selected as I/O channel!
|
||||
%asm {{
|
||||
loadm.w r0,{txt.input_chars.buffer}
|
||||
loadm.w r0,txt.input_chars.buffer
|
||||
syscall 6
|
||||
return
|
||||
}}
|
||||
}
|
||||
|
||||
sub plot (ubyte col, ubyte row) {
|
||||
; use ANSI escape sequence to position the cursor
|
||||
txt.chrout(27)
|
||||
txt.chrout('[')
|
||||
txt.print_ub(row)
|
||||
txt.chrout(';')
|
||||
txt.print_ub(col)
|
||||
txt.chrout('H')
|
||||
}
|
||||
|
||||
sub setchr (ubyte col, ubyte row, ubyte char) {
|
||||
plot(col, row)
|
||||
txt.chrout(char)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
8.4
|
||||
8.6.2
|
||||
|
@ -10,8 +10,12 @@ import prog8.compiler.CompilationResult
|
||||
import prog8.compiler.CompilerArguments
|
||||
import prog8.compiler.compileProgram
|
||||
import java.io.File
|
||||
import java.nio.file.*
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardWatchEventKinds
|
||||
import java.nio.file.WatchKey
|
||||
import java.time.LocalDateTime
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
@ -31,23 +35,24 @@ fun pathFrom(stringPath: String, vararg rest: String): Path = FileSystems.getDe
|
||||
|
||||
private fun compileMain(args: Array<String>): Boolean {
|
||||
val cli = ArgParser("prog8compiler", prefixStyle = ArgParser.OptionPrefixStyle.JVM)
|
||||
val asmListfile by cli.option(ArgType.Boolean, fullName = "asmlist", description = "make the assembler produce a listing file as well")
|
||||
val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple()
|
||||
val evalStackAddrString by cli.option(ArgType.String, fullName = "esa", description = "override the eval-stack base address (must be page aligned)")
|
||||
val startEmulator1 by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation")
|
||||
val startEmulator2 by cli.option(ArgType.Boolean, fullName = "emu2", description = "auto-start alternative emulator after successful compilation")
|
||||
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
|
||||
val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen")
|
||||
val keepIR by cli.option(ArgType.Boolean, fullName = "keepIR", description = "keep the IR code file (for targets that use it)")
|
||||
val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code")
|
||||
val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations")
|
||||
val dontReinitGlobals by cli.option(ArgType.Boolean, fullName = "noreinit", description = "don't create code to reinitialize globals on multiple runs of the program (experimental!)")
|
||||
val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".")
|
||||
val optimizeFloatExpressions by cli.option(ArgType.Boolean, fullName = "optfloatx", description = "optimize float expressions (warning: can increase program size)")
|
||||
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
|
||||
val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation")
|
||||
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/alternative codegen")
|
||||
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}', '${VMTarget.NAME}')").default(C64Target.NAME)
|
||||
val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation")
|
||||
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 startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a p8-virt listing in the VM instead")
|
||||
val symbolDefs by cli.option(ArgType.String, fullName = "D", description = "define assembly symbol(s) with -D SYMBOL=VALUE").multiple()
|
||||
val evalStackAddrString by cli.option(ArgType.String, fullName = "esa", description = "override the eval-stack base address (must be page aligned)")
|
||||
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}', '${VMTarget.NAME}')").default(C64Target.NAME)
|
||||
val startVm by cli.option(ArgType.Boolean, fullName = "vm", description = "load and run a .p8ir IR source file in the VM")
|
||||
val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watch for file changes)")
|
||||
val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999)
|
||||
|
||||
try {
|
||||
@ -122,6 +127,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
quietAssembler == true,
|
||||
asmListfile == true,
|
||||
experimentalCodegen == true,
|
||||
keepIR == true,
|
||||
compilationTarget,
|
||||
evalStackAddr,
|
||||
processedSymbols,
|
||||
@ -140,7 +146,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
for (importedFile in allImportedFiles) {
|
||||
print(" ")
|
||||
println(importedFile)
|
||||
val watchDir = importedFile.parent ?: Path.of("")
|
||||
val watchDir = importedFile.parent ?: Path("")
|
||||
watchDir.register(watchservice, StandardWatchEventKinds.ENTRY_MODIFY)
|
||||
}
|
||||
println("[${LocalDateTime.now().withNano(0)}] Waiting for file changes.")
|
||||
@ -186,6 +192,7 @@ private fun compileMain(args: Array<String>): Boolean {
|
||||
quietAssembler == true,
|
||||
asmListfile == true,
|
||||
experimentalCodegen == true,
|
||||
keepIR == true,
|
||||
compilationTarget,
|
||||
evalStackAddr,
|
||||
processedSymbols,
|
||||
@ -241,13 +248,9 @@ private fun processSymbolDefs(symbolDefs: List<String>): Map<String, String>? {
|
||||
return result
|
||||
}
|
||||
|
||||
fun runVm(listingFilename: String): Boolean {
|
||||
val name =
|
||||
if(listingFilename.endsWith(".p8virt"))
|
||||
listingFilename.substring(0, listingFilename.length-7)
|
||||
else
|
||||
listingFilename
|
||||
fun runVm(irFilename: String): Boolean {
|
||||
val irFile = Path(irFilename)
|
||||
val vmdef = VirtualMachineDefinition()
|
||||
vmdef.launchEmulator(0, Paths.get(name))
|
||||
vmdef.launchEmulator(0, irFile)
|
||||
return true
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import prog8.code.target.*
|
||||
import prog8.compiler.astprocessing.*
|
||||
import prog8.optimizer.*
|
||||
import prog8.parser.ParseError
|
||||
import prog8.vm.codegen.VmCodeGen
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
@ -37,6 +38,7 @@ class CompilerArguments(val filepath: Path,
|
||||
val quietAssembler: Boolean,
|
||||
val asmListfile: Boolean,
|
||||
val experimentalCodegen: Boolean,
|
||||
val keepIR: Boolean,
|
||||
val compilationTarget: String,
|
||||
val evalStackBaseAddress: UInt?,
|
||||
val symbolDefs: Map<String, String>,
|
||||
@ -79,6 +81,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
asmQuiet = args.quietAssembler
|
||||
asmListfile = args.asmListfile
|
||||
experimentalCodegen = args.experimentalCodegen
|
||||
keepIR = args.keepIR
|
||||
evalStackBaseAddress = args.evalStackBaseAddress
|
||||
outputDir = args.outputDir.normalize()
|
||||
symbolDefs = args.symbolDefs
|
||||
@ -339,7 +342,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
|
||||
errors.report()
|
||||
program.reorderStatements(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.changeNotExpression(errors)
|
||||
program.changeNotExpressionAndIfComparisonExpr(errors, compilerOptions.compTarget)
|
||||
errors.report()
|
||||
program.addTypecasts(errors, compilerOptions)
|
||||
errors.report()
|
||||
@ -445,18 +448,15 @@ internal fun asmGeneratorFor(program: Program,
|
||||
options: CompilationOptions): IAssemblyGenerator
|
||||
{
|
||||
if(options.experimentalCodegen) {
|
||||
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02)) {
|
||||
// TODO for now, use the new Intermediary Ast for this experimental codegen:
|
||||
val intermediateAst = IntermediateAstMaker(program).transform()
|
||||
return prog8.codegen.experimental.AsmGen(intermediateAst, symbolTable, options, errors)
|
||||
}
|
||||
val intermediateAst = IntermediateAstMaker(program).transform()
|
||||
return prog8.codegen.experimental.CodeGen(intermediateAst, symbolTable, options, errors)
|
||||
} else {
|
||||
if (options.compTarget.machine.cpu in arrayOf(CpuType.CPU6502, CpuType.CPU65c02))
|
||||
// TODO rewrite 6502 codegen on new Intermediary Ast
|
||||
// TODO rewrite 6502 codegen on new Intermediary Ast or on new Intermediate Representation
|
||||
return prog8.codegen.cpu6502.AsmGen(program, symbolTable, options, errors)
|
||||
if (options.compTarget.name == VMTarget.NAME) {
|
||||
val intermediateAst = IntermediateAstMaker(program).transform()
|
||||
return prog8.codegen.virtual.CodeGen(intermediateAst, symbolTable, options, errors)
|
||||
return VmCodeGen(intermediateAst, symbolTable, options, errors)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,10 +259,7 @@ internal class AstChecker(private val program: Program,
|
||||
)
|
||||
count++
|
||||
} else {
|
||||
if(" return" in assembly || "\treturn" in assembly
|
||||
|| " jump" in assembly || "\tjump" in assembly
|
||||
|| " jumpi" in assembly || "\tjumpi" in assembly
|
||||
)
|
||||
if(" return" in assembly || "\treturn" in assembly || " jump" in assembly || "\tjump" in assembly)
|
||||
count++
|
||||
}
|
||||
}
|
||||
@ -620,7 +617,7 @@ internal class AstChecker(private val program: Program,
|
||||
err("memory address must be valid integer 0..\$ffff")
|
||||
}
|
||||
} else {
|
||||
err("value of memory mapped variable can only be a fixed number, perhaps you meant to use an address pointer type instead?")
|
||||
err("value of memory mapped variable can only be a constant, maybe use an address pointer type instead?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ internal fun Program.reorderStatements(errors: IErrorReporter, options: Compilat
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Program.changeNotExpression(errors: IErrorReporter) {
|
||||
val changer = NotExpressionChanger(this, errors)
|
||||
internal fun Program.changeNotExpressionAndIfComparisonExpr(errors: IErrorReporter, target: ICompilationTarget) {
|
||||
val changer = NotExpressionAndIfComparisonExprChanger(this, errors, target)
|
||||
changer.visit(this)
|
||||
while(errors.noErrors() && changer.applyModifications()>0) {
|
||||
changer.visit(this)
|
||||
@ -172,7 +172,7 @@ internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolea
|
||||
internal fun Subroutine.hasRtsInAsm(compTarget: ICompilationTarget): Boolean {
|
||||
val instructions =
|
||||
if(compTarget.name == VMTarget.NAME)
|
||||
listOf(" return", "\treturn", " jump", "\tjump", " jumpi", "\tjumpi")
|
||||
listOf(" return", "\treturn", " jump", "\tjump")
|
||||
else
|
||||
listOf(" rti", "\trti", " rts", "\trts", " jmp", "\tjmp", " bra", "\tbra")
|
||||
return statements
|
||||
|
@ -10,6 +10,7 @@ import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.VMTarget
|
||||
|
||||
|
||||
class AstPreprocessor(val program: Program,
|
||||
@ -24,7 +25,7 @@ class AstPreprocessor(val program: Program,
|
||||
relocateCx16VirtualRegisters(program, 0x0004u)
|
||||
}
|
||||
}
|
||||
else if(options.compTarget.name!=Cx16Target.NAME) {
|
||||
else if(options.compTarget.name !in setOf(Cx16Target.NAME, VMTarget.NAME)) {
|
||||
relocateCx16VirtualRegisters(program, options.compTarget.machine.ESTACK_HI)
|
||||
}
|
||||
return noModifications
|
||||
|
@ -1,8 +1,11 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.*
|
||||
import prog8.ast.IStatementContainer
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.getTempVar
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
|
@ -1,4 +1,4 @@
|
||||
package prog8.compiler
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
@ -12,11 +12,16 @@ import prog8.code.ast.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.core.SourceCode
|
||||
import prog8.compiler.BuiltinFunctions
|
||||
import prog8.compiler.builtinFunctionReturnType
|
||||
import java.io.File
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
|
||||
/**
|
||||
* Convert 'old' compiler-AST into the 'new' simplified AST with baked types.
|
||||
*/
|
||||
class IntermediateAstMaker(val program: Program) {
|
||||
fun transform(): PtProgram {
|
||||
val ptProgram = PtProgram(
|
||||
@ -175,11 +180,19 @@ class IntermediateAstMaker(val program: Program) {
|
||||
return when(directive.directive) {
|
||||
"%breakpoint" -> PtBreakpoint(directive.position)
|
||||
"%asmbinary" -> {
|
||||
val filename = directive.args[0].str!!
|
||||
val offset: UInt? = if(directive.args.size>=2) directive.args[1].int!! else null
|
||||
val length: UInt? = if(directive.args.size>=3) directive.args[2].int!! else null
|
||||
val sourcePath = Path(directive.definingModule.source.origin)
|
||||
val includedPath = sourcePath.resolveSibling(directive.args[0].str!!)
|
||||
PtIncludeBinary(includedPath, offset, length, directive.position)
|
||||
val abspath = if(File(filename).isFile) {
|
||||
Path(filename).toAbsolutePath()
|
||||
} else {
|
||||
val sourcePath = Path(directive.definingModule.source.origin)
|
||||
sourcePath.resolveSibling(filename).toAbsolutePath()
|
||||
}
|
||||
if(abspath.toFile().isFile)
|
||||
PtIncludeBinary(abspath, offset, length, directive.position)
|
||||
else
|
||||
throw FatalAstException("included file doesn't exist")
|
||||
}
|
||||
"%asminclude" -> {
|
||||
val result = loadAsmIncludeFile(directive.args[0].str!!, directive.definingModule.source)
|
||||
@ -217,7 +230,8 @@ class IntermediateAstMaker(val program: Program) {
|
||||
val type = srcCall.inferType(program).getOrElse {
|
||||
throw FatalAstException("unknown dt $srcCall")
|
||||
}
|
||||
val call = PtFunctionCall(target, type==DataType.UNDEFINED, type, srcCall.position)
|
||||
val isVoid = type==DataType.UNDEFINED
|
||||
val call = PtFunctionCall(target, isVoid, type, srcCall.position)
|
||||
for (arg in srcCall.args)
|
||||
call.add(transformExpression(arg))
|
||||
return call
|
||||
@ -289,6 +303,8 @@ class IntermediateAstMaker(val program: Program) {
|
||||
srcSub.asmReturnvaluesRegisters,
|
||||
srcSub.inline,
|
||||
srcSub.position)
|
||||
sub.parameters.forEach { it.first.parent=sub }
|
||||
|
||||
if(srcSub.asmAddress==null) {
|
||||
var combinedAsm = ""
|
||||
for (asm in srcSub.statements)
|
||||
@ -304,11 +320,15 @@ class IntermediateAstMaker(val program: Program) {
|
||||
|
||||
private fun transformSub(srcSub: Subroutine): PtSub {
|
||||
val (vardecls, statements) = srcSub.statements.partition { it is VarDecl }
|
||||
var returntype = srcSub.returntypes.singleOrNull()
|
||||
if(returntype==DataType.STR)
|
||||
returntype=DataType.UWORD // if a sub returns 'str', replace with uword. Intermediate AST and I.R. don't contain 'str' datatype anymore.
|
||||
val sub = PtSub(srcSub.name,
|
||||
srcSub.parameters.map { PtSubroutineParameter(it.name, it.type, it.position) },
|
||||
srcSub.returntypes.singleOrNull(),
|
||||
returntype,
|
||||
srcSub.inline,
|
||||
srcSub.position)
|
||||
sub.parameters.forEach { it.parent=sub }
|
||||
|
||||
if(vardecls.isNotEmpty()) sub.add(makeScopeVarsDecls(vardecls, sub.position))
|
||||
for (statement in statements)
|
@ -0,0 +1,189 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.*
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.AssignTarget
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.statements.AssignmentOrigin
|
||||
import prog8.ast.statements.IfElse
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
|
||||
internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val errors: IErrorReporter, val compTarget: ICompilationTarget) : AstWalker() {
|
||||
|
||||
override fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator=="==" || expr.operator=="!=") {
|
||||
val left = expr.left as? BinaryExpression
|
||||
if (left != null) {
|
||||
val rightValue = expr.right.constValue(program)
|
||||
if (rightValue?.number == 0.0 && rightValue.type in IntegerDatatypes) {
|
||||
if (left.operator == "==" && expr.operator == "==") {
|
||||
// (x==something)==0 --> x!=something
|
||||
left.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "!=" && expr.operator == "==") {
|
||||
// (x!=something)==0 --> x==something
|
||||
left.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "==" && expr.operator == "!=") {
|
||||
// (x==something)!=0 --> x==something
|
||||
left.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "!=" && expr.operator == "!=") {
|
||||
// (x!=something)!=0 --> x!=something
|
||||
left.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator == "not") {
|
||||
// not(not(x)) -> x
|
||||
if((expr.expression as? PrefixExpression)?.operator=="not")
|
||||
return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent))
|
||||
// not(~x) -> x!=0
|
||||
if((expr.expression as? PrefixExpression)?.operator=="~") {
|
||||
val x = (expr.expression as PrefixExpression).expression
|
||||
val dt = x.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||
val notZero = BinaryExpression(x, "!=", NumericLiteral(dt, 0.0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, notZero, parent))
|
||||
}
|
||||
val subBinExpr = expr.expression as? BinaryExpression
|
||||
if(subBinExpr?.operator=="==") {
|
||||
if(subBinExpr.right.constValue(program)?.number==0.0) {
|
||||
// not(x==0) -> x!=0
|
||||
subBinExpr.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
|
||||
}
|
||||
} else if(subBinExpr?.operator=="!=") {
|
||||
if(subBinExpr.right.constValue(program)?.number==0.0) {
|
||||
// not(x!=0) -> x==0
|
||||
subBinExpr.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
|
||||
}
|
||||
}
|
||||
|
||||
// all other not(x) --> x==0
|
||||
// this means that "not" will never occur anywhere again in the ast after this
|
||||
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(DataType.UBYTE,0.0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
||||
override fun before(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
|
||||
if(compTarget.name == VMTarget.NAME) // don't apply this optimization for Vm target
|
||||
return noModifications
|
||||
|
||||
val binExpr = ifElse.condition as? BinaryExpression
|
||||
if(binExpr==null || binExpr.operator !in ComparisonOperators)
|
||||
return noModifications
|
||||
|
||||
// Simplify the conditional expression, introduce simple assignments if required.
|
||||
// This is REQUIRED for correct code generation on 6502 because evaluating certain expressions
|
||||
// clobber the handful of temporary variables in the zeropage and leaving everything in one
|
||||
// expression then results in invalid values being compared. VM Codegen doesn't suffer from this.
|
||||
// NOTE: sometimes this increases code size because additional stores/loads are generated for the
|
||||
// intermediate variables. We assume these are optimized away from the resulting assembly code later.
|
||||
val simplify = simplifyConditionalExpression(binExpr)
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
if(simplify.rightVarAssignment!=null) {
|
||||
modifications += IAstModification.ReplaceNode(binExpr.right, simplify.rightOperandReplacement!!, binExpr)
|
||||
modifications += IAstModification.InsertBefore(
|
||||
ifElse,
|
||||
simplify.rightVarAssignment,
|
||||
parent as IStatementContainer
|
||||
)
|
||||
}
|
||||
if(simplify.leftVarAssignment!=null) {
|
||||
modifications += IAstModification.ReplaceNode(binExpr.left, simplify.leftOperandReplacement!!, binExpr)
|
||||
modifications += IAstModification.InsertBefore(
|
||||
ifElse,
|
||||
simplify.leftVarAssignment,
|
||||
parent as IStatementContainer
|
||||
)
|
||||
}
|
||||
|
||||
return modifications
|
||||
}
|
||||
|
||||
private class CondExprSimplificationResult(
|
||||
val leftVarAssignment: Assignment?,
|
||||
val leftOperandReplacement: Expression?,
|
||||
val rightVarAssignment: Assignment?,
|
||||
val rightOperandReplacement: Expression?
|
||||
)
|
||||
|
||||
private fun simplifyConditionalExpression(expr: BinaryExpression): CondExprSimplificationResult {
|
||||
|
||||
// TODO: somehow figure out if the expr will result in stack-evaluation STILL after being split off,
|
||||
// in that case: do *not* split it off but just keep it as it is (otherwise code size increases)
|
||||
// NOTE: do NOT move this to an earler ast transform phase (such as StatementReorderer or StatementOptimizer) - it WILL result in larger code.
|
||||
|
||||
if(compTarget.name == VMTarget.NAME) // don't apply this optimization for Vm target
|
||||
return CondExprSimplificationResult(null, null, null, null)
|
||||
|
||||
var leftAssignment: Assignment? = null
|
||||
var leftOperandReplacement: Expression? = null
|
||||
var rightAssignment: Assignment? = null
|
||||
var rightOperandReplacement: Expression? = null
|
||||
|
||||
val separateLeftExpr = !expr.left.isSimple
|
||||
&& expr.left !is IFunctionCall
|
||||
&& expr.left !is ContainmentCheck
|
||||
val separateRightExpr = !expr.right.isSimple
|
||||
&& expr.right !is IFunctionCall
|
||||
&& expr.right !is ContainmentCheck
|
||||
val leftDt = expr.left.inferType(program)
|
||||
val rightDt = expr.right.inferType(program)
|
||||
|
||||
if(!leftDt.isInteger || !rightDt.isInteger) {
|
||||
// we can't reasonably simplify non-integer expressions
|
||||
return CondExprSimplificationResult(null, null, null, null)
|
||||
}
|
||||
|
||||
if(separateLeftExpr) {
|
||||
val name = getTempRegisterName(leftDt)
|
||||
leftOperandReplacement = IdentifierReference(name, expr.position)
|
||||
leftAssignment = Assignment(
|
||||
AssignTarget(IdentifierReference(name, expr.position), null, null, expr.position),
|
||||
expr.left.copy(),
|
||||
AssignmentOrigin.BEFOREASMGEN, expr.position
|
||||
)
|
||||
}
|
||||
if(separateRightExpr) {
|
||||
val (tempVarName, _) = program.getTempVar(rightDt.getOrElse { throw FatalAstException("invalid dt") }, true)
|
||||
rightOperandReplacement = IdentifierReference(tempVarName, expr.position)
|
||||
rightAssignment = Assignment(
|
||||
AssignTarget(IdentifierReference(tempVarName, expr.position), null, null, expr.position),
|
||||
expr.right.copy(),
|
||||
AssignmentOrigin.BEFOREASMGEN, expr.position
|
||||
)
|
||||
}
|
||||
return CondExprSimplificationResult(
|
||||
leftAssignment, leftOperandReplacement,
|
||||
rightAssignment, rightOperandReplacement
|
||||
)
|
||||
}
|
||||
|
||||
fun getTempRegisterName(dt: InferredTypes.InferredType): List<String> {
|
||||
return when {
|
||||
// TODO assume (hope) cx16.r9 isn't used for anything else during the use of this temporary variable...
|
||||
dt istype DataType.UBYTE -> listOf("cx16", "r9L")
|
||||
dt istype DataType.BOOL -> listOf("cx16", "r9L")
|
||||
dt istype DataType.BYTE -> listOf("cx16", "r9sL")
|
||||
dt istype DataType.UWORD -> listOf("cx16", "r9")
|
||||
dt istype DataType.WORD -> listOf("cx16", "r9s")
|
||||
dt.isPassByReference -> listOf("cx16", "r9")
|
||||
else -> throw FatalAstException("invalid dt $dt")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.BinaryExpression
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.expressions.PrefixExpression
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.code.core.IntegerDatatypes
|
||||
|
||||
internal class NotExpressionChanger(val program: Program, val errors: IErrorReporter) : AstWalker() {
|
||||
|
||||
override fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator=="==" || expr.operator=="!=") {
|
||||
val left = expr.left as? BinaryExpression
|
||||
if (left != null) {
|
||||
val rightValue = expr.right.constValue(program)
|
||||
if (rightValue?.number == 0.0 && rightValue.type in IntegerDatatypes) {
|
||||
if (left.operator == "==" && expr.operator == "==") {
|
||||
// (x==something)==0 --> x!=something
|
||||
left.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "!=" && expr.operator == "==") {
|
||||
// (x!=something)==0 --> x==something
|
||||
left.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "==" && expr.operator == "!=") {
|
||||
// (x==something)!=0 --> x==something
|
||||
left.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "!=" && expr.operator == "!=") {
|
||||
// (x!=something)!=0 --> x!=something
|
||||
left.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator == "not") {
|
||||
// not(not(x)) -> x
|
||||
if((expr.expression as? PrefixExpression)?.operator=="not")
|
||||
return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent))
|
||||
// not(~x) -> x!=0
|
||||
if((expr.expression as? PrefixExpression)?.operator=="~") {
|
||||
val x = (expr.expression as PrefixExpression).expression
|
||||
val dt = x.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||
val notZero = BinaryExpression(x, "!=", NumericLiteral(dt, 0.0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, notZero, parent))
|
||||
}
|
||||
val subBinExpr = expr.expression as? BinaryExpression
|
||||
if(subBinExpr?.operator=="==") {
|
||||
if(subBinExpr.right.constValue(program)?.number==0.0) {
|
||||
// not(x==0) -> x!=0
|
||||
subBinExpr.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
|
||||
}
|
||||
} else if(subBinExpr?.operator=="!=") {
|
||||
if(subBinExpr.right.constValue(program)?.number==0.0) {
|
||||
// not(x!=0) -> x==0
|
||||
subBinExpr.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
|
||||
}
|
||||
}
|
||||
|
||||
// all other not(x) --> x==0
|
||||
// this means that "not" will never occur anywhere again in the ast after this
|
||||
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(DataType.UBYTE,0.0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
}
|
@ -36,12 +36,13 @@ internal class SymbolTableMaker: IAstVisitor {
|
||||
}
|
||||
|
||||
override fun visit(subroutine: Subroutine) {
|
||||
val parameters = subroutine.parameters.map { StSubroutineParameter(it.name, it.type) }
|
||||
if(subroutine.asmAddress!=null) {
|
||||
val node = StRomSub(subroutine.name, subroutine.asmAddress!!, parameters, subroutine.returntypes, subroutine.position)
|
||||
val parameters = subroutine.parameters.zip(subroutine.asmParameterRegisters).map { StRomSubParameter(it.second, it.first.type) }
|
||||
val node = StRomSub(subroutine.name, subroutine.asmAddress!!, parameters, subroutine.asmParameterRegisters, subroutine.position)
|
||||
scopestack.peek().add(node)
|
||||
// st.origAstLinks[subroutine] = node
|
||||
} else {
|
||||
val parameters = subroutine.parameters.map { StSubroutineParameter(it.name, it.type) }
|
||||
val returnType = if(subroutine.returntypes.isEmpty()) null else subroutine.returntypes.first()
|
||||
val node = StSub(subroutine.name, parameters, returnType, subroutine.position)
|
||||
scopestack.peek().add(node)
|
||||
@ -103,4 +104,16 @@ internal class SymbolTableMaker: IAstVisitor {
|
||||
scopestack.peek().add(node)
|
||||
// st.origAstLinks[label] = node
|
||||
}
|
||||
|
||||
override fun visit(fcall: BuiltinFunctionCall) {
|
||||
if(fcall.name=="memory") {
|
||||
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
|
||||
val name = (fcall.args[0] as StringLiteral).value
|
||||
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||
val size = (fcall.args[1] as NumericLiteral).number.toUInt()
|
||||
val align = (fcall.args[2] as NumericLiteral).number.toUInt()
|
||||
st.add(StMemorySlab("prog8_memoryslab_$name", size, align, fcall.position))
|
||||
}
|
||||
super.visit(fcall)
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,7 @@ package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.expressions.FunctionCallExpression
|
||||
import prog8.ast.expressions.TypecastExpression
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.code.core.DataType
|
||||
@ -14,16 +12,43 @@ import prog8.compiler.BuiltinFunctions
|
||||
|
||||
internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorReporter) : IAstVisitor {
|
||||
|
||||
override fun visit(program: Program) {
|
||||
super.visit(program)
|
||||
|
||||
// detect invalid (double) memory slabs
|
||||
for(slab in memorySlabs) {
|
||||
val other = memorySlabs.first { it.name==slab.name }
|
||||
if(other!==slab && (other.size!=slab.size || other.align!=slab.align)) {
|
||||
errors.err("memory block '${slab.name}' already exists with a different size and/or alignment at ${other.position}", slab.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Slab(val name: String, val size: Int, val align: Int, val position: Position)
|
||||
private val memorySlabs = mutableListOf<Slab>()
|
||||
|
||||
override fun visit(functionCallExpr: FunctionCallExpression) {
|
||||
val error = checkTypes(functionCallExpr as IFunctionCall, program)
|
||||
if(error!=null)
|
||||
errors.err(error.first, error.second)
|
||||
else {
|
||||
if(functionCallExpr.target.nameInSource==listOf("memory")) {
|
||||
val name = (functionCallExpr.args[0] as StringLiteral).value
|
||||
val size = (functionCallExpr.args[1] as NumericLiteral).number.toInt()
|
||||
val align = (functionCallExpr.args[2] as NumericLiteral).number.toInt()
|
||||
memorySlabs.add(Slab(name, size, align, functionCallExpr.position))
|
||||
}
|
||||
}
|
||||
|
||||
super.visit(functionCallExpr)
|
||||
}
|
||||
|
||||
override fun visit(functionCallStatement: FunctionCallStatement) {
|
||||
val error = checkTypes(functionCallStatement as IFunctionCall, program)
|
||||
if(error!=null)
|
||||
errors.err(error.first, error.second)
|
||||
|
||||
super.visit(functionCallStatement)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -3,18 +3,16 @@ package prog8tests
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.*
|
||||
import prog8.compiler.CompilationResult
|
||||
import prog8.compiler.CompilerArguments
|
||||
import prog8.compiler.compileProgram
|
||||
import prog8tests.helpers.assumeDirectory
|
||||
import prog8tests.helpers.cartesianProduct
|
||||
import prog8tests.helpers.outputDir
|
||||
import prog8tests.helpers.workingDir
|
||||
import prog8tests.helpers.*
|
||||
import prog8tests.helpers.compileText
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.readText
|
||||
|
||||
|
||||
/**
|
||||
@ -36,6 +34,7 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||
quietAssembler = true,
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
keepIR = false,
|
||||
compilationTarget = target.name,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
@ -46,8 +45,11 @@ private fun compileTheThing(filepath: Path, optimize: Boolean, target: ICompilat
|
||||
|
||||
private fun prepareTestFiles(source: String, optimize: Boolean, target: ICompilationTarget): Pair<String, Path> {
|
||||
val searchIn = mutableListOf(examplesDir)
|
||||
if (target is Cx16Target) {
|
||||
searchIn.add(0, assumeDirectory(examplesDir, "cx16"))
|
||||
when (target) {
|
||||
is Cx16Target -> searchIn.add(0, assumeDirectory(examplesDir, "cx16"))
|
||||
is VMTarget -> searchIn.add(0, assumeDirectory(examplesDir, "vm"))
|
||||
is C128Target -> searchIn.add(0, assumeDirectory(examplesDir, "c128"))
|
||||
is AtariTarget -> searchIn.add(0, assumeDirectory(examplesDir, "atari"))
|
||||
}
|
||||
val filepath = searchIn.asSequence()
|
||||
.map { it.resolve("$source.p8") }
|
||||
@ -70,6 +72,7 @@ class TestCompilerOnExamplesC64: FunSpec({
|
||||
"cube3d-sprites",
|
||||
"plasma",
|
||||
"sprites",
|
||||
"starfield",
|
||||
"turtle-gfx",
|
||||
"wizzine",
|
||||
),
|
||||
@ -166,3 +169,24 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class TestCompilerOnExamplesVirtual: FunSpec({
|
||||
|
||||
val onlyVirtual = listOf(
|
||||
"bouncegfx",
|
||||
"bsieve",
|
||||
"pixelshader",
|
||||
"sincos",
|
||||
"textelite"
|
||||
)
|
||||
|
||||
onlyVirtual.forEach {
|
||||
val target = VMTarget()
|
||||
val (displayName, filepath) = prepareTestFiles(it, false, target)
|
||||
test(displayName) {
|
||||
val src = filepath.readText()
|
||||
compileText(target, false, src, writeAssembly = true, keepIR=false) shouldNotBe null
|
||||
compileText(target, false, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -50,6 +50,7 @@ class TestCompilerOptionSourcedirs: FunSpec({
|
||||
quietAssembler = true,
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
keepIR = false,
|
||||
compilationTarget = Cx16Target.NAME,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
|
37
compiler/test/TestLaunchEmu.kt
Normal file
37
compiler/test/TestLaunchEmu.kt
Normal file
@ -0,0 +1,37 @@
|
||||
package prog8tests
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import prog8.code.target.VMTarget
|
||||
import kotlin.io.path.deleteExisting
|
||||
import kotlin.io.path.writeText
|
||||
|
||||
|
||||
class TestLaunchEmu: FunSpec({
|
||||
|
||||
test("test launch virtualmachine via target") {
|
||||
val target = VMTarget()
|
||||
val tmpfile = kotlin.io.path.createTempFile(suffix=".p8ir")
|
||||
tmpfile.writeText("""<PROGRAM NAME=test>
|
||||
<OPTIONS>
|
||||
</OPTIONS>
|
||||
|
||||
<VARIABLES>
|
||||
</VARIABLES>
|
||||
|
||||
<MEMORYMAPPEDVARIABLES>
|
||||
</MEMORYMAPPEDVARIABLES>
|
||||
|
||||
<MEMORYSLABS>
|
||||
</MEMORYSLABS>
|
||||
|
||||
<INITGLOBALS>
|
||||
</INITGLOBALS>
|
||||
|
||||
<BLOCK NAME=main ADDRESS=null ALIGN=NONE POS=[unittest: line 42 col 1-9]>
|
||||
</BLOCK>
|
||||
</PROGRAM>
|
||||
""")
|
||||
target.machine.launchEmulator(0, tmpfile)
|
||||
tmpfile.deleteExisting()
|
||||
}
|
||||
})
|
@ -14,7 +14,6 @@ import prog8.ast.statements.VarDecl
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
import prog8tests.helpers.compileText
|
||||
|
||||
@ -31,7 +30,7 @@ class TestTypecasts: FunSpec({
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
val result = compileText(VMTarget(), false, text, writeAssembly = false, errors=errors)
|
||||
val result = compileText(C64Target(), false, text, writeAssembly = false, errors=errors)
|
||||
result shouldBe null
|
||||
errors.errors.size shouldBe 1
|
||||
errors.errors[0] shouldContain "type mismatch, was: FLOAT expected one of: [UBYTE, BYTE, UWORD, WORD]"
|
||||
@ -627,9 +626,9 @@ main {
|
||||
ubyte @shared wordNr2 = (interlaced >= ${'$'}33) + (interlaced >= ${'$'}66) + (interlaced >= ${'$'}99) + (interlaced >= ${'$'}CC)
|
||||
}
|
||||
}"""
|
||||
val result = compileText(VMTarget(), false, text, writeAssembly = true)!!
|
||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||
val stmts = result.program.entrypoint.statements
|
||||
stmts.size shouldBe 14
|
||||
stmts.size shouldBeGreaterThan 10
|
||||
}
|
||||
|
||||
test("word to byte casts") {
|
||||
|
@ -7,7 +7,7 @@ import io.kotest.matchers.shouldBe
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.compiler.IntermediateAstMaker
|
||||
import prog8.compiler.astprocessing.IntermediateAstMaker
|
||||
import prog8tests.helpers.compileText
|
||||
|
||||
class TestIntermediateAst: FunSpec({
|
||||
|
@ -1,15 +1,10 @@
|
||||
package prog8tests.helpers
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.c64.C64Zeropage
|
||||
import prog8.codegen.cpu6502.AsmGen
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.compiler.CompilationResult
|
||||
import prog8.compiler.CompilerArguments
|
||||
import prog8.compiler.astprocessing.SymbolTableMaker
|
||||
import prog8.compiler.compileProgram
|
||||
import prog8.compiler.determineProgramLoadAddress
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.name
|
||||
|
||||
@ -22,6 +17,7 @@ internal fun compileFile(
|
||||
outputDir: Path = prog8tests.helpers.outputDir,
|
||||
errors: IErrorReporter? = null,
|
||||
writeAssembly: Boolean = true,
|
||||
keepIR: Boolean = true,
|
||||
optFloatExpr: Boolean = true
|
||||
) : CompilationResult? {
|
||||
val filepath = fileDir.resolve(fileName)
|
||||
@ -36,6 +32,7 @@ internal fun compileFile(
|
||||
quietAssembler = true,
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false,
|
||||
keepIR = keepIR,
|
||||
platform.name,
|
||||
evalStackBaseAddress = null,
|
||||
symbolDefs = emptyMap(),
|
||||
@ -56,30 +53,12 @@ internal fun compileText(
|
||||
sourceText: String,
|
||||
errors: IErrorReporter? = null,
|
||||
writeAssembly: Boolean = true,
|
||||
keepIR: Boolean = true,
|
||||
optFloatExpr: Boolean = true
|
||||
) : CompilationResult? {
|
||||
val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8")
|
||||
// we don't assumeNotExists(filePath) - should be ok to just overwrite it
|
||||
filePath.toFile().writeText(sourceText)
|
||||
return compileFile(platform, optimize, filePath.parent, filePath.name, errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr)
|
||||
}
|
||||
|
||||
|
||||
internal fun generateAssembly(
|
||||
program: Program,
|
||||
options: CompilationOptions? = null
|
||||
): IAssemblyProgram? {
|
||||
val coptions = options ?: CompilationOptions(OutputType.RAW, CbmPrgLauncherType.BASIC, ZeropageType.DONTUSE, emptyList(),
|
||||
floats = true,
|
||||
noSysInit = true,
|
||||
compTarget = C64Target(),
|
||||
loadAddress = 0u, outputDir = outputDir)
|
||||
coptions.compTarget.machine.zeropage = C64Zeropage(coptions)
|
||||
val st = SymbolTableMaker().makeFrom(program)
|
||||
val errors = ErrorReporterForTests()
|
||||
determineProgramLoadAddress(program, coptions, errors)
|
||||
errors.report()
|
||||
val asmgen = AsmGen(program, st, coptions, errors)
|
||||
errors.report()
|
||||
return asmgen.compileToAssembly()
|
||||
return compileFile(platform, optimize, filePath.parent, filePath.name,
|
||||
errors=errors, writeAssembly=writeAssembly, optFloatExpr = optFloatExpr, keepIR=keepIR)
|
||||
}
|
||||
|
163
compiler/test/vm/TestCompilerVirtual.kt
Normal file
163
compiler/test/vm/TestCompilerVirtual.kt
Normal file
@ -0,0 +1,163 @@
|
||||
package prog8tests.vm
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import prog8.ast.expressions.BuiltinFunctionCall
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.code.target.Cx16Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8.vm.VmRunner
|
||||
import prog8tests.helpers.compileText
|
||||
import kotlin.io.path.readText
|
||||
|
||||
class TestCompilerVirtual: FunSpec({
|
||||
test("compile virtual: any all sort reverse builtin funcs") {
|
||||
val src = """
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
uword[] words = [1111,2222,0,4444,3333]
|
||||
ubyte result = all(words)
|
||||
result++
|
||||
result = any(words)
|
||||
result++
|
||||
sort(words)
|
||||
reverse(words)
|
||||
}
|
||||
}"""
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: array with pointers") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
str localstr = "hello"
|
||||
ubyte[] otherarray = [1,2,3]
|
||||
uword[] words = [1111,2222,"three",&localstr,&otherarray]
|
||||
uword @shared zz = &words
|
||||
ubyte result = 2222 in words
|
||||
zz = words[2]
|
||||
zz++
|
||||
zz = words[3]
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: str args and return type") {
|
||||
val src = """
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
sub testsub(str s1) -> str {
|
||||
return "result"
|
||||
}
|
||||
|
||||
uword result = testsub("arg")
|
||||
}
|
||||
}"""
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("compile virtual: nested labels") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
uword i
|
||||
uword k
|
||||
|
||||
while k <= 10 {
|
||||
k++
|
||||
}
|
||||
|
||||
mylabel_outside:
|
||||
for i in 0 to 10 {
|
||||
mylabel_inside:
|
||||
if i==100 {
|
||||
goto mylabel_outside
|
||||
goto mylabel_inside
|
||||
}
|
||||
while k <= 10 {
|
||||
k++
|
||||
}
|
||||
do {
|
||||
k--
|
||||
} until k==0
|
||||
for k in 0 to 5 {
|
||||
i++
|
||||
}
|
||||
repeat 10 {
|
||||
k++
|
||||
}
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||
VmRunner().runProgram(virtfile.readText())
|
||||
}
|
||||
|
||||
test("case sensitive symbols") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte bytevar = 11 ; var at 0
|
||||
ubyte byteVAR = 22 ; var at 1
|
||||
ubyte ByteVar = 33 ; var at 2
|
||||
ubyte @shared total = bytevar+byteVAR+ByteVar ; var at 3
|
||||
goto skipLABEL
|
||||
SkipLabel:
|
||||
return
|
||||
skipLABEL:
|
||||
bytevar = 42
|
||||
}
|
||||
}"""
|
||||
val othertarget = Cx16Target()
|
||||
compileText(othertarget, true, src, writeAssembly = true, keepIR=true) shouldNotBe null
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||
vm.memory.getUB(0) shouldBe 42u
|
||||
vm.memory.getUB(3) shouldBe 66u
|
||||
}
|
||||
}
|
||||
|
||||
test("memory slabs") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
uword slab1 = memory("slab1", 2000, 64)
|
||||
slab1[10]=42
|
||||
slab1[11]=43
|
||||
ubyte @shared value1 = slab1[10] ; var at 2
|
||||
ubyte @shared value2 = slab1[11] ; var at 3
|
||||
}
|
||||
}"""
|
||||
val target = VMTarget()
|
||||
val result = compileText(target, true, src, writeAssembly = true)!!
|
||||
val start = result.program.entrypoint
|
||||
start.statements.size shouldBe 9
|
||||
((start.statements[1] as Assignment).value as BuiltinFunctionCall).name shouldBe "memory"
|
||||
val virtfile = result.compilationOptions.outputDir.resolve(result.program.name + ".p8ir")
|
||||
VmRunner().runAndTestProgram(virtfile.readText()) { vm ->
|
||||
vm.memory.getUB(2) shouldBe 42u
|
||||
vm.memory.getUB(3) shouldBe 43u
|
||||
}
|
||||
}
|
||||
})
|
@ -8,7 +8,7 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.code.core.*
|
||||
import prog8.parser.Prog8ANTLRParser
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ private data class NumericLiteralNode(val number: Double, val datatype: DataType
|
||||
private fun ParserRuleContext.toPosition() : Position {
|
||||
val pathString = start.inputStream.sourceName
|
||||
val filename = if(SourceCode.isRegularFilesystemPath(pathString)) {
|
||||
val path = Path.of(pathString)
|
||||
val path = Path(pathString)
|
||||
if(path.isRegularFile()) {
|
||||
SourceCode.relative(path).toString()
|
||||
} else {
|
||||
|
@ -1,2 +1,2 @@
|
||||
sphinx>=4.0
|
||||
sphinx_rtd_theme==1.0.0
|
||||
sphinx>=4.4.0, !=5.2.0.post0 # https://github.com/sphinx-doc/sphinx/issues/10860
|
||||
sphinx_rtd_theme>=1.0.0
|
||||
|
BIN
docs/source/_static/antlrparser.png
Normal file
BIN
docs/source/_static/antlrparser.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
@ -35,18 +35,29 @@ The most interesting gradle commands to run are probably:
|
||||
Creates a zipfile with the above in it, for easy distribution.
|
||||
This file can be found in ``./compiler/build/distributions/``
|
||||
|
||||
For normal use, the ``installDist`` target should suffice and after succesful completion, you can start the compiler with:
|
||||
For normal use, the ``installDist`` task should suffice and after succesful completion, you can start the compiler with:
|
||||
|
||||
``./compiler/build/install/p8compile/bin/p8compile <options> <sourcefile>``
|
||||
|
||||
(You should probably make an alias...)
|
||||
(You should probably make an alias or link...)
|
||||
|
||||
.. hint::
|
||||
Development and testing is done on Linux using the IntelliJ IDEA IDE,
|
||||
but the compiler should run on most operating systems that provide a fairly modern
|
||||
java runtime (11 or newer). If you do have trouble building or running the compiler on your
|
||||
operating system, please let me know!
|
||||
but the compiler should run on all operating systems that provide a java runtime (version 11 or newer).
|
||||
If you do have trouble building or running the compiler on your operating system, please let me know!
|
||||
|
||||
To successfully build and debug in IDEA, you have to manually generate the Antlr-parser classes first.
|
||||
The easiest way to do this is the following:
|
||||
|
||||
1. make sure you have the Antlr4 plugin installed in IDEA
|
||||
2. right click the grammar file Prog8ANTLR.g4 in the parser project, and choose "Generate Antlr Recognizer" from the menu.
|
||||
3. rebuild the full project.
|
||||
|
||||
Alternatively you can also use the Makefile in the antlr directory to generate the parser, but for development the
|
||||
Antlr4 plugin provides several extremely handy features so you'll probably want to have it installed anyway.
|
||||
|
||||
.. image:: _static/antlrparser.png
|
||||
:alt: Generating the Antlr4 parser files
|
||||
|
||||
|
||||
What is a Prog8 "Program" anyway?
|
||||
@ -98,9 +109,10 @@ One or more .p8 module files
|
||||
Prints short command line usage information.
|
||||
|
||||
``-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, atari = Atari 800 XL
|
||||
Default = c64
|
||||
Sets the target output of the compiler.
|
||||
``c64`` = Commodore 64, ``c128`` = Commodore 128, ``cx16`` = Commander X16, ``atari`` = Atari 800 XL,
|
||||
``virtual`` = builtin virtual machine.
|
||||
Default = ``c64``.
|
||||
|
||||
``-srcdirs <pathlist>``
|
||||
Specify a list of extra paths (separated with ':'), to search in for imported modules.
|
||||
@ -154,11 +166,14 @@ One or more .p8 module files
|
||||
``-asmlist``
|
||||
Generate an assembler listing file as well.
|
||||
|
||||
``-keepIR``
|
||||
Keep the IR code in a file (for targets that use it).
|
||||
|
||||
``-expericodegen``
|
||||
Use experimental code generation backend (*incomplete*).
|
||||
|
||||
``-vm``
|
||||
load and run a p8-virt listing in the internal VirtualMachine instead of compiling a prog8 program file..
|
||||
load and run a p8-virt or p8-ir listing in the internal VirtualMachine instead of compiling a prog8 program file..
|
||||
|
||||
``-D SYMBOLNAME=VALUE``
|
||||
Add this user-defined symbol directly to the beginning of the generated assembly file.
|
||||
|
@ -20,7 +20,7 @@ import os
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'Prog8'
|
||||
copyright = '2021, Irmen de Jong'
|
||||
copyright = 'Irmen de Jong'
|
||||
author = 'Irmen de Jong'
|
||||
|
||||
|
||||
|
@ -191,6 +191,12 @@ Provides string manipulation routines.
|
||||
``upper(string)``
|
||||
Uppercases the petscii-string in place.
|
||||
|
||||
``lowerchar(char)``
|
||||
Returns lowercased character.
|
||||
|
||||
``upperchar(char)``
|
||||
Returns uppercased character.
|
||||
|
||||
``startswith(string, prefix) -> bool``
|
||||
Returns true if string starts with prefix, otherwise false
|
||||
|
||||
@ -273,7 +279,7 @@ math
|
||||
Low level math routines. You should not normally have to bother with this directly.
|
||||
The compiler needs it to implement most of the math operations in your programs.
|
||||
|
||||
However there's a bunch of integer trig functions in here too that use lookup tables
|
||||
However there's a bunch of 8-bit integer trig functions in here too that use lookup tables
|
||||
to quickly calculate sine and cosines. Usually a custom lookup table is the way to go if your
|
||||
application needs this, but perhaps the provided ones can be of service too:
|
||||
|
||||
@ -283,12 +289,6 @@ sin8u(x)
|
||||
sin8(x)
|
||||
Fast 8-bit byte sine of angle 0..255, result is in range -127..127
|
||||
|
||||
sin16u(x)
|
||||
Fast 16-bit uword sine of angle 0..255, result is in range 0..65535
|
||||
|
||||
sin16(x)
|
||||
Fast 16-bit word sine of angle 0..255, result is in range -32767..32767
|
||||
|
||||
sinr8u(x)
|
||||
Fast 8-bit ubyte sine of angle 0..179 (each is a 2 degree step), result is in range 0..255
|
||||
Angles 180..255 will yield a garbage result!
|
||||
@ -297,27 +297,12 @@ sinr8(x)
|
||||
Fast 8-bit byte sine of angle 0..179 (each is a 2 degree step), result is in range -127..127
|
||||
Angles 180..255 will yield a garbage result!
|
||||
|
||||
sinr16u(x)
|
||||
Fast 16-bit uword sine of angle 0..179 (each is a 2 degree step), result is in range 0..65535
|
||||
Angles 180..255 will yield a garbage result!
|
||||
|
||||
sinr16(x)
|
||||
Fast 16-bit word sine of angle 0..179 (each is a 2 degree step), result is in range -32767..32767
|
||||
Angles 180..255 will yield a garbage result!
|
||||
|
||||
|
||||
cos8u(x)
|
||||
Fast 8-bit ubyte cosine of angle 0..255, result is in range 0..255
|
||||
|
||||
cos8(x)
|
||||
Fast 8-bit byte cosine of angle 0..255, result is in range -127..127
|
||||
|
||||
cos16u(x)
|
||||
Fast 16-bit uword cosine of angle 0..255, result is in range 0..65535
|
||||
|
||||
cos16(x)
|
||||
Fast 16-bit word cosine of angle 0..255, result is in range -32767..32767
|
||||
|
||||
cosr8u(x)
|
||||
Fast 8-bit ubyte cosine of angle 0..179 (each is a 2 degree step), result is in range 0..255
|
||||
Angles 180..255 will yield a garbage result!
|
||||
@ -326,14 +311,6 @@ cosr8(x)
|
||||
Fast 8-bit byte cosine of angle 0..179 (each is a 2 degree step), result is in range -127..127
|
||||
Angles 180..255 will yield a garbage result!
|
||||
|
||||
cosr16u(x)
|
||||
Fast 16-bit uword cosine of angle 0..179 (each is a 2 degree step), result is in range 0..65535
|
||||
Angles 180..255 will yield a garbage result!
|
||||
|
||||
cosr16(x)
|
||||
Fast 16-bit word cosine of angle 0..179 (each is a 2 degree step), result is in range -32767..32767
|
||||
Angles 180..255 will yield a garbage result!
|
||||
|
||||
|
||||
cx16logo
|
||||
--------
|
||||
|
BIN
docs/source/prog8compiler.odg
Normal file
BIN
docs/source/prog8compiler.odg
Normal file
Binary file not shown.
496
docs/source/prog8compiler.svg
Normal file
496
docs/source/prog8compiler.svg
Normal file
@ -0,0 +1,496 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.2" width="215.9mm" height="210mm" viewBox="0 0 21590 21000" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
|
||||
<defs class="ClipPathGroup">
|
||||
<clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="0" y="0" width="21590" height="21000"/>
|
||||
</clipPath>
|
||||
<clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="21" y="21" width="21547" height="20958"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_1" horiz-adv-x="2048">
|
||||
<font-face font-family="Bitstream Vera Sans Mono embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1879" descent="476"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="821" d="M 1155,889 C 1116,920 1076,942 1035,956 994,970 950,977 901,977 786,977 699,941 638,869 577,797 547,693 547,557 L 547,0 362,0 362,1120 547,1120 547,901 C 578,980 625,1041 689,1084 752,1126 828,1147 915,1147 960,1147 1003,1141 1042,1130 1081,1119 1119,1101 1155,1077 L 1155,889 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="927" d="M 375,141 L 375,-426 190,-426 190,1120 375,1120 375,977 C 406,1032 447,1075 498,1104 549,1133 607,1147 674,1147 809,1147 916,1095 993,990 1070,885 1108,740 1108,555 1108,373 1069,230 992,127 915,23 809,-29 674,-29 606,-29 547,-14 496,15 445,44 404,86 375,141 Z M 915,559 C 915,702 893,809 848,882 803,955 736,991 647,991 558,991 490,955 444,882 398,809 375,701 375,559 375,418 398,310 444,237 490,164 558,127 647,127 736,127 803,163 848,236 893,309 915,416 915,559 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="980" d="M 616,991 C 523,991 452,955 404,882 356,809 332,702 332,559 332,417 356,310 404,237 452,164 523,127 616,127 710,127 781,164 829,237 877,310 901,417 901,559 901,702 877,809 829,882 781,955 710,991 616,991 Z M 616,1147 C 771,1147 890,1097 973,996 1055,895 1096,750 1096,559 1096,368 1055,222 973,122 891,21 772,-29 616,-29 461,-29 342,21 260,122 178,222 137,368 137,559 137,750 178,895 260,996 342,1097 461,1147 616,1147 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="874" d="M 639,406 C 639,323 654,261 685,219 715,177 760,156 819,156 L 1034,156 1034,0 801,0 C 691,0 606,35 546,106 485,177 455,277 455,406 L 455,1423 160,1423 160,1567 639,1567 639,406 Z"/>
|
||||
<glyph unicode="h" horiz-adv-x="874" d="M 1051,694 L 1051,0 866,0 866,694 C 866,795 848,869 813,916 778,963 722,987 647,987 561,987 495,957 449,896 402,835 379,747 379,633 L 379,0 195,0 195,1556 379,1556 379,952 C 412,1016 456,1065 512,1098 568,1131 634,1147 711,1147 825,1147 910,1110 967,1035 1023,960 1051,846 1051,694 Z"/>
|
||||
<glyph unicode="g" horiz-adv-x="953" d="M 858,569 C 858,707 836,812 791,884 746,955 680,991 594,991 504,991 435,955 388,884 341,812 317,707 317,569 317,431 341,326 389,254 436,181 505,145 596,145 681,145 746,181 791,254 836,327 858,432 858,569 Z M 1042,72 C 1042,-96 1002,-223 923,-310 844,-397 727,-440 573,-440 522,-440 469,-435 414,-426 359,-417 303,-403 248,-385 L 248,-203 C 313,-234 373,-256 426,-271 479,-286 528,-293 573,-293 672,-293 745,-266 790,-212 835,-158 858,-72 858,45 L 858,53 858,178 C 829,115 789,69 738,38 687,7 626,-8 553,-8 422,-8 318,44 240,149 162,254 123,394 123,569 123,745 162,885 240,990 318,1095 422,1147 553,1147 625,1147 686,1133 736,1104 786,1075 827,1031 858,971 L 858,1116 1042,1116 1042,72 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="1006" d="M 1112,606 L 1112,516 315,516 315,510 C 315,388 347,294 411,227 474,160 564,127 680,127 739,127 800,136 864,155 928,174 996,202 1069,240 L 1069,57 C 999,28 932,7 867,-8 802,-22 739,-29 678,-29 504,-29 368,23 270,128 172,232 123,376 123,559 123,738 171,880 267,987 363,1094 491,1147 651,1147 794,1147 906,1099 989,1002 1071,905 1112,773 1112,606 Z M 928,659 C 925,767 900,850 852,906 803,963 734,991 643,991 554,991 481,962 424,903 367,844 333,763 322,659 L 928,659 Z"/>
|
||||
<glyph unicode="8" horiz-adv-x="1006" d="M 616,709 C 526,709 457,684 408,634 359,583 334,512 334,420 334,328 359,257 409,206 458,155 527,129 616,129 707,129 777,154 826,205 875,255 899,327 899,420 899,511 874,582 825,633 775,684 705,709 616,709 Z M 440,793 C 354,815 287,856 239,916 190,976 166,1048 166,1133 166,1252 206,1346 287,1416 368,1485 477,1520 616,1520 755,1520 865,1485 946,1416 1027,1346 1067,1252 1067,1133 1067,1048 1043,976 995,916 946,856 879,815 793,793 893,771 970,727 1023,660 1076,593 1102,507 1102,401 1102,266 1059,161 973,85 887,9 768,-29 616,-29 464,-29 345,9 260,85 174,160 131,265 131,399 131,506 158,593 211,660 264,727 340,771 440,793 Z M 367,1114 C 367,1034 388,973 431,931 474,889 535,868 616,868 697,868 759,889 802,931 845,973 866,1034 866,1114 866,1195 845,1257 803,1300 760,1343 698,1364 616,1364 535,1364 474,1343 431,1300 388,1257 367,1195 367,1114 Z"/>
|
||||
<glyph unicode="." horiz-adv-x="266" d="M 489,305 L 741,305 741,0 489,0 489,305 Z"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_2" horiz-adv-x="2048">
|
||||
<font-face font-family="Droid Serif embedded" units-per-em="2048" font-weight="normal" font-style="normal" ascent="1879" descent="476"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="z" horiz-adv-x="875" d="M 696,117 C 720,117 740,122 756,131 771,140 784,153 795,168 805,183 813,201 820,222 826,242 831,263 836,285 L 846,332 932,332 922,0 86,0 86,82 680,981 360,981 C 333,981 311,978 294,971 277,964 263,953 252,939 241,925 232,908 225,887 218,866 210,842 203,815 L 201,807 115,807 135,1098 920,1098 920,1014 324,117 696,117 Z"/>
|
||||
<glyph unicode="y" horiz-adv-x="1165" d="M 1157,1098 L 1157,1012 1151,1012 C 1131,1012 1114,1010 1100,1006 1085,1001 1072,993 1061,981 1049,969 1038,953 1028,932 1018,911 1007,885 995,852 L 684,-8 C 660,-74 637,-132 616,-182 595,-232 572,-275 549,-311 526,-346 500,-376 473,-399 445,-422 413,-441 378,-455 343,-469 302,-479 256,-484 210,-489 157,-492 96,-492 L 78,-492 78,-395 C 147,-395 207,-385 257,-364 307,-343 350,-315 387,-279 423,-243 453,-200 478,-152 502,-102 522,-49 539,8 L 160,903 C 151,924 142,942 133,956 124,969 115,980 104,989 93,998 80,1004 66,1007 51,1010 34,1012 14,1012 L 8,1012 8,1098 500,1098 500,1012 494,1012 C 453,1012 422,1004 402,988 381,972 371,947 371,913 371,902 372,890 375,879 377,867 381,853 387,838 L 537,473 C 546,450 556,424 567,397 577,369 587,342 596,315 605,288 613,262 620,238 627,214 632,193 635,176 L 641,176 C 648,206 659,243 672,286 685,329 700,375 717,424 L 854,823 C 860,840 865,856 868,871 871,886 872,900 872,911 872,946 861,972 839,988 816,1004 782,1012 737,1012 L 731,1012 731,1098 1157,1098 Z"/>
|
||||
<glyph unicode="v" horiz-adv-x="1192" d="M 8,1012 L 8,1098 520,1098 520,1012 494,1012 C 453,1012 422,1004 402,988 381,972 371,947 371,913 371,902 372,890 375,879 378,867 382,853 387,838 L 526,451 C 535,427 544,401 553,372 562,343 571,314 580,286 588,258 595,232 602,207 609,182 613,160 616,143 L 623,143 C 626,158 632,176 640,198 647,219 656,243 666,269 675,294 685,320 696,347 706,374 716,399 725,424 L 872,823 C 879,840 884,856 887,871 890,886 891,900 891,911 891,946 880,972 858,988 835,1004 801,1012 756,1012 L 741,1012 741,1098 1180,1098 1180,1012 1155,1012 C 1135,1012 1118,1010 1104,1006 1090,1001 1077,993 1066,981 1055,969 1044,953 1034,932 1023,911 1012,885 999,852 L 676,0 489,0 160,903 C 152,924 144,942 135,956 126,970 116,981 105,990 94,998 81,1004 66,1007 51,1010 34,1012 14,1012 L 8,1012 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="1245" d="M 1079,223 C 1079,193 1084,169 1093,151 1102,132 1114,118 1129,109 1144,100 1162,94 1183,91 1203,88 1224,86 1247,86 L 1253,86 1253,0 928,0 901,166 891,166 C 870,127 848,96 823,72 798,48 771,29 743,16 715,2 686,-7 655,-13 624,-17 592,-20 559,-20 505,-20 457,-12 415,3 373,18 338,42 309,75 280,108 259,149 244,200 229,251 221,311 221,381 L 221,872 C 221,902 217,926 208,945 199,963 186,977 171,987 156,997 138,1004 118,1007 97,1010 76,1012 53,1012 L 47,1012 47,1098 414,1098 414,391 C 414,346 418,307 425,272 432,237 443,208 460,184 476,160 498,142 526,130 553,117 588,111 629,111 674,111 713,119 746,135 778,151 805,174 826,203 847,232 862,266 872,307 882,348 887,393 887,442 L 887,864 C 887,896 883,922 874,942 865,961 853,976 838,987 823,997 805,1004 785,1007 764,1010 742,1012 719,1012 L 713,1012 713,1098 1079,1098 1079,223 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="663" d="M 543,88 C 568,88 590,89 611,92 632,95 653,98 674,102 L 674,12 C 665,8 654,4 640,0 626,-4 611,-7 595,-11 578,-13 561,-16 543,-18 525,-19 508,-20 492,-20 440,-20 395,-14 358,-4 321,8 290,25 266,50 242,75 224,107 213,148 201,189 195,238 195,297 L 195,981 39,981 39,1063 C 64,1063 91,1068 121,1078 150,1088 176,1105 199,1128 222,1153 241,1184 256,1219 270,1254 282,1297 293,1350 L 387,1350 387,1098 655,1098 655,981 387,981 387,291 C 387,221 401,170 430,137 458,104 496,88 543,88 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="769" d="M 430,-20 C 379,-20 332,-15 291,-7 249,3 213,16 184,35 155,53 132,76 116,103 100,130 92,161 92,197 92,224 97,247 106,266 115,284 126,298 139,309 152,320 166,327 181,332 196,336 209,338 221,338 221,302 225,268 232,237 239,206 252,178 269,155 286,131 309,112 338,99 366,85 401,78 442,78 479,78 511,83 539,92 567,101 591,113 610,130 629,146 643,166 653,189 663,212 668,237 668,264 668,289 664,311 657,330 649,348 636,365 617,381 598,397 572,413 539,430 506,447 465,466 416,487 363,510 318,533 279,555 240,576 207,600 182,625 157,650 138,679 125,712 112,744 106,782 106,827 106,874 115,915 134,951 152,987 178,1017 212,1042 246,1066 287,1084 334,1097 381,1110 434,1116 492,1116 541,1116 584,1111 621,1101 658,1091 690,1078 715,1061 740,1044 759,1024 772,1001 785,978 791,953 791,928 791,891 778,861 753,839 727,816 690,805 643,805 643,874 629,927 601,965 572,1003 528,1022 467,1022 432,1022 403,1018 378,1010 353,1002 333,991 318,976 302,961 290,944 283,924 276,904 272,882 272,858 272,832 277,810 286,791 295,772 310,754 331,738 351,722 377,707 410,692 442,677 481,660 526,641 580,618 626,596 665,574 704,552 736,528 761,502 786,476 804,447 816,414 828,381 834,344 834,301 834,248 824,201 805,161 786,121 758,88 723,61 688,34 645,13 596,0 546,-13 491,-20 430,-20 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="901" d="M 659,0 L 68,0 68,86 74,86 C 97,86 119,88 140,91 160,94 178,101 193,112 208,122 220,137 229,156 238,175 242,201 242,233 L 242,872 C 242,902 238,926 229,945 220,963 207,977 192,987 177,997 159,1004 139,1007 118,1010 97,1012 74,1012 L 68,1012 68,1098 383,1098 422,895 432,895 C 445,926 459,955 473,982 487,1009 504,1032 525,1053 545,1073 570,1089 600,1101 630,1112 668,1118 713,1118 788,1118 843,1105 880,1079 916,1053 934,1016 934,969 934,948 931,928 924,910 917,892 905,877 890,864 875,851 855,841 831,834 807,827 778,823 743,823 743,880 735,921 719,946 703,971 675,983 635,983 610,983 587,976 567,962 547,947 530,928 515,905 500,881 487,854 477,823 466,792 458,761 452,729 445,696 441,664 438,632 435,600 434,571 434,545 L 434,223 C 434,193 439,169 448,151 457,132 469,118 484,109 499,100 517,94 538,91 558,88 579,86 602,86 L 659,86 659,0 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="1139" d="M 692,987 C 639,987 594,978 559,961 523,943 494,916 473,880 452,844 437,799 428,744 419,689 414,625 414,551 414,480 419,417 428,362 437,307 452,261 474,224 495,187 524,159 560,140 595,121 640,111 694,111 739,111 778,121 810,140 841,159 867,187 888,224 908,261 923,308 932,363 941,418 946,481 946,553 946,626 941,689 932,744 923,798 908,843 888,879 867,915 841,942 809,960 776,978 737,987 692,987 Z M 1145,551 C 1145,452 1136,367 1118,295 1099,223 1072,164 1037,117 1002,70 958,36 906,14 854,-9 794,-20 727,-20 688,-20 652,-16 620,-7 588,2 559,14 534,30 508,46 485,65 466,87 446,109 429,133 414,160 L 406,160 C 407,125 409,92 410,61 411,48 411,35 412,22 412,8 412,-5 413,-17 413,-29 413,-40 414,-50 414,-59 414,-67 414,-72 L 414,-268 C 414,-298 419,-322 428,-341 437,-359 449,-373 464,-383 479,-392 497,-398 518,-402 538,-404 559,-406 582,-406 L 588,-406 588,-492 37,-492 37,-406 53,-406 C 76,-406 98,-404 119,-401 139,-398 157,-391 172,-381 187,-370 199,-355 208,-336 217,-316 221,-290 221,-258 L 221,872 C 221,902 217,926 208,945 199,963 186,977 171,987 156,997 138,1004 118,1007 97,1010 76,1012 53,1012 L 27,1012 27,1098 385,1098 406,913 414,913 C 429,944 447,973 466,998 485,1023 508,1045 533,1063 558,1080 587,1094 619,1104 651,1113 687,1118 727,1118 794,1118 854,1107 906,1085 958,1062 1002,1028 1037,982 1072,935 1099,876 1118,805 1136,734 1145,649 1145,551 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="980" d="M 1069,551 C 1069,358 1028,215 947,121 865,27 745,-20 588,-20 514,-20 448,-8 389,15 330,38 281,74 240,121 199,168 167,228 146,300 124,371 113,455 113,551 113,742 154,885 235,978 316,1071 435,1118 594,1118 668,1118 734,1107 793,1084 852,1061 902,1026 943,979 984,932 1015,873 1037,802 1058,731 1069,647 1069,551 Z M 311,551 C 311,475 316,408 326,350 336,292 352,244 375,205 397,166 426,136 462,116 497,96 541,86 592,86 643,86 687,96 722,116 757,136 786,166 808,205 830,244 846,292 856,350 865,408 870,475 870,551 870,627 865,694 855,751 845,808 829,856 807,895 785,933 756,962 721,981 685,1000 641,1010 590,1010 539,1010 495,1000 460,981 425,962 396,933 374,895 352,856 336,808 326,751 316,694 311,627 311,551 Z"/>
|
||||
<glyph unicode="n" horiz-adv-x="1218" d="M 608,86 L 608,0 57,0 57,86 74,86 C 97,86 119,88 140,91 160,94 178,101 193,112 208,122 220,137 229,156 238,175 242,201 242,233 L 242,872 C 242,902 238,926 229,945 220,963 207,977 192,987 177,997 159,1004 139,1007 118,1010 97,1012 74,1012 L 68,1012 68,1098 399,1098 426,932 436,932 C 457,970 480,1001 504,1026 527,1050 552,1069 579,1083 605,1096 633,1106 663,1111 692,1116 723,1118 756,1118 810,1118 858,1110 901,1095 943,1079 979,1055 1009,1023 1038,990 1061,949 1077,898 1092,847 1100,787 1100,717 L 1100,233 C 1100,201 1104,175 1112,156 1119,137 1130,122 1144,112 1158,101 1175,94 1194,91 1213,88 1234,86 1257,86 L 1264,86 1264,0 907,0 907,707 C 907,752 903,791 895,826 887,861 874,890 857,914 839,938 816,956 787,969 758,981 723,987 682,987 635,987 596,978 565,960 533,942 507,918 488,887 469,856 455,821 447,781 438,741 434,699 434,655 L 434,223 C 434,193 439,169 448,151 457,132 469,118 484,109 499,100 517,94 538,91 558,88 579,86 602,86 L 608,86 Z"/>
|
||||
<glyph unicode="m" horiz-adv-x="1827" d="M 608,86 L 608,0 57,0 57,86 84,86 C 107,86 129,88 148,91 167,94 184,101 198,112 212,122 223,137 231,156 238,175 242,201 242,233 L 242,872 C 242,902 238,926 230,945 222,963 211,977 197,987 183,997 166,1004 147,1007 128,1010 107,1012 84,1012 L 78,1012 78,1098 399,1098 426,932 436,932 C 457,970 478,1001 501,1026 524,1050 548,1069 574,1083 599,1096 626,1106 655,1111 683,1116 713,1118 745,1118 778,1118 810,1115 840,1108 870,1101 898,1091 924,1076 949,1061 972,1042 993,1019 1013,995 1029,966 1042,932 L 1059,932 C 1080,970 1102,1001 1126,1026 1150,1050 1176,1069 1203,1083 1230,1096 1258,1106 1288,1111 1317,1116 1348,1118 1380,1118 1432,1118 1479,1110 1520,1095 1561,1079 1596,1055 1625,1023 1654,990 1676,949 1691,898 1706,847 1714,787 1714,717 L 1714,233 C 1714,201 1718,175 1726,156 1734,137 1745,122 1759,112 1773,101 1790,94 1809,91 1828,88 1849,86 1872,86 L 1878,86 1878,0 1522,0 1522,707 C 1522,752 1518,791 1511,826 1503,861 1491,890 1474,914 1457,938 1434,956 1407,969 1380,981 1346,987 1307,987 1264,987 1229,979 1200,963 1171,946 1147,924 1129,896 1111,868 1098,836 1091,799 1083,762 1079,723 1079,682 L 1079,233 C 1079,201 1083,175 1091,156 1099,137 1110,122 1124,112 1138,101 1155,94 1174,91 1193,88 1214,86 1237,86 L 1243,86 1243,0 887,0 887,707 C 887,752 883,791 876,826 868,861 856,890 839,914 822,938 799,956 772,969 745,981 711,987 672,987 627,987 590,978 560,960 529,942 505,918 486,887 467,856 454,821 446,781 438,741 434,699 434,655 L 434,223 C 434,193 439,169 448,151 457,132 469,118 484,109 499,100 517,94 538,91 558,88 579,86 602,86 L 608,86 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="584" d="M 53,86 C 76,86 98,88 119,91 139,94 157,101 172,112 187,122 199,137 208,156 217,175 221,201 221,233 L 221,1331 C 221,1361 217,1385 208,1404 199,1422 186,1436 171,1446 156,1456 138,1463 118,1466 97,1469 76,1470 53,1470 L 27,1470 27,1556 414,1556 414,233 C 414,201 418,175 427,156 436,137 448,122 463,112 478,101 496,94 517,91 537,88 559,86 582,86 L 608,86 608,0 27,0 27,86 53,86 Z"/>
|
||||
<glyph unicode="k" horiz-adv-x="1192" d="M 694,659 L 967,254 C 1002,199 1038,158 1073,129 1108,100 1148,86 1194,86 L 1200,86 1200,0 1171,0 C 1112,0 1063,2 1025,6 986,9 953,18 925,32 897,45 871,65 848,92 825,118 799,154 770,199 L 565,520 414,408 414,223 C 414,193 419,169 428,151 437,132 449,118 464,109 479,100 497,94 518,91 538,88 559,86 582,86 L 588,86 588,0 37,0 37,86 53,86 C 76,86 98,88 119,91 139,94 157,101 172,112 187,122 199,137 208,156 217,175 221,201 221,233 L 221,1331 C 221,1361 217,1385 208,1404 199,1422 186,1436 171,1446 156,1456 138,1463 118,1466 97,1469 76,1470 53,1470 L 37,1470 37,1556 414,1556 414,766 C 414,747 414,724 413,695 412,666 411,637 410,609 409,577 407,543 406,508 L 662,788 C 684,813 702,834 717,853 731,872 742,888 751,902 760,916 766,929 769,940 772,951 774,961 774,971 774,988 766,1000 750,1005 733,1010 708,1012 674,1012 L 674,1098 1126,1098 1126,1012 C 1079,1012 1032,995 987,962 941,929 891,882 838,821 L 694,659 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="610" d="M 74,86 C 97,86 118,88 139,91 159,94 177,100 192,109 207,118 220,132 229,151 238,169 242,193 242,223 L 242,872 C 242,902 238,926 229,945 220,963 207,977 192,987 177,997 159,1004 139,1007 118,1010 97,1012 74,1012 L 68,1012 68,1098 434,1098 434,233 C 434,201 439,175 448,156 457,137 469,122 484,112 499,101 516,94 537,91 558,88 579,86 602,86 L 629,86 629,0 47,0 47,86 74,86 Z M 213,1430 C 213,1454 216,1474 222,1490 228,1506 236,1519 247,1529 258,1539 270,1546 284,1550 298,1554 313,1556 330,1556 346,1556 361,1554 375,1550 389,1546 401,1539 412,1529 422,1519 430,1506 437,1490 443,1474 446,1454 446,1430 446,1406 443,1386 437,1370 430,1354 422,1341 412,1331 401,1321 389,1314 375,1310 361,1305 346,1303 330,1303 313,1303 298,1305 284,1310 270,1314 258,1321 247,1331 236,1341 228,1354 222,1370 216,1386 213,1406 213,1430 Z"/>
|
||||
<glyph unicode="h" horiz-adv-x="1219" d="M 588,86 L 588,0 37,0 37,86 53,86 C 76,86 98,88 119,91 139,94 157,101 172,112 187,122 199,137 208,156 217,175 221,201 221,233 L 221,1331 C 221,1361 217,1385 208,1404 199,1422 186,1436 171,1446 156,1456 138,1463 118,1466 97,1469 76,1470 53,1470 L 37,1470 37,1556 414,1556 414,1106 C 414,1087 414,1068 413,1048 412,1027 411,1008 410,991 409,971 407,951 406,932 L 416,932 C 477,1056 578,1118 717,1118 775,1118 827,1110 872,1095 917,1079 954,1055 985,1023 1016,990 1039,949 1055,898 1071,847 1079,787 1079,717 L 1079,233 C 1079,201 1083,175 1091,156 1099,137 1110,122 1124,112 1138,101 1155,94 1174,91 1193,88 1214,86 1237,86 L 1243,86 1243,0 887,0 887,707 C 887,752 883,791 875,826 867,861 854,890 837,914 819,938 796,956 767,969 738,981 703,987 662,987 619,987 583,979 552,964 521,948 495,926 475,897 454,868 439,833 429,792 419,751 414,705 414,655 L 414,223 C 414,193 419,169 428,151 437,132 449,118 464,109 479,100 497,94 518,91 538,88 559,86 582,86 L 588,86 Z"/>
|
||||
<glyph unicode="g" horiz-adv-x="1060" d="M 1077,1055 C 1077,1040 1075,1027 1071,1014 1066,1001 1060,989 1051,980 1042,970 1031,962 1018,957 1004,951 988,948 969,948 969,956 968,964 966,972 964,980 961,988 956,995 951,1002 944,1007 935,1012 926,1016 915,1018 901,1018 884,1018 868,1016 854,1012 840,1008 826,1002 813,993 836,964 856,931 871,892 886,853 893,804 893,745 893,695 885,648 870,605 855,562 832,525 802,494 771,463 733,438 687,420 640,403 586,394 524,394 516,394 507,394 497,394 487,394 477,394 467,394 457,394 448,395 439,396 430,397 423,397 418,398 405,391 392,384 380,376 368,368 358,359 349,349 340,339 332,328 327,315 322,303 319,289 319,274 319,257 322,244 329,234 335,224 344,216 355,210 366,205 380,201 396,199 411,198 428,197 446,197 L 678,197 C 739,197 791,189 834,174 877,159 912,138 939,111 966,84 985,51 998,14 1010,-24 1016,-65 1016,-109 1016,-168 1005,-221 984,-268 962,-315 929,-355 884,-389 839,-421 783,-447 715,-465 646,-483 566,-492 473,-492 330,-492 224,-466 153,-413 82,-360 47,-287 47,-193 47,-153 54,-118 68,-88 82,-58 101,-32 125,-11 148,10 175,28 206,41 237,54 269,64 303,70 289,76 275,84 262,94 249,104 237,116 226,130 215,144 207,160 200,178 193,196 190,216 190,238 190,279 201,314 222,344 243,373 277,402 324,430 295,442 269,459 246,480 223,501 203,525 188,552 172,579 160,608 152,640 143,672 139,705 139,739 139,798 147,851 163,898 179,945 203,984 235,1017 267,1050 307,1075 355,1092 403,1109 459,1118 524,1118 549,1118 573,1116 597,1113 621,1109 643,1104 664,1098 684,1091 702,1084 719,1076 735,1068 748,1060 758,1051 768,1062 780,1074 793,1087 806,1100 821,1112 838,1123 855,1134 873,1143 893,1150 912,1157 933,1161 956,1161 977,1161 995,1158 1010,1153 1025,1147 1037,1139 1047,1130 1057,1120 1065,1109 1070,1096 1075,1083 1077,1069 1077,1055 Z M 213,-180 C 213,-210 217,-238 225,-264 233,-290 247,-312 267,-331 287,-350 314,-364 348,-375 382,-386 425,-391 477,-391 550,-391 611,-385 659,-373 706,-360 744,-343 772,-321 800,-299 820,-273 831,-243 842,-212 848,-179 848,-143 848,-112 844,-86 835,-66 826,-45 812,-29 795,-18 777,-6 755,2 729,7 703,12 673,14 639,14 L 438,14 C 409,14 382,12 355,7 328,2 304,-8 283,-22 262,-36 245,-56 232,-81 219,-106 213,-139 213,-180 Z M 332,745 C 332,658 347,594 376,553 405,512 452,492 518,492 551,492 580,497 603,507 626,517 644,532 659,553 674,574 684,600 691,633 697,665 700,703 700,748 700,840 686,908 658,952 630,996 583,1018 516,1018 450,1018 403,996 375,951 346,906 332,837 332,745 Z"/>
|
||||
<glyph unicode="f" horiz-adv-x="848" d="M 688,86 L 688,0 55,0 55,86 82,86 C 105,86 127,88 148,91 168,94 186,101 201,112 216,122 228,137 237,156 246,175 250,201 250,233 L 250,1001 63,1001 63,1098 250,1098 250,1200 C 250,1261 258,1315 275,1362 292,1409 316,1448 347,1480 378,1512 416,1536 461,1553 506,1569 556,1577 612,1577 665,1577 710,1574 747,1567 784,1560 813,1550 836,1537 858,1524 874,1509 884,1492 894,1475 899,1455 899,1434 899,1415 895,1399 887,1385 878,1370 867,1358 852,1349 837,1339 819,1332 799,1327 778,1322 756,1319 731,1319 731,1340 729,1360 725,1380 720,1399 713,1417 703,1432 692,1447 678,1460 661,1469 644,1478 622,1483 596,1483 567,1483 542,1477 523,1466 503,1455 487,1438 475,1416 463,1393 455,1366 450,1333 445,1300 442,1262 442,1219 L 442,1098 731,1098 731,1001 442,1001 442,233 C 442,201 447,175 456,156 465,137 477,122 492,112 507,101 524,94 545,91 566,88 587,86 610,86 L 688,86 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="900" d="M 563,1008 C 487,1008 429,977 388,916 347,854 322,764 315,645 L 786,645 C 786,699 782,748 774,793 766,838 753,876 736,908 719,940 696,965 668,982 639,999 604,1008 563,1008 Z M 588,-20 C 514,-20 448,-7 389,18 330,43 280,79 239,127 198,175 167,234 146,304 124,373 113,452 113,541 113,732 152,876 231,973 310,1070 422,1118 567,1118 633,1118 692,1108 745,1087 798,1066 842,1036 879,995 916,954 944,903 964,842 983,781 993,710 993,629 L 993,535 311,535 C 312,460 320,396 334,343 347,289 367,245 393,210 418,175 450,150 487,134 524,117 567,109 616,109 651,109 684,113 715,121 745,129 772,140 797,153 822,166 844,182 863,199 882,216 897,233 909,252 918,248 927,240 936,227 944,214 948,199 948,182 948,161 941,139 926,116 911,92 889,70 859,50 829,30 792,13 747,0 702,-13 649,-20 588,-20 Z"/>
|
||||
<glyph unicode="d" horiz-adv-x="1112" d="M 1036,225 C 1036,195 1041,171 1050,153 1059,134 1071,120 1086,110 1101,100 1119,94 1140,91 1160,88 1181,86 1204,86 L 1221,86 1221,0 874,0 852,184 844,184 C 829,153 811,125 792,100 772,75 749,53 724,36 699,18 670,4 638,-6 606,-15 570,-20 530,-20 463,-20 403,-9 351,14 299,36 255,70 220,117 185,163 158,222 140,293 122,364 113,449 113,547 113,646 122,731 140,803 158,875 185,934 220,981 255,1028 299,1062 351,1085 403,1107 463,1118 530,1118 569,1118 605,1114 637,1105 669,1096 698,1084 724,1068 749,1052 772,1033 792,1011 812,989 829,965 844,938 L 856,938 C 854,971 852,1003 850,1032 849,1057 847,1083 846,1108 845,1133 844,1151 844,1163 L 844,1331 C 844,1361 840,1385 831,1404 822,1422 809,1436 794,1446 779,1456 761,1463 741,1466 720,1469 699,1470 676,1470 L 659,1470 659,1556 1036,1556 1036,225 Z M 565,111 C 618,111 663,120 699,138 734,155 763,182 785,218 806,254 822,299 831,354 840,409 844,473 844,547 844,618 840,681 831,736 822,791 806,837 785,874 763,911 734,939 698,958 662,977 617,987 563,987 518,987 480,977 448,958 416,939 390,910 370,873 349,836 334,790 325,735 316,680 311,616 311,545 311,400 331,291 370,219 409,147 474,111 565,111 Z"/>
|
||||
<glyph unicode="c" horiz-adv-x="821" d="M 580,-20 C 512,-20 449,-9 392,12 335,33 285,66 244,111 203,156 171,215 148,286 125,357 113,442 113,543 113,652 125,744 148,818 171,891 203,950 244,995 285,1040 333,1071 389,1090 444,1109 504,1118 569,1118 612,1118 654,1114 697,1106 739,1097 777,1084 811,1067 845,1050 873,1028 894,1002 915,975 926,944 926,909 926,862 911,828 880,809 849,790 804,780 743,780 743,812 740,842 735,871 730,900 721,925 708,947 695,968 677,985 655,998 632,1010 604,1016 569,1016 530,1016 494,1009 463,994 431,979 404,954 381,918 358,882 341,834 329,773 317,712 311,636 311,545 311,400 335,291 384,220 432,149 511,113 621,113 684,113 740,126 787,153 834,180 870,214 893,256 903,248 911,237 918,224 925,211 928,195 928,176 928,153 921,129 906,106 891,83 870,62 841,43 812,24 775,9 732,-3 689,-14 638,-20 580,-20 Z"/>
|
||||
<glyph unicode="b" horiz-adv-x="1139" d="M 1145,551 C 1145,452 1136,367 1118,295 1099,223 1072,164 1037,117 1002,70 958,36 906,14 854,-9 794,-20 727,-20 688,-20 652,-16 620,-7 588,2 559,14 534,30 508,46 485,65 466,87 446,109 429,133 414,160 L 401,160 365,0 37,0 37,86 53,86 C 76,86 98,88 119,91 139,94 157,101 172,112 187,122 199,137 208,156 217,175 221,201 221,233 L 221,1331 C 221,1361 217,1385 208,1404 199,1422 186,1436 171,1446 156,1456 138,1463 118,1466 97,1469 76,1470 53,1470 L 37,1470 37,1556 414,1556 414,1180 C 414,1157 414,1130 413,1100 412,1069 411,1040 410,1012 409,980 407,947 406,913 L 414,913 C 429,944 447,973 466,998 485,1023 508,1045 533,1063 558,1080 587,1094 619,1104 651,1113 687,1118 727,1118 794,1118 854,1107 906,1085 958,1062 1002,1028 1037,982 1072,935 1099,876 1118,805 1136,734 1145,649 1145,551 Z M 692,987 C 639,987 594,978 559,961 523,943 494,916 473,880 452,844 437,799 428,744 419,689 414,625 414,551 414,480 419,417 428,362 437,307 452,261 474,224 495,187 524,159 560,140 595,121 640,111 694,111 739,111 778,121 810,140 841,159 867,187 888,224 908,261 923,308 932,363 941,418 946,481 946,553 946,626 941,689 932,744 923,798 908,843 888,879 867,915 841,942 809,960 776,978 737,987 692,987 Z"/>
|
||||
<glyph unicode="a" horiz-adv-x="1007" d="M 301,297 C 301,233 315,185 342,154 369,122 410,106 467,106 508,106 546,113 580,126 613,139 642,158 666,183 689,208 707,238 720,273 733,308 739,348 739,391 L 739,557 608,551 C 550,548 502,541 463,530 424,518 392,502 368,481 344,460 327,434 317,403 306,372 301,337 301,297 Z M 549,1016 C 510,1016 478,1011 454,1000 429,989 410,973 397,953 383,933 374,909 369,882 364,855 362,825 362,793 305,793 262,803 233,822 203,841 188,875 188,922 188,957 198,987 217,1012 236,1037 263,1057 297,1073 330,1088 369,1100 414,1107 459,1114 506,1118 557,1118 620,1118 674,1112 721,1100 768,1087 807,1067 838,1039 869,1011 893,975 909,930 924,885 932,829 932,764 L 932,233 C 932,204 934,181 939,162 944,143 951,128 961,117 971,106 984,98 1001,93 1017,88 1036,86 1059,86 L 1065,86 1065,0 788,0 756,176 739,176 C 718,147 697,121 677,97 657,73 635,52 611,35 587,18 560,4 530,-6 499,-15 463,-20 420,-20 375,-20 333,-13 294,-1 255,13 221,33 193,60 164,87 142,121 126,162 110,203 102,251 102,307 102,416 141,496 218,549 295,602 412,630 569,635 L 739,641 739,764 C 739,801 737,835 733,866 729,897 720,923 707,946 694,968 675,985 650,998 625,1010 591,1016 549,1016 Z"/>
|
||||
<glyph unicode="V" horiz-adv-x="1377" d="M 614,0 L 172,1268 C 165,1289 157,1307 148,1321 139,1335 129,1346 118,1354 107,1362 94,1368 79,1371 64,1374 47,1376 27,1376 L 0,1376 0,1462 563,1462 563,1376 516,1376 C 475,1376 444,1368 424,1353 403,1337 393,1312 393,1278 393,1267 395,1255 398,1243 401,1231 405,1217 410,1202 L 635,537 C 656,476 673,418 688,361 703,304 716,250 727,201 738,250 750,303 765,358 780,413 798,473 821,537 L 1047,1188 C 1052,1205 1057,1221 1060,1236 1063,1251 1065,1265 1065,1276 1065,1311 1054,1337 1032,1353 1009,1368 975,1376 930,1376 L 883,1376 883,1462 1382,1462 1382,1376 1343,1376 C 1323,1376 1306,1374 1292,1370 1277,1366 1264,1358 1253,1347 1241,1335 1230,1319 1220,1298 1210,1277 1199,1250 1188,1217 L 764,0 614,0 Z"/>
|
||||
<glyph unicode="T" horiz-adv-x="1192" d="M 729,233 C 729,201 734,175 743,156 752,137 764,122 779,112 794,101 811,94 832,91 853,88 874,86 897,86 L 944,86 944,0 307,0 307,86 354,86 C 377,86 398,88 419,91 439,94 457,100 472,109 487,118 500,132 509,151 518,169 522,193 522,223 L 522,1360 326,1360 C 296,1360 271,1356 251,1347 230,1338 214,1325 201,1310 188,1295 178,1277 172,1257 165,1236 161,1215 158,1192 L 147,1104 41,1104 51,1462 1204,1462 1214,1104 1108,1104 1098,1192 C 1095,1215 1091,1236 1084,1257 1077,1277 1068,1295 1055,1310 1042,1325 1026,1338 1005,1347 984,1356 959,1360 928,1360 L 729,1360 729,233 Z"/>
|
||||
<glyph unicode="S" horiz-adv-x="927" d="M 506,-20 C 439,-20 381,-13 330,1 279,15 236,35 202,60 167,85 141,115 124,151 107,186 98,225 98,268 98,309 111,343 137,368 162,393 199,406 246,406 248,363 255,322 266,283 277,244 293,209 315,179 337,149 365,125 399,107 433,89 474,80 522,80 614,80 686,102 738,147 789,191 815,255 815,338 815,375 810,408 799,437 788,466 771,492 746,517 721,541 689,564 649,587 608,609 558,632 498,657 435,683 379,711 332,741 285,770 245,803 214,840 183,876 159,916 144,961 129,1006 121,1056 121,1112 121,1171 132,1223 155,1269 177,1315 208,1354 248,1386 288,1417 335,1441 390,1458 445,1475 504,1483 569,1483 630,1483 685,1477 732,1464 779,1451 819,1434 852,1413 885,1392 910,1367 927,1340 944,1312 952,1283 952,1253 952,1209 938,1176 909,1154 880,1131 840,1120 791,1120 791,1152 787,1184 780,1215 772,1246 759,1273 741,1298 723,1322 699,1342 670,1357 641,1372 604,1380 561,1380 522,1380 487,1375 456,1364 425,1353 398,1337 377,1317 356,1296 339,1272 328,1243 317,1214 311,1182 311,1147 311,1106 316,1071 327,1040 338,1009 356,981 381,956 406,931 438,907 479,885 520,862 570,839 629,815 689,790 743,764 790,737 837,710 876,679 909,646 942,612 967,574 984,533 1001,491 1010,444 1010,391 1010,326 998,269 975,218 951,167 917,123 873,88 829,53 776,26 714,8 652,-11 583,-20 506,-20 Z"/>
|
||||
<glyph unicode="R" horiz-adv-x="1297" d="M 1135,250 C 1170,195 1203,154 1236,127 1269,100 1307,86 1350,86 L 1356,86 1356,0 1327,0 C 1263,0 1211,2 1170,7 1129,12 1094,21 1065,34 1036,47 1012,66 992,90 971,114 949,145 926,184 L 649,645 479,645 479,223 C 479,193 484,169 493,151 502,132 514,118 529,109 544,100 562,94 583,91 603,88 624,86 647,86 L 674,86 674,0 78,0 78,86 104,86 C 127,86 148,88 169,91 189,94 207,100 222,109 237,118 250,132 259,151 268,169 272,193 272,223 L 272,1237 C 272,1267 268,1291 259,1310 250,1328 237,1342 222,1352 207,1362 189,1369 169,1372 148,1375 127,1376 104,1376 L 78,1376 78,1462 629,1462 C 806,1462 938,1429 1025,1364 1112,1298 1155,1199 1155,1067 1155,1012 1146,965 1129,924 1111,883 1088,847 1059,817 1030,787 998,762 962,742 926,722 890,706 854,694 L 1135,250 Z M 479,741 L 623,741 C 683,741 733,748 773,761 813,774 845,794 869,821 893,848 910,881 921,921 931,961 936,1008 936,1061 936,1116 930,1162 919,1201 908,1239 889,1270 864,1295 839,1319 806,1337 766,1348 725,1359 676,1364 618,1364 L 479,1364 479,741 Z"/>
|
||||
<glyph unicode="P" horiz-adv-x="1112" d="M 78,0 L 78,86 104,86 C 127,86 149,88 170,91 190,94 208,101 223,112 238,122 250,137 259,156 268,175 272,201 272,233 L 272,1237 C 272,1267 268,1291 259,1310 250,1328 237,1342 222,1352 207,1362 189,1369 169,1372 148,1375 127,1376 104,1376 L 78,1376 78,1462 653,1462 C 739,1462 814,1452 877,1433 940,1413 993,1385 1034,1348 1075,1311 1106,1266 1127,1213 1147,1160 1157,1101 1157,1034 1157,973 1148,915 1129,859 1110,803 1078,754 1035,711 992,668 935,633 865,608 795,582 709,569 608,569 L 479,569 479,223 C 479,193 484,169 493,151 502,132 514,118 529,109 544,100 562,94 583,91 603,88 624,86 647,86 L 715,86 715,0 78,0 Z M 479,666 L 588,666 C 650,666 703,673 747,686 791,699 827,720 855,749 883,778 904,815 917,861 930,906 936,961 936,1026 936,1083 930,1133 919,1176 908,1218 889,1253 864,1281 839,1309 806,1330 766,1344 725,1357 676,1364 618,1364 L 479,1364 479,666 Z"/>
|
||||
<glyph unicode="O" horiz-adv-x="1297" d="M 1403,733 C 1403,620 1389,518 1361,425 1333,332 1292,253 1237,187 1182,121 1115,70 1035,34 955,-2 863,-20 760,-20 651,-20 557,-2 476,34 395,70 328,121 275,187 222,253 182,333 155,426 128,519 115,622 115,735 115,848 128,951 155,1044 182,1136 222,1215 275,1280 328,1345 396,1396 477,1432 558,1467 653,1485 762,1485 865,1485 957,1467 1036,1432 1115,1396 1182,1345 1237,1280 1292,1214 1333,1135 1361,1043 1389,950 1403,847 1403,733 Z M 342,733 C 342,632 350,541 365,462 380,382 404,315 437,260 470,205 514,163 567,134 620,105 684,90 760,90 836,90 901,105 954,134 1007,163 1050,205 1083,260 1116,315 1139,382 1154,462 1169,541 1176,632 1176,733 1176,834 1169,925 1154,1005 1139,1084 1116,1151 1083,1206 1050,1261 1007,1302 955,1331 902,1360 838,1374 762,1374 686,1374 621,1360 568,1331 515,1302 471,1261 438,1206 404,1151 380,1084 365,1005 350,925 342,834 342,733 Z"/>
|
||||
<glyph unicode="M" horiz-adv-x="1800" d="M 1298,0 L 1298,86 1305,86 C 1327,86 1347,88 1365,91 1382,94 1397,100 1410,109 1422,118 1432,131 1439,148 1446,165 1451,187 1452,215 L 1452,1309 983,0 872,0 397,1305 397,233 C 397,201 400,175 407,156 414,137 424,122 437,112 450,101 465,94 484,91 502,88 522,86 545,86 L 551,86 551,0 78,0 78,86 104,86 C 127,86 148,88 169,91 189,94 207,100 222,109 237,118 250,132 259,151 268,169 272,193 272,223 L 272,1237 C 272,1267 268,1291 259,1310 250,1328 237,1342 222,1352 207,1362 189,1369 169,1372 148,1375 127,1376 104,1376 L 78,1376 78,1462 545,1462 969,291 1389,1462 1843,1462 1843,1376 1817,1376 C 1794,1376 1772,1374 1752,1371 1731,1368 1713,1361 1698,1351 1683,1340 1671,1325 1662,1306 1653,1287 1649,1261 1649,1229 L 1649,233 C 1649,201 1653,175 1662,156 1671,137 1683,122 1698,112 1713,101 1731,94 1752,91 1772,88 1794,86 1817,86 L 1843,86 1843,0 1298,0 Z"/>
|
||||
<glyph unicode="I" horiz-adv-x="636" d="M 78,0 L 78,86 104,86 C 127,86 149,88 170,91 190,94 208,101 223,112 238,122 250,137 259,156 268,175 272,201 272,233 L 272,1229 C 272,1261 268,1287 259,1306 250,1325 238,1340 223,1351 208,1361 190,1368 170,1371 149,1374 127,1376 104,1376 L 78,1376 78,1462 674,1462 674,1376 647,1376 C 624,1376 603,1374 582,1371 561,1368 544,1361 529,1351 514,1340 502,1325 493,1306 484,1287 479,1261 479,1229 L 479,233 C 479,201 484,175 493,156 502,137 514,122 529,112 544,101 561,94 582,91 603,88 624,86 647,86 L 674,86 674,0 78,0 Z"/>
|
||||
<glyph unicode="G" horiz-adv-x="1324" d="M 821,-20 C 702,-20 599,-2 511,34 422,70 349,121 291,187 232,253 189,332 160,425 131,518 117,620 117,733 117,844 132,945 163,1037 193,1129 238,1208 299,1274 359,1340 434,1391 523,1428 612,1465 716,1483 834,1483 910,1483 976,1477 1033,1466 1089,1454 1136,1438 1174,1417 1211,1396 1239,1372 1258,1344 1277,1316 1286,1286 1286,1253 1286,1231 1281,1211 1271,1194 1261,1176 1248,1161 1231,1149 1214,1136 1194,1127 1171,1120 1148,1113 1123,1110 1096,1110 1096,1142 1091,1174 1082,1205 1073,1236 1057,1265 1036,1290 1015,1315 987,1335 952,1351 917,1366 875,1374 825,1374 738,1374 665,1360 604,1332 543,1303 493,1262 454,1208 415,1153 387,1086 370,1007 353,927 344,836 344,733 344,631 353,540 371,461 389,382 418,315 459,261 500,207 552,166 617,138 682,110 761,96 854,96 893,96 932,98 969,102 1006,106 1038,112 1067,121 L 1067,451 C 1067,481 1063,505 1054,524 1045,542 1032,556 1017,566 1002,575 984,582 964,585 943,588 922,590 899,590 L 891,590 891,676 1423,676 1423,590 1415,590 C 1396,590 1377,588 1360,585 1343,582 1328,575 1315,565 1302,554 1292,539 1285,520 1278,500 1274,474 1274,442 L 1274,74 C 1205,42 1135,18 1062,3 989,-12 909,-20 821,-20 Z"/>
|
||||
<glyph unicode="C" horiz-adv-x="1086" d="M 774,1483 C 844,1483 905,1477 957,1466 1008,1454 1051,1438 1086,1417 1120,1396 1146,1372 1163,1344 1180,1316 1188,1286 1188,1253 1188,1231 1184,1211 1175,1194 1166,1176 1153,1161 1137,1149 1121,1136 1102,1127 1081,1120 1059,1113 1035,1110 1010,1110 1010,1142 1006,1174 998,1205 989,1236 976,1265 957,1290 938,1315 913,1335 883,1351 852,1366 815,1374 770,1374 693,1374 627,1360 573,1332 519,1303 475,1262 441,1208 407,1153 382,1086 367,1007 352,927 344,836 344,733 344,642 352,558 368,482 384,406 409,341 444,287 479,232 523,190 577,160 630,130 695,115 770,115 820,115 864,120 903,130 941,139 975,152 1004,168 1033,184 1059,203 1082,224 1104,245 1124,266 1141,289 1152,282 1162,272 1169,259 1176,246 1180,230 1180,209 1180,183 1171,157 1154,130 1136,103 1109,78 1073,56 1037,34 991,16 936,2 881,-13 815,-20 739,-20 637,-20 547,-2 470,34 393,70 328,121 276,187 223,253 184,332 157,425 130,518 117,620 117,733 117,844 131,945 159,1037 187,1129 229,1208 284,1274 339,1340 407,1391 489,1428 571,1465 666,1483 774,1483 Z"/>
|
||||
<glyph unicode="B" horiz-adv-x="1165" d="M 1153,1096 C 1153,1050 1147,1010 1134,975 1121,940 1103,910 1080,884 1057,858 1031,836 1000,819 969,801 935,786 899,774 L 899,766 C 946,758 988,744 1027,725 1066,706 1099,681 1127,650 1154,619 1176,582 1191,540 1206,497 1214,449 1214,395 1214,263 1171,164 1084,99 997,33 865,0 688,0 L 78,0 78,86 104,86 C 127,86 149,88 170,91 190,94 208,101 223,112 238,122 250,137 259,156 268,175 272,201 272,233 L 272,1237 C 272,1267 268,1291 259,1310 250,1328 237,1342 222,1352 207,1362 189,1369 169,1372 148,1375 127,1376 104,1376 L 78,1376 78,1462 627,1462 C 804,1462 936,1433 1023,1374 1110,1315 1153,1222 1153,1096 Z M 479,102 L 678,102 C 736,102 785,107 825,118 865,129 898,146 923,170 948,193 967,224 978,262 989,300 995,346 995,401 995,454 990,501 980,540 970,579 953,612 929,638 904,664 872,683 832,696 792,709 742,715 682,715 L 479,715 479,102 Z M 479,817 L 621,817 C 681,817 731,822 771,833 811,844 843,860 867,883 891,905 908,934 919,969 929,1004 934,1047 934,1096 934,1146 928,1188 917,1222 906,1255 887,1282 862,1303 837,1324 804,1338 764,1347 723,1356 674,1360 616,1360 L 479,1360 479,817 Z"/>
|
||||
<glyph unicode="A" horiz-adv-x="1456" d="M 414,489 L 336,274 C 330,258 325,242 322,227 319,211 317,197 317,186 317,151 328,126 351,110 373,94 407,86 453,86 L 500,86 500,0 0,0 0,86 39,86 C 59,86 76,88 90,93 104,97 117,105 128,117 139,129 150,145 161,166 171,187 182,213 195,246 L 649,1462 809,1462 1272,195 C 1280,174 1288,156 1297,142 1305,128 1315,117 1326,109 1337,100 1350,94 1365,91 1380,88 1397,86 1417,86 L 1444,86 1444,0 881,0 881,86 928,86 C 1010,86 1051,119 1051,184 1051,195 1050,207 1047,219 1044,231 1039,245 1034,260 L 952,489 414,489 Z M 788,950 C 767,1011 747,1068 730,1121 712,1174 697,1225 686,1274 681,1249 676,1226 670,1203 663,1180 656,1156 649,1132 642,1108 633,1083 624,1057 615,1030 604,1001 592,969 L 453,592 915,592 788,950 Z"/>
|
||||
<glyph unicode="8" horiz-adv-x="980" d="M 94,367 C 94,416 102,460 118,497 133,534 155,567 183,596 211,625 244,651 282,674 320,697 361,720 406,741 367,763 332,787 299,813 266,838 238,866 215,897 192,928 174,961 161,998 148,1034 141,1073 141,1116 141,1163 149,1209 166,1253 183,1297 209,1336 244,1370 279,1404 325,1431 382,1452 438,1473 505,1483 584,1483 648,1483 705,1474 755,1457 805,1439 847,1414 882,1383 916,1352 942,1315 960,1272 978,1229 987,1181 987,1130 987,1085 980,1046 967,1012 954,978 935,948 911,921 887,894 858,869 824,848 790,826 752,805 711,784 762,760 808,734 850,707 891,680 927,650 957,618 987,586 1010,551 1027,514 1043,477 1051,436 1051,391 1051,326 1039,269 1016,218 993,167 960,123 917,88 874,53 823,26 762,8 701,-11 634,-20 559,-20 482,-20 415,-10 357,10 299,30 251,58 212,93 173,128 143,169 124,216 104,263 94,313 94,367 Z M 569,74 C 614,74 654,81 691,95 727,108 758,127 784,151 809,175 829,204 843,237 857,270 864,307 864,346 864,381 858,413 845,443 832,472 812,501 783,529 754,556 717,583 672,610 626,636 570,663 504,692 439,657 388,612 350,557 312,502 293,435 293,358 293,315 299,277 311,242 322,207 340,178 363,153 386,128 414,108 449,95 484,81 524,74 569,74 Z M 805,1135 C 805,1166 801,1197 793,1227 784,1257 771,1284 753,1308 734,1331 710,1350 681,1365 651,1379 614,1386 571,1386 533,1386 499,1380 470,1368 440,1355 415,1338 395,1317 375,1295 360,1269 350,1239 339,1209 334,1176 334,1141 334,1104 340,1071 352,1042 363,1013 381,986 404,962 427,938 455,916 490,895 525,874 565,852 610,831 649,850 681,870 706,891 731,911 750,933 765,958 780,982 790,1009 796,1038 802,1067 805,1099 805,1135 Z"/>
|
||||
<glyph unicode="6" horiz-adv-x="953" d="M 659,1384 C 556,1384 479,1334 426,1233 373,1132 343,981 336,782 353,796 371,810 392,823 412,836 434,847 458,857 482,866 508,874 537,880 565,886 596,889 629,889 692,889 748,879 799,860 850,841 893,813 929,777 964,741 992,697 1011,645 1030,593 1040,534 1040,469 1040,397 1030,331 1011,271 991,211 962,160 925,117 887,74 841,40 787,16 732,-8 670,-20 600,-20 532,-20 469,-6 411,23 353,51 303,96 261,157 218,218 185,296 161,392 137,487 125,602 125,737 125,802 130,865 140,927 149,989 164,1048 183,1103 202,1158 227,1209 256,1256 285,1303 320,1343 360,1377 399,1410 444,1436 494,1455 544,1474 599,1483 659,1483 716,1483 766,1477 809,1465 851,1453 886,1437 914,1417 942,1397 963,1374 977,1348 990,1322 997,1295 997,1268 997,1229 984,1198 957,1177 930,1156 891,1145 840,1145 840,1178 837,1210 831,1239 824,1268 814,1293 799,1315 784,1336 766,1353 743,1366 720,1378 692,1384 659,1384 Z M 588,784 C 561,784 536,781 511,774 486,767 463,758 442,747 420,736 400,723 382,709 364,694 348,680 334,666 335,563 343,476 356,403 369,330 387,271 410,225 433,179 462,145 495,124 528,103 565,92 606,92 679,92 735,121 774,178 812,235 831,325 831,449 831,566 810,651 769,704 727,757 667,784 588,784 Z"/>
|
||||
<glyph unicode="5" horiz-adv-x="900" d="M 489,100 C 531,100 570,106 606,118 641,129 672,149 699,176 725,203 745,238 760,283 775,327 782,381 782,446 782,500 775,547 760,587 745,627 724,660 697,687 670,714 637,734 599,747 561,760 518,766 471,766 436,766 405,765 380,762 354,759 331,756 312,752 292,747 275,742 260,737 245,732 232,726 219,721 L 170,735 236,1460 920,1460 930,1151 844,1151 836,1212 C 834,1227 831,1239 828,1250 824,1260 818,1269 810,1276 802,1283 791,1288 778,1291 764,1294 746,1296 725,1296 L 328,1296 289,846 C 310,853 340,861 379,868 418,875 467,879 528,879 594,879 656,870 713,852 770,834 819,807 861,771 903,735 936,690 960,636 983,581 995,518 995,446 995,377 984,313 962,256 939,199 907,150 865,109 822,68 770,36 709,14 648,-9 578,-20 500,-20 424,-20 361,-13 312,-1 262,13 222,29 193,49 164,69 143,91 131,116 119,140 113,163 113,186 113,224 124,254 145,275 166,296 198,307 242,307 242,278 247,250 258,225 268,200 283,178 304,160 324,141 350,127 381,116 412,105 448,100 489,100 Z"/>
|
||||
<glyph unicode="4" horiz-adv-x="1086" d="M 862,401 L 862,233 C 862,201 867,175 876,156 885,137 897,122 912,112 927,101 944,94 965,91 986,88 1007,86 1030,86 L 1057,86 1057,0 440,0 440,86 498,86 C 521,86 543,88 564,91 584,94 602,101 617,112 632,122 644,137 653,156 662,175 666,201 666,233 L 666,401 35,401 35,485 668,1462 862,1462 862,516 1116,516 1116,401 862,401 Z M 666,895 C 666,925 666,958 667,994 668,1030 669,1067 670,1104 671,1141 672,1179 674,1216 675,1253 677,1287 680,1319 675,1310 669,1297 660,1282 651,1266 642,1248 631,1229 620,1210 608,1189 596,1168 583,1147 571,1126 559,1106 546,1085 535,1066 524,1049 513,1031 504,1016 496,1004 L 182,516 666,516 666,895 Z"/>
|
||||
<glyph unicode="2" horiz-adv-x="927" d="M 944,1141 C 944,1093 936,1046 921,1001 906,956 883,909 854,862 825,814 789,764 747,713 704,662 656,606 602,547 L 256,164 729,164 C 760,164 785,168 805,177 825,186 841,197 854,211 867,225 877,241 884,260 891,278 896,297 901,317 L 909,354 995,354 985,0 104,0 104,150 446,545 C 501,608 547,665 584,715 621,765 650,812 673,857 696,901 712,944 722,987 732,1029 737,1073 737,1120 737,1159 733,1195 725,1227 716,1258 704,1286 687,1309 670,1332 648,1349 622,1362 595,1374 564,1380 528,1380 481,1380 444,1372 415,1355 386,1338 363,1316 346,1288 329,1260 318,1228 312,1191 306,1154 303,1116 303,1075 278,1075 255,1077 234,1081 213,1085 194,1092 178,1103 162,1113 150,1127 141,1144 132,1161 127,1182 127,1208 127,1247 136,1284 153,1318 170,1351 195,1380 229,1405 262,1430 304,1449 354,1463 404,1476 462,1483 528,1483 593,1483 651,1475 702,1459 753,1442 797,1419 833,1390 869,1360 897,1324 916,1282 935,1240 944,1193 944,1141 Z"/>
|
||||
<glyph unicode="0" horiz-adv-x="980" d="M 1053,733 C 1053,620 1043,518 1024,425 1004,332 974,253 934,187 894,121 844,70 784,34 724,-2 654,-20 573,-20 489,-20 417,-2 356,34 295,70 246,121 207,187 168,253 139,333 120,426 101,519 92,622 92,735 92,848 101,951 120,1043 139,1135 168,1214 207,1279 246,1344 296,1395 357,1430 418,1465 490,1483 575,1483 655,1483 725,1465 785,1430 844,1395 894,1344 934,1279 974,1214 1004,1135 1024,1043 1043,950 1053,847 1053,733 Z M 305,733 C 305,632 310,541 319,462 328,382 344,315 365,260 386,205 413,163 448,134 482,105 524,90 573,90 623,90 665,105 699,134 733,163 761,205 782,260 803,315 818,382 827,462 836,541 840,632 840,733 840,834 836,925 827,1004 818,1083 803,1150 782,1205 761,1260 733,1301 700,1330 666,1358 624,1372 575,1372 525,1372 483,1358 449,1330 414,1301 386,1260 365,1205 344,1150 328,1083 319,1004 310,925 305,834 305,733 Z"/>
|
||||
<glyph unicode="." horiz-adv-x="265" d="M 164,125 C 164,152 167,174 174,192 181,209 190,223 202,234 213,245 227,252 243,257 258,262 275,264 293,264 310,264 327,262 343,257 358,252 372,245 384,234 395,223 405,209 412,192 419,174 422,152 422,125 422,99 419,77 412,59 405,41 395,27 384,16 372,5 358,-2 343,-7 327,-12 310,-14 293,-14 275,-14 258,-12 243,-7 227,-2 213,5 202,16 190,27 181,41 174,59 167,77 164,99 164,125 Z"/>
|
||||
<glyph unicode=")" horiz-adv-x="557" d="M 379,649 C 379,730 376,811 370,890 363,969 349,1044 328,1115 306,1186 274,1251 233,1311 192,1370 136,1421 66,1464 L 66,1556 C 160,1519 240,1474 307,1421 374,1368 428,1304 470,1231 512,1158 543,1073 563,978 582,882 592,772 592,649 592,526 582,416 563,320 543,223 512,138 470,65 428,-9 374,-73 307,-126 240,-179 160,-225 66,-262 L 66,-168 C 136,-125 192,-74 233,-14 274,46 306,112 328,183 349,254 363,329 370,408 376,487 379,568 379,649 Z"/>
|
||||
<glyph unicode="(" horiz-adv-x="556" d="M 330,649 C 330,568 333,487 340,408 346,329 360,254 381,183 402,112 434,46 476,-14 517,-74 573,-125 643,-168 L 643,-262 C 549,-225 469,-179 402,-126 335,-73 281,-9 239,65 196,138 165,223 146,320 127,416 117,526 117,649 117,772 127,882 146,978 165,1073 196,1158 239,1231 281,1304 335,1368 402,1421 469,1474 549,1519 643,1556 L 643,1464 C 573,1421 517,1370 476,1311 434,1251 402,1186 381,1115 360,1044 346,969 340,890 333,811 330,730 330,649 Z"/>
|
||||
<glyph unicode=" " horiz-adv-x="529"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_3" horiz-adv-x="2048">
|
||||
<font-face font-family="Droid Serif embedded" units-per-em="2048" font-weight="normal" font-style="italic" ascent="1879" descent="476"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="1086" d="M 135,1098 L 516,1098 381,485 C 354,361 340,279 340,238 340,155 373,113 440,113 510,113 586,164 667,265 748,366 800,473 825,588 L 932,1098 1130,1098 989,440 C 968,343 958,268 958,213 958,144 981,109 1026,109 1065,109 1108,124 1157,154 L 1194,94 C 1107,18 1021,-20 934,-20 883,-20 841,-2 810,35 778,72 762,118 762,174 762,209 765,250 772,295 L 756,295 C 682,173 616,90 558,47 499,4 433,-18 360,-18 214,-18 141,58 141,209 141,252 153,327 178,434 L 258,793 C 270,847 276,888 276,915 276,980 228,1012 133,1012 L 117,1012 135,1098 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="636" d="M 616,154 L 651,78 C 559,13 467,-20 375,-20 226,-20 152,60 152,219 152,270 159,328 172,391 L 297,981 141,981 160,1063 C 293,1063 398,1159 473,1350 L 567,1350 514,1098 762,1098 737,981 489,981 365,397 C 348,318 340,260 340,221 340,146 376,109 449,109 504,109 560,124 616,154 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="901" d="M 799,821 C 799,929 772,983 717,983 654,983 587,921 516,796 445,671 392,530 358,373 L 281,0 90,0 262,823 C 270,861 274,892 274,915 274,980 220,1012 111,1012 L 94,1012 113,1098 475,1098 432,803 453,803 C 508,925 562,1008 615,1052 668,1096 730,1118 801,1118 913,1118 969,1071 969,977 969,873 912,821 799,821 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="1138" d="M 389,-406 L 371,-492 -14,-492 258,807 C 270,864 276,900 276,915 276,980 228,1012 133,1012 L 117,1012 135,1098 498,1098 449,825 459,825 C 558,1020 683,1118 834,1118 917,1118 982,1086 1027,1023 1072,960 1094,868 1094,748 1094,565 1037,391 923,227 808,62 662,-20 483,-20 405,-20 338,-4 283,27 277,-17 271,-50 266,-72 L 238,-197 C 225,-254 219,-292 219,-311 219,-374 267,-406 362,-406 L 389,-406 Z M 315,145 C 359,96 413,72 477,72 591,72 688,147 767,296 846,445 885,596 885,750 885,909 842,989 756,989 685,989 614,940 542,842 470,743 422,641 399,535 L 315,145 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="1007" d="M 698,1118 C 819,1118 914,1082 983,1009 1052,936 1087,831 1087,694 1087,512 1031,348 920,201 809,54 662,-20 481,-20 358,-20 261,17 192,92 123,167 88,270 88,403 88,587 144,752 257,899 369,1045 516,1118 698,1118 Z M 504,80 C 617,80 707,147 774,281 841,414 874,562 874,725 874,915 807,1010 674,1010 563,1010 473,943 404,809 335,675 301,526 301,362 301,174 369,80 504,80 Z"/>
|
||||
<glyph unicode="m" horiz-adv-x="1721" d="M 920,0 L 725,0 C 725,31 734,102 751,213 768,324 783,406 795,461 L 842,673 C 862,756 872,819 872,864 872,945 841,985 778,985 702,985 624,933 544,830 463,726 412,624 391,524 L 281,0 90,0 262,823 C 270,861 274,892 274,915 274,980 226,1012 131,1012 L 115,1012 133,1098 512,1098 457,840 477,840 C 588,1024 712,1116 850,1116 996,1116 1069,1040 1069,889 1069,872 1068,856 1065,840 L 1085,840 C 1196,1024 1321,1116 1458,1116 1604,1116 1677,1040 1677,889 1677,846 1665,771 1640,664 L 1587,422 C 1570,343 1561,271 1561,207 1561,142 1585,109 1632,109 1671,109 1715,125 1763,156 L 1800,96 C 1713,19 1630,-20 1550,-20 1494,-20 1449,-2 1415,35 1381,72 1364,121 1364,184 1364,247 1377,339 1403,461 L 1438,621 C 1467,752 1481,833 1481,864 1481,945 1449,985 1386,985 1316,985 1244,940 1169,851 1094,761 1042,667 1012,569 L 979,422 C 970,385 958,312 943,203 928,94 920,27 920,0 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="504" d="M 207,1470 L 225,1556 612,1556 375,440 C 354,343 344,267 344,213 344,144 367,109 412,109 451,109 500,127 559,162 L 596,102 C 501,21 409,-20 319,-20 270,-20 229,-2 198,34 166,70 150,117 150,174 150,239 165,346 195,496 L 362,1282 C 371,1323 375,1353 375,1374 375,1438 327,1470 231,1470 L 207,1470 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="504" d="M 459,1303 C 382,1303 344,1340 344,1415 344,1458 355,1493 378,1520 400,1546 430,1559 467,1559 544,1559 582,1521 582,1446 582,1399 571,1364 548,1340 525,1315 495,1303 459,1303 Z M 127,1012 L 145,1098 512,1098 373,440 C 352,342 342,266 342,213 342,144 365,109 410,109 449,109 498,127 557,162 L 594,102 C 499,21 407,-20 317,-20 266,-20 225,-2 194,35 163,72 147,118 147,174 147,235 162,343 193,496 L 272,872 C 277,894 279,912 279,926 279,983 237,1012 154,1012 L 127,1012 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="901" d="M 821,256 C 835,247 842,230 842,205 842,150 810,99 746,52 681,4 595,-20 487,-20 368,-20 271,18 198,93 125,168 88,272 88,403 88,582 146,746 261,895 376,1044 522,1118 698,1118 785,1118 852,1097 900,1056 947,1015 971,957 971,883 971,773 914,677 799,595 684,513 543,472 377,472 L 342,472 C 330,472 318,472 305,472 302,453 301,425 301,386 301,201 376,109 526,109 643,109 741,158 821,256 Z M 324,567 L 344,567 C 465,567 564,596 643,655 721,714 760,790 760,883 760,974 720,1020 641,1020 575,1020 513,979 456,896 399,813 355,703 324,567 Z"/>
|
||||
<glyph unicode="d" horiz-adv-x="1113" d="M 748,309 L 735,309 C 637,90 509,-20 352,-20 269,-20 204,13 158,79 111,144 88,236 88,354 88,542 147,716 264,877 381,1038 525,1118 698,1118 775,1118 842,1102 899,1069 910,1132 917,1170 922,1184 L 942,1282 C 951,1328 956,1359 956,1374 956,1438 908,1470 813,1470 L 797,1470 815,1556 1192,1556 954,440 C 934,346 924,270 924,213 924,144 946,109 991,109 1030,109 1079,127 1139,162 L 1176,102 C 1078,21 982,-20 887,-20 780,-20 727,37 727,150 727,193 734,246 748,309 Z M 864,952 C 833,1001 781,1026 709,1026 592,1026 495,952 416,804 337,655 297,503 297,346 297,188 340,109 426,109 494,109 565,159 640,260 715,361 764,471 788,590 L 864,952 Z"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs>
|
||||
<font id="EmbeddedFont_4" horiz-adv-x="2048">
|
||||
<font-face font-family="Liberation Serif embedded" units-per-em="2048" font-weight="normal" font-style="italic" ascent="1826" descent="450"/>
|
||||
<missing-glyph horiz-adv-x="2048" d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"/>
|
||||
<glyph unicode="y" horiz-adv-x="1112" d="M 52,940 L 308,940 453,208 688,614 C 731,689 752,753 752,807 752,832 745,851 731,866 717,881 702,890 686,895 L 694,940 884,940 C 901,925 910,904 910,877 910,824 882,751 827,657 L 431,-10 C 355,-139 295,-231 251,-285 206,-339 162,-379 119,-404 76,-429 29,-442 -22,-442 -76,-442 -126,-436 -171,-424 L -134,-221 -89,-221 -73,-317 C -56,-332 -29,-340 9,-340 99,-340 194,-250 294,-70 L 339,12 156,870 44,895 52,940 Z"/>
|
||||
<glyph unicode="u" horiz-adv-x="875" d="M 268,193 C 268,163 276,139 292,120 308,101 333,92 368,92 418,92 472,113 530,155 588,196 636,247 673,308 L 784,940 950,940 797,70 915,45 907,0 629,0 656,193 C 601,122 543,68 483,31 423,-6 364,-24 305,-24 238,-24 187,-6 153,31 119,67 102,119 102,187 102,197 104,215 108,241 111,266 147,476 215,871 L 104,895 112,940 393,940 291,359 C 276,275 268,220 268,193 Z"/>
|
||||
<glyph unicode="t" horiz-adv-x="531" d="M 264,174 C 264,144 272,122 287,107 302,92 321,84 344,84 393,84 443,94 496,114 L 517,67 C 435,9 352,-20 268,-20 215,-20 174,-4 144,28 113,60 98,105 98,162 98,181 100,204 104,231 107,257 144,465 213,856 L 90,856 98,901 231,940 368,1153 432,1153 395,940 610,940 594,856 379,856 282,307 C 270,246 264,201 264,174 Z"/>
|
||||
<glyph unicode="s" horiz-adv-x="742" d="M 692,276 C 692,175 660,101 596,53 532,4 435,-20 305,-20 213,-20 120,1 25,42 L 66,268 111,268 128,131 C 145,112 170,96 202,81 233,66 269,59 309,59 455,59 528,119 528,238 528,277 513,312 482,343 451,374 400,406 330,440 263,473 213,509 180,549 147,588 131,635 131,688 131,776 161,844 220,893 279,941 362,965 467,965 542,965 632,953 735,930 L 698,721 651,721 637,829 C 595,866 540,885 471,885 416,885 373,873 340,848 307,823 291,784 291,731 291,695 305,663 333,636 361,609 414,575 492,535 561,499 612,460 644,419 676,378 692,330 692,276 Z"/>
|
||||
<glyph unicode="r" horiz-adv-x="742" d="M 724,965 C 757,965 784,962 803,957 L 759,711 716,711 678,838 C 625,838 570,818 513,777 456,736 403,683 356,616 L 249,0 83,0 236,870 118,895 126,940 403,940 372,728 C 422,803 478,862 540,903 601,944 663,965 724,965 Z"/>
|
||||
<glyph unicode="p" horiz-adv-x="1112" d="M 233,2 L 222,-88 174,-365 334,-389 326,-436 -120,-436 -112,-389 9,-365 228,870 125,895 133,940 398,940 379,788 C 496,906 601,965 694,965 775,965 840,935 889,876 938,817 962,735 962,631 962,514 937,405 887,304 837,203 769,123 683,66 597,9 504,-20 403,-20 372,-20 341,-18 308,-14 275,-9 250,-4 233,2 Z M 257,107 C 298,75 354,59 425,59 491,59 551,83 605,132 658,181 701,249 734,337 767,424 783,514 783,605 783,679 768,737 739,778 709,819 669,840 619,840 584,840 542,827 494,801 446,775 403,742 366,701 L 257,107 Z"/>
|
||||
<glyph unicode="o" horiz-adv-x="927" d="M 237,340 C 237,250 255,181 290,134 325,86 373,62 436,62 497,62 555,86 610,135 665,184 708,250 740,335 772,419 788,509 788,606 788,698 771,768 736,816 701,863 650,887 585,887 524,887 467,863 413,814 358,765 315,699 284,615 253,530 237,439 237,340 Z M 427,-20 C 316,-20 228,16 161,87 94,158 61,253 61,374 61,481 84,581 130,672 176,763 240,835 322,887 403,939 495,965 597,965 708,965 796,930 863,859 930,788 963,692 963,571 963,464 940,364 894,273 848,182 784,110 703,58 621,6 529,-20 427,-20 Z"/>
|
||||
<glyph unicode="n" horiz-adv-x="901" d="M 755,748 C 755,778 747,802 731,821 715,840 690,849 655,849 606,849 552,828 494,786 435,744 387,692 349,630 L 239,0 73,0 226,871 108,896 116,941 394,941 367,749 C 423,821 481,875 541,911 601,947 660,965 718,965 785,965 836,947 870,911 904,874 921,822 921,754 921,745 920,730 917,711 914,692 878,478 808,69 L 939,45 931,0 630,0 732,582 C 747,667 755,722 755,748 Z"/>
|
||||
<glyph unicode="m" horiz-adv-x="1350" d="M 873,746 C 918,811 970,863 1027,904 1084,945 1139,965 1192,965 1248,965 1292,947 1325,912 1357,876 1373,824 1373,757 1373,742 1372,723 1369,700 1366,676 1330,466 1262,70 L 1393,45 1384,0 1083,0 1186,582 C 1201,663 1209,718 1209,748 1209,778 1202,802 1188,821 1174,839 1152,848 1122,848 1093,848 1058,834 1017,806 976,778 940,742 907,699 874,655 854,614 847,576 L 748,0 582,0 684,582 C 701,669 709,725 709,748 709,778 702,802 687,821 672,839 649,848 618,848 589,848 553,833 510,804 467,774 430,738 397,696 364,653 345,613 339,576 L 240,0 74,0 227,870 109,895 117,940 395,940 367,746 C 414,812 466,865 524,905 582,945 637,965 688,965 747,965 792,947 825,910 857,873 873,818 873,746 Z"/>
|
||||
<glyph unicode="l" horiz-adv-x="424" d="M 287,70 L 444,45 436,0 109,0 346,1352 217,1376 225,1421 524,1421 287,70 Z"/>
|
||||
<glyph unicode="i" horiz-adv-x="424" d="M 292,70 L 449,45 441,0 114,0 267,870 138,895 146,940 445,940 292,70 Z M 507,1247 C 507,1218 496,1192 475,1171 454,1150 428,1139 398,1139 369,1139 343,1150 322,1171 301,1192 290,1218 290,1247 290,1277 301,1303 322,1324 343,1345 369,1356 398,1356 428,1356 454,1345 475,1324 496,1303 507,1277 507,1247 Z"/>
|
||||
<glyph unicode="g" horiz-adv-x="980" d="M 418,104 C 455,104 497,116 543,141 588,166 633,200 676,243 L 786,861 C 770,865 756,869 743,872 730,875 718,878 706,880 693,882 680,884 666,885 652,886 636,886 618,886 551,886 489,861 432,811 375,761 330,694 297,609 264,524 248,434 248,339 248,267 263,210 293,168 322,125 364,104 418,104 Z M 662,160 C 614,107 561,64 502,30 443,-4 389,-21 342,-21 257,-21 191,9 142,69 93,128 69,210 69,313 69,430 95,538 146,639 197,739 266,818 353,877 440,935 534,964 636,964 676,964 728,960 793,953 857,945 914,935 964,923 L 796,-35 C 771,-176 723,-278 652,-341 580,-404 474,-436 334,-436 275,-436 215,-429 152,-416 89,-402 39,-385 1,-365 L 19,-137 64,-137 100,-263 C 154,-316 232,-342 333,-342 414,-342 479,-321 527,-279 575,-236 607,-168 623,-75 L 662,160 Z"/>
|
||||
<glyph unicode="f" horiz-adv-x="821" d="M 189,-436 L 23,-436 248,856 86,856 94,905 264,944 276,1010 C 303,1159 348,1268 411,1338 474,1407 559,1442 666,1442 717,1442 764,1436 805,1423 L 770,1227 721,1227 702,1341 C 683,1355 655,1362 618,1362 577,1362 545,1345 522,1310 499,1275 477,1203 457,1096 L 428,940 637,940 623,856 414,856 189,-436 Z"/>
|
||||
<glyph unicode="e" horiz-adv-x="821" d="M 863,760 C 863,669 807,592 695,528 583,464 433,426 244,413 L 240,340 C 240,255 258,192 294,149 329,106 382,84 452,84 512,84 567,94 618,115 669,135 716,158 760,184 L 789,142 C 728,90 663,50 595,22 526,-6 461,-20 400,-20 292,-20 209,10 151,71 92,131 63,217 63,330 63,441 87,545 134,642 181,738 246,816 329,876 412,935 500,965 591,965 673,965 739,946 789,909 838,871 863,821 863,760 Z M 252,476 C 384,486 490,517 569,569 648,621 688,685 688,760 688,797 678,828 658,852 637,876 608,888 569,888 522,888 477,869 433,831 389,793 351,742 319,678 287,614 265,547 252,476 Z"/>
|
||||
<glyph unicode="d" horiz-adv-x="980" d="M 783,941 C 786,973 808,1110 851,1352 L 697,1376 705,1421 1029,1421 789,70 902,45 894,0 609,0 638,156 C 525,38 422,-21 329,-21 247,-21 182,10 134,72 86,133 62,215 62,317 62,431 87,538 136,639 185,739 252,818 337,877 422,935 516,964 618,964 681,964 736,956 783,941 Z M 760,837 C 737,852 713,864 688,873 663,882 633,886 598,886 535,886 477,861 422,812 367,763 323,695 290,608 257,521 240,432 240,339 240,268 255,211 284,168 313,125 353,104 403,104 440,104 481,116 525,141 568,165 610,199 651,243 L 760,837 Z"/>
|
||||
<glyph unicode="c" horiz-adv-x="848" d="M 774,142 C 720,92 659,53 592,24 525,-5 461,-20 400,-20 293,-20 210,11 151,73 92,135 63,221 63,330 63,446 86,552 133,648 180,743 246,820 333,878 419,936 509,965 604,965 651,965 702,960 755,950 808,940 852,928 887,913 L 842,651 787,651 771,825 C 729,867 673,888 603,888 539,888 479,864 424,817 368,770 323,704 290,619 257,534 240,441 240,340 240,169 309,84 446,84 541,84 641,117 744,184 L 774,142 Z"/>
|
||||
<glyph unicode="b" horiz-adv-x="927" d="M 305,1352 L 172,1376 180,1421 480,1421 406,980 C 395,904 382,840 367,787 420,842 475,885 532,917 588,949 640,965 687,965 770,965 837,935 887,876 937,816 962,734 962,631 962,516 937,408 888,307 838,205 769,125 682,67 595,9 499,-20 396,-20 337,-20 280,-12 224,3 167,18 118,38 76,64 L 305,1352 Z M 248,107 C 287,75 340,59 409,59 477,59 540,84 598,135 655,185 701,253 734,338 767,423 783,512 783,605 783,680 768,738 737,779 706,820 664,840 612,840 573,840 530,827 485,801 439,775 395,742 354,701 L 248,107 Z"/>
|
||||
<glyph unicode="a" horiz-adv-x="901" d="M 789,70 L 902,45 894,0 609,0 638,156 C 525,38 422,-21 329,-21 248,-21 184,9 135,68 86,127 61,209 61,313 61,430 87,539 138,641 189,742 257,822 342,879 427,936 520,964 620,964 701,964 777,950 848,922 L 893,956 947,956 789,70 Z M 760,837 C 734,855 710,868 687,875 664,882 636,885 603,885 536,885 475,860 420,810 364,759 320,691 288,606 256,521 240,432 240,339 240,268 255,211 284,168 313,125 353,104 404,104 479,104 562,150 651,243 L 760,837 Z"/>
|
||||
<glyph unicode=")" horiz-adv-x="742" d="M -97,-436 L -82,-352 C 5,-306 79,-248 138,-178 197,-108 245,-27 284,64 323,155 358,283 390,446 422,609 438,745 438,854 438,970 420,1068 383,1147 346,1226 289,1289 214,1337 L 229,1421 C 370,1337 471,1244 530,1143 589,1042 619,918 619,772 619,661 604,537 574,400 543,263 500,144 445,43 390,-59 319,-148 234,-224 149,-299 38,-370 -97,-436 Z"/>
|
||||
<glyph unicode="(" horiz-adv-x="742" d="M 251,131 C 251,-95 326,-256 475,-352 L 460,-436 C 322,-355 223,-264 163,-161 102,-58 72,66 72,213 72,330 87,457 118,593 148,728 191,846 246,946 301,1046 370,1134 455,1209 540,1284 650,1354 787,1421 L 772,1337 C 683,1290 609,1232 549,1161 489,1090 439,1006 400,911 361,816 326,686 296,522 266,358 251,228 251,131 Z"/>
|
||||
<glyph unicode=" " horiz-adv-x="503"/>
|
||||
</font>
|
||||
</defs>
|
||||
<defs class="TextShapeIndex">
|
||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5 id6 id7 id8 id9 id10 id11 id12 id13 id14 id15 id16 id17 id18 id19 id20 id21 id22 id23 id24 id25 id26 id27 id28 id29 id30 id31 id32 id33 id34 id35 id36 id37 id38 id39 id40 id41 id42 id43 id44 id45 id46"/>
|
||||
</defs>
|
||||
<defs class="EmbeddedBulletChars">
|
||||
<g id="bullet-char-template-57356" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-57354" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10146" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10132" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10007" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-10004" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-9679" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8226" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-8211" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template-61548" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<g>
|
||||
<g id="id2" class="Master_Slide">
|
||||
<g id="bg-id2" class="Background"/>
|
||||
<g id="bo-id2" class="BackgroundObjects"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="SlideGroup">
|
||||
<g>
|
||||
<g id="container-id1">
|
||||
<g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
|
||||
<g class="Page">
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id3">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="973" y="2843" width="7305" height="6305"/>
|
||||
<path fill="none" stroke="rgb(180,199,220)" stroke-width="53" stroke-linejoin="round" d="M 4625,9120 L 1000,9120 1000,2870 8250,2870 8250,9120 4625,9120 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="370px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="1276" y="3351"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">antlr</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id4">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="3500" width="5611" height="1213"/>
|
||||
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,4685 L 1731,4685 1731,3527 7287,3527 7287,4685 4509,4685 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,4685 L 1731,4685 1731,3527 7287,3527 7287,4685 4509,4685 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2600" y="4277"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Read module.p8</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id5">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="5583" width="5611" height="1212"/>
|
||||
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,6767 L 1731,6767 1731,5610 7287,5610 7287,6767 4509,6767 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,6767 L 1731,6767 1731,5610 7287,5610 7287,6767 4509,6767 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="3451" y="6360"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Tokenize</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id6">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="9750" width="5611" height="1213"/>
|
||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,10935 L 1731,10935 1731,9777 7287,9777 7287,10935 4509,10935 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,10935 L 1731,10935 1731,9777 7287,9777 7287,10935 4509,10935 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2761" y="10527"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Convert to AST</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id7">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="13916" width="5611" height="1444"/>
|
||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,15332 L 1731,15332 1731,13943 7287,13943 7287,15332 4509,15332 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,15332 L 1731,15332 1731,13943 7287,13943 7287,15332 4509,15332 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2263" y="14519"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Semantic and Type </tspan></tspan><tspan class="TextPosition" x="3459" y="15099"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">checking</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id8">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="11833" width="5611" height="1212"/>
|
||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,13017 L 1731,13017 1731,11860 7287,11860 7287,13017 4509,13017 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,13017 L 1731,13017 1731,11860 7287,11860 7287,13017 4509,13017 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2697" y="12610"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Preprocess AST</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id9">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="6741" width="281" height="952"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,6768 L 4509,7432"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,7413 L 4509,7692 4370,7413 4649,7413 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id10">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="10908" width="281" height="954"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,10935 L 4509,11601"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,11582 L 4509,11861 4370,11582 4649,11582 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id11">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="4658" width="281" height="954"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,4685 L 4509,5351"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,5332 L 4509,5611 4370,5332 4649,5332 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id12">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="7260" y="3966" width="1952" height="6418"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 7287,10356 L 7814,10356 7814,4106 7547,4106"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 7566,4246 L 7287,4106 7566,3967 7566,4246 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="7930" y="7138"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">import</tspan></tspan><tspan class="TextPosition" x="7881" y="7591"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">module</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id13">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="12991" width="281" height="954"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,13018 L 4509,13684"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,13665 L 4509,13944 4370,13665 4649,13665 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id14">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4482" y="15306" width="2807" height="1038"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,15333 L 4509,15837 7148,15837 7148,16083"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 7288,16064 L 7148,16343 7009,16064 7288,16064 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id15">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="5269" y="16315" width="3758" height="1212"/>
|
||||
<path fill="rgb(114,159,207)" stroke="none" d="M 7148,17499 L 5296,17499 5296,16342 8999,16342 8999,17499 7148,17499 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 7148,17499 L 5296,17499 5296,16342 8999,16342 8999,17499 7148,17499 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="6072" y="17092"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Optimize</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id16">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="18315" width="5611" height="1213"/>
|
||||
<path fill="rgb(114,159,207)" stroke="none" d="M 4509,19500 L 1731,19500 1731,18342 7287,18342 7287,19500 4509,19500 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,19500 L 1731,19500 1731,18342 7287,18342 7287,19500 4509,19500 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="2604" y="19092"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Postprocess AST</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id17">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="15306" width="281" height="3037"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,15333 L 4509,18082"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,18063 L 4509,18342 4370,18063 4649,18063 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id18">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="17473" width="2807" height="870"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 7148,17500 L 7148,17921 4509,17921 4509,18082"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,18063 L 4509,18342 4370,18063 4649,18063 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id19">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1704" y="7665" width="5611" height="1213"/>
|
||||
<path fill="rgb(142,134,174)" stroke="none" d="M 4509,8850 L 1731,8850 1731,7692 7287,7692 7287,8850 4509,8850 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 4509,8850 L 1731,8850 1731,7692 7287,7692 7287,8850 4509,8850 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="3857" y="8442"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Parse</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id20">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="8823" width="281" height="955"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4509,8850 L 4509,9517"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,9498 L 4509,9777 4370,9498 4649,9498 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id21">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="1750" y="16500" width="3010" height="1167"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="2000" y="16972"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(optional step)</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id22">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="13167" y="3306" width="5611" height="1213"/>
|
||||
<path fill="rgb(129,172,166)" stroke="none" d="M 15972,4491 L 13194,4491 13194,3333 18750,3333 18750,4491 15972,4491 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 15972,4491 L 13194,4491 13194,3333 18750,3333 18750,4491 15972,4491 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="14169" y="3793"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Select CodeGen</tspan></tspan><tspan class="TextPosition" x="14861" y="4373"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">for target</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id23">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="7287" y="3772" width="5908" height="15290"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 7687,18921 L 10241,18921 10241,3912 12934,3912"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 7706,18921 L 7287,19061 7287,18782 7706,18921 Z"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 12915,3773 L 13194,3912 12915,4052 12915,3773 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id24">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="8250" y="18834" width="4631" height="1167"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="8500" y="19306"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(if assembly generation is </tspan></tspan><tspan class="TextPosition" x="8500" y="19738"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">selected)</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id25">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="5621" width="4305" height="1907"/>
|
||||
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,7500 L 14750,7500 14750,5648 19000,5648 19000,7500 16875,7500 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,7500 L 14750,7500 14750,5648 19000,5648 19000,7500 16875,7500 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="16230" y="6165"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Make </tspan></tspan><tspan class="TextPosition" x="15330" y="6745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Intermediate </tspan></tspan><tspan class="TextPosition" x="16420" y="7325"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">AST</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id26">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="15945" y="4464" width="1071" height="1185"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 15972,4491 L 15972,5070 16875,5070 16875,5388"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 17015,5369 L 16875,5648 16736,5369 17015,5369 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id27">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="8472" width="4305" height="1444"/>
|
||||
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,9888 L 14750,9888 14750,8499 19000,8499 19000,9888 16875,9888 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,9888 L 14750,9888 14750,8499 19000,8499 19000,9888 16875,9888 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="15419" y="9365"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate IR </tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id28">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="16735" y="7473" width="281" height="1028"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,7500 L 16875,8240"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 17015,8221 L 16875,8500 16736,8221 17015,8221 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id29">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="14723" y="10972" width="4305" height="1444"/>
|
||||
<path fill="rgb(129,172,166)" stroke="none" d="M 16875,12388 L 14750,12388 14750,10999 19000,10999 19000,12388 16875,12388 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 16875,12388 L 14750,12388 14750,10999 19000,10999 19000,12388 16875,12388 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="15482" y="11865"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Optimize IR</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id30">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="16735" y="9862" width="281" height="1139"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,9889 L 16875,10740"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 17015,10721 L 16875,11000 16736,10721 17015,10721 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id31">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="13157" y="14223" width="3620" height="1457"/>
|
||||
<path fill="rgb(255,166,166)" stroke="none" d="M 14967,15652 L 13184,15652 13184,14250 16749,14250 16749,15652 14967,15652 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14967,15652 L 13184,15652 13184,14250 16749,14250 16749,15652 14967,15652 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="13891" y="14832"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate </tspan></tspan><tspan class="TextPosition" x="13832" y="15412"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">6502 Asm</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id32">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="12223" y="4464" width="3777" height="10628"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 15972,4491 L 15972,5019 12250,5019 12250,14951 12925,14951"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 12906,14812 L 13185,14951 12906,15091 12906,14812 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id33">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="12223" y="5084" width="2778" height="1167"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="12473" y="5556"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(depends </tspan></tspan><tspan class="TextPosition" x="12473" y="5988"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">on codegen)</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id34">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="13167" y="16269" width="3611" height="1509"/>
|
||||
<path fill="rgb(255,166,166)" stroke="none" d="M 14972,17750 L 13194,17750 13194,16296 16750,16296 16750,17750 14972,17750 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 14972,17750 L 13194,17750 13194,16296 16750,16296 16750,17750 14972,17750 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="13844" y="16904"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Assemble </tspan></tspan><tspan class="TextPosition" x="14073" y="17484"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(64tass)</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id35">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="14832" y="15625" width="281" height="672"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 14967,15652 L 14967,15974 14972,15974 14972,16036"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 15112,16017 L 14972,16296 14833,16017 15112,16017 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id36">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="3025" y="998" width="2977" height="1393"/>
|
||||
<path fill="rgb(221,232,203)" stroke="none" d="M 3026,999 L 6000,999 6000,2116 C 4822,2107 4862,2335 3799,2389 3419,2356 3280,2331 3026,2293 L 3026,999 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" d="M 3026,999 L 6000,999 6000,2116 C 4822,2107 4862,2335 3799,2389 3419,2356 3280,2331 3026,2293 L 3026,999 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Bitstream Vera Sans Mono, monospace" font-size="370px" font-weight="400"><tspan class="TextPosition" x="3633" y="1685"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">hello.p8</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id37">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4369" y="2280" width="281" height="1248"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 4514,2307 L 4514,2945 4509,2945 4509,3267"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 4649,3248 L 4509,3527 4370,3248 4649,3248 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id38">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="13498" y="18609" width="2939" height="1393"/>
|
||||
<path fill="rgb(255,245,206)" stroke="none" d="M 13499,18610 L 16435,18610 16435,19727 C 15272,19718 15312,19946 14262,20000 13887,19967 13750,19942 13499,19904 L 13499,18610 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" d="M 13499,18610 L 16435,18610 16435,19727 C 15272,19718 15312,19946 14262,20000 13887,19967 13750,19942 13499,19904 L 13499,18610 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Bitstream Vera Sans Mono, monospace" font-size="370px" font-weight="400"><tspan class="TextPosition" x="13977" y="19296"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">hello.prg</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id39">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="14828" y="17723" width="281" height="889"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 14972,17750 L 14972,18193 14968,18193 14968,18351"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 15108,18332 L 14968,18611 14829,18332 15108,18332 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id40">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="17473" y="14222" width="3305" height="1212"/>
|
||||
<path fill="rgb(255,166,166)" stroke="none" d="M 19125,15406 L 17500,15406 17500,14249 20750,14249 20750,15406 19125,15406 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 19125,15406 L 17500,15406 17500,14249 20750,14249 20750,15406 19125,15406 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="18050" y="14709"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Generate </tspan></tspan><tspan class="TextPosition" x="18109" y="15289"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">VM code</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id41">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="18934" y="15625" width="281" height="778"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 19119,15652 L 19119,16027 19074,16027 19074,16142"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 19214,16123 L 19074,16402 18935,16123 19214,16123 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id42">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="14827" y="12362" width="2076" height="1889"/>
|
||||
<path fill="none" stroke="rgb(183,179,202)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,12389 L 16875,13319 14967,13319 14967,13990"/>
|
||||
<path fill="rgb(183,179,202)" stroke="none" d="M 15107,13971 L 14967,14250 14828,13971 15107,13971 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.ConnectorShape">
|
||||
<g id="id43">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="16848" y="12362" width="2418" height="1889"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="miter" stroke-linecap="round" d="M 16875,12389 L 16875,13319 19125,13319 19125,13990"/>
|
||||
<path fill="rgb(52,101,164)" stroke="none" d="M 19265,13971 L 19125,14250 18986,13971 19265,13971 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="TextShape">
|
||||
<g id="id44">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="13473" y="13084" width="2778" height="1167"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Serif, serif" font-size="388px" font-style="italic" font-weight="400"><tspan class="TextPosition" x="13723" y="13556"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">(future)</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id45">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="17375" y="16375" width="3397" height="1806"/>
|
||||
<path fill="rgb(255,166,166)" stroke="none" d="M 17938,18153 L 17939,18153 C 17845,18153 17752,18113 17670,18036 17589,17959 17521,17848 17474,17715 17427,17582 17402,17431 17402,17278 L 17402,17278 C 17402,17124 17427,16973 17474,16840 17521,16707 17589,16596 17670,16519 17752,16442 17845,16402 17939,16402 L 20207,16402 20207,16402 C 20301,16402 20394,16442 20476,16519 20557,16596 20625,16707 20672,16840 20719,16973 20744,17124 20744,17278 L 20744,17278 20744,17278 C 20744,17431 20719,17582 20672,17715 20625,17848 20557,17959 20476,18036 20394,18113 20301,18153 20207,18153 L 17938,18153 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 17938,18153 L 17939,18153 C 17845,18153 17752,18113 17670,18036 17589,17959 17521,17848 17474,17715 17427,17582 17402,17431 17402,17278 L 17402,17278 C 17402,17124 17427,16973 17474,16840 17521,16707 17589,16596 17670,16519 17752,16442 17845,16402 17939,16402 L 20207,16402 20207,16402 C 20301,16402 20394,16442 20476,16519 20557,16596 20625,16707 20672,16840 20719,16973 20744,17124 20744,17278 L 20744,17278 20744,17278 C 20744,17431 20719,17582 20672,17715 20625,17848 20557,17959 20476,18036 20394,18113 20301,18153 20207,18153 L 17938,18153 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="423px" font-weight="400"><tspan class="TextPosition" x="18402" y="16927"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Run in </tspan></tspan><tspan class="TextPosition" x="18391" y="17423"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">virtual </tspan></tspan><tspan class="TextPosition" x="18199" y="17919"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">machine</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id46">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="17467" y="14223" width="3305" height="1457"/>
|
||||
<path fill="rgb(255,166,166)" stroke="none" d="M 19119,15652 L 17494,15652 17494,14250 20744,14250 20744,15652 19119,15652 Z"/>
|
||||
<path fill="none" stroke="rgb(52,101,164)" stroke-width="53" stroke-linejoin="round" d="M 19119,15652 L 17494,15652 17494,14250 20744,14250 20744,15652 19119,15652 Z"/>
|
||||
<text class="SVGTextShape"><tspan class="TextParagraph" font-family="Droid Serif, serif" font-size="494px" font-weight="400"><tspan class="TextPosition" x="18031" y="14832"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Build VM </tspan></tspan><tspan class="TextPosition" x="18086" y="15412"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">program</tspan></tspan></tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 94 KiB |
@ -236,7 +236,7 @@ Unsigned integers are in the range 0-255 for unsigned byte types, and 0-65535 fo
|
||||
The signed integers integers are in the range -128..127 for bytes,
|
||||
and -32768..32767 for words.
|
||||
|
||||
.. caution::
|
||||
.. attention::
|
||||
Doing math on signed integers can result in code that is a lot larger and slower than
|
||||
when using unsigned integers. Make sure you really need the signed numbers, otherwise
|
||||
stick to unsigned integers for efficiency.
|
||||
@ -419,8 +419,8 @@ address you specified, and setting the varible will directly modify that memory
|
||||
|
||||
.. _pointervars_programming:
|
||||
|
||||
Direct access to memory locations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Direct access to memory locations ('peek' and 'poke')
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Normally memory locations are accessed by a *memory mapped* name, such as ``c64.BGCOL0`` that is defined
|
||||
as the memory mapped address $d021.
|
||||
|
||||
@ -483,7 +483,7 @@ Iterating with a floating point variable is not supported. If you want to loop o
|
||||
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
||||
The *do--until* loop is used to repeat a piece of code until a certain condition is true.
|
||||
The *repeat* loop is used as a short notation of a for loop where the loop variable doesn't matter and you're only interested in the number of iterations.
|
||||
(without iteration count specified it simply loops forever).
|
||||
(without iteration count specified it simply loops forever). A repeat loop will result in the most efficient code generated so use this if possible.
|
||||
|
||||
You can also create loops by using the ``goto`` statement, but this should usually be avoided.
|
||||
|
||||
|
@ -374,8 +374,8 @@ should be the *memory address* where the value is located::
|
||||
|
||||
.. _pointervars:
|
||||
|
||||
Direct access to memory locations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Direct access to memory locations ('peek' and 'poke')
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Instead of defining a memory mapped name for a specific memory location, you can also
|
||||
directly access the memory. Enclose a numeric expression or literal with ``@(...)`` to do that::
|
||||
|
||||
|
@ -15,12 +15,14 @@ Currently these machines can be selected as a compilation target (via the ``-tar
|
||||
- 'cx16': the `Commander X16 <https://www.commanderx16.com/>`_
|
||||
- 'c128': the Commodore 128 (*limited support*)
|
||||
- 'atari': the Atari 800 XL (*experimental support*)
|
||||
- 'virtual': a builtin virtual machine
|
||||
|
||||
This chapter explains some relevant system details of the c64 and cx16 machines.
|
||||
|
||||
.. hint::
|
||||
If you only use standard kernal and prog8 library routines,
|
||||
it is possible to compile the *exact same program* for both machines (just change the compilation target flag)!
|
||||
it is often possible to compile the *exact same program* for
|
||||
different machines (just change the compilation target flag)!
|
||||
|
||||
|
||||
Memory Model
|
||||
|
@ -26,6 +26,7 @@ The software stack is implemented as follows:
|
||||
- 2 pages of memory are allocated for this, exact locations vary per machine target.
|
||||
For the C-64 they are set at $ce00 and $cf00 (so $ce00-$cfff is reserved).
|
||||
For the Commander X16 they are set at $0400 and $0500 (so $0400-$05ff are reserved).
|
||||
This default location can be overridden using the `-esa` command line option.
|
||||
- these are the high and low bytes of the values on the stack (it's a 'split 16 bit word stack')
|
||||
- for byte values just the lsb page is used, for word values both pages
|
||||
- float values (5 bytes) are chopped up into 2 words and 1 byte on this stack.
|
||||
@ -118,3 +119,29 @@ Prog8 also provides some help to deal with this:
|
||||
- you should use a ``clobbers(X)`` specification for asmsub routines that modify the X register; the compiler will preserve it for you automatically when such a routine is called
|
||||
- the ``rsavex()`` and ``rrestorex()`` builtin functions can preserve and restore the X register
|
||||
- the ``rsave()`` and ``rrestore()`` builtin functions can preserve and restore *all* registers (but this is very slow and overkill if you only need to save X)
|
||||
|
||||
|
||||
Compiler Internals
|
||||
------------------
|
||||
|
||||
Here is a diagram of how the compiler translates your program source code into a binary program:
|
||||
|
||||
.. image:: prog8compiler.svg
|
||||
|
||||
Some notes and references into the compiler's source code modules:
|
||||
|
||||
#. The ``compileProgram()`` function (in the ``compiler`` module) does all the coordination and basically drives all of the flow shown in the diagram.
|
||||
#. ANTLR is a Java parser generator and is used for initial parsing of the source code. (``parser`` module)
|
||||
#. Most of the compiler and the optimizer operate on the *Compiler AST*. These are complicated
|
||||
syntax nodes closely representing the Prog8 program structure. (``compilerAst`` module)
|
||||
#. For code generation, a much simpler *intermediate AST* has been defined that replaces the *Compiler AST*.
|
||||
Most notably, node type information is now baked in. (``codeCore`` module)
|
||||
#. An *Intermediate Representation* has been defined that is generated from the intermediate AST. This IR
|
||||
is more or less a machine code language for a virtual machine - and indeed this is what the built-in
|
||||
prog8 VM will execute if you use the 'virtual' compilaton target and use ``-emu`` to launch the VM.
|
||||
(``intermediate`` and ``codeGenIntermediate`` modules, and ``virtualmachine`` module for the VM related stuff)
|
||||
#. Currently the 6502 ASM code generator still works directly on the *Compiler AST*. A future version
|
||||
should replace this by working on the IR code, and should be much smaller and simpler.
|
||||
(``codeGenCpu6502`` module)
|
||||
#. Other code generators may either work on the intermediate AST or on the IR. Selection of what code generator
|
||||
to use is mostly based on the compilation target, and is done in the ``asmGeneratorFor()`` function.
|
||||
|
@ -16,23 +16,19 @@ Need help with
|
||||
Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Compiler:
|
||||
- vm: implement remaining sin/cos functions in math.p8 and merge tables
|
||||
- vm: implement memory mapped variables properly in VariableAllocator
|
||||
- vm: find a solution for the cx16.r0..r15 that "overlap" (r0, r0L, r0H etc) but in the vm each get their own separate variable location now. Maybe this gets solved by the previous item?
|
||||
- vm: encode romsub & romsub call in VM IR (can just crash in virtualmachine itself because program is not in the simulated memory) ExpressionGen.kt
|
||||
|
||||
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
|
||||
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
|
||||
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.
|
||||
- vm: add more optimizations in IRPeepholeOptimizer
|
||||
- vm: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
|
||||
- vm: rather than being able to jump to any 'address' (IPTR), use 'blocks' that have entry and exit points -> even better dead code elimination possible too
|
||||
- vm: add more optimizations in VmPeepholeOptimizer
|
||||
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.
|
||||
this is documented behavior to now loop around but it's too easy to forget about!
|
||||
Lot of work because of so many special cases in ForLoopsAsmgen.....
|
||||
How is it for the vm target? -> just 2 special cases in CodeGen.
|
||||
- when the vm is stable and *if* its language can get promoted to prog8 IL, the variable allocation should be changed.
|
||||
It's now done before the vm code generation, but the IL should probably not depend on the allocations already performed.
|
||||
So the CodeGen doesn't do VariableAlloc *before* the codegen, but as a last step instead.
|
||||
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
|
||||
but probably better to rewrite the 6502 codegen on top of the new Ast.
|
||||
- generate WASM from the new ast (or from vm code?) to eventually run prog8 on a browser canvas?
|
||||
- generate WASM to eventually run prog8 on a browser canvas?
|
||||
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway)
|
||||
then we can get rid of the instruction lists in the machinedefinitions as well?
|
||||
- [problematic due to using 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ...
|
||||
@ -54,18 +50,15 @@ 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 3 and perhaps even 2 to gfx2 (16 color and 4 color)?
|
||||
- add a flood fill routine to gfx2?
|
||||
- add modes 3 and perhaps even 2 to gfx2 (lores 16 color and 4 color)?
|
||||
- add a flood fill (span fill/scanline fill) routine to gfx2?
|
||||
|
||||
|
||||
Expressions:
|
||||
|
||||
- rethink the whole "isAugmentable" business. Because the way this is determined, should always also be exactly mirrorred in the AugmentableAssignmentAsmGen or you'll get a crash at code gen time.
|
||||
note: the new Ast doesn't need this any more so maybe we can get rid of it altogether in the old AST - but it's still used for something in the UnusedCodeRemover.
|
||||
- can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer
|
||||
- rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code that uses a fixed number of predetermined value 'variables'?
|
||||
"Three address code" was mentioned. https://en.wikipedia.org/wiki/Three-address_code
|
||||
these variables have to be unique for each subroutine because they could otherwise be interfered with from irq routines etc.
|
||||
- rewrite expression tree evaluation such that it doesn't use an eval stack but flatten the tree into linear code
|
||||
that, for instance, uses a fixed number of predetermined value 'variables'?
|
||||
The VM IL solves this already (by using unlimited registers) but that still lacks a translation to 6502.
|
||||
- this removes the need for the BinExprSplitter? (which is problematic and very limited now)
|
||||
and perhaps the assignment splitting in BeforeAsmAstChanger too
|
||||
|
@ -19,7 +19,8 @@ main {
|
||||
const uword SIZEPL = 8191
|
||||
uword @zp flags_ptr = memory("flags", SIZEPL, $100)
|
||||
|
||||
txt.print("calculating...\n")
|
||||
txt.print_ub(ITERS)
|
||||
txt.print(" iterations, calculating...\n")
|
||||
|
||||
repeat ITERS {
|
||||
sys.memset(flags_ptr, SIZEPL, 1)
|
||||
|
@ -9,6 +9,8 @@ main {
|
||||
|
||||
sub start() {
|
||||
gfx2.screen_mode(6) ; select 640*480 mode, 4 colors
|
||||
mouse.set_pointer_image()
|
||||
cx16.mouse_config(-1, 640/8, 240/8)
|
||||
uword[4] amigacolors = [$aaa, $000, $fff, $68c] ; gray, black, white, lightblue
|
||||
palette.set_rgb(amigacolors, len(amigacolors))
|
||||
|
||||
@ -99,7 +101,48 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
mouse {
|
||||
sub set_pointer_image() {
|
||||
const uword sprite_data_addr = $a000
|
||||
const ubyte palette_offset = 16
|
||||
; sprite registers base in VRAM: $1fc00
|
||||
; Sprite 0: $1FC00 - $1FC07 ; used by the kernal for mouse pointer
|
||||
cx16.vpoke(1, $fc00, lsb(sprite_data_addr >> 5)) ; sprite data ptr bits 5-12
|
||||
cx16.vpoke(1, $fc01, msb(sprite_data_addr >> 5)) ; mode bit (16 colors = 4 bpp) and sprite dataptr bits 13-16
|
||||
cx16.vpoke(1, $fc07, %01100000 | palette_offset>>4) ; 32x16 pixels (non-square...), palette offset
|
||||
|
||||
ubyte ix
|
||||
for ix in 0 to 255 {
|
||||
cx16.vpoke(0, sprite_data_addr+ix, mousecursor[ix])
|
||||
}
|
||||
|
||||
palette.set_color(palette_offset + %1111, $f00)
|
||||
palette.set_color(palette_offset + %1010, $fff)
|
||||
palette.set_color(palette_offset + %0101, $000)
|
||||
|
||||
ubyte[256] mousecursor = [
|
||||
; The Amiga Workbench 3.0 mouse cursor sprite image.
|
||||
; note that the sprite resolution is 32x16 (non-square pixels) because it follows the bitmap screen resolution
|
||||
; %1111 = red, %1010 = white, %0101 = black, %0000 = transparent
|
||||
%11111111,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%01010101,%11111111,%10101010,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%01010101,%11111111,%11111111,%10101010,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%01010101,%11111111,%11111111,%11111111,%11111111,%10101010,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%01010101,%11111111,%11111111,%11111111,%11111111,%11111111,%10101010,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%01010101,%11111111,%11111111,%11111111,%11111111,%11111111,%11111111,%11111111,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%01010101,%11111111,%11111111,%11111111,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%01010101,%11111111,%11111111,%01010101,%11111111,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%01010101,%11111111,%00000000,%01010101,%11111111,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%01010101,%11111111,%00000000,%00000000,%01010101,%11111111,%10101010,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%01010101,%11111111,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,
|
||||
%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000,%00000000
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
widget {
|
||||
|
||||
|
@ -35,21 +35,21 @@ main {
|
||||
graphics.line(256,0,256,height-1)
|
||||
|
||||
ubyte pixelyb
|
||||
uword pixelyw
|
||||
ubyte pixelxb
|
||||
byte pixelys
|
||||
|
||||
for pixelxb in 0 to 255 {
|
||||
pixelyb = math.cos8u(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelyb)
|
||||
graphics.plot(pixelxb, pixelyb+20)
|
||||
pixelyb = math.sin8u(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelyb)
|
||||
graphics.plot(pixelxb, pixelyb+20)
|
||||
}
|
||||
|
||||
for pixelxb in 0 to 255 {
|
||||
pixelyw = math.cos16u(pixelxb) / 1024 + 120
|
||||
graphics.plot(pixelxb, pixelyw)
|
||||
pixelyw = math.sin16u(pixelxb) / 1024 + 120
|
||||
graphics.plot(pixelxb, pixelyw)
|
||||
pixelys = math.cos8(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelys as uword + 90)
|
||||
pixelys = math.sin8(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelys as uword + 90)
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,21 +57,21 @@ main {
|
||||
graphics.line(180,0,180,height-1)
|
||||
|
||||
ubyte pixelyb
|
||||
uword pixelyw
|
||||
ubyte pixelxb
|
||||
byte pixelys
|
||||
|
||||
for pixelxb in 0 to 179 {
|
||||
pixelyb = math.cosr8u(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelyb)
|
||||
graphics.plot(pixelxb, pixelyb+20)
|
||||
pixelyb = math.sinr8u(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelyb)
|
||||
graphics.plot(pixelxb, pixelyb+20)
|
||||
}
|
||||
|
||||
for pixelxb in 0 to 179 {
|
||||
pixelyw = math.cosr16u(pixelxb) / 1024 + 120
|
||||
graphics.plot(pixelxb, pixelyw)
|
||||
pixelyw = math.sinr16u(pixelxb) / 1024 + 120
|
||||
graphics.plot(pixelxb, pixelyw)
|
||||
pixelys = math.cosr8(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelys as uword + 90)
|
||||
pixelys = math.sinr8(pixelxb) / 2
|
||||
graphics.plot(pixelxb, pixelys as uword + 90)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,20 +80,20 @@ main {
|
||||
uword pixelxw
|
||||
ubyte r
|
||||
|
||||
; circles with "degrees" from 0 to 255
|
||||
; circle with "degrees" from 0 to 255
|
||||
for r in 0 to 255 {
|
||||
pixelxw = ((math.sin8(r)/2 as word) + 80) as uword
|
||||
pixelyb = (math.cos8(r)/2 + height/2) as ubyte
|
||||
pixelxw = (math.sin8(r)/2 as uword) + 80
|
||||
pixelyb = (math.cos8(r)/2 as uword + height/2) as ubyte
|
||||
graphics.plot(pixelxw, pixelyb)
|
||||
}
|
||||
|
||||
for r in 0 to 255 {
|
||||
pixelxw = (math.sin16(r)/1024 + 80) as uword
|
||||
pixelyb = (math.cos16(r)/1024 + height/2) as ubyte
|
||||
graphics.plot(pixelxw, pixelyb)
|
||||
pixelxw = math.sin8u(r)/2
|
||||
pixelyb = math.cos8u(r)/2
|
||||
graphics.plot(pixelxw + 16, pixelyb+50)
|
||||
}
|
||||
|
||||
; circles with half-degrees from 0 to 179 (=full degrees 0..358 with steps of 2 degrees)
|
||||
; circle with half-degrees from 0 to 179 (=full degrees 0..358 with steps of 2 degrees)
|
||||
for r in 0 to 179 {
|
||||
pixelxw = (math.sinr8(r) as word /2 + 220) as uword
|
||||
pixelyb = (math.cosr8(r)/2 + height/2) as ubyte
|
||||
@ -101,10 +101,9 @@ main {
|
||||
}
|
||||
|
||||
for r in 0 to 179 {
|
||||
pixelxw = (math.sinr16(r) as word /1024 + 220) as uword
|
||||
pixelyb = (math.cosr16(r)/1024 + height/2) as ubyte
|
||||
graphics.plot(pixelxw, pixelyb)
|
||||
pixelxw = math.sinr8u(r)/2
|
||||
pixelyb = math.cosr8u(r)/2
|
||||
graphics.plot(pixelxw + 156, pixelyb+50)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -28,13 +28,24 @@ main {
|
||||
ubyte speedlevel
|
||||
ubyte holding
|
||||
bool holdingAllowed
|
||||
|
||||
ubyte ticks_since_previous_action
|
||||
ubyte ticks_since_previous_move
|
||||
|
||||
sub start() {
|
||||
void cx16.screen_mode(3, false) ; low res
|
||||
txt.color2(7,0) ; make sure correct screen colors are (re)set
|
||||
txt.clear_screen()
|
||||
|
||||
; gimmick: make a mirrored R
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+0, %00111110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+1, %01100110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+2, %01100110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+3, %00111110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+4, %00011110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+5, %00110110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+6, %01100110)
|
||||
cx16.vpoke(1,$f000+sc:'r'*8+7, %00000000)
|
||||
|
||||
sound.init()
|
||||
newGame()
|
||||
drawBoard()
|
||||
@ -46,6 +57,14 @@ newgame:
|
||||
spawnNextBlock()
|
||||
|
||||
waitkey:
|
||||
sys.waitvsync()
|
||||
ticks_since_previous_action++
|
||||
ticks_since_previous_move++
|
||||
if ticks_since_previous_action==0
|
||||
ticks_since_previous_action=255
|
||||
if ticks_since_previous_move==0
|
||||
ticks_since_previous_move=255
|
||||
|
||||
ubyte time_lo = lsb(c64.RDTIM16())
|
||||
if time_lo>=(60-4*speedlevel) {
|
||||
c64.SETTIM(0,0,0)
|
||||
@ -76,9 +95,8 @@ waitkey:
|
||||
}
|
||||
|
||||
ubyte key=c64.GETIN()
|
||||
if key==0 goto waitkey
|
||||
|
||||
keypress(key)
|
||||
joystick(cx16.joystick_get2(1))
|
||||
|
||||
goto waitkey
|
||||
|
||||
@ -129,69 +147,127 @@ waitkey:
|
||||
}
|
||||
}
|
||||
|
||||
sub rotate_counterclockwise() {
|
||||
drawBlock(xpos, ypos, true)
|
||||
if blocklogic.canRotateCCW(xpos, ypos) {
|
||||
blocklogic.rotateCCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
else if blocklogic.canRotateCCW(xpos-1, ypos) {
|
||||
xpos--
|
||||
blocklogic.rotateCCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
else if blocklogic.canRotateCCW(xpos+1, ypos) {
|
||||
xpos++
|
||||
blocklogic.rotateCCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
drawBlock(xpos, ypos, false)
|
||||
}
|
||||
|
||||
sub rotate_clockwise() {
|
||||
drawBlock(xpos, ypos, true)
|
||||
if blocklogic.canRotateCW(xpos, ypos) {
|
||||
blocklogic.rotateCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
else if blocklogic.canRotateCW(xpos-1, ypos) {
|
||||
xpos--
|
||||
blocklogic.rotateCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
else if blocklogic.canRotateCW(xpos+1, ypos) {
|
||||
xpos++
|
||||
blocklogic.rotateCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
drawBlock(xpos, ypos, false)
|
||||
}
|
||||
|
||||
sub hold_block() {
|
||||
if holdingAllowed {
|
||||
sound.swapping()
|
||||
if holding<7 {
|
||||
drawBlock(xpos, ypos, true)
|
||||
ubyte newholding = blocklogic.currentBlockNum
|
||||
swapBlock(holding)
|
||||
holding = newholding
|
||||
holdingAllowed = false
|
||||
} else {
|
||||
holding = blocklogic.currentBlockNum
|
||||
drawBlock(xpos, ypos, true)
|
||||
spawnNextBlock()
|
||||
}
|
||||
drawHoldBlock()
|
||||
}
|
||||
}
|
||||
|
||||
sub keypress(ubyte key) {
|
||||
when key {
|
||||
157, ',' -> move_left()
|
||||
29, '/' -> move_right()
|
||||
17, '.' -> move_down_faster()
|
||||
145, ' ' -> drop_down_immediately()
|
||||
'z' -> {
|
||||
; no joystick equivalent (there is only 1 fire button)
|
||||
; rotate counter clockwise
|
||||
drawBlock(xpos, ypos, true)
|
||||
if blocklogic.canRotateCCW(xpos, ypos) {
|
||||
blocklogic.rotateCCW()
|
||||
sound.blockrotate()
|
||||
'z' -> rotate_counterclockwise()
|
||||
'x' -> rotate_clockwise()
|
||||
'c' -> hold_block()
|
||||
}
|
||||
}
|
||||
|
||||
sub joystick(uword joy) {
|
||||
; note: we don't process simultaneous button presses
|
||||
when joy {
|
||||
%1111111111111101 -> {
|
||||
if ticks_since_previous_move > 5 {
|
||||
move_left()
|
||||
ticks_since_previous_move = 0
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
else if blocklogic.canRotateCCW(xpos-1, ypos) {
|
||||
xpos--
|
||||
blocklogic.rotateCCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
else if blocklogic.canRotateCCW(xpos+1, ypos) {
|
||||
xpos++
|
||||
blocklogic.rotateCCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
drawBlock(xpos, ypos, false)
|
||||
}
|
||||
'x' -> {
|
||||
; rotate clockwise
|
||||
drawBlock(xpos, ypos, true)
|
||||
if blocklogic.canRotateCW(xpos, ypos) {
|
||||
blocklogic.rotateCW()
|
||||
sound.blockrotate()
|
||||
%1111111111111110 -> {
|
||||
if ticks_since_previous_move > 5 {
|
||||
move_right()
|
||||
ticks_since_previous_move = 0
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
else if blocklogic.canRotateCW(xpos-1, ypos) {
|
||||
xpos--
|
||||
blocklogic.rotateCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
else if blocklogic.canRotateCW(xpos+1, ypos) {
|
||||
xpos++
|
||||
blocklogic.rotateCW()
|
||||
sound.blockrotate()
|
||||
}
|
||||
drawBlock(xpos, ypos, false)
|
||||
}
|
||||
'c' -> {
|
||||
; hold
|
||||
if holdingAllowed {
|
||||
sound.swapping()
|
||||
if holding<7 {
|
||||
drawBlock(xpos, ypos, true)
|
||||
ubyte newholding = blocklogic.currentBlockNum
|
||||
swapBlock(holding)
|
||||
holding = newholding
|
||||
holdingAllowed = false
|
||||
} else {
|
||||
holding = blocklogic.currentBlockNum
|
||||
drawBlock(xpos, ypos, true)
|
||||
spawnNextBlock()
|
||||
}
|
||||
drawHoldBlock()
|
||||
%1111111111111011 -> {
|
||||
if ticks_since_previous_move > 5 {
|
||||
move_down_faster()
|
||||
ticks_since_previous_move = 0
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
}
|
||||
%1111111101111111 -> {
|
||||
if ticks_since_previous_action > 200 {
|
||||
drop_down_immediately()
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
}
|
||||
%1111111110111111 -> {
|
||||
if ticks_since_previous_action > 20 {
|
||||
rotate_counterclockwise()
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
}
|
||||
%1011111111111111, %0111111111111111 -> {
|
||||
if ticks_since_previous_action > 20 {
|
||||
rotate_clockwise()
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
}
|
||||
%1111111111110111 -> {
|
||||
if ticks_since_previous_action > 60 {
|
||||
hold_block()
|
||||
ticks_since_previous_action = 0
|
||||
}
|
||||
}
|
||||
$ffff -> {
|
||||
; no button pressed, reset timers to allow button tapping
|
||||
ticks_since_previous_move = 255
|
||||
ticks_since_previous_action = 255
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,17 +324,20 @@ waitkey:
|
||||
txt.print("────────────────────────")
|
||||
c64.CHROUT('I')
|
||||
txt.plot(7, 19)
|
||||
txt.print("│ f1 for new game │")
|
||||
txt.print("│ f1/start for new game │")
|
||||
txt.plot(7, 20)
|
||||
c64.CHROUT('J')
|
||||
txt.print("────────────────────────")
|
||||
c64.CHROUT('K')
|
||||
|
||||
ubyte key = 0
|
||||
while key!=133 {
|
||||
; endless loop until user presses F1 to restart the game
|
||||
ubyte key
|
||||
do {
|
||||
; endless loop until user presses F1 or Start button to restart the game
|
||||
cx16.r0 = cx16.joystick_get2(1)
|
||||
if cx16.r0 & %0000000000010000 == 0
|
||||
break
|
||||
key = c64.GETIN()
|
||||
}
|
||||
} until key==133
|
||||
}
|
||||
|
||||
sub newGame() {
|
||||
@ -270,6 +349,8 @@ waitkey:
|
||||
nextBlock = rnd() % 7
|
||||
holding = 255
|
||||
holdingAllowed = true
|
||||
ticks_since_previous_action = 0
|
||||
ticks_since_previous_move = 0
|
||||
}
|
||||
|
||||
sub swapBlock(ubyte newblock) {
|
||||
@ -316,6 +397,8 @@ waitkey:
|
||||
txt.print("spc drop")
|
||||
txt.plot(29,23)
|
||||
txt.print("c hold")
|
||||
txt.plot(25,24)
|
||||
txt.print("or joystick #1")
|
||||
|
||||
txt.setcc(boardOffsetX-1, boardOffsetY-2, 255, 0) ; invisible barrier
|
||||
txt.setcc(boardOffsetX-1, boardOffsetY-3, 255, 0) ; invisible barrier
|
||||
|
163
examples/starfield.p8
Normal file
163
examples/starfield.p8
Normal file
@ -0,0 +1,163 @@
|
||||
; Galencia starfield ported to Prog8. Original: https://github.com/JasonAldred/C64-Starfield
|
||||
; This is for the C64 only.
|
||||
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
const uword starScreenChar = $0400 ; Screen address
|
||||
const uword StarScreenCols = $d800 ; Character attribute address
|
||||
|
||||
const uword charBase = $3000 ; Address of our character set
|
||||
const uword star1Init = charBase+$1d0 ; Init address for each star
|
||||
const uword star2Init = charBase+$298
|
||||
const uword star3Init = charBase+$240
|
||||
const uword star4Init = charBase+$2e0
|
||||
|
||||
const uword star1Limit = charBase+$298 ; Limit for each star
|
||||
const uword star2Limit = charBase+$360 ; Once limit is reached, they are reset
|
||||
const uword star3Limit = charBase+$298
|
||||
const uword star4Limit = charBase+$360
|
||||
const uword star1Reset = charBase+$1d0 ; Reset address for each star
|
||||
const uword star2Reset = charBase+$298
|
||||
const uword star3Reset = charBase+$1d0
|
||||
const uword star4Reset = charBase+$298
|
||||
const uword staticStar1 = charBase+$250 ; 2 Locations for blinking static stars
|
||||
const uword staticStar2 = charBase+$1e0
|
||||
|
||||
const ubyte starColourLimit = 20 ; use values 1 to 20
|
||||
; Galencia uses these values
|
||||
; 1 = mono
|
||||
; 2 = duo
|
||||
; 20 = full colour
|
||||
|
||||
; 4 x pointers for moving stars
|
||||
uword @zp starfieldPtr1
|
||||
uword @zp starfieldPtr2
|
||||
uword @zp starfieldPtr3
|
||||
uword @zp starfieldPtr4
|
||||
|
||||
ubyte rasterCount ; Counter that increments each frame
|
||||
|
||||
sub start () {
|
||||
sys.set_irqd()
|
||||
sys.memset(charBase, 8*256, 0) ; clear charset data
|
||||
c64.EXTCOL = 0
|
||||
c64.BGCOL0 = 0
|
||||
c64.VMCSB = (charBase/1024) | %00010000 ; Characters at $3000
|
||||
initStarfield()
|
||||
createStarScreen()
|
||||
|
||||
repeat {
|
||||
sys.waitvsync()
|
||||
rasterCount ++
|
||||
doStarfield()
|
||||
}
|
||||
}
|
||||
|
||||
sub doStarfield() {
|
||||
; This routine does 3 things:
|
||||
; 1) Erases stars
|
||||
; 2) Moves stars
|
||||
; 3) Draws stars in new position
|
||||
|
||||
@(starfieldPtr1) = 0
|
||||
@(starfieldPtr2) = 0
|
||||
@(starfieldPtr3) = 0
|
||||
@(starfieldPtr4) = 0
|
||||
|
||||
if rasterCount & 1 {
|
||||
starfieldPtr1++
|
||||
if starfieldPtr1==star1Limit
|
||||
starfieldPtr1=star1Reset
|
||||
}
|
||||
starfieldPtr2++
|
||||
if starfieldPtr2==star2Limit
|
||||
starfieldPtr2=star2Reset
|
||||
if rasterCount & 3 == 0 {
|
||||
starfieldPtr3++
|
||||
if starfieldPtr3==star3Limit
|
||||
starfieldPtr3=star3Reset
|
||||
}
|
||||
starfieldPtr4 += 2
|
||||
if starfieldPtr4==star4Limit
|
||||
starfieldPtr4=star4Reset
|
||||
|
||||
; 2 static stars that flicker
|
||||
if rasterCount >= 230
|
||||
@(staticStar1) = 0
|
||||
else
|
||||
@(staticStar1) = 192
|
||||
if rasterCount ^ $80 >= 230
|
||||
@(staticStar2) = 0
|
||||
else
|
||||
@(staticStar2) = 192
|
||||
|
||||
; Plot new stars
|
||||
@(starfieldPtr1) |= 3
|
||||
@(starfieldPtr2) |= 3
|
||||
@(starfieldPtr3) |= 12
|
||||
@(starfieldPtr4) |= 48
|
||||
}
|
||||
|
||||
sub initStarfield() {
|
||||
starfieldPtr1 = star1Init
|
||||
starfieldPtr2 = star2Init
|
||||
starfieldPtr3 = star3Init
|
||||
starfieldPtr4 = star4Init
|
||||
}
|
||||
|
||||
sub createStarScreen() {
|
||||
; Creates the starfield charmap and colour charmap
|
||||
; This routine paints vertical stripes of colour into the colourmap
|
||||
; so the stars are different colours
|
||||
; It also plots the correct characters to the screen, wrapping them around
|
||||
; at the correct char count to give to the starfield effect.
|
||||
|
||||
uword @zp ptr
|
||||
ubyte x
|
||||
for x in 0 to 39 {
|
||||
ubyte limit
|
||||
ubyte char = starfieldRow[x]
|
||||
if char >= 58+25
|
||||
limit = 58+50
|
||||
else
|
||||
limit = 58+25
|
||||
ubyte start = limit - 25
|
||||
ptr = starScreenChar
|
||||
repeat 25 {
|
||||
ptr[x] = char
|
||||
ptr += 40
|
||||
char ++
|
||||
if char == limit
|
||||
char = start
|
||||
}
|
||||
}
|
||||
|
||||
; Fill colour map with vertical stripes of colour for starfield
|
||||
ptr = StarScreenCols
|
||||
ubyte ci = 0
|
||||
repeat 25 {
|
||||
for x in 0 to 39 {
|
||||
ptr[x] = starfieldCols[ci]
|
||||
ci ++
|
||||
if ci==starColourLimit
|
||||
ci=0
|
||||
}
|
||||
ptr += 40
|
||||
}
|
||||
}
|
||||
|
||||
; Dark starfield so it doesnt distract from bullets and text
|
||||
ubyte[20] starfieldCols = [
|
||||
14,10,12,15,14,13,12,11,10,14,
|
||||
14,10,14,15,14,13,12,11,10,12
|
||||
]
|
||||
|
||||
; Star positions, 40 X positions, range 58-107
|
||||
ubyte[40] starfieldRow = [
|
||||
058,092,073,064,091,062,093,081,066,094,
|
||||
086,059,079,087,080,071,076,067,082,095,
|
||||
100,078,099,060,075,063,084,065,083,096,
|
||||
068,088,074,061,090,098,085,101,097,077
|
||||
]
|
||||
}
|
@ -1,21 +1,5 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
uword @zp flags_ptr = memory("flags", 200, 0)
|
||||
txt.print("calculating...\n")
|
||||
txt.print_uwhex(flags_ptr, true)
|
||||
txt.nl()
|
||||
|
||||
repeat 10 {
|
||||
txt.print("new iter\n")
|
||||
txt.print_ub(@($06))
|
||||
sys.memset(flags_ptr, 200, 0)
|
||||
}
|
||||
|
||||
txt.print("done\n")
|
||||
%asmbinary "bsieve.prg", 10, 200
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ main {
|
||||
txt.lowercase()
|
||||
txt.print("\u000c\n --- TextElite v1.2 ---\n")
|
||||
|
||||
planet.set_seed(0, 0)
|
||||
galaxy.travel_to(1, numforLave)
|
||||
market.init(0) ; Lave's market is seeded with 0
|
||||
ship.init()
|
||||
|
@ -1,6 +1,3 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
; NOTE: meant to test to virtual machine output target (use -target virtual)
|
||||
|
||||
main {
|
||||
@ -24,6 +21,7 @@ main {
|
||||
repeat {
|
||||
fade()
|
||||
plot_particles()
|
||||
sys.wait(1)
|
||||
sys.waitvsync()
|
||||
}
|
||||
|
||||
|
37
examples/vm/bsieve.p8
Normal file
37
examples/vm/bsieve.p8
Normal file
@ -0,0 +1,37 @@
|
||||
%import textio
|
||||
|
||||
; The "Byte Sieve" test. https://en.wikipedia.org/wiki/Byte_Sieve
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
uword count
|
||||
uword i
|
||||
uword prime
|
||||
uword k
|
||||
const uword SIZEPL = 8191
|
||||
uword @zp flags_ptr = memory("flags", SIZEPL, $100)
|
||||
|
||||
txt.print("calculating...\n")
|
||||
|
||||
sys.memset(flags_ptr, SIZEPL, 1)
|
||||
count = 0
|
||||
for i in 0 to SIZEPL-1 {
|
||||
if @(flags_ptr+i) {
|
||||
prime = i + i + 3
|
||||
k = i + prime
|
||||
while k <= SIZEPL-1 {
|
||||
@(flags_ptr + k) = false
|
||||
k += prime
|
||||
}
|
||||
txt.print_uw(prime)
|
||||
txt.nl()
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
txt.nl()
|
||||
txt.print_uw(count)
|
||||
txt.print(" primes\n")
|
||||
}
|
||||
}
|
@ -1,6 +1,3 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
; NOTE: meant to test to virtual machine output target (use -target virtual)
|
||||
|
||||
main {
|
||||
@ -23,6 +20,9 @@ main {
|
||||
yy++
|
||||
}
|
||||
shifter+=4
|
||||
|
||||
sys.wait(1)
|
||||
sys.waitvsync()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
examples/vm/sincos.p8
Normal file
115
examples/vm/sincos.p8
Normal file
@ -0,0 +1,115 @@
|
||||
%import math
|
||||
|
||||
; Draw sine and cosine graphs. The sine and cosine functions are table lookups
|
||||
; where the tables are generated by 64tass list functions.
|
||||
|
||||
; Note: this program is compatible with CX16 only.
|
||||
; it doesn't work correctly on C64 because the bitmap screen data overlaps
|
||||
; the program itself in memory $2000-...
|
||||
|
||||
|
||||
main {
|
||||
const uword width = 320
|
||||
const ubyte height = 200
|
||||
|
||||
sub start() {
|
||||
sys.gfx_enable(0) ; enable lo res screen
|
||||
|
||||
sincos255()
|
||||
sys.wait(120)
|
||||
|
||||
sys.gfx_clear(0)
|
||||
|
||||
sincos180()
|
||||
sys.wait(120)
|
||||
|
||||
sys.gfx_clear(0)
|
||||
circles()
|
||||
|
||||
sys.wait(120)
|
||||
}
|
||||
|
||||
sub sincos255() {
|
||||
graphics_line(256)
|
||||
|
||||
ubyte pixelyb
|
||||
ubyte pixelxb
|
||||
byte pixelys
|
||||
|
||||
for pixelxb in 0 to 255 {
|
||||
pixelyb = math.cos8u(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelyb+20, 255)
|
||||
pixelyb = math.sin8u(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelyb+20, 255)
|
||||
}
|
||||
|
||||
for pixelxb in 0 to 255 {
|
||||
pixelys = math.cos8(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelys as uword + 90, 255)
|
||||
pixelys = math.sin8(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelys as uword + 90, 255)
|
||||
}
|
||||
}
|
||||
|
||||
sub sincos180() {
|
||||
graphics_line(180)
|
||||
|
||||
ubyte pixelyb
|
||||
ubyte pixelxb
|
||||
byte pixelys
|
||||
|
||||
for pixelxb in 0 to 179 {
|
||||
pixelyb = math.cosr8u(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelyb+20, 255)
|
||||
pixelyb = math.sinr8u(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelyb+20, 255)
|
||||
}
|
||||
|
||||
for pixelxb in 0 to 179 {
|
||||
pixelys = math.cosr8(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelys as uword + 90, 255)
|
||||
pixelys = math.sinr8(pixelxb) / 2
|
||||
sys.gfx_plot(pixelxb, pixelys as uword + 90, 255)
|
||||
}
|
||||
}
|
||||
|
||||
sub circles() {
|
||||
ubyte pixelyb
|
||||
uword pixelxw
|
||||
ubyte r
|
||||
|
||||
; circle with "degrees" from 0 to 255
|
||||
for r in 0 to 255 {
|
||||
pixelxw = (math.sin8(r)/2 as uword) + 80
|
||||
pixelyb = (math.cos8(r)/2 as uword + height/2) as ubyte
|
||||
sys.gfx_plot(pixelxw, pixelyb, 255)
|
||||
}
|
||||
|
||||
for r in 0 to 255 {
|
||||
pixelxw = math.sin8u(r)/2
|
||||
pixelyb = math.cos8u(r)/2
|
||||
sys.gfx_plot(pixelxw + 16, pixelyb+50, 255)
|
||||
}
|
||||
|
||||
; circle with half-degrees from 0 to 179 (=full degrees 0..358 with steps of 2 degrees)
|
||||
for r in 0 to 179 {
|
||||
pixelxw = (math.sinr8(r) as word /2 + 220) as uword
|
||||
pixelyb = (math.cosr8(r)/2 + height/2) as ubyte
|
||||
sys.gfx_plot(pixelxw, pixelyb, 255)
|
||||
}
|
||||
|
||||
for r in 0 to 179 {
|
||||
pixelxw = math.sinr8u(r)/2
|
||||
pixelyb = math.cosr8u(r)/2
|
||||
sys.gfx_plot(pixelxw + 156, pixelyb+50, 255)
|
||||
}
|
||||
}
|
||||
|
||||
sub graphics_line(uword x) {
|
||||
uword y
|
||||
for y in 0 to height-1 {
|
||||
sys.gfx_plot(x, y, 100)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
949
examples/vm/textelite.p8
Normal file
949
examples/vm/textelite.p8
Normal file
@ -0,0 +1,949 @@
|
||||
%import textio
|
||||
%import conv
|
||||
%import string
|
||||
|
||||
; Prog8 adaptation of the Text-Elite galaxy system trading simulation engine.
|
||||
; Original C-version obtained from: http://www.elitehomepage.org/text/index.htm
|
||||
|
||||
main {
|
||||
|
||||
const ubyte numforLave = 7 ; Lave is 7th generated planet in galaxy one
|
||||
const ubyte numforZaonce = 129
|
||||
const ubyte numforDiso = 147
|
||||
const ubyte numforRiedquat = 46
|
||||
|
||||
sub start() {
|
||||
txt.lowercase()
|
||||
txt.print("\n--- TextElite v1.2 ---\n")
|
||||
txt.print("VirtualMachine edition: no disk saving, bad market table layout!\n")
|
||||
|
||||
planet.set_seed(0, 0)
|
||||
galaxy.travel_to(1, numforLave)
|
||||
market.init(0) ; Lave's market is seeded with 0
|
||||
ship.init()
|
||||
planet.display(false, 0)
|
||||
|
||||
repeat {
|
||||
str input = "????????"
|
||||
txt.print("\nCash: ")
|
||||
util.print_10s(ship.cash)
|
||||
txt.print("\nCommand (?=help): ")
|
||||
ubyte num_chars = txt.input_chars(input)
|
||||
txt.nl()
|
||||
if num_chars {
|
||||
when input[0] {
|
||||
'?' -> {
|
||||
txt.print("\nCommands are:\n"+
|
||||
"buy jump info map quit\n"+
|
||||
"sell teleport market cash\n"+
|
||||
"fuel galhyp local hold\n")
|
||||
}
|
||||
'q' -> break
|
||||
'b' -> trader.do_buy()
|
||||
's' -> trader.do_sell()
|
||||
'f' -> trader.do_fuel()
|
||||
'j' -> trader.do_jump()
|
||||
't' -> trader.do_teleport()
|
||||
'g' -> trader.do_next_galaxy()
|
||||
'i' -> trader.do_info()
|
||||
'm' -> {
|
||||
if input[1]=='a' and input[2]=='p'
|
||||
trader.do_map()
|
||||
else
|
||||
trader.do_show_market()
|
||||
}
|
||||
'l' -> trader.do_local()
|
||||
'c' -> trader.do_cash()
|
||||
'h' -> trader.do_hold()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trader {
|
||||
str input = "??????????"
|
||||
ubyte num_chars
|
||||
|
||||
sub do_jump() {
|
||||
txt.print("\nJump to what system? ")
|
||||
jump_to_system()
|
||||
}
|
||||
|
||||
sub do_teleport() {
|
||||
txt.print("\nCheat! Teleport to what system? ")
|
||||
ubyte fuel = ship.fuel
|
||||
ship.fuel = 255
|
||||
jump_to_system()
|
||||
ship.fuel = fuel
|
||||
}
|
||||
|
||||
sub jump_to_system() {
|
||||
void txt.input_chars(input)
|
||||
ubyte current_planet = planet.number
|
||||
ubyte x = planet.x
|
||||
ubyte y = planet.y
|
||||
if galaxy.search_closest_planet(input) {
|
||||
ubyte distance = planet.distance(x, y)
|
||||
if distance <= ship.fuel {
|
||||
galaxy.init_market_for_planet()
|
||||
ship.fuel -= distance
|
||||
txt.print("\n\nHyperspace jump! Arrived at:\n")
|
||||
planet.display(true,0 )
|
||||
return
|
||||
}
|
||||
txt.print("\nInsufficient fuel\n")
|
||||
} else {
|
||||
txt.print(" Not found!\n")
|
||||
}
|
||||
galaxy.travel_to(galaxy.number, current_planet)
|
||||
}
|
||||
|
||||
sub do_buy() {
|
||||
txt.print("\nBuy what commodity? ")
|
||||
str commodity = "???????????????"
|
||||
void txt.input_chars(commodity)
|
||||
ubyte ci = market.match(commodity)
|
||||
if ci & 128 {
|
||||
txt.print("Unknown\n")
|
||||
} else {
|
||||
txt.print("\nHow much? ")
|
||||
void txt.input_chars(input)
|
||||
ubyte amount = conv.str2ubyte(input)
|
||||
if market.current_quantity[ci] < amount {
|
||||
txt.print(" Insufficient supply!\n")
|
||||
} else {
|
||||
uword price = market.current_price[ci] * amount
|
||||
txt.print(" Total price: ")
|
||||
util.print_10s(price)
|
||||
if price > ship.cash {
|
||||
txt.print(" Not enough cash!\n")
|
||||
} else {
|
||||
ship.cash -= price
|
||||
ship.cargohold[ci] += amount
|
||||
market.current_quantity[ci] -= amount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub do_sell() {
|
||||
txt.print("\nSell what commodity? ")
|
||||
str commodity = "???????????????"
|
||||
void txt.input_chars(commodity)
|
||||
ubyte ci = market.match(commodity)
|
||||
if ci & 128 {
|
||||
txt.print("Unknown\n")
|
||||
} else {
|
||||
txt.print("\nHow much? ")
|
||||
void txt.input_chars(input)
|
||||
ubyte amount = conv.str2ubyte(input)
|
||||
if ship.cargohold[ci] < amount {
|
||||
txt.print(" Insufficient supply!\n")
|
||||
} else {
|
||||
uword price = market.current_price[ci] * amount
|
||||
txt.print(" Total price: ")
|
||||
util.print_10s(price)
|
||||
ship.cash += price
|
||||
ship.cargohold[ci] -= amount
|
||||
market.current_quantity[ci] += amount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub do_fuel() {
|
||||
txt.print("\nBuy fuel. Amount? ")
|
||||
void txt.input_chars(input)
|
||||
ubyte buy_fuel = 10*conv.str2ubyte(input)
|
||||
ubyte max_fuel = ship.Max_fuel - ship.fuel
|
||||
if buy_fuel > max_fuel
|
||||
buy_fuel = max_fuel
|
||||
uword price = buy_fuel as uword * ship.Fuel_cost
|
||||
if price > ship.cash {
|
||||
txt.print("Not enough cash!\n")
|
||||
} else {
|
||||
ship.cash -= price
|
||||
ship.fuel += buy_fuel
|
||||
}
|
||||
}
|
||||
|
||||
sub do_cash() {
|
||||
txt.print("\nCheat! Set cash amount: ")
|
||||
void txt.input_chars(input)
|
||||
ship.cash = conv.str2uword(input)
|
||||
}
|
||||
|
||||
sub do_hold() {
|
||||
txt.print("\nCheat! Set cargohold size: ")
|
||||
void txt.input_chars(input)
|
||||
ship.Max_cargo = conv.str2ubyte(input)
|
||||
}
|
||||
|
||||
sub do_next_galaxy() {
|
||||
txt.print("\n>>>>>>>> Galaxy Hyperjump!\n")
|
||||
galaxy.travel_to(galaxy.number+1, planet.number)
|
||||
planet.display(false, 0)
|
||||
}
|
||||
|
||||
sub do_info() {
|
||||
txt.print("\nSystem name (empty=current): ")
|
||||
num_chars = txt.input_chars(input)
|
||||
if num_chars {
|
||||
ubyte current_planet = planet.number
|
||||
ubyte x = planet.x
|
||||
ubyte y = planet.y
|
||||
if galaxy.search_closest_planet(input) {
|
||||
ubyte distance = planet.distance(x, y)
|
||||
planet.display(false, distance)
|
||||
} else {
|
||||
txt.print(" Not found!")
|
||||
}
|
||||
galaxy.travel_to(galaxy.number, current_planet)
|
||||
} else {
|
||||
planet.display(false, 0)
|
||||
}
|
||||
}
|
||||
|
||||
sub do_local() {
|
||||
galaxy.local_area()
|
||||
}
|
||||
|
||||
sub do_map() {
|
||||
txt.print("\n(l)ocal or (g)alaxy starmap? ")
|
||||
num_chars = txt.input_chars(input)
|
||||
if num_chars {
|
||||
galaxy.starmap(input[0]=='l')
|
||||
}
|
||||
}
|
||||
|
||||
sub do_show_market() {
|
||||
market.display()
|
||||
txt.print("\nFuel: ")
|
||||
util.print_10s(ship.fuel)
|
||||
txt.print(" Cargohold space: ")
|
||||
txt.print_ub(ship.cargo_free())
|
||||
txt.print("t\n")
|
||||
}
|
||||
}
|
||||
|
||||
ship {
|
||||
const ubyte Max_fuel = 70
|
||||
const ubyte Fuel_cost = 2
|
||||
ubyte Max_cargo = 20
|
||||
|
||||
ubyte fuel = Max_fuel
|
||||
uword cash = 1000 ; actually has to be 4 bytes for the ultra rich....
|
||||
ubyte[17] cargohold = 0
|
||||
|
||||
sub init() {
|
||||
sys.memset(cargohold, len(cargohold), 0)
|
||||
}
|
||||
|
||||
sub cargo_free() -> ubyte {
|
||||
ubyte ci
|
||||
ubyte total = 0
|
||||
for ci in 0 to len(cargohold)-1 {
|
||||
if market.units[ci]==0 ; tonnes only
|
||||
total += cargohold[ci]
|
||||
}
|
||||
return Max_cargo - total
|
||||
}
|
||||
}
|
||||
|
||||
market {
|
||||
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
|
||||
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
|
||||
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
|
||||
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
|
||||
ubyte[17] units = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0]
|
||||
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
|
||||
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
|
||||
|
||||
ubyte[17] current_quantity = 0
|
||||
uword[17] current_price = 0
|
||||
|
||||
sub init(ubyte fluct) {
|
||||
; Prices and availabilities are influenced by the planet's economy type
|
||||
; (0-7) and a random "fluctuation" byte that was kept within the saved
|
||||
; commander position to keep the market prices constant over gamesaves.
|
||||
; Availabilities must be saved with the game since the player alters them
|
||||
; by buying (and selling(?))
|
||||
;
|
||||
; Almost all operations are one byte only and overflow "errors" are
|
||||
; extremely frequent and exploited.
|
||||
;
|
||||
; Trade Item prices are held internally in a single byte=true value/4.
|
||||
; The decimal point in prices is introduced only when printing them.
|
||||
; Internally, all prices are integers.
|
||||
; The player's cash is held in four bytes.
|
||||
ubyte ci
|
||||
for ci in 0 to len(names)-1 {
|
||||
word product
|
||||
byte changing
|
||||
product = planet.economy as word * gradients[ci]
|
||||
changing = fluct & maskbytes[ci] as byte
|
||||
ubyte q = (basequants[ci] as word + changing - product) as ubyte
|
||||
if q & $80
|
||||
q = 0 ; clip to positive 8-bit
|
||||
current_quantity[ci] = q & $3f
|
||||
q = (baseprices[ci] + changing + product) as ubyte
|
||||
current_price[ci] = q * $0004
|
||||
}
|
||||
current_quantity[16] = 0 ; force nonavailability of Alien Items
|
||||
}
|
||||
|
||||
sub display() {
|
||||
ubyte ci
|
||||
txt.nl()
|
||||
planet.print_name_uppercase()
|
||||
txt.print(" trade market:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
|
||||
for ci in 0 to len(names)-1 {
|
||||
util.print_right(13, names[ci])
|
||||
txt.print(" ")
|
||||
util.print_10s(current_price[ci])
|
||||
txt.print(" ")
|
||||
txt.print_ub(current_quantity[ci])
|
||||
txt.chrout(' ')
|
||||
when units[ci] {
|
||||
0 -> txt.chrout('t')
|
||||
1 -> txt.print("kg")
|
||||
2 -> txt.chrout('g')
|
||||
}
|
||||
txt.print(" ")
|
||||
txt.print_ub(ship.cargohold[ci])
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
sub match(uword nameptr) -> ubyte {
|
||||
ubyte ci
|
||||
for ci in 0 to len(names)-1 {
|
||||
if util.prefix_matches(nameptr, names[ci])
|
||||
return ci
|
||||
}
|
||||
return 255
|
||||
}
|
||||
}
|
||||
|
||||
galaxy {
|
||||
const uword GALSIZE = 256
|
||||
const uword base0 = $5A4A ; seeds for the first galaxy
|
||||
const uword base1 = $0248
|
||||
const uword base2 = $B753
|
||||
|
||||
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
|
||||
|
||||
ubyte number
|
||||
|
||||
uword[3] seed
|
||||
|
||||
sub init(ubyte galaxynum) {
|
||||
number = 1
|
||||
planet.number = 255
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxynum-1 {
|
||||
nextgalaxy()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy() {
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
}
|
||||
|
||||
sub travel_to(ubyte galaxynum, ubyte system) {
|
||||
init(galaxynum)
|
||||
generate_next_planet() ; always at least planet 0 (separate to avoid repeat ubyte overflow)
|
||||
repeat system {
|
||||
generate_next_planet()
|
||||
}
|
||||
planet.name = make_current_planet_name()
|
||||
init_market_for_planet()
|
||||
}
|
||||
|
||||
sub init_market_for_planet() {
|
||||
market.init(lsb(seed[0])+msb(seed[2]))
|
||||
}
|
||||
|
||||
sub search_closest_planet(uword nameptr) -> ubyte {
|
||||
ubyte x = planet.x
|
||||
ubyte y = planet.y
|
||||
ubyte current_planet_num = planet.number
|
||||
|
||||
init(number)
|
||||
ubyte found = false
|
||||
ubyte current_closest_pi
|
||||
ubyte current_distance = 127
|
||||
ubyte pi
|
||||
for pi in 0 to 255 {
|
||||
generate_next_planet()
|
||||
planet.name = make_current_planet_name()
|
||||
if util.prefix_matches(nameptr, planet.name) {
|
||||
ubyte distance = planet.distance(x, y)
|
||||
if distance < current_distance {
|
||||
current_distance = distance
|
||||
current_closest_pi = pi
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found
|
||||
travel_to(number, current_closest_pi)
|
||||
else
|
||||
travel_to(number, current_planet_num)
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
sub local_area() {
|
||||
ubyte current_planet = planet.number
|
||||
ubyte px = planet.x
|
||||
ubyte py = planet.y
|
||||
ubyte pn = 0
|
||||
|
||||
init(number)
|
||||
txt.print("\nGalaxy #")
|
||||
txt.print_ub(number)
|
||||
txt.print(" - systems in vicinity:\n")
|
||||
do {
|
||||
generate_next_planet()
|
||||
ubyte distance = planet.distance(px, py)
|
||||
if distance <= ship.Max_fuel {
|
||||
if distance <= ship.fuel
|
||||
txt.chrout('*')
|
||||
else
|
||||
txt.chrout('-')
|
||||
txt.spc()
|
||||
planet.name = make_current_planet_name()
|
||||
planet.display(true, distance)
|
||||
}
|
||||
pn++
|
||||
} until pn==0
|
||||
|
||||
travel_to(number, current_planet)
|
||||
}
|
||||
|
||||
sub starmap(bool local) {
|
||||
ubyte current_planet = planet.number
|
||||
ubyte px = planet.x
|
||||
ubyte py = planet.y
|
||||
uword current_name = &planet.name
|
||||
ubyte pn = 0
|
||||
uword scaling = 2
|
||||
if local
|
||||
scaling = 1
|
||||
|
||||
init(number)
|
||||
txt.clear_screen()
|
||||
txt.print("Galaxy #")
|
||||
txt.print_ub(number)
|
||||
if local
|
||||
txt.print(" - local systems")
|
||||
else
|
||||
txt.print(" - galaxy")
|
||||
txt.print(" starmap:\n")
|
||||
ubyte max_distance = 255
|
||||
if local
|
||||
max_distance = ship.Max_fuel
|
||||
do {
|
||||
generate_next_planet()
|
||||
ubyte distance = planet.distance(px, py)
|
||||
if distance <= max_distance {
|
||||
planet.name = make_current_planet_name()
|
||||
planet.name[0] = string.upperchar(planet.name[0])
|
||||
uword tx = planet.x
|
||||
uword ty = planet.y
|
||||
if local {
|
||||
tx = tx + 24 - px
|
||||
ty = ty + 24 - py
|
||||
}
|
||||
tx /= scaling
|
||||
ty /= scaling*4
|
||||
ubyte sx = lsb(tx)
|
||||
ubyte sy = lsb(ty)
|
||||
ubyte char = '*'
|
||||
if planet.number==current_planet
|
||||
char = '%'
|
||||
if local or planet.number==current_planet {
|
||||
txt.plot(2+sx-2, 2+sy+1)
|
||||
txt.print(current_name)
|
||||
if distance {
|
||||
txt.plot(2+sx-2, 2+sy+2)
|
||||
util.print_10s(distance)
|
||||
txt.print(" LY")
|
||||
}
|
||||
}
|
||||
txt.setchr(2+sx, 2+sy, char)
|
||||
}
|
||||
pn++
|
||||
} until pn==0
|
||||
|
||||
if local
|
||||
txt.plot(0, 20)
|
||||
else
|
||||
txt.plot(0, 33)
|
||||
txt.nl()
|
||||
|
||||
travel_to(number, current_planet)
|
||||
}
|
||||
|
||||
ubyte pn_pair1
|
||||
ubyte pn_pair2
|
||||
ubyte pn_pair3
|
||||
ubyte pn_pair4
|
||||
ubyte longname
|
||||
|
||||
sub generate_next_planet() {
|
||||
determine_planet_properties()
|
||||
longname = lsb(seed[0]) & 64
|
||||
|
||||
; Always four iterations of random number
|
||||
pn_pair1 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
pn_pair2 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
pn_pair3 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
pn_pair4 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
}
|
||||
|
||||
sub make_current_planet_name() -> str {
|
||||
ubyte ni = 0
|
||||
str name = " " ; max 8
|
||||
|
||||
if pn_pairs[pn_pair1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair1]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair1+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair1+1]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair2] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair2]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair2+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair2+1]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair3] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair3]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair3+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair3+1]
|
||||
ni++
|
||||
}
|
||||
|
||||
if longname {
|
||||
if pn_pairs[pn_pair4] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair4]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair4+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair4+1]
|
||||
ni++
|
||||
}
|
||||
}
|
||||
|
||||
name[ni] = 0
|
||||
return name
|
||||
}
|
||||
|
||||
sub determine_planet_properties() {
|
||||
; create the planet's characteristics
|
||||
planet.number++
|
||||
planet.x = msb(seed[1])
|
||||
planet.y = msb(seed[0])
|
||||
planet.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
|
||||
planet.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
|
||||
if planet.govtype <= 1
|
||||
planet.economy = (planet.economy | 2)
|
||||
planet.techlevel = (msb(seed[1]) & 3) + (planet.economy ^ 7)
|
||||
planet.techlevel += planet.govtype >> 1
|
||||
if planet.govtype & 1
|
||||
planet.techlevel++
|
||||
planet.population = 4 * planet.techlevel + planet.economy
|
||||
planet.population += planet.govtype + 1
|
||||
planet.productivity = ((planet.economy ^ 7) + 3) * (planet.govtype + 4)
|
||||
planet.productivity *= planet.population * 8
|
||||
ubyte seed2_msb = msb(seed[2])
|
||||
planet.radius = mkword((seed2_msb & 15) + 11, planet.x)
|
||||
planet.species_is_alien = lsb(seed[2]) & 128 ; bit 7 of w2_lo
|
||||
if planet.species_is_alien {
|
||||
planet.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
|
||||
planet.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
|
||||
planet.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
|
||||
planet.species_kind = (planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
planet.goatsoup_seed[0] = lsb(seed[1])
|
||||
planet.goatsoup_seed[1] = msb(seed[1])
|
||||
planet.goatsoup_seed[2] = lsb(seed[2])
|
||||
planet.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
uword temp = seed[0] + seed[1] + seed[2]
|
||||
seed[0] = seed[1]
|
||||
seed[1] = seed[2]
|
||||
seed[2] = temp
|
||||
}
|
||||
|
||||
sub twist(uword x) -> uword {
|
||||
ubyte xh = msb(x)
|
||||
ubyte xl = lsb(x)
|
||||
rol(xh)
|
||||
rol(xl)
|
||||
return mkword(xh, xl)
|
||||
}
|
||||
}
|
||||
|
||||
planet {
|
||||
str[] species_sizes = ["Large", "Fierce", "Small"]
|
||||
str[] species_colors = ["Green", "Red", "Yellow", "Blue", "Black", "Harmless"]
|
||||
str[] species_looks = ["Slimy", "Bug-Eyed", "Horned", "Bony", "Fat", "Furry"]
|
||||
str[] species_kinds = ["Rodents", "Frogs", "Lizards", "Lobsters", "Birds", "Humanoids", "Felines", "Insects"]
|
||||
str[] govnames = ["Anarchy", "Feudal", "Multi-gov", "Dictatorship", "Communist", "Confederacy", "Democracy", "Corporate State"]
|
||||
str[] econnames = ["Rich Industrial", "Average Industrial", "Poor Industrial", "Mainly Industrial",
|
||||
"Mainly Agricultural", "Rich Agricultural", "Average Agricultural", "Poor Agricultural"]
|
||||
|
||||
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
|
||||
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
|
||||
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
|
||||
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
|
||||
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
|
||||
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
|
||||
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
|
||||
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
|
||||
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
|
||||
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
|
||||
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
|
||||
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
|
||||
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
|
||||
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
|
||||
str[] words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
|
||||
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
|
||||
str[] words91 = ["planet", "world", "place", "little planet", "dump"]
|
||||
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
|
||||
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
|
||||
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
|
||||
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
|
||||
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
|
||||
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
|
||||
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
|
||||
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
|
||||
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
|
||||
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
|
||||
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
|
||||
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
|
||||
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
|
||||
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
|
||||
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
|
||||
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
|
||||
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
|
||||
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
|
||||
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
|
||||
|
||||
uword[] @shared wordlists = [
|
||||
words81, words82, words83, words84, words85, words86, words87, words88,
|
||||
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
|
||||
words91, words92, words93, words94, words95, words96, words97, words98,
|
||||
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
|
||||
wordsA1, wordsA2, wordsA3, wordsA4]
|
||||
|
||||
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
|
||||
|
||||
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
|
||||
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
|
||||
|
||||
str name = " " ; 8 max
|
||||
ubyte number ; starts at 0 in new galaxy, then increases by 1 for each generated planet
|
||||
ubyte x
|
||||
ubyte y
|
||||
ubyte economy
|
||||
ubyte govtype
|
||||
ubyte techlevel
|
||||
ubyte population
|
||||
uword productivity
|
||||
uword radius
|
||||
ubyte species_is_alien ; otherwise "Human Colonials"
|
||||
ubyte species_size
|
||||
ubyte species_color
|
||||
ubyte species_look
|
||||
ubyte species_kind
|
||||
|
||||
sub set_seed(uword s1, uword s2) {
|
||||
goatsoup_seed[0] = lsb(s1)
|
||||
goatsoup_seed[1] = msb(s1)
|
||||
goatsoup_seed[2] = lsb(s2)
|
||||
goatsoup_seed[3] = msb(s2)
|
||||
reset_rnd()
|
||||
}
|
||||
|
||||
sub reset_rnd() {
|
||||
goatsoup_rnd[0] = goatsoup_seed[0]
|
||||
goatsoup_rnd[1] = goatsoup_seed[1]
|
||||
goatsoup_rnd[2] = goatsoup_seed[2]
|
||||
goatsoup_rnd[3] = goatsoup_seed[3]
|
||||
}
|
||||
|
||||
sub random_name() -> str {
|
||||
ubyte ii
|
||||
str randname = " " ; 8 chars max
|
||||
ubyte nx = 0
|
||||
for ii in 0 to goatsoup_rnd_number() & 3 {
|
||||
ubyte xx = goatsoup_rnd_number() & $3e
|
||||
if pairs0[xx] != '.' {
|
||||
randname[nx] = pairs0[xx]
|
||||
nx++
|
||||
}
|
||||
xx++
|
||||
if pairs0[xx] != '.' {
|
||||
randname[nx] = pairs0[xx]
|
||||
nx++
|
||||
}
|
||||
}
|
||||
randname[nx] = 0
|
||||
randname[0] = string.upperchar(randname[0])
|
||||
return randname
|
||||
}
|
||||
|
||||
sub goatsoup_rnd_number() -> ubyte {
|
||||
ubyte xx = goatsoup_rnd[0] * 2
|
||||
uword a = xx as uword + goatsoup_rnd[2]
|
||||
if goatsoup_rnd[0] > 127
|
||||
a ++
|
||||
goatsoup_rnd[0] = lsb(a)
|
||||
goatsoup_rnd[2] = xx
|
||||
xx = goatsoup_rnd[1]
|
||||
ubyte ac = xx + goatsoup_rnd[3] + msb(a)
|
||||
goatsoup_rnd[1] = ac
|
||||
goatsoup_rnd[3] = xx
|
||||
return ac
|
||||
}
|
||||
|
||||
sub distance(ubyte px, ubyte py) -> ubyte {
|
||||
uword ax
|
||||
uword ay
|
||||
if px>x
|
||||
ax=px-x
|
||||
else
|
||||
ax=x-px
|
||||
if py>y
|
||||
ay=py-y
|
||||
else
|
||||
ay=y-py
|
||||
ay /= 2
|
||||
ubyte d = sqrt16(ax*ax + ay*ay)
|
||||
if d>63
|
||||
return 255
|
||||
return d*4
|
||||
}
|
||||
|
||||
sub soup() -> str {
|
||||
str planet_result = " " * 160
|
||||
uword[6] source_stack
|
||||
ubyte stack_ptr = 0
|
||||
str start_source = "\x8F is \x97."
|
||||
uword source_ptr = &start_source
|
||||
uword result_ptr = &planet_result
|
||||
|
||||
reset_rnd()
|
||||
recursive_soup()
|
||||
return planet_result
|
||||
|
||||
sub recursive_soup() {
|
||||
repeat {
|
||||
ubyte c = @(source_ptr)
|
||||
source_ptr++
|
||||
if c == $00 {
|
||||
@(result_ptr) = 0
|
||||
return
|
||||
}
|
||||
else if c <= $80 {
|
||||
@(result_ptr) = c
|
||||
result_ptr++
|
||||
}
|
||||
else {
|
||||
if c <= $a4 {
|
||||
ubyte rnr = goatsoup_rnd_number()
|
||||
ubyte wordNr = (rnr >= $33) + (rnr >= $66) + (rnr >= $99) + (rnr >= $CC)
|
||||
source_stack[stack_ptr] = source_ptr
|
||||
stack_ptr++
|
||||
source_ptr = getword(c, wordNr)
|
||||
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
|
||||
stack_ptr--
|
||||
source_ptr = source_stack[stack_ptr]
|
||||
} else {
|
||||
if c == $b0 {
|
||||
@(result_ptr) = string.upperchar(name[0])
|
||||
result_ptr++
|
||||
concat_string(&name + 1)
|
||||
}
|
||||
else if c == $b1 {
|
||||
@(result_ptr) = string.upperchar(name[0])
|
||||
result_ptr++
|
||||
ubyte ni
|
||||
for ni in 1 to len(name) {
|
||||
ubyte cc = name[ni]
|
||||
if cc in ['e', 'o', 0]
|
||||
break
|
||||
else {
|
||||
@(result_ptr) = cc
|
||||
result_ptr++
|
||||
}
|
||||
}
|
||||
@(result_ptr) = 'i'
|
||||
result_ptr++
|
||||
@(result_ptr) = 'a'
|
||||
result_ptr++
|
||||
@(result_ptr) = 'n'
|
||||
result_ptr++
|
||||
}
|
||||
else if c == $b2 {
|
||||
concat_string(random_name())
|
||||
}
|
||||
else {
|
||||
@(result_ptr) = c
|
||||
result_ptr++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub concat_string(uword str_ptr) {
|
||||
repeat {
|
||||
ubyte c = @(str_ptr)
|
||||
if c==0
|
||||
break
|
||||
else {
|
||||
@(result_ptr) = c
|
||||
str_ptr++
|
||||
result_ptr++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub display(bool compressed, ubyte distance) {
|
||||
if compressed {
|
||||
print_name_uppercase()
|
||||
if distance {
|
||||
txt.print(" (")
|
||||
util.print_10s(distance)
|
||||
txt.print(" LY)")
|
||||
}
|
||||
txt.print(" Tech level:")
|
||||
txt.print_ub(techlevel+1)
|
||||
txt.print("\n ")
|
||||
txt.print(econnames[economy])
|
||||
txt.spc()
|
||||
txt.print(govnames[govtype])
|
||||
txt.nl()
|
||||
} else {
|
||||
txt.print("\n\nSystem: ")
|
||||
print_name_uppercase()
|
||||
txt.print("\nPosition: ")
|
||||
txt.print_ub(x)
|
||||
txt.chrout('\'')
|
||||
txt.print_ub(y)
|
||||
txt.spc()
|
||||
txt.chrout('#')
|
||||
txt.print_ub(number)
|
||||
if distance {
|
||||
txt.print("\nDistance: ")
|
||||
util.print_10s(distance)
|
||||
txt.print(" LY")
|
||||
}
|
||||
txt.print("\nEconomy: ")
|
||||
txt.print(econnames[economy])
|
||||
txt.print("\nGovernment: ")
|
||||
txt.print(govnames[govtype])
|
||||
txt.print("\nTech Level: ")
|
||||
txt.print_ub(techlevel+1)
|
||||
txt.print("\nTurnover: ")
|
||||
txt.print_uw(productivity)
|
||||
txt.print("\nRadius: ")
|
||||
txt.print_uw(radius)
|
||||
txt.print("\nPopulation: ")
|
||||
txt.print_ub(population >> 3)
|
||||
txt.print(" Billion\nSpecies: ")
|
||||
if species_is_alien {
|
||||
if species_size < len(species_sizes) {
|
||||
txt.print(species_sizes[species_size])
|
||||
txt.spc()
|
||||
}
|
||||
if species_color < len(species_colors) {
|
||||
txt.print(species_colors[species_color])
|
||||
txt.spc()
|
||||
}
|
||||
if species_look < len(species_looks) {
|
||||
txt.print(species_looks[species_look])
|
||||
txt.spc()
|
||||
}
|
||||
if species_kind < len(species_kinds) {
|
||||
txt.print(species_kinds[species_kind])
|
||||
}
|
||||
} else {
|
||||
txt.print("Human Colonials")
|
||||
}
|
||||
txt.nl()
|
||||
txt.print(soup())
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
sub print_name_uppercase() {
|
||||
str uppername = "????????"
|
||||
uppername = name
|
||||
void string.upper(uppername)
|
||||
txt.print(uppername)
|
||||
}
|
||||
|
||||
sub getword(ubyte listnum, ubyte wordidx) -> uword {
|
||||
uword list = wordlists[listnum-$81]
|
||||
return peekw(list + wordidx*2)
|
||||
}
|
||||
}
|
||||
|
||||
util {
|
||||
sub prefix_matches(uword prefixptr, uword stringptr) -> ubyte {
|
||||
repeat {
|
||||
ubyte pc = @(prefixptr)
|
||||
ubyte sc = @(stringptr)
|
||||
if pc == 0
|
||||
return true
|
||||
; to lowercase for case insensitive compare:
|
||||
pc = string.lowerchar(pc)
|
||||
sc = string.lowerchar(sc)
|
||||
if pc != sc
|
||||
return false
|
||||
prefixptr++
|
||||
stringptr++
|
||||
}
|
||||
}
|
||||
|
||||
sub print_right(ubyte width, uword s) {
|
||||
repeat width - string.length(s) {
|
||||
txt.spc()
|
||||
}
|
||||
txt.print(s)
|
||||
}
|
||||
|
||||
sub print_10s(uword value) {
|
||||
txt.print_uw(value/10)
|
||||
txt.chrout('.')
|
||||
txt.print_uw(value % 10)
|
||||
}
|
||||
}
|
@ -4,4 +4,4 @@ org.gradle.parallel=true
|
||||
org.gradle.daemon=true
|
||||
kotlin.code.style=official
|
||||
javaVersion=11
|
||||
kotlinVersion=1.7.0
|
||||
kotlinVersion=1.7.10
|
@ -13,8 +13,8 @@ import org.takes.rs.RsJson
|
||||
import org.takes.tk.TkSlf4j
|
||||
import prog8.compiler.CompilerArguments
|
||||
import prog8.compiler.compileProgram
|
||||
import java.nio.file.Path
|
||||
import javax.json.Json
|
||||
import kotlin.io.path.Path
|
||||
|
||||
|
||||
class Jsonding: RsJson.Source {
|
||||
@ -31,7 +31,7 @@ class RequestParser : Take {
|
||||
val names = form.names()
|
||||
val a = form.param("a").single()
|
||||
val args = CompilerArguments(
|
||||
Path.of(a),
|
||||
Path(a),
|
||||
optimize = true,
|
||||
optimizeFloatExpressions = false,
|
||||
dontReinitGlobals = false,
|
||||
@ -42,7 +42,8 @@ class RequestParser : Take {
|
||||
symbolDefs = emptyMap(),
|
||||
quietAssembler = false,
|
||||
asmListfile = false,
|
||||
experimentalCodegen = false
|
||||
experimentalCodegen = false,
|
||||
keepIR = false
|
||||
)
|
||||
val compilationResult = compileProgram(args)
|
||||
return RsJson(Jsonding())
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user