#include <stdbool.h>
#include <stdint.h>
#include "../../vmu.arm.h"
#include "printf.h"



void __attribute__((naked)) prPutcharDebug(char chr)
{
	asm volatile(".hword 0xde01\n\tbx lr");
}

static void __attribute__((naked)) appExit(void)
{
	asm volatile(".hword 0xDE08");
}

static void clearScreen(void)
{
	volatile uint32_t *screenData = (volatile uint32_t*)VMU_BASE_ADDR_GFX;
	uint32_t r;
	
	for (r = 0; r < 32; r += 2) {
		
		*screenData++ = 0;
		*screenData++ = 0;
		*screenData++ = 0;
		*screenData++ = 0;
	}
}

#define DOT_SHIFT	24
#define DOT_MUL		(1 << DOT_SHIFT)

static int64_t smull(int32_t a, int32_t b)
{
	int64_t ret;
	
	asm volatile(
		".cpu cortex-m3				\n\t"
		"smull %Q0, %R0, %1, %2		\n\t"
		".cpu cortex-m23			\n\t"
		: "=r"(ret) : "r"(a), "r"(b)
	);
	
	return ret;
}

static int32_t mulFixedpt(int32_t a, int32_t b)
{
	return smull(a, b) >> DOT_SHIFT;
	//return ((int64_t)a * b) >> DOT_SHIFT;
}

void main(void)
{
	const int32_t minX = -2 * DOT_MUL, maxX = 1 * DOT_MUL, stepX = 1.0/16 * DOT_MUL;
	const int32_t minY = -1 * DOT_MUL, maxY = 1 * DOT_MUL, stepY = 1.0/16 * DOT_MUL;
	const uint32_t nsteps = 16;
	
	volatile uint8_t *screenData = (volatile uint8_t*)VMU_BASE_ADDR_GFX;
	uint8_t screenMask = 0x80, screenRow = 0;
	int32_t x, y;
	
	for (y = minY; y < maxY; y += stepY) {
		for (x = minX; x < maxX; x += stepX) {
	
			int32_t ni, re = x, im = y, t;
	
		//	prDebug("testing %08x %08x\n", re, im);
	
			for (ni = 0; ni < nsteps; ni++) {
				
				//square
				t = mulFixedpt(re, re) - mulFixedpt(im, im);
				im = 2 * mulFixedpt(re, im);
				re = t;
				
				//add our value
				re += x;
				im += y;
				
				//calc magnitude
				t = mulFixedpt(re, re) + mulFixedpt(im, im);
				
		//		prDebug(" step %u %08x %08x  magnitude: 0x%08X\n", ni, re, im, t);
				
				if (t > 4 * DOT_MUL)
					break;
			}
	
			if (ni != nsteps)
				*screenData |= screenMask;
	
			if (!(screenMask >>= 1)) {
				
				screenMask = 0x80;
				screenData++;
				screenRow++;
				if (screenRow == 12) {
					screenRow = 0;
					screenData += 4;
				}	
			}
		}
	}
	
	
	do{
		SFR->P3 = 0xFF;
	} while (SFR->P3 != 0xFF);
	do{
		SFR->P3 = 0xFF;
	} while (SFR->P3 == 0xFF);

	//exit
	appExit();
}