#
# CMPUT 229 Public Materials License
# Version 1.1
#
# Copyright 2017 University of Alberta
# Copyright 2017 Austin Crapo
#
# This software is distributed to students in the course
# CMPUT 229 - Computer Organization and Architecture I at the University of
# Alberta, Canada. 
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the disclaimer below in the documentation
#    and/or other materials provided with the distribution.
# 
# 2. Neither the name of the copyright holder nor the names of its
#    contributors may be used to endorse or promote products derived from this
#    software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
######################
#Author: Austin Crapo
#Modified by: Muhammad Usman, Joshua Sabet
#Date: May 2019
#Version 1.0
#
# Fractal renderer to terminal via GLIM library.
# Uses floating point coprocessor for precision.
#
######################

.data
	.align 1
symbols:		#Should not be shorter than paletteSize
	.asciz "."
	.asciz "_"
	.asciz "~"
	.asciz ":"
	.asciz "+"
	.asciz "="
	.asciz "["
	.asciz "{"
	.asciz "$"
	.asciz "#"
	.asciz "@"
	.asciz "&"
	.asciz "}"
    .asciz "}"
	.asciz "*"
	.asciz "+"
	.asciz ";"
	.asciz "~"
	.asciz "-"
	.asciz ","
	.asciz "1"
	.asciz "2"
	.asciz "3"
	.asciz "4"
	.asciz "5"


inSetSymbol:
	.asciz "M"
inSetColor:
	.byte 0

	.align 2
paletteSize:		#min(#symbols, #colors)
	.word	25
	.align 0
colors:		#Should not be shorter than paletteSize
	.byte	17, 18, 19, 20, 21, 27, 33, 39, 45, 51, 50, 49, 48, 47, 46, 82, 118, -102, -66, -30, -29, -28, -27, -26, -25
	.align 3
z_x:
	.float 0.0
z_y:
	.float 0.0
	.align 0
prompt1:
	.asciz "Number of rows to render (int): "
prompt2:
	.asciz "Number of columns to render (int): "
prompt3:
	.asciz "Maximum imaginary value (double): "
prompt4:
	.asciz "Minimum imaginary value (double): "
prompt5:
	.asciz "Maximum real value (double): "
prompt6:
	.asciz "Minimum real value (double): "
prompt7:
	.asciz "Max iterations to calculate (int): "
	.align 2
gameRows:
	.space 4
gameCols:
	.space 4
.text
.globl main
main:	
	# Stack Adjustments
	addi	sp, sp, -4
	sw	s0, 0(sp)
	add	s0, zero, sp
	addi	sp, sp, -16
	sw	ra, -4(s0)
	sw	s1, -8(s0)
	sw	s2, -12(s0)
	sw	s3, -16(s0)
	
	##read the display size
	#Rows
	li	a7, 4
	la	a0, prompt1
	ecall
	li	a7, 5
	ecall
	mv	s1, a0
	#Cols
	li	a7, 4
	la	a0, prompt2
	ecall
	li	a7, 5
	ecall
	mv	s2, a0
	
	
	#get coordinates and set them for map_coords
	li	a7, 4
	la	a0, prompt3
	ecall
	li	a7, 6
	ecall
	fmv.s	ft0, fa0

	li	a7, 4
	la	a0, prompt4
	ecall
	li	a7, 6
	ecall
	fmv.s	fa1, fa0

	li	a7, 4
	la	a0, prompt5
	ecall
	li	a7, 6
	ecall
	fmv.s	fa2, fa0

	li	a7, 4
	la	a0, prompt6
	ecall
	li	a7, 6
	ecall
	fmv.s	fa3, fa0
	
    fmv.s   fa0, ft0

	#provide the screen dimensions as well
	mv	a0, s1
	mv	a1, s2
	
	jal	set_size

	#get the max iterations value
	li	a7, 4
	la	a0, prompt7
	ecall
	li	a7, 5
	ecall
	mv	s3, a0
	
	#set the display size
	mv	a0, s1
	mv	a1, s2
	jal	startGLIM
	la	t0, gameRows
	sw	s1, 0(t0)
	la	t0, gameCols
	sw	s2, 0(t0)
	#prepare the screen
	#jal	clearScreen

	mv	a0, s1
	mv	a1, s2
	mv	a2, s3
	jal	render


	#pause, waiting for input
	li	a7, 5
	ecall

	li	a0, 0
	li	a1, 0
	jal	setColor
	jal	clearScreen
	
	
	
	#MUST BE CALLED BEFORE ENDING PROGRAM
	jal	endGLIM
	
	#Stack Restore
	lw	ra, -4(s0)
	lw	s1, -8(s0)
	lw	s2, -12(s0)
	lw	s3, -16(s0)
	addi	sp, sp, 16
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret
	
