fork Gehstock's project

This commit is contained in:
nino-porcino 2021-12-29 16:18:10 +01:00
parent fe6a59aed6
commit 03281591f6
59 changed files with 25750 additions and 0 deletions

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
Test
build_id.v
db
history.db
greybox_tmp
incremental_db
output_files
simulation
PLLJ_PLLSPE_INFO.txt
*.bak
*.orig
*.rej
*.qdf
*.rpt
*.smsg
*.summary
*.done
*.jdi
*.pin
*.sof
*.qws
*.ppf
*.ddb
*.srf

15
README.md Normal file
View File

@ -0,0 +1,15 @@
# Apple1_MIST
Apple1 implementation for the MiST FPGA.
This was forked from [Gehstock's project](https://github.com/Gehstock/Mist_FPGA).
## CHANGELOG
2021-12-28
- 15 kHz video output (NTSC) and use of MiST scandoubler/video pipeline
- more accurate 7x8 character matrix (5x7 + hardware spacing)
- clock is now derived from 14.31818 instead of 25 MHz (more accurate)
- serial port communication feature is disabled/removed

30
apple-one.qpf Normal file
View File

@ -0,0 +1,30 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2013 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 64-Bit
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
# Date created = 21:11:27 January 26, 2018
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "13.1"
DATE = "21:11:27 January 26, 2018"
# Revisions
PROJECT_REVISION = "apple-one"

192
apple-one.qsf Normal file
View File

@ -0,0 +1,192 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2013 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 64-Bit
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
# Date created = 11:23:36 April 10, 2018
#
# -------------------------------------------------------------------------- #
#
# Notes:
#
# 1) The default values for assignments are stored in the file:
# apple-one_assignment_defaults.qdf
# If this file doesn't exist, see file:
# assignment_defaults.qdf
#
# 2) Altera recommends that you do not modify this file. This
# file is updated automatically by the Quartus II software
# and any changes you make may be lost or overwritten.
#
# -------------------------------------------------------------------------- #
# Project-Wide Assignments
# ========================
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:11:27 JANUARY 26, 2018"
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
# Classic Timing Assignments
# ==========================
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
# Analysis & Synthesis Assignments
# ================================
set_global_assignment -name FAMILY "Cyclone III"
set_global_assignment -name TOP_LEVEL_ENTITY apple1_mist
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8
# Fitter Assignments
# ==================
set_global_assignment -name DEVICE EP3C25E144C8
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF
set_global_assignment -name ENABLE_NCE_PIN OFF
set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF
set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL"
set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON
set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO"
# EDA Netlist Writer Assignments
# ==============================
set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (VHDL)"
# Assembler Assignments
# =====================
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name GENERATE_RBF_FILE ON
# Power Estimation Assignments
# ============================
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
# Advanced I/O Timing Assignments
# ===============================
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
# start EDA_TOOL_SETTINGS(eda_simulation)
# ---------------------------------------
# EDA Netlist Writer Assignments
# ==============================
set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation
# end EDA_TOOL_SETTINGS(eda_simulation)
# -------------------------------------
# start DESIGN_PARTITION(Top)
# ---------------------------
# Incremental Compilation Assignments
# ===================================
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
# end DESIGN_PARTITION(Top)
# -------------------------
# Pin & Location Assignments
# ==========================
set_location_assignment PIN_7 -to LED
set_location_assignment PIN_54 -to CLOCK_27
set_location_assignment PIN_144 -to VGA_R[5]
set_location_assignment PIN_143 -to VGA_R[4]
set_location_assignment PIN_142 -to VGA_R[3]
set_location_assignment PIN_141 -to VGA_R[2]
set_location_assignment PIN_137 -to VGA_R[1]
set_location_assignment PIN_135 -to VGA_R[0]
set_location_assignment PIN_133 -to VGA_B[5]
set_location_assignment PIN_132 -to VGA_B[4]
set_location_assignment PIN_125 -to VGA_B[3]
set_location_assignment PIN_121 -to VGA_B[2]
set_location_assignment PIN_120 -to VGA_B[1]
set_location_assignment PIN_115 -to VGA_B[0]
set_location_assignment PIN_114 -to VGA_G[5]
set_location_assignment PIN_113 -to VGA_G[4]
set_location_assignment PIN_112 -to VGA_G[3]
set_location_assignment PIN_111 -to VGA_G[2]
set_location_assignment PIN_110 -to VGA_G[1]
set_location_assignment PIN_106 -to VGA_G[0]
set_location_assignment PIN_136 -to VGA_VS
set_location_assignment PIN_119 -to VGA_HS
set_location_assignment PIN_65 -to AUDIO_L
set_location_assignment PIN_80 -to AUDIO_R
set_location_assignment PIN_105 -to SPI_DO
set_location_assignment PIN_88 -to SPI_DI
set_location_assignment PIN_126 -to SPI_SCK
set_location_assignment PIN_127 -to SPI_SS2
set_location_assignment PIN_91 -to SPI_SS3
set_location_assignment PIN_13 -to CONF_DATA0
set_location_assignment PLL_1 -to "pll:pll|altpll:altpll_component"
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl"
# end ENTITY(apple1_mist)
# -----------------------
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/user_io.v"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/sd_card.v"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/scandoubler.v"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/rgb2ypbpr.v"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/osd.v"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/mist_video.v"
set_global_assignment -name QIP_FILE "rtl/mist-modules/mist_core.qip"
set_global_assignment -name VHDL_FILE "rtl/mist-modules/mist.vhd"
set_global_assignment -name QIP_FILE "rtl/mist-modules/mist.qip"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/data_io.v"
set_global_assignment -name VHDL_FILE "rtl/mist-modules/dac.vhd"
set_global_assignment -name SYSTEMVERILOG_FILE "rtl/mist-modules/cofi.sv"
set_global_assignment -name VERILOG_FILE "rtl/mist-modules/arcade_inputs.v"
set_global_assignment -name VERILOG_FILE rtl/arlet_6502/cpu.v
set_global_assignment -name VERILOG_FILE rtl/arlet_6502/ALU.v
set_global_assignment -name VERILOG_FILE rtl/arlet_6502/arlet_6502.v
set_global_assignment -name VERILOG_FILE rtl/apple1.v
set_global_assignment -name VERILOG_FILE rtl/clock.v
set_global_assignment -name VERILOG_FILE rtl/pwr_reset.v
set_global_assignment -name VERILOG_FILE rtl/ram.v
set_global_assignment -name VERILOG_FILE rtl/rom_basic.v
set_global_assignment -name VERILOG_FILE rtl/rom_wozmon.v
set_global_assignment -name VERILOG_FILE rtl/vram.v
set_global_assignment -name VERILOG_FILE rtl/uart.v
set_global_assignment -name VERILOG_FILE rtl/ps2keyboard.v
set_global_assignment -name VERILOG_FILE rtl/vga.v
set_global_assignment -name VERILOG_FILE rtl/async_tx_rx.v
set_global_assignment -name VERILOG_FILE rtl/font_rom.v
set_global_assignment -name SYSTEMVERILOG_FILE rtl/video_mixer.sv
set_global_assignment -name VERILOG_FILE rtl/scandoubler.v
set_global_assignment -name QIP_FILE rtl/pll.qip
set_global_assignment -name VERILOG_FILE rtl/osd.v
set_global_assignment -name VERILOG_FILE rtl/mist_io.v
set_global_assignment -name SYSTEMVERILOG_FILE rtl/hq2x.sv
set_global_assignment -name SYSTEMVERILOG_FILE rtl/apple1_mist.sv
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

37
clean.bat Normal file
View File

@ -0,0 +1,37 @@
@echo off
del /s *.bak
del /s *.orig
del /s *.rej
del /s *~
rmdir /s /q db
rmdir /s /q incremental_db
rmdir /s /q output_files
rmdir /s /q simulation
rmdir /s /q greybox_tmp
rmdir /s /q hc_output
rmdir /s /q .qsys_edit
rmdir /s /q hps_isw_handoff
rmdir /s /q sys\.qsys_edit
rmdir /s /q sys\vip
cd sys
for /d %%i in (*_sim) do rmdir /s /q "%%~nxi"
cd ..
for /d %%i in (*_sim) do rmdir /s /q "%%~nxi"
del build_id.v
del c5_pin_model_dump.txt
del PLLJ_PLLSPE_INFO.txt
del /s *.qws
del /s *.ppf
del /s *.ddb
del /s *.csv
del /s *.cmp
del /s *.sip
del /s *.spd
del /s *.bsf
del /s *.f
del /s *.sopcinfo
del /s *.xml
del /s new_rtl_netlist
del /s old_rtl_netlist
pause

0
pll.qip Normal file
View File

263
rtl/apple1.v Normal file
View File

@ -0,0 +1,263 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: Apple1 hardware core
//
// Author.....: Alan Garfield
// Niels A. Moseley
// Date.......: 26-1-2018
//
module apple1(
input clk14, // 25 MHz master clock
input rst_n, // active low synchronous reset (needed for simulation)
// I/O interface to computer
input uart_rx, // asynchronous serial data input from computer
output uart_tx, // asynchronous serial data output to computer
output uart_cts, // clear to send flag to computer
// I/O interface to keyboard
input ps2_clk, // PS/2 keyboard serial clock input
input ps2_din, // PS/2 keyboard serial data input
input ps2_select, // Input to select the PS/2 keyboard instead of the UART
// Outputs to VGA display
output vga_h_sync, // hozizontal VGA sync pulse
output vga_v_sync, // vertical VGA sync pulse
output vga_red, // red VGA signal
output vga_grn, // green VGA signal
output vga_blu, // blue VGA signal
input vga_cls, // clear screen button
// Debugging ports
output [15:0] pc_monitor // spy for program counter / debugging
);
//////////////////////////////////////////////////////////////////////////
// Registers and Wires
wire [15:0] ab;
wire [7:0] dbi;
wire [7:0] dbo;
wire we;
//////////////////////////////////////////////////////////////////////////
// Clocks
wire cpu_clken;
clock clock(
.clk14(clk14),
.rst_n(rst_n),
.cpu_clken(cpu_clken)
);
//////////////////////////////////////////////////////////////////////////
// Reset
wire rst;
pwr_reset pwr_reset(
.clk14(clk14),
.rst_n(rst_n),
.enable(cpu_clken),
.rst(rst)
);
//////////////////////////////////////////////////////////////////////////
// 6502
arlet_6502 arlet_6502(
.clk (clk14),
.enable (cpu_clken),
.rst (rst),
.ab (ab),
.dbi (dbi),
.dbo (dbo),
.we (we),
.irq_n (1'b1),
.nmi_n (1'b1),
.ready (cpu_clken),
.pc_monitor (pc_monitor)
);
//////////////////////////////////////////////////////////////////////////
// Address Decoding
wire ram_cs = (ab[15:13] == 3'b000); // 0x0000 -> 0x1FFF
// font mode, background and foreground colour
wire vga_mode_cs = (ab[15:2] == 14'b11000000000000); // 0xC000 -> 0xC003
// RX: Either keyboard or UART input
// TX: Always VGA and UART output
wire rx_cs = (ab[15:1] == 15'b110100000001000); // 0xD010 -> 0xD011
wire tx_cs = (ab[15:1] == 15'b110100000001001); // 0xD012 -> 0xD013
// select UART on transmit but only receive when PS/2 is not selected.
wire uart_cs = tx_cs | ((~ps2_select) & rx_cs);
// select PS/2 keyboard input when selected.
wire ps2kb_cs = ps2_select & rx_cs;
// VGA always get characters when they are sent.
wire vga_cs = tx_cs;
wire basic_cs = (ab[15:12] == 4'b1110); // 0xE000 -> 0xEFFF
wire rom_cs = (ab[15:8] == 8'b11111111); // 0xFF00 -> 0xFFFF
//////////////////////////////////////////////////////////////////////////
// RAM and ROM
// RAM
wire [7:0] ram_dout;
ram ram(
.clk(clk14),
.address(ab[12:0]),
.w_en(we & ram_cs),
.din(dbo),
.dout(ram_dout)
);
// WozMon ROM
wire [7:0] rom_dout;
rom_wozmon rom_wozmon(
.clk(clk14),
.address(ab[7:0]),
.dout(rom_dout)
);
// Basic ROM
wire [7:0] basic_dout;
rom_basic rom_basic(
.clk(clk14),
.address(ab[11:0]),
.dout(basic_dout)
);
//////////////////////////////////////////////////////////////////////////
// Peripherals
// UART
wire [7:0] uart_dout;
uart #(
`ifdef SIM
100, 10, 2 // for simulation don't need real baud rates
`else
25000000, 115200, 8 // 25MHz, 115200 baud, 8 times RX oversampling
`endif
) my_uart(
.clk(clk14),
.enable(uart_cs & cpu_clken),
.rst(rst),
.uart_rx(uart_rx),
.uart_tx(uart_tx),
.uart_cts(uart_cts),
.address(ab[1:0]), // for uart
.w_en(we & uart_cs),
.din(dbo),
.dout(uart_dout)
);
// PS/2 keyboard interface
wire [7:0] ps2_dout;
ps2keyboard keyboard(
.clk14(clk14),
.rst(rst),
.key_clk(ps2_clk),
.key_din(ps2_din),
.cs(ps2kb_cs),
.address(ab[0]),
.dout(ps2_dout)
);
// VGA Display interface
reg [2:0] fg_colour;
reg [2:0] bg_colour;
reg [1:0] font_mode;
reg [7:0] vga_mode_dout;
vga vga(
.clk14(clk14),
.enable(vga_cs & cpu_clken),
.rst(rst),
.vga_h_sync(vga_h_sync),
.vga_v_sync(vga_v_sync),
.vga_red(vga_red),
.vga_grn(vga_grn),
.vga_blu(vga_blu),
.address(ab[0]),
.w_en(we & vga_cs),
.din(dbo),
.mode(font_mode),
.fg_colour(fg_colour),
.bg_colour(bg_colour),
.clr_screen(vga_cls)
);
// Handle font mode and foreground and background
// colours. This so isn't Apple One authentic, but
// it can't hurt to have some fun. :D
always @(posedge clk14 or posedge rst)
begin
if (rst)
begin
font_mode <= 2'b0;
fg_colour <= 3'd7;
bg_colour <= 3'd0;
end
else
begin
case (ab[1:0])
2'b00:
begin
vga_mode_dout = {6'b0, font_mode};
if (vga_mode_cs & we & cpu_clken)
font_mode <= dbo[1:0];
end
2'b01:
begin
vga_mode_dout = {5'b0, fg_colour};
if (vga_mode_cs & we & cpu_clken)
fg_colour <= dbo[2:0];
end
2'b10:
begin
vga_mode_dout = {5'b0, bg_colour};
if (vga_mode_cs & we & cpu_clken)
bg_colour <= dbo[2:0];
end
default:
vga_mode_dout = 8'b0;
endcase
end
end
//////////////////////////////////////////////////////////////////////////
// CPU Data In MUX
// link up chip selected device to cpu input
assign dbi = ram_cs ? ram_dout :
rom_cs ? rom_dout :
basic_cs ? basic_dout :
uart_cs ? uart_dout :
ps2kb_cs ? ps2_dout :
vga_mode_cs ? vga_mode_dout :
8'hFF;
endmodule

201
rtl/apple1_mist.sv Normal file
View File

@ -0,0 +1,201 @@
// Apple-1 for MiST
//
// Forked from Gehstock's implementation https://github.com/Gehstock/Mist_FPGA
//
//
// TODO integrate with mist-modules
// TODO load binary files into memory
// TODO support ACI interface for load and save
// TODO additional RAM with SDRAM
// TODO reset key from keyboard
// TODO cls key from keyboard
// TODO power on-off
// TODO special expansion boards: TMS9918, SID
// TODO white/green/amber switch?
// TODO reset if pll not locked
// TODO rename "vga" into "display"
// TODO reorganize file structure
// TODO check ps2 clock
module apple1_mist(
input CLOCK_27,
// SPI interface to arm io controller
input SPI_SCK,
output SPI_DO,
input SPI_DI,
//input SPI_SS2,
input SPI_SS3,
//input SPI_SS4,
input CONF_DATA0,
// 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
// VGA interface
output [5:0] VGA_R,
output [5:0] VGA_G,
output [5:0] VGA_B,
output VGA_HS,
output VGA_VS,
// other
output LED,
input UART_RX,
output AUDIO_L,
output AUDIO_R
);
`include "rtl\build_id.v"
/******************************************************************************************/
/******************************************************************************************/
/***************************************** @user_io ***************************************/
/******************************************************************************************/
/******************************************************************************************/
localparam CONF_STR = {
"APPLE 1;;",
"O34,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;",
"T6,Reset;",
"V,v1.00.",`BUILD_DATE
};
localparam conf_str_len = $size(CONF_STR)>>3;
wire st_reset_switch = buttons[1];
wire st_menu_reset = status[6];
wire clk14; // the 14.31818 MHz clock
wire clk_osd; // x4 clock for the OSD menu
wire r, g, b;
wire hs, vs;
wire [31:0] status;
wire [1:0] buttons;
wire [1:0] switches;
wire scandoubler_disable;
wire ypbpr;
wire no_csync;
wire ps2_kbd_clk;
wire ps2_kbd_data;
assign LED = 1;
wire reset_button = status[0] | st_menu_reset | st_reset_switch;
pll pll
(
.inclk0(CLOCK_27),
.c0(clk_osd),
.c1(clk14),
.locked(),
.areset()
);
apple1 apple1
(
.clk14(clk14),
.rst_n(~reset_button),
.uart_rx(), // uart not connected
.uart_tx(), // uart not connected
.uart_cts(), // uart not connected
.ps2_clk(ps2_kbd_clk),
.ps2_din(ps2_kbd_data),
.ps2_select(1'b1),
.vga_h_sync(hs),
.vga_v_sync(vs),
.vga_red(r),
.vga_grn(g),
.vga_blu(b),
.vga_cls(), // clear screen button (not connected yet)
.pc_monitor() // debug program counter (not used)
);
mist_video
#(
.COLOR_DEPTH(1),
.OSD_AUTO_CE(1)
)
mist_video
(
.clk_sys(clk_osd), // 2x the VDP clock for the scandoubler
// OSD SPI interface
.SPI_DI(SPI_DI),
.SPI_SCK(SPI_SCK),
.SPI_SS3(SPI_SS3),
.scanlines(2'b00), // scanlines (00-none 01-25% 10-50% 11-75%)
.ce_divider(1), // non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2
.scandoubler_disable(scandoubler_disable),
.no_csync(no_csync), // 1 = disable csync without scandoubler
.ypbpr(ypbpr), // 1 = YPbPr output on composite sync
.rotate(2'b00), // Rotate OSD [0] - rotate [1] - left or right
.blend(0), // composite-like blending
// video input
.R(r),
.G(g),
.B(b),
.HSync(hs),
.VSync(vs),
// MiST video output signals
.VGA_R(VGA_R),
.VGA_G(VGA_G),
.VGA_B(VGA_B),
.VGA_VS(VGA_VS),
.VGA_HS(VGA_HS),
);
user_io
#(
.STRLEN(conf_str_len)
//.PS2DIV(14) // ps2 clock divider: CLOCK / 14 must be approx = 15 Khz
)
user_io (
.conf_str (CONF_STR ),
.clk_sys (clk14 ),
.SPI_CLK (SPI_SCK ),
.SPI_SS_IO (CONF_DATA0 ),
.SPI_MISO (SPI_DO ),
.SPI_MOSI (SPI_DI ),
.status (status ),
.buttons (buttons ),
.switches (switches ),
.scandoubler_disable ( scandoubler_disable ),
.ypbpr ( ypbpr ),
.no_csync ( no_csync ),
// ps2 interface
.ps2_kbd_clk (ps2_kbd_clk ),
.ps2_kbd_data (ps2_kbd_data )
);
endmodule

108
rtl/arlet_6502/ALU.v Normal file
View File

@ -0,0 +1,108 @@
/*
* ALU.
*
* AI and BI are 8 bit inputs. Result in OUT.
* CI is Carry In.
* CO is Carry Out.
*
* op[3:0] is defined as follows:
*
* 0011 AI + BI
* 0111 AI - BI
* 1011 AI + AI
* 1100 AI | BI
* 1101 AI & BI
* 1110 AI ^ BI
* 1111 AI
*
*/
module ALU( clk, op, right, AI, BI, CI, CO, BCD, OUT, V, Z, N, HC, RDY );
input clk;
input right;
input [3:0] op; // operation
input [7:0] AI;
input [7:0] BI;
input CI;
input BCD; // BCD style carry
output [7:0] OUT;
output CO;
output V;
output Z;
output N;
output HC;
input RDY;
reg [7:0] OUT;
reg CO;
wire V;
wire Z;
reg N;
reg HC;
reg AI7;
reg BI7;
reg [8:0] temp_logic;
reg [7:0] temp_BI;
reg [4:0] temp_l;
reg [4:0] temp_h;
wire [8:0] temp = { temp_h, temp_l[3:0] };
wire adder_CI = (right | (op[3:2] == 2'b11)) ? 0 : CI;
// calculate the logic operations. The 'case' can be done in 1 LUT per
// bit. The 'right' shift is a simple mux that can be implemented by
// F5MUX.
always @* begin
case( op[1:0] )
2'b00: temp_logic = AI | BI;
2'b01: temp_logic = AI & BI;
2'b10: temp_logic = AI ^ BI;
2'b11: temp_logic = AI;
endcase
if( right )
temp_logic = { AI[0], CI, AI[7:1] };
end
// Add logic result to BI input. This only makes sense when logic = AI.
// This stage can be done in 1 LUT per bit, using carry chain logic.
always @* begin
case( op[3:2] )
2'b00: temp_BI = BI; // A+B
2'b01: temp_BI = ~BI; // A-B
2'b10: temp_BI = temp_logic; // A+A
2'b11: temp_BI = 0; // A+0
endcase
end
// HC9 is the half carry bit when doing BCD add
wire HC9 = BCD & (temp_l[3:1] >= 3'd5);
// CO9 is the carry-out bit when doing BCD add
wire CO9 = BCD & (temp_h[3:1] >= 3'd5);
// combined half carry bit
wire temp_HC = temp_l[4] | HC9;
// perform the addition as 2 separate nibble, so we get
// access to the half carry flag
always @* begin
temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI;
temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC;
end
// calculate the flags
always @(posedge clk)
if( RDY ) begin
AI7 <= AI[7];
BI7 <= temp_BI[7];
OUT <= temp[7:0];
CO <= temp[8] | CO9;
N <= temp[7];
HC <= temp_HC;
end
assign V = AI7 ^ BI7 ^ CO ^ N;
assign Z = ~|OUT;
endmodule

View File

@ -0,0 +1,72 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: A wrapper for Arlet Ottens 6502 CPU core
//
// Author.....: Alan Garfield
// Niels A. Moseley
// Date.......: 26-1-2018
//
module arlet_6502(
input clk, // clock signal
input enable, // clock enable strobe
input rst, // active high reset signal
output reg [15:0] ab, // address bus
input [7:0] dbi, // 8-bit data bus (input)
output reg [7:0] dbo, // 8-bit data bus (output)
output reg we, // active high write enable strobe
input irq_n, // active low interrupt request
input nmi_n, // active low non-maskable interrupt
input ready, // CPU updates when ready = 1
output [15:0] pc_monitor // program counter monitor signal for debugging
);
wire [7:0] dbo_c;
wire [15:0] ab_c;
wire we_c;
cpu arlet_cpu(
.clk(clk),
.reset(rst),
.AB(ab_c),
.DI(dbi),
.DO(dbo_c),
.WE(we_c),
.IRQ(~irq_n),
.NMI(~nmi_n),
.RDY(ready),
.PC_MONITOR(pc_monitor)
);
always @(posedge clk or posedge rst)
begin
if (rst)
begin
ab <= 16'd0;
dbo <= 8'd0;
we <= 1'b0;
end
else
if (enable)
begin
ab <= ab_c;
dbo <= dbo_c;
we <= we_c;
end
end
endmodule

View File

@ -0,0 +1,66 @@
`include "../rtl/cpu/aholme/chip_6502_nodes.inc"
module LOGIC (
input [`NUM_NODES-1:0] i,
output [`NUM_NODES-1:0] o);
`include "chip_6502_logic.inc"
endmodule
module chip_6502 (
input clk, // FPGA clock
input phi, // 6502 clock
input res,
input so,
input rdy,
input nmi,
input irq,
input [7:0] dbi,
output [7:0] dbo,
output rw,
output sync,
output [15:0] ab);
// Node states
wire [`NUM_NODES-1:0] no;
reg [`NUM_NODES-1:0] ni;
reg [`NUM_NODES-1:0] q = 0;
LOGIC logic_00 (.i(ni), .o(no));
always @ (posedge clk)
q <= no;
always @* begin
ni = q;
ni[`NODE_vcc ] = 1'b1;
ni[`NODE_vss ] = 1'b0;
ni[`NODE_res ] = res;
ni[`NODE_clk0] = phi;
ni[`NODE_so ] = so;
ni[`NODE_rdy ] = rdy;
ni[`NODE_nmi ] = nmi;
ni[`NODE_irq ] = irq;
{ni[`NODE_db7],ni[`NODE_db6],ni[`NODE_db5],ni[`NODE_db4],
ni[`NODE_db3],ni[`NODE_db2],ni[`NODE_db1],ni[`NODE_db0]} = dbi[7:0];
end
assign dbo[7:0] = {
no[`NODE_db7],no[`NODE_db6],no[`NODE_db5],no[`NODE_db4],
no[`NODE_db3],no[`NODE_db2],no[`NODE_db1],no[`NODE_db0]
};
assign ab[15:0] = {
no[`NODE_ab15], no[`NODE_ab14], no[`NODE_ab13], no[`NODE_ab12],
no[`NODE_ab11], no[`NODE_ab10], no[`NODE_ab9], no[`NODE_ab8],
no[`NODE_ab7], no[`NODE_ab6], no[`NODE_ab5], no[`NODE_ab4],
no[`NODE_ab3], no[`NODE_ab2], no[`NODE_ab1], no[`NODE_ab0]
};
assign rw = no[`NODE_rw];
assign sync = no[`NODE_sync];
endmodule

View File

@ -0,0 +1,10 @@
module MUX #(
parameter N=1
) (
output wire o,
input wire i,
input wire [N-1:0] s,
input wire [N-1:0] d);
assign o = (|s) ? &(d|(~s)) : i;
endmodule

1244
rtl/arlet_6502/cpu.v Normal file

File diff suppressed because it is too large Load Diff

227
rtl/async_tx_rx.v Normal file
View File

@ -0,0 +1,227 @@
////////////////////////////////////////////////////////
// RS-232 RX and TX module
// (c) fpga4fun.com & KNJN LLC - 2003 to 2016
// The RS-232 settings are fixed
// TX: 8-bit data, 2 stop, no-parity
// RX: 8-bit data, 1 stop, no-parity (the receiver can accept more stop bits of course)
////////////////////////////////////////////////////////
module async_transmitter(
input clk,
input rst,
input TxD_start,
input [7:0] TxD_data,
output TxD,
output TxD_busy
);
// Assert TxD_start for (at least) one clock cycle to start transmission of TxD_data
// TxD_data is latched so that it doesn't have to stay valid while it is being sent
parameter ClkFrequency = 25000000; // 25MHz
parameter Baud = 115200;
////////////////////////////////
wire BitTick;
BaudTickGen #(ClkFrequency, Baud) tickgen(.clk(clk), .rst(rst), .enable(TxD_busy), .tick(BitTick));
reg [3:0] TxD_state;
reg [7:0] TxD_shift;
wire TxD_ready = (TxD_state==0);
assign TxD_busy = ~TxD_ready;
always @(posedge clk or posedge rst)
begin
if (rst)
begin
TxD_state <= 0;
TxD_shift <= 0;
end
else
begin
if(TxD_ready & TxD_start)
TxD_shift <= TxD_data;
else
if(TxD_state[3] & BitTick)
TxD_shift <= (TxD_shift >> 1);
case(TxD_state)
4'b0000: if(TxD_start) TxD_state <= 4'b0100;
4'b0100: if(BitTick) TxD_state <= 4'b1000; // start bit
4'b1000: if(BitTick) TxD_state <= 4'b1001; // bit 0
4'b1001: if(BitTick) TxD_state <= 4'b1010; // bit 1
4'b1010: if(BitTick) TxD_state <= 4'b1011; // bit 2
4'b1011: if(BitTick) TxD_state <= 4'b1100; // bit 3
4'b1100: if(BitTick) TxD_state <= 4'b1101; // bit 4
4'b1101: if(BitTick) TxD_state <= 4'b1110; // bit 5
4'b1110: if(BitTick) TxD_state <= 4'b1111; // bit 6
4'b1111: if(BitTick) TxD_state <= 4'b0010; // bit 7
4'b0010: if(BitTick) TxD_state <= 4'b0011; // stop1
4'b0011: if(BitTick) TxD_state <= 4'b0000; // stop2
default: if(BitTick) TxD_state <= 4'b0000;
endcase
end
end
assign TxD = (TxD_state<4) | (TxD_state[3] & TxD_shift[0]);
endmodule
////////////////////////////////////////////////////////
module async_receiver(
input clk,
input rst,
input RxD,
output reg RxD_data_ready,
output reg [7:0] RxD_data, // data received, valid only (for one clock cycle) when RxD_data_ready is asserted
// We also detect if a gap occurs in the received stream of characters
// That can be useful if multiple characters are sent in burst
// so that multiple characters can be treated as a "packet"
output RxD_idle, // asserted when no data has been received for a while
output reg RxD_endofpacket = 0 // asserted for one clock cycle when a packet has been detected (i.e. RxD_idle is going high)
);
parameter ClkFrequency = 25000000; // 12MHz
parameter Baud = 115200;
parameter Oversampling = 8; // needs to be a power of 2
// we oversample the RxD line at a fixed rate to capture each RxD data bit at the "right" time
// 8 times oversampling by default, use 16 for higher quality reception
////////////////////////////////
reg [3:0] RxD_state;
wire OversamplingTick;
BaudTickGen #(ClkFrequency, Baud, Oversampling) tickgen(.clk(clk), .rst(rst), .enable(1'b1), .tick(OversamplingTick));
// synchronize RxD to our clk domain
reg [1:0] RxD_sync; // 2'b11
always @(posedge clk or posedge rst)
begin
if (rst)
RxD_sync <= 2'b11;
else
if(OversamplingTick) RxD_sync <= {RxD_sync[0], RxD};
end
// and filter it
reg [1:0] Filter_cnt; // 2'b11
reg RxD_bit; // 1'b1
always @(posedge clk or posedge rst)
begin
if (rst)
begin
Filter_cnt <= 2'b11;
RxD_bit <= 1'b1;
end
else
if(OversamplingTick)
begin
if(RxD_sync[1]==1'b1 && Filter_cnt!=2'b11) Filter_cnt <= Filter_cnt + 1'd1;
else if(RxD_sync[1]==1'b0 && Filter_cnt!=2'b00) Filter_cnt <= Filter_cnt - 1'd1;
if(Filter_cnt==2'b11) RxD_bit <= 1'b1;
else if(Filter_cnt==2'b00) RxD_bit <= 1'b0;
end
end
// and decide when is the good time to sample the RxD line
function integer log2(input integer v);
begin
log2=0;
while(v>>log2)
log2 = log2 + 1;
end
endfunction
localparam l2o = log2(Oversampling);
reg [l2o-2:0] OversamplingCnt;
always @(posedge clk)
if(OversamplingTick) OversamplingCnt <= (RxD_state==0) ? 1'd0 : OversamplingCnt + 1'd1;
wire sampleNow = OversamplingTick && (OversamplingCnt==Oversampling/2-1);
// now we can accumulate the RxD bits in a shift-register
always @(posedge clk or posedge rst)
begin
if (rst)
RxD_state <= 0;
else
case(RxD_state)
4'b0000: if(~RxD_bit) RxD_state <= 4'b0001; // start bit found?
4'b0001: if(sampleNow) RxD_state <= 4'b1000; // sync start bit to sampleNow
4'b1000: if(sampleNow) RxD_state <= 4'b1001; // bit 0
4'b1001: if(sampleNow) RxD_state <= 4'b1010; // bit 1
4'b1010: if(sampleNow) RxD_state <= 4'b1011; // bit 2
4'b1011: if(sampleNow) RxD_state <= 4'b1100; // bit 3
4'b1100: if(sampleNow) RxD_state <= 4'b1101; // bit 4
4'b1101: if(sampleNow) RxD_state <= 4'b1110; // bit 5
4'b1110: if(sampleNow) RxD_state <= 4'b1111; // bit 6
4'b1111: if(sampleNow) RxD_state <= 4'b0010; // bit 7
4'b0010: if(sampleNow) RxD_state <= 4'b0000; // stop bit
default: RxD_state <= 4'b0000;
endcase
end
always @(posedge clk or posedge rst)
begin
if (rst)
RxD_data <= 0;
else
if (sampleNow && RxD_state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]};
end
always @(posedge clk or posedge rst)
begin
if (rst)
RxD_data_ready <= 0;
else
RxD_data_ready <= (sampleNow && RxD_state==4'b0010 && RxD_bit); // make sure a stop bit is received
end
reg [l2o+1:0] GapCnt;
always @(posedge clk or posedge rst)
begin
if (rst)
GapCnt <= 0;
else
if (RxD_state!=0) GapCnt<=0; else if(OversamplingTick & ~GapCnt[log2(Oversampling)+1]) GapCnt <= GapCnt + 1'h1;
end
assign RxD_idle = GapCnt[l2o+1];
always @(posedge clk)
RxD_endofpacket <= OversamplingTick & ~GapCnt[l2o+1] & &GapCnt[l2o:0];
endmodule
////////////////////////////////////////////////////////
module BaudTickGen(
input clk, rst, enable,
output tick // generate a tick at the specified baud rate * oversampling
);
parameter ClkFrequency = 25000000;
parameter Baud = 115200;
parameter Oversampling = 1;
function integer log2(input integer v); begin log2=0; while(v>>log2) log2=log2+1; end endfunction
localparam AccWidth = log2(ClkFrequency/Baud)+8; // +/- 2% max timing error over a byte
reg [AccWidth:0] Acc;
localparam ShiftLimiter = log2(Baud*Oversampling >> (31-AccWidth)); // this makes sure Inc calculation doesn't overflow
localparam Inc = ((Baud*Oversampling << (AccWidth-ShiftLimiter))+(ClkFrequency>>(ShiftLimiter+1)))/(ClkFrequency>>ShiftLimiter);
always @(posedge clk)
begin
if (rst)
Acc <= 0;
else
if(enable) Acc <= Acc[AccWidth-1:0] + Inc[AccWidth:0]; else Acc <= Inc[AccWidth:0];
end
assign tick = Acc[AccWidth];
endmodule

35
rtl/build_id.tcl Normal file
View File

@ -0,0 +1,35 @@
# ================================================================================
#
# Build ID Verilog Module Script
# Jeff Wiencrot - 8/1/2011
#
# Generates a Verilog module that contains a timestamp,
# from the current build. These values are available from the build_date, build_time,
# physical_address, and host_name output ports of the build_id module in the build_id.v
# Verilog source file.
#
# ================================================================================
proc generateBuildID_Verilog {} {
# Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html)
set buildDate [ clock format [ clock seconds ] -format %y%m%d ]
set buildTime [ clock format [ clock seconds ] -format %H%M%S ]
# Create a Verilog file for output
set outputFileName "rtl/build_id.v"
set outputFile [open $outputFileName "w"]
# Output the Verilog source
puts $outputFile "`define BUILD_DATE \"$buildDate\""
puts $outputFile "`define BUILD_TIME \"$buildTime\""
close $outputFile
# Send confirmation message to the Messages window
post_message "Generated build identification Verilog module: [pwd]/$outputFileName"
post_message "Date: $buildDate"
post_message "Time: $buildTime"
}
# Comment out this line to prevent the process from automatically executing when the file is sourced:
generateBuildID_Verilog

55
rtl/clock.v Normal file
View File

@ -0,0 +1,55 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: Clock divider to provide clock enables for
// devices.
//
// Author.....: Alan Garfield
// Niels A. Moseley
// Date.......: 29-1-2018
//
module clock
(
input clk14, // 14MHz clock master clock
input rst_n, // active low synchronous reset
// Clock enables
output reg cpu_clken // 1MHz clock enable for the CPU and devices
);
// generate clock enable once every
// 14 clocks. This will (hopefully) make
// the 6502 run at 1 MHz
//
// the clock division counter is synchronously
// reset using rst_n to avoid undefined signals
// in simulation
//
reg [4:0] clk_div;
always @(posedge clk14)
begin
if ((clk_div == 14) || (rst_n == 1'b0))
clk_div <= 0;
else
clk_div <= clk_div + 1'b1;
cpu_clken <= (clk_div[4:0] == 0);
end
endmodule

72
rtl/debounce.v Normal file
View File

@ -0,0 +1,72 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// Description: PS/2 keyboard debounce logic to be used for the
// clock line
//
// Author.....: Niels A. Moseley
// Date.......: 8-2-2018
//
module debounce(
input clk14, // 25MHz clock
input rst, // active high reset
input sig_in, // input signal
output reg sig_out // debounced output signal
);
wire clk_enb; // enable triggering at clk14 divided by 64
reg [5:0] clk_div; // clock divider counter
reg sig_ff1; // first input signal synchronizer
reg sig_ff2; // second input signal synchronizer
assign clk_enb = (clk_div == 6'd0);
// clock divider
always @(posedge clk14 or posedge rst)
begin
if (rst)
clk_div <= 6'd0;
else
clk_div <= clk_div + 6'd1;
end
// debounce timer
always @(posedge clk14 or posedge rst)
begin
if (rst)
begin
sig_out <= 1'b0;
sig_ff1 <= 1'b0;
sig_ff2 <= 1'b0;
end
else if (clk_enb)
begin
// this runs ar approximately 391k Hz
// giving a debounce time of around 2.5us
sig_ff1 <= sig_in;
sig_ff2 <= sig_ff1;
if ((sig_ff1 ^ sig_ff2) == 1'd0)
begin
sig_out <= sig_ff2;
end
end
end
endmodule

70
rtl/font_rom.v Normal file
View File

@ -0,0 +1,70 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.