trunk/src/mame/drivers/crystal.cpp
r250324 | r250325 | |
148 | 148 | required_shared_ptr<UINT32> m_vidregs; |
149 | 149 | required_shared_ptr<UINT32> m_textureram; |
150 | 150 | required_shared_ptr<UINT32> m_frameram; |
151 | | required_shared_ptr<UINT32> m_reset_patch; |
| 151 | optional_shared_ptr<UINT32> m_reset_patch; // not needed for trivrus |
152 | 152 | // UINT32 * m_nvram; // currently this uses generic nvram handling |
153 | 153 | |
154 | 154 | /* devices */ |
r250324 | r250325 | |
197 | 197 | DECLARE_DRIVER_INIT(evosocc); |
198 | 198 | DECLARE_DRIVER_INIT(donghaer); |
199 | 199 | |
| 200 | DECLARE_READ32_MEMBER(trivrus_input_r); |
| 201 | DECLARE_WRITE32_MEMBER(trivrus_input_w); |
| 202 | UINT8 m_trivrus_input; |
| 203 | |
200 | 204 | virtual void machine_start(); |
201 | 205 | virtual void machine_reset(); |
202 | 206 | UINT32 screen_update_crystal(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); |
r250324 | r250325 | |
525 | 529 | |
526 | 530 | ADDRESS_MAP_END |
527 | 531 | |
| 532 | // Trivia R Us |
| 533 | // To do: touch panel, RTC |
| 534 | |
| 535 | READ32_MEMBER(crystal_state::trivrus_input_r) |
| 536 | { |
| 537 | switch (m_trivrus_input) |
| 538 | { |
| 539 | case 1: return ioport("IN1")->read(); |
| 540 | case 2: return ioport("IN2")->read(); |
| 541 | case 3: return ioport("IN3")->read(); |
| 542 | case 4: return ioport("IN4")->read(); |
| 543 | case 5: return ioport("IN5")->read(); |
| 544 | case 6: return ioport("DSW")->read(); |
| 545 | } |
| 546 | logerror("%s: unknown input %02x read\n", machine().describe_context(), m_trivrus_input); |
| 547 | return 0xffffffff; |
| 548 | } |
| 549 | |
| 550 | WRITE32_MEMBER(crystal_state::trivrus_input_w) |
| 551 | { |
| 552 | if (ACCESSING_BITS_0_7) |
| 553 | m_trivrus_input = data & 0xff; |
| 554 | } |
| 555 | |
| 556 | static ADDRESS_MAP_START( trivrus_mem, AS_PROGRAM, 32, crystal_state ) |
| 557 | AM_RANGE(0x00000000, 0x0007ffff) AM_ROM AM_WRITENOP |
| 558 | |
| 559 | // 0x01280000 & 0x0000ffff (written at boot) |
| 560 | AM_RANGE(0x01500000, 0x01500003) AM_READWRITE(trivrus_input_r, trivrus_input_w) |
| 561 | // 0x01500010 & 0x000000ff = sec |
| 562 | // 0x01500010 & 0x00ff0000 = min |
| 563 | // 0x01500014 & 0x000000ff = hour |
| 564 | // 0x01500014 & 0x00ff0000 = day |
| 565 | // 0x01500018 & 0x000000ff = month |
| 566 | // 0x0150001c & 0x000000ff = year - 2000 |
| 567 | AM_RANGE(0x01600000, 0x01607fff) AM_RAM AM_SHARE("nvram") |
| 568 | |
| 569 | AM_RANGE(0x01801400, 0x01801403) AM_READWRITE(Timer0_r, Timer0_w) |
| 570 | AM_RANGE(0x01801408, 0x0180140b) AM_READWRITE(Timer1_r, Timer1_w) |
| 571 | AM_RANGE(0x01801410, 0x01801413) AM_READWRITE(Timer2_r, Timer2_w) |
| 572 | AM_RANGE(0x01801418, 0x0180141b) AM_READWRITE(Timer3_r, Timer3_w) |
| 573 | AM_RANGE(0x01802004, 0x01802007) AM_READWRITE(PIO_r, PIO_w) |
| 574 | |
| 575 | AM_RANGE(0x01800800, 0x01800803) AM_READWRITE(DMA0_r, DMA0_w) |
| 576 | AM_RANGE(0x01800810, 0x01800813) AM_READWRITE(DMA1_r, DMA1_w) |
| 577 | |
| 578 | AM_RANGE(0x01800c04, 0x01800c07) AM_WRITE(IntAck_w) |
| 579 | AM_RANGE(0x01800000, 0x0180ffff) AM_RAM AM_SHARE("sysregs") |
| 580 | AM_RANGE(0x02000000, 0x027fffff) AM_RAM AM_SHARE("workram") |
| 581 | |
| 582 | AM_RANGE(0x030000a4, 0x030000a7) AM_READWRITE(FlipCount_r, FlipCount_w) |
| 583 | |
| 584 | AM_RANGE(0x03000000, 0x0300ffff) AM_RAM AM_SHARE("vidregs") |
| 585 | AM_RANGE(0x03800000, 0x03ffffff) AM_RAM AM_SHARE("textureram") |
| 586 | AM_RANGE(0x04000000, 0x047fffff) AM_RAM AM_SHARE("frameram") |
| 587 | AM_RANGE(0x04800000, 0x04800fff) AM_DEVREADWRITE("vrender", vrender0_device, vr0_snd_read, vr0_snd_write) |
| 588 | |
| 589 | AM_RANGE(0x05000000, 0x05000003) AM_READWRITE(FlashCmd_r, FlashCmd_w) |
| 590 | AM_RANGE(0x05000000, 0x05ffffff) AM_ROMBANK("bank1") |
| 591 | |
| 592 | // AM_RANGE(0x44414F4C, 0x44414F7F) AM_RAM AM_SHARE("reset_patch") |
| 593 | |
| 594 | ADDRESS_MAP_END |
| 595 | |
| 596 | |
528 | 597 | void crystal_state::PatchReset( ) |
529 | 598 | { |
| 599 | if (!m_reset_patch) |
| 600 | return; |
| 601 | |
530 | 602 | //The test menu reset routine seems buggy |
531 | 603 | //it reads the reset vector from 0x02000000 but it should be |
532 | 604 | //read from 0x00000000. At 0x2000000 there is the bios signature |
r250324 | r250325 | |
603 | 675 | save_item(NAME(m_PIO)); |
604 | 676 | save_item(NAME(m_DMActrl)); |
605 | 677 | save_item(NAME(m_OldPort4)); |
| 678 | save_item(NAME(m_trivrus_input)); |
606 | 679 | machine().save().register_postload(save_prepost_delegate(FUNC(crystal_state::crystal_banksw_postload), this)); |
607 | 680 | } |
608 | 681 | |
r250324 | r250325 | |
893 | 966 | INPUT_PORTS_END |
894 | 967 | |
895 | 968 | |
| 969 | static INPUT_PORTS_START(trivrus) |
| 970 | PORT_START("IN1") |
| 971 | PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 972 | PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 973 | PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 974 | PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 975 | PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 976 | PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) |
| 977 | PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Left/True") PORT_CODE(KEYCODE_LEFT) |
| 978 | PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) |
| 979 | PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 980 | |
| 981 | PORT_START("IN2") |
| 982 | PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Enter/Exit") |
| 983 | PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Next") |
| 984 | PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 985 | PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 986 | PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Right/False") PORT_CODE(KEYCODE_RIGHT) |
| 987 | PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 988 | PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(1) |
| 989 | PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 990 | PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 991 | |
| 992 | PORT_START("IN3") |
| 993 | PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 994 | PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 995 | PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 996 | PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 997 | PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 998 | PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Sound") |
| 999 | PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1000 | PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1001 | PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1002 | |
| 1003 | PORT_START("IN4") |
| 1004 | PORT_BIT( 0x000000ff, IP_ACTIVE_LOW, IPT_OTHER )PORT_CODE(KEYCODE_9) |
| 1005 | PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1006 | |
| 1007 | PORT_START("IN5") |
| 1008 | PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_SERVICE1 ) // Free Game |
| 1009 | PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1010 | PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1011 | PORT_SERVICE_NO_TOGGLE( 0x08, IP_ACTIVE_LOW ) // Setup |
| 1012 | PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1013 | PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1014 | PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1015 | PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1016 | PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1017 | |
| 1018 | PORT_START("DSW") |
| 1019 | PORT_DIPNAME( 0x01, 0x01, "Interlace?" ) |
| 1020 | PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) |
| 1021 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1022 | PORT_DIPNAME( 0x02, 0x02, "Serial?" ) |
| 1023 | PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) |
| 1024 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) // hangs at boot |
| 1025 | PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) |
| 1026 | PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) |
| 1027 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1028 | PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) |
| 1029 | PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) |
| 1030 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1031 | PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) |
| 1032 | PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) |
| 1033 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1034 | PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) |
| 1035 | PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) |
| 1036 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1037 | PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) |
| 1038 | PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) |
| 1039 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1040 | PORT_DIPNAME( 0x80, 0x80, "Touch Screen" ) |
| 1041 | PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) |
| 1042 | PORT_DIPSETTING( 0x00, DEF_STR( On ) ) |
| 1043 | PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNKNOWN ) |
| 1044 | INPUT_PORTS_END |
| 1045 | |
| 1046 | |
896 | 1047 | static MACHINE_CONFIG_START( crystal, crystal_state ) |
897 | 1048 | |
898 | 1049 | MCFG_CPU_ADD("maincpu", SE3208, 43000000) |
r250324 | r250325 | |
937 | 1088 | |
938 | 1089 | MACHINE_CONFIG_END |
939 | 1090 | |
| 1091 | static MACHINE_CONFIG_DERIVED( trivrus, crystal ) |
| 1092 | MCFG_CPU_MODIFY("maincpu") |
| 1093 | MCFG_CPU_PROGRAM_MAP(trivrus_mem) |
| 1094 | |
| 1095 | MCFG_SCREEN_MODIFY("screen") |
| 1096 | MCFG_SCREEN_SIZE(640, 480) |
| 1097 | MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) |
| 1098 | MACHINE_CONFIG_END |
| 1099 | |
| 1100 | |
940 | 1101 | ROM_START( crysbios ) |
941 | 1102 | ROM_REGION( 0x20000, "maincpu", 0 ) // bios |
942 | 1103 | ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(beff39a9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb) ) |
943 | 1104 | |
944 | 1105 | ROM_REGION32_LE( 0x3000000, "user1", ROMREGION_ERASEFF ) // Flash |
945 | 1106 | |
946 | | ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash |
| 1107 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
947 | 1108 | ROM_END |
948 | 1109 | |
949 | 1110 | ROM_START( crysking ) |
r250324 | r250325 | |
955 | 1116 | ROM_LOAD("bcsv0004f02.u2", 0x1000000, 0x1000000, CRC(0e799845) SHA1(419674ce043cb1efb18303f4cb7fdbbae642ee39) ) |
956 | 1117 | ROM_LOAD("bcsv0004f03.u3", 0x2000000, 0x1000000, CRC(659e2d17) SHA1(342c98f3f695ef4dea8b533612451c4d2fb58809) ) |
957 | 1118 | |
958 | | ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash |
| 1119 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
959 | 1120 | ROM_END |
960 | 1121 | |
961 | 1122 | ROM_START( evosocc ) |
r250324 | r250325 | |
967 | 1128 | ROM_LOAD("bcsv0001u02", 0x1000000, 0x1000000, CRC(47ef1794) SHA1(f573706c17d1342b9b7aed9b40b8b648f0bf58db) ) |
968 | 1129 | ROM_LOAD("bcsv0001u03", 0x2000000, 0x1000000, CRC(f396a2ec) SHA1(f305eb10856fb5d4c229a6b09d6a2fb21b24ce66) ) |
969 | 1130 | |
970 | | ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash |
| 1131 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
971 | 1132 | ROM_END |
972 | 1133 | |
973 | 1134 | ROM_START( topbladv ) |
r250324 | r250325 | |
981 | 1142 | ROM_REGION32_LE( 0x3000000, "user1", 0 ) // Flash |
982 | 1143 | ROM_LOAD("flash.u1", 0x0000000, 0x1000000, CRC(bd23f640) SHA1(1d22aa2c828642bb7c1dfea4e13f777f95acc701) ) |
983 | 1144 | |
984 | | ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash |
| 1145 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
985 | 1146 | ROM_END |
986 | 1147 | |
987 | | |
988 | 1148 | ROM_START( officeye ) |
989 | 1149 | ROM_REGION( 0x20000, "maincpu", 0 ) // bios (not the standard one) |
990 | 1150 | ROM_LOAD("bios.u14", 0x000000, 0x020000, CRC(ffc57e90) SHA1(6b6a17fd4798dea9c7b880f3063be8494e7db302) ) |
r250324 | r250325 | |
997 | 1157 | ROM_LOAD("flash.u1", 0x0000000, 0x1000000, CRC(d3f3eec4) SHA1(ea728415bd4906964b7d37f4379a8a3bd42a1c2d) ) |
998 | 1158 | ROM_LOAD("flash.u2", 0x1000000, 0x1000000, CRC(e4f85d0a) SHA1(2ddfa6b3a30e69754aa9d96434ff3d37784bfa57) ) |
999 | 1159 | |
1000 | | ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash |
| 1160 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
1001 | 1161 | ROM_END |
1002 | 1162 | |
1003 | | |
1004 | 1163 | ROM_START( donghaer ) |
1005 | 1164 | ROM_REGION( 0x20000, "maincpu", 0 ) // bios |
1006 | 1165 | ROM_LOAD("mx27l1000.u14", 0x000000, 0x020000, CRC(beff39a9) SHA1(b6f6dda58d9c82273f9422c1bd623411e58982cb)) |
r250324 | r250325 | |
1012 | 1171 | ROM_LOAD( "u1", 0x0000000, 0x1000000, CRC(61217ad7) SHA1(2593f1356aa850f4f9aa5d00bec822aa59c59224) ) |
1013 | 1172 | ROM_LOAD( "u2", 0x1000000, 0x1000000, CRC(6d82f1a5) SHA1(036bd45f0daac1ffeaa5ad9774fc1b56e3c75ff9) ) |
1014 | 1173 | |
1015 | | ROM_REGION( 0x10000, "user2", ROMREGION_ERASEFF ) //Unmapped flash |
| 1174 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
1016 | 1175 | ROM_END |
1017 | 1176 | |
| 1177 | ROM_START( trivrus ) |
| 1178 | ROM_REGION( 0x80000, "maincpu", 0 ) |
| 1179 | ROM_LOAD( "u4", 0x00000, 0x80000, CRC(2d2e9a11) SHA1(73e7b19a032eae21312ca80f8c42cc16725496a7) ) |
| 1180 | |
| 1181 | ROM_REGION32_LE( 0x3000000, "user1", ROMREGION_ERASEFF ) // Flash |
| 1182 | ROM_LOAD( "u3", 0x000000, 0x1000010, CRC(ba901707) SHA1(e281ba07024cd19ef1ab72d2197014f7b1f4d30f) ) |
| 1183 | |
| 1184 | ROM_REGION( 0x1000000, "user2", ROMREGION_ERASEFF ) // Unmapped flash |
| 1185 | ROM_END |
| 1186 | |
| 1187 | |
1018 | 1188 | DRIVER_INIT_MEMBER(crystal_state,crysking) |
1019 | 1189 | { |
1020 | 1190 | UINT16 *Rom = (UINT16*) memregion("user1")->base(); |
r250324 | r250325 | |
1133 | 1303 | } |
1134 | 1304 | |
1135 | 1305 | |
1136 | | GAME( 2001, crysbios, 0, crystal, crystal, driver_device, 0, ROT0, "BrezzaSoft", "Crystal System BIOS", MACHINE_IS_BIOS_ROOT ) |
1137 | | GAME( 2001, crysking, crysbios, crystal, crystal, crystal_state, crysking, ROT0, "BrezzaSoft", "The Crystal of Kings", 0 ) |
1138 | | GAME( 2001, evosocc, crysbios, crystal, crystal, crystal_state, evosocc, ROT0, "Evoga", "Evolution Soccer", 0 ) |
1139 | | GAME( 2003, topbladv, crysbios, topbladv, crystal, crystal_state, topbladv, ROT0, "SonoKong / Expotato", "Top Blade V", 0 ) |
1140 | | GAME( 2001, officeye, 0, crystal, officeye,crystal_state, officeye, ROT0, "Danbi", "Office Yeo In Cheon Ha (version 1.2)", MACHINE_NOT_WORKING ) // still has some instability issues |
1141 | | GAME( 2001, donghaer, 0, crystal, crystal, crystal_state, donghaer, ROT0, "Danbi", "Donggul Donggul Haerong", MACHINE_NOT_WORKING ) |
| 1306 | GAME( 2001, crysbios, 0, crystal, crystal, driver_device, 0, ROT0, "BrezzaSoft", "Crystal System BIOS", MACHINE_IS_BIOS_ROOT ) |
| 1307 | GAME( 2001, crysking, crysbios, crystal, crystal, crystal_state, crysking, ROT0, "BrezzaSoft", "The Crystal of Kings", 0 ) |
| 1308 | GAME( 2001, evosocc, crysbios, crystal, crystal, crystal_state, evosocc, ROT0, "Evoga", "Evolution Soccer", 0 ) |
| 1309 | GAME( 2003, topbladv, crysbios, topbladv, crystal, crystal_state, topbladv, ROT0, "SonoKong / Expotato", "Top Blade V", 0 ) |
| 1310 | GAME( 2001, officeye, 0, crystal, officeye,crystal_state, officeye, ROT0, "Danbi", "Office Yeo In Cheon Ha (version 1.2)", MACHINE_NOT_WORKING ) // still has some instability issues |
| 1311 | GAME( 2001, donghaer, 0, crystal, crystal, crystal_state, donghaer, ROT0, "Danbi", "Donggul Donggul Haerong", MACHINE_NOT_WORKING ) |
| 1312 | GAME( 2009, trivrus, 0, trivrus, trivrus, driver_device, 0, ROT0, "AGT", "Trivia R Us (v1.07)", 0 ) |