| 
									
										
										
										
											2009-07-28 21:32:10 +00:00
										 |  |  | // Copyright (C) 2003 Dolphin Project.
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, version 2.0.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU General Public License 2.0 for more details.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A copy of the GPL 2.0 should have been included with the program.
 | 
					
						
							|  |  |  | // If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Official SVN repository and contact information can be found at
 | 
					
						
							|  |  |  | // http://code.google.com/p/dolphin-emu/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Additional copyrights go to Duddie and Tratax (c) 2004
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DSPInterpreter.h"
 | 
					
						
							|  |  |  | #include "DSPCore.h"
 | 
					
						
							|  |  |  | #include "DSPMemoryMap.h"
 | 
					
						
							|  |  |  | #include "DSPStacks.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DSPIntCCUtil.h"
 | 
					
						
							|  |  |  | #include "DSPIntUtil.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace DSPInterpreter { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generic call implementation
 | 
					
						
							|  |  |  | // CALLcc addressA
 | 
					
						
							|  |  |  | // 0000 0010 1011 cccc
 | 
					
						
							|  |  |  | // aaaa aaaa aaaa aaaa
 | 
					
						
							|  |  |  | // Call function if condition cc has been met. Push program counter of
 | 
					
						
							|  |  |  | // instruction following "call" to $st0. Set program counter to address
 | 
					
						
							|  |  |  | // represented by value that follows this "call" instruction.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void call(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	// must be outside the if.
 | 
					
						
							|  |  |  | 	u16 dest = dsp_fetch_code(); | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	if (CheckCondition(opc & 0xf)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); | 
					
						
							|  |  |  | 		g_dsp.pc = dest; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generic callr implementation
 | 
					
						
							|  |  |  | // CALLRcc $R
 | 
					
						
							|  |  |  | // 0001 0111 rrr1 cccc
 | 
					
						
							|  |  |  | // Call function if condition cc has been met. Push program counter of 
 | 
					
						
							|  |  |  | // instruction following "call" to call stack $st0. Set program counter to 
 | 
					
						
							|  |  |  | // register $R.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void callr(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	if (CheckCondition(opc & 0xf)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 		u8 reg  = (opc >> 5) & 0x7; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		u16 addr = dsp_op_read_reg(reg); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); | 
					
						
							|  |  |  | 		g_dsp.pc = addr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generic if implementation
 | 
					
						
							|  |  |  | // IFcc
 | 
					
						
							|  |  |  | // 0000 0010 0111 cccc
 | 
					
						
							|  |  |  | // Execute following opcode if the condition has been met.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void ifcc(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	if (!CheckCondition(opc & 0xf)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		// skip the next opcode - we have to lookup its size.
 | 
					
						
							| 
									
										
										
										
											2010-03-29 01:18:05 +00:00
										 |  |  | 		dsp_skip_inst(); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generic jmp implementation
 | 
					
						
							|  |  |  | // Jcc addressA
 | 
					
						
							|  |  |  | // 0000 0010 1001 cccc
 | 
					
						
							|  |  |  | // aaaa aaaa aaaa aaaa
 | 
					
						
							|  |  |  | // Jump to addressA if condition cc has been met. Set program counter to
 | 
					
						
							|  |  |  | // address represented by value that follows this "jmp" instruction.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void jcc(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	u16 dest = dsp_fetch_code(); | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	if (CheckCondition(opc & 0xf)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		g_dsp.pc = dest; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generic jmpr implementation
 | 
					
						
							|  |  |  | // JMPcc $R
 | 
					
						
							|  |  |  | // 0001 0111 rrr0 cccc
 | 
					
						
							|  |  |  | // Jump to address; set program counter to a value from register $R.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void jmprcc(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	if (CheckCondition(opc & 0xf)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 		u8 reg  = (opc >> 5) & 0x7; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 		g_dsp.pc = dsp_op_read_reg(reg); | 
					
						
							|  |  |  | 	}  | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Generic ret implementation
 | 
					
						
							|  |  |  | // RETcc
 | 
					
						
							|  |  |  | // 0000 0010 1101 cccc
 | 
					
						
							|  |  |  | // Return from subroutine if condition cc has been met. Pops stored PC
 | 
					
						
							|  |  |  | // from call stack $st0 and sets $pc to this location.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void ret(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	if (CheckCondition(opc & 0xf)) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RTI
 | 
					
						
							|  |  |  | // 0000 0010 1111 1111
 | 
					
						
							|  |  |  | // Return from exception. Pops stored status register $sr from data stack
 | 
					
						
							|  |  |  | // $st1 and program counter PC from call stack $st0 and sets $pc to this
 | 
					
						
							|  |  |  | // location.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void rti(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-12-29 20:20:52 +00:00
										 |  |  | 	g_dsp.r.sr = dsp_reg_load_stack(DSP_STACK_D); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // HALT
 | 
					
						
							|  |  |  | // 0000 0000 0020 0001 
 | 
					
						
							|  |  |  | // Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void halt(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	g_dsp.cr |= 0x4; | 
					
						
							|  |  |  | 	g_dsp.pc--; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LOOP handling: Loop stack is used to control execution of repeated blocks of
 | 
					
						
							|  |  |  | // instructions. Whenever there is value on stack $st2 and current PC is equal
 | 
					
						
							|  |  |  | // value at $st2, then value at stack $st3 is decremented. If value is not zero
 | 
					
						
							| 
									
										
										
										
											2009-07-06 21:27:56 +00:00
										 |  |  | // then PC is modified with value from call stack $st0. Otherwise values from
 | 
					
						
							| 
									
										
										
										
											2010-12-26 12:34:38 +00:00
										 |  |  | // call stack $st0 and both loop stacks $st2 and $st3 are popped and execution
 | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | // continues at next opcode.
 | 
					
						
							| 
									
										
										
										
											2009-07-06 19:19:03 +00:00
										 |  |  | void HandleLoop() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	// Handle looping hardware. 
 | 
					
						
							| 
									
										
										
										
											2010-12-29 20:20:52 +00:00
										 |  |  | 	const u16 rCallAddress = g_dsp.r.st[0]; | 
					
						
							|  |  |  | 	const u16 rLoopAddress = g_dsp.r.st[2]; | 
					
						
							|  |  |  | 	u16& rLoopCounter = g_dsp.r.st[3]; | 
					
						
							| 
									
										
										
										
											2009-07-06 19:19:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 21:27:56 +00:00
										 |  |  | 	if (rLoopAddress > 0 && rLoopCounter > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-11 10:18:25 +00:00
										 |  |  | 		// FIXME: why -1? because we just read past it.
 | 
					
						
							| 
									
										
										
										
											2009-07-06 21:27:56 +00:00
										 |  |  | 		if (g_dsp.pc - 1 == rLoopAddress) | 
					
						
							| 
									
										
										
										
											2009-07-06 19:19:03 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			rLoopCounter--; | 
					
						
							|  |  |  | 			if (rLoopCounter > 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				g_dsp.pc = rCallAddress; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				// end of loop
 | 
					
						
							|  |  |  | 				dsp_reg_load_stack(0); | 
					
						
							|  |  |  | 				dsp_reg_load_stack(2); | 
					
						
							|  |  |  | 				dsp_reg_load_stack(3); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LOOP $R
 | 
					
						
							|  |  |  | // 0000 0000 010r rrrr
 | 
					
						
							|  |  |  | // Repeatedly execute following opcode until counter specified by value
 | 
					
						
							|  |  |  | // from register $R reaches zero. Each execution decrement counter. Register
 | 
					
						
							|  |  |  | // $R remains unchanged. If register $R is set to zero at the beginning of loop
 | 
					
						
							|  |  |  | // then looped instruction will not get executed.
 | 
					
						
							|  |  |  | // Actually, this instruction simply prepares the loop stacks for the above.
 | 
					
						
							|  |  |  | // The looping hardware takes care of the rest.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void loop(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	u16 reg = opc & 0x1f; | 
					
						
							| 
									
										
										
										
											2010-12-29 02:12:06 +00:00
										 |  |  | 	u16 cnt = dsp_op_read_reg(reg); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	u16 loop_pc = g_dsp.pc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cnt) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		dsp_reg_store_stack(0, g_dsp.pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(2, loop_pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(3, cnt); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LOOPI #I
 | 
					
						
							|  |  |  | // 0001 0000 iiii iiii
 | 
					
						
							|  |  |  | // Repeatedly execute following opcode until counter specified by
 | 
					
						
							|  |  |  | // immediate value I reaches zero. Each execution decrement counter. If
 | 
					
						
							|  |  |  | // immediate value I is set to zero at the beginning of loop then looped
 | 
					
						
							|  |  |  | // instruction will not get executed.
 | 
					
						
							|  |  |  | // Actually, this instruction simply prepares the loop stacks for the above.
 | 
					
						
							|  |  |  | // The looping hardware takes care of the rest.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void loopi(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	u16 cnt = opc & 0xff; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	u16 loop_pc = g_dsp.pc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cnt) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		dsp_reg_store_stack(0, g_dsp.pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(2, loop_pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(3, cnt); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // BLOOP $R, addrA
 | 
					
						
							|  |  |  | // 0000 0000 011r rrrr
 | 
					
						
							|  |  |  | // aaaa aaaa aaaa aaaa
 | 
					
						
							|  |  |  | // Repeatedly execute block of code starting at following opcode until
 | 
					
						
							|  |  |  | // counter specified by value from register $R reaches zero. Block ends at
 | 
					
						
							|  |  |  | // specified address addrA inclusive, ie. opcode at addrA is the last opcode
 | 
					
						
							|  |  |  | // included in loop. Counter is pushed on loop stack $st3, end of block address
 | 
					
						
							|  |  |  | // is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
 | 
					
						
							| 
									
										
										
										
											2010-12-26 12:34:38 +00:00
										 |  |  | // Up to 4 nested loops are allowed.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void bloop(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	u16 reg = opc & 0x1f; | 
					
						
							| 
									
										
										
										
											2010-12-29 02:12:06 +00:00
										 |  |  | 	u16 cnt = dsp_op_read_reg(reg); | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	u16 loop_pc = dsp_fetch_code(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cnt) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		dsp_reg_store_stack(0, g_dsp.pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(2, loop_pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(3, cnt); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-08 20:06:15 +00:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		g_dsp.pc = loop_pc; | 
					
						
							| 
									
										
										
										
											2010-03-29 01:18:05 +00:00
										 |  |  | 		dsp_skip_inst(); | 
					
						
							| 
									
										
										
										
											2009-07-08 20:06:15 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // BLOOPI #I, addrA
 | 
					
						
							|  |  |  | // 0001 0001 iiii iiii
 | 
					
						
							|  |  |  | // aaaa aaaa aaaa aaaa
 | 
					
						
							|  |  |  | // Repeatedly execute block of code starting at following opcode until
 | 
					
						
							|  |  |  | // counter specified by immediate value I reaches zero. Block ends at specified
 | 
					
						
							|  |  |  | // address addrA inclusive, ie. opcode at addrA is the last opcode included in
 | 
					
						
							|  |  |  | // loop. Counter is pushed on loop stack $st3, end of block address is pushed
 | 
					
						
							|  |  |  | // on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
 | 
					
						
							| 
									
										
										
										
											2010-12-26 12:34:38 +00:00
										 |  |  | // nested loops are allowed.
 | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | void bloopi(const UDSPInstruction opc) | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-03-24 05:05:25 +00:00
										 |  |  | 	u16 cnt = opc & 0xff; | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	u16 loop_pc = dsp_fetch_code(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-06 21:27:56 +00:00
										 |  |  | 	if (cnt)  | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		dsp_reg_store_stack(0, g_dsp.pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(2, loop_pc); | 
					
						
							|  |  |  | 		dsp_reg_store_stack(3, cnt); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-08 20:06:15 +00:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		g_dsp.pc = loop_pc; | 
					
						
							| 
									
										
										
										
											2010-03-29 01:18:05 +00:00
										 |  |  | 		dsp_skip_inst(); | 
					
						
							| 
									
										
										
										
											2009-07-08 20:06:15 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-07-06 02:10:26 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace
 |