mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-05-05 15:54:29 +00:00
767 lines
22 KiB
Verilog
767 lines
22 KiB
Verilog
//
|
|
// c16_mist.v - C16 for the MiST
|
|
//
|
|
// https://github.com/mist-devel
|
|
//
|
|
// 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 c16_mist (
|
|
input CLOCK_27,
|
|
|
|
// LED outputs
|
|
output LED, // LED Yellow
|
|
|
|
// SDRAM interface
|
|
inout [15:0] SDRAM_DQ, // SDRAM Data bus 16 Bits
|
|
output [12:0] SDRAM_A, // SDRAM Address bus 13 Bits
|
|
output SDRAM_DQML, // SDRAM Low-byte Data Mask
|
|
output SDRAM_DQMH, // SDRAM High-byte Data Mask
|
|
output SDRAM_nWE, // SDRAM Write Enable
|
|
output SDRAM_nCAS, // SDRAM Column Address Strobe
|
|
output SDRAM_nRAS, // SDRAM Row Address Strobe
|
|
output SDRAM_nCS, // SDRAM Chip Select
|
|
output [1:0] SDRAM_BA, // SDRAM Bank Address
|
|
output SDRAM_CLK, // SDRAM Clock
|
|
output SDRAM_CKE, // SDRAM Clock Enable
|
|
|
|
// SPI interface to arm io controller
|
|
output SPI_DO,
|
|
input SPI_DI,
|
|
input SPI_SCK,
|
|
input SPI_SS2,
|
|
input SPI_SS3,
|
|
input SPI_SS4,
|
|
input CONF_DATA0,
|
|
|
|
output AUDIO_L, // sigma-delta DAC output left
|
|
output AUDIO_R, // sigma-delta DAC output right
|
|
|
|
output VGA_HS,
|
|
output VGA_VS,
|
|
output [5:0] VGA_R,
|
|
output [5:0] VGA_G,
|
|
output [5:0] VGA_B
|
|
);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// ------------------------------ user_io ----------------------------------
|
|
// -------------------------------------------------------------------------
|
|
|
|
// user_io implements a connection to the io controller and receives various
|
|
// kind of user input from there (keyboard, buttons, mouse). It is also used
|
|
// by the fake SD card to exchange data with the real sd card connected to the
|
|
// io controller
|
|
|
|
// the configuration string is returned to the io controller to allow
|
|
// it to control the menu on the OSD
|
|
parameter CONF_STR = {
|
|
"C16;PRG;",
|
|
"S,D64,Mount Disk;",
|
|
"F,ROM,Load Kernal;",
|
|
"O2,Scanlines,Off,On;",
|
|
"O3,Joysticks,Normal,Swapped;",
|
|
"O4,Memory,64k,16k;",
|
|
"T5,Reset;"
|
|
};
|
|
|
|
parameter CONF_STR_LEN = 8+17+18+20+28+18+9;
|
|
|
|
// the status register is controlled by the on screen display (OSD)
|
|
wire [7:0] status;
|
|
wire tv15khz;
|
|
wire ypbpr;
|
|
wire scanlines = status[2];
|
|
wire joystick_swap = status[3];
|
|
wire memory_16k = status[4];
|
|
wire osd_reset = status[5];
|
|
wire [1:0] buttons;
|
|
|
|
wire [7:0] js0, js1;
|
|
wire [7:0] jsA = joystick_swap?js1:js0;
|
|
wire [7:0] jsB = joystick_swap?js0:js1;
|
|
|
|
wire ps2_kbd_clk, ps2_kbd_data;
|
|
wire ps2_mouse_clk, ps2_mouse_data;
|
|
|
|
// -------------------------------------------------------------------------
|
|
// ---------------- interface to the external sdram ------------------------
|
|
// -------------------------------------------------------------------------
|
|
|
|
// SDRAM control signals
|
|
assign SDRAM_CKE = 1'b1;
|
|
|
|
// ram access signals from c16
|
|
wire [15:0] c16_sdram_addr = { c16_a_hi, c16_a_low };
|
|
wire [7:0] c16_sdram_data = c16_dout;
|
|
wire c16_sdram_wr = !c16_cas && !c16_rw;
|
|
wire c16_sdram_oe = !c16_cas && c16_rw;
|
|
|
|
// ram access signals from io controller
|
|
// ioctl_sdram_write
|
|
// ioctl_sdram_addr
|
|
// ioctl_sdram_data
|
|
|
|
// multiplex c16 and ioctl signals
|
|
wire [15:0] mux_sdram_addr = c16_wait?ioctl_sdram_addr:c16_sdram_addr;
|
|
wire [7:0] mux_sdram_data = c16_wait?ioctl_sdram_data:c16_sdram_data;
|
|
wire mux_sdram_wr = c16_wait?ioctl_sdram_write:c16_sdram_wr;
|
|
wire mux_sdram_oe = c16_wait?1'b0:c16_sdram_oe;
|
|
|
|
wire [15:0] sdram_din = { mux_sdram_data, mux_sdram_data };
|
|
wire [14:0] sdram_addr_64k = mux_sdram_addr[15:1]; // 64k mapping
|
|
wire [14:0] sdram_addr_16k = { 1'b0, mux_sdram_addr[13:7], 1'b0, mux_sdram_addr[6:1] }; // 16k
|
|
wire [24:0] sdram_addr = { 10'h00, memory_16k?sdram_addr_16k:sdram_addr_64k };
|
|
|
|
wire sdram_wr = mux_sdram_wr;
|
|
wire sdram_oe = mux_sdram_oe;
|
|
wire [1:0] sdram_ds = { mux_sdram_addr[0], !mux_sdram_addr[0] };
|
|
|
|
// only c16 reads from sdram
|
|
wire [15:0] sdram_dout;
|
|
wire [7:0] c16_din = zp_overwrite?zp_ovl_dout:
|
|
(c16_a_low[0]?sdram_dout[15:8]:sdram_dout[7:0]);
|
|
|
|
assign SDRAM_CLK = ~clk28;
|
|
|
|
// synchronize sdram state machine with the ras/cas phases of the c16
|
|
reg last_ras;
|
|
reg [3:0] clkdiv;
|
|
wire clkref = clkdiv[3];
|
|
always @(posedge clk28) begin
|
|
if(!c16_ras && last_ras) begin
|
|
clkdiv <= 4'd0;
|
|
last_ras <= c16_ras;
|
|
end else
|
|
clkdiv <= clkdiv + 4'd1;
|
|
end
|
|
|
|
// latch/demultiplex dram address
|
|
reg [7:0] c16_a_low;
|
|
always @(negedge c16_ras)
|
|
c16_a_low <= c16_a;
|
|
|
|
reg [7:0] c16_a_hi;
|
|
always @(negedge c16_cas)
|
|
c16_a_hi <= c16_a;
|
|
|
|
sdram sdram (
|
|
// interface to the MT48LC16M16 chip
|
|
.sd_data ( SDRAM_DQ ),
|
|
.sd_addr ( SDRAM_A ),
|
|
.sd_dqm ( {SDRAM_DQMH, SDRAM_DQML} ),
|
|
.sd_cs ( SDRAM_nCS ),
|
|
.sd_ba ( SDRAM_BA ),
|
|
.sd_we ( SDRAM_nWE ),
|
|
.sd_ras ( SDRAM_nRAS ),
|
|
.sd_cas ( SDRAM_nCAS ),
|
|
|
|
// system interface
|
|
.clk ( clk28 ),
|
|
.clkref ( clkref ),
|
|
.init ( !pll_locked ),
|
|
|
|
// cpu interface
|
|
.din ( sdram_din ),
|
|
.addr ( sdram_addr ),
|
|
.we ( sdram_wr ),
|
|
.oe ( sdram_oe ),
|
|
.ds ( sdram_ds ),
|
|
.dout ( sdram_dout )
|
|
);
|
|
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// -------------------------------------- reset ------------------------------------
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
reg last_mem16k;
|
|
reg [31:0] reset_cnt;
|
|
wire reset = (reset_cnt != 0);
|
|
always @(posedge clk28) begin
|
|
last_mem16k <= memory_16k;
|
|
|
|
// long reset on startup and when io controller reboots
|
|
if(status[0] || !pll_locked)
|
|
reset_cnt <= 32'd28000000;
|
|
// short reset on reset button, reset osd or when io controller is
|
|
// done downloading or when memory mapping changes
|
|
else if(buttons[1] || osd_reset || rom_download || (memory_16k != last_mem16k))
|
|
reset_cnt <= 32'd65536;
|
|
else if(reset_cnt != 0)
|
|
reset_cnt <= reset_cnt - 32'd1;
|
|
end
|
|
|
|
// signals to connect io controller with virtual sd card
|
|
wire [31:0] sd_lba;
|
|
wire sd_rd;
|
|
wire sd_wr;
|
|
wire sd_ack;
|
|
wire sd_ack_conf;
|
|
wire sd_conf;
|
|
wire sd_sdhc = 1'b1;
|
|
wire [7:0] sd_dout;
|
|
wire sd_dout_strobe;
|
|
wire [7:0] sd_din;
|
|
wire sd_din_strobe;
|
|
wire img_mounted;
|
|
wire [8:0] sd_buff_addr;
|
|
|
|
// include user_io module for arm controller communication
|
|
user_io #(.STRLEN(CONF_STR_LEN)) user_io (
|
|
.conf_str ( CONF_STR ),
|
|
|
|
.clk_sys ( clk28 ),
|
|
.clk_sd ( clk32 ),
|
|
|
|
.SPI_CLK ( SPI_SCK ),
|
|
.SPI_SS_IO ( CONF_DATA0 ),
|
|
.SPI_MISO ( SPI_DO ),
|
|
.SPI_MOSI ( SPI_DI ),
|
|
|
|
.scandoubler_disable ( tv15khz ),
|
|
.ypbpr ( ypbpr ),
|
|
.buttons ( buttons ),
|
|
|
|
.joystick_0 ( js0 ),
|
|
.joystick_1 ( js1 ),
|
|
|
|
// ps2 interface
|
|
.ps2_kbd_clk ( ps2_kbd_clk ),
|
|
.ps2_kbd_data ( ps2_kbd_data ),
|
|
.ps2_mouse_clk ( ps2_mouse_clk ),
|
|
.ps2_mouse_data ( ps2_mouse_data ),
|
|
|
|
.sd_lba ( sd_lba ),
|
|
.sd_rd ( sd_rd ),
|
|
.sd_wr ( sd_wr ),
|
|
.sd_ack ( sd_ack ),
|
|
.sd_ack_conf ( sd_ack_conf ),
|
|
.sd_conf ( sd_conf ),
|
|
.sd_sdhc ( sd_sdhc ),
|
|
.sd_dout ( sd_dout ),
|
|
.sd_dout_strobe ( sd_dout_strobe ),
|
|
.sd_din ( sd_din ),
|
|
.sd_din_strobe ( sd_din_strobe ),
|
|
.sd_buff_addr ( sd_buff_addr),
|
|
.img_mounted ( img_mounted ),
|
|
|
|
.status ( status )
|
|
);
|
|
|
|
wire sd_cs;
|
|
wire sd_dat;
|
|
wire sd_cmd;
|
|
wire sd_clk;
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// ------------------------------ prg memory injection -----------------------------
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
wire ioctl_wr;
|
|
wire [15:0] ioctl_addr;
|
|
wire [7:0] ioctl_data;
|
|
wire [4:0] ioctl_index;
|
|
wire ioctl_downloading;
|
|
|
|
wire rom_download = ioctl_downloading && ((ioctl_index == 5'd0) || (ioctl_index == 5'd3));
|
|
wire prg_download = ioctl_downloading && (ioctl_index == 5'd1);
|
|
|
|
// halt cpu when it's done with the current cycle
|
|
reg c16_wait;
|
|
always @(posedge c16_ras)
|
|
c16_wait <= prg_download;
|
|
|
|
data_io data_io (
|
|
// SPI interface
|
|
.sck ( SPI_SCK ),
|
|
.ss ( SPI_SS2 ),
|
|
.sdi ( SPI_DI ),
|
|
|
|
// ram interface
|
|
.downloading ( ioctl_downloading ),
|
|
.index ( ioctl_index ),
|
|
.clk ( clk28 ),
|
|
.wr ( ioctl_wr ),
|
|
.a ( ioctl_addr ),
|
|
.d ( ioctl_data )
|
|
);
|
|
|
|
// magic zero page shadow registers to allow the injector to set the
|
|
// basic program end pointers automagically after injection
|
|
reg [15:0] reg_2d;
|
|
reg [15:0] reg_2f;
|
|
reg [15:0] reg_31;
|
|
reg [15:0] reg_9d;
|
|
|
|
wire zp_2d_sel = c16_sdram_addr == 16'h002d;
|
|
wire zp_2e_sel = c16_sdram_addr == 16'h002e;
|
|
wire zp_2f_sel = c16_sdram_addr == 16'h002f;
|
|
wire zp_30_sel = c16_sdram_addr == 16'h0030;
|
|
wire zp_31_sel = c16_sdram_addr == 16'h0031;
|
|
wire zp_32_sel = c16_sdram_addr == 16'h0032;
|
|
wire zp_9d_sel = c16_sdram_addr == 16'h009d;
|
|
wire zp_9e_sel = c16_sdram_addr == 16'h009e;
|
|
|
|
wire zp_overwrite =
|
|
zp_2d_sel || zp_2e_sel || zp_2f_sel || zp_30_sel ||
|
|
zp_31_sel || zp_32_sel || zp_9d_sel || zp_9e_sel;
|
|
|
|
reg zp_cas_delay, zp_sel;
|
|
reg zp_dl_delay, zp_dl;
|
|
|
|
always @(posedge clk28) begin
|
|
// write pulse one cycle after falling edge of cas to make sure address
|
|
// is stable
|
|
zp_cas_delay <= c16_cas;
|
|
zp_sel <= !c16_cas && zp_cas_delay;
|
|
zp_dl_delay <= prg_download;
|
|
zp_dl <= !prg_download && zp_dl_delay;
|
|
|
|
if(zp_dl) begin
|
|
// registers are automatically adjusted at the end of the
|
|
// download/injection
|
|
// the registers to be set have been taken from the vice emulator
|
|
reg_2d <= ioctl_sdram_addr + 16'd1;
|
|
reg_2f <= ioctl_sdram_addr + 16'd1;
|
|
reg_31 <= ioctl_sdram_addr + 16'd1;
|
|
reg_9d <= ioctl_sdram_addr + 16'd1;
|
|
end else if(zp_sel && !c16_rw) begin
|
|
// cpu writes registers
|
|
if(zp_2d_sel) reg_2d[ 7:0] <= c16_dout;
|
|
if(zp_2e_sel) reg_2d[15:8] <= c16_dout;
|
|
if(zp_2f_sel) reg_2f[ 7:0] <= c16_dout;
|
|
if(zp_30_sel) reg_2f[15:8] <= c16_dout;
|
|
if(zp_31_sel) reg_31[ 7:0] <= c16_dout;
|
|
if(zp_32_sel) reg_31[15:8] <= c16_dout;
|
|
if(zp_9d_sel) reg_9d[ 7:0] <= c16_dout;
|
|
if(zp_9e_sel) reg_9d[15:8] <= c16_dout;
|
|
end
|
|
end
|
|
|
|
wire [7:0] zp_ovl_dout =
|
|
zp_2d_sel?reg_2d[7:0]:zp_2e_sel?reg_2d[15:8]:
|
|
zp_2f_sel?reg_2f[7:0]:zp_30_sel?reg_2f[15:8]:
|
|
zp_31_sel?reg_31[7:0]:zp_32_sel?reg_31[15:8]:
|
|
zp_9d_sel?reg_9d[7:0]:zp_9e_sel?reg_9d[15:8]:
|
|
8'hff;
|
|
|
|
// the address taken from the first to bytes of a prg file tell
|
|
// us where the file is to go in memory
|
|
reg [15:0] ioctl_load_addr;
|
|
reg ioctl_ram_wr;
|
|
reg ioctl_sdram_write;
|
|
reg [15:0] ioctl_sdram_addr;
|
|
reg [7:0] ioctl_sdram_data;
|
|
|
|
always @(negedge c16_ras) begin
|
|
ioctl_sdram_write <= ioctl_ram_wr;
|
|
|
|
if(ioctl_ram_wr) begin
|
|
ioctl_sdram_addr <= ioctl_load_addr + ioctl_addr - 16'd2;
|
|
ioctl_sdram_data <= ioctl_data;
|
|
end
|
|
end
|
|
|
|
// address starts counting with 0
|
|
always @(negedge clk28) begin
|
|
if(ioctl_sdram_write)
|
|
ioctl_ram_wr <= 1'b0;
|
|
|
|
// data io has a byte for us
|
|
if(ioctl_wr) begin
|
|
if(ioctl_addr == 16'h0000)
|
|
ioctl_load_addr[7:0] <= ioctl_data;
|
|
else if (ioctl_addr == 16'h0001)
|
|
ioctl_load_addr[15:8] <= ioctl_data;
|
|
else
|
|
// io controller sent a new byte. Store it until it can be
|
|
// saved in RAM
|
|
ioctl_ram_wr <= 1'b1;
|
|
end
|
|
end
|
|
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// ------------------------------ the on screen display ----------------------------
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
// in 15khz mode feed the c16 video directly into the OSD,
|
|
// bypassing the scan doubler
|
|
wire [5:0] osd_r_in = tv15khz?{c16_r, 2'b00}:video_r;
|
|
wire [5:0] osd_g_in = tv15khz?{c16_g, 2'b00}:video_g;
|
|
wire [5:0] osd_b_in = tv15khz?{c16_b, 2'b00}:video_b;
|
|
wire osd_hs_in = tv15khz?!c16_hs:video_hs;
|
|
wire osd_vs_in = tv15khz?!c16_vs:video_vs;
|
|
|
|
wire osd_clk = tv15khz?clk7:clk14;
|
|
|
|
wire [5:0] red, green, blue;
|
|
|
|
// include the on screen display
|
|
osd #(11,0,5) osd (
|
|
.clk_sys ( clk28 ),
|
|
.ce_pix ( osd_clk ),
|
|
|
|
// spi for OSD
|
|
.sdi ( SPI_DI ),
|
|
.sck ( SPI_SCK ),
|
|
.ss ( SPI_SS3 ),
|
|
|
|
.red_in ( osd_r_in ),
|
|
.green_in ( osd_g_in ),
|
|
.blue_in ( osd_b_in ),
|
|
.hs_in ( osd_hs_in ),
|
|
.vs_in ( osd_vs_in ),
|
|
|
|
.red_out ( red ),
|
|
.green_out ( green ),
|
|
.blue_out ( blue )
|
|
);
|
|
|
|
wire [5:0] y, pb, pr;
|
|
rgb2ypbpr rgb2ypbpr (
|
|
.red ( red ),
|
|
.green ( green ),
|
|
.blue ( blue ),
|
|
|
|
.y ( y ),
|
|
.pb ( pb ),
|
|
.pr ( pr )
|
|
);
|
|
|
|
assign VGA_R = ypbpr ? pr : red;
|
|
assign VGA_G = ypbpr ? y : green;
|
|
assign VGA_B = ypbpr ? pb : blue;
|
|
|
|
// in 15khz tv mode directly use the c16's composite sync. Otherwise the VGA
|
|
// output is driven from the sync signals generated by the scan doubler. In
|
|
// 15khz mode the VS signal is used as the RGB detect signal on the SCART
|
|
// connector and thus needs to be driven to 1
|
|
assign VGA_HS = tv15khz?c16_cs:ypbpr ? (video_hs ^ video_vs) : video_hs;
|
|
assign VGA_VS = (tv15khz || ypbpr)?1'b1:video_vs;
|
|
|
|
wire video_hs, video_vs;
|
|
wire [5:0] video_r;
|
|
wire [5:0] video_g;
|
|
wire [5:0] video_b;
|
|
|
|
scandoubler scandoubler (
|
|
// system interface
|
|
.clk_sys ( clk28 ),
|
|
|
|
// scanlines (00-none 01-25% 10-50% 11-75%)
|
|
.scanlines ( scanlines?2'b10:2'b00 ),
|
|
|
|
// shifter video interface
|
|
.hs_in ( !c16_hs ),
|
|
.vs_in ( !c16_vs ),
|
|
.r_in ( c16_r ),
|
|
.g_in ( c16_g ),
|
|
.b_in ( c16_b ),
|
|
|
|
// output interface
|
|
.hs_out ( video_hs ),
|
|
.vs_out ( video_vs ),
|
|
.r_out ( video_r ),
|
|
.g_out ( video_g ),
|
|
.b_out ( video_b )
|
|
);
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// ------------------------------------ c16 core -----------------------------------
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
// c16 generated video signals
|
|
wire c16_hs, c16_vs, c16_cs;
|
|
wire [3:0] c16_r;
|
|
wire [3:0] c16_g;
|
|
wire [3:0] c16_b;
|
|
wire c16_pal;
|
|
|
|
// c16 generated ram access signals
|
|
wire c16_ras;
|
|
wire c16_cas;
|
|
wire c16_rw;
|
|
wire [7:0] c16_a;
|
|
wire [7:0] c16_dout;
|
|
|
|
reg kernal_dl_wr, basic_dl_wr, c1541_dl_wr;
|
|
reg [7:0] rom_dl_data;
|
|
reg [13:0] rom_dl_addr;
|
|
|
|
wire ioctl_rom_wr = rom_download && ioctl_wr;
|
|
|
|
always @(negedge clk28) begin
|
|
reg last_ioctl_rom_wr;
|
|
last_ioctl_rom_wr <= ioctl_rom_wr;
|
|
if(ioctl_rom_wr && !last_ioctl_rom_wr) begin
|
|
rom_dl_data <= ioctl_data;
|
|
rom_dl_addr <= ioctl_addr[13:0];
|
|
c1541_dl_wr <= !ioctl_addr[15:14] && ioctl_index == 5'd0;
|
|
kernal_dl_wr <= ioctl_addr[15:14] == 2'd1 || ioctl_index == 5'd3;
|
|
basic_dl_wr <= ioctl_addr[15:14] == 2'd2 && ioctl_index == 5'd0;
|
|
end else
|
|
{ kernal_dl_wr, basic_dl_wr, c1541_dl_wr } <= 0;
|
|
end
|
|
|
|
// include the c16 itself
|
|
C16 c16 (
|
|
.CLK28 ( clk28 ),
|
|
.RESET ( reset ),
|
|
.WAIT ( c16_wait ),
|
|
.HSYNC ( c16_hs ),
|
|
.VSYNC ( c16_vs ),
|
|
.CSYNC ( c16_cs ),
|
|
.RED ( c16_r ),
|
|
.GREEN ( c16_g ),
|
|
.BLUE ( c16_b ),
|
|
|
|
.RAS ( c16_ras ),
|
|
.CAS ( c16_cas ),
|
|
.RW ( c16_rw ),
|
|
.A ( c16_a ),
|
|
.DOUT ( c16_dout ),
|
|
.DIN ( c16_din ),
|
|
|
|
.JOY0 ( jsB[4:0] ),
|
|
.JOY1 ( jsA[4:0] ),
|
|
|
|
.PS2DAT ( ps2_kbd_data ),
|
|
.PS2CLK ( ps2_kbd_clk ),
|
|
|
|
.dl_addr ( rom_dl_addr ),
|
|
.dl_data ( rom_dl_data ),
|
|
.kernal_dl_write ( kernal_dl_wr ),
|
|
.basic_dl_write ( basic_dl_wr ),
|
|
|
|
.IEC_DATAOUT ( c16_iec_data_o ),
|
|
.IEC_DATAIN ( !c16_iec_data_i ),
|
|
.IEC_CLKOUT ( c16_iec_clk_o ),
|
|
.IEC_CLKIN ( !c16_iec_clk_i ),
|
|
.IEC_ATNOUT ( c16_iec_atn_o ),
|
|
.IEC_RESET ( ),
|
|
|
|
.AUDIO_L ( AUDIO_L ),
|
|
.AUDIO_R ( AUDIO_R ),
|
|
|
|
.PAL ( c16_pal ),
|
|
|
|
.RS232_TX (),
|
|
.RGBS ()
|
|
);
|
|
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
// ------------------------------- clock generation --------------------------------
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
// the FPGATED uses two different clocks for NTSC and PAL mode.
|
|
// Switching the clocks may crash the system. We might need to force a reset it.
|
|
wire pll_locked = pll_c1541_locked && pll_c16_locked;
|
|
wire ntsc = ~c16_pal;
|
|
|
|
// tv15hkz has quarter the pixel rate, so we need a 7mhz clock for the OSD
|
|
reg clk7;
|
|
reg clk14;
|
|
|
|
always @(posedge clk28) begin
|
|
|
|
reg [1:0] counter;
|
|
|
|
counter <= counter + 1'd1;
|
|
clk7 <= !counter;
|
|
clk14 <= !counter[0];
|
|
end
|
|
|
|
// A PLL to derive the system clock from the MiSTs 27MHz
|
|
wire pll_c1541_locked, clk32;
|
|
pll_c1541 pll_c1541 (
|
|
.inclk0 ( CLOCK_27 ),
|
|
.c0 ( clk32 ),
|
|
.locked ( pll_c1541_locked )
|
|
);
|
|
|
|
wire pll_c16_locked, clk28;
|
|
pll_c16 pll_c16 (
|
|
.inclk0(CLOCK_27),
|
|
.c0(clk28),
|
|
.areset(pll_areset),
|
|
.scanclk(pll_scanclk),
|
|
.scandata(pll_scandata),
|
|
.scanclkena(pll_scanclkena),
|
|
.configupdate(pll_configupdate),
|
|
.scandataout(pll_scandataout),
|
|
.scandone(pll_scandone),
|
|
.locked(pll_c16_locked)
|
|
);
|
|
|
|
wire pll_reconfig_busy;
|
|
wire pll_areset;
|
|
wire pll_configupdate;
|
|
wire pll_scanclk;
|
|
wire pll_scanclkena;
|
|
wire pll_scandata;
|
|
wire pll_scandataout;
|
|
wire pll_scandone;
|
|
reg pll_reconfig_reset;
|
|
wire [7:0] pll_rom_address;
|
|
wire pll_rom_q;
|
|
reg pll_write_from_rom;
|
|
wire pll_write_rom_ena;
|
|
reg pll_reconfig;
|
|
wire q_reconfig_ntsc;
|
|
wire q_reconfig_pal;
|
|
|
|
rom_reconfig_pal rom_reconfig_pal
|
|
(
|
|
.address(pll_rom_address),
|
|
.clock(clk32),
|
|
.rden(pll_write_rom_ena),
|
|
.q(q_reconfig_pal)
|
|
);
|
|
|
|
rom_reconfig_ntsc rom_reconfig_ntsc
|
|
(
|
|
.address(pll_rom_address),
|
|
.clock(clk32),
|
|
.rden(pll_write_rom_ena),
|
|
.q(q_reconfig_ntsc)
|
|
);
|
|
|
|
assign pll_rom_q = ntsc ? q_reconfig_ntsc : q_reconfig_pal;
|
|
|
|
pll_reconfig pll_reconfig_inst
|
|
(
|
|
.busy(pll_reconfig_busy),
|
|
.clock(clk32),
|
|
.counter_param(0),
|
|
.counter_type(0),
|
|
.data_in(0),
|
|
.pll_areset(pll_areset),
|
|
.pll_areset_in(0),
|
|
.pll_configupdate(pll_configupdate),
|
|
.pll_scanclk(pll_scanclk),
|
|
.pll_scanclkena(pll_scanclkena),
|
|
.pll_scandata(pll_scandata),
|
|
.pll_scandataout(pll_scandataout),
|
|
.pll_scandone(pll_scandone),
|
|
.read_param(0),
|
|
.reconfig(pll_reconfig),
|
|
.reset(pll_reconfig_reset),
|
|
.reset_rom_address(0),
|
|
.rom_address_out(pll_rom_address),
|
|
.rom_data_in(pll_rom_q),
|
|
.write_from_rom(pll_write_from_rom),
|
|
.write_param(0),
|
|
.write_rom_ena(pll_write_rom_ena)
|
|
);
|
|
|
|
always @(posedge clk32) begin
|
|
reg ntsc_d, ntsc_d2, ntsc_d3;
|
|
reg [1:0] pll_reconfig_state = 0;
|
|
reg [9:0] pll_reconfig_timeout;
|
|
|
|
ntsc_d <= ntsc;
|
|
ntsc_d2 <= ntsc_d;
|
|
pll_write_from_rom <= 0;
|
|
pll_reconfig <= 0;
|
|
pll_reconfig_reset <= 0;
|
|
case (pll_reconfig_state)
|
|
2'b00:
|
|
begin
|
|
ntsc_d3 <= ntsc_d2;
|
|
if (ntsc_d2 ^ ntsc_d3) begin
|
|
pll_write_from_rom <= 1;
|
|
pll_reconfig_state <= 2'b01;
|
|
end
|
|
end
|
|
2'b01: pll_reconfig_state <= 2'b10;
|
|
2'b10:
|
|
if (~pll_reconfig_busy) begin
|
|
pll_reconfig <= 1;
|
|
pll_reconfig_state <= 2'b11;
|
|
pll_reconfig_timeout <= 10'd1000;
|
|
end
|
|
2'b11:
|
|
begin
|
|
pll_reconfig_timeout <= pll_reconfig_timeout - 1'd1;
|
|
if (pll_reconfig_timeout == 10'd1) begin
|
|
// pll_reconfig stuck in busy state
|
|
pll_reconfig_reset <= 1;
|
|
pll_reconfig_state <= 2'b00;
|
|
end
|
|
if (~pll_reconfig & ~pll_reconfig_busy) pll_reconfig_state <= 2'b00;
|
|
end
|
|
default: ;
|
|
endcase
|
|
end
|
|
// ---------------------------------------------------------------------------------
|
|
// ----------------------------------- floppy 1541 ---------------------------------
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
wire led_disk;
|
|
assign LED = !led_disk;
|
|
|
|
wire c16_iec_atn_o;
|
|
wire c16_iec_data_o;
|
|
wire c16_iec_clk_o;
|
|
|
|
wire c16_iec_atn_i = !((!c16_iec_atn_o) & (!c1541_iec_atn_o) );
|
|
wire c16_iec_data_i = !((!c16_iec_data_o) & (!c1541_iec_data_o));
|
|
wire c16_iec_clk_i = !((!c16_iec_clk_o) & (!c1541_iec_clk_o) );
|
|
|
|
wire c1541_iec_atn_o;
|
|
wire c1541_iec_data_o;
|
|
wire c1541_iec_clk_o;
|
|
|
|
wire c1541_iec_atn_i = c16_iec_atn_i;
|
|
wire c1541_iec_data_i = c16_iec_data_i;
|
|
wire c1541_iec_clk_i = c16_iec_clk_i;
|
|
|
|
c1541_sd c1541_sd (
|
|
.clk32 ( clk32 ),
|
|
.reset ( reset ),
|
|
|
|
.disk_change ( img_mounted ),
|
|
.disk_num ( 10'd0 ), // always 0 on MiST, the image is selected by the OSD menu
|
|
|
|
.iec_atn_i ( c1541_iec_atn_i ),
|
|
.iec_data_i ( c1541_iec_data_i ),
|
|
.iec_clk_i ( c1541_iec_clk_i ),
|
|
|
|
.iec_atn_o ( c1541_iec_atn_o ),
|
|
.iec_data_o ( c1541_iec_data_o ),
|
|
.iec_clk_o ( c1541_iec_clk_o ),
|
|
|
|
.sd_lba ( sd_lba ),
|
|
.sd_rd ( sd_rd ),
|
|
.sd_wr ( sd_wr ),
|
|
.sd_ack ( sd_ack ),
|
|
.sd_buff_din ( sd_din ),
|
|
.sd_buff_dout ( sd_dout ),
|
|
.sd_buff_wr ( sd_dout_strobe ),
|
|
.sd_buff_addr ( sd_buff_addr ),
|
|
.led ( led_disk ),
|
|
|
|
.c1541rom_clk ( clk28 ),
|
|
.c1541rom_addr ( rom_dl_addr ),
|
|
.c1541rom_data ( rom_dl_data ),
|
|
.c1541rom_wr ( c1541_dl_wr )
|
|
);
|
|
|
|
endmodule
|