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, *assembler + sh CROSS_GCC, '-nostdlib', '-o', t.name, *source end -file 'build/stage2.s' => ['build/stage1', 'boot/stage2.elna'] do |t| - assembler, exe = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.elna' } +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, assembler + assemble_stage output, exe, source end end -file 'build/stage2' => ['build/stage2.s', 'boot/common-boot.s'] do |t| +file 'build/stage2a' => ['build/stage2a.s', 'boot/common-boot.s'] do |t| + sh CROSS_GCC, '-nostdlib', '-o', t.name, *t.prerequisites +end + +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, source + end +end + +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 similarity index 73% rename from boot/echo-boot.s rename to 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, 8(sp) - addi a0, sp, 8 + sw t0, 4(sp) + addi a0, sp, 4 li a1, 7 call _write_out - lw a0, 20(sp) - lw a1, 16(sp) - call _write_out - - li t0, 0x0a # \n - sw t0, 12(sp) - addi a0, sp, 12 - li a1, 1 - call _write_out - - j .Lbuild_expression_end - -.Lbuild_expression_number_literal: - li t0, 0x202c30 # 0,_ - sw t0, 12(sp) - li t0, 0x6120696c # li a - sw t0, 8(sp) - addi a0, sp, 8 - li a1, 7 - call _write_out - - lw a0, 20(sp) - lw a1, 16(sp) - call _write_out - - li t0, 0x0a # \n - sw t0, 12(sp) - addi a0, sp, 12 - li a1, 1 - call _write_out - - j .Lbuild_expression_end - -.Lbuild_expression_end: 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, 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, 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_literal: + lw t1, 20(sp) + li t0, 0x00202c00 # \0,_ + or t0, t0, t1 + sw t0, 8(sp) + li t0, 0x6120696c # li 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_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 - 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, 0x0a36392d # -96\n - sw t0, 12(sp) - addi a0, sp, 12 - li a1, 4 + 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, 0x70732832 # 2(sp - sw t0, 8(sp) - li t0, 0x39202c61 # a, 9 - 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 + li t0, 0x70732834 # 4(sp sw t0, 8(sp) li t0, 0x38202c30 # 0, 8 sw t0, 4(sp) - li t0, 0x73207773 # sw s + li t0, 0x61207773 # sw a 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, '0' + sb t0, 8(sp) + li t0, 0x38202c31 # 1, 8 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 + + 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. @@ -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 -.section .text - -# Evalutes an expression and saves the result in a0. -proc _build_expression() +# 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 s1, 20(sp) - sw a0, 16(sp) + 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 =. + _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, 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, 8(sp) - addi a0, sp, 8 + sw t0, 4(sp) + addi a0, sp, 4 li a1, 7 call _write_out - lw a0, 20(sp) - lw a1, 16(sp) - call _write_out - - li t0, 0x0a # \n - sw t0, 12(sp) - addi a0, sp, 12 - li a1, 1 - call _write_out - - j .Lbuild_expression_end - -.Lbuild_expression_number_literal: - li t0, 0x202c30 # 0,_ - sw t0, 12(sp) - li t0, 0x6120696c # li a - sw t0, 8(sp) - addi a0, sp, 8 - li a1, 7 - call _write_out - - lw a0, 20(sp) - lw a1, 16(sp) - call _write_out - - li t0, 0x0a # \n - sw t0, 12(sp) - addi a0, sp, 12 - li a1, 1 - call _write_out - - j .Lbuild_expression_end - -.Lbuild_expression_end: 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, 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, 8(sp) + li t0, 0x29707328 # (sp) + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 5 + call _write_out + + goto .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 + + goto .Lbuild_expression_end + + .Lbuild_expression_literal + lw t1, 20(sp) + li t0, 0x00202c00 # \0,_ + or t0, t0, t1 + sw t0, 8(sp) + li t0, 0x6120696c # li 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_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) - mv a0, s1 - addi a1, sp, 16 - 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) 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, 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_identifier: - call _compile_identifier - j .Lcompile_line_section + .Lcompile_line_label + lw a0, 20(sp) + call _compile_label + goto .Lcompile_line_section -.Lcompile_line_exit: - call _compile_exit - j .Lcompile_line_section + .Lcompile_line_goto + _compile_goto() + goto .Lcompile_line_section -.Lcompile_line_begin: - call _compile_entry_point + .Lcompile_line_import + _compile_import() + goto .Lcompile_line_section + + .Lcompile_line_identifier + _compile_identifier() + goto .Lcompile_line_section + + .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)