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*

branches/alto2/src/emu/cpu/cpu.mak
r26018r26022
22682268$(CPUOBJ)/score/scoredsm.o: $(CPUSRC)/score/scoredsm.c \
22692269                     $(CPUSRC)/score/scorem.h
22702270
2271
2272#-------------------------------------------------
2273# Xerox Alto-II
2274#@src/emu/cpu/alto2/alto2.h,CPUS += ALTO2
2275#-------------------------------------------------
2276
2277ifneq ($(filter ALTO2,$(CPUS)),)
2278OBJDIRS += $(CPUOBJ)/alto2
2279CPUOBJS += $(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   
2295DASMOBJS += $(CPUOBJ)/alto2/alto2dsm.o
2296endif
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
branches/alto2/src/emu/cpu/alto2/a2curt.c
r0r26022
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 */
15void 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 */
25void 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 */
48void 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 */
60void 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 */
67void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2curt.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/a2mem.c
r0r26022
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 */
290static __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 */
306static 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 */
329UINT32 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 */
492UINT16 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 */
505void 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 */
521UINT16 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 */
544UINT16 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
561void 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 */
590void 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 */
607UINT16 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 */
626void 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 */
653UINT16 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 */
708void 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 */
770void 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 */
790UINT16 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 */
808void 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 */
828void 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}
Property changes on: branches/alto2/src/emu/cpu/alto2/a2mem.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/a2ram.c
r0r26022
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 */
18void 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 */
37void 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 */
47void 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 */
58void 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 */
68void 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 */
87void 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 */
235void 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 */
244void 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 */
259void 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 */
268void 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 */
278void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2ram.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/a2dht.c
r0r26022
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 */
15void 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 */
31void 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 */
42void 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 */
53void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2dht.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2kwd.c
r0r26022
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 */
15void 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 */
24void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2kwd.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2ksec.c
r0r26022
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 */
13void 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 */
22void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2ksec.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2emu.c
r0r26022
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 */
265void 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 */
280void 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 */
303void 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 */
312void 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 */
324void 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 */
358void 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 */
373void 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 */
384void 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 */
410void 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 */
449void 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 */
501void 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
513void 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 */
559void 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 */
634void 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 */
654void 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 */
668void 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
685void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2emu.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2mouse.c
r0r26022
1#include "alto2.h"
2
3enum {
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 */
99UINT16 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 */
148void 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 */
170void 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 */
204void alto2_cpu_device::mouse_init()
205{
206   memset(&m_mouse, 0, sizeof(m_mouse));
207}
Property changes on: branches/alto2/src/emu/cpu/alto2/a2mouse.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/a2disk.c
r0r26022
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) */
122enum {
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 */
130enum {
131   RECNO_HEADER,
132   RECNO_PAGENO,
133   RECNO_LABEL,
134   RECNO_DATA
135};
136
137
138/** @brief read/write/check numbers */
139enum {
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 */
148static const char *rwc_name[4] = {"read", "check", "write", "write2"};
149#endif
150
151#if   JKFF_FUNCTION
152
153#if   DEBUG
154static 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 */
168static 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) */
243static 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 */
1083void 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) */
1508void 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) */
1517void 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 */
1545void 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 */
1618void 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 */
1630void 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 */
1649void 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 */
1696void 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 */
1712void 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 */
1736void 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 */
1778void 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 */
1852void 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 */
1891void 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 */
1989void 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 */
2013void 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 */
2055void 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 */
2086void 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 */
2129void 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 */
2143void 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 */
2157void 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 */
2172void 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 */
2201void 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 */
2217void 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 */
2276void 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 */
2303void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2disk.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2dvt.c
r0r26022
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 */
15void 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 */
25void 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 */
34void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2dvt.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2dwt.c
r0r26022
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 */
15void 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 */
31void 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
43void 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}
Property changes on: branches/alto2/src/emu/cpu/alto2/a2dwt.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/alto2.c
r0r26022
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
12alto2_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 */
20const 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) */
44const 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 */
84const 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 */
108const 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 */
124const 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 */
148const 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
171UINT8 cram3k_a37[256];
172
173UINT8 madr_a64[256];
174
175UINT8 madr_a65[256];
176
177/** @brief fatal exit on unitialized dynamic phase BUS source */
178void 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 */
185void 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 */
192void 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 */
199void 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 */
206void 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 */
213void 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 */
224UINT16 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 */
236void 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 */
250void 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 */
260void 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 */
270void 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 */
290void 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 */
303void 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 */
313void 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 */
327void 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 */
343typedef 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 */
365typedef 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 */
403static __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 */
537void 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 */
630void 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 */
640void 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 */
650void 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 */
660void 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 */
670void 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 */
680void 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 */
692void 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 */
760void 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 */
803void 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 */
923UINT32 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 */
1187void 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 */
1716void 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) */
1913int 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
1932void alto2_cpu_device::init_001(int task)
1933{
1934
1935}
1936
1937void alto2_cpu_device::init_002(int task)
1938{
1939
1940}
1941
1942void alto2_cpu_device::init_003(int task)
1943{
1944
1945}
1946
1947void alto2_cpu_device::init_005(int task)
1948{
1949
1950}
1951
1952void alto2_cpu_device::init_006(int task)
1953{
1954
1955}
1956
1957void alto2_cpu_device::init_017(int task)
1958{
1959
1960}
Property changes on: branches/alto2/src/emu/cpu/alto2/alto2.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2disp.c
r0r26022
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 */
157static 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 */
195int 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 */
268int 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 */
424void 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 */
438int 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}
Property changes on: branches/alto2/src/emu/cpu/alto2/a2disp.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/alto2dsm.c
r0r26022
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 */
71static 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 */
93static 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 */
131static 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 */
172static 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
190offs_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}
Property changes on: branches/alto2/src/emu/cpu/alto2/alto2dsm.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/alto2.h
r0r26022
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
23extern void logprintf(int type, int level, const char* format, ...);
24#define   LOG(x) logprintf x
25#else
26#define   LOG(x)
27#endif
28
29extern 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
156enum {
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 */
189typedef 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
200class alto2_cpu_device :  public cpu_device
201{
202public:
203   // construction/destruction
204   alto2_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
205
206protected:
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
237private:
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
2023extern const device_type ALTO2;
2024
2025
2026#endif /* _CPU_ALTO2_H_ */
Property changes on: branches/alto2/src/emu/cpu/alto2/alto2.h
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/a2part.c
r0r26022
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 */
13void 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 */
22void alto2_cpu_device::init_part(int task)
23{
24   m_active_callback[task] = &alto2_cpu_device::activate_part;
25}
26
Property changes on: branches/alto2/src/emu/cpu/alto2/a2part.c
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/emu/cpu/alto2/a2ether.c
r0r26022
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 */
13UINT8 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 */
79static 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 */
124void 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 */
317UINT32 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 */
335void 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 */
383void 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
425void 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 */
439void 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 */
454void 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 */
466void 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 */
486void 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 */
505void 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 */
520void 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 */
546void 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 */
564void 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 */
581void 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 */
602void 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 */
620void 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 */
637void 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 */
648void alto2_cpu_device::eth_activate()
649{
650   m_ewfct = 0;
651}
652
653/**
654 * @brief Ethernet task slot initialization
655 */
656void 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
Property changes on: branches/alto2/src/emu/cpu/alto2/a2ether.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/cpu/alto2/a2drive.c
r0r26022
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 */
148typedef 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 */
166typedef 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
244static 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
264static 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 */
293static 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 */
323static 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 */
345static 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 */
367static 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 */
393static 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 */
419static 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 */
442static 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
521static 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 */
540static 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 */
574static 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 */
611static 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 */
649static 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 */
681static 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 */
703static 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 */
830int 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 */
841const 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 */
855const 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 */
871int 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 */
885attotime 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 */
899attotime 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 */
913int 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 */
927int 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 */
943int 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 */
961int 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 */
975int 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 */
989int 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 */
1005int 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 */
1021int 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 */
1040int 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 */
1057int 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 */
1071void 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 */
1124void 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 */
1186void 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 */
1198void 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 */
1210void 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 */
1222void 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 */
1246void 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 */
1297int 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 */
1349int 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 */
1400int 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 */
1446int 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 */
1487void 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 */
1519void 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 */
1533void 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 */
1560int 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 */
1731void 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}
Property changes on: branches/alto2/src/emu/cpu/alto2/a2drive.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/mess/includes/alto2.h
r0r26022
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
14class alto2_state : public driver_device
15{
16public:
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
52protected:
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_ */
Property changes on: branches/alto2/src/mess/includes/alto2.h
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain
branches/alto2/src/mess/mess.mak
r26018r26022
129129CPUS += ES5510
130130CPUS += SCUDSP
131131CPUS += IE15
132CPUS += ALTO2
132133
133134#-------------------------------------------------
134135# specify available sound cores; some of these are
r26018r26022
20992100$(MESSOBJ)/xerox.a:             \
21002101   $(MESS_DRIVERS)/xerox820.o  \
21012102   $(MESS_DRIVERS)/bigbord2.o  \
2103   $(MESS_DRIVERS)/alto2.o     \
21022104
21032105$(MESSOBJ)/yamaha.a:            \
21042106   $(MESS_DRIVERS)/ymmu100.o   \
branches/alto2/src/mess/drivers/alto2.c
r0r26022
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
28static 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)
31ADDRESS_MAP_END
32
33static 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)
35ADDRESS_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
127static 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")
222INPUT_PORTS_END
223
224
225/* F4 character display */
226
227static 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
243static GFXDECODE_START( alto2 )
244   GFXDECODE_ENTRY( "gfx1", 0x0000, alto2_gfx_layout,  0, 2 )
245GFXDECODE_END
246
247
248/* Palette Initialization */
249
250void 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
256static 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")
277MACHINE_CONFIG_END
278
279/* ROMs */
280
281ROM_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)
362ROM_END
363
364/* Game Drivers */
365
366/*    YEAR  NAME        PARENT  COMPAT  MACHINE     INPUT       INIT    COMPANY                     FULLNAME                FLAGS */
367COMP( 1974, alto2,      0,      0,      alto2,      alto2, alto2_state, alto2,    "Xerox Alto-II",            "Alto2",               0 )
Property changes on: branches/alto2/src/mess/drivers/alto2.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native

Previous 199869 Revisions Next


© 1997-2024 The MAME Team