trunk/src/emu/bus/ieee488/c2040fdc.c
| r242307 | r242308 | |
| 9 | 9 | |
| 10 | 10 | **********************************************************************/ |
| 11 | 11 | |
| 12 | | /* |
| 13 | | |
| 14 | | TODO: |
| 15 | | |
| 16 | | - writing starts in the middle of a byte |
| 17 | | - 8050 PLL |
| 18 | | |
| 19 | | */ |
| 20 | | |
| 21 | 12 | #include "c2040fdc.h" |
| 22 | 13 | |
| 23 | 14 | |
| r242307 | r242308 | |
| 35 | 26 | //************************************************************************** |
| 36 | 27 | |
| 37 | 28 | const device_type C2040_FDC = &device_creator<c2040_fdc_t>; |
| 38 | | const device_type C8050_FDC = &device_creator<c8050_fdc_t>; |
| 39 | 29 | |
| 40 | 30 | |
| 41 | 31 | //------------------------------------------------- |
| r242307 | r242308 | |
| 67 | 57 | // c2040_fdc_t - constructor |
| 68 | 58 | //------------------------------------------------- |
| 69 | 59 | |
| 70 | | c2040_fdc_t::c2040_fdc_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : |
| 71 | | device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), |
| 72 | | m_write_sync(*this), |
| 73 | | m_write_ready(*this), |
| 74 | | m_write_error(*this), |
| 75 | | m_gcr_rom(*this, "gcr"), |
| 76 | | m_floppy0(NULL), |
| 77 | | m_floppy1(NULL), |
| 78 | | m_mtr0(1), |
| 79 | | m_mtr1(1), |
| 80 | | m_stp0(0), |
| 81 | | m_stp1(0), |
| 82 | | m_ds(0), |
| 83 | | m_drv_sel(0), |
| 84 | | m_mode_sel(0), |
| 85 | | m_rw_sel(0), |
| 86 | | m_period(attotime::from_hz(clock)) |
| 87 | | { |
| 88 | | cur_live.tm = attotime::never; |
| 89 | | cur_live.state = IDLE; |
| 90 | | cur_live.next_state = -1; |
| 91 | | cur_live.write_position = 0; |
| 92 | | cur_live.write_start_time = attotime::never; |
| 93 | | } |
| 94 | | |
| 95 | 60 | c2040_fdc_t::c2040_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 96 | 61 | device_t(mconfig, C2040_FDC, "C2040 FDC", tag, owner, clock, "c2040fdc", __FILE__), |
| 97 | 62 | m_write_sync(*this), |
| r242307 | r242308 | |
| 118 | 83 | cur_live.drv_sel = m_drv_sel; |
| 119 | 84 | } |
| 120 | 85 | |
| 121 | | c8050_fdc_t::c8050_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 122 | | c2040_fdc_t(mconfig, C8050_FDC, "C8050 FDC", tag, owner, clock, "c8050fdc", __FILE__) { } |
| 123 | 86 | |
| 124 | 87 | |
| 125 | | |
| 126 | 88 | //------------------------------------------------- |
| 127 | 89 | // device_start - device-specific startup |
| 128 | 90 | //------------------------------------------------- |
| r242307 | r242308 | |
| 635 | 597 | m_floppy0 = floppy0; |
| 636 | 598 | m_floppy1 = floppy1; |
| 637 | 599 | } |
| 638 | | |
| 639 | | void c8050_fdc_t::live_start() |
| 640 | | { |
| 641 | | cur_live.tm = machine().time(); |
| 642 | | cur_live.state = RUNNING; |
| 643 | | cur_live.next_state = -1; |
| 644 | | |
| 645 | | cur_live.shift_reg = 0; |
| 646 | | cur_live.shift_reg_write = 0; |
| 647 | | cur_live.cycle_counter = 0; |
| 648 | | cur_live.cell_counter = 0; |
| 649 | | cur_live.bit_counter = 0; |
| 650 | | cur_live.ds = m_ds; |
| 651 | | cur_live.drv_sel = m_drv_sel; |
| 652 | | cur_live.mode_sel = m_mode_sel; |
| 653 | | cur_live.rw_sel = m_rw_sel; |
| 654 | | cur_live.pi = m_pi; |
| 655 | | |
| 656 | | pll_reset(cur_live.tm, attotime::from_double(0)); |
| 657 | | checkpoint_live = cur_live; |
| 658 | | pll_save_checkpoint(); |
| 659 | | |
| 660 | | live_run(); |
| 661 | | } |
| 662 | | |
| 663 | | void c8050_fdc_t::pll_reset(const attotime &when, const attotime clock) |
| 664 | | { |
| 665 | | cur_pll.reset(when); |
| 666 | | cur_pll.set_clock(clock); |
| 667 | | } |
| 668 | | |
| 669 | | void c8050_fdc_t::pll_save_checkpoint() |
| 670 | | { |
| 671 | | checkpoint_pll = cur_pll; |
| 672 | | } |
| 673 | | |
| 674 | | void c8050_fdc_t::pll_retrieve_checkpoint() |
| 675 | | { |
| 676 | | cur_pll = checkpoint_pll; |
| 677 | | } |
| 678 | | |
| 679 | | void c8050_fdc_t::checkpoint() |
| 680 | | { |
| 681 | | checkpoint_live = cur_live; |
| 682 | | pll_save_checkpoint(); |
| 683 | | } |
| 684 | | |
| 685 | | void c8050_fdc_t::rollback() |
| 686 | | { |
| 687 | | cur_live = checkpoint_live; |
| 688 | | pll_retrieve_checkpoint(); |
| 689 | | } |
| 690 | | |
| 691 | | void c8050_fdc_t::live_run(const attotime &limit) |
| 692 | | { |
| 693 | | if(cur_live.state == IDLE || cur_live.next_state != -1) |
| 694 | | return; |
| 695 | | |
| 696 | | for(;;) { |
| 697 | | switch(cur_live.state) { |
| 698 | | case RUNNING: { |
| 699 | | bool syncpoint = false; |
| 700 | | |
| 701 | | if (cur_live.tm > limit) |
| 702 | | return; |
| 703 | | |
| 704 | | int bit = get_next_bit(cur_live.tm, limit); |
| 705 | | if(bit < 0) |
| 706 | | return; |
| 707 | | |
| 708 | | if (syncpoint) { |
| 709 | | commit(cur_live.tm); |
| 710 | | |
| 711 | | cur_live.tm += m_period; |
| 712 | | live_delay(RUNNING_SYNCPOINT); |
| 713 | | return; |
| 714 | | } |
| 715 | | |
| 716 | | cur_live.tm += m_period; |
| 717 | | break; |
| 718 | | } |
| 719 | | |
| 720 | | case RUNNING_SYNCPOINT: { |
| 721 | | m_write_ready(cur_live.ready); |
| 722 | | m_write_sync(cur_live.sync); |
| 723 | | m_write_error(cur_live.error); |
| 724 | | |
| 725 | | cur_live.state = RUNNING; |
| 726 | | checkpoint(); |
| 727 | | break; |
| 728 | | } |
| 729 | | } |
| 730 | | } |
| 731 | | } |
| 732 | | |
| 733 | | int c8050_fdc_t::get_next_bit(attotime &tm, const attotime &limit) |
| 734 | | { |
| 735 | | return cur_pll.get_next_bit(tm, get_floppy(), limit); |
| 736 | | } |
| 737 | | |
| 738 | | void c8050_fdc_t::stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp) |
| 739 | | { |
| 740 | | if (mtr) return; |
| 741 | | |
| 742 | | int tracks = 0; |
| 743 | | |
| 744 | | switch (old_stp) |
| 745 | | { |
| 746 | | case 0: if (stp == 1) tracks++; else if (stp == 2) tracks--; break; |
| 747 | | case 1: if (stp == 3) tracks++; else if (stp == 0) tracks--; break; |
| 748 | | case 2: if (stp == 0) tracks++; else if (stp == 3) tracks--; break; |
| 749 | | case 3: if (stp == 2) tracks++; else if (stp == 1) tracks--; break; |
| 750 | | } |
| 751 | | |
| 752 | | if (tracks == -1) |
| 753 | | { |
| 754 | | floppy->dir_w(1); |
| 755 | | floppy->stp_w(1); |
| 756 | | floppy->stp_w(0); |
| 757 | | } |
| 758 | | else if (tracks == 1) |
| 759 | | { |
| 760 | | floppy->dir_w(0); |
| 761 | | floppy->stp_w(1); |
| 762 | | floppy->stp_w(0); |
| 763 | | } |
| 764 | | |
| 765 | | old_stp = stp; |
| 766 | | } |
| 767 | | |
| 768 | | WRITE_LINE_MEMBER( c8050_fdc_t::odd_hd_w ) |
| 769 | | { |
| 770 | | if (m_odd_hd != state) |
| 771 | | { |
| 772 | | live_sync(); |
| 773 | | m_odd_hd = cur_live.odd_hd = state; |
| 774 | | if (LOG) logerror("%s ODD HD %u\n", machine().time().as_string(), state); |
| 775 | | m_floppy0->ss_w(!state); |
| 776 | | if (m_floppy1) m_floppy1->ss_w(!state); |
| 777 | | checkpoint(); |
| 778 | | live_run(); |
| 779 | | } |
| 780 | | } |
| 781 | | |
| 782 | | WRITE_LINE_MEMBER( c8050_fdc_t::pull_sync_w ) |
| 783 | | { |
| 784 | | // TODO |
| 785 | | if (LOG) logerror("%s PULL SYNC %u\n", machine().time().as_string(), state); |
| 786 | | } |
trunk/src/emu/bus/ieee488/c2040fdc.h
| r242307 | r242308 | |
| 18 | 18 | #include "formats/d64_dsk.h" |
| 19 | 19 | #include "formats/d67_dsk.h" |
| 20 | 20 | #include "formats/g64_dsk.h" |
| 21 | | #include "formats/d80_dsk.h" |
| 22 | | #include "formats/d82_dsk.h" |
| 23 | 21 | #include "imagedev/floppy.h" |
| 24 | | #include "machine/fdc_pll.h" |
| 25 | 22 | |
| 26 | 23 | |
| 27 | 24 | |
| r242307 | r242308 | |
| 50 | 47 | { |
| 51 | 48 | public: |
| 52 | 49 | // construction/destruction |
| 53 | | c2040_fdc_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); |
| 54 | 50 | c2040_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 55 | 51 | |
| 56 | 52 | template<class _Object> static devcb_base &set_sync_wr_callback(device_t &device, _Object object) { return downcast<c2040_fdc_t &>(device).m_write_sync.set_callback(object); } |
| r242307 | r242308 | |
| 68 | 64 | |
| 69 | 65 | DECLARE_READ_LINE_MEMBER( wps_r ) { return checkpoint_live.drv_sel ? m_floppy1->wpt_r() : m_floppy0->wpt_r(); } |
| 70 | 66 | DECLARE_READ_LINE_MEMBER( sync_r ) { return checkpoint_live.sync; } |
| 71 | | DECLARE_READ_LINE_MEMBER( ready_r ) { return checkpoint_live.ready; } |
| 72 | | DECLARE_READ_LINE_MEMBER( error_r ) { return checkpoint_live.error; } |
| 73 | 67 | |
| 74 | 68 | void stp0_w(int stp); |
| 75 | 69 | void stp1_w(int stp); |
| r242307 | r242308 | |
| 147 | 141 | emu_timer *t_gen; |
| 148 | 142 | |
| 149 | 143 | floppy_image_device* get_floppy(); |
| 150 | | virtual void live_start(); |
| 151 | | virtual void checkpoint(); |
| 152 | | virtual void rollback(); |
| 144 | |
| 145 | void live_start(); |
| 146 | void checkpoint(); |
| 147 | void rollback(); |
| 153 | 148 | bool write_next_bit(bool bit, const attotime &limit); |
| 154 | 149 | void start_writing(const attotime &tm); |
| 155 | 150 | void commit(const attotime &tm); |
| r242307 | r242308 | |
| 157 | 152 | void live_delay(int state); |
| 158 | 153 | void live_sync(); |
| 159 | 154 | void live_abort(); |
| 160 | | virtual void live_run(const attotime &limit = attotime::never); |
| 155 | void live_run(const attotime &limit = attotime::never); |
| 161 | 156 | void get_next_edge(const attotime &when); |
| 162 | | virtual int get_next_bit(attotime &tm, const attotime &limit); |
| 157 | int get_next_bit(attotime &tm, const attotime &limit); |
| 163 | 158 | }; |
| 164 | 159 | |
| 165 | 160 | |
| 166 | | // ======================> c8050_fdc_t |
| 167 | | |
| 168 | | class c8050_fdc_t : public c2040_fdc_t |
| 169 | | { |
| 170 | | public: |
| 171 | | // construction/destruction |
| 172 | | c8050_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 173 | | |
| 174 | | DECLARE_WRITE_LINE_MEMBER( odd_hd_w ); |
| 175 | | DECLARE_WRITE_LINE_MEMBER( pull_sync_w ); |
| 176 | | |
| 177 | | protected: |
| 178 | | fdc_pll_t cur_pll, checkpoint_pll; |
| 179 | | |
| 180 | | void stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp); |
| 181 | | |
| 182 | | virtual void live_start(); |
| 183 | | virtual void checkpoint(); |
| 184 | | virtual void rollback(); |
| 185 | | void pll_reset(const attotime &when, const attotime clock); |
| 186 | | void pll_save_checkpoint(); |
| 187 | | void pll_retrieve_checkpoint(); |
| 188 | | virtual void live_run(const attotime &limit = attotime::never); |
| 189 | | virtual int get_next_bit(attotime &tm, const attotime &limit); |
| 190 | | }; |
| 191 | | |
| 192 | | |
| 193 | | |
| 194 | 161 | // device type definition |
| 195 | 162 | extern const device_type C2040_FDC; |
| 196 | | extern const device_type C8050_FDC; |
| 197 | 163 | |
| 198 | 164 | |
| 199 | 165 | |
trunk/src/emu/bus/ieee488/c8050fdc.c
| r0 | r242308 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Curt Coder |
| 3 | /********************************************************************** |
| 4 | |
| 5 | Commodore 8050 floppy disk controller emulation |
| 6 | |
| 7 | Copyright MESS Team. |
| 8 | Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | |
| 10 | **********************************************************************/ |
| 11 | |
| 12 | #include "c8050fdc.h" |
| 13 | |
| 14 | |
| 15 | |
| 16 | //************************************************************************** |
| 17 | // MACROS / CONSTANTS |
| 18 | //************************************************************************** |
| 19 | |
| 20 | #define LOG 0 |
| 21 | |
| 22 | |
| 23 | |
| 24 | //************************************************************************** |
| 25 | // DEVICE DEFINITIONS |
| 26 | //************************************************************************** |
| 27 | |
| 28 | const device_type C8050_FDC = &device_creator<c8050_fdc_t>; |
| 29 | |
| 30 | |
| 31 | //------------------------------------------------- |
| 32 | // ROM( c8050_fdc ) |
| 33 | //------------------------------------------------- |
| 34 | |
| 35 | ROM_START( c8050_fdc ) |
| 36 | ROM_REGION( 0x800, "gcr", 0) |
| 37 | ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) |
| 38 | ROM_END |
| 39 | |
| 40 | |
| 41 | //------------------------------------------------- |
| 42 | // rom_region - device-specific ROM region |
| 43 | //------------------------------------------------- |
| 44 | |
| 45 | const rom_entry *c8050_fdc_t::device_rom_region() const |
| 46 | { |
| 47 | return ROM_NAME( c8050_fdc ); |
| 48 | } |
| 49 | |
| 50 | |
| 51 | |
| 52 | //************************************************************************** |
| 53 | // LIVE DEVICE |
| 54 | //************************************************************************** |
| 55 | |
| 56 | //------------------------------------------------- |
| 57 | // c8050_fdc_t - constructor |
| 58 | //------------------------------------------------- |
| 59 | |
| 60 | c8050_fdc_t::c8050_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 61 | device_t(mconfig, C8050_FDC, "C8050 FDC", tag, owner, clock, "c8050fdc", __FILE__), |
| 62 | m_write_sync(*this), |
| 63 | m_write_ready(*this), |
| 64 | m_write_error(*this), |
| 65 | m_gcr_rom(*this, "gcr"), |
| 66 | m_floppy0(NULL), |
| 67 | m_floppy1(NULL), |
| 68 | m_mtr0(1), |
| 69 | m_mtr1(1), |
| 70 | m_stp0(0), |
| 71 | m_stp1(0), |
| 72 | m_ds(0), |
| 73 | m_drv_sel(0), |
| 74 | m_mode_sel(0), |
| 75 | m_rw_sel(0), |
| 76 | m_period(attotime::from_hz(clock)) |
| 77 | { |
| 78 | cur_live.tm = attotime::never; |
| 79 | cur_live.state = IDLE; |
| 80 | cur_live.next_state = -1; |
| 81 | cur_live.drv_sel = m_drv_sel; |
| 82 | } |
| 83 | |
| 84 | |
| 85 | |
| 86 | //------------------------------------------------- |
| 87 | // device_start - device-specific startup |
| 88 | //------------------------------------------------- |
| 89 | |
| 90 | void c8050_fdc_t::device_start() |
| 91 | { |
| 92 | // resolve callbacks |
| 93 | m_write_sync.resolve_safe(); |
| 94 | m_write_ready.resolve_safe(); |
| 95 | m_write_error.resolve_safe(); |
| 96 | |
| 97 | // allocate timer |
| 98 | t_gen = timer_alloc(0); |
| 99 | |
| 100 | // register for state saving |
| 101 | save_item(NAME(m_mtr0)); |
| 102 | save_item(NAME(m_mtr1)); |
| 103 | save_item(NAME(m_stp0)); |
| 104 | save_item(NAME(m_stp1)); |
| 105 | save_item(NAME(m_ds)); |
| 106 | save_item(NAME(m_drv_sel)); |
| 107 | save_item(NAME(m_mode_sel)); |
| 108 | save_item(NAME(m_rw_sel)); |
| 109 | } |
| 110 | |
| 111 | |
| 112 | //------------------------------------------------- |
| 113 | // device_reset - device-specific reset |
| 114 | //------------------------------------------------- |
| 115 | |
| 116 | void c8050_fdc_t::device_reset() |
| 117 | { |
| 118 | live_abort(); |
| 119 | } |
| 120 | |
| 121 | |
| 122 | //------------------------------------------------- |
| 123 | // device_timer - handler timer events |
| 124 | //------------------------------------------------- |
| 125 | |
| 126 | void c8050_fdc_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 127 | { |
| 128 | live_sync(); |
| 129 | live_run(); |
| 130 | } |
| 131 | |
| 132 | floppy_image_device* c8050_fdc_t::get_floppy() |
| 133 | { |
| 134 | return cur_live.drv_sel ? m_floppy1 : m_floppy0; |
| 135 | } |
| 136 | |
| 137 | void c8050_fdc_t::stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp) |
| 138 | { |
| 139 | if (mtr) return; |
| 140 | |
| 141 | int tracks = 0; |
| 142 | |
| 143 | switch (old_stp) |
| 144 | { |
| 145 | case 0: if (stp == 1) tracks++; else if (stp == 2) tracks--; break; |
| 146 | case 1: if (stp == 3) tracks++; else if (stp == 0) tracks--; break; |
| 147 | case 2: if (stp == 0) tracks++; else if (stp == 3) tracks--; break; |
| 148 | case 3: if (stp == 2) tracks++; else if (stp == 1) tracks--; break; |
| 149 | } |
| 150 | |
| 151 | if (tracks == -1) |
| 152 | { |
| 153 | floppy->dir_w(1); |
| 154 | floppy->stp_w(1); |
| 155 | floppy->stp_w(0); |
| 156 | } |
| 157 | else if (tracks == 1) |
| 158 | { |
| 159 | floppy->dir_w(0); |
| 160 | floppy->stp_w(1); |
| 161 | floppy->stp_w(0); |
| 162 | } |
| 163 | |
| 164 | old_stp = stp; |
| 165 | } |
| 166 | |
| 167 | void c8050_fdc_t::stp0_w(int stp) |
| 168 | { |
| 169 | if (m_stp0 != stp) |
| 170 | { |
| 171 | live_sync(); |
| 172 | this->stp_w(m_floppy0, m_mtr0, m_stp0, stp); |
| 173 | checkpoint(); |
| 174 | live_run(); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | void c8050_fdc_t::stp1_w(int stp) |
| 179 | { |
| 180 | if (m_stp1 != stp) |
| 181 | { |
| 182 | live_sync(); |
| 183 | if (m_floppy1) this->stp_w(m_floppy1, m_mtr1, m_stp1, stp); |
| 184 | checkpoint(); |
| 185 | live_run(); |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | void c8050_fdc_t::ds_w(int ds) |
| 190 | { |
| 191 | if (m_ds != ds) |
| 192 | { |
| 193 | live_sync(); |
| 194 | m_ds = cur_live.ds = ds; |
| 195 | checkpoint(); |
| 196 | live_run(); |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | void c8050_fdc_t::set_floppy(floppy_image_device *floppy0, floppy_image_device *floppy1) |
| 201 | { |
| 202 | m_floppy0 = floppy0; |
| 203 | m_floppy1 = floppy1; |
| 204 | } |
| 205 | |
| 206 | void c8050_fdc_t::live_start() |
| 207 | { |
| 208 | cur_live.tm = machine().time(); |
| 209 | cur_live.state = RUNNING; |
| 210 | cur_live.next_state = -1; |
| 211 | |
| 212 | cur_live.shift_reg = 0; |
| 213 | cur_live.shift_reg_write = 0; |
| 214 | cur_live.cycle_counter = 0; |
| 215 | cur_live.cell_counter = 0; |
| 216 | cur_live.bit_counter = 0; |
| 217 | cur_live.ds = m_ds; |
| 218 | cur_live.drv_sel = m_drv_sel; |
| 219 | cur_live.mode_sel = m_mode_sel; |
| 220 | cur_live.rw_sel = m_rw_sel; |
| 221 | cur_live.pi = m_pi; |
| 222 | |
| 223 | pll_reset(cur_live.tm, attotime::from_double(0)); |
| 224 | checkpoint_live = cur_live; |
| 225 | pll_save_checkpoint(); |
| 226 | |
| 227 | live_run(); |
| 228 | } |
| 229 | |
| 230 | void c8050_fdc_t::pll_reset(const attotime &when, const attotime clock) |
| 231 | { |
| 232 | cur_pll.reset(when); |
| 233 | cur_pll.set_clock(clock); |
| 234 | } |
| 235 | |
| 236 | void c8050_fdc_t::pll_start_writing(const attotime &tm) |
| 237 | { |
| 238 | cur_pll.start_writing(tm); |
| 239 | } |
| 240 | |
| 241 | void c8050_fdc_t::pll_commit(floppy_image_device *floppy, const attotime &tm) |
| 242 | { |
| 243 | cur_pll.commit(floppy, tm); |
| 244 | } |
| 245 | |
| 246 | void c8050_fdc_t::pll_stop_writing(floppy_image_device *floppy, const attotime &tm) |
| 247 | { |
| 248 | cur_pll.stop_writing(floppy, tm); |
| 249 | } |
| 250 | |
| 251 | void c8050_fdc_t::pll_save_checkpoint() |
| 252 | { |
| 253 | checkpoint_pll = cur_pll; |
| 254 | } |
| 255 | |
| 256 | void c8050_fdc_t::pll_retrieve_checkpoint() |
| 257 | { |
| 258 | cur_pll = checkpoint_pll; |
| 259 | } |
| 260 | |
| 261 | int c8050_fdc_t::pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) |
| 262 | { |
| 263 | return cur_pll.get_next_bit(tm, floppy, limit); |
| 264 | } |
| 265 | |
| 266 | bool c8050_fdc_t::pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) |
| 267 | { |
| 268 | return cur_pll.write_next_bit_prev_cell(bit, tm, floppy, limit); |
| 269 | } |
| 270 | |
| 271 | void c8050_fdc_t::checkpoint() |
| 272 | { |
| 273 | pll_commit(get_floppy(), cur_live.tm); |
| 274 | checkpoint_live = cur_live; |
| 275 | pll_save_checkpoint(); |
| 276 | } |
| 277 | |
| 278 | void c8050_fdc_t::rollback() |
| 279 | { |
| 280 | cur_live = checkpoint_live; |
| 281 | pll_retrieve_checkpoint(); |
| 282 | } |
| 283 | |
| 284 | void c8050_fdc_t::live_sync() |
| 285 | { |
| 286 | if(!cur_live.tm.is_never()) { |
| 287 | if(cur_live.tm > machine().time()) { |
| 288 | rollback(); |
| 289 | live_run(machine().time()); |
| 290 | pll_commit(get_floppy(), cur_live.tm); |
| 291 | } else { |
| 292 | pll_commit(get_floppy(), cur_live.tm); |
| 293 | if(cur_live.next_state != -1) { |
| 294 | cur_live.state = cur_live.next_state; |
| 295 | cur_live.next_state = -1; |
| 296 | } |
| 297 | if(cur_live.state == IDLE) { |
| 298 | pll_stop_writing(get_floppy(), cur_live.tm); |
| 299 | cur_live.tm = attotime::never; |
| 300 | } |
| 301 | } |
| 302 | cur_live.next_state = -1; |
| 303 | checkpoint(); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | void c8050_fdc_t::live_abort() |
| 308 | { |
| 309 | if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { |
| 310 | rollback(); |
| 311 | live_run(machine().time()); |
| 312 | } |
| 313 | |
| 314 | pll_stop_writing(get_floppy(), cur_live.tm); |
| 315 | |
| 316 | cur_live.tm = attotime::never; |
| 317 | cur_live.state = IDLE; |
| 318 | cur_live.next_state = -1; |
| 319 | |
| 320 | cur_live.ready = 1; |
| 321 | cur_live.sync = 1; |
| 322 | cur_live.error = 1; |
| 323 | } |
| 324 | |
| 325 | |
| 326 | void c8050_fdc_t::live_run(const attotime &limit) |
| 327 | { |
| 328 | if(cur_live.state == IDLE || cur_live.next_state != -1) |
| 329 | return; |
| 330 | |
| 331 | for(;;) { |
| 332 | switch(cur_live.state) { |
| 333 | case RUNNING: { |
| 334 | bool syncpoint = false; |
| 335 | |
| 336 | if (cur_live.tm > limit) |
| 337 | return; |
| 338 | |
| 339 | int bit = pll_get_next_bit(cur_live.tm, get_floppy(), limit); |
| 340 | if(bit < 0) |
| 341 | return; |
| 342 | |
| 343 | if (syncpoint) { |
| 344 | live_delay(RUNNING_SYNCPOINT); |
| 345 | return; |
| 346 | } |
| 347 | break; |
| 348 | } |
| 349 | |
| 350 | case RUNNING_SYNCPOINT: { |
| 351 | m_write_ready(cur_live.ready); |
| 352 | m_write_sync(cur_live.sync); |
| 353 | m_write_error(cur_live.error); |
| 354 | |
| 355 | cur_live.state = RUNNING; |
| 356 | checkpoint(); |
| 357 | break; |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | READ8_MEMBER( c8050_fdc_t::read ) |
| 364 | { |
| 365 | UINT8 e = checkpoint_live.e; |
| 366 | offs_t i = checkpoint_live.i; |
| 367 | |
| 368 | UINT8 data = (BIT(e, 6) << 7) | (BIT(i, 7) << 6) | (e & 0x33) | (BIT(e, 2) << 3) | (i & 0x04); |
| 369 | |
| 370 | if (LOG) logerror("%s VIA reads data %02x (%03x)\n", machine().time().as_string(), data, checkpoint_live.shift_reg); |
| 371 | |
| 372 | return data; |
| 373 | } |
| 374 | |
| 375 | WRITE8_MEMBER( c8050_fdc_t::write ) |
| 376 | { |
| 377 | if (m_pi != data) |
| 378 | { |
| 379 | live_sync(); |
| 380 | m_pi = cur_live.pi = data; |
| 381 | checkpoint(); |
| 382 | if (LOG) logerror("%s PI %02x\n", machine().time().as_string(), data); |
| 383 | live_run(); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | WRITE_LINE_MEMBER( c8050_fdc_t::drv_sel_w ) |
| 388 | { |
| 389 | if (m_drv_sel != state) |
| 390 | { |
| 391 | live_sync(); |
| 392 | m_drv_sel = cur_live.drv_sel = state; |
| 393 | checkpoint(); |
| 394 | if (LOG) logerror("%s DRV SEL %u\n", machine().time().as_string(), state); |
| 395 | live_run(); |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | WRITE_LINE_MEMBER( c8050_fdc_t::mode_sel_w ) |
| 400 | { |
| 401 | if (m_mode_sel != state) |
| 402 | { |
| 403 | live_sync(); |
| 404 | m_mode_sel = cur_live.mode_sel = state; |
| 405 | checkpoint(); |
| 406 | if (LOG) logerror("%s MODE SEL %u\n", machine().time().as_string(), state); |
| 407 | live_run(); |
| 408 | } |
| 409 | } |
| 410 | |
| 411 | WRITE_LINE_MEMBER( c8050_fdc_t::rw_sel_w ) |
| 412 | { |
| 413 | if (m_rw_sel != state) |
| 414 | { |
| 415 | live_sync(); |
| 416 | m_rw_sel = cur_live.rw_sel = state; |
| 417 | checkpoint(); |
| 418 | if (LOG) logerror("%s RW SEL %u\n", machine().time().as_string(), state); |
| 419 | if (m_rw_sel) { |
| 420 | pll_stop_writing(get_floppy(), machine().time()); |
| 421 | } else { |
| 422 | pll_start_writing(machine().time()); |
| 423 | } |
| 424 | live_run(); |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | WRITE_LINE_MEMBER( c8050_fdc_t::mtr0_w ) |
| 429 | { |
| 430 | if (m_mtr0 != state) |
| 431 | { |
| 432 | live_sync(); |
| 433 | m_mtr0 = state; |
| 434 | if (LOG) logerror("%s MTR0 %u\n", machine().time().as_string(), state); |
| 435 | m_floppy0->mon_w(state); |
| 436 | checkpoint(); |
| 437 | |
| 438 | if (!m_mtr0 || !m_mtr1) { |
| 439 | if(cur_live.state == IDLE) { |
| 440 | live_start(); |
| 441 | } |
| 442 | } else { |
| 443 | live_abort(); |
| 444 | } |
| 445 | |
| 446 | live_run(); |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | WRITE_LINE_MEMBER( c8050_fdc_t::mtr1_w ) |
| 451 | { |
| 452 | if (m_mtr1 != state) |
| 453 | { |
| 454 | live_sync(); |
| 455 | m_mtr1 = state; |
| 456 | if (LOG) logerror("%s MTR1 %u\n", machine().time().as_string(), state); |
| 457 | if (m_floppy1) m_floppy1->mon_w(state); |
| 458 | checkpoint(); |
| 459 | |
| 460 | if (!m_mtr0 || !m_mtr1) { |
| 461 | if(cur_live.state == IDLE) { |
| 462 | live_start(); |
| 463 | } |
| 464 | } else { |
| 465 | live_abort(); |
| 466 | } |
| 467 | |
| 468 | live_run(); |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | WRITE_LINE_MEMBER( c8050_fdc_t::odd_hd_w ) |
| 473 | { |
| 474 | if (m_odd_hd != state) |
| 475 | { |
| 476 | live_sync(); |
| 477 | m_odd_hd = cur_live.odd_hd = state; |
| 478 | if (LOG) logerror("%s ODD HD %u\n", machine().time().as_string(), state); |
| 479 | m_floppy0->ss_w(!state); |
| 480 | if (m_floppy1) m_floppy1->ss_w(!state); |
| 481 | checkpoint(); |
| 482 | live_run(); |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | WRITE_LINE_MEMBER( c8050_fdc_t::pull_sync_w ) |
| 487 | { |
| 488 | // TODO |
| 489 | if (LOG) logerror("%s PULL SYNC %u\n", machine().time().as_string(), state); |
| 490 | } |
trunk/src/emu/bus/ieee488/c8050fdc.h
| r0 | r242308 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Curt Coder |
| 3 | /********************************************************************** |
| 4 | |
| 5 | Commodore 8050 floppy disk controller emulation |
| 6 | |
| 7 | Copyright MESS Team. |
| 8 | Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | |
| 10 | **********************************************************************/ |
| 11 | |
| 12 | #pragma once |
| 13 | |
| 14 | #ifndef __C8050_FLOPPY__ |
| 15 | #define __C8050_FLOPPY__ |
| 16 | |
| 17 | #include "emu.h" |
| 18 | #include "formats/d80_dsk.h" |
| 19 | #include "formats/d82_dsk.h" |
| 20 | #include "imagedev/floppy.h" |
| 21 | #include "machine/fdc_pll.h" |
| 22 | |
| 23 | |
| 24 | |
| 25 | //************************************************************************** |
| 26 | // INTERFACE CONFIGURATION MACROS |
| 27 | //************************************************************************** |
| 28 | |
| 29 | #define MCFG_C8050_SYNC_CALLBACK(_write) \ |
| 30 | devcb = &c8050_fdc_t::set_sync_wr_callback(*device, DEVCB_##_write); |
| 31 | |
| 32 | #define MCFG_C8050_READY_CALLBACK(_write) \ |
| 33 | devcb = &c8050_fdc_t::set_ready_wr_callback(*device, DEVCB_##_write); |
| 34 | |
| 35 | #define MCFG_C8050_ERROR_CALLBACK(_write) \ |
| 36 | devcb = &c8050_fdc_t::set_error_wr_callback(*device, DEVCB_##_write); |
| 37 | |
| 38 | |
| 39 | |
| 40 | //************************************************************************** |
| 41 | // TYPE DEFINITIONS |
| 42 | //************************************************************************** |
| 43 | |
| 44 | // ======================> c8050_fdc_t |
| 45 | |
| 46 | class c8050_fdc_t : public device_t |
| 47 | { |
| 48 | public: |
| 49 | // construction/destruction |
| 50 | c8050_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 51 | |
| 52 | template<class _Object> static devcb_base &set_sync_wr_callback(device_t &device, _Object object) { return downcast<c8050_fdc_t &>(device).m_write_sync.set_callback(object); } |
| 53 | template<class _Object> static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast<c8050_fdc_t &>(device).m_write_ready.set_callback(object); } |
| 54 | template<class _Object> static devcb_base &set_error_wr_callback(device_t &device, _Object object) { return downcast<c8050_fdc_t &>(device).m_write_error.set_callback(object); } |
| 55 | |
| 56 | DECLARE_READ8_MEMBER( read ); |
| 57 | DECLARE_WRITE8_MEMBER( write ); |
| 58 | |
| 59 | DECLARE_WRITE_LINE_MEMBER( drv_sel_w ); |
| 60 | DECLARE_WRITE_LINE_MEMBER( mode_sel_w ); |
| 61 | DECLARE_WRITE_LINE_MEMBER( rw_sel_w ); |
| 62 | DECLARE_WRITE_LINE_MEMBER( mtr0_w ); |
| 63 | DECLARE_WRITE_LINE_MEMBER( mtr1_w ); |
| 64 | DECLARE_WRITE_LINE_MEMBER( odd_hd_w ); |
| 65 | DECLARE_WRITE_LINE_MEMBER( pull_sync_w ); |
| 66 | |
| 67 | DECLARE_READ_LINE_MEMBER( wps_r ) { return checkpoint_live.drv_sel ? m_floppy1->wpt_r() : m_floppy0->wpt_r(); } |
| 68 | DECLARE_READ_LINE_MEMBER( sync_r ) { return checkpoint_live.sync; } |
| 69 | |
| 70 | void stp0_w(int stp); |
| 71 | void stp1_w(int stp); |
| 72 | void ds_w(int ds); |
| 73 | |
| 74 | void set_floppy(floppy_image_device *floppy0, floppy_image_device *floppy1); |
| 75 | |
| 76 | protected: |
| 77 | // device-level overrides |
| 78 | virtual void device_start(); |
| 79 | virtual void device_reset(); |
| 80 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); |
| 81 | |
| 82 | // optional information overrides |
| 83 | virtual const rom_entry *device_rom_region() const; |
| 84 | |
| 85 | void stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp); |
| 86 | |
| 87 | enum { |
| 88 | IDLE, |
| 89 | RUNNING, |
| 90 | RUNNING_SYNCPOINT |
| 91 | }; |
| 92 | |
| 93 | struct live_info { |
| 94 | attotime tm; |
| 95 | int state, next_state; |
| 96 | int sync; |
| 97 | int ready; |
| 98 | int error; |
| 99 | int ds; |
| 100 | int drv_sel; |
| 101 | int mode_sel; |
| 102 | int rw_sel; |
| 103 | int odd_hd; |
| 104 | |
| 105 | attotime edge; |
| 106 | UINT16 shift_reg; |
| 107 | int cycle_counter; |
| 108 | int cell_counter; |
| 109 | int bit_counter; |
| 110 | UINT8 e; |
| 111 | offs_t i; |
| 112 | |
| 113 | UINT8 pi; |
| 114 | UINT16 shift_reg_write; |
| 115 | }; |
| 116 | |
| 117 | devcb_write_line m_write_sync; |
| 118 | devcb_write_line m_write_ready; |
| 119 | devcb_write_line m_write_error; |
| 120 | |
| 121 | required_memory_region m_gcr_rom; |
| 122 | |
| 123 | floppy_image_device *m_floppy0; |
| 124 | floppy_image_device *m_floppy1; |
| 125 | |
| 126 | int m_mtr0; |
| 127 | int m_mtr1; |
| 128 | int m_stp0; |
| 129 | int m_stp1; |
| 130 | int m_ds; |
| 131 | int m_drv_sel; |
| 132 | int m_mode_sel; |
| 133 | int m_rw_sel; |
| 134 | int m_odd_hd; |
| 135 | UINT8 m_pi; |
| 136 | |
| 137 | attotime m_period; |
| 138 | |
| 139 | live_info cur_live, checkpoint_live; |
| 140 | fdc_pll_t cur_pll, checkpoint_pll; |
| 141 | emu_timer *t_gen; |
| 142 | |
| 143 | floppy_image_device* get_floppy(); |
| 144 | |
| 145 | void live_start(); |
| 146 | void checkpoint(); |
| 147 | void rollback(); |
| 148 | void pll_reset(const attotime &when, const attotime clock); |
| 149 | void pll_start_writing(const attotime &tm); |
| 150 | void pll_commit(floppy_image_device *floppy, const attotime &tm); |
| 151 | void pll_stop_writing(floppy_image_device *floppy, const attotime &tm); |
| 152 | int pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); |
| 153 | bool pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); |
| 154 | void pll_save_checkpoint(); |
| 155 | void pll_retrieve_checkpoint(); |
| 156 | void live_delay(int state); |
| 157 | void live_sync(); |
| 158 | void live_abort(); |
| 159 | void live_run(const attotime &limit = attotime::never); |
| 160 | }; |
| 161 | |
| 162 | |
| 163 | // device type definition |
| 164 | extern const device_type C8050_FDC; |
| 165 | |
| 166 | |
| 167 | |
| 168 | #endif |