`timescale 1ns / 100ps /* * IWM module for minimigmac. * * Location to Location to * IWM line turn line on turn line off * * Disk state-control lines: * CA0 dBase+ph0H dBase+ph0L * CA1 dBase+ph1H dBase+ph1L * CA2 dBase+ph2H dBase+ph2L * LSTRB dBase+ph3H dBase+ph3L * * Disk enable line: * ENABLE dBase+motorOn dBase+motorOff * * IWM internal states: * SELECT dBase+extDrive dBase+intDrive * Q6 dBase+q6H dBase+q6L * Q7 dBase+q7H dBase+q7L * * ph0L .EQU 512*0 ;CA0 off (0) * ph0H .EQU 512*1 ;CA0 on (1) * ph1L .EQU 512*2 ;CA1 off (0) * ph1H .EQU 512*3 ;CA1 on (1) * ph2L .EQU 512*4 ;CA2 off (0) * ph2H .EQU 512*5 ;CA2 on (1) * ph3L .EQU 512*6 ;LSTRB off (low) * ph3H .EQU 512*7 ;LSTRB on (high) * mtrOff .EQU 512*8 ;disk enable off * mtrOn .EQU 512*9 ;disk enable on * intDrive .EQU 512*10 ;select internal drive * extDrive .EQU 512*11 ;select external drive * q6L .EQU 512*12 ;Q6 off * q6H .EQU 512*13 ;Q6 on * q7L .EQU 512*14 ;Q7 off * q7H .EQU 512*15 ;Q7 on */ `define IWM_REG_ph0L 0 `define IWM_REG_ph0H 1 `define IWM_REG_ph1L 2 `define IWM_REG_ph1H 3 `define IWM_REG_ph2L 4 `define IWM_REG_ph2H 5 `define IWM_REG_ph3L 6 `define IWM_REG_ph3H 7 `define IWM_REG_mtrOff 8 `define IWM_REG_mtrOn 9 `define IWM_REG_intDrive 10 `define IWM_REG_extDrive 11 `define IWM_REG_q6L 12 `define IWM_REG_q6H 13 `define IWM_REG_q7L 14 `define IWM_REG_q7H 15 module iwm(input sysclk, input reset, /* Bus interface. 4-bit address, to be wired * appropriately upstream (to A9..A12) */ input cs, input we, output ack, input phase, input [3:0] rs, input [7:0] wdata, output [7:0] rdata, /* Backbus interface */ input [5:0] bb_addr, input [7:0] bb_wdata, output reg [7:0] bb_rdata, input bb_strobe, input bb_wr, /* SEL line from VIA */ input via_sel ); /* IWM state register broken up by name */ reg CA0; reg CA1; reg CA2; reg LSTRB; reg ENABLE; reg SELECT; reg Q6; reg Q7; /* Internal wires */ wire new_Q6; wire new_Q7; wire new_EN; wire reg_wr; /* Internal data & mode registers */ reg [7:0] data_reg; reg [4:0] mode_reg; /* Status and write handshake are just wires */ wire [7:0] stat_reg; wire [7:0] whsk_reg; /* Sense line from disk */ wire sense; /* enbl1 and enbl2 lines (not inverted here unlike real HW) */ reg enbl1; reg enbl2; /* Disk register definitions */ wire [3:0] diskreg_sel; `define DISK_REG_DIRTN 0 /* R/W: step direction */ `define DISK_REG_CSTIN 1 /* R: disk in place (1 = no disk) */ /* W: ?? reset disk switch flag ? */ `define DISK_REG_STEP 2 /* R: disk stepping (1 = complete) */ /* W: 0 = step disk */ `define DISK_REG_WRTPRT 3 /* R: 0 = disk is write-protected */ `define DISK_REG_MOTORON 4 /* R/W: 0 = motor on */ `define DISK_REG_TK0 5 /* R: 0 = head at track 0 */ `define DISK_REG_EJECT 6 /* R: disk switched */ /* W: 1 = eject disk */ `define DISK_REG_TACH 7 /* R: tach-o-meter */ `define DISK_REG_RDDATA0 8 /* R: lower head activate */ `define DISK_REG_RDDATA9 9 /* R: upper head activate */ `define DISK_REG_SIDES 12 /* R: number of sides (0=single, 1=dbl) */ `define DISK_REG_READY 13 /* R: disk ready (head loaded) (0=ready) */ `define DISK_REG_INSTALLED 14 /* R: drive present (0 = yes) */ `define DISK_REG_DRVIN 15 /* R: drive present (0=yes, 1=no) XXX HD ?*/ /* Toggle control lines */ always@(posedge reset or posedge sysclk) begin if (reset) begin CA0 <= 0; CA1 <= 0; CA2 <= 0; LSTRB <= 0; ENABLE <= 0; SELECT <= 0; Q6 <= 0; Q7 <= 0; end else if (cs && phase) begin case(rs[3:1]) 0: CA0 <= rs[0]; 1: CA1 <= rs[0]; 2: CA2 <= rs[0]; 3: LSTRB <= rs[0]; 4: ENABLE <= rs[0]; 5: SELECT <= rs[0]; 6: Q6 <= rs[0]; 7: Q7 <= rs[0]; endcase end end /* ENBL1/2 lines. XXX We don't do the 1 second timer yet * but I don't think the Mac ROM uses it anyways */ always@(posedge reset or posedge sysclk) begin if (reset) begin enbl1 <= 0; enbl2 <= 0; end else begin if (cs && phase && rs[3:1] == 4) begin if (SELECT) enbl2 <= rs[0]; else enbl1 <= rs[0]; end end end /* Now for register read/writes, we need to use * the "new" value of Q6, Q7 and ENABLE in the same * cycle. We hack that up here. */ assign new_Q6 = (cs && rs[3:1] == 6) ? rs[0] : Q6; assign new_Q7 = (cs && rs[3:1] == 7) ? rs[0] : Q7; assign new_EN = (cs && rs[3:1] == 4) ? rs[0] : ENABLE; assign reg_wr = cs & phase & new_Q6 & new_Q7 & rs[0]; /* Internal register reads */ assign rdata = (!new_Q7 && !new_Q6 && new_EN) ? data_reg : (!new_Q7 && new_Q6) ? stat_reg : ( new_Q7 && !new_Q6) ? whsk_reg : 8'hff; /* Internal write to mode register */ always@(posedge reset or posedge sysclk) begin if (reset) mode_reg <= 0; else if (reg_wr && !ENABLE) mode_reg <= wdata[4:0]; end /* Make up status and write handshake register wires */ assign stat_reg = { sense, 1'b0, enbl1 | enbl2, mode_reg[4:0] }; assign whsk_reg = 8'b11000000; /* XXX fixme */ /* Disk register reads */ // assign diskreg_idx = { CA2, CA1, CA0, via_sel }; // assign sense = diskregs = SELECT ? diskreg_b[diskreg_idx] : // diskreg_a[diskreg_idx]; assign sense = 1'b1; /* Test values for disk regs */ always@(posedge reset or posedge sysclk) begin if (reset) begin // diskregs[0] <= 16'b1001_1100_0001_0110; // diskregs[1] <= 16'b1111_1111_1111_1111; end end /* For now always ack immediately, we'll change that * eventually when we have something with real data */ assign ack = cs; endmodule