/*
 * This file and its contents are supplied under the terms of the
 * Mozilla Public License (MPL) version 2.0.  You may only use this
 * file in accordance with the terms of version 2.0 of the MPL.
 *
 * A full copy of the text of the MPL should have accompanied this
 * source.  A copy of the MPL is also available via the Internet at
 * https://www.mozilla.org/en-CA/MPL/2.0.
 *
 * This Source Code Form is "Incompatible With Secondary Licenses",
 * as defined by the Mozilla Public License, v. 2.0.
 *
 * This implements the handling of processes.
 *
 * (C) Copyright Rich Teer 1990, 2023, 2026.
 */

#include "proc.h"
#include "pit.h"

proc_t proc_array[NUMBER_OF_PROCS];
int current_process_id = MAIN;											/* Keeps track of current PID */
int proc_id = 0;														/* Initialise process id */


int new_proc (void (*func) (void), int *stack_address, int stack_size)
{
	int exit ();														/* Not strictly necessary, but aids readability */

	if (++proc_id > NUMBER_OF_PROCS)
		return (-1);													/* Bump process id, return error if too many procs */
	proc_array[proc_id].sp = (int)stack_address + stack_size;			/* Move SP to base of stack */
	proc_array[proc_id].sb = (int)stack_address + stack_size;			/* Move SP to stack base */
	*(int *)(proc_array[proc_id].sp) = (int)exit;						/* Push address of exit routine onto stack */
	proc_array[proc_id].sp -= 4;										/* Decrement Stack Pointer no A6 value required */
	proc_array[proc_id].a6 = proc_array [proc_id].sp;					/* Set stack frame pointer */
	*(int *)(proc_array[proc_id].sp) = (int)func;						/* Put start addr of function onto stack */
	return (proc_id);													/* Let the calling function know what proc id it has */
}


transfer (int current_proc, int new_proc)
{
	save_regs (&proc_array[current_proc]);								/* M/C routine to save A0-6, D0-7, & PC */
	current_process_id = new_proc;										/* Update current process number */
	chg_context (&proc_array[new_proc]);								/* M/C to pop regs off of stack, and RTS into new proc */
}


int io_new_proc ( void (*func) (void), int *stack_address, int stack_size, int interrupt_level)
{
	int exit ();														/* Not strictly necessary, but aids readability */

	if (++proc_id > NUMBER_OF_PROCS)
		return (-1);													/* Bump process id, return error if too many procs */
	proc_array[proc_id].sp = (int)stack_address + stack_size;			/* Move SP to base of stack */
	proc_array[proc_id].sb = (int)stack_address + stack_size;			/* Move SP to stack base */
	*(int *)(proc_array[proc_id].sp) = (int)exit;						/* Push address of exit routine onto stack */
	proc_array[proc_id].sp -= 4;										/* Decrement Stack Pointer no A6 value required */
	proc_array[proc_id].a6 = proc_array[proc_id].sp;					/* Set stack frame pointer */
	*(int *)(proc_array[proc_id].sp) = (int)func;						/* Put start addr of function onto stack */
	proc_array[proc_id].sp -= 4;										/* Decrement Stack Pointer */
	*(int *)(proc_array[proc_id].sp) = (word)(0x20 + interrupt_level) << 8;		/* Put dummy Status Register on to stack */
	proc_array[proc_id].sp += 2;										/* Increment SP 'cos SR is only 16 bits wide */
	return (proc_id);													/* Let the calling function know what proc id it has */
}


void io_transfer (int current_proc, int new_proc, int vector)
{
	save_regs (&proc_array[current_proc]);								/* M/C routine to save A0-6, D0-7, & PC */
	set_vector (vector);												/* M/C to set up the interrupt vector */
	current_process_id = new_proc;										/* Update current process number */
	io_chg_context (&proc_array[new_proc]);							 	/* MC to pop regs off of stack, and RTS into new proc */
}


void start_critical (int interrupt_level)
{
	set_int_mask (interrupt_level);									 	/* MC to change the SR interrupt level mask */
}


void end_critical (void)
{
	reset_int_mask ();													/* MC to restore the old interrupt level mask */
}


void set_diag_exit (void (*func) (void))
{
	int loop;

	for (loop = 1; loop <= proc_id; loop++)
		*(int *)(proc_array[loop].sb) = (int)func;						/* Address of new process exit routine */
}


static void default_diags (void)
{
	pit_t *pit = (pit_t *)0x800000;

	pit->tcr = 0xA0;													/* Disable the timer to prevent context switches */
	printf ("\n\nExit from PID %d\n", current_process_id);
	exit ();
}


void set_diag (void)
{
	set_diag_exit (default_diags);
}
