Close

SD Card Code

A project log for OSI SD Card Operating System (OSISDOS)

Ohio Scientific / UK101 SD Card based Operating System under Multicomp FPGA Computer

land-boards.comland-boards.com 07/31/2020 at 20:280 Comments

Minimal SD card code in C:

/* OSISDOS.c - Minimal Operating System for OSI C1P/SuperBoard ][ 	*/
/* SDHC card based disk operating system							*/
/* 8KB Microsoft BASIC-In-ROM has I/O support routines				*/
/* CEGMON has various hooks to the I/O in BASIC						*/
/* Uses Banked SRAM from $E000-$EFFF to buffer SD card data.		*/
/* Intended to fit within a small ROM space below CEGMON			*/
/*	Target ROM space goes from $F100-$F7FF (1.75kb)					*/
/*																	*/
/* Compiled using CC65 toolchain 									*/

/* 
Memory Map
	$0000-$9FFF - SRAM (40KB)
	$A000-$BFFF - Microsoft BASIC-in-ROM (8KB)
		$D000-$D3FF - 1KB Display RAM
		$DC00 - PS/2 Keyboard
		$E000-$EFFF - Bank Selectable SRAM (not detectable as BASIC RAM)
		$F000-$FFFF - CEGMON Monitor ROM 4K
		$F000-$F001 - ACIA (UART) 61440-61441 dec
		$F002 - J6 I/O Connector 61442 dec
		$F003 - J8 I/O Connector 61443 dec
 	$F004 - LEDS 61444 dec
		d0-d1 LEDs are on the FPGA card
 	$F005 - Bank Select Register 61445 dec
		d0..d3 used for 128KB SRAMs
	$F010-$F017 - SD card
	   	0    SDDATA        read/write data
		1    SDSTATUS      read
		1    SDCONTROL     write
		2    SDLBA0        write-only
		3    SDLBA1        write-only
		4    SDLBA2        write-only (only bits 6:0 are valid)
*/

//#include "osic1p.h"

#define READ_BUFFER_START	0xE000	/* Banked SRAM			*/
#define WRITE_BUFFER_START	0xE200	
#define BANK_SELECT_REG_ADR	0xF005
#define START_BANKED_RAM 	0xE000
#define SD_DATA				0xF000
#define SD_CTRL				0xF001
#define SD_STATUS			0xF001
#define SD_LBA0				0xF002
#define SD_LBA1				0xF003
#define SD_LBA2				0xF004
#define READ_COMMMAND		0x00
#define WRITE_COMMMAND		0x01

/* issueSDCardCommand - Send read or write command to SD Card		*/
void issueSDCardCommand(unsigned char rwCmd)
{
	*(unsigned char *) SD_CTRL = rwCmd;
}

/* setLBA0 - Set the least significant logical block address bits	*/
void setLBA0(unsigned char lba0)
{
	*(unsigned char *) SD_LBA0 = lba0;
}

/* setLBA1 - Set the middle 8 bits of the logical block addr bits	*/
void setLBA1(unsigned char lba1)
{
	*(unsigned char *) SD_LBA1 = lba1; 
}

/* setLBA2 - Set the upper 8 bits of the logical block addr bits	*/
void setLBA2(unsigned char lba2)
{
	*(unsigned char *) SD_LBA2 = lba2;
}

/* waitSDCardReady - Wait for the SD Card to be ready				*/
void waitSDCardReady(void)
{
	while (*(unsigned char *) SD_STATUS != 0x80);
}

/* waitSDCardRcvDataReady - Wait for the SD Card to have data ready	*/
void waitSDCardRcvDataReady(void)
{
	while (*(unsigned char *) SD_STATUS != 0xE0);
}

/* waitSDCardTxDataEmpty - Wait for transmit ready from SD ctrlr	*/
void waitSDCardTxDataEmpty(void)
{
	while (*(unsigned char *) SD_STATUS != 0xA0);
}

/* readByteFromSDCard - Read a byte from the SD Card				*/
unsigned char readByteFromSDCard(void)
{
	char rdChar;
	waitSDCardRcvDataReady();
	rdChar = *(unsigned char *) SD_DATA;
	return(rdChar);
}

/* writeByteToSDCard - Write a byte to the SD Card					*/
void writeByteToSDCard(unsigned char outChar)
{
	waitSDCardTxDataEmpty();
	*(unsigned char *) SD_DATA = outChar;
}

