/*
    TMClockAsm.S, Copyright (c) by Silvio Dragone & David Reist,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.

    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.

    For further information, please visit http://www.tik.ee.ethz.ch/~topsy

    This software is provided under the terms of the GNU General Public Licence.

    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/

#include "asm.h"
#include "cpu.h"

#define TIMER_MASK   0x00FFFFFF  // Mask to get right size of timer value

.text
	
/* Purpose  : Function to set the period of SA timer and enable it periodic.
 * Prototype: void setClock_asm( unsigned long int TimerNo, int period, unsigned long int TimerEnable )
 *
 * a0 -> SA_TIMER_n_LOAD address
 * a1 -> period
 * a2 -> SA_TIMER_n_CONTROL address
 */
ENTRY( setClockValue_asm )
	and	a1, a1, #TIMER_MASK  // mask period
	str	a1, [a0]	// init. timer
	mov	a1, #SA_TIMER_ENABLE // mask to enable sys timer
	str	a1, [a2]	// enable timer
END( setClockValue_asm )

/* Purpose  : Procedure to disable the OS timer. The interrupt mask
 *            doesn't get manupulated here!
 * Prototype: void resetClock_asm( unsigned long int TimerNo )
 *
 * a0 -> SA_TIMER_n_CLEAR address
 * a1 -> SA_TIMER_n_CONTROL address
 */
ENTRY( resetClock_asm )
	mov	a2, #0		// a2 -> #0
	str	a2, [a1]	// disable timer n
	str	a2, [a0]	// clear interrupt
END( resetClock_asm )

/* Purpose  : Interrupt handler for the PCI source. It reads out the PCI_STATUS register
 *            to determine which of the PCI interrupts is activ and jumps to the specific
 *            handler.
 * Prototype: InterruptHandler tmPCIIntHandler()
 */
ENTRY( tmPCIIntHandler )
	mov	ip, sp
	stmdb	sp!, {fp, ip, lr, pc} // stack working register
	sub	fp, ip, #4
	mov	ip, #PCI_IRQ_RAW // Since we don't make any difference between IRQ and FIQ
	ldr	ip, [ip]	 // ... we only read the RAW_STATUS to be efficent
	and	ip, ip, #PCI_TIMER1_MASK // check whether TIMER1 has occured	
	cmp	ip, #PCI_TIMER1_MASK
	bleq	tmClockHandler	// if true, branch to tmClockHandler, else PANIC ;-)
	ldmdb	fp, {fp, sp, pc} // restore last working register and ...
	                         // ... return