.data
max_i:
	.float	0.0
min_r:
	.float	0.0
step_r:
	.float 0.0
step_i:
	.float 0.0
.text
map_coords:
	########################################################################
	# Given a set of integer screen coordinates (row, column) where:
	#	0 <= row < # of screen rows
	#	0 <= column < # of screen columns
	# maps the coordinates to the complex plane of the mandelbrot set
	# (real, imaginary) as doubles where:
	#	min_r <= real <= max_r
	#	min_i <= imaginary <= max_i
	# row => imaginary and column => real
	# Column is mapped proportionally (low mapped to low)
	# Row is mapped inverse proportionally (low mapped to high)
	#
	# Arguments:
	# a0 = row
	# a1 = column
	#
	# Returns (double floating point values):
	# fa0 = real part
	# fa1 = imaginary part
	#
	# Register Usage
	# ft0 = floating point conversion of a0/a1
	# ft1 = jump step calculation
	# ft2 = boundary we need (max_i or min_r)
	# ft3 = step_r
	# ft4 = step_i
	########################################################################
	# to convert one range of discrete (integer) numbers, to another range
	# of continuous (real) numbers, we first need a 'step size'.
	# Step_size = (max_discrete - min_discrete)/number_of_discrete_values
	# Then the max continuous number = min continuous number + step_size*# of discrete values
	# and for any discrete value which is the nth discrete value
	# nth real number = min real number + step_size*n
	
	#get the step sizes
	la  t0, step_r
	flw	ft3, 0(t0)
	la  t0, step_i
	flw	ft4, 0(t0)
	
	#convert inputs to doubles, imaginary part
	fcvt.s.w	ft0, a0	#row
	
	# row - inversely mapped so we minus from max instead of add from min
	la  t0, max_i
	flw	ft2, 0(t0)
	fmul.s	ft1, ft0, ft4	# jump = row*step_i
	fsub.s	fa1, ft2, ft1	# i = max_i - jump
	
	#convert inputs to doubles, real part
	fcvt.s.w	ft0, a1	#col
	
	# col
	la t0, min_r
	flw	ft2, 0(t0)
	fmul.s	ft1, ft0, ft3	# jump = col*step_r
	fadd.s	fa0, ft2, ft1	# r = min_r + jump
	
	ret
##############################################################################
#					START OF GLIM
##############################################################################
# The following copy of GLIM has been reduced to only those functions relevant
# to this assigment.
######################
#Author: Austin Crapo
#Date: June 2017
#Version: 2017.6.30
#
#
# Does not support being run in a tab; Requires a separate window.
#
# Currently printing to negative values does not print. Printing to
# offscreen pixels in the positive directions prints to last pixel
# available on the screen in that direction.
######################
.data
.align 2
clearScreenCmd:
	.byte 0x1b, 0x5b, 0x32, 0x4a, 0x00
.text
clearScreen:
	########################################################################
	# Uses xfce4-terminal escape sequence to clear the screen
	#
	# Register Usage
	# Overwrites a7 and a0 during operation
	########################################################################
	li	a7, 4
	la	a0, clearScreenCmd
	ecall
	
	ret

.data
setCstring:
	.byte 0x1b, 0x5b, 0x30, 0x30, 0x30, 0x3b, 0x30, 0x30, 0x30, 0x48, 0x00