/* readBlock - -Read a block from the SD Card						*/
void readBlock(void)
{
	unsigned short loopCount;
	unsigned char * inBuffer;
	inBuffer = (unsigned char *) READ_BUFFER_START;
	waitSDCardReady();
	issueSDCardCommand(READ_COMMMAND);
	for (loopCount = 0; loopCount < 512; loopCount++)
	{
		*inBuffer++ = readByteFromSDCard();
	}
}

/* writeBlock - Write a block to the SD Card						*/
void writeBlock(void)
{
	unsigned short loopCount;
	unsigned char * outBuffer;
	outBuffer = (unsigned char *) WRITE_BUFFER_START;
	waitSDCardReady();
	issueSDCardCommand(WRITE_COMMMAND);
	for (loopCount = 0; loopCount < 512; loopCount++)
	{
		writeByteToSDCard(*outBuffer++);
	}
}

/* main - Test the SD Card interface								*/
void main(void)
{
	/* Set to first bank of the banked SRAM */ 
	*(unsigned char*) BANK_SELECT_REG_ADR = 0x00;
	setLBA0(0);
	setLBA1(0);
	setLBA2(0);
	readBlock();
}

 Assembly output list file:

ca65 V2.17 - Git de519b9
Main file   : OSISDOS.s
Current file: OSISDOS.s

