mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-16 20:30:54 +00:00
ACSI harddisk support
This commit is contained in:
@@ -12,11 +12,16 @@ module data_io (
|
||||
input ss,
|
||||
output sdo,
|
||||
|
||||
// dma interface
|
||||
// dma status interface
|
||||
output [4:0] dma_idx,
|
||||
input [7:0] dma_data,
|
||||
output reg dma_ack,
|
||||
|
||||
// acsi data interface
|
||||
input acsi_out_available,
|
||||
output reg acsi_out_strobe,
|
||||
input [9:0] acsi_out_data,
|
||||
|
||||
// ram interface
|
||||
output reg [2:0] state, // state bits required to drive the sdram host
|
||||
output [22:0] addr,
|
||||
@@ -67,7 +72,6 @@ reg [15:0] txData;
|
||||
assign sdo = txData[15];
|
||||
|
||||
always@(negedge sck) begin
|
||||
|
||||
// memory read
|
||||
if(cmd == 3) begin
|
||||
if(cnt == 8)
|
||||
@@ -83,6 +87,19 @@ always@(negedge sck) begin
|
||||
else
|
||||
txData[15:1] <= txData[14:0];
|
||||
end
|
||||
|
||||
// acsi daza read
|
||||
// send alternating "data available flag + address" and "data"
|
||||
if(cmd == 7) begin
|
||||
if(cnt == 8) begin
|
||||
txData[15:8] <= { 5'd0, acsi_out_data[9:8], acsi_out_available };
|
||||
acsi_out_strobe <= 1'b0;
|
||||
end else if(cnt == 16) begin
|
||||
txData[15:8] <= acsi_out_data[7:0];
|
||||
acsi_out_strobe <= 1'b1;
|
||||
end else
|
||||
txData[15:1] <= txData[14:0];
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge sck, posedge ss) begin
|
||||
|
||||
158
cores/mist/dma.v
158
cores/mist/dma.v
@@ -12,6 +12,7 @@ module dma (
|
||||
|
||||
// output to mfp
|
||||
output irq,
|
||||
output reg br,
|
||||
|
||||
// input from system config
|
||||
input fdc_wr_prot,
|
||||
@@ -21,6 +22,11 @@ module dma (
|
||||
output reg [7:0] dio_data,
|
||||
input dio_ack,
|
||||
|
||||
// interface to fifo for acsi commands
|
||||
output acsi_data_out_available,
|
||||
input acsi_strobe_out,
|
||||
output [9:0] acsi_data_out, // 2 bit a0/a1 + 8 bit data
|
||||
|
||||
// input from psg
|
||||
input drv_side,
|
||||
input [1:0] drv_sel
|
||||
@@ -33,23 +39,42 @@ always @(dio_idx, base, scnt, fdc_cmd, fdc_track, fdc_sector,
|
||||
dio_data = 8'h00;
|
||||
|
||||
case (dio_idx)
|
||||
// DMA status
|
||||
0: dio_data = base[23:16];
|
||||
1: dio_data = base[15:8];
|
||||
2: dio_data = base[7:0];
|
||||
3: dio_data = scnt;
|
||||
// FDC status
|
||||
4: dio_data = fdc_cmd;
|
||||
5: dio_data = fdc_track;
|
||||
6: dio_data = fdc_sector;
|
||||
7: dio_data = fdc_data;
|
||||
8: dio_data = { 4'b0000, drv_sel, drv_side, fdc_busy };
|
||||
8: dio_data = { 3'b000, acsi_busy, drv_sel, drv_side, fdc_busy != 0 };
|
||||
// ACSI status
|
||||
9: dio_data = { acsi_target, acsi_cmd };
|
||||
10: dio_data = acsi_cmd_parms[0];
|
||||
11: dio_data = acsi_cmd_parms[1];
|
||||
12: dio_data = acsi_cmd_parms[2];
|
||||
13: dio_data = acsi_cmd_parms[3];
|
||||
14: dio_data = acsi_cmd_parms[4];
|
||||
|
||||
default: dio_data = 8'h00;
|
||||
endcase
|
||||
end
|
||||
// ------------------ cpu interface --------------------
|
||||
|
||||
reg fdc_busy;
|
||||
// fdc_busy is a counter. counts down from 2 to 0. stays at 3 since that
|
||||
// means that the fdc is waiting for the arm io controller
|
||||
reg [1:0] fdc_busy;
|
||||
|
||||
assign irq = !fdc_busy;
|
||||
// route FDC or ACSI irq out on irq pin
|
||||
assign irq = fdc_irq || acsi_irq;
|
||||
|
||||
// fdc irq is set at end of busy phase and cleared by fdc status register read
|
||||
reg fdc_irq;
|
||||
|
||||
// detect cpu read access on fdc status register (4:4 == 00 -> fdc controller access)
|
||||
wire fdc_status_read = sel && rw && (addr == 3'h2) && (mode[4:3] == 2'b00);
|
||||
|
||||
reg [15:0] mode;
|
||||
|
||||
@@ -73,7 +98,7 @@ reg step_dir;
|
||||
wire [7:0] fdc_status;
|
||||
assign fdc_status = {
|
||||
!(motor_on == 0), fdc_wr_prot, 3'b000,
|
||||
(fdc_cmd[7]==1'b0)?track0:1'b0, 1'b0, fdc_busy };
|
||||
(fdc_cmd[7]==1'b0)?track0:1'b0, 1'b0, fdc_busy != 0 };
|
||||
|
||||
wire [15:0] dma_status;
|
||||
assign dma_status = { 14'd0, !(scnt == 0), 1'b1 }; // bit 0 = 1: DMA_OK
|
||||
@@ -82,7 +107,7 @@ assign dma_status = { 14'd0, !(scnt == 0), 1'b1 }; // bit 0 = 1: DMA_OK
|
||||
reg [15:0] motor_on;
|
||||
|
||||
always @(sel, rw, addr, mode, base, fdc_data, fdc_sector, fdc_status, fdc_track,
|
||||
dma_status, scnt) begin
|
||||
dma_status, scnt, acsi_target) begin
|
||||
dout = 16'h0000;
|
||||
|
||||
if(sel && rw) begin
|
||||
@@ -99,6 +124,10 @@ always @(sel, rw, addr, mode, base, fdc_data, fdc_sector, fdc_status, fdc_track,
|
||||
if(mode[2:1] == 2'b11) // data register
|
||||
dout = { 8'h00, fdc_data };
|
||||
end
|
||||
if(mode[3] == 1'b1) begin
|
||||
// acsi status register [3]==1 -> BUSY
|
||||
dout = { 8'h00, acsi_target, 5'h00 }; // status "ok"
|
||||
end
|
||||
end
|
||||
|
||||
if(addr == 3'h3)
|
||||
@@ -117,11 +146,43 @@ always @(sel, rw, addr, mode, base, fdc_data, fdc_sector, fdc_status, fdc_track,
|
||||
dout = { 8'h00, base[7:0] };
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// -------------- fifo to send acsi data to io controller -------------
|
||||
assign acsi_data_out_available = (readPout != writePout);
|
||||
assign acsi_data_out = fifoOut[readPout];
|
||||
|
||||
localparam FIFO_ADDR_BITS = 8;
|
||||
localparam FIFO_DEPTH = (1 << FIFO_ADDR_BITS);
|
||||
reg [9:0] fifoOut [FIFO_DEPTH-1:0];
|
||||
reg [FIFO_ADDR_BITS-1:0] writePout, readPout;
|
||||
|
||||
reg acsi_strobe_outD, acsi_strobe_outD2;
|
||||
always @(posedge clk) begin
|
||||
acsi_strobe_outD <= acsi_strobe_out;
|
||||
acsi_strobe_outD2 <= acsi_strobe_outD;
|
||||
|
||||
if(reset)
|
||||
readPout <= 0;
|
||||
else
|
||||
if(acsi_strobe_outD && !acsi_strobe_outD2)
|
||||
readPout <= readPout + 8'd1;
|
||||
end
|
||||
|
||||
// --------------- acsi handling --------------------
|
||||
reg [2:0] acsi_target;
|
||||
reg [4:0] acsi_cmd;
|
||||
reg [2:0] acsi_byte_counter;
|
||||
reg [7:0] acsi_cmd_parms [4:0];
|
||||
reg acsi_busy;
|
||||
reg acsi_irq;
|
||||
|
||||
// acsi status register is read (clears interrupt)
|
||||
wire acsi_status_read = sel && rw && (mode[4:3] == 2'b01);
|
||||
|
||||
reg dio_ackD, dio_ackD2;
|
||||
always @(posedge clk)
|
||||
dio_ackD <= dio_ack;
|
||||
|
||||
|
||||
always @(negedge clk) begin
|
||||
if(reset) begin
|
||||
mode <= 16'd0;
|
||||
@@ -131,16 +192,51 @@ always @(negedge clk) begin
|
||||
fdc_data <= 8'd0;
|
||||
base <= 24'h000000;
|
||||
scnt <= 8'h00;
|
||||
fdc_busy <= 1'b0;
|
||||
fdc_busy <= 2'd0;
|
||||
motor_on <= 16'd0;
|
||||
writePout <= 0;
|
||||
fdc_irq <= 1'b0;
|
||||
acsi_target <= 3'd0;
|
||||
acsi_cmd <= 5'd0;
|
||||
acsi_irq <= 1'b0;
|
||||
acsi_busy <= 1'b0;
|
||||
br <= 1'b0;
|
||||
end else begin
|
||||
// acknowledge comes from io controller
|
||||
// rising edge on ack -> clear busy flag
|
||||
dio_ackD2 <= dio_ackD;
|
||||
if(dio_ackD && !dio_ackD2) begin
|
||||
br <= 1'b0; // release bus
|
||||
scnt <= 8'h00; // all sectors transmitted
|
||||
fdc_busy <= 1'b0;
|
||||
|
||||
// fdc_busy == 3 -> fdc waiting for io controller
|
||||
if(fdc_busy == 3)
|
||||
fdc_busy <= 2'd1; // jump to end of busy phase
|
||||
|
||||
// acsi_busy -> acsi waiting for io controller
|
||||
if(acsi_busy) begin
|
||||
acsi_irq <= 1'b1; // set acsi irq
|
||||
acsi_busy <= 1'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// fdc is ending busy phase
|
||||
if(fdc_busy == 1)
|
||||
fdc_irq <= 1'b1;
|
||||
|
||||
// cpu is reading status register -> clear fdc irq
|
||||
if(fdc_status_read)
|
||||
fdc_irq <= 1'b0;
|
||||
|
||||
// cpu is reading status register -> clear fdc irq
|
||||
if(acsi_status_read)
|
||||
acsi_irq <= 1'b0;
|
||||
|
||||
// if fdc is busy (==0), but not blocked by io controller (==15)
|
||||
// then count it down
|
||||
if((fdc_busy != 0) && (fdc_busy != 3))
|
||||
fdc_busy <= fdc_busy - 2'd1;
|
||||
|
||||
// let "motor" run for some time
|
||||
if(motor_on != 0)
|
||||
motor_on <= motor_on - 16'd1;
|
||||
@@ -152,6 +248,7 @@ always @(negedge clk) begin
|
||||
if(mode[3] == 1'b0) begin
|
||||
// fdc register write
|
||||
if(mode[2:1] == 2'b00) begin // command register
|
||||
fdc_busy <= 2'd2;
|
||||
fdc_cmd <= din[7:0];
|
||||
|
||||
// all TYPE I and TYPE II commands start the motor
|
||||
@@ -185,28 +282,28 @@ always @(negedge clk) begin
|
||||
|
||||
// ------------- TYPE II commands -------------
|
||||
if(din[7:5] == 3'b100) // read sector
|
||||
fdc_busy <= 1'b1;
|
||||
fdc_busy <= 2'd3;
|
||||
|
||||
if(din[7:5] == 3'b101) // write sector
|
||||
if(!fdc_wr_prot)
|
||||
fdc_busy <= 1'b1;
|
||||
fdc_busy <= 2'd3;
|
||||
|
||||
// ------------- TYPE III commands ------------
|
||||
|
||||
// these aren't supported yet
|
||||
// if(din[7:4] == 4'b1100) // read address
|
||||
// fdc_busy <= 1'b1;
|
||||
// fdc_busy <= 2'd3;
|
||||
|
||||
// if(din[7:4] == 4'b1110) // read track
|
||||
// fdc_busy <= 1'b1;
|
||||
// fdc_busy <= 2'd3;
|
||||
|
||||
// if(din[7:4] == 4'b1111) // write track
|
||||
// if(!fdc_wr_prot)
|
||||
// fdc_busy <= 1'b1;
|
||||
// fdc_busy <= 2'd3;
|
||||
|
||||
// ------------- TYPE IV commands -------------
|
||||
if(din[7:4] == 4'b1101) // force intrerupt
|
||||
fdc_busy <= 1'b0;
|
||||
fdc_busy <= 2'd1;
|
||||
|
||||
end if(mode[2:1] == 2'b01) // track register
|
||||
fdc_track <= din[7:0];
|
||||
@@ -214,6 +311,37 @@ always @(negedge clk) begin
|
||||
fdc_sector <= din[7:0];
|
||||
if(mode[2:1] == 2'b11) // data register
|
||||
fdc_data <= din[7:0];
|
||||
end else begin
|
||||
// acsi register access
|
||||
if(!mode[1]) begin
|
||||
// mode[1] == 0 -> first command byte
|
||||
acsi_target <= din[7:5];
|
||||
acsi_cmd <= din[4:0];
|
||||
acsi_byte_counter <= 3'd0;
|
||||
|
||||
// only acsi 0 is supported
|
||||
if(din[7:5] == 3'd0)
|
||||
acsi_irq <= 1'b1;
|
||||
end else begin
|
||||
// further bytes
|
||||
acsi_cmd_parms[acsi_byte_counter] <= din[7:0];
|
||||
acsi_byte_counter <= acsi_byte_counter + 3'd1;
|
||||
|
||||
// only acsi 0 is supported
|
||||
if(acsi_target == 3'd0) begin
|
||||
// auto-ack first 5 bytes
|
||||
if(acsi_byte_counter < 4)
|
||||
acsi_irq <= 1'b1;
|
||||
else begin
|
||||
br <= 1'b1; // request bus
|
||||
acsi_busy <= 1'b1; // request io cntroller
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// acsi: write data in output buffer
|
||||
fifoOut[writePout] <= { mode[2:1], din[7:0] };
|
||||
writePout <= writePout + 8'd1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -58,7 +58,26 @@ wire io_dtack = vreg_sel || mmu_sel || mfp_sel || mfp_iack ||
|
||||
// TOS versions cope with that, TOS versions with blitter support need this to work as this is
|
||||
// required to properly detect that a blitter is not present.
|
||||
// a bus error is now generated once no dtack is seen for 63 clock cycles.
|
||||
wire tg68_berr = (dtack_timeout == 6'd63); // || cpu_write_illegal;
|
||||
wire tg68_berr = (dtack_timeout == 5'd31); // || cpu_write_illegal;
|
||||
|
||||
// count bus errors for debugging purposes. we can thus trigger for a
|
||||
// certain bus error
|
||||
reg [3:0] berr_cnt_out;
|
||||
reg [3:0] berr_cnt;
|
||||
always @(posedge clk_8) begin
|
||||
if(reset) begin
|
||||
berr_cnt <= 4'd0;
|
||||
end else begin
|
||||
berr_cnt_out <= 4'd0;
|
||||
if(tg68_berr) begin
|
||||
berr_cnt_out <= berr_cnt + 4'd1;
|
||||
berr_cnt <= berr_cnt + 4'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// the following is just to prevent optimization
|
||||
assign UART_TX = (berr_cnt_out == 4'd0);
|
||||
|
||||
wire cpu_write = cpu_cycle && cpu2io && data_strobe && !tg68_rw;
|
||||
|
||||
@@ -67,18 +86,24 @@ wire cpu_write = cpu_cycle && cpu2io && data_strobe && !tg68_rw;
|
||||
wire cpu_write_illegal = cpu_write &&
|
||||
(tg68_adr[23:3] === 21'd0); // the first two long words $0 and $4
|
||||
|
||||
reg [5:0] dtack_timeout;
|
||||
|
||||
reg [4:0] dtack_timeout;
|
||||
always @(posedge clk_8) begin
|
||||
if(reset) begin
|
||||
dtack_timeout <= 6'd0;
|
||||
dtack_timeout <= 5'd0;
|
||||
end else begin
|
||||
if(!tg68_dtack)
|
||||
dtack_timeout <= 6'd0;
|
||||
else if(dtack_timeout != 6'd63)
|
||||
dtack_timeout <= dtack_timeout + 6'd1;
|
||||
if(!tg68_dtack || br)
|
||||
dtack_timeout <= 5'd0;
|
||||
else if(dtack_timeout != 5'd31)
|
||||
dtack_timeout <= dtack_timeout + 5'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// no tristate busses exist inside the FPGA. so bus request doesn't do
|
||||
// much more than halting the cpu by suppressing dtack
|
||||
wire br = dma_br; // dma is only other bus master (yet)
|
||||
wire dma_br;
|
||||
|
||||
// request interrupt ack from mfp for IPL == 6
|
||||
wire mfp_iack;
|
||||
assign mfp_iack = cpu_cycle && cpu2iack && data_strobe && (tg68_adr[3:1] == 3'b110);
|
||||
@@ -293,6 +318,11 @@ wire [7:0 ]dma_dio_data;
|
||||
// floppy_sel is active low
|
||||
wire wr_prot = (floppy_sel == 2'b01)?system_ctrl[7]:system_ctrl[6];
|
||||
|
||||
// acsi interface
|
||||
wire data_from_acsi_available;
|
||||
wire strobe_from_acsi;
|
||||
wire [9:0] data_from_acsi;
|
||||
|
||||
dma dma (
|
||||
// cpu interface
|
||||
.clk (clk_8 ),
|
||||
@@ -306,6 +336,7 @@ dma dma (
|
||||
.dout (dma_data_out),
|
||||
|
||||
.irq (dma_irq ),
|
||||
.br (dma_br ),
|
||||
|
||||
// system control interface
|
||||
.fdc_wr_prot (wr_prot),
|
||||
@@ -315,6 +346,11 @@ dma dma (
|
||||
.dio_data (dma_dio_data),
|
||||
.dio_ack (dma_dio_ack ),
|
||||
|
||||
// acsi interface
|
||||
.acsi_data_out_available (data_from_acsi_available),
|
||||
.acsi_strobe_out (strobe_from_acsi),
|
||||
.acsi_data_out (data_from_acsi),
|
||||
|
||||
// floppy interface
|
||||
.drv_sel (floppy_sel ),
|
||||
.drv_side (floppy_side )
|
||||
@@ -543,7 +579,7 @@ wire data_strobe;
|
||||
assign data_strobe = ~tg68_uds || ~tg68_lds;
|
||||
|
||||
// generate dtack (for st ram only and rom), TODO: no dtack for rom write
|
||||
assign tg68_dtack = ~((cpu2mem && data_strobe && cpu_cycle) || io_dtack );
|
||||
assign tg68_dtack = ~(((cpu2mem && data_strobe && cpu_cycle) || io_dtack ) && !br);
|
||||
|
||||
wire ram_oe;
|
||||
assign ram_oe = video_cycle?~video_read:
|
||||
@@ -668,11 +704,16 @@ data_io data_io (
|
||||
.ss (SPI_SS2 ),
|
||||
.sdo (data_io_sdo ),
|
||||
|
||||
// dma interface
|
||||
// dma status interface
|
||||
.dma_idx (dma_dio_idx ),
|
||||
.dma_data (dma_dio_data ),
|
||||
.dma_ack (dma_dio_ack ),
|
||||
|
||||
// acsi interface
|
||||
.acsi_out_available (data_from_acsi_available ),
|
||||
.acsi_out_strobe (strobe_from_acsi ),
|
||||
.acsi_out_data (data_from_acsi ),
|
||||
|
||||
// ram interface
|
||||
.state (host_state ),
|
||||
.addr (host_addr ),
|
||||
|
||||
Reference in New Issue
Block a user