/*
 *	Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *	SOFTWARE.
 */


#include "oc_memory.h"
#include "variable.h"
#include "state.h"
#include "memory.h"


void opcodes_load(void) {
	uint8_t dst = ZPEEK(__state.pc++);
	uint8_t src = (uint8_t)(__state.operands[0] & 0xFF);
	int16_t val;

	if (src == 0) {
		// Indirect access.  Do not pull, just read.
		val = __state.stack[__state.sp - 1];
	} else {
		val = variableLoad(src);
	}

	variableStore(dst, val);
}


void opcodes_loadb(void) {
	uint16_t offset = __state.operands[0] + __state.operands[1];
	variableStore(ZPEEK(__state.pc++), ZPEEK(offset));
}


void opcodes_loadw(void) {
	uint16_t offset = __state.operands[0] + (__state.operands[1] * 2);
	variableStore(ZPEEK(__state.pc++), ZPEEKW(offset));
}


void opcodes_pop(void) {
	variableAddress(0, 0);  // Causes a pop.
}


void opcodes_pull(void) {
	byte     dst = (__state.operands[0] & 0xFF);
	uint16_t val = variableLoad(0);

	if (dst == 0) {
		// Indirect access.  Do not push, just write.
		__state.stack[__state.sp - 1] = val;
	} else {
		variableStore(dst, val);
	}
}


void opcodes_push(void) {
	variableStore(0, __state.operands[0]);
}


void opcodes_store(void) {
	byte     dst = (__state.operands[0] & 0xFF);
	uint16_t val = __state.operands[1];

	if (dst == 0) {
		// Indirect access.  Do not push, just write.
		__state.stack[__state.sp - 1] = val;
	} else {
		variableStore(dst, val);
	}
}


void opcodes_storeb(void) {
	ZPOKE(__state.operands[0] + __state.operands[1], __state.operands[2]);
}


void opcodes_storew(void) {
	ZPOKEW(__state.operands[0] + (__state.operands[1] * 2), __state.operands[2]);
}
