diff options
Diffstat (limited to 'src/devices/bus/isa/sb16.cpp')
-rw-r--r-- | src/devices/bus/isa/sb16.cpp | 205 |
1 files changed, 113 insertions, 92 deletions
diff --git a/src/devices/bus/isa/sb16.cpp b/src/devices/bus/isa/sb16.cpp index 6bce4b4198c..b260edca7b9 100644 --- a/src/devices/bus/isa/sb16.cpp +++ b/src/devices/bus/isa/sb16.cpp @@ -14,7 +14,7 @@ DEFINE_DEVICE_TYPE(ISA16_SB16, sb16_lle_device, "sb16", "SoundBlaster 16 Audio Adapter LLE") -READ8_MEMBER( sb16_lle_device::dsp_data_r ) +uint8_t sb16_lle_device::dsp_data_r() { if(!machine().side_effects_disabled()) m_data_in = false; @@ -22,18 +22,18 @@ READ8_MEMBER( sb16_lle_device::dsp_data_r ) return m_in_byte; } -WRITE8_MEMBER( sb16_lle_device::dsp_data_w ) +void sb16_lle_device::dsp_data_w(uint8_t data) { m_data_out = true; m_out_byte = data; } -READ8_MEMBER( sb16_lle_device::dac_ctrl_r ) +uint8_t sb16_lle_device::dac_ctrl_r() { return 0; } -WRITE8_MEMBER( sb16_lle_device::dac_ctrl_w ) +void sb16_lle_device::dac_ctrl_w(uint8_t data) { /* port 0x05 * bit0 - @@ -52,18 +52,18 @@ WRITE8_MEMBER( sb16_lle_device::dac_ctrl_w ) } } -READ8_MEMBER( sb16_lle_device::adc_data_r ) +uint8_t sb16_lle_device::adc_data_r() { return 0; } -WRITE8_MEMBER( sb16_lle_device::dac_data_w ) +void sb16_lle_device::dac_data_w(uint8_t data) { m_ldac->write(data << 8); m_rdac->write(data << 8); } -READ8_MEMBER( sb16_lle_device::p1_r ) +uint8_t sb16_lle_device::p1_r() { uint8_t ret = 0; ret |= m_data_out << 0; @@ -71,7 +71,7 @@ READ8_MEMBER( sb16_lle_device::p1_r ) return ret; } -WRITE8_MEMBER( sb16_lle_device::p1_w ) +void sb16_lle_device::p1_w(uint8_t data) { /* port P1 * bit0 - output byte ready @@ -85,12 +85,12 @@ WRITE8_MEMBER( sb16_lle_device::p1_w ) */ } -READ8_MEMBER( sb16_lle_device::p2_r ) +uint8_t sb16_lle_device::p2_r() { return 0; } -WRITE8_MEMBER( sb16_lle_device::p2_w ) +void sb16_lle_device::p2_w(uint8_t data) { /* port P2 * bit0 - @@ -115,25 +115,25 @@ void sb16_lle_device::control_timer(bool start) m_timer->adjust(attotime::never); } -WRITE8_MEMBER( sb16_lle_device::rate_w ) +void sb16_lle_device::rate_w(uint8_t data) { m_freq = data; if(!(m_ctrl8 & 2) || !(m_ctrl16 & 2)) control_timer(true); } -READ8_MEMBER( sb16_lle_device::dma8_r ) +uint8_t sb16_lle_device::dma8_r() { return m_dac_fifo[0].b[0]; } -WRITE8_MEMBER( sb16_lle_device::dma8_w ) +void sb16_lle_device::dma8_w(uint8_t data) { m_adc_fifo[0].b[0] = data; m_isa->drq1_w(0); } -READ8_MEMBER( sb16_lle_device::dma_stat_r ) +uint8_t sb16_lle_device::dma_stat_r() { /* port 0x06 * bit0 - 8 bit complete @@ -149,12 +149,12 @@ READ8_MEMBER( sb16_lle_device::dma_stat_r ) return ret; } -READ8_MEMBER( sb16_lle_device::ctrl8_r ) +uint8_t sb16_lle_device::ctrl8_r() { return m_ctrl8; } -WRITE8_MEMBER( sb16_lle_device::ctrl8_w ) +void sb16_lle_device::ctrl8_w(uint8_t data) { /* port 0x08 * bit0 - ? @@ -163,12 +163,15 @@ WRITE8_MEMBER( sb16_lle_device::ctrl8_w ) * bit3 - * bit4 - * bit5 - - * bit6 - ? + * bit6 - ? (wolf3d) * bit7 - toggle for 8bit irq */ if(data & 4) { m_dma8_cnt = m_dma8_len; + if (!(BIT(m_mode, 6))) + m_dma8_cnt >>= 1; + m_dma8_cnt ++; m_dma8_done = false; } if(!(data & 2) || !(m_ctrl16 & 2)) @@ -190,12 +193,12 @@ WRITE8_MEMBER( sb16_lle_device::ctrl8_w ) m_ctrl8 = data; } -READ8_MEMBER( sb16_lle_device::ctrl16_r ) +uint8_t sb16_lle_device::ctrl16_r() { return m_ctrl16; } -WRITE8_MEMBER( sb16_lle_device::ctrl16_w ) +void sb16_lle_device::ctrl16_w(uint8_t data) { /* port 0x10 * bit0 - @@ -210,6 +213,9 @@ WRITE8_MEMBER( sb16_lle_device::ctrl16_w ) if(data & 4) { m_dma16_cnt = m_dma16_len; + if (!(BIT(m_mode, 7))) + m_dma16_cnt >>= 1; + m_dma16_cnt ++; m_dma16_done = false; } if(!(data & 2) || !(m_ctrl8 & 2)) @@ -231,16 +237,16 @@ WRITE8_MEMBER( sb16_lle_device::ctrl16_w ) m_ctrl16 = data; } -READ8_MEMBER( sb16_lle_device::dac_fifo_ctrl_r ) +uint8_t sb16_lle_device::dac_fifo_ctrl_r() { return m_dac_fifo_ctrl; } -WRITE8_MEMBER( sb16_lle_device::dac_fifo_ctrl_w ) +void sb16_lle_device::dac_fifo_ctrl_w(uint8_t data) { /* port 0x0E * bit0 - reset fifo - * bit1 - ? + * bit1 - DAC output sw off? * bit2 - disable fifo * bit3 - * bit4 - @@ -255,15 +261,16 @@ WRITE8_MEMBER( sb16_lle_device::dac_fifo_ctrl_w ) m_dac_r = false; m_dac_h = false; } + m_mixer->dac_speaker_off_cb(BIT(data, 1)); m_dac_fifo_ctrl = data; } -READ8_MEMBER( sb16_lle_device::adc_fifo_ctrl_r ) +uint8_t sb16_lle_device::adc_fifo_ctrl_r() { return m_adc_fifo_ctrl; } -WRITE8_MEMBER( sb16_lle_device::adc_fifo_ctrl_w ) +void sb16_lle_device::adc_fifo_ctrl_w(uint8_t data) { /* port 0x16 * bit0 - reset fifo @@ -285,12 +292,12 @@ WRITE8_MEMBER( sb16_lle_device::adc_fifo_ctrl_w ) m_adc_fifo_ctrl = data; } -READ8_MEMBER( sb16_lle_device::mode_r ) +uint8_t sb16_lle_device::mode_r() { return m_mode; } -WRITE8_MEMBER( sb16_lle_device::mode_w ) +void sb16_lle_device::mode_w(uint8_t data) { /* port 0x04 * bit0 - 1 -- dac 16, adc 8; 0 -- adc 16, dac 8 @@ -305,7 +312,7 @@ WRITE8_MEMBER( sb16_lle_device::mode_w ) m_mode = data; } -READ8_MEMBER( sb16_lle_device::dma8_ready_r ) +uint8_t sb16_lle_device::dma8_ready_r() { /* port 0x0F * bit0 - @@ -320,7 +327,7 @@ READ8_MEMBER( sb16_lle_device::dma8_ready_r ) return ((m_dac_fifo_tail - m_dac_fifo_head) != 1) << 6; } -READ8_MEMBER( sb16_lle_device::adc_data_ready_r ) +uint8_t sb16_lle_device::adc_data_ready_r() { /* port 0x17 * bit0 - @@ -335,32 +342,32 @@ READ8_MEMBER( sb16_lle_device::adc_data_ready_r ) return (m_mode & 1) ? 0x80 : 0; } -READ8_MEMBER( sb16_lle_device::dma8_cnt_lo_r ) +uint8_t sb16_lle_device::dma8_cnt_lo_r() { return m_dma8_cnt & 0xff; } -READ8_MEMBER( sb16_lle_device::dma8_cnt_hi_r ) +uint8_t sb16_lle_device::dma8_cnt_hi_r() { return m_dma8_cnt >> 8; } -WRITE8_MEMBER( sb16_lle_device::dma8_len_lo_w ) +void sb16_lle_device::dma8_len_lo_w(uint8_t data) { m_dma8_len = (m_dma8_len & 0xff00) | data; } -WRITE8_MEMBER( sb16_lle_device::dma8_len_hi_w ) +void sb16_lle_device::dma8_len_hi_w(uint8_t data) { m_dma8_len = (m_dma8_len & 0xff) | (data << 8); } -WRITE8_MEMBER( sb16_lle_device::dma16_len_lo_w ) +void sb16_lle_device::dma16_len_lo_w(uint8_t data) { m_dma16_len = (m_dma16_len & 0xff00) | data; } -WRITE8_MEMBER( sb16_lle_device::dma16_len_hi_w ) +void sb16_lle_device::dma16_len_hi_w(uint8_t data) { m_dma16_len = (m_dma16_len & 0xff) | (data << 8); } @@ -376,12 +383,12 @@ ROM_END void sb16_lle_device::sb16_io(address_map &map) { map(0x0000, 0x0000).mirror(0xff00).rw(FUNC(sb16_lle_device::dsp_data_r), FUNC(sb16_lle_device::dsp_data_w)); -// AM_RANGE(0x0001, 0x0001) // MIDI related? -// AM_RANGE(0x0002, 0x0002) +// map(0x0001, 0x0001) // MIDI related? +// map(0x0002, 0x0002) map(0x0004, 0x0004).mirror(0xff00).rw(FUNC(sb16_lle_device::mode_r), FUNC(sb16_lle_device::mode_w)); map(0x0005, 0x0005).mirror(0xff00).rw(FUNC(sb16_lle_device::dac_ctrl_r), FUNC(sb16_lle_device::dac_ctrl_w)); map(0x0006, 0x0006).mirror(0xff00).r(FUNC(sb16_lle_device::dma_stat_r)); -// AM_RANGE(0x0007, 0x0007) // unknown +// map(0x0007, 0x0007) // unknown, readback status of stereo f/f? map(0x0008, 0x0008).mirror(0xff00).rw(FUNC(sb16_lle_device::ctrl8_r), FUNC(sb16_lle_device::ctrl8_w)); map(0x0009, 0x0009).mirror(0xff00).w(FUNC(sb16_lle_device::rate_w)); map(0x000A, 0x000A).mirror(0xff00).r(FUNC(sb16_lle_device::dma8_cnt_lo_r)); @@ -399,9 +406,18 @@ void sb16_lle_device::sb16_io(address_map &map) map(0x001B, 0x001B).mirror(0xff00).r(FUNC(sb16_lle_device::adc_data_r)); map(0x001D, 0x001D).mirror(0xff00).w(FUNC(sb16_lle_device::dma8_w)); map(0x001F, 0x001F).mirror(0xff00).r(FUNC(sb16_lle_device::dma8_r)); -// AM_RANGE(0x0080, 0x0080) // ASP comms -// AM_RANGE(0x0081, 0x0081) -// AM_RANGE(0x0082, 0x0082) +// map(0x0080, 0x0080) // ASP comms +// map(0x0081, 0x0081) +// map(0x0082, 0x0082) +} + +void sb16_lle_device::host_io(address_map &map) +{ + map(0x4, 0x5).rw(m_mixer, FUNC(ct1745_mixer_device::read), FUNC(ct1745_mixer_device::write)); + map(0x6, 0x7).w(FUNC(sb16_lle_device::dsp_reset_w)); + map(0xa, 0xb).r(FUNC(sb16_lle_device::host_data_r)); + map(0xc, 0xd).rw(FUNC(sb16_lle_device::dsp_wbuf_status_r), FUNC(sb16_lle_device::host_cmd_w)); + map(0xe, 0xf).r(FUNC(sb16_lle_device::dsp_rbuf_status_r)); } const tiny_rom_entry *sb16_lle_device::device_rom_region() const @@ -418,27 +434,38 @@ void sb16_lle_device::device_add_mconfig(machine_config &config) m_cpu->port_in_cb<2>().set(FUNC(sb16_lle_device::p2_r)); m_cpu->port_out_cb<2>().set(FUNC(sb16_lle_device::p2_w)); - SPEAKER(config, "lspeaker").front_left(); - SPEAKER(config, "rspeaker").front_right(); - ymf262_device &ymf262(YMF262(config, "ymf262", XTAL(14'318'181))); - ymf262.add_route(0, "lspeaker", 1.00); - ymf262.add_route(1, "rspeaker", 1.00); - ymf262.add_route(2, "lspeaker", 1.00); - ymf262.add_route(3, "rspeaker", 1.00); + SPEAKER(config, "speaker", 2).front(); + + CT1745(config, m_mixer); + m_mixer->set_fm_tag("ymf262"); + m_mixer->set_ldac_tag(m_ldac); + m_mixer->set_rdac_tag(m_rdac); + m_mixer->add_route(0, "speaker", 1.0, 0); + m_mixer->add_route(1, "speaker", 1.0, 1); + m_mixer->irq_status_cb().set([this] () { + return (m_irq8 << 0) | (m_irq16 << 1) | (m_irq_midi << 2) | (0x8 << 4); + }); - DAC_16BIT_R2R(config, m_ldac, 0).add_route(ALL_OUTPUTS, "lspeaker", 0.5); // unknown DAC - DAC_16BIT_R2R(config, m_rdac, 0).add_route(ALL_OUTPUTS, "rspeaker", 0.5); // unknown DAC + DAC_16BIT_R2R(config, m_ldac, 0).add_route(ALL_OUTPUTS, m_mixer, 0.5, 0); // unknown DAC + DAC_16BIT_R2R(config, m_rdac, 0).add_route(ALL_OUTPUTS, m_mixer, 0.5, 1); // unknown DAC + + ymf262_device &ymf262(YMF262(config, "ymf262", XTAL(14'318'181))); + ymf262.add_route(0, m_mixer, 1.00, 0); + ymf262.add_route(1, m_mixer, 1.00, 1); + ymf262.add_route(2, m_mixer, 1.00, 0); + ymf262.add_route(3, m_mixer, 1.00, 1); PC_JOY(config, m_joy); } -READ8_MEMBER( sb16_lle_device::host_data_r ) +uint8_t sb16_lle_device::host_data_r() { - m_data_out = false; + if (!machine().side_effects_disabled()) + m_data_out = false; return m_out_byte; } -WRITE8_MEMBER( sb16_lle_device::host_cmd_w ) +void sb16_lle_device::host_cmd_w(uint8_t data) { m_data_in = true; m_in_byte = data; @@ -474,7 +501,7 @@ uint8_t sb16_lle_device::dack_r(int line) return ret; } - ++m_adc_fifo_tail %= 16; + ++m_adc_fifo_tail %= FIFO_SIZE; if(m_adc_fifo_ctrl & 4) { @@ -482,7 +509,7 @@ uint8_t sb16_lle_device::dack_r(int line) return ret; } - if(m_adc_fifo_head == ((m_adc_fifo_tail + 1) % 16)) + if(m_adc_fifo_head == ((m_adc_fifo_tail + 1) % FIFO_SIZE)) m_isa->drq1_w(0); return ret; } @@ -517,7 +544,7 @@ void sb16_lle_device::dack_w(int line, uint8_t data) return; } - ++m_dac_fifo_head %= 16; + ++m_dac_fifo_head %= FIFO_SIZE; if(m_dac_fifo_ctrl & 4) { @@ -551,7 +578,7 @@ uint16_t sb16_lle_device::dack16_r(int line) m_isa->drq5_w(0); return ret; } - ++m_adc_fifo_tail %= 16; + ++m_adc_fifo_tail %= FIFO_SIZE; if(m_adc_fifo_ctrl & 4) { @@ -559,7 +586,7 @@ uint16_t sb16_lle_device::dack16_r(int line) return ret; } - if(m_adc_fifo_head == ((m_adc_fifo_tail + 1) % 16)) + if(m_adc_fifo_head == ((m_adc_fifo_tail + 1) % FIFO_SIZE)) m_isa->drq5_w(0); return ret; } @@ -586,7 +613,7 @@ void sb16_lle_device::dack16_w(int line, uint16_t data) m_isa->drq5_w(0); return; } - ++m_dac_fifo_head %= 16; + ++m_dac_fifo_head %= FIFO_SIZE; if(m_dac_fifo_ctrl & 4) { @@ -598,7 +625,7 @@ void sb16_lle_device::dack16_w(int line, uint16_t data) m_isa->drq5_w(0); } -WRITE8_MEMBER( sb16_lle_device::dsp_reset_w ) +void sb16_lle_device::dsp_reset_w(uint8_t data) { if(data & 1) { @@ -607,39 +634,34 @@ WRITE8_MEMBER( sb16_lle_device::dsp_reset_w ) } } -READ8_MEMBER( sb16_lle_device::dsp_wbuf_status_r ) +uint8_t sb16_lle_device::dsp_wbuf_status_r(offs_t offset) { if(offset) return 0xff; return m_data_in << 7; } -READ8_MEMBER( sb16_lle_device::dsp_rbuf_status_r ) +uint8_t sb16_lle_device::dsp_rbuf_status_r(offs_t offset) { if(offset) { - m_irq16 = false; - m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + if(!machine().side_effects_disabled()) + { + m_irq16 = false; + m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + } return 0xff; } - m_irq8 = false; - m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + if(!machine().side_effects_disabled()) + { + m_irq8 = false; + m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + } return m_data_out << 7; } -WRITE8_MEMBER( sb16_lle_device::invalid_w ) -{ - logerror("sb16: invalid port write\n"); -} - -READ8_MEMBER( sb16_lle_device::invalid_r ) -{ - logerror("sb16: invalid port read\n"); - return 0xff; -} - // just using the old dummy mpu401 for now -READ8_MEMBER( sb16_lle_device::mpu401_r ) +uint8_t sb16_lle_device::mpu401_r(offs_t offset) { uint8_t res; @@ -658,7 +680,7 @@ READ8_MEMBER( sb16_lle_device::mpu401_r ) return res; } -WRITE8_MEMBER( sb16_lle_device::mpu401_w ) +void sb16_lle_device::mpu401_w(offs_t offset, uint8_t data) { if(offset == 0) // data { @@ -683,6 +705,7 @@ WRITE8_MEMBER( sb16_lle_device::mpu401_w ) sb16_lle_device::sb16_lle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, ISA16_SB16, tag, owner, clock), device_isa16_card_interface(mconfig, *this), + m_mixer(*this, "mixer"), m_ldac(*this, "ldac"), m_rdac(*this, "rdac"), m_joy(*this, "pc_joy"), @@ -702,21 +725,18 @@ void sb16_lle_device::device_start() rom[i] = rom[i] ^ xor_table[i & 0x3f]; - ymf262_device *ymf262 = subdevice<ymf262_device>("ymf262"); + ymf262_device &ymf262 = *subdevice<ymf262_device>("ymf262"); set_isa_device(); - m_isa->install_device(0x0200, 0x0207, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice<pc_joy_device>("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice<pc_joy_device>("pc_joy"))); - m_isa->install_device(0x0226, 0x0227, read8_delegate(FUNC(sb16_lle_device::invalid_r), this), write8_delegate(FUNC(sb16_lle_device::dsp_reset_w), this)); - m_isa->install_device(0x022a, 0x022b, read8_delegate(FUNC(sb16_lle_device::host_data_r), this), write8_delegate(FUNC(sb16_lle_device::invalid_w), this) ); - m_isa->install_device(0x022c, 0x022d, read8_delegate(FUNC(sb16_lle_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb16_lle_device::host_cmd_w), this) ); - m_isa->install_device(0x022e, 0x022f, read8_delegate(FUNC(sb16_lle_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb16_lle_device::invalid_w), this) ); - m_isa->install_device(0x0330, 0x0331, read8_delegate(FUNC(sb16_lle_device::mpu401_r), this), write8_delegate(FUNC(sb16_lle_device::mpu401_w), this)); - m_isa->install_device(0x0388, 0x0389, read8sm_delegate(FUNC(ymf262_device::read), ymf262), write8sm_delegate(FUNC(ymf262_device::write), ymf262)); - m_isa->install_device(0x0220, 0x0223, read8sm_delegate(FUNC(ymf262_device::read), ymf262), write8sm_delegate(FUNC(ymf262_device::write), ymf262)); - m_isa->install_device(0x0228, 0x0229, read8sm_delegate(FUNC(ymf262_device::read), ymf262), write8sm_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0200, 0x0207, read8smo_delegate(*subdevice<pc_joy_device>("pc_joy"), FUNC(pc_joy_device::joy_port_r)), write8smo_delegate(*subdevice<pc_joy_device>("pc_joy"), FUNC(pc_joy_device::joy_port_w))); + m_isa->install_device(0x0220, 0x022f, *this, &sb16_lle_device::host_io); + m_isa->install_device(0x0330, 0x0331, read8sm_delegate(*this, FUNC(sb16_lle_device::mpu401_r)), write8sm_delegate(*this, FUNC(sb16_lle_device::mpu401_w))); + m_isa->install_device(0x0388, 0x038b, read8sm_delegate(ymf262, FUNC(ymf262_device::read)), write8sm_delegate(ymf262, FUNC(ymf262_device::write))); + m_isa->install_device(0x0220, 0x0223, read8sm_delegate(ymf262, FUNC(ymf262_device::read)), write8sm_delegate(ymf262, FUNC(ymf262_device::write))); + m_isa->install_device(0x0228, 0x0229, read8sm_delegate(ymf262, FUNC(ymf262_device::read)), write8sm_delegate(ymf262, FUNC(ymf262_device::write))); m_isa->set_dma_channel(1, this, false); m_isa->set_dma_channel(5, this, false); - m_timer = timer_alloc(); + m_timer = timer_alloc(FUNC(sb16_lle_device::timer_tick), this); } @@ -741,7 +761,7 @@ void sb16_lle_device::device_reset() m_dma8_done = m_dma16_done = false; } -void sb16_lle_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +TIMER_CALLBACK_MEMBER(sb16_lle_device::timer_tick) { uint16_t dacl = 0, dacr = 0, adcl = 0, adcr = 0; if(m_mode & 2) @@ -751,6 +771,7 @@ void sb16_lle_device::device_timer(emu_timer &timer, device_timer_id tid, int pa m_cpu->set_input_line(MCS51_INT0_LINE, ASSERT_LINE); return; } + if(m_mode & 1) { switch(m_mode & 0xa0) // dac 16 @@ -843,12 +864,12 @@ void sb16_lle_device::device_timer(emu_timer &timer, device_timer_id tid, int pa m_isa->drq5_w(1); if((!(m_ctrl8 & 2) && !(m_mode & 1)) || (!(m_ctrl16 & 2) && (m_mode & 1))) - ++m_dac_fifo_tail %= 16; + ++m_dac_fifo_tail %= FIFO_SIZE; if((!(m_ctrl8 & 2) && (m_mode & 1)) || (!(m_ctrl16 & 2) && !(m_mode & 1))) { m_adc_fifo[m_adc_fifo_head].h[0] = adcl; m_adc_fifo[m_adc_fifo_head].h[1] = adcr; - ++m_adc_fifo_head %= 16; + ++m_adc_fifo_head %= FIFO_SIZE; } } |