.text
setCursor:
	########################################################################
	#mvs the cursor to the specified location on the screen. Max location
	# is 3 digits for row number, and 3 digits for column number. (row, col)
	#
	# a0 = row number to mv to
	# a1 = col number to mv to
	#
	# Register Usage
	# Overwrites a0 and a0 during operation
	########################################################################
	# Stack Adjustments
	addi	sp, sp, -4		# Adjust the stack to save s0
	sw	s0, 0(sp)		# Save s0
	add	s0, zero, sp		# s0 <= sp
	addi	sp, sp, -12		# Adjust stack to save variables
	sw	ra, -4(s0)		# Save ra
	#skip s1, this could be cleaned up
	sw	s2, -8(s0)		
	sw	s3, -12(s0)		
	
	#The control sequence we need is "\x1b[a1;a2H" where "\x1b"
	#is xfce4-terminal's method of passing the hex value for the ESC key.
	#This mvs the cursor to the position, where we can then print.
	
	#The command is preset in memory, with triple zeros as placeholders
	#for the char coords. We translate the args to decimal chars and edit
	# the command string, then print
	
	mv	s2, a0
	mv	s3, a1
	
	li	t0, 0x30	#'0' in ascii, we add according to the number
	#separate the three digits of the passed in number
	#1's = x%10
	#10's = x%100 - x%10
	#100's = x - x$100
	
	# NOTE: we add 1 to each coordinate because we want (0,0) to be the top
	# left corner of the screen, but most terminals define (1,1) as top left
	#ROW
	addi	a0, s2, 1
	la	t2, setCstring
	jal	intToChar
	lb	t0, 0(a0)
	sb	t0, 4(t2)
	lb	t0, 1(a0)
	sb	t0, 3(t2)
	lb	t0, 2(a0)
	sb	t0, 2(t2)
	
	#COL
	addi	a0, s3, 1
	la	t2, setCstring
	jal	intToChar
	lb	t0, 0(a0)
	sb	t0, 8(t2)
	lb	t0, 1(a0)
	sb	t0, 7(t2)
	lb	t0, 2(a0)
	sb	t0, 6(t2)

	#mv the cursor
	li	a7, 4
	la	a0, setCstring
	ecall
	
	#Stack Restore
	lw	ra, -4(s0)
	lw	s2, -8(s0)
	lw	s3, -12(s0)
	addi	sp, sp, 12
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret

.text
printString:
	########################################################################
	# Prints the specified null-terminated string started at the
	# specified location to the string and then continuing until
	# the end of the string, according to the printing preferences of your
	# terminal (standard terminals print left to right, top to bottom).
	# Is not screen aware, passing paramaters that would print a character
	# off screen have undefined effects on your terminal window. For most
	# terminals the cursor will wrap around to the next row and continue
	# printing. If you have hit the bottom of the terminal window,
	# the xfce4-terminal window default behavior is to scroll the window 
	# down. This can offset your screen without you knowing and is 
	# dangerous since it is undetectable. The most likely useage of this
	# function is to print characters. The reason that it is a string it
	# prints is to support the printing of escape character sequences
	# around the character so that fancy effects are supported. Some other
	# terminals may treat the boundaries of the terminal window different,
	# for example some may not wrap or scroll. It is up to the user to
	# test their terminal window for its default behaviour.
	# Is built for xfce4-terminal.
	# Position (0, 0) is defined as the top left of the terminal.
	#
	# a0 = address of string to print
	# a1 = integer value 0-999, row to print to (y position)
	# a2 = integer value 0-999, col to print to (x position)
	#
	# Register Usage
	# t0 - t3, t4-t6 = temp storage of bytes and values
	########################################################################
	# Stack Adjustments
	addi	sp, sp, -4		# Adjust the stack to save s0
	sw	s0, 0(sp)		# Save s0
	add	s0, zero, sp		# s0 <= sp
	addi	sp, sp, -8		# Adjust stack to save variables
	sw	ra, -4(s0)		# Save ra
	sw	s1, -8(s0)		# Save s1
	
	mv	s1, a0
	
	mv	a0, a1
	mv	a1, a2
	jal	setCursor
	
	#print the char
	li	a7, 4
	mv	a0, s1
	ecall
	
	#Stack Restore
	lw	ra, -4(s0)
	lw	s1, -8(s0)
	addi	sp, sp, 8
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret


