#include	"stdio.h"

typedef struct{
	unsigned int	Command;
	unsigned int	Result;
	unsigned int	Reserved1[4];
	unsigned int	Reserved2;
	unsigned int	TargetAddr;
	unsigned int	Length;
	unsigned int	Reserved3;
	unsigned int	Reserved4;
	unsigned int	Reserved5;
	unsigned int	Reserved6;
	unsigned int	Reserved7;
	unsigned int	Reserved8;
	INT8U	Buf[8192];
}FLASH_INFO_Str;


FLASH_INFO_Str Flash_Info;
unsigned int EraseCounter = 0, NbrOfPage = 0, FLASHStatus = 0, MemoryProgramStatus = 0, HSEStartUpStatus = 0;

#define RCC_CR  		*(unsigned int *)(0x40021000UL + 0x00)	//MEMORY[0x40021000]
#define RCC_CFGR  		*(unsigned int *)(0x40021000UL + 0x04)	//MEMORY[0x40021004]
#define RCC_CIR  		*(unsigned int *)(0x40021000UL + 0x08)	//MEMORY[0x40021008]

#define RCC_APB2RSTR  	*(unsigned int *)(0x40021000UL + 0x0c)	//MEMORY[0x4002100C]
#define RCC_APB1RSTR  	*(unsigned int *)(0x40021000UL + 0x10)	//MEMORY[0x40021010]
#define RCC_AHBENR		*(unsigned int *)(0x40021000UL + 0x14)	//MEMORY[0x40021014]
#define RCC_APB2ENR		*(unsigned int *)(0x40021000UL + 0x18)	//MEMORY[0x40021018]
#define RCC_APB1ENR		*(unsigned int *)(0x40021000UL + 0x1c)	//MEMORY[0x4002101C]
#define CR_PLLON_BB		*(unsigned int *)0x42420060	//MEMORY[0x42420060]


#define FLASH_KEYR		*(unsigned int *)0x40022004	//MEMORY[0x40022004]
#define FLASH_SR		*(unsigned int *)0x4002200c	//MEMORY[0x4002200c]
#define FLASH_CR		*(unsigned int *)0x40022010	//MEMORY[0x40022010]
#define FLASH_AR		*(unsigned int *)0x40022014	//MEMORY[0x40022014]

#define	SCB_VTOR		*(unsigned int *)0xE000ED08	//MEMORY[0xE000ED08]

#define	PASSED			1
#define FLASH_COMPLETE	4

void RCC_DeInit()
{
  RCC_APB2RSTR 	= 0;
  RCC_APB1RSTR 	= 0;
  RCC_AHBENR 	= 20;
  RCC_APB2ENR 	= 0;
  RCC_APB1ENR 	= 0;
  RCC_CR 		|= 1u;
  RCC_CFGR 		&= 0xF8FF0000;
  RCC_CR &= 0xFEF6FFFF;
  RCC_CR &= ~0x40000u;
  RCC_CFGR &= 0xFF80FFFF;
  RCC_CIR = 0;
}

void __fastcall RCC_HSEConfig(u32 RCC_HSE)
{
  RCC_CR &= ~0x10000u;
  RCC_CR &= ~0x40000u;
  if ( RCC_HSE == 0x10000 )
  {
    RCC_CR |= 0x10000u;
  }
  else if ( RCC_HSE == 0x40000 )
  {
    RCC_CR |= 0x50000u;
  }
}

void __fastcall RCC_GetFlagStatus(u8 RCC_FLAG)
{
  ;
}

bool RCC_WaitForHSEStartUp()
{
  int i; // r4
  int v1; // r0
  int v2; // r0

  for ( i = 0; ; ++i )
  {
    RCC_GetFlagStatus(0x31u);
    if ( v1 || i == 128 )
      break;
  }
  RCC_GetFlagStatus(0x31u);
  return v2 != 0;
}

void RCC_HCLKConfig(u32 RCC_HCLK)
{
  RCC_CFGR = RCC_CFGR & 0xFFFFFF0F | RCC_HCLK;
}

void RCC_PCLK2Config(u32 RCC_PCLK2)
{
  RCC_CFGR = RCC_CFGR & 0xFFFFC7FF | (8 * RCC_PCLK2);
}

void RCC_PCLK1Config(u32 RCC_PCLK1)
{
  RCC_CFGR = RCC_CFGR & 0xFFFFF8FF | RCC_PCLK1;
}

#define	FLASH_ACR	0x40022000	//MEMORY[0x40022000]

void FLASH_SetLatency(u32 FLASH_Latency)
{
  FLASH_ACR = FLASH_ACR & 0x38;
  FLASH_ACR |= FLASH_Latency;
}

void FLASH_PrefetchBufferCmd(u32 FLASH_PrefetchBuffer)
{
  FLASH_ACR &= ~0x10u;
  FLASH_ACR |= FLASH_PrefetchBuffer;
}

void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)
{
  RCC_CFGR = RCC_CFGR & 0xFFC0FFFF | RCC_PLLSource | RCC_PLLMul;
}

void RCC_PLLCmd(FunctionalState NewState)
{
  CR_PLLON_BB = NewState;
}

void RCC_GetFlagStatus(u8 RCC_FLAG)
{
  ;
}

void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource)
{
  RCC_CFGR = RCC_CFGR & 0xFFFFFFFC | RCC_SYSCLKSource;
}

