1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-01-27 12:21:44 +00:00

ATari ST DMA rewritten

This commit is contained in:
harbaum
2015-01-22 07:46:09 +00:00
parent f08d07244d
commit c861c7072e
12 changed files with 1296 additions and 633 deletions

View File

@@ -97,30 +97,23 @@ 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
@@ -128,6 +121,7 @@ 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;
@@ -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
@@ -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
@@ -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;
@@ -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
@@ -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

120
cores/mist/acsi.v Normal file
View File

@@ -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

View File

@@ -1,199 +0,0 @@
// SPI data client (rom, floppy, harddisk io)
module data_io (
// clocks
input clk_8,
input reset,
input [1:0] bus_cycle,
output reg [31:0] ctrl_out,
// spi interface
input sdi,
input sck,
input ss,
output sdo,
// dma status interface
output [4:0] dma_idx,
input [7:0] dma_data,
output reg dma_ack,
output reg br,
// horizontal and vertical screen adjustments
output reg [15:0] video_adj,
// ram interface
output reg read,
output reg write,
output [22:0] addr,
output reg [15:0] data_out, // write data register
input [15:0] data_in
);
assign dma_idx = bcnt;
reg [4:0] cnt; // bit counter (counting spi bits, rolling from 23 to 8)
reg [4:0] bcnt; // payload byte counter
reg [14:0] sbuf; // receive buffer (buffer used to assemble spi bytes/words)
reg [7:0] cmd; // command byte (first byte of spi transmission)
reg [30:0] addrR;// address register (word address for memory transfers)
reg writeCmd; // write request received via SPI
reg writeD; // write synchonized to 8Mhz clock
reg writeD2; // synchronized write delayed by one 8Mhz clock
reg readCmd; // read request received via SPI
reg readD; // read synchonized to 8Mhz clock
reg readD2; // synchronized read delayed by one 8Mhz clock
reg [15:0] ram_data; // latch for incoming ram data
reg brI; // signals to bring br into local clock domain
// during write the address needs to be decremented by one as the
// address auto increment takes place at the beginning of each transfer
assign addr = (cmd==2)?(addrR[22:0]-23'd1):addrR[22:0];
// latch bus cycle to have it stable at the end of the cycle (rising edge of clk8)
reg [1:0] bus_cycle_L;
always @(negedge clk_8) begin
bus_cycle_L <= bus_cycle;
if(bus_cycle == 0)
br <= brI;
end
// generate state signals required to control the sdram host interface
always @(posedge clk_8) begin
// start io transfers clock cycles after bus_cycle 0
// (after the cpu cycle)
writeD <= writeCmd && ((bus_cycle_L == 3) || writeD);
writeD2 <= writeD;
readD <= readCmd && ((bus_cycle_L == 3) || readD);
readD2 <= readD;
// at the end of a read cycle latch the incoming ram data for later spi transmission
if(read) ram_data <= data_in;
if(reset) begin
read <= 1'b0;
write <= 1'b0;
end else begin
if(writeD && ~writeD2) begin
write <= 1'b1;
read <= 1'b0;
end else if(readD && ~readD2) begin
write <= 1'b0;
read <= 1'b1;
end else begin
write <= 1'b0;
read <= 1'b0;
end
end
end
reg [15:0] txData;
assign sdo = txData[15];
always@(negedge sck) begin
// memory read
if(cmd == 3) begin
if(cnt == 8)
txData <= ram_data;
else
txData[15:1] <= txData[14:0];
end
// dma status read
if(cmd == 5) begin
if((cnt == 8) || (cnt == 16))
txData[15:8] <= dma_data;
else
txData[15:1] <= txData[14:0];
end
end
always@(posedge sck, posedge ss) begin
if(ss == 1'b1) begin
cnt <= 5'd0;
bcnt <= 4'd0;
writeCmd <= 1'b0;
readCmd <= 1'b0;
dma_ack <= 1'b0;
end else begin
dma_ack <= 1'b0;
sbuf <= { sbuf[13:0], sdi};
// 0:7 is command, 8:15 and 16:23 is payload bytes
if(cnt < 5'd23)
cnt <= cnt + 5'd1;
else
cnt <= 5'd8;
// count payload bytes
if((cnt == 15) || (cnt == 23))
bcnt <= bcnt + 4'd1;
if(cnt == 5'd7) begin
cmd <= {sbuf[6:0], sdi};
// send ack
if({sbuf[6:0], sdi } == 8'd6)
dma_ack <= 1'b1;
// request bus
if({sbuf[6:0], sdi } == 8'd7)
brI <= 1'b1;
// release bus
if({sbuf[6:0], sdi } == 8'd8)
brI <= 1'b0;
// if we can see a read coming initiate sdram read transfer asap
if({sbuf[6:0], sdi } == 8'd3)
readCmd <= 1;
end
// handle "payload"
if(cnt >= 8) begin
// set address
if(cmd == 1)
addrR <= { addrR[29:0], sdi};
// write ram
if(cmd == 2) begin
if(cnt == 5'd16)
writeCmd <= 1'b0;
if(cnt == 5'd23) begin
data_out <= { sbuf, sdi };
addrR <= addrR + 31'b1;
writeCmd <= 1'b1;
end
end
// read ram
if(cmd == 3) begin
if(cnt == 16)
readCmd <= 0;
if(cnt == 23) begin
addrR <= addrR + 31'b1;
readCmd <= 1;
end
end
// set control register (32 bits written in 2 * 16 bits)
if((cmd == 4) && (cnt == 5'd23)) begin
if(bcnt < 2)
ctrl_out[31:16] <= { sbuf, sdi };
else
ctrl_out[15:0] <= { sbuf, sdi };
end
// set video offsets
if((cmd == 9) && (cnt == 5'd23))
video_adj <= { sbuf, sdi };
end
end
end
endmodule

File diff suppressed because it is too large Load Diff

271
cores/mist/fdc.v Normal file
View File

@@ -0,0 +1,271 @@
// fdc.v
//
// Atari ST floppy implementation for the MIST baord
// http://code.google.com/p/mist-board/
//
// Copyright (c) 2014 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 fdc (
// clocks and system interface
input clk,
input reset,
// write protection of currently selected floppy
input [1:0] drv_sel,
input drv_side,
input wr_prot,
input dma_ack,
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 reg [7:0] cpu_dout,
output reg irq
);
// 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
localparam STATE_IDLE = 2'd0;
localparam STATE_IRQ = 2'd1;
localparam STATE_INT_WAIT = 2'd2;
localparam STATE_IO_WAIT = 2'd3;
reg [1:0] state; // fdc busy state
// the fdc registers
reg [7:0] cmd; // write only
reg [7:0] track;
reg [7:0] sector;
reg [7:0] data;
// fdc status as reported to the io controller
assign status_byte =
(status_sel == 0)?cmd:
(status_sel == 1)?track:
(status_sel == 2)?sector:
(status_sel == 3)?data:
(status_sel == 4)?{ 4'b0000, drv_sel, drv_side, state == STATE_IO_WAIT }:
8'h00;
reg step_dir;
reg [31:0] delay;
wire cmd_type_1 = (cmd[7] == 1'b0);
wire cmd_type_2 = (cmd[7:6] == 2'b10);
// ---------------- floppy motor simulation -------------
// timer to simulate motor-on. This runs for x/8000000 seconds after each command
reg motor_start;
reg [31:0] motor_on_counter;
wire motor_on = (motor_on_counter != 0);
// motor_on_counter > 16000000 means the motor is spinning up
wire motor_spin_up_done = motor_on && (motor_on_counter <= 16000000);
always @(posedge clk or posedge motor_start) begin
if(motor_start)
// motor runs for 2 seconds if it was already on. it rus for one
// more second if if wasn't on yet (spin up)
motor_on_counter <= motor_on?32'd16000000:32'd24000000;
else begin
// let "motor" run
if(motor_on_counter != 0)
motor_on_counter <= motor_on_counter - 32'd1;
end
end
// -------------- index pulse generation ----------------
// floppy rotates at 300rpm = 5rps -> generate 5 index pulses per second
wire index_pulse = index_pulse_cnt > 32'd1500000; // 1/16 rotation
reg [31:0] index_pulse_cnt;
always @(posedge clk) begin
if(!motor_on)
index_pulse_cnt <= 32'd0;
else begin
if(index_pulse_cnt != 0)
index_pulse_cnt <= index_pulse_cnt - 32'd1;
else
index_pulse_cnt <= 32'd1600000; // 8000000/5
end
end
// status byte returned by the fdc when reading register 0
wire [7:0] status = {
motor_on,
wr_prot,
cmd_type_1?motor_spin_up_done:1'b0,
2'b00 /* track not found/crc err */,
cmd_type_1?(track == 0):1'b0,
cmd_type_1?index_pulse:(state!=STATE_IDLE),
state != STATE_IDLE
};
// CPU register read
always @(cpu_sel, cpu_addr, cpu_rw) begin
cpu_dout = 8'h00;
if(cpu_sel && cpu_rw) begin
case(cpu_addr)
0: cpu_dout = status;
1: cpu_dout = track;
2: cpu_dout = sector;
3: cpu_dout = data;
endcase
end
end
// CPU register write
always @(negedge clk or posedge reset) begin
if(reset) begin
// clear internal registers
cmd <= 8'h00;
track <= 8'h00;
sector <= 8'h00;
data <= 8'h00;
// reset state machines and counters
state <= STATE_IDLE;
irq <= 1'b0;
motor_start <= 1'b0;
delay <= 32'd0;
end else begin
motor_start <= 1'b0;
// DMA transfer has been ack'd by io controller
if(dma_ack) begin
// fdc waiting for io controller
if(state == STATE_IO_WAIT)
state <= STATE_IRQ; // jump to end of busy phase
end
// fdc may be waiting internally (e.g. for step completion)
if(state == STATE_INT_WAIT) begin
// count down and go into irq state if done
if(delay != 0)
delay <= delay - 32'd1;
else
state <= STATE_IRQ;
end
// fdc is ending busy phase
if(state == STATE_IRQ) begin
irq <= 1'b1;
state <= STATE_IDLE;
end
// cpu is reading status register or writing command register -> clear fdc irq
if(cpu_sel && (cpu_addr == 0))
irq <= 1'b0;
if(cpu_sel && !cpu_rw) begin
// fdc register write
if(cpu_addr == 0) begin // command register
cmd <= cpu_din;
state <= STATE_INT_WAIT;
delay <= 31'd0;
// all TYPE I and TYPE II commands start the motor
if((cpu_din[7] == 1'b0) || (cpu_din[7:6] == 2'b10))
motor_start <= 1'b1;
// ------------- TYPE I commands -------------
if(cpu_din[7:4] == 4'b0000) begin // RESTORE
track <= 8'd0;
delay <= 31'd2000000; // 250ms delay
end
if(cpu_din[7:4] == 4'b0001) begin // SEEK
track <= data;
delay <= 31'd200000; // 25ms delay
end
if(cpu_din[7:3] == 3'b001) begin // STEP
delay <= 31'd20000; // 2.5ms delay
if(cpu_din[4]) // update flag
track <= (step_dir == 1)?(track + 8'd1):(track - 8'd1);
end
if(cpu_din[7:5] == 3'b010) begin // STEP-IN
delay <= 31'd20000; // 2.5ms delay
step_dir <= 1'b1;
if(cpu_din[4]) // update flag
track <= track + 8'd1;
end
if(cpu_din[7:5] == 3'b011) begin // STEP-OUT
delay <= 31'd20000; // 2.5ms delay
step_dir <= 1'b0;
if(cpu_din[4]) // update flag
track <= track - 8'd1;
end
// ------------- TYPE II commands -------------
if(cpu_din[7:5] == 3'b100) begin // read sector
state <= STATE_IO_WAIT;
end
if(cpu_din[7:5] == 3'b101) // write sector
if(!wr_prot)
state <= STATE_IO_WAIT;
// ------------- TYPE III commands ------------
if(cpu_din[7:4] == 4'b1100) // read address
state <= STATE_IO_WAIT;
if(cpu_din[7:4] == 4'b1110) // read track
state <= STATE_IO_WAIT;
if(cpu_din[7:4] == 4'b1111) // write track
if(!wr_prot)
state <= STATE_IO_WAIT;
// ------------- TYPE IV commands -------------
if(cpu_din[7:4] == 4'b1101) begin // force intrerupt
if(cpu_din[3:0] == 4'b0000)
state <= STATE_IDLE; // immediately
else
state <= STATE_IRQ; // with irq
end
end // if (cpu_addr == 0)
if(cpu_addr == 1) // track register
track <= cpu_din;
if(cpu_addr == 2) // sector register
sector <= cpu_din;
if(cpu_addr == 3) // data register
data <= cpu_din;
end // if (cpu_sel && !cpu_rw)
end // else: !if(reset)
end // always @ (negedge clk or posedge reset)
endmodule

View File

@@ -19,6 +19,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// TODO: Make this truly async
// http://www.asic-world.com/examples/verilog/asyn_fifo.html
module io_fifo #(
parameter DATA_WIDTH = 8,
parameter DEPTH = 4

View File

@@ -90,8 +90,10 @@ always @(negedge CLK) begin
// then write the data to the appropriate register.
if(DAT_WE) begin
data <= DAT_I;
down_counter <= DAT_I;
end
// the counter itself is only loaded here if it's stopped
if(!started)
down_counter <= DAT_I;
end
if(CTRL_WE) begin
control <= CTRL_I[3:0];

View File

@@ -327,7 +327,8 @@ set_global_assignment -name VERILOG_FILE viking.v
set_global_assignment -name VERILOG_FILE video_modes.v
set_global_assignment -name VERILOG_FILE io_fifo.v
set_global_assignment -name VERILOG_FILE osd.v
set_global_assignment -name VERILOG_FILE data_io.v
set_global_assignment -name VERILOG_FILE fdc.v
set_global_assignment -name VERILOG_FILE acsi.v
set_global_assignment -name VERILOG_FILE mfp.v
set_global_assignment -name VERILOG_FILE dma.v
set_global_assignment -name VERILOG_FILE sigma_delta_dac.v

View File

@@ -1,7 +1,7 @@
/********************************************/
/* */
/********************************************/
module mist_top (
// clock inputsxque
input wire [ 2-1:0] CLOCK_27, // 27 MHz
@@ -130,8 +130,8 @@ always @(posedge clk_32 or posedge berr_reset) begin
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 = data_io_br || blitter_br; // dma/blitter are only other bus masters
// much more than halting the cpu by suppressing
wire br = dma_br || blitter_br; // dma/blitter are only other bus masters
// request interrupt ack from mfp for IPL == 6. This must not be done by
// combinatorics as it must be glitch free since the mfp does things on the
@@ -172,8 +172,11 @@ wire rom_sel_all = ethernec_present && cpu_cycle && tg68_as && tg68_rw && ({tg68
wire [1:0] rom_sel = { rom_sel_all && tg68_adr[16], rom_sel_all && !tg68_adr[16] };
wire [15:0] rom_data_out;
// mmu 8 bit interface at $ff8000 - $ff8001
wire mmu_sel = io_sel && ({tg68_adr[15:1], 1'd0} == 16'h8000);
// mmu 8 bit interface at $ff8000 - $ff800d
wire mmu_sel = io_sel &&
(({tg68_adr[15:3], 3'd0} == 16'h8000) || // ff8000-ff8007
({tg68_adr[15:2], 2'd0} == 16'h8008) || // ff8008-ff800b
({tg68_adr[15:1], 1'd0} == 16'h800c)); // ff800c-ff800d
wire [7:0] mmu_data_out;
// mega ste cache controller 8 bit interface at $ff8e20 - $ff8e21
@@ -185,8 +188,14 @@ wire [7:0] mste_ctrl_data_out;
// (requierd to enable Mega STE cpu speed/cache control)
wire vme_sel = !steroids && mste && io_sel && ({tg68_adr[15:4], 4'd0} == 16'h8e00);
// video controller 16 bit interface at $ff8200 - $ff827f
wire vreg_sel = io_sel && ({tg68_adr[15:7], 7'd0} == 16'h8200);
// shifter 16 bit interface at $ff8200 - $ff820d and $ff8240 - $ff827f
// STE shifter also has registers at ff820f and ff8265
wire vreg_sel = io_sel && (
({tg68_adr[15:3], 3'd0} == 16'h8200) || // ff8200-ff8207
({tg68_adr[15:2], 2'd0} == 16'h8208) || // ff8208-ff820b
({tg68_adr[15:1], 1'd0} == 16'h820c) || // ff820c-ff820d
(({tg68_adr[15:1], 1'd0} == 16'h820e) && ste) || // ff820e-ff820f (STE)
({tg68_adr[15:6], 6'd0} == 16'h8240)); // ff8240-ff827f
wire [15:0] vreg_data_out;
// ste joystick 16 bit interface at $ff9200 - $ff923f
@@ -197,24 +206,29 @@ wire [15:0] ste_joy_data_out;
wire ste_dma_snd_sel = ste && io_sel && ({tg68_adr[15:6], 6'd0} == 16'h8900);
wire [15:0] ste_dma_snd_data_out;
// mfp 8 bit interface at $fffa00 - $fffa3f
wire mfp_sel = io_sel && ({tg68_adr[15:6], 6'd0} == 16'hfa00);
// mfp 8 bit interface at $fffa00 - $fffa3f, odd byte and word only
wire mfp_sel = io_sel && (tg68_lds == 1'd0) && ({tg68_adr[15:6], 6'd0} == 16'hfa00);
wire [7:0] mfp_data_out;
// acia 8 bit interface at $fffc00 - $fffc07
wire acia_sel = io_sel && ({tg68_adr[15:8], 8'd0} == 16'hfc00);
// acia 8 bit interface at $fffc00 - $fffdff
wire acia_sel = io_sel && ({tg68_adr[15:9], 9'd0} == 16'hfc00); // fffc00-fffdff
wire [7:0] acia_data_out;
// blitter 16 bit interface at $ff8a00 - $ff8a3f, STE always has a blitter
wire blitter_sel = (system_ctrl[19] || ste) && io_sel && ({tg68_adr[15:8], 8'd0} == 16'h8a00);
wire blitter_sel = (system_ctrl[19] || ste) && io_sel && ({tg68_adr[15:6], 6'd0} == 16'h8a00);
wire [15:0] blitter_data_out;
// psg 8 bit interface at $ff8800 - $ff8803
// psg 8 bit interface at $ff8800 - $ff88ff
wire psg_sel = io_sel && ({tg68_adr[15:8], 8'd0} == 16'h8800);
wire [7:0] psg_data_out;
// dma 16 bit interface at $ff8600 - $ff860f
wire dma_sel = io_sel && ({tg68_adr[15:4], 4'd0} == 16'h8600);
// dma 16 bit interface at $ff8604 - $ff8607 (word only) and $ff8606 - $ff860d (STE - ff860f)
wire word_access = (tg68_uds == 1'd0) && (tg68_lds == 1'd0);
wire dma_sel = io_sel && (
(({tg68_adr[15:2], 2'd0} == 16'h8604) && word_access) || // ff8604-ff8607 word only
({tg68_adr[15:2], 2'd0} == 16'h8608) || // ff8608-ff860b
({tg68_adr[15:1], 1'd0} == 16'h860c) || // ff860c-ff860d
(({tg68_adr[15:1], 1'd0} == 16'h860e) && ste)); // ff860e-ff860f (hdmode, STE)
wire [15:0] dma_data_out;
// de-multiplex the various io data output ports into one
@@ -288,7 +302,6 @@ wire [5:0] shifter_r, shifter_g, shifter_b;
video video (
.clk (clk_32 ),
.clk27 (CLOCK_27[0]),
.bus_cycle (bus_cycle ),
// spi for OSD
@@ -464,7 +477,7 @@ blitter blitter (
.bm_read (blitter_master_read),
.bm_data_in (ram_data_out),
.br_in (data_io_br ),
.br_in (dma_br ),
.br_out (blitter_br ),
.bg (blitter_bg ),
.irq (blitter_irq ),
@@ -636,39 +649,53 @@ YM2149 ym2149 (
.CLK8 ( clk_8 ) // 8 MHz CPU bus clock
);
wire dma_dio_ack;
wire [4:0] dma_dio_idx;
wire [7:0] dma_dio_data;
// floppy_sel is active low
wire wr_prot = (floppy_sel == 2'b01)?system_ctrl[7]:system_ctrl[6];
wire [22:0] dma_addr;
wire [15:0] dma_dout;
wire dma_write, dma_read;
wire dma_br;
dma dma (
// system interface
.clk (clk_8 ),
.reset (reset ),
.bus_cycle (bus_cycle ),
.irq (dma_irq ),
.turbo (1'b0 ),
.ctrl_out (system_ctrl ),
.video_adj (video_adj ),
// spi
.sdi (SPI_DI ),
.sck (SPI_SCK ),
.ss (SPI_SS2 ),
.sdo (dma_sdo ),
// cpu interface
.clk (clk_8 ),
.reset (reset ),
.din (tg68_dat_out[15:0]),
.sel (dma_sel ),
.addr (tg68_adr[3:1]),
.uds (tg68_uds ),
.lds (tg68_lds ),
.rw (tg68_rw ),
.dout (dma_data_out),
.cpu_din (tg68_dat_out[15:0]),
.cpu_sel (dma_sel ),
.cpu_addr (tg68_adr[3:1]),
.cpu_uds (tg68_uds ),
.cpu_lds (tg68_lds ),
.cpu_rw (tg68_rw ),
.cpu_dout (dma_data_out),
.irq (dma_irq ),
// system control interface
// additional signals for floppy/acsi interface
.fdc_wr_prot (wr_prot),
.acsi_enable (system_ctrl[17:10]),
// data_io (arm controller imterface)
.dio_idx (dma_dio_idx ),
.dio_data (dma_dio_data),
.dio_ack (dma_dio_ack ),
// floppy interface
.drv_sel (floppy_sel ),
.drv_side (floppy_side )
.drv_side (floppy_side ),
.acsi_enable (system_ctrl[17:10]),
// ram interface
.ram_br (dma_br ),
.ram_read (dma_read ),
.ram_write (dma_write ),
.ram_addr (dma_addr ),
.ram_dout (dma_dout ),
.ram_din (ram_data_out )
);
wire [1:0] floppy_sel;
@@ -681,7 +708,7 @@ wire clk_8;
wire clk_32;
wire clk_128;
wire clk_mfp;
// use pll
clock clock (
.areset (1'b0 ), // async reset input
@@ -694,23 +721,9 @@ clock clock (
);
//// 8MHz clock ////
reg [3:0] clk_cnt;
reg [1:0] clk_cnt;
reg [1:0] bus_cycle;
always @ (posedge clk_32, negedge pll_locked) begin
if (!pll_locked) begin
clk_cnt <= #1 4'b0010;
bus_cycle <= 2'd0;
end else begin
clk_cnt <= #1 clk_cnt + 4'd1;
if(clk_cnt[1:0] == 2'd1) begin
bus_cycle <= bus_cycle + 2'd1;
end
end
end
assign clk_8 = clk_cnt[1];
// MFP clock
// required: 2.4576 MHz
// derived from 27MHZ: 27*74/824 = 2.457525 MHz => 0.003% error
@@ -722,6 +735,19 @@ pll_mfp1 pll_mfp1 (
.c0 (clk_mfp ) // output clock c0 (2.457627MHz)
);
always @ (posedge clk_32, negedge pll_locked) begin
if (!pll_locked) begin
clk_cnt <= 2'd2;
bus_cycle <= 2'd0;
end else begin
clk_cnt <= clk_cnt + 2'd1;
if(clk_cnt == 2'd1)
bus_cycle <= bus_cycle + 2'd1;
end
end
assign clk_8 = clk_cnt[1];
// bus cycle counter for debugging
reg [31:0] cycle_counter /* synthesis noprune */;
always @ (posedge clk_8) begin
@@ -838,14 +864,19 @@ always @(posedge clk_32)
// the TG68 core works on the rising clock edge. We thus prepare everything
// on the falling clock edge
reg brD;
always @(negedge clk_32) begin
brD <= br; // delay bus request by one cycle. This only has an effect in
// STEroids mode as otherwise br changes in those cycles not used by
// CPU
// default: cpu does not run
clkena <= 1'b0;
iCacheStore <= 1'b0;
dCacheStore <= 1'b0;
cacheUpdate <= 1'b0;
if(br || reset)
if(br || brD || reset)
tg68_as <= 1'b0;
else begin
// run cpu if it owns the bus
@@ -1059,7 +1090,7 @@ wire cpu2io = (tg68_adr[23:16] == 8'hff);
// irq ack happens
wire cpu2iack = (tg68_fc == 3'b111);
// generate dtack (for st ram and rom on read, no dtack for rom write)
assign tg68_dtack = ((cpu2mem && cpu_cycle && tg68_as) || io_dtack ) && !br;
@@ -1067,6 +1098,9 @@ assign tg68_dtack = ((cpu2mem && cpu_cycle && tg68_as) || io_dtack ) && !br;
/* ------------------------------- bus multiplexer ------------------------------ */
/* ------------------------------------------------------------------------------ */
wire dma_has_bus = dma_br;
wire blitter_has_bus = blitter_br;
// singnal indicating if cpu should use a second cpu slot for 16Mhz like operation
// steroids (STEroid) always runs at max speed
wire second_cpu_slot = (mste && enable_16mhz) || steroids;
@@ -1079,27 +1113,27 @@ wire viking_cycle = (bus_cycle == 2);
// ----------------- RAM address --------------
wire [22:0] video_cycle_addr = (st_hs && ste)?ste_dma_snd_addr:video_address;
wire [22:0] cpu_cycle_addr = data_io_br?data_io_addr:(blitter_br?blitter_master_addr:tg68_adr[23:1]);
wire [22:0] cpu_cycle_addr = dma_has_bus?dma_addr:(blitter_has_bus?blitter_master_addr:tg68_adr[23:1]);
wire [22:0] ram_address = viking_cycle?viking_address:(video_cycle?video_cycle_addr:cpu_cycle_addr);
// ----------------- RAM read -----------------
// memory access during the video cycle is shared between video and ste_dma_snd
wire video_cycle_oe = (st_hs && ste)?ste_dma_snd_read:video_read;
// memory access during the cpu cycle is shared between blitter and cpu
wire cpu_cycle_oe = data_io_br?data_io_read:(blitter_br?blitter_master_read:(cpu_cycle && tg68_as && tg68_rw && cpu2mem));
wire cpu_cycle_oe = dma_has_bus?dma_read:(blitter_has_bus?blitter_master_read:(cpu_cycle && tg68_as && tg68_rw && cpu2mem));
wire ram_oe = viking_cycle?viking_read:(video_cycle?video_cycle_oe:(cpu_cycle?cpu_cycle_oe:1'b0));
// ----------------- RAM write -----------------
wire cpu_cycle_wr = data_io_br?data_io_write:(blitter_br?blitter_master_write:(cpu_cycle && tg68_as && ~tg68_rw && cpu2ram));
wire cpu_cycle_wr = dma_has_bus?dma_write:(blitter_has_bus?blitter_master_write:(cpu_cycle && tg68_as && ~tg68_rw && cpu2ram));
wire ram_wr = (viking_cycle||video_cycle)?1'b0:(cpu_cycle?cpu_cycle_wr:1'b0);
wire [15:0] ram_data_out;
wire [15:0] system_data_out = cpu2mem?ram_data_out:io_data_out;
wire [15:0] ram_data_in = data_io_br?data_io_dout:(blitter_br?blitter_master_data_out:tg68_dat_out);
wire [15:0] ram_data_in = dma_has_bus?dma_dout:(blitter_has_bus?blitter_master_data_out:tg68_dat_out);
// data strobe
wire ram_uds = video_cycle?1'b1:((blitter_br||data_io_br)?1'b1:~tg68_uds);
wire ram_lds = video_cycle?1'b1:((blitter_br||data_io_br)?1'b1:~tg68_lds);
wire ram_uds = video_cycle?1'b1:((br && brD)?1'b1:~tg68_uds);
wire ram_lds = video_cycle?1'b1:((br && brD)?1'b1:~tg68_lds);
// sdram controller has 64 bit output
wire [63:0] ram_data_out_64;
@@ -1143,11 +1177,11 @@ sdram sdram (
// multiplex spi_do, drive it from user_io if that's selected, drive
// it from minimig if it's selected and leave it open else (also
// to be able to monitor sd card data directly)
wire data_io_sdo;
wire dma_sdo;
wire user_io_sdo;
assign SPI_DO = (CONF_DATA0 == 1'b0)?user_io_sdo:
((SPI_SS2 == 1'b0)?data_io_sdo:1'bZ);
((SPI_SS2 == 1'b0)?dma_sdo:1'bZ);
wire [31:0] system_ctrl;
@@ -1241,40 +1275,6 @@ user_io user_io(
.CORE_TYPE (8'ha3) // mist core id
);
wire [22:0] data_io_addr;
wire [15:0] data_io_dout;
wire data_io_write, data_io_read;
wire data_io_br;
data_io data_io (
// system control
.clk_8 (clk_8 ),
.reset (init ),
.bus_cycle (bus_cycle ),
.ctrl_out (system_ctrl ),
// spi
.sdi (SPI_DI ),
.sck (SPI_SCK ),
.ss (SPI_SS2 ),
.sdo (data_io_sdo ),
.video_adj (video_adj ),
// dma status interface
.dma_idx (dma_dio_idx ),
.dma_data (dma_dio_data ),
.dma_ack (dma_dio_ack ),
.br (data_io_br ),
// ram interface
.read (data_io_read ),
.write (data_io_write ),
.addr (data_io_addr ),
.data_out (data_io_dout ),
.data_in (ram_data_out )
);
endmodule

View File

@@ -5,7 +5,6 @@
// http://code.google.com/p/mist-board/
//
// Copyright (c) 2013 Till Harbaum <till@harbaum.org>
// Modified by Juan Carlos González Amestoy.
//
// 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

View File

@@ -61,19 +61,19 @@ module user_io(
wire [7:0] spi_sck_D = { spi_sck_D[6:0], SPI_CLK } /* synthesis keep */;
wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff);
reg [1:0] byte_cnt;
reg [6:0] sbuf;
reg [7:0] cmd;
reg [3:0] bit_cnt; // 0..15
reg [3:0] but_sw;
reg [1:0] byte_cnt;
reg [6:0] sbuf;
reg [7:0] cmd;
reg [3:0] bit_cnt; // 0..15
reg [3:0] but_sw;
// counter runs 0..7,8..15,8..15,8..15
wire [2:0] tx_bit = ~(bit_cnt[2:0]);
// counter runs 0..7,8..15,8..15,8..15
wire [2:0] tx_bit = ~(bit_cnt[2:0]);
assign BUTTONS = but_sw[1:0];
assign SWITCHES = but_sw[3:2];
assign BUTTONS = but_sw[1:0];
assign SWITCHES = but_sw[3:2];
always@(negedge spi_sck) begin
always@(negedge spi_sck) begin
if(bit_cnt <= 7)
SPI_MISO <= CORE_TYPE[7-bit_cnt];
else begin

View File

@@ -23,7 +23,6 @@
module video (
// system interface
input clk, // 31.875 MHz
input clk27, // 27.000 Mhz
input [1:0] bus_cycle, // bus-cycle for sync
// SPI interface for OSD