| Previous | 199869 Revisions | Next |
| r26022 Wednesday 6th November, 2013 at 18:05:49 UTC by Dirk Best |
|---|
| Initial commit of preliminary Alto2 driver by Jürgen Buchmüller |
| [/branches/alto2/src/emu/cpu] | cpu.mak |
| [/branches/alto2/src/emu/cpu/alto2] | a2curt.c* a2dht.c* a2disk.c* a2disp.c* a2drive.c* a2dvt.c* a2dwt.c* a2emu.c* a2ether.c* a2ksec.c* a2kwd.c* a2mem.c* a2mouse.c* a2part.c* a2ram.c* alto2.c* alto2.h* alto2dsm.c* |
| [/branches/alto2/src/mess] | mess.mak |
| [/branches/alto2/src/mess/drivers] | alto2.c* |
| [/branches/alto2/src/mess/includes] | alto2.h* |
| r26018 | r26022 | |
|---|---|---|
| 2268 | 2268 | $(CPUOBJ)/score/scoredsm.o: $(CPUSRC)/score/scoredsm.c \ |
| 2269 | 2269 | $(CPUSRC)/score/scorem.h |
| 2270 | 2270 | |
| 2271 | ||
| 2272 | #------------------------------------------------- | |
| 2273 | # Xerox Alto-II | |
| 2274 | #@src/emu/cpu/alto2/alto2.h,CPUS += ALTO2 | |
| 2275 | #------------------------------------------------- | |
| 2276 | ||
| 2277 | ifneq ($(filter ALTO2,$(CPUS)),) | |
| 2278 | OBJDIRS += $(CPUOBJ)/alto2 | |
| 2279 | CPUOBJS += $(CPUOBJ)/alto2/alto2.o \ | |
| 2280 | $(CPUOBJ)/alto2/a2disk.o \ | |
| 2281 | $(CPUOBJ)/alto2/a2disp.o \ | |
| 2282 | $(CPUOBJ)/alto2/a2curt.o \ | |
| 2283 | $(CPUOBJ)/alto2/a2dht.o \ | |
| 2284 | $(CPUOBJ)/alto2/a2dvt.o \ | |
| 2285 | $(CPUOBJ)/alto2/a2dwt.o \ | |
| 2286 | $(CPUOBJ)/alto2/a2emu.o \ | |
| 2287 | $(CPUOBJ)/alto2/a2ether.o \ | |
| 2288 | $(CPUOBJ)/alto2/a2ksec.o \ | |
| 2289 | $(CPUOBJ)/alto2/a2kwd.o \ | |
| 2290 | $(CPUOBJ)/alto2/a2mem.o \ | |
| 2291 | $(CPUOBJ)/alto2/a2mouse.o \ | |
| 2292 | $(CPUOBJ)/alto2/a2part.o \ | |
| 2293 | $(CPUOBJ)/alto2/a2ram.o | |
| 2294 | ||
| 2295 | DASMOBJS += $(CPUOBJ)/alto2/alto2dsm.o | |
| 2296 | endif | |
| 2297 | ||
| 2298 | $(CPUOBJ)/alto2/alto2.o: $(CPUSRC)/alto2/alto2.c \ | |
| 2299 | $(CPUSRC)/alto2/alto2.h | |
| 2300 | ||
| 2301 | $(CPUOBJ)/alto2/a2disk.o: $(CPUSRC)/alto2/a2disk.c \ | |
| 2302 | $(CPUSRC)/alto2/alto2.h | |
| 2303 | ||
| 2304 | $(CPUOBJ)/alto2/a2disp.o: $(CPUSRC)/alto2/a2disp.c \ | |
| 2305 | $(CPUSRC)/alto2/alto2.h | |
| 2306 | ||
| 2307 | $(CPUOBJ)/alto2/a2curt.o: $(CPUSRC)/alto2/a2curt.c \ | |
| 2308 | $(CPUSRC)/alto2/alto2.h | |
| 2309 | ||
| 2310 | $(CPUOBJ)/alto2/a2dht.o: $(CPUSRC)/alto2/a2dht.c \ | |
| 2311 | $(CPUSRC)/alto2/alto2.h | |
| 2312 | ||
| 2313 | $(CPUOBJ)/alto2/a2dvt.o: $(CPUSRC)/alto2/a2dvt.c \ | |
| 2314 | $(CPUSRC)/alto2/alto2.h | |
| 2315 | ||
| 2316 | $(CPUOBJ)/alto2/a2dwt.o: $(CPUSRC)/alto2/a2dwt.c \ | |
| 2317 | $(CPUSRC)/alto2/alto2.h | |
| 2318 | ||
| 2319 | $(CPUOBJ)/alto2/a2emu.o: $(CPUSRC)/alto2/a2emu.c \ | |
| 2320 | $(CPUSRC)/alto2/alto2.h | |
| 2321 | ||
| 2322 | $(CPUOBJ)/alto2/a2ether.o: $(CPUSRC)/alto2/a2ether.c \ | |
| 2323 | $(CPUSRC)/alto2/alto2.h | |
| 2324 | ||
| 2325 | $(CPUOBJ)/alto2/a2ksec.o: $(CPUSRC)/alto2/a2ksec.c \ | |
| 2326 | $(CPUSRC)/alto2/alto2.h | |
| 2327 | ||
| 2328 | $(CPUOBJ)/alto2/a2kwd.o: $(CPUSRC)/alto2/a2kwd.c \ | |
| 2329 | $(CPUSRC)/alto2/alto2.h | |
| 2330 | ||
| 2331 | $(CPUOBJ)/alto2/a2mem.o: $(CPUSRC)/alto2/a2mem.c \ | |
| 2332 | $(CPUSRC)/alto2/alto2.h | |
| 2333 | ||
| 2334 | $(CPUOBJ)/alto2/a2mouse.o: $(CPUSRC)/alto2/a2mouse.c \ | |
| 2335 | $(CPUSRC)/alto2/alto2.h | |
| 2336 | ||
| 2337 | $(CPUOBJ)/alto2/a2part.o: $(CPUSRC)/alto2/a2part.c \ | |
| 2338 | $(CPUSRC)/alto2/alto2.h | |
| 2339 | ||
| 2340 | $(CPUOBJ)/alto2/a2ram.o: $(CPUSRC)/alto2/a2ram.c \ | |
| 2341 | $(CPUSRC)/alto2/alto2.h | |
| 2342 | ||
| 2343 | $(CPUOBJ)/alto2/alto2dsm.o: $(CPUSRC)/alto2/alto2dsm.c \ | |
| 2344 | $(CPUSRC)/alto2/alto2.h | |
| 2345 | ||
| No newline at end of file |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII cursor task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief f1_curt_block early: disable the cursor task and set the curt_blocks flag | |
| 14 | */ | |
| 15 | void alto2_cpu_device::f1_curt_block_0() | |
| 16 | { | |
| 17 | m_task_wakeup &= ~(1 << m_task); | |
| 18 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 19 | m_dsp.curt_blocks = 1; | |
| 20 | } | |
| 21 | ||
| 22 | /** | |
| 23 | * @brief f2_load_xpreg late: load the x position register from BUS[6-15] | |
| 24 | */ | |
| 25 | void alto2_cpu_device::f2_load_xpreg_1() | |
| 26 | { | |
| 27 | m_dsp.xpreg = A2_GET32(m_bus,16,6,15); | |
| 28 | LOG((0,2," XPREG<- BUS[6-15] (%#o)\n", dsp.xpreg)); | |
| 29 | } | |
| 30 | ||
| 31 | /** | |
| 32 | * @brief f2_load_csr late: load the cursor shift register from BUS[0-15] | |
| 33 | * | |
| 34 | * Shift CSR to xpreg % 16 position to make it easier to | |
| 35 | * to handle the word xor in unload_word(). | |
| 36 | * <PRE> | |
| 37 | * xpreg % 16 cursor bits | |
| 38 | * [ first word ][ second word ] | |
| 39 | * ---------------------------------------------- | |
| 40 | * 0 xxxxxxxxxxxxxxxx0000000000000000 | |
| 41 | * 1 0xxxxxxxxxxxxxxxx000000000000000 | |
| 42 | * 2 00xxxxxxxxxxxxxxxx00000000000000 | |
| 43 | * ... | |
| 44 | * 14 00000000000000xxxxxxxxxxxxxxxx00 | |
| 45 | * 15 000000000000000xxxxxxxxxxxxxxxx0 | |
| 46 | * </PRE> | |
| 47 | */ | |
| 48 | void alto2_cpu_device::f2_load_csr_1() | |
| 49 | { | |
| 50 | m_dsp.csr = m_bus; | |
| 51 | LOG((0,2," CSR<- BUS (%#o)\n", dsp.csr)); | |
| 52 | int x = 1023 - m_dsp.xpreg; \ | |
| 53 | m_dsp.curdata = m_dsp.csr << (16 - (x & 15)); \ | |
| 54 | m_dsp.curword = x / 16; \ | |
| 55 | } | |
| 56 | ||
| 57 | /** | |
| 58 | * @brief curt_activate: called by the CPU when the cursor task becomes active | |
| 59 | */ | |
| 60 | void alto2_cpu_device::curt_activate() | |
| 61 | { | |
| 62 | m_task_wakeup &= ~(1 << m_task); | |
| 63 | m_dsp.curt_wakeup = 0; | |
| 64 | } | |
| 65 | ||
| 66 | /** @brief initialize the cursor task F1 and F2 functions */ | |
| 67 | void alto2_cpu_device::init_curt(int task) | |
| 68 | { | |
| 69 | set_f1(task, f1_block, &alto2_cpu_device::f1_curt_block_0, 0); | |
| 70 | set_f2(task, f2_curt_load_xpreg, 0, &alto2_cpu_device::f2_load_xpreg_1); | |
| 71 | set_f2(task, f2_curt_load_csr, 0, &alto2_cpu_device::f2_load_csr_1); | |
| 72 | m_active_callback[task] = &alto2_cpu_device::curt_activate; | |
| 73 | } | |
| 74 |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII memory interface | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | #define PUT_EVEN(dword,word) A2_PUT32(dword,32, 0,15,word) | |
| 13 | #define GET_EVEN(dword) A2_GET32(dword,32, 0,15) | |
| 14 | #define PUT_ODD(dword,word) A2_PUT32(dword,32,16,31,word) | |
| 15 | #define GET_ODD(dword) A2_GET32(dword,32,16,31) | |
| 16 | ||
| 17 | #define GET_MESR_HAMMING(mesr) A2_GET16(mesr,16,0,5) | |
| 18 | #define PUT_MESR_HAMMING(mesr,val) A2_PUT16(mesr,16,0,5,val) | |
| 19 | #define GET_MESR_PERR(mesr) A2_GET16(mesr,16,6,6) | |
| 20 | #define PUT_MESR_PERR(mesr,val) A2_PUT16(mesr,16,6,6,val) | |
| 21 | #define GET_MESR_PARITY(mesr) A2_GET16(mesr,16,7,7) | |
| 22 | #define PUT_MESR_PARITY(mesr,val) A2_PUT16(mesr,16,7,7,val) | |
| 23 | #define GET_MESR_SYNDROME(mesr) A2_GET16(mesr,16,8,13) | |
| 24 | #define PUT_MESR_SYNDROME(mesr,val) A2_PUT16(mesr,16,8,13,val) | |
| 25 | #define GET_MESR_BANK(mesr) A2_GET16(mesr,16,14,15) | |
| 26 | #define PUT_MESR_BANK(mesr,val) A2_PUT16(mesr,16,14,15,val) | |
| 27 | ||
| 28 | #define GET_MECR_SPARE1(mecr,val) A2_GET16(mecr,16,0,3) | |
| 29 | #define PUT_MECR_SPARE1(mecr,val) A2_PUT16(mecr,16,0,3,val) | |
| 30 | #define GET_MECR_TEST_CODE(mecr) A2_GET16(mecr,16,4,10) | |
| 31 | #define PUT_MECR_TEST_CODE(mecr,val) A2_PUT16(mecr,16,4,10,val) | |
| 32 | #define GET_MECR_TEST_MODE(mecr) A2_GET16(mecr,16,11,11) | |
| 33 | #define PUT_MECR_TEST_MODE(mecr,val) A2_PUT16(mecr,16,11,11,val) | |
| 34 | #define GET_MECR_INT_SBERR(mecr) A2_GET16(mecr,16,12,12) | |
| 35 | #define PUT_MECR_INT_SBERR(mecr,val) A2_PUT16(mecr,16,12,12,val) | |
| 36 | #define GET_MECR_INT_DBERR(mecr) A2_GET16(mecr,16,13,13) | |
| 37 | #define PUT_MECR_INT_DBERR(mecr,val) A2_PUT16(mecr,16,13,13,val) | |
| 38 | #define GET_MECR_ERRCORR(mecr) A2_GET16(mecr,16,14,14) | |
| 39 | #define PUT_MECR_ERRCORR(mecr,val) A2_PUT16(mecr,16,14,14,val) | |
| 40 | #define GET_MECR_SPARE2(mecr) A2_GET16(mecr,16,15,15) | |
| 41 | #define PUT_MECR_SPARE2(mecr,val) A2_PUT16(mecr,16,15,15,val) | |
| 42 | ||
| 43 | /** | |
| 44 | * <PRE> | |
| 45 | * AltoII Memory | |
| 46 | * | |
| 47 | * Address mapping | |
| 48 | * | |
| 49 | * The mapping of addresses to memory chips can be altered by the setting of | |
| 50 | * the "memory configuration switch". This switch is located at the top of the | |
| 51 | * backplane of the AltoII. If the switch is in the alternate position, the | |
| 52 | * first and second 32K portions of memory are exchanged. | |
| 53 | * | |
| 54 | * The AltoII memory system is organized around 32-bit doublewords. Stored | |
| 55 | * along with each doubleword is 6 bits of Hamming code and a Parity bit for | |
| 56 | * a total of 39 bits: | |
| 57 | * | |
| 58 | * bits 0-15 even data word | |
| 59 | * bits 16-31 odd data word | |
| 60 | * bits 32-37 Hamming code | |
| 61 | * bit 38 Parity bit | |
| 62 | * | |
| 63 | * Things are further complicated by the fact that two types of memory chips | |
| 64 | * are used: 16K chips in machines with extended memory and 4K chips for all | |
| 65 | * others. | |
| 66 | * | |
| 67 | * The bits in a 1-word deep slice of memory are called a group. A group | |
| 68 | * contains 4K oder 16K doublewords, depending on the chip type. The bits of | |
| 69 | * a group on a single board are called a subgroup. Thus a subgroup contains | |
| 70 | * 10 of the 40 bits in a group. There are 8 subgroups on a memory board. | |
| 71 | * Subgroups are numbered from the high 3 bits of the address; for 4K chips | |
| 72 | * this means MAR[0-2]; for 16K chips (i.e., an Alto with extended memory) | |
| 73 | * this means BANK,MAR[0]: | |
| 74 | * | |
| 75 | * Subgroup Chip Positions | |
| 76 | * 7 81-90 | |
| 77 | * 6 71-80 | |
| 78 | * 5 61-70 | |
| 79 | * 4 51-60 | |
| 80 | * 3 41-50 | |
| 81 | * 2 31-40 | |
| 82 | * 1 21-30 | |
| 83 | * 0 11-20 | |
| 84 | * | |
| 85 | * The location of the bits in group 0 is: | |
| 86 | * | |
| 87 | * CARD 1 CARD2 CARD3 CARD4 | |
| 88 | * 32 24 16 08 00 33 25 17 09 01 34 26 18 10 02 35 27 19 11 03 | |
| 89 | * 36 28 20 12 04 37 29 21 13 05 38 30 22 14 06 xx 31 23 25 07 | |
| 90 | * | |
| 91 | * Chips 15, 25, 35, 45, 65, 75 and 85 on board 4 aren't used. If you are out | |
| 92 | * of replacement memory chips, you can use one of these, but then the board | |
| 93 | * with the missing chips will only work in Slot 4. | |
| 94 | * | |
| 95 | * o WORD = 16 BITS | |
| 96 | * o ACCESS -> 2 WORDS AT A TIME | |
| 97 | * o -> 32 BITS + 6 BITS EC + PARITY + SPARE = 40 BITS | |
| 98 | * o 10 BITS/MODULE 80 DRAMS/MODULE | |
| 99 | * o 4 MODULES/ALTO 320 DRAMS/ALTO | |
| 100 | * | |
| 101 | * ADDRESS A0-6, WE, CAS' | |
| 102 | * | TO ALL DEVICES | |
| 103 | * v | |
| 104 | * +-----------------------------------------+ | |
| 105 | * | ^ 8 DEVICES (32K OR 128K FOR XM) | | |
| 106 | * | | | CARD 1 | |
| 107 | * /| v <------------ DATA OUT ----------> | | |
| 108 | * / | 0 1 2 3 4 5 6 7 8 9 | | |
| 109 | * / +-----------------------------------------+ | |
| 110 | * | H4 H0 28 24 20 16 12 8 4 0 | |
| 111 | * | | |
| 112 | * | +-----------------------------------------+ | |
| 113 | * | /| | CARD 2 | |
| 114 | * | / +-----------------------------------------+ | |
| 115 | * RAS H5 H1 29 25 21 17 13 9 5 1 | |
| 116 | * 0-7 | |
| 117 | * | \ +-----------------------------------------+ | |
| 118 | * | \| | CARD 3 | |
| 119 | * | +-----------------------------------------+ | |
| 120 | * | P H2 30 26 22 18 14 10 6 2 | |
| 121 | * \ | |
| 122 | * \ +-----------------------------------------+ | |
| 123 | * \| | CARD 4 | |
| 124 | * +-----------------------------------------+ | |
| 125 | * X H3 31 27 23 19 15 11 7 3 | |
| 126 | * | |
| 127 | * [ ODD WORD ] [ EVEN WORD ] | |
| 128 | * | |
| 129 | * <HR> | |
| 130 | * | |
| 131 | * 32K x 10 STORAGE MODULE | |
| 132 | * | |
| 133 | * Table I | |
| 134 | * | |
| 135 | * +-------+-------+-------+---------------+-------+ | |
| 136 | * |CIRCUIT| INPUT | SIGNAL| INVERTER | | | |
| 137 | * | NO. | PINS | NAME | DEF?? ??? |RESIST.| | |
| 138 | * +-------+-------+-------+---------------+-------+ | |
| 139 | * | | 71 | RAS0 | A1 1 -> 2 | ?? R2 | | |
| 140 | * | 1 +-------+-------+---------------+-------+ | |
| 141 | * | | 110 | CS0 | A1 3 -> 4 | ?? R3 | | |
| 142 | * +-------+-------+-------+---------------+-------+ | |
| 143 | * | | 79 | RAS1 | A2 1 -> 2 | ?? R4 | | |
| 144 | * | 2 +-------+-------+---------------+-------+ | |
| 145 | * | | 110 | CS1 | A2 3 -> 4 | ?? R5 | | |
| 146 | * +-------+-------+-------+---------------+-------+ | |
| 147 | * | | 90 | RAS2 | A3 1 -> 2 | ?? R7 | | |
| 148 | * | 3 +-------+-------+---------------+-------+ | |
| 149 | * | | 110 | CS2 | A3 3 -> 4 | ?? R8 | | |
| 150 | * +-------+-------+-------+---------------+-------+ | |
| 151 | * | | 86 | RAS3 | A3 11 -> 10 | ?? R9 | | |
| 152 | * | 4 +-------+-------+---------------+-------+ | |
| 153 | * | | 110 | CS3 | A4 11 -> 10 | ?? R7 | | |
| 154 | * +-------+-------+-------+---------------+-------+ | |
| 155 | * | | 102 | RAS4 | A4 1 -> 2 | ?? R4 | | |
| 156 | * | 5 +-------+-------+---------------+-------+ | |
| 157 | * | | 110 | CS4 | A3 13 -> 12 | ?? R5 | | |
| 158 | * +-------+-------+-------+---------------+-------+ | |
| 159 | * | | 106 | RAS5 | A5 11 -> 10 | ?? R3 | | |
| 160 | * | 6 +-------+-------+---------------+-------+ | |
| 161 | * | | 110 | CS5 | A5 3 -> 4 | ?? R2 | | |
| 162 | * +-------+-------+-------+---------------+-------+ | |
| 163 | * | | 111 | RAS6 | A5 1 -> 2 | ?? R8 | | |
| 164 | * | 7 +-------+-------+---------------+-------+ | |
| 165 | * | | 110 | CS6 | A5 13 -> 12 | ?? R9 | | |
| 166 | * +-------+-------+-------+---------------+-------+ | |
| 167 | * | | 99 | RAS7 | A4 13 -> 12 | ?? R5 | | |
| 168 | * | 8 +-------+-------+---------------+-------+ | |
| 169 | * | | 110 | CS7 | A4 3 -> 4 | ?? R5 | | |
| 170 | * +-------+-------+-------+---------------+-------+ | |
| 171 | * | |
| 172 | * Table II | |
| 173 | * | |
| 174 | * MEMORY CHIP REFERENCE DESIGNATOR | |
| 175 | * | |
| 176 | * CIRCUIT NO. | |
| 177 | * ROW NO. 1 2 3 4 5 6 7 8 | |
| 178 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ | |
| 179 | * | 1 | 15 20 | 25 30 | 35 40 | 45 50 | 55 60 | 65 70 | 75 80 | 85 90 | | |
| 180 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ | |
| 181 | * | 2 | 14 19 | 24 29 | 34 39 | 44 49 | 54 59 | 64 69 | 64 79 | 84 89 | | |
| 182 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ | |
| 183 | * | 3 | 13 18 | 23 28 | 33 38 | 43 48 | 53 58 | 63 68 | 73 78 | 83 88 | | |
| 184 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ | |
| 185 | * | 4 | 12 17 | 22 27 | 32 37 | 42 47 | 52 57 | 62 67 | 72 77 | 82 87 | | |
| 186 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ | |
| 187 | * | 5 | 11 16 | 21 26 | 31 36 | 41 46 | 52 56 | 61 66 | 71 76 | 81 86 | | |
| 188 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ | |
| 189 | * | |
| 190 | * | |
| 191 | * The Hamming code generator: | |
| 192 | * | |
| 193 | * WDxx is write data bit xx. | |
| 194 | * H(x) is Hammming code bit x. | |
| 195 | * HC(x) is generated Hamming code bit x. | |
| 196 | * HC(x/y) is an intermediate value. | |
| 197 | * HC(x)A and HC(x)B are also intermediate values. | |
| 198 | * | |
| 199 | * Chips used are: | |
| 200 | * 74S280 9-bit parity generator (A-I inputs, even and odd outputs) | |
| 201 | * 74S135 EX-OR/EX-NOR gates (5 inputs, 2 outputs) | |
| 202 | * 74S86 EX-OR gates (2 inputs, 1 output) | |
| 203 | * | |
| 204 | * chip A B C D E F G H I even odd | |
| 205 | * --------------------------------------------------------------------------------- | |
| 206 | * a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A | |
| 207 | * a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD28 HC(0B1) --- | |
| 208 | * a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- | |
| 209 | * a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A | |
| 210 | * a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- | |
| 211 | * | |
| 212 | * H(0) ^ HC(0)A ^ HC(0B1) -> HC(0) | |
| 213 | * H(1) ^ HC(1)A ^ HC(0B1) -> HC(1) | |
| 214 | * HC(2)A ^ HC(2)B ^ H(2) -> HC(2) | |
| 215 | * H(0) ^ H(1) ^ H(2) -> H(0/2) | |
| 216 | * | |
| 217 | * chip A B C D E F G H I even odd | |
| 218 | * --------------------------------------------------------------------------------- | |
| 219 | * a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A | |
| 220 | * a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA | |
| 221 | * a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A | |
| 222 | * a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB | |
| 223 | * | |
| 224 | * HC(3)A ^ HC(3/4) -> HC(3) | |
| 225 | * HC(4)A ^ HC(3/4) -> HC(4) | |
| 226 | * | |
| 227 | * WD00 ^ WD01 -> XX01 | |
| 228 | * | |
| 229 | * chip A B C D E F G H I even odd | |
| 230 | * --------------------------------------------------------------------------------- | |
| 231 | * a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 RP PERR --- | |
| 232 | * a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA | |
| 233 | * a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- | |
| 234 | * | |
| 235 | * PCA ^ PCB -> PC | |
| 236 | * | |
| 237 | * Whoa ;-) | |
| 238 | * </PRE> | |
| 239 | */ | |
| 240 | #if ALTO2_HAMMING_CHECK | |
| 241 | ||
| 242 | #define WD(x) (1ul<<(31-x)) | |
| 243 | ||
| 244 | /* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */ | |
| 245 | #define A75 (WD( 1)|WD( 4)|WD( 8)|WD(11)|WD(15)|WD(19)|WD(23)|WD(26)|WD(30)) | |
| 246 | ||
| 247 | /* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */ | |
| 248 | #define A76 (WD( 0)|WD( 3)|WD( 6)|WD(10)|WD(13)|WD(17)|WD(21)|WD(25)|WD(28)) | |
| 249 | ||
| 250 | /* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */ | |
| 251 | #define A86 (WD( 2)|WD( 5)|WD( 9)|WD(12)|WD(16)|WD(20)|WD(24)|WD(27)|WD(31)) | |
| 252 | ||
| 253 | /* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */ | |
| 254 | #define A64 (WD( 1)|WD( 2)|WD( 3)|WD( 7)|WD( 8)|WD( 9)|WD(10)|WD(14)|WD(15)) | |
| 255 | ||
| 256 | /* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */ | |
| 257 | #define A85 (WD(16)|WD(17)|WD(22)|WD(23)|WD(24)|WD(25)|WD(29)|WD(30)|WD(31)) | |
| 258 | ||
| 259 | /* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */ | |
| 260 | #define A66 (WD( 4)|WD( 5)|WD( 6)|WD( 7)|WD( 8)|WD( 9)|WD(10)) | |
| 261 | ||
| 262 | /* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */ | |
| 263 | #define A84 (WD(18)|WD(19)|WD(20)|WD(21)|WD(22)|WD(23)|WD(24)|WD(25)) | |
| 264 | ||
| 265 | /* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */ | |
| 266 | #define A63 (WD(11)|WD(12)|WD(13)|WD(14)|WD(15)|WD(16)|WD(17)) | |
| 267 | ||
| 268 | /* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */ | |
| 269 | #define A87 (WD(26)|WD(27)|WD(28)|WD(29)|WD(30)|WD(31)) | |
| 270 | ||
| 271 | /* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- */ | |
| 272 | #define A54 (WD( 2)|WD( 3)) | |
| 273 | ||
| 274 | /* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */ | |
| 275 | #define A65 (WD( 0)|WD( 1)|WD( 2)|WD( 4)|WD( 5)|WD( 7)|WD(10)|WD(11)|WD(12)) | |
| 276 | ||
| 277 | /* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */ | |
| 278 | #define A74 (WD(14)|WD(17)|WD(18)|WD(21)|WD(23)|WD(24)|WD(26)|WD(27)|WD(29)) | |
| 279 | ||
| 280 | #define H0(hpb) A2_GET8(hpb,8,0,0) //!< get Hamming code bit 0 from hpb data (really bit 32) | |
| 281 | #define H1(hpb) A2_GET8(hpb,8,1,1) //!< get Hamming code bit 1 from hpb data (really bit 33) | |
| 282 | #define H2(hpb) A2_GET8(hpb,8,2,2) //!< get Hamming code bit 2 from hpb data (really bit 34) | |
| 283 | #define H3(hpb) A2_GET8(hpb,8,3,3) //!< get Hamming code bit 3 from hpb data (really bit 35) | |
| 284 | #define H4(hpb) A2_GET8(hpb,8,4,4) //!< get Hamming code bit 4 from hpb data (really bit 36) | |
| 285 | #define H5(hpb) A2_GET8(hpb,8,5,5) //!< get Hamming code bit 5 from hpb data (really bit 37) | |
| 286 | #define RH(hpb) A2_GET8(hpb,8,0,5) //!< get Hamming code from hpb data (bits 32 to 37) | |
| 287 | #define RP(hpb) A2_BIT8(hpb,8,6) //!< get parity bit from hpb data (really bit 38) | |
| 288 | ||
| 289 | /** @brief return even parity of a (masked) 32 bit value */ | |
| 290 | static __inline UINT8 parity_even(UINT32 val) | |
| 291 | { | |
| 292 | val -= ((val >> 1) & 0x55555555); | |
| 293 | val = (((val >> 2) & 0x33333333) + (val & 0x33333333)); | |
| 294 | val = (((val >> 4) + val) & 0x0f0f0f0f); | |
| 295 | val += (val >> 8); | |
| 296 | val += (val >> 16); | |
| 297 | return (val & 1); | |
| 298 | } | |
| 299 | ||
| 300 | /** @brief return odd parity of a (masked) 32 bit value */ | |
| 301 | #define parity_odd(val) (parity_even(val)^1) | |
| 302 | ||
| 303 | /** | |
| 304 | * @brief lookup table to convert a Hamming syndrome into a bit number to correct | |
| 305 | */ | |
| 306 | static const int hamming_lut[64] = { | |
| 307 | -1, -1, -1, 0, -1, 1, 2, 3, /* A69: HR(5):0 HR(4):0 HR(3):0 */ | |
| 308 | -1, 4, 5, 6, 7, 8, 9, 10, /* A79: HR(5):0 HR(4):0 HR(3):1 */ | |
| 309 | -1, 11, 12, 13, 14, 15, 16, 17, /* A67: HR(5):0 HR(4):1 HR(3):0 */ | |
| 310 | -1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */ | |
| 311 | -1, 26, 27, 28, 29, 30, 31, -1, /* A68: HR(5):1 HR(4):0 HR(3):0 */ | |
| 312 | -1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */ | |
| 313 | 18, 19, 20, 21, 22, 23, 24, 25, /* A78: HR(5):1 HR(4):1 HR(3):0 */ | |
| 314 | -1, -1, -1, -1, -1, 1, -1, -1 /* non chip selected */ | |
| 315 | }; | |
| 316 | ||
| 317 | /** | |
| 318 | * @brief read or write a memory double-word and caluclate its Hamming code | |
| 319 | * | |
| 320 | * Hamming code generation according to the schematics described above. | |
| 321 | * It's certainly overkill to do this on a modern PC, but I think we'll | |
| 322 | * need it for perfect emulation anyways (Hamming code hardware checking). | |
| 323 | * | |
| 324 | * @param write non-zero if this is a memory write (don't check for error) | |
| 325 | * @param dw_addr the double-word address | |
| 326 | * @param dw_data the double-word data to write | |
| 327 | * @return dw_data | |
| 328 | */ | |
| 329 | UINT32 alto2_cpu_device::hamming_code(int write, UINT32 dw_addr, UINT32 dw_data) | |
| 330 | { | |
| 331 | register UINT8 hpb = write ? 0 : m_mem.hpb[dw_addr]; | |
| 332 | register UINT8 hc_0_a; | |
| 333 | register UINT8 hc_0b1; | |
| 334 | register UINT8 hc_1_a; | |
| 335 | register UINT8 hc_2_a; | |
| 336 | register UINT8 hc_2_b; | |
| 337 | register UINT8 hc_0; | |
| 338 | register UINT8 hc_1; | |
| 339 | register UINT8 hc_2; | |
| 340 | register UINT8 h_0_2; | |
| 341 | register UINT8 hc_3_a; | |
| 342 | register UINT8 hc_3_4; | |
| 343 | register UINT8 hcpa; | |
| 344 | register UINT8 hc_4_a; | |
| 345 | register UINT8 hc_3; | |
| 346 | register UINT8 hc_4; | |
| 347 | register UINT8 hc_5; | |
| 348 | register UINT8 hcpb; | |
| 349 | register UINT8 perr; | |
| 350 | register UINT8 pca; | |
| 351 | register UINT8 pcb; | |
| 352 | register UINT8 pc; | |
| 353 | register int syndrome; | |
| 354 | ||
| 355 | /* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */ | |
| 356 | hc_0_a = parity_odd (dw_data & A75); | |
| 357 | /* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */ | |
| 358 | hc_0b1 = parity_even(dw_data & A76); | |
| 359 | /* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */ | |
| 360 | hc_1_a = parity_even(dw_data & A86); | |
| 361 | /* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */ | |
| 362 | hc_2_a = parity_odd (dw_data & A64); | |
| 363 | /* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */ | |
| 364 | hc_2_b = parity_even(dw_data & A85); | |
| 365 | ||
| 366 | hc_0 = H0(hpb) ^ hc_0_a ^ hc_0b1; | |
| 367 | hc_1 = H1(hpb) ^ hc_1_a ^ hc_0b1; | |
| 368 | hc_2 = hc_2_a ^ hc_2_b ^ H2(hpb); | |
| 369 | h_0_2 = H0(hpb) ^ H1(hpb) ^ H2(hpb); | |
| 370 | ||
| 371 | /* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */ | |
| 372 | hc_3_a = parity_odd ((dw_data & A66) ^ H3(hpb)); | |
| 373 | /* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */ | |
| 374 | hcpa = parity_odd (dw_data & A84); | |
| 375 | hc_3_4 = hcpa ^ 1; | |
| 376 | /* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */ | |
| 377 | hc_4_a = parity_odd ((dw_data & A63) ^ H4(hpb)); | |
| 378 | ||
| 379 | /* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */ | |
| 380 | hcpb = parity_odd ((dw_data & A87) ^ H5(hpb)); | |
| 381 | hc_3 = hc_3_a ^ hc_3_4; | |
| 382 | hc_4 = hc_4_a ^ hc_3_4; | |
| 383 | hc_5 = hcpb ^ 1; | |
| 384 | ||
| 385 | syndrome = (hc_0<<5)|(hc_1<<4)|(hc_2<<3)|(hc_3<<2)|(hc_4<<1)|(hc_5); | |
| 386 | ||
| 387 | /* | |
| 388 | * Note: Here I XOR all the non dw_data inputs into bit 0, | |
| 389 | * which has the same effect as spreading them over some bits | |
| 390 | * and then counting them... I hope ;-) | |
| 391 | */ | |
| 392 | /* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- */ | |
| 393 | perr = parity_even( | |
| 394 | hc_3_a ^ | |
| 395 | hc_4_a ^ | |
| 396 | hcpa ^ | |
| 397 | hcpb ^ | |
| 398 | h_0_2 ^ | |
| 399 | (A2_GET32(dw_data,32,0,0) ^ A2_GET32(dw_data,32,1,1)) ^ | |
| 400 | (dw_data & A54) ^ | |
| 401 | RP(hpb) ^ | |
| 402 | 1); | |
| 403 | ||
| 404 | /* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */ | |
| 405 | pca = parity_odd (dw_data & A65); | |
| 406 | /* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */ | |
| 407 | pcb = parity_even(dw_data & A74); | |
| 408 | pc = pca ^ pcb; | |
| 409 | ||
| 410 | if (write) { | |
| 411 | /* update the hamming code and parity bit store */ | |
| 412 | m_mem.hpb[dw_addr] = (syndrome << 2) | (pc << 1); | |
| 413 | return dw_data; | |
| 414 | ||
| 415 | } | |
| 416 | ||
| 417 | /** | |
| 418 | * <PRE> | |
| 419 | * A22 (74H30) 8-input NAND to check for error | |
| 420 | * input signal | |
| 421 | * ------------------------- | |
| 422 | * 1 POK = PERR' | |
| 423 | * 4 NER(08) = HC(0)' | |
| 424 | * 3 NER(09) = HC(1)' | |
| 425 | * 2 NER(10) = HC(2)' | |
| 426 | * 6 NER(11) = HC(3)' | |
| 427 | * 5 NER(12) = HC(4)' | |
| 428 | * 12 NER(13) = HC(5)' | |
| 429 | * 11 1 (VPUL3) | |
| 430 | * | |
| 431 | * output signal | |
| 432 | * ------------------------- | |
| 433 | * 8 ERROR | |
| 434 | * | |
| 435 | * Remembering De Morgan this can be simplified: | |
| 436 | * ERROR is 0, whenever all of PERR and HC(0) to HC(5) are 0. | |
| 437 | * Or the other way round: any of perr or syndrome non-zero means ERROR=1. | |
| 438 | * </PRE> | |
| 439 | */ | |
| 440 | if (perr || syndrome) { | |
| 441 | /* latch data on the first error */ | |
| 442 | if (!m_mem.error) { | |
| 443 | m_mem.error = 1; | |
| 444 | PUT_MESR_HAMMING(m_mem.mesr, RH(hpb)); | |
| 445 | PUT_MESR_PERR(m_mem.mesr, perr); | |
| 446 | PUT_MESR_PARITY(m_mem.mesr, RP(hpb)); | |
| 447 | PUT_MESR_SYNDROME(m_mem.mesr, syndrome); | |
| 448 | PUT_MESR_BANK(m_mem.mesr, (dw_addr >> 15)); | |
| 449 | /* latch memory address register */ | |
| 450 | m_mem.mear = m_mem.mar & 0177777; | |
| 451 | LOG((0,5," memory error at dword addr:%07o data:%011o check:%03o\n", dw_addr * 2, dw_data, hpb)); | |
| 452 | LOG((0,6," MEAR: %06o\n", m_mem.mear)); | |
| 453 | LOG((0,6," MESR: %06o\n", m_mem.mesr ^ 0177777)); | |
| 454 | LOG((0,6," Hamming code read : %#o\n", GET_MESR_HAMMING(mem.mesr))); | |
| 455 | LOG((0,6," Parity error : %o\n", GET_MESR_PERR(mem.mesr))); | |
| 456 | LOG((0,6," Memory parity bit : %o\n", GET_MESR_PARITY(mem.mesr))); | |
| 457 | LOG((0,6," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(mem.mesr), | |
| 458 | hamming_lut[GET_MESR_SYNDROME(mem.mesr)])); | |
| 459 | LOG((0,6," Memory bank : %#o\n", GET_MESR_BANK(mem.mesr))); | |
| 460 | LOG((0,6," MECR: %06o\n", mem.mecr ^ 0177777)); | |
| 461 | LOG((0,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(mem.mecr))); | |
| 462 | LOG((0,6," Test mode : %s\n", GET_MECR_TEST_MODE(mem.mecr) ? "on" : "off")); | |
| 463 | LOG((0,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(mem.mecr) ? "on" : "off")); | |
| 464 | LOG((0,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(mem.mecr) ? "on" : "off")); | |
| 465 | LOG((0,6," Error correction : %s\n", GET_MECR_ERRCORR(mem.mecr) ? "off" : "on")); | |
| 466 | } | |
| 467 | if (-1 == hamming_lut[syndrome]) { | |
| 468 | /* double-bit error: wake task_part, if we're told so */ | |
| 469 | if (GET_MECR_INT_DBERR(m_mem.mecr)) | |
| 470 | m_task_wakeup |= 1 << task_part; | |
| 471 | } else { | |
| 472 | /* single-bit error: wake task_part, if we're told so */ | |
| 473 | if (GET_MECR_INT_SBERR(m_mem.mecr)) | |
| 474 | m_task_wakeup |= 1 << task_part; | |
| 475 | /* should we correct the single bit error ? */ | |
| 476 | if (0 == GET_MECR_ERRCORR(m_mem.mecr)) { | |
| 477 | LOG((0,0," correct bit #%d addr:%07o data:%011o check:%03o\n", hamming_lut[syndrome], dw_addr * 2, dw_data, hpb)); | |
| 478 | dw_data ^= 1ul << hamming_lut[syndrome]; | |
| 479 | } | |
| 480 | } | |
| 481 | } | |
| 482 | return dw_data; | |
| 483 | } | |
| 484 | #endif /* ALTO2_HAMMING_CHECK */ | |
| 485 | ||
| 486 | ||
| 487 | /** | |
| 488 | * @brief catch unmapped memory mapped I/O reads | |
| 489 | * | |
| 490 | * @param address address that is read from | |
| 491 | */ | |
| 492 | UINT16 alto2_cpu_device::bad_mmio_read_fn(UINT32 address) | |
| 493 | { | |
| 494 | LOG((0,1," stray I/O read of address %#o\n", address)); | |
| 495 | (void)address; | |
| 496 | return 0177777; | |
| 497 | } | |
| 498 | ||
| 499 | /** | |
| 500 | * @brief catch unmapped memory mapped I/O writes | |
| 501 | * | |
| 502 | * @param address address that is written to | |
| 503 | * @param data data that is written | |
| 504 | */ | |
| 505 | void alto2_cpu_device::bad_mmio_write_fn(UINT32 address, UINT16 data) | |
| 506 | { | |
| 507 | LOG((0,1," stray I/O write of address %06o, data %#o\n", address, data)); | |
| 508 | (void)address; | |
| 509 | (void)data; | |
| 510 | } | |
| 511 | ||
| 512 | /** | |
| 513 | * @brief memory error address register read | |
| 514 | * | |
| 515 | * This register is a 'shadow MAR'; it holds the address of the | |
| 516 | * first error since the error status was last reset. If no error | |
| 517 | * has occured, MEAR reports the address of the most recent | |
| 518 | * memory access. Note that MEAR is set whenever an error of | |
| 519 | * _any kind_ (single-bit or double-bit) is detected. | |
| 520 | */ | |
| 521 | UINT16 alto2_cpu_device::mear_r(UINT32 address) | |
| 522 | { | |
| 523 | int data = m_mem.error ? m_mem.mear : m_mem.mar; | |
| 524 | LOG((0,2," MEAR read %07o\n", data)); | |
| 525 | return data; | |
| 526 | } | |
| 527 | ||
| 528 | /** | |
| 529 | * @brief memory error status register read | |
| 530 | * | |
| 531 | * This register reports specifics of the first error that | |
| 532 | * occured since MESR was last reset. Storing anything into | |
| 533 | * this register resets the error logic and enables it to | |
| 534 | * detect a new error. Bits are "low true", i.e. if the bit | |
| 535 | * is 0, the conidition is true. | |
| 536 | * <PRE> | |
| 537 | * MESR[0-5] Hamming code reported from error | |
| 538 | * MESR[6] Parity error | |
| 539 | * MESR[7] Memory parity bit | |
| 540 | * MESR[8-13] Syndrome bits | |
| 541 | * MESR[14-15] Bank number in which error occured | |
| 542 | * </PRE> | |
| 543 | */ | |
| 544 | UINT16 alto2_cpu_device::mesr_r(UINT32 address) | |
| 545 | { | |
| 546 | UINT16 data = m_mem.mesr ^ 0177777; | |
| 547 | (void)address; | |
| 548 | LOG((0,2," MESR read %07o\n", data)); | |
| 549 | LOG((0,6," Hamming code read : %#o\n", GET_MESR_HAMMING(data))); | |
| 550 | LOG((0,6," Parity error : %o\n", GET_MESR_PERR(data))); | |
| 551 | LOG((0,6," Memory parity bit : %o\n", GET_MESR_PARITY(data))); | |
| 552 | #if ALTO2_HAMMING_CHECK | |
| 553 | LOG((0,6," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(data), hamming_lut[GET_MESR_SYNDROME(data)])); | |
| 554 | #else | |
| 555 | LOG((0,6," Hamming syndrome : %#o\n", GET_MESR_SYNDROME(data))); | |
| 556 | #endif | |
| 557 | LOG((0,6," Memory bank : %#o\n", GET_MESR_BANK(data))); | |
| 558 | return data; | |
| 559 | } | |
| 560 | ||
| 561 | void alto2_cpu_device::mesr_w(UINT32 address, UINT16 data) | |
| 562 | { | |
| 563 | LOG((0,2," MESR write %07o (clear MESR; was %07o)\n", data, mem.mesr)); | |
| 564 | m_mem.mesr = 0; // set all bits to 0 | |
| 565 | m_mem.error = 0; // reset the error flag | |
| 566 | m_task_wakeup &= ~(1 << task_part); // clear the task wakeup for the parity error task | |
| 567 | } | |
| 568 | ||
| 569 | /** | |
| 570 | * @brief memory error control register write | |
| 571 | * | |
| 572 | * Storing into this register is the means for controlling | |
| 573 | * the memory error logic. This register is set to all ones | |
| 574 | * (disable all interrupts) when the alto is bootstrapped | |
| 575 | * and when the parity error task first detects an error. | |
| 576 | * When an error has occured, MEAR and MESR should be read | |
| 577 | * before setting MECR. Bits are "low true", i.e. a 0 bit | |
| 578 | * enables the condition. | |
| 579 | * | |
| 580 | * <PRE> | |
| 581 | * MECR[0-3] Spare | |
| 582 | * MECR[4-10] Test hamming code (used only for special diagnostics) | |
| 583 | * MECR[11] Test mode (used only for special diagnostics) | |
| 584 | * MECR[12] Cause interrupt on single-bit errors if zero | |
| 585 | * MECR[13] Cause interrupt on double-bit errors if zero | |
| 586 | * MECR[14] Do not use error correction if zero | |
| 587 | * MECR[15] Spare | |
| 588 | * </PRE> | |
| 589 | */ | |
| 590 | void alto2_cpu_device::mecr_w(UINT32 address, UINT16 data) | |
| 591 | { | |
| 592 | m_mem.mecr = data ^ 0177777; | |
| 593 | (void)address; | |
| 594 | A2_PUT16(m_mem.mecr,16, 0, 3,0); | |
| 595 | A2_PUT16(m_mem.mecr,16,15,15,0); | |
| 596 | LOG((0,2," MECR write %07o\n", data)); | |
| 597 | LOG((0,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(mem.mecr))); | |
| 598 | LOG((0,6," Test mode : %s\n", GET_MECR_TEST_MODE(mem.mecr) ? "on" : "off")); | |
| 599 | LOG((0,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(mem.mecr) ? "on" : "off")); | |
| 600 | LOG((0,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(mem.mecr) ? "on" : "off")); | |
| 601 | LOG((0,6," Error correction : %s\n", GET_MECR_ERRCORR(mem.mecr) ? "off" : "on")); | |
| 602 | } | |
| 603 | ||
| 604 | /** | |
| 605 | * @brief memory error control register read | |
| 606 | */ | |
| 607 | UINT16 alto2_cpu_device::mecr_r(UINT32 address) | |
| 608 | { | |
| 609 | UINT16 data = m_mem.mecr ^ 0177777; | |
| 610 | /* set all spare bits */ | |
| 611 | LOG((0,2," MECR read %07o\n", data)); | |
| 612 | LOG((0,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(data))); | |
| 613 | LOG((0,6," Test mode : %s\n", GET_MECR_TEST_MODE(data) ? "on" : "off")); | |
| 614 | LOG((0,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(data) ? "on" : "off")); | |
| 615 | LOG((0,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(data) ? "on" : "off")); | |
| 616 | LOG((0,6," Error correction : %s\n", GET_MECR_ERRCORR(data) ? "off" : "on")); | |
| 617 | return data; | |
| 618 | } | |
| 619 | ||
| 620 | /** | |
| 621 | * @brief load the memory address register with some value | |
| 622 | * | |
| 623 | * @param rsel selected register (to detect refresh cycles) | |
| 624 | * @param addr memory address | |
| 625 | */ | |
| 626 | void alto2_cpu_device::load_mar(UINT8 rsel, UINT32 addr) | |
| 627 | { | |
| 628 | if (rsel == 037) { | |
| 629 | /* | |
| 630 | * starting a memory refresh cycle | |
| 631 | * currently we don't do anything special | |
| 632 | */ | |
| 633 | LOG((0,5, " MAR<-; refresh cycle @ %#o\n", addr)); | |
| 634 | } else if (addr < ALTO2_RAM_SIZE) { | |
| 635 | LOG((0,2, " MAR<-; mar = %#o\n", addr)); | |
| 636 | m_mem.access = ALTO2_MEM_RAM; | |
| 637 | m_mem.mar = addr; | |
| 638 | /* fetch memory double-word to read/write latches */ | |
| 639 | m_mem.rmdd = m_mem.wmdd = m_mem.ram[m_mem.mar/2]; | |
| 640 | m_mem.cycle = cycle(); | |
| 641 | } else { | |
| 642 | m_mem.access = ALTO2_MEM_NIRVANA; | |
| 643 | m_mem.mar = addr; | |
| 644 | m_mem.rmdd = m_mem.wmdd = ~0; | |
| 645 | } | |
| 646 | } | |
| 647 | ||
| 648 | /** | |
| 649 | * @brief read memory or memory mapped I/O from the address in mar to md | |
| 650 | * | |
| 651 | * @result returns value from memory (RAM or MMIO) | |
| 652 | */ | |
| 653 | UINT16 alto2_cpu_device::read_mem() | |
| 654 | { | |
| 655 | UINT32 base_addr; | |
| 656 | ||
| 657 | if (ALTO2_MEM_NONE == m_mem.access) { | |
| 658 | LOG((0,0," fatal: mem read with no preceding address\n")); | |
| 659 | return 0177777; | |
| 660 | } | |
| 661 | ||
| 662 | if (cycle() > m_mem.cycle + 4) { | |
| 663 | LOG((0,0," fatal: mem read (MAR %#o) too late (+%lld cyc)\n", m_mem.mar, cycle() - m_mem.cycle)); | |
| 664 | m_mem.access = ALTO2_MEM_NONE; | |
| 665 | return 0177777; | |
| 666 | } | |
| 667 | ||
| 668 | base_addr = m_mem.mar & 0177777; | |
| 669 | if (base_addr >= ALTO2_IO_PAGE_BASE) { | |
| 670 | m_mem.md = ((*this).*mmio_read_fn[base_addr - ALTO2_IO_PAGE_BASE])(base_addr); | |
| 671 | LOG((0,6," MD = MMIO[%#o] (%#o)\n", base_addr, m_mem.md)); | |
| 672 | m_mem.access = ALTO2_MEM_NONE; | |
| 673 | #if DEBUG | |
| 674 | if (m_mem.watch_read) | |
| 675 | (*m_mem.watch_read)(m_mem.mar, m_mem.md); | |
| 676 | #endif | |
| 677 | return m_mem.md; | |
| 678 | } | |
| 679 | ||
| 680 | #if ALTO2_HAMMING_CHECK | |
| 681 | /* check for errors on the first access */ | |
| 682 | if (!(m_mem.access & ALTO2_MEM_ODD)) | |
| 683 | m_mem.rmdd = hamming_code(0, m_mem.mar/2, m_mem.rmdd); | |
| 684 | #endif | |
| 685 | m_mem.md = (m_mem.mar & ALTO2_MEM_ODD) ? GET_ODD(m_mem.rmdd) : GET_EVEN(m_mem.rmdd); | |
| 686 | LOG((0,6," MD = RAM[%#o] (%#o)\n", mem.mar, mem.md)); | |
| 687 | ||
| 688 | #if DEBUG | |
| 689 | if (m_mem.watch_read) | |
| 690 | (*m_mem.watch_read)(m_mem.mar, m_mem.md); | |
| 691 | #endif | |
| 692 | ||
| 693 | if (m_mem.access & ALTO2_MEM_ODD) { | |
| 694 | m_mem.access = ALTO2_MEM_NONE; | |
| 695 | } else { | |
| 696 | m_mem.mar ^= ALTO2_MEM_ODD; | |
| 697 | m_mem.access ^= ALTO2_MEM_ODD; | |
| 698 | m_mem.cycle++; | |
| 699 | } | |
| 700 | return m_mem.md; | |
| 701 | } | |
| 702 | ||
| 703 | /** | |
| 704 | * @brief write memory or memory mapped I/O from md to the address in mar | |
| 705 | * | |
| 706 | * @param data data to write to RAM or MMIO | |
| 707 | */ | |
| 708 | void alto2_cpu_device::write_mem(UINT16 data) | |
| 709 | { | |
| 710 | int base_addr; | |
| 711 | ||
| 712 | m_mem.md = data & 0177777; | |
| 713 | if (ALTO2_MEM_NONE == m_mem.access) { | |
| 714 | LOG((0,0," fatal: mem write with no preceding address\n")); | |
| 715 | return; | |
| 716 | } | |
| 717 | ||
| 718 | if (cycle() > m_mem.cycle + 4) { | |
| 719 | LOG((0,0," fatal: mem write (MAR %#o, data %#o) too late (+%lld cyc)\n", m_mem.mar, data, cycle() - mem.cycle)); | |
| 720 | m_mem.access = ALTO2_MEM_NONE; | |
| 721 | return; | |
| 722 | } | |
| 723 | ||
| 724 | base_addr = m_mem.mar & 0177777; | |
| 725 | if (base_addr >= ALTO2_IO_PAGE_BASE) { | |
| 726 | LOG((0,6, " MMIO[%#o] = MD (%#o)\n", base_addr, m_mem.md)); | |
| 727 | ((*this).*mmio_write_fn[base_addr - ALTO2_IO_PAGE_BASE])(base_addr, m_mem.md); | |
| 728 | m_mem.access = ALTO2_MEM_NONE; | |
| 729 | #if DEBUG | |
| 730 | if (m_mem.watch_write) | |
| 731 | ((*this).*m_mem.watch_write)(m_mem.mar, m_mem.md); | |
| 732 | #endif | |
| 733 | return; | |
| 734 | } | |
| 735 | ||
| 736 | LOG((0,6, " RAM[%#o] = MD (%#o)\n", m_mem.mar, m_mem.md)); | |
| 737 | if (m_mem.mar & ALTO2_MEM_ODD) | |
| 738 | PUT_ODD(m_mem.wmdd, m_mem.md); | |
| 739 | else | |
| 740 | PUT_EVEN(m_mem.wmdd, m_mem.md); | |
| 741 | ||
| 742 | #if ALTO2_HAMMING_CHECK | |
| 743 | if (m_mem.access & ALTO2_MEM_RAM) | |
| 744 | m_mem.ram[m_mem.mar/2] = hamming_code(1, m_mem.mar/2, m_mem.wmdd); | |
| 745 | #else | |
| 746 | if (m_mem.access & ALTO2_MEM_RAM) | |
| 747 | m_mem.ram[m_mem.mar/2] = m_mem.wmdd; | |
| 748 | #endif | |
| 749 | ||
| 750 | #if DEBUG | |
| 751 | if (m_mem.watch_write) | |
| 752 | ((*this).*m_mem.watch_write)(m_mem.mar, m_mem.md); | |
| 753 | #endif | |
| 754 | /* don't reset mem.access to permit double word exchange */ | |
| 755 | m_mem.mar ^= ALTO2_MEM_ODD; | |
| 756 | m_mem.access ^= ALTO2_MEM_ODD; | |
| 757 | m_mem.cycle++; | |
| 758 | } | |
| 759 | ||
| 760 | /** | |
| 761 | * @brief install read and/or writte memory mapped I/O handler(s) for a range first to last | |
| 762 | * | |
| 763 | * This function fatal()s, if you specify a bad address for first and/or last. | |
| 764 | * | |
| 765 | * @param first first memory address to map | |
| 766 | * @param last last memory address to map | |
| 767 | * @param rfn pointer to a read function of type 'UINT16 (*read)(UINT32)' | |
| 768 | * @param wfn pointer to a write function of type 'void (*write)(UINT32,UINT16)' | |
| 769 | */ | |
| 770 | void alto2_cpu_device::install_mmio_fn(int first, int last, a2io_rd rfn, a2io_wr wfn) | |
| 771 | { | |
| 772 | int address; | |
| 773 | ||
| 774 | if (first <= ALTO2_IO_PAGE_BASE || last >= (ALTO2_IO_PAGE_BASE + ALTO2_IO_PAGE_SIZE) || first > last) { | |
| 775 | fatal(3, "internal error - bad memory-mapped I/O address\n"); | |
| 776 | } | |
| 777 | ||
| 778 | for (address = first; address <= last; address++) { | |
| 779 | mmio_read_fn[address - ALTO2_IO_PAGE_BASE] = rfn ? rfn : &alto2_cpu_device::bad_mmio_read_fn; | |
| 780 | mmio_write_fn[address - ALTO2_IO_PAGE_BASE] = wfn ? wfn : &alto2_cpu_device::bad_mmio_write_fn; | |
| 781 | } | |
| 782 | } | |
| 783 | ||
| 784 | /** | |
| 785 | * @brief debugger interface to read memory | |
| 786 | * | |
| 787 | * @param addr address to read | |
| 788 | * @return memory contents at address (16 bits) | |
| 789 | */ | |
| 790 | UINT16 alto2_cpu_device::debug_read_mem(UINT32 addr) | |
| 791 | { | |
| 792 | int base_addr = addr & 0177777; | |
| 793 | int data; | |
| 794 | if (base_addr >= ALTO2_IO_PAGE_BASE) { | |
| 795 | data = ((*this).*mmio_read_fn[base_addr - ALTO2_IO_PAGE_BASE])(addr); | |
| 796 | } else { | |
| 797 | data = (addr & ALTO2_MEM_ODD) ? GET_ODD(m_mem.ram[addr/2]) : GET_EVEN(m_mem.ram[addr/2]); | |
| 798 | } | |
| 799 | return data; | |
| 800 | } | |
| 801 | ||
| 802 | /** | |
| 803 | * @brief debugger interface to write memory | |
| 804 | * | |
| 805 | * @param addr address to write | |
| 806 | * @param data data to write (16 bits used) | |
| 807 | */ | |
| 808 | void alto2_cpu_device::debug_write_mem(UINT32 addr, UINT16 data) | |
| 809 | { | |
| 810 | int base_addr = addr & 0177777; | |
| 811 | if (base_addr >= ALTO2_IO_PAGE_BASE) { | |
| 812 | ((*this).*mmio_write_fn[base_addr - ALTO2_IO_PAGE_BASE])(addr, data); | |
| 813 | } else if (addr & ALTO2_MEM_ODD) { | |
| 814 | PUT_ODD(m_mem.ram[addr/2], data); | |
| 815 | } else { | |
| 816 | PUT_EVEN(m_mem.ram[addr/2], data); | |
| 817 | } | |
| 818 | } | |
| 819 | ||
| 820 | /** | |
| 821 | * @brief initialize the memory system | |
| 822 | * | |
| 823 | * Zeroes the memory context, including RAM and installs dummy | |
| 824 | * handlers for the memory mapped I/O area. | |
| 825 | * Sets handlers for access to the memory error address, status, | |
| 826 | * and control registers at 0177024 to 0177026. | |
| 827 | */ | |
| 828 | void alto2_cpu_device::init_memory() | |
| 829 | { | |
| 830 | int addr; | |
| 831 | memset(&m_mem, 0, sizeof(m_mem)); | |
| 832 | ||
| 833 | for (addr = 0; addr < ALTO2_IO_PAGE_SIZE; addr++) { | |
| 834 | mmio_read_fn[addr] = &alto2_cpu_device::bad_mmio_read_fn; | |
| 835 | mmio_write_fn[addr] = &alto2_cpu_device::bad_mmio_write_fn; | |
| 836 | } | |
| 837 | ||
| 838 | /** | |
| 839 | * <PRE> | |
| 840 | * TODO: use madr.a65 and madr.a64 to determine the actual I/O address ranges | |
| 841 | * | |
| 842 | * madr.a65 | |
| 843 | * address line connected to | |
| 844 | * ------------------------------- | |
| 845 | * A0 MAR[11] | |
| 846 | * A1 KEYSEL | |
| 847 | * A2 MAR[7-10] == 0 | |
| 848 | * A3 MAR[12] | |
| 849 | * A4 MAR[13] | |
| 850 | * A5 MAR[14] | |
| 851 | * A6 MAR[15] | |
| 852 | * A7 IOREF (MAR[0-6] == 1) | |
| 853 | * | |
| 854 | * output data connected to | |
| 855 | * ------------------------------- | |
| 856 | * D0 IOSEL0 | |
| 857 | * D1 IOSEL1 | |
| 858 | * D2 IOSEL2 | |
| 859 | * D3 INTIO | |
| 860 | * | |
| 861 | * madr.a64 | |
| 862 | * address line connected to | |
| 863 | * ------------------------------- | |
| 864 | * A0 STORE | |
| 865 | * A1 MAR[11] | |
| 866 | * A2 MAR[7-10] == 0 | |
| 867 | * A3 MAR[12] | |
| 868 | * A4 MAR[13] | |
| 869 | * A5 MAR[14] | |
| 870 | * A6 MAR[15] | |
| 871 | * A7 IOREF (MAR[0-6] == 1) | |
| 872 | * | |
| 873 | * output data connected to | |
| 874 | * ------------------------------- | |
| 875 | * D0 & MISYSCLK -> SELP | |
| 876 | * D1 ^ INTIO -> INTIOX | |
| 877 | * " ^ 1 -> NERRSEL | |
| 878 | * " & WRTCLK -> NRSTE | |
| 879 | * D2 XREG' | |
| 880 | * D3 & MISYSCLK -> LOADERC | |
| 881 | * </PRE> | |
| 882 | */ | |
| 883 | install_mmio_fn(0177024, 0177024, &alto2_cpu_device::mear_r, 0); | |
| 884 | install_mmio_fn(0177025, 0177025, &alto2_cpu_device::mesr_r, &alto2_cpu_device::mesr_w); | |
| 885 | install_mmio_fn(0177026, 0177026, &alto2_cpu_device::mecr_r, &alto2_cpu_device::mecr_w); | |
| 886 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII RAM related functions | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief bs_read_sreg early: drive bus by S register or M (MYL), if rsel is = 0 | |
| 14 | * | |
| 15 | * Note: RSEL == 0 can't be read, because it is decoded as | |
| 16 | * access to the M register (MYL latch access, LREF' in the schematics) | |
| 17 | */ | |
| 18 | void alto2_cpu_device::bs_read_sreg_0() | |
| 19 | { | |
| 20 | UINT8 reg = MIR_RSEL(m_mir); | |
| 21 | UINT16 r; | |
| 22 | ||
| 23 | if (reg) { | |
| 24 | UINT8 bank = m_s_reg_bank[m_task]; | |
| 25 | r = m_s[bank][reg]; | |
| 26 | LOG((0,2," <-S%02o; bus &= S[%o][%02o] (%#o)\n", reg, bank, reg, r)); | |
| 27 | } else { | |
| 28 | r = m_m; | |
| 29 | LOG((0,2," <-S%02o; bus &= M (%#o)\n", reg, r)); | |
| 30 | } | |
| 31 | m_bus &= r; | |
| 32 | } | |
| 33 | ||
| 34 | /** | |
| 35 | * @brief bs_load_sreg early: load S register puts garbage on the bus | |
| 36 | */ | |
| 37 | void alto2_cpu_device::bs_load_sreg_0() | |
| 38 | { | |
| 39 | int r = 0; /* ??? */ | |
| 40 | LOG((0,2," S%02o<- BUS &= garbage (%#o)\n", MIR_RSEL(m_mir), r)); | |
| 41 | m_bus &= r; | |
| 42 | } | |
| 43 | ||
| 44 | /** | |
| 45 | * @brief bs_load_sreg late: load S register from M | |
| 46 | */ | |
| 47 | void alto2_cpu_device::bs_load_sreg_1() | |
| 48 | { | |
| 49 | UINT8 reg = MIR_RSEL(m_mir); | |
| 50 | UINT8 bank = m_s_reg_bank[m_task]; | |
| 51 | m_s[bank][reg] = m_m; | |
| 52 | LOG((0,2," S%02o<- S[%o][%02o] := %#o\n", reg, bank, reg, m_m)); | |
| 53 | } | |
| 54 | ||
| 55 | /** | |
| 56 | * @brief branch to ROM page | |
| 57 | */ | |
| 58 | void alto2_cpu_device::branch_ROM(const char *from, int page) | |
| 59 | { | |
| 60 | (void)from; | |
| 61 | m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + page * ALTO2_UCODE_PAGE_SIZE; | |
| 62 | LOG((0,2," SWMODE: branch from %s to ROM%d (%#o)\n", from, page, m_next2)); | |
| 63 | } | |
| 64 | ||
| 65 | /** | |
| 66 | * @brief branch to RAM page | |
| 67 | */ | |
| 68 | void alto2_cpu_device::branch_RAM(const char *from, int page) | |
| 69 | { | |
| 70 | (void)from; | |
| 71 | m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + ALTO2_UCODE_RAM_BASE + page * ALTO2_UCODE_PAGE_SIZE; | |
| 72 | LOG((0,2," SWMODE: branch from %s to RAM%d\n", from, page, m_next2)); | |
| 73 | } | |
| 74 | ||
| 75 | /** | |
| 76 | * @brief f1_swmode early: switch to micro program counter BUS[6-15] in other bank | |
| 77 | * | |
| 78 | * Note: Jumping to uninitialized CRAM | |
| 79 | * | |
| 80 | * When jumping to uninitialized RAM, which, because of the inverted bits of the | |
| 81 | * microcode words F1(0), F2(0) and LOADL, it is then read as F1=010 (SWMODE), | |
| 82 | * F2=010 (BUSODD) and LOADL=1, loading the M register (MYL latch), too. | |
| 83 | * This causes control to go back to the Emulator task at 0, because the | |
| 84 | * NEXT[0-9] of uninitialized RAM is 0. | |
| 85 | * | |
| 86 | */ | |
| 87 | void alto2_cpu_device::f1_swmode_1() | |
| 88 | { | |
| 89 | /* currently executing in what page? */ | |
| 90 | UINT16 current = m_mpc / ALTO2_UCODE_PAGE_SIZE; | |
| 91 | ||
| 92 | #if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 1) | |
| 93 | switch (current) { | |
| 94 | case 0: | |
| 95 | branch_RAM("ROM0", 0); | |
| 96 | break; | |
| 97 | case 1: | |
| 98 | branch_ROM("RAM0", 0); | |
| 99 | break; | |
| 100 | default: | |
| 101 | fatal(1, "Impossible current mpc %d\n", current); | |
| 102 | } | |
| 103 | #endif | |
| 104 | #if (ALTO2_UCODE_ROM_PAGES == 2 && ALTO2_UCODE_RAM_PAGES == 1) | |
| 105 | UINT16 next = A2_GET16(m_next2,10,1,1); | |
| 106 | ||
| 107 | switch (current) { | |
| 108 | case 0: /* ROM0 to RAM0 or ROM1 */ | |
| 109 | switch (next) { | |
| 110 | case 0: | |
| 111 | branch_RAM("ROM0", 0); | |
| 112 | break; | |
| 113 | case 1: | |
| 114 | branch_ROM("ROM0", 1); | |
| 115 | break; | |
| 116 | default: | |
| 117 | fatal(1, "Impossible next %d\n", next); | |
| 118 | } | |
| 119 | break; | |
| 120 | case 1: /* ROM1 to ROM0 or RAM0 */ | |
| 121 | switch (next) { | |
| 122 | case 0: | |
| 123 | branch_ROM("ROM1", 0); | |
| 124 | break; | |
| 125 | case 1: | |
| 126 | branch_RAM("ROM1", 0); | |
| 127 | break; | |
| 128 | default: | |
| 129 | fatal(1, "Impossible next %d\n", next); | |
| 130 | } | |
| 131 | break; | |
| 132 | case 2: /* RAM0 to ROM0 or ROM1 */ | |
| 133 | switch (next) { | |
| 134 | case 0: | |
| 135 | branch_ROM("RAM0", 0); | |
| 136 | break; | |
| 137 | case 1: | |
| 138 | branch_ROM("RAM0", 1); | |
| 139 | break; | |
| 140 | default: | |
| 141 | fatal(1, "Impossible next %d\n", next); | |
| 142 | } | |
| 143 | break; | |
| 144 | default: | |
| 145 | fatal(1, "Impossible current mpc %d\n", current); | |
| 146 | } | |
| 147 | #endif | |
| 148 | #if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 3) | |
| 149 | UINT16 next = A2_GET16(m_next2,10,1,2); | |
| 150 | ||
| 151 | switch (current) { | |
| 152 | case 0: /* ROM0 to RAM0, RAM2, RAM1, RAM0 */ | |
| 153 | switch (next) { | |
| 154 | case 0: | |
| 155 | branch_RAM("ROM0", 0); | |
| 156 | break; | |
| 157 | case 1: | |
| 158 | branch_RAM("ROM0", 2); | |
| 159 | break; | |
| 160 | case 2: | |
| 161 | branch_RAM("ROM0", 1); | |
| 162 | break; | |
| 163 | case 3: | |
| 164 | branch_RAM("ROM0", 0); | |
| 165 | break; | |
| 166 | default: | |
| 167 | fatal(1, "Impossible next %d\n", next); | |
| 168 | } | |
| 169 | break; | |
| 170 | case 1: /* RAM0 to ROM0, RAM2, RAM1, RAM1 */ | |
| 171 | switch (next) { | |
| 172 | case 0: | |
| 173 | branch_ROM("RAM0", 0); | |
| 174 | break; | |
| 175 | case 1: | |
| 176 | branch_RAM("RAM0", 2); | |
| 177 | break; | |
| 178 | case 2: | |
| 179 | branch_RAM("RAM0", 1); | |
| 180 | break; | |
| 181 | case 3: | |
| 182 | branch_RAM("RAM0", 1); | |
| 183 | break; | |
| 184 | default: | |
| 185 | fatal(1, "Impossible next %d\n", next); | |
| 186 | } | |
| 187 | break; | |
| 188 | case 2: /* RAM1 to ROM0, RAM2, RAM0, RAM0 */ | |
| 189 | switch (next) { | |
| 190 | case 0: | |
| 191 | branch_ROM("RAM1", 0); | |
| 192 | break; | |
| 193 | case 1: | |
| 194 | branch_RAM("RAM1", 2); | |
| 195 | break; | |
| 196 | case 2: | |
| 197 | branch_RAM("RAM1", 0); | |
| 198 | break; | |
| 199 | case 3: | |
| 200 | branch_RAM("RAM1", 0); | |
| 201 | break; | |
| 202 | default: | |
| 203 | fatal(1, "Impossible next %d\n", next); | |
| 204 | } | |
| 205 | break; | |
| 206 | case 3: /* RAM2 to ROM0, RAM1, RAM0, RAM0 */ | |
| 207 | switch (next) { | |
| 208 | case 0: | |
| 209 | branch_ROM("RAM2", 0); | |
| 210 | break; | |
| 211 | case 1: | |
| 212 | branch_RAM("RAM2", 1); | |
| 213 | break; | |
| 214 | case 2: | |
| 215 | branch_RAM("RAM2", 0); | |
| 216 | break; | |
| 217 | case 3: | |
| 218 | branch_RAM("RAM2", 0); | |
| 219 | break; | |
| 220 | default: | |
| 221 | fatal(1, "Impossible next %d\n", next); | |
| 222 | } | |
| 223 | break; | |
| 224 | default: | |
| 225 | fatal(1, "Impossible current mpc %d\n", current); | |
| 226 | } | |
| 227 | #else | |
| 228 | fatal(1, "Impossible control ROM/RAM combination %d/%d\n", ALTO2_UCODE_ROM_PAGES, ALTO2_UCODE_RAM_PAGES); | |
| 229 | #endif | |
| 230 | } | |
| 231 | ||
| 232 | /** | |
| 233 | * @brief f1_wrtram late: start WRTRAM cycle | |
| 234 | */ | |
| 235 | void alto2_cpu_device::f1_wrtram_1() | |
| 236 | { | |
| 237 | m_wrtram_flag = 1; | |
| 238 | LOG((0,2," WRTRAM\n")); | |
| 239 | } | |
| 240 | ||
| 241 | /** | |
| 242 | * @brief f1_rdram late: start RDRAM cycle | |
| 243 | */ | |
| 244 | void alto2_cpu_device::f1_rdram_1() | |
| 245 | { | |
| 246 | m_rdram_flag = 1; | |
| 247 | LOG((0,2," RDRAM\n")); | |
| 248 | } | |
| 249 | ||
| 250 | #if (ALTO2_UCODE_RAM_PAGES == 3) | |
| 251 | ||
| 252 | /** | |
| 253 | * @brief f1_load_rmr late: load the reset mode register | |
| 254 | * | |
| 255 | * F1=013 corresponds to RMR<- in the emulator. In Altos with the 3K | |
| 256 | * RAM option, F1=013 performs RMR<- in all RAM-related tasks, including | |
| 257 | * the emulator. | |
| 258 | */ | |
| 259 | void alto2_cpu_device::f1_load_rmr_1() | |
| 260 | { | |
| 261 | LOG((0,2," RMR<-; BUS (%#o)\n", m_bus)); | |
| 262 | m_reset_mode = m_bus; | |
| 263 | } | |
| 264 | #else // ALTO2_UCODE_RAM_PAGES != 3 | |
| 265 | /** | |
| 266 | * @brief f1_load_srb late: load the S register bank from BUS[12-14] | |
| 267 | */ | |
| 268 | void alto2_cpu_device::f1_load_srb_1() | |
| 269 | { | |
| 270 | m_s_reg_bank[m_task] = A2_GET16(m_bus,16,12,14) % ALTO2_SREG_BANKS; | |
| 271 | LOG((0,2," SRB<-; srb[%d] := %#o\n", m_task, m_s_reg_bank[m_task])); | |
| 272 | } | |
| 273 | #endif | |
| 274 | ||
| 275 | /** | |
| 276 | * @brief RAM related task slots initialization | |
| 277 | */ | |
| 278 | void alto2_cpu_device::init_ram(int task) | |
| 279 | { | |
| 280 | m_ram_related[task] = true; | |
| 281 | ||
| 282 | set_bs(task, bs_ram_read_slocation, &alto2_cpu_device::bs_read_sreg_0, 0); | |
| 283 | set_bs(task, bs_ram_load_slocation, &alto2_cpu_device::bs_load_sreg_0, &alto2_cpu_device::bs_load_sreg_1); | |
| 284 | ||
| 285 | set_f1(task, f1_ram_swmode, 0, &alto2_cpu_device::f1_swmode_1); | |
| 286 | set_f1(task, f1_ram_wrtram, 0, &alto2_cpu_device::f1_wrtram_1); | |
| 287 | set_f1(task, f1_ram_rdram, 0, &alto2_cpu_device::f1_rdram_1); | |
| 288 | #if (ALTO2_UCODE_RAM_PAGES == 3) | |
| 289 | set_f1(task, f1_ram_load_rmr, 0, &alto2_cpu_device::f1_load_rmr_1); | |
| 290 | #else // ALTO2_UCODE_RAM_PAGES != 3 | |
| 291 | set_f1(task, f1_ram_load_srb, 0, &alto2_cpu_device::f1_load_srb_1); | |
| 292 | #endif | |
| 293 | } | |
| 294 |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII display horizontal task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief f1_dht_block early: disable the display word task | |
| 14 | */ | |
| 15 | void alto2_cpu_device::f1_dht_block_0() | |
| 16 | { | |
| 17 | m_dsp.dht_blocks = 1; | |
| 18 | /* clear the wakeup for the display horizontal task */ | |
| 19 | m_task_wakeup &= ~(1 << m_task); | |
| 20 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 21 | } | |
| 22 | ||
| 23 | /** | |
| 24 | * @brief f2_dht_setmode late: set the next scanline's mode inverse and half clock and branch | |
| 25 | * | |
| 26 | * BUS[0] selects the pixel clock (0), or half pixel clock (1) | |
| 27 | * BUS[1] selects normal mode (0), or inverse mode (1) | |
| 28 | * | |
| 29 | * The current BUS[0] drives the NEXT[09] line, i.e. branches to 0 or 1 | |
| 30 | */ | |
| 31 | void alto2_cpu_device::f2_dht_setmode_1() | |
| 32 | { | |
| 33 | UINT16 r = A2_GET32(m_bus,16,0,0); | |
| 34 | m_dsp.setmode = m_bus; | |
| 35 | LOG((0,2," SETMODE<- BUS (%#o), branch on BUS[0] (%#o | %#o)\n", m_bus, m_next2, r)); | |
| 36 | m_next2 |= r; | |
| 37 | } | |
| 38 | ||
| 39 | /** | |
| 40 | * @brief called by the CPU when the display horizontal task becomes active | |
| 41 | */ | |
| 42 | void alto2_cpu_device::activate_dht() | |
| 43 | { | |
| 44 | /* TODO: what do we do here? */ | |
| 45 | m_task_wakeup &= ~(1 << m_task); | |
| 46 | } | |
| 47 | ||
| 48 | /** | |
| 49 | * @brief initialize the display horizontal task | |
| 50 | * | |
| 51 | * @param task task number | |
| 52 | */ | |
| 53 | void alto2_cpu_device::init_dht(int task) | |
| 54 | { | |
| 55 | set_f1(task, f1_block, &alto2_cpu_device::f1_dht_block_0, 0); | |
| 56 | set_f2(task, f2_dht_evenfield, 0, &alto2_cpu_device::f2_evenfield_1); | |
| 57 | set_f2(task, f2_dht_setmode, 0, &alto2_cpu_device::f2_dht_setmode_1); | |
| 58 | m_active_callback[task] = &alto2_cpu_device::activate_dht; | |
| 59 | } | |
| 60 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII disk word task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief block the disk word task | |
| 14 | */ | |
| 15 | void alto2_cpu_device::f1_kwd_block_0() | |
| 16 | { | |
| 17 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 18 | disk_block(m_task); | |
| 19 | } | |
| 20 | ||
| 21 | /** | |
| 22 | * @brief disk word task slot initialization | |
| 23 | */ | |
| 24 | void alto2_cpu_device::init_kwd(int task) | |
| 25 | { | |
| 26 | set_bs(task, bs_kwd_read_kstat, &alto2_cpu_device::bs_read_kstat_0, 0); | |
| 27 | set_bs(task, bs_kwd_read_kdata, &alto2_cpu_device::bs_read_kdata_0, 0); | |
| 28 | ||
| 29 | set_f1(task, f1_block, &alto2_cpu_device::f1_kwd_block_0, 0); | |
| 30 | ||
| 31 | set_f1(task, f1_task_10, 0, 0); | |
| 32 | set_f1(task, f1_kwd_strobe, 0, &alto2_cpu_device::f1_strobe_1); | |
| 33 | set_f1(task, f1_kwd_load_kstat, 0, &alto2_cpu_device::f1_load_kstat_1); | |
| 34 | set_f1(task, f1_kwd_increcno, 0, &alto2_cpu_device::f1_increcno_1); | |
| 35 | set_f1(task, f1_kwd_clrstat, 0, &alto2_cpu_device::f1_clrstat_1); | |
| 36 | set_f1(task, f1_kwd_load_kcom, 0, &alto2_cpu_device::f1_load_kcom_1); | |
| 37 | set_f1(task, f1_kwd_load_kadr, 0, &alto2_cpu_device::f1_load_kadr_1); | |
| 38 | set_f1(task, f1_kwd_load_kdata, 0, &alto2_cpu_device::f1_load_kdata_1); | |
| 39 | ||
| 40 | set_f2(task, f2_kwd_init, 0, &alto2_cpu_device::f2_init_1); | |
| 41 | set_f2(task, f2_kwd_rwc, 0, &alto2_cpu_device::f2_rwc_1); | |
| 42 | set_f2(task, f2_kwd_recno, 0, &alto2_cpu_device::f2_recno_1); | |
| 43 | set_f2(task, f2_kwd_xfrdat, 0, &alto2_cpu_device::f2_xfrdat_1); | |
| 44 | set_f2(task, f2_kwd_swrnrdy, 0, &alto2_cpu_device::f2_swrnrdy_1); | |
| 45 | set_f2(task, f2_kwd_nfer, 0, &alto2_cpu_device::f2_nfer_1); | |
| 46 | set_f2(task, f2_kwd_strobon, 0, &alto2_cpu_device::f2_strobon_1); | |
| 47 | set_f2(task, f2_task_17, 0, 0); | |
| 48 | } | |
| 49 | ||
| 50 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII disk sector task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** @brief block the disk sector task */ | |
| 13 | void alto2_cpu_device::f1_ksec_block_0(void) | |
| 14 | { | |
| 15 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 16 | disk_block(m_task); | |
| 17 | } | |
| 18 | ||
| 19 | /** | |
| 20 | * @brief disk sector task slot initialization | |
| 21 | */ | |
| 22 | void alto2_cpu_device::init_ksec(int task) | |
| 23 | { | |
| 24 | set_bs(task, bs_ksec_read_kstat, &alto2_cpu_device::bs_read_kstat_0, 0); | |
| 25 | set_bs(task, bs_ksec_read_kdata, &alto2_cpu_device::bs_read_kdata_0, 0); | |
| 26 | ||
| 27 | set_f1(task, f1_block, &alto2_cpu_device::f1_ksec_block_0, 0); | |
| 28 | ||
| 29 | set_f1(task, f1_task_10, 0, 0); | |
| 30 | set_f1(task, f1_ksec_strobe, 0, &alto2_cpu_device::f1_strobe_1); | |
| 31 | set_f1(task, f1_ksec_load_kstat, 0, &alto2_cpu_device::f1_load_kstat_1); | |
| 32 | set_f1(task, f1_ksec_increcno, 0, &alto2_cpu_device::f1_increcno_1); | |
| 33 | set_f1(task, f1_ksec_clrstat, 0, &alto2_cpu_device::f1_clrstat_1); | |
| 34 | set_f1(task, f1_ksec_load_kcom, 0, &alto2_cpu_device::f1_load_kcom_1); | |
| 35 | set_f1(task, f1_ksec_load_kadr, 0, &alto2_cpu_device::f1_load_kadr_1); | |
| 36 | set_f1(task, f1_ksec_load_kdata, 0, &alto2_cpu_device::f1_load_kdata_1); | |
| 37 | ||
| 38 | set_f2(task, f2_ksec_init, 0, &alto2_cpu_device::f2_init_1); | |
| 39 | set_f2(task, f2_ksec_rwc, 0, &alto2_cpu_device::f2_rwc_1); | |
| 40 | set_f2(task, f2_ksec_recno, 0, &alto2_cpu_device::f2_recno_1); | |
| 41 | set_f2(task, f2_ksec_xfrdat, 0, &alto2_cpu_device::f2_xfrdat_1); | |
| 42 | set_f2(task, f2_ksec_swrnrdy, 0, &alto2_cpu_device::f2_swrnrdy_1); | |
| 43 | set_f2(task, f2_ksec_nfer, 0, &alto2_cpu_device::f2_nfer_1); | |
| 44 | set_f2(task, f2_ksec_strobon, 0, &alto2_cpu_device::f2_strobon_1); | |
| 45 | set_f2(task, f2_task_17, 0, 0); | |
| 46 | ||
| 47 | m_task_wakeup |= 1 << task; | |
| 48 | } | |
| 49 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII emulator task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** @brief CTL2K_U3 address line for F2 function */ | |
| 13 | #define CTL2K_U3(f2) (f2 == f2_emu_idisp ? 0x80 : 0x00) | |
| 14 | ||
| 15 | /** @brief set non-zero to use expressions after the schematics for RSEL[3-4] */ | |
| 16 | #define USE_SCHEMATICS_RSEL 0 | |
| 17 | ||
| 18 | /** | |
| 19 | * width,from,to of the 16 bit instruction register | |
| 20 | * 1 1 1 1 1 1 | |
| 21 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 | |
| 22 | * ============================================================= | |
| 23 | * x - - - - - - - - - - - - - - - arithmetic operation | |
| 24 | * 0 m m - - - - - - - - - - - - - memory function | |
| 25 | * 0 0 0 - - - - - - - - - - - - - jump functions | |
| 26 | * 0 0 1 d d - - - - - - - - - - - LDA dstAC | |
| 27 | * 0 1 0 d d - - - - - - - - - - - STA dstAC | |
| 28 | * 0 1 1 - - - - - - - - - - - - - augmented functions | |
| 29 | * 1 s s - - - - - - - - - - - - - source accumulator (0-3) | |
| 30 | * 1 - - d d - - - - - - - - - - - destination accumulator (0-3) | |
| 31 | * 1 s s d d x x x - - - - - - - - accumulator function | |
| 32 | * 1 s s d d 0 0 0 - - - - - - - - COM dstAC, srcAC | |
| 33 | * 1 s s d d 0 0 1 - - - - - - - - NEG dstAC, srcAC | |
| 34 | * 1 s s d d 0 1 0 - - - - - - - - MOV dstAC, srcAC | |
| 35 | * 1 s s d d 0 1 1 - - - - - - - - INC dstAC, srcAC | |
| 36 | * 1 s s d d 1 0 0 - - - - - - - - ADC dstAC, srcAC | |
| 37 | * 1 s s d d 1 0 1 - - - - - - - - SUB dstAC, srcAC | |
| 38 | * 1 s s d d 1 1 0 - - - - - - - - ADD dstAC, srcAC | |
| 39 | * 1 s s d d 1 1 1 - - - - - - - - AND dstAC, srcAC | |
| 40 | * 1 - - - - - - - x x - - - - - - shift operation | |
| 41 | * 1 - - - - - - - 0 0 - - - - - - nothing | |
| 42 | * 1 - - - - - - - 0 1 - - - - - - rotate left through carry | |
| 43 | * 1 - - - - - - - 1 0 - - - - - - rotate right through carry | |
| 44 | * 1 - - - - - - - 1 1 - - - - - - swap byte halves | |
| 45 | * 1 - - - - - - - - - x x - - - - carry in mode | |
| 46 | * 1 - - - - - - - - - 0 0 - - - - nothing | |
| 47 | * 1 - - - - - - - - - 0 1 - - - - Z carry in is zero | |
| 48 | * 1 - - - - - - - - - 1 0 - - - - O carry in is one | |
| 49 | * 1 - - - - - - - - - 1 1 - - - - C carry in is complemented carry | |
| 50 | * 1 - - - - - - - - - - - x - - - NL | |
| 51 | * - - - - - - - - - - - - - x x x conditional execution | |
| 52 | * - - - - - - - - - - - - - 0 0 0 NVR never skip | |
| 53 | * - - - - - - - - - - - - - 0 0 1 SKP always skip | |
| 54 | * - - - - - - - - - - - - - 0 1 0 SZC skip if carry result is zero | |
| 55 | * - - - - - - - - - - - - - 0 1 1 SNC skip if carry result is non-zero | |
| 56 | * - - - - - - - - - - - - - 1 0 0 SZR skip if 16 bit result is zero | |
| 57 | * - - - - - - - - - - - - - 1 0 1 SNR skip if 16 bit result is non-zero | |
| 58 | * - - - - - - - - - - - - - 1 1 0 SEZ skip if either result is zero | |
| 59 | * - - - - - - - - - - - - - 1 1 1 SBN skip if both results are non-zero | |
| 60 | */ | |
| 61 | #define IR_ARITH(ir) A2_GET16(ir,16, 0, 0) | |
| 62 | #define IR_SrcAC(ir) A2_GET16(ir,16, 1, 2) | |
| 63 | #define IR_DstAC(ir) A2_GET16(ir,16, 3, 4) | |
| 64 | #define IR_AFunc(ir) A2_GET16(ir,16, 5, 7) | |
| 65 | #define IR_SH(ir) A2_GET16(ir,16, 8, 9) | |
| 66 | #define IR_CY(ir) A2_GET16(ir,16,10,11) | |
| 67 | #define IR_NL(ir) A2_GET16(ir,16,12,12) | |
| 68 | #define IR_SK(ir) A2_GET16(ir,16,13,15) | |
| 69 | ||
| 70 | #define IR_MFunc(ir) A2_GET16(ir,16, 1, 2) | |
| 71 | #define IR_JFunc(ir) A2_GET16(ir,16, 3, 4) | |
| 72 | #define IR_I(ir) A2_GET16(ir,16, 5, 5) | |
| 73 | #define IR_X(ir) A2_GET16(ir,16, 6, 7) | |
| 74 | #define IR_DISP(ir) A2_GET16(ir,16, 8,15) | |
| 75 | #define IR_AUGFUNC(ir) A2_GET16(ir,16, 3, 7) | |
| 76 | ||
| 77 | #define op_MFUNC_MASK 0060000 //!< instruction register memory function mask | |
| 78 | #define op_MFUNC_JUMP 0000000 //!< jump functions value | |
| 79 | #define op_JUMP_MASK 0014000 //!< jump functions mask | |
| 80 | #define op_JMP 0000000 //!< jump | |
| 81 | #define op_JSR 0004000 //!< jump to subroutine | |
| 82 | #define op_ISZ 0010000 //!< increment and skip if zero | |
| 83 | #define op_DSZ 0014000 //!< decrement and skip if zero | |
| 84 | #define op_LDA 0020000 //!< load accu functions value | |
| 85 | #define op_STA 0040000 //!< store accu functions value | |
| 86 | #define op_AUGMENTED 0060000 //!< store accu functions value | |
| 87 | #define op_AUGM_MASK 0077400 //!< mask covering all augmented functions | |
| 88 | #define op_AUGM_NODISP 0061000 //!< augmented functions w/o displacement | |
| 89 | #define op_AUGM_SUBFUNC 0000037 //!< mask for augmented subfunctions in DISP | |
| 90 | #define op_CYCLE 0060000 //!< cycle AC0 | |
| 91 | #define op_NODISP 0061000 //!< NODISP: opcodes without displacement | |
| 92 | #define op_DIR 0061000 //!< disable interrupts | |
| 93 | #define op_EIR 0061001 //!< enable interrupts | |
| 94 | #define op_BRI 0061002 //!< branch and return from interrupt | |
| 95 | #define op_RCLK 0061003 //!< read clock to AC0, AC1 | |
| 96 | #define op_SIO 0061004 //!< start I/O | |
| 97 | #define op_BLT 0061005 //!< block transfer | |
| 98 | #define op_BLKS 0061006 //!< block set value | |
| 99 | #define op_SIT 0061007 //!< start interval timer | |
| 100 | #define op_JMPRAM 0061010 //!< jump to microcode RAM (actually ROM, too) | |
| 101 | #define op_RDRAM 0061011 //!< read microcode RAM | |
| 102 | #define op_WRTRAM 0061012 //!< write microcode RAM | |
| 103 | #define op_DIRS 0061013 //!< disable interrupts, and skip, if already disabled | |
| 104 | #define op_VERS 0061014 //!< get microcode version in AC0 | |
| 105 | #define op_DREAD 0061015 //!< double word read (Alto II) | |
| 106 | #define op_DWRITE 0061016 //!< double word write (Alto II) | |
| 107 | #define op_DEXCH 0061017 //!< double word exchange (Alto II) | |
| 108 | #define op_MUL 0061020 //!< unsigned multiply | |
| 109 | #define op_DIV 0061021 //!< unsigned divide | |
| 110 | #define op_DIAGNOSE1 0061022 //!< write two different accus in fast succession | |
| 111 | #define op_DIAGNOSE2 0061023 //!< write Hamming code and memory | |
| 112 | #define op_BITBLT 0061024 //!< bit-aligned block transfer | |
| 113 | #define op_XMLDA 0061025 //!< load accu AC0 from extended memory (Alto II/XM) | |
| 114 | #define op_XMSTA 0061026 //!< store accu AC0 to extended memory (Alto II/XM) | |
| 115 | #define op_JSRII 0064400 //!< jump to subroutine PC relative, doubly indirect | |
| 116 | #define op_JSRIS 0065000 //!< jump to subroutine AC2 relative, doubly indirect | |
| 117 | #define op_CONVERT 0067000 //!< convert bitmapped font to bitmap | |
| 118 | #define op_ARITH_MASK 0103400 //!< mask for arithmetic functions | |
| 119 | #define op_COM 0100000 //!< one's complement | |
| 120 | #define op_NEG 0100400 //!< two's complement | |
| 121 | #define op_MOV 0101000 //!< accu transfer | |
| 122 | #define op_INC 0101400 //!< increment | |
| 123 | #define op_ADC 0102000 //!< add one's complement | |
| 124 | #define op_SUB 0102400 //!< subtract by adding two's complement | |
| 125 | #define op_ADD 0103000 //!< add | |
| 126 | #define op_AND 0103400 //!< logical and | |
| 127 | ||
| 128 | #define ea_DIRECT 0000000 //!< effective address is direct | |
| 129 | #define ea_INDIRECT 0002000 //!< effective address is indirect | |
| 130 | #define ea_MASK 0001400 //!< mask for effective address modes | |
| 131 | #define ea_PAGE0 0000000 //!< e is page 0 address | |
| 132 | #define ea_PCREL 0000400 //!< e is PC + signed displacement | |
| 133 | #define ea_AC2REL 0001000 //!< e is AC2 + signed displacement | |
| 134 | #define ea_AC3REL 0001400 //!< e is AC3 + signed displacement | |
| 135 | ||
| 136 | ||
| 137 | #define sh_MASK 0000300 //!< shift mode mask (do novel shifts) | |
| 138 | #define sh_L 0000100 //!< rotate left through carry | |
| 139 | #define sh_R 0000200 //!< rotate right through carry | |
| 140 | #define sh_S 0000300 //!< swap byte halves | |
| 141 | ||
| 142 | #define cy_MASK 0000060 //!< carry in mode mask | |
| 143 | #define cy_Z 0000020 //!< carry in is zero | |
| 144 | #define cy_O 0000040 //!< carry in is one | |
| 145 | #define cy_C 0000060 //!< carry in is complemented carry | |
| 146 | ||
| 147 | #define nl_MASK 0000010 //!< no-load mask | |
| 148 | #define nl_NONE 0000010 //!< do not load DstAC nor carry | |
| 149 | ||
| 150 | #define sk_MASK 0000007 //!< skip mask | |
| 151 | #define sk_NVR 0000000 //!< never skip | |
| 152 | #define sk_SKP 0000001 //!< always skip | |
| 153 | #define sk_SZC 0000002 //!< skip if carry result is zero | |
| 154 | #define sk_SNC 0000003 //!< skip if carry result is non-zero | |
| 155 | #define sk_SZR 0000004 //!< skip if 16-bit result is zero | |
| 156 | #define sk_SNR 0000005 //!< skip if 16-bit result is non-zero | |
| 157 | #define sk_SEZ 0000006 //!< skip if either result is zero | |
| 158 | #define sk_SBN 0000007 //!< skip if both results are non-zero | |
| 159 | ||
| 160 | /** | |
| 161 | * @brief register selection | |
| 162 | * | |
| 163 | * <PRE> | |
| 164 | * From the schematics: 08_ALU, page 6 (PDF page 4) | |
| 165 | * | |
| 166 | * EMACT emulator task active | |
| 167 | * F2[0-2]=111b <-ACSOURCE and F2_17 | |
| 168 | * F2[0-2]=101b DNS<- and ACDEST<- | |
| 169 | * | |
| 170 | * u49 (8 input NAND 74S30) | |
| 171 | * ---------------------------------------------- | |
| 172 | * F2[0] & F2[2] & F2[1]' & IR[03]' & EMACT | |
| 173 | * | |
| 174 | * F2[0-2] IR[03] EMACT output u49pin8 | |
| 175 | * -------------------------------------- | |
| 176 | * 101 0 1 0 | |
| 177 | * all others 1 | |
| 178 | * | |
| 179 | * | |
| 180 | * u59 (8 input NAND 74S30) | |
| 181 | * ---------------------------------------------- | |
| 182 | * F2[0] & F2[2] & F2[1] & IR[01]' & EMACT | |
| 183 | * | |
| 184 | * F2[0-2] IR[01] EMACT output u59pin8 | |
| 185 | * -------------------------------------- | |
| 186 | * 111 0 1 0 | |
| 187 | * all others 1 | |
| 188 | * | |
| 189 | * u70d (2 input NOR 74S02 used as inverter) | |
| 190 | * --------------------------------------------- | |
| 191 | * RSEL3 -> RSEL3' | |
| 192 | * | |
| 193 | * u79b (3 input NAND 74S10) | |
| 194 | * --------------------------------------------- | |
| 195 | * u49pin8 u59pin8 RSEL3' output 6RA3 | |
| 196 | * ------------------------------------- | |
| 197 | * 1 1 1 0 | |
| 198 | * 0 x x 1 | |
| 199 | * x 0 x 1 | |
| 200 | * x x 0 1 | |
| 201 | * | |
| 202 | * | |
| 203 | * u60 (8 input NAND 74S30) | |
| 204 | * ---------------------------------------------- | |
| 205 | * F2[0] & F2[2] & F2[1]' & IR[02]' & EMACT | |
| 206 | * | |
| 207 | * F2[0-2] IR[02] EMACT output u60pin8 | |
| 208 | * -------------------------------------- | |
| 209 | * 101 0 1 0 | |
| 210 | * all others 1 | |
| 211 | * | |
| 212 | * u50 (8 input NAND 74S30) | |
| 213 | * ---------------------------------------------- | |
| 214 | * F2[0] & F2[2] & F2[1] & IR[04]' & EMACT | |
| 215 | * | |
| 216 | * F2[0-2] IR[04] EMACT output u50pin8 | |
| 217 | * -------------------------------------- | |
| 218 | * 111 0 1 0 | |
| 219 | * all others 1 | |
| 220 | * | |
| 221 | * u70c (2 input NOR 74S02 used as inverter) | |
| 222 | * --------------------------------------------- | |
| 223 | * RSEL4 -> RSEL4' | |
| 224 | * | |
| 225 | * | |
| 226 | * u79c (3 input NAND 74S10) | |
| 227 | * --------------------------------------------- | |
| 228 | * u60pin8 u50pin8 RSEL4' output 8RA4 | |
| 229 | * ------------------------------------- | |
| 230 | * 1 1 1 0 | |
| 231 | * 0 x x 1 | |
| 232 | * x 0 x 1 | |
| 233 | * x x 0 1 | |
| 234 | * | |
| 235 | * BUG?: schematics seem to have swapped IR(04)' and IR(02)' inputs for the | |
| 236 | * RA4 decoding, because SrcAC is selected from IR[1-2]? | |
| 237 | * </PRE> | |
| 238 | */ | |
| 239 | ||
| 240 | #if USE_SCHEMATICS_RSEL | |
| 241 | #define RA3(f2,ir,rs) (\ | |
| 242 | (((ALTO2_GET(f2,4,0,2)==5 && ALTO2_GET(ir,16,3,3)==0) ? 0 : 1) && \ | |
| 243 | ((ALTO2_GET(f2,4,0,2)==7 && ALTO2_GET(ir,16,1,1)==0) ? 0 : 1) && \ | |
| 244 | (ALTO2_GET(rs,5,3,3)==0)) ? 0 : 1) | |
| 245 | ||
| 246 | #define RA4(f2,ir,rs) (\ | |
| 247 | (((ALTO2_GET(f2,4,0,2)==5 && ALTO2_GET(ir,16,4,4)==0) ? 0 : 1) && \ | |
| 248 | ((ALTO2_GET(f2,4,0,2)==7 && ALTO2_GET(ir,16,2,2)==0) ? 0 : 1) && \ | |
| 249 | (ALTO2_GET(rs,5,4,4)==0)) ? 0 : 1) | |
| 250 | #endif /* USE_SCHEMATICS_RSEL */ | |
| 251 | ||
| 252 | /** | |
| 253 | * @brief bs_disp early: drive bus by IR[8-15], possibly sign extended | |
| 254 | * | |
| 255 | * The high order bits of IR cannot be read directly, but the | |
| 256 | * displacement field of IR (8 low order bits) may be read with | |
| 257 | * the <-DISP bus source. If the X field of the instruction is | |
| 258 | * zero (i.e., it specifies page 0 addressing), then the DISP | |
| 259 | * field of the instruction is put on BUS[8-15] and BUS[0-7] | |
| 260 | * is zeroed. If the X field of the instruction is non-zero | |
| 261 | * (i.e. it specifies PC-relative or base-register addressing) | |
| 262 | * then the DISP field is sign-extended and put on the bus. | |
| 263 | * | |
| 264 | */ | |
| 265 | void alto2_cpu_device::bs_emu_disp_0() | |
| 266 | { | |
| 267 | UINT16 r = IR_DISP(m_emu.ir); | |
| 268 | if (IR_X(m_emu.ir)) { | |
| 269 | r = ((signed char)r) & 0177777; | |
| 270 | } | |
| 271 | LOG((0,2, " <-DISP (%06o)\n", r)); | |
| 272 | m_bus &= r; | |
| 273 | } | |
| 274 | ||
| 275 | /** | |
| 276 | * @brief f1_block early: block task | |
| 277 | * | |
| 278 | * The task request for the active task is cleared | |
| 279 | */ | |
| 280 | void alto2_cpu_device::f1_emu_block_0() | |
| 281 | { | |
| 282 | #if 0 | |
| 283 | CPU_CLR_TASK_WAKEUP(m_task); | |
| 284 | LOG((0,2, " BLOCK %02o:%s\n", m_task, task_name(m_task))); | |
| 285 | #elif 0 | |
| 286 | fatal(1, "Emulator task want's to BLOCK.\n" \ | |
| 287 | "%s-%04o: r:%02o af:%02o bs:%02o f1:%02o f2:%02o" \ | |
| 288 | " t:%o l:%o next:%05o next2:%05o cycle:%lld\n", | |
| 289 | task_name(m_task), m_mpc, | |
| 290 | m_rsel, MIR_ALUF, MIR_BS, | |
| 291 | MIR_F1, MIR_F2, | |
| 292 | MIR_T, MIR_L, | |
| 293 | MIR_NEXT, m_next2, | |
| 294 | ntime() / CPU_MICROCYCLE_TIME); | |
| 295 | #else | |
| 296 | /* just ignore (?) */ | |
| 297 | #endif | |
| 298 | } | |
| 299 | ||
| 300 | /** | |
| 301 | * @brief f1_load_rmr late: load the reset mode register | |
| 302 | */ | |
| 303 | void alto2_cpu_device::f1_emu_load_rmr_1() | |
| 304 | { | |
| 305 | LOG((0,2," RMR<-; BUS (%#o)\n", m_bus)); | |
| 306 | m_reset_mode = m_bus; | |
| 307 | } | |
| 308 | ||
| 309 | /** | |
| 310 | * @brief f1_load_esrb late: load the extended S register bank from BUS[12-14] | |
| 311 | */ | |
| 312 | void alto2_cpu_device::f1_emu_load_esrb_1() | |
| 313 | { | |
| 314 | LOG((0,2," ESRB<-; BUS[12-14] (%#o)\n", m_bus)); | |
| 315 | m_s_reg_bank[m_task] = A2_GET32(m_bus,16,12,14); | |
| 316 | } | |
| 317 | ||
| 318 | /** | |
| 319 | * @brief f1_rsnf early: drive the bus from the Ethernet node ID | |
| 320 | * | |
| 321 | * TODO: move this to the Ethernet code? It's really a emulator | |
| 322 | * specific function that is decoded by the Ethernet card. | |
| 323 | */ | |
| 324 | void alto2_cpu_device::f1_rsnf_0() | |
| 325 | { | |
| 326 | UINT16 r = 0177400 | m_ether_id; | |
| 327 | LOG((0,2," <-RSNF; (%#o)\n", r)); | |
| 328 | m_bus &= r; | |
| 329 | } | |
| 330 | ||
| 331 | /** | |
| 332 | * @brief f1_startf early: defines commands for for I/O hardware, including Ethernet | |
| 333 | * <PRE> | |
| 334 | * (SIO) Start I/O is included to facilitate I/O control, It places the contents of | |
| 335 | * AC0 on the processor bus and executes the STARTF function (F1 = 17B). By convention, | |
| 336 | * bits of AC0 must be "1" in order to signal devices. See Appendix C for a summary of | |
| 337 | * assigned bits. | |
| 338 | * Bit 0 100000B Standard Alto: Software boot feature | |
| 339 | * Bit 14 000002B Standard Alto: Ethernet | |
| 340 | * Bit 15 000001B Standard Alto: Ethernet | |
| 341 | * If bit 0 of AC0 is 1, and if an Ethernet board is plugged into the Alto, the machine | |
| 342 | * will boot, just as if the "boot button" were pressed (see sections 3.4, 8.4 and 9.2.2 | |
| 343 | * for discussions of bootstrapping). | |
| 344 | * | |
| 345 | * SIO also returns a result in AC0. If the Ethernet hardware is installed, the serial | |
| 346 | * number and/or Ethernet host address of the machine (0-377B) is loaded into AC0[8-15]. | |
| 347 | * (On Alto I, the serial number and Ethernet host address are equivalent; on Alto II, | |
| 348 | * the value loaded into AC0 is the Ethernet host address only.) If Ethernet hardware | |
| 349 | * is missing, AC0[8-15] = 377B. Microcode installed after June 1976, which this manual | |
| 350 | * describes, returns AC0[0] = 0. Microcode installed prior to June 1976 returns | |
| 351 | * AC0[0] = 1; this is a quick way to acquire the approximate vintage of a machine's | |
| 352 | * microcode. | |
| 353 | * </PRE> | |
| 354 | * | |
| 355 | * TODO: move this to the Ethernet code? It's really a emulator | |
| 356 | * specific function that is decoded by the Ethernet card. | |
| 357 | */ | |
| 358 | void alto2_cpu_device::f1_startf_0() | |
| 359 | { | |
| 360 | LOG((0,2," STARTF (BUS is %06o)\n", m_bus)); | |
| 361 | /* TODO: what do we do here? reset the CPU on bit 0? */ | |
| 362 | if (A2_BIT32(m_bus,16,0)) { | |
| 363 | LOG((0,2,"**** Software boot feature\n")); | |
| 364 | soft_reset(); | |
| 365 | } else { | |
| 366 | eth_startf(); | |
| 367 | } | |
| 368 | } | |
| 369 | ||
| 370 | /** | |
| 371 | * @brief f2_busodd late: branch on odd bus | |
| 372 | */ | |
| 373 | void alto2_cpu_device::f2_busodd_1() | |
| 374 | { | |
| 375 | UINT16 r = m_bus & 1; | |
| 376 | LOG((0,2," BUSODD; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); | |
| 377 | m_next2 |= r; | |
| 378 | } | |
| 379 | ||
| 380 | #if 1 | |
| 381 | /** | |
| 382 | * @brief f2_magic late: shift and use T | |
| 383 | */ | |
| 384 | void alto2_cpu_device::f2_magic_1() | |
| 385 | { | |
| 386 | int XC; | |
| 387 | switch (MIR_F1(m_mir)) { | |
| 388 | case f1_l_lsh_1: // <-L MLSH 1 | |
| 389 | XC = (m_t >> 15) & 1; | |
| 390 | m_shifter = (m_l << 1) & 0177777; | |
| 391 | m_shifter |= XC; | |
| 392 | LOG((0,2," <-L MLSH 1 (shifer:%06o XC:%o)", m_shifter, XC)); | |
| 393 | break; | |
| 394 | case f1_l_rsh_1: // <-L MRSH 1 | |
| 395 | XC = m_t & 1; | |
| 396 | m_shifter = m_l >> 1; | |
| 397 | m_shifter |= XC << 15; | |
| 398 | LOG((0,2," <-L MRSH 1 (shifter:%06o XC:%o)", m_shifer, XC)); | |
| 399 | break; | |
| 400 | case f1_l_lcy_8: // <-L LCY 8 | |
| 401 | default: // other | |
| 402 | break; | |
| 403 | } | |
| 404 | } | |
| 405 | #endif | |
| 406 | ||
| 407 | /** | |
| 408 | * @brief dns early: modify RESELECT with DstAC = (3 - IR[3-4]) | |
| 409 | */ | |
| 410 | void alto2_cpu_device::f2_load_dns_0() | |
| 411 | { | |
| 412 | #if USE_SCHEMATICS_RSEL | |
| 413 | A2_PUT8(m_rsel, 5, 3, 3, RA3(f2_emu_load_dns, m_emu.ir, m_rsel)); | |
| 414 | A2_PUT8(m_rsel, 5, 4, 4, RA4(f2_emu_load_dns, m_emu.ir, m_rsel)); | |
| 415 | #else | |
| 416 | A2_PUT8(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3); | |
| 417 | #endif | |
| 418 | LOG((0,2," DNS<-; rsel := DstAC (%#o %s)\n", m_rsel, r_name[m_rsel])); | |
| 419 | } | |
| 420 | ||
| 421 | /** | |
| 422 | * @brief f2_load_dns late: do novel shifts | |
| 423 | * | |
| 424 | * <PRE> | |
| 425 | * New emulator carry is selected by instruction register | |
| 426 | * bits CY = IR[10-11]. R register and emulator carry are | |
| 427 | * loaded only if NL = IR[12] is 0. | |
| 428 | * SKIP is set according to SK = IR[13-15]. | |
| 429 | * | |
| 430 | * CARRY = !m_emu.cy | |
| 431 | * exorB = IR11 ^ IR10 | |
| 432 | * ORA = !(exorB | CARRY) | |
| 433 | * = (exorB | CARRY) ^ 1 | |
| 434 | * exorC = ORA ^ !IR11 | |
| 435 | * = ORA ^ IR11 ^ 1 | |
| 436 | * exorD = exorC ^ LALUC0 | |
| 437 | * XC = !(!(DNS & exorD) & !(MAGIC & OUTza)) | |
| 438 | * = (DNS & exorD) | (MAGIC & OUTza) | |
| 439 | * = exorD, because this is DNS | |
| 440 | * NEWCARRY = [XC, L(00), L(15), XC] for F1 = no shift, <-L RSH 1, <-L LSH 1, LCY 8 | |
| 441 | * SHZERO = shifter == 0 | |
| 442 | * DCARRY = !((!IR12 & NEWCARRY) | (IR12 & CARRY)) | |
| 443 | * = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1 | |
| 444 | * DSKIP = !((!NEWCARRY & IR14) | (SHZERO & IR13)) ^ !IR15 | |
| 445 | * = ((((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ 1) ^ (IR15 ^ 1) | |
| 446 | * = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15 | |
| 447 | * </PRE> | |
| 448 | */ | |
| 449 | void alto2_cpu_device::f2_load_dns_1() | |
| 450 | { | |
| 451 | UINT8 IR10 = A2_BIT32(m_emu.ir,16,10); | |
| 452 | UINT8 IR11 = A2_BIT32(m_emu.ir,16,11); | |
| 453 | UINT8 IR12 = A2_BIT32(m_emu.ir,16,12); | |
| 454 | UINT8 IR13 = A2_BIT32(m_emu.ir,16,13); | |
| 455 | UINT8 IR14 = A2_BIT32(m_emu.ir,16,14); | |
| 456 | UINT8 IR15 = A2_BIT32(m_emu.ir,16,15); | |
| 457 | UINT8 exorB = IR11 ^ IR10; | |
| 458 | UINT8 CARRY = m_emu.cy ^ 1; | |
| 459 | UINT8 ORA = (exorB | CARRY) ^ 1; | |
| 460 | UINT8 exorC = ORA ^ (IR11 ^ 1); | |
| 461 | UINT8 exorD = exorC ^ m_laluc0; | |
| 462 | UINT8 XC = exorD; | |
| 463 | UINT8 NEWCARRY; | |
| 464 | UINT8 DCARRY; | |
| 465 | UINT8 DSKIP; | |
| 466 | UINT8 SHZERO; | |
| 467 | ||
| 468 | switch (MIR_F1(m_mir)) { | |
| 469 | case f1_l_rsh_1: // <-L RSH 1 | |
| 470 | NEWCARRY = m_l & 1; | |
| 471 | m_shifter = ((m_l >> 1) | (XC << 15)) & 0177777; | |
| 472 | LOG((0,2," DNS; <-L RSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY)); | |
| 473 | break; | |
| 474 | case f1_l_lsh_1: // <-L LSH 1 | |
| 475 | NEWCARRY = (m_l >> 15) & 1; | |
| 476 | m_shifter = ((m_l << 1) | XC) & 0177777; | |
| 477 | LOG((0,2," DNS; <-L LSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY)); | |
| 478 | break; | |
| 479 | case f1_l_lcy_8: // <-L LCY 8 | |
| 480 | default: /* other */ | |
| 481 | NEWCARRY = XC; | |
| 482 | LOG((0,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY)); | |
| 483 | break; | |
| 484 | } | |
| 485 | SHZERO = (m_shifter == 0); | |
| 486 | DCARRY = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1; | |
| 487 | DSKIP = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15; | |
| 488 | ||
| 489 | m_emu.cy = DCARRY; // DCARRY is latched as new m_emu.cy | |
| 490 | m_emu.skip = DSKIP; // DSKIP is latched as new m_emu.skip | |
| 491 | ||
| 492 | /* !(IR12 & DNS) -> WR' = 0 for the register file */ | |
| 493 | if (!IR12) { | |
| 494 | m_r[m_rsel] = m_shifter; | |
| 495 | } | |
| 496 | } | |
| 497 | ||
| 498 | /** | |
| 499 | * @brief f2_acdest early: modify RSELECT with DstAC = (3 - IR[3-4]) | |
| 500 | */ | |
| 501 | void alto2_cpu_device::f2_acdest_0() | |
| 502 | { | |
| 503 | #if USE_SCHEMATICS_RSEL | |
| 504 | ALTO2_PUT(m_rsel, 5, 3, 3, RA3(f2_emu_acdest, m_emu.ir, m_rsel)); | |
| 505 | ALTO2_PUT(m_rsel, 5, 4, 4, RA4(f2_emu_acdest, m_emu.ir, m_rsel)); | |
| 506 | #else | |
| 507 | A2_PUT8(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3); | |
| 508 | #endif | |
| 509 | LOG((0,2," ACDEST<-; mux (rsel:%#o %s)\n", m_rsel, r_name[m_rsel])); | |
| 510 | } | |
| 511 | ||
| 512 | #if DEBUG | |
| 513 | void alto2_cpu_device::bitblt_info() | |
| 514 | { | |
| 515 | static const char *type_name[4] = {"bitmap","complement","and gray","gray"}; | |
| 516 | static const char *oper_name[4] = {"replace","paint","invert","erase"}; | |
| 517 | int bbt = m_r[rsel_ac2]; | |
| 518 | int val = debug_read_mem(bbt); | |
| 519 | ||
| 520 | LOG((0,3," BITBLT AC1:%06o AC2:%06o\n", m_r[rsel_ac1], m_r[rsel_ac2])); | |
| 521 | LOG((0,3," function : %06o\n", val)); | |
| 522 | LOG((0,3," src extRAM: %o\n", ALTO2_BIT(val,16,10))); | |
| 523 | LOG((0,3," dst extRAM: %o\n", ALTO2_BIT(val,16,11))); | |
| 524 | LOG((0,3," src type : %o (%s)\n", ALTO2_GET(val,16,12,13), type_name[ALTO2_GET(val,16,12,13)])); | |
| 525 | LOG((0,3," operation : %o (%s)\n", ALTO2_GET(val,16,14,15), oper_name[ALTO2_GET(val,16,14,15)])); | |
| 526 | val = debug_read_mem(bbt+1); | |
| 527 | LOG((0,3," unused AC2: %06o (%d)\n", val, val)); | |
| 528 | val = debug_read_mem(bbt+2); | |
| 529 | LOG((0,3," DBCA : %06o (%d)\n", val, val)); | |
| 530 | val = debug_read_mem(bbt+3); | |
| 531 | LOG((0,3," DBMR : %06o (%d words)\n", val, val)); | |
| 532 | val = debug_read_mem(bbt+4); | |
| 533 | LOG((0,3," DLX : %06o (%d bits)\n", val, val)); | |
| 534 | val = debug_read_mem(bbt+5); | |
| 535 | LOG((0,3," DTY : %06o (%d scanlines)\n", val, val)); | |
| 536 | val = debug_read_mem(bbt+6); | |
| 537 | LOG((0,3," DW : %06o (%d bits)\n", val, val)); | |
| 538 | val = debug_read_mem(bbt+7); | |
| 539 | LOG((0,3," DH : %06o (%d scanlines)\n", val, val)); | |
| 540 | val = debug_read_mem(bbt+8); | |
| 541 | LOG((0,3," SBCA : %06o (%d)\n", val, val)); | |
| 542 | val = debug_read_mem(bbt+9); | |
| 543 | LOG((0,3," SBMR : %06o (%d words)\n", val, val)); | |
| 544 | val = debug_read_mem(bbt+10); | |
| 545 | LOG((0,3," SLX : %06o (%d bits)\n", val, val)); | |
| 546 | val = debug_read_mem(bbt+11); | |
| 547 | LOG((0,3," STY : %06o (%d scanlines)\n", val, val)); | |
| 548 | LOG((0,3," GRAY0-3 : %06o %06o %06o %06o\n", | |
| 549 | debug_read_mem(bbt+12), debug_read_mem(bbt+13), | |
| 550 | debug_read_mem(bbt+14), debug_read_mem(bbt+15))); | |
| 551 | } | |
| 552 | #endif /* DEBUG */ | |
| 553 | ||
| 554 | /** | |
| 555 | * @brief f2_load_ir late: load instruction register IR and branch on IR[0,5-7] | |
| 556 | * | |
| 557 | * Loading the IR clears the skip latch. | |
| 558 | */ | |
| 559 | void alto2_cpu_device::f2_load_ir_1() | |
| 560 | { | |
| 561 | UINT16 r = (A2_BIT32(m_bus,16,0) << 3) | A2_GET32(m_bus,16,5,7); | |
| 562 | ||
| 563 | #if DEBUG | |
| 564 | if (ll[task_emu].level > 1) { | |
| 565 | char dasm[64]; | |
| 566 | dbg_dasm(dasm, sizeof(dasm), 0, m_r[6], m_bus); | |
| 567 | LOG((0,2," IR<-; IR = %06o, branch on IR[0,5-7] (%#o|%#o)\n", m_bus, m_next2, r)); | |
| 568 | /* disassembled instruction */ | |
| 569 | LOG((0,2," %06o: %06o %s\n", m_mem_mar, m_bus, dasm)); | |
| 570 | } | |
| 571 | #endif /* DEBUG */ | |
| 572 | ||
| 573 | /* special logging of some opcodes */ | |
| 574 | switch (m_bus) { | |
| 575 | case op_CYCLE: | |
| 576 | LOG((0,3," CYCLE AC0:#o\n", m_r[rsel_ac0])); | |
| 577 | break; | |
| 578 | case op_CYCLE + 1: case op_CYCLE + 2: case op_CYCLE + 3: case op_CYCLE + 4: | |
| 579 | case op_CYCLE + 5: case op_CYCLE + 6: case op_CYCLE + 7: case op_CYCLE + 8: | |
| 580 | case op_CYCLE + 9: case op_CYCLE +10: case op_CYCLE +11: case op_CYCLE +12: | |
| 581 | case op_CYCLE +13: case op_CYCLE +14: case op_CYCLE +15: | |
| 582 | LOG((0,3," CYCLE %#o\n", m_bus - op_CYCLE)); | |
| 583 | break; | |
| 584 | case op_BLT: | |
| 585 | LOG((0,3," BLT dst:%#o src:%#o size:%#o\n", | |
| 586 | (m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777, | |
| 587 | (m_r[rsel_ac0] + 1) & 017777, -m_r[rsel_ac3] & 0177777)); | |
| 588 | break; | |
| 589 | case op_BLKS: | |
| 590 | LOG((0,3," BLKS dst:%#o val:%#o size:%#o\n", | |
| 591 | (m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777, | |
| 592 | m_r[rsel_ac0], -m_r[rsel_ac3] & 0177777)); | |
| 593 | break; | |
| 594 | case op_DIAGNOSE1: | |
| 595 | LOG((0,3," DIAGNOSE1 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n", | |
| 596 | m_r[rsel_ac0], m_r[rsel_ac1], | |
| 597 | m_r[rsel_ac2], m_r[rsel_ac3])); | |
| 598 | break; | |
| 599 | case op_DIAGNOSE2: | |
| 600 | LOG((0,3," DIAGNOSE2 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n", | |
| 601 | m_r[rsel_ac0], m_r[rsel_ac1], | |
| 602 | m_r[rsel_ac2], m_r[rsel_ac3])); | |
| 603 | break; | |
| 604 | case op_BITBLT: | |
| 605 | #if DEBUG | |
| 606 | bitblt_info(); | |
| 607 | #endif | |
| 608 | break; | |
| 609 | case op_RDRAM: | |
| 610 | LOG((0,3," RDRAM addr:%#o\n", m_r[rsel_ac1])); | |
| 611 | break; | |
| 612 | case op_WRTRAM: | |
| 613 | LOG((0,3," WRTAM addr:%#o upper:%06o lower:%06o\n", m_r[rsel_ac1], m_r[rsel_ac0], m_r[rsel_ac3])); | |
| 614 | break; | |
| 615 | case op_JMPRAM: | |
| 616 | LOG((0,3," JMPRAM addr:%#o\n", m_r[rsel_ac1])); | |
| 617 | break; | |
| 618 | case op_XMLDA: | |
| 619 | LOG((0,3," XMLDA AC0 = [bank:%o AC1:#o]\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1])); | |
| 620 | break; | |
| 621 | case op_XMSTA: | |
| 622 | LOG((0,3," XMSTA [bank:%o AC1:#o] = AC0 (%#o)\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1], m_r[rsel_ac0])); | |
| 623 | break; | |
| 624 | } | |
| 625 | m_emu.ir = m_bus; | |
| 626 | m_emu.skip = 0; | |
| 627 | m_next2 |= r; | |
| 628 | } | |
| 629 | ||
| 630 | ||
| 631 | /** | |
| 632 | * @brief f2_idisp late: branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] | |
| 633 | */ | |
| 634 | void alto2_cpu_device::f2_idisp_1() | |
| 635 | { | |
| 636 | UINT16 r; | |
| 637 | ||
| 638 | if (IR_ARITH(m_emu.ir)) { | |
| 639 | /* 1xxxxxxxxxxxxxxx */ | |
| 640 | r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */ | |
| 641 | LOG((0,2," IDISP<-; branch on SH^3 (%#o|%#o)\n", m_next2, r)); | |
| 642 | } else { | |
| 643 | int addr = CTL2K_U3(f2_emu_idisp) + A2_GET32(m_emu.ir,16,1,7); | |
| 644 | /* 0???????xxxxxxxx */ | |
| 645 | r = m_ctl2k_u3[addr]; | |
| 646 | LOG((0,2," IDISP<-; IR (%#o) branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", m_emu.ir, addr, m_next2, r)); | |
| 647 | } | |
| 648 | m_next2 |= r; | |
| 649 | } | |
| 650 | ||
| 651 | /** | |
| 652 | * @brief f2_acsource early: modify RSELECT with SrcAC = (3 - IR[1-2]) | |
| 653 | */ | |
| 654 | void alto2_cpu_device::f2_acsource_0() | |
| 655 | { | |
| 656 | #if USE_SCHEMATICS_RSEL | |
| 657 | A2_PUT8(m_rsel, 5, 3, 3, RA3(f2_emu_acsource, m_emu.ir, m_rsel)); | |
| 658 | A2_PUT8(m_rsel, 5, 4, 4, RA4(f2_emu_acsource, m_emu.ir, m_rsel)); | |
| 659 | #else | |
| 660 | A2_PUT8(m_rsel, 5, 3, 4, IR_SrcAC(m_emu.ir) ^ 3); | |
| 661 | #endif | |
| 662 | LOG((0,2," <-ACSOURCE; rsel := SrcAC (%#o %s)\n", m_rsel, r_name[m_rsel])); | |
| 663 | } | |
| 664 | ||
| 665 | /** | |
| 666 | * @brief f2_acsource late: branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] | |
| 667 | */ | |
| 668 | void alto2_cpu_device::f2_acsource_1() | |
| 669 | { | |
| 670 | UINT16 r; | |
| 671 | ||
| 672 | if (IR_ARITH(m_emu.ir)) { | |
| 673 | /* 1xxxxxxxxxxxxxxx */ | |
| 674 | r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */ | |
| 675 | LOG((0,2," <-ACSOURCE; branch on SH^3 (%#o|%#o)\n", m_next2, r)); | |
| 676 | } else { | |
| 677 | int addr = CTL2K_U3(f2_emu_acsource) + A2_GET32(m_emu.ir,16,1,7); | |
| 678 | /* 0???????xxxxxxxx */ | |
| 679 | r = m_ctl2k_u3[addr]; | |
| 680 | LOG((0,2," <-ACSOURCE; branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", addr, m_next2, r)); | |
| 681 | } | |
| 682 | m_next2 |= r; | |
| 683 | } | |
| 684 | ||
| 685 | void alto2_cpu_device::init_emu(int task) | |
| 686 | { | |
| 687 | init_ram(task); | |
| 688 | ||
| 689 | set_bs(task, bs_emu_read_sreg, &alto2_cpu_device::bs_read_sreg_0, 0); | |
| 690 | set_bs(task, bs_emu_load_sreg, &alto2_cpu_device::bs_load_sreg_0, &alto2_cpu_device::bs_load_sreg_1); | |
| 691 | set_bs(task, bs_disp, &alto2_cpu_device::bs_emu_disp_0, 0); | |
| 692 | ||
| 693 | set_f1(task, f1_block, &alto2_cpu_device::f1_emu_block_0, 0); // catch the emulator task trying to block (wrong branch) | |
| 694 | set_f1(task, f1_emu_swmode, 0, &alto2_cpu_device::f1_swmode_1); | |
| 695 | set_f1(task, f1_emu_wrtram, 0, &alto2_cpu_device::f1_wrtram_1); | |
| 696 | set_f1(task, f1_emu_rdram, 0, &alto2_cpu_device::f1_rdram_1); | |
| 697 | set_f1(task, f1_emu_load_rmr, 0, &alto2_cpu_device::f1_emu_load_rmr_1); | |
| 698 | /* F1 014 is undefined (?) */ | |
| 699 | set_f1(task, f1_task_14, 0, &alto2_cpu_device::f1_load_srb_1); | |
| 700 | set_f1(task, f1_emu_load_esrb, 0, &alto2_cpu_device::f1_emu_load_esrb_1); | |
| 701 | set_f1(task, f1_emu_rsnf, &alto2_cpu_device::f1_rsnf_0, 0); | |
| 702 | set_f1(task, f1_emu_startf, &alto2_cpu_device::f1_startf_0, 0); | |
| 703 | ||
| 704 | set_f2(task, f2_emu_busodd, 0, &alto2_cpu_device::f2_busodd_1); | |
| 705 | #if 0 | |
| 706 | set_f2(task, f2_emu_magic, 0, &alto2_cpu_device::f2_magic_1); | |
| 707 | #else | |
| 708 | set_f2(task, f2_emu_magic, 0, 0); | |
| 709 | #endif | |
| 710 | set_f2(task, f2_emu_load_dns, &alto2_cpu_device::f2_load_dns_0, &alto2_cpu_device::f2_load_dns_1); | |
| 711 | set_f2(task, f2_emu_acdest, &alto2_cpu_device::f2_acdest_0, 0); | |
| 712 | set_f2(task, f2_emu_load_ir, 0, &alto2_cpu_device::f2_load_ir_1); | |
| 713 | set_f2(task, f2_emu_idisp, 0, &alto2_cpu_device::f2_idisp_1); | |
| 714 | set_f2(task, f2_emu_acsource, &alto2_cpu_device::f2_acsource_0, &alto2_cpu_device::f2_acsource_1); | |
| 715 | } | |
| 716 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | #include "alto2.h" | |
| 2 | ||
| 3 | enum { | |
| 4 | MX1 = (1<<0), //!< MX1 signal is bit 0 (latch bit 1) | |
| 5 | LMX1 = (1<<1), | |
| 6 | MX2 = (1<<2), //!< MX2 signal is bit 2 (latch bit 3) | |
| 7 | LMX2 = (1<<3), | |
| 8 | MY1 = (1<<4), //!< MY1 signal is bit 4 (latch bit 5) | |
| 9 | LMY1 = (1<<5), | |
| 10 | MY2 = (1<<6), //!< MY2 signal is bit 6 (latch bit 7) | |
| 11 | LMY2 = (1<<7), | |
| 12 | MACTIVE = (MX1|MX2|MY1|MY2), //!< mask for the active bits | |
| 13 | MLATCH = (LMX1|LMX2|LMY1|LMY2) //!< mask for the latched bits | |
| 14 | }; | |
| 15 | ||
| 16 | /** | |
| 17 | * <PRE> | |
| 18 | * The mouse inputs from the shutters are connected to a quad | |
| 19 | * 2/3 input RS flip flop (SN74279). | |
| 20 | * | |
| 21 | * 74279 | |
| 22 | * +---+--+---+ | |
| 23 | * | +--+ | | |
| 24 | * R1 -|1 16|- Vcc | |
| 25 | * | | | |
| 26 | * S1a -|2 15|- S4 | |
| 27 | * | | | |
| 28 | * S1b -|3 14|- R4 | |
| 29 | * | | | |
| 30 | * Q1 -|4 13|- Q4 | |
| 31 | * | | | |
| 32 | * R2 -|5 12|- S3a | |
| 33 | * | | | |
| 34 | * S2 -|6 11|- S3b | |
| 35 | * | | | |
| 36 | * Q2 -|7 10|- R3 | |
| 37 | * | | | |
| 38 | * GND -|8 9|- Q3 | |
| 39 | * | | | |
| 40 | * +----------+ | |
| 41 | * | |
| 42 | * The 'Y' Encoder signals are connected to IC1: | |
| 43 | * shutter pin(s) R/S output | |
| 44 | * ------------------------------------ | |
| 45 | * 0 2,3 S1a,b Q1 MX2 -> 1 | |
| 46 | * 1 1 R1 Q1 MX2 -> 0 | |
| 47 | * 2 5 R2 Q2 MX1 -> 0 | |
| 48 | * 3 6 S2 Q2 MX1 -> 1 | |
| 49 | * | |
| 50 | * The 'X' Encoder signals are connected to IC2: | |
| 51 | * shutter pin(s) R/S output | |
| 52 | * ------------------------------------ | |
| 53 | * 0 2,3 S1a,b Q1 MY2 -> 1 | |
| 54 | * 1 1 R1 Q1 MY2 -> 0 | |
| 55 | * 2 5 R2 Q2 MY1 -> 0 | |
| 56 | * 3 6 S2 Q2 MY1 -> 1 | |
| 57 | * | |
| 58 | * | |
| 59 | * The pulse train generated by a left or up rotation is: | |
| 60 | * | |
| 61 | * +---+ +---+ +---+ | |
| 62 | * MX1/MY1 | | | | | | | |
| 63 | * ---+ +---+ +---+ +--- | |
| 64 | * | |
| 65 | * +---+ +---+ +---+ +- | |
| 66 | * MX2/MY2 | | | | | | | | |
| 67 | * -+ +---+ +---+ +---+ | |
| 68 | * | |
| 69 | * | |
| 70 | * The pulse train generated by a right or down rotation is: | |
| 71 | * | |
| 72 | * +---+ +---+ +---+ +- | |
| 73 | * MX1/MY1 | | | | | | | | |
| 74 | * -+ +---+ +---+ +---+ | |
| 75 | * | |
| 76 | * +---+ +---+ +---+ | |
| 77 | * MX2/MY2 | | | | | | | |
| 78 | * ---+ +---+ +---+ +--- | |
| 79 | * | |
| 80 | * In order to simulate the shutter sequence for the mouse motions | |
| 81 | * we have to generate a sequence of pulses on MX1/MX2 and MY1/MY2 | |
| 82 | * that have their phases shifted by 90°. | |
| 83 | * </PRE> | |
| 84 | */ | |
| 85 | ||
| 86 | ||
| 87 | #define MOVEX(x) ((((x) < 0) ? MY2 : ((x) > 0) ? MY1 : 0)) | |
| 88 | #define MOVEY(y) ((((y) < 0) ? MX2 : ((y) > 0) ? MX1 : 0)) | |
| 89 | ||
| 90 | /** | |
| 91 | * @brief return the mouse motion flags | |
| 92 | * | |
| 93 | * Advance the mouse x and y coordinates to the dx and dy | |
| 94 | * coordinates by either toggling MX2 or MX1 first for a | |
| 95 | * y movement, or MY2 or MY1 for x movement. | |
| 96 | * | |
| 97 | * @result lookup value from madr_a32 | |
| 98 | */ | |
| 99 | UINT16 alto2_cpu_device::mouse_read() | |
| 100 | { | |
| 101 | static int arg; | |
| 102 | UINT16 data; | |
| 103 | ||
| 104 | m_mouse.latch = (m_mouse.latch << 1) & MLATCH; | |
| 105 | data = m_madr_a32[m_mouse.latch]; | |
| 106 | ||
| 107 | switch (arg & 3) { | |
| 108 | case 0: | |
| 109 | m_mouse.latch |= MOVEX(m_mouse.dx - m_mouse.x); | |
| 110 | m_mouse.latch |= MOVEY(m_mouse.dy - m_mouse.y); | |
| 111 | break; | |
| 112 | case 1: | |
| 113 | m_mouse.latch |= MACTIVE; | |
| 114 | if (m_mouse.x < m_mouse.dx) | |
| 115 | m_mouse.x++; | |
| 116 | if (m_mouse.x > m_mouse.dx) | |
| 117 | m_mouse.x--; | |
| 118 | if (m_mouse.y < m_mouse.dy) | |
| 119 | m_mouse.y++; | |
| 120 | if (m_mouse.y > m_mouse.dy) | |
| 121 | m_mouse.y--; | |
| 122 | break; | |
| 123 | case 2: | |
| 124 | m_mouse.latch ^= MOVEX(m_mouse.dx - m_mouse.x); | |
| 125 | m_mouse.latch ^= MOVEY(m_mouse.dy - m_mouse.y); | |
| 126 | break; | |
| 127 | default: | |
| 128 | m_mouse.latch &= ~MACTIVE; | |
| 129 | if (m_mouse.x < m_mouse.dx) | |
| 130 | m_mouse.x++; | |
| 131 | if (m_mouse.x > m_mouse.dx) | |
| 132 | m_mouse.x--; | |
| 133 | if (m_mouse.y < m_mouse.dy) | |
| 134 | m_mouse.y++; | |
| 135 | if (m_mouse.y > m_mouse.dy) | |
| 136 | m_mouse.y--; | |
| 137 | } | |
| 138 | arg++; | |
| 139 | return data; | |
| 140 | } | |
| 141 | ||
| 142 | /** | |
| 143 | * @brief register a mouse motion | |
| 144 | * | |
| 145 | * @param x new mouse x coordinate | |
| 146 | * @param y new mouse y coordinate | |
| 147 | */ | |
| 148 | void alto2_cpu_device::mouse_motion(int x, int y) | |
| 149 | { | |
| 150 | /* set new destination (absolute) mouse x and y coordinates */ | |
| 151 | m_mouse.dx = x; | |
| 152 | m_mouse.dy = y; | |
| 153 | #if 1 | |
| 154 | /* XXX: dirty, dirty, hack */ | |
| 155 | #if ALTO2_HAMMING_CHECK | |
| 156 | m_mem.ram[0424/2] = hamming_code(1, 0424 / 2, (x << 16) | y); | |
| 157 | #else | |
| 158 | m_mem.ram[0424/2] = (x << 16) | y; | |
| 159 | #endif | |
| 160 | #endif | |
| 161 | } | |
| 162 | ||
| 163 | /** | |
| 164 | * @brief register a mouse button change | |
| 165 | * | |
| 166 | * convert button bits to UTILIN[13-15] | |
| 167 | * | |
| 168 | * @param b mouse buttons (bit 0:left 1:right 2:middle) | |
| 169 | */ | |
| 170 | void alto2_cpu_device::mouse_button(int b) | |
| 171 | { | |
| 172 | /* UTILIN[13] TOP or LEFT button (RED) */ | |
| 173 | PUT_MOUSE_RED (m_hw.utilin, (b & (1 << 0)) ? 0 : 1); | |
| 174 | /* UTILIN[14] BOTTOM or RIGHT button (BLUE) */ | |
| 175 | PUT_MOUSE_BLUE (m_hw.utilin, (b & (1 << 1)) ? 0 : 1); | |
| 176 | /* UTILIN[15] MIDDLE button (YELLOW) */ | |
| 177 | PUT_MOUSE_YELLOW(m_hw.utilin, (b & (1 << 2)) ? 0 : 1); | |
| 178 | } | |
| 179 | ||
| 180 | ||
| 181 | /** | |
| 182 | * @brief initialize the mouse context to useful values | |
| 183 | * | |
| 184 | * From the Alto Hardware Manual: | |
| 185 | * <PRE> | |
| 186 | * The mouse is a hand-held pointing device which contains two encoders | |
| 187 | * which digitize its position as it is rolled over a table-top. It also | |
| 188 | * has three buttons which may be read as the three low order bits of | |
| 189 | * memory location UTILIN (0177030), iin the manner of the keyboard. | |
| 190 | * The bit/button correspondence in UTILIN are (depressed keys | |
| 191 | * correspond to 0's in memory): | |
| 192 | * | |
| 193 | * UTILIN[13] TOP or LEFT button (RED) | |
| 194 | * UTILIN[14] BOTTOM or RIGHT button (BLUE) | |
| 195 | * UTILIN[15] MIDDLE button (YELLOW) | |
| 196 | * | |
| 197 | * The mouse coordinates are maintained by the MRT microcode in locations | |
| 198 | * MOUSELOC(0424)=X and MOUSELOC+1(0425)=Y in page one of the Alto memory. | |
| 199 | * These coordinates are relative, i.e., the hardware only increments and | |
| 200 | * decrements them. The resolution of the mouse is approximately 100 points | |
| 201 | * per inch. | |
| 202 | * </PRE> | |
| 203 | */ | |
| 204 | void alto2_cpu_device::mouse_init() | |
| 205 | { | |
| 206 | memset(&m_mouse, 0, sizeof(m_mouse)); | |
| 207 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII disk interface | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** @brief 1 to debug the JK flip-flops, 0 to use a lookup table */ | |
| 13 | #define JKFF_FUNCTION 0 | |
| 14 | ||
| 15 | /** | |
| 16 | * | |
| 17 | * Just for completeness' sake: | |
| 18 | * The mapping of disk controller connector P2 pins to the | |
| 19 | * Winchester disk drive signals (see drive.h) | |
| 20 | * <PRE> | |
| 21 | * Alto Controller Winchester | |
| 22 | * P2 signal disk bus | |
| 23 | * ----------------------------------------------- | |
| 24 | * 1 GND D_GROUND | |
| 25 | * 2 RDCLK' A_READ_CLOCK | |
| 26 | * 3 WRDATA' B_WRITE_DATA_AND_CLOCK | |
| 27 | * 4 SRWRDY' F_S_R_W | |
| 28 | * 5 DISK L_SELECT_LINE_UNIT_1 | |
| 29 | * 6 CYL(7)' N_CYL_7 | |
| 30 | * 7 DISK' R_SELECT_LINE_UNIT_2 | |
| 31 | * 8 CYL(2)' T_CYL_2 | |
| 32 | * 9 ??? V_SELECT_LINE_UNIT_3 | |
| 33 | * 10 CYL(4)' X_CYL_4 | |
| 34 | * 11 CYL(0)' Z_CYL_0 | |
| 35 | * 12 CYL(1)' BB_CYL_1 | |
| 36 | * 13 CYL(3)' FF_CYL_3 | |
| 37 | * 14 ??? KK_BIT_2 | |
| 38 | * 15 CYL(8)' LL_CYL_8 | |
| 39 | * 16 ADRACK' NN_ADDX_ACKNOWLEDGE | |
| 40 | * 17 SKINC' TT_SEEK_INCOMPLETE | |
| 41 | * 18 LAI' XX_LOG_ADDX_INTERLOCK | |
| 42 | * 19 CYL(6)' RR_CYL_6 | |
| 43 | * 20 RESTOR' VV_RESTORE | |
| 44 | * 21 ??? UU_BIT_16 | |
| 45 | * 22 STROBE' SS_STROBE | |
| 46 | * 23 ??? MM_BIT_8 | |
| 47 | * 24 ??? KK_BIT_4 | |
| 48 | * 25 ??? HH_WRITE_CHK | |
| 49 | * 26 WRTGATE' EE_WRITE_GATE | |
| 50 | * 27 ??? CC_BIT_SECTOR_ADDX | |
| 51 | * 28 HEAD' AA_HEAD_SELECT | |
| 52 | * 29 ??? Y_INDEX_MARK | |
| 53 | * 30 SECT(4)' W_SECTOR_MARK | |
| 54 | * 31 READY' U_FILE_READY | |
| 55 | * 32 ??? S_PSEUDO_SECTOR_MARK | |
| 56 | * 33 ??? P_WRITE_PROTECT_IND | |
| 57 | * 34 ??? H_WRITE_PROTECT_INPUT_ATTENTION | |
| 58 | * 35 ERGATE' K_ERASE_GATE | |
| 59 | * 36 ??? M_HIGH_DENSITY | |
| 60 | * 37 CYL(5)' J_CYL_5 | |
| 61 | * 38 RDDATA' C_READ_DATA | |
| 62 | * 39 RDGATE' E_READ_GATE | |
| 63 | * 40 GND ?? | |
| 64 | * </PRE> | |
| 65 | */ | |
| 66 | ||
| 67 | #define GET_KADDR_SECTOR(kaddr) A2_GET16(kaddr,16, 0, 3) //!< get sector number from address register | |
| 68 | #define PUT_KADDR_SECTOR(kaddr,val) A2_PUT16(kaddr,16, 0, 3,val) //!< put sector number into address register | |
| 69 | #define GET_KADDR_CYLINDER(kaddr) A2_GET16(kaddr,16, 4,12) //!< get cylinder number from address register | |
| 70 | #define PUT_KADDR_CYLINDER(kaddr,val) A2_PUT16(kaddr,16, 4,12,val) //!< put cylinder number int address register | |
| 71 | #define GET_KADDR_HEAD(kaddr) A2_GET16(kaddr,16,13,13) //!< get head number from address register | |
| 72 | #define PUT_KADDR_HEAD(kaddr,val) A2_PUT16(kaddr,16,13,13,val) //!< put head number into address register | |
| 73 | #define GET_KADDR_DRIVE(kaddr) A2_GET16(kaddr,16,14,14) //!< get drive (unit) number from address register | |
| 74 | #define PUT_KADDR_DRIVE(kaddr,val) A2_PUT16(kaddr,16,14,14,val) //!< put drive (unit) number into address register | |
| 75 | #define GET_KADDR_RESTORE(kaddr) A2_GET16(kaddr,16,15,15) //!< get restore flag from address register | |
| 76 | #define PUT_KADDR_RESTORE(kaddr,val) A2_PUT16(kaddr,16,15,15,val) //!< putt restore flag into address register | |
| 77 | ||
| 78 | #define GET_KADR_SEAL(kadr) A2_GET16(kadr,16, 0, 7) //!< get command seal from command register | |
| 79 | #define PUT_KADR_SEAL(kadr,val) A2_PUT16(kadr,16, 0, 7,val) //!< put command seal into command register | |
| 80 | #define GET_KADR_HEADER(kadr) A2_GET16(kadr,16, 8, 9) //!< get r/w/c for header from command register | |
| 81 | #define PUT_KADR_HEADER(kadr,val) A2_PUT16(kadr,16, 8, 9,val) //!< put r/w/c for header from command register | |
| 82 | #define GET_KADR_LABEL(kadr) A2_GET16(kadr,16,10,11) //!< get r/w/c for label from command register | |
| 83 | #define PUT_KADR_LABEL(kadr,val) A2_PUT16(kadr,16,10,11,val) //!< put r/w/c for label into command register | |
| 84 | #define GET_KADR_DATA(kadr) A2_GET16(kadr,16,12,13) //!< get r/w/c for data from command register | |
| 85 | #define PUT_KADR_DATA(kadr,val) A2_PUT16(kadr,16,12,13,val) //!< put r/w/c for data into command register | |
| 86 | #define GET_KADR_NOXFER(kadr) A2_GET16(kadr,16,14,14) //!< get no transfer flag from command register | |
| 87 | #define PUT_KADR_NOXFER(kadr,val) A2_PUT16(kadr,16,14,14,val) //!< put no transfer flag into command register | |
| 88 | #define GET_KADR_UNUSED(kadr) A2_GET16(kadr,16,15,15) //!< get unused (drive?) flag from command register | |
| 89 | #define PUT_KADR_UNUSED(kadr,val) A2_PUT16(kadr,16,15,15,val) //!< put unused (drive?) flag into command register | |
| 90 | ||
| 91 | #define GET_KSTAT_SECTOR(kstat) A2_GET16(kstat,16,0,3) //!< get current sector number from status register | |
| 92 | #define PUT_KSTAT_SECTOR(kstat,val) A2_PUT16(kstat,16,0,3,val) //!< put current sector number into status register | |
| 93 | #define GET_KSTAT_DONE(kstat) A2_GET16(kstat,16,4,7) //!< get 'done' field from status register (017) | |
| 94 | #define PUT_KSTAT_DONE(kstat,val) A2_PUT16(kstat,16,4,7,val) //!< put 'done' field int status register (017) | |
| 95 | #define GET_KSTAT_SEEKFAIL(kstat) A2_GET16(kstat,16,8,8) //!< get seek fail flag from status register | |
| 96 | #define PUT_KSTAT_SEEKFAIL(kstat,val) A2_PUT16(kstat,16,8,8,val) //!< put seek fail flag into status register | |
| 97 | #define GET_KSTAT_SEEK(kstat) A2_GET16(kstat,16,9,9) //!< get seek busy flag (strobe) from status register | |
| 98 | #define PUT_KSTAT_SEEK(kstat,val) A2_PUT16(kstat,16,9,9,val) //!< put seek busy flag (strobe) into status register | |
| 99 | #define GET_KSTAT_NOTRDY(kstat) A2_GET16(kstat,16,10,10) //!< get drive not ready flag from status register | |
| 100 | #define PUT_KSTAT_NOTRDY(kstat,val) A2_PUT16(kstat,16,10,10,val) //!< put drive not ready flag into status register | |
| 101 | #define GET_KSTAT_DATALATE(kstat) A2_GET16(kstat,16,11,11) //!< get data late flag from status register | |
| 102 | #define PUT_KSTAT_DATALATE(kstat,val) A2_PUT16(kstat,16,11,11,val) //!< put data late flag into status register | |
| 103 | #define GET_KSTAT_IDLE(kstat) A2_GET16(kstat,16,12,12) //!< get idle flag from status register (idle is a software flag) | |
| 104 | #define PUT_KSTAT_IDLE(kstat,val) A2_PUT16(kstat,16,12,12,val) //!< put idle flag into status register (idle is a software flag) | |
| 105 | #define GET_KSTAT_CKSUM(kstat) A2_GET16(kstat,16,13,13) //!< get checksum flag from status register (checksum is a software flag; it is ORed when 0) | |
| 106 | #define PUT_KSTAT_CKSUM(kstat,val) A2_PUT16(kstat,16,13,13,val) //!< put checksum flag into status register (checksum is a software flag; it is ORed when 0) | |
| 107 | #define GET_KSTAT_COMPLETION(kstat) A2_GET16(kstat,16,14,15) //!< get completion code from status register (completion is a 2-bit software latch) | |
| 108 | #define PUT_KSTAT_COMPLETION(kstat,val) A2_PUT16(kstat,16,14,15,val) //!< put completion code into status register (completion is a 2-bit software latch) | |
| 109 | ||
| 110 | #define GET_KCOM_XFEROFF(kcom) A2_GET16(kcom,16,1,1) //!< get transfer off flag from controller command (hardware command register) | |
| 111 | #define PUT_KCOM_XFEROFF(kcom,val) A2_PUT16(kcom,16,1,1,val) //!< put transfer off flag into controller command (hardware command register) | |
| 112 | #define GET_KCOM_WDINHIB(kcom) A2_GET16(kcom,16,2,2) //!< get word task inhibit flag from controller command (hardware command register) | |
| 113 | #define PUT_KCOM_WDINHIB(kcom,val) A2_PUT16(kcom,16,2,2,val) //!< put word task inhibit flag into controller command (hardware command register) | |
| 114 | #define GET_KCOM_BCLKSRC(kcom) A2_GET16(kcom,16,3,3) //!< get bit clock source flag from controller command (hardware command register) | |
| 115 | #define PUT_KCOM_BCLKSRC(kcom,val) A2_PUT16(kcom,16,3,3,val) //!< put bit clock source flag into controller command (hardware command register) | |
| 116 | #define GET_KCOM_WFFO(kcom) A2_GET16(kcom,16,4,4) //!< get write fixed frequency oscillator flag from controller command (hardware command register) | |
| 117 | #define PUT_KCOM_WFFO(kcom,val) A2_PUT16(kcom,16,4,4,val) //!< put write fixed frequency oscillator flag into controller command (hardware command register) | |
| 118 | #define GET_KCOM_SENDADR(kcom) A2_GET16(kcom,16,5,5) //!< get send address flag from controller command (hardware command register) | |
| 119 | #define PUT_KCOM_SENDADR(kcom,val) A2_PUT16(kcom,16,5,5,val) //!< put send address flag into controller command (hardware command register) | |
| 120 | ||
| 121 | /** @brief completion codes (only for documentation, since this is microcode defined) */ | |
| 122 | enum { | |
| 123 | STATUS_COMPLETION_GOOD, | |
| 124 | STATUS_COMPLETION_HARDWARE_ERROR, | |
| 125 | STATUS_COMPLETION_CHECK_ERROR, | |
| 126 | STATUS_COMPLETION_ILLEGAL_SECTOR | |
| 127 | }; | |
| 128 | ||
| 129 | /** @brief record numbers per sector in INCRECNO order */ | |
| 130 | enum { | |
| 131 | RECNO_HEADER, | |
| 132 | RECNO_PAGENO, | |
| 133 | RECNO_LABEL, | |
| 134 | RECNO_DATA | |
| 135 | }; | |
| 136 | ||
| 137 | ||
| 138 | /** @brief read/write/check numbers */ | |
| 139 | enum { | |
| 140 | RWC_READ, | |
| 141 | RWC_CHECK, | |
| 142 | RWC_WRITE, | |
| 143 | RWC_WRITE2 | |
| 144 | }; | |
| 145 | ||
| 146 | #if DEBUG | |
| 147 | /** @brief human readable names for the KADR<- modes */ | |
| 148 | static const char *rwc_name[4] = {"read", "check", "write", "write2"}; | |
| 149 | #endif | |
| 150 | ||
| 151 | #if JKFF_FUNCTION | |
| 152 | ||
| 153 | #if DEBUG | |
| 154 | static const char *jkff_name; | |
| 155 | /** @brief macro to set the name of a FF in DEBUG=1 builds only */ | |
| 156 | #define DEBUG_NAME(x) jkff_name = x | |
| 157 | #else | |
| 158 | #define DEBUG_NAME(x) | |
| 159 | #endif | |
| 160 | ||
| 161 | /** | |
| 162 | * @brief simulate a 74109 J-K flip-flop with set and reset inputs | |
| 163 | * | |
| 164 | * @param s0 is the previous state of the FF's in- and outputs | |
| 165 | * @param s1 is the next state | |
| 166 | * @result returns the next state and probably modified Q output | |
| 167 | */ | |
| 168 | static inline jkff_t update_jkff(jkff_t s0, jkff_t s1) | |
| 169 | { | |
| 170 | switch (s1 & (JKFF_C | JKFF_S)) { | |
| 171 | case JKFF_C | JKFF_S: /* C' is 1, and S' is 1 */ | |
| 172 | if (((s0 ^ s1) & s1) & JKFF_CLK) { | |
| 173 | /* rising edge of the clock */ | |
| 174 | switch (s1 & (JKFF_J | JKFF_K)) { | |
| 175 | case 0: | |
| 176 | /* both J and K' are 0: set Q to 0, Q' to 1 */ | |
| 177 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; | |
| 178 | if (s0 & JKFF_Q) { | |
| 179 | LOG((0,5,"%s J:0 K':0 -> Q:0\n", jkff_name)); | |
| 180 | } | |
| 181 | break; | |
| 182 | case JKFF_J: | |
| 183 | /* J is 1, and K' is 0: toggle Q */ | |
| 184 | if (s0 & JKFF_Q) | |
| 185 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; | |
| 186 | else | |
| 187 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; | |
| 188 | LOG((0,5,"%s J:0 K':1 flip-flop Q:%d\n", | |
| 189 | jkff_name, (s1 & JKFF_Q) ? 1 : 0)); | |
| 190 | break; | |
| 191 | case JKFF_K: | |
| 192 | if ((s0 ^ s1) & JKFF_Q) { | |
| 193 | LOG((0,5,"%s J:0 K':1 keep Q:%d\n", | |
| 194 | jkff_name, (s1 & JKFF_Q) ? 1 : 0)); | |
| 195 | } | |
| 196 | /* J is 0, and K' is 1: keep Q as is */ | |
| 197 | if (s0 & JKFF_Q) | |
| 198 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; | |
| 199 | else | |
| 200 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; | |
| 201 | break; | |
| 202 | case JKFF_J | JKFF_K: | |
| 203 | /* both J and K' are 1: set Q to 1 */ | |
| 204 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; | |
| 205 | if (!(s0 & JKFF_Q)) { | |
| 206 | LOG((0,5,"%s J:1 K':1 -> Q:1\n", | |
| 207 | jkff_name)); | |
| 208 | } | |
| 209 | break; | |
| 210 | } | |
| 211 | } else { | |
| 212 | /* keep Q */ | |
| 213 | s1 = (s1 & ~JKFF_Q) | (s0 & JKFF_Q); | |
| 214 | } | |
| 215 | break; | |
| 216 | case JKFF_S: | |
| 217 | /* S' is 1, C' is 0: set Q to 0, Q' to 1 */ | |
| 218 | s1 = (s1 & ~JKFF_Q) | JKFF_Q0; | |
| 219 | if (s0 & JKFF_Q) { | |
| 220 | LOG((0,5,"%s C':0 -> Q:0\n", jkff_name)); | |
| 221 | } | |
| 222 | break; | |
| 223 | case JKFF_C: | |
| 224 | /* S' is 0, C' is 1: set Q to 1, Q' to 0 */ | |
| 225 | s1 = (s1 | JKFF_Q) & ~JKFF_Q0; | |
| 226 | if (!(s0 & JKFF_Q)) { | |
| 227 | LOG((0,5,"%s S':0 -> Q:1\n", jkff_name)); | |
| 228 | } | |
| 229 | break; | |
| 230 | case 0: | |
| 231 | default: | |
| 232 | /* unstable state (what to do?) */ | |
| 233 | s1 = s1 | JKFF_Q | JKFF_Q0; | |
| 234 | LOG((0,5,"%s C':0 S':0 -> Q:1 and Q':1 <unstable>\n", jkff_name)); | |
| 235 | break; | |
| 236 | } | |
| 237 | return s1; | |
| 238 | } | |
| 239 | ||
| 240 | #else | |
| 241 | ||
| 242 | /** @brief table constructed for update_jkff(s0,s1) */ | |
| 243 | static UINT8 jkff_lookup[64][64] = { | |
| 244 | { | |
| 245 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 246 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 247 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 248 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 249 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 250 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 251 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 252 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60 | |
| 253 | },{ | |
| 254 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 255 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 256 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 257 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 258 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 259 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 260 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 261 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61 | |
| 262 | },{ | |
| 263 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 264 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 265 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 266 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 267 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 268 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 269 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 270 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62 | |
| 271 | },{ | |
| 272 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 273 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 274 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 275 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 276 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 277 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 278 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 279 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63 | |
| 280 | },{ | |
| 281 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 282 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 283 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 284 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 285 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 286 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 287 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 288 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64 | |
| 289 | },{ | |
| 290 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 291 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 292 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 293 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 294 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 295 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 296 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 297 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65 | |
| 298 | },{ | |
| 299 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 300 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 301 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 302 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 303 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 304 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 305 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 306 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66 | |
| 307 | },{ | |
| 308 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 309 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 310 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 311 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 312 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 313 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 314 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 315 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67 | |
| 316 | },{ | |
| 317 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 318 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 319 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 320 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 321 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 322 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 323 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 324 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48 | |
| 325 | },{ | |
| 326 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 327 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 328 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 329 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 330 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 331 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 332 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 333 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49 | |
| 334 | },{ | |
| 335 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 336 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 337 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 338 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 339 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 340 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 341 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 342 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a | |
| 343 | },{ | |
| 344 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 345 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 346 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 347 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 348 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 349 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 350 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 351 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b | |
| 352 | },{ | |
| 353 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 354 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 355 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 356 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 357 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 358 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 359 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 360 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c | |
| 361 | },{ | |
| 362 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 363 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 364 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 365 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 366 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 367 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 368 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 369 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d | |
| 370 | },{ | |
| 371 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 372 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 373 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 374 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 375 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 376 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 377 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 378 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e | |
| 379 | },{ | |
| 380 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 381 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 382 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 383 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 384 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 385 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 386 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 387 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f | |
| 388 | },{ | |
| 389 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 390 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 391 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 392 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 393 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 394 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 395 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 396 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30 | |
| 397 | },{ | |
| 398 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 399 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 400 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 401 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 402 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 403 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 404 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 405 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31 | |
| 406 | },{ | |
| 407 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 408 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 409 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 410 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 411 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 412 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 413 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 414 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32 | |
| 415 | },{ | |
| 416 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 417 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 418 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 419 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 420 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 421 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 422 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 423 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33 | |
| 424 | },{ | |
| 425 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 426 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 427 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 428 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 429 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 430 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 431 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 432 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34 | |
| 433 | },{ | |
| 434 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 435 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 436 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 437 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 438 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 439 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 440 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 441 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35 | |
| 442 | },{ | |
| 443 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 444 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 445 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 446 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 447 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 448 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 449 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 450 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36 | |
| 451 | },{ | |
| 452 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 453 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 454 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 455 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 456 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 457 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 458 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 459 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37 | |
| 460 | },{ | |
| 461 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 462 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 463 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 464 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 465 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, | |
| 466 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, | |
| 467 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, | |
| 468 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38 | |
| 469 | },{ | |
| 470 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 471 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 472 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 473 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 474 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39, | |
| 475 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39, | |
| 476 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39, | |
| 477 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39 | |
| 478 | },{ | |
| 479 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 480 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 481 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 482 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 483 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, | |
| 484 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, | |
| 485 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, | |
| 486 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a | |
| 487 | },{ | |
| 488 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 489 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 490 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 491 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 492 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b, | |
| 493 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b, | |
| 494 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b, | |
| 495 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b | |
| 496 | },{ | |
| 497 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 498 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 499 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 500 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 501 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, | |
| 502 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, | |
| 503 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, | |
| 504 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c | |
| 505 | },{ | |
| 506 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 507 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 508 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 509 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 510 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, | |
| 511 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, | |
| 512 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, | |
| 513 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d | |
| 514 | },{ | |
| 515 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 516 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 517 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 518 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 519 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, | |
| 520 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, | |
| 521 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, | |
| 522 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e | |
| 523 | },{ | |
| 524 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 525 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 526 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 527 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 528 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, | |
| 529 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, | |
| 530 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, | |
| 531 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f | |
| 532 | },{ | |
| 533 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 534 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 535 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 536 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 537 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 538 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 539 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, | |
| 540 | 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60 | |
| 541 | },{ | |
| 542 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 543 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 544 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 545 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 546 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 547 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 548 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, | |
| 549 | 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61 | |
| 550 | },{ | |
| 551 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 552 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 553 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 554 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 555 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 556 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 557 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, | |
| 558 | 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62 | |
| 559 | },{ | |
| 560 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 561 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 562 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 563 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 564 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 565 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 566 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, | |
| 567 | 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63 | |
| 568 | },{ | |
| 569 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 570 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 571 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 572 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 573 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 574 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 575 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, | |
| 576 | 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64 | |
| 577 | },{ | |
| 578 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 579 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 580 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 581 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 582 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 583 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 584 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, | |
| 585 | 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65 | |
| 586 | },{ | |
| 587 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 588 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 589 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 590 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 591 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 592 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 593 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, | |
| 594 | 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66 | |
| 595 | },{ | |
| 596 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 597 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 598 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 599 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 600 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 601 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 602 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, | |
| 603 | 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67 | |
| 604 | },{ | |
| 605 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 606 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 607 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 608 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 609 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 610 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 611 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, | |
| 612 | 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48 | |
| 613 | },{ | |
| 614 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 615 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 616 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 617 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 618 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 619 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 620 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, | |
| 621 | 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49 | |
| 622 | },{ | |
| 623 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 624 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 625 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 626 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 627 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 628 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 629 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, | |
| 630 | 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a | |
| 631 | },{ | |
| 632 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 633 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 634 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 635 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 636 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 637 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 638 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, | |
| 639 | 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b | |
| 640 | },{ | |
| 641 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 642 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 643 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 644 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 645 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 646 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 647 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, | |
| 648 | 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c | |
| 649 | },{ | |
| 650 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 651 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 652 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 653 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 654 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 655 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 656 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, | |
| 657 | 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d | |
| 658 | },{ | |
| 659 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 660 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 661 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 662 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 663 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 664 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 665 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, | |
| 666 | 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e | |
| 667 | },{ | |
| 668 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 669 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 670 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 671 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 672 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 673 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 674 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, | |
| 675 | 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f | |
| 676 | },{ | |
| 677 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 678 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 679 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 680 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 681 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 682 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 683 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, | |
| 684 | 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30 | |
| 685 | },{ | |
| 686 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 687 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 688 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 689 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 690 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 691 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 692 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, | |
| 693 | 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31 | |
| 694 | },{ | |
| 695 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 696 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 697 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 698 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 699 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 700 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 701 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, | |
| 702 | 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32 | |
| 703 | },{ | |
| 704 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 705 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 706 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 707 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 708 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 709 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 710 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, | |
| 711 | 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33 | |
| 712 | },{ | |
| 713 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 714 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 715 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 716 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 717 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 718 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 719 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, | |
| 720 | 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34 | |
| 721 | },{ | |
| 722 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 723 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 724 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 725 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 726 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 727 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 728 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, | |
| 729 | 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35 | |
| 730 | },{ | |
| 731 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 732 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 733 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 734 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 735 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 736 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 737 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, | |
| 738 | 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36 | |
| 739 | },{ | |
| 740 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 741 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 742 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 743 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 744 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 745 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 746 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, | |
| 747 | 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37 | |
| 748 | },{ | |
| 749 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 750 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 751 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 752 | 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, | |
| 753 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, | |
| 754 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, | |
| 755 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, | |
| 756 | 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38 | |
| 757 | },{ | |
| 758 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 759 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 760 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 761 | 0x59,0x19,0x59,0x19,0x59,0x19,0x59,0x19, | |
| 762 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39, | |
| 763 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39, | |
| 764 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39, | |
| 765 | 0x59,0x39,0x59,0x39,0x59,0x39,0x59,0x39 | |
| 766 | },{ | |
| 767 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 768 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 769 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 770 | 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, | |
| 771 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, | |
| 772 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, | |
| 773 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, | |
| 774 | 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a | |
| 775 | },{ | |
| 776 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 777 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 778 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 779 | 0x3b,0x1b,0x3b,0x1b,0x3b,0x1b,0x3b,0x1b, | |
| 780 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b, | |
| 781 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b, | |
| 782 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b, | |
| 783 | 0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b | |
| 784 | },{ | |
| 785 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 786 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 787 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 788 | 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, | |
| 789 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, | |
| 790 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, | |
| 791 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, | |
| 792 | 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c | |
| 793 | },{ | |
| 794 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 795 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 796 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 797 | 0x5d,0x1d,0x5d,0x1d,0x5d,0x1d,0x5d,0x1d, | |
| 798 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, | |
| 799 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, | |
| 800 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, | |
| 801 | 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d | |
| 802 | },{ | |
| 803 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 804 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 805 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 806 | 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, | |
| 807 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, | |
| 808 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, | |
| 809 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, | |
| 810 | 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e | |
| 811 | },{ | |
| 812 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 813 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 814 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 815 | 0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, | |
| 816 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, | |
| 817 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, | |
| 818 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, | |
| 819 | 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f | |
| 820 | } | |
| 821 | }; | |
| 822 | ||
| 823 | ||
| 824 | /** @brief just ignore debug arguments with the lookup table */ | |
| 825 | #define DEBUG_NAME(name) | |
| 826 | ||
| 827 | /** @brief lookup JK flip-flop state change from s0 to s1 */ | |
| 828 | #define update_jkff(s0,s1) static_cast<jkff_t>(jkff_lookup[(s1)&63][(s0)&63]) | |
| 829 | ||
| 830 | #endif | |
| 831 | ||
| 832 | /** | |
| 833 | * <PRE> | |
| 834 | * SECTOR, ERROR WAKEUPS | |
| 835 | * | |
| 836 | * | |
| 837 | * Monoflop pulse duration: | |
| 838 | * tW = K * Rt * Cext * (1 + 0.7/Rt) | |
| 839 | * K = 0.28 for 74123 | |
| 840 | * Rt = kOhms | |
| 841 | * Cext = pF | |
| 842 | * | |
| 843 | * +------+ | |
| 844 | * CLRSTAT' >---------oS' | 15k, .47µF (=470000pF) | |
| 845 | * | MONO | 2066120ns ~= 2ms | |
| 846 | * | FLOP | | |
| 847 | * | | Q' +----+ | |
| 848 | * READY' >---------oC' o--------|NAND| ERRWAKE' | |
| 849 | * +------+ | o----· | |
| 850 | * RDYLAT' >-------------------------| | | | |
| 851 | * +----+ | | |
| 852 | * | | |
| 853 | * | | |
| 854 | * .---------------------· | |
| 855 | * | | |
| 856 | * +---o--+ Q +------+ | |
| 857 | * ·-----|J S' |----+---------|S | 30k, .01µF (=10000pF) | |
| 858 | * | | | | | MONO | 85960ns ~= 86µs | |
| 859 | * SECT[4] >---|-----|CLK | | | FLOP | | |
| 860 | * | | 21a| | | | Q' | |
| 861 | * | 1 >-|K' C' | | 1 >-|C' |--------------------> SECLATE | |
| 862 | * | +---o--+ | +------+ | |
| 863 | * | | | | |
| 864 | * ·---------+-------|-----------------------------------. | |
| 865 | * | | | |
| 866 | * ·---------------· | | |
| 867 | * | | | |
| 868 | * | 1 1 RESET' >------· | | |
| 869 | * | | | | | | |
| 870 | * | +---o--+ Q +---o--+ Q +---o--+ Q | | |
| 871 | * ·---|J S' |----------|J S' |----------|J S' |------> STSKENA | |
| 872 | * | | | | | | | | |
| 873 | * SYSCLKB' >--+------|CLK | .-------|CLK | ·-------|CLK | | | |
| 874 | * | | 21b| | | 22a| | | 22b| Q' | | |
| 875 | * | 1 >-|K' C' | | 1 >-|K' C' | | ·---|K' C' |----+-> WAKEST' | |
| 876 | * | +---o--+ | +---o--+ | | +---o--+ | | |
| 877 | * | | | | | | 1 | | |
| 878 | * | ·-----|-----------+-----|---|---------------· | |
| 879 | * | | | | | |
| 880 | * ·----------------+-----------------· | | |
| 881 | * | | |
| 882 | * +----+ | | |
| 883 | * BLOCK >-------------------------|NAND| | | |
| 884 | * | o----------· | |
| 885 | * STSKACT >-------------------------| | | |
| 886 | * +----+ | |
| 887 | * | |
| 888 | * A CLRSTAT starts the monoflop, and READY', i.e. the ready signal from the disk | |
| 889 | * drive, clears it. The Q' output is thus 0 for some time after CLRSTAT, and as | |
| 890 | * long as the disk signals being ready. | |
| 891 | * | |
| 892 | * If the disk is not ready, i.e. the Q' being 1, and if RDYLAT' - the READY' state | |
| 893 | * latched at the most recent CLRSTAT - is also 1, the ERRWAKE' signal will go 0. | |
| 894 | * | |
| 895 | * Each new sector (SECT[4]' going 1) will clock the FF 21a, which changes | |
| 896 | * its Q output depending on WAKEST' (K' is always 1): | |
| 897 | * if J and K' are both 1, sets its Q to 1. | |
| 898 | * if J is 0, and K' is 1, keeps Q as is. | |
| 899 | * So Q becomes 0 by WAKEST' going 0, and it becomes 1 with the next sector, if | |
| 900 | * WAKEST' is 1. | |
| 901 | * | |
| 902 | * The mono-flop to the right will generate a SECLATE signal, if WAKEST' was | |
| 903 | * not 0 when the disk signalled a new sector. | |
| 904 | * | |
| 905 | * The three J-K FFs at the bottom are all clocked with the rising edge of | |
| 906 | * SYSCLKB' (i.e falling edge of SYSCLKB). | |
| 907 | * | |
| 908 | * The left JK-FF propagates the current state of the upper JK-FF's Q output | |
| 909 | * to its own Q. The middle propagates the previous state of the left one, | |
| 910 | * and the JK-FF to the right delays the wandering Q for a third SYSCLKB' | |
| 911 | * rising edge, but only in one case: | |
| 912 | * 1) if J and K' are both 1, set its Q to 1. | |
| 913 | * 2) if J is 1, and K' is 0, toggle Q. | |
| 914 | * 3) if J is 0, and K' is 1, keep Q as is. | |
| 915 | * 4) if J and K' are both 0, set its Q to 0. | |
| 916 | * | |
| 917 | * The right FF's K' is 0 whenever the BLOCK signal (see DISK WORD TIMING) | |
| 918 | * and the sector task active signal (STSKACT) are 1 at the same time. | |
| 919 | * | |
| 920 | * Case 1) is the normal case, and it wakes the KSECT on the third SYSCLKB' | |
| 921 | * positive edge. It resets at that same time the left, middle, and upper | |
| 922 | * J-K FFs . | |
| 923 | * | |
| 924 | * Case 2) is due, when the sector task is already active the moment | |
| 925 | * the BLOCK signal arrives. This toggles the output, i.e. removes the | |
| 926 | * wake. | |
| 927 | * | |
| 928 | * Case 3) is for an active sector task without a new sector. | |
| 929 | * | |
| 930 | * And finally case 4) happens when an active sector task sees no new | |
| 931 | * sector, and BLOCK rises. | |
| 932 | * | |
| 933 | * (This is like the video timing's dwt_blocks and dht_blocks signals) | |
| 934 | * </PRE> | |
| 935 | */ | |
| 936 | ||
| 937 | /** | |
| 938 | * @brief monoflop 31a pulse duration | |
| 939 | * Rt = 15k, Cext = .47µF (=470000pF) => 2066120ns (~2ms) | |
| 940 | */ | |
| 941 | #define TW_READY attotime::from_nsec(2066120) | |
| 942 | ||
| 943 | /** | |
| 944 | * @brief monoflop 31b pulse duration | |
| 945 | * Rt = 30k, Cext = .01µF (=10000pF) => 86960ns (~85us) | |
| 946 | * | |
| 947 | * There's something wrong with this, or the KSEC would never ever | |
| 948 | * be able to commence the KWD. The SECLATE monoflop ouput has to go | |
| 949 | * high some time into the KSEC task microcode, before the sequence | |
| 950 | * error state is checked. | |
| 951 | * | |
| 952 | * TW_SECLATE (85960 nsec) | |
| 953 | * TW_SECLATE (46*ALTO2_UCYCLE) | |
| 954 | */ | |
| 955 | #define TW_SECLATE 8596 | |
| 956 | ||
| 957 | /** @brief monoflop 52b pulse duration | |
| 958 | * Rt = 20k, Cext = 0.01µF (=10000pF) => 57960ns (~58us) | |
| 959 | */ | |
| 960 | #define TW_STROBON 57960 | |
| 961 | ||
| 962 | /** | |
| 963 | * <PRE> | |
| 964 | * DISK WORD TIMING | |
| 965 | * | |
| 966 | * | |
| 967 | * SECLATE ----· +-+-+-+---< 1 | |
| 968 | * | | | | | | |
| 969 | * +--o-----------+ CARRY +---+ | |
| 970 | * | CLR 1 2 4 8 |-------|INVo-----> WDDONE' | |
| 971 | * +---+ BITCLK' | | +---+ | |
| 972 | * BITCLK >----|INVo----+------|CLK/ 74161 | | |
| 973 | * +---+ | +----o---------+ | |
| 974 | * | |LOAD' | |
| 975 | * ·----------· | | |
| 976 | * | +----+ | | |
| 977 | * ·--|NAND| | | |
| 978 | * | o----· | | |
| 979 | * HIORDBIT >-----| | | | | |
| 980 | * +----+ | | | |
| 981 | * | | | |
| 982 | * +---o--+ Q | | |
| 983 | * BUS[4] >--------+--|J S' |------· | |
| 984 | * | | | +----+ | |
| 985 | * LDCOM' >--------|--|CLK | ·------|NAND| | |
| 986 | * | | 67b| | | o----> WAKEWDT' | |
| 987 | * +--|K' C' | | ·--| | | |
| 988 | * +---o--+ | | +----+ | |
| 989 | * | | | | |
| 990 | * 1 | ·----------· | |
| 991 | * | | | |
| 992 | * OK TO RUN >---------------· 1 | 1 | | |
| 993 | * (1 in AltoI) | | | | | | |
| 994 | * +---o--+ Q +---o--+ Q | +---o--+ Q | | |
| 995 | * 1 >-|J S' |----------|J S' |------+---|J S' |---· | |
| 996 | * | | | | | | | | |
| 997 | * WDDONE' >-----------|CLK | ·-------|CLK | .--|---|CLK | | |
| 998 | * | 43b| | | 53a| | | | 43a| | |
| 999 | * 1 >-|K' C' | | ·-----|K' C' | | `---|K' C' o---· | |
| 1000 | * +---o--+ | | +---o--+ | +---o--+ Q'| | |
| 1001 | * | | | | | | | | |
| 1002 | * ·-----|-|---------|------|----------|------· | |
| 1003 | * | | | | | | |
| 1004 | * SYSCLKA' >---------------------|-|---------|------· | | |
| 1005 | * | | | | | |
| 1006 | * WDALLOW >---------------------|-|---------+-----------------· | |
| 1007 | * | | | | |
| 1008 | * SYSCLKB' >---------------------+ | +---o--+ Q | |
| 1009 | * | | 0 >-|J S' |-------------> WDINIT | |
| 1010 | * | | | | | |
| 1011 | * +----+ ·-|-----|CLK | | |
| 1012 | * BLOCK >--|NAND| | | 53b| | |
| 1013 | * | o---------------+-----|K C' | | |
| 1014 | * WDTSKACT >--| | +---o--+ | |
| 1015 | * +----+ | | |
| 1016 | * 1 | |
| 1017 | * | |
| 1018 | * | |
| 1019 | * If SECLATE is 0, WDDONE' never goes low (counter's clear has precedence). | |
| 1020 | * | |
| 1021 | * If SECLATE is 1, WDDONE', the counter will count: | |
| 1022 | * | |
| 1023 | * If HIORDBIT is 1 at the falling edge of BITCLK, it sets the J-K flip-flop 67b, and | |
| 1024 | * thus takes away the LOAD' assertion from the counter. It has been loaded with | |
| 1025 | * 15, so it counts to 16 on the next rising edge and makes WDDONE' go to 0. | |
| 1026 | * | |
| 1027 | * If HIORDBIT is 0 at the falling edge of BITCLK, counting continues as it was | |
| 1028 | * preset with BUS[4] at the last KCOM<- load: | |
| 1029 | * | |
| 1030 | * If BUS[4] was 1, both J and K' of the FF (74109) will be 1 at the rising edge | |
| 1031 | * of LDCOM' (at the end of KCOM<-) and Q will be 1 => LOAD' is deasserted. | |
| 1032 | * | |
| 1033 | * If BUS[4] was 0, both J and K' will be 0, and Q will be 0 => LOAD' asserted. | |
| 1034 | * | |
| 1035 | * WDDONE' going from 0 to 1 will make the Q output of FF 43b go to 1. | |
| 1036 | * The FF is also set, as long as OK TO RUN is 0. | |
| 1037 | * | |
| 1038 | * The FF 53a is clocked with falling edge of SYSCLKB (rising of SYSCLKB'), | |
| 1039 | * and will: | |
| 1040 | * if J and K' are both 1, set its Q to 1. | |
| 1041 | * if J is 1, and K' is 0, toggle Q. | |
| 1042 | * if J is 0, and K' is 1, keep Q as is. | |
| 1043 | * if J and K' are both 0, set its Q to 0. | |
| 1044 | * J is = Q of the FF 43b. | |
| 1045 | * K is = 0, if both BLOCK and WDTASKACT are 1, and 1 otherwise. | |
| 1046 | * | |
| 1047 | * The FF 43a is clocked with falling edge of SYSCLKA (rising of SYSCLKA'). | |
| 1048 | * Its J and K' inputs are the Q output of the previous (middle) FF, thus | |
| 1049 | * it will propagate the middle FF's Q to its own Q when SYSCLKA goes 0. | |
| 1050 | * | |
| 1051 | * If Q (53a) and Q (43a) are both 1, the WAKEKWDT' is 0 and the | |
| 1052 | * word task wakeup signal is sent. | |
| 1053 | * | |
| 1054 | * WDALLOW going 0 asynchronously resets the 53a and 43a FFs, and thus | |
| 1055 | * deasserts the WAKEKWD'. It also asynchronously sets the FF 53b, and | |
| 1056 | * its output Q is the WDINIT signal. | |
| 1057 | * | |
| 1058 | * WDINIT is also deasserted with SYSCLKB going high, whenever both BLOCK | |
| 1059 | * and WDTSKACT are 1. | |
| 1060 | * | |
| 1061 | * Whoa there! :-) | |
| 1062 | * </PRE> | |
| 1063 | */ | |
| 1064 | #define INIT (m_task == task_kwd && m_dsk.wdinit0) | |
| 1065 | ||
| 1066 | #define WFFO (GET_KCOM_WFFO(m_dsk.kcom)) | |
| 1067 | #define WDALLOW (!GET_KCOM_WDINHIB(m_dsk.kcom)) | |
| 1068 | #define WDINIT ((m_dsk.ff_53b & JKFF_Q) ? 1 : 0) | |
| 1069 | #define RDYLAT ((m_dsk.ff_45a & JKFF_Q) ? 1 : 0) | |
| 1070 | #define SEQERR ((m_task == task_ksec && m_dsk.seclate == 0) || (m_task == task_kwd && m_dsk.carry == 1)) | |
| 1071 | #define ERRWAKE (RDYLAT | m_dsk.ready_mf31a) | |
| 1072 | #define SEEKOK (m_dsk.seekok) | |
| 1073 | ||
| 1074 | /** | |
| 1075 | * @brief disk word timing | |
| 1076 | * | |
| 1077 | * Implement the FIFOs and gates in the description above. | |
| 1078 | * | |
| 1079 | * @param bitclk the current bitclk level | |
| 1080 | * @param datin the level of the bit read from the disk | |
| 1081 | * @param block contains the task number of a blocking task, or 0 otherwise | |
| 1082 | */ | |
| 1083 | void alto2_cpu_device::kwd_timing(int bitclk, int datin, int block) | |
| 1084 | { | |
| 1085 | static int wddone0; | |
| 1086 | int wddone1 = wddone0; | |
| 1087 | int i; | |
| 1088 | UINT8 s0, s1; | |
| 1089 | ||
| 1090 | LOG((0,5," >>> KWD timing bitclk:%d datin:%d sect4:%d\n", bitclk, datin, drive_sector_mark_0(m_dsk.drive))); | |
| 1091 | ||
| 1092 | if (0 == m_dsk.seclate) { | |
| 1093 | /* If SECLATE is 0, WDDONE' never goes low (counter's clear has precedence). */ | |
| 1094 | LOG((0,3," SECLATE:0 clears bitcount:0\n")); | |
| 1095 | m_dsk.bitcount = 0; | |
| 1096 | m_dsk.carry = 0; | |
| 1097 | } else if (m_dsk.bitclk && !bitclk) { | |
| 1098 | /* | |
| 1099 | * If SECLATE is 1, the counter will count or load: | |
| 1100 | */ | |
| 1101 | if ((m_dsk.shiftin & (1 << 16)) && !WFFO) { | |
| 1102 | /* | |
| 1103 | * If HIORDBIT is 1 at the falling edge of BITCLK, it sets the | |
| 1104 | * JK-FF 67b, and thus takes away the LOAD' assertion from the | |
| 1105 | * counter. It has been loaded with 15, so it counts to 16 on | |
| 1106 | * the next rising edge and makes WDDONE' go to 0. | |
| 1107 | */ | |
| 1108 | LOG((0,3," HIORDBIT:1 sets WFFO:1\n")); | |
| 1109 | PUT_KCOM_WFFO(m_dsk.kcom, 1); | |
| 1110 | } | |
| 1111 | /* | |
| 1112 | * Falling edge of BITCLK, counting continues as it was preset | |
| 1113 | * with BUS[4] (WFFO) at the last KCOM<- load, or as set by a | |
| 1114 | * 1 bit being read in HIORDBIT. | |
| 1115 | */ | |
| 1116 | if (WFFO) { | |
| 1117 | /* | |
| 1118 | * If BUS[4] (WFFO) was 1, both J and K' of the FF (74109) will | |
| 1119 | * be 1 at the rising edge of LDCOM' (at the end of KCOM<-) | |
| 1120 | * and Q will be 1. LOAD' is deassterted: count on clock. | |
| 1121 | */ | |
| 1122 | m_dsk.bitcount = (m_dsk.bitcount + 1) % 16; | |
| 1123 | m_dsk.carry = m_dsk.bitcount == 15; | |
| 1124 | LOG((0,3," WFFO:1 count bitcount:%2d\n", m_dsk.bitcount)); | |
| 1125 | } else { | |
| 1126 | /* | |
| 1127 | * If BUS[4] (WFFO) was 0, both J and K' will be 0, and Q | |
| 1128 | * will be 0. LOAD' is asserted: load on clock. | |
| 1129 | */ | |
| 1130 | m_dsk.bitcount = 15; | |
| 1131 | m_dsk.carry = 1; | |
| 1132 | LOG((0,3," WFFO:0 load bitcount:%2d\n", m_dsk.bitcount)); | |
| 1133 | } | |
| 1134 | } else if (!m_dsk.bitclk && bitclk) { | |
| 1135 | /* clock the shift register on the rising edge of bitclk */ | |
| 1136 | m_dsk.shiftin = (m_dsk.shiftin << 1) | datin; | |
| 1137 | /* and the output shift register, too */ | |
| 1138 | m_dsk.shiftout = m_dsk.shiftout << 1; | |
| 1139 | } | |
| 1140 | ||
| 1141 | if (wddone0 != wddone1) { | |
| 1142 | LOG((0,2," WDDONE':%d->%d\n", wddone0, wddone1)); | |
| 1143 | } | |
| 1144 | ||
| 1145 | if (m_dsk.carry) { | |
| 1146 | /* CARRY = 1 -> WDDONE' = 0 */ | |
| 1147 | wddone1 = 0; | |
| 1148 | if (wddone0 == 0) { | |
| 1149 | /* | |
| 1150 | * Latch a new data word while WDDONE is 0 | |
| 1151 | * Note: The shifter outputs for bits 0 to 14 are connected | |
| 1152 | * to the latches inputs 1 to 15, while input bit 0 comes | |
| 1153 | * from the current datin. | |
| 1154 | * Shifter output 15 is the HIORDBIT signal. | |
| 1155 | */ | |
| 1156 | m_dsk.datain = m_dsk.shiftin & 0177777; | |
| 1157 | /* load the output shift register */ | |
| 1158 | m_dsk.shiftout = m_dsk.dataout; | |
| 1159 | LOG((0,6," LATCH in:%06o (0x%04x) out:%06o (0x%04x)\n", m_dsk.datain, m_dsk.datain, m_dsk.dataout, m_dsk.dataout)); | |
| 1160 | } | |
| 1161 | } else { | |
| 1162 | /* CARRY = 0 -> WDDONE' = 1 */ | |
| 1163 | wddone1 = 1; | |
| 1164 | } | |
| 1165 | ||
| 1166 | /* remember previous state of wddone */ | |
| 1167 | wddone0 = wddone1; | |
| 1168 | ||
| 1169 | /** | |
| 1170 | * JK flip-flop 43b (word task) | |
| 1171 | * <PRE> | |
| 1172 | * CLK WDDONE' | |
| 1173 | * J 1 | |
| 1174 | * K' 1 | |
| 1175 | * S' 1 | |
| 1176 | * C' WDTSKENA | |
| 1177 | * Q to 53a J | |
| 1178 | * </PRE> | |
| 1179 | */ | |
| 1180 | DEBUG_NAME(" KWD 43b"); | |
| 1181 | m_dsk.ff_43b = update_jkff(m_dsk.ff_43b, | |
| 1182 | (wddone1 ? JKFF_CLK : 0) | | |
| 1183 | JKFF_J | | |
| 1184 | JKFF_K | | |
| 1185 | (m_dsk.ok_to_run ? JKFF_S : 0) | | |
| 1186 | ((m_dsk.ff_43a & JKFF_Q) ? 0 : JKFF_C)); | |
| 1187 | ||
| 1188 | /* count for the 4 stages of sysclka and sysclkb transitions */ | |
| 1189 | for (i = 0; i < 4; i++) { | |
| 1190 | ||
| 1191 | if (m_sysclka0[i] != m_sysclka1[i]) { | |
| 1192 | LOG((0,7," SYSCLKA':%d->%d\n", m_sysclka0[i], m_sysclka1[i])); | |
| 1193 | } | |
| 1194 | if (m_sysclkb0[i] != m_sysclkb1[i]) { | |
| 1195 | LOG((0,7," SYSCLKB':%d->%d\n", m_sysclkb0[i], m_sysclkb1[i])); | |
| 1196 | } | |
| 1197 | ||
| 1198 | /** | |
| 1199 | * JK flip-flop 53b (word task) | |
| 1200 | * <PRE> | |
| 1201 | * CLK SYSCLKB' | |
| 1202 | * J 0 | |
| 1203 | * K' (BLOCK & WDTSKACT)' | |
| 1204 | * S' WDALLOW | |
| 1205 | * C' 1 | |
| 1206 | * Q WDINIT | |
| 1207 | * </PRE> | |
| 1208 | */ | |
| 1209 | DEBUG_NAME(" KWD 53b"); | |
| 1210 | s0 = m_dsk.ff_53b; | |
| 1211 | s1 = m_sysclkb1[i]; | |
| 1212 | if (block != task_kwd) | |
| 1213 | s1 |= JKFF_K; // (BLOCK & WDTSKACT)' | |
| 1214 | if (WDALLOW) | |
| 1215 | s1 |= JKFF_S; | |
| 1216 | s1 |= JKFF_C; | |
| 1217 | m_dsk.ff_53b = update_jkff(s0, s1); | |
| 1218 | ||
| 1219 | /** | |
| 1220 | * JK flip-flop 53a (word task) | |
| 1221 | * <PRE> | |
| 1222 | * CLK SYSCLKB' | |
| 1223 | * J from 43b Q | |
| 1224 | * K' (BLOCK & WDTSKACT)' | |
| 1225 | * S' 1 | |
| 1226 | * C' WDALLOW | |
| 1227 | * Q to 43a J and K' | |
| 1228 | * </PRE> | |
| 1229 | */ | |
| 1230 | DEBUG_NAME(" KWD 53a"); | |
| 1231 | s0 = m_dsk.ff_53a; | |
| 1232 | s1 = m_sysclkb1[i]; | |
| 1233 | if (m_dsk.ff_43b & JKFF_Q) | |
| 1234 | s1 |= JKFF_J; | |
| 1235 | if (block != task_kwd) | |
| 1236 | s1 |= JKFF_K; | |
| 1237 | s1 |= JKFF_S; | |
| 1238 | if (WDALLOW) | |
| 1239 | s1 |= JKFF_C; | |
| 1240 | m_dsk.ff_53a = update_jkff(s0, s1); | |
| 1241 | ||
| 1242 | /** | |
| 1243 | * JK flip-flop 43a (word task) | |
| 1244 | * <PRE> | |
| 1245 | * CLK SYSCLKA' | |
| 1246 | * J from 53a Q | |
| 1247 | * K' from 53a Q | |
| 1248 | * S' 1 | |
| 1249 | * C' WDALLOW | |
| 1250 | * Q WDTSKENA', Q' WDTSKENA | |
| 1251 | * </PRE> | |
| 1252 | */ | |
| 1253 | DEBUG_NAME(" KWD 43a"); | |
| 1254 | s0 = m_dsk.ff_43a; | |
| 1255 | s1 = m_sysclka1[i]; | |
| 1256 | if (m_dsk.ff_53a & JKFF_Q) | |
| 1257 | s1 |= JKFF_J; | |
| 1258 | if (m_dsk.ff_53a & JKFF_Q) | |
| 1259 | s1 |= JKFF_K; | |
| 1260 | s1 |= JKFF_S; | |
| 1261 | if (WDALLOW) | |
| 1262 | s1 |= JKFF_C; | |
| 1263 | m_dsk.ff_43a = update_jkff(s0, s1); | |
| 1264 | ||
| 1265 | /** | |
| 1266 | * JK flip-flop 45a (ready latch) | |
| 1267 | * <PRE> | |
| 1268 | * CLK SYSCLKA' | |
| 1269 | * J READY' from drive | |
| 1270 | * K' 1 | |
| 1271 | * S' 1 | |
| 1272 | * C' CLRSTAT' | |
| 1273 | * Q RDYLAT' | |
| 1274 | * </PRE> | |
| 1275 | */ | |
| 1276 | DEBUG_NAME(" RDYLAT 45a"); | |
| 1277 | s0 = m_dsk.ff_45a; | |
| 1278 | s1 = m_sysclka1[i]; | |
| 1279 | if (drive_ready_0(m_dsk.drive)) | |
| 1280 | s1 |= JKFF_J; | |
| 1281 | s1 |= JKFF_K; | |
| 1282 | s1 |= JKFF_S; | |
| 1283 | s1 |= JKFF_C; // FIXME: CLRSTAT' ? | |
| 1284 | ||
| 1285 | m_dsk.ff_45a = update_jkff(s0, s1); | |
| 1286 | ||
| 1287 | /** | |
| 1288 | * sets the seqerr flip-flop 45b (Q' is SEQERR) | |
| 1289 | * JK flip-flop 45b (seqerr latch) | |
| 1290 | * <PRE> | |
| 1291 | * CLK SYSCLKA' | |
| 1292 | * J 1 | |
| 1293 | * K' SEQERR' | |
| 1294 | * S' CLRSTAT' | |
| 1295 | * C' 1 | |
| 1296 | * Q to KSTAT[11] DATALATE | |
| 1297 | * </PRE> | |
| 1298 | */ | |
| 1299 | DEBUG_NAME(" SEQERR 45b"); | |
| 1300 | s0 = m_dsk.ff_45b; | |
| 1301 | s1 = m_sysclka1[i]; | |
| 1302 | s1 |= JKFF_J; | |
| 1303 | if (SEQERR) | |
| 1304 | s1 |= JKFF_K; | |
| 1305 | s1 |= JKFF_S; // FIXME: CLRSTAT' ? | |
| 1306 | s1 |= JKFF_C; | |
| 1307 | m_dsk.ff_45b = update_jkff(s0, s1); | |
| 1308 | ||
| 1309 | /** | |
| 1310 | * JK flip-flop 22b (sector task) | |
| 1311 | * <PRE> | |
| 1312 | * CLK SYSCLKB' | |
| 1313 | * J from 22a Q | |
| 1314 | * K' (BLOCK & STSKACT)' | |
| 1315 | * S' 1 (really it's RESET') | |
| 1316 | * C' 1 | |
| 1317 | * Q STSKENA; Q' WAKEKST' | |
| 1318 | * </PRE> | |
| 1319 | */ | |
| 1320 | DEBUG_NAME(" KSEC 22b"); | |
| 1321 | s0 = m_dsk.ff_22b; | |
| 1322 | s1 = m_sysclkb1[i]; | |
| 1323 | if (m_dsk.ff_22a & JKFF_Q) | |
| 1324 | s1 |= JKFF_J; | |
| 1325 | if (block != task_ksec) | |
| 1326 | s1 |= JKFF_K; | |
| 1327 | s1 |= JKFF_S; // FIXME: RESET' ? | |
| 1328 | s1 |= JKFF_C; | |
| 1329 | m_dsk.ff_22b = update_jkff(s0, s1); | |
| 1330 | ||
| 1331 | /** | |
| 1332 | * JK flip-flop 22a (sector task) | |
| 1333 | * <PRE> | |
| 1334 | * CLK SYSCLKB' | |
| 1335 | * J from 21b Q | |
| 1336 | * K' 1 | |
| 1337 | * S' 1 | |
| 1338 | * C' WAKEST' | |
| 1339 | * Q to 22b J | |
| 1340 | * </PRE> | |
| 1341 | */ | |
| 1342 | DEBUG_NAME(" KSEC 22a"); | |
| 1343 | s0 = m_dsk.ff_22a; | |
| 1344 | s1 = m_sysclkb1[i]; | |
| 1345 | if (m_dsk.ff_21b & JKFF_Q) | |
| 1346 | s1 |= JKFF_J; | |
| 1347 | s1 |= JKFF_K; | |
| 1348 | s1 |= JKFF_S; | |
| 1349 | if (!(m_dsk.ff_22b & JKFF_Q)) | |
| 1350 | s1 |= JKFF_C; | |
| 1351 | m_dsk.ff_22a = update_jkff(s0, s1); | |
| 1352 | ||
| 1353 | /** | |
| 1354 | * JK flip-flop 21b (sector task) | |
| 1355 | * <PRE> | |
| 1356 | * CLK SYSCLKB' | |
| 1357 | * J from 21a Q | |
| 1358 | * K' 1 | |
| 1359 | * S' 1 | |
| 1360 | * C' WAKEST' | |
| 1361 | * Q to 22a J | |
| 1362 | * </PRE> | |
| 1363 | */ | |
| 1364 | DEBUG_NAME(" KSEC 21b"); | |
| 1365 | s0 = m_dsk.ff_21b; | |
| 1366 | s1 = m_sysclkb1[i]; | |
| 1367 | if (m_dsk.ff_21a & JKFF_Q) | |
| 1368 | s1 |= JKFF_J; | |
| 1369 | s1 |= JKFF_K; | |
| 1370 | s1 |= JKFF_S; | |
| 1371 | if (!(m_dsk.ff_22b & JKFF_Q)) | |
| 1372 | s1 |= JKFF_C; | |
| 1373 | m_dsk.ff_21b = update_jkff(s0, s1); | |
| 1374 | } | |
| 1375 | ||
| 1376 | /* The 53b FF Q output is the WDINIT signal. */ | |
| 1377 | if (WDINIT != m_dsk.wdinit) { | |
| 1378 | m_dsk.wdinit0 = m_dsk.wdinit; | |
| 1379 | /* rising edge immediately */ | |
| 1380 | if ((m_dsk.wdinit = WDINIT) == 1) | |
| 1381 | m_dsk.wdinit0 = 1; | |
| 1382 | LOG((0,2," WDINIT:%d\n", m_dsk.wdinit)); | |
| 1383 | } | |
| 1384 | ||
| 1385 | /* | |
| 1386 | * If Q (53a) and Q (43a) are both 1, the WAKEKWDT' | |
| 1387 | * output is 0 and the disk word task wakeup signal is asserted. | |
| 1388 | */ | |
| 1389 | if (m_dsk.ff_53a & m_dsk.ff_43a & JKFF_Q) { | |
| 1390 | if (m_dsk.wdtskena == 1) { | |
| 1391 | LOG((0,2," WDTSKENA':0 and WAKEKWDT':0 wake KWD\n")); | |
| 1392 | m_dsk.wdtskena = 0; | |
| 1393 | m_task_wakeup |= 1 << task_kwd; | |
| 1394 | } | |
| 1395 | } else if (m_dsk.ff_43a & JKFF_Q) { | |
| 1396 | /* | |
| 1397 | * If Q (43a) is 1, the WDTSKENA' signal is deasserted. | |
| 1398 | */ | |
| 1399 | if (m_dsk.wdtskena == 0) { | |
| 1400 | LOG((0,2," WDTSKENA':1\n")); | |
| 1401 | m_dsk.wdtskena = 1; | |
| 1402 | m_task_wakeup &= ~(1 << task_kwd); | |
| 1403 | } | |
| 1404 | } | |
| 1405 | ||
| 1406 | if (m_dsk.kfer) { | |
| 1407 | /* no fatal error: ready and not seqerr and seekok */ | |
| 1408 | if (!RDYLAT && !SEQERR && SEEKOK) { | |
| 1409 | LOG((0,2," reset KFER\n")); | |
| 1410 | m_dsk.kfer = 0; | |
| 1411 | } | |
| 1412 | } else { | |
| 1413 | /* fatal error: not ready or seqerr or not seekok */ | |
| 1414 | if (RDYLAT) { | |
| 1415 | LOG((0,2," RDYLAT sets KFER\n")); | |
| 1416 | m_dsk.kfer = 1; | |
| 1417 | } else if (SEQERR) { | |
| 1418 | LOG((0,2," SEQERR sets KFER\n")); | |
| 1419 | m_dsk.kfer = 1; | |
| 1420 | } else if (!SEEKOK) { | |
| 1421 | LOG((0,2," not SEEKOK sets KFER\n")); | |
| 1422 | m_dsk.kfer = 1; | |
| 1423 | } | |
| 1424 | } | |
| 1425 | ||
| 1426 | /* | |
| 1427 | * The FF 22b Q output is the STSKENA signal, | |
| 1428 | * the Q' is the WAKEKST' signal. | |
| 1429 | */ | |
| 1430 | if (m_dsk.ff_22b & JKFF_Q) { | |
| 1431 | if (!(m_task_wakeup & (1 << task_ksec))) { | |
| 1432 | LOG((0,2," STSKENA:1; WAKEST':0 wake KSEC\n")); | |
| 1433 | m_task_wakeup |= 1 << task_kwd; | |
| 1434 | } | |
| 1435 | } else { | |
| 1436 | if (m_task_wakeup & (1 << task_ksec)) { | |
| 1437 | LOG((0,2," STSKENA:0; WAKEST':1\n")); | |
| 1438 | m_task_wakeup &= ~(1 << task_kwd); | |
| 1439 | } | |
| 1440 | } | |
| 1441 | ||
| 1442 | /** | |
| 1443 | * JK flip-flop 21a (sector task) | |
| 1444 | * <PRE> | |
| 1445 | * CLK SECT4 (inverted sector mark from drive) | |
| 1446 | * J WAKEST' | |
| 1447 | * K' 1 | |
| 1448 | * S' ERRWAKE' | |
| 1449 | * C' WAKEST' | |
| 1450 | * Q to seclate monoflop | |
| 1451 | * </PRE> | |
| 1452 | */ | |
| 1453 | DEBUG_NAME(" KSEC 21a"); | |
| 1454 | s0 = m_dsk.ff_21a; | |
| 1455 | s1 = drive_sector_mark_0(m_dsk.drive) ? 0 : JKFF_CLK; | |
| 1456 | if (!(m_dsk.ff_22b & JKFF_Q)) | |
| 1457 | s1 |= JKFF_J; | |
| 1458 | s1 |= JKFF_K; | |
| 1459 | if (!ERRWAKE) | |
| 1460 | s1 |= JKFF_S; | |
| 1461 | if (!(m_dsk.ff_22b & JKFF_Q)) | |
| 1462 | s1 |= JKFF_C; | |
| 1463 | m_dsk.ff_21a = update_jkff(s0, s1); | |
| 1464 | ||
| 1465 | /* | |
| 1466 | * If the KSEC FF 21a Q goes 1, pulse the SECLATE signal for | |
| 1467 | * some time. | |
| 1468 | */ | |
| 1469 | if (!(m_dsk.ff_21a_old & JKFF_Q) && (m_dsk.ff_21a & JKFF_Q)) { | |
| 1470 | if (!m_dsk.seclate_timer) | |
| 1471 | m_dsk.seclate_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_seclate),this));; | |
| 1472 | m_dsk.seclate_timer->adjust(attotime::from_nsec(TW_SECLATE), 1, attotime::never); | |
| 1473 | if (m_dsk.seclate) { | |
| 1474 | m_dsk.seclate = 0; | |
| 1475 | LOG((0,4," SECLATE -> 0 pulse until %lldns\n", ntime() + TW_SECLATE)); | |
| 1476 | } | |
| 1477 | } | |
| 1478 | ||
| 1479 | /* | |
| 1480 | * check if write and erase gate, or read gate are changed | |
| 1481 | */ | |
| 1482 | if ((m_task_wakeup & (1 << task_ksec)) || GET_KCOM_XFEROFF(m_dsk.kcom) || m_dsk.kfer) { | |
| 1483 | drive_egate(m_dsk.drive, 1); | |
| 1484 | drive_wrgate(m_dsk.drive, 1); | |
| 1485 | drive_rdgate(m_dsk.drive, 1); | |
| 1486 | } else { | |
| 1487 | /* enable either read or write gates depending on current record R/W */ | |
| 1488 | if (m_dsk.krwc & RWC_WRITE) { | |
| 1489 | /* enable erase and write gates only if OKTORUN is high */ | |
| 1490 | if (m_dsk.ok_to_run) { | |
| 1491 | drive_egate(m_dsk.drive, 0); | |
| 1492 | drive_wrgate(m_dsk.drive, 0); | |
| 1493 | } | |
| 1494 | } else { | |
| 1495 | /* enable read gate */ | |
| 1496 | drive_rdgate(m_dsk.drive, 0); | |
| 1497 | } | |
| 1498 | } | |
| 1499 | ||
| 1500 | m_dsk.ff_21a_old = m_dsk.ff_21a; | |
| 1501 | m_dsk.bitclk = bitclk; | |
| 1502 | m_dsk.datin = datin; | |
| 1503 | LOG((0,5," <<< KWD timing\n")); | |
| 1504 | } | |
| 1505 | ||
| 1506 | ||
| 1507 | /** @brief timer callback to take away the SECLATE pulse (monoflop) */ | |
| 1508 | void alto2_cpu_device::disk_seclate(void* ptr, INT32 arg) | |
| 1509 | { | |
| 1510 | (void)ptr; | |
| 1511 | LOG((0,2," SECLATE -> %d\n", arg)); | |
| 1512 | m_dsk.seclate = arg; | |
| 1513 | m_dsk.seclate_timer->enable(false); | |
| 1514 | } | |
| 1515 | ||
| 1516 | /** @brief timer callback to take away the OK TO RUN pulse (reset) */ | |
| 1517 | void alto2_cpu_device::disk_ok_to_run(void* ptr, INT32 arg) | |
| 1518 | { | |
| 1519 | (void)ptr; | |
| 1520 | LOG((0,2," OK TO RUN -> %d\n", arg)); | |
| 1521 | m_dsk.ok_to_run = arg; | |
| 1522 | m_dsk.ok_to_run_timer->enable(false); | |
| 1523 | } | |
| 1524 | ||
| 1525 | /** | |
| 1526 | * @brief timer callback to pulse the STROBE' signal to the drive | |
| 1527 | * | |
| 1528 | * STROBE' pulses are sent to the drive at a rate that depends on | |
| 1529 | * the monoflop 52b external resistor and capacitor. | |
| 1530 | * | |
| 1531 | * The drive compares the cylinder number that is presented on | |
| 1532 | * it's inputs against the current cylinder, and if they don't | |
| 1533 | * match steps into the corresponding direction. | |
| 1534 | * | |
| 1535 | * On the falling edge of a strobe, the drive sets the log_addx_interlock | |
| 1536 | * flag 0 (LAI, active low). On the rising edge of the strobe the drive then | |
| 1537 | * indicates seek completion by setting addx_acknowledge to 0 (ADDRACK, active low). | |
| 1538 | * If the seek is not yet complete, it instead keeps the seek_incomplete | |
| 1539 | * flag 0 (SKINC, active low). If the seek would go beyond the last cylinder, | |
| 1540 | * the drive deasserts seek_incomplete, but does not assert the addx_acknowledge. | |
| 1541 | * | |
| 1542 | * @param id timer id | |
| 1543 | * @param arg contains the drive, cylinder, and restore flag | |
| 1544 | */ | |
| 1545 | void alto2_cpu_device::disk_strobon(void* ptr, INT32 arg) | |
| 1546 | { | |
| 1547 | (void)ptr; | |
| 1548 | UINT8 unit = static_cast<UINT8>(arg & 1); | |
| 1549 | UINT8 restore = static_cast<UINT8>((arg >> 1) & 1); | |
| 1550 | INT32 cylinder = arg >> 2; | |
| 1551 | int seekok; | |
| 1552 | int lai; | |
| 1553 | int strobe; | |
| 1554 | ||
| 1555 | LOG((0,2," STROBE #%d restore:%d cylinder:%d\n", unit, restore, cylinder)); | |
| 1556 | ||
| 1557 | /* This is really monoflop 52a generating a very short 0 pulse */ | |
| 1558 | for (strobe = 0; strobe < 2; strobe++) { | |
| 1559 | UINT8 s0, s1; | |
| 1560 | /* pulse the strobe signal to the unit */ | |
| 1561 | drive_strobe(unit, cylinder, restore, strobe); | |
| 1562 | ||
| 1563 | lai = drive_log_addx_interlock_0(unit); | |
| 1564 | LOG((0,6," LAI':%d\n", lai)); | |
| 1565 | /** | |
| 1566 | * JK flip-flop 44a (LAI' clocked) | |
| 1567 | * <PRE> | |
| 1568 | * CLK LAI | |
| 1569 | * J 1 | |
| 1570 | * K' 1 | |
| 1571 | * S' 1 | |
| 1572 | * C' CLRSTAT' (not now) | |
| 1573 | * Q to seekok | |
| 1574 | * </PRE> | |
| 1575 | */ | |
| 1576 | DEBUG_NAME(" LAI 44a"); | |
| 1577 | s0 = m_dsk.ff_44a; | |
| 1578 | s1 = lai ? JKFF_CLK : JKFF_0; | |
| 1579 | s1 |= JKFF_J; | |
| 1580 | s1 |= JKFF_K; | |
| 1581 | s1 |= JKFF_S; | |
| 1582 | s1 |= JKFF_C; | |
| 1583 | m_dsk.ff_44a = update_jkff(s0, s1); | |
| 1584 | if (drive_addx_acknowledge_0(unit) == 0 && (m_dsk.ff_44a & JKFF_Q)) { | |
| 1585 | /* if address is acknowledged, and Q' of FF 44a, clear the strobe */ | |
| 1586 | m_dsk.strobe = 0; | |
| 1587 | } | |
| 1588 | } | |
| 1589 | ||
| 1590 | if (drive_addx_acknowledge_0(unit)) { | |
| 1591 | ||
| 1592 | /* no acknowledge yet */ | |
| 1593 | ||
| 1594 | } else { | |
| 1595 | /* clear the monoflop 52b, i.e. no timer restart */ | |
| 1596 | LOG((0,2," STROBON:%d\n", m_dsk.strobe)); | |
| 1597 | ||
| 1598 | /* update the seekok status: SKINC' && LAI' && Q' of FF 44a */ | |
| 1599 | seekok = drive_seek_incomplete_0(unit); | |
| 1600 | if (seekok != m_dsk.seekok) { | |
| 1601 | m_dsk.seekok = seekok; | |
| 1602 | LOG((0,2," SEEKOK:%d\n", m_dsk.seekok)); | |
| 1603 | } | |
| 1604 | } | |
| 1605 | ||
| 1606 | LOG((0,2," current cylinder:%d\n", drive_cylinder(unit) ^ DRIVE_CYLINDER_MASK)); | |
| 1607 | ||
| 1608 | /* if the strobe is still set, restart the timer */ | |
| 1609 | if (m_dsk.strobe) { | |
| 1610 | m_dsk.strobon_timer->adjust(attotime::from_nsec(TW_STROBON), arg); | |
| 1611 | m_dsk.strobon_timer->enable(); | |
| 1612 | } else { | |
| 1613 | m_dsk.strobon_timer->enable(false); | |
| 1614 | } | |
| 1615 | } | |
| 1616 | ||
| 1617 | /** @brief timer callback to change the READY monoflop 31a */ | |
| 1618 | void alto2_cpu_device::disk_ready_mf31a(void* ptr, INT32 arg) | |
| 1619 | { | |
| 1620 | m_dsk.ready_mf31a = arg & drive_ready_0(m_dsk.drive); | |
| 1621 | /* log the not ready result with level 0, else 2 */ | |
| 1622 | LOG((0,m_dsk.ready_mf31a ? 0 : 2," ready mf31a:%d\n", m_dsk.ready_mf31a)); | |
| 1623 | } | |
| 1624 | ||
| 1625 | /** | |
| 1626 | * @brief called if one of the disk tasks (task_kwd or task_ksec) blocks | |
| 1627 | * | |
| 1628 | * @param task task that blocks (either task_ksec or task_kwd) | |
| 1629 | */ | |
| 1630 | void alto2_cpu_device::disk_block(int task) | |
| 1631 | { | |
| 1632 | kwd_timing(m_dsk.bitclk, m_dsk.datin, task); | |
| 1633 | } | |
| 1634 | ||
| 1635 | /** | |
| 1636 | * @brief bs_read_kstat early: bus driven by disk status register KSTAT | |
| 1637 | * <PRE> | |
| 1638 | * Part of the KSTAT register is made of two 4 bit latches S8T10 (Signetics). | |
| 1639 | * The signals BUS[8-11] are the current state of: | |
| 1640 | * BUS[0-3] SECT[0-3]; from the Winchester drive (inverted) | |
| 1641 | * BUS[8] SEEKOK' | |
| 1642 | * BUS[9] SRWRDY' from the Winchester drive | |
| 1643 | * BUS[10] RDYLAT' (latched READY' at last CLRSTAT, FF 45a output Q) | |
| 1644 | * BUS[11] SEQERR (latched SEQERR at last CLRSTAT, FF 45b output Q') | |
| 1645 | * The signals BUS[12,14-15] are just as they were loaded at KSTAT<- time. | |
| 1646 | * BUS[13] CHSEMERROR (FF 44b output Q' inverted) | |
| 1647 | * </PRE> | |
| 1648 | */ | |
| 1649 | void alto2_cpu_device::bs_read_kstat_0() | |
| 1650 | { | |
| 1651 | UINT16 r; | |
| 1652 | int unit = m_dsk.drive; | |
| 1653 | ||
| 1654 | /* KSTAT[4-7] bus is open */ | |
| 1655 | PUT_KSTAT_DONE(m_dsk.kstat, 017); | |
| 1656 | ||
| 1657 | /* KSTAT[8] latch the inverted seekok status */ | |
| 1658 | PUT_KSTAT_SEEKFAIL(m_dsk.kstat, m_dsk.seekok ? 0 : 1); | |
| 1659 | ||
| 1660 | /* KSTAT[9] latch the drive seek/read/write status */ | |
| 1661 | PUT_KSTAT_SEEK(m_dsk.kstat, drive_seek_read_write_0(unit)); | |
| 1662 | ||
| 1663 | /* KSTAT[10] latch the latched (FF 45a at CLRSTAT) ready status */ | |
| 1664 | PUT_KSTAT_NOTRDY(m_dsk.kstat, m_dsk.ff_45a & JKFF_Q ? 1 : 0); | |
| 1665 | ||
| 1666 | /* KSTAT[11] latch the latched (FF 45b at CLRSTAT) seqerr status (Q') */ | |
| 1667 | PUT_KSTAT_DATALATE(m_dsk.kstat, m_dsk.ff_45b & JKFF_Q ? 0 : 1); | |
| 1668 | ||
| 1669 | /* KSTAT[13] latch the latched (FF 44b at CLRSTAT/KSTAT<-) checksum status */ | |
| 1670 | PUT_KSTAT_CKSUM(m_dsk.kstat, m_dsk.ff_44b & JKFF_Q ? 1 : 0); | |
| 1671 | ||
| 1672 | r = m_dsk.kstat; | |
| 1673 | ||
| 1674 | LOG((0,1," <-KSTAT; BUS &= %#o\n", r)); | |
| 1675 | LOG((0,2," sector: %d\n", GET_KSTAT_SECTOR(m_dsk.kstat))); | |
| 1676 | LOG((0,2," done: %d\n", GET_KSTAT_DONE(m_dsk.kstat))); | |
| 1677 | LOG((0,2," seekfail: %d\n", GET_KSTAT_SEEKFAIL(m_dsk.kstat))); | |
| 1678 | LOG((0,2," seek: %d\n", GET_KSTAT_SEEK(m_dsk.kstat))); | |
| 1679 | LOG((0,2," notrdy: %d\n", GET_KSTAT_NOTRDY(m_dsk.kstat))); | |
| 1680 | LOG((0,2," datalate: %d\n", GET_KSTAT_DATALATE(m_dsk.kstat))); | |
| 1681 | LOG((0,2," idle: %d\n", GET_KSTAT_IDLE(m_dsk.kstat))); | |
| 1682 | LOG((0,2," cksum: %d\n", GET_KSTAT_CKSUM(m_dsk.kstat))); | |
| 1683 | LOG((0,2," completion:%d\n", GET_KSTAT_COMPLETION(m_dsk.kstat))); | |
| 1684 | ||
| 1685 | m_bus &= r; | |
| 1686 | } | |
| 1687 | ||
| 1688 | /** | |
| 1689 | * @brief bs_read_kdata early: bus driven by disk data register KDATA input | |
| 1690 | * | |
| 1691 | * The input data register is a latch that latches the contents of | |
| 1692 | * the lower 15 bits of a 16 bit shift register in its more significant | |
| 1693 | * 15 bits, and the current read data bit is the least significant | |
| 1694 | * bit. This is handled in kwd_timing. | |
| 1695 | */ | |
| 1696 | void alto2_cpu_device::bs_read_kdata_0() | |
| 1697 | { | |
| 1698 | UINT16 r; | |
| 1699 | /* get the current word from the drive */ | |
| 1700 | r = m_dsk.datain; | |
| 1701 | LOG((0,1," <-KDATA (%#o)\n", r)); | |
| 1702 | m_bus &= r; | |
| 1703 | } | |
| 1704 | ||
| 1705 | /** | |
| 1706 | * @brief f1_strobe late: initiates a disk seek | |
| 1707 | * | |
| 1708 | * Initiates a disk seek operation. The KDATA register must have | |
| 1709 | * been loaded previously, and the SENDADR bit of the KCOM | |
| 1710 | * register previously set to 1. | |
| 1711 | */ | |
| 1712 | void alto2_cpu_device::f1_strobe_1() | |
| 1713 | { | |
| 1714 | if (GET_KCOM_SENDADR(m_dsk.kcom)) { | |
| 1715 | LOG((0,1," STROBE (SENDADR:1)\n")); | |
| 1716 | /* Set the STROBON flag and start the STROBON monoflop */ | |
| 1717 | m_dsk.strobe = 1; | |
| 1718 | disk_strobon(0, | |
| 1719 | 4 * GET_KADDR_CYLINDER(m_dsk.kaddr) + | |
| 1720 | 2 * GET_KADDR_RESTORE(m_dsk.kaddr) + | |
| 1721 | m_dsk.drive); | |
| 1722 | } else { | |
| 1723 | LOG((0,1," STROBE (w/o SENDADR)\n")); | |
| 1724 | /* FIXME: what to do if SENDADR isn't set? */ | |
| 1725 | } | |
| 1726 | } | |
| 1727 | ||
| 1728 | /** | |
| 1729 | * @brief f1_load_kstat late: load disk status register | |
| 1730 | * | |
| 1731 | * KSTAT[12-15] are loaded from BUS[12-15], except that BUS[13] is | |
| 1732 | * ORed into KSTAT[13]. | |
| 1733 | * | |
| 1734 | * NB: The 4 bits are just software, not changed by hardware | |
| 1735 | */ | |
| 1736 | void alto2_cpu_device::f1_load_kstat_1() | |
| 1737 | { | |
| 1738 | int i; | |
| 1739 | LOG((0,1," KSTAT<-; BUS[12-15] %#o\n", m_bus)); | |
| 1740 | LOG((0,2," idle: %d\n", GET_KSTAT_IDLE(m_bus))); | |
| 1741 | LOG((0,2," cksum: %d\n", GET_KSTAT_CKSUM(m_bus))); | |
| 1742 | LOG((0,2," completion:%d\n", GET_KSTAT_COMPLETION(m_bus))); | |
| 1743 | ||
| 1744 | /* KSTAT[12] is just taken from BUS[12] */ | |
| 1745 | PUT_KSTAT_IDLE(m_dsk.kstat, GET_KSTAT_IDLE(m_bus)); | |
| 1746 | ||
| 1747 | /* KSTAT[14-15] are just taken from BUS[14-15] */ | |
| 1748 | PUT_KSTAT_COMPLETION(m_dsk.kstat, GET_KSTAT_COMPLETION(m_bus)); | |
| 1749 | ||
| 1750 | /* May set the the CKSUM flip-flop 44b | |
| 1751 | * JK flip-flop 44b (KSTAT<- clocked) | |
| 1752 | * CLK SYSCLKA' | |
| 1753 | * J !BUS[13] | |
| 1754 | * K' 1 | |
| 1755 | * S' 1 | |
| 1756 | * C' CLRSTAT' (not now) | |
| 1757 | * Q Q' inverted to BUS[13] on <-KSTAT | |
| 1758 | */ | |
| 1759 | for (i = 0; i < 2; i++) { | |
| 1760 | UINT8 s0, s1; | |
| 1761 | DEBUG_NAME(" CKSUM 44b"); | |
| 1762 | s0 = m_dsk.ff_44b; | |
| 1763 | s1 = i ? JKFF_CLK : 0; | |
| 1764 | if (!A2_GET16(m_bus,16,13,13)) | |
| 1765 | s1 |= JKFF_J; | |
| 1766 | s1 |= JKFF_K; | |
| 1767 | s1 |= JKFF_S; | |
| 1768 | s1 |= JKFF_C; | |
| 1769 | m_dsk.ff_44b = update_jkff(s0, s1); | |
| 1770 | } | |
| 1771 | } | |
| 1772 | ||
| 1773 | /** | |
| 1774 | * @brief f1_load_kdata late: load data out register, or the disk address register | |
| 1775 | * | |
| 1776 | * KDATA is loaded from BUS. | |
| 1777 | */ | |
| 1778 | void alto2_cpu_device::f1_load_kdata_1() | |
| 1779 | { | |
| 1780 | m_dsk.dataout = m_bus; | |
| 1781 | if (GET_KCOM_SENDADR(m_dsk.kcom)) { | |
| 1782 | PUT_KADDR_SECTOR(m_dsk.kaddr, GET_KADDR_SECTOR(m_bus)); | |
| 1783 | PUT_KADDR_CYLINDER(m_dsk.kaddr, GET_KADDR_CYLINDER(m_bus)); | |
| 1784 | PUT_KADDR_HEAD(m_dsk.kaddr, GET_KADDR_HEAD(m_bus)); | |
| 1785 | PUT_KADDR_DRIVE(m_dsk.kaddr, GET_KADDR_DRIVE(m_bus)); | |
| 1786 | PUT_KADDR_RESTORE(m_dsk.kaddr, GET_KADDR_RESTORE(m_bus)); | |
| 1787 | PUT_KADDR_DRIVE(m_dsk.kaddr, GET_KADDR_DRIVE(m_bus)); | |
| 1788 | m_dsk.drive = GET_KADDR_DRIVE(m_dsk.kaddr); | |
| 1789 | ||
| 1790 | LOG((0,1," KDATA<-; BUS (%#o) (drive:%d restore:%d %d/%d/%02d page:%d)\n", | |
| 1791 | m_bus, | |
| 1792 | GET_KADDR_DRIVE(m_dsk.kaddr), | |
| 1793 | GET_KADDR_RESTORE(m_dsk.kaddr), | |
| 1794 | GET_KADDR_CYLINDER(m_dsk.kaddr), | |
| 1795 | GET_KADDR_HEAD(m_dsk.kaddr), | |
| 1796 | GET_KADDR_SECTOR(m_dsk.kaddr), | |
| 1797 | DRIVE_PAGE(GET_KADDR_CYLINDER(m_dsk.kaddr),GET_KADDR_HEAD(m_dsk.kaddr),GET_KADDR_SECTOR(m_dsk.kaddr)))); | |
| 1798 | #if 0 | |
| 1799 | /* printing changes in the disk address */ | |
| 1800 | { | |
| 1801 | static int last_kaddr; | |
| 1802 | if (m_dsk.kaddr != last_kaddr) { | |
| 1803 | int c = GET_KADDR_CYLINDER(m_dsk.kaddr); | |
| 1804 | int h = GET_KADDR_HEAD(m_dsk.kaddr); | |
| 1805 | int s = GET_KADDR_SECTOR(m_dsk.kaddr); | |
| 1806 | int page = DRIVE_PAGE(c,h,s); | |
| 1807 | last_kaddr = m_dsk.kaddr; | |
| 1808 | printf(" unit:%d restore:%d %d/%d/%02d page:%d\n", | |
| 1809 | GET_KADDR_DRIVE(m_dsk.kaddr), | |
| 1810 | GET_KADDR_RESTORE(m_dsk.kaddr), | |
| 1811 | c, h, s, page); | |
| 1812 | } | |
| 1813 | } | |
| 1814 | #endif | |
| 1815 | } else { | |
| 1816 | LOG((0,1," KDATA<-; BUS %#o (%#x)\n", m_bus, m_bus)); | |
| 1817 | } | |
| 1818 | } | |
| 1819 | ||
| 1820 | /** | |
| 1821 | * @brief f1_increcno late: advances shift registers holding KADR | |
| 1822 | * | |
| 1823 | * Advances the shift registers holding the KADR register so that they | |
| 1824 | * present the number and read/write/check status of the next record | |
| 1825 | * to the hardware. | |
| 1826 | * | |
| 1827 | * <PRE> | |
| 1828 | * Sheet 10, shifter (74195) parts #36 and #37 | |
| 1829 | * | |
| 1830 | * Vcc, BUS[08], BUS[10], BUS[12] go to #36 A,B,C,D | |
| 1831 | * Vcc, BUS[09], BUS[11], BUS[13] go to #37 A,B,C,D | |
| 1832 | * A is connected to ground on both chips; | |
| 1833 | * both shifters are loaded with KADR<- | |
| 1834 | * | |
| 1835 | * The QA outputs are #36 -> RECNO(0) and #37 -> RECNO(1) | |
| 1836 | * | |
| 1837 | * RECNO(0) (QA of #37) goes to J and K' of #36 | |
| 1838 | * RECNO(1) (QA of #36) is inverted and goes to J and K' of #37 | |
| 1839 | * | |
| 1840 | * shift/ RECNO(0) RECNO(1) R/W/C presented | |
| 1841 | * load #37 #36 to the drive | |
| 1842 | * --------------------------------------------------- | |
| 1843 | * load 0 0 HEADER | |
| 1844 | * 1st shift 1 0 LABEL | |
| 1845 | * 2nd shift 1 1 DATA | |
| 1846 | * 3rd shift 0 1 (none) 0 = read | |
| 1847 | * [ 4th 0 0 (none) 2 = write ] | |
| 1848 | * [ 5th 1 0 (none) 3 = write ] | |
| 1849 | * [ 6th 1 1 (none) 1 = check ] | |
| 1850 | * </PRE> | |
| 1851 | */ | |
| 1852 | void alto2_cpu_device::f1_increcno_1() | |
| 1853 | { | |
| 1854 | switch (m_dsk.krecno) { | |
| 1855 | case RECNO_HEADER: | |
| 1856 | m_dsk.krecno = RECNO_LABEL; | |
| 1857 | m_dsk.krwc = GET_KADR_LABEL(m_dsk.kadr); | |
| 1858 | LOG((0,2," INCRECNO; HEADER -> LABEL (%o, rwc:%o)\n", | |
| 1859 | m_dsk.krecno, m_dsk.krwc)); | |
| 1860 | break; | |
| 1861 | case RECNO_PAGENO: | |
| 1862 | m_dsk.krecno = RECNO_HEADER; | |
| 1863 | m_dsk.krwc = GET_KADR_HEADER(m_dsk.kadr); | |
| 1864 | LOG((0,2," INCRECNO; PAGENO -> HEADER (%o, rwc:%o)\n", | |
| 1865 | m_dsk.krecno, m_dsk.krwc)); | |
| 1866 | break; | |
| 1867 | case RECNO_LABEL: | |
| 1868 | m_dsk.krecno = RECNO_DATA; | |
| 1869 | m_dsk.krwc = GET_KADR_DATA(m_dsk.kadr); | |
| 1870 | LOG((0,2," INCRECNO; LABEL -> DATA (%o, rwc:%o)\n", | |
| 1871 | m_dsk.krecno, m_dsk.krwc)); | |
| 1872 | break; | |
| 1873 | case RECNO_DATA: | |
| 1874 | m_dsk.krecno = RECNO_PAGENO; | |
| 1875 | m_dsk.krwc = 0; /* read (?) */ | |
| 1876 | LOG((0,2," INCRECNO; DATA -> PAGENO (%o, rwc:%o)\n", | |
| 1877 | m_dsk.krecno, m_dsk.krwc)); | |
| 1878 | break; | |
| 1879 | } | |
| 1880 | // TODO: show disk indicator | |
| 1881 | } | |
| 1882 | ||
| 1883 | /** | |
| 1884 | * @brief f1_clrstat late: reset all error latches | |
| 1885 | * | |
| 1886 | * Causes all error latches in the disk controller hardware to reset, | |
| 1887 | * clears KSTAT[13]. | |
| 1888 | * | |
| 1889 | * NB: IDLE (KSTAT[12]) and COMPLETION (KSTAT[14-15]) are not cleared | |
| 1890 | */ | |
| 1891 | void alto2_cpu_device::f1_clrstat_1() | |
| 1892 | { | |
| 1893 | LOG((0,1," CLRSTAT\n")); | |
| 1894 | ||
| 1895 | /* clears the LAI clocked flip-flop 44a | |
| 1896 | * JK flip-flop 44a (LAI' clocked) | |
| 1897 | * CLK (LAI')' | |
| 1898 | * J 1 | |
| 1899 | * K' 1 | |
| 1900 | * S' 1 | |
| 1901 | * C' CLRSTAT' | |
| 1902 | * Q to seekok | |
| 1903 | */ | |
| 1904 | DEBUG_NAME(" LAI 44a"); | |
| 1905 | m_dsk.ff_44a = update_jkff(m_dsk.ff_44a, | |
| 1906 | (m_dsk.ff_44a & JKFF_CLK) | | |
| 1907 | JKFF_J | | |
| 1908 | JKFF_K | | |
| 1909 | JKFF_S | | |
| 1910 | 0); | |
| 1911 | ||
| 1912 | /* clears the CKSUM flip-flop 44b | |
| 1913 | * JK flip-flop 44b (KSTAT<- clocked) | |
| 1914 | * CLK SYSCLKA' (not used here, just clearing) | |
| 1915 | * J 1 (BUS[13] during KSTAT<-) | |
| 1916 | * K' 1 | |
| 1917 | * S' 1 | |
| 1918 | * C' CLRSTAT' | |
| 1919 | * Q to seekok | |
| 1920 | */ | |
| 1921 | DEBUG_NAME(" CKSUM 44b"); | |
| 1922 | m_dsk.ff_44b = update_jkff(m_dsk.ff_44b, | |
| 1923 | (m_dsk.ff_44b & JKFF_CLK) | | |
| 1924 | (m_dsk.ff_44b & JKFF_J) | | |
| 1925 | JKFF_K | | |
| 1926 | JKFF_S | | |
| 1927 | 0); | |
| 1928 | ||
| 1929 | /* clears the rdylat flip-flop 45a | |
| 1930 | * JK flip-flop 45a (ready latch) | |
| 1931 | * CLK SYSCLKA' | |
| 1932 | * J READY' from drive | |
| 1933 | * K' 1 | |
| 1934 | * S' 1 | |
| 1935 | * C' CLRSTAT' | |
| 1936 | * Q RDYLAT' | |
| 1937 | */ | |
| 1938 | DEBUG_NAME(" RDYLAT 45a"); | |
| 1939 | m_dsk.ff_45a = update_jkff(m_dsk.ff_45a, | |
| 1940 | (m_dsk.ff_45a & JKFF_CLK) | | |
| 1941 | drive_ready_0(m_dsk.drive) | | |
| 1942 | JKFF_K | | |
| 1943 | JKFF_S | | |
| 1944 | 0); | |
| 1945 | ||
| 1946 | /* sets the seqerr flip-flop 45b (Q' is SEQERR) | |
| 1947 | * JK flip-flop 45b (seqerr latch) | |
| 1948 | * CLK SYSCLKA' | |
| 1949 | * J 1 | |
| 1950 | * K' SEQERR' | |
| 1951 | * S' CLRSTAT' | |
| 1952 | * C' 1 | |
| 1953 | * Q to KSTAT[11] DATALATE | |
| 1954 | */ | |
| 1955 | DEBUG_NAME(" SEQERR 45b"); | |
| 1956 | m_dsk.ff_45b = update_jkff(m_dsk.ff_45b, | |
| 1957 | (m_dsk.ff_45b & JKFF_CLK) | | |
| 1958 | JKFF_J | | |
| 1959 | (m_dsk.ff_45b & JKFF_K) | | |
| 1960 | 0 | | |
| 1961 | JKFF_C); | |
| 1962 | ||
| 1963 | /* set or reset monoflop 31a, depending on drive READY' */ | |
| 1964 | m_dsk.ready_mf31a = drive_ready_0(m_dsk.drive); | |
| 1965 | ||
| 1966 | /* start monoflop 31a, which resets ready_mf31a */ | |
| 1967 | if (!m_dsk.ready_timer) | |
| 1968 | m_dsk.ready_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_ready_mf31a),this)); | |
| 1969 | m_dsk.ready_timer->adjust(TW_READY, 1); | |
| 1970 | m_dsk.ready_timer->enable(); | |
| 1971 | } | |
| 1972 | ||
| 1973 | /** | |
| 1974 | * @brief f1_load_kcom late: load the KCOM register from bus | |
| 1975 | * <PRE> | |
| 1976 | * This causes the KCOM register to be loaded from BUS[1-5]. The | |
| 1977 | * KCOM register has the following interpretation: | |
| 1978 | * (1) XFEROFF = 1 inhibits data transmission to/from the m_dsk. | |
| 1979 | * (2) WDINHIB = 1 prevents the disk word task from awakening. | |
| 1980 | * (3) BCLKSRC = 0 takes bit clock from disk input or crystal clock, | |
| 1981 | * as appropriate. BCLKSRC = 1 force use of crystal clock. | |
| 1982 | * (4) WFFO = 0 holds the disk bit counter at -1 until a 1 bit is read. | |
| 1983 | * WFFO = 1 allows the bit counter to proceed normally. | |
| 1984 | * (5) SENDADR = 1 causes KDATA[4-12] and KDATA[15] to be transmitted | |
| 1985 | * to disk unit as track address. SENDADR = 0 inhibits such | |
| 1986 | * transmission. | |
| 1987 | * </PRE> | |
| 1988 | */ | |
| 1989 | void alto2_cpu_device::f1_load_kcom_1() | |
| 1990 | { | |
| 1991 | if (m_dsk.kcom != m_bus) { | |
| 1992 | m_dsk.kcom = m_bus; | |
| 1993 | LOG((0,2," KCOM<-; BUS %06o\n", m_dsk.kcom)); | |
| 1994 | LOG((0,2," xferoff: %d\n", GET_KCOM_XFEROFF(m_dsk.kcom))); | |
| 1995 | LOG((0,2," wdinhib: %d\n", GET_KCOM_WDINHIB(m_dsk.kcom))); | |
| 1996 | LOG((0,2," bclksrc: %d\n", GET_KCOM_BCLKSRC(m_dsk.kcom))); | |
| 1997 | LOG((0,2," wffo: %d\n", GET_KCOM_WFFO(m_dsk.kcom))); | |
| 1998 | LOG((0,2," sendadr: %d\n", GET_KCOM_SENDADR(m_dsk.kcom))); | |
| 1999 | ||
| 2000 | // TODO: show disk indicator | |
| 2001 | } | |
| 2002 | } | |
| 2003 | ||
| 2004 | /** | |
| 2005 | * @brief f1_load_kadr late: load the KADR register from bus | |
| 2006 | * | |
| 2007 | * The KADR register is loaded from BUS[8-14]. This register has the format | |
| 2008 | * of word C in section 6.0 above. In addition, it causes the head address | |
| 2009 | * bit to be loaded from KDATA[13]. | |
| 2010 | * | |
| 2011 | * NB: the record numer RECNO(0) and RECNO(1) is reset to 0 | |
| 2012 | */ | |
| 2013 | void alto2_cpu_device::f1_load_kadr_1() | |
| 2014 | { | |
| 2015 | int unit, head; | |
| 2016 | ||
| 2017 | /* store into the separate fields of KADR */ | |
| 2018 | PUT_KADR_SEAL(m_dsk.kadr, GET_KADR_SEAL(m_bus)); | |
| 2019 | PUT_KADR_HEADER(m_dsk.kadr, GET_KADR_HEADER(m_bus)); | |
| 2020 | PUT_KADR_LABEL(m_dsk.kadr, GET_KADR_LABEL(m_bus)); | |
| 2021 | PUT_KADR_DATA(m_dsk.kadr, GET_KADR_DATA(m_bus)); | |
| 2022 | PUT_KADR_NOXFER(m_dsk.kadr, GET_KADR_NOXFER(m_bus)); | |
| 2023 | PUT_KADR_UNUSED(m_dsk.kadr, GET_KADR_UNUSED(m_bus)); | |
| 2024 | ||
| 2025 | /* get selected drive from DATA[14] output (FF 67a really) */ | |
| 2026 | unit = GET_KADDR_DRIVE(m_dsk.kaddr); | |
| 2027 | ||
| 2028 | /* get the selected head, and select drive unit and head */ | |
| 2029 | /* latch head from DATA[13] */ | |
| 2030 | head = GET_KADDR_HEAD(m_dsk.dataout); | |
| 2031 | PUT_KADDR_HEAD(m_dsk.kaddr, head); | |
| 2032 | drive_select(unit, head); | |
| 2033 | ||
| 2034 | /* On KDAR<- bit 0 of parts #36 and #37 is reset to 0, i.e. recno = 0 */ | |
| 2035 | m_dsk.krecno = 0; | |
| 2036 | /* current read/write/check is that for the header */ | |
| 2037 | m_dsk.krwc = GET_KADR_HEADER(m_dsk.kadr); | |
| 2038 | ||
| 2039 | LOG((0,1," KADR<-; BUS[8-14] #%o\n", m_dsk.kadr)); | |
| 2040 | LOG((0,2," seal: %#o\n", GET_KADR_SEAL(m_dsk.kadr))); | |
| 2041 | LOG((0,2," header: %s\n", rwc_name[GET_KADR_HEADER(m_dsk.kadr)])); | |
| 2042 | LOG((0,2," label: %s\n", rwc_name[GET_KADR_LABEL(m_dsk.kadr)])); | |
| 2043 | LOG((0,2," data: %s\n", rwc_name[GET_KADR_DATA(m_dsk.kadr)])); | |
| 2044 | LOG((0,2," noxfer: %d\n", GET_KADR_NOXFER(m_dsk.kadr))); | |
| 2045 | LOG((0,2," unused: %d (drive?)\n", GET_KADR_UNUSED(m_dsk.kadr))); | |
| 2046 | ||
| 2047 | // TODO: show disk indicator | |
| 2048 | } | |
| 2049 | ||
| 2050 | /** | |
| 2051 | * @brief f2_init late: branch on disk word task active and init | |
| 2052 | * | |
| 2053 | * NEXT <- NEXT OR (WDTASKACT && WDINIT ? 037 : 0) | |
| 2054 | */ | |
| 2055 | void alto2_cpu_device::f2_init_1() | |
| 2056 | { | |
| 2057 | UINT16 r = INIT ? 037 : 0; | |
| 2058 | LOG((0,1," INIT; %sbranch (%#o | %#o)\n", r ? "" : "no ", m_next2, r)); | |
| 2059 | m_next2 |= r; | |
| 2060 | m_dsk.wdinit0 = 0; | |
| 2061 | } | |
| 2062 | ||
| 2063 | /** | |
| 2064 | * @brief f2_rwc late: branch on read/write/check state of the current record | |
| 2065 | * <PRE> | |
| 2066 | * NEXT <- NEXT OR (current record to be written ? 3 : | |
| 2067 | * current record to be checked ? 2 : 0); | |
| 2068 | * | |
| 2069 | * NB: note how krecno counts 0,2,3,1 ... etc. | |
| 2070 | * on 0: it presents the RWC for HEADER | |
| 2071 | * on 2: it presents the RWC for LABEL | |
| 2072 | * on 3: it presents the RWC for DATA | |
| 2073 | * on 1: it presents the RWC 0, i.e. READ | |
| 2074 | * | |
| 2075 | * -NEXT[08] = -CHECK = RWC[0] | RWC[1] | |
| 2076 | * -NEXT[09] = W/R = RWC[0] | |
| 2077 | * | |
| 2078 | * rwc | -next | |
| 2079 | * -------+------ | |
| 2080 | * 0 0 | 0 | |
| 2081 | * 0 1 | 2 | |
| 2082 | * 1 0 | 3 | |
| 2083 | * 1 1 | 3 | |
| 2084 | * </PRE> | |
| 2085 | */ | |
| 2086 | void alto2_cpu_device::f2_rwc_1() | |
| 2087 | { | |
| 2088 | static UINT16 branch_map[4] = {0,2,3,3}; | |
| 2089 | UINT16 r = branch_map[m_dsk.krwc];; | |
| 2090 | UINT16 init = INIT ? 037 : 0; | |
| 2091 | ||
| 2092 | switch (m_dsk.krecno) { | |
| 2093 | case RECNO_HEADER: | |
| 2094 | LOG((0,1," RWC; %sbranch header(%d):%s (%#o|%#o|%#o)\n", | |
| 2095 | (r | init) ? "" : "no ", m_dsk.krecno, | |
| 2096 | rwc_name[m_dsk.krwc], m_next2, r, init)); | |
| 2097 | break; | |
| 2098 | case RECNO_PAGENO: | |
| 2099 | LOG((0,1," RWC; %sbranch pageno(%d):%s (%#o|%#o|%#o)\n", | |
| 2100 | (r | init) ? "" : "no ", m_dsk.krecno, | |
| 2101 | rwc_name[m_dsk.krwc], m_next2, r, init)); | |
| 2102 | break; | |
| 2103 | case RECNO_LABEL: | |
| 2104 | LOG((0,1," RWC; %sbranch label(%d):%s (%#o|%#o|%#o)\n", | |
| 2105 | (r | init) ? "" : "no ", m_dsk.krecno, | |
| 2106 | rwc_name[m_dsk.krwc], m_next2, r, init)); | |
| 2107 | break; | |
| 2108 | case RECNO_DATA: | |
| 2109 | LOG((0,1," RWC; %sbranch data(%d):%s (%#o|%#o|%#o)\n", | |
| 2110 | (r | init) ? "" : "no ", m_dsk.krecno, | |
| 2111 | rwc_name[m_dsk.krwc], m_next2, r, init)); | |
| 2112 | break; | |
| 2113 | } | |
| 2114 | m_next2 |= r | init; | |
| 2115 | m_dsk.wdinit0 = 0; | |
| 2116 | } | |
| 2117 | ||
| 2118 | /** | |
| 2119 | * @brief f2_recno late: branch on the current record number by a lookup table | |
| 2120 | * <PRE> | |
| 2121 | * NEXT <- NEXT OR MAP (current record number) where | |
| 2122 | * MAP(0) = 0 (header) | |
| 2123 | * MAP(1) = 2 (label) | |
| 2124 | * MAP(2) = 3 (pageno) | |
| 2125 | * MAP(3) = 1 (data) | |
| 2126 | * </PRE> | |
| 2127 | * NB: The map isn't needed, because m_dsk.krecno counts exactly this way. | |
| 2128 | */ | |
| 2129 | void alto2_cpu_device::f2_recno_1() | |
| 2130 | { | |
| 2131 | UINT16 r = m_dsk.krecno; | |
| 2132 | UINT16 init = INIT ? 037 : 0; | |
| 2133 | LOG((0,1," RECNO; %sbranch recno:%d (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_dsk.krecno, m_next2, r, init)); | |
| 2134 | m_next2 |= r | init; | |
| 2135 | m_dsk.wdinit0 = 0; | |
| 2136 | } | |
| 2137 | ||
| 2138 | /** | |
| 2139 | * @brief f2_xfrdat late: branch on the data transfer state | |
| 2140 | * | |
| 2141 | * NEXT <- NEXT OR (if current command wants data transfer ? 1 : 0) | |
| 2142 | */ | |
| 2143 | void alto2_cpu_device::f2_xfrdat_1() | |
| 2144 | { | |
| 2145 | UINT16 r = GET_KADR_NOXFER(m_dsk.kadr) ? 0 : 1; | |
| 2146 | UINT16 init = INIT ? 037 : 0; | |
| 2147 | LOG((0,1," XFRDAT; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); | |
| 2148 | m_next2 |= r | init; | |
| 2149 | m_dsk.wdinit0 = 0; | |
| 2150 | } | |
| 2151 | ||
| 2152 | /** | |
| 2153 | * @brief f2_swrnrdy late: branch on the disk ready signal | |
| 2154 | * | |
| 2155 | * NEXT <- NEXT OR (if disk not ready to accept command ? 1 : 0) | |
| 2156 | */ | |
| 2157 | void alto2_cpu_device::f2_swrnrdy_1() | |
| 2158 | { | |
| 2159 | UINT16 r = drive_seek_read_write_0(m_dsk.drive); | |
| 2160 | UINT16 init = INIT ? 037 : 0; | |
| 2161 | ||
| 2162 | LOG((0,1," SWRNRDY; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); | |
| 2163 | m_next2 |= r | init; | |
| 2164 | m_dsk.wdinit0 = 0; | |
| 2165 | } | |
| 2166 | ||
| 2167 | /** | |
| 2168 | * @brief f2_nfer late: branch on the disk fatal error condition | |
| 2169 | * | |
| 2170 | * NEXT <- NEXT OR (if fatal error in latches ? 0 : 1) | |
| 2171 | */ | |
| 2172 | void alto2_cpu_device::f2_nfer_1() | |
| 2173 | { | |
| 2174 | UINT16 r = m_dsk.kfer ? 0 : 1; | |
| 2175 | UINT16 init = INIT ? 037 : 0; | |
| 2176 | ||
| 2177 | LOG((0,1," NFER; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); | |
| 2178 | m_next2 |= r | init; | |
| 2179 | m_dsk.wdinit0 = 0; | |
| 2180 | } | |
| 2181 | ||
| 2182 | /** | |
| 2183 | * @brief f2_strobon late: branch on the seek busy status | |
| 2184 | * | |
| 2185 | * NEXT <- NEXT OR (if seek strobe still on ? 1 : 0) | |
| 2186 | * <PRE> | |
| 2187 | * The STROBE signal is elongated with the help of two monoflops. | |
| 2188 | * The first one has a rather short pulse duration: | |
| 2189 | * tW = K * Rt * Cext * (1 + 0.7/Rt) | |
| 2190 | * K = 0.28 for 74123 | |
| 2191 | * Rt = kOhms | |
| 2192 | * Cext = pF | |
| 2193 | * Rt = 20k, Cext = 150pf => 870ns | |
| 2194 | * | |
| 2195 | * The first one triggers the second, which will be cleared | |
| 2196 | * by ADDRACK' from the drive going 0. | |
| 2197 | * Its duration is: | |
| 2198 | * Rt = 20k, Cext = 0.01µF (=10000pF) => 57960ns (~= 58µs) | |
| 2199 | * </PRE> | |
| 2200 | */ | |
| 2201 | void alto2_cpu_device::f2_strobon_1() | |
| 2202 | { | |
| 2203 | UINT16 r = m_dsk.strobe; | |
| 2204 | UINT16 init = INIT ? 037 : 0; | |
| 2205 | ||
| 2206 | LOG((0,2," STROBON; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); | |
| 2207 | m_next2 |= r | init; | |
| 2208 | m_dsk.wdinit0 = 0; | |
| 2209 | } | |
| 2210 | ||
| 2211 | /** | |
| 2212 | * @brief update the disk controller with a new bitclk | |
| 2213 | * | |
| 2214 | * @param id timer id | |
| 2215 | * @param arg bit number | |
| 2216 | */ | |
| 2217 | void alto2_cpu_device::disk_bitclk(void* ptr, INT32 arg) | |
| 2218 | { | |
| 2219 | (void)ptr; | |
| 2220 | int bits = drive_bits_per_sector(); | |
| 2221 | int clk = arg & 1; | |
| 2222 | int bit = 0; | |
| 2223 | ||
| 2224 | /** | |
| 2225 | * The source for BITCLK and DATAIN depends on disk controller part #65 | |
| 2226 | * <PRE> | |
| 2227 | * BCLKSRC W/R | BITCLK | DATAIN | |
| 2228 | * --------------+--------+--------- | |
| 2229 | * 0 0 | RDCLK | RDDATA | |
| 2230 | * 0 1 | CLK/2 | DATOUT | |
| 2231 | * 1 0 | CLK/2 | RDDATA | |
| 2232 | * 1 1 | CLK/2 | DATOUT | |
| 2233 | * </PRE> | |
| 2234 | */ | |
| 2235 | if (m_dsk.krwc & RWC_WRITE) { | |
| 2236 | bit = (m_dsk.shiftout >> 15) & 1; | |
| 2237 | kwd_timing(clk, bit, 0); | |
| 2238 | if (GET_KCOM_XFEROFF(m_dsk.kcom)) { | |
| 2239 | /* do anything, if the transfer is off? */ | |
| 2240 | } else { | |
| 2241 | LOG((0,7," BITCLK#%d bit:%d (write) @%lldns\n", arg, bit, ntime())); | |
| 2242 | if (clk) | |
| 2243 | drive_wrdata(m_dsk.drive, arg, bit); | |
| 2244 | else | |
| 2245 | drive_wrdata(m_dsk.drive, arg, 1); | |
| 2246 | } | |
| 2247 | } else if (GET_KCOM_BCLKSRC(m_dsk.kcom)) { | |
| 2248 | /* always select the crystal clock */ | |
| 2249 | bit = drive_rddata(m_dsk.drive, arg); | |
| 2250 | LOG((0,7," BITCLK#%d bit:%d (read, crystal) @%lldns\n", arg, bit, ntime())); | |
| 2251 | kwd_timing(clk, bit, 0); | |
| 2252 | } else { | |
| 2253 | /* if XFEROFF is set, keep the bit at 1 (RDGATE' is high) */ | |
| 2254 | if (GET_KCOM_XFEROFF(m_dsk.kcom)) { | |
| 2255 | bit = 1; | |
| 2256 | } else { | |
| 2257 | clk = drive_rdclk(m_dsk.drive, arg); | |
| 2258 | bit = drive_rddata(m_dsk.drive, arg); | |
| 2259 | LOG((0,7," BITCLK#%d bit:%d (read, driveclk) @%lldns\n", arg, bit, ntime())); | |
| 2260 | } | |
| 2261 | kwd_timing(clk, bit, 0); | |
| 2262 | } | |
| 2263 | ||
| 2264 | /* more bits to clock? */ | |
| 2265 | if (++arg < bits) { | |
| 2266 | m_dsk.bitclk_timer->adjust(drive_bit_time(m_dsk.drive), arg); | |
| 2267 | m_dsk.bitclk_timer->enable(); | |
| 2268 | } | |
| 2269 | } | |
| 2270 | ||
| 2271 | /** | |
| 2272 | * @brief callback is called by the drive timer whenever a new sector starts | |
| 2273 | * | |
| 2274 | * @param unit the unit number | |
| 2275 | */ | |
| 2276 | void alto2_cpu_device::disk_sector_start(int unit) | |
| 2277 | { | |
| 2278 | if (m_dsk.bitclk_timer) { | |
| 2279 | LOG((0,0," unit #%d stop bitclk\n", m_dsk.bitclk)); | |
| 2280 | m_dsk.bitclk_timer->enable(false); | |
| 2281 | } | |
| 2282 | ||
| 2283 | /* KSTAT[0-3] update the current sector in the kstat field */ | |
| 2284 | PUT_KSTAT_SECTOR(m_dsk.kstat, drive_sector(unit) ^ DRIVE_SECTOR_MASK); | |
| 2285 | ||
| 2286 | /* clear input and output shift registers (?) */ | |
| 2287 | m_dsk.shiftin = 0; | |
| 2288 | m_dsk.shiftout = 0; | |
| 2289 | ||
| 2290 | LOG((0,1," unit #%d sector %d start\n", unit, GET_KSTAT_SECTOR(m_dsk.kstat))); | |
| 2291 | ||
| 2292 | /* HACK: no command, no bit clock */ | |
| 2293 | if (debug_read_mem(0521)) | |
| 2294 | /* start a timer chain for the bit clock */ | |
| 2295 | disk_bitclk(0, 0); | |
| 2296 | } | |
| 2297 | ||
| 2298 | /** | |
| 2299 | * @brief initialize the disk context and insert a disk wort timer | |
| 2300 | * | |
| 2301 | * @result returns 0 on success, fatal() on error | |
| 2302 | */ | |
| 2303 | void alto2_cpu_device::init_disk() | |
| 2304 | { | |
| 2305 | memset(&m_dsk, 0, sizeof(m_dsk)); | |
| 2306 | ||
| 2307 | /** @brief simulate previous sysclka */ | |
| 2308 | m_sysclka0[0] = JKFF_CLK; | |
| 2309 | m_sysclka0[1] = JKFF_0; | |
| 2310 | m_sysclka0[2] = JKFF_0; | |
| 2311 | m_sysclka0[3] = JKFF_CLK; | |
| 2312 | ||
| 2313 | /** @brief simulate current sysclka */ | |
| 2314 | m_sysclka1[0] = JKFF_0; | |
| 2315 | m_sysclka1[1] = JKFF_0; | |
| 2316 | m_sysclka1[2] = JKFF_CLK; | |
| 2317 | m_sysclka1[3] = JKFF_CLK; | |
| 2318 | ||
| 2319 | /** @brief simulate previous sysclkb */ | |
| 2320 | m_sysclkb0[0] = JKFF_CLK; | |
| 2321 | m_sysclkb0[1] = JKFF_CLK; | |
| 2322 | m_sysclkb0[2] = JKFF_0; | |
| 2323 | m_sysclkb0[3] = JKFF_0; | |
| 2324 | ||
| 2325 | /** @brief simulate current sysclkb */ | |
| 2326 | m_sysclkb1[0] = JKFF_CLK; | |
| 2327 | m_sysclkb1[1] = JKFF_0; | |
| 2328 | m_sysclkb1[2] = JKFF_0; | |
| 2329 | m_sysclkb1[3] = JKFF_CLK; | |
| 2330 | ||
| 2331 | m_dsk.wdtskena = 1; | |
| 2332 | ||
| 2333 | m_dsk.seclate = 0; | |
| 2334 | m_dsk.ok_to_run = 0; | |
| 2335 | ||
| 2336 | m_dsk.bitclk_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_bitclk),this)); | |
| 2337 | ||
| 2338 | m_dsk.seclate_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_seclate),this)); | |
| 2339 | m_dsk.seclate_timer->set_param(1); | |
| 2340 | m_dsk.seclate_timer->adjust(attotime::from_nsec(TW_SECLATE), 1); | |
| 2341 | ||
| 2342 | m_dsk.ok_to_run_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_ok_to_run),this)); | |
| 2343 | m_dsk.ok_to_run_timer->set_param(1); | |
| 2344 | m_dsk.ok_to_run_timer->adjust(attotime::from_nsec(15 * ALTO2_UCYCLE), 1); | |
| 2345 | ||
| 2346 | /* install a callback to be called whenever a drive sector starts */ | |
| 2347 | drive_sector_callback(&alto2_cpu_device::disk_sector_start); | |
| 2348 | } | |
| 2349 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII display vertical task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief f1_dvt_block early: disable the display word task | |
| 14 | */ | |
| 15 | void alto2_cpu_device::f1_dvt_block_0() | |
| 16 | { | |
| 17 | m_task_wakeup &= ~(1 << m_task); | |
| 18 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 19 | } | |
| 20 | ||
| 21 | ||
| 22 | /** | |
| 23 | * @brief called by the CPU when the display vertical task becomes active | |
| 24 | */ | |
| 25 | void alto2_cpu_device::activate_dvt() | |
| 26 | { | |
| 27 | /* TODO: what do we do here? */ | |
| 28 | m_task_wakeup &= ~(1 << m_task); | |
| 29 | } | |
| 30 | ||
| 31 | /** | |
| 32 | * @brief initialize display vertical task | |
| 33 | */ | |
| 34 | void alto2_cpu_device::init_dvt(int task) | |
| 35 | { | |
| 36 | set_f1(task, f1_block, &alto2_cpu_device::f1_dvt_block_0, 0); | |
| 37 | set_f2(task, f2_dvt_evenfield, 0, &alto2_cpu_device::f2_evenfield_1); | |
| 38 | m_active_callback[task] = &alto2_cpu_device::activate_dvt; | |
| 39 | } | |
| 40 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII display word task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief f1_dwt_block early: block the display word task | |
| 14 | */ | |
| 15 | void alto2_cpu_device::f1_dwt_block_0() | |
| 16 | { | |
| 17 | m_dsp.dwt_blocks = 1; | |
| 18 | ||
| 19 | /* clear the wakeup for the display word task */ | |
| 20 | m_task_wakeup &= ~(1 << m_task); | |
| 21 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 22 | ||
| 23 | /* wakeup the display horizontal task, if it didn't block itself */ | |
| 24 | if (!m_dsp.dht_blocks) | |
| 25 | m_task_wakeup |= 1 << task_dht; | |
| 26 | } | |
| 27 | ||
| 28 | /** | |
| 29 | * @brief f2_load_ddr late: load the display data register | |
| 30 | */ | |
| 31 | void alto2_cpu_device::f2_dwt_load_ddr_1() | |
| 32 | { | |
| 33 | LOG((0,2," DDR<- BUS (%#o)\n", m_bus)); | |
| 34 | m_dsp.fifo[m_dsp.fifo_wr] = m_bus; | |
| 35 | m_dsp.fifo_wr = (m_dsp.fifo_wr + 1) % ALTO2_DISPLAY_FIFO; | |
| 36 | if (FIFO_STOPWAKE_0() == 0) | |
| 37 | m_task_wakeup &= ~(1 << task_dwt); | |
| 38 | LOG((0,2, " DWT push %04x into FIFO[%02o]%s\n", | |
| 39 | m_bus, (m_dsp.fifo_wr - 1) & (ALTO2_DISPLAY_FIFO - 1), | |
| 40 | FIFO_STOPWAKE_0() == 0 ? " STOPWAKE" : "")); | |
| 41 | } | |
| 42 | ||
| 43 | void alto2_cpu_device::init_dwt(int task) | |
| 44 | { | |
| 45 | set_f1(task, f1_block, &alto2_cpu_device::f1_dwt_block_0, 0); | |
| 46 | set_f2(task, f2_dwt_load_ddr, 0, &alto2_cpu_device::f2_dwt_load_ddr_1); | |
| 47 | } |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII CPU core | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | alto2_cpu_device::alto2_cpu_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) : | |
| 13 | cpu_device(mconfig, ALTO2, "Xerox Alto-II", tag, owner, clock, "alto2", __FILE__), | |
| 14 | m_ucode_config("program", ENDIANNESS_BIG, 8, 32, 0), | |
| 15 | m_ram_config("io", ENDIANNESS_BIG, 8, 16, 0) | |
| 16 | { | |
| 17 | } | |
| 18 | ||
| 19 | /** @brief task names */ | |
| 20 | const char* alto2_cpu_device::task_name(int task) | |
| 21 | { | |
| 22 | switch (task) { | |
| 23 | case 000: return "emu"; | |
| 24 | case 001: return "task01"; | |
| 25 | case 002: return "task02"; | |
| 26 | case 003: return "task03"; | |
| 27 | case 004: return "ksec"; | |
| 28 | case 005: return "task05"; | |
| 29 | case 006: return "task06"; | |
| 30 | case 007: return "ether"; | |
| 31 | case 010: return "mrt"; | |
| 32 | case 011: return "dwt"; | |
| 33 | case 012: return "curt"; | |
| 34 | case 013: return "dht"; | |
| 35 | case 014: return "dvt"; | |
| 36 | case 015: return "part"; | |
| 37 | case 016: return "kwd"; | |
| 38 | case 017: return "task17"; | |
| 39 | } | |
| 40 | return "???"; | |
| 41 | } | |
| 42 | ||
| 43 | /** @brief register names (as used by the microcode) */ | |
| 44 | const char* alto2_cpu_device::r_name(UINT8 reg) | |
| 45 | { | |
| 46 | switch (reg) { | |
| 47 | case 000: return "ac(3)"; | |
| 48 | case 001: return "ac(2)"; | |
| 49 | case 002: return "ac(1)"; | |
| 50 | case 003: return "ac(0)"; | |
| 51 | case 004: return "nww"; | |
| 52 | case 005: return "r05"; | |
| 53 | case 006: return "pc"; | |
| 54 | case 007: return "r07"; | |
| 55 | case 010: return "xh"; | |
| 56 | case 011: return "r11"; | |
| 57 | case 012: return "ecntr"; | |
| 58 | case 013: return "epntr"; | |
| 59 | case 014: return "r14"; | |
| 60 | case 015: return "r15"; | |
| 61 | case 016: return "r16"; | |
| 62 | case 017: return "r17"; | |
| 63 | case 020: return "curx"; | |
| 64 | case 021: return "curdata"; | |
| 65 | case 022: return "cba"; | |
| 66 | case 023: return "aecl"; | |
| 67 | case 024: return "slc"; | |
| 68 | case 025: return "mtemp"; | |
| 69 | case 026: return "htab"; | |
| 70 | case 027: return "ypos"; | |
| 71 | case 030: return "dwa"; | |
| 72 | case 031: return "kwdctw"; | |
| 73 | case 032: return "cksumrw"; | |
| 74 | case 033: return "knmarw"; | |
| 75 | case 034: return "dcbr"; | |
| 76 | case 035: return "dwax"; | |
| 77 | case 036: return "mask"; | |
| 78 | case 037: return "r37"; | |
| 79 | } | |
| 80 | return "???"; | |
| 81 | } | |
| 82 | ||
| 83 | /** @brief ALU function names */ | |
| 84 | const char* alto2_cpu_device::aluf_name(UINT8 aluf) | |
| 85 | { | |
| 86 | switch (aluf) { | |
| 87 | case 000: return "bus"; | |
| 88 | case 001: return "t"; | |
| 89 | case 002: return "bus or t"; | |
| 90 | case 003: return "bus and t"; | |
| 91 | case 004: return "bus xor t"; | |
| 92 | case 005: return "bus + 1"; | |
| 93 | case 006: return "bus - 1"; | |
| 94 | case 007: return "bus + t"; | |
| 95 | case 010: return "bus - t"; | |
| 96 | case 011: return "bus - t - 1"; | |
| 97 | case 012: return "bus + t + 1"; | |
| 98 | case 013: return "bus + skip"; | |
| 99 | case 014: return "bus, t"; | |
| 100 | case 015: return "bus and not t"; | |
| 101 | case 016: return "0 (undef)"; | |
| 102 | case 017: return "0 (undef)"; | |
| 103 | } | |
| 104 | return "???"; | |
| 105 | } | |
| 106 | ||
| 107 | /** @brief BUS source names */ | |
| 108 | const char* alto2_cpu_device::bs_name(UINT8 bs) | |
| 109 | { | |
| 110 | switch (bs) { | |
| 111 | case 000: return "read_r"; | |
| 112 | case 001: return "load_r"; | |
| 113 | case 002: return "no_source"; | |
| 114 | case 003: return "task_3"; | |
| 115 | case 004: return "task_4"; | |
| 116 | case 005: return "read_md"; | |
| 117 | case 006: return "mouse"; | |
| 118 | case 007: return "disp"; | |
| 119 | } | |
| 120 | return "???"; | |
| 121 | } | |
| 122 | ||
| 123 | /** @brief F1 function names */ | |
| 124 | const char* alto2_cpu_device::f1_name(UINT8 f1) | |
| 125 | { | |
| 126 | switch (f1) { | |
| 127 | case 000: return "nop"; | |
| 128 | case 001: return "load_mar"; | |
| 129 | case 002: return "task"; | |
| 130 | case 003: return "block"; | |
| 131 | case 004: return "l_lsh_1"; | |
| 132 | case 005: return "l_rsh_1"; | |
| 133 | case 006: return "l_lcy_8"; | |
| 134 | case 007: return "const"; | |
| 135 | case 010: return "task_10"; | |
| 136 | case 011: return "task_11"; | |
| 137 | case 012: return "task_12"; | |
| 138 | case 013: return "task_13"; | |
| 139 | case 014: return "task_14"; | |
| 140 | case 015: return "task_15"; | |
| 141 | case 016: return "task_16"; | |
| 142 | case 017: return "task_17"; | |
| 143 | } | |
| 144 | return "???"; | |
| 145 | } | |
| 146 | ||
| 147 | /** @brief F2 function names */ | |
| 148 | const char* alto2_cpu_device::f2_name(UINT8 f2) | |
| 149 | { | |
| 150 | switch (f2) { | |
| 151 | case 000: return "nop"; | |
| 152 | case 001: return "bus=0"; | |
| 153 | case 002: return "shifter<0"; | |
| 154 | case 003: return "shifter=0"; | |
| 155 | case 004: return "bus"; | |
| 156 | case 005: return "alucy"; | |
| 157 | case 006: return "load_md"; | |
| 158 | case 007: return "const"; | |
| 159 | case 010: return "task_10"; | |
| 160 | case 011: return "task_11"; | |
| 161 | case 012: return "task_12"; | |
| 162 | case 013: return "task_13"; | |
| 163 | case 014: return "task_14"; | |
| 164 | case 015: return "task_15"; | |
| 165 | case 016: return "task_16"; | |
| 166 | case 017: return "task_17"; | |
| 167 | } | |
| 168 | return "???"; | |
| 169 | } | |
| 170 | ||
| 171 | UINT8 cram3k_a37[256]; | |
| 172 | ||
| 173 | UINT8 madr_a64[256]; | |
| 174 | ||
| 175 | UINT8 madr_a65[256]; | |
| 176 | ||
| 177 | /** @brief fatal exit on unitialized dynamic phase BUS source */ | |
| 178 | void alto2_cpu_device::fn_bs_bad_0() | |
| 179 | { | |
| 180 | fatal(9,"fatal: bad early bus source pointer for task %s, mpc:%05o bs:%s\n", | |
| 181 | task_name(m_task), m_mpc, bs_name(MIR_BS(m_mir))); | |
| 182 | } | |
| 183 | ||
| 184 | /** @brief fatal exit on unitialized latching phase BUS source */ | |
| 185 | void alto2_cpu_device::fn_bs_bad_1() | |
| 186 | { | |
| 187 | fatal(9,"fatal: bad late bus source pointer for task %s, mpc:%05o bs: %s\n", | |
| 188 | task_name(m_task), m_mpc, bs_name(MIR_BS(m_mir))); | |
| 189 | } | |
| 190 | ||
| 191 | /** @brief fatal exit on unitialized dynamic phase F1 function */ | |
| 192 | void alto2_cpu_device::fn_f1_bad_0() | |
| 193 | { | |
| 194 | fatal(9,"fatal: bad early f1 function pointer for task %s, mpc:%05o f1: %s\n", | |
| 195 | task_name(m_task), m_mpc, f1_name(MIR_F1(m_mir))); | |
| 196 | } | |
| 197 | ||
| 198 | /** @brief fatal exit on unitialized latching phase F1 function */ | |
| 199 | void alto2_cpu_device::fn_f1_bad_1() | |
| 200 | { | |
| 201 | fatal(9,"fatal: bad late f1 function pointer for task %s, mpc:%05o f1: %s\n", | |
| 202 | task_name(m_task), m_mpc, f1_name(MIR_F1(m_mir))); | |
| 203 | } | |
| 204 | ||
| 205 | /** @brief fatal exit on unitialized dynamic phase F2 function */ | |
| 206 | void alto2_cpu_device::fn_f2_bad_0() | |
| 207 | { | |
| 208 | fatal(9,"fatal: bad early f2 function pointer for task %s, mpc:%05o f2: %s\n", | |
| 209 | task_name(m_task), m_mpc, f2_name(MIR_F2(m_mir))); | |
| 210 | } | |
| 211 | ||
| 212 | /** @brief fatal exit on unitialized latching phase F2 function */ | |
| 213 | void alto2_cpu_device::fn_f2_bad_1() | |
| 214 | { | |
| 215 | fatal(9,"fatal: bad late f2 function pointer for task %s, mpc:%05o f2: %s\n", | |
| 216 | task_name(m_task), m_mpc, f2_name(MIR_F2(m_mir))); | |
| 217 | } | |
| 218 | ||
| 219 | /** | |
| 220 | * @brief read bank register in memory mapped I/O range | |
| 221 | * | |
| 222 | * The bank registers are stored in a 16x4-bit RAM 74S189. | |
| 223 | */ | |
| 224 | UINT16 alto2_cpu_device::bank_reg_r(UINT32 address) | |
| 225 | { | |
| 226 | int task = address & 017; | |
| 227 | int bank = m_bank_reg[task] | 0177760; | |
| 228 | return bank; | |
| 229 | } | |
| 230 | ||
| 231 | /** | |
| 232 | * @brief write bank register in memory mapped I/O range | |
| 233 | * | |
| 234 | * The bank registers are stored in a 16x4-bit RAM 74S189. | |
| 235 | */ | |
| 236 | void alto2_cpu_device::bank_reg_w(UINT32 address, UINT16 data) | |
| 237 | { | |
| 238 | int task = address & 017; | |
| 239 | m_bank_reg[task] = data & 017; | |
| 240 | LOG((0,0," write bank[%02o]=%#o normal:%o extended:%o (%s)\n", | |
| 241 | task, data, | |
| 242 | GET_BANK_NORMAL(data), | |
| 243 | GET_BANK_EXTENDED(data), | |
| 244 | task_name(task))); | |
| 245 | } | |
| 246 | ||
| 247 | /** | |
| 248 | * @brief bs_read_r early: drive bus by R register | |
| 249 | */ | |
| 250 | void alto2_cpu_device::bs_read_r_0() | |
| 251 | { | |
| 252 | UINT16 r = m_r[m_rsel]; | |
| 253 | LOG((0,2," <-R%02o; %s (%#o)\n", m_rsel, r_name(m_rsel), r)); | |
| 254 | m_bus &= r; | |
| 255 | } | |
| 256 | ||
| 257 | /** | |
| 258 | * @brief bs_load_r early: load R places 0 on the BUS | |
| 259 | */ | |
| 260 | void alto2_cpu_device::bs_load_r_0() | |
| 261 | { | |
| 262 | UINT16 r = 0; | |
| 263 | LOG((0,2," R%02o<-; %s (BUS&=0)\n", m_rsel, r_name(m_rsel))); | |
| 264 | m_bus &= r; | |
| 265 | } | |
| 266 | ||
| 267 | /** | |
| 268 | * @brief bs_load_r late: load R from SHIFTER | |
| 269 | */ | |
| 270 | void alto2_cpu_device::bs_load_r_1() | |
| 271 | { | |
| 272 | if (MIR_F2(m_mir) != f2_emu_load_dns) { | |
| 273 | m_r[m_rsel] = m_shifter; | |
| 274 | LOG((0,2," R%02o<-; %s = SHIFTER (%#o)\n", m_rsel, r_name(m_rsel), m_shifter)); | |
| 275 | /* HACK: programs writing r37 with xxx3 make the cursor | |
| 276 | * display go nuts. Until I found the real reason for this | |
| 277 | * obviously buggy display, I just clear the two | |
| 278 | * least significant bits of r37 if they are set at once. | |
| 279 | */ | |
| 280 | if (m_rsel == 037 && ((m_shifter & 3) == 3)) { | |
| 281 | printf("writing r37 = %#o\n", m_shifter); | |
| 282 | m_r[037] &= ~3; | |
| 283 | } | |
| 284 | } | |
| 285 | } | |
| 286 | ||
| 287 | /** | |
| 288 | * @brief bs_read_md early: drive BUS from read memory data | |
| 289 | */ | |
| 290 | void alto2_cpu_device::bs_read_md_0() | |
| 291 | { | |
| 292 | #if DEBUG | |
| 293 | UINT32 mar = m_mem.mar; | |
| 294 | #endif | |
| 295 | UINT16 md = read_mem(); | |
| 296 | LOG((0,2," <-MD; BUS&=MD (%#o=[%#o])\n", md, mar)); | |
| 297 | m_bus &= md; | |
| 298 | } | |
| 299 | ||
| 300 | /** | |
| 301 | * @brief bs_mouse early: drive bus by mouse | |
| 302 | */ | |
| 303 | void alto2_cpu_device::bs_mouse_0() | |
| 304 | { | |
| 305 | UINT16 r = mouse_read(); | |
| 306 | LOG((0,2," <-MOUSE; BUS&=MOUSE (%#o)\n", r)); | |
| 307 | m_bus &= r; | |
| 308 | } | |
| 309 | ||
| 310 | /** | |
| 311 | * @brief bs_disp early: drive bus by displacement (which?) | |
| 312 | */ | |
| 313 | void alto2_cpu_device::bs_disp_0() | |
| 314 | { | |
| 315 | UINT16 r = 0177777; | |
| 316 | LOG((0,0,"BS <-DISP not handled by task %s mpc:%04x\n", task_name(m_task), m_mpc)); | |
| 317 | LOG((0,2," <-DISP; BUS&=DISP ?? (%#o)\n", r)); | |
| 318 | m_bus &= r; | |
| 319 | } | |
| 320 | ||
| 321 | /** | |
| 322 | * @brief f1_load_mar late: load memory address register | |
| 323 | * | |
| 324 | * Load memory address register from the ALU output; | |
| 325 | * start main memory reference (see section 2.3). | |
| 326 | */ | |
| 327 | void alto2_cpu_device::f1_load_mar_1() | |
| 328 | { | |
| 329 | UINT8 bank = m_bank_reg[m_task]; | |
| 330 | UINT32 msb; | |
| 331 | if (MIR_F2(m_mir) == f2_load_md) { | |
| 332 | msb = GET_BANK_EXTENDED(bank) << 16; | |
| 333 | LOG((0,7, " XMAR %#o\n", msb | m_alu)); | |
| 334 | } else { | |
| 335 | msb = GET_BANK_NORMAL(bank) << 16; | |
| 336 | ||
| 337 | } | |
| 338 | load_mar(m_rsel, msb | m_alu); | |
| 339 | } | |
| 340 | ||
| 341 | #if USE_PRIO_F9318 | |
| 342 | /** @brief F9318 input lines */ | |
| 343 | typedef enum { | |
| 344 | PRIO_IN_EI = (1<<8), | |
| 345 | PRIO_IN_I7 = (1<<7), | |
| 346 | PRIO_IN_I6 = (1<<6), | |
| 347 | PRIO_IN_I5 = (1<<5), | |
| 348 | PRIO_IN_I4 = (1<<4), | |
| 349 | PRIO_IN_I3 = (1<<3), | |
| 350 | PRIO_IN_I2 = (1<<2), | |
| 351 | PRIO_IN_I1 = (1<<1), | |
| 352 | PRIO_IN_I0 = (1<<0), | |
| 353 | /* masks */ | |
| 354 | PRIO_I7 = PRIO_IN_I7, | |
| 355 | PRIO_I6_I7 = (PRIO_IN_I6 | PRIO_IN_I7), | |
| 356 | PRIO_I5_I7 = (PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), | |
| 357 | PRIO_I4_I7 = (PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), | |
| 358 | PRIO_I3_I7 = (PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), | |
| 359 | PRIO_I2_I7 = (PRIO_IN_I2 | PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), | |
| 360 | PRIO_I1_I7 = (PRIO_IN_I1 | PRIO_IN_I2 | PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), | |
| 361 | PRIO_I0_I7 = (PRIO_IN_I0 | PRIO_IN_I1 | PRIO_IN_I2 | PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), | |
| 362 | } f9318_in_t; | |
| 363 | ||
| 364 | /** @brief F9318 output lines */ | |
| 365 | typedef enum { | |
| 366 | PRIO_OUT_Q0 = (1<<0), | |
| 367 | PRIO_OUT_Q1 = (1<<1), | |
| 368 | PRIO_OUT_Q2 = (1<<2), | |
| 369 | PRIO_OUT_EO = (1<<3), | |
| 370 | PRIO_OUT_GS = (1<<4), | |
| 371 | /* masks */ | |
| 372 | PRIO_OUT_QZ = (PRIO_OUT_Q0 | PRIO_OUT_Q1 | PRIO_OUT_Q2) | |
| 373 | } f9318_out_t; | |
| 374 | ||
| 375 | /** | |
| 376 | * @brief F9318 priority encoder 8 to 3-bit | |
| 377 | * | |
| 378 | * Emulation of the F9318 chip (pin compatible with 74348). | |
| 379 | * | |
| 380 | * <PRE> | |
| 381 | * F9318 | |
| 382 | * +---+-+---+ | |
| 383 | * | +-+ | +---------------------------------+----------------+ | |
| 384 | * I4' -|1 16|- Vcc | input | output | | |
| 385 | * | | +---------------------------------+----------------+ | |
| 386 | * I5' -|2 15|- EO' | EI I0 I1 I2 I3 I4 I5 I6 I7 | GS Q0 Q1 Q2 EO | | |
| 387 | * | | +---------------------------------+----------------+ | |
| 388 | * I6' -|3 14|- GS' | (a) H x x x x x x x x | H H H H H | | |
| 389 | * | | | (b) L H H H H H H H H | H H H H L | | |
| 390 | * I7' -|4 13|- I3' +---------------------------------+----------------+ | |
| 391 | * | | | (c) L x x x x x x x L | L L L L H | | |
| 392 | * EI' -|5 12|- I2' | (d) L x x x x x x L H | L H L L H | | |
| 393 | * | | | (e) L x x x x x L H H | L L H L H | | |
| 394 | * Q2' -|6 11|- I1' | (f) L x x x x L H H H | L H H L H | | |
| 395 | * | | | (g) L x x x L H H H H | L L L H H | | |
| 396 | * Q1' -|7 10|- I0' | (h) L x x L H H H H H | L H L H H | | |
| 397 | * | | | (i) L x L H H H H H H | L L H H H | | |
| 398 | * GND -|8 9|- Q0' | (j) L L H H H H H H H | L H H H H | | |
| 399 | * | | +---------------------------------+----------------+ | |
| 400 | * +---------+ | |
| 401 | * </PRE> | |
| 402 | */ | |
| 403 | static __inline f9318_out_t f9318(f9318_in_t in) | |
| 404 | { | |
| 405 | f9318_out_t out; | |
| 406 | ||
| 407 | if (in & PRIO_IN_EI) { | |
| 408 | out = PRIO_OUT_EO | PRIO_OUT_GS | PRIO_OUT_QZ; | |
| 409 | LOG((0,2," f9318 case (a) in:%#o out:%#o\n", in, out)); | |
| 410 | return out; | |
| 411 | } | |
| 412 | ||
| 413 | if (0 == (in & PRIO_I7)) { | |
| 414 | out = PRIO_OUT_EO; | |
| 415 | LOG((0,2," f9318 case (c) in:%#o out:%#o\n", in, out)); | |
| 416 | return out; | |
| 417 | } | |
| 418 | ||
| 419 | if (PRIO_I7 == (in & PRIO_I6_I7)) { | |
| 420 | out = PRIO_OUT_EO | PRIO_OUT_Q0; | |
| 421 | LOG((0,2," f9318 case (d) in:%#o out:%#o\n", in, out)); | |
| 422 | return out; | |
| 423 | } | |
| 424 | ||
| 425 | if (PRIO_I6_I7 == (in & PRIO_I5_I7)) { | |
| 426 | out = PRIO_OUT_EO | PRIO_OUT_Q1; | |
| 427 | LOG((0,2," f9318 case (e) in:%#o out:%#o\n", in, out)); | |
| 428 | return out; | |
| 429 | } | |
| 430 | ||
| 431 | if (PRIO_I5_I7 == (in & PRIO_I4_I7)) { | |
| 432 | out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q1; | |
| 433 | LOG((0,2," f9318 case (f) in:%#o out:%#o\n", in, out)); | |
| 434 | return out; | |
| 435 | } | |
| 436 | ||
| 437 | if (PRIO_I4_I7 == (in & PRIO_I3_I7)) { | |
| 438 | out = PRIO_OUT_EO | PRIO_OUT_Q2; | |
| 439 | LOG((0,2," f9318 case (g) in:%#o out:%#o\n", in, out)); | |
| 440 | return out; | |
| 441 | } | |
| 442 | ||
| 443 | if (PRIO_I3_I7 == (in & PRIO_I2_I7)) { | |
| 444 | out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q2; | |
| 445 | LOG((0,2," f9318 case (h) in:%#o out:%#o\n", in, out)); | |
| 446 | return out; | |
| 447 | } | |
| 448 | ||
| 449 | if (PRIO_I2_I7 == (in & PRIO_I1_I7)) { | |
| 450 | out = PRIO_OUT_EO | PRIO_OUT_Q1 | PRIO_OUT_Q2; | |
| 451 | LOG((0,2," f9318 case (i) in:%#o out:%#o\n", in, out)); | |
| 452 | return out; | |
| 453 | } | |
| 454 | ||
| 455 | if (PRIO_I1_I7 == (in & PRIO_I0_I7)) { | |
| 456 | out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q1 | PRIO_OUT_Q2; | |
| 457 | LOG((0,2," f9318 case (j) in:%#o out:%#o\n", in, out)); | |
| 458 | return out; | |
| 459 | } | |
| 460 | ||
| 461 | out = PRIO_OUT_QZ | PRIO_OUT_GS; | |
| 462 | LOG((0,2," f9318 case (b) in:%#o out:%#o\n", in, out)); | |
| 463 | return out; | |
| 464 | } | |
| 465 | #endif | |
| 466 | ||
| 467 | /** | |
| 468 | * @brief f1_task early: task switch | |
| 469 | * | |
| 470 | * The priority encoder finds the highest task requesting service | |
| 471 | * and switches the task number after the next cycle. | |
| 472 | * | |
| 473 | * <PRE> | |
| 474 | * CT PROM NEXT' RDCT' | |
| 475 | * 1 2 4 8 DATA 6 7 8 9 1 2 4 8 | |
| 476 | * --------------------------------- | |
| 477 | * 0 0 0 0 0367 1 1 1 1 0 1 1 1 | |
| 478 | * 1 0 0 0 0353 1 1 1 0 1 0 1 1 | |
| 479 | * 0 1 0 0 0323 1 1 0 1 0 0 1 1 | |
| 480 | * 1 1 0 0 0315 1 1 0 0 1 1 0 1 | |
| 481 | * 0 0 1 0 0265 1 0 1 1 0 1 0 1 | |
| 482 | * 1 0 1 0 0251 1 0 1 0 1 0 0 1 | |
| 483 | * 0 1 1 0 0221 1 0 0 1 0 0 0 1 | |
| 484 | * 1 1 1 0 0216 1 0 0 0 1 1 1 0 | |
| 485 | * 0 0 0 1 0166 0 1 1 1 0 1 1 0 | |
| 486 | * 1 0 0 1 0152 0 1 1 0 1 0 1 0 | |
| 487 | * 0 1 0 1 0122 0 1 0 1 0 0 1 0 | |
| 488 | * 1 1 0 1 0114 0 1 0 0 1 1 0 0 | |
| 489 | * 0 0 1 1 0064 0 0 1 1 0 1 0 0 | |
| 490 | * 1 0 1 1 0050 0 0 1 0 1 0 0 0 | |
| 491 | * 0 1 1 1 0020 0 0 0 1 0 0 0 0 | |
| 492 | * 1 1 1 1 0017 0 0 0 0 1 1 1 1 | |
| 493 | * | |
| 494 | * The various task wakeups are encoded using two 8:3-bit priority encoders F9318, | |
| 495 | * which are pin-compatible to the 74348 (inverted inputs and outputs). | |
| 496 | * Their part numbers are U1 and U2. | |
| 497 | * The two encoders are chained (EO of U1 goes to EI of U2): | |
| 498 | * | |
| 499 | * The outputs are fed into some NAND gates (74H10 and 74H00) to decode | |
| 500 | * the task number to latch (CT1-CT4) after a F1 TASK. The case where all | |
| 501 | * of RDCT1' to RDCT8' are high (1) is decoded as RESET'. | |
| 502 | * | |
| 503 | * signal function | |
| 504 | * -------------------------------------------------- | |
| 505 | * CT1 (U1.Q0' & U2.Q0' & RDCT1')' | |
| 506 | * CT2 (U1.Q1' & U2.Q1' & RDCT2')' | |
| 507 | * CT4 (U1.Q2' & U2.Q2' & RDCT4')' | |
| 508 | * CT8 (U1.GS' & RDCT8')' | |
| 509 | * RESET' RDCT1' & RDCT2' & RDCT4' & RDCT8' | |
| 510 | * | |
| 511 | * In the tables below "x" is RDCTx' of current task | |
| 512 | * | |
| 513 | * signal input output, if first 0 CT1 CT2 CT4 CT8 | |
| 514 | * ---------------------------------------------------------------------------------------- | |
| 515 | * WAKE17' (T19?) 4 I7 Q2:0 Q1:0 Q0:0 GS:0 EO:1 1 1 1 1 | |
| 516 | * WAKEKWDT' 3 I6 Q2:0 Q1:0 Q0:1 GS:0 EO:1 x 1 1 1 | |
| 517 | * WAKEPART' 2 I5 Q2:0 Q1:1 Q0:0 GS:0 EO:1 1 x 1 1 | |
| 518 | * WAKEDVT' 1 I4 Q2:0 Q1:1 Q0:1 GS:0 EO:1 x x 1 1 | |
| 519 | * WAKEDHT' 13 I3 Q2:1 Q1:0 Q0:0 GS:0 EO:1 1 1 x 1 | |
| 520 | * WAKECURT' 12 I2 Q2:1 Q1:0 Q0:1 GS:0 EO:1 x 1 x 1 | |
| 521 | * WAKEDWT' 11 I1 Q2:1 Q1:1 Q0:0 GS:0 EO:1 1 x x 1 | |
| 522 | * WAKEMRT' 10 I0 Q2:1 Q1:1 Q0:1 GS:0 EO:1 x x x 1 | |
| 523 | * otherwise Q2:1 Q1:1 Q0:1 GS:1 EO:0 x x x x | |
| 524 | * | |
| 525 | * signal input output, if first 0 | |
| 526 | * ---------------------------------------------------------------------------------------- | |
| 527 | * WAKEET' 4 I7 Q2:0 Q1:0 Q0:0 GS:0 EO:1 1 1 1 x | |
| 528 | * WAKE6' 3 I6 Q2:0 Q1:0 Q0:1 GS:0 EO:1 x 1 1 x | |
| 529 | * WAKE5' 2 I5 Q2:0 Q1:1 Q0:0 GS:0 EO:1 1 x 1 x | |
| 530 | * WAKEKST' 1 I4 Q2:0 Q1:1 Q0:1 GS:0 EO:1 x x 1 x | |
| 531 | * WAKE3' (T23?) 13 I3 Q2:1 Q1:0 Q0:0 GS:0 EO:1 1 1 x x | |
| 532 | * WAKE2' 12 I2 Q2:1 Q1:0 Q0:1 GS:0 EO:1 x 1 x x | |
| 533 | * WAKE1' 11 I1 Q2:1 Q1:1 Q0:0 GS:0 EO:1 1 x x x | |
| 534 | * 0 (GND) 10 I0 Q2:1 Q1:1 Q0:1 GS:0 EO:1 x x x x | |
| 535 | * </PRE> | |
| 536 | */ | |
| 537 | void alto2_cpu_device::f1_task_0() | |
| 538 | { | |
| 539 | #if USE_PRIO_F9318 | |
| 540 | /* Doesn't work yet */ | |
| 541 | register f9318_in_t wakeup_hi; | |
| 542 | register f9318_out_t u1; | |
| 543 | register f9318_in_t wakeup_lo; | |
| 544 | register f9318_out_t u2; | |
| 545 | register int addr = 017; | |
| 546 | register int rdct1, rdct2, rdct4, rdct8; | |
| 547 | register int ct1, ct2, ct4, ct8; | |
| 548 | register int wakeup, ct; | |
| 549 | ||
| 550 | LOG((0,2, " TASK %02o:%s\n", m_task, task_name(m_task))); | |
| 551 | ||
| 552 | if (m_task > task_emu && (m_task_wakeup & (1 << m_task))) | |
| 553 | addr = m_task; | |
| 554 | LOG((0,2," ctl2k_u38[%02o] = %04o\n", addr, ctl2k_u38[addr] & 017)); | |
| 555 | ||
| 556 | rdct1 = (ctl2k_u38[addr] >> U38_RDCT1) & 1; | |
| 557 | rdct2 = (ctl2k_u38[addr] >> U38_RDCT2) & 1; | |
| 558 | rdct4 = (ctl2k_u38[addr] >> U38_RDCT4) & 1; | |
| 559 | rdct8 = (ctl2k_u38[addr] >> U38_RDCT8) & 1; | |
| 560 | ||
| 561 | /* wakeup signals are active low */ | |
| 562 | wakeup = ~m_task_wakeup; | |
| 563 | ||
| 564 | /* U1 | |
| 565 | * task wakeups 017 to 010 on I7 to I0 | |
| 566 | * EI is 0 (would be 1 at reset) | |
| 567 | */ | |
| 568 | wakeup_hi = (wakeup >> 8) & PRIO_I0_I7; | |
| 569 | u1 = f9318(wakeup_hi); | |
| 570 | ||
| 571 | /* U2 | |
| 572 | * task wakeups 007 to 001 on I7 to I1, I0 is 0 | |
| 573 | * EO of U1 chained to EI | |
| 574 | */ | |
| 575 | wakeup_lo = wakeup & PRIO_I0_I7; | |
| 576 | if (u1 & PRIO_OUT_EO) | |
| 577 | wakeup_lo |= PRIO_IN_EI; | |
| 578 | u2 = f9318(wakeup_lo); | |
| 579 | ||
| 580 | /* CT1 = (U1.Q0' & U2.Q0' & RDCT1')' */ | |
| 581 | ct1 = !((u1 & PRIO_OUT_Q0) && (u2 & PRIO_OUT_Q0) && rdct1); | |
| 582 | LOG((0,2," CT1:%o U1.Q0':%o U2.Q0':%o RDCT1':%o\n", | |
| 583 | ct1, (u1 & PRIO_OUT_Q0)?1:0, (u2 & PRIO_OUT_Q0)?1:0, rdct1)); | |
| 584 | /* CT2 = (U1.Q1' & U2.Q1' & RDCT2')' */ | |
| 585 | ct2 = !((u1 & PRIO_OUT_Q1) && (u2 & PRIO_OUT_Q1) && rdct2); | |
| 586 | LOG((0,2," CT2:%o U1.Q1':%o U2.Q1':%o RDCT2':%o\n", | |
| 587 | ct2, (u1 & PRIO_OUT_Q1)?1:0, (u2 & PRIO_OUT_Q1)?1:0, rdct2)); | |
| 588 | /* CT4 = (U1.Q2' & U2.Q2' & RDCT4')' */ | |
| 589 | ct4 = !((u1 & PRIO_OUT_Q2) && (u2 & PRIO_OUT_Q2) && rdct4); | |
| 590 | LOG((0,2," CT4:%o U1.Q2':%o U2.Q2':%o RDCT4':%o\n", | |
| 591 | ct4, (u1 & PRIO_OUT_Q2)?1:0, (u2 & PRIO_OUT_Q2)?1:0, rdct4)); | |
| 592 | /* CT8 */ | |
| 593 | ct8 = !((u1 & PRIO_OUT_GS) && rdct8); | |
| 594 | LOG((0,2," CT8:%o U1.GS':%o RDCT8':%o\n", | |
| 595 | ct8, (u1 & PRIO_OUT_GS)?1:0, rdct8)); | |
| 596 | ||
| 597 | ct = 8*ct8 + 4*ct4 + 2*ct2 + ct1; | |
| 598 | ||
| 599 | if (ct != m_next_task) { | |
| 600 | LOG((0,2, " switch to %02o\n", ct)); | |
| 601 | m_next2_task = ct; | |
| 602 | } else { | |
| 603 | LOG((0,2, " no switch\n")); | |
| 604 | } | |
| 605 | #else /* USE_PRIO_F9318 */ | |
| 606 | int i; | |
| 607 | ||
| 608 | LOG((0,2, " TASK %02o:%s", m_task, task_name(m_task))); | |
| 609 | for (i = 15; i >= 0; i--) { | |
| 610 | if (m_task_wakeup & (1 << i)) { | |
| 611 | m_next2_task = i; | |
| 612 | if (m_next2_task != m_next_task) { | |
| 613 | LOG((0,2, " switch to %02o:%s\n", m_next2_task, task_name(m_next2_task))); | |
| 614 | } else { | |
| 615 | LOG((0,2, " no switch\n")); | |
| 616 | } | |
| 617 | return; | |
| 618 | } | |
| 619 | } | |
| 620 | fatal(3, "no tasks requesting service\n"); | |
| 621 | #endif /* !USE_PRIO_F9318 */ | |
| 622 | } | |
| 623 | ||
| 624 | #ifdef f1_block0_unused | |
| 625 | /** | |
| 626 | * @brief f1_block early: block task | |
| 627 | * | |
| 628 | * The task request for the active task is cleared | |
| 629 | */ | |
| 630 | void alto2_cpu_device::f1_block_0() | |
| 631 | { | |
| 632 | CPU_CLR_TASK_WAKEUP(m_task); | |
| 633 | LOG((0,2, " BLOCK %02o:%s\n", m_task, task_name(m_task))); | |
| 634 | } | |
| 635 | #endif | |
| 636 | ||
| 637 | /** | |
| 638 | * @brief f2_bus_eq_zero late: branch on bus equals zero | |
| 639 | */ | |
| 640 | void alto2_cpu_device::f2_bus_eq_zero_1() | |
| 641 | { | |
| 642 | UINT16 r = m_bus == 0 ? 1 : 0; | |
| 643 | LOG((0,2, " BUS=0; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); | |
| 644 | m_next2 |= r; | |
| 645 | } | |
| 646 | ||
| 647 | /** | |
| 648 | * @brief f2_shifter_lt_zero late: branch on shifter less than zero | |
| 649 | */ | |
| 650 | void alto2_cpu_device::f2_shifter_lt_zero_1() | |
| 651 | { | |
| 652 | UINT16 r = (m_shifter & 0100000) ? 1 : 0; | |
| 653 | LOG((0,2, " SH<0; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); | |
| 654 | m_next2 |= r; | |
| 655 | } | |
| 656 | ||
| 657 | /** | |
| 658 | * @brief f2_shifter_eq_zero late: branch on shifter equals zero | |
| 659 | */ | |
| 660 | void alto2_cpu_device::f2_shifter_eq_zero_1() | |
| 661 | { | |
| 662 | UINT16 r = m_shifter == 0 ? 1 : 0; | |
| 663 | LOG((0,2, " SH=0; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); | |
| 664 | m_next2 |= r; | |
| 665 | } | |
| 666 | ||
| 667 | /** | |
| 668 | * @brief f2_bus late: branch on bus bits BUS[6-15] | |
| 669 | */ | |
| 670 | void alto2_cpu_device::f2_bus_1() | |
| 671 | { | |
| 672 | UINT16 r = A2_GET32(m_bus,16,6,15); | |
| 673 | LOG((0,2, " BUS; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); | |
| 674 | m_next2 |= r; | |
| 675 | } | |
| 676 | ||
| 677 | /** | |
| 678 | * @brief f2_alucy late: branch on latched ALU carry | |
| 679 | */ | |
| 680 | void alto2_cpu_device::f2_alucy_1() | |
| 681 | { | |
| 682 | UINT16 r = m_laluc0; | |
| 683 | LOG((0,2, " ALUCY; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); | |
| 684 | m_next2 |= r; | |
| 685 | } | |
| 686 | ||
| 687 | /** | |
| 688 | * @brief f2_load_md late: load memory data | |
| 689 | * | |
| 690 | * Deliver BUS data to memory. | |
| 691 | */ | |
| 692 | void alto2_cpu_device::f2_load_md_1() | |
| 693 | { | |
| 694 | #if DEBUG | |
| 695 | UINT16 mar = m_mem.mar; | |
| 696 | #endif | |
| 697 | if (MIR_F1(m_mir) == f1_load_mar) { | |
| 698 | /* part of an XMAR */ | |
| 699 | LOG((0,2, " XMAR %#o (%#o)\n", mar, m_bus)); | |
| 700 | } else { | |
| 701 | write_mem(m_bus); | |
| 702 | LOG((0,2, " MD<- BUS ([%#o]=%#o)\n", mar, m_bus)); | |
| 703 | } | |
| 704 | } | |
| 705 | ||
| 706 | /** | |
| 707 | * @brief read the microcode ROM/RAM halfword | |
| 708 | * | |
| 709 | * Note: HALFSEL is selecting the even (0) or odd (1) half of the | |
| 710 | * microcode RAM 32-bit word. Here's how the demultiplexers (74298) | |
| 711 | * u8, u18, u28 and u38 select the bits: | |
| 712 | * | |
| 713 | * SN74298 | |
| 714 | * +---+-+---+ | |
| 715 | * | +-+ | | |
| 716 | * B2 -|1 16|- Vcc | |
| 717 | * | | | |
| 718 | * A2 -|2 15|- QA | |
| 719 | * | | | |
| 720 | * A1 -|3 14|- QB | |
| 721 | * | | | |
| 722 | * B1 -|4 13|- QC | |
| 723 | * | | | |
| 724 | * C2 -|5 12|- QD | |
| 725 | * | | | |
| 726 | * D2 -|6 11|- CLK | |
| 727 | * | | | |
| 728 | * D1 -|7 10|- SEL | |
| 729 | * | | | |
| 730 | * GND -|8 9|- C1 | |
| 731 | * | | | |
| 732 | * +---------+ | |
| 733 | * | |
| 734 | * chip out pin BUS in pin HSEL=0 in pin HSEL=1 | |
| 735 | * -------------------------------------------------------------- | |
| 736 | * u8 QA 15 0 A1 3 DRSEL(0)' A2 2 DF2(0) | |
| 737 | * u8 QB 14 1 B1 4 DRSEL(1)' B2 1 DF2(1)' | |
| 738 | * u8 QC 13 2 C1 9 DRSEL(2)' C2 5 DF2(2)' | |
| 739 | * u8 QD 12 3 D1 7 DRSEL(3)' D2 6 DF2(3)' | |
| 740 | * | |
| 741 | * u18 QA 15 4 A1 3 DRSEL(4)' A2 2 LOADT' | |
| 742 | * u18 QB 14 5 B1 4 DALUF(0)' B2 1 LOADL | |
| 743 | * u18 QC 13 6 C1 9 DALUF(1)' C2 5 NEXT(00)' | |
| 744 | * u18 QD 12 7 D1 7 DALUF(2)' D2 6 NEXT(01)' | |
| 745 | * | |
| 746 | * u28 QA 15 8 A1 3 DALUF(3)' A2 2 NEXT(02)' | |
| 747 | * u28 QB 14 9 B1 4 DBS(0)' B2 1 NEXT(03)' | |
| 748 | * u28 QC 13 10 C1 9 DBS(1)' C2 5 NEXT(04)' | |
| 749 | * u28 QD 12 11 D1 7 DBS(2)' D2 6 NEXT(05)' | |
| 750 | * | |
| 751 | * u38 QA 15 12 A1 3 DF1(0) A2 2 NEXT(06)' | |
| 752 | * u38 QB 14 13 B1 4 DF1(1)' B2 1 NEXT(07)' | |
| 753 | * u38 QC 13 14 C1 9 DF1(2)' C2 5 NEXT(08)' | |
| 754 | * u38 QD 12 15 D1 7 DF1(3)' D2 6 NEXT(09)' | |
| 755 | * | |
| 756 | * The HALFSEL signal to the demultiplexers is the inverted bit BUS(5): | |
| 757 | * BUS(5)=1, HALFSEL=0, A1,B1,C1,D1 inputs, upper half of the 32-bit word | |
| 758 | * BUS(5)=0, HALFSEL=1, A2,B2,C2,D2 inputs, lower half of the 32-bit word | |
| 759 | */ | |
| 760 | void alto2_cpu_device::rdram() | |
| 761 | { | |
| 762 | UINT32 addr, val; | |
| 763 | UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr) % ALTO2_UCODE_RAM_PAGES; | |
| 764 | UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr); | |
| 765 | ||
| 766 | m_rdram_flag = 0; | |
| 767 | if (GET_CRAM_RAMROM(m_cram_addr)) { | |
| 768 | /* read ROM 0 at current mpc */ | |
| 769 | addr = m_mpc & 01777; | |
| 770 | LOG((0,0," rdram: ROM [%05o] ", addr)); | |
| 771 | } else { | |
| 772 | /* read RAM 0,1,2 */ | |
| 773 | addr = ALTO2_UCODE_RAM_BASE + bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; | |
| 774 | LOG((0,0," rdram: RAM%d [%04o] ", bank, wordaddr)); | |
| 775 | } | |
| 776 | ||
| 777 | if (addr >= ALTO2_UCODE_SIZE) { | |
| 778 | val = 0177777; /* ??? */ | |
| 779 | LOG((0,0,"invalid address (%06o)\n", val)); | |
| 780 | return; | |
| 781 | } | |
| 782 | val = m_ucode_raw[addr] ^ ALTO2_UCODE_INVERTED; | |
| 783 | if (GET_CRAM_HALFSEL(m_cram_addr)) { | |
| 784 | val = val >> 16; | |
| 785 | LOG((0,0,"upper:%06o\n", val)); | |
| 786 | } else { | |
| 787 | val = val & 0177777; | |
| 788 | LOG((0,0,"lower:%06o\n", val)); | |
| 789 | } | |
| 790 | m_bus &= val; | |
| 791 | } | |
| 792 | ||
| 793 | /** | |
| 794 | * @brief write the microcode RAM from M register and ALU | |
| 795 | * | |
| 796 | * Note: M is a latch (MYL, i.e. memory L) on the CRAM board that latches | |
| 797 | * the ALU whenever LOADL and GOODTASK are met. GOODTASK is the Emulator | |
| 798 | * task and something I have not yet found out about: TASKA' and TASKB'. | |
| 799 | * | |
| 800 | * There's also an undumped PROM u21 which is addressed by GOODTASK and | |
| 801 | * 7 other signals... | |
| 802 | */ | |
| 803 | void alto2_cpu_device::wrtram() | |
| 804 | { | |
| 805 | UINT32 addr; | |
| 806 | UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr) % ALTO2_UCODE_RAM_PAGES; | |
| 807 | UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr); | |
| 808 | ||
| 809 | m_wrtram_flag = 0; | |
| 810 | ||
| 811 | /* write RAM 0,1,2 */ | |
| 812 | addr = ALTO2_UCODE_RAM_BASE + bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; | |
| 813 | LOG((0,0," wrtram: RAM%d [%04o] upper:%06o lower:%06o", bank, wordaddr, m_m, m_alu)); | |
| 814 | if (addr >= ALTO2_UCODE_SIZE) { | |
| 815 | LOG((0,0," invalid address\n")); | |
| 816 | return; | |
| 817 | } | |
| 818 | LOG((0,0,"\n")); | |
| 819 | m_ucode_raw[addr] = ((m_m << 16) | m_alu) ^ ALTO2_UCODE_INVERTED; | |
| 820 | } | |
| 821 | ||
| 822 | #if USE_ALU_74181 | |
| 823 | /** | |
| 824 | * <PRE> | |
| 825 | * Functional description of the 4-bit ALU 74181 | |
| 826 | * | |
| 827 | * The 74181 is a 4-bit high speed parallel Arithmetic Logic Unit (ALU). | |
| 828 | * Controlled by four Function Select inputs (S0-S3) and the Mode Control | |
| 829 | * input (M), it can perform all the 16 possible logic operations or 16 | |
| 830 | * different arithmetic operations on active HIGH or active LOW operands. | |
| 831 | * The Function Table lists these operations. | |
| 832 | * | |
| 833 | * When the Mode Control input (M) is HIGH, all internal carries are | |
| 834 | * inhibited and the device performs logic operations on the individual | |
| 835 | * bits as listed. When the Mode Control input is LOW, the carries are | |
| 836 | * enabled and the device performs arithmetic operations on the two 4-bit | |
| 837 | * words. The device incorporates full internal carry lookahead and | |
| 838 | * provides for either ripple carry between devices using the Cn+4 output, | |
| 839 | * or for carry lookahead between packages using the signals P' (Carry | |
| 840 | * Propagate) and G' (Carry Generate). In the ADD mode, P' indicates that | |
| 841 | * F' is 15 or more, while G' indicates that F' is 16 or more. In the | |
| 842 | * SUBTRACT mode, P' indicates that F' is zero or less, while G' indicates | |
| 843 | * that F' is less than zero. P' and G' are not affected by carry in. | |
| 844 | * When speed requirements are not stringent, it can be used in a simple | |
| 845 | * ripple carry mode by connecting the Carry output (Cn+4) signal to the | |
| 846 | * Carry input (Cn) of the next unit. For high speed operation the device | |
| 847 | * is used in conjunction with the 74182 carry lookahead circuit. One | |
| 848 | * carry lookahead package is required for each group of four 74181 devices. | |
| 849 | * Carry lookahead can be provided at various levels and offers high speed | |
| 850 | * capability over extremely long word lengths. | |
| 851 | * | |
| 852 | * The A=B output from the device goes HIGH when all four F' outputs are | |
| 853 | * HIGH and can be used to indicate logic equivalence over four bits when | |
| 854 | * the unit is in the subtract mode. The A=B output is open collector and | |
| 855 | * can be wired-AND with other A=B outputs to give a comparison for more | |
| 856 | * than four bits. The A=B signal can also be used with the Cn+4 signal | |
| 857 | * to indicated A>B and A<B. | |
| 858 | * | |
| 859 | * The Function Table lists the arithmetic operations that are performed | |
| 860 | * without a carry in. An incoming carry adds a one to each operation. | |
| 861 | * Thus, select code 0110 generates A minus B minus 1 (2's complement | |
| 862 | * notation) without a carry in and generates A minus B when a carry is | |
| 863 | * applied. Because subtraction is actually performed by the complementary | |
| 864 | * addition (1's complement), a carry out means borrow; thus a carry is | |
| 865 | * generated when there is no underflow and no carry is generated when | |
| 866 | * there is underflow. As indicated, this device can be used with either | |
| 867 | * active LOW inputs producing active LOW outputs or with active HIGH | |
| 868 | * inputs producing active HIGH outputs. For either case the table lists | |
| 869 | * the operations that are performed to the operands labeled inside the | |
| 870 | * logic symbol. | |
| 871 | * | |
| 872 | * The AltoI/II use four 74181s and a 74182 carry lookahead circuit, | |
| 873 | * and the inputs and outputs are all active HIGH. | |
| 874 | * | |
| 875 | * Active HIGH operands: | |
| 876 | * | |
| 877 | * +-------------------+-------------+------------------------+------------------------+ | |
| 878 | * | Mode Select | Logic | Arithmetic w/o carry | Arithmetic w/ carry | | |
| 879 | * | Inputs | | | | | |
| 880 | * | S3 S2 S1 S0 | (M=1) | (M=0) (Cn=1) | (M=0) (Cn=0) | | |
| 881 | * +-------------------+-------------+------------------------+------------------------+ | |
| 882 | * | 0 0 0 0 | A' | A | A + 1 | | |
| 883 | * +-------------------+-------------+------------------------+------------------------+ | |
| 884 | * | 0 0 0 1 | A' | B' | A | B | (A | B) + 1 | | |
| 885 | * +-------------------+-------------+------------------------+------------------------+ | |
| 886 | * | 0 0 1 0 | A' & B | A | B' | (A | B') + 1 | | |
| 887 | * +-------------------+-------------+------------------------+------------------------+ | |
| 888 | * | 0 0 1 1 | logic 0 | - 1 | -1 + 1 | | |
| 889 | * +-------------------+-------------+------------------------+------------------------+ | |
| 890 | * | 0 1 0 0 | (A & B)' | A + (A & B') | A + (A & B') + 1 | | |
| 891 | * +-------------------+-------------+------------------------+------------------------+ | |
| 892 | * | 0 1 0 1 | B' | (A | B) + (A & B') | (A | B) + (A & B') + 1 | | |
| 893 | * +-------------------+-------------+------------------------+------------------------+ | |
| 894 | * | 0 1 1 0 | A ^ B | A - B - 1 | A - B - 1 + 1 | | |
| 895 | * +-------------------+-------------+------------------------+------------------------+ | |
| 896 | * | 0 1 1 1 | A & B' | (A & B) - 1 | (A & B) - 1 + 1 | | |
| 897 | * +-------------------+-------------+------------------------+------------------------+ | |
| 898 | * | 1 0 0 0 | A' | B | A + (A & B) | A + (A & B) + 1 | | |
| 899 | * +-------------------+-------------+------------------------+------------------------+ | |
| 900 | * | 1 0 0 1 | A' ^ B' | A + B | A + B + 1 | | |
| 901 | * +-------------------+-------------+------------------------+------------------------+ | |
| 902 | * | 1 0 1 0 | B | (A | B') + (A & B) | (A | B') + (A & B) + 1 | | |
| 903 | * +-------------------+-------------+------------------------+------------------------+ | |
| 904 | * | 1 0 1 1 | A & B | (A & B) - 1 | (A & B) - 1 + 1 | | |
| 905 | * +-------------------+-------------+------------------------+------------------------+ | |
| 906 | * | 1 1 0 0 | logic 1 | A + A | A + A + 1 | | |
| 907 | * +-------------------+-------------+------------------------+------------------------+ | |
| 908 | * | 1 1 0 1 | A | B' | (A | B) + A | (A | B) + A + 1 | | |
| 909 | * +-------------------+-------------+------------------------+------------------------+ | |
| 910 | * | 1 1 1 0 | A | B | (A | B') + A | (A | B') + A + 1 | | |
| 911 | * +-------------------+-------------+------------------------+------------------------+ | |
| 912 | * | 1 1 1 1 | A | A - 1 | A - 1 + 1 | | |
| 913 | * +-------------------+-------------+------------------------+------------------------+ | |
| 914 | * </PRE> | |
| 915 | */ | |
| 916 | #define SMC(s3,s2,s1,s0,m,c) (32*(s3)+16*(s2)+8*(s1)+4*(s0)+2*(m)+(c)) | |
| 917 | ||
| 918 | /** | |
| 919 | * @brief Compute the 74181 ALU operation smc | |
| 920 | * @param smc S function, arithmetic/logic flag, carry | |
| 921 | * @return resulting ALU output | |
| 922 | */ | |
| 923 | UINT32 alto2_cpu_device::alu_74181(UINT32 smc) | |
| 924 | { | |
| 925 | register UINT32 a = m_bus; | |
| 926 | register UINT32 b = m_t; | |
| 927 | register UINT32 s = 0; | |
| 928 | register UINT32 f = 0; | |
| 929 | ||
| 930 | switch (smc) { | |
| 931 | case SMC(0,0,0,0, 0, 0): // 0000: A + 1 | |
| 932 | s = 0; | |
| 933 | f = a + 1; | |
| 934 | break; | |
| 935 | ||
| 936 | case SMC(0,0,0,0, 0, 1): // 0000: A | |
| 937 | s = 0; | |
| 938 | f = a; | |
| 939 | break; | |
| 940 | ||
| 941 | case SMC(0,0,0,1, 0, 0): // 0001: (A | B) + 1 | |
| 942 | s = 0; | |
| 943 | f = (a | b) + 1; | |
| 944 | break; | |
| 945 | ||
| 946 | case SMC(0,0,0,1, 0, 1): // 0001: A | B | |
| 947 | s = 0; | |
| 948 | f = a | b; | |
| 949 | break; | |
| 950 | ||
| 951 | case SMC(0,0,1,0, 0, 0): // 0010: (A | B') + 1 | |
| 952 | s = 0; | |
| 953 | f = (a | ~b) + 1; | |
| 954 | break; | |
| 955 | ||
| 956 | case SMC(0,0,1,0, 0, 1): // 0010: A | B' | |
| 957 | s = 0; | |
| 958 | f = a | ~b; | |
| 959 | break; | |
| 960 | ||
| 961 | case SMC(0,0,1,1, 0, 0): // 0011: -1 + 1 | |
| 962 | s = 1; | |
| 963 | f = -1 + 1; | |
| 964 | break; | |
| 965 | ||
| 966 | case SMC(0,0,1,1, 0, 1): // 0011: -1 | |
| 967 | s = 1; | |
| 968 | f = -1; | |
| 969 | break; | |
| 970 | ||
| 971 | case SMC(0,1,0,0, 0, 0): // 0100: A + (A & B') + 1 | |
| 972 | s = 0; | |
| 973 | f = a + (a & ~b) + 1; | |
| 974 | break; | |
| 975 | ||
| 976 | case SMC(0,1,0,0, 0, 1): // 0100: A + (A & B') | |
| 977 | s = 0; | |
| 978 | f = a + (a & ~b); | |
| 979 | break; | |
| 980 | ||
| 981 | case SMC(0,1,0,1, 0, 0): // 0101: (A | B) + (A & B') + 1 | |
| 982 | s = 0; | |
| 983 | f = (a | b) + (a & ~b) + 1; | |
| 984 | break; | |
| 985 | ||
| 986 | case SMC(0,1,0,1, 0, 1): // 0101: (A | B) + (A & B') | |
| 987 | s = 0; | |
| 988 | f = (a | b) + (a & ~b); | |
| 989 | break; | |
| 990 | ||
| 991 | case SMC(0,1,1,0, 0, 0): // 0110: A - B - 1 + 1 | |
| 992 | s = 1; | |
| 993 | f = a - b - 1 + 1; | |
| 994 | break; | |
| 995 | ||
| 996 | case SMC(0,1,1,0, 0, 1): // 0110: A - B - 1 | |
| 997 | s = 1; | |
| 998 | f = a - b - 1; | |
| 999 | break; | |
| 1000 | ||
| 1001 | case SMC(0,1,1,1, 0, 0): // 0111: (A & B) - 1 + 1 | |
| 1002 | s = 1; | |
| 1003 | f = (a & b) - 1 + 1; | |
| 1004 | break; | |
| 1005 | ||
| 1006 | case SMC(0,1,1,1, 0, 1): // 0111: (A & B) - 1 | |
| 1007 | s = 1; | |
| 1008 | f = (a & b) - 1; | |
| 1009 | break; | |
| 1010 | ||
| 1011 | case SMC(1,0,0,0, 0, 0): // 1000: A + (A & B) + 1 | |
| 1012 | s = 0; | |
| 1013 | f = a + (a & b) + 1; | |
| 1014 | break; | |
| 1015 | ||
| 1016 | case SMC(1,0,0,0, 0, 1): // 1000: A + (A & B) | |
| 1017 | s = 0; | |
| 1018 | f = a + (a & b); | |
| 1019 | break; | |
| 1020 | ||
| 1021 | case SMC(1,0,0,1, 0, 0): // 1001: A + B + 1 | |
| 1022 | s = 0; | |
| 1023 | f = a + b + 1; | |
| 1024 | break; | |
| 1025 | ||
| 1026 | case SMC(1,0,0,1, 0, 1): // 1001: A + B | |
| 1027 | s = 0; | |
| 1028 | f = a + b; | |
| 1029 | break; | |
| 1030 | ||
| 1031 | case SMC(1,0,1,0, 0, 0): // 1010: (A | B') + (A & B) + 1 | |
| 1032 | s = 0; | |
| 1033 | f = (a | ~b) + (a & b) + 1; | |
| 1034 | break; | |
| 1035 | ||
| 1036 | case SMC(1,0,1,0, 0, 1): // 1010: (A | B') + (A & B) | |
| 1037 | s = 0; | |
| 1038 | f = (a | ~b) + (a & b); | |
| 1039 | break; | |
| 1040 | ||
| 1041 | case SMC(1,0,1,1, 0, 0): // 1011: (A & B) - 1 + 1 | |
| 1042 | s = 1; | |
| 1043 | f = (a & b) - 1 + 1; | |
| 1044 | break; | |
| 1045 | ||
| 1046 | case SMC(1,0,1,1, 0, 1): // 1011: (A & B) - 1 | |
| 1047 | s = 1; | |
| 1048 | f = (a & b) - 1; | |
| 1049 | break; | |
| 1050 | ||
| 1051 | case SMC(1,1,0,0, 0, 0): // 1100: A + A + 1 | |
| 1052 | s = 0; | |
| 1053 | f = a + a + 1; | |
| 1054 | break; | |
| 1055 | ||
| 1056 | case SMC(1,1,0,0, 0, 1): // 1100: A + A | |
| 1057 | s = 0; | |
| 1058 | f = a + a; | |
| 1059 | break; | |
| 1060 | ||
| 1061 | case SMC(1,1,0,1, 0, 0): // 1101: (A | B) + A + 1 | |
| 1062 | s = 0; | |
| 1063 | f = (a | b) + a + 1; | |
| 1064 | break; | |
| 1065 | ||
| 1066 | case SMC(1,1,0,1, 0, 1): // 1101: (A | B) + A | |
| 1067 | s = 0; | |
| 1068 | f = (a | b) + a; | |
| 1069 | break; | |
| 1070 | ||
| 1071 | case SMC(1,1,1,0, 0, 0): // 1110: (A | B') + A + 1 | |
| 1072 | s = 0; | |
| 1073 | f = (a | ~b) + a + 1; | |
| 1074 | break; | |
| 1075 | ||
| 1076 | case SMC(1,1,1,0, 0, 1): // 1110: (A | B') + A | |
| 1077 | s = 0; | |
| 1078 | f = (a | ~b) + a; | |
| 1079 | break; | |
| 1080 | ||
| 1081 | case SMC(1,1,1,1, 0, 0): // 1111: A - 1 + 1 | |
| 1082 | s = 1; | |
| 1083 | f = a - 1 + 1; | |
| 1084 | break; | |
| 1085 | ||
| 1086 | case SMC(1,1,1,1, 0, 1): // 1111: A - 1 | |
| 1087 | s = 1; | |
| 1088 | f = a - 1; | |
| 1089 | break; | |
| 1090 | ||
| 1091 | case SMC(0,0,0,0, 1, 0): // 0000: A' | |
| 1092 | case SMC(0,0,0,0, 1, 1): | |
| 1093 | f = ~a; | |
| 1094 | break; | |
| 1095 | ||
| 1096 | case SMC(0,0,0,1, 1, 0): // 0001: A' | B' | |
| 1097 | case SMC(0,0,0,1, 1, 1): | |
| 1098 | f = ~a | ~b; | |
| 1099 | break; | |
| 1100 | ||
| 1101 | case SMC(0,0,1,0, 1, 0): // 0010: A' & B | |
| 1102 | case SMC(0,0,1,0, 1, 1): | |
| 1103 | f = ~a & b; | |
| 1104 | break; | |
| 1105 | ||
| 1106 | case SMC(0,0,1,1, 1, 0): // 0011: logic 0 | |
| 1107 | case SMC(0,0,1,1, 1, 1): | |
| 1108 | f = 0; | |
| 1109 | break; | |
| 1110 | ||
| 1111 | case SMC(0,1,0,0, 1, 0): // 0100: (A & B)' | |
| 1112 | case SMC(0,1,0,0, 1, 1): | |
| 1113 | f = ~(a & b); | |
| 1114 | break; | |
| 1115 | ||
| 1116 | case SMC(0,1,0,1, 1, 0): // 0101: B' | |
| 1117 | case SMC(0,1,0,1, 1, 1): | |
| 1118 | f = ~b; | |
| 1119 | break; | |
| 1120 | ||
| 1121 | case SMC(0,1,1,0, 1, 0): // 0110: A ^ B | |
| 1122 | case SMC(0,1,1,0, 1, 1): | |
| 1123 | f = a ^ b; | |
| 1124 | break; | |
| 1125 | ||
| 1126 | case SMC(0,1,1,1, 1, 0): // 0111: A & B' | |
| 1127 | case SMC(0,1,1,1, 1, 1): | |
| 1128 | f = a & ~b; | |
| 1129 | break; | |
| 1130 | ||
| 1131 | case SMC(1,0,0,0, 1, 0): // 1000: A' | B | |
| 1132 | case SMC(1,0,0,0, 1, 1): | |
| 1133 | f = ~a | b; | |
| 1134 | break; | |
| 1135 | ||
| 1136 | case SMC(1,0,0,1, 1, 0): // 1001: A' ^ B' | |
| 1137 | case SMC(1,0,0,1, 1, 1): | |
| 1138 | f = ~a ^ ~b; | |
| 1139 | break; | |
| 1140 | ||
| 1141 | case SMC(1,0,1,0, 1, 0): // 1010: B | |
| 1142 | case SMC(1,0,1,0, 1, 1): | |
| 1143 | f = b; | |
| 1144 | break; | |
| 1145 | ||
| 1146 | case SMC(1,0,1,1, 1, 0): // 1011: A & B | |
| 1147 | case SMC(1,0,1,1, 1, 1): | |
| 1148 | f = a & b; | |
| 1149 | break; | |
| 1150 | ||
| 1151 | case SMC(1,1,0,0, 1, 0): // 1100: logic 1 | |
| 1152 | case SMC(1,1,0,0, 1, 1): | |
| 1153 | f = ~0; | |
| 1154 | break; | |
| 1155 | ||
| 1156 | case SMC(1,1,0,1, 1, 0): // 1101: A | B' | |
| 1157 | case SMC(1,1,0,1, 1, 1): | |
| 1158 | f = a | ~b; | |
| 1159 | break; | |
| 1160 | ||
| 1161 | case SMC(1,1,1,0, 1, 0): // 1110: A | B | |
| 1162 | case SMC(1,1,1,0, 1, 1): | |
| 1163 | f = a | b; | |
| 1164 | break; | |
| 1165 | ||
| 1166 | case SMC(1,1,1,1, 1, 0): // 1111: A | |
| 1167 | case SMC(1,1,1,1, 1, 1): | |
| 1168 | f = a; | |
| 1169 | break; | |
| 1170 | } | |
| 1171 | if (smc & 2) { | |
| 1172 | m_aluc0 = ((f >> 16) ^ s) & 1; | |
| 1173 | } else { | |
| 1174 | m_aluc0 = 1; | |
| 1175 | } | |
| 1176 | return f; | |
| 1177 | } | |
| 1178 | #endif | |
| 1179 | ||
| 1180 | /** @brief flag that tells whether to load the T register from BUS or ALU */ | |
| 1181 | #define TSELECT 1 | |
| 1182 | ||
| 1183 | /** @brief flag that tells wheter operation was 0: logic (M=1) or 1: arithmetic (M=0) */ | |
| 1184 | #define ALUM2 2 | |
| 1185 | ||
| 1186 | /** @brief execute the CPU for at most nsecs nano seconds */ | |
| 1187 | void alto2_cpu_device::execute_run() | |
| 1188 | { | |
| 1189 | m_alto_leave = 0; | |
| 1190 | ||
| 1191 | m_next = m_task_mpc[m_task]; // get current task's next mpc and address modifier | |
| 1192 | m_next2 = m_task_next2[m_task]; | |
| 1193 | ||
| 1194 | for (;;) { | |
| 1195 | int do_bs, flags; | |
| 1196 | UINT32 alu; | |
| 1197 | UINT8 aluf; | |
| 1198 | UINT8 bs; | |
| 1199 | UINT8 f1; | |
| 1200 | UINT8 f2; | |
| 1201 | ||
| 1202 | // FIXME: cycle counting? | |
| 1203 | if (m_alto_leave) | |
| 1204 | break; | |
| 1205 | ||
| 1206 | /* | |
| 1207 | * Subtract the microcycle time from the display time accu. | |
| 1208 | * If it underflows, call the display state machine and add | |
| 1209 | * the time for 24 pixel clocks to the accu. | |
| 1210 | * This is very close to every seventh CPU cycle. | |
| 1211 | */ | |
| 1212 | m_dsp_time -= ALTO2_UCYCLE; | |
| 1213 | if (m_dsp_time < 0) { | |
| 1214 | m_dsp_state = display_state_machine(m_dsp_state); | |
| 1215 | m_dsp_time += ALTO2_DISPLAY_BITTIME(24); | |
| 1216 | } | |
| 1217 | if (m_unload_time >= 0) { | |
| 1218 | /* | |
| 1219 | * Subtract the microcycle time from the unload time accu. | |
| 1220 | * If it underflows call the unload word function which adds | |
| 1221 | * the time for 16 or 32 pixel clocks to the accu, or ends | |
| 1222 | * the unloading by leaving m_unload_time at -1. | |
| 1223 | */ | |
| 1224 | m_unload_time -= ALTO2_UCYCLE; | |
| 1225 | if (m_unload_time < 0) { | |
| 1226 | m_unload_word = unload_word(m_unload_word); | |
| 1227 | } | |
| 1228 | } | |
| 1229 | ||
| 1230 | m_cycle++; | |
| 1231 | /* nano seconds per cycle */ | |
| 1232 | m_ntime[m_task] += ALTO2_UCYCLE; | |
| 1233 | ||
| 1234 | /* next instruction's mpc */ | |
| 1235 | m_mpc = m_next; | |
| 1236 | m_mir = m_ucode_raw[m_mpc]; | |
| 1237 | m_rsel = MIR_RSEL(m_mir); | |
| 1238 | m_next = MIR_NEXT(m_mir) | m_next2; | |
| 1239 | m_next2 = A2_GET32(m_ucode_raw[m_next], 32, NEXT0, NEXT9) | (m_next2 & ~ALTO2_UCODE_PAGE_MASK); | |
| 1240 | aluf = MIR_ALUF(m_mir); | |
| 1241 | bs = MIR_BS(m_mir); | |
| 1242 | f1 = MIR_F1(m_mir); | |
| 1243 | f2 = MIR_F2(m_mir); | |
| 1244 | LOG((0,2,"\n%s-%04o: r:%02o af:%02o bs:%02o f1:%02o f2:%02o t:%o l:%o next:%05o next2:%05o cycle:%lld\n", | |
| 1245 | task_name(m_task), m_mpc, m_rsel, aluf, bs, f1, f2, MIR_T(m_mir), MIR_L(m_mir), m_next, m_next2, cycle())); | |
| 1246 | ||
| 1247 | /* | |
| 1248 | * This bus source decoding is not performed if f1 = 7 or f2 = 7. | |
| 1249 | * These functions use the BS field to provide part of the address | |
| 1250 | * to the constant ROM | |
| 1251 | */ | |
| 1252 | do_bs = !(f1 == f1_const || f2 == f2_const); | |
| 1253 | ||
| 1254 | if (f1 == f1_load_mar) { | |
| 1255 | if (check_mem_load_mar_stall(m_rsel)) { | |
| 1256 | LOG((0,3, " MAR<- stall\n")); | |
| 1257 | m_next2 = m_next; | |
| 1258 | m_next = m_mpc; | |
| 1259 | continue; | |
| 1260 | } | |
| 1261 | } else if (f2 == f2_load_md) { | |
| 1262 | if (check_mem_write_stall()) { | |
| 1263 | LOG((0,3, " MD<- stall\n")); | |
| 1264 | m_next2 = m_next; | |
| 1265 | m_next = m_mpc; | |
| 1266 | continue; | |
| 1267 | } | |
| 1268 | } | |
| 1269 | if (do_bs && bs == bs_read_md) { | |
| 1270 | if (check_mem_read_stall()) { | |
| 1271 | LOG((0,3, " <-MD stall\n")); | |
| 1272 | m_next2 = m_next; | |
| 1273 | m_next = m_mpc; | |
| 1274 | continue; | |
| 1275 | } | |
| 1276 | } | |
| 1277 | ||
| 1278 | m_bus = 0177777; | |
| 1279 | ||
| 1280 | if (m_rdram_flag) | |
| 1281 | rdram(); | |
| 1282 | ||
| 1283 | /* | |
| 1284 | * The constant memory is gated to the bus by F1 = 7, F2 = 7, or BS >= 4 | |
| 1285 | */ | |
| 1286 | if (!do_bs || bs >= 4) { | |
| 1287 | int addr = 8 * m_rsel + bs; | |
| 1288 | LOG((0,2," %#o; BUS &= CONST[%03o]\n", m_const_prom[addr], addr)); | |
| 1289 | m_bus &= m_const_prom[addr]; | |
| 1290 | } | |
| 1291 | ||
| 1292 | /* | |
| 1293 | * early f2 has to be done before early bs, because the | |
| 1294 | * emulator f2 acsource or acdest may change rsel | |
| 1295 | */ | |
| 1296 | if (m_f2[0][m_task][f2]) | |
| 1297 | ((*this).*m_f2[0][m_task][f2])(); | |
| 1298 | ||
| 1299 | /* | |
| 1300 | * early bs can be done now | |
| 1301 | */ | |
| 1302 | if (do_bs) | |
| 1303 | if (m_bs[0][m_task][bs]) | |
| 1304 | ((*this).*m_bs[0][m_task][bs])(); | |
| 1305 | ||
| 1306 | /* | |
| 1307 | * early f1 | |
| 1308 | */ | |
| 1309 | if (m_f1[0][m_task][f1]) | |
| 1310 | ((*this).*m_f1[0][m_task][f1])(); | |
| 1311 | ||
| 1312 | /* compute the ALU function */ | |
| 1313 | switch (aluf) { | |
| 1314 | /** | |
| 1315 | * 00: ALU <- BUS | |
| 1316 | * PROM data for S3-0:1111 M:1 C:0 | |
| 1317 | * 74181 function F=A | |
| 1318 | * T source is ALU | |
| 1319 | */ | |
| 1320 | case aluf_bus__alut: | |
| 1321 | #if USE_ALU_74181 | |
| 1322 | alu = alu_74181(SMC(1,1,1,1, 1, 0)); | |
| 1323 | #else | |
| 1324 | alu = m_bus; | |
| 1325 | m_aluc0 = 1; | |
| 1326 | #endif | |
| 1327 | flags = TSELECT; | |
| 1328 | LOG((0,2," ALU<- BUS (%#o := %#o)\n", alu, m_bus)); | |
| 1329 | break; | |
| 1330 | ||
| 1331 | /** | |
| 1332 | * 01: ALU <- T | |
| 1333 | * PROM data for S3-0:1010 M:1 C:0 | |
| 1334 | * 74181 function F=B | |
| 1335 | * T source is BUS | |
| 1336 | */ | |
| 1337 | case aluf_treg: | |
| 1338 | #if USE_ALU_74181 | |
| 1339 | alu = alu_74181(SMC(1,0,1,0, 1, 0)); | |
| 1340 | #else | |
| 1341 | alu = m_t; | |
| 1342 | m_aluc0 = 1; | |
| 1343 | #endif | |
| 1344 | flags = 0; | |
| 1345 | LOG((0,2," ALU<- T (%#o := %#o)\n", alu, m_t)); | |
| 1346 | break; | |
| 1347 | ||
| 1348 | /** | |
| 1349 | * 02: ALU <- BUS | T | |
| 1350 | * PROM data for S3-0:1110 M:1 C:0 | |
| 1351 | * 74181 function F=A|B | |
| 1352 | * T source is ALU | |
| 1353 | */ | |
| 1354 | case aluf_bus_or_t__alut: | |
| 1355 | #if USE_ALU_74181 | |
| 1356 | alu = alu_74181(SMC(1,1,1,0, 1, 0)); | |
| 1357 | #else | |
| 1358 | alu = m_bus | m_t; | |
| 1359 | m_aluc0 = 1; | |
| 1360 | #endif | |
| 1361 | flags = TSELECT; | |
| 1362 | LOG((0,2," ALU<- BUS OR T (%#o := %#o | %#o)\n", alu, m_bus, m_t)); | |
| 1363 | break; | |
| 1364 | ||
| 1365 | /** | |
| 1366 | * 03: ALU <- BUS & T | |
| 1367 | * PROM data for S3-0:1011 M:1 C:0 | |
| 1368 | * 74181 function F=A&B | |
| 1369 | * T source is BUS | |
| 1370 | */ | |
| 1371 | case aluf_bus_and_t: | |
| 1372 | #if USE_ALU_74181 | |
| 1373 | alu = alu_74181(SMC(1,0,1,1, 1, 0)); | |
| 1374 | #else | |
| 1375 | alu = m_bus & m_t; | |
| 1376 | m_aluc0 = 1; | |
| 1377 | #endif | |
| 1378 | flags = 0; | |
| 1379 | LOG((0,2," ALU<- BUS AND T (%#o := %#o & %#o)\n", alu, m_bus, m_t)); | |
| 1380 | break; | |
| 1381 | ||
| 1382 | /** | |
| 1383 | * 04: ALU <- BUS ^ T | |
| 1384 | * PROM data for S3-0:0110 M:1 C:0 | |
| 1385 | * 74181 function F=A^B | |
| 1386 | * T source is BUS | |
| 1387 | */ | |
| 1388 | case aluf_bus_xor_t: | |
| 1389 | #if USE_ALU_74181 | |
| 1390 | alu = alu_74181(SMC(0,1,1,0, 1, 0)); | |
| 1391 | #else | |
| 1392 | alu = m_bus ^ m_t; | |
| 1393 | m_aluc0 = 1; | |
| 1394 | #endif | |
| 1395 | flags = 0; | |
| 1396 | LOG((0,2," ALU<- BUS XOR T (%#o := %#o ^ %#o)\n", alu, m_bus, m_t)); | |
| 1397 | break; | |
| 1398 | ||
| 1399 | /** | |
| 1400 | * 05: ALU <- BUS + 1 | |
| 1401 | * PROM data for S3-0:0000 M:0 C:0 | |
| 1402 | * 74181 function F=A+1 | |
| 1403 | * T source is ALU | |
| 1404 | */ | |
| 1405 | case aluf_bus_plus_1__alut: | |
| 1406 | #if USE_ALU_74181 | |
| 1407 | alu = alu_74181(SMC(0,0,0,0, 0, 0)); | |
| 1408 | #else | |
| 1409 | alu = m_bus + 1; | |
| 1410 | m_aluc0 = (alu >> 16) & 1; | |
| 1411 | #endif | |
| 1412 | flags = ALUM2 | TSELECT; | |
| 1413 | LOG((0,2," ALU<- BUS + 1 (%#o := %#o + 1)\n", alu, m_bus)); | |
| 1414 | break; | |
| 1415 | ||
| 1416 | /** | |
| 1417 | * 06: ALU <- BUS - 1 | |
| 1418 | * PROM data for S3-0:1111 M:0 C:1 | |
| 1419 | * 74181 function F=A-1 | |
| 1420 | * T source is ALU | |
| 1421 | */ | |
| 1422 | case aluf_bus_minus_1__alut: | |
| 1423 | #if USE_ALU_74181 | |
| 1424 | alu = alu_74181(SMC(1,1,1,1, 0, 1)); | |
| 1425 | #else | |
| 1426 | alu = m_bus + 0177777; | |
| 1427 | m_aluc0 = (~m_alu >> 16) & 1; | |
| 1428 | #endif | |
| 1429 | flags = ALUM2 | TSELECT; | |
| 1430 | LOG((0,2," ALU<- BUS - 1 (%#o := %#o - 1)\n", alu, m_bus)); | |
| 1431 | break; | |
| 1432 | ||
| 1433 | /** | |
| 1434 | * 07: ALU <- BUS + T | |
| 1435 | * PROM data for S3-0:1001 M:0 C:1 | |
| 1436 | * 74181 function F=A+B | |
| 1437 | * T source is BUS | |
| 1438 | */ | |
| 1439 | case aluf_bus_plus_t: | |
| 1440 | #if USE_ALU_74181 | |
| 1441 | alu = alu_74181(SMC(1,0,0,1, 0, 1)); | |
| 1442 | #else | |
| 1443 | alu = m_bus + m_t; | |
| 1444 | m_aluc0 = (m_alu >> 16) & 1; | |
| 1445 | #endif | |
| 1446 | flags = ALUM2; | |
| 1447 | LOG((0,2," ALU<- BUS + T (%#o := %#o + %#o)\n", alu, m_bus, m_t)); | |
| 1448 | break; | |
| 1449 | ||
| 1450 | /** | |
| 1451 | * 10: ALU <- BUS - T | |
| 1452 | * PROM data for S3-0:0110 M:0 C:0 | |
| 1453 | * 74181 function F=A-B | |
| 1454 | * T source is BUS | |
| 1455 | */ | |
| 1456 | case aluf_bus_minus_t: | |
| 1457 | #if USE_ALU_74181 | |
| 1458 | alu = alu_74181(SMC(0,1,1,0, 0, 0)); | |
| 1459 | #else | |
| 1460 | alu = m_bus + ~m_t + 1; | |
| 1461 | m_aluc0 = (~m_alu >> 16) & 1; | |
| 1462 | #endif | |
| 1463 | flags = ALUM2; | |
| 1464 | LOG((0,2," ALU<- BUS - T (%#o := %#o - %#o)\n", alu, m_bus, m_t)); | |
| 1465 | break; | |
| 1466 | ||
| 1467 | /** | |
| 1468 | * 11: ALU <- BUS - T - 1 | |
| 1469 | * PROM data for S3-0:0110 M:0 C:1 | |
| 1470 | * 74181 function F=A-B-1 | |
| 1471 | * T source is BUS | |
| 1472 | */ | |
| 1473 | case aluf_bus_minus_t_minus_1: | |
| 1474 | #if USE_ALU_74181 | |
| 1475 | alu = alu_74181(SMC(0,1,1,0, 0, 1)); | |
| 1476 | #else | |
| 1477 | alu = m_bus + ~m_t; | |
| 1478 | m_aluc0 = (~m_alu >> 16) & 1; | |
| 1479 | #endif | |
| 1480 | flags = ALUM2; | |
| 1481 | LOG((0,2," ALU<- BUS - T - 1 (%#o := %#o - %#o - 1)\n", alu, m_bus, m_t)); | |
| 1482 | break; | |
| 1483 | ||
| 1484 | /** | |
| 1485 | * 12: ALU <- BUS + T + 1 | |
| 1486 | * PROM data for S3-0:1001 M:0 C:0 | |
| 1487 | * 74181 function F=A+B+1 | |
| 1488 | * T source is ALU | |
| 1489 | */ | |
| 1490 | case aluf_bus_plus_t_plus_1__alut: | |
| 1491 | #if USE_ALU_74181 | |
| 1492 | alu = alu_74181(SMC(1,0,0,1, 0, 0)); | |
| 1493 | #else | |
| 1494 | alu = m_bus + m_t + 1; | |
| 1495 | m_aluc0 = (m_alu >> 16) & 1; | |
| 1496 | #endif | |
| 1497 | flags = ALUM2 | TSELECT; | |
| 1498 | LOG((0,2," ALU<- BUS + T + 1 (%#o := %#o + %#o + 1)\n", alu, m_bus, m_t)); | |
| 1499 | break; | |
| 1500 | ||
| 1501 | /** | |
| 1502 | * 13: ALU <- BUS + SKIP | |
| 1503 | * PROM data for S3-0:0000 M:0 C:SKIP | |
| 1504 | * 74181 function F=A (SKIP=1) or F=A+1 (SKIP=0) | |
| 1505 | * T source is ALU | |
| 1506 | */ | |
| 1507 | case aluf_bus_plus_skip__alut: | |
| 1508 | #if USE_ALU_74181 | |
| 1509 | alu = alu_74181(SMC(0,0,0,0, 0, m_emu.skip^1)); | |
| 1510 | #else | |
| 1511 | alu = m_bus + m_emu.skip; | |
| 1512 | m_aluc0 = (m_alu >> 16) & 1; | |
| 1513 | #endif | |
| 1514 | flags = ALUM2 | TSELECT; | |
| 1515 | LOG((0,2," ALU<- BUS + SKIP (%#o := %#o + %#o)\n", alu, m_bus, m_emu.skip)); | |
| 1516 | break; | |
| 1517 | ||
| 1518 | /** | |
| 1519 | * 14: ALU <- BUS,T | |
| 1520 | * PROM data for S3-0:1011 M:1 C:0 | |
| 1521 | * 74181 function F=A&B | |
| 1522 | * T source is ALU | |
| 1523 | */ | |
| 1524 | case aluf_bus_and_t__alut: | |
| 1525 | #if USE_ALU_74181 | |
| 1526 | alu = alu_74181(SMC(1,0,1,1, 1, 0)); | |
| 1527 | #else | |
| 1528 | alu = m_bus & m_t; | |
| 1529 | m_aluc0 = 1; | |
| 1530 | #endif | |
| 1531 | flags = TSELECT; | |
| 1532 | LOG((0,2," ALU<- BUS,T (%#o := %#o & %#o)\n", alu, m_bus, m_t)); | |
| 1533 | break; | |
| 1534 | ||
| 1535 | /** | |
| 1536 | * 15: ALU <- BUS & ~T | |
| 1537 | * PROM data for S3-0:0111 M:1 C:0 | |
| 1538 | * 74181 function F=A&~B | |
| 1539 | * T source is BUS | |
| 1540 | */ | |
| 1541 | case aluf_bus_and_not_t: | |
| 1542 | #if USE_ALU_74181 | |
| 1543 | alu = alu_74181(SMC(0,1,1,1, 1, 0)); | |
| 1544 | #else | |
| 1545 | alu = m_bus & ~m_t; | |
| 1546 | m_aluc0 = 1; | |
| 1547 | #endif | |
| 1548 | flags = 0; | |
| 1549 | LOG((0,2," ALU<- BUS AND NOT T (%#o := %#o & ~%#o)\n", alu, m_bus, m_t)); | |
| 1550 | break; | |
| 1551 | ||
| 1552 | /** | |
| 1553 | * 16: ALU <- ??? | |
| 1554 | * PROM data for S3-0:???? M:? C:? | |
| 1555 | * 74181 perhaps F=0 (0011/0/0) | |
| 1556 | * T source is BUS | |
| 1557 | */ | |
| 1558 | case aluf_undef_16: | |
| 1559 | #if USE_ALU_74181 | |
| 1560 | alu = alu_74181(SMC(0,0,1,1, 0, 0)); | |
| 1561 | #else | |
| 1562 | alu = 0; | |
| 1563 | m_aluc0 = 1; | |
| 1564 | #endif | |
| 1565 | flags = ALUM2; | |
| 1566 | LOG((0,0," ALU<- 0 (illegal aluf in task %s, mpc:%05o aluf:%02o)\n", task_name(m_task), m_mpc, aluf)); | |
| 1567 | break; | |
| 1568 | ||
| 1569 | /** | |
| 1570 | * 17: ALU <- ??? | |
| 1571 | * PROM data for S3-0:???? M:? C:? | |
| 1572 | * 74181 perhaps F=~0 (0011/0/1) | |
| 1573 | * T source is BUS | |
| 1574 | */ | |
| 1575 | case aluf_undef_17: | |
| 1576 | default: | |
| 1577 | #if USE_ALU_74181 | |
| 1578 | alu = alu_74181(SMC(0,0,1,1, 0, 1)); | |
| 1579 | #else | |
| 1580 | alu = 0177777; | |
| 1581 | m_aluc0 = 1; | |
| 1582 | #endif | |
| 1583 | flags = ALUM2; | |
| 1584 | LOG((0,0," ALU<- 0 (illegal aluf in task %s, mpc:%05o aluf:%02o)\n", task_name(m_task), m_mpc, aluf)); | |
| 1585 | } | |
| 1586 | m_alu = static_cast<UINT16>(alu); | |
| 1587 | ||
| 1588 | /* WRTRAM now, before L is changed */ | |
| 1589 | if (m_wrtram_flag) | |
| 1590 | wrtram(); | |
| 1591 | ||
| 1592 | switch (f1) { | |
| 1593 | case f1_l_lsh_1: | |
| 1594 | if (m_task == task_emu) { | |
| 1595 | if (f2 == f2_emu_magic) { | |
| 1596 | m_shifter = ((m_l << 1) | (m_t >> 15)) & 0177777; | |
| 1597 | LOG((0,2," SHIFTER <-L MLSH 1 (%#o := %#o<<1|%#o)\n", m_shifter, m_l, m_t >> 15)); | |
| 1598 | break; | |
| 1599 | } | |
| 1600 | if (f2 == f2_emu_load_dns) { | |
| 1601 | /* shifter is done in F2 */ | |
| 1602 | break; | |
| 1603 | } | |
| 1604 | } | |
| 1605 | m_shifter = (m_l << 1) & 0177777; | |
| 1606 | LOG((0,2," SHIFTER <-L LSH 1 (%#o := %#o<<1)\n", m_shifter, m_l)); | |
| 1607 | break; | |
| 1608 | ||
| 1609 | case f1_l_rsh_1: | |
| 1610 | if (m_task == task_emu) { | |
| 1611 | if (f2 == f2_emu_magic) { | |
| 1612 | m_shifter = ((m_l >> 1) | (m_t << 15)) & 0177777; | |
| 1613 | LOG((0,2," SHIFTER <-L MRSH 1 (%#o := %#o>>1|%#o)\n", m_shifter, m_l, (m_t << 15) & 0100000)); | |
| 1614 | break; | |
| 1615 | } | |
| 1616 | if (f2 == f2_emu_load_dns) { | |
| 1617 | /* shifter is done in F2 */ | |
| 1618 | break; | |
| 1619 | } | |
| 1620 | } | |
| 1621 | m_shifter = m_l >> 1; | |
| 1622 | LOG((0,2," SHIFTER <-L RSH 1 (%#o := %#o>>1)\n", m_shifter, m_l)); | |
| 1623 | break; | |
| 1624 | ||
| 1625 | case f1_l_lcy_8: | |
| 1626 | m_shifter = ((m_l >> 8) | (m_l << 8)) & 0177777; | |
| 1627 | LOG((0,2," SHIFTER <-L LCY 8 (%#o := bswap %#o)\n", m_shifter, m_l)); | |
| 1628 | break; | |
| 1629 | ||
| 1630 | default: | |
| 1631 | /* shifter passes L, if F1 is not one of L LSH 1, L RSH 1 or L LCY 8 */ | |
| 1632 | m_shifter = m_l; | |
| 1633 | } | |
| 1634 | ||
| 1635 | /* late F1 is done now, if any */ | |
| 1636 | if (m_f1[1][m_task][f1]) | |
| 1637 | ((*this).*m_f1[1][m_task][f1])(); | |
| 1638 | ||
| 1639 | /* late F2 is done now, if any */ | |
| 1640 | if (m_f2[1][m_task][f2]) | |
| 1641 | ((*this).*m_f2[1][m_task][f2])(); | |
| 1642 | ||
| 1643 | /* late BS is done now, if no constant was put on the bus */ | |
| 1644 | if (do_bs) | |
| 1645 | if (m_bs[1][m_task][bs]) | |
| 1646 | ((*this).*m_bs[1][m_task][bs])(); | |
| 1647 | ||
| 1648 | /* | |
| 1649 | * update L register and LALUC0, and also M register, | |
| 1650 | * if a RAM related task is active | |
| 1651 | */ | |
| 1652 | if (MIR_L(m_mir)) { | |
| 1653 | /* load L from ALU */ | |
| 1654 | m_l = m_alu; | |
| 1655 | if (flags & ALUM2) { | |
| 1656 | m_laluc0 = m_aluc0; | |
| 1657 | LOG((0,2, " L<- ALU (%#o); LALUC0<- ALUC0 (%o)\n", m_alu, m_laluc0)); | |
| 1658 | } else { | |
| 1659 | m_laluc0 = 0; | |
| 1660 | LOG((0,2, " L<- ALU (%#o); LALUC0<- %o\n", m_alu, m_laluc0)); | |
| 1661 | } | |
| 1662 | if (m_ram_related[m_task]) { | |
| 1663 | /* load M from ALU, if 'GOODTASK' */ | |
| 1664 | m_m = m_alu; | |
| 1665 | /* also writes to S[bank][0], which can't be read */ | |
| 1666 | m_s[m_s_reg_bank[m_task]][0] = m_alu; | |
| 1667 | LOG((0,2, " M<- ALU (%#o)\n", m_alu)); | |
| 1668 | } | |
| 1669 | } | |
| 1670 | ||
| 1671 | /* update T register, if LOADT is set */ | |
| 1672 | if (MIR_T(m_mir)) { | |
| 1673 | m_cram_addr = m_alu; | |
| 1674 | if (flags & TSELECT) { | |
| 1675 | LOG((0,2, " T<- ALU (%#o)\n", m_alu)); | |
| 1676 | m_t = m_alu; | |
| 1677 | } else { | |
| 1678 | LOG((0,2, " T<- BUS (%#o)\n", m_bus)); | |
| 1679 | m_t = m_bus; | |
| 1680 | } | |
| 1681 | } | |
| 1682 | ||
| 1683 | if (m_task != m_next2_task) { | |
| 1684 | /* switch now? */ | |
| 1685 | if (m_task == m_next_task) { | |
| 1686 | /* one more microinstruction */ | |
| 1687 | m_next_task = m_next2_task; | |
| 1688 | } else { | |
| 1689 | /* save this task's mpc */ | |
| 1690 | m_task_mpc[m_task] = m_next; | |
| 1691 | m_task_next2[m_task] = m_next2; | |
| 1692 | m_task = m_next_task; | |
| 1693 | LOG((0,1, "task switch to %02o:%s (cycle %lld)\n", m_task, task_name(m_task), cycle())); | |
| 1694 | /* get new task's mpc */ | |
| 1695 | m_next = m_task_mpc[m_task]; | |
| 1696 | /* get address modifier after task switch (?) */ | |
| 1697 | m_next2 = m_task_next2[m_task]; | |
| 1698 | ||
| 1699 | if (m_active_callback[m_task]) { | |
| 1700 | /* | |
| 1701 | * let the task know it becomes active now | |
| 1702 | * and (most probably) reset the wakeup | |
| 1703 | */ | |
| 1704 | ((*this).*m_active_callback[m_task])(); | |
| 1705 | } | |
| 1706 | } | |
| 1707 | } | |
| 1708 | } | |
| 1709 | ||
| 1710 | /* save this task's mpc and address modifier */ | |
| 1711 | m_task_mpc[m_task] = m_next; | |
| 1712 | m_task_next2[m_task] = m_next2; | |
| 1713 | } | |
| 1714 | ||
| 1715 | /** @brief reset the various registers */ | |
| 1716 | void alto2_cpu_device::hard_reset() | |
| 1717 | { | |
| 1718 | static const UINT8 ctl2k_u3[256] = { | |
| 1719 | /* 0000 */ 000,000,013,016,012,016,014,016,000,001,013,016,012,016,016,016, | |
| 1720 | /* 0020 */ 010,001,013,016,012,016,015,016,010,001,013,016,012,016,017,016, | |
| 1721 | /* 0040 */ 004,001,013,017,012,017,014,017,004,001,013,017,012,017,016,017, | |
| 1722 | /* 0060 */ 014,001,013,017,012,017,015,017,014,001,013,017,012,017,017,017, | |
| 1723 | /* 0100 */ 002,001,013,016,012,016,014,016,002,001,013,016,012,016,016,016, | |
| 1724 | /* 0120 */ 012,001,013,016,012,016,015,016,012,001,013,016,012,016,017,016, | |
| 1725 | /* 0140 */ 006,001,013,017,012,017,014,017,006,013,013,017,012,017,016,017, | |
| 1726 | /* 0160 */ 017,001,013,017,012,017,015,017,017,001,013,017,012,017,017,017, | |
| 1727 | /* 0200 */ 011,001,013,016,012,016,014,016,011,016,013,016,012,016,016,016, | |
| 1728 | /* 0220 */ 001,001,013,016,012,016,015,016,001,001,013,016,012,016,017,016, | |
| 1729 | /* 0240 */ 005,001,013,017,012,017,014,017,005,013,013,017,012,017,016,017, | |
| 1730 | /* 0260 */ 015,001,013,017,012,017,015,017,015,014,013,017,012,017,017,017, | |
| 1731 | /* 0300 */ 003,001,013,016,012,016,014,016,003,001,013,016,012,016,016,016, | |
| 1732 | /* 0320 */ 013,001,013,016,012,016,015,016,013,001,013,016,012,016,017,016, | |
| 1733 | /* 0340 */ 007,001,013,017,012,017,014,017,007,001,013,017,012,017,016,017, | |
| 1734 | /* 0360 */ 016,001,013,017,012,017,015,017,016,015,013,017,012,017,017,017 | |
| 1735 | }; | |
| 1736 | memcpy(m_ctl2k_u3, ctl2k_u3, sizeof(m_ctl2k_u3)); | |
| 1737 | ||
| 1738 | static const UINT8 ctl2k_u38[32] = { | |
| 1739 | /* 0000 */ 0367,0353,0323,0315,0265,0251,0221,0216, | |
| 1740 | /* 0010 */ 0166,0152,0122,0114,0064,0050,0020,0017, | |
| 1741 | /* 0020 */ 0000,0000,0000,0000,0000,0000,0000,0000, | |
| 1742 | /* 0030 */ 0000,0000,0000,0000,0000,0000,0000,0000 | |
| 1743 | }; | |
| 1744 | memcpy(m_ctl2k_u38, ctl2k_u38, sizeof(m_ctl2k_u38)); | |
| 1745 | ||
| 1746 | static const UINT8 ctl2k_u76[256] = { | |
| 1747 | /* 0000 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1748 | /* 0020 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1749 | /* 0040 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1750 | /* 0060 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1751 | /* 0100 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1752 | /* 0120 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1753 | /* 0140 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1754 | /* 0160 */ 000,014,000,000,000,000,000,000,014,000,000,000,000,000,000,000, | |
| 1755 | /* 0200 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1756 | /* 0220 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1757 | /* 0240 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1758 | /* 0260 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1759 | /* 0300 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1760 | /* 0320 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1761 | /* 0340 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000, | |
| 1762 | /* 0360 */ 000,014,000,000,000,000,000,000,000,014,000,000,000,000,000,000 | |
| 1763 | }; | |
| 1764 | memcpy(m_ctl2k_u76, ctl2k_u76, sizeof(m_ctl2k_u76)); | |
| 1765 | ||
| 1766 | static const UINT8 cram3k_a37[256] = { | |
| 1767 | /* 0000 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1768 | /* 0020 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1769 | /* 0040 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1770 | /* 0060 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1771 | /* 0100 */ 014,014,014,014,014,014,014,014,014,014,014,014,014,014,014,014, | |
| 1772 | /* 0120 */ 014,014,014,016,014,014,014,004,014,014,014,010,014,014,014,015, | |
| 1773 | /* 0140 */ 015,015,015,015,015,015,015,015,015,015,015,015,015,015,015,015, | |
| 1774 | /* 0160 */ 015,015,015,017,015,015,015,005,015,015,015,011,015,015,015,014, | |
| 1775 | /* 0200 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1776 | /* 0220 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1777 | /* 0240 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1778 | /* 0260 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000, | |
| 1779 | /* 0300 */ 014,014,014,014,014,014,014,014,014,014,014,014,014,014,014,014, | |
| 1780 | /* 0320 */ 014,014,014,016,014,014,014,014,014,014,014,014,014,014,014,015, | |
| 1781 | /* 0340 */ 015,015,015,015,015,015,015,015,015,015,015,015,015,015,015,015, | |
| 1782 | /* 0360 */ 015,015,015,017,015,015,015,015,015,015,015,015,015,015,015,014 | |
| 1783 | }; | |
| 1784 | memcpy(m_cram3k_a37, cram3k_a37, sizeof(m_cram3k_a37)); | |
| 1785 | ||
| 1786 | static const UINT8 madr_a64[256] = { | |
| 1787 | /* 0000 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1788 | /* 0020 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1789 | /* 0040 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1790 | /* 0060 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1791 | /* 0100 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1792 | /* 0120 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1793 | /* 0140 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1794 | /* 0160 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1795 | /* 0200 */ 004,004,004,004,004,004,000,000,004,004,004,004,004,004,004,004, | |
| 1796 | /* 0220 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,004,004,004, | |
| 1797 | /* 0240 */ 004,004,004,004,004,004,000,000,004,004,004,004,004,004,004,004, | |
| 1798 | /* 0260 */ 004,004,004,004,004,004,004,014,004,004,004,004,004,005,004,004, | |
| 1799 | /* 0300 */ 004,004,004,004,004,004,000,000,004,004,004,004,004,004,004,004, | |
| 1800 | /* 0320 */ 004,004,004,004,004,004,006,006,004,004,004,004,004,004,004,004, | |
| 1801 | /* 0340 */ 004,004,004,004,004,004,000,000,004,004,004,004,004,004,004,004, | |
| 1802 | /* 0360 */ 004,004,004,004,004,004,004,004,004,004,004,004,004,005,004,004 | |
| 1803 | }; | |
| 1804 | memcpy(m_madr_a64, madr_a64, sizeof(m_madr_a64)); | |
| 1805 | ||
| 1806 | static const UINT8 madr_a65[256] = { | |
| 1807 | /* 0000 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1808 | /* 0020 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1809 | /* 0040 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1810 | /* 0060 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1811 | /* 0100 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1812 | /* 0120 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1813 | /* 0140 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1814 | /* 0160 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 1815 | /* 0200 */ 007,007,007,007,007,017,007,017,007,007,007,007,007,014,007,014, | |
| 1816 | /* 0220 */ 007,007,007,007,007,015,007,015,007,007,007,007,007,013,007,016, | |
| 1817 | /* 0240 */ 007,007,007,007,007,017,007,017,007,007,007,007,007,014,007,014, | |
| 1818 | /* 0260 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,011,007,016, | |
| 1819 | /* 0300 */ 007,007,007,007,007,017,007,017,007,007,007,007,007,014,007,014, | |
| 1820 | /* 0320 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,012,007,016, | |
| 1821 | /* 0340 */ 007,007,007,007,007,017,007,017,007,007,007,007,007,014,007,014, | |
| 1822 | /* 0360 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,010,007,016 | |
| 1823 | }; | |
| 1824 | memcpy(m_madr_a65, madr_a65, sizeof(m_madr_a65)); | |
| 1825 | ||
| 1826 | /* all tasks start in ROM0 */ | |
| 1827 | m_reset_mode = 0xffff; | |
| 1828 | ||
| 1829 | memset(&m_ram_related, 0, sizeof(m_ram_related)); | |
| 1830 | ||
| 1831 | // install standard handlers in all tasks | |
| 1832 | for (int task = 0; task < ALTO2_TASKS; task++) { | |
| 1833 | ||
| 1834 | // every task starts at mpc = task number, in either ROM0 or RAM0 | |
| 1835 | m_task_mpc[task] = (m_ctl2k_u38[task] >> 4) ^ 017; | |
| 1836 | if (0 == (m_reset_mode & (1 << task))) | |
| 1837 | m_task_mpc[task] |= ALTO2_UCODE_RAM_BASE; | |
| 1838 | ||
| 1839 | set_bs(task, bs_read_r, &alto2_cpu_device::bs_read_r_0, 0); | |
| 1840 | set_bs(task, bs_load_r, &alto2_cpu_device::bs_load_r_0, &alto2_cpu_device::bs_load_r_1); | |
| 1841 | set_bs(task, bs_no_source, 0, 0); | |
| 1842 | set_bs(task, bs_task_3, &alto2_cpu_device::fn_bs_bad_0, &alto2_cpu_device::fn_bs_bad_1); // task specific | |
| 1843 | set_bs(task, bs_task_4, &alto2_cpu_device::fn_bs_bad_0, &alto2_cpu_device::fn_bs_bad_1); // task specific | |
| 1844 | set_bs(task, bs_read_md, &alto2_cpu_device::bs_read_md_0, 0); | |
| 1845 | set_bs(task, bs_mouse, &alto2_cpu_device::bs_mouse_0, 0); | |
| 1846 | set_bs(task, bs_disp, &alto2_cpu_device::bs_disp_0, 0); | |
| 1847 | ||
| 1848 | set_f1(task, f1_nop, 0, 0); | |
| 1849 | set_f1(task, f1_load_mar, 0, &alto2_cpu_device::f1_load_mar_1); | |
| 1850 | set_f1(task, f1_task, &alto2_cpu_device::f1_task_0, 0); | |
| 1851 | set_f1(task, f1_block, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // not all tasks have the f1_block | |
| 1852 | set_f1(task, f1_l_lsh_1, 0, 0); // inlined in execute() | |
| 1853 | set_f1(task, f1_l_rsh_1, 0, 0); // inlined in execute() | |
| 1854 | set_f1(task, f1_l_lcy_8, 0, 0); // inlined in execute() | |
| 1855 | set_f1(task, f1_const, 0, 0); | |
| 1856 | set_f1(task, f1_task_10, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1857 | set_f1(task, f1_task_11, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1858 | set_f1(task, f1_task_12, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1859 | set_f1(task, f1_task_13, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1860 | set_f1(task, f1_task_14, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1861 | set_f1(task, f1_task_15, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1862 | set_f1(task, f1_task_16, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1863 | set_f1(task, f1_task_17, &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1); // f1_task_10 to f1_task_17 are task specific | |
| 1864 | ||
| 1865 | set_f2(task, f2_nop, 0, 0); | |
| 1866 | set_f2(task, f2_bus_eq_zero, 0, &alto2_cpu_device::f2_bus_eq_zero_1); | |
| 1867 | set_f2(task, f2_shifter_lt_zero,0, &alto2_cpu_device::f2_shifter_lt_zero_1); | |
| 1868 | set_f2(task, f2_shifter_eq_zero,0, &alto2_cpu_device::f2_shifter_eq_zero_1); | |
| 1869 | set_f2(task, f2_bus, 0, &alto2_cpu_device::f2_bus_1); | |
| 1870 | set_f2(task, f2_alucy, 0, &alto2_cpu_device::f2_alucy_1); | |
| 1871 | set_f2(task, f2_load_md, 0, &alto2_cpu_device::f2_load_md_1); | |
| 1872 | set_f2(task, f2_const, 0, 0); | |
| 1873 | set_f2(task, f2_task_10, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1874 | set_f2(task, f2_task_11, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1875 | set_f2(task, f2_task_12, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1876 | set_f2(task, f2_task_13, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1877 | set_f2(task, f2_task_14, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1878 | set_f2(task, f2_task_15, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1879 | set_f2(task, f2_task_16, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1880 | set_f2(task, f2_task_17, &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1); // f2_task_10 to f2_task_17 are task specific | |
| 1881 | } | |
| 1882 | ||
| 1883 | init_disk(); | |
| 1884 | init_disp(); | |
| 1885 | ||
| 1886 | init_emu(task_emu); | |
| 1887 | init_001(task_1); | |
| 1888 | init_002(task_2); | |
| 1889 | init_003(task_3); | |
| 1890 | init_ksec(task_ksec); | |
| 1891 | init_005(task_5); | |
| 1892 | init_006(task_6); | |
| 1893 | init_ether(task_ether); | |
| 1894 | init_mrt(task_mrt); | |
| 1895 | init_dwt(task_dwt); | |
| 1896 | init_curt(task_curt); | |
| 1897 | init_dht(task_dht); | |
| 1898 | init_dvt(task_dvt); | |
| 1899 | init_part(task_part); | |
| 1900 | init_kwd(task_kwd); | |
| 1901 | init_017(task_17); | |
| 1902 | ||
| 1903 | install_mmio_fn(0177740, 0177757, &alto2_cpu_device::bank_reg_r, &alto2_cpu_device::bank_reg_w); | |
| 1904 | ||
| 1905 | m_dsp_time = 0; // reset the display state machine values | |
| 1906 | m_dsp_state = 020; | |
| 1907 | ||
| 1908 | m_task = 0; // start with task 0 | |
| 1909 | m_task_wakeup |= 1 << 0; // set wakeup flag | |
| 1910 | } | |
| 1911 | ||
| 1912 | /** @brief software initiated reset (STARTF) */ | |
| 1913 | int alto2_cpu_device::soft_reset() | |
| 1914 | { | |
| 1915 | int task; | |
| 1916 | ||
| 1917 | for (task = 0; task < ALTO2_TASKS; task++) { | |
| 1918 | // every task starts at mpc = task number, in either ROM0 or RAM0 | |
| 1919 | m_task_mpc[task] = (m_ctl2k_u38[task] >> 4) ^ 017; | |
| 1920 | if (0 == (m_reset_mode & (1 << task))) | |
| 1921 | m_task_mpc[task] |= ALTO2_UCODE_RAM_BASE; | |
| 1922 | } | |
| 1923 | m_next2_task = 0; // switch to task 0 | |
| 1924 | m_reset_mode = 0xffff; // all tasks start in ROM0 again | |
| 1925 | ||
| 1926 | m_dsp_time = 0; // reset the display state machine values | |
| 1927 | m_dsp_state = 020; | |
| 1928 | ||
| 1929 | return m_next_task; // return next task (?) | |
| 1930 | } | |
| 1931 | ||
| 1932 | void alto2_cpu_device::init_001(int task) | |
| 1933 | { | |
| 1934 | ||
| 1935 | } | |
| 1936 | ||
| 1937 | void alto2_cpu_device::init_002(int task) | |
| 1938 | { | |
| 1939 | ||
| 1940 | } | |
| 1941 | ||
| 1942 | void alto2_cpu_device::init_003(int task) | |
| 1943 | { | |
| 1944 | ||
| 1945 | } | |
| 1946 | ||
| 1947 | void alto2_cpu_device::init_005(int task) | |
| 1948 | { | |
| 1949 | ||
| 1950 | } | |
| 1951 | ||
| 1952 | void alto2_cpu_device::init_006(int task) | |
| 1953 | { | |
| 1954 | ||
| 1955 | } | |
| 1956 | ||
| 1957 | void alto2_cpu_device::init_017(int task) | |
| 1958 | { | |
| 1959 | ||
| 1960 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII display interface | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** | |
| 13 | * @brief PROM a38 contains the STOPWAKE' and MBEMBPTY' signals for the FIFO | |
| 14 | * <PRE> | |
| 15 | * The inputs to a38 are the UNLOAD counter RA[0-3] and the DDR<- counter | |
| 16 | * WA[0-3], and the designer decided to reverse the address lines :-) | |
| 17 | * | |
| 18 | * a38 counter | |
| 19 | * ------------- | |
| 20 | * A0 RA[0] | |
| 21 | * A1 RA[1] | |
| 22 | * A2 RA[2] | |
| 23 | * A3 RA[3] | |
| 24 | * A4 WA[0] | |
| 25 | * A5 WA[1] | |
| 26 | * A6 WA[2] | |
| 27 | * A7 WA[3] | |
| 28 | * | |
| 29 | * Only two bits of a38 are used: | |
| 30 | * O1 (002) = STOPWAKE' | |
| 31 | * O3 (010) = MBEMPTY' | |
| 32 | * | |
| 33 | * This dump is from PROM displ.a38: | |
| 34 | * 0000: 003,013,015,013,015,013,017,013,015,013,017,013,015,013,017,013, | |
| 35 | * 0020: 013,003,013,015,013,015,013,017,013,015,013,017,013,015,013,017, | |
| 36 | * 0040: 013,015,003,013,013,017,015,013,013,017,015,013,013,017,015,013, | |
| 37 | * 0060: 015,013,013,003,017,013,013,015,017,013,013,015,017,013,013,015, | |
| 38 | * 0100: 013,017,015,013,003,013,015,013,013,017,015,013,015,013,017,013, | |
| 39 | * 0120: 017,013,013,015,013,003,013,015,017,013,013,015,013,015,013,017, | |
| 40 | * 0140: 013,015,013,017,013,015,003,013,013,015,013,017,013,017,015,013, | |
| 41 | * 0160: 015,013,017,013,015,013,013,003,015,013,017,013,017,013,013,015, | |
| 42 | * 0200: 013,017,015,013,015,013,017,013,003,013,015,013,015,013,017,013, | |
| 43 | * 0220: 017,013,013,015,013,015,013,017,013,003,013,015,013,015,013,017, | |
| 44 | * 0240: 013,015,013,017,013,017,015,013,013,015,003,013,013,017,015,013, | |
| 45 | * 0260: 015,013,017,013,017,013,013,015,015,013,013,003,017,013,013,015, | |
| 46 | * 0300: 013,017,015,013,013,017,015,013,013,017,015,013,003,013,015,013, | |
| 47 | * 0320: 017,013,013,015,017,013,013,015,017,013,013,015,013,003,013,015, | |
| 48 | * 0340: 013,015,013,017,013,015,013,017,013,015,013,017,013,015,003,013, | |
| 49 | * 0360: 015,013,017,013,015,013,017,013,015,013,017,013,015,013,013,003 | |
| 50 | * </PRE> | |
| 51 | */ | |
| 52 | ||
| 53 | /** | |
| 54 | * @brief emulation of PROM a63 in the display schematics page 8 | |
| 55 | * <PRE> | |
| 56 | * The PROM's address lines are driven by a clock CLK, which is | |
| 57 | * pixel clock / 24, and an inverted half-scanline signal H[1]'. | |
| 58 | * | |
| 59 | * It is 32x8 bits and its output bits (B) are connected to the | |
| 60 | * signals, as well as its own address lines (A) through a latch | |
| 61 | * of the type SN74774 like this: | |
| 62 | * | |
| 63 | * PROM 174 A others | |
| 64 | * ------------------------ | |
| 65 | * B0 D5 - HBLANK | |
| 66 | * B1 D0 - HSYNC | |
| 67 | * B2 D4 A0 - | |
| 68 | * B3 D1 A1 - | |
| 69 | * B4 D3 A2 - | |
| 70 | * B5 D2 A3 - | |
| 71 | * B6 - - SCANEND | |
| 72 | * B7 - - HLCGATE | |
| 73 | * ------------------------ | |
| 74 | * H[1]' - A4 - | |
| 75 | * | |
| 76 | * The display_state_machine() is called at a rate of pixelclock/24. | |
| 77 | * | |
| 78 | * This dump is from PROM displ.a63: | |
| 79 | * 0000: 0007,0013,0015,0021,0024,0030,0034,0040, | |
| 80 | * 0010: 0044,0050,0054,0060,0064,0070,0074,0200, | |
| 81 | * 0020: 0004,0010,0014,0020,0024,0030,0034,0040, | |
| 82 | * 0030: 0044,0050,0054,0060,0064,0070,0175,0203 | |
| 83 | * | |
| 84 | * Decoded states of this PROM: | |
| 85 | * | |
| 86 | * STATE PROM binary HBLANK HSYNC NEXT SCANEND HLCGATE | |
| 87 | * ---------------------------------------------------------- | |
| 88 | * 000 0007 00000111 1 1 001 0 0 | |
| 89 | * 001 0013 00001011 1 1 002 0 0 | |
| 90 | * 002 0015 00001101 1 0 003 0 0 | |
| 91 | * 003 0021 00010001 1 0 004 0 0 | |
| 92 | * 004 0024 00010100 0 0 005 0 0 | |
| 93 | * 005 0030 00011000 0 0 006 0 0 | |
| 94 | * 006 0034 00011100 0 0 007 0 0 | |
| 95 | * 007 0040 00100000 0 0 010 0 0 | |
| 96 | * 010 0044 00100100 0 0 011 0 0 | |
| 97 | * 011 0050 00101000 0 0 012 0 0 | |
| 98 | * 012 0054 00101100 0 0 013 0 0 | |
| 99 | * 013 0060 00110000 0 0 014 0 0 | |
| 100 | * 014 0064 00110100 0 0 015 0 0 | |
| 101 | * 015 0070 00111000 0 0 016 0 0 | |
| 102 | * 016 0074 00111100 0 0 017 0 0 | |
| 103 | * 017 0200 10000000 0 0 000 0 1 | |
| 104 | * 020 0004 00000100 0 0 001 0 0 | |
| 105 | * 021 0010 00001000 0 0 002 0 0 | |
| 106 | * 022 0014 00001100 0 0 003 0 0 | |
| 107 | * 023 0020 00010000 0 0 004 0 0 | |
| 108 | * 024 0024 00010100 0 0 005 0 0 | |
| 109 | * 025 0030 00011000 0 0 006 0 0 | |
| 110 | * 026 0034 00011100 0 0 007 0 0 | |
| 111 | * 027 0040 00100000 0 0 010 0 0 | |
| 112 | * 030 0044 00100100 0 0 011 0 0 | |
| 113 | * 031 0050 00101000 0 0 012 0 0 | |
| 114 | * 032 0054 00101100 0 0 013 0 0 | |
| 115 | * 033 0060 00110000 0 0 014 0 0 | |
| 116 | * 034 0064 00110100 0 0 015 0 0 | |
| 117 | * 035 0070 00111000 0 0 016 0 0 | |
| 118 | * 036 0175 01111101 1 0 017 1 0 | |
| 119 | * 037 0203 10000011 1 1 000 0 1 | |
| 120 | * </PRE> | |
| 121 | */ | |
| 122 | ||
| 123 | /** | |
| 124 | * @brief PROM a66 is a 256x4 bit (type 3601) | |
| 125 | * <PRE> | |
| 126 | * Address lines are driven by H[1] to H[128] of the the horz. line counters. | |
| 127 | * PROM is enabled when H[256] and H[512] are both 0. | |
| 128 | * | |
| 129 | * Q1 is VSYNC for the odd field (with H1024=0) | |
| 130 | * Q2 is VSYNC for the even field (with H1024=1) | |
| 131 | * Q3 is VBLANK for the odd field (with H1024=0) | |
| 132 | * Q4 is VBLANK for the even field (with H1024=1) | |
| 133 | * | |
| 134 | * This dump is from PROM displ.a66: | |
| 135 | * 0000: 013,013,013,013,013,012,012,012,012,012,012,012,012,013,013,013, | |
| 136 | * 0020: 013,013,013,013,013,013,013,013,013,013,013,013,013,013,013,013, | |
| 137 | * 0040: 013,013,013,013,013,013,013,013,013,013,013,013,013,013,013,013, | |
| 138 | * 0060: 013,013,013,013,013,013,013,013,013,013,013,013,013,013,013,013, | |
| 139 | * 0100: 013,013,013,013,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 140 | * 0120: 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 141 | * 0140: 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 142 | * 0160: 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 143 | * 0200: 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 144 | * 0220: 017,017,017,017,017,017,007,007,007,007,005,005,005,005,005,005, | |
| 145 | * 0240: 005,005,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 146 | * 0260: 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 147 | * 0300: 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 148 | * 0320: 007,007,007,007,007,007,007,007,017,017,017,017,017,017,017,017, | |
| 149 | * 0340: 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 150 | * 0360: 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017 | |
| 151 | * </PRE> | |
| 152 | */ | |
| 153 | ||
| 154 | /** | |
| 155 | * @brief double the bits for a byte (left and right of display word) to a word | |
| 156 | */ | |
| 157 | static const UINT16 double_bits[256] = { | |
| 158 | 0x0000,0x0003,0x000c,0x000f,0x0030,0x0033,0x003c,0x003f, | |
| 159 | 0x00c0,0x00c3,0x00cc,0x00cf,0x00f0,0x00f3,0x00fc,0x00ff, | |
| 160 | 0x0300,0x0303,0x030c,0x030f,0x0330,0x0333,0x033c,0x033f, | |
| 161 | 0x03c0,0x03c3,0x03cc,0x03cf,0x03f0,0x03f3,0x03fc,0x03ff, | |
| 162 | 0x0c00,0x0c03,0x0c0c,0x0c0f,0x0c30,0x0c33,0x0c3c,0x0c3f, | |
| 163 | 0x0cc0,0x0cc3,0x0ccc,0x0ccf,0x0cf0,0x0cf3,0x0cfc,0x0cff, | |
| 164 | 0x0f00,0x0f03,0x0f0c,0x0f0f,0x0f30,0x0f33,0x0f3c,0x0f3f, | |
| 165 | 0x0fc0,0x0fc3,0x0fcc,0x0fcf,0x0ff0,0x0ff3,0x0ffc,0x0fff, | |
| 166 | 0x3000,0x3003,0x300c,0x300f,0x3030,0x3033,0x303c,0x303f, | |
| 167 | 0x30c0,0x30c3,0x30cc,0x30cf,0x30f0,0x30f3,0x30fc,0x30ff, | |
| 168 | 0x3300,0x3303,0x330c,0x330f,0x3330,0x3333,0x333c,0x333f, | |
| 169 | 0x33c0,0x33c3,0x33cc,0x33cf,0x33f0,0x33f3,0x33fc,0x33ff, | |
| 170 | 0x3c00,0x3c03,0x3c0c,0x3c0f,0x3c30,0x3c33,0x3c3c,0x3c3f, | |
| 171 | 0x3cc0,0x3cc3,0x3ccc,0x3ccf,0x3cf0,0x3cf3,0x3cfc,0x3cff, | |
| 172 | 0x3f00,0x3f03,0x3f0c,0x3f0f,0x3f30,0x3f33,0x3f3c,0x3f3f, | |
| 173 | 0x3fc0,0x3fc3,0x3fcc,0x3fcf,0x3ff0,0x3ff3,0x3ffc,0x3fff, | |
| 174 | 0xc000,0xc003,0xc00c,0xc00f,0xc030,0xc033,0xc03c,0xc03f, | |
| 175 | 0xc0c0,0xc0c3,0xc0cc,0xc0cf,0xc0f0,0xc0f3,0xc0fc,0xc0ff, | |
| 176 | 0xc300,0xc303,0xc30c,0xc30f,0xc330,0xc333,0xc33c,0xc33f, | |
| 177 | 0xc3c0,0xc3c3,0xc3cc,0xc3cf,0xc3f0,0xc3f3,0xc3fc,0xc3ff, | |
| 178 | 0xcc00,0xcc03,0xcc0c,0xcc0f,0xcc30,0xcc33,0xcc3c,0xcc3f, | |
| 179 | 0xccc0,0xccc3,0xcccc,0xcccf,0xccf0,0xccf3,0xccfc,0xccff, | |
| 180 | 0xcf00,0xcf03,0xcf0c,0xcf0f,0xcf30,0xcf33,0xcf3c,0xcf3f, | |
| 181 | 0xcfc0,0xcfc3,0xcfcc,0xcfcf,0xcff0,0xcff3,0xcffc,0xcfff, | |
| 182 | 0xf000,0xf003,0xf00c,0xf00f,0xf030,0xf033,0xf03c,0xf03f, | |
| 183 | 0xf0c0,0xf0c3,0xf0cc,0xf0cf,0xf0f0,0xf0f3,0xf0fc,0xf0ff, | |
| 184 | 0xf300,0xf303,0xf30c,0xf30f,0xf330,0xf333,0xf33c,0xf33f, | |
| 185 | 0xf3c0,0xf3c3,0xf3cc,0xf3cf,0xf3f0,0xf3f3,0xf3fc,0xf3ff, | |
| 186 | 0xfc00,0xfc03,0xfc0c,0xfc0f,0xfc30,0xfc33,0xfc3c,0xfc3f, | |
| 187 | 0xfcc0,0xfcc3,0xfccc,0xfccf,0xfcf0,0xfcf3,0xfcfc,0xfcff, | |
| 188 | 0xff00,0xff03,0xff0c,0xff0f,0xff30,0xff33,0xff3c,0xff3f, | |
| 189 | 0xffc0,0xffc3,0xffcc,0xffcf,0xfff0,0xfff3,0xfffc,0xffff | |
| 190 | }; | |
| 191 | ||
| 192 | /** | |
| 193 | * @brief unload the next word from the display FIFO and shift it to the screen | |
| 194 | */ | |
| 195 | int alto2_cpu_device::unload_word(int x) | |
| 196 | { | |
| 197 | UINT32 word, word1, word2; | |
| 198 | int y = ((m_dsp.hlc - m_dsp.vblank) & ~(1024|1)) + HLC1024(); | |
| 199 | ||
| 200 | word = m_dsp.inverse; | |
| 201 | if (FIFO_MBEMPTY_0() == 0) { | |
| 202 | LOG((0,1, " DSP FIFO underrun y:%d x:%d\n", y, x)); | |
| 203 | } else { | |
| 204 | word ^= m_dsp.fifo[m_dsp.fifo_rd]; | |
| 205 | m_dsp.fifo_rd = (m_dsp.fifo_rd + 1) % ALTO2_DISPLAY_FIFO; | |
| 206 | LOG((0,3, " DSP pull %04x from FIFO[%02o] y:%d x:%d\n", | |
| 207 | word, (m_dsp.fifo_rd - 1) & (ALTO2_DISPLAY_FIFO - 1), y, x)); | |
| 208 | } | |
| 209 | ||
| 210 | if (y >= 0 && y < ALTO2_DISPLAY_HEIGHT && x < ALTO2_DISPLAY_VISIBLE_WORDS) { | |
| 211 | if (m_dsp.halfclock) { | |
| 212 | word1 = double_bits[word / 256]; | |
| 213 | word2 = double_bits[word % 256]; | |
| 214 | /* mixing with the cursor */ | |
| 215 | if (x == m_dsp.curword + 0) | |
| 216 | word1 ^= m_dsp.curdata >> 16; | |
| 217 | if (x == m_dsp.curword + 1) | |
| 218 | word1 ^= m_dsp.curdata & 0177777; | |
| 219 | if (word1 != m_dsp.raw_bitmap[y * ALTO2_DISPLAY_SCANLINE_WORDS + x]) { | |
| 220 | m_dsp.raw_bitmap[y * ALTO2_DISPLAY_SCANLINE_WORDS + x] = word1; | |
| 221 | // sdl_write(x * 16, y, word1); // FIXME: invalidate bitmap word | |
| 222 | } | |
| 223 | x++; | |
| 224 | if (x < ALTO2_DISPLAY_VISIBLE_WORDS) { | |
| 225 | /* mixing with the cursor */ | |
| 226 | if (x == m_dsp.curword + 0) | |
| 227 | word2 ^= m_dsp.curdata >> 16; | |
| 228 | if (x == m_dsp.curword + 1) | |
| 229 | word2 ^= m_dsp.curdata & 0177777; | |
| 230 | if (word2 != m_dsp.raw_bitmap[y * ALTO2_DISPLAY_SCANLINE_WORDS + x]) { | |
| 231 | m_dsp.raw_bitmap[y * ALTO2_DISPLAY_SCANLINE_WORDS + x] = word2; | |
| 232 | // sdl_write(x * 16, y, word2); // FIXME: invalidate bitmap word | |
| 233 | } | |
| 234 | x++; | |
| 235 | } | |
| 236 | } else { | |
| 237 | /* mixing with the cursor */ | |
| 238 | if (x == m_dsp.curword + 0) | |
| 239 | word ^= m_dsp.curdata >> 16; | |
| 240 | if (x == m_dsp.curword + 1) | |
| 241 | word ^= m_dsp.curdata & 0177777; | |
| 242 | if (word != m_dsp.raw_bitmap[y * ALTO2_DISPLAY_SCANLINE_WORDS + x]) { | |
| 243 | m_dsp.raw_bitmap[y * ALTO2_DISPLAY_SCANLINE_WORDS + x] = word; | |
| 244 | // sdl_write(x * 16, y, word); // FIXME: invalidate bitmap word | |
| 245 | } | |
| 246 | x++; | |
| 247 | } | |
| 248 | } | |
| 249 | ||
| 250 | if (x < ALTO2_DISPLAY_VISIBLE_WORDS) { | |
| 251 | m_unload_time += ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16); | |
| 252 | return x; | |
| 253 | } | |
| 254 | ||
| 255 | m_unload_time = -1; | |
| 256 | return -1; | |
| 257 | } | |
| 258 | ||
| 259 | ||
| 260 | /** | |
| 261 | * @brief function called by the CPU to enter the next display state | |
| 262 | * | |
| 263 | * There are 32 states per scanline and 875 scanlines per frame. | |
| 264 | * | |
| 265 | * @param arg the current displ_a63 PROM address | |
| 266 | * @result returns the next state of the display state machine | |
| 267 | */ | |
| 268 | int alto2_cpu_device::display_state_machine(int arg) | |
| 269 | { | |
| 270 | int next, a63, a66; | |
| 271 | ||
| 272 | LOG((0,5,"DSP%03o:", arg)); | |
| 273 | if (020 == arg) { | |
| 274 | LOG((0,2," HLC=%d", m_dsp.hlc)); | |
| 275 | } | |
| 276 | ||
| 277 | a63 = m_disp_a63[arg]; | |
| 278 | ||
| 279 | if (A2_HLCGATE_HI(a63)) { | |
| 280 | /* reset or count horizontal line counters */ | |
| 281 | if (m_dsp.hlc == ALTO2_DISPLAY_HLC_END) | |
| 282 | m_dsp.hlc = ALTO2_DISPLAY_HLC_START; | |
| 283 | else | |
| 284 | m_dsp.hlc++; | |
| 285 | /* start the refresh task _twice_ on each scanline */ | |
| 286 | m_task_wakeup |= 1 << task_mrt; | |
| 287 | if (m_ewfct) { | |
| 288 | /* The Ether task wants a wakeup, too */ | |
| 289 | m_task_wakeup |= 1 << task_ether; | |
| 290 | } | |
| 291 | } | |
| 292 | if (HLC256() || HLC512()) { | |
| 293 | // PROM a66 is disabled, if any of HLC256 or HLC512 are high | |
| 294 | a66 = 017; | |
| 295 | } else { | |
| 296 | // PROM a66 address lines are connected the HLC1 to HLC128 signals | |
| 297 | a66 = m_disp_a66[m_dsp.hlc & 0377]; | |
| 298 | } | |
| 299 | ||
| 300 | // next address from PROM a63, use A4 from HLC1 | |
| 301 | next = (16 * (HLC1() ^ 1)) | A63_NEXT(a63); | |
| 302 | ||
| 303 | if (A2_VBLANK_HI(a66)) { | |
| 304 | /* VBLANK: remember hlc */ | |
| 305 | m_dsp.vblank = m_dsp.hlc | 1; | |
| 306 | ||
| 307 | LOG((0,1, " VBLANK")); | |
| 308 | ||
| 309 | /* VSYNC is always within VBLANK */ | |
| 310 | if (A2_VSYNC_HI(a66)) { | |
| 311 | if (A2_VSYNC_LO(m_dsp.a66)) { | |
| 312 | LOG((0,1, " VSYNC/ (wake DVT)")); | |
| 313 | /* | |
| 314 | * The display vertical task DVT is awakened once per field, | |
| 315 | * at the beginning of vertical retrace. | |
| 316 | */ | |
| 317 | m_task_wakeup |= 1 << task_dvt; | |
| 318 | // sdl_update(HLC1024()); // FIXME: upade odd or even field | |
| 319 | } else { | |
| 320 | LOG((0,1, " VSYNC")); | |
| 321 | } | |
| 322 | } | |
| 323 | } else { | |
| 324 | if (A2_VBLANK_HI(m_dsp.a66)) { | |
| 325 | /** | |
| 326 | * VBLANKPULSE: | |
| 327 | * The display horizontal task DHT is awakened once at the | |
| 328 | * beginning of each field, and thereafter whenever the | |
| 329 | * display word task blocks. | |
| 330 | * The DHT can block itself, in which case neither it nor | |
| 331 | * the word task can be awakened until the start of the | |
| 332 | * next field. | |
| 333 | */ | |
| 334 | LOG((0,1, " VBLANKPULSE (wake DHT)")); | |
| 335 | m_dsp.dht_blocks = 0; | |
| 336 | m_dsp.dwt_blocks = 0; | |
| 337 | m_task_wakeup |= 1 << task_dht; | |
| 338 | /* | |
| 339 | * VBLANKPULSE also resets the cursor task block flip flop, | |
| 340 | * which is built from two NAND gates a40c and a40d (74H01). | |
| 341 | */ | |
| 342 | m_dsp.curt_blocks = 0; | |
| 343 | } | |
| 344 | if (A2_HBLANK_LO(a63) && A2_HBLANK_HI(m_dsp.a63)) { | |
| 345 | /* falling edge of a63 HBLANK starts unload */ | |
| 346 | LOG((0,1, " HBLANK\\ UNLOAD")); | |
| 347 | m_unload_time = ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16); | |
| 348 | m_unload_word = 0; | |
| 349 | #if DEBUG_DISPLAY_TIMING | |
| 350 | printf("@%lld: first unload_word @%lldns hlc:+%d (id:%d)\n", | |
| 351 | ntime(), ntime() + DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16), | |
| 352 | m_dsp.hlc - DISPLAY_HLC_START, m_dsp.unload_id); | |
| 353 | #endif | |
| 354 | } | |
| 355 | } | |
| 356 | ||
| 357 | /* | |
| 358 | * The wakeup request for the display word task (DWT) is controlled by | |
| 359 | * the state of the 16 word buffer. If DWT has not executed a BLOCK, | |
| 360 | * if DHT is not blocked, and if the buffer is not full, DWT wakeups | |
| 361 | * are generated. | |
| 362 | */ | |
| 363 | if (!m_dsp.dwt_blocks && !m_dsp.dht_blocks && FIFO_STOPWAKE_0() != 0) { | |
| 364 | if (!(m_task_wakeup & (1 << task_dwt))) { | |
| 365 | m_task_wakeup |= 1 << task_dwt; | |
| 366 | LOG((0,1, " (wake DWT)")); | |
| 367 | } | |
| 368 | } | |
| 369 | ||
| 370 | if (A2_SCANEND_HI(a63)) { | |
| 371 | LOG((0,1, " SCANEND")); | |
| 372 | m_task_wakeup &= ~(1 << task_dwt); | |
| 373 | } | |
| 374 | ||
| 375 | LOG((0,1, "%s", (a63 & A63_HBLANK) ? " HBLANK": "")); | |
| 376 | ||
| 377 | if (A2_HSYNC_HI(a63)) { | |
| 378 | if (A2_HSYNC_LO(m_dsp.a63)) { | |
| 379 | LOG((0,1, " HSYNC/ (CLRBUF)")); | |
| 380 | /* | |
| 381 | * The hardware sets the buffer empty and clears the DWT block | |
| 382 | * flip-flop at the beginning of horizontal retrace for | |
| 383 | * every scanline. | |
| 384 | */ | |
| 385 | m_dsp.fifo_wr = 0; | |
| 386 | m_dsp.fifo_rd = 0; | |
| 387 | m_dsp.dwt_blocks = 0; | |
| 388 | /* now take the new values from the last setmode */ | |
| 389 | m_dsp.inverse = GET_SETMODE_INVERSE(m_dsp.setmode) ? 0xffff : 0x0000; | |
| 390 | m_dsp.halfclock = GET_SETMODE_SPEEDY(m_dsp.setmode); | |
| 391 | /* stop the CPU from calling unload_word() */ | |
| 392 | m_unload_time = -1; | |
| 393 | } else { | |
| 394 | LOG((0,1, " HSYNC")); | |
| 395 | } | |
| 396 | } else if (A2_HSYNC_HI(m_dsp.a63)) { | |
| 397 | /* | |
| 398 | * CLRBUF' also resets the 2nd cursor task block flip flop, | |
| 399 | * which is built from two NAND gates a30c and a30d (74H00). | |
| 400 | * If both flip flops are reset, the NOR gate a20d (74S02) | |
| 401 | * decodes this as WAKECURT signal. | |
| 402 | */ | |
| 403 | m_dsp.curt_wakeup = 1; | |
| 404 | } | |
| 405 | ||
| 406 | if (!m_dsp.curt_blocks && m_dsp.curt_wakeup) { | |
| 407 | m_task_wakeup |= 1 << task_curt; | |
| 408 | } | |
| 409 | ||
| 410 | ||
| 411 | LOG((0,1, " NEXT:%03o\n", next)); | |
| 412 | ||
| 413 | m_dsp.a63 = a63; | |
| 414 | m_dsp.a66 = a66; | |
| 415 | ||
| 416 | return next; | |
| 417 | } | |
| 418 | ||
| 419 | /** | |
| 420 | * @brief f2_evenfield late: branch on evenfield | |
| 421 | * | |
| 422 | * NEXT(09) = even field ? 1 : 0 | |
| 423 | */ | |
| 424 | void alto2_cpu_device::f2_evenfield_1() | |
| 425 | { | |
| 426 | UINT16 r = HLC1024() ^ 1; | |
| 427 | LOG((0,2," evenfield branch on HLC1024 (%#o | %#o)\n", cpu.next2, r)); | |
| 428 | m_next2 |= r; | |
| 429 | } | |
| 430 | ||
| 431 | /** | |
| 432 | * @brief initialize the display context to useful values | |
| 433 | * | |
| 434 | * Zap the display context to all 0s. | |
| 435 | * Allocate a raw_bitmap array to save blitting to the screen when | |
| 436 | * there is no change in the data words. | |
| 437 | */ | |
| 438 | int alto2_cpu_device::init_disp() | |
| 439 | { | |
| 440 | int y; | |
| 441 | ||
| 442 | UINT8 disp_a38[256] = { | |
| 443 | /* 0000 */ 003,013,015,013,015,013,017,013,015,013,017,013,015,013,017,013, | |
| 444 | /* 0020 */ 013,003,013,015,013,015,013,017,013,015,013,017,013,015,013,017, | |
| 445 | /* 0040 */ 013,015,003,013,013,017,015,013,013,017,015,013,013,017,015,013, | |
| 446 | /* 0060 */ 015,013,013,003,017,013,013,015,017,013,013,015,017,013,013,015, | |
| 447 | /* 0100 */ 013,017,015,013,003,013,015,013,013,017,015,013,015,013,017,013, | |
| 448 | /* 0120 */ 017,013,013,015,013,003,013,015,017,013,013,015,013,015,013,017, | |
| 449 | /* 0140 */ 013,015,013,017,013,015,003,013,013,015,013,017,013,017,015,013, | |
| 450 | /* 0160 */ 015,013,017,013,015,013,013,003,015,013,017,013,017,013,013,015, | |
| 451 | /* 0200 */ 013,017,015,013,015,013,017,013,003,013,015,013,015,013,017,013, | |
| 452 | /* 0220 */ 017,013,013,015,013,015,013,017,013,003,013,015,013,015,013,017, | |
| 453 | /* 0240 */ 013,015,013,017,013,017,015,013,013,015,003,013,013,017,015,013, | |
| 454 | /* 0260 */ 015,013,017,013,017,013,013,015,015,013,013,003,017,013,013,015, | |
| 455 | /* 0300 */ 013,017,015,013,013,017,015,013,013,017,015,013,003,013,015,013, | |
| 456 | /* 0320 */ 017,013,013,015,017,013,013,015,017,013,013,015,013,003,013,015, | |
| 457 | /* 0340 */ 013,015,013,017,013,015,013,017,013,015,013,017,013,015,003,013, | |
| 458 | /* 0360 */ 015,013,017,013,015,013,017,013,015,013,017,013,015,013,013,003 | |
| 459 | }; | |
| 460 | memcpy(m_disp_a38, disp_a38, sizeof(m_disp_a38)); | |
| 461 | ||
| 462 | UINT8 disp_a63[32] = { | |
| 463 | /* 0000 */ 0007,0013,0015,0021,0024,0030,0034,0040, | |
| 464 | /* 0010 */ 0044,0050,0054,0060,0064,0070,0074,0200, | |
| 465 | /* 0020 */ 0004,0010,0014,0020,0024,0030,0034,0040, | |
| 466 | /* 0030 */ 0044,0050,0054,0060,0064,0070,0175,0203 | |
| 467 | }; | |
| 468 | memcpy(m_disp_a63, disp_a63, sizeof(m_disp_a63)); | |
| 469 | ||
| 470 | UINT8 disp_a66[256] = { | |
| 471 | /* 0000 */ 013,013,013,013,013,012,012,012,012,012,012,012,012,013,013,013, | |
| 472 | /* 0020 */ 013,013,013,013,013,013,013,013,013,013,013,013,013,013,013,013, | |
| 473 | /* 0040 */ 013,013,013,013,013,013,013,013,013,013,013,013,013,013,013,013, | |
| 474 | /* 0060 */ 013,013,013,013,013,013,013,013,013,013,013,013,013,013,013,013, | |
| 475 | /* 0100 */ 013,013,013,013,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 476 | /* 0120 */ 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 477 | /* 0140 */ 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 478 | /* 0160 */ 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 479 | /* 0200 */ 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 480 | /* 0220 */ 017,017,017,017,017,017,007,007,007,007,005,005,005,005,005,005, | |
| 481 | /* 0240 */ 005,005,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 482 | /* 0260 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 483 | /* 0300 */ 007,007,007,007,007,007,007,007,007,007,007,007,007,007,007,007, | |
| 484 | /* 0320 */ 007,007,007,007,007,007,007,007,017,017,017,017,017,017,017,017, | |
| 485 | /* 0340 */ 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017, | |
| 486 | /* 0360 */ 017,017,017,017,017,017,017,017,017,017,017,017,017,017,017,017 | |
| 487 | }; | |
| 488 | memcpy(m_disp_a66, disp_a66, sizeof(m_disp_a66)); | |
| 489 | ||
| 490 | memset(&m_dsp, 0, sizeof(m_dsp)); | |
| 491 | m_dsp.hlc = ALTO2_DISPLAY_HLC_START; | |
| 492 | m_dsp.raw_bitmap = (UINT16*)malloc(ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS * sizeof(UINT16)); | |
| 493 | if (NULL == m_dsp.raw_bitmap) | |
| 494 | return -1; | |
| 495 | ||
| 496 | for (y = 0; y < ALTO2_DISPLAY_HEIGHT; y++) | |
| 497 | memset(m_dsp.raw_bitmap + y * ALTO2_DISPLAY_SCANLINE_WORDS, 0x55, ALTO2_DISPLAY_VISIBLE_WORDS * sizeof(UINT16)); | |
| 498 | ||
| 499 | return 0; | |
| 500 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /********************************************************** | |
| 2 | * Portable Xerox AltoII disassembler | |
| 3 | * | |
| 4 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 5 | * | |
| 6 | * Licenses: MAME, GPLv2 | |
| 7 | **********************************************************/ | |
| 8 | #include "alto2.h" | |
| 9 | ||
| 10 | #define loc_DASTART 0000420 // display list header | |
| 11 | #define loc_DVIBITS 0000421 // display vertical field interrupt bitword | |
| 12 | #define loc_ITQUAN 0000422 // interval timer stored quantity | |
| 13 | #define loc_ITBITS 0000423 // interval timer bitword | |
| 14 | #define loc_MOUSEX 0000424 // mouse X coordinate | |
| 15 | #define loc_MOUSEY 0000425 // mouse Y coordinate | |
| 16 | #define loc_CURSORX 0000426 // cursor X coordinate | |
| 17 | #define loc_CURSORY 0000427 // cursor Y coordinate | |
| 18 | #define loc_RTC 0000430 // real time clock | |
| 19 | #define loc_CURMAP 0000431 // cursor bitmap (16 words up to 00450) | |
| 20 | #define loc_WW 0000452 // interrupt wakeups waiting | |
| 21 | #define loc_ACTIVE 0000453 // active interrupt bitword | |
| 22 | #define loc_MASKTAB 0000460 // mask table for convert | |
| 23 | #define loc_PCLOC 0000500 // saved interrupt PC | |
| 24 | #define loc_INTVEC 0000501 // interrupt transfer vector (15 words up to 00517) | |
| 25 | #define loc_KBLK 0000521 // disk command block address | |
| 26 | #define loc_KSTAT 0000522 // disk status at start of current sector | |
| 27 | #define loc_KADDR 0000523 // disk address of latest disk command | |
| 28 | #define loc_KSIBITS 0000524 // sector interrupt bit mask | |
| 29 | #define loc_ITTIME 0000525 // interval timer timer | |
| 30 | #define loc_TRAPPC 0000527 // trap saved PC | |
| 31 | #define loc_TRAPVEC 0000530 // trap vectors (up to 0567) | |
| 32 | #define loc_TIMERDATA 0000570 // timer data (OS; up to 0577) | |
| 33 | #define loc_EPLOC 0000600 // ethernet post location | |
| 34 | #define loc_EBLOC 0000601 // ethernet interrupt bitmask | |
| 35 | #define loc_EELOC 0000602 // ethernet ending count | |
| 36 | #define loc_ELLOC 0000603 // ethernet load location | |
| 37 | #define loc_EICLOC 0000604 // ethernet input buffer count | |
| 38 | #define loc_EIPLOC 0000605 // ethernet input buffer pointer | |
| 39 | #define loc_EOCLOC 0000606 // ethernet output buffer count | |
| 40 | #define loc_EOPLOC 0000607 // ethernet output buffer pointer | |
| 41 | #define loc_EHLOC 0000610 // ethernet host address | |
| 42 | #define loc_ERSVD 0000611 // reserved for ethernet expansion (up to 00612) | |
| 43 | #define loc_ALTOV 0000613 // Alto I/II indication that microcode caninterrogate (0 = Alto I, -1 = Alto II) | |
| 44 | #define loc_DCBR 0000614 // posted by parity task (main memory parity error) | |
| 45 | #define loc_KNMAR 0000615 // -"- | |
| 46 | #define loc_DWA 0000616 // -"- | |
| 47 | #define loc_CBA 0000617 // -"- | |
| 48 | #define loc_PC 0000620 // -"- | |
| 49 | #define loc_SAD 0000621 // -"- | |
| 50 | #define loc_SWATR 0000700 // saved registers (Swat; up to 00707) | |
| 51 | #define loc_UTILOUT 0177016 // printer output (up to 177017) | |
| 52 | #define loc_XBUS 0177020 // untility input bus (up to 177023) | |
| 53 | #define loc_MEAR 0177024 // memory error address register | |
| 54 | #define loc_MESR 0177025 // memory error status register | |
| 55 | #define loc_MECR 0177026 // memory error control register | |
| 56 | #define loc_UTILIN 0177030 // printer status, mouse keyset | |
| 57 | #define loc_KBDAD 0177034 // undecoded keyboard (up to 177037) | |
| 58 | #define loc_BANKREGS 0177740 // extended memory option bank registers | |
| 59 | ||
| 60 | /** | |
| 61 | * @brief Microcode and constants PROM size | |
| 62 | */ | |
| 63 | #define MCODE_PAGE 1024 | |
| 64 | #define MCODE_SIZE (2*MCODE_PAGE) /* Alto II may have 2 pages (or even 4?) */ | |
| 65 | #define MCODE_MASK (MCODE_SIZE - 1) | |
| 66 | #define PROM_SIZE 256 | |
| 67 | ||
| 68 | /** | |
| 69 | * @brief short names for the 16 tasks | |
| 70 | */ | |
| 71 | static const char *taskname[16] = { | |
| 72 | "EMU", // emulator task | |
| 73 | "T01", | |
| 74 | "T02", | |
| 75 | "T03", | |
| 76 | "DSC", // disk sector task | |
| 77 | "T05", | |
| 78 | "T06", | |
| 79 | "ETH", // ethernet task | |
| 80 | "MRT", // memory refresh task | |
| 81 | "DWT", // display word task | |
| 82 | "CUR", // cursor task | |
| 83 | "DHT", // display horizontal task | |
| 84 | "DVT", // display vertical task | |
| 85 | "PAR", // parity task | |
| 86 | "DWD", // disk word task | |
| 87 | "T17" | |
| 88 | }; | |
| 89 | ||
| 90 | /** | |
| 91 | * @brief names for the 32 R registers | |
| 92 | */ | |
| 93 | static const char *regname[32] = { | |
| 94 | "AC(3)", // emulator accu 3 | |
| 95 | "AC(2)", // emulator accu 2 | |
| 96 | "AC(1)", // emulator accu 1 | |
| 97 | "AC(0)", // emulator accu 0 | |
| 98 | "R04", | |
| 99 | "R05", | |
| 100 | "PC", // emulator program counter | |
| 101 | "R07", | |
| 102 | "R10", | |
| 103 | "R11", | |
| 104 | "R12", | |
| 105 | "R13", | |
| 106 | "R14", | |
| 107 | "R15", | |
| 108 | "R16", | |
| 109 | "R17", | |
| 110 | "R20", | |
| 111 | "R21", | |
| 112 | "CBA", // address of the currently active DCB+1 | |
| 113 | "AECL", // address of end of current scanline's bitmap | |
| 114 | "SLC", // scan line count | |
| 115 | "HTAB", // number of tab words remaining on current scanline | |
| 116 | "DWA", // address of the bit map double word being fetched | |
| 117 | "MTEMP", // temporary cell | |
| 118 | "R30", | |
| 119 | "R31", | |
| 120 | "R32", | |
| 121 | "R33", | |
| 122 | "R34", | |
| 123 | "R35", | |
| 124 | "R36", | |
| 125 | "R37" | |
| 126 | }; | |
| 127 | ||
| 128 | /** | |
| 129 | * @brief copy of the constant PROM, which this disassembler may not have access to | |
| 130 | */ | |
| 131 | static UINT16 const_prom[PROM_SIZE] = { | |
| 132 | /* 0000 */ 0x0000, 0x0001, 0x0002, 0xfffe, 0xffff, 0xffff, 0x000f, 0xffff, | |
| 133 | /* 0008 */ 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0xfff8, 0xfff8, | |
| 134 | /* 0010 */ 0x0010, 0x001f, 0x0020, 0x003f, 0x0040, 0x007f, 0x0080, 0x0007, | |
| 135 | /* 0018 */ 0x00ff, 0xff00, 0x0400, 0x0100, 0x0110, 0x0151, 0x0114, 0x000f, | |
| 136 | /* 0020 */ 0x0116, 0x0118, 0x0ffa, 0xf000, 0x4000, 0xfffc, 0xfff6, 0xffeb, | |
| 137 | /* 0028 */ 0x4800, 0x6c00, 0x0800, 0x1000, 0xfe00, 0x7fff, 0x7fe0, 0x7f00, | |
| 138 | /* 0030 */ 0xffbd, 0x0f00, 0x0f0f, 0xf0f0, 0x6048, 0x3000, 0x7159, 0x2109, | |
| 139 | /* 0038 */ 0x6a3c, 0x4213, 0xa5a5, 0xfe1c, 0x3f00, 0xffc0, 0x012a, 0x0140, | |
| 140 | /* 0040 */ 0x8000, 0xffe0, 0x00bf, 0xfff9, 0xfff0, 0xfffd, 0x0970, 0x5d20, | |
| 141 | /* 0048 */ 0x3844, 0x6814, 0xfc00, 0xfe20, 0xfe22, 0x0083, 0x00f0, 0xff80, | |
| 142 | /* 0050 */ 0xf800, 0xe000, 0xc000, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, | |
| 143 | /* 0058 */ 0x3fff, 0x0200, 0x2000, 0xfff1, 0x0156, 0x0157, 0x0138, 0x0c00, | |
| 144 | /* 0060 */ 0x0130, 0x1813, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, | |
| 145 | /* 0068 */ 0x0186, 0x0187, 0x0188, 0x018a, 0x0112, 0x0113, 0x0102, 0xfff0, | |
| 146 | /* 0070 */ 0x0153, 0x0154, 0xffef, 0xffe4, 0xfffb, 0x000a, 0xffc1, 0x001f, | |
| 147 | /* 0078 */ 0x0e00, 0x007e, 0xff7e, 0x0018, 0x000d, 0x03f8, 0x83f9, 0xffe0, | |
| 148 | /* 0080 */ 0xfbff, 0x0009, 0x000b, 0x000c, 0x000e, 0x0030, 0x01fe, 0xff7f, | |
| 149 | /* 0088 */ 0x81ff, 0xffbf, 0xffcc, 0x0557, 0x0041, 0x0198, 0x0199, 0x01a2, | |
| 150 | /* 0090 */ 0xfe72, 0xfe58, 0x0012, 0x0014, 0x00dd, 0x02ff, 0x0101, 0x0001, | |
| 151 | /* 0098 */ 0x0401, 0x0011, 0x0013, 0x0015, 0x0016, 0x0017, 0x0019, 0x0003, | |
| 152 | /* 00a0 */ 0x03bd, 0x01de, 0xfe50, 0x00c0, 0x0c01, 0x6200, 0x6300, 0x0008, | |
| 153 | /* 00a8 */ 0x6400, 0x6500, 0x6e00, 0x6700, 0x6900, 0x6d00, 0x6600, 0x000c, | |
| 154 | /* 00b0 */ 0x6b00, 0x6b01, 0x6b02, 0x6b03, 0x6b04, 0x6b05, 0x6b06, 0x0010, | |
| 155 | /* 00b8 */ 0x6b07, 0x6b08, 0x6b09, 0x6b0a, 0x6b0b, 0x6b0c, 0x6b0d, 0x0020, | |
| 156 | /* 00c0 */ 0x6b0e, 0x6b0f, 0xfff3, 0xfe14, 0xfe15, 0xfe16, 0x0ffc, 0x0040, | |
| 157 | /* 00c8 */ 0x04ff, 0x05ff, 0x06ff, 0x013f, 0x017e, 0xfe7d, 0xffff, 0x0080, | |
| 158 | /* 00d0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00c0, | |
| 159 | /* 00d8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00ff, | |
| 160 | /* 00e0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, | |
| 161 | /* 00e8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, | |
| 162 | /* 00f0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, | |
| 163 | /* 00f8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff | |
| 164 | }; | |
| 165 | ||
| 166 | /** | |
| 167 | * @brief print a symbolic name for an mpc address | |
| 168 | * | |
| 169 | * @param a microcode address (mpc) | |
| 170 | * @return pointer to const string with the address or symbolic name | |
| 171 | */ | |
| 172 | static const char *addrname(int a) | |
| 173 | { | |
| 174 | static char buffer[4][32]; | |
| 175 | static int which = 0; | |
| 176 | char *dst; | |
| 177 | ||
| 178 | which = (which + 1) % 4; | |
| 179 | dst = buffer[which]; | |
| 180 | ||
| 181 | if (a < 020) { | |
| 182 | // start value for mpc per task is the task number | |
| 183 | snprintf(dst, sizeof(buffer[0]), "→%s", taskname[a]); | |
| 184 | } else { | |
| 185 | snprintf(dst, sizeof(buffer[0]), "%04o", a); | |
| 186 | } | |
| 187 | return dst; | |
| 188 | } | |
| 189 | ||
| 190 | offs_t alto2_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) | |
| 191 | { | |
| 192 | const UINT8* src; | |
| 193 | size_t len = 128; | |
| 194 | ||
| 195 | src = oprom + 4 * pc; | |
| 196 | UINT32 mir = (static_cast<UINT32>(src[0]) << 24) | | |
| 197 | (static_cast<UINT32>(src[1]) << 16) | | |
| 198 | (static_cast<UINT32>(src[2]) << 8) | | |
| 199 | (static_cast<UINT32>(src[3])); | |
| 200 | UINT8 rsel = static_cast<UINT8>((mir >> 27) & 31); | |
| 201 | UINT8 aluf = static_cast<UINT8>((mir >> 23) & 15); | |
| 202 | UINT8 bs = static_cast<UINT8>((mir >> 20) & 7); | |
| 203 | UINT8 f1 = static_cast<UINT8>((mir >> 16) & 15); | |
| 204 | UINT8 f2 = static_cast<UINT8>((mir >> 12) & 15); | |
| 205 | UINT8 t = static_cast<UINT8>((mir >> 11) & 1); | |
| 206 | UINT8 l = static_cast<UINT8>((mir >> 10) & 1); | |
| 207 | offs_t next = static_cast<offs_t>(mir & 1023); | |
| 208 | src = oprom + 4 * next; | |
| 209 | UINT32 next2 = (static_cast<UINT32>(src[0]) << 24) | | |
| 210 | (static_cast<UINT32>(src[1]) << 16) | | |
| 211 | (static_cast<UINT32>(src[2]) << 8) | | |
| 212 | (static_cast<UINT32>(src[3])); | |
| 213 | UINT16 prefetch = next2 & 1023; | |
| 214 | char *dst = buffer; | |
| 215 | int pa; | |
| 216 | ||
| 217 | switch (aluf) { | |
| 218 | case 0: // T?: BUS | |
| 219 | if (t) | |
| 220 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 221 | if (l) | |
| 222 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 223 | if (bs == 1) | |
| 224 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 225 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS) "); | |
| 226 | break; | |
| 227 | case 1: // : T | |
| 228 | if (t) | |
| 229 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 230 | if (l) | |
| 231 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 232 | if (bs == 1) | |
| 233 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 234 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(T) "); | |
| 235 | break; | |
| 236 | case 2: // T?: BUS OR T | |
| 237 | if (t) | |
| 238 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 239 | if (l) | |
| 240 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 241 | if (bs == 1) | |
| 242 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 243 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS OR T) "); | |
| 244 | break; | |
| 245 | case 3: // : BUS AND T | |
| 246 | if (t) | |
| 247 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 248 | if (l) | |
| 249 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 250 | if (bs == 1) | |
| 251 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 252 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS AND T) "); | |
| 253 | break; | |
| 254 | case 4: // : BUS XOR T | |
| 255 | if (t) | |
| 256 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 257 | if (l) | |
| 258 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 259 | if (bs == 1) | |
| 260 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 261 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS XOR T) "); | |
| 262 | break; | |
| 263 | case 5: // T?: BUS + 1 | |
| 264 | if (t) | |
| 265 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 266 | if (l) | |
| 267 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 268 | if (bs == 1) | |
| 269 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 270 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS + 1) "); | |
| 271 | break; | |
| 272 | case 6: // T?: BUS - 1 | |
| 273 | if (t) | |
| 274 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 275 | if (l) | |
| 276 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 277 | if (bs == 1) | |
| 278 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 279 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS - 1) "); | |
| 280 | break; | |
| 281 | case 7: // : BUS + T | |
| 282 | if (t) | |
| 283 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 284 | if (l) | |
| 285 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 286 | if (bs == 1) | |
| 287 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 288 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS + T) "); | |
| 289 | break; | |
| 290 | case 8: // : BUS - T | |
| 291 | if (t) | |
| 292 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 293 | if (l) | |
| 294 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 295 | if (bs == 1) | |
| 296 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 297 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS - T) "); | |
| 298 | break; | |
| 299 | case 9: // : BUS - T - 1 | |
| 300 | if (t) | |
| 301 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 302 | if (l) | |
| 303 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 304 | if (bs == 1) | |
| 305 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 306 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS - T - 1) "); | |
| 307 | break; | |
| 308 | case 10: // T?: BUS + T + 1 | |
| 309 | if (t) | |
| 310 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 311 | if (l) | |
| 312 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 313 | if (bs == 1) | |
| 314 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 315 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS + T + 1) "); | |
| 316 | break; | |
| 317 | case 11: // T?: BUS + SKIP | |
| 318 | if (t) | |
| 319 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 320 | if (l) | |
| 321 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 322 | if (bs == 1) | |
| 323 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 324 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS + SKIP) "); | |
| 325 | break; | |
| 326 | case 12: // T?: BUS, T (AND) | |
| 327 | if (t) | |
| 328 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←ALU "); | |
| 329 | if (l) | |
| 330 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 331 | if (bs == 1) | |
| 332 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 333 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS AND T) "); | |
| 334 | break; | |
| 335 | case 13: // : BUS AND NOT T | |
| 336 | if (t) | |
| 337 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 338 | if (l) | |
| 339 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 340 | if (bs == 1) | |
| 341 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 342 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS AND NOT T) "); | |
| 343 | break; | |
| 344 | case 14: // : undefined | |
| 345 | if (t) | |
| 346 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 347 | if (l) | |
| 348 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 349 | if (bs == 1) | |
| 350 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 351 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(14) "); | |
| 352 | break; | |
| 353 | case 15: // : undefined | |
| 354 | if (t) | |
| 355 | dst += snprintf(dst, len - (size_t)(dst - buffer), "T←BUS "); | |
| 356 | if (l) | |
| 357 | dst += snprintf(dst, len - (size_t)(dst - buffer), "L← "); | |
| 358 | if (bs == 1) | |
| 359 | dst += snprintf(dst, len - (size_t)(dst - buffer), "%s← ", regname[rsel]); | |
| 360 | dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(15) "); | |
| 361 | break; | |
| 362 | } | |
| 363 | ||
| 364 | switch (bs) { | |
| 365 | case 0: // read R | |
| 366 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←%s ", regname[rsel]); | |
| 367 | break; | |
| 368 | case 1: // load R from shifter output | |
| 369 | // dst += snprintf(dst, len - (size_t)(dst - buffer), "; %s←", rn[rsel]); | |
| 370 | break; | |
| 371 | case 2: // enables no source to the BUS, leaving it all ones | |
| 372 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←177777 "); | |
| 373 | break; | |
| 374 | case 3: // performs different functions in different tasks | |
| 375 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←BS3 "); | |
| 376 | break; | |
| 377 | case 4: // performs different functions in different tasks | |
| 378 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←BS4 "); | |
| 379 | break; | |
| 380 | case 5: // memory data | |
| 381 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←MD "); | |
| 382 | break; | |
| 383 | case 6: // BUS[3-0] <- MOUSE; BUS[15-4] <- -1 | |
| 384 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←MOUSE "); | |
| 385 | break; | |
| 386 | case 7: // IR[7-0], possibly sign extended | |
| 387 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←DISP "); | |
| 388 | break; | |
| 389 | } | |
| 390 | ||
| 391 | ||
| 392 | switch (f1) { | |
| 393 | case 0: // no operation | |
| 394 | break; | |
| 395 | case 1: // load MAR from ALU output; start main memory reference | |
| 396 | dst += snprintf(dst, len - (size_t)(dst - buffer), "MAR←ALU "); | |
| 397 | break; | |
| 398 | case 2: // switch tasks if higher priority wakeup is pending | |
| 399 | dst += snprintf(dst, len - (size_t)(dst - buffer), "[TASK] "); | |
| 400 | break; | |
| 401 | case 3: // disable the current task until re-enabled by a hardware-generated condition | |
| 402 | dst += snprintf(dst, len - (size_t)(dst - buffer), "[BLOCK] "); | |
| 403 | break; | |
| 404 | case 4: // SHIFTER output will be L shifted left one place | |
| 405 | dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER←L(LSH1) "); | |
| 406 | break; | |
| 407 | case 5: // SHIFTER output will be L shifted right one place | |
| 408 | dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER←L(RSH1) "); | |
| 409 | break; | |
| 410 | case 6: // SHIFTER output will be L rotated left 8 places | |
| 411 | dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER←L(LCY8) "); | |
| 412 | break; | |
| 413 | case 7: // put the constant from PROM (RSELECT,BS) on the bus | |
| 414 | pa = (rsel << 3) | bs; | |
| 415 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←[%03o]%05o ", pa, const_prom[pa]); | |
| 416 | break; | |
| 417 | default: | |
| 418 | dst += snprintf(dst, len - (size_t)(dst - buffer), "F1_%02o ", f1); | |
| 419 | break; | |
| 420 | } | |
| 421 | ||
| 422 | switch (f2) { | |
| 423 | case 0: // no operation | |
| 424 | break; | |
| 425 | case 1: // NEXT ← NEXT OR (if (BUS=0) then 1 else 0) | |
| 426 | dst += snprintf(dst, len - (size_t)(dst - buffer), "[(BUS=0) ? %s : %s] ", | |
| 427 | addrname((prefetch | 1) & MCODE_MASK), | |
| 428 | addrname(prefetch & MCODE_MASK)); | |
| 429 | break; | |
| 430 | case 2: // NEXT ← NEXT OR (if (SHIFTER OUTPUT<0) then 1 else 0) | |
| 431 | dst += snprintf(dst, len - (size_t)(dst - buffer), "[(SH=0) ? %s : %s] ", | |
| 432 | addrname((prefetch | 1) & MCODE_MASK), | |
| 433 | addrname(prefetch & MCODE_MASK)); | |
| 434 | break; | |
| 435 | case 3: // NEXT ← NEXT OR (if (SHIFTER OUTPUT<0) then 1 else 0) | |
| 436 | dst += snprintf(dst, len - (size_t)(dst - buffer), "[(SH<0) ? %s : %s] ", | |
| 437 | addrname((prefetch | 1) & MCODE_MASK), | |
| 438 | addrname(prefetch & MCODE_MASK)); | |
| 439 | break; | |
| 440 | case 4: // NEXT ← NEXT OR BUS | |
| 441 | dst += snprintf(dst, len - (size_t)(dst - buffer), "NEXT←BUS "); | |
| 442 | break; | |
| 443 | case 5: // NEXT ← NEXT OR ALUC0. ALUC0 is the carry produced by last L loading microinstruction. | |
| 444 | dst += snprintf(dst, len - (size_t)(dst - buffer), "[(ALUC0) ? %s : %s] ", | |
| 445 | addrname((prefetch | 1) & MCODE_MASK), | |
| 446 | addrname(prefetch & MCODE_MASK)); | |
| 447 | break; | |
| 448 | case 6: // deliver BUS data to memory | |
| 449 | dst += snprintf(dst, len - (size_t)(dst - buffer), "MD←BUS "); | |
| 450 | break; | |
| 451 | case 7: // put on the bus the constant from PROM (RSELECT,BS) | |
| 452 | pa = (rsel << 3) | bs; | |
| 453 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←[%03o]%05o ", pa, const_prom[pa]); | |
| 454 | break; | |
| 455 | default: | |
| 456 | dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS←F2_%02o ", f2); | |
| 457 | break; | |
| 458 | } | |
| 459 | return pc + 4; | |
| 460 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII CPU core interface | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "emu.h" | |
| 11 | #include "debugger.h" | |
| 12 | ||
| 13 | #pragma once | |
| 14 | ||
| 15 | #ifndef _CPU_ALTO2_H_ | |
| 16 | #define _CPU_ALTO2_H | |
| 17 | ||
| 18 | #ifndef DEBUG | |
| 19 | #define DEBUG 0 | |
| 20 | #endif | |
| 21 | ||
| 22 | #if DEBUG | |
| 23 | extern void logprintf(int type, int level, const char* format, ...); | |
| 24 | #define LOG(x) logprintf x | |
| 25 | #else | |
| 26 | #define LOG(x) | |
| 27 | #endif | |
| 28 | ||
| 29 | extern void fatal(int level, const char* format, ...); | |
| 30 | ||
| 31 | #define USE_PRIO_F9318 0 //!< define to 1 to use the F9318 priority encoder code | |
| 32 | #define USE_ALU_74181 1 //!< define to 1 to use the SN74181 ALU code | |
| 33 | #define DEBUG_DISPLAY_TIMING 0 //!< define to 1 to debug the display timing | |
| 34 | ||
| 35 | #define ALTO2_TASKS 16 //!< 16 task slots | |
| 36 | #define ALTO2_REGS 32 //!< 32 16-bit words in the R register file | |
| 37 | #define ALTO2_ALUF 16 //!< 16 ALU functions (74181) | |
| 38 | #define ALTO2_BUSSRC 8 //!< 8 bus sources | |
| 39 | #define ALTO2_F1MAX 16 //!< 16 F1 functions | |
| 40 | #define ALTO2_F2MAX 16 //!< 16 F2 functions | |
| 41 | #define ALTO2_UCYCLE 170 //!< time in nano seconds for a CPU micro cycle | |
| 42 | ||
| 43 | #define ALTO2_ETHER_FIFO_SIZE 16 | |
| 44 | ||
| 45 | #ifndef ALTO2_CRAM_CONFIG | |
| 46 | #define ALTO2_CRAM_CONFIG 2 //!< use default configuration 2 | |
| 47 | #endif | |
| 48 | ||
| 49 | #if (ALTO2_CRAM_CONFIG==1) | |
| 50 | #define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages | |
| 51 | #define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages | |
| 52 | #elif (ALTO2_CRAM_CONFIG==2) | |
| 53 | #define ALTO2_UCODE_ROM_PAGES 2 //!< number of microcode ROM pages | |
| 54 | #define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages | |
| 55 | #elif (ALTO2_CRAM_CONFIG==3) | |
| 56 | #define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages | |
| 57 | #define ALTO2_UCODE_RAM_PAGES 3 //!< number of microcode RAM pages | |
| 58 | #else | |
| 59 | #error "Undefined CROM/CRAM configuration" | |
| 60 | #endif | |
| 61 | ||
| 62 | /** | |
| 63 | * \brief number of S register banks | |
| 64 | * This depends on the number of RAM pages | |
| 65 | * 8 pages in 3K CRAM configuration | |
| 66 | * 1 page in 1K CRAM configurations | |
| 67 | */ | |
| 68 | #if (ALTO2_UCODE_RAM_PAGES == 3) | |
| 69 | #define ALTO2_SREG_BANKS 8 | |
| 70 | #else | |
| 71 | #define ALTO2_SREG_BANKS 1 | |
| 72 | #endif | |
| 73 | ||
| 74 | #define ALTO2_UCODE_PAGE_SIZE 1024 //!< number of words of microcode | |
| 75 | #define ALTO2_UCODE_PAGE_MASK (ALTO2_UCODE_PAGE_SIZE-1) //!< mask for microcode ROM/RAM address | |
| 76 | #define ALTO2_UCODE_SIZE ((ALTO2_UCODE_ROM_PAGES + ALTO2_UCODE_RAM_PAGES) * ALTO2_UCODE_PAGE_SIZE) //!< total number of words of microcode | |
| 77 | #define ALTO2_UCODE_RAM_BASE (ALTO2_UCODE_ROM_PAGES * ALTO2_UCODE_PAGE_SIZE) //!< base offset for the RAM page(s) | |
| 78 | #define ALTO2_CONST_SIZE 256 //!< number words in the constant ROM | |
| 79 | #define ALTO2_RAM_SIZE 262144 //!< size of main memory in bytes | |
| 80 | ||
| 81 | /** | |
| 82 | * @brief start value for the horizontal line counter | |
| 83 | * | |
| 84 | * This value is loaded into the three 4 bit counters (type 9316) | |
| 85 | * with numbers 65, 67, and 75. | |
| 86 | * 65: A=0 B=1 C=1 D=0 | |
| 87 | * 67: A=1 B=0 C=0 D=1 | |
| 88 | * 75: A=0 B=0 C=0 D=0 | |
| 89 | * | |
| 90 | * The value is 150 | |
| 91 | */ | |
| 92 | #define ALTO2_DISPLAY_HLC_START (2+4+16+128) | |
| 93 | ||
| 94 | /** | |
| 95 | * @brief end value for the horizontal line counter | |
| 96 | * | |
| 97 | * This is decoded by H30, an 8 input NAND gate. | |
| 98 | * The value is 1899; horz. line count range 150…1899 = 1750. | |
| 99 | * | |
| 100 | * There are 1750 / 2 = 875 total scanlines. | |
| 101 | */ | |
| 102 | #define ALTO2_DISPLAY_HLC_END (1+2+8+32+64+256+512+1024) | |
| 103 | ||
| 104 | /** | |
| 105 | * @brief display total height, including overscan (vertical blanking and synch) | |
| 106 | * | |
| 107 | * The display is interleaved in two fields, alternatingly drawing the even and odd | |
| 108 | * scanlines to the monitor. The frame rate is 60Hz, which is actually the rate | |
| 109 | * of the half-frames. The rate for full frames is thus 30Hz. | |
| 110 | */ | |
| 111 | #define ALTO2_DISPLAY_TOTAL_HEIGHT ((ALTO2_DISPLAY_HLC_END + 1 - ALTO2_DISPLAY_HLC_START) / 2) | |
| 112 | ||
| 113 | /** | |
| 114 | * @brief display total width, including horizontal blanking | |
| 115 | * | |
| 116 | * Known facts: | |
| 117 | * | |
| 118 | * We have 606x808 visible pixels, and the pixel clock is said to be 50ns | |
| 119 | * (20MHz), while the crystal in the schematics is labeled 20.16 MHz, | |
| 120 | * so the pixel clock would actually be 49.6031ns. | |
| 121 | * | |
| 122 | * The total number of scanlines is, according to the docs, 875. | |
| 123 | * | |
| 124 | * 875 scanlines at 30 frames per second, thus the scanline rate is 26.250 kHz. | |
| 125 | * | |
| 126 | * If I divide 20.16 MHz by 26.250 kHz, I get 768 pixels for the total width | |
| 127 | * of a scanline in pixels. | |
| 128 | * | |
| 129 | * The horizontal blanking period would then be 768 - 606 = 162 pixels, and | |
| 130 | * thus 162 * 49.6031ns ~= 8036ns = 8.036us for the HBLANK time. | |
| 131 | * | |
| 132 | * In the display schematics there is a divide by 24 logic, and when | |
| 133 | * dividing the 768 pixels per scanline by 24, we have 32 phases of a scanline. | |
| 134 | * | |
| 135 | * A S8223 PROM (a63) with 32x8 bits contains the status of the HBLANK and | |
| 136 | * HSYNC signals for these phases, the SCANEND and HLCGATE signals, as well | |
| 137 | * as its own next address A0-A3! | |
| 138 | * | |
| 139 | */ | |
| 140 | #define ALTO2_DISPLAY_TOTAL_WIDTH 768 | |
| 141 | ||
| 142 | ||
| 143 | #define ALTO2_DISPLAY_SCANLINE_WORDS (ALTO2_DISPLAY_TOTAL_WIDTH/16) //!< words per scanline | |
| 144 | #define ALTO2_DISPLAY_HEIGHT 808 //!< number of visible scanlines per frame; 808 really, but there are some empty lines? | |
| 145 | #define ALTO2_DISPLAY_WIDTH 606 //!< visible width of the display | |
| 146 | #define ALTO2_DISPLAY_VISIBLE_WORDS ((ALTO2_DISPLAY_WIDTH+15)/16) //!< visible words per scanline | |
| 147 | #define ALTO2_DISPLAY_BITCLOCK 20160000ll //!< display bit clock in in Hertz (20.16MHz) | |
| 148 | #define ALTO2_DISPLAY_BITTIME(n) (HZ_TO_ATTOSECONDS(ALTO2_DISPLAY_BITCLOCK)*(n)) //!< display bit time in in atto seconds (~= 49.6031ns) | |
| 149 | #define ALTO2_DISPLAY_SCANLINE_TIME ALTO2_DISPLAY_BITTIME(ALTO2_DISPLAY_TOTAL_WIDTH) //!< time for a scanline in nano seconds (768 * 49.6031ns) | |
| 150 | #define ALTO2_DISPLAY_VISIBLE_TIME ALTO2_DISPLAY_BITTIME(ALTO2_DISPLAY_WIDTH) //!< time of the visible part of a scanline (606 * 49.6031ns) | |
| 151 | #define ALTO2_DISPLAY_WORD_TIME ALTO2_DISPLAY_BITTIME(16) //!< time for a word (16 pixels * 49.6031ns) | |
| 152 | #define ALTO2_DISPLAY_VBLANK_TIME ((ALTO2_DISPLAY_TOTAL_HEIGHT-ALTO2_DISPLAY_HEIGHT)*HZ_TO_ATTOSECONDS(26250)) | |
| 153 | #define ALTO2_DISPLAY_FIFO 16 //!< the display fifo has 16 words | |
| 154 | ||
| 155 | //! 32 R registers | |
| 156 | enum { | |
| 157 | A2_AC3, A2_AC2, A2_AC1, A2_AC0, | |
| 158 | A2_R04, A2_R05, A2_PC, A2_R07, | |
| 159 | A2_R10, A2_R11, A2_R12, A2_R13, | |
| 160 | A2_R14, A2_R15, A2_R16, A2_R17, | |
| 161 | A2_R20, A2_R21, A2_R22, A2_R23, | |
| 162 | A2_R24, A2_R25, A2_R26, A2_R27, | |
| 163 | A2_R30, A2_R31, A2_R32, A2_R33, | |
| 164 | A2_R34, A2_R35, A2_R36, A2_R37 | |
| 165 | }; | |
| 166 | ||
| 167 | /** | |
| 168 | * @brief enumeration of the inputs and outputs of a JK flip-flop type 74109 | |
| 169 | * <PRE> | |
| 170 | * 74109 | |
| 171 | * Dual J-/K flip-flops with set and reset. | |
| 172 | * | |
| 173 | * +----------+ +-----------------------------+ | |
| 174 | * /1RST |1 +--+ 16| VCC | J |/K |CLK|/SET|/RST| Q |/Q | | |
| 175 | * 1J |2 15| /2RST |---+---+---+----+----+---+---| | |
| 176 | * /1K |3 14| 2J | X | X | X | 0 | 0 | 1 | 1 | | |
| 177 | * 1CLK |4 74 13| /2K | X | X | X | 0 | 1 | 1 | 0 | | |
| 178 | * /1SET |5 109 12| 2CLK | X | X | X | 1 | 0 | 0 | 1 | | |
| 179 | * 1Q |6 11| /2SET | 0 | 0 | / | 1 | 1 | 0 | 1 | | |
| 180 | * /1Q |7 10| 2Q | 0 | 1 | / | 1 | 1 | - | - | | |
| 181 | * GND |8 9| /2Q | 1 | 0 | / | 1 | 1 |/Q | Q | | |
| 182 | * +----------+ | 1 | 1 | / | 1 | 1 | 1 | 0 | | |
| 183 | * | X | X |!/ | 1 | 1 | - | - | | |
| 184 | * +-----------------------------+ | |
| 185 | * | |
| 186 | * [This information is part of the GIICM] | |
| 187 | * </PRE> | |
| 188 | */ | |
| 189 | typedef enum { | |
| 190 | JKFF_0 = 0000, //!< no inputs or outputs | |
| 191 | JKFF_CLK = 0001, //!< clock signal | |
| 192 | JKFF_J = 0002, //!< J input | |
| 193 | JKFF_K = 0004, //!< K' input | |
| 194 | JKFF_S = 0010, //!< S' input | |
| 195 | JKFF_C = 0020, //!< C' input | |
| 196 | JKFF_Q = 0040, //!< Q output | |
| 197 | JKFF_Q0 = 0100 //!< Q' output | |
| 198 | } jkff_t; | |
| 199 | ||
| 200 | class alto2_cpu_device : public cpu_device | |
| 201 | { | |
| 202 | public: | |
| 203 | // construction/destruction | |
| 204 | alto2_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); | |
| 205 | ||
| 206 | protected: | |
| 207 | //! device-level override for start | |
| 208 | virtual void device_start(); | |
| 209 | //! device-level override for reset | |
| 210 | virtual void device_reset(); | |
| 211 | ||
| 212 | //! device_execute_interface overrides | |
| 213 | virtual UINT32 execute_min_cycles() const { return 1; } | |
| 214 | virtual UINT32 execute_max_cycles() const { return 1; } | |
| 215 | virtual UINT32 execute_input_lines() const { return 1; } | |
| 216 | virtual void execute_run(); | |
| 217 | virtual void execute_set_input(int inputnum, int state); | |
| 218 | ||
| 219 | //! device_memory_interface overrides | |
| 220 | virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const | |
| 221 | { | |
| 222 | if (AS_PROGRAM == spacenum) | |
| 223 | return &m_ucode_config; | |
| 224 | if (AS_IO == spacenum) | |
| 225 | return &m_ram_config; | |
| 226 | return NULL; | |
| 227 | } | |
| 228 | ||
| 229 | //! device_state_interface overrides | |
| 230 | void state_string_export(const device_state_entry &entry, astring &string); | |
| 231 | ||
| 232 | //! device_disasm_interface overrides | |
| 233 | virtual UINT32 disasm_min_opcode_bytes() const { return 4; } | |
| 234 | virtual UINT32 disasm_max_opcode_bytes() const { return 4; } | |
| 235 | virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); | |
| 236 | ||
| 237 | private: | |
| 238 | address_space_config m_ucode_config; | |
| 239 | address_space_config m_ram_config; | |
| 240 | ||
| 241 | static const UINT8 m_ether_id = 0121; | |
| 242 | ||
| 243 | typedef void (alto2_cpu_device::*a2func)(); | |
| 244 | typedef void (alto2_cpu_device::*a2cb)(int unit); | |
| 245 | typedef void (alto2_cpu_device::*a2io_wr)(UINT32 addr, UINT16 data); | |
| 246 | typedef UINT16 (alto2_cpu_device::*a2io_rd)(UINT32 addr); | |
| 247 | ||
| 248 | //! task numbers | |
| 249 | enum { | |
| 250 | task_emu, //!< emulator task | |
| 251 | task_1, //!< unused | |
| 252 | task_2, //!< unused | |
| 253 | task_3, //!< unused | |
| 254 | task_ksec, //!< disk sector task | |
| 255 | task_5, //!< unused | |
| 256 | task_6, //!< unused | |
| 257 | task_ether, //!< ethernet task | |
| 258 | task_mrt, //!< memory refresh task | |
| 259 | task_dwt, //!< display word task | |
| 260 | task_curt, //!< cursor task | |
| 261 | task_dht, //!< display horizontal task | |
| 262 | task_dvt, //!< display vertical task | |
| 263 | task_part, //!< parity task | |
| 264 | task_kwd, //!< disk word task | |
| 265 | task_17 //!< unused task slot 017 | |
| 266 | }; | |
| 267 | ||
| 268 | //! register select values accessing R (Note: register numbers are octal) | |
| 269 | enum { | |
| 270 | rsel_ac3, //!< AC3 used by emulator as accu 3. Also used by Mesa emulator to keep bytecode to execute after breakpoint | |
| 271 | rsel_ac2, //!< AC2 used by emulator as accu 2. Also used by Mesa emulator as x register for xfer | |
| 272 | rsel_ac1, //!< AC1 used by emulator as accu 1. Also used by Mesa emulator as r-temporary for return indices and values | |
| 273 | rsel_ac0, //!< AC0 used by emulator as accu 0. Also used by Mesa emulator as new field bits for WF and friends | |
| 274 | rsel_r04, //!< NWW state of the interrupt system | |
| 275 | rsel_r05, //!< SAD. Also used by Mesa emulator as scratch R-register for counting | |
| 276 | rsel_pc, //!< PC used by emulator as program counter | |
| 277 | rsel_r07, //!< XREG. Also used by Mesa emulator as task hole, i.e. pigeonhole for saving things across tasks. | |
| 278 | rsel_r10, //!< XH. Also used by Mesa emulator as instruction byte register | |
| 279 | rsel_r11, //!< CLOCKTEMP - used in the MRT | |
| 280 | rsel_r12, //!< ECNTR remaining words in buffer - ETHERNET | |
| 281 | rsel_r13, //!< EPNTR points BEFORE next word in buffer - ETHERNET | |
| 282 | rsel_r14, | |
| 283 | rsel_r15, //!< MPC. Used by the Mesa emulator as program counter | |
| 284 | rsel_r16, //!< STKP. Used by the Mesa emulator as stack pointer [0-10] 0 empty, 10 full | |
| 285 | rsel_r17, //!< XTSreg. Used by the Mesa emulator to xfer trap state | |
| 286 | rsel_r20, //!< CURX. Holds cursor X; used by the cursor task | |
| 287 | rsel_r21, //!< CURDATA. Holds the cursor data; used by the cursor task | |
| 288 | rsel_r22, //!< CBA. Holds the address of the currently active DCB+1 | |
| 289 | rsel_r23, //!< AECL. Holds the address of the end of the current scanline's bitmap | |
| 290 | rsel_r24, //!< SLC. Holds the number of scanlines remaining in currently active DCB | |
| 291 | rsel_r25, //!< MTEMP. Holds the temporary cell | |
| 292 | rsel_r26, //!< HTAB. Holds the number of tab words remaining on current scanline | |
| 293 | rsel_r27, //!< YPOS | |
| 294 | rsel_r30, //!< DWA. Holds the address of the bit map doubleword currently being fetched for transmission to the hardware buffer. | |
| 295 | rsel_r31, //!< KWDCT. Used by the disk tasks as word counter | |
| 296 | rsel_r32, //!< CKSUMR. Used by the disk tasks as checksum register (and *amble counter?) | |
| 297 | rsel_r33, //!< KNMAR. Used by the disk tasks as transfer memory address register | |
| 298 | rsel_r34, //!< DCBR. Used by the disk tasks to keep the current device control block | |
| 299 | rsel_r35, //!< TEMP. Used by the Mesa emulator, and also by BITBLT | |
| 300 | rsel_r36, //!< TEMP2. Used by the Mesa emulator, and also by BITBLT | |
| 301 | rsel_r37 //!< CLOCKREG. Low order bits of the real time clock | |
| 302 | }; | |
| 303 | ||
| 304 | //! ALU function numbers | |
| 305 | enum { | |
| 306 | /** | |
| 307 | * \brief 00: ALU <- BUS | |
| 308 | * PROM data for S3-0,M,C: 1111/1/0 | |
| 309 | * function F=A | |
| 310 | * T source is ALU | |
| 311 | */ | |
| 312 | aluf_bus__alut, | |
| 313 | /** | |
| 314 | * \brief 01: ALU <- T | |
| 315 | * PROM data for S3-0,M,C: 1010/1/0 | |
| 316 | * function F=B | |
| 317 | * T source is BUS | |
| 318 | */ | |
| 319 | aluf_treg, | |
| 320 | /** | |
| 321 | * \brief 02: ALU <- BUS | T | |
| 322 | * PROM data for S3-0,M,C: 1110/1/0 | |
| 323 | * function F=A|B | |
| 324 | * T source is ALU | |
| 325 | */ | |
| 326 | aluf_bus_or_t__alut, | |
| 327 | /** | |
| 328 | * \brief 03: ALU <- BUS & T | |
| 329 | * PROM data for S3-0,M,C: 1011/1/0 | |
| 330 | * function F=A&B | |
| 331 | * T source is BUS | |
| 332 | */ | |
| 333 | aluf_bus_and_t, | |
| 334 | /** | |
| 335 | * \brief 04: ALU <- BUS ^ T | |
| 336 | * PROM data for S3-0,M,C: 0110/1/0 | |
| 337 | * function F=A^B | |
| 338 | * T source is BUS | |
| 339 | */ | |
| 340 | aluf_bus_xor_t, | |
| 341 | /** | |
| 342 | * \brief 05: ALU <- BUS + 1 | |
| 343 | * PROM data for S3-0,M,C: 0000/0/0 | |
| 344 | * function F=A+1 | |
| 345 | * T source is ALU | |
| 346 | */ | |
| 347 | aluf_bus_plus_1__alut, | |
| 348 | /** | |
| 349 | * \brief 06: ALU <- BUS - 1 | |
| 350 | * PROM data for S3-0,M,C: 1111/0/1 | |
| 351 | * function F=A-1 | |
| 352 | * T source is ALU | |
| 353 | */ | |
| 354 | aluf_bus_minus_1__alut, | |
| 355 | /** | |
| 356 | * \brief 07: ALU <- BUS + T | |
| 357 | * PROM data for S3-0,M,C: 1001/0/1 | |
| 358 | * function F=A+B | |
| 359 | * T source is BUS | |
| 360 | */ | |
| 361 | aluf_bus_plus_t, | |
| 362 | /** | |
| 363 | * \brief 10: ALU <- BUS - T | |
| 364 | * PROM data for S3-0,M,C: 0110/0/0 | |
| 365 | * function F=A-B | |
| 366 | * T source is BUS | |
| 367 | */ | |
| 368 | aluf_bus_minus_t, | |
| 369 | /** | |
| 370 | * \brief 11: ALU <- BUS - T - 1 | |
| 371 | * PROM data for S3-0,M,C: 0110/0/1 | |
| 372 | * function F=A-B-1 | |
| 373 | * T source is BUS | |
| 374 | */ | |
| 375 | aluf_bus_minus_t_minus_1, | |
| 376 | /** | |
| 377 | * \brief 12: ALU <- BUS + T + 1 | |
| 378 | * PROM data for S3-0,M,C: 1001/0/0 | |
| 379 | * function F=A+B+1 | |
| 380 | * T source is ALU | |
| 381 | */ | |
| 382 | aluf_bus_plus_t_plus_1__alut, | |
| 383 | /** | |
| 384 | * \brief 13: ALU <- BUS + SKIP | |
| 385 | * PROM data for S3-0,M,C: 0000/0/SKIP | |
| 386 | * function F=A (SKIP=1) or F=A+1 (SKIP=0) | |
| 387 | * T source is ALU | |
| 388 | */ | |
| 389 | aluf_bus_plus_skip__alut, | |
| 390 | /** | |
| 391 | * \brief 14: ALU <- BUS & T | |
| 392 | * PROM data for S3-0,M,C: 1011/1/0 | |
| 393 | * function F=A&B | |
| 394 | * T source is ALU | |
| 395 | */ | |
| 396 | aluf_bus_and_t__alut, | |
| 397 | /** | |
| 398 | * \brief 15: ALU <- BUS & ~T | |
| 399 | * PROM data for S3-0,M,C: 0111/1/0 | |
| 400 | * function F=A&~B | |
| 401 | * T source is BUS | |
| 402 | */ | |
| 403 | aluf_bus_and_not_t, | |
| 404 | /** | |
| 405 | * \brief 16: ALU <- ??? | |
| 406 | * PROM data for S3-0,M,C: ????/?/? | |
| 407 | * perhaps F=0 (0011/0/0) | |
| 408 | * T source is BUS | |
| 409 | */ | |
| 410 | aluf_undef_16, | |
| 411 | /** | |
| 412 | * \brief 17: ALU <- ??? | |
| 413 | * PROM data for S3-0,M,C: ????/?/? | |
| 414 | * perhaps F=0 (0011/0/0) | |
| 415 | * T source is BUS | |
| 416 | */ | |
| 417 | aluf_undef_17 | |
| 418 | }; | |
| 419 | ||
| 420 | //! BUS source selection numbers | |
| 421 | enum { | |
| 422 | bs_read_r, //!< BUS source is R register | |
| 423 | bs_load_r, //!< load R register from BUS | |
| 424 | bs_no_source, //!< BUS is open (0177777) | |
| 425 | bs_task_3, //!< BUS source is task specific | |
| 426 | bs_task_4, //!< BUS source is task specific | |
| 427 | bs_read_md, //!< BUS source is memory data | |
| 428 | bs_mouse, //!< BUS source is mouse data | |
| 429 | bs_disp, //!< BUS source displacement | |
| 430 | ||
| 431 | bs_ram_read_slocation= bs_task_3, //!< ram related: read S register | |
| 432 | bs_ram_load_slocation= bs_task_4, //!< ram related: load S register | |
| 433 | ||
| 434 | bs_emu_read_sreg = bs_task_3, //!< emulator task: read S register | |
| 435 | bs_emu_load_sreg = bs_task_4, //!< emulator task: load S register from BUS | |
| 436 | ||
| 437 | bs_ksec_read_kstat = bs_task_3, //!< disk sector task: read status register | |
| 438 | bs_ksec_read_kdata = bs_task_4, //!< disk sector task: read data register | |
| 439 | ||
| 440 | bs_ether_eidfct = bs_task_3, //!< ethernet task: Ethernet input data function | |
| 441 | ||
| 442 | bs_kwd_read_kstat = bs_task_3, //!< disk word task: read status register | |
| 443 | bs_kwd_read_kdata = bs_task_4 //!< disk word task: read data register | |
| 444 | }; | |
| 445 | ||
| 446 | //! Function 1 numbers | |
| 447 | enum { | |
| 448 | f1_nop, //!< f1 (0000) no operation | |
| 449 | f1_load_mar, //!< f1 (0001) load memory address register | |
| 450 | f1_task, //!< f1 (0010) task switch | |
| 451 | f1_block, //!< f1 (0011) block task | |
| 452 | f1_l_lsh_1, //!< f1 (0100) left shift L once | |
| 453 | f1_l_rsh_1, //!< f1 (0101) right shift L once | |
| 454 | f1_l_lcy_8, //!< f1 (0110) cycle L 8 times | |
| 455 | f1_const, //!< f1 (0111) constant from PROM | |
| 456 | ||
| 457 | f1_task_10, //!< f1 (1000) task specific | |
| 458 | f1_task_11, //!< f1 (1001) task specific | |
| 459 | f1_task_12, //!< f1 (1010) task specific | |
| 460 | f1_task_13, //!< f1 (1011) task specific | |
| 461 | f1_task_14, //!< f1 (1100) task specific | |
| 462 | f1_task_15, //!< f1 (1101) task specific | |
| 463 | f1_task_16, //!< f1 (1110) task specific | |
| 464 | f1_task_17, //!< f1 (1111) task specific | |
| 465 | ||
| 466 | f1_ram_swmode = f1_task_10, //!< f1 (1000) ram related: switch mode to CROM/CRAM in same page | |
| 467 | f1_ram_wrtram = f1_task_11, //!< f1 (1001) ram related: start WRTRAM cycle | |
| 468 | f1_ram_rdram = f1_task_12, //!< f1 (1010) ram related: start RDRAM cycle | |
| 469 | #if (ALTO2_UCODE_RAM_PAGES == 3) | |
| 470 | f1_ram_load_rmr = f1_task_13, //!< f1 (1011) ram related: load the reset mode register | |
| 471 | #else // ALTO2_UCODE_RAM_PAGES != 3 | |
| 472 | f1_ram_load_srb = f1_task_13, //!< f1 (1011) ram related: load the S register bank from BUS[12-14] | |
| 473 | #endif | |
| 474 | ||
| 475 | f1_emu_swmode = f1_task_10, //!< f1 (1000) emu: switch mode; branch to ROM/RAM microcode | |
| 476 | f1_emu_wrtram = f1_task_11, //!< f1 (1001) emu: write microcode RAM | |
| 477 | f1_emu_rdram = f1_task_12, //!< f1 (1010) emu: read microcode RAM | |
| 478 | f1_emu_load_rmr = f1_task_13, //!< f1 (1011) emu: load reset mode register | |
| 479 | //!< f1 (1100) emu: undefined | |
| 480 | f1_emu_load_esrb = f1_task_15, //!< f1 (1101) emu: load extended S register bank | |
| 481 | f1_emu_rsnf = f1_task_16, //!< f1 (1110) emu: read serial number (Ethernet ID) | |
| 482 | f1_emu_startf = f1_task_17, //!< f1 (1111) emu: start I/O hardware (Ethernet) | |
| 483 | ||
| 484 | f1_ksec_strobe = f1_task_11, //!< f1 (1001) ksec: strobe | |
| 485 | f1_ksec_load_kstat = f1_task_12, //!< f1 (1010) ksec: load kstat register | |
| 486 | f1_ksec_increcno = f1_task_13, //!< f1 (1011) ksec: increment record number | |
| 487 | f1_ksec_clrstat = f1_task_14, //!< f1 (1100) ksec: clear status register | |
| 488 | f1_ksec_load_kcom = f1_task_15, //!< f1 (1101) ksec: load kcom register | |
| 489 | f1_ksec_load_kadr = f1_task_16, //!< f1 (1110) ksec: load kadr register | |
| 490 | f1_ksec_load_kdata = f1_task_17, //!< f1 (1111) ksec: load kdata register | |
| 491 | ||
| 492 | f1_ether_eilfct = f1_task_13, //!< f1 (1011) ether: Ethernet input look function | |
| 493 | f1_ether_epfct = f1_task_14, //!< f1 (1100) ether: Ethernet post function | |
| 494 | f1_ether_ewfct = f1_task_15, //!< f1 (1101) ether: Ethernet countdown wakeup function | |
| 495 | ||
| 496 | f1_kwd_strobe = f1_task_11, //!< f1 (1001) kwd: strobe | |
| 497 | f1_kwd_load_kstat = f1_task_12, //!< f1 (1010) kwd: load kstat register | |
| 498 | f1_kwd_increcno = f1_task_13, //!< f1 (1011) kwd: increment record number | |
| 499 | f1_kwd_clrstat = f1_task_14, //!< f1 (1100) kwd: clear status register | |
| 500 | f1_kwd_load_kcom = f1_task_15, //!< f1 (1101) kwd: load kcom register | |
| 501 | f1_kwd_load_kadr = f1_task_16, //!< f1 (1110) kwd: load kadr register | |
| 502 | f1_kwd_load_kdata = f1_task_17, //!< f1 (1111) kwd: load kdata register | |
| 503 | }; | |
| 504 | ||
| 505 | //! Function 2 numbers | |
| 506 | enum { | |
| 507 | f2_nop, //!< f2 00 no operation | |
| 508 | f2_bus_eq_zero, //!< f2 01 branch on bus equals 0 | |
| 509 | f2_shifter_lt_zero, //!< f2 02 branch on shifter less than 0 | |
| 510 | f2_shifter_eq_zero, //!< f2 03 branch on shifter equals 0 | |
| 511 | f2_bus, //!< f2 04 branch on BUS[6-15] | |
| 512 | f2_alucy, //!< f2 05 branch on (latched) ALU carry | |
| 513 | f2_load_md, //!< f2 06 load memory data | |
| 514 | f2_const, //!< f2 07 constant from PROM | |
| 515 | f2_task_10, //!< f2 10 task specific | |
| 516 | f2_task_11, //!< f2 11 task specific | |
| 517 | f2_task_12, //!< f2 12 task specific | |
| 518 | f2_task_13, //!< f2 13 task specific | |
| 519 | f2_task_14, //!< f2 14 task specific | |
| 520 | f2_task_15, //!< f2 15 task specific | |
| 521 | f2_task_16, //!< f2 16 task specific | |
| 522 | f2_task_17, //!< f2 17 task specific | |
| 523 | ||
| 524 | f2_emu_busodd = f2_task_10, //!< f2 (1000) emu: branch on bus odd | |
| 525 | f2_emu_magic = f2_task_11, //!< f2 (1001) emu: magic shifter (MRSH 1: shifter[15]=T[0], MLSH 1: shifter[015]) | |
| 526 | f2_emu_load_dns = f2_task_12, //!< f2 (1010) emu: do novel shift (RSH 1: shifter[15]=XC, LSH 1: shifer[0]=XC) | |
| 527 | f2_emu_acdest = f2_task_13, //!< f2 (1011) emu: destination accu | |
| 528 | f2_emu_load_ir = f2_task_14, //!< f2 (1100) emu: load instruction register and branch | |
| 529 | f2_emu_idisp = f2_task_15, //!< f2 (1101) emu: load instruction displacement and branch | |
| 530 | f2_emu_acsource = f2_task_16, //!< f2 (1110) emu: source accu | |
| 531 | ||
| 532 | f2_ksec_init = f2_task_10, //!< f2 (1000) ksec: branches NEXT[5-9] on WDTASKACT && WDINIT | |
| 533 | f2_ksec_rwc = f2_task_11, //!< f2 (1001) ksec: branches NEXT[8-9] on READ/WRITE/CHECK for record | |
| 534 | f2_ksec_recno = f2_task_12, //!< f2 (1010) ksec: branches NEXT[8-9] on RECNO[0-1] | |
| 535 | f2_ksec_xfrdat = f2_task_13, //!< f2 (1011) ksec: branches NEXT[9] on !SEEKONLY | |
| 536 | f2_ksec_swrnrdy = f2_task_14, //!< f2 (1100) ksec: branches NEXT[9] on !SWRDY | |
| 537 | f2_ksec_nfer = f2_task_15, //!< f2 (1101) ksec: branches NEXT[9] on !KFER | |
| 538 | f2_ksec_strobon = f2_task_16, //!< f2 (1110) ksec: branches NEXT[9] on STROBE | |
| 539 | ||
| 540 | f2_ether_eodfct = f2_task_10, //!< f2 (1000) ether: Ethernet output data function | |
| 541 | f2_ether_eosfct = f2_task_11, //!< f2 (1001) ether: Ethernet output start function | |
| 542 | f2_ether_erbfct = f2_task_12, //!< f2 (1010) ether: Ethernet reset branch function | |
| 543 | f2_ether_eefct = f2_task_13, //!< f2 (1011) ether: Ethernet end of transmission function | |
| 544 | f2_ether_ebfct = f2_task_14, //!< f2 (1100) ether: Ethernet branch function | |
| 545 | f2_ether_ecbfct = f2_task_15, //!< f2 (1101) ether: Ethernet countdown branch function | |
| 546 | f2_ether_eisfct = f2_task_16, //!< f2 (1110) ether: Ethernet input start function | |
| 547 | ||
| 548 | f2_dwt_load_ddr = f2_task_10, //!< f2 (1000) dwt: load display data register | |
| 549 | ||
| 550 | f2_curt_load_xpreg = f2_task_10, //!< f2 (1000) curt: load x position register | |
| 551 | f2_curt_load_csr = f2_task_11, //!< f2 (1001) curt: load cursor shift register | |
| 552 | ||
| 553 | f2_dht_evenfield = f2_task_10, //!< f2 (1000) dht: load even field | |
| 554 | f2_dht_setmode = f2_task_11, //!< f2 (1001) dht: set mode | |
| 555 | ||
| 556 | f2_dvt_evenfield = f2_task_10, //!< f2 (1000) dvt: load even field | |
| 557 | ||
| 558 | f2_kwd_init = f2_task_10, //!< f2 (1000) kwd: branches NEXT[5-9] on WDTASKACT && WDINIT | |
| 559 | f2_kwd_rwc = f2_task_11, //!< f2 (1001) kwd: branches NEXT[8-9] on READ/WRITE/CHECK for record | |
| 560 | f2_kwd_recno = f2_task_12, //!< f2 (1010) kwd: branches NEXT[8-9] on RECNO[0-1] | |
| 561 | f2_kwd_xfrdat = f2_task_13, //!< f2 (1011) kwd: branches NEXT[9] on !SEEKONLY | |
| 562 | f2_kwd_swrnrdy = f2_task_14, //!< f2 (1100) kwd: branches NEXT[9] on !SWRDY | |
| 563 | f2_kwd_nfer = f2_task_15, //!< f2 (1101) kwd: branches NEXT[9] on !KFER | |
| 564 | f2_kwd_strobon = f2_task_16, //!< f2 (1110) kwd: branches NEXT[9] on STROBE | |
| 565 | }; | |
| 566 | ||
| 567 | enum { | |
| 568 | p_dynamic, //!< dynamic functions (e.g. ALU and SHIFTER operations) | |
| 569 | p_latches //!< latching function (T, L, M, R, etc. register latch) | |
| 570 | }; | |
| 571 | ||
| 572 | ||
| 573 | /** | |
| 574 | * Bit field primitives | |
| 575 | * These are some inline functions to make it easier to access variable by the | |
| 576 | * bit-reversed notation that the Xerox Alto documents use all over the place. | |
| 577 | * Bit number 0 is the most significant there, and bit number (width - 1) | |
| 578 | * is the least significant. | |
| 579 | */ | |
| 580 | ||
| 581 | //! get the left shift required to access bit %to in a word of %width bits | |
| 582 | static inline UINT8 A2_BITSHIFT(UINT8 width, UINT8 to) { return width - 1 - to; } | |
| 583 | ||
| 584 | //! build a least significant bit mask for bits %from to %to (inclusive) | |
| 585 | static inline UINT32 A2_BITMASK(UINT8 from, UINT8 to) { return (1ul << (to + 1 - from)) - 1; } | |
| 586 | ||
| 587 | //! get a single bit number %bit value from %reg, a word of %width bits | |
| 588 | static inline UINT8 A2_BIT8(UINT8 reg, UINT8 width, UINT8 bit) { return (reg >> A2_BITSHIFT(width,bit)) & 1; } | |
| 589 | ||
| 590 | //! get a bit field from %reg, a word of %width bits, starting at bit %from until bit %to | |
| 591 | static inline UINT8 A2_GET8(UINT8 reg, UINT8 width, UINT8 from, UINT8 to) { return (reg >> A2_BITSHIFT(width,to)) & A2_BITMASK(from,to); } | |
| 592 | ||
| 593 | //! put a value %val into %reg, a word of %width bits, starting at bit %from until bit %to | |
| 594 | static inline void A2_PUT8(UINT8& reg, UINT8 width, UINT8 from, UINT8 to, UINT8 val) { | |
| 595 | UINT8 mask = A2_BITMASK(from,to) << A2_BITSHIFT(width,to); | |
| 596 | reg = (reg & ~mask) | ((val << A2_BITSHIFT(width,to)) & mask); | |
| 597 | } | |
| 598 | ||
| 599 | //! get a single bit number %bit value from %reg, a word of %width bits | |
| 600 | static inline UINT16 A2_BIT16(UINT16 reg, UINT8 width, UINT8 bit) { return (reg >> A2_BITSHIFT(width,bit)) & 1; } | |
| 601 | ||
| 602 | //! get a bit field from %reg, a word of %width bits, starting at bit %from until bit %to | |
| 603 | static inline UINT16 A2_GET16(UINT16 reg, UINT8 width, UINT8 from, UINT8 to) { return (reg >> A2_BITSHIFT(width,to)) & A2_BITMASK(from,to); } | |
| 604 | ||
| 605 | //! put a value %val into %reg, a word of %width bits, starting at bit %from until bit %to | |
| 606 | static inline void A2_PUT16(UINT16& reg, UINT8 width, UINT8 from, UINT8 to, UINT16 val) { | |
| 607 | UINT16 mask = A2_BITMASK(from,to) << A2_BITSHIFT(width,to); | |
| 608 | reg = (reg & ~mask) | ((val << A2_BITSHIFT(width,to)) & mask); | |
| 609 | } | |
| 610 | ||
| 611 | //! get a single bit number %bit value from %reg, a word of %width bits | |
| 612 | static inline UINT32 A2_BIT32(UINT32 reg, UINT8 width, UINT8 bit) { return (reg >> A2_BITSHIFT(width,bit)) & 1; } | |
| 613 | ||
| 614 | //! get a bit field from %reg, a word of %width bits, starting at bit %from until bit %to | |
| 615 | static inline UINT32 A2_GET32(UINT32 reg, UINT8 width, UINT8 from, UINT8 to) { return (reg >> A2_BITSHIFT(width,to)) & A2_BITMASK(from,to); } | |
| 616 | ||
| 617 | //! put a value %val into %reg, a word of %width bits, starting at bit %from until bit %to | |
| 618 | static inline void A2_PUT32(UINT32& reg, UINT8 width, UINT8 from, UINT8 to, UINT32 val) { | |
| 619 | UINT32 mask = A2_BITMASK(from,to) << A2_BITSHIFT(width,to); | |
| 620 | reg = (reg & ~mask) | ((val << A2_BITSHIFT(width,to)) & mask); | |
| 621 | } | |
| 622 | ||
| 623 | //! enumeration of the micro code word bits | |
| 624 | //! Note: The Alto documents enumerate bits from left (MSB = 0) to right (LSB = 31) | |
| 625 | enum { | |
| 626 | DRSEL0, DRSEL1, DRSEL2, DRSEL3, DRSEL4, | |
| 627 | DALUF0, DALUF1, DALUF2, DALUF3, | |
| 628 | DBS0, DBS1, DBS2, | |
| 629 | DF1_0, DF1_1, DF1_2, DF1_3, | |
| 630 | DF2_0, DF2_1, DF2_2, DF2_3, | |
| 631 | LOADT, | |
| 632 | LOADL, | |
| 633 | NEXT0, NEXT1, NEXT2, NEXT3, NEXT4, NEXT5, NEXT6, NEXT7, NEXT8, NEXT9 | |
| 634 | }; | |
| 635 | ||
| 636 | //! inverted bits in the micro instruction 32 bit word | |
| 637 | static const UINT32 ALTO2_UCODE_INVERTED = ((1 << (31 - DF1_0)) | (1 << (31 - DF2_0)) | (1 << (31 - LOADL))); | |
| 638 | ||
| 639 | //! get the RSEL value from a micro instruction word | |
| 640 | static inline UINT32 MIR_RSEL(UINT32 mir) { return A2_GET32(mir, 32, DRSEL0, DRSEL4); } | |
| 641 | ||
| 642 | //! get the ALUF value from a micro instruction word | |
| 643 | static inline UINT32 MIR_ALUF(UINT32 mir) { return A2_GET32(mir, 32, DALUF0, DALUF3); } | |
| 644 | ||
| 645 | //! get the BS value from a micro instruction word | |
| 646 | static inline UINT32 MIR_BS(UINT32 mir) { return A2_GET32(mir, 32, DBS0, DBS2); } | |
| 647 | ||
| 648 | //! get the F1 value from a micro instruction word | |
| 649 | static inline UINT32 MIR_F1(UINT32 mir) { return A2_GET32(mir, 32, DF1_0, DF1_3); } | |
| 650 | ||
| 651 | //! get the F2 value from a micro instruction word | |
| 652 | static inline UINT32 MIR_F2(UINT32 mir) { return A2_GET32(mir, 32, DF2_0, DF2_3); } | |
| 653 | ||
| 654 | //! get the T value from a micro instruction word | |
| 655 | static inline UINT32 MIR_T(UINT32 mir) { return A2_BIT32(mir, 32, LOADT); } | |
| 656 | ||
| 657 | //! get the L value from a micro instruction word | |
| 658 | static inline UINT32 MIR_L(UINT32 mir) { return A2_BIT32(mir, 32, LOADL); } | |
| 659 | ||
| 660 | //! get the NEXT value from a micro instruction word | |
| 661 | static inline UINT32 MIR_NEXT(UINT32 mir) { return A2_GET32(mir, 32, NEXT0, NEXT9); } | |
| 662 | ||
| 663 | //! get the normally accessed bank number from a bank register | |
| 664 | static inline UINT16 GET_BANK_NORMAL(UINT16 breg) { return A2_GET16(breg,16,12,13); } | |
| 665 | ||
| 666 | //! get the extended bank number (accessed via XMAR) from a bank register | |
| 667 | static inline UINT16 GET_BANK_EXTENDED(UINT16 breg) { return A2_GET16(breg,16,14,15); } | |
| 668 | ||
| 669 | //! get an ignored bit field from a control RAM address | |
| 670 | static inline UINT16 GET_CRAM_IGNORE(UINT16 addr) { return A2_GET16(addr,16,0,1); } | |
| 671 | ||
| 672 | //! get the bank select bit field from a control RAM address | |
| 673 | static inline UINT16 GET_CRAM_BANKSEL(UINT16 addr) { return A2_GET16(addr,16,2,3); } | |
| 674 | ||
| 675 | //! get the ROM/RAM flag from a control RAM address | |
| 676 | static inline UINT16 GET_CRAM_RAMROM(UINT16 addr) { return A2_GET16(addr,16,4,4); } | |
| 677 | ||
| 678 | //! get the half select flag from a control RAM address | |
| 679 | static inline UINT16 GET_CRAM_HALFSEL(UINT16 addr) { return A2_GET16(addr,16,5,5); } | |
| 680 | ||
| 681 | //! get the word address bit field from a control RAM address | |
| 682 | static inline UINT16 GET_CRAM_WORDADDR(UINT16 addr) { return A2_GET16(addr,16,6,15); } | |
| 683 | ||
| 684 | UINT16 m_task_mpc[ALTO2_TASKS]; //!< per task micro program counter | |
| 685 | UINT16 m_task_next2[ALTO2_TASKS]; //!< per task address modifier | |
| 686 | attoseconds_t m_ntime[ALTO2_TASKS]; //!< per task atto seconds executed | |
| 687 | UINT8 m_task; //!< active task | |
| 688 | UINT8 m_next_task; //!< next micro instruction's task | |
| 689 | UINT8 m_next2_task; //!< next but one micro instruction's task | |
| 690 | UINT16 m_mpc; //!< micro program counter | |
| 691 | UINT32 m_mir; //!< micro instruction register | |
| 692 | ||
| 693 | /** | |
| 694 | * \brief current micro instruction's register selection | |
| 695 | * The emulator F2s ACSOURCE and ACDEST modify this. | |
| 696 | * Note: S registers are addressed by the original RSEL[0-4], | |
| 697 | * even when the the emulator modifies this. | |
| 698 | */ | |
| 699 | UINT8 m_rsel; | |
| 700 | ||
| 701 | UINT16 m_next; //!< current micro instruction's next | |
| 702 | UINT16 m_next2; //!< next micro instruction's next | |
| 703 | UINT16 m_r[ALTO2_REGS]; //!< R register file | |
| 704 | UINT16 m_s[ALTO2_SREG_BANKS][ALTO2_REGS]; //!< S register file(s) | |
| 705 | UINT16 m_bus; //!< wired-AND bus | |
| 706 | UINT16 m_t; //!< T register | |
| 707 | UINT16 m_alu; //!< the current ALU | |
| 708 | UINT16 m_aluc0; //!< the current ALU carry output | |
| 709 | UINT16 m_l; //!< L register | |
| 710 | UINT16 m_shifter; //!< shifter output | |
| 711 | UINT16 m_laluc0; //!< the latched ALU carry output | |
| 712 | UINT16 m_m; //!< M register of RAM related tasks (MYL latch in the schematics) | |
| 713 | UINT16 m_cram_addr; //!< constant RAM address | |
| 714 | UINT16 m_task_wakeup; //!< task wakeup: bit 1<<n set if task n requesting service | |
| 715 | a2func m_active_callback[ALTO2_TASKS]; //!< task activation callbacks | |
| 716 | ||
| 717 | UINT16 m_reset_mode; //!< reset mode register: bit 1<<n set if task n starts in ROM | |
| 718 | bool m_rdram_flag; //!< set by rdram, action happens on next cycle | |
| 719 | bool m_wrtram_flag; //!< set by wrtram, action happens on next cycle | |
| 720 | ||
| 721 | UINT8 m_s_reg_bank[ALTO2_TASKS]; //!< active S register bank per task | |
| 722 | UINT8 m_bank_reg[ALTO2_TASKS]; //!< normal and extended RAM banks per task | |
| 723 | bool m_ether_enable; //!< set to true, if the ethernet should be simulated | |
| 724 | bool m_ewfct; //!< set by Ether task when it want's a wakeup at switch to task_mrt | |
| 725 | int m_dsp_time; //!< display_state_machine() time accu | |
| 726 | int m_dsp_state; //!< display_state_machine() previous state | |
| 727 | int m_unload_time; //!< unload word time accu | |
| 728 | int m_unload_word; //!< unload word number | |
| 729 | ||
| 730 | static const char *task_name(int task); //!< human readable task names | |
| 731 | static const char *r_name(UINT8 reg); //!< human readable register names | |
| 732 | static const char *aluf_name(UINT8 aluf); //!< human readable ALU function names | |
| 733 | static const char *bs_name(UINT8 bs); //!< human readable bus source names | |
| 734 | static const char *f1_name(UINT8 f1); //!< human readable F1 function names | |
| 735 | static const char *f2_name(UINT8 f2); //!< human readable F2 function names | |
| 736 | ||
| 737 | UINT32 m_ucode_raw[ALTO2_UCODE_SIZE]; //!< raw microcode words, decoded | |
| 738 | UINT16 m_const_prom[ALTO2_CONST_SIZE]; //!< constant PROM, decoded | |
| 739 | ||
| 740 | /** | |
| 741 | * @brief 2KCTL PROM u3 - 256x4 | |
| 742 | * <PRE> | |
| 743 | * PROM u3 is 256x4 type 3601-1, looks like SN74387, and it | |
| 744 | * controls NEXT[6-9]', i.e. the outputs are wire-AND to NEXT | |
| 745 | * | |
| 746 | * SN74387 | |
| 747 | * +---+-+---+ | |
| 748 | * | +-+ | | |
| 749 | * A6 -|1 16|- Vcc | |
| 750 | * | | | |
| 751 | * A5 -|2 15|- A7 | |
| 752 | * | | | |
| 753 | * A4 -|3 14|- FE1' | |
| 754 | * | | | |
| 755 | * A3 -|4 13|- FE2' | |
| 756 | * | | | |
| 757 | * A0 -|5 12|- D0 | |
| 758 | * | | | |
| 759 | * A1 -|6 11|- D1 | |
| 760 | * | | | |
| 761 | * A2 -|7 10|- D2 | |
| 762 | * | | | |
| 763 | * GND -|8 9|- D3 | |
| 764 | * | | | |
| 765 | * +---------+ | |
| 766 | * | |
| 767 | * | |
| 768 | * It is enabled whenever the Emulator task is active and: | |
| 769 | * both F2[0] and F2[1] are 1 F2 functions 014, 015, 016, 017 | |
| 770 | * F2=14 is 0 not for F2 = 14 (load IR<-) | |
| 771 | * IR[0] is 0 not for arithmetic group | |
| 772 | * | |
| 773 | * This means it controls the F2 functions 015:IDISP<- and 016:<-ACSOURCE | |
| 774 | * | |
| 775 | * Its address lines are: | |
| 776 | * line pin connected to load swap | |
| 777 | * ------------------------------------------------------------------- | |
| 778 | * A0 5 F2[2] (i.e. MIR[18]) IR[07] | |
| 779 | * A1 6 IR[01] IR[06] | |
| 780 | * A2 7 IR[02] IR[05] | |
| 781 | * A3 4 IR[03] IR[04] | |
| 782 | * A4 3 IR[04] IR[03] | |
| 783 | * A5 2 IR[05] IR[02] | |
| 784 | * A6 1 IR[06] IR[01] | |
| 785 | * A7 15 IR[07] F2[2] | |
| 786 | * | |
| 787 | * Its data lines are: | |
| 788 | * line pin connected to load | |
| 789 | * ------------------------------------------------------------------- | |
| 790 | * D3 9 NEXT[06]' NEXT[06] | |
| 791 | * D2 10 NEXT[07]' NEXT[07] | |
| 792 | * D1 11 NEXT[08]' NEXT[08] | |
| 793 | * D0 12 NEXT[09]' NEXT[09] | |
| 794 | * | |
| 795 | * Its address lines are reversed at load time to make it easier to | |
| 796 | * access it. Also both, address and data lines, are inverted. | |
| 797 | * </PRE> | |
| 798 | */ | |
| 799 | UINT8 m_ctl2k_u3[256]; | |
| 800 | ||
| 801 | /** | |
| 802 | * @brief 2KCTL PROM u38; 82S23; 32x8 bit | |
| 803 | * <PRE> | |
| 804 | * | |
| 805 | * 82S23 | |
| 806 | * +---+-+---+ | |
| 807 | * | +-+ | | |
| 808 | * B0 -|1 16|- Vcc | |
| 809 | * | | | |
| 810 | * B1 -|2 15|- EN' | |
| 811 | * | | | |
| 812 | * B2 -|3 14|- A4 | |
| 813 | * | | | |
| 814 | * B3 -|4 13|- A3 | |
| 815 | * | | | |
| 816 | * B4 -|5 12|- A2 | |
| 817 | * | | | |
| 818 | * B5 -|6 11|- A1 | |
| 819 | * | | | |
| 820 | * B6 -|7 10|- A0 | |
| 821 | * | | | |
| 822 | * GND -|8 9|- B7 | |
| 823 | * | | | |
| 824 | * +---------+ | |
| 825 | * | |
| 826 | * Task priority encoder | |
| 827 | * | |
| 828 | * line pin signal | |
| 829 | * ------------------------------- | |
| 830 | * A0 10 CT1 (current task LSB) | |
| 831 | * A1 11 CT2 | |
| 832 | * A2 12 CT4 | |
| 833 | * A3 13 CT8 (current task MSB) | |
| 834 | * A4 14 0 (GND) | |
| 835 | * | |
| 836 | * line pin signal | |
| 837 | * ------------------------------- | |
| 838 | * B0 1 RDCT8' | |
| 839 | * B1 2 RDCT4' | |
| 840 | * B2 3 RDCT2' | |
| 841 | * B3 4 RDCT1' | |
| 842 | * B4 5 NEXT[09]' | |
| 843 | * B5 6 NEXT[08]' | |
| 844 | * B6 7 NEXT[07]' | |
| 845 | * B7 9 NEXT[06]' | |
| 846 | * </PRE> | |
| 847 | */ | |
| 848 | UINT8 m_ctl2k_u38[32]; | |
| 849 | ||
| 850 | //! output lines of the 2KCTL U38 PROM | |
| 851 | enum { | |
| 852 | U38_RDCT8, | |
| 853 | U38_RDCT4, | |
| 854 | U38_RDCT2, | |
| 855 | U38_RDCT1, | |
| 856 | U38_NEXT09, | |
| 857 | U38_NEXT08, | |
| 858 | U38_NEXT07, | |
| 859 | U38_NEXT06 | |
| 860 | }; | |
| 861 | ||
| 862 | /** | |
| 863 | * @brief 2KCTL PROM u76; P3601-1; 256x4; PC0I and PC1I decoding | |
| 864 | * <PRE> | |
| 865 | * Replacement for u51, which is used in 1KCTL | |
| 866 | * | |
| 867 | * SN74387 | |
| 868 | * +---+-+---+ | |
| 869 | * | +-+ | | |
| 870 | * A6 -|1 16|- Vcc | |
| 871 | * | | | |
| 872 | * A5 -|2 15|- A7 | |
| 873 | * | | | |
| 874 | * A4 -|3 14|- FE1' | |
| 875 | * | | | |
| 876 | * A3 -|4 13|- FE2' | |
| 877 | * | | | |
| 878 | * A0 -|5 12|- D0 | |
| 879 | * | | | |
| 880 | * A1 -|6 11|- D1 | |
| 881 | * | | | |
| 882 | * A2 -|7 10|- D2 | |
| 883 | * | | | |
| 884 | * GND -|8 9|- D3 | |
| 885 | * | | | |
| 886 | * +---------+ | |
| 887 | * | |
| 888 | * input line signal | |
| 889 | * ---------------------------- | |
| 890 | * A7 15 EMACT' | |
| 891 | * A6 1 F1(0) | |
| 892 | * A5 2 F1(1)' | |
| 893 | * A4 3 F1(2)' | |
| 894 | * A3 4 F1(3)' | |
| 895 | * A2 7 0 (GND) | |
| 896 | * A1 6 PC1O | |
| 897 | * A0 5 PC0O | |
| 898 | * | |
| 899 | * output line signal | |
| 900 | * ---------------------------- | |
| 901 | * D0 12 PC1T | |
| 902 | * D1 11 PC1F | |
| 903 | * D2 10 PC0T | |
| 904 | * D3 9 PC0F | |
| 905 | * | |
| 906 | * The outputs are connected to a dual 4:1 demultiplexer 74S153, so that | |
| 907 | * depending on NEXT01' and RESET the following signals are passed through: | |
| 908 | * | |
| 909 | * RESET NEXT[01]' PC0I PC1I | |
| 910 | * -------------------------------------- | |
| 911 | * 0 0 PC0T PC1T | |
| 912 | * 0 1 PC0F PC1F | |
| 913 | * 1 0 PC0I4 T14 (?) | |
| 914 | * 1 1 -"- -"- | |
| 915 | * | |
| 916 | * This selects the microcode "page" to jump to on SWMODE (F1 = 010) | |
| 917 | * depending on the current NEXT[01]' level. | |
| 918 | * </PRE> | |
| 919 | */ | |
| 920 | UINT8 m_ctl2k_u76[256]; | |
| 921 | ||
| 922 | /** | |
| 923 | * @brief 3k CRAM PROM a37 | |
| 924 | */ | |
| 925 | UINT8 m_cram3k_a37[256]; | |
| 926 | ||
| 927 | /** | |
| 928 | * @brief memory addressing PROM a64 | |
| 929 | */ | |
| 930 | UINT8 m_madr_a64[256]; | |
| 931 | ||
| 932 | /** | |
| 933 | * @brief memory addressing PROM a65 | |
| 934 | */ | |
| 935 | UINT8 m_madr_a65[256]; | |
| 936 | ||
| 937 | //! per task bus source function pointers, early (0) and late (1) | |
| 938 | a2func m_bs[2][ALTO2_TASKS][ALTO2_BUSSRC]; | |
| 939 | void set_bs(UINT8 task, UINT8 fn, a2func f0, a2func f1) { | |
| 940 | m_bs[0][task][fn] = f0; | |
| 941 | m_bs[1][task][fn] = f1; | |
| 942 | } | |
| 943 | ||
| 944 | //! per task f1 function pointers, early (0) and late (1) | |
| 945 | a2func m_f1[2][ALTO2_TASKS][ALTO2_F1MAX]; | |
| 946 | void set_f1(UINT8 task, UINT8 fn, a2func f0, a2func f1) { | |
| 947 | m_f1[0][task][fn] = f0; | |
| 948 | m_f1[1][task][fn] = f1; | |
| 949 | } | |
| 950 | ||
| 951 | //! per task f2 function pointers, early (0) and late (1) | |
| 952 | a2func m_f2[2][ALTO2_TASKS][ALTO2_F2MAX]; | |
| 953 | void set_f2(UINT8 task, UINT8 fn, a2func f0, a2func f1) { | |
| 954 | m_f2[0][task][fn] = f0; | |
| 955 | m_f2[1][task][fn] = f1; | |
| 956 | } | |
| 957 | ||
| 958 | bool m_ram_related[ALTO2_TASKS]; //!< set when task is RAM related | |
| 959 | ||
| 960 | UINT64 m_cycle; //!< number of cycles executed in the current slice | |
| 961 | int m_alto_leave; //!< flag set by timer.c if alto_execute() shall leave its loop | |
| 962 | ||
| 963 | UINT64 cycle() { return m_cycle; } //!< return the current CPU cycle | |
| 964 | ||
| 965 | void hard_reset(); //!< reset the various registers | |
| 966 | int soft_reset(); //!< soft reset | |
| 967 | ||
| 968 | void fn_bs_bad_0(); //! bs dummy early function | |
| 969 | void fn_bs_bad_1(); //! bs dummy late function | |
| 970 | ||
| 971 | void fn_f1_bad_0(); //! f1 dummy early function | |
| 972 | void fn_f1_bad_1(); //! f1 dummy late function | |
| 973 | ||
| 974 | void fn_f2_bad_0(); //! f2 dummy early function | |
| 975 | void fn_f2_bad_1(); //! f2 dummy late function | |
| 976 | ||
| 977 | UINT16 bank_reg_r(UINT32 address); //!< read bank register in memory mapped I/O range | |
| 978 | void bank_reg_w(UINT32 address, UINT16 data); //!< write bank register in memory mapped I/O range | |
| 979 | ||
| 980 | void bs_read_r_0(); //!< bs_read_r early: drive bus by R register | |
| 981 | void bs_load_r_0(); //!< bs_load_r early: load R places 0 on the BUS | |
| 982 | void bs_load_r_1(); //!< bs_load_r late: load R from SHIFTER | |
| 983 | void bs_read_md_0(); //!< bs_read_md early: drive BUS from read memory data | |
| 984 | void bs_mouse_0(); //!< bs_mouse early: drive bus by mouse | |
| 985 | void bs_disp_0(); //!< bs_disp early: drive bus by displacement (which?) | |
| 986 | void f1_load_mar_1(); //!< f1_load_mar late: load memory address register | |
| 987 | void f1_task_0(); //!< f1_task early: task switch | |
| 988 | void f2_bus_eq_zero_1(); //!< f2_bus_eq_zero late: branch on bus equals zero | |
| 989 | void f2_shifter_lt_zero_1(); //!< f2_shifter_lt_zero late: branch on shifter less than zero | |
| 990 | void f2_shifter_eq_zero_1(); //!< f2_shifter_eq_zero late: branch on shifter equals zero | |
| 991 | void f2_bus_1(); //!< f2_bus late: branch on bus bits BUS[6-15] | |
| 992 | void f2_alucy_1(); //!< f2_alucy late: branch on latched ALU carry | |
| 993 | void f2_load_md_1(); //!< f2_load_md late: load memory data | |
| 994 | ||
| 995 | UINT32 alu_74181(UINT32 smc); | |
| 996 | ||
| 997 | void rdram(); //!< read the microcode ROM/RAM halfword | |
| 998 | void wrtram(); //!< write the microcode RAM from M register and ALU | |
| 999 | ||
| 1000 | // ************************************************ | |
| 1001 | // ram related stuff | |
| 1002 | // ************************************************ | |
| 1003 | void bs_read_sreg_0(); //!< bs_read_sreg early: drive bus by S register or M (MYL), if rsel is = 0 | |
| 1004 | void bs_load_sreg_0(); //!< bs_load_sreg early: load S register puts garbage on the bus | |
| 1005 | void bs_load_sreg_1(); //!< bs_load_sreg late: load S register from M | |
| 1006 | void branch_ROM(const char *from, int page); //!< branch to ROM page | |
| 1007 | void branch_RAM(const char *from, int page); //!< branch to RAM page | |
| 1008 | void f1_swmode_1(); //!< f1_swmode early: switch to micro program counter BUS[6-15] in other bank | |
| 1009 | void f1_wrtram_1(); //!< f1_wrtram late: start WRTRAM cycle | |
| 1010 | void f1_rdram_1(); //!< f1_rdram late: start RDRAM cycle | |
| 1011 | #if (ALTO2_UCODE_RAM_PAGES == 3) | |
| 1012 | void f1_load_rmr_1(); //!< f1_load_rmr late: load the reset mode register | |
| 1013 | #else // ALTO2_UCODE_RAM_PAGES != 3 | |
| 1014 | void f1_load_srb_1(); //!< f1_load_srb late: load the S register bank from BUS[12-14] | |
| 1015 | #endif | |
| 1016 | void init_ram(int task); //!< | |
| 1017 | ||
| 1018 | // ************************************************ | |
| 1019 | // memory mapped i/o stuff | |
| 1020 | // ************************************************ | |
| 1021 | /** | |
| 1022 | * @brief get printer paper ready bit | |
| 1023 | * Paper ready bit. 0 when the printer is ready for a paper scrolling operation. | |
| 1024 | */ | |
| 1025 | static inline UINT16 GET_PPRDY(UINT16 utilin) { return A2_GET16(utilin,16,0,0); } | |
| 1026 | ||
| 1027 | /** @brief put printer paper ready bit */ | |
| 1028 | static inline void PUT_PPRDY(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,0,0,val); } | |
| 1029 | ||
| 1030 | /** | |
| 1031 | * @brief get printer check bit | |
| 1032 | * Printer check bit bit. Should the printer find itself in an abnormal state, | |
| 1033 | * it sets this bit to 0 | |
| 1034 | */ | |
| 1035 | static inline UINT16 GET_PCHECK(UINT16 utilin) { return A2_GET16(utilin,16,1,1); } | |
| 1036 | ||
| 1037 | /** @brief put printer check bit */ | |
| 1038 | static inline void PUT_PCHECK(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,1,1,val); } | |
| 1039 | ||
| 1040 | /** @brief get unused bit 2 */ | |
| 1041 | static inline UINT16 GET_UNUSED_2(UINT16 utilin) { return A2_GET16(utilin,16,2,2); } | |
| 1042 | ||
| 1043 | /** @brief put unused bit 2 */ | |
| 1044 | static inline void PUT_UNUSED_2(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,2,2,val); } | |
| 1045 | ||
| 1046 | /** | |
| 1047 | * @brief get printer daisy ready bit | |
| 1048 | * Daisy ready bit. 0 when the printer is ready to print a character. | |
| 1049 | */ | |
| 1050 | static inline UINT16 GET_PCHRDY(UINT16 utilin) { return A2_GET16(utilin,16,3,3); } | |
| 1051 | ||
| 1052 | /** @brief put printer daisy ready bit */ | |
| 1053 | static inline void PUT_PCHRDY(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,3,3,val); } | |
| 1054 | ||
| 1055 | /** | |
| 1056 | * @brief get printer carriage ready bit | |
| 1057 | * Carriage ready bit. 0 when the printer is ready for horizontal positioning. | |
| 1058 | */ | |
| 1059 | static inline UINT16 GET_PCARRDY(UINT16 utilin) { return A2_GET16(utilin,16,4,4); } | |
| 1060 | ||
| 1061 | /** @brief put printer carriage ready bit */ | |
| 1062 | static inline void PUT_PCARRDY(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,4,4,val); } | |
| 1063 | ||
| 1064 | /** | |
| 1065 | * @brief get printer ready bit | |
| 1066 | * Ready bit. Both this bit and the appropriate other ready bit (carriage, | |
| 1067 | * daisy, etc.) must be 0 before attempting any output operation. | |
| 1068 | */ | |
| 1069 | static inline UINT16 GET_PREADY(UINT16 utilin) { return A2_GET16(utilin,16,5,5); } | |
| 1070 | ||
| 1071 | /** @brief put printer ready bit */ | |
| 1072 | static inline void PUT_PREADY(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,5,5,val); } | |
| 1073 | ||
| 1074 | /** | |
| 1075 | * @brief memory configuration switch | |
| 1076 | */ | |
| 1077 | static inline UINT16 GET_MEMCONFIG(UINT16 utilin) { return A2_GET16(utilin,16,6,6); } | |
| 1078 | ||
| 1079 | /** @brief put memory configuration switch */ | |
| 1080 | static inline void PUT_MEMCONFIG(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,6,6,val); } | |
| 1081 | ||
| 1082 | /** @brief get unused bit 7 */ | |
| 1083 | static inline UINT16 GET_UNUSED_7(UINT16 utilin) { return A2_GET16(utilin,16,7,7); } | |
| 1084 | /** @brief put unused bit 7 */ | |
| 1085 | static inline void PUT_UNUSED_7(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,7,7,val); } | |
| 1086 | ||
| 1087 | /** @brief get key set key 0 */ | |
| 1088 | static inline UINT16 GET_KEYSET_KEY0(UINT16 utilin) { return A2_GET16(utilin,16,8,8); } | |
| 1089 | /** @brief put key set key 0 */ | |
| 1090 | static inline void PUT_KEYSET_KEY0(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,8,8,val); } | |
| 1091 | ||
| 1092 | /** @brief get key set key 1 */ | |
| 1093 | static inline UINT16 GET_KEYSET_KEY1(UINT16 utilin) { return A2_GET16(utilin,16,9,9); } | |
| 1094 | /** @brief put key set key 1 */ | |
| 1095 | static inline void PUT_KEYSET_KEY1(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,9,9,val); } | |
| 1096 | ||
| 1097 | /** @brief get key set key 2 */ | |
| 1098 | static inline UINT16 GET_KEYSET_KEY2(UINT16 utilin) { return A2_GET16(utilin,16,10,10); } | |
| 1099 | /** @brief put key set key 2 */ | |
| 1100 | static inline void PUT_KEYSET_KEY2(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,10,10,val); } | |
| 1101 | ||
| 1102 | /** @brief get key set key 3 */ | |
| 1103 | static inline UINT16 GET_KEYSET_KEY3(UINT16 utilin) { return A2_GET16(utilin,16,11,11); } | |
| 1104 | /** @brief put key set key 3 */ | |
| 1105 | static inline void PUT_KEYSET_KEY3(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,11,11,val); } | |
| 1106 | ||
| 1107 | /** @brief get key set key 4 */ | |
| 1108 | static inline UINT16 GET_KEYSET_KEY4(UINT16 utilin) { return A2_GET16(utilin,16,12,12); } | |
| 1109 | /** @brief put key set key 4 */ | |
| 1110 | static inline void PUT_KEYSET_KEY4(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,12,12,val); } | |
| 1111 | ||
| 1112 | /** @brief get mouse red button bit */ | |
| 1113 | static inline UINT16 GET_MOUSE_RED(UINT16 utilin) { return A2_GET16(utilin,16,13,13); } | |
| 1114 | /** @brief put mouse red button bit */ | |
| 1115 | static inline void PUT_MOUSE_RED(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,13,13,val); } | |
| 1116 | ||
| 1117 | /** @brief get mouse blue button bit */ | |
| 1118 | static inline UINT16 GET_MOUSE_BLUE(UINT16 utilin) { return A2_GET16(utilin,16,14,14); } | |
| 1119 | /** @brief put mouse blue button bit */ | |
| 1120 | static inline void PUT_MOUSE_BLUE(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,14,14,val); } | |
| 1121 | ||
| 1122 | /** @brief get mouse yellow button bit */ | |
| 1123 | static inline UINT16 GET_MOUSE_YELLOW(UINT16 utilin) { return A2_GET16(utilin,16,15,15); } | |
| 1124 | /** @brief put mouse yellow button bit */ | |
| 1125 | static inline void PUT_MOUSE_YELLOW(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,15,15,val); } | |
| 1126 | ||
| 1127 | /** @brief put mouse bits */ | |
| 1128 | static inline void PUT_MOUSE(UINT16& utilin, UINT16 val) { A2_PUT16(utilin,16,13,15,val); } | |
| 1129 | ||
| 1130 | /** | |
| 1131 | * @brief printer paper strobe bit | |
| 1132 | * Paper strobe bit. Toggling this bit causes a paper scrolling operation. | |
| 1133 | */ | |
| 1134 | static inline UINT16 GET_PPPSTR(UINT16 utilout) { return A2_GET16(utilout,16,0,0); } | |
| 1135 | ||
| 1136 | /** | |
| 1137 | * @brief printer retstore bit | |
| 1138 | * Restore bit. Toggling this bit resets the printer (including clearing | |
| 1139 | * the "check" condition if present) and moves the carriage to the | |
| 1140 | * left margin. | |
| 1141 | */ | |
| 1142 | static inline UINT16 GET_PREST(UINT16 utilout) { return A2_GET16(utilout,16,1,1); } | |
| 1143 | ||
| 1144 | /** | |
| 1145 | * @brief printer ribbon bit | |
| 1146 | * Ribbon bit. When this bit is 1 the ribbon is up (in printing | |
| 1147 | * position); when 0, it is down. | |
| 1148 | */ | |
| 1149 | static inline UINT16 GET_PRIB(UINT16 utilout) { return A2_GET16(utilout,16,2,2); } | |
| 1150 | ||
| 1151 | /** | |
| 1152 | * @brief printer daisy strobe bit | |
| 1153 | * Daisy strobe bit. Toggling this bit causes a character to be printed. | |
| 1154 | */ | |
| 1155 | static inline UINT16 GET_PCHSTR(UINT16 utilout) { return A2_GET16(utilout,16,3,3); } | |
| 1156 | ||
| 1157 | /** | |
| 1158 | * @brief printer carriage strobe bit | |
| 1159 | * Carriage strobe bit. Toggling this bit causes a horizontal position operation. | |
| 1160 | */ | |
| 1161 | static inline UINT16 GET_PCARSTR(UINT16 utilout) { return A2_GET16(utilout,16,4,4); } | |
| 1162 | ||
| 1163 | /** | |
| 1164 | * @brief printer data | |
| 1165 | * Argument to various output operations: | |
| 1166 | * 1. Printing characters. When the daisy bit is toggled bits 9-15 of this field | |
| 1167 | * are interpreted as an ASCII character code to be printed (it should be noted | |
| 1168 | * that all codes less than 040 print as lower case "w"). | |
| 1169 | * 2. For paper and carriage operations the field is interpreted as a displacement | |
| 1170 | * (-1024 to +1023), in units of 1/48 inch for paper and 1/60 inch for carriage. | |
| 1171 | * Positive is down or to the right, negative up or to the left. The value is | |
| 1172 | * represented as sign-magnitude (i.e., bit 5 is 1 for negative numbers, 0 for | |
| 1173 | * positive; bits 6-15 are the absolute value of the number). | |
| 1174 | */ | |
| 1175 | static inline UINT16 GET_PDATA(UINT16 utilout) { return A2_GET16(utilout,16,5,15); } | |
| 1176 | ||
| 1177 | /** @brief miscellaneous hardware registers in the memory mapped I/O range */ | |
| 1178 | struct { | |
| 1179 | UINT16 eia; //!< the EIA port at 0177001 | |
| 1180 | UINT16 utilout; //!< the UTILOUT port at 0177016 (active-low outputs) */ | |
| 1181 | UINT16 xbus[4]; //!< the XBUS port at 0177020 to 0177023 | |
| 1182 | UINT16 utilin; //!< the UTILIN port at 0177030 to 0177033 (same value on all addresses) | |
| 1183 | } m_hw; | |
| 1184 | ||
| 1185 | UINT16 utilin_r(UINT32 addr); //!< read an UTILIN address | |
| 1186 | UINT16 utilout_r(UINT32 addr); //!< read the UTILOUT address | |
| 1187 | void utilout_w(UINT32 addr, UINT16 data); //!< write the UTILOUT address | |
| 1188 | UINT16 xbus_r(UINT32 addr); //!< read an XBUS address | |
| 1189 | void xbus_w(UINT32 addr, UINT16 data); //!< write an XBUS address (?) | |
| 1190 | void init_hardware(); //!< initialize miscellaneous hardware | |
| 1191 | ||
| 1192 | // ************************************************ | |
| 1193 | // mouse stuff | |
| 1194 | // ************************************************ | |
| 1195 | /** | |
| 1196 | * @brief PROM madr.a32 contains a lookup table to translate mouse motions | |
| 1197 | * | |
| 1198 | * <PRE> | |
| 1199 | * The 4 mouse motion signals MX1, MX2, MY1, and MY2 are connected | |
| 1200 | * to a 256x4 PROM's (3601, SN74387) address lines A0, A2, A4, and A6. | |
| 1201 | * The previous (latched) state of the 4 signals is connected to the | |
| 1202 | * address lines A1, A3, A5, and A7. | |
| 1203 | * | |
| 1204 | * SN74387 | |
| 1205 | * +---+--+---+ | |
| 1206 | * | +--+ | | |
| 1207 | * MY2 A6 -|1 16|- Vcc | |
| 1208 | * | | | |
| 1209 | * LMY1 A5 -|2 15|- A7 LMY2 | |
| 1210 | * | | | |
| 1211 | * MY1 A4 -|3 14|- FE1' 0 | |
| 1212 | * | | | |
| 1213 | * LMX2 A3 -|4 13|- FE2' 0 | |
| 1214 | * | | | |
| 1215 | * MX1 A0 -|5 12|- D0 BUS[12] | |
| 1216 | * | | | |
| 1217 | * LMX1 A1 -|6 11|- D1 BUS[13] | |
| 1218 | * | | | |
| 1219 | * MX2 A2 -|7 10|- D2 BUS[14] | |
| 1220 | * | | | |
| 1221 | * GND -|8 9|- D3 BUS[15] | |
| 1222 | * | | | |
| 1223 | * +----------+ | |
| 1224 | * | |
| 1225 | * A motion to the west will first toggle MX2, then MX1. | |
| 1226 | * sequence: 04 -> 0d -> 0b -> 02 | |
| 1227 | * A motion to the east will first toggle MX1, then MX2. | |
| 1228 | * sequence: 01 -> 07 -> 0e -> 08 | |
| 1229 | * | |
| 1230 | * A motion to the north will first toggle MY2, then MY1. | |
| 1231 | * sequence: 40 -> d0 -> b0 -> 20 | |
| 1232 | * A motion to the south will first toggle MY1, then MY2. | |
| 1233 | * sequence: 10 -> 70 -> e0 -> 80 | |
| 1234 | * | |
| 1235 | * This dump is from PROM madr.a32: | |
| 1236 | * 0000: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1237 | * 0020: 003,015,005,003,005,003,003,015,015,003,003,005,003,005,015,003, | |
| 1238 | * 0040: 011,001,016,011,016,011,011,001,001,011,011,016,011,016,001,011, | |
| 1239 | * 0060: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1240 | * 0100: 011,001,016,011,016,011,011,001,001,011,011,016,011,016,001,011, | |
| 1241 | * 0120: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1242 | * 0140: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1243 | * 0160: 003,015,005,003,005,003,003,015,015,003,003,005,003,005,015,003, | |
| 1244 | * 0200: 003,015,005,003,005,003,003,015,015,003,003,005,003,005,015,003, | |
| 1245 | * 0220: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1246 | * 0240: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1247 | * 0260: 011,001,016,011,016,011,011,001,001,011,011,016,011,016,001,011, | |
| 1248 | * 0300: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017, | |
| 1249 | * 0320: 011,001,016,011,016,011,011,001,001,011,011,016,011,016,001,011, | |
| 1250 | * 0340: 003,015,005,003,005,003,003,015,015,003,003,005,003,005,015,003, | |
| 1251 | * 0360: 017,007,013,017,013,017,017,007,007,017,017,013,017,013,007,017 | |
| 1252 | * </PRE> | |
| 1253 | */ | |
| 1254 | UINT8 m_madr_a32[256]; | |
| 1255 | struct { | |
| 1256 | int x; | |
| 1257 | int y; | |
| 1258 | int dx; | |
| 1259 | int dy; | |
| 1260 | UINT8 latch; | |
| 1261 | } m_mouse; | |
| 1262 | ||
| 1263 | UINT16 mouse_read(); //!< return the mouse motion flags | |
| 1264 | void mouse_motion(int x, int y); //!< register a mouse motion | |
| 1265 | void mouse_button(int b); //!< register a mouse button change | |
| 1266 | void mouse_init(); //!< initialize the mouse context to useful values | |
| 1267 | ||
| 1268 | // ************************************************ | |
| 1269 | // diablo31 drive stuff | |
| 1270 | // ************************************************ | |
| 1271 | static const int DRIVE_MAX = 2; //!< max number of drive units | |
| 1272 | static const int DRIVE_CYLINDERS = 203; //!< number of cylinders per drive | |
| 1273 | static const int DRIVE_CYLINDER_MASK = 0777; //!< bit maks for cylinder number (9 bits) | |
| 1274 | static const int DRIVE_SPT = 12; //!< number of sectors per track | |
| 1275 | static const int DRIVE_SECTOR_MASK = 017; //!< bit maks for cylinder number (4 bits) | |
| 1276 | static const int DRIVE_HEADS = 2; //!< number of heads per drive | |
| 1277 | static const int DRIVE_PAGES = 203*2*12; //!< number of pages per drive | |
| 1278 | static const int DRIVE_HEAD_MASK = 1; //!< bit maks for cylinder number (4 bits) | |
| 1279 | //! convert a cylinder/head/sector to a logical block address (page) | |
| 1280 | static inline int DRIVE_PAGE(int c,int h,int s) { return (c * DRIVE_HEADS + h) * DRIVE_SPT + s; } | |
| 1281 | ||
| 1282 | void* m_drive[2]; //!< private drive data | |
| 1283 | int m_unit_selected; //!< selected drive unit | |
| 1284 | int m_head_selected; //!< selected drive head | |
| 1285 | a2cb m_sector_callback; //!< callback to call at the start of each sector | |
| 1286 | emu_timer* m_sector_timer; //!< sector timer | |
| 1287 | int drive_bits_per_sector() const; //!< return number of bitclk edges for a sector | |
| 1288 | const char* drive_description(int unit); //!< return a pointer to a drive's description | |
| 1289 | const char* drive_basename(int unit); //!< return a pointer to a drive's image basename | |
| 1290 | int drive_unit(int unit); //!< return the number of a drive unit | |
| 1291 | attotime drive_rotation_time(int unit); //!< return the atto time for a full rotation | |
| 1292 | attotime drive_bit_time(int unit); //!< return the atto time for a data bit | |
| 1293 | int drive_seek_read_write_0(int unit); //!< return the seek/read/write status of a drive | |
| 1294 | int drive_ready_0(int unit); //!< return the ready status of a drive | |
| 1295 | int drive_sector_mark_0(int unit); //!< return the current sector mark status of a drive | |
| 1296 | int drive_addx_acknowledge_0(int unit); //!< return the address acknowledge state | |
| 1297 | int drive_log_addx_interlock_0(int unit); //!< return the log address interlock state | |
| 1298 | int drive_seek_incomplete_0(int unit); //!< return the seek incomplete state | |
| 1299 | int drive_cylinder(int unit); //!< return the current cylinder of a drive unit | |
| 1300 | int drive_head(int unit); //!< return the current head of a drive unit | |
| 1301 | int drive_sector(int unit); //!< return the current sector of a drive unit | |
| 1302 | int drive_page(int unit); //!< return the current page of a drive unit | |
| 1303 | void drive_select(int unit, int head); //!< select a drive unit and head | |
| 1304 | void drive_sector_callback(a2cb callback); //!< set a new drive sector callback | |
| 1305 | void drive_strobe(int unit, int cylinder, int restore, int strobe); //!< strobe a seek operation | |
| 1306 | void drive_egate(int unit, int gate); //!< set the drive erase gate | |
| 1307 | void drive_wrgate(int unit, int gate); //!< set the drive write gate | |
| 1308 | void drive_rdgate(int unit, int gate); //!< set the drive read gate | |
| 1309 | void drive_wrdata(int unit, int index, int wrdata); //!< write the sector relative bit at index | |
| 1310 | int drive_rddata(int unit, int index); //!< read the sector relative bit at index | |
| 1311 | int drive_rdclk(int unit, int index); //!< get the sector relative clock at index | |
| 1312 | int debug_read_sync(int unit, int page, int offs); //!< debug function to read sync bit position from a sector | |
| 1313 | int debug_read_sec(int unit, int page, int offs); //!< debug function to read bits from a drive sector | |
| 1314 | TIMER_CALLBACK_MEMBER( drive_next_sector ); //!< timer callback that is called once per sector in the rotation | |
| 1315 | void sector_mark_1(int unit); //!< deasserts the sector mark | |
| 1316 | void sector_mark_0(int unit); //!< asserts the sector mark | |
| 1317 | void drive_init(); //!< initialize the disk drive context and insert a disk word timer | |
| 1318 | ||
| 1319 | // ************************************************ | |
| 1320 | // disk controller stuff | |
| 1321 | // ************************************************ | |
| 1322 | ||
| 1323 | //! disk controller context | |
| 1324 | struct { | |
| 1325 | UINT8 drive; //!< selected drive from KADDR[14] (written to data out with SENDADR) | |
| 1326 | UINT16 kaddr; //!< A[0-15] disk hardware address (sector, cylinder, head, drive, restore) | |
| 1327 | UINT16 kadr; //!< C[0-15] with read/write/check modes for header, label and data | |
| 1328 | UINT16 kstat; //!< S[0-15] disk status | |
| 1329 | UINT16 kcom; //!< disk command (5 bits kcom[1-5]) | |
| 1330 | UINT8 krecno; //!< record number (2 bits indexing header, label, data, -/-) | |
| 1331 | UINT32 shiftin; //!< input shift register | |
| 1332 | UINT32 shiftout; //!< output shift register | |
| 1333 | UINT32 datain; //!< disk data in latch | |
| 1334 | UINT32 dataout; //!< disk data out latch | |
| 1335 | UINT8 krwc; //!< read/write/check for current record | |
| 1336 | UINT8 kfer; //!< disk fatal error signal state | |
| 1337 | UINT8 wdtskena; //!< disk word task enable (active low) | |
| 1338 | UINT8 wdinit0; //!< disk word task init at the early microcycle | |
| 1339 | UINT8 wdinit; //!< disk word task init at the late microcycle | |
| 1340 | UINT8 strobe; //!< strobe (still) active | |
| 1341 | emu_timer* strobon_timer; //!< set strobe on timer | |
| 1342 | UINT8 bitclk; //!< current bitclk state (either crystal clock, or rdclk from the drive) | |
| 1343 | emu_timer* bitclk_timer; //!< bit clock timer | |
| 1344 | UINT8 datin; //!< current datin from the drive | |
| 1345 | UINT8 bitcount; //!< bit counter | |
| 1346 | UINT8 carry; //!< carry output of the bitcounter | |
| 1347 | UINT8 seclate; //!< sector late (monoflop output) | |
| 1348 | emu_timer* seclate_timer; //!< sector late timer | |
| 1349 | UINT8 seekok; //!< seekok state (SKINC' & LAI' & ff_44a.Q') | |
| 1350 | UINT8 ok_to_run; //!< ok to run signal (set to 1 some time after reset) | |
| 1351 | emu_timer* ok_to_run_timer; //!< ok to run timer | |
| 1352 | UINT8 ready_mf31a; //!< ready monoflop 31a | |
| 1353 | emu_timer* ready_timer; //!< ready timer | |
| 1354 | UINT8 seclate_mf31b; //!< seclate monoflop 31b | |
| 1355 | jkff_t ff_21a; //!< JK flip-flop 21a (sector task) | |
| 1356 | jkff_t ff_21a_old; //!< -"- previous state | |
| 1357 | jkff_t ff_21b; //!< JK flip-flop 21b (sector task) | |
| 1358 | jkff_t ff_22a; //!< JK flip-flop 22a (sector task) | |
| 1359 | jkff_t ff_22b; //!< JK flip-flop 22b (sector task) | |
| 1360 | jkff_t ff_43b; //!< JK flip-flop 43b (word task) | |
| 1361 | jkff_t ff_53a; //!< JK flip-flop 53a (word task) | |
| 1362 | jkff_t ff_43a; //!< JK flip-flop 43a (word task) | |
| 1363 | jkff_t ff_53b; //!< brief JK flip-flop 53b (word task) | |
| 1364 | jkff_t ff_44a; //!< JK flip-flop 44a (LAI' clocked) | |
| 1365 | jkff_t ff_44b; //!< JK flip-flop 44b (CKSUM) | |
| 1366 | jkff_t ff_45a; //!< JK flip-flop 45a (ready latch) | |
| 1367 | jkff_t ff_45b; //!< JK flip-flop 45b (seqerr latch) | |
| 1368 | } m_dsk; | |
| 1369 | ||
| 1370 | jkff_t m_sysclka0[4]; //!< simulate previous sysclka | |
| 1371 | jkff_t m_sysclka1[4]; //!< simulate current sysclka | |
| 1372 | jkff_t m_sysclkb0[4]; //!< simulate previous sysclkb | |
| 1373 | jkff_t m_sysclkb1[4]; //!< simulate current sysclkb | |
| 1374 | ||
| 1375 | void kwd_timing(int bitclk, int datin, int block); //!< disk word timing | |
| 1376 | TIMER_CALLBACK_MEMBER( disk_seclate ); //!< timer callback to take away the SECLATE pulse (monoflop) | |
| 1377 | TIMER_CALLBACK_MEMBER( disk_ok_to_run ); //!< timer callback to take away the OK TO RUN pulse (reset) | |
| 1378 | TIMER_CALLBACK_MEMBER( disk_strobon ); //!< timer callback to pulse the STROBE' signal to the drive | |
| 1379 | TIMER_CALLBACK_MEMBER( disk_ready_mf31a ); //!< timer callback to change the READY monoflop 31a | |
| 1380 | void disk_block(int task); //!< called if one of the disk tasks (task_kwd or task_ksec) blocks | |
| 1381 | void bs_read_kstat_0(); //!< bs_read_kstat early: bus driven by disk status register KSTAT | |
| 1382 | void bs_read_kdata_0(); //!< bs_read_kdata early: bus driven by disk data register KDATA input | |
| 1383 | void f1_strobe_1(); //!< f1_strobe late: initiates a disk seek | |
| 1384 | void f1_load_kstat_1(); //!< f1_load_kstat late: load disk status register | |
| 1385 | void f1_load_kdata_1(); //!< f1_load_kdata late: load data out register, or the disk address register | |
| 1386 | void f1_increcno_1(); //!< f1_increcno late: advances shift registers holding KADR | |
| 1387 | void f1_clrstat_1(); //!< f1_clrstat late: reset all error latches | |
| 1388 | void f1_load_kcom_1(); //!< f1_load_kcom late: load the KCOM register from bus | |
| 1389 | void f1_load_kadr_1(); //!< f1_load_kadr late: load the KADR register from bus | |
| 1390 | void f2_init_1(); //!< f2_init late: branch on disk word task active and init | |
| 1391 | void f2_rwc_1(); //!< f2_rwc late: branch on read/write/check state of the current record | |
| 1392 | void f2_recno_1(); //!< f2_recno late: branch on the current record number by a lookup table | |
| 1393 | void f2_xfrdat_1(); //!< f2_xfrdat late: branch on the data transfer state | |
| 1394 | void f2_swrnrdy_1(); //!< f2_swrnrdy late: branch on the disk ready signal | |
| 1395 | void f2_nfer_1(); //!< f2_nfer late: branch on the disk fatal error condition | |
| 1396 | void f2_strobon_1(); //!< f2_strobon late: branch on the seek busy status | |
| 1397 | TIMER_CALLBACK_MEMBER( disk_bitclk ); //!< callback to update the disk controller with a new bitclk | |
| 1398 | void disk_sector_start(int unit); //!< callback is called by the drive timer whenever a new sector starts | |
| 1399 | void init_disk(); //!< initialize the disk context and insert a disk wort timer | |
| 1400 | ||
| 1401 | // ************************************************ | |
| 1402 | // display stuff | |
| 1403 | // ************************************************ | |
| 1404 | /** | |
| 1405 | * @brief structure of the display context | |
| 1406 | * | |
| 1407 | * Schematics of the task clear and wakeup signal generators | |
| 1408 | * <PRE> | |
| 1409 | * A quote (') appended to a signal name means inverted signal. | |
| 1410 | * | |
| 1411 | * AND | NAND| NOR | FF | Q N174 | |
| 1412 | * -----+--- -----+--- -----+--- -----+--- ----- | |
| 1413 | * 0 0 | 0 0 0 | 1 0 0 | 1 S'\0| 1 delay | |
| 1414 | * 0 1 | 0 0 1 | 1 0 1 | 0 R'\0| 0 | |
| 1415 | * 1 0 | 0 1 0 | 1 1 0 | 0 | |
| 1416 | * 1 1 | 1 1 1 | 0 1 1 | 0 | |
| 1417 | * | |
| 1418 | * | |
| 1419 | * DVTAC' | |
| 1420 | * >-------· +-----+ | |
| 1421 | * | | FF | | |
| 1422 | * VBLANK'+----+ DELVBLANK' +---+ DELVBLANK +----+ ·--|S' | | |
| 1423 | * >------|N174|------+-----|inv|--------------|NAND| VBLANKPULSE | | WAKEDVT' | |
| 1424 | * +----+ | +---+ | o--+-----------|R' Q|----------------------> | |
| 1425 | * | ·-| | | | | | |
| 1426 | * +----+ | DDELVBLANK' | +----+ | +-----+ | |
| 1427 | * ·-|N174|-----------------------------· | +---+ | |
| 1428 | * | +----+ | +------oAND| | |
| 1429 | * | | DSP07.01 | | o----------· | |
| 1430 | * ·-------------· >---------|------o | | | |
| 1431 | * | +---+ | | |
| 1432 | * | | | |
| 1433 | * | +-----+ | | |
| 1434 | * | | FF | | +-----+ | |
| 1435 | * DHTAC' +---+ | | | | | FF | | |
| 1436 | * >--------------oNOR| *07.25 +----+ ·-|S' | DHTBLK' | | | | |
| 1437 | * BLOCK' | |---------------|NAND| | Q|--+----------|--|S1' | WAKEDHT' | |
| 1438 | * >--------------o | DCSYSCLK | o--------|R' | | >--------|--|S2' Q|---------> | |
| 1439 | * +---+ >---------| | +-----+ | DHTAC' ·--|R' | | |
| 1440 | * +----+ | +-----+ | |
| 1441 | * ·------------· | |
| 1442 | * | | |
| 1443 | * DWTAC' +---+ | +-----+ | |
| 1444 | * >--------------oNOR| *07.26 +----+ | | FF | | |
| 1445 | * BLOCK' | |---------|NAND| DSP07.01 | | | | |
| 1446 | * >--------------o | DCSYSCLK| o----------|---|S1' | DWTCN' +---+ DWTCN | |
| 1447 | * +---+ >-------| | ·---|S2' Q|--------|inv|-----------+---- | |
| 1448 | * +----+ ·---|R' | +---+ | | |
| 1449 | * | +-----+ | | |
| 1450 | * SCANEND +----+ | | | |
| 1451 | * >-------------|NAND| CLRBUF' | .----------------------· | |
| 1452 | * DCLK | o----------------· | | |
| 1453 | * >-------------| | | +-----+ | |
| 1454 | * +----+ ·--| NAND| | |
| 1455 | * STOPWAKE' | |preWake +----+ WAKEDWT' | |
| 1456 | * >-----------| o--------|N174|---------> | |
| 1457 | * VBLANK' | | +----+ | |
| 1458 | * >-----------| | | |
| 1459 | * +-----+ | |
| 1460 | * a40c | |
| 1461 | * VBLANKPULSE +----+ | |
| 1462 | * -------------|NAND| | |
| 1463 | * | o--· | |
| 1464 | * ·--| | | | |
| 1465 | * | +----+ | | |
| 1466 | * ·----------|-· | |
| 1467 | * ·----------· | | |
| 1468 | * CURTAC' +---+ | +----+ | a20d | |
| 1469 | * >--------------oNOR| *07.27 +----+ ·--|NAND| | +----+ | |
| 1470 | * BLOCK' | |---------|NAND| DSP07.07 | o----+----o NOR| preWK +----+ WAKECURT' | |
| 1471 | * >--------------o | DCSYSCLK| o-----------| | | |--------|N174|---------> | |
| 1472 | * +---+ >-------| | +----+ +----o | +----+ | |
| 1473 | * +----+ a40d | +----+ | |
| 1474 | * a30c | | |
| 1475 | * CURTAC' +----+ | | |
| 1476 | * >------------|NAND| DSP07.03 | | |
| 1477 | * | o--+------------· | |
| 1478 | * ·--| | | | |
| 1479 | * | +----+ | | |
| 1480 | * ·----------|-· | |
| 1481 | * ·----------· | | |
| 1482 | * | +----+ | | |
| 1483 | * ·--|NAND| | | |
| 1484 | * CLRBUF' | o----· | |
| 1485 | * >------------| | | |
| 1486 | * +----+ | |
| 1487 | * a30d | |
| 1488 | * </PRE> | |
| 1489 | */ | |
| 1490 | struct { | |
| 1491 | UINT16 hlc; //!< horizontal line counter | |
| 1492 | UINT8 a63; //!< most recent value read from the PROM a63 | |
| 1493 | UINT8 a66; //!< most recent value read from the PROM a66 | |
| 1494 | UINT16 setmode; //!< value written by last SETMODE<- | |
| 1495 | UINT16 inverse; //!< set to 0xffff if line is inverse, 0x0000 otherwise | |
| 1496 | UINT8 halfclock; //!< set 0 for normal pixel clock, 1 for half pixel clock | |
| 1497 | UINT8 clr; //!< set non-zero if any of VBLANK or HBLANK is active (a39a 74S08) | |
| 1498 | UINT16 fifo[ALTO2_DISPLAY_FIFO]; //!< display word fifo | |
| 1499 | UINT8 fifo_wr; //!< fifo input pointer (4-bit) | |
| 1500 | UINT8 fifo_rd; //!< fifo output pointer (4-bit) | |
| 1501 | UINT8 dht_blocks; //!< set non-zero, if the DHT executed BLOCK | |
| 1502 | UINT8 dwt_blocks; //!< set non-zero, if the DWT executed BLOCK | |
| 1503 | UINT8 curt_blocks; //!< set non-zero, if the CURT executed BLOCK | |
| 1504 | UINT8 curt_wakeup; //!< set non-zero, if CURT wakeups are generated | |
| 1505 | UINT16 vblank; //!< most recent HLC with VBLANK still high (11-bit) | |
| 1506 | UINT16 xpreg; //!< cursor cursor x position register (10-bit) | |
| 1507 | UINT16 csr; //!< cursor shift register (16-bit) | |
| 1508 | UINT32 curword; //!< helper: first cursor word in current scanline | |
| 1509 | UINT32 curdata; //!< helper: shifted cursor data (32-bit) | |
| 1510 | UINT16 *raw_bitmap; //!< array of words of the raw bitmap that is displayed | |
| 1511 | } m_dsp; | |
| 1512 | ||
| 1513 | //! horizontal line counter bit 0 | |
| 1514 | inline int HLC1() { return A2_BIT16(m_dsp.hlc,11,10); } | |
| 1515 | //! horizontal line counter bit 1 | |
| 1516 | inline int HLC2() { return A2_BIT16(m_dsp.hlc,11,9); } | |
| 1517 | //! horizontal line counter bit 2 | |
| 1518 | inline int HLC4() { return A2_BIT16(m_dsp.hlc,11,8); } | |
| 1519 | //! horizontal line counter bit 3 | |
| 1520 | inline int HLC8() { return A2_BIT16(m_dsp.hlc,11,7); } | |
| 1521 | //! horizontal line counter bit 4 | |
| 1522 | inline int HLC16() { return A2_BIT16(m_dsp.hlc,11,6); } | |
| 1523 | //! horizontal line counter bit 5 | |
| 1524 | inline int HLC32() { return A2_BIT16(m_dsp.hlc,11,5); } | |
| 1525 | //! horizontal line counter bit 6 | |
| 1526 | inline int HLC64() { return A2_BIT16(m_dsp.hlc,11,4); } | |
| 1527 | //! horizontal line counter bit 7 | |
| 1528 | inline int HLC128() { return A2_BIT16(m_dsp.hlc,11,3); } | |
| 1529 | //! horizontal line counter bit 8 | |
| 1530 | inline int HLC256() { return A2_BIT16(m_dsp.hlc,11,2); } | |
| 1531 | //! horizontal line counter bit 9 | |
| 1532 | inline int HLC512() { return A2_BIT16(m_dsp.hlc,11,1); } | |
| 1533 | //! horizontal line counter bit 10 | |
| 1534 | inline int HLC1024() { return A2_BIT16(m_dsp.hlc,11,0); } | |
| 1535 | ||
| 1536 | //! get the pixel clock speed from a SETMODE<- bus value | |
| 1537 | static inline UINT16 GET_SETMODE_SPEEDY(UINT16 mode) { return A2_GET16(mode,16,0,0); } | |
| 1538 | //! get the inverse video flag from a SETMODE<- bus value | |
| 1539 | static inline UINT16 GET_SETMODE_INVERSE(UINT16 mode) { return A2_GET16(mode,16,1,1); } | |
| 1540 | ||
| 1541 | /** | |
| 1542 | * @brief PROM a38 contains the STOPWAKE' and MBEMBPTY' signals for the FIFO | |
| 1543 | * <PRE> | |
| 1544 | * The inputs to a38 are the UNLOAD counter RA[0-3] and the DDR<- counter | |
| 1545 | * WA[0-3], and the designer decided to reverse the address lines :-) | |
| 1546 | * | |
| 1547 | * a38 counter FIFO counter | |
| 1548 | * -------------------------- | |
| 1549 | * A0 RA[0] fifo_rd | |
| 1550 | * A1 RA[1] | |
| 1551 | * A2 RA[2] | |
| 1552 | * A3 RA[3] | |
| 1553 | * A4 WA[0] fifo_wr | |
| 1554 | * A5 WA[1] | |
| 1555 | * A6 WA[2] | |
| 1556 | * A7 WA[3] | |
| 1557 | * | |
| 1558 | * Only two bits of a38 are used: | |
| 1559 | * O1 (002) = STOPWAKE' | |
| 1560 | * O3 (010) = MBEMPTY' | |
| 1561 | * </PRE> | |
| 1562 | */ | |
| 1563 | UINT8 m_disp_a38[256]; | |
| 1564 | ||
| 1565 | //! PROM a38 bit O1 is STOPWAKE' (stop DWT if bit is zero) | |
| 1566 | inline int FIFO_STOPWAKE_0() { return m_disp_a38[m_dsp.fifo_rd * 16 + m_dsp.fifo_wr] & 002; } | |
| 1567 | ||
| 1568 | //! PROM a38 bit O3 is MBEMPTY' (FIFO is empty if bit is zero) | |
| 1569 | inline int FIFO_MBEMPTY_0() { return m_disp_a38[m_dsp.fifo_rd * 16 + m_dsp.fifo_wr] & 010; } | |
| 1570 | ||
| 1571 | /** | |
| 1572 | * @brief emulation of PROM a63 in the display schematics page 8 | |
| 1573 | * <PRE> | |
| 1574 | * The PROM's address lines are driven by a clock CLK, which is | |
| 1575 | * pixel clock / 24, and an inverted half-scanline signal H[1]'. | |
| 1576 | * | |
| 1577 | * It is 32x8 bits and its output bits (B) are connected to the | |
| 1578 | * signals, as well as its own address lines (A) through a latch | |
| 1579 | * of the type SN74774 like this: | |
| 1580 | * | |
| 1581 | * B 174 A others | |
| 1582 | * ------------------------ | |
| 1583 | * 0 5 - HBLANK | |
| 1584 | * 1 0 - HSYNC | |
| 1585 | * 2 4 0 | |
| 1586 | * 3 1 1 | |
| 1587 | * 4 3 2 | |
| 1588 | * 5 2 3 | |
| 1589 | * 6 - - SCANEND | |
| 1590 | * 7 - - HLCGATE | |
| 1591 | * ------------------------ | |
| 1592 | * H[1]' - 4 | |
| 1593 | * | |
| 1594 | * The display_state_machine() is called by the CPU at a rate of pixelclock/24, | |
| 1595 | * which happens to be very close to every 7th CPU micrcocycle. | |
| 1596 | * </PRE> | |
| 1597 | */ | |
| 1598 | UINT8 m_disp_a63[32]; | |
| 1599 | ||
| 1600 | enum { | |
| 1601 | A63_HBLANK = (1 << 0), //!< PROM a63 B0 is latched as HBLANK signal | |
| 1602 | A63_HSYNC = (1 << 1), //!< PROM a63 B1 is latched as HSYNC signal | |
| 1603 | A63_A0 = (1 << 2), //!< PROM a63 B2 is the latched next address bit A0 | |
| 1604 | A63_A1 = (1 << 3), //!< PROM a63 B3 is the latched next address bit A1 | |
| 1605 | A63_A2 = (1 << 4), //!< PROM a63 B4 is the latched next address bit A2 | |
| 1606 | A63_A3 = (1 << 5), //!< PROM a63 B5 is the latched next address bit A3 | |
| 1607 | A63_SCANEND = (1 << 6), //!< PROM a63 B6 SCANEND signal, which resets the FIFO counters | |
| 1608 | A63_HLCGATE = (1 << 7) //!< PROM a63 B7 HLCGATE signal, which enables counting the HLC | |
| 1609 | }; | |
| 1610 | //!< helper to extract A3-A0 from a PROM a63 value | |
| 1611 | inline UINT8 A63_NEXT(UINT8 n) { return (n >> 2) & 017; } | |
| 1612 | ||
| 1613 | //!< test the HBLANK (horizontal blanking) signal in PROM a63 being high | |
| 1614 | static inline bool A2_HBLANK_HI(UINT8 a) { return (a & A63_HBLANK) ? true : false; } | |
| 1615 | //!< test the HBLANK (horizontal blanking) signal in PROM a63 being low | |
| 1616 | static inline bool A2_HBLANK_LO(UINT8 a) { return !A2_HBLANK_HI(a); } | |
| 1617 | //!< test the HSYNC (horizontal synchonisation) signal in PROM a63 being high | |
| 1618 | static inline bool A2_HSYNC_HI(UINT8 a) { return (a & A63_HSYNC) ? true : false; } | |
| 1619 | //!< test the HSYNC (horizontal synchonisation) signal in PROM a63 being low | |
| 1620 | static inline bool A2_HSYNC_LO(UINT8 a) { return !A2_HSYNC_HI(a); } | |
| 1621 | //!< test the SCANEND (scanline end) signal in PROM a63 being high | |
| 1622 | static inline bool A2_SCANEND_HI(UINT8 a) { return (a & A63_SCANEND) ? true : false; } | |
| 1623 | //!< test the SCANEND (scanline end) signal in PROM a63 being low | |
| 1624 | static inline bool A2_SCANEND_LO(UINT8 a) { return !A2_SCANEND_HI(a); } | |
| 1625 | //!< test the HLCGATE (horz. line counter gate) signal in PROM a63 being high | |
| 1626 | static inline bool A2_HLCGATE_HI(UINT8 a) { return (a & A63_HLCGATE) ? true : false; } | |
| 1627 | //!< test the HLCGATE (horz. line counter gate) signal in PROM a63 being low | |
| 1628 | static inline bool A2_HLCGATE_LO(UINT8 a) { return !A2_HLCGATE_HI(a); } | |
| 1629 | ||
| 1630 | /** | |
| 1631 | * @brief vertical blank and synch PROM | |
| 1632 | * | |
| 1633 | * PROM a66 is a 256x4 bit (type 3601), containing the vertical blank + synch. | |
| 1634 | * Address lines are driven by H[1] to H[128] of the the horz. line counters. | |
| 1635 | * The PROM is enabled whenever H[256] and H[512] are both 0. | |
| 1636 | * | |
| 1637 | * Q1 (001) is VSYNC for the odd field (with H1024=1) | |
| 1638 | * Q2 (002) is VSYNC for the even field (with H1024=0) | |
| 1639 | * Q3 (004) is VBLANK for the odd field (with H1024=1) | |
| 1640 | * Q4 (010) is VBLANK for the even field (with H1024=0) | |
| 1641 | */ | |
| 1642 | UINT8 m_disp_a66[256]; | |
| 1643 | ||
| 1644 | enum { | |
| 1645 | A66_VSYNC_ODD = (1 << 0), | |
| 1646 | A66_VSYNC_EVEN = (1 << 1), | |
| 1647 | A66_VBLANK_ODD = (1 << 2), | |
| 1648 | A66_VBLANK_EVEN = (1 << 3) | |
| 1649 | }; | |
| 1650 | ||
| 1651 | //! test for the VSYNC signal (depends on "field", i.e. HLC1024) | |
| 1652 | inline bool A66_VSYNC(UINT8 a) { return a & (HLC1024() ? A66_VSYNC_ODD : A66_VSYNC_EVEN) ? true : false; } | |
| 1653 | //! test for the VBLANK signal (depends on "field", i.e. HLC1024) | |
| 1654 | inline bool A66_VBLANK(UINT8 a) { return a & (HLC1024() ? A66_VBLANK_ODD : A66_VBLANK_EVEN) ? true : false; } | |
| 1655 | //! test the VSYNC (vertical synchronisation) signal in PROM a66 being high | |
| 1656 | inline bool A2_VSYNC_HI(UINT8 a) { return A66_VSYNC(a); } | |
| 1657 | //! test the VSYNC (vertical synchronisation) signal in PROM a66 being low | |
| 1658 | inline bool A2_VSYNC_LO(UINT8 a) { return !A66_VSYNC(a); } | |
| 1659 | //! test the VBLANK (vertical blanking) signal in PROM a66 being high | |
| 1660 | inline bool A2_VBLANK_HI(UINT8 a) { return A66_VBLANK(a); } | |
| 1661 | //! test the VBLANK (vertical blanking) signal in PROM a66 being low | |
| 1662 | inline bool A2_VBLANK_LO(UINT8 a) { return !A66_VBLANK(a); } | |
| 1663 | ||
| 1664 | /** | |
| 1665 | * @brief unload the next word from the display FIFO and shift it to the screen | |
| 1666 | */ | |
| 1667 | int unload_word(int x); | |
| 1668 | ||
| 1669 | /** | |
| 1670 | * @brief function called by the CPU to enter the next display state | |
| 1671 | * | |
| 1672 | * There are 32 states per scanline and 875 scanlines per frame. | |
| 1673 | * | |
| 1674 | * @param arg the current m_disp_a63 PROM address | |
| 1675 | * @result returns the next state of the display state machine | |
| 1676 | */ | |
| 1677 | int display_state_machine(int arg); | |
| 1678 | ||
| 1679 | /** @brief branch on the evenfield flip-flop */ | |
| 1680 | void f2_evenfield_1(void); | |
| 1681 | ||
| 1682 | /** @brief initialize the display context */ | |
| 1683 | int init_disp(); | |
| 1684 | ||
| 1685 | // ************************************************ | |
| 1686 | // memory stuff | |
| 1687 | // ************************************************ | |
| 1688 | /** @brief set non-zero to incorporate the Hamming code and Parity check */ | |
| 1689 | #define ALTO2_HAMMING_CHECK 1 | |
| 1690 | ||
| 1691 | #define ALTO2_IO_PAGE_SIZE 01000 | |
| 1692 | #define ALTO2_IO_PAGE_BASE 0177000 | |
| 1693 | ||
| 1694 | enum { | |
| 1695 | ALTO2_MEM_NONE, | |
| 1696 | ALTO2_MEM_ODD = (1 << 0), | |
| 1697 | ALTO2_MEM_RAM = (1 << 1), | |
| 1698 | ALTO2_MEM_NIRVANA = (1 << 2) | |
| 1699 | }; | |
| 1700 | ||
| 1701 | struct { | |
| 1702 | UINT32 ram[ALTO2_RAM_SIZE/4]; //!< main memory organized as double-words | |
| 1703 | UINT8 hpb[ALTO2_RAM_SIZE/4]; //!< Hamming code (6) and Parity bits (1) per double word | |
| 1704 | UINT32 mar; //!< memory address register | |
| 1705 | UINT32 rmdd; //!< read memory data double-word | |
| 1706 | UINT32 wmdd; //!< write memory data double-word | |
| 1707 | UINT16 md; //!< memory data register | |
| 1708 | UINT64 cycle; //!< cycle when the memory address register was loaded | |
| 1709 | ||
| 1710 | /** | |
| 1711 | * @brief memory access under the way if non-zero | |
| 1712 | * 0: no memory access (MEM_NONE) | |
| 1713 | * 1: invalid | |
| 1714 | * 2: memory access even word (MEM_RAM) | |
| 1715 | * 3: memory access odd word (MEM_RAM | MEM_ODD) | |
| 1716 | * 4: refresh even word (MEM_REFRESH) | |
| 1717 | * 5: refresh odd word (MEM_REFRESH | MEM_ODD) | |
| 1718 | */ | |
| 1719 | int access; | |
| 1720 | int error; //!< non-zero after a memory error was detected | |
| 1721 | int mear; //!< memory error address register | |
| 1722 | UINT16 mesr; //!< memory error status register | |
| 1723 | UINT16 mecr; //!< memory error control register | |
| 1724 | ||
| 1725 | #if DEBUG | |
| 1726 | void (*watch_read)(int mar, int md); //!< watch read function (debugging) | |
| 1727 | void (*watch_write)(int mar, int md); //!< watch write function (debugging) | |
| 1728 | #endif | |
| 1729 | } m_mem; | |
| 1730 | ||
| 1731 | /** | |
| 1732 | * @brief check if memory address register load is yet possible | |
| 1733 | * suspend if accessing RAM and previous MAR<- was less than 5 cycles ago | |
| 1734 | * | |
| 1735 | * 1. MAR<- ANY | |
| 1736 | * 2. REQUIRED | |
| 1737 | * 3. MD<- whatever | |
| 1738 | * 4. SUSPEND | |
| 1739 | * 5. SUSPEND | |
| 1740 | * 6. MAR<- ANY | |
| 1741 | * | |
| 1742 | * @result returns 0, if memory address can be loaded | |
| 1743 | */ | |
| 1744 | inline bool check_mem_load_mar_stall(UINT8 rsel) { | |
| 1745 | return (ALTO2_MEM_NONE == m_mem.access ? false : cycle() < m_mem.cycle+5); | |
| 1746 | } | |
| 1747 | ||
| 1748 | /** | |
| 1749 | * @brief check if memory read is yet possible | |
| 1750 | * MAR<- = cycle #1, earliest read at cycle #5, i.e. + 4 | |
| 1751 | * | |
| 1752 | * 1. MAR<- ANY | |
| 1753 | * 2. REQUIRED | |
| 1754 | * 3. SUSPEND | |
| 1755 | * 4. SUSPEND | |
| 1756 | * 5. whereever <-MD | |
| 1757 | * | |
| 1758 | * @result returns 0, if memory can be read without wait cycle | |
| 1759 | */ | |
| 1760 | inline bool check_mem_read_stall() { | |
| 1761 | return (ALTO2_MEM_NONE == m_mem.access ? false : cycle() < m_mem.cycle+4); | |
| 1762 | } | |
| 1763 | ||
| 1764 | /** | |
| 1765 | * @brief check if memory write is yet possible | |
| 1766 | * MAR<- = cycle #1, earliest write at cycle #3, i.e. + 2 | |
| 1767 | * | |
| 1768 | * 1. MAR<- ANY | |
| 1769 | * 2. REQUIRED | |
| 1770 | * 3. OPTIONAL | |
| 1771 | * 4. MD<- whatever | |
| 1772 | * | |
| 1773 | * @result returns 0, if memory can be written without wait cycle | |
| 1774 | */ | |
| 1775 | inline bool check_mem_write_stall() { | |
| 1776 | return (ALTO2_MEM_NONE == m_mem.access ? false : cycle() < m_mem.cycle+2); | |
| 1777 | } | |
| 1778 | ||
| 1779 | //! memory mapped I/O read functions - FIXME: use MAME memory handlers for AS_IO | |
| 1780 | a2io_rd mmio_read_fn[ALTO2_IO_PAGE_SIZE]; | |
| 1781 | ||
| 1782 | //! memory mapped I/O write functions - FIXME: use MAME memory handlers for AS_IO | |
| 1783 | a2io_wr mmio_write_fn[ALTO2_IO_PAGE_SIZE]; | |
| 1784 | ||
| 1785 | //! catch unmapped memory mapped I/O reads | |
| 1786 | UINT16 bad_mmio_read_fn(UINT32 address); | |
| 1787 | ||
| 1788 | //! catch unmapped memory mapped I/O writes | |
| 1789 | void bad_mmio_write_fn(UINT32 address, UINT16 data); | |
| 1790 | ||
| 1791 | //! memory error address register read | |
| 1792 | UINT16 mear_r(UINT32 address); | |
| 1793 | ||
| 1794 | //! memory error status register read | |
| 1795 | UINT16 mesr_r(UINT32 address); | |
| 1796 | ||
| 1797 | //! memory error status register write (clear) | |
| 1798 | void mesr_w(UINT32 address, UINT16 data); | |
| 1799 | ||
| 1800 | //! memory error control register read | |
| 1801 | UINT16 mecr_r(UINT32 address); | |
| 1802 | ||
| 1803 | //! memory error control register write | |
| 1804 | void mecr_w(UINT32 address, UINT16 data); | |
| 1805 | ||
| 1806 | //! read or write a memory double-word and caluclate its Hamming code | |
| 1807 | UINT32 hamming_code(int write, UINT32 dw_addr, UINT32 dw_data); | |
| 1808 | ||
| 1809 | //! load the memory address register with some value | |
| 1810 | void load_mar(UINT8 rsel, UINT32 addr); | |
| 1811 | ||
| 1812 | //! read memory or memory mapped I/O from the address in mar to md | |
| 1813 | UINT16 read_mem(); | |
| 1814 | ||
| 1815 | //! write memory or memory mapped I/O from md to the address in mar | |
| 1816 | void write_mem(UINT16 data); | |
| 1817 | ||
| 1818 | //! install read and/or write memory mapped I/O handler(s) for a range first to last | |
| 1819 | void install_mmio_fn(int first, int last, a2io_rd rfn, a2io_wr wfn); | |
| 1820 | ||
| 1821 | //! debugger interface to read memory | |
| 1822 | UINT16 debug_read_mem(UINT32 addr); | |
| 1823 | ||
| 1824 | //! debugger interface to write memory | |
| 1825 | void debug_write_mem(UINT32 addr, UINT16 data); | |
| 1826 | ||
| 1827 | //! initialize the memory system | |
| 1828 | void init_memory(); | |
| 1829 | ||
| 1830 | // ************************************************ | |
| 1831 | // emulator task | |
| 1832 | // ************************************************ | |
| 1833 | struct { | |
| 1834 | UINT16 ir; //!< emulator instruction register | |
| 1835 | UINT8 skip; //!< emulator skip | |
| 1836 | UINT8 cy; //!< emulator carry | |
| 1837 | } m_emu; | |
| 1838 | void bs_emu_disp_0(); //!< bs_emu_disp early: drive bus by IR[8-15], possibly sign extended | |
| 1839 | void f1_emu_block_0(); //!< f1_block early: block task | |
| 1840 | void f1_emu_load_rmr_1(); //!< f1_load_rmr late: load the reset mode register | |
| 1841 | void f1_emu_load_esrb_1(); //!< f1_load_esrb late: load the extended S register bank from BUS[12-14] | |
| 1842 | void f1_rsnf_0(); //!< f1_rsnf early: drive the bus from the Ethernet node ID | |
| 1843 | void f1_startf_0(); //!< f1_startf early: defines commands for for I/O hardware, including Ethernet | |
| 1844 | void f2_busodd_1(); //!< f2_busodd late: branch on odd bus | |
| 1845 | void f2_magic_1(); //!< f2_magic late: shift and use T | |
| 1846 | void f2_load_dns_0(); //!< f2_load_dns early: modify RESELECT with DstAC = (3 - IR[3-4]) | |
| 1847 | void f2_load_dns_1(); //!< f2_load_dns late: do novel shifts | |
| 1848 | void f2_acdest_0(); //!< f2_acdest early: modify RSELECT with DstAC = (3 - IR[3-4]) | |
| 1849 | void bitblt_info(); //!< debug bitblt opcode | |
| 1850 | void f2_load_ir_1(); //!< f2_load_ir late: load instruction register IR and branch on IR[0,5-7] | |
| 1851 | void f2_idisp_1(); //!< f2_idisp late: branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] | |
| 1852 | void f2_acsource_0(); //!< f2_acsource early: modify RSELECT with SrcAC = (3 - IR[1-2]) | |
| 1853 | void f2_acsource_1(); //!< f2_acsource late: branch on arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] | |
| 1854 | void init_emu(int task); //!< 000 initialize emulator task | |
| 1855 | ||
| 1856 | // ksec task | |
| 1857 | void f1_ksec_block_0(void); | |
| 1858 | void init_ksec(int task); //!< 004 initialize disk sector task | |
| 1859 | ||
| 1860 | // ************************************************ | |
| 1861 | // ethernet task | |
| 1862 | // ************************************************ | |
| 1863 | /** | |
| 1864 | * @brief BPROMs P3601-1; 256x4; enet.a41 "PE1" and enet.a42 "PE2" | |
| 1865 | * | |
| 1866 | * Phase encoder | |
| 1867 | * | |
| 1868 | * a41: P3601-1; 256x4; "PE1" | |
| 1869 | * a42: P3601-1; 256x4; "PE2" | |
| 1870 | * | |
| 1871 | * PE1/PE2 inputs | |
| 1872 | * ---------------- | |
| 1873 | * A0 (5) OUTGO | |
| 1874 | * A1 (6) XDATA | |
| 1875 | * A2 (7) OSDATAG | |
| 1876 | * A3 (4) XCLOCK | |
| 1877 | * A4 (3) OCNTR0 | |
| 1878 | * A5 (2) OCNTR1 | |
| 1879 | * A6 (1) OCNTR2 | |
| 1880 | * A7 (15) OCNTR3 | |
| 1881 | * | |
| 1882 | * PE1 outputs | |
| 1883 | * ---------------- | |
| 1884 | * D0 (12) OCNTR0 | |
| 1885 | * D1 (11) OCNTR1 | |
| 1886 | * D2 (10) OCNTR2 | |
| 1887 | * D3 (9) OCNTR3 | |
| 1888 | * | |
| 1889 | * PE2 outputs | |
| 1890 | * ---------------- | |
| 1891 | * D0 (12) n.c. | |
| 1892 | * D1 (11) to OSLOAD flip flop J and K' | |
| 1893 | * D2 (10) XDATA | |
| 1894 | * D3 (9) XCLOCK | |
| 1895 | */ | |
| 1896 | UINT8 m_ether_a41[256]; | |
| 1897 | UINT8 m_ether_a42[256]; | |
| 1898 | ||
| 1899 | /** | |
| 1900 | * @brief BPROM; P3601-1; 265x4 enet.a49 "AFIFO" | |
| 1901 | * | |
| 1902 | * Perhaps try with the contents of the display FIFO, as it is | |
| 1903 | * the same type and the display FIFO has the same size. | |
| 1904 | * | |
| 1905 | * FIFO control | |
| 1906 | * | |
| 1907 | * a49: P3601-1; 256x4; "AFIFO" | |
| 1908 | * | |
| 1909 | * inputs | |
| 1910 | * ---------------- | |
| 1911 | * A0 (5) fifo_wr[0] | |
| 1912 | * A1 (6) fifo_wr[1] | |
| 1913 | * A2 (7) fifo_wr[2] | |
| 1914 | * A3 (4) fifo_wr[3] | |
| 1915 | * A4 (3) fifo_rd[0] | |
| 1916 | * A5 (2) fifo_rd[1] | |
| 1917 | * A6 (1) fifo_rd[2] | |
| 1918 | * A7 (15) fifo_rd[3] | |
| 1919 | * | |
| 1920 | * outputs active low | |
| 1921 | * ---------------------------- | |
| 1922 | * D0 (12) BE' (buffer empty) | |
| 1923 | * D1 (11) BNE' (buffer next empty ?) | |
| 1924 | * D2 (10) BNNE' (buffer next next empty ?) | |
| 1925 | * D3 (9) BF' (buffer full) | |
| 1926 | * | |
| 1927 | * Data from enet.a49 after address line reversal: | |
| 1928 | * 000: 010 007 017 017 017 017 017 017 017 017 017 017 017 017 013 011 | |
| 1929 | * 020: 011 010 007 017 017 017 017 017 017 017 017 017 017 017 017 013 | |
| 1930 | * 040: 013 011 010 007 017 017 017 017 017 017 017 017 017 017 017 017 | |
| 1931 | * 060: 017 013 011 010 007 017 017 017 017 017 017 017 017 017 017 017 | |
| 1932 | * 100: 017 017 013 011 010 007 017 017 017 017 017 017 017 017 017 017 | |
| 1933 | * 120: 017 017 017 013 011 010 007 017 017 017 017 017 017 017 017 017 | |
| 1934 | * 140: 017 017 017 017 013 011 010 007 017 017 017 017 017 017 017 017 | |
| 1935 | * 160: 017 017 017 017 017 013 011 010 007 017 017 017 017 017 017 017 | |
| 1936 | * 200: 017 017 017 017 017 017 013 011 010 007 017 017 017 017 017 017 | |
| 1937 | * 220: 017 017 017 017 017 017 017 013 011 010 007 017 017 017 017 017 | |
| 1938 | * 240: 017 017 017 017 017 017 017 017 013 011 010 007 017 017 017 017 | |
| 1939 | * 260: 017 017 017 017 017 017 017 017 017 013 011 010 007 017 017 017 | |
| 1940 | * 300: 017 017 017 017 017 017 017 017 017 017 013 011 010 007 017 017 | |
| 1941 | * 320: 017 017 017 017 017 017 017 017 017 017 017 013 011 010 007 017 | |
| 1942 | * 340: 017 017 017 017 017 017 017 017 017 017 017 017 013 011 010 007 | |
| 1943 | * 360: 007 017 017 017 017 017 017 017 017 017 017 017 017 013 011 010 | |
| 1944 | */ | |
| 1945 | UINT8 m_ether_a49[256]; | |
| 1946 | ||
| 1947 | static const int m_duckbreath_sec = 15; //!< send duckbreath every 15 seconds | |
| 1948 | ||
| 1949 | struct { | |
| 1950 | UINT16 fifo[ALTO2_ETHER_FIFO_SIZE]; //!< FIFO buffer | |
| 1951 | UINT16 fifo_rd; //!< FIFO input pointer | |
| 1952 | UINT16 fifo_wr; //!< FIFO output pointer | |
| 1953 | UINT16 status; //!< status word | |
| 1954 | UINT32 rx_crc; //!< receiver CRC | |
| 1955 | UINT32 tx_crc; //!< transmitter CRC | |
| 1956 | UINT32 rx_count; //!< received words count | |
| 1957 | UINT32 tx_count; //!< transmitted words count | |
| 1958 | emu_timer* tx_timer; //!< transmitter timer | |
| 1959 | int duckbreath; //!< if non-zero, interval in seconds at which to broadcast the duckbreath | |
| 1960 | } m_eth; | |
| 1961 | ||
| 1962 | TIMER_CALLBACK_MEMBER( rx_duckbreath ); //!< HACK: pull the next word from the duckbreath in the fifo | |
| 1963 | TIMER_CALLBACK_MEMBER( tx_packet ); //!< transmit data from the FIFO to <nirvana for now> | |
| 1964 | void eth_wakeup(); //!< check for the various reasons to wakeup the Ethernet task | |
| 1965 | void eth_startf(); //!< start input or output depending on m_bus | |
| 1966 | void bs_eidfct_0(); //!< bs_eidfct early: Ethernet input data function | |
| 1967 | void f1_eth_block_0(); //!< f1_eth_block early: block the Ether task | |
| 1968 | void f1_eilfct_0(); //!< f1_eilfct early: Ethernet input look function | |
| 1969 | void f1_epfct_0(); //!< f1_epfct early: Ethernet post function | |
| 1970 | void f1_ewfct_1(); //!< f1_ewfct late: Ethernet countdown wakeup function | |
| 1971 | void f2_eodfct_1(); //!< f2_eodfct late: Ethernet output data function | |
| 1972 | void f2_eosfct_1(); //!< f2_eosfct late: Ethernet output start function | |
| 1973 | void f2_erbfct_1(); //!< f2_erbfct late: Ethernet reset branch function | |
| 1974 | void f2_eefct_1(); //!< f2_eefct late: Ethernet end of transmission function | |
| 1975 | void f2_ebfct_1(); //!< f2_ebfct late: Ethernet branch function | |
| 1976 | void f2_ecbfct_1(); //!< f2_ecbfct late: Ethernet countdown branch function | |
| 1977 | void f2_eisfct_1(); //!< f2_eisfct late: Ethernet input start function | |
| 1978 | void eth_activate(); //!< called by the CPU when the Ethernet task becomes active | |
| 1979 | void init_ether(int task); //!< 007 initialize ethernet task | |
| 1980 | ||
| 1981 | // memory refresh task | |
| 1982 | void init_mrt(int task); //!< 010 initialize memory refresh task | |
| 1983 | ||
| 1984 | // display word task | |
| 1985 | void f1_dwt_block_0(); //!< f1_dwt_block early: block the display word task | |
| 1986 | void f2_dwt_load_ddr_1(); //!< f2_dwt_load_ddr late: load the display data register | |
| 1987 | void init_dwt(int task); //!< 011 initialize display word task | |
| 1988 | ||
| 1989 | // cursor task | |
| 1990 | void f1_curt_block_0(); //!< f1_curt_block early: disable the cursor task and set the curt_blocks flag | |
| 1991 | void f2_load_xpreg_1(); //!< f2_load_xpreg late: load the x position register from BUS[6-15] | |
| 1992 | void f2_load_csr_1(); //!< f2_load_csr late: load the cursor shift register from BUS[0-15] | |
| 1993 | void curt_activate(); //!< curt_activate: called by the CPU when the cursor task becomes active | |
| 1994 | void init_curt(int task); //!< 012 initialize cursor task | |
| 1995 | ||
| 1996 | // display horizontal task | |
| 1997 | void f1_dht_block_0(); //!< f1_dht_block early: disable the display word task | |
| 1998 | void f2_dht_setmode_1(); //!< f2_dht_setmode late: set the next scanline's mode inverse and half clock and branch | |
| 1999 | void activate_dht(); //!< called by the CPU when the display horizontal task becomes active | |
| 2000 | void init_dht(int task); //!< 013 initialize display horizontal task | |
| 2001 | ||
| 2002 | // display vertical task | |
| 2003 | void f1_dvt_block_0(); //!< f1_dvt_block early: disable the display word task | |
| 2004 | void activate_dvt(); //!< called by the CPU when the display vertical task becomes active | |
| 2005 | void init_dvt(int task); //!< 014 initialize display vertical task | |
| 2006 | ||
| 2007 | // parity task | |
| 2008 | void activate_part(); | |
| 2009 | void init_part(int task); //!< 015 initialize parity task | |
| 2010 | ||
| 2011 | // disk word task | |
| 2012 | void f1_kwd_block_0(void); | |
| 2013 | void init_kwd(int task); //!< 016 initialize disk word task | |
| 2014 | ||
| 2015 | void init_001(int task); //!< 001 initialize unused task | |
| 2016 | void init_002(int task); //!< 002 initialize unused task | |
| 2017 | void init_003(int task); //!< 003 initialize unused task | |
| 2018 | void init_005(int task); //!< 005 initialize unused task | |
| 2019 | void init_006(int task); //!< 006 initialize unused task | |
| 2020 | void init_017(int task); //!< 017 initialize unused task | |
| 2021 | }; | |
| 2022 | ||
| 2023 | extern const device_type ALTO2; | |
| 2024 | ||
| 2025 | ||
| 2026 | #endif /* _CPU_ALTO2_H_ */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII parity task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** @brief called by the CPU when the parity task becomes active */ | |
| 13 | void alto2_cpu_device::activate_part() | |
| 14 | { | |
| 15 | /* TODO: what do we do here ? */ | |
| 16 | m_task_wakeup &= ~(1 << m_task); | |
| 17 | } | |
| 18 | ||
| 19 | /** | |
| 20 | * @brief parity task slots initialization | |
| 21 | */ | |
| 22 | void alto2_cpu_device::init_part(int task) | |
| 23 | { | |
| 24 | m_active_callback[task] = &alto2_cpu_device::activate_part; | |
| 25 | } | |
| 26 |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII ethernet task | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | /** @brief the ethernet ID of this machine */ | |
| 13 | UINT8 ether_id = 254; | |
| 14 | ||
| 15 | /** @brief hardware status: write latch full/filled (? set by EODFCT) */ | |
| 16 | #define GET_ETH_WLF(st) A2_BIT16(st,16,4) | |
| 17 | #define PUT_ETH_WLF(st,val) A2_PUT16(st,16,4,4,val) | |
| 18 | ||
| 19 | /** @brief hardware status: output end of transmission (set by EEFCT) */ | |
| 20 | #define GET_ETH_OEOT(st) A2_BIT16(st,16,5) | |
| 21 | #define PUT_ETH_OEOT(st,val) A2_PUT16(st,16,5,5,val) | |
| 22 | ||
| 23 | /** @brief hardware status: input gone */ | |
| 24 | #define GET_ETH_IGONE(st) A2_BIT16(st,16,6) | |
| 25 | #define PUT_ETH_IGONE(st,val) A2_PUT16(st,16,6,6,val) | |
| 26 | ||
| 27 | /** @brief hardware status: input busy (set by EISFCT, bit isn't visible to microcode) */ | |
| 28 | #define GET_ETH_IBUSY(st) A2_BIT16(st,16,7) | |
| 29 | #define PUT_ETH_IBUSY(st,val) A2_PUT16(st,16,7,7,val) | |
| 30 | ||
| 31 | /** @brief hardware status: output gone */ | |
| 32 | #define GET_ETH_OGONE(st) A2_BIT16(st,16,8) | |
| 33 | #define PUT_ETH_OGONE(st,val) A2_PUT16(st,16,8,8,val) | |
| 34 | ||
| 35 | /** @brief hardware status: output busy (set by EOSFCT, bit isn't visible to microcode) */ | |
| 36 | #define GET_ETH_OBUSY(st) A2_BIT16(st,16,9) | |
| 37 | #define PUT_ETH_OBUSY(st,val) A2_PUT16(st,16,9,9,val) | |
| 38 | ||
| 39 | /** @brief hardware status: input data late */ | |
| 40 | #define GET_ETH_IDL(st) A2_BIT16(st,16,10) | |
| 41 | #define PUT_ETH_IDL(st,val) A2_PUT16(st,16,10,10,val) | |
| 42 | ||
| 43 | /** @brief hardware status: collision */ | |
| 44 | #define GET_ETH_COLL(st) A2_BIT16(st,16,11) | |
| 45 | #define PUT_ETH_COLL(st,val) A2_PUT16(st,16,11,11,val) | |
| 46 | ||
| 47 | /** @brief hardware status: CRC error */ | |
| 48 | #define GET_ETH_CRC(st) A2_BIT16(st,16,12) | |
| 49 | #define PUT_ETH_CRC(st,val) A2_PUT16(st,16,12,12,val) | |
| 50 | ||
| 51 | /** @brief hardware status: input command (set from BUS[14] on SIO, reset by EPFCT) */ | |
| 52 | #define GET_ETH_ICMD(st) A2_BIT16(st,16,13) | |
| 53 | #define PUT_ETH_ICMD(st,val) A2_PUT16(st,16,13,13,val) | |
| 54 | ||
| 55 | /** @brief hardware status: output command (set from BUS[15] on SIO, reset by EPFCT) */ | |
| 56 | #define GET_ETH_OCMD(st) A2_BIT16(st,16,14) | |
| 57 | #define PUT_ETH_OCMD(st,val) A2_PUT16(st,16,14,14,val) | |
| 58 | ||
| 59 | /** @brief hardware status: IT flip flop & ISRFULL' */ | |
| 60 | #define GET_ETH_IT(st) ALTO2_GET(st,16,15,15) | |
| 61 | #define PUT_ETH_IT(st,val) A2_PUT16(st,16,15,15,val) | |
| 62 | ||
| 63 | /** @brief missing PROM ether.u49; buffer empty (active low) */ | |
| 64 | #define ETHER_A49_BE (m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd] & (1 << 0)) | |
| 65 | ||
| 66 | /** @brief missing PROM ether.u49; buffer next(?) empty (active low) */ | |
| 67 | #define ETHER_A49_BNE (m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd] & (1 << 1)) | |
| 68 | ||
| 69 | /** @brief missing PROM ether.u49; buffer next next(?) empty (active low) */ | |
| 70 | #define ETHER_A49_BNNE (m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd] & (1 << 2)) | |
| 71 | ||
| 72 | /** @brief missing PROM ether.u49; buffer full (active low) */ | |
| 73 | #define ETHER_A49_BF (m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd] & (1 << 3)) | |
| 74 | ||
| 75 | ||
| 76 | #define BREATHLEN 0400 /* ethernet packet length */ | |
| 77 | #define BREATHADDR 0177400 /* dest,,source */ | |
| 78 | #define BREATHTYPE 0000602 /* ethernet packet type */ | |
| 79 | static const UINT16 duckbreath_data[BREATHLEN] = | |
| 80 | { | |
| 81 | BREATHADDR, /* 3MB dest,,source */ | |
| 82 | BREATHTYPE, /* ether packet type */ | |
| 83 | /* the rest is the contents of a breath of life packet. | |
| 84 | * see <altosource>etherboot.dm (etherboot.asm) for alto | |
| 85 | * assembly code. | |
| 86 | */ | |
| 87 | 0022574, 0100000, 0040437, 0102000, 0034431, 0164000, | |
| 88 | 0061005, 0102460, 0024567, 0034572, 0061006, 0024565, 0034570, 0061006, | |
| 89 | 0024564, 0034566, 0061006, 0020565, 0034565, 0061005, 0125220, 0046573, | |
| 90 | 0020576, 0061004, 0123400, 0030551, 0041211, 0004416, 0000000, 0001000, | |
| 91 | 0000026, 0000244, 0000000, 0000000, 0000000, 0000000, 0000004, 0000000, | |
| 92 | 0000000, 0000020, 0177777, 0055210, 0025400, 0107000, 0045400, 0041411, | |
| 93 | 0020547, 0041207, 0020544, 0061004, 0006531, 0034517, 0030544, 0051606, | |
| 94 | 0020510, 0041605, 0042526, 0102460, 0041601, 0020530, 0061004, 0021601, | |
| 95 | 0101014, 0000414, 0061020, 0014737, 0000773, 0014517, 0000754, 0020517, | |
| 96 | 0061004, 0030402, 0002402, 0000000, 0000732, 0034514, 0162414, 0000746, | |
| 97 | 0021001, 0024511, 0106414, 0000742, 0021003, 0163400, 0035005, 0024501, | |
| 98 | 0106415, 0175014, 0000733, 0021000, 0042465, 0034457, 0056445, 0055775, | |
| 99 | 0055776, 0101300, 0041400, 0020467, 0041401, 0020432, 0041402, 0121400, | |
| 100 | 0041403, 0021006, 0041411, 0021007, 0041412, 0021010, 0041413, 0021011, | |
| 101 | 0041406, 0021012, 0041407, 0021013, 0041410, 0015414, 0006427, 0012434, | |
| 102 | 0006426, 0020421, 0024437, 0134000, 0030417, 0002422, 0177035, 0000026, | |
| 103 | 0000415, 0000427, 0000567, 0000607, 0000777, 0177751, 0177641, 0177600, | |
| 104 | 0000225, 0177624, 0001013, 0000764, 0000431, 0000712, 0000634, 0000735, | |
| 105 | 0000611, 0000567, 0000564, 0000566, 0000036, 0000002, 0000003, 0000015, | |
| 106 | 0000030, 0000377, 0001000, 0177764, 0000436, 0054731, 0050750, 0020753, | |
| 107 | 0040745, 0102460, 0040737, 0020762, 0061004, 0020734, 0105304, 0000406, | |
| 108 | 0020743, 0101014, 0014741, 0000772, 0002712, 0034754, 0167700, 0116415, | |
| 109 | 0024752, 0021001, 0106414, 0000754, 0021000, 0024703, 0106414, 0000750, | |
| 110 | 0021003, 0163400, 0024736, 0106405, 0000404, 0121400, 0101404, 0000740, | |
| 111 | 0044714, 0021005, 0042732, 0024664, 0122405, 0000404, 0101405, 0004404, | |
| 112 | 0000727, 0010656, 0034654, 0024403, 0120500, 0101404, 0000777, 0040662, | |
| 113 | 0040664, 0040664, 0102520, 0061004, 0020655, 0101015, 0000776, 0106415, | |
| 114 | 0001400, 0014634, 0000761, 0020673, 0061004, 0000400, 0061005, 0102000, | |
| 115 | 0143000, 0034672, 0024667, 0166400, 0061005, 0004670, 0020663, 0034664, | |
| 116 | 0164000, 0147000, 0061005, 0024762, 0132414, 0133000, 0020636, 0034416, | |
| 117 | 0101015, 0156415, 0131001, 0000754, 0024643, 0044625, 0101015, 0000750, | |
| 118 | 0014623, 0004644, 0020634, 0061004, 0002000, 0176764, 0001401, 0041002 | |
| 119 | }; | |
| 120 | ||
| 121 | /** | |
| 122 | * @brief check for the various reasons to wakeup the Ethernet task | |
| 123 | */ | |
| 124 | void alto2_cpu_device::eth_wakeup() | |
| 125 | { | |
| 126 | register int busy, idr, odr, etac; | |
| 127 | ||
| 128 | etac = m_task == task_ether; | |
| 129 | ||
| 130 | LOG((0,0,"eth_wakeup: ibusy=%d obusy=%d ", GET_ETH_IBUSY(m_eth.status), GET_ETH_OBUSY(m_eth.status))); | |
| 131 | busy = GET_ETH_IBUSY(m_eth.status) | GET_ETH_OBUSY(m_eth.status); | |
| 132 | /* if not busy, reset the FIFO read and write counters */ | |
| 133 | if (busy == 0) { | |
| 134 | m_eth.fifo_rd = 0; | |
| 135 | m_eth.fifo_wr = 0; | |
| 136 | } | |
| 137 | ||
| 138 | /* | |
| 139 | * POST conditions to wakeup the Ether task: | |
| 140 | * input data late | |
| 141 | * output command | |
| 142 | * input command | |
| 143 | * output gone | |
| 144 | * input gone | |
| 145 | */ | |
| 146 | if (GET_ETH_IDL(m_eth.status)) { | |
| 147 | LOG((0,0,"post (input data late)\n")); | |
| 148 | m_task_wakeup |= 1 << task_ether; | |
| 149 | return; | |
| 150 | } | |
| 151 | if (GET_ETH_OCMD(m_eth.status)) { | |
| 152 | LOG((0,0,"post (output command)\n")); | |
| 153 | m_task_wakeup |= 1 << task_ether; | |
| 154 | return; | |
| 155 | } | |
| 156 | if (GET_ETH_ICMD(m_eth.status)) { | |
| 157 | LOG((0,0,"post (input command)\n")); | |
| 158 | m_task_wakeup |= 1 << task_ether; | |
| 159 | return; | |
| 160 | } | |
| 161 | if (GET_ETH_OGONE(m_eth.status)) { | |
| 162 | LOG((0,0,"post (output gone)\n")); | |
| 163 | m_task_wakeup |= 1 << task_ether; | |
| 164 | return; | |
| 165 | } | |
| 166 | if (GET_ETH_IGONE(m_eth.status)) { | |
| 167 | LOG((0,0,"post (input gone)\n")); | |
| 168 | m_task_wakeup |= 1 << task_ether; | |
| 169 | return; | |
| 170 | } | |
| 171 | ||
| 172 | /* | |
| 173 | * IDR (input data ready) conditions to wakeup the Ether task (AND): | |
| 174 | * IBUSY input busy | |
| 175 | * BNNE buffer next next empty | |
| 176 | * BNE buffer next empty | |
| 177 | * ETAC ether task active | |
| 178 | * | |
| 179 | * IDR' = (IBUSY & (BNNE & (BNE' & ETAC')')')' | |
| 180 | */ | |
| 181 | idr = GET_ETH_IBUSY(m_eth.status) && (ETHER_A49_BNNE || (ETHER_A49_BNE == 0 && etac)); | |
| 182 | if (idr) { | |
| 183 | m_task_wakeup |= 1 << task_ether; | |
| 184 | LOG((0,0,"input data ready\n")); | |
| 185 | return; | |
| 186 | } | |
| 187 | ||
| 188 | /* | |
| 189 | * ODR (output data ready) conditions to wakeup the Ether task: | |
| 190 | * WLF write latch filled(?) | |
| 191 | * BF buffer (FIFO) full | |
| 192 | * OEOT output end of transmission | |
| 193 | * OBUSY output busy | |
| 194 | * | |
| 195 | * ODR' = (OBUSY & OEOT' & (BF' & WLF')')' | |
| 196 | */ | |
| 197 | odr = GET_ETH_OBUSY(m_eth.status) && (GET_ETH_OEOT(m_eth.status) || (GET_ETH_WLF(m_eth.status) && ETHER_A49_BF == 0)); | |
| 198 | if (odr) { | |
| 199 | m_task_wakeup |= 1 << task_ether; | |
| 200 | LOG((0,0,"output data ready\n")); | |
| 201 | return; | |
| 202 | } | |
| 203 | ||
| 204 | /* | |
| 205 | * EWFCT (ether wake function) conditions to wakeup the Ether task: | |
| 206 | * EWFCT flip flop set by the F1 EWFCT | |
| 207 | * The task is activated by the display.c code together with the | |
| 208 | * next wakeup of the MRT (memory refresh task). | |
| 209 | */ | |
| 210 | if (m_ewfct) { | |
| 211 | m_task_wakeup |= 1 << task_ether; | |
| 212 | LOG((0,0,"ether wake function\n")); | |
| 213 | return; | |
| 214 | } | |
| 215 | ||
| 216 | /* otherwise no more wakeup for the Ether task */ | |
| 217 | LOG((0,0,"-/-\n")); | |
| 218 | m_task_wakeup &= ~(1 << task_ether); | |
| 219 | } | |
| 220 | ||
| 221 | /** | |
| 222 | * @brief F9401 CRC checker | |
| 223 | * <PRE> | |
| 224 | * | |
| 225 | * The F9401 looks similiar to the SN74F401. However, in the schematics | |
| 226 | * there is a connection from pin 9 (labeled D9) to pin 2 (labeled Q8). | |
| 227 | * See below for the difference: | |
| 228 | * | |
| 229 | * SN74F401 F9401 | |
| 230 | * +---+-+---+ +---+-+---+ | |
| 231 | * | +-+ | | +-+ | | |
| 232 | * CP' -|1 14|- Vcc CLK' -|1 14|- Vcc | |
| 233 | * | | | | | |
| 234 | * P' -|2 13|- ER P' -|2 13|- CRCZ' | |
| 235 | * | | | | | |
| 236 | * S0 -|3 12|- Q Z -|3 12|- CRCDATA | |
| 237 | * | | | | | |
| 238 | * MR -|4 11|- D MR -|4 11|- SDI | |
| 239 | * | | | | | |
| 240 | * S1 -|5 10|- CWE Y -|5 10|- SR | |
| 241 | * | | | | | |
| 242 | * NC -|6 9|- NC D1 -|6 9|- D9 | |
| 243 | * | | | | | |
| 244 | * GND -|7 8|- S2 GND -|7 8|- X | |
| 245 | * | | | | | |
| 246 | * +---------+ +---------+ | |
| 247 | * | |
| 248 | * Functional description (SN74F401) | |
| 249 | * | |
| 250 | * The 'F401 is a 16-bit programmable device which operates on serial data | |
| 251 | * streams and provides a means of detecting transmission errors. Cyclic | |
| 252 | * encoding and decoding schemes for error detection are based on polynomial | |
| 253 | * manipulation in modulo arithmetic. For encoding, the data stream (message | |
| 254 | * polynomial) is divided by a selected polynomial. This division results | |
| 255 | * in a remainder which is appended to the message as check bits. For error | |
| 256 | * checking, the bit stream containing both data and check bits is divided | |
| 257 | * by the same selected polynomial. If there are no detectable errors, this | |
| 258 | * division results in a zero remainder. Although it is possible to choose | |
| 259 | * many generating polynomials of a given degree, standards exist that | |
| 260 | * specify a small number of useful polynomials. The 'F401 implements the | |
| 261 | * polynomials listed in Tabel I by applying the appropriate logic levels | |
| 262 | * to the select pins S0, S1 and S2. | |
| 263 | * | |
| 264 | * Teh 'F401 consists of a 16-bit register, a Read Only Memory (ROM) and | |
| 265 | * associated control circuitry as shown in the block diagram. The | |
| 266 | * polynomial control code presented at inputs S0, S1 and S2 is decoded | |
| 267 | * by the ROM, selecting the desired polynomial by establishing shift | |
| 268 | * mode operation on the register with Exclusive OR gates at appropriate | |
| 269 | * inputs. To generate check bits, the data stream is entered via the | |
| 270 | * Data inputs (D), using the HIGH-to-LOW transition of the Clock input | |
| 271 | * (CP'). This data is gated with the most significant output (Q) of | |
| 272 | * the register, and controls the Exclusive OR gates (Figure 1). The | |
| 273 | * Check Word Enable (CWE) must be held HIGH while the data is being | |
| 274 | * entered. After the last data bit is entered, the CWE is brought LOW | |
| 275 | * and the check bits are shifted out of the register and appended to | |
| 276 | * the data bits using external gating (Figure 2). | |
| 277 | * | |
| 278 | * To check an incoming message for errors, both the data and check bits | |
| 279 | * are entered through the D input with the CWE input held HIGH. The | |
| 280 | * 'F401 is not in the data path, but only monitors the message. The | |
| 281 | * Error output becomes valid after the last check bit has been entered | |
| 282 | * into the 'F401 by a HIGH-to-LOW transition of CP'. If no detectable | |
| 283 | * errors have occured during the transmission, the resultant internal | |
| 284 | * register bits are all LOW and the Error Output (ER) is LOW. | |
| 285 | * If a detectable error has occured, ER is HIGH. | |
| 286 | * | |
| 287 | * A HIGH on the Master Reset input (MR) asynchronously clears the | |
| 288 | * register. A LOW on the Preset input (P') asynchronously sets the | |
| 289 | * entire register if the control code inputs specify a 16-bit | |
| 290 | * polynomial; in the case of 12- or 8-bit check polynomials only the | |
| 291 | * most significant 12 or 8 register bits are set and the remaining | |
| 292 | * bits are cleared. | |
| 293 | * | |
| 294 | * [Table I] | |
| 295 | * | |
| 296 | * S2 S1 S0 polynomial remarks | |
| 297 | * ---------------------------------------------------------------- | |
| 298 | * L L L x^16+x^15+x^2+1 CRC16 | |
| 299 | * L L H x^16+x^14+x+1 CRC16 reverse | |
| 300 | * L H L x^16+x^15+x^13+x^7+x^4+x^2+x+1 -/- | |
| 301 | * L H H x^12+x^11+x^3+x^2+x+1 CRC-12 | |
| 302 | * H L L x^8+x^7+x^5+x^4+x+1 -/- | |
| 303 | * H L H x^8+1 LRC-8 | |
| 304 | * H H L X^16+x^12+x^5+1 CRC-CCITT | |
| 305 | * H H H X^16+x^11+x^4+1 CRC-CCITT reverse | |
| 306 | * | |
| 307 | * </PRE> | |
| 308 | * The Alto Ethernet interface seems to be using the last one of polynomials, | |
| 309 | * or perhaps something entirely different. | |
| 310 | * | |
| 311 | * TODO: verify polynomial generator; build a lookup table to make it faster. | |
| 312 | * | |
| 313 | * @param crc previous CRC value | |
| 314 | * @param data 16 bit data | |
| 315 | * @result new CRC value after 16 bits | |
| 316 | */ | |
| 317 | UINT32 f9401_7(UINT32 crc, UINT32 data) | |
| 318 | { | |
| 319 | int i; | |
| 320 | for (i = 0; i < 16; i++) { | |
| 321 | crc <<= 1; | |
| 322 | if (data & 0100000) | |
| 323 | crc ^= (1<<15) | (1<<10) | (1<<3) | (1<<0); | |
| 324 | data <<= 1; | |
| 325 | } | |
| 326 | return crc & 0177777; | |
| 327 | } | |
| 328 | ||
| 329 | /** | |
| 330 | * @brief HACK: pull the next word from the duckbreath_data in the fifo | |
| 331 | * | |
| 332 | * This is probably lacking the updates to one or more of | |
| 333 | * the status flip flops. | |
| 334 | */ | |
| 335 | void alto2_cpu_device::rx_duckbreath(void* ptr, INT32 arg) | |
| 336 | { | |
| 337 | UINT32 data; | |
| 338 | ||
| 339 | if (arg == 0) { | |
| 340 | /* first word: set the IBUSY flip flop */ | |
| 341 | PUT_ETH_IBUSY(m_eth.status, 1); | |
| 342 | } | |
| 343 | ||
| 344 | data = duckbreath_data[arg++]; | |
| 345 | m_eth.rx_crc = f9401_7(m_eth.rx_crc, data); | |
| 346 | ||
| 347 | m_eth.fifo[m_eth.fifo_wr] = data; | |
| 348 | m_eth.fifo_wr = (m_eth.fifo_wr + 1) % ALTO2_ETHER_FIFO_SIZE; | |
| 349 | ||
| 350 | PUT_ETH_WLF(m_eth.status, 1); | |
| 351 | if (ETHER_A49_BF == 0) { | |
| 352 | /* fifo is overrun: set input data late flip flop */ | |
| 353 | PUT_ETH_IDL(m_eth.status, 1); | |
| 354 | } | |
| 355 | ||
| 356 | if (arg == BREATHLEN) { | |
| 357 | /* | |
| 358 | * last word: reset the receiver CRC | |
| 359 | * | |
| 360 | * TODO: if data comes from some other source, | |
| 361 | * compare our CRC with the next word received | |
| 362 | * and set the CRC error flag if they differ. | |
| 363 | */ | |
| 364 | m_eth.rx_crc = 0; | |
| 365 | /* set the IGONE flip flop */ | |
| 366 | PUT_ETH_IGONE(m_eth.status, 1); | |
| 367 | ||
| 368 | m_eth.tx_timer->adjust(attotime::from_seconds(m_duckbreath_sec), 0); | |
| 369 | } else { | |
| 370 | /* 5.44us per word (?) */ | |
| 371 | m_eth.tx_timer->adjust(attotime::from_usec(5.44), arg); | |
| 372 | } | |
| 373 | ||
| 374 | eth_wakeup(); | |
| 375 | } | |
| 376 | ||
| 377 | /** | |
| 378 | * @brief transmit data from the FIFO to <nirvana for now> | |
| 379 | * | |
| 380 | * @param id timer id | |
| 381 | * @param arg word count if >= 0, -1 if CRC is to be transmitted (last word) | |
| 382 | */ | |
| 383 | void alto2_cpu_device::tx_packet(void* ptr, INT32 arg) | |
| 384 | { | |
| 385 | UINT32 data; | |
| 386 | ||
| 387 | /* last word is the CRC */ | |
| 388 | if (arg == -1) { | |
| 389 | if (m_eth.tx_timer) | |
| 390 | m_eth.tx_timer->enable(false); | |
| 391 | /* TODO: send the CRC as final word of the packet */ | |
| 392 | LOG((0,0," CRC:%06o\n", m_eth.tx_crc)); | |
| 393 | m_eth.tx_crc = 0; | |
| 394 | PUT_ETH_OGONE(m_eth.status, 1); // set the OGONE flip flop | |
| 395 | eth_wakeup(); | |
| 396 | return; | |
| 397 | } | |
| 398 | ||
| 399 | data = m_eth.fifo[m_eth.fifo_rd]; | |
| 400 | m_eth.tx_crc = f9401_7(m_eth.tx_crc, data); | |
| 401 | if (m_eth.fifo_rd % 8) | |
| 402 | LOG((0,0," %06o", data)); | |
| 403 | else | |
| 404 | LOG((0,0,"\n%06o: %06o", m_eth.tx_count, data)); | |
| 405 | m_eth.fifo_rd = (m_eth.fifo_rd + 1) % ALTO2_ETHER_FIFO_SIZE; | |
| 406 | m_eth.tx_count++; | |
| 407 | ||
| 408 | /* is the FIFO empty now? */ | |
| 409 | if (ETHER_A49_BE) { | |
| 410 | /* clear the OBUSY and WLF flip flops */ | |
| 411 | PUT_ETH_OBUSY(m_eth.status, 0); | |
| 412 | PUT_ETH_WLF(m_eth.status, 0); | |
| 413 | // FIXME: Use MAME timer | |
| 414 | // m_eth.tx_id = timer_insert(TIME_US(5.44), tx_packet, -1, "tx packet CRC"); | |
| 415 | eth_wakeup(); | |
| 416 | return; | |
| 417 | } | |
| 418 | ||
| 419 | /* next word */ | |
| 420 | // FIXME: Use MAME timer | |
| 421 | // m_eth.tx_id = timer_insert(TIME_US(5.44), tx_packet, arg + 1, "tx packet"); | |
| 422 | eth_wakeup(); | |
| 423 | } | |
| 424 | ||
| 425 | void alto2_cpu_device::eth_startf() | |
| 426 | { | |
| 427 | PUT_ETH_ICMD(m_eth.status, A2_BIT16(m_bus,16,14)); | |
| 428 | PUT_ETH_OCMD(m_eth.status, A2_BIT16(m_bus,16,15)); | |
| 429 | if (GET_ETH_ICMD(m_eth.status) || GET_ETH_OCMD(m_eth.status)) | |
| 430 | m_task_wakeup |= 1 << task_ether; | |
| 431 | } | |
| 432 | ||
| 433 | /** | |
| 434 | * @brief bs_eidfct early: Ethernet input data function | |
| 435 | * | |
| 436 | * Gates the contents of the FIFO to BUS[0-15], and increments | |
| 437 | * the read pointer at the end of the cycle. | |
| 438 | */ | |
| 439 | void alto2_cpu_device::bs_eidfct_0() | |
| 440 | { | |
| 441 | UINT16 r = m_eth.fifo[m_eth.fifo_rd]; | |
| 442 | ||
| 443 | LOG((0,3, " <-EIDFCT; pull %06o from FIFO[%02o]\n", r, m_eth.fifo_rd)); | |
| 444 | m_eth.fifo_rd = (m_eth.fifo_rd + 1) % ALTO2_ETHER_FIFO_SIZE; | |
| 445 | m_bus &= r; | |
| 446 | m_eth.rx_count++; | |
| 447 | ||
| 448 | eth_wakeup(); | |
| 449 | } | |
| 450 | ||
| 451 | /** | |
| 452 | * @brief f1_eth_block early: block the Ether task | |
| 453 | */ | |
| 454 | void alto2_cpu_device::f1_eth_block_0() | |
| 455 | { | |
| 456 | LOG((0,2," BLOCK %s\n", task_name(m_task))); | |
| 457 | m_task_wakeup &= ~(1 << task_ether); | |
| 458 | } | |
| 459 | ||
| 460 | /** | |
| 461 | * @brief f1_eilfct early: Ethernet input look function | |
| 462 | * | |
| 463 | * Gates the contents of the FIFO to BUS[0-15], but does not | |
| 464 | * increment the read pointer; | |
| 465 | */ | |
| 466 | void alto2_cpu_device::f1_eilfct_0() | |
| 467 | { | |
| 468 | UINT16 r = m_eth.fifo[m_eth.fifo_rd]; | |
| 469 | LOG((0,3, " <-EILFCT; %06o at FIFO[%02o]\n", r, m_eth.fifo_rd)); | |
| 470 | m_bus &= r; | |
| 471 | } | |
| 472 | ||
| 473 | /** | |
| 474 | * @brief f1_epfct early: Ethernet post function | |
| 475 | * | |
| 476 | * Gates the interface status to BUS[8-15]. Resets the interface | |
| 477 | * at the end of the function. | |
| 478 | * | |
| 479 | * The schematics suggest that just BUS[10-15] is modified. | |
| 480 | * | |
| 481 | * Also a comment from the microcode: | |
| 482 | * ;Ether Post Function - EPFCT. Gate the hardware status | |
| 483 | * ;(LOW TRUE) to Bus [10:15], reset interface. | |
| 484 | * | |
| 485 | */ | |
| 486 | void alto2_cpu_device::f1_epfct_0() | |
| 487 | { | |
| 488 | UINT16 r = ~A2_GET16(m_eth.status,16,10,15) & 0177777; | |
| 489 | ||
| 490 | LOG((0,3, " <-EPFCT; BUS[8-15] = STATUS (%#o)\n", r)); | |
| 491 | m_bus &= r; | |
| 492 | ||
| 493 | m_eth.status = 0; | |
| 494 | eth_wakeup(); | |
| 495 | } | |
| 496 | ||
| 497 | /** | |
| 498 | * @brief f1_ewfct late: Ethernet countdown wakeup function | |
| 499 | * | |
| 500 | * Sets a flip flop in the interface that will cause a wakeup to the | |
| 501 | * Ether task on the next tick of SWAKMRT (memory refresh task). | |
| 502 | * This function must be issued in the instruction after a TASK. | |
| 503 | * The resulting wakeup is cleared when the Ether task next runs. | |
| 504 | */ | |
| 505 | void alto2_cpu_device::f1_ewfct_1() | |
| 506 | { | |
| 507 | /* | |
| 508 | * Set a flag in the CPU to handle the next task switch | |
| 509 | * to the task_mrt by also waking up the task_ether. | |
| 510 | */ | |
| 511 | m_ewfct = m_ether_enable; | |
| 512 | } | |
| 513 | ||
| 514 | /** | |
| 515 | * @brief f2_eodfct late: Ethernet output data function | |
| 516 | * | |
| 517 | * Loads the FIFO from BUS[0-15], then increments the write | |
| 518 | * pointer at the end of the cycle. | |
| 519 | */ | |
| 520 | void alto2_cpu_device::f2_eodfct_1() | |
| 521 | { | |
| 522 | LOG((0,3, " EODFCT<-; push %06o into FIFO[%02o]\n", m_bus, m_eth.fifo_wr)); | |
| 523 | ||
| 524 | m_eth.fifo[m_eth.fifo_wr] = m_bus; | |
| 525 | m_eth.fifo_wr = (m_eth.fifo_wr + 1) % ALTO2_ETHER_FIFO_SIZE; | |
| 526 | ||
| 527 | PUT_ETH_WLF(m_eth.status, 1); | |
| 528 | PUT_ETH_OBUSY(m_eth.status, 1); | |
| 529 | /* if the FIFO is full */ | |
| 530 | if (ETHER_A49_BF == 0) { | |
| 531 | if (!m_eth.tx_timer) { | |
| 532 | m_eth.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::tx_packet),this)); | |
| 533 | } | |
| 534 | } | |
| 535 | eth_wakeup(); | |
| 536 | } | |
| 537 | ||
| 538 | /** | |
| 539 | * @brief f2_eosfct late: Ethernet output start function | |
| 540 | * | |
| 541 | * Sets the OBUSY flip flop in the interface, starting data | |
| 542 | * wakeups to fill the FIFO for output. When the FIFO is full, | |
| 543 | * or EEFCT has been issued, the interface will wait for silence | |
| 544 | * on the Ether and begin transmitting. | |
| 545 | */ | |
| 546 | void alto2_cpu_device::f2_eosfct_1() | |
| 547 | { | |
| 548 | LOG((0,3, " EOSFCT\n")); | |
| 549 | PUT_ETH_WLF(m_eth.status, 0); | |
| 550 | PUT_ETH_OBUSY(m_eth.status, 0); | |
| 551 | eth_wakeup(); | |
| 552 | } | |
| 553 | ||
| 554 | /** | |
| 555 | * @brief f2_erbfct late: Ethernet reset branch function | |
| 556 | * | |
| 557 | * This command dispatch function merges the ICMD and OCMD flip flops | |
| 558 | * into NEXT[6-7]. These flip flops are the means of communication | |
| 559 | * between the emulator task and the Ethernet task. The emulator | |
| 560 | * task sets them up from BUS[14-15] with the STARTF function, | |
| 561 | * causing the Ethernet task to wakeup, dispatch on them and then | |
| 562 | * reset them with EPFCT. | |
| 563 | */ | |
| 564 | void alto2_cpu_device::f2_erbfct_1() | |
| 565 | { | |
| 566 | UINT16 r = 0; | |
| 567 | A2_PUT16(r,10,6,6,GET_ETH_ICMD(m_eth.status)); | |
| 568 | A2_PUT16(r,10,7,7,GET_ETH_OCMD(m_eth.status)); | |
| 569 | LOG((0,3, " ERBFCT; NEXT[6-7] = ICMD,OCMD (%#o | %#o)\n", m_next2, r)); | |
| 570 | m_next2 |= r; | |
| 571 | eth_wakeup(); | |
| 572 | } | |
| 573 | ||
| 574 | /** | |
| 575 | * @brief f2_eefct late: Ethernet end of transmission function | |
| 576 | * | |
| 577 | * This function is issued when all of the main memory output buffer | |
| 578 | * has been transferred to the FIFO. EEFCT disables further data | |
| 579 | * wakeups. | |
| 580 | */ | |
| 581 | void alto2_cpu_device::f2_eefct_1() | |
| 582 | { | |
| 583 | /* start transmitting the packet */ | |
| 584 | PUT_ETH_OBUSY(m_eth.status, 1); | |
| 585 | PUT_ETH_OEOT(m_eth.status, 1); | |
| 586 | if (m_eth.tx_timer) { | |
| 587 | m_eth.tx_timer->enable(); | |
| 588 | } else { | |
| 589 | m_eth.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::tx_packet),this)); | |
| 590 | m_eth.tx_timer->adjust(attotime::from_usec(5.44), 0); | |
| 591 | } | |
| 592 | eth_wakeup(); | |
| 593 | } | |
| 594 | ||
| 595 | /** | |
| 596 | * @brief f2_ebfct late: Ethernet branch function | |
| 597 | * | |
| 598 | * ORs a 1 into NEXT[7] if an input data late is detected, or an SIO | |
| 599 | * with AC0[14-15] non-zero is issued, or if the transmitter or | |
| 600 | * receiver is gone. ORs a 1 into NEXT[6] if a collision is detected. | |
| 601 | */ | |
| 602 | void alto2_cpu_device::f2_ebfct_1() | |
| 603 | { | |
| 604 | UINT16 r = 0; | |
| 605 | A2_PUT16(r,10,6,6, GET_ETH_COLL(m_eth.status)); | |
| 606 | A2_PUT16(r,10,7,7, GET_ETH_IDL(m_eth.status) | | |
| 607 | GET_ETH_ICMD(m_eth.status) | | |
| 608 | GET_ETH_OCMD(m_eth.status) | | |
| 609 | GET_ETH_IGONE(m_eth.status) | | |
| 610 | GET_ETH_OGONE(m_eth.status)); | |
| 611 | LOG((0,3, " EBFCT; NEXT ... (%#o | %#o)\n", m_next2, r)); | |
| 612 | m_next2 |= r; | |
| 613 | } | |
| 614 | ||
| 615 | /** | |
| 616 | * @brief f2_ecbfct late: Ethernet countdown branch function | |
| 617 | * | |
| 618 | * ORs a one into NEXT[7] if the FIFO is not empty. | |
| 619 | */ | |
| 620 | void alto2_cpu_device::f2_ecbfct_1() | |
| 621 | { | |
| 622 | UINT16 r = 0; | |
| 623 | /* TODO: the BE' (buffer empty) signal is output D0 of PROM a49 */ | |
| 624 | A2_PUT16(r,10,7,7,ETHER_A49_BE); | |
| 625 | LOG((0,3, " ECBFCT; NEXT[7] = FIFO %sempty (%#o | %#o)\n", r ? "not " : "is ", m_next2, r)); | |
| 626 | m_next2 |= r; | |
| 627 | } | |
| 628 | ||
| 629 | /** | |
| 630 | * @brief f2_eisfct late: Ethernet input start function | |
| 631 | * | |
| 632 | * Sets the IBUSY flip flop in the interface, causing it to hunt | |
| 633 | * for the beginning of a packet: silence on the Ether followed | |
| 634 | * by a transition. When the interface has collected two words, | |
| 635 | * it will begin generating data wakeups to the microcode. | |
| 636 | */ | |
| 637 | void alto2_cpu_device::f2_eisfct_1() | |
| 638 | { | |
| 639 | LOG((0,3, " EISFCT\n")); | |
| 640 | PUT_ETH_IBUSY(m_eth.status, 0); | |
| 641 | eth_wakeup(); | |
| 642 | } | |
| 643 | ||
| 644 | /** @brief called by the CPU when the Ethernet task becomes active | |
| 645 | * | |
| 646 | * Reset the Ether wake flip flop | |
| 647 | */ | |
| 648 | void alto2_cpu_device::eth_activate() | |
| 649 | { | |
| 650 | m_ewfct = 0; | |
| 651 | } | |
| 652 | ||
| 653 | /** | |
| 654 | * @brief Ethernet task slot initialization | |
| 655 | */ | |
| 656 | void alto2_cpu_device::init_ether(int task) | |
| 657 | { | |
| 658 | // intialize all ethernet variables | |
| 659 | memset(&m_eth, 0, sizeof(m_eth)); | |
| 660 | ||
| 661 | set_bs(task, bs_ether_eidfct, &alto2_cpu_device::bs_eidfct_0, 0); | |
| 662 | ||
| 663 | set_f1(task, f1_block, &alto2_cpu_device::f1_eth_block_0, 0); | |
| 664 | set_f1(task, f1_ether_eilfct, &alto2_cpu_device::f1_eilfct_0, 0); | |
| 665 | set_f1(task, f1_ether_epfct, &alto2_cpu_device::f1_epfct_0, 0); | |
| 666 | set_f1(task, f1_ether_ewfct, 0, &alto2_cpu_device::f1_ewfct_1); | |
| 667 | ||
| 668 | set_f2(task, f2_ether_eodfct, 0, &alto2_cpu_device::f2_eodfct_1); | |
| 669 | set_f2(task, f2_ether_eosfct, 0, &alto2_cpu_device::f2_eosfct_1); | |
| 670 | set_f2(task, f2_ether_erbfct, 0, &alto2_cpu_device::f2_erbfct_1); | |
| 671 | set_f2(task, f2_ether_eefct, 0, &alto2_cpu_device::f2_eefct_1); | |
| 672 | set_f2(task, f2_ether_ebfct, 0, &alto2_cpu_device::f2_ebfct_1); | |
| 673 | set_f2(task, f2_ether_ecbfct, 0, &alto2_cpu_device::f2_ecbfct_1); | |
| 674 | set_f2(task, f2_ether_eisfct, 0, &alto2_cpu_device::f2_eisfct_1); | |
| 675 | ||
| 676 | m_active_callback[task] = &alto2_cpu_device::eth_activate; | |
| 677 | } | |
| 678 |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * Portable Xerox AltoII disk drive DIABLO31 | |
| 4 | * | |
| 5 | * Copyright: Juergen Buchmueller <pullmoll@t-online.de> | |
| 6 | * | |
| 7 | * Licenses: MAME, GPLv2 | |
| 8 | * | |
| 9 | *****************************************************************************/ | |
| 10 | #include "alto2.h" | |
| 11 | ||
| 12 | #define DIABLO31 1 | |
| 13 | ||
| 14 | #define PAGENO_WORDS 1 //!< number of words in a page number (this doesn't really belong here) | |
| 15 | #define HEADER_WORDS 2 //!< number of words in a header (this doesn't really belong here) | |
| 16 | #define LABEL_WORDS 8 //!< number of words in a label (this doesn't really belong here) | |
| 17 | #define DATA_WORDS 256 //!< number of data words (this doesn't really belong here) | |
| 18 | #define CKSUM_WORDS 1 //!< number of words for a checksum (this doesn't really belong here) | |
| 19 | #define MFROBL 34 //!< from the microcode: disk header preamble is 34 words | |
| 20 | #define MFRRDL 21 //!< from the microcode: disk header read delay is 21 words | |
| 21 | #define MIRRDL 4 //!< from the microcode: interrecord read delay is 4 words | |
| 22 | #define MIROBL 3 //!< from the microcode: disk interrecord preamble is 3 words | |
| 23 | #define MRPAL 3 //!< from the microcode: disk read postamble length is 3 words | |
| 24 | #define MWPAL 5 //!< from the microcode: disk write postamble length is 5 words | |
| 25 | /** | |
| 26 | * @brief description of the sector layout | |
| 27 | * <PRE> | |
| 28 | * | |
| 29 | * xx.x msec sector mark pulses | |
| 30 | * -+ +-------------------------------------------------------------------------------+ +-- | |
| 31 | * | | | | | |
| 32 | * +---+ +---+ | |
| 33 | * | |
| 34 | * | | | |
| 35 | * | |
| 36 | * +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+ | |
| 37 | * | PRE- |SYNC|HEADER|CKSUM| PRE- |SYNC| LABEL |CKSUM| PRE- |SYNC| DATA |CKSUM| POST | | |
| 38 | * |AMBLE1| 1 | | 1 |AMBLE2| 2 | | 2 |AMBLE3| 3 | | 3 |AMBLE | | |
| 39 | * +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+ | |
| 40 | * | |
| 41 | * | | | |
| 42 | * | |
| 43 | * +-----------------------------------------------------------------------------------+ | |
| 44 | * | | | |
| 45 | * ---+ +---- | |
| 46 | * FORMAT WRITE GATE FOR INITIALIZING | |
| 47 | * | | | |
| 48 | * | |
| 49 | * | +------------------------------+ | |
| 50 | * | | | |
| 51 | * ---|----------------------------------------------------+ +---- | |
| 52 | * WRITE GATE FOR DATA XFER (*) | |
| 53 | * | | | |
| 54 | * | |
| 55 | * | +-----------------------+-+------------------------------+ | |
| 56 | * | | | may be continuous (?) | | |
| 57 | * ------------------------------+ +-+ +---- | |
| 58 | * ??? WRITE GATE FOR LABEL AND DATA XFER (*) | |
| 59 | * | | | |
| 60 | * | |
| 61 | * | +--------------------+ +---------------------+ +----------------------------+ | |
| 62 | * | | | | | | | |
| 63 | * -------+ +---+ +---+ +---- | |
| 64 | * READ GATE FOR INITIALIZING OR DATA XFER (**) | |
| 65 | * | |
| 66 | * | |
| 67 | * (*) Enable should be delayed 1 byte/word time from last bit of checks sum. | |
| 68 | * (**) Read Gate should be enabled half way through the preamble area. This | |
| 69 | * ensures reading a zero field for data separator synchronization. | |
| 70 | * | |
| 71 | * </PRE> | |
| 72 | */ | |
| 73 | #if DIABLO31 | |
| 74 | ||
| 75 | /** @brief DIABLO 31 rotation time is approx. 40ms */ | |
| 76 | #define ROTATION_TIME attotime::from_msec(39.9999) | |
| 77 | ||
| 78 | /** @brief DIABLO 31 sector time */ | |
| 79 | #define SECTOR_TIME attotime::from_msec(39.9999/DRIVE_SPT) | |
| 80 | ||
| 81 | /** @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit | |
| 82 | * ~= 133333 bits/track (?) | |
| 83 | * ~= 11111 bits/sector | |
| 84 | * ~= 347 words/sector | |
| 85 | */ | |
| 86 | #define BIT_TIME(bits) attotime::from_nsec(300*(bits)) | |
| 87 | ||
| 88 | /** @brief DIABLO 31 possible sector words */ | |
| 89 | #define SECTOR_WORDS (int)(SECTOR_TIME / BIT_TIME(1) / 32) | |
| 90 | ||
| 91 | ||
| 92 | /** @brief pulse width of sector mark before the next sector begins */ | |
| 93 | #define SECTOR_MARK_PULSE_PRE BIT_TIME(16) | |
| 94 | ||
| 95 | /** @brief pulse width of sector mark after the next sector began */ | |
| 96 | #define SECTOR_MARK_PULSE_POST BIT_TIME(16) | |
| 97 | ||
| 98 | #else /* DIABLO31 */ | |
| 99 | ||
| 100 | /** @brief DIABLO 44 rotation time is approx. 25ms */ | |
| 101 | #define ROTATION_TIME attotime::from_msec(25) | |
| 102 | ||
| 103 | /** @brief DIABLO 44 sector time */ | |
| 104 | #define SECTOR_TIME attotime::from_msec(25/DRIVE_SPT) | |
| 105 | ||
| 106 | /** @brief DIABLO 44 bit clock is 5000kHz ~= 200ns per bit | |
| 107 | * ~= 125184 bits/track (?) | |
| 108 | * ~= 10432 bits/sector | |
| 109 | * ~= 325 words/sector | |
| 110 | */ | |
| 111 | #define BIT_TIME attotime::from_nsec(200) | |
| 112 | ||
| 113 | /** @brief DIABLO 44 possible sector words */ | |
| 114 | #define SECTOR_WORDS (int)(SECTOR_TIME / BIT_TIME / 32) | |
| 115 | ||
| 116 | /** @brief pulse width of sector mark before the next sector begins */ | |
| 117 | #define SECTOR_MARK_PULSE_PRE (16 * BIT_TIME) | |
| 118 | ||
| 119 | /** @brief pulse width of sector mark after the next sector began */ | |
| 120 | #define SECTOR_MARK_PULSE_POST (16 * BIT_TIME) | |
| 121 | #endif | |
| 122 | ||
| 123 | ||
| 124 | /** @brief end of the guard zone at the beginning of a sector (wild guess!) */ | |
| 125 | #define GUARD_ZONE_BITS (16*32) | |
| 126 | ||
| 127 | /** @brief write a bit into an array of UINT32 */ | |
| 128 | #define WRBIT(bits,dst,bit) do { \ | |
| 129 | if (bit) { \ | |
| 130 | bits[(dst)/32] |= 1 << ((dst) % 32); \ | |
| 131 | } else { \ | |
| 132 | bits[(dst)/32] &= ~(1 << ((dst) % 32)); \ | |
| 133 | } \ | |
| 134 | } while (0) | |
| 135 | ||
| 136 | /** @brief read a bit from an array of UINT32 */ | |
| 137 | #define RDBIT(bits,src) ((bits[(src)/32] >> ((src) % 32)) & 1) | |
| 138 | ||
| 139 | /** | |
| 140 | * @brief format of the cooked disk image sectors, i.e. pure data | |
| 141 | * | |
| 142 | * The available images are a multiple of 267 words per sector, | |
| 143 | * 1 word page number | |
| 144 | * 2 words header | |
| 145 | * 8 words label | |
| 146 | * 256 words data | |
| 147 | */ | |
| 148 | typedef struct { | |
| 149 | /** @brief sector page number */ | |
| 150 | UINT8 pageno[2*PAGENO_WORDS]; | |
| 151 | ||
| 152 | /** @brief sector header words */ | |
| 153 | UINT8 header[2*HEADER_WORDS]; | |
| 154 | ||
| 155 | /** @brief sector label words */ | |
| 156 | UINT8 label[2*LABEL_WORDS]; | |
| 157 | ||
| 158 | /** @brief sector data words */ | |
| 159 | UINT8 data[2*DATA_WORDS]; | |
| 160 | } diablo_sector_t; | |
| 161 | ||
| 162 | ||
| 163 | /** | |
| 164 | * @brief Structure of the disk drive context (2 drives or packs per system) | |
| 165 | */ | |
| 166 | typedef struct { | |
| 167 | /** @brief disk image, made up of 203 x 2 x 12 sectors */ | |
| 168 | diablo_sector_t *image; | |
| 169 | ||
| 170 | /** @brief drive unit number (0 or 1) */ | |
| 171 | int unit; | |
| 172 | ||
| 173 | /** @brief description of the drive(s) */ | |
| 174 | char description[32]; | |
| 175 | ||
| 176 | /** @brief basename of the drive image */ | |
| 177 | char basename[80]; | |
| 178 | ||
| 179 | /** @brief number of packs in drive (1 or 2) */ | |
| 180 | int packs; | |
| 181 | ||
| 182 | /** @brief rotation time */ | |
| 183 | attotime rotation_time; | |
| 184 | ||
| 185 | /** @brief bit time in atto seconds */ | |
| 186 | attotime bit_time; | |
| 187 | ||
| 188 | /** @brief drive seek/read/write signal (active 0) */ | |
| 189 | int s_r_w_0; | |
| 190 | ||
| 191 | /** @brief drive ready signal (active 0) */ | |
| 192 | int ready_0; | |
| 193 | ||
| 194 | /** @brief sector mark (0 if new sector) */ | |
| 195 | int sector_mark_0; | |
| 196 | ||
| 197 | /** @brief address acknowledge, i.e. seek successful (active 0) */ | |
| 198 | int addx_acknowledge_0; | |
| 199 | ||
| 200 | /** @brief log address interlock, i.e. seek in progress (active 0) */ | |
| 201 | int log_addx_interlock_0; | |
| 202 | ||
| 203 | /** @brief seek incomplete, i.e. seek in progress (active 0) */ | |
| 204 | int seek_incomplete_0; | |
| 205 | ||
| 206 | /** @brief erase gate */ | |
| 207 | int egate_0; | |
| 208 | ||
| 209 | /** @brief write gate */ | |
| 210 | int wrgate_0; | |
| 211 | ||
| 212 | /** @brief read gate */ | |
| 213 | int rdgate_0; | |
| 214 | ||
| 215 | /** @brief current cylinder number */ | |
| 216 | int cylinder; | |
| 217 | ||
| 218 | /** @brief current head (track) number on cylinder */ | |
| 219 | int head; | |
| 220 | ||
| 221 | /** @brief current sector number in track */ | |
| 222 | int sector; | |
| 223 | ||
| 224 | /** @brief sectors expanded to bits */ | |
| 225 | UINT32 *bits[DRIVE_CYLINDERS * DRIVE_HEADS * DRIVE_SPT]; | |
| 226 | ||
| 227 | /** @brief current page = (cylinder * HEADS + head) * SPT + sector */ | |
| 228 | int page; | |
| 229 | ||
| 230 | /** @brief set to first bit of a sector that is read from */ | |
| 231 | int rdfirst; | |
| 232 | ||
| 233 | /** @brief set to last bit of a sector that was read from */ | |
| 234 | int rdlast; | |
| 235 | ||
| 236 | /** @brief set to non-zero if a sector is written to */ | |
| 237 | int wrfirst; | |
| 238 | ||
| 239 | /** @brief set to last bit of a sector that was written to */ | |
| 240 | int wrlast; | |
| 241 | } diablo_drive_t; | |
| 242 | ||
| 243 | #if DIABLO31 | |
| 244 | static diablo_drive_t drive[DRIVE_MAX] = { | |
| 245 | { | |
| 246 | NULL, | |
| 247 | 0, | |
| 248 | "DIABLO31", "", | |
| 249 | 1, | |
| 250 | ROTATION_TIME, | |
| 251 | BIT_TIME, | |
| 252 | 0, | |
| 253 | },{ | |
| 254 | NULL, | |
| 255 | 1, | |
| 256 | "DIABLO31", "", | |
| 257 | 1, | |
| 258 | ROTATION_TIME, | |
| 259 | BIT_TIME, | |
| 260 | 0, | |
| 261 | } | |
| 262 | }; | |
| 263 | #else | |
| 264 | static drive_t drive[DRIVE_MAX] = { | |
| 265 | { | |
| 266 | NULL, | |
| 267 | 0, | |
| 268 | "DIABLO44", "", | |
| 269 | 1, | |
| 270 | ROTATION_TIME, | |
| 271 | BIT_TIME, | |
| 272 | 0, | |
| 273 | },{ | |
| 274 | NULL, | |
| 275 | 1, | |
| 276 | "DIABLO44", "", | |
| 277 | 1, | |
| 278 | ROTATION_TIME, | |
| 279 | BIT_TIME, | |
| 280 | 0, | |
| 281 | } | |
| 282 | }; | |
| 283 | #endif | |
| 284 | ||
| 285 | /** | |
| 286 | * @brief calculate the sector from the logical block address | |
| 287 | * | |
| 288 | * Modifies drive's page by calculating the logical | |
| 289 | * block address from cylinder, head, and sector. | |
| 290 | * | |
| 291 | * @param unit unit number | |
| 292 | */ | |
| 293 | static void drive_get_sector(int unit) | |
| 294 | { | |
| 295 | diablo_drive_t *d = &drive[unit]; | |
| 296 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 297 | fatal(1, "invalid unit %d in call to drive_get_sector()\n", unit); | |
| 298 | ||
| 299 | /* If there's no image, just reset the page number */ | |
| 300 | if (!d->image) { | |
| 301 | d->page = -1; | |
| 302 | return; | |
| 303 | } | |
| 304 | if (d->cylinder < 0 || d->cylinder >= DRIVE_CYLINDERS) { | |
| 305 | LOG((log_DRV,9," DRIVE C/H/S:%d/%d/%d => invalid cylinder\n", | |
| 306 | d->cylinder, d->head, d->sector)); | |
| 307 | d->page = -1; | |
| 308 | return; | |
| 309 | } | |
| 310 | /* calculate the new disk relative sector offset */ | |
| 311 | d->page = DRIVE_PAGE(d->cylinder, d->head, d->sector); | |
| 312 | LOG((log_DRV,9," DRIVE C/H/S:%d/%d/%d => page:%d\n", d->cylinder, d->head, d->sector, d->page)); | |
| 313 | } | |
| 314 | ||
| 315 | /** | |
| 316 | * @brief compute the checksum of a record | |
| 317 | * | |
| 318 | * @param src pointer to a record (header, label, data) | |
| 319 | * @param size size of the record in bytes | |
| 320 | * @param start start value for the checksum | |
| 321 | * @result returns the checksum of the record | |
| 322 | */ | |
| 323 | static int cksum(UINT8 *src, size_t size, int start) | |
| 324 | { | |
| 325 | size_t offs; | |
| 326 | int sum = start; | |
| 327 | int word; | |
| 328 | ||
| 329 | /* compute XOR of all words */ | |
| 330 | for (offs = 0; offs < size; offs += 2) { | |
| 331 | word = src[size - 2 - offs] + 256 * src[size - 2 - offs + 1]; | |
| 332 | sum ^= word; | |
| 333 | } | |
| 334 | return sum; | |
| 335 | } | |
| 336 | ||
| 337 | /** | |
| 338 | * @brief expand a series of clock bits and 0 data bits | |
| 339 | * | |
| 340 | * @param bits pointer to the sector bits | |
| 341 | * @param dst destination offset into bits (bit number) | |
| 342 | * @param size number of words to write | |
| 343 | * @result pointer to next destination bit | |
| 344 | */ | |
| 345 | static size_t expand_zeroes(UINT32 *bits, size_t dst, size_t size) | |
| 346 | { | |
| 347 | size_t offs; | |
| 348 | ||
| 349 | for (offs = 0; offs < 32 * size; offs += 2) { | |
| 350 | WRBIT(bits, dst, 1); // write the clock bit | |
| 351 | dst++; | |
| 352 | WRBIT(bits, dst, 0); // write the 0 data bit | |
| 353 | dst++; | |
| 354 | } | |
| 355 | ||
| 356 | return dst; | |
| 357 | } | |
| 358 | ||
| 359 | /** | |
| 360 | * @brief expand a series of 0 words and write a final sync bit | |
| 361 | * | |
| 362 | * @param bits pointer to the sector bits | |
| 363 | * @param dst destination offset into bits (bit number) | |
| 364 | * @param size number of words to write | |
| 365 | * @result pointer to next destination bit | |
| 366 | */ | |
| 367 | static size_t expand_sync(UINT32 *bits, size_t dst, size_t size) | |
| 368 | { | |
| 369 | size_t offs; | |
| 370 | ||
| 371 | for (offs = 0; offs < 32 * size - 2; offs += 2) { | |
| 372 | WRBIT(bits, dst, 1); // write the clock bit | |
| 373 | dst++; | |
| 374 | WRBIT(bits, dst, 0); // write the 0 data bit | |
| 375 | dst++; | |
| 376 | } | |
| 377 | WRBIT(bits, dst, 1); // write the final clock bit | |
| 378 | dst++; | |
| 379 | WRBIT(bits, dst, 1); // write the 1 data bit | |
| 380 | dst++; | |
| 381 | return dst; | |
| 382 | } | |
| 383 | ||
| 384 | /** | |
| 385 | * @brief expand a record of words into a array of bits at dst | |
| 386 | * | |
| 387 | * @param bits pointer to the sector bits | |
| 388 | * @param dst destination offset into bits (bit number) | |
| 389 | * @param field pointer to the record data (bytes) | |
| 390 | * @param size size of the record in bytes | |
| 391 | * @result pointer to next destination bit | |
| 392 | */ | |
| 393 | static size_t expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size) | |
| 394 | { | |
| 395 | size_t offs, bit; | |
| 396 | ||
| 397 | for (offs = 0; offs < size; offs += 2) { | |
| 398 | int word = field[size - 2 - offs] + 256 * field[size - 2 - offs + 1]; | |
| 399 | for (bit = 0; bit < 16; bit++) { | |
| 400 | WRBIT(bits, dst, 1); // write the clock bit | |
| 401 | dst++; | |
| 402 | WRBIT(bits, dst, (word >> 15) & 1); // write the data bit | |
| 403 | dst++; | |
| 404 | word <<= 1; | |
| 405 | } | |
| 406 | } | |
| 407 | return dst; | |
| 408 | } | |
| 409 | ||
| 410 | /** | |
| 411 | * @brief Expand a record's checksum word to 32 bits | |
| 412 | * | |
| 413 | * @param bits pointer to the sector bits | |
| 414 | * @param dst destination offset into bits (bit number) | |
| 415 | * @param field pointer to the record data (bytes) | |
| 416 | * @param size size of the record in bytes | |
| 417 | * @result pointer to next destination bit | |
| 418 | */ | |
| 419 | static size_t expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size) | |
| 420 | { | |
| 421 | size_t bit; | |
| 422 | int word = cksum(field, size, 0521); | |
| 423 | ||
| 424 | for (bit = 0; bit < 32; bit += 2) { | |
| 425 | /* write the clock bit */ | |
| 426 | WRBIT(bits, dst, 1); | |
| 427 | dst++; | |
| 428 | /* write the data bit */ | |
| 429 | WRBIT(bits, dst, (word >> 15) & 1); | |
| 430 | dst++; | |
| 431 | word <<= 1; | |
| 432 | } | |
| 433 | return dst; | |
| 434 | } | |
| 435 | ||
| 436 | /** | |
| 437 | * @brief Expand a sector into an array of clock and data bits | |
| 438 | * | |
| 439 | * @param unit drive unit number (0 or 1) | |
| 440 | * @param page page number (0 to DRIVE_PAGES-1) | |
| 441 | */ | |
| 442 | static void expand_sector(int unit, int page) | |
| 443 | { | |
| 444 | diablo_drive_t *d = &drive[unit]; | |
| 445 | diablo_sector_t *s; | |
| 446 | UINT32 *bits; | |
| 447 | size_t dst; | |
| 448 | ||
| 449 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 450 | fatal(1, "invalid unit %d in call to expand_sector()\n", unit); | |
| 451 | ||
| 452 | if (page < 0 || page >= DRIVE_PAGES) | |
| 453 | return; | |
| 454 | ||
| 455 | /* already expanded this sector? */ | |
| 456 | if (d->bits[page]) | |
| 457 | return; | |
| 458 | ||
| 459 | if (-1 == page || !d->image) { | |
| 460 | LOG((log_DRV,0," no sector for #%d: %d/%d/%d\n", | |
| 461 | d->unit, d->cylinder, d->head, d->sector)); | |
| 462 | return; | |
| 463 | } | |
| 464 | ||
| 465 | /* get the sector pointer */ | |
| 466 | s = &d->image[page]; | |
| 467 | ||
| 468 | /* allocate a bits image */ | |
| 469 | bits = (UINT32 *)calloc(400, sizeof(UINT32)); | |
| 470 | if (!bits) { | |
| 471 | fatal(1, "failed to malloc(%d) bytes bits for drive #%d page #%d\n", | |
| 472 | sizeof(bits), unit, page); | |
| 473 | } | |
| 474 | ||
| 475 | #if DIABLO31 | |
| 476 | /* write sync bit after 31 words - 1 bit */ | |
| 477 | dst = expand_sync(bits, 0, 31); | |
| 478 | dst = expand_record(bits, dst, s->header, sizeof(s->header)); | |
| 479 | dst = expand_cksum(bits, dst, s->header, sizeof(s->header)); | |
| 480 | ||
| 481 | /* write sync bit after 2 * 5 + 1 words - 1 bit */ | |
| 482 | dst = expand_sync(bits, dst, 2 * MWPAL); | |
| 483 | dst = expand_record(bits, dst, s->label, sizeof(s->label)); | |
| 484 | dst = expand_cksum(bits, dst, s->label, sizeof(s->label)); | |
| 485 | ||
| 486 | /* write sync bit after 2 * 5 + 1 words - 1 bit */ | |
| 487 | dst = expand_sync(bits, dst, 2 * MWPAL); | |
| 488 | dst = expand_record(bits, dst, s->data, sizeof(s->data)); | |
| 489 | dst = expand_cksum(bits, dst, s->data, sizeof(s->data)); | |
| 490 | ||
| 491 | /* fill MWPAL words of clock and 0 data bits */ | |
| 492 | dst = expand_zeroes(bits, dst, MWPAL); | |
| 493 | #else | |
| 494 | /* write sync bit after 31 words - 1 bit */ | |
| 495 | dst = expand_sync(bits, 0, 31); | |
| 496 | dst = expand_record(bits, dst, s->header, sizeof(s->header)); | |
| 497 | dst = expand_cksum(bits, dst, s->header, sizeof(s->header)); | |
| 498 | ||
| 499 | /* write sync bit after 2 * 5 words - 1 bit */ | |
| 500 | dst = expand_sync(bits, dst, 2 * MWPAL); | |
| 501 | dst = expand_record(bits, dst, s->label, sizeof(s->label)); | |
| 502 | dst = expand_cksum(bits, dst, s->label, sizeof(s->label)); | |
| 503 | ||
| 504 | /* write sync bit after 2 * 5 words - 1 bit */ | |
| 505 | dst = expand_sync(bits, dst, 2 * MWPAL); | |
| 506 | dst = expand_record(bits, dst, s->data, sizeof(s->data)); | |
| 507 | dst = expand_cksum(bits, dst, s->data, sizeof(s->data)); | |
| 508 | ||
| 509 | /* fill MWPAL words of clock and 0 data bits */ | |
| 510 | dst = expand_zeroes(bits, dst, MWPAL); | |
| 511 | #endif | |
| 512 | d->bits[page] = bits; | |
| 513 | ||
| 514 | LOG((log_DRV,0," BITS #%d: %03d/%d/%02d #%-5d bits (@%03d.%02d)\n", | |
| 515 | d->unit, d->cylinder, d->head, d->sector, | |
| 516 | dst, dst / 32, dst % 32)); | |
| 517 | ||
| 518 | } | |
| 519 | ||
| 520 | #if DEBUG | |
| 521 | static void drive_dump_ascii(UINT8 *src, size_t size) | |
| 522 | { | |
| 523 | size_t offs; | |
| 524 | LOG((log_DRV,0," [")); | |
| 525 | for (offs = 0; offs < size; offs++) { | |
| 526 | char ch = (char)src[offs ^ 1]; | |
| 527 | LOG((log_DRV,0, "%c", ch < 32 || ch > 126 ? '.' : ch)); | |
| 528 | } | |
| 529 | LOG((log_DRV,0,"]\n")); | |
| 530 | } | |
| 531 | ||
| 532 | ||
| 533 | /** | |
| 534 | * @brief Dump a record's contents | |
| 535 | * | |
| 536 | * @param src pointer to a record (header, label, data) | |
| 537 | * @param size size of the record in bytes | |
| 538 | * @param name name to print before the dump | |
| 539 | */ | |
| 540 | static size_t dump_record(UINT8 *src, size_t addr, size_t size, const char *name, int cr) | |
| 541 | { | |
| 542 | size_t offs; | |
| 543 | LOG((log_DRV,0,"%s:", name)); | |
| 544 | for (offs = 0; offs < size; offs += 2) { | |
| 545 | int word = src[offs] + 256 * src[offs + 1]; | |
| 546 | if (offs % 16) { | |
| 547 | LOG((log_DRV,0," %06o", word)); | |
| 548 | } else { | |
| 549 | if (offs > 0) | |
| 550 | drive_dump_ascii(&src[offs-16], 16); | |
| 551 | LOG((log_DRV,0,"\t%05o: %06o", (addr + offs) / 2, word)); | |
| 552 | } | |
| 553 | } | |
| 554 | if (offs % 16) { | |
| 555 | drive_dump_ascii(&src[offs - (offs % 16)], offs % 16); | |
| 556 | } else { | |
| 557 | drive_dump_ascii(&src[offs-16], 16); | |
| 558 | } | |
| 559 | if (cr) { | |
| 560 | LOG((log_DRV,0,"\n")); | |
| 561 | } | |
| 562 | return size; | |
| 563 | } | |
| 564 | #endif | |
| 565 | ||
| 566 | /** | |
| 567 | * @brief find a sync bit in an array of clock and data bits | |
| 568 | * | |
| 569 | * @param bits pointer to the sector's bits | |
| 570 | * @param src source offset into bits (bit number) | |
| 571 | * @param size number of words to scan for a sync word | |
| 572 | * @result next src pointer | |
| 573 | */ | |
| 574 | static size_t squeeze_sync(UINT32 *bits, size_t src, size_t size) | |
| 575 | { | |
| 576 | size_t offs, bitcount; | |
| 577 | UINT32 accu = 0; | |
| 578 | ||
| 579 | /* hunt for the first 0x0001 word */ | |
| 580 | for (bitcount = 0, offs = 0; offs < size; /* */) { | |
| 581 | /* | |
| 582 | * accumulate clock and data bits until we are | |
| 583 | * on the clock bit boundary | |
| 584 | */ | |
| 585 | accu = (accu << 1) | RDBIT(bits,src); | |
| 586 | src++; | |
| 587 | /* | |
| 588 | * look for 15 alternating clocks and 0-bits | |
| 589 | * and the 16th clock with a 1-bit | |
| 590 | */ | |
| 591 | if (accu == 0xaaaaaaab) | |
| 592 | return src; | |
| 593 | if (++bitcount == 32) { | |
| 594 | bitcount = 0; | |
| 595 | offs++; | |
| 596 | } | |
| 597 | } | |
| 598 | /* return if no sync found within size*32 clock and data bits */ | |
| 599 | LOG((log_DRV,0," no sync within %d words\n", size)); | |
| 600 | return src; | |
| 601 | } | |
| 602 | ||
| 603 | /** | |
| 604 | * @brief find a 0 bit sequence in an array of clock and data bits | |
| 605 | * | |
| 606 | * @param bits pointer to the sector's bits | |
| 607 | * @param src source offset into bits (bit number) | |
| 608 | * @param size number of words to scan for a sync word | |
| 609 | * @result next src pointer | |
| 610 | */ | |
| 611 | static size_t squeeze_unsync(UINT32 *bits, size_t src, size_t size) | |
| 612 | { | |
| 613 | size_t offs, bitcount; | |
| 614 | UINT32 accu = 0; | |
| 615 | ||
| 616 | /* hunt for the first 0x0000 word */ | |
| 617 | for (bitcount = 0, offs = 0; offs < size; /* */) { | |
| 618 | /* | |
| 619 | * accumulate clock and data bits until we are | |
| 620 | * on the clock bit boundary | |
| 621 | */ | |
| 622 | accu = (accu << 1) | RDBIT(bits,src); | |
| 623 | src++; | |
| 624 | /* | |
| 625 | * look for 15 alternating clocks and 0-bits | |
| 626 | * and the 16th clock with a 1-bit | |
| 627 | */ | |
| 628 | if (accu == 0xaaaaaaaa) | |
| 629 | return src; | |
| 630 | if (++bitcount == 32) { | |
| 631 | bitcount = 0; | |
| 632 | offs++; | |
| 633 | } | |
| 634 | } | |
| 635 | /* return if no sync found within size*32 clock and data bits */ | |
| 636 | LOG((log_DRV,0," no unsync within %d words\n", size)); | |
| 637 | return src; | |
| 638 | } | |
| 639 | ||
| 640 | /** | |
| 641 | * @brief squeeze an array of clock and data bits into a sector's record | |
| 642 | * | |
| 643 | * @param bits pointer to the sector's bits | |
| 644 | * @param src source offset into bits (bit number) | |
| 645 | * @param field pointer to the record data (bytes) | |
| 646 | * @param size size of the record in bytes | |
| 647 | * @result next src pointer | |
| 648 | */ | |
| 649 | static size_t squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size) | |
| 650 | { | |
| 651 | size_t offs, bitcount; | |
| 652 | UINT32 accu = 0; | |
| 653 | ||
| 654 | ||
| 655 | for (bitcount = 0, offs = 0; offs < size; /* */) { | |
| 656 | /* skip clock */ | |
| 657 | src++; | |
| 658 | /* get data bit */ | |
| 659 | accu = (accu << 1) | RDBIT(bits,src); | |
| 660 | src++; | |
| 661 | bitcount += 2; | |
| 662 | if (bitcount == 32) { | |
| 663 | /* collected a word */ | |
| 664 | field[size - 2 - offs + 0] = accu % 256; | |
| 665 | field[size - 2 - offs + 1] = accu / 256; | |
| 666 | offs += 2; | |
| 667 | bitcount = 0; | |
| 668 | } | |
| 669 | } | |
| 670 | return src; | |
| 671 | } | |
| 672 | ||
| 673 | /** | |
| 674 | * @brief squeeze an array of 32 clock and data bits into a checksum word | |
| 675 | * | |
| 676 | * @param bits pointer to the sector's bits | |
| 677 | * @param src source offset into bits (bit number) | |
| 678 | * @param cksum pointer to an int to receive the checksum word | |
| 679 | * @result next src pointer | |
| 680 | */ | |
| 681 | static size_t squeeze_cksum(UINT32 *bits, size_t src, int *cksum) | |
| 682 | { | |
| 683 | size_t bitcount; | |
| 684 | UINT32 accu = 0; | |
| 685 | ||
| 686 | ||
| 687 | for (bitcount = 0; bitcount < 32; bitcount += 2) { | |
| 688 | /* skip clock */ | |
| 689 | src++; | |
| 690 | /* get data bit */ | |
| 691 | accu = (accu << 1) | RDBIT(bits,src); | |
| 692 | src++; | |
| 693 | } | |
| 694 | ||
| 695 | /* set the cksum to the extracted word */ | |
| 696 | *cksum = accu; | |
| 697 | return src; | |
| 698 | } | |
| 699 | ||
| 700 | /** | |
| 701 | * @brief squeeze a array of clock and data bits into a sector's data | |
| 702 | */ | |
| 703 | static void squeeze_sector(int unit) | |
| 704 | { | |
| 705 | diablo_drive_t *d = &drive[unit]; | |
| 706 | diablo_sector_t *s; | |
| 707 | UINT32 *bits; | |
| 708 | size_t src; | |
| 709 | int cksum_header, cksum_label, cksum_data; | |
| 710 | ||
| 711 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 712 | fatal(1, "invalid unit %d in call to squeeze_sector()\n", unit); | |
| 713 | ||
| 714 | if (d->rdfirst >= 0) { | |
| 715 | LOG((log_DRV,0, | |
| 716 | " RD #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n", | |
| 717 | d->unit, d->cylinder, d->head, d->sector, | |
| 718 | d->rdfirst, d->rdfirst / 32, d->rdfirst % 32, | |
| 719 | d->rdlast, d->rdlast / 32, d->rdlast % 32)); | |
| 720 | } | |
| 721 | d->rdfirst = -1; | |
| 722 | d->rdlast = -1; | |
| 723 | ||
| 724 | /* not written to, just drop it now */ | |
| 725 | if (d->wrfirst < 0) { | |
| 726 | d->wrfirst = -1; | |
| 727 | d->wrlast = -1; | |
| 728 | return; | |
| 729 | } | |
| 730 | ||
| 731 | /* did write into the next sector (?) */ | |
| 732 | if (d->wrlast > d->wrfirst && d->wrlast < 256) { | |
| 733 | d->wrfirst = -1; | |
| 734 | d->wrlast = -1; | |
| 735 | return; | |
| 736 | } | |
| 737 | ||
| 738 | if (d->wrfirst >= 0) { | |
| 739 | LOG((log_DRV,0, | |
| 740 | " WR #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n", | |
| 741 | d->unit, d->cylinder, d->head, d->sector, | |
| 742 | d->wrfirst, d->wrfirst / 32, d->wrfirst % 32, | |
| 743 | d->wrlast, d->wrlast / 32, d->wrlast % 32)); | |
| 744 | } | |
| 745 | d->wrfirst = -1; | |
| 746 | d->wrlast = -1; | |
| 747 | ||
| 748 | if (d->page < 0 || d->page >= DRIVE_PAGES) { | |
| 749 | LOG((log_DRV,0," no sector for #%d: %d/%d/%d\n", | |
| 750 | d->unit, d->cylinder, d->head, d->sector)); | |
| 751 | return; | |
| 752 | } | |
| 753 | ||
| 754 | /* get the sector pointer */ | |
| 755 | s = &d->image[d->page]; | |
| 756 | ||
| 757 | /* get the bits pointer */ | |
| 758 | bits = d->bits[d->page]; | |
| 759 | ||
| 760 | /* no bits to write? */ | |
| 761 | if (!bits) { | |
| 762 | LOG((log_DRV,0," no sector for #%d: %d/%d/%d\n", | |
| 763 | d->unit, d->cylinder, d->head, d->sector)); | |
| 764 | return; | |
| 765 | } | |
| 766 | ||
| 767 | /* zap the sector first */ | |
| 768 | memset(s->header, 0, sizeof(s->header)); | |
| 769 | memset(s->label, 0, sizeof(s->label)); | |
| 770 | memset(s->data, 0, sizeof(s->data)); | |
| 771 | ||
| 772 | src = MFRRDL * 32; | |
| 773 | /* skip first words and garbage until 0 bits are coming in */ | |
| 774 | src = squeeze_unsync(bits, src, 40); | |
| 775 | /* sync on header preamble */ | |
| 776 | src = squeeze_sync(bits, src, 40); | |
| 777 | LOG((log_DRV,0," header sync bit #%d (@%03d.%02d)\n", | |
| 778 | src, src / 32, src % 32)); | |
| 779 | src = squeeze_record(bits, src, s->header, sizeof(s->header)); | |
| 780 | src = squeeze_cksum(bits, src, &cksum_header); | |
| 781 | #if DEBUG | |
| 782 | dump_record(s->header, 0, sizeof(s->header), "header", 0); | |
| 783 | #endif | |
| 784 | ||
| 785 | /* skip garbage until 0 bits are coming in */ | |
| 786 | src = squeeze_unsync(bits, src, 40); | |
| 787 | /* sync on label preamble */ | |
| 788 | src = squeeze_sync(bits, src, 40); | |
| 789 | LOG((log_DRV,0," label sync bit #%d (@%03d.%02d)\n", | |
| 790 | src, src / 32, src % 32)); | |
| 791 | src = squeeze_record(bits, src, s->label, sizeof(s->label)); | |
| 792 | src = squeeze_cksum(bits, src, &cksum_label); | |
| 793 | #if DEBUG | |
| 794 | dump_record(s->label, 0, sizeof(s->label), "label", 0); | |
| 795 | #endif | |
| 796 | ||
| 797 | /* skip garbage until 0 bits are coming in */ | |
| 798 | src = squeeze_unsync(bits, src, 40); | |
| 799 | /* sync on data preamble */ | |
| 800 | src = squeeze_sync(bits, src, 40); | |
| 801 | LOG((log_DRV,0," data sync bit #%d (@%03d.%02d)\n", | |
| 802 | src, src / 32, src % 32)); | |
| 803 | src = squeeze_record(bits, src, s->data, sizeof(s->data)); | |
| 804 | src = squeeze_cksum(bits, src, &cksum_data); | |
| 805 | #if DEBUG | |
| 806 | dump_record(s->data, 0, sizeof(s->data), "data", 1); | |
| 807 | #endif | |
| 808 | ||
| 809 | /* TODO: what is the cksum start value for the data record? */ | |
| 810 | cksum_header ^= cksum(s->header, sizeof(s->header), 0521); | |
| 811 | cksum_label ^= cksum(s->label, sizeof(s->label), 0521); | |
| 812 | cksum_data ^= cksum(s->data, sizeof(s->data), 0521); | |
| 813 | ||
| 814 | if (cksum_header || cksum_label || cksum_data) { | |
| 815 | #if DEBUG | |
| 816 | LOG((log_DRV,0," cksum check - header:%06o label:%06o data:%06o\n", | |
| 817 | cksum_header, cksum_label, cksum_data)); | |
| 818 | #else | |
| 819 | printf(" cksum check - header:%06o label:%06o data:%06o\n", | |
| 820 | cksum_header, cksum_label, cksum_data); | |
| 821 | #endif | |
| 822 | } | |
| 823 | } | |
| 824 | ||
| 825 | /** | |
| 826 | * @brief return number of bitclk edges for a sector | |
| 827 | * | |
| 828 | * @result number of bitclk edges for a sector | |
| 829 | */ | |
| 830 | int alto2_cpu_device::drive_bits_per_sector() const | |
| 831 | { | |
| 832 | return SECTOR_WORDS * 32; | |
| 833 | } | |
| 834 | ||
| 835 | /** | |
| 836 | * @brief return a pointer to a drive's description | |
| 837 | * | |
| 838 | * @param unit unit number | |
| 839 | * @result a pointer to the string description | |
| 840 | */ | |
| 841 | const char* alto2_cpu_device::drive_description(int unit) | |
| 842 | { | |
| 843 | diablo_drive_t *d = &drive[unit]; | |
| 844 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 845 | fatal(1, "invalid unit %d in call to drive_description()\n", unit); | |
| 846 | return d->description; | |
| 847 | } | |
| 848 | ||
| 849 | /** | |
| 850 | * @brief return a pointer to a drive's image basename | |
| 851 | * | |
| 852 | * @param unit unit number | |
| 853 | * @result a pointer to the string basename | |
| 854 | */ | |
| 855 | const char* alto2_cpu_device::drive_basename(int unit) | |
| 856 | { | |
| 857 | diablo_drive_t *d = &drive[unit]; | |
| 858 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 859 | fatal(1, "invalid unit %d in call to drive_description()\n", unit); | |
| 860 | return d->basename; | |
| 861 | } | |
| 862 | ||
| 863 | /** | |
| 864 | * @brief return the number of a drive unit | |
| 865 | * | |
| 866 | * This is usually a no-op, but drives may be swapped? | |
| 867 | * | |
| 868 | * @param unit unit number | |
| 869 | * @result the unit number | |
| 870 | */ | |
| 871 | int alto2_cpu_device::drive_unit(int unit) | |
| 872 | { | |
| 873 | diablo_drive_t *d = &drive[unit]; | |
| 874 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 875 | fatal(1, "invalid unit %d in call to drive_unit()\n", unit); | |
| 876 | return d->unit; | |
| 877 | } | |
| 878 | ||
| 879 | /** | |
| 880 | * @brief return the time for a full rotation | |
| 881 | * | |
| 882 | * @param unit unit number | |
| 883 | * @result the time for a full track rotation | |
| 884 | */ | |
| 885 | attotime alto2_cpu_device::drive_rotation_time(int unit) | |
| 886 | { | |
| 887 | diablo_drive_t *d = &drive[unit]; | |
| 888 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 889 | fatal(1, "invalid unit %d in call to drive_rotation_time()\n", unit); | |
| 890 | return d->rotation_time; | |
| 891 | } | |
| 892 | ||
| 893 | /** | |
| 894 | * @brief return the time for a data bit | |
| 895 | * | |
| 896 | * @param unit unit number | |
| 897 | * @result the time in nano seconds per bit clock | |
| 898 | */ | |
| 899 | attotime alto2_cpu_device::drive_bit_time(int unit) | |
| 900 | { | |
| 901 | diablo_drive_t *d = &drive[unit]; | |
| 902 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 903 | fatal(1, "invalid unit %d in call to drive_bit_time()\n", unit); | |
| 904 | return d->bit_time; | |
| 905 | } | |
| 906 | ||
| 907 | /** | |
| 908 | * @brief return the seek/read/write status of a drive | |
| 909 | * | |
| 910 | * @param unit unit number | |
| 911 | * @result the seek/read/write status for the drive unit (0: active, 1: inactive) | |
| 912 | */ | |
| 913 | int alto2_cpu_device::drive_seek_read_write_0(int unit) | |
| 914 | { | |
| 915 | diablo_drive_t *d = &drive[unit]; | |
| 916 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 917 | fatal(1, "invalid unit %d in call to drive_seek_read_write_0()\n", unit); | |
| 918 | return d->s_r_w_0; | |
| 919 | } | |
| 920 | ||
| 921 | /** | |
| 922 | * @brief return the ready status of a drive | |
| 923 | * | |
| 924 | * @param unit unit number | |
| 925 | * @result the ready status for the drive unit | |
| 926 | */ | |
| 927 | int alto2_cpu_device::drive_ready_0(int unit) | |
| 928 | { | |
| 929 | diablo_drive_t *d = &drive[unit]; | |
| 930 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 931 | fatal(1, "invalid unit %d in call to drive_ready_0()\n", unit); | |
| 932 | return d->ready_0; | |
| 933 | } | |
| 934 | ||
| 935 | /** | |
| 936 | * @brief return the current sector mark status of a drive | |
| 937 | * | |
| 938 | * The sector mark is derived from the offset into the current sector. | |
| 939 | * | |
| 940 | * @param unit unit number | |
| 941 | * @result the current sector for the drive unit | |
| 942 | */ | |
| 943 | int alto2_cpu_device::drive_sector_mark_0(int unit) | |
| 944 | { | |
| 945 | diablo_drive_t *d = &drive[unit]; | |
| 946 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 947 | fatal(1, "invalid unit %d in call to drive_sector_mark_0()\n", unit); | |
| 948 | /* no sector marks while seeking (?) */ | |
| 949 | if (d->s_r_w_0) | |
| 950 | return 1; | |
| 951 | /* return the sector mark */ | |
| 952 | return d->sector_mark_0; | |
| 953 | } | |
| 954 | ||
| 955 | /** | |
| 956 | * @brief return the address acknowledge state | |
| 957 | * | |
| 958 | * @param unit unit number | |
| 959 | * @result the address acknowledge state | |
| 960 | */ | |
| 961 | int alto2_cpu_device::drive_addx_acknowledge_0(int unit) | |
| 962 | { | |
| 963 | diablo_drive_t *d = &drive[unit]; | |
| 964 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 965 | fatal(1, "invalid unit %d in call to drive_addx_acknowledge_0()\n", unit); | |
| 966 | return d->addx_acknowledge_0; | |
| 967 | } | |
| 968 | ||
| 969 | /** | |
| 970 | * @brief return the log address interlock state | |
| 971 | * | |
| 972 | * @param unit unit number | |
| 973 | * @result the log address interlock state | |
| 974 | */ | |
| 975 | int alto2_cpu_device::drive_log_addx_interlock_0(int unit) | |
| 976 | { | |
| 977 | diablo_drive_t *d = &drive[unit]; | |
| 978 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 979 | fatal(1, "invalid unit %d in call to drive_log_addx_interlock_0()\n", unit); | |
| 980 | return d->log_addx_interlock_0; | |
| 981 | } | |
| 982 | ||
| 983 | /** | |
| 984 | * @brief return the seek incomplete state | |
| 985 | * | |
| 986 | * @param unit unit number | |
| 987 | * @result the address acknowledge state | |
| 988 | */ | |
| 989 | int alto2_cpu_device::drive_seek_incomplete_0(int unit) | |
| 990 | { | |
| 991 | diablo_drive_t *d = &drive[unit]; | |
| 992 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 993 | fatal(1, "invalid unit %d in call to drive_addx_acknowledge_0()\n", unit); | |
| 994 | return d->seek_incomplete_0; | |
| 995 | } | |
| 996 | ||
| 997 | /** | |
| 998 | * @brief return the current cylinder of a drive unit | |
| 999 | * | |
| 1000 | * Note: the bus lines are active low, thus the XOR with DRIVE_CYLINDER_MASK. | |
| 1001 | * | |
| 1002 | * @param unit unit number | |
| 1003 | * @result the current cylinder number for the drive unit | |
| 1004 | */ | |
| 1005 | int alto2_cpu_device::drive_cylinder(int unit) | |
| 1006 | { | |
| 1007 | diablo_drive_t *d = &drive[unit]; | |
| 1008 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 1009 | fatal(1, "invalid unit %d in call to drive_cylinder()\n", unit); | |
| 1010 | return d->cylinder ^ DRIVE_CYLINDER_MASK; | |
| 1011 | } | |
| 1012 | ||
| 1013 | /** | |
| 1014 | * @brief return the current head of a drive unit | |
| 1015 | * | |
| 1016 | * Note: the bus lines are active low, thus the XOR with DRIVE_HEAD_MASK. | |
| 1017 | * | |
| 1018 | * @param unit unit number | |
| 1019 | * @result the currently selected head for the drive unit | |
| 1020 | */ | |
| 1021 | int alto2_cpu_device::drive_head(int unit) | |
| 1022 | { | |
| 1023 | diablo_drive_t *d = &drive[unit]; | |
| 1024 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 1025 | fatal(1, "invalid unit %d in call to drive_head()\n", unit); | |
| 1026 | return d->head ^ DRIVE_HEAD_MASK; | |
| 1027 | } | |
| 1028 | ||
| 1029 | /** | |
| 1030 | * @brief return the current sector of a drive unit | |
| 1031 | * | |
| 1032 | * The current sector number is derived from the time since the | |
| 1033 | * most recent track rotation started. | |
| 1034 | * | |
| 1035 | * Note: the bus lines are active low, thus the XOR with DRIVE_SECTOR_MASK. | |
| 1036 | * | |
| 1037 | * @param unit unit number | |
| 1038 | * @result the current sector for the drive unit | |
| 1039 | */ | |
| 1040 | int alto2_cpu_device::drive_sector(int unit) | |
| 1041 | { | |
| 1042 | diablo_drive_t *d = &drive[unit]; | |
| 1043 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 1044 | fatal(1, "invalid unit %d in call to drive_sector()\n", unit); | |
| 1045 | return d->sector ^ DRIVE_SECTOR_MASK; | |
| 1046 | } | |
| 1047 | ||
| 1048 | /** | |
| 1049 | * @brief return the current page of a drive unit | |
| 1050 | * | |
| 1051 | * The current page number is derived from the cylinder, head, | |
| 1052 | * and sector numbers. | |
| 1053 | * | |
| 1054 | * @param unit unit number | |
| 1055 | * @result the current page for the drive unit | |
| 1056 | */ | |
| 1057 | int alto2_cpu_device::drive_page(int unit) | |
| 1058 | { | |
| 1059 | diablo_drive_t *d = &drive[unit]; | |
| 1060 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 1061 | fatal(1, "invalid unit %d in call to drive_page()\n", unit); | |
| 1062 | return d->page; | |
| 1063 | } | |
| 1064 | ||
| 1065 | /** | |
| 1066 | * @brief select a drive unit and head | |
| 1067 | * | |
| 1068 | * @param unit unit number | |
| 1069 | * @param head head number | |
| 1070 | */ | |
| 1071 | void alto2_cpu_device::drive_select(int unit, int head) | |
| 1072 | { | |
| 1073 | diablo_drive_t *d = &drive[unit]; | |
| 1074 | ||
| 1075 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 1076 | fatal(1, "invalid unit %d in call to drive_select()\n", unit); | |
| 1077 | ||
| 1078 | if (unit != m_unit_selected || head != m_head_selected) { | |
| 1079 | /* this drive is selected */ | |
| 1080 | m_unit_selected = unit; | |
| 1081 | m_head_selected = head; | |
| 1082 | printf("select unit:%d head:%d\n", unit, head); | |
| 1083 | } | |
| 1084 | ||
| 1085 | if (d->image) { | |
| 1086 | /* it is ready */ | |
| 1087 | d->ready_0 = 0; | |
| 1088 | /* and can take seek/read/write commands */ | |
| 1089 | d->s_r_w_0 = 0; | |
| 1090 | /* address acknowledge (?) */ | |
| 1091 | d->addx_acknowledge_0 = 0; | |
| 1092 | /* clear log address interlock (?) */ | |
| 1093 | d->log_addx_interlock_0 = 1; | |
| 1094 | LOG((log_DRV,1," UNIT select %d ready\n", unit)); | |
| 1095 | } else { | |
| 1096 | /* it is not ready (?) */ | |
| 1097 | d->ready_0 = 1; | |
| 1098 | /* can't take seek/read/write commands (?) */ | |
| 1099 | d->s_r_w_0 = 1; | |
| 1100 | /* address acknowledge (?) */ | |
| 1101 | d->addx_acknowledge_0 = 0; | |
| 1102 | LOG((log_DRV,1," UNIT select %d not ready (no image)\n", unit)); | |
| 1103 | } | |
| 1104 | ||
| 1105 | /* Note: head select input is active low (0: selects head 1, 1: selects head 0) */ | |
| 1106 | head = head & DRIVE_HEAD_MASK; | |
| 1107 | if (head != d->head) { | |
| 1108 | d->head = head; | |
| 1109 | LOG((log_DRV,1," HEAD %d select on unit %d\n", head, unit)); | |
| 1110 | } | |
| 1111 | drive_get_sector(unit); | |
| 1112 | } | |
| 1113 | ||
| 1114 | /** | |
| 1115 | * @brief strobe a seek operation | |
| 1116 | * | |
| 1117 | * Seek to the cylinder cylinder, or restore. | |
| 1118 | * | |
| 1119 | * @param unit unit number | |
| 1120 | * @param cylinder cylinder number to seek to | |
| 1121 | * @param restore flag if the drive should restore to cylinder 0 | |
| 1122 | * @param strobe current level of the strobe signal (for edge detection) | |
| 1123 | */ | |
| 1124 | void alto2_cpu_device::drive_strobe(int unit, int cylinder, int restore, int strobe) | |
| 1125 | { | |
| 1126 | diablo_drive_t *d = &drive[unit]; | |
| 1127 | int seekto = restore ? 0 : cylinder; | |
| 1128 | ||
| 1129 | if (unit < 0 || unit >= DRIVE_MAX) | |
| 1130 | fatal(1, "invalid unit %d in call to drive_strobe()\n", unit); | |
| 1131 | ||
| 1132 | if (strobe == 1) { | |
| 1133 | LOG((log_DRV,1," STROBE end of interlock\n", seekto)); | |
| 1134 | /* deassert the log address interlock */ | |
| 1135 | d->log_addx_interlock_0 = 1; | |
| 1136 | return; | |
| 1137 | } | |
| 1138 | ||
| 1139 | /* assert the log address interlock */ | |
| 1140 | d->log_addx_interlock_0 = 0; | |
| 1141 | ||
| 1142 | if (seekto == d->cylinder) { | |
| 1143 | LOG((log_DRV,1," STROBE to cylinder %d acknowledge\n", seekto)); | |
| 1144 | d->addx_acknowledge_0 = 0; /* address acknowledge, if cylinder is reached */ | |
| 1145 | d->seek_incomplete_0 = 1; /* reset seek incomplete */ | |
| 1146 | return; | |
| 1147 | } | |
| 1148 | ||
| 1149 | d->s_r_w_0 = 0; | |
| 1150 | ||
| 1151 | if (seekto < d->cylinder) { | |
| 1152 | /* decrement cylinder */ | |
| 1153 | d->cylinder -= 1; | |
| 1154 | if (d->cylinder < 0) { | |
| 1155 | d->cylinder = 0; | |
| 1156 | d->log_addx_interlock_0 = 1; /* deassert the log address interlock */ | |
| 1157 | d->seek_incomplete_0 = 1; /* deassert seek incomplete */ | |
| 1158 | d->addx_acknowledge_0 = 0; /* assert address acknowledge */ | |
| 1159 | LOG((log_DRV,1," STROBE to cylinder %d incomplete\n", seekto)); | |
| 1160 | return; | |
| 1161 | } | |
| 1162 | } else { | |
| 1163 | /* increment cylinder */ | |
| 1164 | d->cylinder += 1; | |
| 1165 | if (d->cylinder >= DRIVE_CYLINDERS) { | |
| 1166 | d->cylinder = DRIVE_CYLINDERS - 1; | |
| 1167 | d->log_addx_interlock_0 = 1; /* deassert the log address interlock */ | |
| 1168 | d->seek_incomplete_0 = 1; /* deassert seek incomplete */ | |
| 1169 | d->addx_acknowledge_0 = 0; /* assert address acknowledge */ | |
| 1170 | LOG((log_DRV,1," STROBE to cylinder %d incomplete\n", seekto)); | |
| 1171 | return; | |
| 1172 | } | |
| 1173 | } | |
| 1174 | LOG((log_DRV,1," STROBE to cylinder %d (now %d) - interlock\n", seekto, d->cylinder)); | |
| 1175 | ||
| 1176 | d->addx_acknowledge_0 = 1; /* deassert address acknowledge */ | |
| 1177 | d->seek_incomplete_0 = 1; /* deassert seek incomplete */ | |
| 1178 | drive_get_sector(unit); | |
| 1179 | } | |
| 1180 | ||
| 1181 | /** | |
| 1182 | * @brief install a callback to be called whenever a drive sector starts | |
| 1183 | * | |
| 1184 | * @param callback function to call when a new sector begins | |
| 1185 | */ | |
| 1186 | void alto2_cpu_device::drive_sector_callback(a2cb callback) | |
| 1187 | { | |
| 1188 | m_sector_callback = callback; | |
| 1189 | } | |
| 1190 | ||
| 1191 | ||
| 1192 | /** | |
| 1193 | * @brief set the drive erase gate | |
| 1194 | * | |
| 1195 | * @param unit drive unit number | |
| 1196 | * @param gate value of erase gate | |
| 1197 | */ | |
| 1198 | void alto2_cpu_device::drive_egate(int unit, int gate) | |
| 1199 | { | |
| 1200 | diablo_drive_t *d = &drive[unit]; | |
| 1201 | d->egate_0 = gate; | |
| 1202 | } | |
| 1203 | ||
| 1204 | /** | |
| 1205 | * @brief set the drive write gate | |
| 1206 | * | |
| 1207 | * @param unit drive unit number | |
| 1208 | * @param gate value of write gate | |
| 1209 | */ | |
| 1210 | void alto2_cpu_device::drive_wrgate(int unit, int gate) | |
| 1211 | { | |
| 1212 | diablo_drive_t *d = &drive[unit]; | |
| 1213 | d->wrgate_0 = gate; | |
| 1214 | } | |
| 1215 | ||
| 1216 | /** | |
| 1217 | * @brief set the drive read gate | |
| 1218 | * | |
| 1219 | * @param unit drive unit number | |
| 1220 | * @param gate value of read gate | |
| 1221 | */ | |
| 1222 | void alto2_cpu_device::drive_rdgate(int unit, int gate) | |
| 1223 | { | |
| 1224 | diablo_drive_t *d = &drive[unit]; | |
| 1225 | d->rdgate_0 = gate; | |
| 1226 | } | |
| 1227 | ||
| 1228 | /** | |
| 1229 | * @brief write the sector relative bit at index | |
| 1230 | * | |
| 1231 | * The disk controller writes a combined clock and data pulse to one output | |
| 1232 | * <PRE> | |
| 1233 | * Encoding of binary 01011 | |
| 1234 | * | |
| 1235 | * clk data clk data clk data clk data clk data | |
| 1236 | * 0 1 2 3 4 5 6 7 8 9 | |
| 1237 | * +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +-- | |
| 1238 | * | | | | | | | | | | | | | | | | | | |
| 1239 | * --+ +--------+ +--+ +--+ +--------+ +--+ +--+ +--+ +--+ | |
| 1240 | * </PRE> | |
| 1241 | * | |
| 1242 | * @param unit drive unit number | |
| 1243 | * @param index relative index of bit/clock into sector | |
| 1244 | * @param wrdata write data clock or bit | |
| 1245 | */ | |
| 1246 | void alto2_cpu_device::drive_wrdata(int unit, int index, int wrdata) | |
| 1247 | { | |
| 1248 | diablo_drive_t *d = &drive[unit]; | |
| 1249 | UINT32 *bits; | |
| 1250 | ||
| 1251 | if (d->wrgate_0) { | |
| 1252 | /* write gate is not asserted (active 0) */ | |
| 1253 | return; | |
| 1254 | } | |
| 1255 | ||
| 1256 | /* don't write before or beyond the sector */ | |
| 1257 | if (index < 0 || index >= drive_bits_per_sector()) | |
| 1258 | return; | |
| 1259 | ||
| 1260 | if (-1 == d->page) { | |
| 1261 | /* invalid page */ | |
| 1262 | return; | |
| 1263 | } | |
| 1264 | ||
| 1265 | bits = d->bits[d->page]; | |
| 1266 | if (!bits) { | |
| 1267 | /* expand the sector to bits */ | |
| 1268 | expand_sector(unit, d->page); | |
| 1269 | bits = d->bits[d->page]; | |
| 1270 | /* just to be safe */ | |
| 1271 | if (!bits) | |
| 1272 | fatal(1, "No bits for drive #%d page #%d\n", unit, d->page); | |
| 1273 | } | |
| 1274 | if (-1 == d->wrfirst) | |
| 1275 | d->wrfirst = index; | |
| 1276 | ||
| 1277 | LOG((log_DRV,7," write #%d %d/%d/%d bit #%d bit:%d\n", unit, d->cylinder, d->head, d->sector, index, wrdata)); | |
| 1278 | ||
| 1279 | if (index < GUARD_ZONE_BITS) { | |
| 1280 | /* don't write in the guard zone (?) */ | |
| 1281 | } else { | |
| 1282 | WRBIT(bits,index,wrdata); | |
| 1283 | } | |
| 1284 | d->wrlast = index; | |
| 1285 | } | |
| 1286 | ||
| 1287 | /** | |
| 1288 | * @brief read the sector relative bit at index | |
| 1289 | * | |
| 1290 | * Note: this is a gross hack to allow the controller pulling bits | |
| 1291 | * at its will, rather than clocking them with the drive's RDCLK- | |
| 1292 | * | |
| 1293 | * @param unit is the drive index | |
| 1294 | * @param index is the sector relative bit index | |
| 1295 | * @result returns the sector's bit by index | |
| 1296 | */ | |
| 1297 | int alto2_cpu_device::drive_rddata(int unit, int index) | |
| 1298 | { | |
| 1299 | diablo_drive_t *d = &drive[unit]; | |
| 1300 | UINT32 *bits; | |
| 1301 | int bit = 0; | |
| 1302 | ||
| 1303 | if (d->rdgate_0) { | |
| 1304 | /* read gate is not asserted (active 0) */ | |
| 1305 | return 0; | |
| 1306 | } | |
| 1307 | ||
| 1308 | /* don't read before or beyond the sector */ | |
| 1309 | if (index < 0 || index >= drive_bits_per_sector()) | |
| 1310 | return 1; | |
| 1311 | ||
| 1312 | /* no data while sector mark is low (?) */ | |
| 1313 | if (0 == d->sector_mark_0) | |
| 1314 | return 1; | |
| 1315 | ||
| 1316 | if (-1 == d->page) { | |
| 1317 | /* invalid page */ | |
| 1318 | return 1; | |
| 1319 | } | |
| 1320 | ||
| 1321 | bits = d->bits[d->page]; | |
| 1322 | if (!bits) { | |
| 1323 | /* expand the sector to bits */ | |
| 1324 | expand_sector(unit, d->page); | |
| 1325 | bits = d->bits[d->page]; | |
| 1326 | /* just to be safe */ | |
| 1327 | if (!bits) | |
| 1328 | fatal(1, "No bits for drive #%d page #%d\n", unit, d->page); | |
| 1329 | } | |
| 1330 | if (-1 == d->rdfirst) | |
| 1331 | d->rdfirst = index; | |
| 1332 | ||
| 1333 | bit = RDBIT(bits,index); | |
| 1334 | LOG((log_DRV,7," read #%d %d/%d/%d bit #%d:%d\n", unit, d->cylinder, d->head, d->sector, index, bit)); | |
| 1335 | d->rdlast = index; | |
| 1336 | return bit; | |
| 1337 | } | |
| 1338 | ||
| 1339 | /** | |
| 1340 | * @brief get the sector relative clock at index | |
| 1341 | * | |
| 1342 | * Note: this is a gross hack to allow the controller pulling bits | |
| 1343 | * at its will, rather than clocking them with the drive's RDCLK- | |
| 1344 | * | |
| 1345 | * @param unit is the drive index | |
| 1346 | * @param index is the sector relative bit index | |
| 1347 | * @result returns the sector's bit by index | |
| 1348 | */ | |
| 1349 | int alto2_cpu_device::drive_rdclk(int unit, int index) | |
| 1350 | { | |
| 1351 | diablo_drive_t *d = &drive[unit]; | |
| 1352 | UINT32 *bits; | |
| 1353 | int clk; | |
| 1354 | ||
| 1355 | /* don't read before or beyond the sector */ | |
| 1356 | if (index < 0 || index >= drive_bits_per_sector()) | |
| 1357 | return 1; | |
| 1358 | ||
| 1359 | /* no clock while sector mark is low (?) */ | |
| 1360 | if (0 == d->sector_mark_0) | |
| 1361 | return 1; | |
| 1362 | ||
| 1363 | if (-1 == d->page) { | |
| 1364 | /* invalid page */ | |
| 1365 | return 1; | |
| 1366 | } | |
| 1367 | ||
| 1368 | bits = d->bits[d->page]; | |
| 1369 | if (!bits) { | |
| 1370 | /* expand the sector to bits */ | |
| 1371 | expand_sector(unit, d->page); | |
| 1372 | bits = d->bits[d->page]; | |
| 1373 | /* just to be safe */ | |
| 1374 | if (!bits) | |
| 1375 | fatal(1, "No bits for drive #%d page #%d\n", unit, d->page); | |
| 1376 | } | |
| 1377 | if (-1 == d->rdfirst) | |
| 1378 | d->rdfirst = index; | |
| 1379 | ||
| 1380 | if (index & 1) { | |
| 1381 | clk = 0; | |
| 1382 | } else { | |
| 1383 | clk = RDBIT(bits,index); | |
| 1384 | } | |
| 1385 | ||
| 1386 | LOG((log_DRV,7, " read #%d %d/%d/%d clk #%d:%d\n", unit, d->cylinder, d->head, d->sector, index, clk)); | |
| 1387 | ||
| 1388 | d->rdlast = index; | |
| 1389 | return clk ^ 1; | |
| 1390 | } | |
| 1391 | ||
| 1392 | /** | |
| 1393 | * @brief debug function to read sync bit position from a sector | |
| 1394 | * | |
| 1395 | * @param unit is the drive index | |
| 1396 | * @param page is the page number to read | |
| 1397 | * @param offs is the first bit offset | |
| 1398 | * @result returns bit offset after the next sync bit | |
| 1399 | */ | |
| 1400 | int alto2_cpu_device::debug_read_sync(int unit, int page, int offs) | |
| 1401 | { | |
| 1402 | diablo_drive_t *d = &drive[unit]; | |
| 1403 | UINT32 *bits; | |
| 1404 | UINT32 accu; | |
| 1405 | ||
| 1406 | if (unit < 0 || unit > 1) | |
| 1407 | return 0; | |
| 1408 | ||
| 1409 | /* don't read before or beyond the sector */ | |
| 1410 | if (offs < 0 || offs >= 400*32) | |
| 1411 | return 0; | |
| 1412 | ||
| 1413 | /* check for invalid page */ | |
| 1414 | if (page < 0 || page >= DRIVE_CYLINDERS * DRIVE_HEADS * DRIVE_SPT) | |
| 1415 | return 0; | |
| 1416 | ||
| 1417 | bits = d->bits[page]; | |
| 1418 | if (!bits) { | |
| 1419 | /* expand the sector to bits */ | |
| 1420 | expand_sector(unit, page); | |
| 1421 | bits = d->bits[page]; | |
| 1422 | /* just to be safe */ | |
| 1423 | if (!bits) | |
| 1424 | return 0; | |
| 1425 | } | |
| 1426 | ||
| 1427 | accu = 0; | |
| 1428 | while (offs < 400 * 32) { | |
| 1429 | accu = (accu << 1) | RDBIT(bits,offs); | |
| 1430 | offs++; | |
| 1431 | if (accu == 0xaaaaaaab) | |
| 1432 | break; | |
| 1433 | } | |
| 1434 | ||
| 1435 | return offs; | |
| 1436 | } | |
| 1437 | ||
| 1438 | /** | |
| 1439 | * @brief debug function to read bits from a drive sector | |
| 1440 | * | |
| 1441 | * @param unit is the drive index | |
| 1442 | * @param page is the page number to read | |
| 1443 | * @param offs is the first bit offset | |
| 1444 | * @result returns a word starting at the bit offset | |
| 1445 | */ | |
| 1446 | int alto2_cpu_device::debug_read_sec(int unit, int page, int offs) | |
| 1447 | { | |
| 1448 | diablo_drive_t *d = &drive[unit]; | |
| 1449 | UINT32 *bits; | |
| 1450 | int i, clks, word; | |
| 1451 | ||
| 1452 | if (unit < 0 || unit > 1) | |
| 1453 | return 0177777; | |
| 1454 | ||
| 1455 | /* don't read before or beyond the sector */ | |
| 1456 | if (offs < 0 || offs >= 400*32) | |
| 1457 | return 0177777; | |
| 1458 | ||
| 1459 | /* check for invalid page */ | |
| 1460 | if (page < 0 || page >= DRIVE_CYLINDERS * DRIVE_HEADS * DRIVE_SPT) | |
| 1461 | return 0177777; | |
| 1462 | ||
| 1463 | bits = d->bits[page]; | |
| 1464 | if (!bits) { | |
| 1465 | /* expand the sector to bits */ | |
| 1466 | expand_sector(unit, page); | |
| 1467 | bits = d->bits[page]; | |
| 1468 | /* just to be safe */ | |
| 1469 | if (!bits) | |
| 1470 | return 0177777; | |
| 1471 | } | |
| 1472 | ||
| 1473 | for (i = 0, clks = 0, word = 0; i < 16; i++, offs += 2) { | |
| 1474 | clks = (clks << 1) | RDBIT(bits,offs); | |
| 1475 | word = (word << 1) | RDBIT(bits,offs+1); | |
| 1476 | } | |
| 1477 | ||
| 1478 | return word; | |
| 1479 | } | |
| 1480 | ||
| 1481 | /** | |
| 1482 | * @brief timer callback that is called once per sector in the rotation | |
| 1483 | * | |
| 1484 | * @param id timer id | |
| 1485 | * @param arg argument supplied to timer_insert (unused) | |
| 1486 | */ | |
| 1487 | void alto2_cpu_device::drive_next_sector(void* ptr, int arg) | |
| 1488 | { | |
| 1489 | (void)ptr; | |
| 1490 | int unit = m_unit_selected; | |
| 1491 | diablo_drive_t *d = &drive[unit]; | |
| 1492 | ||
| 1493 | LOG((log_DRV,5, " next sector (unit #%d sector %d)\n", unit, d->sector)); | |
| 1494 | ||
| 1495 | /* deassert sector mark after pulse width */ | |
| 1496 | switch (arg) { | |
| 1497 | case 0: | |
| 1498 | /* next sector starting soon now */ | |
| 1499 | m_sector_timer->adjust(SECTOR_MARK_PULSE_PRE, 1); | |
| 1500 | sector_mark_1(unit); | |
| 1501 | break; | |
| 1502 | case 1: | |
| 1503 | m_sector_timer->adjust(SECTOR_MARK_PULSE_POST, 2); | |
| 1504 | sector_mark_0(unit); | |
| 1505 | break; | |
| 1506 | case 2: | |
| 1507 | m_sector_timer->adjust(SECTOR_TIME - SECTOR_MARK_PULSE_PRE, 0); | |
| 1508 | /* call the sector_callback, if any */ | |
| 1509 | if (m_sector_callback) | |
| 1510 | ((*this).*m_sector_callback)(unit); | |
| 1511 | } | |
| 1512 | } | |
| 1513 | ||
| 1514 | /** | |
| 1515 | * @brief timer callback that deasserts the sector mark | |
| 1516 | * | |
| 1517 | * @param unit drive unit number | |
| 1518 | */ | |
| 1519 | void alto2_cpu_device::sector_mark_1(int unit) | |
| 1520 | { | |
| 1521 | diablo_drive_t *d = &drive[unit]; | |
| 1522 | ||
| 1523 | LOG((log_DRV,5, " sector mark 1 (unit #%d sector %d)\n", unit, d->sector)); | |
| 1524 | /* set sector mark to 1 */ | |
| 1525 | d->sector_mark_0 = 1; | |
| 1526 | } | |
| 1527 | ||
| 1528 | /** | |
| 1529 | * @brief timer callback that asserts the sector mark | |
| 1530 | * | |
| 1531 | * @param unit drive unit number | |
| 1532 | */ | |
| 1533 | void alto2_cpu_device::sector_mark_0(int unit) | |
| 1534 | { | |
| 1535 | diablo_drive_t *d = &drive[unit]; | |
| 1536 | ||
| 1537 | LOG((log_DRV,5," sector mark 0 (unit #%d sector %d)\n", unit, d->sector)); | |
| 1538 | ||
| 1539 | /* squeeze previous sector, if it was written to */ | |
| 1540 | squeeze_sector(unit); | |
| 1541 | ||
| 1542 | d->sector_mark_0 = 0; | |
| 1543 | ||
| 1544 | /* reset read and write bit locations */ | |
| 1545 | d->rdfirst = -1; | |
| 1546 | d->rdlast = -1; | |
| 1547 | d->wrfirst = -1; | |
| 1548 | d->wrlast = -1; | |
| 1549 | ||
| 1550 | /* count sectors */ | |
| 1551 | d->sector = (d->sector + 1) % DRIVE_SPT; | |
| 1552 | drive_get_sector(unit); | |
| 1553 | } | |
| 1554 | /** | |
| 1555 | * @brief pass down command line arguments to the drive emulation | |
| 1556 | * | |
| 1557 | * @param arg command line argument | |
| 1558 | * @result returns 0 if this was a disk image, -1 on error | |
| 1559 | */ | |
| 1560 | int drive_args(const char *arg) | |
| 1561 | { | |
| 1562 | const char *basename; | |
| 1563 | int unit; | |
| 1564 | int hdr, c, h, s, chs; | |
| 1565 | diablo_drive_t *d; | |
| 1566 | int zcat; | |
| 1567 | FILE *fp; | |
| 1568 | size_t size; /* size in sectors */ | |
| 1569 | size_t done; /* read loops */ | |
| 1570 | size_t csize; /* size of cooked image */ | |
| 1571 | UINT8 *image; /* file image (either cooked, or compressed) */ | |
| 1572 | diablo_sector_t *cooked; /* cooked sector data */ | |
| 1573 | UINT8 *ip, *cp; | |
| 1574 | char *p; | |
| 1575 | ||
| 1576 | basename = strrchr(arg, '/'); | |
| 1577 | if (basename) { | |
| 1578 | basename++; | |
| 1579 | } else { | |
| 1580 | basename = strrchr(arg, '\\'); | |
| 1581 | if (basename) | |
| 1582 | basename++; | |
| 1583 | else | |
| 1584 | basename = arg; | |
| 1585 | } | |
| 1586 | ||
| 1587 | /* find trailing dot */ | |
| 1588 | p = strrchr(basename, '.'); | |
| 1589 | if (!p) | |
| 1590 | return -1; | |
| 1591 | ||
| 1592 | /* check for .Z extension */ | |
| 1593 | if (!strcmp(p, ".z") || !strcmp(p, ".Z") || | |
| 1594 | !strcmp(p, ".gz") || !strcmp(p, ".GZ")) { | |
| 1595 | /* compress (LZW) or gzip compressed image */ | |
| 1596 | LOG((log_DRV,0,"loading compressed disk image %s\n", arg)); | |
| 1597 | zcat = 1; | |
| 1598 | } else if (!strcmp(p, ".dsk") || !strcmp(p, ".DSK")) { | |
| 1599 | /* uncompressed .dsk extension */ | |
| 1600 | LOG((log_DRV,0,"loading uncompressed disk image %s\n", arg)); | |
| 1601 | zcat = 0; | |
| 1602 | } else { | |
| 1603 | return -1; | |
| 1604 | } | |
| 1605 | ||
| 1606 | for (unit = 0; unit < DRIVE_MAX; unit++) | |
| 1607 | if (!drive[unit].image) | |
| 1608 | break; | |
| 1609 | ||
| 1610 | /* all drive slots filled? */ | |
| 1611 | if (unit == DRIVE_MAX) | |
| 1612 | return -1; | |
| 1613 | ||
| 1614 | d = &drive[unit]; | |
| 1615 | ||
| 1616 | snprintf(d->basename, sizeof(d->basename), "%s", basename); | |
| 1617 | ||
| 1618 | fp = fopen(arg, "rb"); | |
| 1619 | if (!fp) | |
| 1620 | fatal(1, "failed to fopen(%s,\"rb\") (%s)\n", | |
| 1621 | arg, strerror(errno)); | |
| 1622 | ||
| 1623 | /* size in sectors */ | |
| 1624 | size = DRIVE_CYLINDERS * DRIVE_HEADS * DRIVE_SPT; | |
| 1625 | ||
| 1626 | csize = size * sizeof(diablo_sector_t); | |
| 1627 | image = (UINT8 *)malloc(csize + 1); | |
| 1628 | if (!image) | |
| 1629 | fatal(1, "failed to malloc(%d) bytes\n", csize); | |
| 1630 | ip = (UINT8 *)image; | |
| 1631 | for (done = 0; done < size * sizeof(diablo_sector_t); /* */) { | |
| 1632 | int got = fread(ip + done, 1, size * sizeof(diablo_sector_t) - done, fp); | |
| 1633 | if (got < 0) { | |
| 1634 | LOG((0,0,"fread() returned error (%s)\n", | |
| 1635 | strerror(errno))); | |
| 1636 | break; | |
| 1637 | } | |
| 1638 | if (got == 0) | |
| 1639 | break; | |
| 1640 | done += got; | |
| 1641 | } | |
| 1642 | fclose(fp); | |
| 1643 | ||
| 1644 | LOG((log_DRV,0, "got %d (%#x) bytes\n", done, done)); | |
| 1645 | ||
| 1646 | cooked = (diablo_sector_t *)malloc(csize); | |
| 1647 | if (!cooked) | |
| 1648 | fatal(1, "failed to malloc(%d) bytes\n", csize); | |
| 1649 | cp = (UINT8 *)cooked; | |
| 1650 | ||
| 1651 | if (zcat) { | |
| 1652 | size_t skip; | |
| 1653 | int type = z_header(ip, done, &skip); | |
| 1654 | ||
| 1655 | switch (type) { | |
| 1656 | case 0: | |
| 1657 | LOG((log_MISC,0, "compression type unknown, skip:%d\n", skip)); | |
| 1658 | csize = gz_copy(cp, csize, ip, done); | |
| 1659 | break; | |
| 1660 | case 1: | |
| 1661 | LOG((log_MISC,0, "compression type compress (LZW), skip:%d\n", skip)); | |
| 1662 | csize = z_copy(cp, csize, ip + skip, done - skip); | |
| 1663 | break; | |
| 1664 | case 2: | |
| 1665 | LOG((log_MISC,0, "compression type gzip, skip:%d\n", skip)); | |
| 1666 | csize = gz_copy(cp, csize, ip, done); | |
| 1667 | break; | |
| 1668 | } | |
| 1669 | } else { | |
| 1670 | memcpy(cp, ip, done); | |
| 1671 | csize = done; | |
| 1672 | } | |
| 1673 | free(image); | |
| 1674 | image = NULL; | |
| 1675 | ip = NULL; | |
| 1676 | ||
| 1677 | if (csize != size * sizeof(diablo_sector_t)) { | |
| 1678 | LOG((log_DRV,0,"disk image %s size mismatch (%d bytes)\n", arg, csize)); | |
| 1679 | free(cooked); | |
| 1680 | return -1; | |
| 1681 | } | |
| 1682 | ||
| 1683 | /* reset cylinder, head, sector counters */ | |
| 1684 | c = h = s = 0; | |
| 1685 | ||
| 1686 | /* check image sectors for sanity */ | |
| 1687 | for (done = 0; done < size; done++) { | |
| 1688 | /* copy the available records in their place */ | |
| 1689 | ||
| 1690 | /* verify the chs with the header and log any mismatches */ | |
| 1691 | hdr = cooked->header[2] + 256 * cooked->header[3]; | |
| 1692 | chs = (s << 12) | (c << 3) | (h << 2) | (unit << 1); | |
| 1693 | if (chs != hdr) { | |
| 1694 | LOG((log_DRV,0,"WARNING: header mismatch C/H/S: %3d/%d/%2d chs:%06o hdr:%06o\n", | |
| 1695 | c, h, s, chs, hdr)); | |
| 1696 | } | |
| 1697 | if (++s == DRIVE_SPT) { | |
| 1698 | s = 0; | |
| 1699 | if (++h == DRIVE_HEADS) { | |
| 1700 | h = 0; | |
| 1701 | c++; | |
| 1702 | } | |
| 1703 | } | |
| 1704 | cooked++; | |
| 1705 | } | |
| 1706 | ||
| 1707 | /* set drive image */ | |
| 1708 | d->image = (diablo_sector_t *)cp; | |
| 1709 | ||
| 1710 | LOG((log_DRV,0,"drive #%d successfully created image for %s\n", unit, arg)); | |
| 1711 | ||
| 1712 | drive_select(unit, 0); | |
| 1713 | ||
| 1714 | /* drive address acknowledge is active now */ | |
| 1715 | d->s_r_w_0 = 0; | |
| 1716 | /* drive address acknowledge is active now */ | |
| 1717 | d->addx_acknowledge_0 = 0; | |
| 1718 | ||
| 1719 | LOG((log_DRV,0,"possible %s sector size is %#o (%d) words\n", d->description, SECTOR_WORDS, SECTOR_WORDS)); | |
| 1720 | ||
| 1721 | LOG((log_DRV,0,"sector mark pulse length is %lldns\n", SECTOR_MARK_PULSE_PRE + SECTOR_MARK_PULSE_POST)); | |
| 1722 | ||
| 1723 | return 0; | |
| 1724 | } | |
| 1725 | ||
| 1726 | /** | |
| 1727 | * @brief initialize the disk drive context and insert a disk word timer | |
| 1728 | * | |
| 1729 | * @result returns 0 on success, fatal() on error | |
| 1730 | */ | |
| 1731 | void alto2_cpu_device::drive_init() | |
| 1732 | { | |
| 1733 | int i; | |
| 1734 | ||
| 1735 | if (sizeof(diablo_sector_t) != 267 * 2) | |
| 1736 | fatal(1, "sizeof(sector_t) is not %d (%d)\n", | |
| 1737 | 267 * 2, sizeof(diablo_sector_t)); | |
| 1738 | ||
| 1739 | for (i = 0; i < DRIVE_MAX; i++) { | |
| 1740 | diablo_drive_t *d = &drive[i]; | |
| 1741 | ||
| 1742 | d->unit = i; /* set the unit number */ | |
| 1743 | d->s_r_w_0 = 1; /* seek/read/write not ready */ | |
| 1744 | d->ready_0 = 1; /* drive is not ready */ | |
| 1745 | d->sector_mark_0 = 1; /* sector mark clear */ | |
| 1746 | d->addx_acknowledge_0 = 1; /* drive address acknowledge is not active */ | |
| 1747 | d->log_addx_interlock_0 = 1; /* drive log address interlock is not active */ | |
| 1748 | d->seek_incomplete_0 = 1; /* drive seek incomplete is not active */ | |
| 1749 | ||
| 1750 | /* reset the disk drive's address */ | |
| 1751 | d->cylinder = 0; | |
| 1752 | d->head = 0; | |
| 1753 | d->sector = 0; | |
| 1754 | ||
| 1755 | d->egate_0 = 1; | |
| 1756 | d->wrgate_0 = 1; | |
| 1757 | d->rdgate_0 = 1; | |
| 1758 | ||
| 1759 | /* clocks + bits for the expanded sector + some slack */ | |
| 1760 | d->wrfirst = -1; | |
| 1761 | d->wrlast = -1; | |
| 1762 | d->rdfirst = -1; | |
| 1763 | d->rdlast = -1; | |
| 1764 | } | |
| 1765 | ||
| 1766 | m_sector_callback = 0; | |
| 1767 | m_sector_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::drive_next_sector),this)); | |
| 1768 | m_sector_timer->adjust(SECTOR_TIME - SECTOR_MARK_PULSE_PRE, 0); | |
| 1769 | } |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| r0 | r26022 | |
|---|---|---|
| 1 | /***************************************************************************** | |
| 2 | * | |
| 3 | * includes/alto2.h | |
| 4 | * | |
| 5 | ****************************************************************************/ | |
| 6 | ||
| 7 | #ifndef _INCLUDES_ALTO2_H_ | |
| 8 | #define _INCLUDES_ALTO2_H_ | |
| 9 | ||
| 10 | #include "emu.h" | |
| 11 | #include "cpu/alto2/alto2.h" | |
| 12 | #include "machine/ram.h" | |
| 13 | ||
| 14 | class alto2_state : public driver_device | |
| 15 | { | |
| 16 | public: | |
| 17 | alto2_state(const machine_config &mconfig, device_type type, const char *tag) | |
| 18 | : driver_device(mconfig, type, tag), | |
| 19 | m_maincpu(*this, "maincpu"), | |
| 20 | m_ram(*this, RAM_TAG), | |
| 21 | #if 0 // FIXME: write a harddisk_image_device like device_t for the DIABLO31 | |
| 22 | m_disk0(*this, "disk0"), | |
| 23 | m_disk1(*this, "disk1"), | |
| 24 | #endif | |
| 25 | m_region_maincpu(*this, "maincpu"), | |
| 26 | m_region_gfx1(*this, "gfx1"), | |
| 27 | m_io_row0(*this, "ROW0"), | |
| 28 | m_io_row1(*this, "ROW1"), | |
| 29 | m_io_row2(*this, "ROW2"), | |
| 30 | m_io_row3(*this, "ROW3"), | |
| 31 | m_io_row4(*this, "ROW4"), | |
| 32 | m_io_row5(*this, "ROW5"), | |
| 33 | m_io_row6(*this, "ROW6"), | |
| 34 | m_io_row7(*this, "ROW7"), | |
| 35 | m_io_config(*this, "CONFIG") { } | |
| 36 | ||
| 37 | UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); | |
| 38 | ||
| 39 | bitmap_ind16 m_bitmap; | |
| 40 | ||
| 41 | DECLARE_READ32_MEMBER(alto2_ucode_r); | |
| 42 | DECLARE_WRITE32_MEMBER(alto2_ucode_w); | |
| 43 | DECLARE_READ16_MEMBER(alto2_ram_r); | |
| 44 | DECLARE_WRITE16_MEMBER(alto2_ram_w); | |
| 45 | DECLARE_DRIVER_INIT(alto2); | |
| 46 | virtual void machine_reset(); | |
| 47 | virtual void video_start(); | |
| 48 | virtual void palette_init(); | |
| 49 | DECLARE_MACHINE_RESET(alto2); | |
| 50 | void screen_eof_alto2(screen_device &screen, bool state); | |
| 51 | ||
| 52 | protected: | |
| 53 | required_device<cpu_device> m_maincpu; | |
| 54 | required_device<ram_device> m_ucode; | |
| 55 | required_device<ram_device> m_ram; | |
| 56 | #if 0 // FIXME: write a harddisk_image_device like device_t for the DIABLO31 | |
| 57 | required_device<diablo_device> m_disk0; | |
| 58 | optional_device<diablo_device> m_disk1; | |
| 59 | #endif | |
| 60 | required_memory_region m_region_maincpu; | |
| 61 | optional_memory_region m_region_gfx1; | |
| 62 | required_ioport m_io_row0; | |
| 63 | required_ioport m_io_row1; | |
| 64 | required_ioport m_io_row2; | |
| 65 | required_ioport m_io_row3; | |
| 66 | required_ioport m_io_row4; | |
| 67 | required_ioport m_io_row5; | |
| 68 | required_ioport m_io_row6; | |
| 69 | required_ioport m_io_row7; | |
| 70 | optional_ioport m_io_config; | |
| 71 | ||
| 72 | // FIXME: use device timers instead of individual emu_timer* in alto2 code(?) | |
| 73 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); | |
| 74 | }; | |
| 75 | ||
| 76 | #endif /* _INCLUDES_ALTO2_H_ */ |
| Added: svn:eol-style + native Added: svn:mime-type + text/plain |
| r26018 | r26022 | |
|---|---|---|
| 129 | 129 | CPUS += ES5510 |
| 130 | 130 | CPUS += SCUDSP |
| 131 | 131 | CPUS += IE15 |
| 132 | CPUS += ALTO2 | |
| 132 | 133 | |
| 133 | 134 | #------------------------------------------------- |
| 134 | 135 | # specify available sound cores; some of these are |
| r26018 | r26022 | |
| 2099 | 2100 | $(MESSOBJ)/xerox.a: \ |
| 2100 | 2101 | $(MESS_DRIVERS)/xerox820.o \ |
| 2101 | 2102 | $(MESS_DRIVERS)/bigbord2.o \ |
| 2103 | $(MESS_DRIVERS)/alto2.o \ | |
| 2102 | 2104 | |
| 2103 | 2105 | $(MESSOBJ)/yamaha.a: \ |
| 2104 | 2106 | $(MESS_DRIVERS)/ymmu100.o \ |
| r0 | r26022 | |
|---|---|---|
| 1 | // license:MAME | |
| 2 | // copyright-holders:Juergen Buchmueller | |
| 3 | /*************************************************************************** | |
| 4 | * alto2.c | |
| 5 | * | |
| 6 | * Original driver by: | |
| 7 | * Juergen Buchmueller, Nov 2013 | |
| 8 | * | |
| 9 | ***************************************************************************/ | |
| 10 | ||
| 11 | #include "includes/alto2.h" | |
| 12 | ||
| 13 | /* Memory Maps */ | |
| 14 | ||
| 15 | #if (ALTO2_CRAM_CONFIG==1) | |
| 16 | #define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages | |
| 17 | #define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages | |
| 18 | #elif (ALTO2_CRAM_CONFIG==2) | |
| 19 | #define ALTO2_UCODE_ROM_PAGES 2 //!< number of microcode ROM pages | |
| 20 | #define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages | |
| 21 | #elif (ALTO2_CRAM_CONFIG==3) | |
| 22 | #define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages | |
| 23 | #define ALTO2_UCODE_RAM_PAGES 3 //!< number of microcode RAM pages | |
| 24 | #else | |
| 25 | #error "Undefined CROM/CRAM configuration" | |
| 26 | #endif | |
| 27 | ||
| 28 | static ADDRESS_MAP_START( alto2_ucode_map, AS_PROGRAM, 32, alto2_state ) | |
| 29 | AM_RANGE(0x0000, ALTO2_UCODE_RAM_BASE-1) AM_ROM | |
| 30 | AM_RANGE(ALTO2_UCODE_RAM_BASE, ALTO2_UCODE_SIZE-1) AM_READWRITE(alto2_ucode_r, alto2_ucode_w) | |
| 31 | ADDRESS_MAP_END | |
| 32 | ||
| 33 | static ADDRESS_MAP_START( alto2_ram_map, AS_IO, 16, alto2_state ) | |
| 34 | AM_RANGE(0x0000, ALTO2_RAM_SIZE/2-1) AM_READWRITE(alto2_ram_r, alto2_ram_w) | |
| 35 | ADDRESS_MAP_END | |
| 36 | ||
| 37 | /* Input Ports */ | |
| 38 | ||
| 39 | /** @brief make an Alto key int from 1 << bit */ | |
| 40 | #define MAKE_KEY(a,b) (1 << (b)) | |
| 41 | ||
| 42 | /** @brief no key assigned is -1 */ | |
| 43 | #define A2_KEY_NONE (-1) | |
| 44 | ||
| 45 | #define A2_KEY_5 MAKE_KEY(0,017) //!< normal: 5 shifted: % | |
| 46 | #define A2_KEY_4 MAKE_KEY(0,016) //!< normal: 4 shifted: $ | |
| 47 | #define A2_KEY_6 MAKE_KEY(0,015) //!< normal: 6 shifted: ~ | |
| 48 | #define A2_KEY_E MAKE_KEY(0,014) //!< normal: e shifted: E | |
| 49 | #define A2_KEY_7 MAKE_KEY(0,013) //!< normal: 7 shifted: & | |
| 50 | #define A2_KEY_D MAKE_KEY(0,012) //!< normal: d shifted: D | |
| 51 | #define A2_KEY_U MAKE_KEY(0,011) //!< normal: u shifted: U | |
| 52 | #define A2_KEY_V MAKE_KEY(0,010) //!< normal: v shifted: V | |
| 53 | #define A2_KEY_0 MAKE_KEY(0,007) //!< normal: 0 shifted: ) | |
| 54 | #define A2_KEY_K MAKE_KEY(0,006) //!< normal: k shifted: K | |
| 55 | #define A2_KEY_MINUS MAKE_KEY(0,005) //!< normal: - shifted: _ | |
| 56 | #define A2_KEY_P MAKE_KEY(0,004) //!< normal: p shifted: P | |
| 57 | #define A2_KEY_SLASH MAKE_KEY(0,003) //!< normal: / shifted: ? | |
| 58 | #define A2_KEY_BACKSLASH MAKE_KEY(0,002) //!< normal: \ shifted: | | |
| 59 | #define A2_KEY_LF MAKE_KEY(0,001) //!< normal: LF shifted: ? | |
| 60 | #define A2_KEY_BS MAKE_KEY(0,000) //!< normal: BS shifted: ? | |
| 61 | ||
| 62 | #define A2_KEY_FR2 MAKE_KEY(0,002) //!< ADL right function key 2 | |
| 63 | #define A2_KEY_FL2 MAKE_KEY(0,001) //!< ADL left function key 1 | |
| 64 | ||
| 65 | #define A2_KEY_3 MAKE_KEY(1,017) //!< normal: 3 shifted: # | |
| 66 | #define A2_KEY_2 MAKE_KEY(1,016) //!< normal: 2 shifted: @ | |
| 67 | #define A2_KEY_W MAKE_KEY(1,015) //!< normal: w shifted: W | |
| 68 | #define A2_KEY_Q MAKE_KEY(1,014) //!< normal: q shifted: Q | |
| 69 | #define A2_KEY_S MAKE_KEY(1,013) //!< normal: s shifted: S | |
| 70 | #define A2_KEY_A MAKE_KEY(1,012) //!< normal: a shifted: A | |
| 71 | #define A2_KEY_9 MAKE_KEY(1,011) //!< normal: 9 shifted: ( | |
| 72 | #define A2_KEY_I MAKE_KEY(1,010) //!< normal: i shifted: I | |
| 73 | #define A2_KEY_X MAKE_KEY(1,007) //!< normal: x shifted: X | |
| 74 | #define A2_KEY_O MAKE_KEY(1,006) //!< normal: o shifted: O | |
| 75 | #define A2_KEY_L MAKE_KEY(1,005) //!< normal: l shifted: L | |
| 76 | #define A2_KEY_COMMA MAKE_KEY(1,004) //!< normal: , shifted: < | |
| 77 | #define A2_KEY_QUOTE MAKE_KEY(1,003) //!< normal: ' shifted: " | |
| 78 | #define A2_KEY_RBRACKET MAKE_KEY(1,002) //!< normal: ] shifted: } | |
| 79 | #define A2_KEY_BLANK_MID MAKE_KEY(1,001) //!< middle blank key | |
| 80 | #define A2_KEY_BLANK_TOP MAKE_KEY(1,000) //!< top blank key | |
| 81 | ||
| 82 | #define A2_KEY_FR4 MAKE_KEY(1,001) //!< ADL right funtion key 4 | |
| 83 | #define A2_KEY_BW MAKE_KEY(1,000) //!< ADL BW (?) | |
| 84 | ||
| 85 | #define A2_KEY_1 MAKE_KEY(2,017) //!< normal: 1 shifted: ! | |
| 86 | #define A2_KEY_ESCAPE MAKE_KEY(2,016) //!< normal: ESC shifted: ? | |
| 87 | #define A2_KEY_TAB MAKE_KEY(2,015) //!< normal: TAB shifted: ? | |
| 88 | #define A2_KEY_F MAKE_KEY(2,014) //!< normal: f shifted: F | |
| 89 | #define A2_KEY_CTRL MAKE_KEY(2,013) //!< CTRL | |
| 90 | #define A2_KEY_C MAKE_KEY(2,012) //!< normal: c shifted: C | |
| 91 | #define A2_KEY_J MAKE_KEY(2,011) //!< normal: j shifted: J | |
| 92 | #define A2_KEY_B MAKE_KEY(2,010) //!< normal: b shifted: B | |
| 93 | #define A2_KEY_Z MAKE_KEY(2,007) //!< normal: z shifted: Z | |
| 94 | #define A2_KEY_LSHIFT MAKE_KEY(2,006) //!< LSHIFT | |
| 95 | #define A2_KEY_PERIOD MAKE_KEY(2,005) //!< normal: . shifted: > | |
| 96 | #define A2_KEY_SEMICOLON MAKE_KEY(2,004) //!< normal: ; shifted: : | |
| 97 | #define A2_KEY_RETURN MAKE_KEY(2,003) //!< RETURN | |
| 98 | #define A2_KEY_LEFTARROW MAKE_KEY(2,002) //!< normal: left arrow shifted: up arrow (caret) | |
| 99 | #define A2_KEY_DEL MAKE_KEY(2,001) //!< normal: DEL shifted: ? | |
| 100 | #define A2_KEY_MSW_2_17 MAKE_KEY(2,000) //!< unused on Microswitch KDB | |
| 101 | ||
| 102 | #define A2_KEY_FR3 MAKE_KEY(2,002) //!< ADL right function key 3 | |
| 103 | #define A2_KEY_FL1 MAKE_KEY(2,001) //!< ADL left function key 1 | |
| 104 | #define A2_KEY_FL3 MAKE_KEY(2,000) //!< ADL left function key 3 | |
| 105 | ||
| 106 | #define A2_KEY_R MAKE_KEY(3,017) //!< normal: r shifted: R | |
| 107 | #define A2_KEY_T MAKE_KEY(3,016) //!< normal: t shifted: T | |
| 108 | #define A2_KEY_G MAKE_KEY(3,015) //!< normal: g shifted: G | |
| 109 | #define A2_KEY_Y MAKE_KEY(3,014) //!< normal: y shifted: Y | |
| 110 | #define A2_KEY_H MAKE_KEY(3,013) //!< normal: h shifted: H | |
| 111 | #define A2_KEY_8 MAKE_KEY(3,012) //!< normal: 8 shifted: * | |
| 112 | #define A2_KEY_N MAKE_KEY(3,011) //!< normal: n shifted: N | |
| 113 | #define A2_KEY_M MAKE_KEY(3,010) //!< normal: m shifted: M | |
| 114 | #define A2_KEY_LOCK MAKE_KEY(3,007) //!< LOCK | |
| 115 | #define A2_KEY_SPACE MAKE_KEY(3,006) //!< SPACE | |
| 116 | #define A2_KEY_LBRACKET MAKE_KEY(3,005) //!< normal: [ shifted: { | |
| 117 | #define A2_KEY_EQUALS MAKE_KEY(3,004) //!< normal: = shifted: + | |
| 118 | #define A2_KEY_RSHIFT MAKE_KEY(3,003) //!< RSHIFT | |
| 119 | #define A2_KEY_BLANK_BOT MAKE_KEY(3,002) //!< bottom blank key | |
| 120 | #define A2_KEY_MSW_3_16 MAKE_KEY(3,001) //!< unused on Microswitch KDB | |
| 121 | #define A2_KEY_MSW_3_17 MAKE_KEY(3,000) //!< unused on Microswitch KDB | |
| 122 | ||
| 123 | #define A2_KEY_FR1 MAKE_KEY(3,002) //!< ADL right function key 4 | |
| 124 | #define A2_KEY_FL4 MAKE_KEY(3,001) //!< ADL left function key 4 | |
| 125 | #define A2_KEY_FR5 MAKE_KEY(3,000) //!< ADL right function key 5 | |
| 126 | ||
| 127 | static INPUT_PORTS_START( alto2 ) | |
| 128 | PORT_START("ROW0") | |
| 129 | PORT_BIT(A2_KEY_5, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') //!< normal: 5 shifted: % | |
| 130 | PORT_BIT(A2_KEY_4, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') //!< normal: 4 shifted: $ | |
| 131 | PORT_BIT(A2_KEY_6, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 ~") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('~') //!< normal: 6 shifted: ~ | |
| 132 | PORT_BIT(A2_KEY_E, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("e E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') //!< normal: e shifted: E | |
| 133 | PORT_BIT(A2_KEY_7, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') //!< normal: 7 shifted: & | |
| 134 | PORT_BIT(A2_KEY_D, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("d D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') //!< normal: d shifted: D | |
| 135 | PORT_BIT(A2_KEY_U, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("u U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') //!< normal: u shifted: U | |
| 136 | PORT_BIT(A2_KEY_V, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("v V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') //!< normal: v shifted: V | |
| 137 | PORT_BIT(A2_KEY_0, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') //!< normal: 0 shifted: ) | |
| 138 | PORT_BIT(A2_KEY_K, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("k K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') //!< normal: k shifted: K | |
| 139 | PORT_BIT(A2_KEY_MINUS, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') //!< normal: - shifted: _ | |
| 140 | PORT_BIT(A2_KEY_P, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("p P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') //!< normal: p shifted: P | |
| 141 | PORT_BIT(A2_KEY_SLASH, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') //!< normal: / shifted: ? | |
| 142 | PORT_BIT(A2_KEY_BACKSLASH, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') //!< normal: \ shifted: | | |
| 143 | PORT_BIT(A2_KEY_LF, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LF") PORT_CODE(KEYCODE_DOWN) PORT_CHAR('\012') //!< normal: LF shifted: ? | |
| 144 | PORT_BIT(A2_KEY_BS, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BS") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('\010') //!< normal: BS shifted: ? | |
| 145 | ||
| 146 | PORT_START("ROW1") | |
| 147 | PORT_BIT(A2_KEY_3, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') //!< normal: 3 shifted: # | |
| 148 | PORT_BIT(A2_KEY_2, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') //!< normal: 2 shifted: @ | |
| 149 | PORT_BIT(A2_KEY_W, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("w W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') //!< normal: w shifted: W | |
| 150 | PORT_BIT(A2_KEY_Q, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("q Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') //!< normal: q shifted: Q | |
| 151 | PORT_BIT(A2_KEY_S, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("s S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') //!< normal: s shifted: S | |
| 152 | PORT_BIT(A2_KEY_A, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("a A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') //!< normal: a shifted: A | |
| 153 | PORT_BIT(A2_KEY_9, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') //!< normal: 9 shifted: ( | |
| 154 | PORT_BIT(A2_KEY_I, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("i I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') //!< normal: i shifted: I | |
| 155 | PORT_BIT(A2_KEY_X, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("x X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') //!< normal: x shifted: X | |
| 156 | PORT_BIT(A2_KEY_O, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("o O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') //!< normal: o shifted: O | |
| 157 | PORT_BIT(A2_KEY_L, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("l L") PORT_CODE(KEYCODE_E) PORT_CHAR('l') PORT_CHAR('L') //!< normal: l shifted: L | |
| 158 | PORT_BIT(A2_KEY_COMMA, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') //!< normal: , shifted: < | |
| 159 | PORT_BIT(A2_KEY_QUOTE, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\x27') PORT_CHAR('"') //!< normal: ' shifted: " | |
| 160 | PORT_BIT(A2_KEY_RBRACKET, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') //!< normal: ] shifted: } | |
| 161 | PORT_BIT(A2_KEY_BLANK_MID, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M[ ]") PORT_CODE(KEYCODE_END) //!< middle blank key | |
| 162 | PORT_BIT(A2_KEY_BLANK_TOP, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T[ ]") PORT_CODE(KEYCODE_PGUP) //!< top blank key | |
| 163 | ||
| 164 | PORT_START("ROW2") | |
| 165 | PORT_BIT(A2_KEY_1, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') //!< normal: 1 shifted: ! | |
| 166 | PORT_BIT(A2_KEY_ESCAPE, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR('\x1b') //!< normal: ESC shifted: ? | |
| 167 | PORT_BIT(A2_KEY_TAB, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\011') //!< normal: TAB shifted: ? | |
| 168 | PORT_BIT(A2_KEY_F, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("f F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') //!< normal: f shifted: F | |
| 169 | PORT_BIT(A2_KEY_CTRL, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) //!< CTRL | |
| 170 | PORT_BIT(A2_KEY_C, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("c C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') //!< normal: c shifted: C | |
| 171 | PORT_BIT(A2_KEY_J, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("j J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') //!< normal: j shifted: J | |
| 172 | PORT_BIT(A2_KEY_B, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("b B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') //!< normal: b shifted: B | |
| 173 | PORT_BIT(A2_KEY_Z, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("z Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') //!< normal: z shifted: Z | |
| 174 | PORT_BIT(A2_KEY_LSHIFT, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LSHIFT") PORT_CODE(KEYCODE_LSHIFT) //!< LSHIFT | |
| 175 | PORT_BIT(A2_KEY_P, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') //!< normal: . shifted: > | |
| 176 | PORT_BIT(A2_KEY_S, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')//!< normal: ; shifted: : | |
| 177 | PORT_BIT(A2_KEY_RETURN, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\013') //!< RETURN | |
| 178 | PORT_BIT(A2_KEY_L, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("← ↑") PORT_CODE(KEYCODE_LEFT) //!< normal: left arrow shifted: up arrow (caret) | |
| 179 | PORT_BIT(A2_KEY_DEL, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) //!< normal: DEL shifted: ? | |
| 180 | PORT_BIT(A2_KEY_MSW_2_17, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2/17") PORT_CODE(KEYCODE_MENU) //!< unused on Microswitch KDB | |
| 181 | ||
| 182 | PORT_START("ROW3") | |
| 183 | PORT_BIT(A2_KEY_R, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("r R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') //!< normal: r shifted: R | |
| 184 | PORT_BIT(A2_KEY_T, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("t T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') //!< normal: t shifted: T | |
| 185 | PORT_BIT(A2_KEY_G, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("g G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') //!< normal: g shifted: G | |
| 186 | PORT_BIT(A2_KEY_Y, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("y Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') //!< normal: y shifted: Y | |
| 187 | PORT_BIT(A2_KEY_H, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("h H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') //!< normal: h shifted: H | |
| 188 | PORT_BIT(A2_KEY_8, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') //!< normal: 8 shifted: * | |
| 189 | PORT_BIT(A2_KEY_N, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("n N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') //!< normal: n shifted: N | |
| 190 | PORT_BIT(A2_KEY_M, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("m M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') //!< normal: m shifted: M | |
| 191 | PORT_BIT(A2_KEY_LOCK, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LOCK") PORT_CODE(KEYCODE_SCRLOCK) //!< LOCK | |
| 192 | PORT_BIT(A2_KEY_SPACE, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_E) PORT_CHAR(' ') //!< SPACE | |
| 193 | PORT_BIT(A2_KEY_L, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') //!< normal: [ shifted: { | |
| 194 | PORT_BIT(A2_KEY_EQUALS, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') //!< normal: = shifted: + | |
| 195 | PORT_BIT(A2_KEY_RSHIFT, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RSHIFT") PORT_CODE(KEYCODE_RSHIFT) //!< RSHIFT | |
| 196 | PORT_BIT(A2_KEY_BLANK_BOT, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B[ ]") PORT_CODE(KEYCODE_PGDN) //!< bottom blank key | |
| 197 | PORT_BIT(A2_KEY_MSW_3_16, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3/16") PORT_CODE(KEYCODE_HOME) //!< unused on Microswitch KDB | |
| 198 | PORT_BIT(A2_KEY_MSW_3_17, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3/17") PORT_CODE(KEYCODE_INSERT) //!< unused on Microswitch KDB | |
| 199 | ||
| 200 | PORT_START("ROW4") | |
| 201 | PORT_BIT(A2_KEY_FR2, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FR2") PORT_CODE(KEYCODE_F6) //!< ADL right function key 2 | |
| 202 | PORT_BIT(A2_KEY_FL2, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FL2") PORT_CODE(KEYCODE_F2) //!< ADL left function key 2 | |
| 203 | ||
| 204 | PORT_START("ROW5") | |
| 205 | PORT_BIT(A2_KEY_FR4, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FR4") PORT_CODE(KEYCODE_F8) //!< ADL right funtion key 4 | |
| 206 | PORT_BIT(A2_KEY_BW, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BW") PORT_CODE(KEYCODE_F10) //!< ADL BW (?) | |
| 207 | ||
| 208 | PORT_START("ROW6") | |
| 209 | PORT_BIT(A2_KEY_FR3, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FR3") PORT_CODE(KEYCODE_F7) //!< ADL right function key 3 | |
| 210 | PORT_BIT(A2_KEY_FL1, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FL1") PORT_CODE(KEYCODE_F1) //!< ADL left function key 1 | |
| 211 | PORT_BIT(A2_KEY_FL3, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FL3") PORT_CODE(KEYCODE_F3) //!< ADL left function key 3 | |
| 212 | ||
| 213 | PORT_START("ROW7") | |
| 214 | PORT_BIT(A2_KEY_FR1, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FR1") PORT_CODE(KEYCODE_F5) //!< ADL right function key 1 | |
| 215 | PORT_BIT(A2_KEY_FL4, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FL4") PORT_CODE(KEYCODE_F4) //!< ADL left function key 4 | |
| 216 | PORT_BIT(A2_KEY_FR5, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FR5") PORT_CODE(KEYCODE_F9) //!< ADL right function key 5 | |
| 217 | ||
| 218 | PORT_START("CONFIG") /* config diode on main board */ | |
| 219 | PORT_CONFNAME( 0x40, 0x40, "TV system") | |
| 220 | PORT_CONFSETTING( 0x00, "NTSC") | |
| 221 | PORT_CONFSETTING( 0x40, "PAL") | |
| 222 | INPUT_PORTS_END | |
| 223 | ||
| 224 | ||
| 225 | /* F4 character display */ | |
| 226 | ||
| 227 | static const gfx_layout alto2_gfx_layout = | |
| 228 | { | |
| 229 | 16, 1, /* 16x1 pixels */ | |
| 230 | 65536, /* 65536 codes */ | |
| 231 | 1, /* 1 bit per pixel */ | |
| 232 | {0}, /* no bitplanes */ | |
| 233 | /* x offsets */ | |
| 234 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, | |
| 235 | /* y offsets */ | |
| 236 | {0}, | |
| 237 | 16 /* two bytes per code */ | |
| 238 | }; | |
| 239 | ||
| 240 | ||
| 241 | /* Graphics Decode Information */ | |
| 242 | ||
| 243 | static GFXDECODE_START( alto2 ) | |
| 244 | GFXDECODE_ENTRY( "gfx1", 0x0000, alto2_gfx_layout, 0, 2 ) | |
| 245 | GFXDECODE_END | |
| 246 | ||
| 247 | ||
| 248 | /* Palette Initialization */ | |
| 249 | ||
| 250 | void alto2_state::palette_init() | |
| 251 | { | |
| 252 | palette_set_color(machine(),0,RGB_WHITE); /* white */ | |
| 253 | palette_set_color(machine(),1,RGB_BLACK); /* black */ | |
| 254 | } | |
| 255 | ||
| 256 | static MACHINE_CONFIG_START( alto2, alto2_state ) | |
| 257 | /* basic machine hardware */ | |
| 258 | MCFG_CPU_ADD("maincpu", ALTO2, 20160000) | |
| 259 | MCFG_CPU_PROGRAM_MAP(alto2_ucode_map) | |
| 260 | MCFG_CPU_IO_MAP(alto2_ram_map) | |
| 261 | MCFG_SCREEN_ADD("screen", RASTER) | |
| 262 | MCFG_SCREEN_REFRESH_RATE(60) | |
| 263 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(ALTO2_DISPLAY_VBLANK_TIME)) | |
| 264 | ||
| 265 | /* video hardware */ | |
| 266 | MCFG_SCREEN_UPDATE_DRIVER(alto2_state, screen_update) | |
| 267 | MCFG_SCREEN_SIZE(ALTO2_DISPLAY_TOTAL_WIDTH, ALTO2_DISPLAY_HLC_END-1) | |
| 268 | MCFG_SCREEN_VISIBLE_AREA(0, ALTO2_DISPLAY_WIDTH-1, 0, ALTO2_DISPLAY_HEIGHT-1) | |
| 269 | MCFG_SCREEN_VBLANK_DRIVER(alto2_state, screen_eof_alto2) | |
| 270 | ||
| 271 | MCFG_GFXDECODE(alto2) | |
| 272 | MCFG_PALETTE_LENGTH(2) | |
| 273 | ||
| 274 | /* internal ram */ | |
| 275 | MCFG_RAM_ADD(RAM_TAG) | |
| 276 | MCFG_RAM_DEFAULT_SIZE("256K") | |
| 277 | MACHINE_CONFIG_END | |
| 278 | ||
| 279 | /* ROMs */ | |
| 280 | ||
| 281 | ROM_START(alto2) | |
| 282 | ROM_REGION( 01440, "2k_ctrl", 0 ) | |
| 283 | ROMX_LOAD( "2kctl.u3", 00000, 00377, CRC(5f8d89e8) SHA1(487cd944ab074290aea73425e81ef4900d92e250), ROM_NIBBLE) //!< 3601-1 256x4 BPROM; Emulator address modifier | |
| 284 | ROMX_LOAD( "2kctl.u76", 00400, 00777, CRC(1edef867) SHA1(928b8a15ac515a99109f32672441832173883b81), ROM_NIBBLE) //!< 3601-1 256x4 BPROM; 2KCTL replacement for u51 (1KCTL) | |
| 285 | ROMX_LOAD( "3kcram.a37", 01000, 01377, CRC(9417360d) SHA1(bfcdbc56ee4ffafd0f2f672c0c869a55d6dd194b), ROM_NIBBLE) | |
| 286 | ROMX_LOAD( "2kctl.u38", 01400, 01437, CRC(fc51b1d1) SHA1(e36c2a12a5da377394264899b5ae504e2ffda46e), 0) //!< 82S23 32x8 BPROM; task priority and initial address | |
| 287 | ||
| 288 | ROM_REGION16_LE( 0400, "const", 0 ) | |
| 289 | // constant PROMs, 4 x 4bit | |
| 290 | // UINT16 src = BITS(addr, 3,2,1,4,5,6,7,0); | |
| 291 | // UINT16 u16 = ~((const[src] << 8) | (const[src+0x100)); | |
| 292 | // m_const[addr] = u16; | |
| 293 | ROMX_LOAD( "madr.a6", 00000, 00377, CRC(c2c196b2) SHA1(8b2a599ac839ec2a070dbfef2f1626e645c858ca), ROM_NIBBLE | ROM_BITSHIFT(12)) //!< 0000-0377 C(00)',C(01)',C(02)',C(03)' | |
| 294 | ROMX_LOAD( "madr.a5", 00000, 00377, CRC(42336101) SHA1(c77819cf40f063af3abf66ea43f17cc1a62e928b), ROM_NIBBLE | ROM_BITSHIFT( 8)) //!< 0000-0377 C(04)',C(05)',C(06)',C(07)' | |
| 295 | ROMX_LOAD( "madr.a4", 00000, 00377, CRC(b957e490) SHA1(c72660ad3ada4ca0ed8697c6bb6275a4fe703184), ROM_NIBBLE | ROM_BITSHIFT( 4)) //!< 0000-0377 C(08)',C(09)',C(10)',C(11)' | |
| 296 | ROMX_LOAD( "madr.a3", 00000, 00377, CRC(e0992757) SHA1(5c45ea824970663cb9ee672dc50861539c860249), ROM_NIBBLE | ROM_BITSHIFT( 0)) //!< 0000-0377 C(12)',C(13)',C(14)',C(15)' | |
| 297 | ||
| 298 | #if 0 // FIXME: just different names(?) | |
| 299 | ROM_REGION16_LE( 0400, "const_alt", 0 ) | |
| 300 | // alternate constant PROMs, 4 x 4bit | |
| 301 | // UINT16 src = BITS(addr, 3,2,1,4,5,6,7,0); | |
| 302 | // UINT16 u16 = ~((const[src] << 8) | (const[src+0x100)); | |
| 303 | // m_const[addr] = u16; | |
| 304 | ROMX_LOAD( "c3.3", 00000, 00377, CRC(c2c196b2) SHA1(8b2a599ac839ec2a070dbfef2f1626e645c858ca), ROM_NIBBLE | ROM_BITSHIFT(12)) //!< 0000-0377 C(00)',C(01)',C(02)',C(03)' | |
| 305 | ROMX_LOAD( "c2.3", 00000, 00377, CRC(42336101) SHA1(c77819cf40f063af3abf66ea43f17cc1a62e928b), ROM_NIBBLE | ROM_BITSHIFT( 8)) //!< 0000-0377 C(04)',C(05)',C(06)',C(07)' | |
| 306 | ROMX_LOAD( "c1.3", 00000, 00377, CRC(b957e490) SHA1(c72660ad3ada4ca0ed8697c6bb6275a4fe703184), ROM_NIBBLE | ROM_BITSHIFT( 4)) //!< 0000-0377 C(08)',C(09)',C(10)',C(11)' | |
| 307 | ROMX_LOAD( "c0.3", 00000, 00377, CRC(e0992757) SHA1(5c45ea824970663cb9ee672dc50861539c860249), ROM_NIBBLE | ROM_BITSHIFT( 0)) //!< 0000-0377 C(12)',C(13)',C(14)',C(15)' | |
| 308 | #endif | |
| 309 | ||
| 310 | ROM_REGION32_LE( 02000, "ucode", ROMREGION_INVERT ) | |
| 311 | // micro code PROMs, 8 x 4bit | |
| 312 | // UINT32 src = addr ^ 0x3ff; | |
| 313 | // UINT32 u32 = ~((ucode[src] << 24) | (ucode[src+0x400] << 16) | (ucode[src+0x800] << 8) | (ucode[src+0xc00)); | |
| 314 | // m_ucode[addr] = u32 ^ ALTO2_UCODE_INVERTED; | |
| 315 | ROMX_LOAD( "55x.3", 00000, 01777, CRC(de870d75) SHA1(2b98cc769d8302cb39948711424d987d94e4159b), ROM_NIBBLE | ROM_BITSHIFT(28)) //!< 00000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' | |
| 316 | ROMX_LOAD( "64x.3", 00000, 01777, CRC(51b444c0) SHA1(8756e51f7f3253a55d75886465beb7ee1be6e1c4), ROM_NIBBLE | ROM_BITSHIFT(24)) //!< 00000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' | |
| 317 | ROMX_LOAD( "65x.3", 00000, 01777, CRC(741d1437) SHA1(01f7cf07c2173ac93799b2475180bfbbe7e0149b), ROM_NIBBLE | ROM_BITSHIFT(20)) //!< 00000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' | |
| 318 | ROMX_LOAD( "63x.3", 00000, 01777, CRC(f22d5028) SHA1(c65a42baef702d4aff2d9ad8e363daec27de6801), ROM_NIBBLE | ROM_BITSHIFT(16)) //!< 00000-01777 F1(0),F1(1)',F1(2)',F1(3)' | |
| 319 | ROMX_LOAD( "53x.3", 00000, 01777, CRC(3c89a740) SHA1(95d812d489b2bde03884b2f126f961caa6c8ec45), ROM_NIBBLE | ROM_BITSHIFT(12)) //!< 00000-01777 F2(0),F2(1)',F2(2)',F2(3)' | |
| 320 | ROMX_LOAD( "60x.3", 00000, 01777, CRC(a35de0bf) SHA1(7fa4aead44dcf5393bbfd1706c0ada24aa6fd3ac), ROM_NIBBLE | ROM_BITSHIFT( 8)) //!< 00000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' | |
| 321 | ROMX_LOAD( "61x.3", 00000, 01777, CRC(f25bcb2d) SHA1(acb57f3104a8dc4ba750dd1bf22ccc81cce9f084), ROM_NIBBLE | ROM_BITSHIFT( 4)) //!< 00000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' | |
| 322 | ROMX_LOAD( "62x.3", 00000, 01777, CRC(1b20a63f) SHA1(41dc86438e91c12b0fe42ffcce6b2ac2eb9e714a), ROM_NIBBLE | ROM_BITSHIFT( 0)) //!< 00000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' | |
| 323 | ||
| 324 | ROM_REGION32_LE( 02000, "xm_mesa_5.1", ROMREGION_INVERT ) | |
| 325 | // extended memory Mesa 5.1 micro code PROMs, 8 x 4bit | |
| 326 | ROMX_LOAD( "xm51.u54", 00000, 01777, CRC(11086ae9) SHA1(c394e3fadbfb91801ddc1a70cb25dc6f606c4f76), ROM_NIBBLE | ROM_BITSHIFT(28)) //!< 00000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' | |
| 327 | ROMX_LOAD( "xm51.u74", 00000, 01777, CRC(be8224f2) SHA1(ea9abcc3832b26a094319796901237e1e3f238b6), ROM_NIBBLE | ROM_BITSHIFT(24)) //!< 00000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' | |
| 328 | ROMX_LOAD( "xm51.u75", 00000, 01777, CRC(dfe3e3ac) SHA1(246fd29f92150a5d5d7627fbb4f2504c7b6cd5ec), ROM_NIBBLE | ROM_BITSHIFT(20)) //!< 00000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' | |
| 329 | ROMX_LOAD( "xm51.u73", 00000, 01777, CRC(6c20fa46) SHA1(a054330c65048011f12209aaed5c6da73d95f029), ROM_NIBBLE | ROM_BITSHIFT(16)) //!< 00000-01777 F1(0),F1(1)',F1(2)',F1(3)' | |
| 330 | ROMX_LOAD( "xm51.u52", 00000, 01777, CRC(0a31eec8) SHA1(4e2ad5daa5e6a6f2143ee4de00c7b625d096fb02), ROM_NIBBLE | ROM_BITSHIFT(12)) //!< 00000-01777 F2(0),F2(1)',F2(2)',F2(3)' | |
| 331 | ROMX_LOAD( "xm51.u70", 00000, 01777, CRC(5c64ee54) SHA1(0eb16d1b5e5967be7c1bf8c8ef6efdf0518a752c), ROM_NIBBLE | ROM_BITSHIFT( 8)) //!< 00000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' | |
| 332 | ROMX_LOAD( "xm51.u71", 00000, 01777, CRC(7283bf71) SHA1(819fdcc407ed0acdd8f12b02db6efbcab7bec19a), ROM_NIBBLE | ROM_BITSHIFT( 4)) //!< 00000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' | |
| 333 | ROMX_LOAD( "xm51.u72", 00000, 01777, CRC(a28e5251) SHA1(44dd8ad4ad56541b5394d30ce3521b4d1d561394), ROM_NIBBLE | ROM_BITSHIFT( 0)) //!< 00000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' | |
| 334 | ||
| 335 | ROM_REGION32_LE( 02000, "xm_mesa_4.1", ROMREGION_INVERT ) | |
| 336 | // extended memory Mesa 4.1 (?) micro code PROMs, 8 x 4bit | |
| 337 | ROMX_LOAD( "xm654.41", 00000, 01777, CRC(beace302) SHA1(0002fea03a0261f57365095c4b87385d833f7063), ROM_NIBBLE | ROM_BITSHIFT(28)) //!< 00000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' | |
| 338 | ROMX_LOAD( "xm674.41", 00000, 01777, CRC(7db5c097) SHA1(364bc41951baa3ad274031bd49abec1cf5b7a980), ROM_NIBBLE | ROM_BITSHIFT(24)) //!< 00000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' | |
| 339 | ROMX_LOAD( "xm675.41", 00000, 01777, CRC(26eac1e7) SHA1(9220a1386afae8de96bdb2cf084afbadeeb61d42), ROM_NIBBLE | ROM_BITSHIFT(20)) //!< 00000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' | |
| 340 | ROMX_LOAD( "xm673.41", 00000, 01777, CRC(8173d7e3) SHA1(7fbacf6dccb60dfe9cef88a248c3a1660efddcf4), ROM_NIBBLE | ROM_BITSHIFT(16)) //!< 00000-01777 F1(0),F1(1)',F1(2)',F1(3)' | |
| 341 | ROMX_LOAD( "xm652.41", 00000, 01777, CRC(ddfa94bb) SHA1(38625e269400aaf38cd07b5dbf36c0087a0f1b92), ROM_NIBBLE | ROM_BITSHIFT(12)) //!< 00000-01777 F2(0),F2(1)',F2(2)',F2(3)' | |
| 342 | ROMX_LOAD( "xm670.41", 00000, 01777, CRC(1cd187f3) SHA1(0fd5eff7c6b5c2383aa20148a795b80286554675), ROM_NIBBLE | ROM_BITSHIFT( 8)) //!< 00000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' | |
| 343 | ROMX_LOAD( "xm671.41", 00000, 01777, CRC(f21b1ad7) SHA1(1e18bdb35de7802892ac373c128f900786d40886), ROM_NIBBLE | ROM_BITSHIFT( 4)) //!< 00000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' | |
| 344 | ROMX_LOAD( "xm672.41", 00000, 01777, CRC(110ee075) SHA1(bb72fceba5ce9e5e8c8a0024915006bdd011a3f3), ROM_NIBBLE | ROM_BITSHIFT( 0)) //!< 00000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' | |
| 345 | ||
| 346 | ROM_REGION( 01040, "displ", 0 ) | |
| 347 | ROMX_LOAD( "displ.a38", 00000, 00377, CRC(fd30beb7) SHA1(65e4a19ba4ff748d525122128c514abedd55d866), ROM_NIBBLE) //!< P3601 256x4 BPROM; display FIFO control: STOPWAKE, MBEMPTY | |
| 348 | ROMX_LOAD( "displ.a66", 00400, 00777, CRC(9f91aad9) SHA1(69b1d4c71f4e18103112e8601850c2654e9265cf), ROM_NIBBLE) //!< P3601 256x4 BPROM; display VSYNC and VBLANK | |
| 349 | ROMX_LOAD( "displ.a63", 01000, 01037, CRC(82a20d60) SHA1(39d90703568be5419ada950e112d99227873fdea), 0) //!< 82S23 32x8 BPROM; display HBLANK, HSYNC, SCANEND, HLCGATE ... | |
| 350 | ||
| 351 | ROM_REGION( 01400, "ether", 0 ) | |
| 352 | ROMX_LOAD( "enet.a41", 00000, 00377, CRC(d5de8d86) SHA1(c134a4c898c73863124361a9b0218f7a7f00082a), ROM_NIBBLE) | |
| 353 | ROMX_LOAD( "enet.a42", 00400, 00777, CRC(9d5c81bd) SHA1(ac7e63332a3dad0bef7cd0349b24e156a96a4bf0), ROM_NIBBLE) | |
| 354 | ROMX_LOAD( "enet.a49", 01000, 01377, CRC(4d2dcdb2) SHA1(583327a7d70cd02702c941c0e43c1e9408ff7fd0), ROM_NIBBLE) | |
| 355 | ||
| 356 | ROM_REGION( 0x0300, "memory", 0 ) | |
| 357 | ROMX_LOAD( "madr.a32", 0x0000, 0x00ff, CRC(a0e3b4a7) SHA1(24e50afdeb637a6a8588f8d3a3493c9188b8da2c), ROM_NIBBLE) //! P3601 256x4 BPROM; mouse motion signals MX1, MX2, MY1, MY2 | |
| 358 | ROMX_LOAD( "madr.a64", 0x0100, 0x01ff, CRC(a66b0eda) SHA1(4d9088f592caa3299e90966b17765be74e523144), ROM_NIBBLE) //! P3601 256x4 BPROM; memory addressing | |
| 359 | ROMX_LOAD( "madr.a65", 0x0200, 0x02ff, CRC(ba37febd) SHA1(82e9db1cb65f451755295f0d179e6f8fe3349d4d), ROM_NIBBLE) //! P3601 256x4 BPROM; memory addressing | |
| 360 | ROMX_LOAD( "madr.a90", 0x0300, 0x03ff, CRC(7a2d8799) SHA1(c3760dba147740729d33b9b88e59088a4cc7437a), ROM_NIBBLE) | |
| 361 | ROMX_LOAD( "madr.a91", 0x0400, 0x04ff, CRC(dd556aeb) SHA1(900f333a091e3ccde0843019c25f25fba62e6023), ROM_NIBBLE) | |
| 362 | ROM_END | |
| 363 | ||
| 364 | /* Game Drivers */ | |
| 365 | ||
| 366 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ | |
| 367 | COMP( 1974, alto2, 0, 0, alto2, alto2, alto2_state, alto2, "Xerox Alto-II", "Alto2", 0 ) |
| Added: svn:mime-type + text/plain Added: svn:eol-style + native |
| Previous | 199869 Revisions | Next |