.data
.align 2
intToCharSpace:
	.space	4	#storing 4 bytes, only using 3, because of spacing.
.text
intToChar:
	########################################################################
	# Given an int x where 0 <= x <= 999, converts the integer into 3 bytes,
	# which are the character representation of the int. If the integer
	# requires larger than 3 chars to represent, only the 3 least 
	# significant digits will be converted.
	#
	# a0 = integer to convert
	#
	# Return Values:
	# a0 = address of the bytes, in the following order, 1's, 10's, 100's
	#
	# Register Usage
	# t0-t6 = temporary value storage
	########################################################################
	li	t0, 0x30	#'0' in ascii, we add according to the number
	#separate the three digits of the passed in number
	#1's = x%10
	#10's = x%100 - x%10
	#100's = x - x$100
	la	a1, intToCharSpace
	#ones
	li	t1, 10		
	rem	t4, a0, t1
	add	t1, t0, t4	#byte = 0x30 + x%10
	sb	t1, 0(a1)
	#tens
	li	t1, 100		
	rem	t5, a0, t1
	sub	t1, t5, t4	#byte = 0x30 + (x%100 - x%10)/10
	li	t3, 10
	div	t1, t1, t3
	add	t1, t0, t1	
	sb	t1, 1(a1)
	#100s
	li	t1, 1000		
	rem	t6, a0, t1
	sub	t1, t6, t5	#byte = 0x30 + (x%1000 - x%100)/100
	li	t3, 100
	div	t1, t1, t3
	add	t1, t0, t1	
	sb	t1, 2(a1)
	
    mv a0, a1

	ret
	
.data
.align 2
setFGorBG:
	.byte 0x1b, 0x5b, 0x34, 0x38, 0x3b, 0x35, 0x3b, 0x30, 0x30, 0x30, 0x6d, 0x00
.text
setColor:
	########################################################################
	# Prints the escape sequence that sets the color of the text to the
	# color specified.
	# 
	# xfce4-terminal supports the 256 color lookup table assignment, 
	# see the index for a list of color codes.
	#
	#
	# a0 = color code (see index)
	# a1 = 0 if setting background, 1 if setting foreground
	#
	# Register Usage
	# s1 = temporary arguement storage accross calls
	# s2 = temporary arguement storage accross calls
	########################################################################
	# Stack Adjustments
	addi	sp, sp, -4		
	sw	s0, 0(sp)		
	add	s0, zero, sp		
	addi	sp, sp, -12		
	sw	ra, -4(s0)		
	sw	s1, -8(s0)		
	sw	s2, -12(s0)		
	
	mv	s1, a0
	mv	s2, a1
	
	jal	intToChar		#get the digits of the color code to print
	
    mv  t2, a0

	mv	a0, s1
	mv	a1, s2
	
	la	t0, setFGorBG
	lb	t1, 0(t2)		#alter the string to print
	sb	t1, 9(t0)
	lb	t1, 1(t2)
	sb	t1, 8(t0)
	lb	t1, 2(t2)
	sb	t1, 7(t0)
	
	beq	a1, zero, sCsetBG	#set the code to print FG or BG
		#setting FG
		li	t1, 0x33
		j	sCset
	sCsetBG:
		li	t1, 0x34
	sCset:
		sb	t1, 2(t0)
	
	li	a7, 4
	mv	a0, t0
	ecall
		
	#Stack Restore
	lw	ra, -4(s0)
	lw	s1, -8(s0)
	lw	s2, -12(s0)
	addi	sp, sp, 12
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret

.data
.align 2
rSstring:
	.byte 0x1b, 0x5b, 0x30, 0x6d, 0x00
.text
restoreSettings:
	########################################################################
	# Prints the escape sequence that restores all default color settings to
	# the terminal
	#
	# Register Usage
	# NA
	########################################################################
	la	a0, rSstring
	li	a7, 4
	ecall
	
	ret

