334 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/****************************************************************************
 | 
						|
 | 
						|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
 | 
						|
 | 
						|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
 | 
						|
be copied by any method or incorporated into another program without
 | 
						|
the express written consent of Aerospace C.Power. This Information or any portion
 | 
						|
thereof remains the property of Aerospace C.Power. The Information contained herein
 | 
						|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
 | 
						|
liability for its use in any way and conveys no license or title under
 | 
						|
any patent or copyright and makes no representation or warranty that this
 | 
						|
Information is free from patent or copyright infringement.
 | 
						|
 | 
						|
****************************************************************************/
 | 
						|
/* os shim includes */
 | 
						|
#include "os_types.h"
 | 
						|
#include "os_utils.h"
 | 
						|
#include "os_mem.h"
 | 
						|
#include "dbg_io.h"
 | 
						|
#include "iot_diag.h"
 | 
						|
#include "iot_io.h"
 | 
						|
#include "ddr_reg_rf.h"
 | 
						|
#include "dmc_reg_rf.h"
 | 
						|
#include "hw_reg_api.h"
 | 
						|
#include "ahb.h"
 | 
						|
#include "ahb_rf.h"
 | 
						|
 | 
						|
// ############################################################################
 | 
						|
// common define
 | 
						|
#define REG32(a)    (*((volatile uint32_t *)(a)))
 | 
						|
 | 
						|
// common define end
 | 
						|
// ############################################################################
 | 
						|
 | 
						|
// ############################################################################
 | 
						|
// ddr define
 | 
						|
#define MODE_REGISTER_WRITE 0xc0
 | 
						|
#define MODE_REGISTER_READ 0x40
 | 
						|
#define DDR_BASE    0x55228000
 | 
						|
#define DDR_POERATION_INT_MEM3_ADDR (DDR_BASE + 0x11c)
 | 
						|
#define DDR_RST_CFG_ADDR (DDR_BASE + 0x4)
 | 
						|
 | 
						|
typedef enum ddr_dev_x8_x16_mode {
 | 
						|
    DEV_X8_MODE = 0,
 | 
						|
    DEV_X16_MODE = 1,
 | 
						|
}ddr_dev_x8_x16_mode_t;
 | 
						|
// ddr define end
 | 
						|
 | 
						|
void ddr_op_clear()
 | 
						|
{
 | 
						|
    uint32_t tmp;
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_HANDLE_EB, tmp, 0);
 | 
						|
    REG_FIELD_SET(PHY_EB_SOFT, tmp, 0);
 | 
						|
    REG_FIELD_SET(SW_MEM_RD, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_OPERATION_SW, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR, tmp);
 | 
						|
 | 
						|
     tmp = DDR_RF_READ_REG(CFG_DDR_RST_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(RXTX_RAM_SOFT_RST, tmp, 1);
 | 
						|
    REG_FIELD_SET(SAMPLE_REG_SOFT_RST, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_RST_CFG_ADDR, tmp);
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_RST_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(RXTX_RAM_SOFT_RST, tmp, 0);
 | 
						|
    REG_FIELD_SET(SAMPLE_REG_SOFT_RST, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_RST_CFG_ADDR, tmp);
 | 
						|
 | 
						|
}
 | 
						|
