Skip to content

Commit

Permalink
ATari ST DMA rewritten
Browse files Browse the repository at this point in the history
git-svn-id: file:///Users/ces/dev/mist-subversion/trunk@762 8578a998-a533-420b-88ed-89baca3f5bf4
  • Loading branch information
till.harbaum@googlemail.com committed Jan 22, 2015
1 parent ead16ab commit 9231d71
Show file tree
Hide file tree
Showing 12 changed files with 1,307 additions and 644 deletions.
38 changes: 23 additions & 15 deletions cores/mist/acia.v
Original file line number Diff line number Diff line change
Expand Up @@ -97,37 +97,31 @@ reg ikbd_cpu_data_read;
reg [7:0] ikbd_cr;
reg [7:0] midi_cr;

reg [15:0] ikbd_rx_counter /* synthesis noprune */;

always @(negedge clk) begin
if(reset) begin
readTimer <= 14'd0;
ikbd_rx_counter <= 16'd0;
end else begin
if(readTimer > 0)
readTimer <= readTimer - 14'd1;

// read on ikbd data register
ikbd_cpu_data_read <= 1'b0;
if(sel && ~ds && rw && (addr == 2'd1)) begin
if(sel && ~ds && rw && (addr == 2'd1))
ikbd_cpu_data_read <= 1'b1;
ikbd_rx_counter <= ikbd_rx_counter + 16'd1;
end


if(ikbd_cpu_data_read && ikbd_rx_data_available) begin
// Some programs (e.g. bolo) need a pause between two ikbd bytes.
// The ikbd runs at 7812.5 bit/s 1 start + 8 data + 1 stop bit.
// One byte is 1/718.25 seconds. A pause of ~1ms is thus required
// 8000000/718.25 = 11138.18
// readTimer <= 14'd11138;
readTimer <= 14'd15000;
end
end
end

// ------------------ cpu interface --------------------

wire [7:0] ikbd_status = { ikbd_irq, 6'b000001, cpu_ikbd_rx_data_available};
wire [7:0] ikbd_rx_data;
wire ikbd_rx_data_available;

Expand All @@ -149,11 +143,11 @@ always @(sel, ds, rw, addr, ikbd_rx_data_available, ikbd_rx_data, ikbd_irq,

if(sel && ~ds && rw) begin
// keyboard acia read
if(addr == 2'd0) dout = { ikbd_irq, 6'b000001, cpu_ikbd_rx_data_available};
if(addr == 2'd0) dout = ikbd_status;
if(addr == 2'd1) dout = ikbd_rx_data;

// midi acia read
if(addr == 2'd2) dout = { midi_irq, 5'b00000, midi_tx_empty, midi_rx_data_available};
if(addr == 2'd2) dout = midi_status;
if(addr == 2'd3) dout = midi_rx_data;
end
end
Expand All @@ -162,6 +156,9 @@ end
wire midi_irq = (midi_cr[7] && midi_rx_data_available) || // rx irq
((midi_cr[6:5] == 2'b01) && midi_tx_empty); // tx irq

wire [7:0] midi_status = { midi_irq, 1'b0 /* parity err */, midi_rx_overrun, midi_rx_frame_error,
2'b00 /* CTS & DCD */, midi_tx_empty, midi_rx_data_available};

// MIDI runs at 31250bit/s which is exactly 1/256 of the 8Mhz system clock

// 8MHz/256 = 31250Hz -> MIDI bit rate
Expand All @@ -171,10 +168,11 @@ always @(posedge clk)

// --------------------------- midi receiver -----------------------------
reg [7:0] midi_rx_cnt; // bit + sub-bit counter
reg [8:0] midi_rx_shift_reg; // shift register used during reception
reg [7:0] midi_rx_shift_reg; // shift register used during reception
reg [7:0] midi_rx_data;
reg [3:0] midi_rx_filter; // filter to reduce noise
reg midi_rx_frame_error;
reg midi_rx_overrun;
reg midi_rx_data_available;
reg midi_in_filtered;

Expand All @@ -183,17 +181,23 @@ always @(negedge clk) begin
midi_rx_cnt <= 8'd0;
midi_rx_data_available <= 1'b0;
midi_rx_filter <= 4'b1111;
midi_rx_overrun <= 1'b0;
midi_rx_frame_error <= 1'b0;
end else begin

// read on midi data register
if(sel && ~ds && rw && (addr == 2'd3))
if(sel && ~ds && rw && (addr == 2'd3)) begin
midi_rx_data_available <= 1'b0; // read on midi data clears rx status
midi_rx_overrun <= 1'b0;
end

// midi acia master reset
if(midi_cr[1:0] == 2'b11) begin
midi_rx_cnt <= 8'd0;
midi_rx_data_available <= 1'b0;
midi_rx_filter <= 4'b1111;
midi_rx_overrun <= 1'b0;
midi_rx_frame_error <= 1'b0;
end

// 1/16 system clock == 16 times midi clock
Expand All @@ -218,20 +222,24 @@ always @(negedge clk) begin
// received a bit
if(midi_rx_cnt[3:0] == 4'd0) begin
// in the middle of the bit -> shift new bit into msb
midi_rx_shift_reg <= { midi_in_filtered, midi_rx_shift_reg[8:1] };
midi_rx_shift_reg <= { midi_in_filtered, midi_rx_shift_reg[7:1] };
end

// receiving last (stop) bit
if(midi_rx_cnt[7:0] == 8'd1) begin
if(midi_in_filtered == 1'b1) begin
// copy data into rx register
midi_rx_data <= midi_rx_shift_reg[8:1]; // pure data w/o start and stop bits
midi_rx_data <= midi_rx_shift_reg; // pure data w/o start and stop bits
midi_rx_data_available <= 1'b1;
midi_rx_frame_error <= 1'b0;
end else
// report frame error via status register
midi_rx_frame_error <= 1'b1;


// data hasn't been read yet? -> overrun
if(midi_rx_data_available)
midi_rx_overrun <= 1'b1;

end
end
end
Expand Down
120 changes: 120 additions & 0 deletions cores/mist/acsi.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// acsi.v
//
// Atari ST ACSI implementation for the MIST baord
// http://code.google.com/p/mist-board/
//
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

module acsi (
// clocks and system interface
input clk,
input reset,

input [7:0] enable,

input dma_ack, // IO controller answers request
input dma_nak, // IO controller rejects request
input [7:0] dma_status,


input [2:0] status_sel,
output [7:0] status_byte,

// cpu interface
input [1:0] cpu_addr,
input cpu_sel,
input cpu_rw,
input [7:0] cpu_din,
output [7:0] cpu_dout,

output reg irq
);

// acsi always returns dma status on cpu_read
assign cpu_dout = dma_status;

reg [2:0] target;
reg [4:0] cmd;
reg [2:0] byte_counter;
reg [7:0] cmd_parms [4:0];
reg busy;

// acsi status as reported to the io controller
assign status_byte =
(status_sel == 0)?{ target, cmd }:
(status_sel == 1)?cmd_parms[0]:
(status_sel == 2)?cmd_parms[1]:
(status_sel == 3)?cmd_parms[2]:
(status_sel == 4)?cmd_parms[3]:
(status_sel == 5)?cmd_parms[4]:
(status_sel == 6)?{ 7'b0000000, busy }:
8'h00;

// CPU write interface
always @(negedge clk) begin
if(reset) begin
target <= 3'd0;
cmd <= 5'd0;
irq <= 1'b0;
busy <= 1'b0;
end else begin

// DMA transfer has been ack'd by io controller
if(dma_ack && busy) begin
irq <= 1'b1; // set acsi irq
busy <= 1'd0;
end

// DMA transfer has been rejected by io controller (no such device)
if(dma_nak)
busy <= 1'd0;

// cpu is accessing acsi bus -> clear acsi irq
// status itself is returned by the io controller with the dma_ack.
if(cpu_sel)
irq <= 1'b0;

// acsi register access
if(cpu_sel && !cpu_rw) begin
if(!cpu_addr[0]) begin
// a0 == 0 -> first command byte
target <= cpu_din[7:5];
cmd <= cpu_din[4:0];
byte_counter <= 3'd0;

// check if this acsi device is enabled
if(enable[cpu_din[7:5]] == 1'b1)
irq <= 1'b1;
end else begin
// further bytes
cmd_parms[byte_counter] <= cpu_din[7:0];
byte_counter <= byte_counter + 3'd1;

// check if this acsi device is enabled
if(enable[target] == 1'b1) begin
// auto-ack first 5 bytes
if(byte_counter < 4)
irq <= 1'b1;
else
busy <= 1'b1; // request io cntroller
end
end
end
end
end

endmodule // acsi
Loading

0 comments on commit 9231d71

Please sign in to comment.