.text
startGLIM:
	########################################################################
	# Sets up the display in order to provide
	# a stable environment. Call endGLIM when program is finished to return
	# to as many defaults and stable settings as possible.
	# Unfortunately screen size changes are not code-reversible, so endGLIM
	# will only return the screen to the hardcoded value of 24x80.
	#
	#
	# a0 = number of rows to set the screen to
	# a1 = number of cols to set the screen to
	#
	# Register Usage
	# NA
	########################################################################
	# Stack Adjustments
	addi	sp, sp, -4		
	sw	s0, 0(sp)		
	add	s0, zero, sp		
	addi	sp, sp, -4		
	sw	ra, -4(s0)
	
	jal	setDisplaySize
	jal	restoreSettings
	jal	clearScreen
	
	jal	hideCursor
	
	#Stack Restore
	lw	ra, -4(s0)
	addi	sp, sp, 4
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret
	

.text
endGLIM:
	########################################################################
	# Reverts to default as many settings as it can, meant to end a program
	# that was started with startGLIM. The default terminal window in
	# xfce4-terminal is 24x80, so this is the assumed default we want to
	# return to.
	#
	# Register Usage
	# NA
	########################################################################
	# Stack Adjustments
	addi	sp, sp, -4		
	sw	s0, 0(sp)		
	add	s0, zero, sp		
	addi	sp, sp, -4		
	sw	ra, -4(s0)
	
	li	a0, 24
	li	a1, 80
	jal	setDisplaySize
	jal	restoreSettings
	
	jal	clearScreen
	
	jal	showCursor
	li	a0, 0
	li	a1, 0
	jal	setCursor
	
	#Stack Restore
	lw	ra, -4(s0)
	addi	sp, sp, 4
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret
	
.data
.align 2
hCstring:
	.byte 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c, 0x00
.text
hideCursor:
	########################################################################
	# Prints the escape sequence that hides the cursor
	#
	# Register Usage
	# NA
	########################################################################
	la	a0, hCstring
	li	a7, 4
	ecall
	
	ret

.data
.align 2
sCstring:
	.byte 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x68, 0x00
.text
showCursor:
	########################################################################
	#Prints the escape sequence that restores the cursor visibility
	#
	# Register Usage
	# NA
	########################################################################
	la	a0, sCstring
	li	a7, 4
	ecall
	
	ret

.data
.align 2
sDSstring:
	.byte 0x1b, 0x5b, 0x38, 0x3b, 0x30, 0x30, 0x30, 0x3b, 0x30, 0x30, 0x30, 0x74 0x00
.text
setDisplaySize:
	########################################################################
	# Prints the escape sequence that changes the size of the display to 
	# match the parameters passed. The number of rows and cols are 
	# ints x and y s.t.:
	# 0<=x,y<=999
	#
	# a0 = number of rows
	# a1 = number of columns
	#
	# Register Usage
	# s1 = temporary a0 storage
	# s2 = temporary a1 storage
	########################################################################
	# Stack Adjustments
	addi	sp, sp, -4		
	sw	s0, 0(sp)		
	add	s0, zero, sp		
	addi	sp, sp, -12		
	sw	ra, -4(s0)		
	sw	s1, -8(s0)		
	sw	s2, -12(s0)
	
	mv	s1, a0
	mv	s2, a1
	
	#rows
	jal	intToChar		#get the digits of the params to print
	
	la	t0, sDSstring
	lb	t1, 0(a0)		#alter the string to print
	sb	t1, 6(t0)
	lb	t1, 1(a0)
	sb	t1, 5(t0)
	lb	t1, 2(a0)
	sb	t1, 4(t0)
	
	#cols
	mv	a0, s2
	jal	intToChar		#get the digits of the params to print
	
	la	t0, sDSstring
	lb	t1, 0(a0)		#alter the string to print
	sb	t1, 10(t0)
	lb	t1, 1(a0)
	sb	t1, 9(t0)
	lb	t1, 2(a0)
	sb	t1, 8(t0)
	
	li	a7, 4
	mv	a0, t0
	ecall
	
	#Stack Restore
	lw	ra, -4(s0)
	lw	s1, -8(s0)
	lw	s2, -12(s0)
	addi	sp, sp, 12
	lw	s0, 0(sp)
	addi	sp, sp, 4
	
	ret
##############################################################################
#					END OF GLIM
##############################################################################