000000r 1               ;
000000r 1               ; File generated by cc65 v 2.17 - Git de519b9
000000r 1               ;
000000r 1               	.fopt		compiler,"cc65 v 2.17 - Git de519b9"
000000r 1               	.setcpu		"6502"
000000r 1               	.smart		on
000000r 1               	.autoimport	on
000000r 1               	.case		on
000000r 1               	.debuginfo	off
000000r 1               	.importzp	sp, sreg, regsave, regbank
000000r 1               	.importzp	tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
000000r 1               	.macpack	longbranch
000000r 2               .macro  jeq     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                       bne     *+5
000000r 2                       jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               beq     Target
000000r 2                       .else
000000r 2                               bne     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jne     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               beq     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bne     Target
000000r 2                       .else
000000r 2                               beq     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jmi     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               bpl     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bmi     Target
000000r 2                       .else
000000r 2                               bpl     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jpl     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               bmi     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bpl     Target
000000r 2                       .else
000000r 2                               bmi     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jcs     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               bcc     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bcs     Target
000000r 2                       .else
000000r 2                               bcc     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jcc     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               bcs     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bcc     Target
000000r 2                       .else
000000r 2                               bcs     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jvs     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               bvc     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bvs     Target
000000r 2                       .else
000000r 2                               bvc     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               .macro  jvc     Target
000000r 2                       .if     .match(Target, 0)
000000r 2                               bvs     *+5
000000r 2                               jmp     Target
000000r 2                       .elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
000000r 2                               bvc     Target
000000r 2                       .else
000000r 2                               bvs     *+5
000000r 2                               jmp     Target
000000r 2                       .endif
000000r 2               .endmacro
000000r 2               
000000r 1               	.forceimport	__STARTUP__
000000r 1               	.export		_issueSDCardCommand
000000r 1               	.export		_setLBA0
000000r 1               	.export		_setLBA1
000000r 1               	.export		_setLBA2
000000r 1               	.export		_waitSDCardReady
000000r 1               	.export		_waitSDCardRcvDataReady
000000r 1               	.export		_waitSDCardTxDataEmpty
000000r 1               	.export		_readByteFromSDCard
000000r 1               	.export		_writeByteToSDCard
000000r 1               	.export		_readBlock
000000r 1               	.export		_writeBlock
000000r 1               	.export		_main
000000r 1               
000000r 1               ; ---------------------------------------------------------------
000000r 1               ; void __near__ issueSDCardCommand (unsigned char)
000000r 1               ; ---------------------------------------------------------------
000000r 1               
000000r 1               .segment	"CODE"
000000r 1               
000000r 1               .proc	_issueSDCardCommand: near
000000r 1               
000000r 1               .segment	"CODE"
000000r 1               
000000r 1  20 rr rr     	jsr     pusha
000003r 1  A0 00        	ldy     #$00
000005r 1  A2 00        	ldx     #$00
000007r 1  B1 rr        	lda     (sp),y
000009r 1  8D 01 F0     	sta     $F001
00000Cr 1  20 rr rr     	jsr     incsp1
00000Fr 1  60           	rts
000010r 1               
000010r 1               .endproc
000010r 1               
000010r 1               ; ---------------------------------------------------------------
000010r 1               ; void __near__ setLBA0 (unsigned char)
000010r 1               ; ---------------------------------------------------------------
000010r 1               
000010r 1               .segment	"CODE"
000010r 1               
000010r 1               .proc	_setLBA0: near
000010r 1               
000010r 1               .segment	"CODE"
000010r 1               
000010r 1  20 rr rr     	jsr     pusha
000013r 1  A0 00        	ldy     #$00
000015r 1  A2 00        	ldx     #$00
000017r 1  B1 rr        	lda     (sp),y
000019r 1  8D 02 F0     	sta     $F002
00001Cr 1  20 rr rr     	jsr     incsp1
00001Fr 1  60           	rts
000020r 1               
000020r 1               .endproc
000020r 1               
000020r 1               ; ---------------------------------------------------------------
000020r 1               ; void __near__ setLBA1 (unsigned char)
000020r 1               ; ---------------------------------------------------------------
000020r 1               
000020r 1               .segment	"CODE"
000020r 1               
000020r 1               .proc	_setLBA1: near
000020r 1               
000020r 1               .segment	"CODE"
000020r 1               
000020r 1  20 rr rr     	jsr     pusha
000023r 1  A0 00        	ldy     #$00
000025r 1  A2 00        	ldx     #$00
000027r 1  B1 rr        	lda     (sp),y
000029r 1  8D 03 F0     	sta     $F003
00002Cr 1  20 rr rr     	jsr     incsp1
00002Fr 1  60           	rts
000030r 1               
000030r 1               .endproc
000030r 1               
000030r 1               ; ---------------------------------------------------------------
000030r 1               ; void __near__ setLBA2 (unsigned char)
000030r 1               ; ---------------------------------------------------------------
000030r 1               
000030r 1               .segment	"CODE"
000030r 1               
000030r 1               .proc	_setLBA2: near
000030r 1               
000030r 1               .segment	"CODE"
000030r 1               
000030r 1  20 rr rr     	jsr     pusha
000033r 1  A0 00        	ldy     #$00
000035r 1  A2 00        	ldx     #$00
000037r 1  B1 rr        	lda     (sp),y
000039r 1  8D 04 F0     	sta     $F004
00003Cr 1  20 rr rr     	jsr     incsp1
00003Fr 1  60           	rts
000040r 1               
000040r 1               .endproc
000040r 1               
000040r 1               ; ---------------------------------------------------------------
000040r 1               ; void __near__ waitSDCardReady (void)
000040r 1               ; ---------------------------------------------------------------
000040r 1               
000040r 1               .segment	"CODE"
000040r 1               
000040r 1               .proc	_waitSDCardReady: near
000040r 1               
000040r 1               .segment	"CODE"
000040r 1               
000040r 1  4C rr rr     	jmp     L000E
000043r 1  A2 00        L000E:	ldx     #$00
000045r 1  AD 01 F0     	lda     $F001
000048r 1  C9 80        	cmp     #$80
00004Ar 1  20 rr rr     	jsr     boolne
00004Dr 1  D0 F4        	jne     L000E
00004Fr 1  60           	rts
000050r 1               
000050r 1               .endproc
000050r 1               
000050r 1               ; ---------------------------------------------------------------
000050r 1               ; void __near__ waitSDCardRcvDataReady (void)
000050r 1               ; ---------------------------------------------------------------
000050r 1               
000050r 1               .segment	"CODE"
000050r 1               
000050r 1               .proc	_waitSDCardRcvDataReady: near
000050r 1               
000050r 1               .segment	"CODE"
000050r 1               
000050r 1  4C rr rr     	jmp     L0013
000053r 1  A2 00        L0013:	ldx     #$00
000055r 1  AD 01 F0     	lda     $F001
000058r 1  C9 E0        	cmp     #$E0
00005Ar 1  20 rr rr     	jsr     boolne
00005Dr 1  D0 F4        	jne     L0013
00005Fr 1  60           	rts
000060r 1               
000060r 1               .endproc
000060r 1               
000060r 1               ; ---------------------------------------------------------------
000060r 1               ; void __near__ waitSDCardTxDataEmpty (void)
000060r 1               ; ---------------------------------------------------------------
000060r 1               
000060r 1               .segment	"CODE"
000060r 1               
000060r 1               .proc	_waitSDCardTxDataEmpty: near
000060r 1               
000060r 1               .segment	"CODE"
000060r 1               
000060r 1  4C rr rr     	jmp     L0018
000063r 1  A2 00        L0018:	ldx     #$00
000065r 1  AD 01 F0     	lda     $F001
000068r 1  C9 A0        	cmp     #$A0
00006Ar 1  20 rr rr     	jsr     boolne
00006Dr 1  D0 F4        	jne     L0018
00006Fr 1  60           	rts
000070r 1               
000070r 1               .endproc
000070r 1               
000070r 1               ; ---------------------------------------------------------------
000070r 1               ; unsigned char __near__ readByteFromSDCard (void)
000070r 1               ; ---------------------------------------------------------------
000070r 1               
000070r 1               .segment	"CODE"
000070r 1               
000070r 1               .proc	_readByteFromSDCard: near
000070r 1               
000070r 1               .segment	"CODE"
000070r 1               
000070r 1  20 rr rr     	jsr     decsp1
000073r 1  20 rr rr     	jsr     _waitSDCardRcvDataReady
000076r 1  A2 00        	ldx     #$00
000078r 1  AD 00 F0     	lda     $F000
00007Br 1  A0 00        	ldy     #$00
00007Dr 1  91 rr        	sta     (sp),y
00007Fr 1  A0 00        	ldy     #$00
000081r 1  A2 00        	ldx     #$00
000083r 1  B1 rr        	lda     (sp),y
000085r 1  4C rr rr     	jmp     L001C
000088r 1  20 rr rr     L001C:	jsr     incsp1
00008Br 1  60           	rts
00008Cr 1               
00008Cr 1               .endproc
00008Cr 1               
00008Cr 1               ; ---------------------------------------------------------------
00008Cr 1               ; void __near__ writeByteToSDCard (unsigned char)
00008Cr 1               ; ---------------------------------------------------------------
00008Cr 1               
00008Cr 1               .segment	"CODE"
00008Cr 1               
00008Cr 1               .proc	_writeByteToSDCard: near
00008Cr 1               
00008Cr 1               .segment	"CODE"
00008Cr 1               
00008Cr 1  20 rr rr     	jsr     pusha
00008Fr 1  20 rr rr     	jsr     _waitSDCardTxDataEmpty
000092r 1  A0 00        	ldy     #$00
000094r 1  A2 00        	ldx     #$00
000096r 1  B1 rr        	lda     (sp),y
000098r 1  8D 00 F0     	sta     $F000
00009Br 1  20 rr rr     	jsr     incsp1
00009Er 1  60           	rts
00009Fr 1               
00009Fr 1               .endproc
00009Fr 1               
00009Fr 1               ; ---------------------------------------------------------------
00009Fr 1               ; void __near__ readBlock (void)
00009Fr 1               ; ---------------------------------------------------------------
00009Fr 1               
00009Fr 1               .segment	"CODE"
00009Fr 1               
00009Fr 1               .proc	_readBlock: near
00009Fr 1               
00009Fr 1               .segment	"CODE"
00009Fr 1               
00009Fr 1  20 rr rr     	jsr     decsp4
0000A2r 1  A2 E0        	ldx     #$E0
0000A4r 1  A9 00        	lda     #$00
0000A6r 1  A0 00        	ldy     #$00
0000A8r 1  20 rr rr     	jsr     staxysp
0000ABr 1  20 rr rr     	jsr     _waitSDCardReady
0000AEr 1  A9 00        	lda     #$00
0000B0r 1  20 rr rr     	jsr     _issueSDCardCommand
0000B3r 1  A2 00        	ldx     #$00
0000B5r 1  A9 00        	lda     #$00
0000B7r 1  A0 02        	ldy     #$02
0000B9r 1  20 rr rr     	jsr     staxysp
0000BCr 1  A0 03        L002C:	ldy     #$03
0000BEr 1  20 rr rr     	jsr     ldaxysp
0000C1r 1  E0 02        	cpx     #$02
0000C3r 1  20 rr rr     	jsr     boolult
0000C6r 1  F0 03 4C rr  	jne     L002F
0000CAr 1  rr           
0000CBr 1  4C rr rr     	jmp     L002D
0000CEr 1  A0 01        L002F:	ldy     #$01
0000D0r 1  20 rr rr     	jsr     ldaxysp
0000D3r 1  85 rr        	sta     regsave
0000D5r 1  86 rr        	stx     regsave+1
0000D7r 1  20 rr rr     	jsr     incax1
0000DAr 1  A0 00        	ldy     #$00
0000DCr 1  20 rr rr     	jsr     staxysp
0000DFr 1  A5 rr        	lda     regsave
0000E1r 1  A6 rr        	ldx     regsave+1
0000E3r 1  20 rr rr     	jsr     pushax
0000E6r 1  20 rr rr     	jsr     _readByteFromSDCard
0000E9r 1  A0 00        	ldy     #$00
0000EBr 1  20 rr rr     	jsr     staspidx
0000EEr 1  A0 03        	ldy     #$03
0000F0r 1  20 rr rr     	jsr     ldaxysp
0000F3r 1  85 rr        	sta     regsave
0000F5r 1  86 rr        	stx     regsave+1
0000F7r 1  20 rr rr     	jsr     incax1
0000FAr 1  A0 02        	ldy     #$02
0000FCr 1  20 rr rr     	jsr     staxysp
0000FFr 1  A5 rr        	lda     regsave
000101r 1  A6 rr        	ldx     regsave+1
000103r 1  4C rr rr     	jmp     L002C
000106r 1  20 rr rr     L002D:	jsr     incsp4
000109r 1  60           	rts
00010Ar 1               
00010Ar 1               .endproc
00010Ar 1               
00010Ar 1               ; ---------------------------------------------------------------
00010Ar 1               ; void __near__ writeBlock (void)
00010Ar 1               ; ---------------------------------------------------------------
00010Ar 1               
00010Ar 1               .segment	"CODE"
00010Ar 1               
00010Ar 1               .proc	_writeBlock: near
00010Ar 1               
00010Ar 1               .segment	"CODE"
00010Ar 1               
00010Ar 1  20 rr rr     	jsr     decsp4
00010Dr 1  A2 E2        	ldx     #$E2
00010Fr 1  A9 00        	lda     #$00
000111r 1  A0 00        	ldy     #$00
000113r 1  20 rr rr     	jsr     staxysp
000116r 1  20 rr rr     	jsr     _waitSDCardReady
000119r 1  A9 01        	lda     #$01
00011Br 1  20 rr rr     	jsr     _issueSDCardCommand
00011Er 1  A2 00        	ldx     #$00
000120r 1  A9 00        	lda     #$00
000122r 1  A0 02        	ldy     #$02
000124r 1  20 rr rr     	jsr     staxysp
000127r 1  A0 03        L003C:	ldy     #$03
000129r 1  20 rr rr     	jsr     ldaxysp
00012Cr 1  E0 02        	cpx     #$02
00012Er 1  20 rr rr     	jsr     boolult
000131r 1  F0 03 4C rr  	jne     L003F
000135r 1  rr           
000136r 1  4C rr rr     	jmp     L003D
000139r 1  A0 01        L003F:	ldy     #$01
00013Br 1  20 rr rr     	jsr     ldaxysp
00013Er 1  85 rr        	sta     regsave
000140r 1  86 rr        	stx     regsave+1
000142r 1  20 rr rr     	jsr     incax1
000145r 1  A0 00        	ldy     #$00
000147r 1  20 rr rr     	jsr     staxysp
00014Ar 1  A5 rr        	lda     regsave
00014Cr 1  A6 rr        	ldx     regsave+1
00014Er 1  A0 00        	ldy     #$00
000150r 1  20 rr rr     	jsr     ldauidx
000153r 1  20 rr rr     	jsr     _writeByteToSDCard
000156r 1  A0 03        	ldy     #$03
000158r 1  20 rr rr     	jsr     ldaxysp
00015Br 1  85 rr        	sta     regsave
00015Dr 1  86 rr        	stx     regsave+1
00015Fr 1  20 rr rr     	jsr     incax1
000162r 1  A0 02        	ldy     #$02
000164r 1  20 rr rr     	jsr     staxysp
000167r 1  A5 rr        	lda     regsave
000169r 1  A6 rr        	ldx     regsave+1
00016Br 1  4C rr rr     	jmp     L003C
00016Er 1  20 rr rr     L003D:	jsr     incsp4
000171r 1  60           	rts
000172r 1               
000172r 1               .endproc
000172r 1               
000172r 1               ; ---------------------------------------------------------------
000172r 1               ; void __near__ main (void)
000172r 1               ; ---------------------------------------------------------------
000172r 1               
000172r 1               .segment	"CODE"
000172r 1               
000172r 1               .proc	_main: near
000172r 1               
000172r 1               .segment	"CODE"
000172r 1               
000172r 1  A2 00        	ldx     #$00
000174r 1  A9 00        	lda     #$00
000176r 1  8D 05 F0     	sta     $F005
000179r 1  A9 00        	lda     #$00
00017Br 1  20 rr rr     	jsr     _setLBA0
00017Er 1  A9 00        	lda     #$00
000180r 1  20 rr rr     	jsr     _setLBA1
000183r 1  A9 00        	lda     #$00
000185r 1  20 rr rr     	jsr     _setLBA2
000188r 1  20 rr rr     	jsr     _readBlock
00018Br 1  60           	rts
00018Cr 1               
00018Cr 1               .endproc
00018Cr 1               
00018Cr 1               

main() starts at 0x172 from 0x300 or 0x472. 

Nice!

Discussions