#
#  linux_logo in ppc assembly language
#    based on the code from ll_asm-0.36
#
#  By Vince Weaver <vince _at_ deater.net>
#
# Modified to remove non-deterministic system calls
# And to avoid reading from /proc
#

# offsets into the results returned by the uname syscall
.equ U_SYSNAME,0
.equ U_NODENAME,65
.equ U_RELEASE,65*2
.equ U_VERSION,(65*3)
.equ U_MACHINE,(65*4)
.equ U_DOMAINNAME,65*5

# offset into the SYSCALL_SYSINFO buffer
.equ S_TOTALRAM,16

# Sycscalls
.equ SYSCALL_EXIT,     1
#.equ SYSCALL_READ,     3
.equ SYSCALL_WRITE,    4
#.equ SYSCALL_OPEN,     5
#.equ SYSCALL_CLOSE,    6
#.equ SYSCALL_SYSINFO,116
#.equ SYSCALL_UNAME,  122

#
.equ STDIN, 0
.equ STDOUT,1
.equ STDERR,2

.equ BSS_BEGIN,25
.equ DATA_BEGIN,26

.include "../logo.include"

	.globl _start	
_start:	

        #========================
	# Initialization
	#========================
	

#	eieio				# coolest opcode of all time ;)
					# not needed, but I had to put it here
  	# the hack loading BSS_BEGIN and DATA_BEGIN
	# saves one instruction on any future load from memory
	# as we can just do an addi rather than an lis;addi

	lis	25,bss_begin@ha
	addi	25,25,bss_begin@l
	
	lis	26,data_begin@ha
	addi	26,26,data_begin@l

	addi	14,BSS_BEGIN,(out_buffer-bss_begin)
					# the output buffer

	addi	21,BSS_BEGIN,(text_buf-bss_begin)
 	     	

	mr	17,14		    	# store out-buffer for later

        #=========================
	# PRINT LOGO
	#=========================

# LZSS decompression algorithm implementation
# by Stephan Walter 2002, based on LZSS.C by Haruhiko Okumura 1989
# optimized some more by Vince Weaver


	li	8,(N-F)			# grab "R"

	addi	9,DATA_BEGIN,(logo-data_begin)-1
					# logo_pointer

	addi	12,DATA_BEGIN,(logo_end-data_begin)-1
					# end of the logo


	mr      16,17

decompression_loop:
	lbzu 	10,1(9)			# load in a byte
					# auto-update
	mr	11,10			# copy to 11
	ori	11,11,0xff00		# re-load top as a hackish 
					# 8-bit counter

test_flags:
	cmpw	0,12,9			# have we reached the end?
	ble	done_logo		# ! if so exit

	andi.	13,11,0x1
	srawi   11,11,1
	
	bne	0,discrete_char

offset_length:
	lbzu  	10,1(9)
	lbzu	24,1(9)
	slwi	24,24,8
	or	24,24,10
	
	mr	10,24

	srawi  15,10,P_BITS
	addi   15,15,THRESHOLD+1 # cl = ax >> (P_BITS)+THRESH+1
	       			 # = match length
	       			 
output_loop:
	andi.  24,24,(POSITION_MASK<<8+0xff)	# mask it
	lbzx   10,21,24				
	addi   24,24,1
	
store_byte:
	stbu   10,1(16)
	
	stbx    10,21,8
	addi	8,8,1
	andi.	8,8,(N-1)

	addic.	15,15,-1
	bne	0,output_loop
	
	andi.	13,11,0xff00
	bne	test_flags
	
	b	decompression_loop

discrete_char:

	lbzu    10,1(9)
	li	15,1

	b       store_byte

done_logo:

	addi	4,17,1		# restore (plus one because r17 is decremented)
	bl	write_stdout	# and print the logo
	

        #==========================
	# First Line
	#==========================

	
	#==========================
	# PRINT VERSION
	#==========================
	
#	li	0,SYSCALL_UNAME		# uname syscall
#	addi	3,BSS_BEGIN,(uname_info-bss_begin)		
					# uname struct
#	sc				# do syscall


	addi	16,DATA_BEGIN,(uname_info-data_begin)+U_SYSNAME@l-1	
					# os-name from uname "Linux"
	bl	strcat
	
	addi	16,DATA_BEGIN,(ver_string-data_begin)-1
					# source is " Version "
	bl 	strcat
	
	addi	16,DATA_BEGIN,(uname_info-data_begin)+U_RELEASE@l-1
					# version from uname "2.4.1"
	bl 	strcat
	
	addi	16,DATA_BEGIN,(compiled_string-data_begin)-1
					# source is ", Compiled "
	bl 	strcat

	addi	16,DATA_BEGIN,(uname_info-data_begin)+U_VERSION-1
      					# compiled date
	bl 	strcat
	
	bl	center_and_print	# write it to screen
	

	#===============================
	# Middle-Line
	#===============================
	
	#=========
	# Load /proc/cpuinfo into buffer
	#=========

