Added arithmetic functions to core.asm
authorBen Dudson <bd512@york.ac.uk>
Sun, 22 Oct 2017 14:09:13 +0000 (15:09 +0100)
committerBen Dudson <bd512@york.ac.uk>
Sun, 22 Oct 2017 14:09:13 +0000 (15:09 +0100)
Starting step 2.

* core_add, core_sub, core_mul and core_div are defined
  in core.asm. These take a list of integers and return an integer.

Currently step2_eval.asm is hard-wired to call core_add,
so (1 2 3) -> 6

nasm/Makefile
nasm/core.asm [new file with mode: 0644]
nasm/step2_eval.asm [new file with mode: 0644]

index 1e7ea2f..9dfc396 100644 (file)
@@ -2,6 +2,12 @@ step0_repl: step0_repl.asm
        nasm -felf64 step0_repl.asm
        ld -o $@ step0_repl.o
 
-step1_read_print: step1_read_print.asm
+COMPONENTS=core.asm reader.asm printer.asm types.asm system.asm
+
+step1_read_print: step1_read_print.asm $(COMPONENTS)
        nasm -felf64 step1_read_print.asm
        ld -o $@ step1_read_print.o
+
+step2_eval: step2_eval.asm $(COMPONENTS)
+       nasm -felf64 step2_eval.asm
+       ld -o $@ step2_eval.o
diff --git a/nasm/core.asm b/nasm/core.asm
new file mode 100644 (file)
index 0000000..79d88cd
--- /dev/null
@@ -0,0 +1,86 @@
+;; Core functions
+;;
+;;
+
+section .text
+
+;; Adds a list of numbers, address in RSI
+;; Returns the sum as a number object with address in RAX
+;; Since most of the code is common to all operators,
+;; RBX is used to jump to the required instruction
+core_add:
+        mov rbx, core_arithmetic.do_addition
+        jmp core_arithmetic
+core_sub:
+        mov rbx, core_arithmetic.do_subtraction
+        jmp core_arithmetic
+core_mul:
+        mov rbx, core_arithmetic.do_multiply
+        jmp core_arithmetic
+core_div:
+        mov rbx, core_arithmetic.do_division
+        ; Fall through to core_arithmetic
+core_arithmetic:
+        ; Check that the first object is a number
+        mov cl, BYTE [rsi]
+        mov ch, cl
+        and ch, block_mask
+        cmp ch, block_cons
+        jne .error
+        mov ch, cl
+        and ch, content_mask
+        cmp ch, content_int
+        jne .error
+
+        ; Put the starting value in rax
+        mov rax, [rsi + Cons.car]
+        
+.add_loop:
+        ; Fetch the next value
+        mov cl, [rsi + Cons.typecdr]
+        cmp cl, content_nil
+        je .finished            ; Nothing let
+        cmp cl, content_pointer
+        jne .error
+
+        mov rsi, [rsi + Cons.cdr] ; Get next cons
+
+        ; Check that it is an integer
+        mov cl, BYTE [rsi]
+        and cl, content_mask
+        cmp cl, content_int
+        jne .error
+
+        ; Jump to the required operation, address in RBX
+        jmp rbx
+        
+.do_addition:
+        add rax, [rsi + Cons.car]
+        jmp .add_loop
+.do_subtraction:
+        sub rax, [rsi + Cons.car]
+        jmp .add_loop
+.do_multiply:
+        imul rax, [rsi + Cons.car]
+        jmp .add_loop
+.do_division:
+        xor rdx, rdx            ; Zero high bits
+        mov rcx, [rsi + Cons.car]
+        idiv rcx
+        jmp .add_loop
+        
+.finished:
+        ; Value in rbx
+        push rax
+        ; Get a Cons object to put the result into
+        call alloc_cons
+        pop rbx
+        mov [rax], BYTE maltype_integer
+        mov [rax + Cons.car], rbx
+        ret
+.error:
+        ; Return nil
+        call alloc_cons
+        mov [rax], BYTE maltype_nil
+        mov [rax + Cons.typecdr], BYTE content_nil
+        ret
diff --git a/nasm/step2_eval.asm b/nasm/step2_eval.asm
new file mode 100644 (file)
index 0000000..eed5fe1
--- /dev/null
@@ -0,0 +1,124 @@
+;; 
+;; nasm -felf64 step1_read_print.asm && ld step1_read_print.o && ./a.out
+
+;; Calling convention: Address of input is in RSI
+;;                     Address of return value is in RAX
+;;
+        
+global  _start
+        
+%include "types.asm"            ; Data types, memory
+%include "system.asm"           ; System calls
+%include "reader.asm"           ; String -> Data structures
+%include "core.asm"             ; Core functions
+%include "printer.asm"          ; Data structures -> String
+        
+section .data
+
+test_string1: db 10, "test1", 10
+.len: equ $ - test_string1
+
+test_string2: db 10, "test2", 10
+.len: equ $ - test_string2    
+        
+;str: ISTRUC Array
+;AT Array.type,  db   maltype_string
+;AT Array.length, dd  6
+;AT Array.data, db 'hello',10
+;IEND
+
+test_cons: ISTRUC Cons
+AT Cons.typecar, db ( maltype_integer + 2 )
+AT Cons.typecdr, db 0
+AT Cons.car, dq 123
+IEND
+
+test_cons2: ISTRUC Cons
+AT Cons.typecar, db ( maltype_integer + 2 )
+AT Cons.typecdr, db content_pointer
+AT Cons.car, dq 456
+AT Cons.cdr, dq test_cons
+IEND
+        
+;; ------------------------------------------
+;; Fixed strings for printing
+        
+prompt_string: db 10,"user> "      ; The string to print at the prompt
+.len: equ $ - prompt_string
+  
+section .text   
+        
+;; Evaluates a form
+eval:
+        mov rax, rsi            ; Return the input
+        ret
+        
+;; Prints the result
+print:
+        mov rax, rsi            ; Return the input
+        ret
+
+;; Read-Eval-Print in sequence
+rep_seq:
+        call read_str
+        mov rsi, rax            ; Output of read into input of eval
+        call eval
+        mov rsi, rax            ; Output of eval into input of print 
+        call print
+        mov rsi, rax            ; Return value
+        ret
+
+
+_start:
+        
+        ; -----------------------------
+        ; Main loop
+        
+.mainLoop:
+        ; print the prompt
+        mov rdx, prompt_string.len ; number of bytes
+        mov rsi, prompt_string        ; address of raw string to output
+        call print_rawstring
+
+        call read_line
+        
+        ; Check if we have a zero-length string
+        cmp DWORD [rax+Array.length], 0
+        je .mainLoopEnd
+
+        push rax                ; Save address of the string
+
+        ; Put into read_str
+        mov rsi, rax
+        call read_str
+        push rax
+
+        ; Add together
+        mov rsi, rax
+        call core_add
+        
+        ; Put into pr_str
+        mov rsi, rax
+        call pr_str
+        push rax
+        
+        mov rsi, rax            ; Put into input of print_string
+        call print_string
+
+        ; Release string from pr_str
+        pop rsi
+        call release_array
+        
+        ; Release the object from read_str
+        pop rsi
+        call release_object     ; Could be Cons or Array
+        
+        ; Release the string
+        pop rsi
+        call release_array
+        
+        jmp .mainLoop
+.mainLoopEnd:
+        
+        jmp quit
+