diff options
Diffstat (limited to 'sys/alpha/tc/tc.c')
-rw-r--r-- | sys/alpha/tc/tc.c | 688 |
1 files changed, 0 insertions, 688 deletions
diff --git a/sys/alpha/tc/tc.c b/sys/alpha/tc/tc.c deleted file mode 100644 index 39459f4..0000000 --- a/sys/alpha/tc/tc.c +++ /dev/null @@ -1,688 +0,0 @@ -/* $FreeBSD$ */ -/* - * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. - * All rights reserved. - * - * Author: Chris G. Demetriou - * - * Permission to use, copy, modify and distribute this software and - * its documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND - * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include "opt_cpu.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/malloc.h> - -#include <machine/rpb.h> -#include <alpha/tc/tcreg.h> -#include <alpha/tc/tcvar.h> -#include <alpha/tc/tcdevs.h> -#include <alpha/tc/ioasicreg.h> - -/*#include <alpha/tc/dwlpxreg.h>*/ - -#define KV(pa) ALPHA_PHYS_TO_K0SEG(pa) - -static devclass_t tc_devclass; -device_t tc0; /* XXX only one for now */ - -struct tc_softc { - device_t sc_dv; - int sc_speed; - int sc_nslots; - int nbuiltins; - struct tc_builtin *builtins; - struct tc_slotdesc *sc_slots; - void (*sc_intr_establish)(struct device *, void *, - tc_intrlevel_t, int (*)(void *), void *); - void (*sc_intr_disestablish)(struct device *, void *); -/* bus_dma_tag_t (*sc_get_dma_tag)(int); -*/ -}; -#define NTC_ROMOFFS 2 -static tc_offset_t tc_slot_romoffs[NTC_ROMOFFS] = { - TC_SLOT_ROM, - TC_SLOT_PROTOROM, -}; - - -#define TC_SOFTC(dev) (struct tc_softc*) device_get_softc(dev) - -static int tc_probe(device_t dev); -static int tc_attach(device_t dev); -int tc_checkslot( tc_addr_t slotbase, char *namep); - -static device_method_t tc_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, tc_probe), - DEVMETHOD(device_attach, tc_attach), - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - { 0, 0 }, -}; - -static driver_t tc_driver = { - "tc", - tc_methods, - sizeof(struct tc_softc), -}; - -#define C(x) ((void *)(u_long)x) - -int tc_intrnull(void *); -struct tcintr { - int (*tci_func)(void *); - void *tci_arg; -}; - -#ifdef DEC_3000_300 - -void tc_3000_300_intr_setup(void); -void tc_3000_300_intr_establish(struct device *, void *, - tc_intrlevel_t, int (*)(void *), void *); -void tc_3000_300_intr_disestablish(struct device *, void *); -void tc_3000_300_iointr(void *, unsigned long); - - - -#define DEC_3000_300_IOASIC_ADDR KV(0x1a0000000) - -struct tc_slotdesc tc_3000_300_slots[] = { - { KV(0x100000000), C(TC_3000_300_DEV_OPT0), }, /* 0 - opt slot 0 */ - { KV(0x120000000), C(TC_3000_300_DEV_OPT1), }, /* 1 - opt slot 1 */ - { KV(0x180000000), C(TC_3000_300_DEV_BOGUS), }, /* 2 - TCDS ASIC */ - { KV(0x1a0000000), C(TC_3000_300_DEV_BOGUS), }, /* 3 - IOCTL ASIC */ - { KV(0x1c0000000), C(TC_3000_300_DEV_CXTURBO), }, /* 4 - CXTurbo */ -}; -int tc_3000_300_nslots = - sizeof(tc_3000_300_slots) / sizeof(tc_3000_300_slots[0]); - -struct tc_builtin tc_3000_300_builtins[] = { -#ifdef notyet - { "PMAGB-BA", 4, 0x02000000, C(TC_3000_300_DEV_CXTURBO), }, -#endif - { "ioasic", 3, 0x00000000, C(TC_3000_300_DEV_IOASIC), }, - { "tcds", 2, 0x00000000, C(TC_3000_300_DEV_TCDS), }, -}; -int tc_3000_300_nbuiltins = - sizeof(tc_3000_300_builtins) / sizeof(tc_3000_300_builtins[0]); - -struct tcintr tc_3000_300_intr[TC_3000_300_NCOOKIES]; - - -#endif /* DEC_3000_300 */ - -#ifdef DEC_3000_500 -void tc_3000_500_intr_setup(void); -void tc_3000_500_intr_establish(struct device *, void *, - tc_intrlevel_t, int (*)(void *), void *); -void tc_3000_500_intr_disestablish(struct device *, void *); -void tc_3000_500_iointr(void *, unsigned long); - -struct tc_slotdesc tc_3000_500_slots[] = { - { KV(0x100000000), C(TC_3000_500_DEV_OPT0), }, /* 0 - opt slot 0 */ - { KV(0x120000000), C(TC_3000_500_DEV_OPT1), }, /* 1 - opt slot 1 */ - { KV(0x140000000), C(TC_3000_500_DEV_OPT2), }, /* 2 - opt slot 2 */ - { KV(0x160000000), C(TC_3000_500_DEV_OPT3), }, /* 3 - opt slot 3 */ - { KV(0x180000000), C(TC_3000_500_DEV_OPT4), }, /* 4 - opt slot 4 */ - { KV(0x1a0000000), C(TC_3000_500_DEV_OPT5), }, /* 5 - opt slot 5 */ - { KV(0x1c0000000), C(TC_3000_500_DEV_BOGUS), }, /* 6 - TCDS ASIC */ - { KV(0x1e0000000), C(TC_3000_500_DEV_BOGUS), }, /* 7 - IOCTL ASIC */ -}; -int tc_3000_500_nslots = - sizeof(tc_3000_500_slots) / sizeof(tc_3000_500_slots[0]); - -struct tc_builtin tc_3000_500_builtins[] = { - { "ioasic", 7, 0x00000000, C(TC_3000_500_DEV_IOASIC), }, -#ifdef notyet - { "PMAGB-BA", 7, 0x02000000, C(TC_3000_500_DEV_CXTURBO), }, -#endif - { "tcds", 6, 0x00000000, C(TC_3000_500_DEV_TCDS), }, -}; -int tc_3000_500_nbuiltins = sizeof(tc_3000_500_builtins) / - sizeof(tc_3000_500_builtins[0]); - -u_int32_t tc_3000_500_intrbits[TC_3000_500_NCOOKIES] = { - TC_3000_500_IR_OPT0, - TC_3000_500_IR_OPT1, - TC_3000_500_IR_OPT2, - TC_3000_500_IR_OPT3, - TC_3000_500_IR_OPT4, - TC_3000_500_IR_OPT5, - TC_3000_500_IR_TCDS, - TC_3000_500_IR_IOASIC, - TC_3000_500_IR_CXTURBO, -}; - -struct tcintr tc_3000_500_intr[TC_3000_500_NCOOKIES]; - -u_int32_t tc_3000_500_imask; /* intrs we want to ignore; mirrors IMR. */ - - -#endif /* DEC_3000_500 */ - - -#ifdef DEC_3000_300 - -void -tc_3000_300_intr_setup() -{ - volatile u_int32_t *imskp; - u_long i; - - /* - * Disable all interrupts that we can (can't disable builtins). - */ - imskp = (volatile u_int32_t *)IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR); - *imskp &= ~(IOASIC_INTR_300_OPT0 | IOASIC_INTR_300_OPT1); - - /* - * Set up interrupt handlers. - */ - for (i = 0; i < TC_3000_300_NCOOKIES; i++) { - tc_3000_300_intr[i].tci_func = tc_intrnull; - tc_3000_300_intr[i].tci_arg = (void *)i; - } -} - -void -tc_3000_300_intr_establish(tcadev, cookie, level, func, arg) - struct device *tcadev; - void *cookie, *arg; - tc_intrlevel_t level; - int (*func)(void *); -{ - volatile u_int32_t *imskp; - u_long dev = (u_long)cookie; - -#ifdef DIAGNOSTIC - /* XXX bounds-check cookie. */ -#endif - - if (tc_3000_300_intr[dev].tci_func != tc_intrnull) - panic("tc_3000_300_intr_establish: cookie %ld twice", dev); - - tc_3000_300_intr[dev].tci_func = func; - tc_3000_300_intr[dev].tci_arg = arg; - - imskp = (volatile u_int32_t *)IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR); - switch (dev) { - case TC_3000_300_DEV_OPT0: - *imskp |= IOASIC_INTR_300_OPT0; - break; - case TC_3000_300_DEV_OPT1: - *imskp |= IOASIC_INTR_300_OPT1; - break; - default: - /* interrupts for builtins always enabled */ - break; - } -} - -void -tc_3000_300_intr_disestablish(tcadev, cookie) - struct device *tcadev; - void *cookie; -{ - volatile u_int32_t *imskp; - u_long dev = (u_long)cookie; - -#ifdef DIAGNOSTIC - /* XXX bounds-check cookie. */ -#endif - - if (tc_3000_300_intr[dev].tci_func == tc_intrnull) - panic("tc_3000_300_intr_disestablish: cookie %ld bad intr", - dev); - - imskp = (volatile u_int32_t *)IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR); - switch (dev) { - case TC_3000_300_DEV_OPT0: - *imskp &= ~IOASIC_INTR_300_OPT0; - break; - case TC_3000_300_DEV_OPT1: - *imskp &= ~IOASIC_INTR_300_OPT1; - break; - default: - /* interrupts for builtins always enabled */ - break; - } - - tc_3000_300_intr[dev].tci_func = tc_intrnull; - tc_3000_300_intr[dev].tci_arg = (void *)dev; -} - -void -tc_3000_300_iointr(framep, vec) - void *framep; - unsigned long vec; -{ - u_int32_t tcir, ioasicir, ioasicimr; - int ifound; - -#ifdef DIAGNOSTIC - int s; - if (vec != 0x800) - panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec); - s = splhigh(); - if (s != ALPHA_PSL_IPL_IO) - panic("INVALID ASSUMPTION: IPL %d, not %d", s, - ALPHA_PSL_IPL_IO); - splx(s); -#endif - - do { - tc_syncbus(); - - /* find out what interrupts/errors occurred */ - tcir = *(volatile u_int32_t *)TC_3000_300_IR; - ioasicir = *(volatile u_int32_t *) - IOASIC_REG_INTR(DEC_3000_300_IOASIC_ADDR); - ioasicimr = *(volatile u_int32_t *) - IOASIC_REG_IMSK(DEC_3000_300_IOASIC_ADDR); - tc_mb(); - - /* Ignore interrupts that aren't enabled out. */ - ioasicir &= ioasicimr; - - /* clear the interrupts/errors we found. */ - *(volatile u_int32_t *)TC_3000_300_IR = tcir; - /* XXX can't clear TC option slot interrupts here? */ - tc_wmb(); - - ifound = 0; - - -#define CHECKINTR(slot, flag) \ - if (flag) { \ - ifound = 1; \ - (*tc_3000_300_intr[slot].tci_func) \ - (tc_3000_300_intr[slot].tci_arg); \ - } - /* Do them in order of priority; highest slot # first. */ - CHECKINTR(TC_3000_300_DEV_CXTURBO, - tcir & TC_3000_300_IR_CXTURBO); - CHECKINTR(TC_3000_300_DEV_IOASIC, - (tcir & TC_3000_300_IR_IOASIC) && - (ioasicir & ~(IOASIC_INTR_300_OPT1|IOASIC_INTR_300_OPT0))); - CHECKINTR(TC_3000_300_DEV_TCDS, tcir & TC_3000_300_IR_TCDS); - CHECKINTR(TC_3000_300_DEV_OPT1, - ioasicir & IOASIC_INTR_300_OPT1); - CHECKINTR(TC_3000_300_DEV_OPT0, - ioasicir & IOASIC_INTR_300_OPT0); -#undef CHECKINTR - -#ifdef DIAGNOSTIC -#define PRINTINTR(msg, bits) \ - if (tcir & bits) \ - printf(msg); - PRINTINTR("BCache tag parity error\n", - TC_3000_300_IR_BCTAGPARITY); - PRINTINTR("TC overrun error\n", TC_3000_300_IR_TCOVERRUN); - PRINTINTR("TC I/O timeout\n", TC_3000_300_IR_TCTIMEOUT); - PRINTINTR("Bcache parity error\n", - TC_3000_300_IR_BCACHEPARITY); - PRINTINTR("Memory parity error\n", TC_3000_300_IR_MEMPARITY); -#undef PRINTINTR -#endif - } while (ifound); -} - -#endif /* DEC_3000_300 */ - -#ifdef DEC_3000_500 - -void -tc_3000_500_intr_setup() -{ - u_long i; - - /* - * Disable all slot interrupts. Note that this cannot - * actually disable CXTurbo, TCDS, and IOASIC interrupts. - */ - tc_3000_500_imask = *(volatile u_int32_t *)TC_3000_500_IMR_READ; - for (i = 0; i < TC_3000_500_NCOOKIES; i++) - tc_3000_500_imask |= tc_3000_500_intrbits[i]; - *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask; - tc_mb(); - - /* - * Set up interrupt handlers. - */ - for (i = 0; i < TC_3000_500_NCOOKIES; i++) { - tc_3000_500_intr[i].tci_func = tc_intrnull; - tc_3000_500_intr[i].tci_arg = (void *)i; - } -} - -void -tc_3000_500_intr_establish(tcadev, cookie, level, func, arg) - struct device *tcadev; - void *cookie, *arg; - tc_intrlevel_t level; - int (*func)(void *); -{ - u_long dev = (u_long)cookie; - -#ifdef DIAGNOSTIC - /* XXX bounds-check cookie. */ -#endif - - if (tc_3000_500_intr[dev].tci_func != tc_intrnull) - panic("tc_3000_500_intr_establish: cookie %ld twice", dev); - - tc_3000_500_intr[dev].tci_func = func; - tc_3000_500_intr[dev].tci_arg = arg; - - tc_3000_500_imask &= ~tc_3000_500_intrbits[dev]; - *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask; - tc_mb(); -} - -void -tc_3000_500_intr_disestablish(tcadev, cookie) - struct device *tcadev; - void *cookie; -{ - u_long dev = (u_long)cookie; - -#ifdef DIAGNOSTIC - /* XXX bounds-check cookie. */ -#endif - - if (tc_3000_500_intr[dev].tci_func == tc_intrnull) - panic("tc_3000_500_intr_disestablish: cookie %ld bad intr", - dev); - - tc_3000_500_imask |= tc_3000_500_intrbits[dev]; - *(volatile u_int32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask; - tc_mb(); - - tc_3000_500_intr[dev].tci_func = tc_intrnull; - tc_3000_500_intr[dev].tci_arg = (void *)dev; -} - -void -tc_3000_500_iointr(framep, vec) - void *framep; - unsigned long vec; -{ - u_int32_t ir; - int ifound; - -#ifdef DIAGNOSTIC - int s; - if (vec != 0x800) - panic("INVALID ASSUMPTION: vec 0x%lx, not 0x800", vec); - s = splhigh(); - if (s != ALPHA_PSL_IPL_IO) - panic("INVALID ASSUMPTION: IPL %d, not %d", s, - ALPHA_PSL_IPL_IO); - splx(s); -#endif - - do { - tc_syncbus(); - ir = *(volatile u_int32_t *)TC_3000_500_IR_CLEAR; - - /* Ignore interrupts that we haven't enabled. */ - ir &= ~(tc_3000_500_imask & 0x1ff); - - ifound = 0; - -#define CHECKINTR(slot) \ - if (ir & tc_3000_500_intrbits[slot]) { \ - ifound = 1; \ - (*tc_3000_500_intr[slot].tci_func) \ - (tc_3000_500_intr[slot].tci_arg); \ - } - /* Do them in order of priority; highest slot # first. */ - CHECKINTR(TC_3000_500_DEV_CXTURBO); - CHECKINTR(TC_3000_500_DEV_IOASIC); - CHECKINTR(TC_3000_500_DEV_TCDS); - CHECKINTR(TC_3000_500_DEV_OPT5); - CHECKINTR(TC_3000_500_DEV_OPT4); - CHECKINTR(TC_3000_500_DEV_OPT3); - CHECKINTR(TC_3000_500_DEV_OPT2); - CHECKINTR(TC_3000_500_DEV_OPT1); - CHECKINTR(TC_3000_500_DEV_OPT0); -#undef CHECKINTR - -#ifdef DIAGNOSTIC -#define PRINTINTR(msg, bits) \ - if (ir & bits) \ - printf(msg); - PRINTINTR("Second error occurred\n", TC_3000_500_IR_ERR2); - PRINTINTR("DMA buffer error\n", TC_3000_500_IR_DMABE); - PRINTINTR("DMA cross 2K boundary\n", TC_3000_500_IR_DMA2K); - PRINTINTR("TC reset in progress\n", TC_3000_500_IR_TCRESET); - PRINTINTR("TC parity error\n", TC_3000_500_IR_TCPAR); - PRINTINTR("DMA tag error\n", TC_3000_500_IR_DMATAG); - PRINTINTR("Single-bit error\n", TC_3000_500_IR_DMASBE); - PRINTINTR("Double-bit error\n", TC_3000_500_IR_DMADBE); - PRINTINTR("TC I/O timeout\n", TC_3000_500_IR_TCTIMEOUT); - PRINTINTR("DMA block too long\n", TC_3000_500_IR_DMABLOCK); - PRINTINTR("Invalid I/O address\n", TC_3000_500_IR_IOADDR); - PRINTINTR("DMA scatter/gather invalid\n", TC_3000_500_IR_DMASG); - PRINTINTR("Scatter/gather parity error\n", - TC_3000_500_IR_SGPAR); -#undef PRINTINTR -#endif - } while (ifound); -} - -#if 0 -/* - * tc_3000_500_ioslot -- - * Set the PBS bits for devices on the TC. - */ -void -tc_3000_500_ioslot(slot, flags, set) - u_int32_t slot, flags; - int set; -{ - volatile u_int32_t *iosp; - u_int32_t ios; - int s; - - iosp = (volatile u_int32_t *)TC_3000_500_IOSLOT; - ios = *iosp; - flags <<= (slot * 3); - if (set) - ios |= flags; - else - ios &= ~flags; - s = splhigh(); - *iosp = ios; - tc_mb(); - splx(s); -} -#endif - -#endif /* DEC_3000_500 */ - -int -tc_intrnull(val) - void *val; -{ - - panic("tc_intrnull: uncaught TC intr for cookie %ld\n", - (u_long)val); -} - - -static int -tc_probe(device_t dev) -{ - if((hwrpb->rpb_type != ST_DEC_3000_300) && - (hwrpb->rpb_type != ST_DEC_3000_500)) - return ENXIO; - tc0 = dev; - if(hwrpb->rpb_type == ST_DEC_3000_300) { - device_set_desc(dev, "12.5 Mhz Turbochannel Bus"); - } else { - device_set_desc(dev, "25 Mhz Turbochannel Bus"); - - } - return 0; -} - -static int -tc_attach(device_t dev) -{ - struct tc_softc* sc = TC_SOFTC(dev); - tc_addr_t tcaddr; - const struct tc_builtin *builtin; - struct tc_attach_args *ta; - int i; - device_t child = NULL; - - tc0 = dev; - - switch(hwrpb->rpb_type){ -#ifdef DEC_3000_300 - case ST_DEC_3000_300: - sc->sc_speed = TC_SPEED_12_5_MHZ; - sc->sc_nslots = tc_3000_300_nslots; - sc->sc_slots = tc_3000_300_slots; - sc->nbuiltins = tc_3000_300_nbuiltins; - sc->builtins = tc_3000_300_builtins; - tc_3000_300_intr_setup(); - set_iointr(tc_3000_300_iointr); - sc->sc_intr_establish = tc_3000_300_intr_establish; - sc->sc_intr_disestablish = tc_3000_300_intr_disestablish; - break; -#endif /* DEC_3000_500 */ -#ifdef DEC_3000_500 - case ST_DEC_3000_500: - sc->sc_speed = TC_SPEED_25_MHZ; - sc->sc_nslots = tc_3000_500_nslots; - sc->sc_slots = tc_3000_500_slots; - sc->nbuiltins = tc_3000_500_nbuiltins; - sc->builtins = tc_3000_500_builtins; - tc_3000_500_intr_setup(); - set_iointr(tc_3000_500_iointr); - sc->sc_intr_establish = tc_3000_500_intr_establish; - sc->sc_intr_disestablish = tc_3000_500_intr_disestablish; - break; -#endif /* DEC_3000_500 */ - - default: - panic("tcattach: bad cpu type"); - } - /* - * Try to configure each built-in device - */ - - for (i = 0; i < sc->nbuiltins; i++) { - builtin = &sc->builtins[i]; - tcaddr = sc->sc_slots[builtin->tcb_slot].tcs_addr + - builtin->tcb_offset; - if (tc_badaddr(tcaddr)) - continue; - ta = malloc(sizeof(struct tc_attach_args), M_DEVBUF, M_NOWAIT); - if (!ta) - continue; - ta->ta_slot = builtin->tcb_slot; - ta->ta_offset = builtin->tcb_offset; - ta->ta_addr = tcaddr; - ta->ta_cookie = builtin->tcb_cookie; - ta->ta_busspeed = sc->sc_speed; - - child = device_add_child(dev, builtin->tcb_modname, 0); - device_set_ivars(child, ta); - device_probe_and_attach(child); - } - - return 0; -} - - -int -tc_checkslot(slotbase, namep) - tc_addr_t slotbase; - char *namep; -{ - struct tc_rommap *romp; - int i, j; - - for (i = 0; i < NTC_ROMOFFS; i++) { - romp = (struct tc_rommap *) - (slotbase + tc_slot_romoffs[i]); - - switch (romp->tcr_width.v) { - case 1: - case 2: - case 4: - break; - - default: - continue; - } - - if (romp->tcr_stride.v != 4) - continue; - - for (j = 0; j < 4; j++) - if (romp->tcr_test[j+0*romp->tcr_stride.v] != 0x55 || - romp->tcr_test[j+1*romp->tcr_stride.v] != 0x00 || - romp->tcr_test[j+2*romp->tcr_stride.v] != 0xaa || - romp->tcr_test[j+3*romp->tcr_stride.v] != 0xff) - continue; - - for (j = 0; j < TC_ROM_LLEN; j++) - namep[j] = romp->tcr_modname[j].v; - namep[j] = '\0'; - return (1); - } - return (0); -} - -void -tc_intr_establish(dev, cookie, level, handler, arg) - struct device *dev; - void *cookie, *arg; - tc_intrlevel_t level; - int (*handler)(void *); -{ - struct tc_softc *sc = (struct tc_softc *)device_get_softc(dev); - - (*sc->sc_intr_establish)(device_get_parent(dev), cookie, level, - handler, arg); -} - -void -tc_intr_disestablish(dev, cookie) - struct device *dev; - void *cookie; -{ - struct tc_softc *sc = (struct tc_softc *)device_get_softc(dev); - - (*sc->sc_intr_disestablish)(device_get_parent(dev), cookie); -} - -DRIVER_MODULE(tc, tcasic, tc_driver, tc_devclass, 0, 0); - |