summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Rakefile37
-rw-r--r--boot/asm-boot.s894
-rw-r--r--boot/stage1.s (renamed from boot/echo-boot.s)675
-rw-r--r--boot/stage2.elna643
-rwxr-xr-xrun.rb46
5 files changed, 969 insertions, 1326 deletions
diff --git a/Rakefile b/Rakefile
index 86ca2e1..5976113 100644
--- a/Rakefile
+++ b/Rakefile
@@ -22,31 +22,44 @@ def assemble_stage(output, compiler, source)
end
desc 'Final stage'
-task default: ['build/stage2', 'boot/stage2.elna'] do |t|
- assembler, exe = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.elna' }
+task default: ['build/stage2b', 'build/stage2b.s', 'boot/stage2.elna'] do |t|
+ exe, previous_output, source = t.prerequisites
- File.open File::NULL, 'w' do |output|
- assemble_stage output, exe, assembler
- end
+ cat_arguments = ['cat', source]
+ compiler_arguments = [QEMU, '-L', SYSROOT, exe]
+ diff_arguments = ['diff', '-Nur', previous_output, '-']
+ Open3.pipeline(cat_arguments, compiler_arguments, diff_arguments)
end
directory 'build'
desc 'Initial stage'
-file 'build/stage1' => ['boot/echo-boot.s', 'boot/common-boot.s', 'build'] do |t|
- assembler = t.prerequisites.filter { |prerequisite| prerequisite.end_with? '.s' }
+file 'build/stage1' => ['boot/stage1.s', 'boot/common-boot.s', 'build'] do |t|
+ source = t.prerequisites.filter { |prerequisite| prerequisite.end_with? '.s' }
+
+ sh CROSS_GCC, '-nostdlib', '-o', t.name, *source
+end
- sh CROSS_GCC, '-nostdlib', '-o', t.name, *assembler
+file 'build/stage2a.s' => ['build/stage1', 'boot/stage2.elna'] do |t|
+ source, exe = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.elna' }
+
+ File.open t.name, 'w' do |output|
+ assemble_stage output, exe, source
+ end
+end
+
+file 'build/stage2a' => ['build/stage2a.s', 'boot/common-boot.s'] do |t|
+ sh CROSS_GCC, '-nostdlib', '-o', t.name, *t.prerequisites
end
-file 'build/stage2.s' => ['build/stage1', 'boot/stage2.elna'] do |t|
- assembler, exe = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.elna' }
+file 'build/stage2b.s' => ['build/stage2a', 'boot/stage2.elna'] do |t|
+ source, exe = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.elna' }
File.open t.name, 'w' do |output|
- assemble_stage output, exe, assembler
+ assemble_stage output, exe, source
end
end
-file 'build/stage2' => ['build/stage2.s', 'boot/common-boot.s'] do |t|
+file 'build/stage2b' => ['build/stage2b.s', 'boot/common-boot.s'] do |t|
sh CROSS_GCC, '-nostdlib', '-o', t.name, *t.prerequisites
end
diff --git a/boot/asm-boot.s b/boot/asm-boot.s
deleted file mode 100644
index fca0d3f..0000000
--- a/boot/asm-boot.s
+++ /dev/null
@@ -1,894 +0,0 @@
-# s1 - Contains the current position in the source text.
-
-.global _start # Program entry point.
-
-.section .rodata
-
-.equ SOURCE_BUFFER_SIZE, 2048
-
-asm_begin: .ascii ".text\n.global _start\n_start:\naddi sp, sp, -64\nsw ra, 60(sp)\nsw s0, 56(sp)\naddi s0, sp, 64\n"
-.equ ASM_BEGIN_SIZE, . - asm_begin
-asm_end: .ascii "addi a0, zero, 0\naddi a7, zero, 93\necall\nlw ra, 60(sp)\nlw s0, 56(sp)\naddi sp, sp, 64\nret\n"
-.equ ASM_END_SIZE, . - asm_end
-asm_program: .ascii ".bss\n"
-.equ ASM_PROGRAM_SIZE, . - asm_program
-asm_type: .ascii ".type "
-.equ ASM_TYPE_SIZE, . - asm_type
-asm_object: .ascii ", @object\n"
-.equ ASM_OBJECT_SIZE, . - asm_object
-asm_size: .ascii ".size "
-.equ ASM_SIZE_SIZE, . - asm_size
-asm_zero: .ascii ".zero "
-.equ ASM_ZERO_SIZE, . - asm_zero
-asm_global: .ascii ".global "
-.equ ASM_GLOBAL_SIZE, . - asm_global
-
-token_begin: .string "begin"
-token_end: .string "end"
-token_import: .string "import"
-token_open_paren: .string "("
-token_close_paren: .string ")"
-token_open_square: .string "["
-token_assign: .string ":="
-token_var: .string "var"
-token_comma: .string ","
-
-space: .ascii " "
-comma: .ascii ","
-new_line: .ascii "\n"
-colon: .ascii ":"
-digit_zero: .ascii "0"
-
-instruction_la: .ascii "la"
-instruction_call: .ascii "call"
-instruction_addi: .ascii "addi"
-instruction_li: .ascii "li"
-instruction_sw: .ascii "sw"
-instruction_lw: .ascii "lw"
-
-register_a0: .ascii "a0"
-register_sp: .ascii "sp"
-register_a: .ascii "a"
-
-.section .bss
-.global source_code
-.type source_code, @object
-.size source_code, SOURCE_BUFFER_SIZE
-source_code: .zero SOURCE_BUFFER_SIZE
-
-.section .text
-
-.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
-
-# 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
-
-# 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
-
-.Ltoken_character_loop_do: # Expect an identifier or a number.
- 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
-
-# Generate entry point symbol.
-.type _compile_begin, @function
-_compile_begin:
- # Prologue.
- addi sp, sp, -8
- sw ra, 4(sp)
- sw s0, 0(sp)
- addi s0, sp, 8
-
- # Write initial assembler.
- la a0, asm_begin
- addi a1, zero, ASM_BEGIN_SIZE
- call write_out
-
- addi s1, s1, 5
-
- # Epilogue.
- lw ra, 4(sp)
- lw s0, 0(sp)
- addi sp, sp, 8
- ret
-
-# Generate program termination code.
-.type _compile_end, @function
-_compile_end:
- # Prologue.
- addi sp, sp, -8
- sw ra, 4(sp)
- sw s0, 0(sp)
- addi s0, sp, 8
-
- # Write closing assembler.
- la a0, asm_end
- addi a1, zero, ASM_END_SIZE
- call write_out
-
- addi s1, s1, 3
-
- # Epilogue.
- lw ra, 4(sp)
- lw s0, 0(sp)
- addi sp, sp, 8
- ret
-
-# 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
-
-# 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
- call _read_token
- addi a1, a0, 0
- addi a0, s1, 0
- la a2, token_close_paren
- call _token_compare
- beqz a0, .Lcompile_call_complete
-
-.Lcompile_call_argument:
- call _build_expression
-
- la a0, instruction_sw
- li a1, 2
- call write_out
-
- la a0, space
- li a1, 1
- call write_out
-
- la a0, register_a0
- li a1, 2
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- lw t0, 12(sp) # Argument count for a procedure call.
-
- # Only 8 arguments are supported with a0-a7.
- # Save all arguments on the stack so they aren't overriden afterwards.
- # The offset on the stack always has two digits in this case.
- li t1, -4
- mul t1, t0, t1
- addi t1, t1, 52
- li t2, 10
- div t3, t1, t2
- rem t4, t1, t2
- addi t3, t3, '0'
- addi t4, t4, '0'
-
- sw t3, 8(sp)
- sw t4, 4(sp)
-
- addi a0, sp, 8
- li a1, 1
- call write_out
-
- addi a0, sp, 4
- li a1, 1
- call write_out
-
- la a0, token_open_paren
- li a1, 1
- call write_out
-
- la a0, register_sp
- li a1, 2
- call write_out
-
- la a0, token_close_paren
- li a1, 1
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- call _skip_spaces
- call _read_token
- addi a1, a0, 0
- addi a0, s1, 0
- la a2, token_comma
- call _token_compare
-
- bnez a0, .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-a7 registers and read them from stack.
- # If this stack value contains garbage, the procedure just shouldn't use it.
- lw t0, 12(sp)
- li t1, 7
- bgt t0, t1, .Lcompile_call_perform
-
- la a0, instruction_lw
- li a1, 2
- call write_out
-
- la a0, space
- li a1, 1
- call write_out
-
- la a0, register_a
- li a1, 1
- call write_out
-
- lw t0, 12(sp)
- addi t0, t0, '0'
- sw t0, 8(sp)
-
- addi a0, sp, 8
- li a1, 1
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- lw t0, 12(sp) # Argument count for a procedure call.
-
- li t1, -4
- mul t1, t0, t1
- addi t1, t1, 52
- li t2, 10
- div t3, t1, t2
- rem t4, t1, t2
- addi t3, t3, '0'
- addi t4, t4, '0'
-
- sw t3, 8(sp)
- sw t4, 4(sp)
-
- addi a0, sp, 8
- li a1, 1
- call write_out
-
- addi a0, sp, 4
- li a1, 1
- call write_out
-
- la a0, token_open_paren
- li a1, 1
- call write_out
-
- la a0, register_sp
- li a1, 2
- call write_out
-
- la a0, token_close_paren
- li a1, 1
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- lw t0, 12(sp) # Increment.
- addi t0, t0, 1
- sw t0, 12(sp)
-
- j .Lcompile_call_restore
-
-.Lcompile_call_perform:
- la a0, instruction_call
- li a1, 4
- call write_out
-
- la a0, space
- li a1, 1
- call write_out
-
- lw a0, 20(sp)
- lw a1, 16(sp)
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- 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
-
-.type _compile, @function
-compile:
- # Prologue.
- addi sp, sp, -16
- sw ra, 12(sp)
- sw s0, 8(sp)
- addi s0, sp, 16
-
- # Write .bss section header for global variables.
- la a0, asm_program
- addi a1, zero, ASM_PROGRAM_SIZE
- call write_out
-
- call _skip_spaces
- addi s1, s1, 7 # Skip "program" keyword.
-
-.Lcharacter_loop_do:
- call _skip_spaces
-
- lbu t0, (s1) # t0 = Current character.
- beqz t0, .Lcharacter_loop_end
-
- call _read_token
- sw a0, 4(sp) # Save the token length on the stack.
- beqz a0, .Lcharacter_loop_end # No token read, there is unrecognized input.
-
- lw a0, 4(sp)
- call _handle_token
-
- j .Lcharacter_loop_do
-.Lcharacter_loop_end:
-
- # Epilogue.
- lw ra, 12(sp)
- lw s0, 8(sp)
- addi sp, sp, 16
- ret
-
-# Evalutes an expression and saves the result in a0.
-.type _build_expression, @function
-_build_expression:
- # Prologue.
- addi sp, sp, -16
- sw ra, 12(sp)
- sw s0, 8(sp)
- addi s0, sp, 16
-
- call _skip_spaces
- call _read_token
- sw s1, 4(sp)
- sw a0, 0(sp)
-
- # Integer literal.
- addi a0, s1, 0
- lb a0, (a0)
- call is_digit
- bnez a0, .Lbuild_expression_number_literal
-
- # Named identifier.
- la a0, instruction_la
- li a1, 2
- call write_out
-
- la a0, space
- li a1, 1
- call write_out
-
- la a0, register_a0
- li a1, 2
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- lw a0, 4(sp)
- lw a1, 0(sp)
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- j .Lbuild_expression_end
-
-.Lbuild_expression_number_literal:
- la a0, instruction_li
- li a1, 2
- call write_out
-
- la a0, space
- li a1, 1
- call write_out
-
- la a0, register_a0
- li a1, 2
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- lw a0, 4(sp)
- lw a1, 0(sp)
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- j .Lbuild_expression_end
-
-.Lbuild_expression_end:
- lw a0, 0(sp)
- add s1, s1, a0
-
- # Epilogue.
- lw ra, 12(sp)
- lw s0, 8(sp)
- addi sp, sp, 16
- ret
-
-# Compiles a statement beginning with an identifier.
-.type _compile_identifier, @function
-_compile_identifier:
- # Prologue.
- addi sp, sp, -32
- sw ra, 28(sp)
- sw s0, 24(sp)
- addi s0, sp, 32
-
- # Save the pointer to the identifier and its length on the stack.
- sw a0, 20(sp)
- sw a1, 16(sp)
-
- add s1, s1, a1
- 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
-
- lw a0, 12(sp)
- lw a1, 8(sp)
- la a2, token_assign
- call _token_compare
- beqz a0, .Lcompile_identifier_assign
-
- lw a0, 12(sp)
- lw a1, 8(sp)
- la a2, token_open_paren
- call _token_compare
- beqz a0, .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_expression
-
- la a0, instruction_addi
- li a1, 4
- call write_out
-
- la a0, space
- li a1, 1
- call write_out
-
- lw a0, 20(sp)
- lw a1, 16(sp)
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- la a0, register_a0
- li a1, 2
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- la a0, digit_zero
- li a1, 1
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- j .Lcompile_identifier_end
-
-.Lcompile_identifier_end:
- # Epilogue.
- lw ra, 28(sp)
- lw s0, 24(sp)
- addi sp, sp, 32
- ret
-
-.type _compile_var, @function
-_compile_var:
- # Prologue.
- addi sp, sp, -32
- sw ra, 28(sp)
- sw s0, 24(sp)
- addi s0, sp, 32
-
- # Variable name.
- addi s1, s1, 3
- call _skip_spaces
- call _read_token
- sw s1, 20(sp)
- sw a0, 16(sp)
- add s1, s1, a0
-
- # Skip the colon.
- call _skip_spaces
- call _read_token
- add s1, s1, a0
-
- call _skip_spaces
- call _read_token
- sw a0, 12(sp)
-
- addi a0, s1, 0
- lw a1, 12(sp)
- la a2, token_open_square
- call _token_compare
- beqz a0, .Lcompile_var_array
-
- j .Lcompile_var_end
-
-.Lcompile_var_array:
- call _skip_spaces
- add s1, s1, 1 # Skip the opening square bracket.
-
- call _skip_spaces
- call _read_token
- sw a0, 8(sp)
-
- la a0, asm_type
- li a1, ASM_TYPE_SIZE
- call write_out
-
- lw a0, 20(sp)
- lw a1, 16(sp)
- call write_out
-
- la a0, asm_object
- li a1, ASM_OBJECT_SIZE
- call write_out
-
- la a0, asm_size
- li a1, ASM_SIZE_SIZE
- call write_out
-
- lw a0, 20(sp)
- lw a1, 16(sp)
- call write_out
-
- la a0, comma
- li a1, 1
- call write_out
-
- addi a0, s1, 0
- lw a1, 8(sp)
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- lw a0, 20(sp)
- lw a1, 16(sp)
- call write_out
-
- la a0, colon
- li a1, 1
- call write_out
-
- la a0, asm_zero
- li a1, ASM_ZERO_SIZE
- call write_out
-
- addi a0, s1, 0
- lw a1, 8(sp)
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- la a0, asm_global
- li a1, ASM_GLOBAL_SIZE
- call write_out
-
- lw a0, 20(sp)
- lw a1, 16(sp)
- call write_out
-
- la a0, new_line
- li a1, 1
- call write_out
-
- lw a0, 8(sp)
- add s1, s1, a0
-
- call _skip_spaces
- add s1, s1, 1 # Skip the closing square bracket.
-
- call _skip_spaces
- call _read_token
-
- sw a0, 12(sp)
- j .Lcompile_var_end
-
-.Lcompile_var_end:
- lw a0, 12(sp)
- add s1, s1, a0
-
- # Epilogue.
- lw ra, 28(sp)
- lw s0, 24(sp)
- addi sp, sp, 32
- ret
-
-.type _handle_token, @function
-_handle_token:
- # Prologue.
- addi sp, sp, -32
- sw ra, 28(sp)
- sw s0, 24(sp)
- addi s0, sp, 32
-
- sw a0, 20(sp)
-
- # Detect what token has been read.
- addi a0, s1, 0
- lw a1, 20(sp)
- la a2, token_begin
- call _token_compare
- beqz a0, .Lhandle_token_begin
-
- addi a0, s1, 0
- lw a1, 20(sp)
- la a2, token_end
- call _token_compare
- beqz a0, .Lhandle_token_end
-
- addi a0, s1, 0
- lw a1, 20(sp)
- la a2, token_import
- call _token_compare
- beqz a0, .Lhandle_token_import
-
- addi a0, s1, 0
- lw a1, 20(sp)
- la a2, token_var
- call _token_compare
- beqz a0, .Lhandle_token_var
-
- # If the first symbol in the token is a character, assume an identifier.
- addi a0, s1, 0
- lb a0, (a0)
- call is_alpha
- bnez a0, .Lhandle_token_identifier
-
- # Ignore the unknown token.
- lw t0, 20(sp)
- add s1, s1, t0
- j .Lhandle_token_return
-
-.Lhandle_token_begin:
- call _compile_begin
- j .Lhandle_token_return
-
-.Lhandle_token_end:
- call _compile_end
- j .Lhandle_token_return
-
-.Lhandle_token_import:
- call _compile_import
- j .Lhandle_token_return
-
-.Lhandle_token_var:
- call _compile_var
- j .Lhandle_token_return
-
-.Lhandle_token_identifier:
- addi a0, s1, 0
- lw a1, 20(sp)
- call _compile_identifier
- j .Lhandle_token_return
-
-.Lhandle_token_return:
- # Epilogue.
- lw ra, 28(sp)
- lw s0, 24(sp)
- addi sp, sp, 32
- ret
-
-_start:
- # Read the source from the standard input.
- la a0, source_code
- li a1, SOURCE_BUFFER_SIZE # Buffer size.
- call read_file
-
- la s1, source_code # s1 = Source code position.
- call compile
-
- # Call exit.
- li a0, 0 # Use 0 return code.
- call exit
diff --git a/boot/echo-boot.s b/boot/stage1.s
index 8256bbd..fbfa16d 100644
--- a/boot/echo-boot.s
+++ b/boot/stage1.s
@@ -1,17 +1,143 @@
-.global _start
+.global _start # Program entry point.
# s1 - Contains the current position in the source text.
+.equ SOURCE_BUFFER_SIZE, 40960
+
.section .rodata
-SOURCE_BUFFER_SIZE: .long 20480
+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
.section .bss
.type source_code, @object
-.size source_code, 20480
-source_code: .zero 20480
+.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, 0x26 # &
+ 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, 0x3d # =
+ 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
+
+ /* DEBUG
+ mv a0, s1
+ li a1, 8
+ call _write_error */
+
+ j .Lbuild_binary_expression_end
+
+.L_build_binary_expression_equal:
+ addi s1, s1, 1 # Skip =.
+ li a0, 1
+ call _build_expression
+ li t0, 0x0a3161 # a1\n
+ sw t0, 16(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 12(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 8(sp)
+ li t0, 0x20627573 # sub_
+ sw t0, 4(sp)
+ addi a0, sp, 4
+ li a1, 15
+ call _write_out
+
+ li t0, 0x0a306120 # _a0\n
+ sw t0, 16(sp)
+ li t0, 0x2c306120 # _a0,
+ sw t0, 12(sp)
+ li t0, 0x7a716573 # seqz
+ sw t0, 8(sp)
+ addi a0, sp, 8
+ li a1, 12
+ call _write_out
+
+ j .Lbuild_binary_expression_end
+
+.L_build_binary_expression_and:
+ addi s1, s1, 1 # Skip &.
+ li a0, 1
+ call _build_expression
+ li t0, 0x0a3161 # a1\n
+ sw t0, 16(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 12(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 8(sp)
+ li t0, 0x20646e61 # and_
+ sw t0, 4(sp)
+ addi a0, sp, 4
+ li a1, 15
+ 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.
@@ -20,63 +146,120 @@ _build_expression:
sw s0, 24(sp)
addi s0, sp, 32
+ addi a0, a0, '0' # Make the register number to a character.
+ sw a0, 20(sp) # And save it.
+
call _skip_spaces
call _read_token
- sw s1, 20(sp)
- sw a0, 16(sp)
+ sw s1, 16(sp)
+ sw a0, 12(sp)
# Integer literal.
addi a0, s1, 0
- lb a0, (a0)
+ lbu a0, (a0)
call _is_digit
- bnez a0, .Lbuild_expression_number_literal
+ bnez a0, .Lbuild_expression_literal
+
+ addi a0, s1, 0
+ lbu a0, (a0)
+ li t0, 0x5f # _
+ 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.
- li t0, 0x202c30 # 0,_
- sw t0, 12(sp)
+ lw t1, 20(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, 16(sp)
+ lw a1, 12(sp)
+ call _write_out
+
+ li t0, 0x0a # \n
sw t0, 8(sp)
addi a0, sp, 8
+ li a1, 1
+ call _write_out
+
+ j .Lbuild_expression_advance
+
+.Lbuild_expression_identifier:
+ lw t1, 20(sp)
+ li t0, 0x00202c00 # \0,_
+ or t0, t0, t1
+ sw t0, 8(sp)
+ li t0, 0x6120776c # lw a
+ sw t0, 4(sp)
+ addi a0, sp, 4
li a1, 7
call _write_out
- lw a0, 20(sp)
- lw a1, 16(sp)
+ lw a0, 16(sp)
+ lw a1, 12(sp)
+ addi a0, a0, 4 # Skip the "loca" variable prefix.
+ addi a1, a1, -4 # Skip the "loca" variable prefix.
call _write_out
li t0, 0x0a # \n
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 1
+ sw t0, 8(sp)
+ li t0, 0x29707328 # (sp)
+ sw t0, 4(sp)
+ addi a0, sp, 4
+ li a1, 5
call _write_out
+ j .Lbuild_expression_advance
+
+.Lbuild_expression_call:
+ lw a0, 16(sp)
+ lw a1, 12(sp)
+ add s1, s1, a1
+ addi s1, s1, 1
+ call _compile_call
+
j .Lbuild_expression_end
-.Lbuild_expression_number_literal:
- li t0, 0x202c30 # 0,_
- sw t0, 12(sp)
- li t0, 0x6120696c # li a
+.Lbuild_expression_literal:
+ lw t1, 20(sp)
+ li t0, 0x00202c00 # \0,_
+ or t0, t0, t1
sw t0, 8(sp)
- addi a0, sp, 8
+ li t0, 0x6120696c # li a
+ sw t0, 4(sp)
+ addi a0, sp, 4
li a1, 7
call _write_out
- lw a0, 20(sp)
- lw a1, 16(sp)
+ lw a0, 16(sp)
+ lw a1, 12(sp)
call _write_out
li t0, 0x0a # \n
- sw t0, 12(sp)
- addi a0, sp, 12
+ sw t0, 8(sp)
+ addi a0, sp, 8
li a1, 1
call _write_out
- j .Lbuild_expression_end
+ j .Lbuild_expression_advance
-.Lbuild_expression_end:
- lw a0, 16(sp)
+.Lbuild_expression_advance:
+ lw a0, 12(sp)
add s1, s1, a0
+.Lbuild_expression_end:
# Epilogue.
lw ra, 28(sp)
lw s0, 24(sp)
@@ -120,11 +303,6 @@ _compile_identifier:
call _token_compare
beqz a0, .Lcompile_identifier_assign
- /* DEBUG
- mv a0, s1
- li a1, 4
- call _write_error */
-
lw t0, 12(sp)
lbu t0, (t0)
li t1, 0x28 # (
@@ -140,7 +318,7 @@ _compile_identifier:
j .Lcompile_identifier_end
.Lcompile_identifier_assign:
- call _build_expression
+ call _build_binary_expression
li t0, 0x202c30 # 0,_
sw t0, 12(sp)
@@ -198,6 +376,7 @@ _compile_call:
beq t0, t1, .Lcompile_call_complete
.Lcompile_call_argument:
+ li a0, 0
call _build_expression
li t0, 0x202c30 # 0,_
@@ -210,12 +389,12 @@ _compile_call:
lw t0, 12(sp) # Argument count for a procedure call.
- # Only 8 arguments are supported with a0-a7.
+ # Only 6 arguments are supported with a0-a5.
# Save all arguments on the stack so they aren't overriden afterwards.
# The offset on the stack always has two digits in this case.
li t1, -4
mul t1, t0, t1
- addi t1, t1, 84
+ addi t1, t1, 60
li t2, 10
div t3, t1, t2
rem t4, t1, t2
@@ -258,10 +437,10 @@ _compile_call:
sw zero, 12(sp)
.Lcompile_call_restore:
- # Just go through all a0-a7 registers and read them from stack.
+ # 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.
lw t0, 12(sp)
- li t1, 7
+ li t1, 5
bgt t0, t1, .Lcompile_call_perform
li t0, 0x6120776c # lw a
@@ -274,7 +453,7 @@ _compile_call:
li t1, -4
mul t1, t0, t1
- addi t1, t1, 84
+ addi t1, t1, 60
li t2, 10
div t3, t1, t2
rem t4, t1, t2
@@ -367,7 +546,16 @@ _read_token:
li t1, ']'
beq t0, t1, .Ltoken_character_single
-.Ltoken_character_loop_do: # Expect an identifier or a number.
+ 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.
@@ -491,55 +679,33 @@ _compile_assembly:
.type _compile_program, @function
_compile_program:
# Prologue.
- addi sp, sp, -32
- sw ra, 28(sp)
- sw s0, 24(sp)
- addi s0, sp, 32
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw s0, 0(sp)
+ addi s0, sp, 8
- # .global _start
- li t0, 0x0a7472 # rt\n
- sw t0, 20(sp)
- li t0, 0x6174735f # _sta
- sw t0, 16(sp)
- li t0, 0x206c6162 # bal_
- sw t0, 12(sp)
- li t0, 0x6f6c672e # .glo
- sw t0, 8(sp)
-
- addi a0, sp, 8
- li a1, 15
+ la a0, global_start
+ li a1, GLOBAL_START_SIZE
call _write_out
addi s1, s1, 8 # program\n.
# Epilogue.
- lw ra, 28(sp)
- lw s0, 24(sp)
- addi sp, sp, 32
+ 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, -32
- sw ra, 28(sp)
- sw s0, 24(sp)
- addi s0, sp, 32
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw s0, 0(sp)
+ addi s0, sp, 8
- # .section .rodata
- li t0, 0x0a # \n
- sw t0, 20(sp)
- li t0, 0x61746164 # data
- sw t0, 16(sp)
- li t0, 0x6f722e20 # _.ro
- sw t0, 12(sp)
- li t0, 0x6e6f6974 # tion
- sw t0, 8(sp)
- li t0, 0x6365732e # .sec
- sw t0, 4(sp)
-
- addi a0, sp, 4
- li a1, 17
+ la a0, section_rodata
+ li a1, SECTION_RODATA_SIZE
call _write_out
addi s1, s1, 6 # const\n.
@@ -555,9 +721,9 @@ _compile_constant_section:
.Lcompile_constant_section_end:
# Epilogue.
- lw ra, 28(sp)
- lw s0, 24(sp)
- addi sp, sp, 32
+ lw ra, 4(sp)
+ lw s0, 0(sp)
+ addi sp, sp, 8
ret
.type _compile_constant, @function
@@ -611,23 +777,13 @@ _compile_constant:
.type _compile_variable_section, @function
_compile_variable_section:
# Prologue.
- addi sp, sp, -24
- sw ra, 20(sp)
- sw s0, 16(sp)
- addi s0, sp, 24
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw s0, 0(sp)
+ addi s0, sp, 8
- # .section .bss
- li t0, 0x0a73 # s\n
- sw t0, 12(sp)
- li t0, 0x73622e20 # _.bs
- sw t0, 8(sp)
- li t0, 0x6e6f6974 # tion
- sw t0, 4(sp)
- li t0, 0x6365732e # .sec
- sw t0, 0(sp)
-
- addi a0, sp, 0
- li a1, 14
+ la a0, section_bss
+ li a1, SECTION_BSS_SIZE
call _write_out
addi s1, s1, 4 # var\n.
@@ -643,9 +799,9 @@ _compile_variable_section:
.Lcompile_variable_section_end:
# Epilogue.
- lw ra, 20(sp)
- lw s0, 16(sp)
- addi sp, sp, 24
+ lw ra, 4(sp)
+ lw s0, 0(sp)
+ addi sp, sp, 8
ret
.type _compile_variable, @function
@@ -836,63 +992,61 @@ _compile_procedure:
bnez a0, .Lcompile_procedure_begin
# Generate the procedure prologue with a predefined stack size.
- li t0, 0x69646461 # addi
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 4
+ la a0, prologue
+ li a1, PROLOGUE_SIZE
call _write_out
- li t0, 0x2c707320 # _sp,
+ # Save passed arguments on the stack.
+ li t0, 0x0a29 # )\n
sw t0, 12(sp)
-
- addi a0, sp, 12
- li a1, 4
+ 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
- addi a0, sp, 12
- li a1, 4
+ 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, 0x0a36392d # -96\n
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 4
+ 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, 0x0a29 # )\n
- sw t0, 12(sp)
- li t0, 0x70732832 # 2(sp
- sw t0, 8(sp)
- li t0, 0x39202c61 # a, 9
+ li t0, '2'
+ sb t0, 8(sp)
+ li t0, 0x37202c33 # 3, 7
sw t0, 4(sp)
- li t0, 0x72207773 # sw r
- sw t0, 0(sp)
addi a0, sp, 0
li a1, 14
call _write_out
- li t0, 0x0a29 # )\n
- sw t0, 12(sp)
- li t0, 0x70732838 # 2(sp
- sw t0, 8(sp)
- li t0, 0x38202c30 # 0, 8
+ li t0, '8'
+ sb t0, 8(sp)
+ li t0, 0x36202c34 # 4, 6
sw t0, 4(sp)
- li t0, 0x73207773 # sw s
- sw t0, 0(sp)
addi a0, sp, 0
li a1, 14
call _write_out
- li t0, 0x0a363920 # _96\n
- sw t0, 12(sp)
- li t0, 0x2c707320 # _sp,
- sw t0, 8(sp)
- li t0, 0x2c307320 # _s0,
+ li t0, '4'
+ sb t0, 8(sp)
+ li t0, 0x36202c35 # 5, 6
sw t0, 4(sp)
- li t0, 0x69646461 # addi
- sw t0, 0(sp)
addi a0, sp, 0
- li a1, 16
+ li a1, 14
call _write_out
# Generate the body of the procedure.
@@ -917,57 +1071,8 @@ _compile_procedure:
add s1, s1, 4 # Skip end\n.
# Generate the procedure epilogue with a predefined stack size.
- li t0, 0x0a29 # )\n
- sw t0, 12(sp)
- li t0, 0x70732832 # 2(sp
- sw t0, 8(sp)
- li t0, 0x39202c61 # a, 9
- sw t0, 4(sp)
- li t0, 0x7220776c # lw r
- sw t0, 0(sp)
- addi a0, sp, 0
- li a1, 14
- call _write_out
-
- li t0, 0x0a29 # )\n
- sw t0, 12(sp)
- li t0, 0x70732838 # 2(sp
- sw t0, 8(sp)
- li t0, 0x38202c30 # 0, 8
- sw t0, 4(sp)
- li t0, 0x7320776c # lw s
- sw t0, 0(sp)
- addi a0, sp, 0
- li a1, 14
- call _write_out
-
- li t0, 0x69646461 # addi
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 4
- call _write_out
-
- li t0, 0x2c707320 # _sp,
- sw t0, 12(sp)
-
- addi a0, sp, 12
- li a1, 4
- call _write_out
-
- addi a0, sp, 12
- li a1, 4
- call _write_out
-
- li t0, 0x0a3639 # 96\n
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 3
- call _write_out
-
- li t0, 0x0a746572 # ret\n
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 4
+ la a0, epilogue
+ li a1, EPILOGUE_SIZE
call _write_out
# Epilogue.
@@ -1018,8 +1123,100 @@ _token_compare:
.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 t0, 0x0a # \n
+ sw t0, 8(sp)
+ addi a0, sp, 8
+ li a1, 1
+ call _write_out
+
+ # 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, 0x0a # \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
+
# 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
@@ -1030,7 +1227,9 @@ _compile_line:
sw s0, 24(sp)
addi s0, sp, 32
- sw a0, 20(sp) # a0 - Line length.
+ # Preserve passed arguments.
+ sw a0, 20(sp)
+ sw a1, 16(sp)
beqz a0, .Lcompile_line_empty # Skip an empty line.
@@ -1039,75 +1238,108 @@ _compile_line:
beq t0, t1, .Lcompile_line_comment
li t0, 0x0a6d6172 # ram\n
- sw t0, 16(sp)
- li t0, 0x676f7270 # prog
sw t0, 12(sp)
+ li t0, 0x676f7270 # prog
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 8
call _memcmp
beqz a0, .Lcompile_line_program
li t0, 0x0a74 # t\n
- sw t0, 16(sp)
- li t0, 0x736e6f63 # cons
sw t0, 12(sp)
+ li t0, 0x736e6f63 # cons
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_const
li t0, 0x0a726176 # var\n
- sw t0, 16(sp)
+ sw t0, 12(sp)
mv a0, s1
- addi a1, sp, 16
+ addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_var
li t0, 0x20 # _
- sw t0, 16(sp)
- li t0, 0x636f7270 # proc
sw t0, 12(sp)
+ li t0, 0x636f7270 # proc
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 5
call _memcmp
beqz a0, .Lcompile_line_procedure
li t0, 0x0a6e # n\n
- sw t0, 16(sp)
- li t0, 0x69676562 # begi
sw t0, 12(sp)
+ li t0, 0x69676562 # begi
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_begin
li t0, 0x2e646e65 # end.
- sw t0, 16(sp)
+ sw t0, 12(sp)
mv a0, s1
- addi a1, sp, 16
+ addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_exit
li t0, 0x61636f6c # loca
- sw t0, 16(sp)
+ sw t0, 12(sp)
mv a0, s1
- addi a1, sp, 16
+ 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
+
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_label:
+ lw a0, 20(sp)
+ call _compile_label
+ 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
@@ -1117,6 +1349,10 @@ _compile_line:
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
@@ -1126,6 +1362,10 @@ _compile_line:
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
@@ -1162,6 +1402,7 @@ _compile_line:
addi sp, sp, 32
ret
+# Prints ".section .text" and exits.
.type _compile_text_section, @function
_compile_text_section:
# Prologue.
@@ -1170,18 +1411,8 @@ _compile_text_section:
sw s0, 16(sp)
addi s0, sp, 24
- # .section .text
- li t0, 0x0a7478 # xt\n
- sw t0, 12(sp)
- li t0, 0x65742e20 # _.te
- sw t0, 8(sp)
- li t0, 0x6e6f6974 # tion
- sw t0, 4(sp)
- li t0, 0x6365732e # .sec
- sw t0, 0(sp)
-
- addi a0, sp, 0
- li a1, 15
+ la a0, section_text
+ li a1, SECTION_TEXT_SIZE
call _write_out
# Epilogue.
@@ -1291,14 +1522,23 @@ _compile:
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:
@@ -1313,8 +1553,7 @@ _compile:
_start:
# Read the source from the standard input.
la a0, source_code
- la a1, SOURCE_BUFFER_SIZE # Buffer size.
- lw a1, (a1)
+ li a1, SOURCE_BUFFER_SIZE # Buffer size.
call _read_file
la s1, source_code # s1 = Source code position.
diff --git a/boot/stage2.elna b/boot/stage2.elna
index e37b3e6..4e87e89 100644
--- a/boot/stage2.elna
+++ b/boot/stage2.elna
@@ -1,73 +1,221 @@
program
# s1 - Contains the current position in the source text.
+import dummy
+
const
- SOURCE_BUFFER_SIZE := 20480
+ SOURCE_BUFFER_SIZE := 40960
var
- source_code: [20480]Byte
+ source_code: [40960]Byte
+
+# Ignores the import.
+proc _compile_import()
+var loca0: Word
+begin
+ _advance(6)
+ _skip_spaces()
+ loca0 := _read_token()
+ _advance(loca0) # Skip the imported module name.
+end
+
+proc _build_binary_expression()
+begin
+ _build_expression(0)
+
+ _skip_spaces()
+ call _read_token
+ sw a0, 20(sp)
+
+ li t0, 0x26 # &
+ 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, 0x3d # =
+ 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
-.section .text
+ /* DEBUG
+ mv a0, s1
+ li a1, 8
+ call _write_error */
+
+ j .Lbuild_binary_expression_end
+
+.L_build_binary_expression_equal:
+ addi s1, s1, 1 # Skip =.
+ _build_expression(1)
+ li t0, 0x0a3161 # a1\n
+ sw t0, 16(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 12(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 8(sp)
+ li t0, 0x20627573 # sub_
+ sw t0, 4(sp)
+ addi a0, sp, 4
+ li a1, 15
+ call _write_out
+
+ li t0, 0x0a306120 # _a0\n
+ sw t0, 16(sp)
+ li t0, 0x2c306120 # _a0,
+ sw t0, 12(sp)
+ li t0, 0x7a716573 # seqz
+ sw t0, 8(sp)
+ addi a0, sp, 8
+ li a1, 12
+ call _write_out
+
+ j .Lbuild_binary_expression_end
+
+.L_build_binary_expression_and:
+ addi s1, s1, 1 # Skip &.
+ _build_expression(1)
+ li t0, 0x0a3161 # a1\n
+ sw t0, 16(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 12(sp)
+ li t0, 0x202c3061 # a0,_
+ sw t0, 8(sp)
+ li t0, 0x20646e61 # and_
+ sw t0, 4(sp)
+ addi a0, sp, 4
+ li a1, 15
+ call _write_out
+
+ j .Lbuild_binary_expression_end
+
+.Lbuild_binary_expression_end:
+end
# Evalutes an expression and saves the result in a0.
+#
+# a0 - X in aX, the register number to save the result.
proc _build_expression()
begin
+ addi a0, a0, '0' # Make the register number to a character.
+ sw a0, 20(sp) # And save it.
+
_skip_spaces()
call _read_token
- sw s1, 20(sp)
- sw a0, 16(sp)
+ sw s1, 16(sp)
+ sw a0, 12(sp)
# Integer literal.
addi a0, s1, 0
- lb a0, (a0)
+ lbu a0, (a0)
call _is_digit
- bnez a0, .Lbuild_expression_number_literal
+ bnez a0, .Lbuild_expression_literal
+
+ addi a0, s1, 0
+ lbu a0, (a0)
+ li t0, 0x5f # _
+ 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.
- li t0, 0x202c30 # 0,_
- sw t0, 12(sp)
+ lw t1, 20(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, 16(sp)
+ lw a1, 12(sp)
+ call _write_out
+
+ li t0, 0x0a # \n
sw t0, 8(sp)
addi a0, sp, 8
+ li a1, 1
+ call _write_out
+
+ goto .Lbuild_expression_advance
+
+ .Lbuild_expression_identifier
+ lw t1, 20(sp)
+ li t0, 0x00202c00 # \0,_
+ or t0, t0, t1
+ sw t0, 8(sp)
+ li t0, 0x6120776c # lw a
+ sw t0, 4(sp)
+ addi a0, sp, 4
li a1, 7
call _write_out
- lw a0, 20(sp)
- lw a1, 16(sp)
+ lw a0, 16(sp)
+ lw a1, 12(sp)
+ addi a0, a0, 4 # Skip the "loca" variable prefix.
+ addi a1, a1, -4 # Skip the "loca" variable prefix.
call _write_out
li t0, 0x0a # \n
- sw t0, 12(sp)
- addi a0, sp, 12
- li a1, 1
+ sw t0, 8(sp)
+ li t0, 0x29707328 # (sp)
+ sw t0, 4(sp)
+ addi a0, sp, 4
+ li a1, 5
call _write_out
- j .Lbuild_expression_end
+ goto .Lbuild_expression_advance
-.Lbuild_expression_number_literal:
- li t0, 0x202c30 # 0,_
- sw t0, 12(sp)
- li t0, 0x6120696c # li a
+ .Lbuild_expression_call
+ lw a0, 16(sp)
+ lw a1, 12(sp)
+ add s1, s1, a1
+ addi s1, s1, 1
+ call _compile_call
+
+ goto .Lbuild_expression_end
+
+ .Lbuild_expression_literal
+ lw t1, 20(sp)
+ li t0, 0x00202c00 # \0,_
+ or t0, t0, t1
sw t0, 8(sp)
- addi a0, sp, 8
+ li t0, 0x6120696c # li a
+ sw t0, 4(sp)
+ addi a0, sp, 4
li a1, 7
call _write_out
- lw a0, 20(sp)
- lw a1, 16(sp)
+ lw a0, 16(sp)
+ lw a1, 12(sp)
call _write_out
li t0, 0x0a # \n
- sw t0, 12(sp)
- addi a0, sp, 12
+ sw t0, 8(sp)
+ addi a0, sp, 8
li a1, 1
call _write_out
- j .Lbuild_expression_end
+ goto .Lbuild_expression_advance
-.Lbuild_expression_end:
- lw a0, 16(sp)
+ .Lbuild_expression_advance
+ lw a0, 12(sp)
add s1, s1, a0
+
+ .Lbuild_expression_end
end
# Compiles a statement beginning with an identifier.
@@ -101,27 +249,22 @@ begin
call _token_compare
beqz a0, .Lcompile_identifier_assign
- /* DEBUG
- mv a0, s1
- li a1, 4
- call _write_error */
-
lw t0, 12(sp)
lbu t0, (t0)
li t1, 0x28 # (
beq t0, t1, .Lcompile_identifier_call
- j .Lcompile_identifier_end
+ goto .Lcompile_identifier_end
-.Lcompile_identifier_call:
+ .Lcompile_identifier_call
lw a0, 20(sp)
lw a1, 16(sp)
call _compile_call
- j .Lcompile_identifier_end
+ goto .Lcompile_identifier_end
-.Lcompile_identifier_assign:
- call _build_expression
+ .Lcompile_identifier_assign
+ _build_binary_expression()
li t0, 0x202c30 # 0,_
sw t0, 12(sp)
@@ -145,9 +288,9 @@ begin
li a1, 5
call _write_out
- j .Lcompile_identifier_end
+ goto .Lcompile_identifier_end
-.Lcompile_identifier_end:
+ .Lcompile_identifier_end
end
# Compiles a procedure call. Expects s1 to point to the first argument.
@@ -161,15 +304,15 @@ begin
sw a1, 16(sp)
sw zero, 12(sp) # Argument count for a procedure call.
-.Lcompile_call_paren:
+ .Lcompile_call_paren
_skip_spaces()
call _read_token
lbu t0, (s1)
li t1, 0x29 # )
beq t0, t1, .Lcompile_call_complete
-.Lcompile_call_argument:
- call _build_expression
+ .Lcompile_call_argument
+ _build_expression(0)
li t0, 0x202c30 # 0,_
sw t0, 8(sp)
@@ -181,12 +324,12 @@ begin
lw t0, 12(sp) # Argument count for a procedure call.
- # Only 8 arguments are supported with a0-a7.
+ # Only 6 arguments are supported with a0-a5.
# Save all arguments on the stack so they aren't overriden afterwards.
# The offset on the stack always has two digits in this case.
li t1, -4
mul t1, t0, t1
- addi t1, t1, 84
+ addi t1, t1, 60
li t2, 10
div t3, t1, t2
rem t4, t1, t2
@@ -223,16 +366,16 @@ begin
sw t0, 12(sp)
_advance(1) # Skip the comma between the arguments.
- j .Lcompile_call_argument
+ goto .Lcompile_call_argument
-.Lcompile_call_complete:
+ .Lcompile_call_complete
sw zero, 12(sp)
-.Lcompile_call_restore:
- # Just go through all a0-a7 registers and read them from stack.
+ .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.
lw t0, 12(sp)
- li t1, 7
+ li t1, 5
bgt t0, t1, .Lcompile_call_perform
li t0, 0x6120776c # lw a
@@ -245,7 +388,7 @@ begin
li t1, -4
mul t1, t0, t1
- addi t1, t1, 84
+ addi t1, t1, 60
li t2, 10
div t3, t1, t2
rem t4, t1, t2
@@ -271,9 +414,9 @@ begin
addi t0, t0, 1
sw t0, 12(sp)
- j .Lcompile_call_restore
+ goto .Lcompile_call_restore
-.Lcompile_call_perform:
+ .Lcompile_call_perform
li t0, 0x20
sw t0, 8(sp)
li t0, 0x6c6c6163
@@ -327,7 +470,16 @@ begin
li t1, ']'
beq t0, t1, .Ltoken_character_single
-.Ltoken_character_loop_do: # Expect an identifier or a number.
+ 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.
@@ -338,15 +490,15 @@ begin
lw t6, 4(sp)
addi t6, t6, 1
sw t6, 4(sp)
- j .Ltoken_character_loop_do
+ goto .Ltoken_character_loop_do
-.Ltoken_character_single:
+ .Ltoken_character_single
lw t6, 4(sp)
addi t6, t6, 1
sw t6, 4(sp)
- j .Ltoken_character_end
+ goto .Ltoken_character_end
-.Ltoken_character_colon:
+ .Ltoken_character_colon
lbu t0, 1(s1) # t0 = The character after the colon.
lw t6, 4(sp)
addi t6, t6, 1
@@ -354,16 +506,16 @@ begin
li t1, '='
beq t0, t1, .Ltoken_character_single
- j .Ltoken_character_end
+ goto .Ltoken_character_end
-.Ltoken_character_end:
+ .Ltoken_character_end
lw a0, 4(sp)
end
# Skips the spaces till the next non space character.
proc _skip_spaces()
begin
-.Lspace_loop_do:
+ .Lspace_loop_do
lbu t0, (s1) # t0 = Current character.
li t1, ' '
@@ -375,53 +527,50 @@ begin
li t1, '\r'
beq t0, t1, .Lspace_loop_repeat
- j .Lspace_loop_end
-.Lspace_loop_repeat:
+ goto .Lspace_loop_end
+ .Lspace_loop_repeat
_advance(1)
- j .Lspace_loop_do
+ goto .Lspace_loop_do
-.Lspace_loop_end:
+ .Lspace_loop_end
end
# Skips tabs at the line beginning.
proc _skip_indentation()
begin
-.Lskip_indentation_do:
+ .Lskip_indentation_do
lbu t0, (s1)
li t1, '\t'
beq t0, t1, .Lskip_indentation_skip
- j .Lskip_indentation_end
+ goto .Lskip_indentation_end
-.Lskip_indentation_skip:
+ .Lskip_indentation_skip
_advance(1)
- j .Lskip_indentation_do
+ goto .Lskip_indentation_do
-.Lskip_indentation_end:
+ .Lskip_indentation_end
end
# Parameters:
# a0 - Line length.
-proc _skip_comment()
+proc _skip_comment(loca84: Word)
begin
- add s1, s1, a0
+ _advance(loca84)
_advance(1) # Skip the new line.
end
# Parameters:
# a0 - Line length.
-proc _compile_assembly()
+proc _compile_assembly(loca84: Word)
+var loca0: ^Byte
begin
- sw a0, 4(sp) # a0 - Line length.
-
# Write the source to the standard output.
- mv a0, s1
- lw a1, 4(sp)
- call _write_out
+ loca0 := _current()
- lw t0, 4(sp)
- add s1, s1, t0
+ _write_out(loca0, loca84)
+ _advance(loca84)
li t0, '\n'
sb t0, 0(sp)
@@ -471,16 +620,16 @@ begin
_advance(6) # const\n.
-.Lcompile_constant_section_item:
+ .Lcompile_constant_section_item
_skip_spaces()
lbu a0, (s1)
call _is_upper
beqz a0, .Lcompile_constant_section_end
- call _compile_constant
- j .Lcompile_constant_section_item
+ _compile_constant()
+ goto .Lcompile_constant_section_item
-.Lcompile_constant_section_end:
+ .Lcompile_constant_section_end
end
proc _compile_constant()
@@ -538,16 +687,16 @@ begin
_advance(4) # var\n.
-.Lcompile_variable_section_item:
+ .Lcompile_variable_section_item
_skip_spaces()
lbu a0, (s1)
call _is_lower
beqz a0, .Lcompile_variable_section_end
- call _compile_variable
- j .Lcompile_variable_section_item
+ _compile_variable()
+ goto .Lcompile_variable_section_item
-.Lcompile_variable_section_end:
+ .Lcompile_variable_section_end
end
proc _compile_variable()
@@ -708,7 +857,7 @@ begin
# Skip all declarations until we find the "begin" keyword, denoting the
# beginning of the procedure body.
-.Lcompile_procedure_begin:
+ .Lcompile_procedure_begin
_skip_spaces()
call _read_token
@@ -758,7 +907,7 @@ begin
li t0, 0x0a29 # )\n
sw t0, 12(sp)
- li t0, 0x70732838 # 2(sp
+ li t0, 0x70732838 # 8(sp
sw t0, 8(sp)
li t0, 0x38202c30 # 0, 8
sw t0, 4(sp)
@@ -780,8 +929,61 @@ begin
li a1, 16
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:
+ .Lcompile_procedure_body
_skip_indentation()
call _read_line
sw a0, 12(sp)
@@ -796,9 +998,9 @@ begin
lw a0, 12(sp)
call _compile_line
- j .Lcompile_procedure_body
+ goto .Lcompile_procedure_body
-.Lcompile_procedure_end:
+ .Lcompile_procedure_end
add s1, s1, 4 # Skip end\n.
# Generate the procedure epilogue with a predefined stack size.
@@ -816,7 +1018,7 @@ begin
li t0, 0x0a29 # )\n
sw t0, 12(sp)
- li t0, 0x70732838 # 2(sp
+ li t0, 0x70732838 # 8(sp
sw t0, 8(sp)
li t0, 0x38202c30 # 0, 8
sw t0, 4(sp)
@@ -869,7 +1071,7 @@ begin
addi t1, a1, 0
addi t2, a2, 0
-.Ltoken_compare_loop:
+ .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
@@ -886,25 +1088,97 @@ begin
addi t0, t0, 1
addi t1, t1, -1
addi t2, t2, 1
- j .Ltoken_compare_loop
+ goto .Ltoken_compare_loop
-.Ltoken_compare_not_equal:
+ .Ltoken_compare_not_equal
li a0, 1
- j .Ltoken_compare_end
+ goto .Ltoken_compare_end
-.Ltoken_compare_equal:
+ .Ltoken_compare_equal
li a0, 0
-.Ltoken_compare_end:
+ .Ltoken_compare_end
+end
+
+proc _compile_goto()
+begin
+ 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
+
+ _skip_spaces()
+ sw s1, 8(sp) # We should be on dot the label is beginning with.
+ _advance(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
+
+ _advance(1) # Skip the new line.
+
+ li t0, 0x0a # \n
+ sw t0, 8(sp)
+ addi a0, sp, 8
+ li a1, 1
+ call _write_out
+end
+
+# a0 - Line length.
+proc _compile_label()
+begin
+ 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, 0x0a # \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.
end
# 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.
proc _compile_line()
begin
- sw a0, 20(sp) # a0 - Line length.
+ # Preserve passed arguments.
+ sw a0, 20(sp)
+ sw a1, 16(sp)
beqz a0, .Lcompile_line_empty # Skip an empty line.
@@ -913,125 +1187,167 @@ begin
beq t0, t1, .Lcompile_line_comment
li t0, 0x0a6d6172 # ram\n
- sw t0, 16(sp)
- li t0, 0x676f7270 # prog
sw t0, 12(sp)
+ li t0, 0x676f7270 # prog
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 8
call _memcmp
beqz a0, .Lcompile_line_program
li t0, 0x0a74 # t\n
- sw t0, 16(sp)
- li t0, 0x736e6f63 # cons
sw t0, 12(sp)
+ li t0, 0x736e6f63 # cons
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_const
li t0, 0x0a726176 # var\n
- sw t0, 16(sp)
+ sw t0, 12(sp)
mv a0, s1
- addi a1, sp, 16
+ addi a1, sp, 12
li a2, 4
- call _memcmp;
+ call _memcmp
beqz a0, .Lcompile_line_var
li t0, 0x20 # _
- sw t0, 16(sp)
- li t0, 0x636f7270 # proc
sw t0, 12(sp)
+ li t0, 0x636f7270 # proc
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 5
call _memcmp
beqz a0, .Lcompile_line_procedure
li t0, 0x0a6e # n\n
- sw t0, 16(sp)
- li t0, 0x69676562 # begi
sw t0, 12(sp)
+ li t0, 0x69676562 # begi
+ sw t0, 8(sp)
mv a0, s1
- addi a1, sp, 12
+ addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_begin
li t0, 0x2e646e65 # end.
- sw t0, 16(sp)
+ sw t0, 12(sp)
mv a0, s1
- addi a1, sp, 16
+ addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_exit
li t0, 0x61636f6c # loca
- sw t0, 16(sp)
+ sw t0, 12(sp)
mv a0, s1
- addi a1, sp, 16
+ 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
+
lbu t0, (s1)
+ li t1, '.'
+ beq t0, t1, .Lcompile_line_label
li t1, '_'
beq t0, t1, .Lcompile_line_identifier
- j .Lcompile_line_unchanged # Else.
+ goto .Lcompile_line_unchanged # Else.
+
+ .Lcompile_line_label
+ lw a0, 20(sp)
+ call _compile_label
+ goto .Lcompile_line_section
+
+ .Lcompile_line_goto
+ _compile_goto()
+ goto .Lcompile_line_section
-.Lcompile_line_identifier:
- call _compile_identifier
- j .Lcompile_line_section
+ .Lcompile_line_import
+ _compile_import()
+ goto .Lcompile_line_section
-.Lcompile_line_exit:
- call _compile_exit
- j .Lcompile_line_section
+ .Lcompile_line_identifier
+ _compile_identifier()
+ goto .Lcompile_line_section
-.Lcompile_line_begin:
- call _compile_entry_point
+ .Lcompile_line_exit
+ _compile_exit()
+ goto .Lcompile_line_section
+
+ .Lcompile_line_begin
+ lw a1, 16(sp)
+ bnez a1, .Lcompile_line_compile_entry
+ _compile_text_section()
+ .Lcompile_line_compile_entry
+ _compile_entry_point()
li a0, 1
- j .Lcompile_line_end
+ goto .Lcompile_line_end
-.Lcompile_line_const:
- call _compile_constant_section
- j .Lcompile_line_section
+ .Lcompile_line_const
+ _compile_constant_section()
+ goto .Lcompile_line_section
-.Lcompile_line_procedure:
- call _compile_procedure
+ .Lcompile_line_procedure
+ lw a1, 16(sp)
+ bnez a1, .Lcompile_line_compile_procedure
+ _compile_text_section()
+ .Lcompile_line_compile_procedure
+ _compile_procedure()
li a0, 1
- j .Lcompile_line_end
+ goto .Lcompile_line_end
-.Lcompile_line_var:
- call _compile_variable_section
- j .Lcompile_line_section
+ .Lcompile_line_var
+ _compile_variable_section()
+ goto .Lcompile_line_section
-.Lcompile_line_program:
- call _compile_program
- j .Lcompile_line_section
+ .Lcompile_line_program
+ _compile_program()
+ goto .Lcompile_line_section
-.Lcompile_line_comment:
+ .Lcompile_line_comment
lw a0, 20(sp)
call _skip_comment
- j .Lcompile_line_section
+ goto .Lcompile_line_section
-.Lcompile_line_empty:
+ .Lcompile_line_empty
_advance(1)
- j .Lcompile_line_section
+ goto .Lcompile_line_section
-.Lcompile_line_unchanged:
+ .Lcompile_line_unchanged
lw a0, 20(sp)
call _compile_assembly
- j .Lcompile_line_section
+ goto .Lcompile_line_section
-.Lcompile_line_section:
+ .Lcompile_line_section
mv a0, zero
-.Lcompile_line_end:
+ .Lcompile_line_end
end
+# Prints ".section .text" and exits.
proc _compile_text_section()
begin
# .section .text
@@ -1107,31 +1423,40 @@ proc _read_line()
begin
mv t0, s1 # Local position in the source text.
-.Lread_line_do:
+ .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
+ goto .Lread_line_do
-.Lread_line_end:
+ .Lread_line_end
sub a0, t0, s1 # Return the line length.
end
proc _compile()
begin
-.Lcompile_do:
+ 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.
_skip_indentation()
call _read_line
+ lw a1, 4(sp)
call _compile_line
- j .Lcompile_do
-.Lcompile_end:
+ 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)
+
+ goto .Lcompile_do
+ .Lcompile_end
end
# Returns the pointer to the current position in the source text in a0.
@@ -1146,6 +1471,12 @@ begin
add s1, s1, a0
end
+# Returns the first character in the remaining source text.
+proc _front()
+begin
+ lbu a0, (s1)
+end
+
# Entry point.
begin
# Read the source from the standard input.
@@ -1155,5 +1486,5 @@ begin
call _read_file
la s1, source_code # s1 = Source code position.
- call _compile
+ _compile()
end.
diff --git a/run.rb b/run.rb
deleted file mode 100755
index ac8fc3d..0000000
--- a/run.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env ruby
-
-require 'open3'
-require 'fileutils'
-require 'pathname'
-
-TMP = Pathname.new 'build'
-CROSS_GCC = '../riscv32-ilp32d--glibc/bin/riscv32-linux-gcc'
-SYSROOT = '../riscv32-ilp32d--glibc/riscv32-buildroot-linux-gnu/sysroot'
-
-COMMON_BOOT_OBJECT = TMP + 'common-boot.o'
-
-FileUtils.rm_rf TMP
-FileUtils.mkdir_p TMP
-
-FileUtils.cp 'boot/asm-boot.s', TMP
-
-def stage(source_elna, stage_name, output)
- boot_exe = (TMP + stage_name).to_path
- stage_path = TMP + "#{stage_name}.s"
- arguments = [CROSS_GCC, '-nostdlib', '-o', boot_exe, stage_path.to_path, COMMON_BOOT_OBJECT.to_path]
-
- puts(arguments * ' ')
- system *arguments, exception: true
-
- arguments = ['qemu-riscv32', '-L', SYSROOT, boot_exe]
-
- puts(arguments * ' ')
- puts
- Open3.popen2(*arguments) do |qemu_in, qemu_out|
- qemu_in.write source_elna
- qemu_in.close
-
- IO.copy_stream qemu_out, output
- qemu_out.close
- end
-end
-
-system CROSS_GCC, '-nostdlib', '-c', '-o', COMMON_BOOT_OBJECT.to_path, 'boot/common-boot.s', exception: true
-source_elna = File.read 'boot/goto-boot.elna'
-
-next_stage = TMP + 'goto-boot.s'
-File.open next_stage, 'w' do |output|
- stage source_elna, 'asm-boot', output
-end
-stage(source_elna, 'goto-boot', $stdout)