MacPlus_MiSTer/rtl/ncr5380.sv

303 lines
8.1 KiB
Systemverilog

/* verilator lint_off UNUSED */
/* based on minimigmac by Benjamin Herrenschmidt */
/* Read registers */
`define RREG_CDR 3'h0 /* Current SCSI data */
`define RREG_ICR 3'h1 /* Initiator Command */
`define RREG_MR 3'h2 /* Mode register */
`define RREG_TCR 3'h3 /* Target Command */
`define RREG_CSR 3'h4 /* SCSI bus status */
`define RREG_BSR 3'h5 /* Bus and status */
`define RREG_IDR 3'h6 /* Input data */
`define RREG_RST 3'h7 /* Reset */
/* Write registers */
`define WREG_ODR 3'h0 /* Output data */
`define WREG_ICR 3'h1 /* Initiator Command */
`define WREG_MR 3'h2 /* Mode register */
`define WREG_TCR 3'h3 /* Target Command */
`define WREG_SER 3'h4 /* Select Enable */
`define WREG_DMAS 3'h5 /* Start DMA Send */
`define WREG_DMATR 3'h6 /* Start DMA Target receive */
`define WREG_IDMAR 3'h7 /* Start DMA Initiator receive */
/* MR bit numbers */
`define MR_DMA_MODE 1
`define MR_ARB 0
/* ICR bit numbers */
`define ICR_A_RST 7
`define ICR_TEST_MODE 6
`define ICR_DIFF_ENBL 5
`define ICR_A_ACK 4
`define ICR_A_BSY 3
`define ICR_A_SEL 2
`define ICR_A_ATN 1
`define ICR_A_DATA 0
/* TCR bit numbers */
`define TCR_A_REQ 3
`define TCR_A_MSG 2
`define TCR_A_CD 1
`define TCR_A_IO 0
module ncr5380
(
input clk,
input reset,
/* Bus interface. 3-bit address, to be wired
* appropriately upstream (to A4..A6) plus one
* more bit (A9) wired as dack.
*/
input bus_cs,
input [2:0] bus_rs,
input ior,
input iow,
input dack,
output dreq,
input [7:0] wdata,
output [7:0] rdata,
// connections to io controller
input [DEVS-1:0] img_mounted,
input [31:0] img_size,
output reg [31:0] io_lba[DEVS],
output [DEVS-1:0] io_rd,
output [DEVS-1:0] io_wr,
input [DEVS-1:0] io_ack,
input [7:0] sd_buff_addr,
input [15:0] sd_buff_dout,
output [15:0] sd_buff_din[DEVS],
input sd_buff_wr
);
parameter DEVS = 2;
assign dreq = scsi_req & dma_en;
reg [7:0] mr; /* Mode Register */
reg [7:0] icr; /* Initiator Command Register */
reg [3:0] tcr; /* Target Command Register */
wire [7:0] csr; /* SCSI bus status register */
/* Data in and out latches and associated
* control logic for DMA
*/
reg [7:0] din;
reg [7:0] dout;
reg dma_en;
/* --- Main host-side interface --- */
/* Register & DMA accesses decodes */
reg dma_wr;
reg reg_wr;
reg dma_ack;
wire i_dma_rd = bus_cs & dack & ior;
wire i_dma_wr = bus_cs & dack & iow;
wire i_reg_wr = bus_cs & ~dack & iow;
always @(posedge clk) begin
reg old_dma_rd, old_dma_wr, old_reg_wr;
old_dma_rd <= i_dma_rd;
old_dma_wr <= i_dma_wr;
old_reg_wr <= i_reg_wr;
dma_wr <= 0;
dma_ack <= 0;
reg_wr <= 0;
if(~old_dma_wr & i_dma_wr) dma_wr <= 1;
if(~old_reg_wr & i_reg_wr) reg_wr <= 1;
if((old_dma_wr & ~i_dma_wr) | (old_dma_rd & ~i_dma_rd)) dma_ack <= dma_en;
end
/* System bus reads */
assign rdata = dack ? cur_data :
bus_rs == `RREG_CDR ? cur_data :
bus_rs == `RREG_ICR ? icr_read :
bus_rs == `RREG_MR ? mr :
bus_rs == `RREG_TCR ? { 4'h0, tcr } :
bus_rs == `RREG_CSR ? csr :
bus_rs == `RREG_BSR ? bsr :
bus_rs == `RREG_IDR ? cur_data :
bus_rs == `RREG_RST ? 8'hff :
8'hff;
/* Data out latch (in DMA mode, this is one cycle after we've
* asserted ACK)
*/
always@(posedge clk) if((reg_wr && bus_rs == `WREG_ODR) || dma_wr) dout <= wdata;
/* Current data register. Simplified logic: We loop back the
* output data if we are asserting the bus, else we get the
* input latch
*/
wire [7:0] cur_data = out_en ? dout : din;
/* Logic for "asserting the bus" simplified */
wire out_en = icr[`ICR_A_DATA] | mr[`MR_ARB];
/* ICR read wires */
wire [7:0] icr_read = { icr[`ICR_A_RST],
icr_aip,
icr_la,
icr[`ICR_A_ACK],
icr[`ICR_A_BSY],
icr[`ICR_A_SEL],
icr[`ICR_A_ATN],
icr[`ICR_A_DATA] };
/* ICR write */
always@(posedge clk or posedge reset) begin
if (reset) begin
icr <= 0;
end else if (reg_wr && (bus_rs == `WREG_ICR)) begin
icr <= wdata;
end
end
/* MR write */
always@(posedge clk or posedge reset) begin
if (reset) mr <= 8'b0;
else if (reg_wr && (bus_rs == `WREG_MR)) mr <= wdata;
end
/* TCR write */
always@(posedge clk or posedge reset) begin
if (reset) tcr <= 4'b0;
else if (reg_wr && (bus_rs == `WREG_TCR)) tcr <= wdata[3:0];
end
/* DMA start send & receive registers. We currently ignore
* the direction.
*/
always@(posedge clk or posedge reset) begin
if (reset) begin
dma_en <= 0;
end else begin
if (!mr[`MR_DMA_MODE]) begin
dma_en <= 0;
end else if (reg_wr && (bus_rs == `WREG_DMAS)) begin
dma_en <= 1;
end else if (reg_wr && (bus_rs == `WREG_IDMAR)) begin
dma_en <= 1;
end
end
end
/* CSR (read only). We don't do parity */
assign csr = { scsi_rst, scsi_bsy, scsi_req, scsi_msg,
scsi_cd, scsi_io, scsi_sel, 1'b0 };
/* Bus and Status register */
/* BSR (read only). We don't do a few things... */
wire bsr_eodma = 1'b0; /* We don't do EOP */
wire bsr_dmarq = scsi_req & dma_en;
wire bsr_perr = 1'b0; /* We don't do parity */
wire bsr_irq = 1'b0; /* XXX ? Does MacOS use this ? */
wire bsr_pmatch =
tcr[`TCR_A_MSG] == scsi_msg &&
tcr[`TCR_A_CD ] == scsi_cd &&
tcr[`TCR_A_IO ] == scsi_io;
wire bsr_berr = 1'b0; /* XXX ? Does MacOS use this ? */
wire [7:0] bsr = { bsr_eodma, bsr_dmarq, bsr_perr, bsr_irq,
bsr_pmatch, bsr_berr, scsi_atn, scsi_ack };
/* --- Simulated SCSI Signals --- */
/* BSY logic (simplified arbitration, see notes) */
wire scsi_bsy =
icr[`ICR_A_BSY] |
|target_bsy |
//scsi2_bsy |
//scsi6_bsy |
mr[`MR_ARB];
/* Remains of simplified arbitration logic */
wire icr_aip = mr[`MR_ARB];
wire icr_la = 0;
/* Other ORed SCSI signals */
wire scsi_sel = icr[`ICR_A_SEL];
wire scsi_rst = icr[`ICR_A_RST];
wire scsi_ack = icr[`ICR_A_ACK] | dma_ack;
wire scsi_atn = icr[`ICR_A_ATN];
/* Mux target signals */
reg scsi_cd, scsi_io, scsi_msg, scsi_req;
always begin
integer i;
scsi_cd = 0;
scsi_io = 0;
scsi_msg = 0;
scsi_req = 0;
din = 8'h55;
for (i = 0; i < DEVS; i = i + 1) begin
if (target_bsy[i]) begin
scsi_cd = target_cd[i];
scsi_io = target_io[i];
scsi_msg = target_msg[i];
scsi_req = target_req[i];
din = target_dout[i];
end
end
end
// input signals from targets
wire [DEVS-1:0] target_bsy;
wire [DEVS-1:0] target_msg;
wire [DEVS-1:0] target_io;
wire [DEVS-1:0] target_cd;
wire [DEVS-1:0] target_req;
wire [7:0] target_dout[DEVS];
generate
genvar i;
for (i = 0; i < DEVS; i = i + 1) begin : target
// connect a target
scsi #(.ID(3'd6 - i[2:0])) target
(
.clk ( clk ),
.rst ( scsi_rst ),
.sel ( scsi_sel ),
.atn ( scsi_atn ),
.ack ( scsi_ack ),
.bsy ( target_bsy[i] ),
.msg ( target_msg[i] ),
.cd ( target_cd[i] ),
.io ( target_io[i] ),
.req ( target_req[i] ),
.dout ( target_dout[i] ),
.din ( dout ),
// connection to io controller to read and write sectors
// to sd card
.img_mounted(img_mounted[i]),
.img_blocks(img_size),
.io_lba ( io_lba[i] ),
.io_rd ( io_rd[i] ),
.io_wr ( io_wr[i] ),
.io_ack ( io_ack[i] & target_bsy[i] ),
.sd_buff_addr( sd_buff_addr ),
.sd_buff_dout( sd_buff_dout ),
.sd_buff_din( sd_buff_din[i] ),
.sd_buff_wr( sd_buff_wr & target_bsy[i] )
);
end
endgenerate
endmodule