void ddr_reg_write(uint8_t instruction, uint32_t addr,
 | 
						|
        uint8_t write_lt, uint32_t wdata0, uint32_t wdata1)
 | 
						|
{
 | 
						|
    uint32_t tmp;
 | 
						|
 | 
						|
    // step 1
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_RD_OR_WR, tmp, 1);
 | 
						|
    REG_FIELD_SET(SW_MEM_RD, tmp, 0);
 | 
						|
    REG_FIELD_SET(PHY_EB_SOFT, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
    
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_RST_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(RXTX_RAM_SOFT_RST, tmp, 1);
 | 
						|
    REG_FIELD_SET(SAMPLE_REG_SOFT_RST, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_RST_CFG_ADDR, tmp);
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_RST_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(RXTX_RAM_SOFT_RST, tmp, 0);
 | 
						|
    REG_FIELD_SET(SAMPLE_REG_SOFT_RST, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_RST_CFG_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_CMD_DLY_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_WR_LATENCY, tmp, write_lt);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_CMD_DLY_CFG_ADDR, tmp);
 | 
						|
 | 
						|
    // step 2
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_OPERATION_SW, tmp, 0);
 | 
						|
    REG_FIELD_SET(DEV_CMD_SW, tmp, instruction);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG1_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_ADDR_SW, tmp, addr);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG1_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_HANDLE_EB, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_OPERATION_SW, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR, tmp); 
 | 
						|
 | 
						|
    // step 3
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_HANDLE_EB, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp); 
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM0_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WDATA0, tmp, wdata0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM0_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM1_ADDR);
 | 
						|
    REG_FIELD_SET(CMD_OR_DATA_FIFO, tmp, 0);
 | 
						|
    if (instruction == MODE_REGISTER_WRITE) {
 | 
						|
        REG_FIELD_SET(SW_MEM_WDATA1, tmp, 0x6db69a);
 | 
						|
    } else {
 | 
						|
        REG_FIELD_SET(SW_MEM_WDATA1, tmp, 0x69a69a);
 | 
						|
    }
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM1_ADDR, tmp);
 | 
						|
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WR, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_HANDLE_EB, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM0_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WDATA0, tmp, wdata1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM0_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM1_ADDR);
 | 
						|
    REG_FIELD_SET(CMD_OR_DATA_FIFO, tmp, 0);
 | 
						|
    if (instruction == MODE_REGISTER_WRITE) {
 | 
						|
        REG_FIELD_SET(SW_MEM_WDATA1, tmp, 0x6db6db);
 | 
						|
    } else {
 | 
						|
        REG_FIELD_SET(SW_MEM_WDATA1, tmp, 0x69a69a);
 | 
						|
    }
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM1_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WR, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    // step 4
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM0_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WDATA0, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM0_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM1_ADDR);
 | 
						|
    REG_FIELD_SET(CMD_OR_DATA_FIFO, tmp, 0);
 | 
						|
    REG_FIELD_SET(SW_MEM_WDATA1, tmp, 0xaebaeb);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM1_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WR, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_WR, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(PHY_EB_SOFT, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    volatile uint32_t cnt = 50000;
 | 
						|
    while(cnt--);
 | 
						|
 | 
						|
    ddr_op_clear();
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void ddr_reg_read(uint8_t instruction, uint32_t addr,
 | 
						|
        uint32_t *rdata0, uint32_t *rdata1)
 | 
						|
{
 | 
						|
    uint32_t tmp;
 | 
						|
 | 
						|
    // step 1
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_RD_OR_WR, tmp, 0);
 | 
						|
    REG_FIELD_SET(SW_MEM_RD, tmp, 0);
 | 
						|
    REG_FIELD_SET(PHY_EB_SOFT, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
    
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_RST_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(RXTX_RAM_SOFT_RST, tmp, 1);
 | 
						|
    REG_FIELD_SET(SAMPLE_REG_SOFT_RST, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_RST_CFG_ADDR, tmp);
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_RST_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(RXTX_RAM_SOFT_RST, tmp, 0);
 | 
						|
    REG_FIELD_SET(SAMPLE_REG_SOFT_RST, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_RST_CFG_ADDR, tmp);
 | 
						|
 | 
						|
    // step 2
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_OPERATION_SW, tmp, 0);
 | 
						|
    REG_FIELD_SET(DEV_CMD_SW, tmp, instruction);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG1_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_ADDR_SW, tmp, addr);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG1_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_HANDLE_EB, tmp, 0);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_OPERATION_SW, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_SOFT_CMD_CFG0_ADDR, tmp);
 | 
						|
 | 
						|
    for(volatile uint32_t i = 0; i < 100; i++);
 | 
						|
 | 
						|
    // step 3
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR);
 | 
						|
    REG_FIELD_SET(SW_MEM_HANDLE_EB, tmp, 1);
 | 
						|
    REG_FIELD_SET(PHY_EB_SOFT, tmp, 1);
 | 
						|
    REG_FIELD_SET(SW_MEM_RD, tmp, 1);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_OPERATION_INT_MEM3_ADDR, tmp);
 | 
						|
 | 
						|
    // step 4
 | 
						|
    /*
 | 
						|
    uint32_t cnt = 0;
 | 
						|
    while(1) {
 | 
						|
        cnt++;
 | 
						|
        *rdata0 = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM2_ADDR);
 | 
						|
        *rdata1 = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM4_ADDR);
 | 
						|
        if (*rdata0 != 0 && *rdata1 != 0) {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    iot_printf("read cnt: %d\n", cnt);
 | 
						|
    */
 | 
						|
    volatile uint32_t cnt = 1000;
 | 
						|
    while(cnt--);
 | 
						|
    *rdata0 = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM2_ADDR);
 | 
						|
    *rdata1 = DDR_RF_READ_REG(CFG_DDR_OPERATION_INT_MEM4_ADDR);
 | 
						|
 | 
						|
    ddr_op_clear();
 | 
						|
}
 | 
						|
 | 
						|
