#################################################################################
#										#
# GTMICRO gigatron micro emulator						#
# copyright (c) 2018-2019 Joerg Wolfram (joerg@jcwolfram.de)			#
#										#
# This program is free software under the BSD 2-Clause License.			#
# See LICENSE file in main directory.						#
#										#
#################################################################################

			.section	.startup,"ax"
			.thumb
			.syntax unified
			.cpu cortex-m4
			.globl reset_addr
			.globl dummy_handler
			.globl code_start
		
reset_addr:
		.include "inc/vectable.inc"
		.include "inc/setup.inc"

# register usage:
#----------------
#
#	r0	serial input buffer
#	r1	scratch  
#	r2	scratch
#	r3	PC
#	r4	ACC
#	r5	YX
#	r6	ALU
#	r7	next opcode from fetch stage
#	r8	current $dd value
#	r9	scratch
#	r10	pointer to EXTOUT port structure
#	r11	pointer to VIDOUT/EXTIN port structure
#	r12	ram base address
#	r13	stack pointer (unused)
#	r14	jumptable base
#	r15	cortex PC

#-------------------------------------------------------------------------------
# here starts the code from RESET vector
#-------------------------------------------------------------------------------
code_start:		nop

			//set flash wait states
			ldr	r1,=0x40023C00		// FLASH
			ldr	r2,=0x00000105		// 5 wait states, prefetch active
			str	r2,[r1,#0x00]		// ACR

			//init clock system
			ldr	r1,=0x40023800		// RCC

			// switch HSE on
			ldr	r2,[r1,#0x00]		// CR
			orr	r2,#0x10000		// HSE ON
			str	r2,[r1,#0x00]		// CR
hse_wait:		ldr	r2,[r1,#0x00]		// CR
			ands	r2,#0x20000			
			beq	hse_wait		// wait until HSE is ready 

			
			// enable PLL
//			ldr	r2,=0x2440348C		// 20MHz / 12 * 210 / 2 ->175 MHz
//			ldr	r2,=0x24403C0C		// 20MHz / 12 * 240 / 2 ->200 MHz
//			ldr	r2,=0x2440438C		// 20MHz / 12 * 270 / 2 ->225 MHz
//			ldr	r2,=0x24404B0C		// 20MHz / 12 * 300 / 2 ->225 MHz
			ldr	r2,=PLL_SET_20_225
			str	r2,[r1,#0x04]		// PLLCFGR			
			ldr	r2,[r1,#0x00]		// CR
			orr	r2,#0x1000000		// PLL ON
			str	r2,[r1,#0x00]		// CR
pll_wait:		ldr	r2,[r1,#0x00]		// CR
			ands	r2,#0x2000000			
			beq	pll_wait		// wait until PLL is ready 
			
			
			// switch clock to PLL
			ldr	r2,=0x0000B802		// set correct dividers (APB2/4, APB1/8)
			str	r2,[r1,#0x08]		// CFGR			
sw_wait:		ldr	r2,[r1,#0x08]		// CR
			and	r2,#0x0F
			cmp	r2,#0x0A				
			bne	sw_wait			// wait until source is switched 

	
tp1:			ldr	r1,=0x40023800		// RCC
			ldr	r2,=0x00140007		// CCM, backup RAM and PORT A-C on
			str	r2,[r1,#0x30]		// AHB1ENR
.if pwmcheck == 1
			ldr	r2,=0x00000002		// timer 3 enable
			str	r2,[r1,#0x40]		// APB1ENR
.endif		
		
			//init video port
			ldr	r1,=VID_PORT
			ldr	r2,=0x00005555		// all output
			str	r2,[r1,#0x00]		// MODERR
			ldr	r2,=0x00005555
			str	r2,[r1,#0x08]		// OSPEEDR
			ldr	r2,=0x55555555		// all PU
			str	r2,[r1,#0x0c]		// PUPDR
			mov	r2,#0x00		// HS+VS HI
			str	r2,[r1,#0x14]		// ODR

			//init sound/led port
			ldr	r1,=AUX_PORT
			ldr	r2,=0x00005555		// all output
			str	r2,[r1,#0x00]		// MODERR
			ldr	r2,=0x55555555		// all PU
			str	r2,[r1,#0x0c]		// PUPDR
			mov	r2,#0			// all off
			str	r2,[r1,#0x14]		// ODR

			//init status port
			ldr	r1,=LED_PORT
			ldr	r2,=0x00004400		// B7+B5 output
			str	r2,[r1,#0x00]		// MODERR
			ldr	r2,=0x55555555		// all PU
			str	r2,[r1,#0x0c]		// PUPDR
			mov	r2,#(1 << GLED_PIN)
			str	r2,[r1,#0x14]		// ODR
			
			
			//init PWM for reference (PWM3, channel 2, PC7)
refpwm:		
.if pwmcheck == 1
			ldr	r1,=0x40000400		// TIM3
			mov	r2,0x00			// prescaler 1:1
			str	r2,[r1,#0x28]		// PSC
			mov	r2,0x59			// 72 clocks
			str	r2,[r1,#0x2C]		// ARR
			mov	r2,0x01			// count enable
			str	r2,[r1,#0x00]		// CR1
			
			mov	r2,#0x6000
			str	r2,[r1,0x18]		// CCMR1

			mov	r2,#0x2D		// half period
			str	r2,[r1,0x38]		// CCR2
			
			mov	r2,#0x10
			str	r2,[r1,0x20]		// CCER
			
			ldr	r1,=0x40020800		// GPIOC
			ldr	r2,=0x00009555		// C0-C6 output, C7 alt
			str	r2,[r1,#0x00]		// MODERR
			ldr	r2,=0x20000000		// C7 = AF2
			str	r2,[r1,#0x20]		// AFRL
			ldr	r6,=rom_test		// we use the test ROM
			b	copy_image
.else
			// copy image into RAM 
			mov	r3,#0x1000000		// wait
wait1:			subs	r3,#1
			bne	wait1
			mov	r2,#0xC0		// HS+VS HI
			str	r2,[r1,#0x14]		// ODR
			ldr	r1,=0x40020000		// GPIOA
			bl	both_leds
		
			bl	get_keys		// get keys value
			bl	get_keys		// get keys value
			bl	get_keys		// get keys value
			ldr	r6,=rom_alta		// ALT A ROM
			cmp	r5,0x7F			// KEY A pressed
			beq	copy_image						
			ldr	r6,=rom_altb		// ALT B ROM
			cmp	r5,0xBF			// KEY B pressed
			beq	copy_image						
			ldr	r6,=rom_default		// default ROM
.endif


copy_image:		ldr	r2,=0x20000000		// RAM
			mov	r3,#0x8000		// LW to do
copy_image_loop:	ldr	r4,[r6,#0]
			str	r4,[r2,#0]
			add	r6,#4
			add	r2,#4
			subs	r3,#1
			bne	copy_image_loop

			//wait for key release
wnkey:			bl	get_keys
			cmp	r5,0xFF
			bne	wnkey
			
			bl	green_led
			
			// clear CCM
			ldr	r2,=0x10000000		// RAM
			mov	r3,#0x4000		// LW to do
			mov	r4,#0
clear_ccm:		str	r4,[r2,#0]
			add	r2,#4
			subs	r3,#1
			bne	clear_ccm
			
			//set registers
			mov	r0,#0			// serial input
			mov	r1,#0			// scratch
			mov	r2,#0			// scratch
			mov	r3,#0			// PC
			mov	r4,#0			// ACC
			mov	r5,#0			// YX
			mov	r6,#0			// ALU
			mov	r7,#0			// opcode
			mov	r8,#0			// last D
			ldr	r9,=#0			// scratch
			ldr	r10,=0x40020800		// GPIOC (ext out)
			ldr	r11,=0x40020000		// GPIOA (video out)
			ldr	r12,=0x10000000		// 32K RAM (CCM)
			ldr	r14,=0x00008001		// jumptable base			
			
			bx	r14			// jump to emulator (ld 0x00, dummy instruction)

#-------------------------------------------------------------------------------
# subroutine: input keys from external controller -> r5
# killed: r1,r2,r3,r4
#-------------------------------------------------------------------------------
			// init signals and wait a bit
get_keys:		ldr	r1,=0x40020000		// GPIOA
			mov	r2,#0xC0		// HS+VS HI
			str	r2,[r1,#0x14]		// ODR
			mov	r3,#0x100000		// wait
get_keys_w1:		subs	r3,#1
			bne	get_keys_w1

			// some hsync pulses with vsync=high 
			mov	r4,#128			// cycles
get_keys_w2a:		mov	r2,#0x80		// HS
			str	r2,[r1,#0x14]		// ODR
			mov	r3,#1000		// wait
get_keys_w2b:		subs	r3,#1
			bne	get_keys_w2b
			mov	r2,#0xC0		// no sync
			str	r2,[r1,#0x14]		// ODR
			mov	r3,#4000		// wait
get_keys_w2c:		subs	r3,#1
			bne	get_keys_w2c
			subs	r4,#1
			bne	get_keys_w2a

			// now get data
			mov	r4,#8			// bits to do
			mov	r5,#0			// start value

get_keys_loop:		lsl	r5,#1			// shift
			ldr	r6,[r1,#0x10]		// IDR
			and	r6,#0x100		// data bit 8
			cmp	r6,#0x100		// data bit 8
			bne	get_keys_zero
			add	r5,#1			// set bit
get_keys_zero:	
			mov	r2,#0x00		// HS LOW
			str	r2,[r1,#0x14]		// ODR
			
			mov	r3,#1000		// wait
get_keys_w3:		subs	r3,#1
			bne	get_keys_w3

			mov	r2,#0x40		// HS HI
			str	r2,[r1,#0x14]		// ODR

			mov	r3,#4000		// wait
get_keys_w4:		subs	r3,#1
			bne	get_keys_w4
		
			subs	r4,#1			// decrement bit counter
			bne	get_keys_loop		// bit loop
	
			mov	r2,#0xC0		// HS+VS HI
			str	r2,[r1,#0x14]		// ODR

			mov	r2,r5
#			str	r2,[r1,#0x814]		//view low bits (debug)
			lsr	r2,#4
			str	r2,[r1,#0x814]		//view high bits (debug)			
			bx	lr		

#-------------------------------------------------------------------------------
# sub functions for the status LED
#-------------------------------------------------------------------------------
			// set error led
dummy_handler:		ldr	r1,=LED_PORT
			mov	r2,1 << RLED_PIN
			str	r2,[r1,#0x14]		// ODR
			b	dummy_handler		// do not exit

			// set both leds
both_leds:		ldr	r1,=LED_PORT
			mov	r2,(1 << RLED_PIN) | (1 << GLED_PIN)
			str	r2,[r1,#0x14]		// ODR
			bx	lr

			// set green led
green_led:		ldr	r1,=LED_PORT
			mov	r2,1 << GLED_PIN
			str	r2,[r1,#0x14]		// ODR
			bx	lr
					