int RCC_GetSYSCLKSource()
{
  return RCC_CFGR & 0xC;
}

void RCC_Configuration()
{
  int v0; // r0

  RCC_DeInit();
  RCC_HSEConfig(0x10000u);
  HSEStartUpStatus = RCC_WaitForHSEStartUp();
  if ( HSEStartUpStatus == SUCCESS )
  {
    RCC_HCLKConfig(0u);
    RCC_PCLK2Config(0u);
    RCC_PCLK1Config(0x400u);
    FLASH_SetLatency(2u);
    FLASH_PrefetchBufferCmd(0x10u);
    RCC_PLLConfig(0x10000u, 0x1C0000u);
    RCC_PLLCmd(ENABLE);
    do
      RCC_GetFlagStatus(0x39u);
    while ( !v0 );
    RCC_SYSCLKConfig(2u);
    while ( RCC_GetSYSCLKSource() != 8 )
      ;
  }
}

void NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
{
  SCB_VTOR = Offset & 0x1FFFFF80 | NVIC_VectTab;
}

void NVIC_Configuration()
{
  NVIC_SetVectorTable(0x8000000u, 0u);
}

void FLASH_Unlock()
{
  FLASH_KEYR = -839939669;
}

void FLASH_ClearFlag(u16 FLASH_FLAG)
{
  FLASH_SR = FLASH_FLAG;
}

void Flash_Init()
{
  FLASHStatus = FLASH_COMPLETE;
  MemoryProgramStatus = PASSED;
  RCC_Configuration();
  NVIC_Configuration();
  FLASH_Unlock();
  NbrOfPage = 128;
  FLASH_ClearFlag(0x35u);
}

int FLASH_GetStatus()
{
  if ( (FLASH_SR & 1) == 1 )
    return 1;
  if ( (FLASH_SR & 4) != 0 )
    return 2;
  if ( (FLASH_SR & 0x10) != 0 )
    return 3;
  return 4;
}

void delay(void)
{
	int i = 4095;

	while(i--);
}

FLASH_Status FLASH_WaitForLastOperation(u32 Timeout)
{
  int v1; // r2
  int Status; // r3
  int v3; // r2

  Status = FLASH_GetStatus();
  while ( Status == 1 && v1 )
  {
    delay();
    Status = FLASH_GetStatus();
    v1 = v3 - 1;
  }
  if ( !v1 )
    (unsigned char)(Status) = 5;
  return (char)Status;
}

FLASH_Status FLASH_ErasePage(u32 Page_Address)
{
  int Operation; // r5

  Operation = FLASH_WaitForLastOperation(0xFFFu);
  if ( Operation == 4 )
  {
    FLASH_CR |= 2u;
    FLASH_AR = Page_Address;
    FLASH_CR |= 0x40u;
    Operation = FLASH_WaitForLastOperation(0xFFFu);
    if ( Operation != 1 )
      FLASH_CR = FLASH_CR & 0x1FFD;
  }
  return (char)Operation;
}

void EraseAll()
{
  for ( EraseCounter = 0; EraseCounter < NbrOfPage && FLASHStatus == FLASH_COMPLETE; ++EraseCounter )
    FLASHStatus = FLASH_ErasePage((EraseCounter << 10) + 0x8000000);
  Flash_Info.Result = 1;
}

FLASH_Status FLASH_ProgramHalfWord(u32 targetP, u16 *srcP)
{
  int Operation; // r6

  Operation = FLASH_WaitForLastOperation(0xFu);
  if ( Operation == 4 )
  {
    FLASH_CR |= 1u;
    *(int *)targetP = *srcP;
    Operation = FLASH_WaitForLastOperation(0xFu);
    if ( Operation != 1 )
      FLASH_CR = FLASH_CR & 0x1FFE;
  }
  return (char)Operation;
}

void EraseSector()
{
  vu32 i; // r4
  int v1; // r0

  Flash_Info.Result = 0;
  for ( i = 0; NbrOfPage - 1 > i && ((i + 1) << 10) + 0x8000000 <= Flash_Info.TargetAddr; ++i )
    ;
  while ( NbrOfPage - 1 > i
       && FLASHStatus == FLASH_COMPLETE
       && Flash_Info.TargetAddr + Flash_Info.Length > (i << 10) + 0x8000000 )
  {
    v1 = FLASH_ErasePage((i << 10) + 0x8000000);
    FLASHStatus = (char)v1;
    if ( !v1 )
      return;
    ++i;
  }
  Flash_Info.Result = 1;
}

void ReadChipID()
{
  Flash_Info.Result = 1;
}

void Program()
{
  u32 TargetAddr; // r4
  u16 *Buf; // r5
  u32 i; // r6

  TargetAddr = Flash_Info.TargetAddr;
  Buf = (u16 *)Flash_Info.Buf;
  for ( i = 0; Flash_Info.Length > i; i += 2 )
  {
    FLASHStatus = FLASH_ProgramHalfWord(TargetAddr, Buf);
    TargetAddr += 2;
    ++Buf;
  }
  Flash_Info.Result = 1;
}

void Main()
{
  Flash_Init();
  if ( Flash_Info.Command )
  {
    switch ( Flash_Info.Command )
    {
      case 1u:
        EraseAll();
        break;
      case 2u:
        EraseSector();
        break;
      case 3u:
        ReadChipID();
        break;
      default:
        Flash_Info.Result = 0;
        break;
    }
  }
  else
  {
    Program();
  }
}


