elna/boot/stage1.s

1754 lines
30 KiB
ArmAsm

.global _start # Program entry point.
# Global variables or registers.
# s1 - Contains the current position in the source text.
# s2 - Label counter.
.equ SOURCE_BUFFER_SIZE, 81920
.section .rodata
section_rodata: .ascii ".section .rodata\n"
.equ SECTION_RODATA_SIZE, . - section_rodata
section_text: .ascii ".section .text\n"
.equ SECTION_TEXT_SIZE, . - section_text
section_bss: .ascii ".section .bss\n"
.equ SECTION_BSS_SIZE, . - section_bss
global_start: .ascii ".global _start\n"
.equ GLOBAL_START_SIZE, . - global_start
prologue: .ascii "addi sp, sp, -96\nsw ra, 92(sp)\nsw s0, 88(sp)\naddi s0, sp, 96\n"
.equ PROLOGUE_SIZE, . - prologue
epilogue: .ascii "lw ra, 92(sp)\nlw s0, 88(sp)\naddi sp, sp, 96\nret\n"
.equ EPILOGUE_SIZE, . - epilogue
asm_exit: .ascii "li a0, 0\nli a7, 93\necall\n"
.equ ASM_EXIT_SIZE, . - asm_exit
asm_start: .ascii ".type _start, @function\n_start:\n"
.equ ASM_START_SIZE, . - asm_start
asm_and_a0_a1: .ascii "and a0, a0, a1\n"
.equ ASM_AND_A0_A1_SIZE, . - asm_and_a0_a1
asm_or_a0_a1: .ascii "or a0, a0, a1\n"
.equ ASM_OR_A0_A1_SIZE, . - asm_or_a0_a1
asm_add_a0_a1: .ascii "add a0, a0, a1\n"
.equ ASM_ADD_A0_A1_SIZE, . - asm_add_a0_a1
asm_sub_a0_a1: .ascii "sub a0, a0, a1\n"
.equ ASM_SUB_A0_A1_SIZE, . - asm_sub_a0_a1
asm_mul_a0_a1: .ascii "mul a0, a0, a1\n"
.equ ASM_MUL_A0_A1_SIZE, . - asm_mul_a0_a1
asm_seqz_a0: .ascii "seqz a0, a0\n"
.equ ASM_SEQZ_A0_SIZE, . - asm_seqz_a0
asm_neg_a0: .ascii "neg a0, a0\n"
.equ ASM_NEG_A0_SIZE, . - asm_neg_a0
asm_type: .ascii ".type "
.equ ASM_TYPE_SIZE, . - asm_type
asm_restore_parameters:
.ascii "lw a0, 60(sp)\nlw a1, 56(sp)\nlw a2, 52(sp)\nlw a3, 48(sp)\nlw a4, 44(sp)\nlw a5, 40(sp)\n"
.equ ASM_RESTORE_PARAMETERS_SIZE, . - asm_restore_parameters
.section .bss
.type source_code, @object
.size source_code, SOURCE_BUFFER_SIZE
source_code: .zero SOURCE_BUFFER_SIZE
.section .text
# Ignores the import.
.type _compile_import, @function
_compile_import:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
addi s1, s1, 6
call _skip_spaces
call _read_token
add s1, s1, a0 # Skip the imported module name.
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
.type _build_binary_expression, @function
_build_binary_expression:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
li a0, 0
call _build_expression
call _skip_spaces
call _read_token
sw a0, 20(sp)
li t0, '&'
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_and
li t0, 0x726f # or
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_or
li t0, '='
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_equal
li t0, '+'
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_plus
li t0, '-'
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_minus
li t0, '*'
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_product
j .Lbuild_binary_expression_end
.L_build_binary_expression_equal:
addi s1, s1, 1 # Skip =.
li a0, 1
call _build_expression
la a0, asm_sub_a0_a1
li a1, ASM_SUB_A0_A1_SIZE
call _write_out
la a0, asm_seqz_a0
li a1, ASM_SEQZ_A0_SIZE
call _write_out
j .Lbuild_binary_expression_end
.L_build_binary_expression_and:
addi s1, s1, 1 # Skip &.
li a0, 1
call _build_expression
la a0, asm_and_a0_a1
li a1, ASM_AND_A0_A1_SIZE
call _write_out
j .Lbuild_binary_expression_end
.L_build_binary_expression_or:
addi s1, s1, 2 # Skip or.
li a0, 1
call _build_expression
la a0, asm_or_a0_a1
li a1, ASM_OR_A0_A1_SIZE
call _write_out
j .Lbuild_binary_expression_end
.L_build_binary_expression_plus:
addi s1, s1, 1 # Skip +.
li a0, 1
call _build_expression
la a0, asm_add_a0_a1
li a1, ASM_ADD_A0_A1_SIZE
call _write_out
j .Lbuild_binary_expression_end
.L_build_binary_expression_minus:
addi s1, s1, 1 # Skip -.
li a0, 1
call _build_expression
la a0, asm_sub_a0_a1
li a1, ASM_SUB_A0_A1_SIZE
call _write_out
j .Lbuild_binary_expression_end
.L_build_binary_expression_product:
addi s1, s1, 1 # Skip *.
li a0, 1
call _build_expression
la a0, asm_mul_a0_a1
li a1, ASM_MUL_A0_A1_SIZE
call _write_out
j .Lbuild_binary_expression_end
.Lbuild_binary_expression_end:
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Evalutes an expression and saves the result in a0.
#
# a0 - X in aX, the register number to save the result.
.type _build_expression, @function
_build_expression:
# Prologue.
addi sp, sp, -40
sw ra, 36(sp)
sw s0, 32(sp)
addi s0, sp, 40
addi a0, a0, '0' # Make the register number to a character.
sw a0, 28(sp) # And save it.
call _skip_spaces
call _read_token
sw s1, 24(sp)
sw a0, 20(sp)
lbu a0, (s1)
li t0, '-'
beq a0, t0, .Lbuild_expression_negate
lbu a0, (s1)
li t0, '@'
beq a0, t0, .Lbuild_expression_address
lbu a0, (s1)
call _is_digit
bnez a0, .Lbuild_expression_literal
lbu a0, (s1)
li t0, '_'
beq a0, t0, .Lbuild_expression_call
li t0, 0x61636f6c # loca
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 4
call _memcmp
beqz a0, .Lbuild_expression_identifier
# Named identifier.
lw t1, 28(sp)
li t0, 0x00202c00 # \0,_
or t0, t0, t1
sw t0, 8(sp)
li t0, 0x6120616c # la a
sw t0, 4(sp)
addi a0, sp, 4
li a1, 7
call _write_out
lw a0, 24(sp)
lw a1, 20(sp)
call _write_out
li a0, '\n'
call _put_char
j .Lbuild_expression_advance
.Lbuild_expression_negate:
addi s1, s1, 1 # Skip the -.
mv a0, zero
call _build_expression
la a0, asm_neg_a0
li a1, ASM_NEG_A0_SIZE
call _write_out
j .Lbuild_expression_advance
.Lbuild_expression_address:
lw t1, 28(sp)
li t0, 0x20 # _
sw t0, 16(sp)
li t0, 0x2c707320 # _sp,
sw t0, 12(sp)
li t0, 0x2c006120 # _a\0,
sw t0, 8(sp)
sb t1, 10(sp)
li t0, 0x69646461 # addi
sw t0, 4(sp)
addi a0, sp, 4
li a1, 13
call _write_out
addi s1, s1, 1 # Skip @.
call _skip_spaces
call _read_token
sw s1, 24(sp)
sw a0, 20(sp)
lw a0, 24(sp)
lw a1, 20(sp)
addi a0, a0, 4 # Skip the "loca" variable prefix.
addi a1, a1, -4 # Skip the "loca" variable prefix.
call _write_out
li a0, '\n'
call _put_char
j .Lbuild_expression_advance
.Lbuild_expression_identifier:
lw t1, 28(sp)
li t0, 0x00202c00 # \0,_
or t0, t0, t1
sw t0, 16(sp)
li t0, 0x6120776c # lw a
sw t0, 12(sp)
addi a0, sp, 12
li a1, 7
call _write_out
lw a0, 24(sp)
lw a1, 20(sp)
addi a0, a0, 4 # Skip the "loca" variable prefix.
addi a1, a1, -4 # Skip the "loca" variable prefix.
call _write_out
li t0, '\n'
sw t0, 16(sp)
li t0, 0x29707328 # (sp)
sw t0, 12(sp)
addi a0, sp, 12
li a1, 5
call _write_out
j .Lbuild_expression_advance
.Lbuild_expression_call:
lw a0, 24(sp)
lw a1, 20(sp)
add s1, s1, a1
addi s1, s1, 1
call _compile_call
j .Lbuild_expression_end
.Lbuild_expression_literal:
lw t1, 28(sp)
li t0, 0x00202c00 # \0,_
or t0, t0, t1
sw t0, 16(sp)
li t0, 0x6120696c # li a
sw t0, 12(sp)
addi a0, sp, 12
li a1, 7
call _write_out
lw a0, 24(sp)
lw a1, 20(sp)
call _write_out
li a0, '\n'
call _put_char
j .Lbuild_expression_advance
.Lbuild_expression_advance:
lw a0, 20(sp)
add s1, s1, a0
.Lbuild_expression_end:
# Epilogue.
lw ra, 36(sp)
lw s0, 32(sp)
addi sp, sp, 40
ret
# Compiles a statement beginning with an identifier.
#
# Left values should be variables named "loca n", where n is the offset
# of the variable on the stack, like loca8 or loca4.
.type _compile_identifier, @function
_compile_identifier:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
call _read_token
# Save the pointer to the identifier and its length on the stack.
sw s1, 20(sp)
sw a0, 16(sp)
add s1, s1, a0
call _skip_spaces
call _read_token
# Save the pointer and the length of the token following the identifier.
sw s1, 12(sp)
sw a0, 8(sp)
add s1, s1, a0 # Skip that token.
call _skip_spaces
li t0, 0x3d3a # :=
sw t0, 4(sp)
lw a0, 12(sp)
lw a1, 8(sp)
addi a2, sp, 4
call _token_compare
beqz a0, .Lcompile_identifier_assign
lw t0, 12(sp)
lbu t0, (t0)
li t1, 0x28 # (
beq t0, t1, .Lcompile_identifier_call
j .Lcompile_identifier_end
.Lcompile_identifier_call:
lw a0, 20(sp)
lw a1, 16(sp)
call _compile_call
j .Lcompile_identifier_end
.Lcompile_identifier_assign:
call _build_binary_expression
li t0, 0x202c30 # 0,_
sw t0, 12(sp)
li t0, 0x61207773 # sw a
sw t0, 8(sp)
addi a0, sp, 8
li a1, 7
call _write_out
lw a0, 20(sp)
lw a1, 16(sp)
addi a0, a0, 4 # Skip the "loca" variable prefix.
addi a1, a1, -4 # Skip the "loca" variable prefix.
call _write_out
li t0, '\n'
sw t0, 12(sp)
li t0, 0x29707328 # (sp)
sw t0, 8(sp)
addi a0, sp, 8
li a1, 5
call _write_out
j .Lcompile_identifier_end
.Lcompile_identifier_end:
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Compiles a procedure call. Expects s1 to point to the first argument.
# a0 - Pointer to the procedure name.
# a1 - Length of the procedure name.
#
# Returns the procedure result in a0.
.type _compile_call, @function
_compile_call:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
sw a0, 20(sp)
sw a1, 16(sp)
sw zero, 12(sp) # Argument count for a procedure call.
.Lcompile_call_paren:
call _skip_spaces
lbu t0, (s1)
li t1, 0x29 # )
beq t0, t1, .Lcompile_call_complete
.Lcompile_call_argument:
li a0, 0
call _build_expression
li t0, 0x202c30 # 0,_
sw t0, 8(sp)
li t0, 0x61207773 # sw a
sw t0, 4(sp)
addi a0, sp, 4
li a1, 7
call _write_out
lw t0, 12(sp) # Argument count for a procedure call.
# Only 6 arguments are supported with a0-a5.
# Save all arguments on the stack so they aren't overriden afterwards.
li a0, -4
mul a0, t0, a0
addi a0, a0, 60
call _printi
li t0, '\n'
sw t0, 8(sp)
li t0, 0x29707328 # (sp)
sw t0, 4(sp)
addi a0, sp, 4
li a1, 5
call _write_out
call _skip_spaces
lbu t0, (s1)
li t1, ','
bne t0, t1, .Lcompile_call_paren
lw t0, 12(sp) # Argument count for a procedure call.
addi t0, t0, 1
sw t0, 12(sp)
addi s1, s1, 1 # Skip the comma between the arguments.
j .Lcompile_call_argument
.Lcompile_call_complete:
sw zero, 12(sp)
.Lcompile_call_restore:
# Just go through all a0-a5 registers and read them from stack.
# If this stack value contains garbage, the procedure just shouldn't use it.
la a0, asm_restore_parameters
li a1, ASM_RESTORE_PARAMETERS_SIZE
call _write_out
.Lcompile_call_perform:
li t0, 0x20
sw t0, 8(sp)
li t0, 0x6c6c6163 # call
sw t0, 4(sp)
addi a0, sp, 4
li a1, 5
call _write_out
lw a0, 20(sp)
lw a1, 16(sp)
call _write_out
li a0, '\n'
call _put_char
call _skip_spaces
addi s1, s1, 1 # Skip the close paren.
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Reads a token and returns its length in a0.
# _read_token doesn't change s1, it finds the length of the token s1 is pointing to.
.type _read_token, @function
_read_token:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
lbu t0, (s1) # t0 = Current character.
sw zero, 4(sp)
li t1, '.'
beq t0, t1, .Ltoken_character_single
li t1, ','
beq t0, t1, .Ltoken_character_single
li t1, ':'
beq t0, t1, .Ltoken_character_colon
li t1, ';'
beq t0, t1, .Ltoken_character_single
li t1, '('
beq t0, t1, .Ltoken_character_single
li t1, ')'
beq t0, t1, .Ltoken_character_single
li t1, '['
beq t0, t1, .Ltoken_character_single
li t1, ']'
beq t0, t1, .Ltoken_character_single
li t1, '^'
beq t0, t1, .Ltoken_character_single
li t1, '&'
beq t0, t1, .Ltoken_character_single
li t1, '='
beq t0, t1, .Ltoken_character_single
li t1, '+'
beq t0, t1, .Ltoken_character_single
li t1, '-'
beq t0, t1, .Ltoken_character_single
li t1, '*'
beq t0, t1, .Ltoken_character_single
li t1, '@'
beq t0, t1, .Ltoken_character_single
# Expect an identifier or a number.
.Ltoken_character_loop_do:
lw t6, 4(sp)
add t1, s1, t6
lbu a0, (t1) # a0 = Current character.
call _is_alnum
beqz a0, .Ltoken_character_end
lw t6, 4(sp)
addi t6, t6, 1
sw t6, 4(sp)
j .Ltoken_character_loop_do
.Ltoken_character_single:
lw t6, 4(sp)
addi t6, t6, 1
sw t6, 4(sp)
j .Ltoken_character_end
.Ltoken_character_colon:
lbu t0, 1(s1) # t0 = The character after the colon.
lw t6, 4(sp)
addi t6, t6, 1
sw t6, 4(sp)
li t1, '='
beq t0, t1, .Ltoken_character_single
j .Ltoken_character_end
.Ltoken_character_end:
lw a0, 4(sp)
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
# Skips the spaces till the next non space character.
.type _skip_spaces, @function
_skip_spaces:
.Lspace_loop_do:
lbu t0, (s1) # t0 = Current character.
li t1, ' '
beq t0, t1, .Lspace_loop_repeat
li t1, '\t'
beq t0, t1, .Lspace_loop_repeat
li t1, '\n'
beq t0, t1, .Lspace_loop_repeat
li t1, '\r'
beq t0, t1, .Lspace_loop_repeat
j .Lspace_loop_end
.Lspace_loop_repeat:
addi s1, s1, 1
j .Lspace_loop_do
.Lspace_loop_end:
ret
# Skips tabs at the line beginning.
.type _skip_indentation, @function
_skip_indentation:
.Lskip_indentation_do:
lbu t0, (s1)
li t1, '\t'
beq t0, t1, .Lskip_indentation_skip
j .Lskip_indentation_end
.Lskip_indentation_skip:
addi s1, s1, 1
j .Lskip_indentation_do
.Lskip_indentation_end:
ret
# Parameters:
# a0 - Line length.
.type _skip_comment, @function
_skip_comment:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
# Check whether this is a comment.
li t0, 0x2a28 # (*
sw t0, 4(sp)
addi a0, sp, 4
mv a1, s1
li a2, 2
call _memcmp
bnez a0, .Lskip_comment_end
addi s1, s1, 2 # Skip (*.
li t0, 0x292a # *)
sw t0, 4(sp)
.Lskip_comment_loop:
addi a0, sp, 4
mv a1, s1
li a2, 2
call _memcmp
beqz a0, .Lskip_comment_close
addi s1, s1, 1
j .Lskip_comment_loop
.Lskip_comment_close:
addi s1, s1, 2 # Skip *).
.Lskip_comment_end:
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
# Parameters:
# a0 - Line length.
.type _compile_assembly, @function
_compile_assembly:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, 4(sp) # a0 - Line length.
# Write the source to the standard output.
mv a0, s1
lw a1, 4(sp)
call _write_out
lw t0, 4(sp)
add s1, s1, t0
li a0, '\n'
call _put_char
addi s1, s1, 1 # Skip the new line.
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
.type _compile_program, @function
_compile_program:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
la a0, global_start
li a1, GLOBAL_START_SIZE
call _write_out
addi s1, s1, 8 # program\n.
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
.type _compile_constant_section, @function
_compile_constant_section:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
la a0, section_rodata
li a1, SECTION_RODATA_SIZE
call _write_out
addi s1, s1, 6 # const\n.
.Lcompile_constant_section_item:
call _skip_spaces
lbu a0, (s1)
call _is_upper
beqz a0, .Lcompile_constant_section_end
call _compile_constant
j .Lcompile_constant_section_item
.Lcompile_constant_section_end:
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
.type _compile_constant, @function
_compile_constant:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
call _read_token
mv a1, a0 # The identifier length from _read_token should be in a1.
mv a0, s1 # Save the identifier pointer before advancing it.
add s1, s1, a1
call _write_out
call _skip_spaces
addi s1, s1, 2 # Skip the assignment sign.
# : .long
li t0, 0x20676e6f # ong_
sw t0, 4(sp)
li t0, 0x6c2e203a # : .l
sw t0, 0(sp)
mv a0, sp
li a1, 8
call _write_out
call _skip_spaces
call _read_token
mv a1, a0 # The literal length from _read_token should be in a1.
mv a0, s1 # Save the literal pointer before advancing it.
add s1, s1, a1
call _write_out
li a0, '\n'
call _put_char
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
.type _compile_variable_section, @function
_compile_variable_section:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
la a0, section_bss
li a1, SECTION_BSS_SIZE
call _write_out
addi s1, s1, 4 # var\n.
.Lcompile_variable_section_item:
call _skip_spaces
lbu a0, (s1)
call _is_lower
beqz a0, .Lcompile_variable_section_end
call _compile_variable
j .Lcompile_variable_section_item
.Lcompile_variable_section_end:
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
.type _compile_variable, @function
_compile_variable:
# Prologue.
addi sp, sp, -40
sw ra, 36(sp)
sw s0, 32(sp)
addi s0, sp, 40
call _read_token
# Save the identifier on the stack since it should emitted multiple times.
sw s1, 28(sp)
sw a0, 24(sp)
add s1, s1, a0
call _skip_spaces
addi s1, s1, 1 # Skip the colon in front of the type.
call _skip_spaces
addi s1, s1, 1 # Skip the opening bracket.
call _read_token
# Save the array size on the stack since it has to be emitted multiple times.
sw s1, 20(sp)
sw a0, 16(sp)
add s1, s1, a0
call _skip_spaces
addi s1, s1, 1 # Skip the closing bracket.
call _skip_spaces
call _read_token
add s1, s1, a0 # Skip the type.
# .type identifier, @object
la a0, asm_type
li a1, ASM_TYPE_SIZE
call _write_out
lw a0, 28(sp)
lw a1, 24(sp)
call _write_out
li t0, 0x0a74 # t\n
sw t0, 12(sp)
li t0, 0x63656a62 # bjec
sw t0, 8(sp)
li t0, 0x6f40202c # , @o
sw t0, 4(sp)
addi a0, sp, 4
li a1, 10
call _write_out
# .size identifier, size
li t0, 0x2065 # e_
sw t0, 12(sp)
li t0, 0x7a69732e # .siz
sw t0, 8(sp)
addi a0, sp, 8
li a1, 6
call _write_out
lw a0, 28(sp)
lw a1, 24(sp)
call _write_out
li t0, 0x202c # ,_
sw t0, 12(sp)
addi a0, sp, 12
li a1, 2
call _write_out
lw a0, 20(sp)
lw a1, 16(sp)
call _write_out
li a0, '\n'
call _put_char
# identifier: .zero size
lw a0, 28(sp)
lw a1, 24(sp)
call _write_out
li t0, 0x206f7265 # ero_
sw t0, 12(sp)
li t0, 0x7a2e203a # : .z
sw t0, 8(sp)
addi a0, sp, 8
li a1, 8
call _write_out
lw a0, 20(sp)
lw a1, 16(sp)
call _write_out
li a0, '\n'
call _put_char
# Epilogue.
lw ra, 36(sp)
lw s0, 32(sp)
addi sp, sp, 40
ret
.type _compile_procedure, @function
_compile_procedure:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
addi s1, s1, 5 # Skip proc_
call _read_token
sw s1, 20(sp)
sw a0, 16(sp)
add s1, s1, a0
# .type identifier, @function
la a0, asm_type
li a1, ASM_TYPE_SIZE
call _write_out
lw a0, 20(sp)
lw a1, 16(sp)
call _write_out
li t0, 0x0a6e6f69 # ion\n
sw t0, 12(sp)
li t0, 0x74636e75 # unct
sw t0, 8(sp)
li t0, 0x6640202c # , @f
sw t0, 4(sp)
addi a0, sp, 4
li a1, 12
call _write_out
lw a0, 20(sp)
lw a1, 16(sp)
call _write_out
li t0, 0x0a3a # :\n
sw t0, 12(sp)
addi a0, sp, 12
li a1, 2
call _write_out
call _skip_spaces
addi s1, s1, 1 # Skip opening argument paren.
call _skip_spaces
addi s1, s1, 1 # Skip closing argument paren.
li t0, 0x6e # n
sw t0, 12(sp)
li t0, 0x69676562 # begi
sw t0, 8(sp)
# Skip all declarations until we find the "begin" keyword, denoting the
# beginning of the procedure body.
.Lcompile_procedure_begin:
call _skip_spaces
call _read_token
mv a1, a0
mv a0, s1
addi a2, sp, 8
add s1, s1, a1
call _token_compare
bnez a0, .Lcompile_procedure_begin
# Generate the procedure prologue with a predefined stack size.
la a0, prologue
li a1, PROLOGUE_SIZE
call _write_out
# Save passed arguments on the stack.
li t0, 0x0a29 # )\n
sw t0, 12(sp)
li t0, 0x70732834 # 4(sp
sw t0, 8(sp)
li t0, 0x38202c30 # 0, 8
sw t0, 4(sp)
li t0, 0x61207773 # sw a
sw t0, 0(sp)
addi a0, sp, 0
li a1, 14
call _write_out
li t0, '0'
sb t0, 8(sp)
li t0, 0x38202c31 # 1, 8
sw t0, 4(sp)
addi a0, sp, 0
li a1, 14
call _write_out
li t0, '6'
sb t0, 8(sp)
li t0, 0x37202c32 # 2, 7
sw t0, 4(sp)
addi a0, sp, 0
li a1, 14
call _write_out
li t0, '2'
sb t0, 8(sp)
li t0, 0x37202c33 # 3, 7
sw t0, 4(sp)
addi a0, sp, 0
li a1, 14
call _write_out
li t0, '8'
sb t0, 8(sp)
li t0, 0x36202c34 # 4, 6
sw t0, 4(sp)
addi a0, sp, 0
li a1, 14
call _write_out
li t0, '4'
sb t0, 8(sp)
li t0, 0x36202c35 # 5, 6
sw t0, 4(sp)
addi a0, sp, 0
li a1, 14
call _write_out
# Generate the body of the procedure.
.Lcompile_procedure_body:
call _skip_indentation
call _read_line
sw a0, 12(sp)
li t0, 0x0a646e65 # end\n
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 4
call _memcmp
beqz a0, .Lcompile_procedure_end
lw a0, 12(sp)
call _compile_line
j .Lcompile_procedure_body
.Lcompile_procedure_end:
add s1, s1, 4 # Skip end\n.
# Generate the procedure epilogue with a predefined stack size.
la a0, epilogue
li a1, EPILOGUE_SIZE
call _write_out
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Compares two string, which of one has a length, the other one is null-terminated.
#
# a0 - The address of the token string.
# a1 - The length of the string in a0.
# a2 - The address of the null-terminated string.
#
# If the strings match sets a0 to 0, otherwise sets it to 1.
.type _token_compare, @function
_token_compare:
addi t0, a0, 0
addi t1, a1, 0
addi t2, a2, 0
.Ltoken_compare_loop:
lbu t3, (t2)
# Will only be 0 if the current character in the null terminated string is \0 and the remaining length of the
# another string is 0.
or t4, t3, t1
beqz t4, .Ltoken_compare_equal
beqz t1, .Ltoken_compare_not_equal
beqz t3, .Ltoken_compare_not_equal
lbu t4, (t0)
bne t3, t4, .Ltoken_compare_not_equal
addi t0, t0, 1
addi t1, t1, -1
addi t2, t2, 1
j .Ltoken_compare_loop
.Ltoken_compare_not_equal:
li a0, 1
j .Ltoken_compare_end
.Ltoken_compare_equal:
li a0, 0
.Ltoken_compare_end:
ret
.type _compile_goto, @function
_compile_goto:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
addi s1, s1, 4 # Skip the goto keyword.
li t0, 0x206a # j_
sw t0, 8(sp)
addi a0, sp, 8
li a1, 2
call _write_out
call _skip_spaces
sw s1, 8(sp) # We should be on dot the label is beginning with.
addi s1, s1, 1
call _read_token
add s1, s1, a0
addi a1, a0, 1 # Label length and the dot.
lw a0, 8(sp) # Saved dot position.
call _write_out
addi s1, s1, 1 # Skip the new line.
li a0, '\n'
call _put_char
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
# a0 - Line length.
.type _compile_label, @function
_compile_label:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw a0, 0(sp) # Save the line length.
# Write the whole line as is.
mv a0, s1
lw a1, 0(sp)
call _write_out
lw t0, 0(sp) # Line length.
mv t1, s1 # Line start.
add t1, t1, t0
addi t1, t1, -1 # Last character on the line.
lbu t1, (t1)
li t2, ':'
beq t1, t2, .Lcompile_label_colon
li t0, 0x3a # :
sw t0, 4(sp)
addi a0, sp, 4
li a1, 1
call _write_out
.Lcompile_label_colon:
li t0, '\n'
sw t0, 4(sp)
addi a0, sp, 4
li a1, 1
call _write_out
lw a0, 0(sp)
addi a0, a0, 1 # Skip the new line as well.
add s1, s1, a0 # Skip the line.
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
.type _compile_return, @function
_compile_return:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
addi s1, s1, 6 # Skip return.
call _skip_spaces
call _build_binary_expression
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
.type _compile_if, @function
_compile_if:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
addi s1, s1, 2 # Skip the if.
call _skip_spaces
call _build_binary_expression
call _skip_spaces
addi s1, s1, 4 # Skip the then.
# if end marker.
li t0, 0x00646e65 # end\0
sw t0, 20(sp)
# Label prefix.
li t0, 0x66694c2e # .Lif
sw t0, 16(sp)
li t0, 0x202c3061 # a0,_
sw t0, 12(sp)
li t0, 0x207a7165 # eqz_
sw t0, 8(sp)
li t0, 0x62626262 # bbbb
sb t0, 7(sp)
addi a0, sp, 7
li a1, 13
call _write_out
# Write the label counter.
mv a0, s2
call _printi
li a0, '\n'
call _put_char
.Lcompile_if_loop:
/* DEBUG
mv a0, s1
li a1, 6
call _write_error
call _divide_by_zero_error */
call _skip_spaces
call _read_token
mv a1, a0
mv a0, s1
addi a2, sp, 20
call _token_compare
beqz a0, .Lcompile_if_end
call _read_line
li a1, 1
call _compile_line
j .Lcompile_if_loop
.Lcompile_if_end:
# Write the label prefix.
addi a0, sp, 16
li a1, 4
call _write_out
# Write the label counter.
mv a0, s2
call _printi
# Finalize the label.
li t0, 0x0a3a0a3a # :\n:\n
sh t0, 12(sp)
addi a0, sp, 12
li a1, 2
call _write_out
addi s2, s2, 1 # Increment the label counter.
addi s1, s1, 4 # Skip the end with newline.
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Parameters:
# a0 - Line length.
# a1 - Whether the section header was already emitted. If not it should be
# emitted before any code is written.
#
# Returns 1 in a0 if the parsed line contained a text section element such a
# procedure or the program entry point. Otherwise sets a0 to 0.
.type _compile_line, @function
_compile_line:
# Prologue.
addi sp, sp, -32
sw ra, 28(sp)
sw s0, 24(sp)
addi s0, sp, 32
# Preserve passed arguments.
sw a0, 20(sp)
sw a1, 16(sp)
beqz a0, .Lcompile_line_empty # Skip an empty line.
lbu t0, (s1)
li t1, '('
beq t0, t1, .Lcompile_line_comment
li t0, 0x0a6d6172 # ram\n
sw t0, 12(sp)
li t0, 0x676f7270 # prog
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 8
call _memcmp
beqz a0, .Lcompile_line_program
li t0, 0x0a74 # t\n
sw t0, 12(sp)
li t0, 0x736e6f63 # cons
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_const
li t0, 0x0a726176 # var\n
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_var
li t0, 0x20 # _
sw t0, 12(sp)
li t0, 0x636f7270 # proc
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 5
call _memcmp
beqz a0, .Lcompile_line_procedure
li t0, 0x0a6e # n\n
sw t0, 12(sp)
li t0, 0x69676562 # begi
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_begin
li t0, 0x2e646e65 # end.
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_exit
li t0, 0x61636f6c # loca
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_identifier
li t0, 0x7472 # rt
sw t0, 12(sp)
li t0, 0x6f706d69 # impo
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_import
li t0, 0x6f746f67 # goto
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_goto
li t0, 0x6e72 # rn
sw t0, 12(sp)
li t0, 0x75746572 # retu
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_return
li t0, 0x6669 # if
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 2
call _memcmp
beqz a0, .Lcompile_line_if
lbu t0, (s1)
li t1, '.'
beq t0, t1, .Lcompile_line_label
li t1, '_'
beq t0, t1, .Lcompile_line_identifier
j .Lcompile_line_unchanged # Else.
.Lcompile_line_if:
call _compile_if
j .Lcompile_line_section
.Lcompile_line_label:
lw a0, 20(sp)
call _compile_label
j .Lcompile_line_section
.Lcompile_line_return:
call _compile_return
j .Lcompile_line_section
.Lcompile_line_goto:
call _compile_goto
j .Lcompile_line_section
.Lcompile_line_import:
call _compile_import
j .Lcompile_line_section
.Lcompile_line_identifier:
call _compile_identifier
j .Lcompile_line_section
.Lcompile_line_exit:
call _compile_exit
j .Lcompile_line_section
.Lcompile_line_begin:
lw a1, 16(sp)
bnez a1, .Lcompile_line_compile_entry
call _compile_text_section
.Lcompile_line_compile_entry:
call _compile_entry_point
li a0, 1
j .Lcompile_line_end
.Lcompile_line_const:
call _compile_constant_section
j .Lcompile_line_section
.Lcompile_line_procedure:
lw a1, 16(sp)
bnez a1, .Lcompile_line_compile_procedure
call _compile_text_section
.Lcompile_line_compile_procedure:
call _compile_procedure
li a0, 1
j .Lcompile_line_end
.Lcompile_line_var:
call _compile_variable_section
j .Lcompile_line_section
.Lcompile_line_program:
call _compile_program
j .Lcompile_line_section
.Lcompile_line_comment:
lw a0, 20(sp)
call _skip_comment
j .Lcompile_line_section
.Lcompile_line_empty:
addi s1, s1, 1
j .Lcompile_line_section
.Lcompile_line_unchanged:
lw a0, 20(sp)
call _compile_assembly
j .Lcompile_line_section
.Lcompile_line_section:
mv a0, zero
.Lcompile_line_end:
sw a0, 12(sp)
call _skip_spaces
call _skip_comment
lw a0, 12(sp)
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
addi sp, sp, 32
ret
# Prints ".section .text" and exits.
.type _compile_text_section, @function
_compile_text_section:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
la a0, section_text
li a1, SECTION_TEXT_SIZE
call _write_out
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
.type _compile_entry_point, @function
_compile_entry_point:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
# .type _start, @function
la a0, asm_start
li a1, ASM_START_SIZE
call _write_out
addi s1, s1, 6 # Skip begin\n.
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
.type _compile_exit, @function
_compile_exit:
# Prologue.
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
addi s0, sp, 8
la a0, asm_exit
li a1, ASM_EXIT_SIZE
call _write_out
addi s1, s1, 4 # Skip end.
call _skip_spaces # Read the possible new line at the end of the file.
# Epilogue.
lw ra, 4(sp)
lw s0, 0(sp)
addi sp, sp, 8
ret
# Finds the end of the line and returns its length in a0.
.type _read_line, @function
_read_line:
mv t0, s1 # Local position in the source text.
.Lread_line_do:
lbu t1, (t0) # t1 = Current character.
beqz t1, .Lread_line_end # Exit the loop on the NUL character.
li t2, '\n'
beq t1, t2, .Lread_line_end # Exit the loop on the new line.
addi t0, t0, 1
j .Lread_line_do
.Lread_line_end:
sub a0, t0, s1 # Return the line length.
ret
.type _compile, @function
_compile:
# Prologue.
addi sp, sp, -16
sw ra, 12(sp)
sw s0, 8(sp)
addi s0, sp, 16
sw zero, 4(sp) # Whether the text section header was already emitted.
.Lcompile_do:
lbu t0, (s1) # t0 = Current character.
beqz t0, .Lcompile_end # Exit the loop on the NUL character.
call _skip_indentation
call _read_line
lw a1, 4(sp)
call _compile_line
beqz a0, .Lcompile_do
# Update whether the text section header was already emitted.
lw t0, 4(sp)
or t0, t0, a0
sw t0, 4(sp)
j .Lcompile_do
.Lcompile_end:
# Epilogue.
lw ra, 12(sp)
lw s0, 8(sp)
addi sp, sp, 16
ret
# Entry point.
.type _start, @function
_start:
# Read the source from the standard input.
la a0, source_code
li a1, SOURCE_BUFFER_SIZE # Buffer size.
call _read_file
li s2, 1
la s1, source_code # s1 = Source code position.
call _compile
# Call exit.
li a0, 0 # Use 0 return code.
call _exit