dbx.v
16.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
// dbx.v v1 Frank Berndt
// debug board fpga logic;
// :set tabstop=4
// Both configuration and user operation are achieved through the parallel port.
// The design is synchronous to CLK to control delays.
// The debug requires the use of the internal fpga pullups.
// RST of the parallel port is wired to the PROGRAM pin of the fpga.
// The fpga DONE signal is wired to the pp USR2 signal.
// BB ide address space, IOCS0;
// 0000..7ffe 32kB of sram, appears multiple times;
// 8000..fffe 32kB of cmd register;
`timescale 1ns/1ns
module dbx (
CLK, SW,
DATA, ASTROBE, DSTROBE, WRITE, WAIT, IRQ, USR1, USR3,
IORST, IOAD, IOALE, IOR, IOW, IOCS0, IOCS2, IOIRQ,
BUT_A, BUT_B, BUT_C, BUT_D, BUT_E, BUT_F, BUT_L, BUT_R, BUT_Z,
BUT_LEFT, BUT_RIGHT, BUT_UP, BUT_DOWN, BUT_START
);
input CLK; // 33MHz reference clock;
input SW; // switch setting;
// parallel port interface;
inout [7:0] DATA; // data bus;
input ASTROBE; // address strobe;
input DSTROBE; // data strobe;
input WRITE; // write to dbx;
output WAIT; // wait;
output IRQ; // interrupt to host;
output USR1; // user signal 1;
output USR3; // user signal 3;
// bb IO interface;
input IORST; // io bus reset;
inout [15:0] IOAD; // io addr/data bus;
input IOALE; // address latch enable;
input IOR; // read strobe;
input IOW; // write strobe;
input IOCS0; // io cs 0, debug port;
input IOCS2; // io cs 2, button smapling;
output IOIRQ; // interrupt to bb;
// button interface;
input BUT_A; // button A;
input BUT_B; // button B;
input BUT_C; // button C;
input BUT_D; // button D;
input BUT_E; // button E;
input BUT_F; // button F;
input BUT_L; // button L;
input BUT_R; // button R;
input BUT_Z; // button Z;
input BUT_LEFT; // button LEFT;
input BUT_RIGHT; // button RIGHT;
input BUT_UP; // button UP;
input BUT_DOWN; // button DOWN;
input BUT_START; // button START;
// assign global clock;
wire in_clk; // clk out of input buffer;
wire gclk; // global clock;
IBUFG io_clk ( .I(CLK), .O(in_clk) );
BUFG g_clk ( .I(in_clk), .O(gclk) );
// SW determines mode;
// 0=debug 1=jtag;
// turn off pp DATA and WAIT outputs;
wire in_sw; // output of input buffer;
IBUF io_sw ( .I(SW), .O(in_sw) );
// button input io cells;
// use flops in io cell to sample button inputs;
wire in_a, in_b, in_c, in_d, in_e, in_f, in_l, in_r, in_z;
wire in_left, in_right, in_up, in_down, in_start;
IBUF io_a ( .I(BUT_A), .O(in_a) );
IBUF io_b ( .I(BUT_B), .O(in_b) );
IBUF io_c ( .I(BUT_C), .O(in_c) );
IBUF io_d ( .I(BUT_D), .O(in_d) );
IBUF io_e ( .I(BUT_E), .O(in_e) );
IBUF io_f ( .I(BUT_F), .O(in_f) );
IBUF io_l ( .I(BUT_L), .O(in_l) );
IBUF io_r ( .I(BUT_R), .O(in_r) );
IBUF io_z ( .I(BUT_Z), .O(in_z) );
IBUF io_left ( .I(BUT_LEFT), .O(in_left) );
IBUF io_right ( .I(BUT_RIGHT), .O(in_right) );
IBUF io_up ( .I(BUT_UP), .O(in_up) );
IBUF io_down ( .I(BUT_DOWN), .O(in_down) );
IBUF io_start ( .I(BUT_START), .O(in_start) );
wire [13:0] in_but; // vector of button inputs;
reg [13:0] r_but; // flops in io cells;
assign in_but = { in_l, in_r, in_e, in_d, in_c, in_f, in_b, in_a, in_z,
in_start, in_up, in_down, in_left, in_right };
always @(posedge gclk)
begin
r_but <= in_but;
end
// bb io bus interface;
// must synchronize all inputs;
wire in_iorst; // output of input buffer;
wire in_ior; // output of input buffer;
wire in_iow; // output of input buffer;
wire in_iocs0; // output of input buffer;
wire in_iocs2; // output of input buffer;
IBUF io_iorst ( .I(IORST), .O(in_iorst) );
IBUF io_ior ( .I(IOR), .O(in_ior) );
IBUF io_iow ( .I(IOW), .O(in_iow) );
IBUF io_iocs0 ( .I(IOCS0), .O(in_iocs0) );
IBUF io_iocs2 ( .I(IOCS2), .O(in_iocs2) );
reg r_iorst; // reset, active 0;
reg r_ior; // read strobe;
reg r_iow; // write strobe;
reg r_iocs0; // debug port select;
reg r_iocs2; // button port select;
always @(posedge gclk)
begin
r_iorst <= in_iorst;
r_ior <= in_ior;
r_iow <= in_iow;
r_iocs0 <= in_iocs0;
r_iocs2 <= in_iocs2;
end
// bb io data bus interface;
// use registers in io cell;
wire [15:0] in_ioad; // outputs of input buffers;
wire [15:0] out_ioad; // output data to bb ide bus;
wire b_oe;
reg [15:0] ri_ioad; // input registers;
reg [15:0] ro_ioad; // output registers;
reg [15:0] re_ioad; // output enable registers;
IOBUF_F_12
io_ioad15 ( .IO(IOAD[15]), .I(ro_ioad[15]), .O(in_ioad[15]), .T(re_ioad[15]) ),
io_ioad14 ( .IO(IOAD[14]), .I(ro_ioad[14]), .O(in_ioad[14]), .T(re_ioad[14]) ),
io_ioad13 ( .IO(IOAD[13]), .I(ro_ioad[13]), .O(in_ioad[13]), .T(re_ioad[13]) ),
io_ioad12 ( .IO(IOAD[12]), .I(ro_ioad[12]), .O(in_ioad[12]), .T(re_ioad[12]) ),
io_ioad11 ( .IO(IOAD[11]), .I(ro_ioad[11]), .O(in_ioad[11]), .T(re_ioad[11]) ),
io_ioad10 ( .IO(IOAD[10]), .I(ro_ioad[10]), .O(in_ioad[10]), .T(re_ioad[10]) ),
io_ioad9 ( .IO(IOAD[9]), .I(ro_ioad[9]), .O(in_ioad[9]), .T(re_ioad[9]) ),
io_ioad8 ( .IO(IOAD[8]), .I(ro_ioad[8]), .O(in_ioad[8]), .T(re_ioad[8]) ),
io_ioad7 ( .IO(IOAD[7]), .I(ro_ioad[7]), .O(in_ioad[7]), .T(re_ioad[7]) ),
io_ioad6 ( .IO(IOAD[6]), .I(ro_ioad[6]), .O(in_ioad[6]), .T(re_ioad[6]) ),
io_ioad5 ( .IO(IOAD[5]), .I(ro_ioad[5]), .O(in_ioad[5]), .T(re_ioad[5]) ),
io_ioad4 ( .IO(IOAD[4]), .I(ro_ioad[4]), .O(in_ioad[4]), .T(re_ioad[4]) ),
io_ioad3 ( .IO(IOAD[3]), .I(ro_ioad[3]), .O(in_ioad[3]), .T(re_ioad[3]) ),
io_ioad2 ( .IO(IOAD[2]), .I(ro_ioad[2]), .O(in_ioad[2]), .T(re_ioad[2]) ),
io_ioad1 ( .IO(IOAD[1]), .I(ro_ioad[1]), .O(in_ioad[1]), .T(re_ioad[1]) ),
io_ioad0 ( .IO(IOAD[0]), .I(ro_ioad[0]), .O(in_ioad[0]), .T(re_ioad[0]) );
always @(posedge gclk)
begin
ri_ioad <= in_ioad;
ro_ioad <= out_ioad;
re_ioad <= {16{~b_oe}};
end
// enable ide output drivers;
// for both cs spaces and IOR=0;
assign b_oe = ~in_ior & (~in_iocs0 | ~in_iocs2);
// ide address latch;
// cannot use gclk because it is slower than IOALE;
// transfer address into CLK domain;
wire in_ioale; // output of input buffer;
reg [15:0] ale_addr; // ale address;
reg [15:0] ide_addr; // ide bus address;
IBUF io_ioale ( .I(IOALE), .O(in_ioale) );
always @(negedge in_ioale)
begin
ale_addr <= in_ioad;
end
always @(posedge gclk)
begin
ide_addr <= ale_addr;
end
// parallel port interface;
// sample inputs in io cell;
wire in_astrobe; // output of input buffer;
wire in_dstrobe; // output of input buffer;
wire in_write; // output of input buffer;
IBUF io_astrobe ( .I(ASTROBE), .O(in_astrobe) );
IBUF io_dstrobe ( .I(DSTROBE), .O(in_dstrobe) );
IBUF io_write ( .I(WRITE), .O(in_write) );
reg r_astrobe; // pp address strobe;
reg r_dstrobe; // pp data strobe;
reg r_write; // pp write request;
always @(posedge gclk)
begin
r_astrobe <= in_astrobe;
r_dstrobe <= in_dstrobe;
r_write <= in_write;
end
// pp output signals;
// drive outputs from io cell reg;
wire h_oe; // pp output enable;
wire out_wait; // pp wait;
wire out_usr1; // pp user 1;
wire out_usr3; // pp user 3;
reg ro_wait; // io cell register;
reg re_wait; // io cell oe register;
reg r_usr1; // io cell register;
reg r_usr3; // io cell register;
always @(posedge gclk)
begin
ro_wait <= out_wait;
re_wait <= in_sw;
r_usr1 <= out_usr1;
r_usr3 <= out_usr3;
end
OBUFT_F_12 io_wait ( .I(ro_wait), .O(WAIT), .T(re_wait) );
OBUF_F_12 io_usr1 ( .I(r_usr1), .O(USR1) );
OBUF_F_12 io_usr3 ( .I(r_usr3), .O(USR3) );
// pp bidirectional data bus;
// use io cell registers;
wire [7:0] in_data; // outputs of input buffers;
reg [7:0] out_data; // pp output data;
reg [7:0] ri_data; // pp input register;
reg [7:0] ro_data; // pp output register;
reg [7:0] re_data; // pp output enable register;
IOBUF_F_12
io_data7 ( .IO(DATA[7]), .I(ro_data[7]), .O(in_data[7]), .T(re_data[7]) ),
io_data6 ( .IO(DATA[6]), .I(ro_data[6]), .O(in_data[6]), .T(re_data[6]) ),
io_data5 ( .IO(DATA[5]), .I(ro_data[5]), .O(in_data[5]), .T(re_data[5]) ),
io_data4 ( .IO(DATA[4]), .I(ro_data[4]), .O(in_data[4]), .T(re_data[4]) ),
io_data3 ( .IO(DATA[3]), .I(ro_data[3]), .O(in_data[3]), .T(re_data[3]) ),
io_data2 ( .IO(DATA[2]), .I(ro_data[2]), .O(in_data[2]), .T(re_data[2]) ),
io_data1 ( .IO(DATA[1]), .I(ro_data[1]), .O(in_data[1]), .T(re_data[1]) ),
io_data0 ( .IO(DATA[0]), .I(ro_data[0]), .O(in_data[0]), .T(re_data[0]) );
always @(posedge gclk)
begin
ri_data <= in_data;
ro_data <= out_data;
re_data <= {8{~h_oe}};
end
// pp read/write state machine;
// start pp state machine as soon as there is one strobe;
// assert nWait after wait time is reached;
reg del_astrobe; // delayed addr strobe;
reg del_dstrobe; // delayed data strobe;
wire pp_stb; // got a strobe;
reg [5:0] pp_sm; // pp state machine;
reg pp_ack; // ack with posedge wait;
reg [1:0] pp_wait; // wait interlock signal;
assign pp_stb = del_astrobe | del_dstrobe;
always @(posedge gclk)
begin
del_astrobe <= ~r_astrobe;
del_dstrobe <= ~r_dstrobe;
if(pp_stb == 1'b0)
pp_sm <= 6'd0;
else if(pp_sm[5])
pp_sm <= 6'd63;
else
pp_sm <= pp_sm + 1;
pp_ack <= (pp_sm == 6'd15);
if(pp_stb == 1'b0)
pp_wait[0] <= 1'b0;
else if(pp_ack)
pp_wait[0] <= 1'b1;
pp_wait[1] <= pp_wait[0];
end
assign out_wait = pp_wait[0];
assign h_oe = ~in_sw & pp_stb & r_write;
// latch pp write data;
// at end of write cycle;
wire pp_wcyc; // pp write cycle;
reg [7:0] pp_wdat; // pp write byte;
reg pp_cwr; // pp cmd write;
reg pp_dwr; // pp data write;
reg pp_inc; // increment ptr on data rw;
reg pp_winc; // increment write pointer;
reg pp_rinc; // increment read pointer;
assign pp_wcyc = pp_ack & ~r_write;
always @(posedge gclk)
begin
if(pp_wcyc)
pp_wdat <= ri_data;
pp_cwr <= pp_wcyc & del_astrobe;
pp_dwr <= pp_wcyc & del_dstrobe;
pp_inc <= pp_ack & del_dstrobe;
pp_winc <= pp_inc & ~r_write;
pp_rinc <= (pp_wait == 2'b10) & r_write;
end
// tie unused signals;
assign out_usr1 = 1'b1;
assign out_usr3 = 1'b1;
// dual-port sram;
// use all of sram as a bidirectional msg buffer;
// organized as 1kx16 bits;
wire mh_rst; // zero pp read data;
wire mh_ena; // pp enable;
wire [9:0] mh_addr; // pp address;
wire [15:0] mh_wdat; // pp write data;
wire [1:0] mh_we; // pp write enables;
wire [15:0] mh_rdat; // pp read data;
wire mb_rst; // zero pp read data;
wire mb_ena; // pp enable;
wire [9:0] mb_addr; // pp address;
wire [15:0] mb_wdat; // pp write data;
wire mb_we; // pp write enables;
wire [15:0] mb_rdat; // pp read data;
RAMB4_S4_S4 mbuf3 (
.CLKA(gclk),
.RSTA(mh_rst),
.ENA(mh_ena),
.ADDRA(mh_addr),
.DIA(mh_wdat[15:12]),
.WEA(mh_we[1]),
.DOA(mh_rdat[15:12]),
.CLKB(gclk),
.RSTB(mb_rst),
.ENB(mb_ena),
.ADDRB(mb_addr),
.DIB(mb_wdat[15:12]),
.WEB(mb_we),
.DOB(mb_rdat[15:12])
);
RAMB4_S4_S4 mbuf2 (
.CLKA(gclk),
.RSTA(mh_rst),
.ENA(mh_ena),
.ADDRA(mh_addr),
.DIA(mh_wdat[11:8]),
.WEA(mh_we[1]),
.DOA(mh_rdat[11:8]),
.CLKB(gclk),
.RSTB(mb_rst),
.ENB(mb_ena),
.ADDRB(mb_addr),
.DIB(mb_wdat[11:8]),
.WEB(mb_we),
.DOB(mb_rdat[11:8])
);
RAMB4_S4_S4 mbuf1 (
.CLKA(gclk),
.RSTA(mh_rst),
.ENA(mh_ena),
.ADDRA(mh_addr),
.DIA(mh_wdat[7:4]),
.WEA(mh_we[0]),
.DOA(mh_rdat[7:4]),
.CLKB(gclk),
.RSTB(mb_rst),
.ENB(mb_ena),
.ADDRB(mb_addr),
.DIB(mb_wdat[7:4]),
.WEB(mb_we),
.DOB(mb_rdat[7:4])
);
RAMB4_S4_S4 mbuf0 (
.CLKA(gclk),
.RSTA(mh_rst),
.ENA(mh_ena),
.ADDRA(mh_addr),
.DIA(mh_wdat[3:0]),
.WEA(mh_we[0]),
.DOA(mh_rdat[3:0]),
.CLKB(gclk),
.RSTB(mb_rst),
.ENB(mb_ena),
.ADDRB(mb_addr),
.DIB(mb_wdat[3:0]),
.WEB(mb_we),
.DOB(mb_rdat[3:0])
);
// host command writes;
// 10xx_xxxx set write data ptr to x*32;
// 11xx_xxxx set read data ptr to x*32;
// 01xx_xxxx host reset;
// 00xx_xxx1 set host->bb request;
// 00xx_xx1x set host->bb ack;
// 00xx_x1xx clear host<-bb request;
// 00xx_1xxx clear host<-bb ack;
wire h_reset; // host pp reset;
wire h_set_wptr; // set write data pointer;
wire h_set_rptr; // set read data pointer;
wire h_set_req; // set host->bb request;
wire h_set_ack; // set host->bb ack;
wire h_clr_req; // clear host<-bb request;
wire h_clr_ack; // clear host<-bb ack;
assign h_set_wptr = pp_cwr & (pp_wdat[7:6] == 2'b10);
assign h_set_rptr = pp_cwr & (pp_wdat[7:6] == 2'b11);
assign h_reset = pp_cwr & ~pp_wdat[7] & pp_wdat[6];
assign h_set_req = pp_cwr & ~pp_wdat[7] & pp_wdat[0];
assign h_set_ack = pp_cwr & ~pp_wdat[7] & pp_wdat[1];
assign h_clr_req = h_reset | (pp_cwr & ~pp_wdat[7] & pp_wdat[2]);
assign h_clr_ack = h_reset | (pp_cwr & ~pp_wdat[7] & pp_wdat[3]);
// host write data pointer;
// used for all pp data writes;
// increments after each byte;
reg [10:0] h_wptr; // host write pointer;
always @(posedge gclk)
begin
if(h_reset)
h_wptr <= 11'd0;
else if(h_set_wptr)
h_wptr <= { pp_wdat[5:0], 5'd0 };
else if(pp_winc)
h_wptr <= h_wptr + 1;
end
// host read data pointer;
// used for all pp data read;
// increments after each byte;
reg [10:0] h_rptr; // host read pointer;
always @(posedge gclk)
begin
if(h_reset)
h_rptr <= 11'd0;
else if(h_set_rptr)
h_rptr <= { pp_wdat[5:0], 5'd0 };
else if(pp_rinc)
h_rptr <= h_rptr + 1;
end
// host side buffer control;
// select read pointer as default;
// turn to write pointer for write cycle;
assign mh_rst = 1'b0;
assign mh_ena = pp_stb;
assign mh_addr = pp_dwr? h_wptr[10:1] : h_rptr[10:1];
assign mh_we[1] = pp_dwr & ~h_wptr[0];
assign mh_we[0] = pp_dwr & h_wptr[0];
assign mh_wdat = { pp_wdat, pp_wdat };
// detect end of ide write cycle;
reg b_diow; // delayed iow;
wire ide_iow; // write pulse;
reg [15:0] ide_wdat; // ide write data;
reg ide_swe; // ide sram write enable;
reg ide_cwe; // ide cmd write enable;
assign ide_iow = ~r_iocs0 & ~b_diow & ~r_iow;
always @(posedge gclk)
begin
b_diow <= r_iow;
if(ide_iow)
ide_wdat <= ri_ioad;
ide_swe <= ide_iow & ~ide_addr[14];
ide_cwe <= ide_iow & ide_addr[14];
end
// bb command writes;
// 01xx_xxxx b bside reset;
// 00xx_xxx1 set host->bb request;
// 00xx_xx1x set host->bb ack;
// 00xx_x1xx clear host<-bb request;
// 00xx_1xxx clear host<-bb ack;
wire b_reset; // host pp reset;
wire b_set_req; // set host<-bb request;
wire b_set_ack; // set host<-bb ack;
wire b_clr_req; // clear host->bb request;
wire b_clr_ack; // clear host->bb ack;
assign b_reset = (ide_cwe & ide_wdat[6]) | ~r_iorst;
assign b_set_req = ide_cwe & ide_wdat[0];
assign b_set_ack = ide_cwe & ide_wdat[1];
assign b_clr_req = b_reset | (ide_cwe & ide_wdat[2]);
assign b_clr_ack = b_reset | (ide_cwe & ide_wdat[3]);
// host->bb semaphores;
// set by host cmd write;
// cleared by bb cmd write or reset;
reg b_req; // host->bb request;
reg b_ack; // host->bb ack;
wire b_intr; // sum of host->bb intr;
always @(posedge gclk)
begin
if(h_set_req)
b_req <= 1'b1;
else if(b_clr_req)
b_req <= 1'b0;
if(h_set_ack)
b_ack <= 1'b1;
else if(b_clr_ack)
b_ack <= 1'b0;
end
assign b_intr = b_req | b_ack;
OBUF_F_12 io_ioirq ( .I(b_intr), .O(IOIRQ) );
// host<-bb interrupt;
// set by bb cmd write;
// cleared by host cmd write or reset;
reg h_req; // host<-bb request;
reg h_ack; // host<-bb ack;
wire h_intr; // sum of host<-bb intr;
always @(posedge gclk)
begin
if(b_set_req)
h_req <= 1'b1;
else if(h_clr_req)
h_req <= 1'b0;
if(b_set_ack)
h_ack <= 1'b1;
else if(h_clr_ack)
h_ack <= 1'b0;
end
assign h_intr = h_req | h_ack;
OBUF_F_12 io_irq ( .I(~h_intr), .O(IRQ) );
// bb port always reads;
// RST and ENA are not used;
// write enables are active at end of write;
assign mb_rst = 1'b0;
assign mb_ena = 1'b1;
assign mb_addr = ide_addr[9:0];
assign mb_wdat = ide_wdat;
assign mb_we = ide_swe;
// bb read data mux;
// select data from buttons, status register or sram;
wire [15:0] b_sts; // bb side status;
assign b_sts = { 14'd0, b_ack, b_req, h_ack, h_req };
assign out_ioad = ~r_iocs2? r_but : ide_addr[14]? b_sts : mb_rdat;
// pp read data mux;
// select cmd register or buffer data;
wire [7:0] h_sts; // pp read status;
assign h_sts = { 4'd0, h_ack, h_req, b_ack, b_req };
always @(posedge gclk)
begin
out_data <= del_astrobe? h_sts : h_rptr[0]? mh_rdat[7:0] : mh_rdat[15:8];
end
endmodule