#	li	0,SYSCALL_OPEN		# open()
#	addi	3,DATA_BEGIN,(cpuinfo-data_begin)		
					# '/proc/cpuinfo'
#	li	4,0			# O_RDONLY <bits/fcntl.h>
#	sc				# syscall.  fd in r0.  
					# we should check that r0>=0
					
#	mr	13,3			# save fd in r13
	
#	li	0,SYSCALL_READ		# read
#	addi	4,BSS_BEGIN,(disk_buffer-bss_begin)
#	li	5,4096		 	# 4096 is maximum size of proc file ;)
#	sc	

#	mr	3,13			# restore fd
#	li	0,6			# close
#	sc

	#=============
	# Number of CPUs
	#=============
	
	mr	14,17 			# point output to out_buf

	# Assume 1 CPU for now
	# my iBook's /proc/cpuinfo does not have a "processor" line ???
	
	addi	16,DATA_BEGIN,(one-data_begin)-1
	bl	strcat
	
	#=========
	# MHz
	#=========
	
    	lis	20,('l'<<8)+'o'		# find 'lock ' and grab up to M
	addi	20,20,('c'<<8)+'k'
	li	23,'M'			
   	bl	find_string
   
	addi	16,DATA_BEGIN,(megahertz-data_begin)-1
					# print 'MHz '
	bl	strcat
   
  
	#=========
	# Chip Name
	#=========
	
   	lis     20,('c'<<8)+'p'     	# find 'cpu\t: ' and grab up to \n
	addi	20,20,('u'<<8)+'\t'
	li	23,'\n'
	bl	find_string
	
	addi	16,DATA_BEGIN,(comma-data_begin)-1
					# print ', '
	bl	strcat
	
	#========
	# RAM
	#========
	
#	li	0,SYSCALL_SYSINFO	# sysinfo() syscall
#	addi	3,BSS_BEGIN,(sysinfo_buff-bss_begin)
					# sysinfo_buffer

#	sc

	lwz	4,(sysinfo_buff+S_TOTALRAM-data_begin)(DATA_BEGIN)
					# load bytes of RAM into r4

	srawi	4,4,20		# divide by 2^20 to get MB
	li	5,0

	bl	num_to_ascii

	addi	16,DATA_BEGIN,(ram_comma-data_begin)-1
					# print 'M RAM, '

	bl	strcat
	
	#========
	# Bogomips
	#========
	
	lis	20,('m'<<8)+'i'		# find 'mips' and grab up to \n
	addi	20,20,('p'<<8)+'s'
	li	23,'\n'
	bl	find_string
      
	addi	16,DATA_BEGIN,(bogo_total-data_begin)-1
					# print "Bogomips Total"
	bl	strcat

	bl	center_and_print	# center it


	#=================================
	# Print Host Name
	#=================================
	
	mr	14,17			# restore out buffer
	
	addi	16,DATA_BEGIN,((uname_info-data_begin)+U_NODENAME)-1
					# hostname		      
					
	bl	strcat				
	
	bl	center_and_print

	#================================
	# Exit
	#================================
exit:	
        li      3,0		# 0 exit value
	li      0,SYSCALL_EXIT  # put the exit syscall number in eax
	sc	             	# and exit




	#=================================
	# FIND_STRING 
	#=================================
	#   r23 is char to end at
	#   r20 is the 4-char ascii string to look for
	#   r14 points at output buffer
	#   r16,r21

find_string:
		
	addi	16,DATA_BEGIN,(disk_buffer-data_begin)-1	
					# look in cpuinfo buffer
					# -1 so we can use lbzu
	
find_loop:
	lwzu	13,1(16)		# load in 32 bits, incrementing 8bits
	cmpwi	13,0			# ! if null, we are done
	beq	done
	cmpw	13,20			# compare with out 4 char string
	bne	find_loop		# ! if no match, keep looping

	
					# ! if we get this far, we matched
					
	li	21,':'
find_colon:
	lbzu	13,1(16)		# repeat till we find colon
	cmpwi	13,0
	beq	done
	cmpw	13,21
	bne	find_colon

	addi	16,16,1			# skip a char [should be space]
	
store_loop:	 
	 lbzu	13,1(16)
	 cmpwi	13,0
	 beq	done
    	 cmpw	13,23			# is it end string?
	 beq 	almost_done		# ! if so, finish
	 stbu	13,1(14)		# ! if not store and continue
	 b	store_loop
	 
almost_done:	 
	li	13,0			# replace last value with null
	stb	13,1(14)

done:
	blr

	#================================
	# strcat
	#================================
	# r13 = "temp"
	# r16 = "source"
       	# r14 = "destination"
strcat:
	lbzu	13,1(16)		# load a byte from [r16]
	stbu	13,1(14)		# store a byte to [r14]
	cmpwi	13,0			# is it zero?
	bne	strcat			# ! if not loop
	subi	14,14,1			# point to one less than null
	blr				# return

	#==============================
	# center_and_print
	#==============================
	# r14 is end of buffer
	# r17 is start of buffer
	# r29 = saved link register
	# r4-r10, r19-r22, r30 trashed
	
