Compare commits

...

3 Commits

6 changed files with 124 additions and 75 deletions

View File

@ -4,11 +4,8 @@ module Chalk
# that is provided by chalk's standard library, and therefore
# has predefined output.
abstract class BuiltinFunction
# Gets the number of parameters this function has.
getter param_count : Int32
# Creates a new function with *param_count* parameters.
def initialize(@param_count)
def initialize()
end
# Uses the given `Compiler::Emitter` to output code.
@ -22,11 +19,8 @@ module Chalk
# function also accepts trees rather than register numbers,
# and therefore can accept and manipulate trees.
abstract class InlineFunction
# Gets the number of parameters this function has.
getter param_count : Int32
# Creates a new function with *param_count* parameters.
def initialize(@param_count)
def initialize()
end
# Generates code like `Compiler::CodeGenerator` would.

View File

@ -8,11 +8,6 @@ module Chalk
class CodeGenerator
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.
getter instructions
@ -42,10 +37,7 @@ module Chalk
# `#generate!` call.
def generate!(tree, function : Trees::TreeFunction | Builtin::BuiltinFunction, table, target, free)
start_at = free
# Move I to stack
setis
# Get to correct stack position
addi STACK_REG
to_stack
# Store variables
store (start_at - 1) unless start_at == 0
# Increment I and stack position
@ -67,10 +59,7 @@ module Chalk
# Reduce stack pointer
load free, start_at
opr TokenType::OpSub, STACK_REG, free
# Move I to stack
setis
# Get to correct stack position
addi STACK_REG
to_stack
# Restore
restore (start_at - 1) unless start_at == 0
# Get call value into target
@ -96,12 +85,9 @@ module Chalk
generate! tree.right, table, free, free + 1
opr tree.op, target, free
when Trees::TreeCall
entry = table[tree.name]?
raise "Unknown function" unless entry &&
entry.is_a?(FunctionEntry)
function = entry.function
raise "Invalid call" if tree.params.size != function.param_count
generate! tree, function, table, target, free
entry = table[tree.name]?.not_nil!
raise "Unknown function" unless entry.is_a?(FunctionEntry)
generate! tree, entry.function, table, target, free
when Trees::TreeBlock
table = Table.new(table)
tree.children.each do |child|

View File

@ -53,11 +53,11 @@ module Chalk
end
@logger.debug("Done creating symbol table")
table["draw"] = FunctionEntry.new Builtin::InlineDrawFunction.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["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
end

View File

@ -1,8 +1,19 @@
module Chalk
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
# them into an existing array.
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*.
def load(into, value)
inst = Ir::LoadInstruction.new into, value.to_i32

View File

@ -3,31 +3,8 @@ require "./type"
module Chalk
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.
class InlineAwaitKeyFunction < InlineFunction
def initialize
@param_count = 0
end
def generate!(emitter, params, table, target, free)
emitter.instructions << Ir::AwaitKeyInstruction.new target
end
@ -36,31 +13,13 @@ module Chalk
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.
class InlineSetDelayFunction < 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::SetDelayTimerInstruction.new free
end
def type
return Compiler::FunctionType.new([Compiler::Type::U8], Compiler::Type::U0)
end
@ -68,10 +27,6 @@ module Chalk
# Inline function to get the delay timer.
class InlineGetDelayFunction < InlineFunction
def initialize
@param_count = 0
end
def generate!(emitter, params, table, target, free)
emitter.instructions << Ir::GetDelayTimerInstruction.new target
end
@ -79,5 +34,52 @@ module Chalk
return Compiler::FunctionType.new(([] of Compiler::Type), Compiler::Type::U8)
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

View File

@ -12,6 +12,33 @@ module Chalk
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.
class LoadInstruction < Instruction
def initialize(@register : Int32, @value : Int32)
@ -367,5 +394,34 @@ module Chalk
return 0xf007 | (@into << 8)
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