#################################################################################
#	File : reset.s
#	Author : Alain Greiner
#	Date : 15/04/2011
#################################################################################
# 	This is a boot code for a generic multi-clusters / multi-processors
#       TSAR architecture (up to 256 clusters / up to 4  processors per cluster). 
#       There is one XICU, one TTY, one DMA and one stack segment per cluster.
#       segment base adresses = base + cluster_segment_increment*cluster_id
#	- Each processor initializes the stack pointer ($29) depending on pid.
#	- Only processor 0 initializes the Interrupt vector (TTY, DMA & IOC).
#       - Each processor initialises its private ICU mask register.
#	- Each processor initializes the Status Register (SR) 
#	- Each processor initializes the EPC register, and jumps to the main 
#	  address in kernel mode...
#################################################################################
		
	.section .reset,"ax",@progbits

	.extern	seg_stack_base
	.extern	seg_icu_base
	.extern _interrupt_vector
	.extern _isr_tty_get
	.extern _isr_dma
	.extern _isr_ioc

        .extern NB_PROCS
        .extern NB_CLUSTERS

	.globl  reset	 			# makes reset an external symbol 
	.ent	reset
	.align	2

reset:
       	.set noreorder

# computes proc_id, local_id, cluster_id, and cluster_increment
    mfc0    $26,    $15,    1
    andi    $10,    $26,    0x3FF	# $10 <= proc_id (at most 1024 processors)
    la      $26,    NB_PROCS		# $26 <= number of processors per cluster
    divu    $10,    $26
    mfhi    $11                 	# $11 <= local_id = proc_id % NB_PROCS
    mflo    $12              		# $12 <= cluster_id = proc_id / NB_PROCS
    la      $26,    NB_CLUSTERS
    li      $13,    0x80000000
    divu    $13,    $26
    mflo    $14
    sll     $14,    1			# $14 <= cluster_increment = 4G / NB_CLUSTERS
    mult    $14,    $12	
    mflo    $13                 	# $13 <= cluster_id * cluster_increment

# initializes stack pointer depending on both the local_id and the cluster_id
    la      $27,    seg_stack_base
    addu    $27,    $27,    $13		# $27 <= seg_stack_base + cluster_id * increment
    li      $26,    0x10000		# $26 <= 64K
    addi    $25,    $11,    1		# $25 <= local_id + 1
    mult    $25,    $26
    mflo    $24				# $24 <= 64K * (local_id+1)
    addu    $29,    $27,    $24		# $29 <= seg_stack_base + (cluster_id*increment) + (local_id+1)*64K

# in each cluster, each processor initializes its private XICU mask register
# in each cluster, the ICU base address depends on the cluster_id
    la      $20,    seg_icu_base
    addu    $20,    $20,    $13		# $20 <= seg_icu_base + cluster_id*cluster_increment
    la      $21,    _reset_switch
    sll     $22,    $11,    2           # $22 <= local_id*4
    addu    $23,    $21,    $22         # $23 <= &_reset_switch[local_id*4]
    lw      $24,    0($23)
    jr      $24
    nop
_reset_proc0:
    li      $13,    0b010010000000      # offset for MSK_HWI_ENABLE & proc[0]
    addu    $13,    $20,    $13
    li      $27,    0x111		# TTY[0] DMA[0] IOC
    sw      $27,    0($13)              # MASK[0]
    j       _reset_itvector
_reset_proc1:
    li      $13,    0b010010000100      # offset for MSK_HWI_ENABLE & proc[1]
    addu    $13,    $20,    $13
    li      $27,    0x022		# TTY[1] DMA[1]
    sw      $27,    0($13)              # MASK[1]
    j       _reset_itvector
_reset_proc2:
    li      $13,    0b010010001000      # offset for MSK_HWI_ENABLE & proc[2]
    addu    $13,    $20,    $13
    li      $27,    0x044		# TTY[2] DMA[2]
    sw      $27,    0($13)              # MASK[2]
    j       _reset_itvector
_reset_proc3:
    li      $13,    0b010010001100      # offset for MSK_HWI_ENABLE & proc[3]
    addu    $13,    $20,    $13
    li      $27,    0x088		# TTY[3] DMA[3]
    sw      $27,    0($13)              # MASK[3]
    j       _reset_itvector
    nop

_reset_switch:
    .word	_reset_proc0
    .word	_reset_proc1
    .word	_reset_proc2
    .word	_reset_proc3

# only processor 0 in cluster 0 initializes interrupt vector

_reset_itvector:
    bne	    $10,    $0,    _reset_end
    nop
    la      $26,    _interrupt_vector   # interrupt vector address
    la      $27,    _isr_dma 
    sw      $27,    0($26)              # interrupt_vector[0] <= _isr_dma_get
    sw      $27,    4($26)              # interrupt_vector[1] <= _isr_dma_get
    sw      $27,    8($26)              # interrupt_vector[2] <= _isr_dma_get
    sw      $27,   12($26)              # interrupt_vector[3] <= _isr_dma_get
    la      $27,    _isr_tty_get 
    sw      $27,   16($26)              # interrupt_vector[4] <= _isr_tty
    sw      $27,   20($26)              # interrupt_vector[5] <= _isr_tty
    sw      $27,   24($26)              # interrupt_vector[6] <= _isr_tty
    sw      $27,   28($26)              # interrupt_vector[7] <= _isr_tty
    la      $27,    _isr_ioc 
    sw      $27,   32($26)              # interrupt_vector[8] <= _isr_ioc

_reset_end:

# initializes SR register
    li	    $26,    0x0000FF01		
    mtc0    $26,    $12			# SR <= kernel mode / IRQ enable 

# jumps to main in kernel mode
    la	    $26,    main
    jr      $26
    nop

    .end	reset

    .set reorder