center_and_print:

	mflr 	29			# back up return address

	subf	5,17,14			# see how long the output
					# buffer is
					
	cmpwi	5,80			# see if we are >80
        bgt	done_center		# ! if so, bail

	li	4,80			# 80 column screen
	subf	4,5,4			# subtract strlen
	srawi	23,4,1			# divide by two

	lis	4,escape@ha
	addi	4,4,escape@l
	bl	write_stdout

	mr	4,23
	li	5,1			# print to stdout
	bl	num_to_ascii		# print number
	
	lis	4,c@ha
	addi	4,4,c@l
	bl	write_stdout


done_center:	

	addi	4,17,1			# move string to output+1
	bl	write_stdout		# call write stdout

	lis	4,linefeed@ha
	addi	4,4,linefeed@l

	mtlr	29	      		# restore link register
					# and let write_stdout
					# return for us



	#================================
	# WRITE_STDOUT
	#================================
	# r4 has string
	# r0,r3,r4,r5,r6 trashed
		
write_stdout:
	li	0,SYSCALL_WRITE		# write syscall
	li	3,STDOUT		# stdout	
	
	li	5,0			# string length counter
strlen_loop:
	lbzx 	6,4,5			# get byte from (r4+r5)
       	addi	5,5,1			# increment counter
	cmpi	0,6,0			# is it zero?
	bne	strlen_loop		# ! if not keep counting
	addi	5,5,-1
	sc				# syscall
	
	blr				# return


	##############################
	# Num to Ascii
	##############################
	# num is in r4
	# r5 =0 then strcat, otherwise stdout
	# r5-r10,r19,r20,r21,r22,r30 trashed	

num_to_ascii:

	mflr    30			# save the link register

	addi	16,BSS_BEGIN,(num_to_ascii_end-bss_begin)
					# the end of a backwards growing
					# 10 byte long buffer.  
					
	li	20,10			# we will divide by 10
	mr	19,4			# load in the value passed
	
div_by_10:
	divw	21,19,20		# divide r19 by r20 put into r21 
	
	mullw	22,21,20		# find remainder.  1st q*dividend
	subf	22,22,19		# then subtract from original = R
	addi	22,22,0x30		# convert remainder to ascii
    	
	stbu	22,-1(16)		# Store to backwards buffer
	
	mr	19,21			# move Quotient as new dividend
	cmpwi	19,0			# was quotient zero?
	bne    	div_by_10		# ! if not keep dividing
	
write_out:
	cmpwi	5,0			# ! if r5 is 0 then skip ahead
	bne 	stdout_num		

	addi	16,16,-1		# point to the beginning
	bl	strcat			# and strcat it

	mtlr	30			# restore link register

	blr				# return
	
stdout_num:
        mr	4,16			# point to our buffer
	mtlr	30			# restore link register
	b	write_stdout		# stdout will return for us


#===========================================================================
.data
#===========================================================================


data_begin:

.include "../logo.lzss_new"

ver_string:	.ascii	" Version \0"
compiled_string:	.ascii	", Compiled \0"
megahertz:	.ascii	"MHz PPC \0"
.equ space, ram_comma+6
.equ comma, ram_comma+5
linefeed:   	.ascii  "\n\0"
escape:		.ascii	"\033[\0"
c:		.ascii  "C\0"
ram_comma:	.ascii	"M RAM, \0"

bogo_total:	.ascii	" Bogomips Total\0"

default_colors:	.ascii	"\033[0m\n\n\0"

cpuinfo:	.ascii	"/proc/cpuinfo\0"

one:	.ascii	"One \0"

disk_buffer:
.ascii "processor	: 0\n"
.ascii "cpu		: 745/755\n"
.ascii "temperature 	: 22-24 C (uncalibrated)\n"
.ascii "clock		: 600.000000MHz\n"
.ascii "revision	: 51.17 (pvr 0008 3311)\n"
.ascii "bogomips	: 49.79\n"
.ascii "timebase	: 24960000\n"
.ascii "platform	: PowerMac\n"
.ascii "model		: PowerBook4,1\n"
.ascii "machine		: PowerBook4,1\n"
.ascii "motherboard	: PowerBook4,1 MacRISC2 MacRISC Power Macintosh\n"
.ascii "detected as	: 257 (iBook 2)\n"
.ascii "pmac flags	: 0000001b\n"
.ascii "L2 cache	: 256K unified\n"
.ascii "pmac-generation	: NewWorld\n\0"

uname_info:
.ascii "Linux\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "henparma\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "2.6.29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "#1 Wed May 13 15:51:54 UTC 2009\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

	
sysinfo_buff:
.long 0,0,0,0,512*1024*1024,0,0,0

#============================================================================
#.bss
#============================================================================

.lcomm bss_begin,0
.lcomm	num_to_ascii_buff,10
.lcomm num_to_ascii_end,1
.lcomm  text_buf, (N+F-1)	# These buffers must follow each other
.lcomm	out_buffer,16384