### GNU Mes --- Maxwell Equations of Software
### Copyright (C) 2016 Jeremiah Orians
### Copyright © 2022 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
###
### This file is part of GNU Mes.
###
### GNU Mes is free software; you can redistribute it and/or modify it
### under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 3 of the License, or (at
### your option) any later version.
###
### GNU Mes is distributed in the hope that it will be useful, but
### WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.

:_start
	'0' SP BP NO_SHIFT MOVE_ALWAYS  ; Setup Base Pointer

	;; Prepare argv
	!4 R0 ADD BP ARITH_ALWAYS       ; ARGV_address = BP + 4
	{R0} PUSH_ALWAYS                ; Put argv on the stack

	;; Prepare envp
	'0' BP R0 NO_SHIFT MOVE_ALWAYS  ; Address we need to load from
	!0 R0 LOAD32 R0 MEMORY          ; Get ARGC
	!2 R0 ADD R0 ARITH_ALWAYS       ; OFFSET = ARGC + 2
	'0' R0 R0 '1' MOVE_ALWAYS       ; OFFSET = OFFSET * WORDSIZE
	'0' R0 R0 ADD BP ARITH2_ALWAYS  ; ENVP_address = BP + OFFSET
	{R0} PUSH_ALWAYS                ; Put envp on the stack

	mov____%r0,0x32 &GLOBAL_environ

	;; Stack offset
	!4 BP ADD BP ARITH_ALWAYS       ; Fix BP

	;;^~FUNCTION___init_io CALL_ALWAYS ; Setup for FILE*

        ;; Initialize MesCC lib file descriptors.
	!0 mov____$i8,%r0
	mov____%r0,0x32 &GLOBAL___stdin
	!1 mov____$i8,%r0
	mov____%r0,0x32 &GLOBAL___stdout
	!2 mov____$i8,%r0
	mov____%r0,0x32 &GLOBAL___stderr

	^~FUNCTION_main CALL_ALWAYS     ; Jump right into main

	SYS_exit mov____$i8,%r7
	swi____$0


# Unsigned Divide
:divide
	{R4} PUSH_ALWAYS                ; Protect R4
	{R3} PUSH_ALWAYS                ; Protect R3
	{R2} PUSH_ALWAYS                ; Protect R2

	'0' R0 R3 NO_SHIFT MOVE_ALWAYS  ; MOV R3,R0
	'0' R1 R2 NO_SHIFT MOVE_ALWAYS  ; MOV R2,R1

	!0 R0 LOADI8_ALWAYS             ; MOV R0,#0
	!0 CMPI8 R2 IMM_ALWAYS          ; CMP R2,#0
	!1 R0 SUB R0 ARITH_LT           ; SUBLT R0,R0,#1
	!0 CMPI8 R3 IMM_ALWAYS          ; CMP R3,#0
	!0 R3 RSUB R3 ARITH_LT          ; RSBLT R3,R3,#0
	'0' R0 R0 MVN_LT                ; MVNLT R0,R0
	'0' R0 R4 NO_SHIFT MOVE_ALWAYS  ; MOV R4,R0

	!32 R0 LOADI8_ALWAYS            ; MOV  R0,#32.
	!0 R1 LOADI8_ALWAYS             ; MOV  R1,#0
:divide_loop
	'0' R2 R2 ADDS R2 ARITH2_ALWAYS ; ADDS R2,R2,R2
	'0' R1 R1 ADCS R1 ARITH2_ALWAYS ; ADCS R1,R1,R1
	'0' R3 CMP R1 AUX_ALWAYS        ; CMP  R1,R3
	'0' R3 R1 SUB R1 ARITH2_GE      ; SUBGE  R1,R1,R3
	!1 R2 ADD R2 ARITH_GE           ; ADDGE  R2,R2,#1
	!1 R0 SUB R0 ARITH_ALWAYS       ; SUB  R0,R0,#1
	!0 CMPI8 R0 IMM_ALWAYS          ; CMP  R0,#0
	^~divide_loop JUMP_NE           ; BNE  loop

	'0' R2 R0 NO_SHIFT MOVE_ALWAYS  ; MOV R0,R2

	{R2} POP_ALWAYS                 ; Restore R2
	{R3} POP_ALWAYS                 ; Restore R3
	{R4} POP_ALWAYS                 ; Restore R4
	'1' LR RETURN

# Signed Divide
:divides
	{R4} PUSH_ALWAYS                ; Protect R4
	{R3} PUSH_ALWAYS                ; Protect R3
	{R2} PUSH_ALWAYS                ; Protect R2

	'0' R0 R3 NO_SHIFT MOVE_ALWAYS  ; MOV R3,R0
	'0' R1 R2 NO_SHIFT MOVE_ALWAYS  ; MOV R2,R1

	!0 R0 LOADI8_ALWAYS             ; MOV R0,#0
	!0 CMPI8 R2 IMM_ALWAYS          ; CMP R2,#0
	!0 R2 RSUB R2 ARITH_LT          ; RSBLT R2,R2,#0
	!1 R0 SUB R0 ARITH_LT           ; SUBLT R0,R0,#1
	!0 CMPI8 R3 IMM_ALWAYS          ; CMP R3,#0
	!0 R3 RSUB R3 ARITH_LT          ; RSBLT R3,R3,#0
	'0' R0 R0 MVN_LT                ; MVNLT R0,R0
	'0' R0 R4 NO_SHIFT MOVE_ALWAYS  ; MOV R4,R0

	!32 R0 LOADI8_ALWAYS            ; MOV  R0,#32.
	!0 R1 LOADI8_ALWAYS             ; MOV  R1,#0
:divides_loop
	'0' R2 R2 ADDS R2 ARITH2_ALWAYS ; ADDS R2,R2,R2
	'0' R1 R1 ADCS R1 ARITH2_ALWAYS ; ADCS R1,R1,R1
	'0' R3 CMP R1 AUX_ALWAYS        ; CMP  R1,R3
	'0' R3 R1 SUB R1 ARITH2_GE      ; SUBGE  R1,R1,R3
	!1 R2 ADD R2 ARITH_GE           ; ADDGE  R2,R2,#1
	!1 R0 SUB R0 ARITH_ALWAYS       ; SUB  R0,R0,#1
	!0 CMPI8 R0 IMM_ALWAYS          ; CMP  R0,#0
	^~divides_loop JUMP_NE          ; BNE  loop

	!0 CMPI8 R4 IMM_ALWAYS          ; CMP R4,#0
	!0 R2 RSUB R2 ARITH_NE          ; RSBNE R2,R2,#0
	'0' R2 R0 NO_SHIFT MOVE_ALWAYS  ; MOV R0,R2

	{R2} POP_ALWAYS                 ; Restore R2
	{R3} POP_ALWAYS                 ; Restore R3
	{R4} POP_ALWAYS                 ; Restore R4
	'1' LR RETURN

# Unsigned Modulus
:modulus
	{LR} PUSH_ALWAYS                ; Prepare to leverage divide
	^~divide CALL_ALWAYS            ; Use divide
	'0' R1 R0 NO_SHIFT MOVE_ALWAYS  ; MOV R0,R1
	{LR} POP_ALWAYS                 ; Prepare for return
	'1' LR RETURN

# Signed Modulus
:moduluss
	{LR} PUSH_ALWAYS                ; Prepare to leverage divide
	^~divides CALL_ALWAYS           ; Use divides
	'0' R1 R0 NO_SHIFT MOVE_ALWAYS  ; MOV R0,R1
	{LR} POP_ALWAYS                 ; Prepare for return
	'1' LR RETURN
