Compare commits
3 Commits
f8320bcb82
...
4de89d98a1
Author | SHA1 | Date |
---|---|---|
Danila Fedorin | 4de89d98a1 | |
Danila Fedorin | ecbe84134d | |
Danila Fedorin | 3fa292347f |
|
@ -4,11 +4,8 @@ module Chalk
|
||||||
# that is provided by chalk's standard library, and therefore
|
# that is provided by chalk's standard library, and therefore
|
||||||
# has predefined output.
|
# has predefined output.
|
||||||
abstract class BuiltinFunction
|
abstract class BuiltinFunction
|
||||||
# Gets the number of parameters this function has.
|
|
||||||
getter param_count : Int32
|
|
||||||
|
|
||||||
# Creates a new function with *param_count* parameters.
|
# Creates a new function with *param_count* parameters.
|
||||||
def initialize(@param_count)
|
def initialize()
|
||||||
end
|
end
|
||||||
|
|
||||||
# Uses the given `Compiler::Emitter` to output code.
|
# Uses the given `Compiler::Emitter` to output code.
|
||||||
|
@ -22,11 +19,8 @@ module Chalk
|
||||||
# function also accepts trees rather than register numbers,
|
# function also accepts trees rather than register numbers,
|
||||||
# and therefore can accept and manipulate trees.
|
# and therefore can accept and manipulate trees.
|
||||||
abstract class InlineFunction
|
abstract class InlineFunction
|
||||||
# Gets the number of parameters this function has.
|
|
||||||
getter param_count : Int32
|
|
||||||
|
|
||||||
# Creates a new function with *param_count* parameters.
|
# Creates a new function with *param_count* parameters.
|
||||||
def initialize(@param_count)
|
def initialize()
|
||||||
end
|
end
|
||||||
|
|
||||||
# Generates code like `Compiler::CodeGenerator` would.
|
# Generates code like `Compiler::CodeGenerator` would.
|
||||||
|
|
|
@ -8,11 +8,6 @@ module Chalk
|
||||||
class CodeGenerator
|
class CodeGenerator
|
||||||
include Emitter
|
include Emitter
|
||||||
|
|
||||||
# The register into which the return value of a function is stored.
|
|
||||||
RETURN_REG = 14
|
|
||||||
# The register into which the "stack pointer" is stored.
|
|
||||||
STACK_REG = 13
|
|
||||||
|
|
||||||
# Gets the instructions currently emitted by this code generator.
|
# Gets the instructions currently emitted by this code generator.
|
||||||
getter instructions
|
getter instructions
|
||||||
|
|
||||||
|
@ -42,10 +37,7 @@ module Chalk
|
||||||
# `#generate!` call.
|
# `#generate!` call.
|
||||||
def generate!(tree, function : Trees::TreeFunction | Builtin::BuiltinFunction, table, target, free)
|
def generate!(tree, function : Trees::TreeFunction | Builtin::BuiltinFunction, table, target, free)
|
||||||
start_at = free
|
start_at = free
|
||||||
# Move I to stack
|
to_stack
|
||||||
setis
|
|
||||||
# Get to correct stack position
|
|
||||||
addi STACK_REG
|
|
||||||
# Store variables
|
# Store variables
|
||||||
store (start_at - 1) unless start_at == 0
|
store (start_at - 1) unless start_at == 0
|
||||||
# Increment I and stack position
|
# Increment I and stack position
|
||||||
|
@ -67,10 +59,7 @@ module Chalk
|
||||||
# Reduce stack pointer
|
# Reduce stack pointer
|
||||||
load free, start_at
|
load free, start_at
|
||||||
opr TokenType::OpSub, STACK_REG, free
|
opr TokenType::OpSub, STACK_REG, free
|
||||||
# Move I to stack
|
to_stack
|
||||||
setis
|
|
||||||
# Get to correct stack position
|
|
||||||
addi STACK_REG
|
|
||||||
# Restore
|
# Restore
|
||||||
restore (start_at - 1) unless start_at == 0
|
restore (start_at - 1) unless start_at == 0
|
||||||
# Get call value into target
|
# Get call value into target
|
||||||
|
@ -96,12 +85,9 @@ module Chalk
|
||||||
generate! tree.right, table, free, free + 1
|
generate! tree.right, table, free, free + 1
|
||||||
opr tree.op, target, free
|
opr tree.op, target, free
|
||||||
when Trees::TreeCall
|
when Trees::TreeCall
|
||||||
entry = table[tree.name]?
|
entry = table[tree.name]?.not_nil!
|
||||||
raise "Unknown function" unless entry &&
|
raise "Unknown function" unless entry.is_a?(FunctionEntry)
|
||||||
entry.is_a?(FunctionEntry)
|
generate! tree, entry.function, table, target, free
|
||||||
function = entry.function
|
|
||||||
raise "Invalid call" if tree.params.size != function.param_count
|
|
||||||
generate! tree, function, table, target, free
|
|
||||||
when Trees::TreeBlock
|
when Trees::TreeBlock
|
||||||
table = Table.new(table)
|
table = Table.new(table)
|
||||||
tree.children.each do |child|
|
tree.children.each do |child|
|
||||||
|
|
|
@ -53,11 +53,11 @@ module Chalk
|
||||||
end
|
end
|
||||||
@logger.debug("Done creating symbol table")
|
@logger.debug("Done creating symbol table")
|
||||||
|
|
||||||
table["draw"] = FunctionEntry.new Builtin::InlineDrawFunction.new
|
|
||||||
table["get_key"] = FunctionEntry.new Builtin::InlineAwaitKeyFunction.new
|
table["get_key"] = FunctionEntry.new Builtin::InlineAwaitKeyFunction.new
|
||||||
table["get_font"] = FunctionEntry.new Builtin::InlineGetFontFunction.new
|
|
||||||
table["set_delay"] = FunctionEntry.new Builtin::InlineSetDelayFunction.new
|
table["set_delay"] = FunctionEntry.new Builtin::InlineSetDelayFunction.new
|
||||||
table["get_delay"] = FunctionEntry.new Builtin::InlineGetDelayFunction.new
|
table["get_delay"] = FunctionEntry.new Builtin::InlineGetDelayFunction.new
|
||||||
|
table["set_sound"] = FunctionEntry.new Builtin::InlineSetSoundFunction.new
|
||||||
|
table["draw_number"] = FunctionEntry.new Builtin::InlineDrawNumberFunction.new
|
||||||
return table
|
return table
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
module Chalk
|
module Chalk
|
||||||
module Compiler
|
module Compiler
|
||||||
|
# The register into which the return value of a function is stored.
|
||||||
|
RETURN_REG = 14
|
||||||
|
# The register into which the "stack pointer" is stored.
|
||||||
|
STACK_REG = 13
|
||||||
|
|
||||||
# Module to emit instructions and store
|
# Module to emit instructions and store
|
||||||
# them into an existing array.
|
# them into an existing array.
|
||||||
module Emitter
|
module Emitter
|
||||||
|
# Moves I to the next available value on the stack.
|
||||||
|
def to_stack
|
||||||
|
setis
|
||||||
|
addi STACK_REG
|
||||||
|
end
|
||||||
|
|
||||||
# Emits an instruction to load a *value* into a register, *into*.
|
# Emits an instruction to load a *value* into a register, *into*.
|
||||||
def load(into, value)
|
def load(into, value)
|
||||||
inst = Ir::LoadInstruction.new into, value.to_i32
|
inst = Ir::LoadInstruction.new into, value.to_i32
|
||||||
|
|
|
@ -3,31 +3,8 @@ require "./type"
|
||||||
|
|
||||||
module Chalk
|
module Chalk
|
||||||
module Builtin
|
module Builtin
|
||||||
# Inline function to draw sprite at address I.
|
|
||||||
class InlineDrawFunction < InlineFunction
|
|
||||||
def initialize
|
|
||||||
@param_count = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
|
||||||
if !params[2].is_a?(Trees::TreeLit)
|
|
||||||
raise "Third parameter must be a constant."
|
|
||||||
end
|
|
||||||
emitter.generate! params[0], table, free, free + 1
|
|
||||||
emitter.generate! params[1], table, free + 1, free + 2
|
|
||||||
emitter.instructions << Ir::DrawInstruction.new free, free + 1, params[2].as(Trees::TreeLit).lit.to_i32
|
|
||||||
end
|
|
||||||
def type
|
|
||||||
return Compiler::FunctionType.new([Compiler::Type::U8] * 3, Compiler::Type::U0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Inline function to await for a key and return it.
|
# Inline function to await for a key and return it.
|
||||||
class InlineAwaitKeyFunction < InlineFunction
|
class InlineAwaitKeyFunction < InlineFunction
|
||||||
def initialize
|
|
||||||
@param_count = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.instructions << Ir::AwaitKeyInstruction.new target
|
emitter.instructions << Ir::AwaitKeyInstruction.new target
|
||||||
end
|
end
|
||||||
|
@ -36,31 +13,13 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Inline function to get font for a given value.
|
|
||||||
class InlineGetFontFunction < InlineFunction
|
|
||||||
def initialize
|
|
||||||
@param_count = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
|
||||||
emitter.generate! params[0], table, free, free + 1
|
|
||||||
emitter.instructions << Ir::GetFontInstruction.new free
|
|
||||||
end
|
|
||||||
def type
|
|
||||||
return Compiler::FunctionType.new([Compiler::Type::U8], Compiler::Type::U0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Inline function to set the delay timer.
|
# Inline function to set the delay timer.
|
||||||
class InlineSetDelayFunction < InlineFunction
|
class InlineSetDelayFunction < InlineFunction
|
||||||
def initialize
|
|
||||||
@param_count = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.generate! params[0], table, free, free + 1
|
emitter.generate! params[0], table, free, free + 1
|
||||||
emitter.instructions << Ir::SetDelayTimerInstruction.new free
|
emitter.instructions << Ir::SetDelayTimerInstruction.new free
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
return Compiler::FunctionType.new([Compiler::Type::U8], Compiler::Type::U0)
|
return Compiler::FunctionType.new([Compiler::Type::U8], Compiler::Type::U0)
|
||||||
end
|
end
|
||||||
|
@ -68,10 +27,6 @@ module Chalk
|
||||||
|
|
||||||
# Inline function to get the delay timer.
|
# Inline function to get the delay timer.
|
||||||
class InlineGetDelayFunction < InlineFunction
|
class InlineGetDelayFunction < InlineFunction
|
||||||
def initialize
|
|
||||||
@param_count = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate!(emitter, params, table, target, free)
|
def generate!(emitter, params, table, target, free)
|
||||||
emitter.instructions << Ir::GetDelayTimerInstruction.new target
|
emitter.instructions << Ir::GetDelayTimerInstruction.new target
|
||||||
end
|
end
|
||||||
|
@ -79,5 +34,52 @@ module Chalk
|
||||||
return Compiler::FunctionType.new(([] of Compiler::Type), Compiler::Type::U8)
|
return Compiler::FunctionType.new(([] of Compiler::Type), Compiler::Type::U8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Function to set the sound timer.
|
||||||
|
class InlineSetSoundFunction < InlineFunction
|
||||||
|
def generate!(emitter, params, table, target, free)
|
||||||
|
emitter.generate! params[0], table, free, free + 1
|
||||||
|
emitter.instructions << Ir::SetSoundTimerInstruction.new free
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
return Compiler::FunctionType.new([Compiler::Type::U8], Compiler::Type::U0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Function to draw numbers.
|
||||||
|
class InlineDrawNumberFunction < InlineFunction
|
||||||
|
def generate!(emitter, params, table, target, free)
|
||||||
|
emitter.to_stack
|
||||||
|
# Save variables from R0-R2
|
||||||
|
emitter.store 0x2
|
||||||
|
emitter.load free, 0x3
|
||||||
|
emitter.addi free
|
||||||
|
# Write BCD values to I
|
||||||
|
emitter.generate! params[0], table, free, free + 1
|
||||||
|
emitter.instructions << Ir::BCDInstruction.new free
|
||||||
|
emitter.restore 0x2
|
||||||
|
# Get the coordinates
|
||||||
|
free = 3 if free < 3
|
||||||
|
emitter.generate! params[1], table, free, free + 1
|
||||||
|
emitter.generate! params[2], table, free + 1, free + 2
|
||||||
|
# Draw
|
||||||
|
emitter.instructions << Ir::GetFontInstruction.new 0x0
|
||||||
|
emitter.instructions << Ir::DrawInstruction.new free, free + 1, 5
|
||||||
|
emitter.op(Compiler::TokenType::OpAdd, free, 6)
|
||||||
|
emitter.instructions << Ir::GetFontInstruction.new 0x1
|
||||||
|
emitter.instructions << Ir::DrawInstruction.new free, free + 1, 5
|
||||||
|
emitter.op(Compiler::TokenType::OpAdd, free, 6)
|
||||||
|
emitter.instructions << Ir::GetFontInstruction.new 0x2
|
||||||
|
emitter.instructions << Ir::DrawInstruction.new free, free + 1, 5
|
||||||
|
# Load variables from RO-R2 back
|
||||||
|
emitter.to_stack
|
||||||
|
emitter.restore 0x2
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
return Compiler::FunctionType.new([Compiler::Type::U8] * 3, Compiler::Type::U0)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,33 @@ module Chalk
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Instruction to clear the screen
|
||||||
|
class ClearInstruction < Instruction
|
||||||
|
def to_s(io)
|
||||||
|
io << "clear"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(table, stack, index)
|
||||||
|
return 0x00e0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Instruction to assign a random value to a register.
|
||||||
|
class RandomInstruction < Instruction
|
||||||
|
def initialize(@register : Int32, @value : Int32)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(io)
|
||||||
|
io << "rand R"
|
||||||
|
@register.to_s(16, io)
|
||||||
|
io << " " << @value
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(table, stack, index)
|
||||||
|
return 0xc000 | (@register << 8) | (@value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Instruction to load a value into a register.
|
# Instruction to load a value into a register.
|
||||||
class LoadInstruction < Instruction
|
class LoadInstruction < Instruction
|
||||||
def initialize(@register : Int32, @value : Int32)
|
def initialize(@register : Int32, @value : Int32)
|
||||||
|
@ -367,5 +394,34 @@ module Chalk
|
||||||
return 0xf007 | (@into << 8)
|
return 0xf007 | (@into << 8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Instruction to set the sound timer to a value.
|
||||||
|
class SetSoundTimerInstruction < Instruction
|
||||||
|
def initialize(@from : Int32)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(io)
|
||||||
|
io << "set_sound R"
|
||||||
|
@from.to_s(16, io)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(table, stack, index)
|
||||||
|
return 0xf018 | (@from << 8)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class BCDInstruction < Instruction
|
||||||
|
def initialize(@from : Int32)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(io)
|
||||||
|
io << "bcd R"
|
||||||
|
@from.to_s(16, io)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_bin(table, stack, index)
|
||||||
|
return 0xf033 | (@from << 8)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue