1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-02-06 16:14:42 +00:00
Files
mist-devel.mist-board/cores/c16/c16.v
2020-02-17 22:13:44 +01:00

365 lines
9.3 KiB
Verilog

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Copyright 2013-2016 Istvan Hegedus
//
// FPGATED 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.
//
// FPGATED 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/>.
//
//
// Create Date: 12:02:05 10/24/2014
// Design Name: Commodore 16
// Module Name: C16.v
// Project Name: FPGATED
//
// Description:
// This module provides the top level framework for FPGATED. It implements a Commodore 16 computer without expansion port.
// It is written for Papilio FPGATED wing 1.x but can be easily modified for any other platforms.
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module C16 (
input wire CLK28,
input wire RESET,
input wire WAIT,
output wire HSYNC,
output wire VSYNC,
output wire CSYNC,
output wire [3:0] RED,
output wire [3:0] GREEN,
output wire [3:0] BLUE,
output wire RAS,
output wire CAS,
output wire RW,
output wire [7:0] A,
input wire [7:0] DIN,
output wire [7:0] DOUT,
output wire CS0, // Select BASIC ROM (low active)
output wire CS1, // Select Kernal ROM (low active)
output wire [3:0] ROM_SEL, // 3:2 - Kernal, Cartridge1 HIGH, Function HIGH, Cartridge2 HIGH
// 1:0 - BASIC, Cartridge2 LOW, Function LOW, Cartridge2 LOW
output wire [13:0] ROM_ADDR,
input [4:0] JOY0,
input [4:0] JOY1,
input PS2DAT,
input PS2CLK,
output IEC_DATAOUT,
input IEC_DATAIN,
output IEC_CLKOUT,
input IEC_CLKIN,
output IEC_ATNOUT,
//input IEC_ATNIN,
output IEC_RESET,
input CASS_READ,
output CASS_WRITE,
input CASS_SENSE,
output CASS_MOTOR,
input [1:0] SID_TYPE,
output [17:0] SID_AUDIO,
output AUDIO_L,
output AUDIO_R,
input [13:0] dl_addr,
input [7:0] dl_data,
input kernal_dl_write,
input basic_dl_write,
output PAL,
output RS232_TX,
output RGBS
);
parameter MODE_PAL = 1;
parameter INTERNAL_ROM = 1;
wire [15:0] c16_addr;
wire [15:0] ted_addr;
wire [15:0] cpu_addr;
wire [7:0] c16_data,ted_data,ram_data,cpu_data,basic_data,kernal_data,port_in,port_out,keyport_data;
wire [7:0] keyboard_row,kbus,kbus_kbd;
wire [7:0] keyscancode;
wire keyreceived;
wire [6:0] c16_color;
wire mux,cpuenable;
wire aec,rdy;
wire keyboardio;
wire sound;
reg [7:0] c16_datalatch=8'b0;
reg sreset=1'b0;
reg [23:0] resetcounter=24'b0;
reg [15:0] c16_addrlatch=16'b0;
wire irq1;
wire keyreset;
// wire joysticks
wire [4:0] joy0_sel = (!c16_data[2])?{!JOY0[4],!JOY0[0],!JOY0[1],!JOY0[2],!JOY0[3]}:5'h1f;
wire [4:0] joy1_sel = (!c16_data[1])?{!JOY1[4],!JOY1[0],!JOY1[1],!JOY1[2],!JOY1[3]}:5'h1f;
assign kbus[3:0] = kbus_kbd[3:0] & joy0_sel[3:0] & joy1_sel[3:0];
assign kbus[5:4] = kbus_kbd[5:4]; // no joystick line connected here
assign kbus[6] = kbus_kbd[6] & joy0_sel[4];
assign kbus[7] = kbus_kbd[7] & joy1_sel[4];
assign ROM_ADDR = c16_addr[13:0];
reg [3:0] rom_sel_reg;
wire kern = c16_addr[15:8] == 8'hFC; // FCXX is always kernal
assign ROM_SEL = { rom_sel_reg[3:2] & { ~kern, ~kern }, rom_sel_reg[1:0] };
always @(posedge CLK28) begin
if (sreset)
rom_sel_reg <= 0;
else begin
// FDD0-FDDF is ROM banking address
if (c16_addr[15:4] == 12'hFDD && ~RW) rom_sel_reg <= c16_addr[3:0];
end
end
// 8501 CPU
mos8501 cpu (
.clk(CLK28),
.reset(sreset),
.enable(cpuenable && !WAIT),
.irq_n(irq_n),
.data_in(c16_data),
.data_out(cpu_data),
.address(cpu_addr),
.gate_in(mux),
.rw(RW), // rw=high read, rw=low write
.port_in(port_in),
.port_out(port_out),
.rdy(rdy),
.aec(aec)
);
// TED 8360 instance
wire irq_n, cpuclk;
ted mos8360(
.clk(CLK28),
.addr_in(c16_addr),
.addr_out(ted_addr),
.data_in(c16_data),
.data_out(ted_data),
.rw(RW),
.cpuclk(cpuclk),
.color(c16_color),
.csync(CSYNC),
.hsync(HSYNC),
.vsync(VSYNC),
.irq(irq_n),
.ba(rdy),
.mux(mux),
.ras(RAS),
.cas(CAS),
.cs0(CS0),
.cs1(CS1),
.aec(aec),
.k(kbus),
.snd(sound),
.pal(PAL),
.cpuenable(cpuenable)
);
// Kernal rom
kernal_rom #(.MODE_PAL(MODE_PAL)) kernal(
.clk(CLK28),
.address_in(kernal_dl_write?dl_addr:c16_addr[13:0]),
.data_out(kernal_data_int),
.data_in(dl_data),
.wr(kernal_dl_write),
.cs(CS1)
);
wire [7:0] kernal_data_int;
assign kernal_data = INTERNAL_ROM ? kernal_data_int : (~CS1 & RW) ? DIN : 8'hFF;
// Basic rom
basic_rom basic(
.clk(CLK28),
.address_in(basic_dl_write?dl_addr:c16_addr[13:0]),
.data_out(basic_data_int),
.data_in(dl_data),
.wr(basic_dl_write),
.cs(CS0)
);
wire [7:0] basic_data_int;
assign basic_data = INTERNAL_ROM ? basic_data_int : (~CS0 & RW) ? DIN : 8'hFF;
// Color decoder to 12bit RGB
colors_to_rgb colordecode (
.clk(CLK28),
.color(c16_color),
.red(RED),
.green(GREEN),
.blue(BLUE)
);
// keyboard part
ps2receiver ps2rcv(
.clk(CLK28),
.ps2_clk(PS2CLK),
.ps2_data(PS2DAT),
.rx_done(keyreceived),
.ps2scancode(keyscancode)
);
c16_keymatrix keyboard(
.clk(CLK28),
.scancode(keyscancode),
.receiveflag(keyreceived),
.row(keyboard_row),
.kbus(kbus_kbd),
.keyreset(keyreset)
);
mos6529 keyport(
.clk(CLK28),
.data_in(c16_data),
.data_out(keyport_data),
.port_in(keyboard_row), // keyport 6529 in C16 is unidirectional however if we read it the last written data is read back so we feed back its output.
.port_out(keyboard_row),
.rw(RW),
.cs(keyboardio)
);
assign AUDIO_R=sound;
assign AUDIO_L=sound;
assign RGBS=1'bz; // VGA/RGBS jumper is not implemented in current version
assign RS232_TX=1'bz; // RS232 is not implemented in current version
assign keyboardio=(c16_addr[15:4]==12'hfd3)?1'b1:1'b0; // as we don't have PLA, keyport is identified here
// C16 additional motherboard functions
always @(posedge CLK28) // reset tries to emulate the length of a real reset
begin
if(RESET|keyreset) begin // reset can be triggered by reset button or CTRL+ALT+DEL from keyboard
resetcounter<=0;
sreset<=1;
end else begin
if(resetcounter==24'd16777215)
sreset<=0;
else begin
resetcounter<=resetcounter+1'd1;
sreset<=1;
end
end
end
// assign VSYNC=1'b1; // set scart mode to RGB for TV
assign c16_addr=(~mux)?c16_addrlatch:cpu_addr&ted_addr; // C16 address bus
assign c16_data=(mux)?c16_datalatch:cpu_data&ted_data&ram_data&kernal_data&basic_data&keyport_data&cass_data&sid_data; // C16 data bus
always @(posedge CLK28) // addres and data bus latching emulates dynamic memory behaviour of these buses
begin
c16_datalatch<=c16_data;
c16_addrlatch<=c16_addr;
end
// external 4464 DRAM signal connections on Papilio FPGATED wing
assign A=(~mux)?c16_addr[15:8]:c16_addr[7:0]; // DRAM address multiplexer for TMS4464 address lines
assign DOUT=c16_data; // only drive external TMS4464 data lines when there is a write cycle
assign ram_data=(RW & ~CAS)?DIN:8'hff; // internal ram_data should be 0xff when external RAM's data line is in high impedance state
// connect IEC bus
assign IEC_DATAOUT=~port_out[0];
assign port_in[7]=IEC_DATAIN & IEC_DATAOUT;
assign IEC_CLKOUT=~port_out[1];
assign port_in[6]=IEC_CLKIN & IEC_CLKOUT;
assign IEC_ATNOUT=~port_out[2];
//assign ATN=IEC_ATNIN;
assign IEC_RESET=sreset;
assign CASS_MOTOR = port_out[3];
assign port_in[4] = CASS_READ;
wire cass_sel = cpu_addr[15:4] == 12'hFD1;
wire [7:0] cass_data = { 5'b11111, cass_sel ? CASS_SENSE : 1'b1, 2'b11 };
assign CASS_WRITE = port_out[6];
// SID extension
reg sid_clk_en;
always @(posedge CLK28) begin
reg muxD, sid_clk;
sid_clk_en <= 0;
muxD <= mux;
if (~muxD & mux) begin
sid_clk <= ~sid_clk;
sid_clk_en <= sid_clk;
end
end
// valid adresses for SID: FD40-FD5F and FE80-FE9F
wire cs_sid = SID_TYPE && ((c16_addr[15:5] == 'b1111_1101_010) || (c16_addr[15:5] == 'b1111_1110_100));
wire [7:0] sid8580_data;
wire [15:0] sid8580_audio;
sid8580 sid8580
(
.reset(sreset),
.clk32(CLK28),
.clk_1MHz(sid_clk_en),
.cs(cs_sid),
.we(~RW),
.addr(c16_addr[4:0]),
.data_in(c16_data),
.data_out(sid8580_data),
.extfilter_en(1),
.audio_data(sid8580_audio)
);
wire [7:0] sid6581_data;
wire [17:0] sid6581_audio;
sid_top #(.g_num_voices(3)) sid6581
(
.reset(sreset),
.clock(CLK28),
.start_iter(sid_clk_en),
.wren(~RW & cs_sid),
.addr({ 3'd0, c16_addr[4:0] }),
.wdata(c16_data),
.rdata(sid6581_data),
.extfilter_en(1),
.sample_left(sid6581_audio)
);
assign SID_AUDIO = SID_TYPE[0] ? sid6581_audio : (SID_TYPE[1] ? { sid8580_audio, 2'd0 } : 18'd0);
wire [7:0] sid_data = (cs_sid & RW) ? (SID_TYPE[0] ? sid6581_data : sid8580_data) : 8'hFF;
endmodule