void ddr_mode_sel(uint8_t bit_mode)
 | 
						|
{
 | 
						|
 | 
						|
    uint32_t tmp;
 | 
						|
    if (bit_mode == DEV_X8_MODE) {
 | 
						|
        iot_printf("bit mode is X8\n");
 | 
						|
        tmp = DDR_RF_READ_REG(CFG_DDR_PROPERTY_CFG_ADDR);
 | 
						|
        REG_FIELD_SET(DEV_CS_INTG, tmp, 1);
 | 
						|
        REG_FIELD_SET(DEV_X8_X16_MODE, tmp, 0);
 | 
						|
        DDR_RF_WRITE_REG(CFG_DDR_PROPERTY_CFG_ADDR, tmp);
 | 
						|
    } else {
 | 
						|
        iot_printf("bit mode is X16\n");
 | 
						|
        tmp = DDR_RF_READ_REG(CFG_DDR_PROPERTY_CFG_ADDR);
 | 
						|
        REG_FIELD_SET(DEV_CS_INTG, tmp, 0);
 | 
						|
        REG_FIELD_SET(DEV_X8_X16_MODE, tmp, 1);
 | 
						|
        DDR_RF_WRITE_REG(CFG_DDR_PROPERTY_CFG_ADDR, tmp);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void ddr_module_cache_cfg()
 | 
						|
{
 | 
						|
    // disable cache
 | 
						|
    iot_printf("disable cache\n");
 | 
						|
    ahb_cache_disable();
 | 
						|
 | 
						|
    // ddr x16 mode
 | 
						|
    iot_printf("set ddr x16 mode\n");
 | 
						|
    ddr_mode_sel(DEV_X16_MODE);
 | 
						|
    uint8_t instruction;
 | 
						|
    uint32_t rdata0, rdata1;
 | 
						|
 | 
						|
    for(uint32_t i = 0; i<=4; i++) {
 | 
						|
        instruction = MODE_REGISTER_READ;
 | 
						|
        ddr_reg_read(instruction, i, &rdata0, &rdata1);
 | 
						|
        iot_printf("==instr: %02x, addr: %08x, rdata0: %08x, rdata1: %08x\n",
 | 
						|
                instruction, i, rdata0, rdata1);
 | 
						|
    }
 | 
						|
    // ddr write reg
 | 
						|
    iot_printf("ddr write reg\n");
 | 
						|
    ddr_reg_write(MODE_REGISTER_WRITE, 0, 1, 0x01010101, 0x01010101);
 | 
						|
    ddr_reg_write(MODE_REGISTER_WRITE, 4, 1, 0x0, 0x0);
 | 
						|
 | 
						|
    // set ddr read/write latency
 | 
						|
    iot_printf("set ddr data read/write latency\n");
 | 
						|
    uint32_t tmp;
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_CMD_DLY_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(DEV_RD_LATENCY, tmp, 3);
 | 
						|
    REG_FIELD_SET(DEV_WR_LATENCY, tmp, 3);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_CMD_DLY_CFG_ADDR, tmp);
 | 
						|
 | 
						|
    // set ddr chip size, 2^n, unit is bit
 | 
						|
    tmp = DDR_RF_READ_REG(CFG_DDR_PROPERTY_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(CS_SIZE, tmp, 0x7);
 | 
						|
    DDR_RF_WRITE_REG(CFG_DDR_PROPERTY_CFG_ADDR, tmp);
 | 
						|
 | 
						|
    tmp = DMC_RF_READ_REG(CFG_DMC_INF_CFG_ADDR);
 | 
						|
    REG_FIELD_SET(DMC_TOTAL_SIZE, tmp, 0x7);
 | 
						|
    DMC_RF_WRITE_REG(CFG_DMC_INF_CFG_ADDR, tmp);
 | 
						|
 | 
						|
    // enable ahb cache
 | 
						|
    iot_printf("cache enable\n");
 | 
						|
    ahb_cache_enable();
 | 
						|
    ahb_cache_reset();
 | 
						|
 | 
						|
    // set cache ddr mode
 | 
						|
    tmp = AHB_RF_READ_REG(CFG_AHB_CTR0_ADDR);
 | 
						|
    REG_FIELD_SET(ICACHE_DMC_MODE, tmp, 1);
 | 
						|
    REG_FIELD_SET(DCACHE_DMC_MODE, tmp, 1);
 | 
						|
    AHB_RF_WRITE_REG(CFG_AHB_CTR0_ADDR, tmp);
 | 
						|
 | 
						|
    // set space
 | 
						|
    tmp = AHB_RF_READ_REG(CFG_CACHE_VALID_SPACE_ADDR);
 | 
						|
    REG_FIELD_SET(SMC_SPACE, tmp, 0x10);
 | 
						|
    REG_FIELD_SET(SFC_SPACE, tmp, 4);
 | 
						|
    AHB_RF_WRITE_REG(CFG_CACHE_VALID_SPACE_ADDR, tmp);
 | 
						|
}
 |