mirror of
https://github.com/nippur72/Apple1_MiST.git
synced 2024-12-26 14:29:30 +00:00
fork Gehstock's project
This commit is contained in:
parent
fe6a59aed6
commit
03281591f6
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal 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
15
README.md
Normal 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
30
apple-one.qpf
Normal 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
192
apple-one.qsf
Normal 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
37
clean.bat
Normal 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
|
263
rtl/apple1.v
Normal file
263
rtl/apple1.v
Normal 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
201
rtl/apple1_mist.sv
Normal 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
108
rtl/arlet_6502/ALU.v
Normal 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
|
72
rtl/arlet_6502/arlet_6502.v
Normal file
72
rtl/arlet_6502/arlet_6502.v
Normal 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
|
66
rtl/arlet_6502/chip_6502.v
Normal file
66
rtl/arlet_6502/chip_6502.v
Normal 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
|
10
rtl/arlet_6502/chip_6502_mux.v
Normal file
10
rtl/arlet_6502/chip_6502_mux.v
Normal 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
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
227
rtl/async_tx_rx.v
Normal 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
35
rtl/build_id.tcl
Normal 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
55
rtl/clock.v
Normal 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
72
rtl/debounce.v
Normal 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
70
rtl/font_rom.v
Normal 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.
|
||||
//
|
||||
// Description: 8KB RAM for system
|
||||
//
|
||||
// Author.....: Alan Garfield
|
||||
// Date.......: 3-2-2018
|
||||
//
|
||||
|
||||
module font_rom (
|
||||
input clk, // clock signal
|
||||
input [1:0] mode, // character mode
|
||||
input [5:0] character, // address bus
|
||||
input [3:0] pixel, // address of the pixel to output
|
||||
input [4:0] line, // address of the line to output
|
||||
output reg out // single pixel from address and pixel pos
|
||||
);
|
||||
|
||||
reg [7:0] rom[0:1023];
|
||||
|
||||
initial
|
||||
$readmemh("roms/vga_font_bitreversed.hex", rom, 0, 1023);
|
||||
|
||||
// double height of pixel by ignoring bit 0
|
||||
wire [3:0] line_ptr = line[4:1];
|
||||
|
||||
// Note: Quartus II reverses the pixels when we do:
|
||||
//
|
||||
// rom[address][bitindex]
|
||||
//
|
||||
// directly, so we use an intermediate
|
||||
// signal, romout, to work around this
|
||||
// problem.
|
||||
//
|
||||
// IceCube2 and Yosys don't seem to have this problem.
|
||||
//
|
||||
|
||||
reg [7:0] romout;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
// mode
|
||||
// 00 - normal
|
||||
// 01 - vertical scanlines
|
||||
// 10 - horizontal scanlines
|
||||
// 11 - dotty mode
|
||||
|
||||
romout = rom[(character * 10) + {2'd0, line_ptr}];
|
||||
|
||||
out <= (mode[1] & line[0]) ? 1'b0 :
|
||||
(mode[0] & pixel[0]) ? 1'b0 :
|
||||
romout[pixel[3:1]];
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
167
rtl/led_and_key.v
Normal file
167
rtl/led_and_key.v
Normal file
@ -0,0 +1,167 @@
|
||||
module ledAndKey(
|
||||
input clk,
|
||||
input clk_en,
|
||||
input rst,
|
||||
|
||||
input [3:0] display,
|
||||
input [7:0] digit1,
|
||||
input [7:0] digit2,
|
||||
input [7:0] digit3,
|
||||
input [7:0] digit4,
|
||||
input [7:0] digit5,
|
||||
input [7:0] digit6,
|
||||
input [7:0] digit7,
|
||||
input [7:0] digit8,
|
||||
input [7:0] leds,
|
||||
|
||||
output reg [7:0] keys,
|
||||
|
||||
output reg tm_cs,
|
||||
output tm_clk,
|
||||
inout tm_dio
|
||||
);
|
||||
|
||||
localparam
|
||||
HIGH = 1'b1,
|
||||
LOW = 1'b0;
|
||||
|
||||
localparam [7:0]
|
||||
C_READ = 8'b01000010,
|
||||
C_WRITE = 8'b01000000,
|
||||
C_DISP = 8'b10001111,
|
||||
C_ADDR = 8'b11000000;
|
||||
|
||||
reg counter;
|
||||
reg [5:0] instruction_step;
|
||||
|
||||
// set up tristate IO pin for display
|
||||
// tm_dio is physical pin
|
||||
// dio_in for reading from display
|
||||
// dio_out for sending to display
|
||||
// tm_rw selects input or output
|
||||
reg tm_rw;
|
||||
wire dio_in, dio_out;
|
||||
SB_IO #(
|
||||
.PIN_TYPE(6'b101001),
|
||||
.PULLUP(1'b1)
|
||||
) tm_dio_io (
|
||||
.PACKAGE_PIN(tm_dio),
|
||||
.OUTPUT_ENABLE(tm_rw),
|
||||
.D_IN_0(dio_in),
|
||||
.D_OUT_0(dio_out)
|
||||
);
|
||||
|
||||
// setup tm1638 module with it's tristate IO
|
||||
// tm_in is read from module
|
||||
// tm_out is written to module
|
||||
// tm_latch triggers the module to read/write display
|
||||
// tm_rw selects read or write mode to display
|
||||
// busy indicates when module is busy
|
||||
// (another latch will interrupt)
|
||||
// tm_clk is the data clk
|
||||
// dio_in for reading from display
|
||||
// dio_out for sending to display
|
||||
//
|
||||
// tm_data the tristate io pin to module
|
||||
reg tm_latch;
|
||||
wire busy;
|
||||
wire [7:0] tm_data, tm_in;
|
||||
reg [7:0] tm_out;
|
||||
|
||||
assign tm_in = tm_data;
|
||||
assign tm_data = tm_rw ? tm_out : 8'hZZ;
|
||||
|
||||
tm1638 u_tm1638 (
|
||||
.clk(clk),
|
||||
.clk_en(clk_en),
|
||||
.rst(rst),
|
||||
.data_latch(tm_latch),
|
||||
.data(tm_data),
|
||||
.rw(tm_rw),
|
||||
.busy(busy),
|
||||
.sclk(tm_clk),
|
||||
.dio_in(dio_in),
|
||||
.dio_out(dio_out)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (clk_en) begin
|
||||
if (rst) begin
|
||||
instruction_step <= 6'b0;
|
||||
tm_cs <= HIGH;
|
||||
tm_rw <= HIGH;
|
||||
|
||||
counter <= 1'b0;
|
||||
keys <= 8'b0;
|
||||
|
||||
end else begin
|
||||
if (counter && ~busy) begin
|
||||
case (instruction_step)
|
||||
// *** KEYS ***
|
||||
1: {tm_cs, tm_rw} <= {LOW, HIGH};
|
||||
2: {tm_latch, tm_out} <= {HIGH, C_READ}; // read mode
|
||||
3: {tm_latch, tm_rw} <= {HIGH, LOW};
|
||||
|
||||
// read back keys S1 - S8
|
||||
4: {keys[7], keys[3]} <= {tm_in[0], tm_in[4]};
|
||||
5: {tm_latch} <= {HIGH};
|
||||
6: {keys[6], keys[2]} <= {tm_in[0], tm_in[4]};
|
||||
7: {tm_latch} <= {HIGH};
|
||||
8: {keys[5], keys[1]} <= {tm_in[0], tm_in[4]};
|
||||
9: {tm_latch} <= {HIGH};
|
||||
10: {keys[4], keys[0]} <= {tm_in[0], tm_in[4]};
|
||||
11: {tm_cs} <= {HIGH};
|
||||
|
||||
// *** DISPLAY ***
|
||||
12: {tm_cs, tm_rw} <= {LOW, HIGH};
|
||||
13: {tm_latch, tm_out} <= {HIGH, C_WRITE}; // write mode
|
||||
14: {tm_cs} <= {HIGH};
|
||||
|
||||
15: {tm_cs, tm_rw} <= {LOW, HIGH};
|
||||
16: {tm_latch, tm_out} <= {HIGH, C_ADDR}; // set addr 0 pos
|
||||
|
||||
17: {tm_latch, tm_out} <= {HIGH, digit1}; // Digit 1
|
||||
18: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[7]}}; // LED 1
|
||||
|
||||
19: {tm_latch, tm_out} <= {HIGH, digit2}; // Digit 2
|
||||
20: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[6]}}; // LED 2
|
||||
|
||||
21: {tm_latch, tm_out} <= {HIGH, digit3}; // Digit 3
|
||||
22: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[5]}}; // LED 3
|
||||
|
||||
23: {tm_latch, tm_out} <= {HIGH, digit4}; // Digit 4
|
||||
24: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[4]}}; // LED 4
|
||||
|
||||
25: {tm_latch, tm_out} <= {HIGH, digit5}; // Digit 5
|
||||
26: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[3]}}; // LED 5
|
||||
|
||||
27: {tm_latch, tm_out} <= {HIGH, digit6}; // Digit 6
|
||||
28: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[2]}}; // LED 6
|
||||
|
||||
29: {tm_latch, tm_out} <= {HIGH, digit7}; // Digit 7
|
||||
30: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[1]}}; // LED 7
|
||||
|
||||
31: {tm_latch, tm_out} <= {HIGH, digit8}; // Digit 8
|
||||
32: {tm_latch, tm_out} <= {HIGH, {7'b0, leds[0]}}; // LED 8
|
||||
|
||||
33: {tm_cs} <= {HIGH};
|
||||
|
||||
34: {tm_cs, tm_rw} <= {LOW, HIGH};
|
||||
35: {tm_latch, tm_out} <= {HIGH, {4'b1000, display}}; // display
|
||||
36: {tm_cs, instruction_step} <= {HIGH, 6'b0};
|
||||
|
||||
endcase
|
||||
|
||||
instruction_step <= instruction_step + 1;
|
||||
|
||||
end else if (busy) begin
|
||||
// pull latch low next clock cycle after module has been
|
||||
// latched
|
||||
tm_latch <= LOW;
|
||||
end
|
||||
|
||||
counter <= ~counter;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
1
rtl/mist-modules/.gitignore
vendored
Normal file
1
rtl/mist-modules/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.bak
|
33
rtl/mist-modules/README.md
Normal file
33
rtl/mist-modules/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
Common components for MiST board
|
||||
================================
|
||||
|
||||
This repository contains common components, which should be used by almost all cores.
|
||||
The modules:
|
||||
|
||||
- user_io.v - communicating with the IO controller.
|
||||
- data_io.v - handling file uploads from the IO controller.
|
||||
- mist_video.v - a video pipeline, which gives an optional scandoubler, OSD and rgb2ypbpr conversion.
|
||||
- osd.v, scandoubler.v, rgb2ypbpr.sv, cofi.sv - these are used in mist_video, but can be used separately, too.
|
||||
- sd_card.v - gives an SPI interface with SD-Card commands towards the IO-Controller, accessing .VHD and other mounted files.
|
||||
- dac.vhd - a simple sigma-delta DAC for audio output.
|
||||
- arcade_inputs.v - mostly for arcade-style games, gives access to the joysticks with MAME-style keyboard mapping.
|
||||
- mist.vhd - VHDL component declarations for user_io and mist_video.
|
||||
- mist_core.qip - collects the core components, which are needed in almost every case.
|
||||
|
||||
Usage hints
|
||||
===========
|
||||
|
||||
All of these components should be clocked by a synchronous clock to the core. The data between the external SPI
|
||||
interface and this internal clock are synchronized. However to make Quartus' job easier, you have to tell it to
|
||||
don't try to optimize paths between the SPI and the system clock domain. Also you have to define the incoming
|
||||
27 MHz and the SPI clocks. These lines in the .sdc file do that:
|
||||
|
||||
```
|
||||
set sys_clk "your_system_clock"
|
||||
|
||||
create_clock -name {clk_27} -period 37.037 -waveform { 0.000 18.500 } [get_ports {CLOCK_27[0]}]
|
||||
create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}]
|
||||
set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks $sys_clk]
|
||||
```
|
||||
|
||||
Replace "your_system_clock" with the name of the pll clock, like "pll|altpll_component|auto_generated|pll1|clk[0]".
|
191
rtl/mist-modules/arcade_inputs.v
Normal file
191
rtl/mist-modules/arcade_inputs.v
Normal file
@ -0,0 +1,191 @@
|
||||
/* Provides arcade controls from joystick/keyboard
|
||||
Keyboard has a simplified (ESC-coin, F1-F4 start) and MAME-style mapping */
|
||||
|
||||
module arcade_inputs(
|
||||
// clock, same as for userio
|
||||
input clk,
|
||||
// signals from userio
|
||||
input key_strobe,
|
||||
input key_pressed,
|
||||
input [7:0] key_code,
|
||||
input [19:0] joystick_0,
|
||||
input [19:0] joystick_1,
|
||||
input [19:0] joystick_2,
|
||||
input [19:0] joystick_3,
|
||||
|
||||
// required rotating of controls
|
||||
input rotate,
|
||||
// original orientation [1]-left/right if portrait, [0]-landscape/portrait
|
||||
input [1:0] orientation,
|
||||
// joystick_0 and joystick_1 should be swapped
|
||||
input joyswap,
|
||||
// player1 and player2 should get both joystick_0 and joystick_1
|
||||
input oneplayer,
|
||||
|
||||
// tilt, coin4-1, start4-1
|
||||
output [8:0] controls,
|
||||
// up2, down2, left2, right2, fire12-1, up, down, left, right
|
||||
output [19:0] player1,
|
||||
output [19:0] player2,
|
||||
output [19:0] player3,
|
||||
output [19:0] player4
|
||||
);
|
||||
|
||||
assign controls = { btn_tilt,
|
||||
btn_coin | btn_coin4_mame, btn_coin | btn_coin3_mame, btn_coin | btn_coin2_mame, btn_coin | btn_coin1_mame,
|
||||
btn_four_players | btn_start4_mame, btn_three_players | btn_start3_mame, btn_two_players | btn_start2_mame, btn_one_player | btn_start1_mame };
|
||||
|
||||
wire [19:0] joy0 = joyswap ? joystick_1 : joystick_0;
|
||||
wire [19:0] joy1 = joyswap ? joystick_0 : joystick_1;
|
||||
wire [19:0] joy2 = joystick_2;
|
||||
wire [19:0] joy3 = joystick_3;
|
||||
|
||||
wire [19:0] p1;
|
||||
wire [19:0] p2;
|
||||
wire [19:0] p3;
|
||||
wire [19:0] p4;
|
||||
|
||||
assign p1[15:4] = joy0[15:4] | { 4'h0, btn_fireH, btn_fireG, btn_fireF, btn_fireE, btn_fireD, btn_fireC, btn_fireB, btn_fireA };
|
||||
assign p2[15:4] = joy1[15:4] | { 4'h0, btn_fire2H, btn_fire2G, btn_fire2F, btn_fire2E, btn_fire2D, btn_fire2C, btn_fire2B, btn_fire2A };
|
||||
assign p3[15:4] = joy2[15:4];
|
||||
assign p4[15:4] = joy3[15:4];
|
||||
|
||||
// Left or only stick
|
||||
control_rotator l1(joy0[3:0], {btn_up, btn_down, btn_left, btn_right }, rotate, orientation, p1[3:0]);
|
||||
control_rotator l2(joy1[3:0], {btn_up2, btn_down2, btn_left2, btn_right2}, rotate, orientation, p2[3:0]);
|
||||
control_rotator l3(joy2[3:0], 4'd0, rotate, orientation, p3[3:0]);
|
||||
control_rotator l4(joy3[3:0], 4'd0, rotate, orientation, p4[3:0]);
|
||||
|
||||
// Right stick
|
||||
control_rotator r1(joy0[19:16], 4'd0, rotate, orientation, p1[19:16]);
|
||||
control_rotator r2(joy1[19:16], 4'd0, rotate, orientation, p2[19:16]);
|
||||
control_rotator r3(joy2[19:16], 4'd0, rotate, orientation, p3[19:16]);
|
||||
control_rotator r4(joy3[19:16], 4'd0, rotate, orientation, p4[19:16]);
|
||||
|
||||
assign player1 = oneplayer ? p1 | p2 : p1;
|
||||
assign player2 = oneplayer ? p1 | p2 : p2;
|
||||
assign player3 = p3;
|
||||
assign player4 = p4;
|
||||
|
||||
// keyboard controls
|
||||
reg btn_tilt = 0;
|
||||
reg btn_one_player = 0;
|
||||
reg btn_two_players = 0;
|
||||
reg btn_three_players = 0;
|
||||
reg btn_four_players = 0;
|
||||
reg btn_left = 0;
|
||||
reg btn_right = 0;
|
||||
reg btn_down = 0;
|
||||
reg btn_up = 0;
|
||||
reg btn_fireA = 0;
|
||||
reg btn_fireB = 0;
|
||||
reg btn_fireC = 0;
|
||||
reg btn_fireD = 0;
|
||||
reg btn_fireE = 0;
|
||||
reg btn_fireF = 0;
|
||||
reg btn_fireG = 0;
|
||||
reg btn_fireH = 0;
|
||||
reg btn_coin = 0;
|
||||
reg btn_start1_mame = 0;
|
||||
reg btn_start2_mame = 0;
|
||||
reg btn_start3_mame = 0;
|
||||
reg btn_start4_mame = 0;
|
||||
reg btn_coin1_mame = 0;
|
||||
reg btn_coin2_mame = 0;
|
||||
reg btn_coin3_mame = 0;
|
||||
reg btn_coin4_mame = 0;
|
||||
reg btn_up2 = 0;
|
||||
reg btn_down2 = 0;
|
||||
reg btn_left2 = 0;
|
||||
reg btn_right2 = 0;
|
||||
reg btn_fire2A = 0;
|
||||
reg btn_fire2B = 0;
|
||||
reg btn_fire2C = 0;
|
||||
reg btn_fire2D = 0;
|
||||
reg btn_fire2E = 0;
|
||||
reg btn_fire2F = 0;
|
||||
reg btn_fire2G = 0;
|
||||
reg btn_fire2H = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if(key_strobe) begin
|
||||
case(key_code)
|
||||
'h75: btn_up <= key_pressed; // up
|
||||
'h72: btn_down <= key_pressed; // down
|
||||
'h6B: btn_left <= key_pressed; // left
|
||||
'h74: btn_right <= key_pressed; // right
|
||||
'h76: btn_coin <= key_pressed; // ESC
|
||||
'h05: btn_one_player <= key_pressed; // F1
|
||||
'h06: btn_two_players <= key_pressed; // F2
|
||||
'h04: btn_three_players <= key_pressed; // F3
|
||||
'h0C: btn_four_players <= key_pressed; // F4
|
||||
'h14: btn_fireA <= key_pressed; // ctrl
|
||||
'h11: btn_fireB <= key_pressed; // alt
|
||||
'h29: btn_fireC <= key_pressed; // Space
|
||||
'h12: btn_fireD <= key_pressed; // l-shift
|
||||
'h1A: btn_fireE <= key_pressed; // Z
|
||||
'h22: btn_fireF <= key_pressed; // X
|
||||
'h21: btn_fireG <= key_pressed; // C
|
||||
'h2A: btn_fireH <= key_pressed; // V
|
||||
'h66: btn_tilt <= key_pressed; // Backspace
|
||||
|
||||
// JPAC/IPAC/MAME Style Codes
|
||||
'h16: btn_start1_mame <= key_pressed; // 1
|
||||
'h1E: btn_start2_mame <= key_pressed; // 2
|
||||
'h26: btn_start3_mame <= key_pressed; // 3
|
||||
'h25: btn_start4_mame <= key_pressed; // 4
|
||||
'h2E: btn_coin1_mame <= key_pressed; // 5
|
||||
'h36: btn_coin2_mame <= key_pressed; // 6
|
||||
'h3D: btn_coin3_mame <= key_pressed; // 7
|
||||
'h3E: btn_coin4_mame <= key_pressed; // 8
|
||||
'h2D: btn_up2 <= key_pressed; // R
|
||||
'h2B: btn_down2 <= key_pressed; // F
|
||||
'h23: btn_left2 <= key_pressed; // D
|
||||
'h34: btn_right2 <= key_pressed; // G
|
||||
'h1C: btn_fire2A <= key_pressed; // A
|
||||
'h1B: btn_fire2B <= key_pressed; // S
|
||||
'h15: btn_fire2C <= key_pressed; // Q
|
||||
'h1D: btn_fire2D <= key_pressed; // W
|
||||
'h43: btn_fire2E <= key_pressed; // I
|
||||
'h42: btn_fire2F <= key_pressed; // K
|
||||
'h3B: btn_fire2G <= key_pressed; // J
|
||||
'h4B: btn_fire2H <= key_pressed; // L
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module control_rotator (
|
||||
input [3:0] joystick, //UDLR
|
||||
input [3:0] keyboard,
|
||||
input rotate,
|
||||
input [1:0] orientation,
|
||||
output [3:0] out
|
||||
);
|
||||
|
||||
assign out = { m_up, m_down, m_left, m_right };
|
||||
|
||||
wire m_up = ~(orientation[0] ^ rotate) ? keyboard[3] | joystick[3] : ((orientation[1] ^ orientation[0]) ? keyboard[0] | joystick[0] : keyboard[1] | joystick[1]);
|
||||
wire m_down = ~(orientation[0] ^ rotate) ? keyboard[2] | joystick[2] : ((orientation[1] ^ orientation[0]) ? keyboard[1] | joystick[1] : keyboard[0] | joystick[0]);
|
||||
wire m_left = ~(orientation[0] ^ rotate) ? keyboard[1] | joystick[1] : ((orientation[1] ^ orientation[0]) ? keyboard[3] | joystick[3] : keyboard[2] | joystick[2]);
|
||||
wire m_right = ~(orientation[0] ^ rotate) ? keyboard[0] | joystick[0] : ((orientation[1] ^ orientation[0]) ? keyboard[2] | joystick[2] : keyboard[3] | joystick[3]);
|
||||
|
||||
endmodule
|
||||
|
||||
// A simple toggle-switch
|
||||
module input_toggle(
|
||||
input clk,
|
||||
input reset,
|
||||
input btn,
|
||||
output reg state
|
||||
);
|
||||
|
||||
reg btn_old;
|
||||
always @(posedge clk) begin
|
||||
btn_old <= btn;
|
||||
if (reset) state <= 0;
|
||||
else if (~btn_old & btn) state <= ~state;
|
||||
end
|
||||
|
||||
endmodule
|
59
rtl/mist-modules/cofi.sv
Normal file
59
rtl/mist-modules/cofi.sv
Normal file
@ -0,0 +1,59 @@
|
||||
// Composite-like horizontal blending by Kitrinx
|
||||
|
||||
// AMR - disable shift register recognition
|
||||
(* altera_attribute = "-name AUTO_SHIFT_REGISTER_RECOGNITION OFF" *)
|
||||
module cofi (
|
||||
input clk,
|
||||
input pix_ce,
|
||||
input enable,
|
||||
|
||||
input hblank,
|
||||
input vblank,
|
||||
input hs,
|
||||
input vs,
|
||||
input [VIDEO_DEPTH-1:0] red,
|
||||
input [VIDEO_DEPTH-1:0] green,
|
||||
input [VIDEO_DEPTH-1:0] blue,
|
||||
|
||||
output reg hblank_out,
|
||||
output reg vblank_out,
|
||||
output reg hs_out,
|
||||
output reg vs_out,
|
||||
output reg [VIDEO_DEPTH-1:0] red_out,
|
||||
output reg [VIDEO_DEPTH-1:0] green_out,
|
||||
output reg [VIDEO_DEPTH-1:0] blue_out
|
||||
);
|
||||
|
||||
parameter VIDEO_DEPTH=8;
|
||||
|
||||
function bit [VIDEO_DEPTH-1:0] color_blend (
|
||||
input [VIDEO_DEPTH-1:0] color_prev,
|
||||
input [VIDEO_DEPTH-1:0] color_curr,
|
||||
input blank_last
|
||||
);
|
||||
begin
|
||||
color_blend = blank_last ? color_curr : (color_prev >> 1) + (color_curr >> 1);
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg [VIDEO_DEPTH-1:0] red_last;
|
||||
reg [VIDEO_DEPTH-1:0] green_last;
|
||||
reg [VIDEO_DEPTH-1:0] blue_last;
|
||||
|
||||
wire ce = enable ? pix_ce : 1'b1;
|
||||
always @(posedge clk) if (ce) begin
|
||||
hblank_out <= hblank;
|
||||
vblank_out <= vblank;
|
||||
vs_out <= vs;
|
||||
hs_out <= hs;
|
||||
|
||||
red_last <= red;
|
||||
blue_last <= blue;
|
||||
green_last <= green;
|
||||
|
||||
red_out <= enable ? color_blend(red_last, red, hblank_out) : red;
|
||||
blue_out <= enable ? color_blend(blue_last, blue, hblank_out) : blue;
|
||||
green_out <= enable ? color_blend(green_last, green, hblank_out) : green;
|
||||
end
|
||||
|
||||
endmodule
|
48
rtl/mist-modules/dac.vhd
Normal file
48
rtl/mist-modules/dac.vhd
Normal file
@ -0,0 +1,48 @@
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Delta-Sigma DAC
|
||||
--
|
||||
-- Refer to Xilinx Application Note XAPP154.
|
||||
--
|
||||
-- This DAC requires an external RC low-pass filter:
|
||||
--
|
||||
-- dac_o 0---XXXXX---+---0 analog audio
|
||||
-- 3k3 |
|
||||
-- === 4n7
|
||||
-- |
|
||||
-- GND
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity dac is
|
||||
generic (
|
||||
C_bits : integer := 8
|
||||
);
|
||||
port (
|
||||
clk_i : in std_logic;
|
||||
res_n_i : in std_logic;
|
||||
dac_i : in std_logic_vector(C_bits-1 downto 0);
|
||||
dac_o : out std_logic
|
||||
);
|
||||
end dac;
|
||||
|
||||
architecture rtl of dac is
|
||||
signal sig_in: unsigned(C_bits downto 0);
|
||||
begin
|
||||
seq: process(clk_i, res_n_i)
|
||||
begin
|
||||
if res_n_i = '0' then
|
||||
sig_in <= to_unsigned(2**C_bits, sig_in'length);
|
||||
dac_o <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
-- not dac_i(C_bits-1) effectively adds 0x8..0 to dac_i
|
||||
--sig_in <= sig_in + unsigned(sig_in(C_bits) & (not dac_i(C_bits-1)) & dac_i(C_bits-2 downto 0));
|
||||
sig_in <= sig_in + unsigned(sig_in(C_bits) & dac_i);
|
||||
dac_o <= sig_in(C_bits);
|
||||
end if;
|
||||
end process seq;
|
||||
end rtl;
|
259
rtl/mist-modules/data_io.v
Normal file
259
rtl/mist-modules/data_io.v
Normal file
@ -0,0 +1,259 @@
|
||||
//
|
||||
// data_io.v
|
||||
//
|
||||
// data_io for the MiST board
|
||||
// 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 data_io
|
||||
(
|
||||
input clk_sys,
|
||||
input SPI_SCK,
|
||||
input SPI_SS2,
|
||||
input SPI_SS4,
|
||||
input SPI_DI,
|
||||
inout SPI_DO,
|
||||
|
||||
input clkref_n, // assert ioctl_wr one cycle after clkref stobe (negative active)
|
||||
|
||||
// ARM -> FPGA download
|
||||
output reg ioctl_download = 0, // signal indicating an active download
|
||||
output reg ioctl_upload = 0, // signal indicating an active upload
|
||||
output reg [7:0] ioctl_index, // menu index used to upload the file ([7:6] - extension index, [5:0] - menu index)
|
||||
// Note: this is also set for user_io mounts.
|
||||
// Valid when ioctl_download = 1 or when img_mounted strobe is active in user_io.
|
||||
output reg ioctl_wr, // strobe indicating ioctl_dout valid
|
||||
output reg [24:0] ioctl_addr,
|
||||
output reg [7:0] ioctl_dout,
|
||||
input [7:0] ioctl_din,
|
||||
output reg [23:0] ioctl_fileext, // file extension
|
||||
output reg [31:0] ioctl_filesize // file size
|
||||
);
|
||||
|
||||
parameter START_ADDR = 25'd0;
|
||||
parameter ROM_DIRECT_UPLOAD = 0;
|
||||
|
||||
/////////////////////////////// DOWNLOADING ///////////////////////////////
|
||||
|
||||
reg [7:0] data_w;
|
||||
reg [7:0] data_w2 = 0;
|
||||
reg [3:0] cnt;
|
||||
reg rclk = 0;
|
||||
reg rclk2 = 0;
|
||||
reg addr_reset = 0;
|
||||
reg downloading_reg = 0;
|
||||
reg uploading_reg = 0;
|
||||
reg reg_do;
|
||||
|
||||
localparam DIO_FILE_TX = 8'h53;
|
||||
localparam DIO_FILE_TX_DAT = 8'h54;
|
||||
localparam DIO_FILE_INDEX = 8'h55;
|
||||
localparam DIO_FILE_INFO = 8'h56;
|
||||
localparam DIO_FILE_RX = 8'h57;
|
||||
localparam DIO_FILE_RX_DAT = 8'h58;
|
||||
|
||||
assign SPI_DO = reg_do;
|
||||
|
||||
// data_io has its own SPI interface to the io controller
|
||||
always@(negedge SPI_SCK or posedge SPI_SS2) begin : SPI_TRANSMITTER
|
||||
reg [7:0] dout_r;
|
||||
|
||||
if(SPI_SS2) begin
|
||||
reg_do <= 1'bZ;
|
||||
end else begin
|
||||
if (cnt == 15) dout_r <= ioctl_din;
|
||||
reg_do <= dout_r[~cnt[2:0]];
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
|
||||
reg [6:0] sbuf;
|
||||
reg [24:0] addr;
|
||||
reg [7:0] cmd;
|
||||
reg [5:0] bytecnt;
|
||||
|
||||
if(SPI_SS2) begin
|
||||
bytecnt <= 0;
|
||||
cnt <= 0;
|
||||
end else begin
|
||||
// don't shift in last bit. It is evaluated directly
|
||||
// when writing to ram
|
||||
if(cnt != 15) sbuf <= { sbuf[5:0], SPI_DI};
|
||||
|
||||
// count 0-7 8-15 8-15 ...
|
||||
if(cnt != 15) cnt <= cnt + 1'd1;
|
||||
else cnt <= 8;
|
||||
|
||||
// finished command byte
|
||||
if(cnt == 7) cmd <= {sbuf, SPI_DI};
|
||||
|
||||
if(cnt == 15) begin
|
||||
case (cmd)
|
||||
// prepare/end transmission
|
||||
DIO_FILE_TX: begin
|
||||
// prepare
|
||||
if(SPI_DI) begin
|
||||
addr_reset <= ~addr_reset;
|
||||
downloading_reg <= 1;
|
||||
end else begin
|
||||
downloading_reg <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
DIO_FILE_RX: begin
|
||||
// prepare
|
||||
if(SPI_DI) begin
|
||||
addr_reset <= ~addr_reset;
|
||||
uploading_reg <= 1;
|
||||
end else begin
|
||||
uploading_reg <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
// command 0x57: DIO_FILE_RX_DAT
|
||||
// command 0x54: DIO_FILE_TX_DAT
|
||||
DIO_FILE_RX_DAT,
|
||||
DIO_FILE_TX_DAT: begin
|
||||
data_w <= {sbuf, SPI_DI};
|
||||
rclk <= ~rclk;
|
||||
end
|
||||
|
||||
// expose file (menu) index
|
||||
DIO_FILE_INDEX: ioctl_index <= {sbuf, SPI_DI};
|
||||
|
||||
// receiving FAT directory entry (mist-firmware/fat.h - DIRENTRY)
|
||||
DIO_FILE_INFO: begin
|
||||
bytecnt <= bytecnt + 1'd1;
|
||||
case (bytecnt)
|
||||
8'h08: ioctl_fileext[23:16] <= {sbuf, SPI_DI};
|
||||
8'h09: ioctl_fileext[15: 8] <= {sbuf, SPI_DI};
|
||||
8'h0A: ioctl_fileext[ 7: 0] <= {sbuf, SPI_DI};
|
||||
8'h1C: ioctl_filesize[ 7: 0] <= {sbuf, SPI_DI};
|
||||
8'h1D: ioctl_filesize[15: 8] <= {sbuf, SPI_DI};
|
||||
8'h1E: ioctl_filesize[23:16] <= {sbuf, SPI_DI};
|
||||
8'h1F: ioctl_filesize[31:24] <= {sbuf, SPI_DI};
|
||||
endcase
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// direct SD Card->FPGA transfer
|
||||
generate if (ROM_DIRECT_UPLOAD == 1) begin
|
||||
|
||||
always@(posedge SPI_SCK, posedge SPI_SS4) begin : SPI_DIRECT_RECEIVER
|
||||
reg [6:0] sbuf2;
|
||||
reg [2:0] cnt2;
|
||||
reg [9:0] bytecnt;
|
||||
|
||||
if(SPI_SS4) begin
|
||||
cnt2 <= 0;
|
||||
bytecnt <= 0;
|
||||
end else begin
|
||||
// don't shift in last bit. It is evaluated directly
|
||||
// when writing to ram
|
||||
if(cnt2 != 7)
|
||||
sbuf2 <= { sbuf2[5:0], SPI_DO };
|
||||
|
||||
cnt2 <= cnt2 + 1'd1;
|
||||
|
||||
// received a byte
|
||||
if(cnt2 == 7) begin
|
||||
bytecnt <= bytecnt + 1'd1;
|
||||
// read 514 byte/sector (512 + 2 CRC)
|
||||
if (bytecnt == 513) bytecnt <= 0;
|
||||
// don't send the CRC bytes
|
||||
if (~bytecnt[9]) begin
|
||||
data_w2 <= {sbuf2, SPI_DO};
|
||||
rclk2 <= ~rclk2;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always@(posedge clk_sys) begin : DATA_OUT
|
||||
// synchronisers
|
||||
reg rclkD, rclkD2;
|
||||
reg rclk2D, rclk2D2;
|
||||
reg addr_resetD, addr_resetD2;
|
||||
|
||||
reg wr_int, wr_int_direct, rd_int;
|
||||
reg [24:0] addr;
|
||||
reg [31:0] filepos;
|
||||
|
||||
// bring flags from spi clock domain into core clock domain
|
||||
{ rclkD, rclkD2 } <= { rclk, rclkD };
|
||||
{ rclk2D ,rclk2D2 } <= { rclk2, rclk2D };
|
||||
{ addr_resetD, addr_resetD2 } <= { addr_reset, addr_resetD };
|
||||
|
||||
ioctl_wr <= 0;
|
||||
|
||||
if (!downloading_reg) begin
|
||||
ioctl_download <= 0;
|
||||
wr_int <= 0;
|
||||
wr_int_direct <= 0;
|
||||
end
|
||||
|
||||
if (!uploading_reg) begin
|
||||
ioctl_upload <= 0;
|
||||
rd_int <= 0;
|
||||
end
|
||||
|
||||
if (~clkref_n) begin
|
||||
rd_int <= 0;
|
||||
wr_int <= 0;
|
||||
wr_int_direct <= 0;
|
||||
if (wr_int || wr_int_direct) begin
|
||||
ioctl_dout <= wr_int ? data_w : data_w2;
|
||||
ioctl_wr <= 1;
|
||||
addr <= addr + 1'd1;
|
||||
ioctl_addr <= addr;
|
||||
end
|
||||
if (rd_int) begin
|
||||
ioctl_addr <= ioctl_addr + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// detect transfer start from the SPI receiver
|
||||
if(addr_resetD ^ addr_resetD2) begin
|
||||
addr <= START_ADDR;
|
||||
ioctl_addr <= START_ADDR;
|
||||
filepos <= 0;
|
||||
ioctl_download <= downloading_reg;
|
||||
ioctl_upload <= uploading_reg;
|
||||
end
|
||||
|
||||
// detect new byte from the SPI receiver
|
||||
if (rclkD ^ rclkD2) begin
|
||||
wr_int <= downloading_reg;
|
||||
rd_int <= uploading_reg;
|
||||
end
|
||||
// direct transfer receiver
|
||||
if (rclk2D ^ rclk2D2 && filepos != ioctl_filesize) begin
|
||||
filepos <= filepos + 1'd1;
|
||||
wr_int_direct <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
10
rtl/mist-modules/mist.qip
Normal file
10
rtl/mist-modules/mist.qip
Normal file
@ -0,0 +1,10 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) mist.vhd]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) user_io.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) data_io.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mist_video.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_inputs.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) dac.vhd]
|
123
rtl/mist-modules/mist.vhd
Normal file
123
rtl/mist-modules/mist.vhd
Normal file
@ -0,0 +1,123 @@
|
||||
-- user_io
|
||||
-- Interface to the MiST IO Controller
|
||||
|
||||
-- mist_video
|
||||
-- A video pipeline for MiST. Just insert between the core video output and the VGA pins
|
||||
-- Provides an optional scandoubler, a rotateable OSD and (optional) RGb->YPbPr conversion
|
||||
|
||||
library IEEE;
|
||||
use IEEE.std_logic_1164.all;
|
||||
use IEEE.numeric_std.all;
|
||||
|
||||
package mist is
|
||||
|
||||
component user_io
|
||||
generic(
|
||||
STRLEN : integer := 0;
|
||||
PS2DIV : integer := 100;
|
||||
ROM_DIRECT_UPLOAD : boolean := false;
|
||||
SD_IMAGES: integer := 2;
|
||||
PS2BIDIR : boolean := false;
|
||||
FEATURES: std_logic_vector(31 downto 0) := (others=>'0')
|
||||
);
|
||||
port (
|
||||
clk_sys : in std_logic;
|
||||
clk_sd : in std_logic := '0';
|
||||
SPI_CLK, SPI_SS_IO, SPI_MOSI :in std_logic;
|
||||
SPI_MISO : out std_logic;
|
||||
conf_str : in std_logic_vector(8*STRLEN-1 downto 0) := (others => '0');
|
||||
conf_addr : out std_logic_vector(9 downto 0);
|
||||
conf_chr : in std_logic_vector(7 downto 0) := (others => '0');
|
||||
joystick_0 : out std_logic_vector(31 downto 0);
|
||||
joystick_1 : out std_logic_vector(31 downto 0);
|
||||
joystick_2 : out std_logic_vector(31 downto 0);
|
||||
joystick_3 : out std_logic_vector(31 downto 0);
|
||||
joystick_4 : out std_logic_vector(31 downto 0);
|
||||
joystick_analog_0 : out std_logic_vector(31 downto 0);
|
||||
joystick_analog_1 : out std_logic_vector(31 downto 0);
|
||||
status : out std_logic_vector(63 downto 0);
|
||||
switches : out std_logic_vector(1 downto 0);
|
||||
buttons : out std_logic_vector(1 downto 0);
|
||||
scandoubler_disable : out std_logic;
|
||||
ypbpr : out std_logic;
|
||||
no_csync : out std_logic;
|
||||
core_mod : out std_logic_vector(6 downto 0);
|
||||
|
||||
sd_lba : in std_logic_vector(31 downto 0) := (others => '0');
|
||||
sd_rd : in std_logic_vector(SD_IMAGES-1 downto 0) := (others => '0');
|
||||
sd_wr : in std_logic_vector(SD_IMAGES-1 downto 0) := (others => '0');
|
||||
sd_ack : out std_logic;
|
||||
sd_ack_conf : out std_logic;
|
||||
sd_conf : in std_logic := '0';
|
||||
sd_sdhc : in std_logic := '1';
|
||||
img_size : out std_logic_vector(63 downto 0);
|
||||
img_mounted : out std_logic_vector(SD_IMAGES-1 downto 0);
|
||||
|
||||
sd_buff_addr : out std_logic_vector(8 downto 0);
|
||||
sd_dout : out std_logic_vector(7 downto 0);
|
||||
sd_din : in std_logic_vector(7 downto 0) := (others => '0');
|
||||
sd_dout_strobe : out std_logic;
|
||||
sd_din_strobe : out std_logic;
|
||||
|
||||
ps2_kbd_clk : out std_logic;
|
||||
ps2_kbd_data : out std_logic;
|
||||
ps2_kbd_clk_i : in std_logic := '1';
|
||||
ps2_kbd_data_i : in std_logic := '1';
|
||||
key_pressed : out std_logic;
|
||||
key_extended : out std_logic;
|
||||
key_code : out std_logic_vector(7 downto 0);
|
||||
key_strobe : out std_logic;
|
||||
|
||||
ps2_mouse_clk : out std_logic;
|
||||
ps2_mouse_data : out std_logic;
|
||||
ps2_mouse_clk_i : in std_logic := '1';
|
||||
ps2_mouse_data_i : in std_logic := '1';
|
||||
mouse_x : out signed(8 downto 0);
|
||||
mouse_y : out signed(8 downto 0);
|
||||
mouse_z : out signed(3 downto 0);
|
||||
mouse_flags : out std_logic_vector(7 downto 0); -- YOvfl, XOvfl, dy8, dx8, 1, mbtn, rbtn, lbtn
|
||||
mouse_strobe : out std_logic;
|
||||
mouse_idx : out std_logic
|
||||
);
|
||||
end component user_io;
|
||||
|
||||
component mist_video
|
||||
generic (
|
||||
OSD_COLOR : std_logic_vector(2 downto 0) := "110";
|
||||
OSD_X_OFFSET : std_logic_vector(9 downto 0) := (others => '0');
|
||||
OSD_Y_OFFSET : std_logic_vector(9 downto 0) := (others => '0');
|
||||
SD_HCNT_WIDTH: integer := 9;
|
||||
COLOR_DEPTH : integer := 6;
|
||||
OSD_AUTO_CE : boolean := true;
|
||||
SYNC_AND : boolean := false
|
||||
);
|
||||
port (
|
||||
clk_sys : in std_logic;
|
||||
|
||||
SPI_SCK : in std_logic;
|
||||
SPI_SS3 : in std_logic;
|
||||
SPI_DI : in std_logic;
|
||||
|
||||
scanlines : in std_logic_vector(1 downto 0);
|
||||
ce_divider : in std_logic := '0';
|
||||
scandoubler_disable : in std_logic;
|
||||
ypbpr : in std_logic;
|
||||
rotate : in std_logic_vector(1 downto 0);
|
||||
no_csync : in std_logic := '0';
|
||||
blend : in std_logic := '0';
|
||||
|
||||
HSync : in std_logic;
|
||||
VSync : in std_logic;
|
||||
R : in std_logic_vector(COLOR_DEPTH-1 downto 0);
|
||||
G : in std_logic_vector(COLOR_DEPTH-1 downto 0);
|
||||
B : in std_logic_vector(COLOR_DEPTH-1 downto 0);
|
||||
|
||||
VGA_HS : out std_logic;
|
||||
VGA_VS : out std_logic;
|
||||
VGA_R : out std_logic_vector(5 downto 0);
|
||||
VGA_G : out std_logic_vector(5 downto 0);
|
||||
VGA_B : out std_logic_vector(5 downto 0)
|
||||
);
|
||||
end component mist_video;
|
||||
|
||||
end package;
|
7
rtl/mist-modules/mist_core.qip
Normal file
7
rtl/mist-modules/mist_core.qip
Normal file
@ -0,0 +1,7 @@
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) mist.vhd]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) user_io.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mist_video.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v]
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv]
|
156
rtl/mist-modules/mist_video.v
Normal file
156
rtl/mist-modules/mist_video.v
Normal file
@ -0,0 +1,156 @@
|
||||
// A video pipeline for MiST. Just insert between the core video output and the VGA pins
|
||||
// Provides an optional scandoubler, a rotateable OSD and (optional) RGb->YPbPr conversion
|
||||
|
||||
module mist_video
|
||||
(
|
||||
// master clock
|
||||
// it should be 4x (or 2x) pixel clock for the scandoubler
|
||||
input clk_sys,
|
||||
|
||||
// OSD SPI interface
|
||||
input SPI_SCK,
|
||||
input SPI_SS3,
|
||||
input SPI_DI,
|
||||
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
input [1:0] scanlines,
|
||||
|
||||
// non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2
|
||||
input ce_divider,
|
||||
|
||||
// 0 = HVSync 31KHz, 1 = CSync 15KHz
|
||||
input scandoubler_disable,
|
||||
// disable csync without scandoubler
|
||||
input no_csync,
|
||||
// YPbPr always uses composite sync
|
||||
input ypbpr,
|
||||
// Rotate OSD [0] - rotate [1] - left or right
|
||||
input [1:0] rotate,
|
||||
// composite-like blending
|
||||
input blend,
|
||||
|
||||
// video in
|
||||
input [COLOR_DEPTH-1:0] R,
|
||||
input [COLOR_DEPTH-1:0] G,
|
||||
input [COLOR_DEPTH-1:0] B,
|
||||
|
||||
input HSync,
|
||||
input VSync,
|
||||
|
||||
// MiST video output signals
|
||||
output reg [5:0] VGA_R,
|
||||
output reg [5:0] VGA_G,
|
||||
output reg [5:0] VGA_B,
|
||||
output reg VGA_VS,
|
||||
output reg VGA_HS
|
||||
);
|
||||
|
||||
parameter OSD_COLOR = 3'd4;
|
||||
parameter OSD_X_OFFSET = 10'd0;
|
||||
parameter OSD_Y_OFFSET = 10'd0;
|
||||
parameter SD_HCNT_WIDTH = 9;
|
||||
parameter COLOR_DEPTH = 6; // 1-6
|
||||
parameter OSD_AUTO_CE = 1'b1;
|
||||
parameter SYNC_AND = 1'b0; // 0 - XOR, 1 - AND
|
||||
|
||||
wire [5:0] SD_R_O;
|
||||
wire [5:0] SD_G_O;
|
||||
wire [5:0] SD_B_O;
|
||||
wire SD_HS_O;
|
||||
wire SD_VS_O;
|
||||
|
||||
wire pixel_ena;
|
||||
|
||||
scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH) scandoubler
|
||||
(
|
||||
.clk_sys ( clk_sys ),
|
||||
.bypass ( scandoubler_disable ),
|
||||
.ce_divider ( ce_divider ),
|
||||
.scanlines ( scanlines ),
|
||||
.pixel_ena ( pixel_ena ),
|
||||
.hs_in ( HSync ),
|
||||
.vs_in ( VSync ),
|
||||
.r_in ( R ),
|
||||
.g_in ( G ),
|
||||
.b_in ( B ),
|
||||
.hs_out ( SD_HS_O ),
|
||||
.vs_out ( SD_VS_O ),
|
||||
.r_out ( SD_R_O ),
|
||||
.g_out ( SD_G_O ),
|
||||
.b_out ( SD_B_O )
|
||||
);
|
||||
|
||||
wire [5:0] osd_r_o;
|
||||
wire [5:0] osd_g_o;
|
||||
wire [5:0] osd_b_o;
|
||||
|
||||
osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR, OSD_AUTO_CE) osd
|
||||
(
|
||||
.clk_sys ( clk_sys ),
|
||||
.rotate ( rotate ),
|
||||
.ce ( pixel_ena ),
|
||||
.SPI_DI ( SPI_DI ),
|
||||
.SPI_SCK ( SPI_SCK ),
|
||||
.SPI_SS3 ( SPI_SS3 ),
|
||||
.R_in ( SD_R_O ),
|
||||
.G_in ( SD_G_O ),
|
||||
.B_in ( SD_B_O ),
|
||||
.HSync ( SD_HS_O ),
|
||||
.VSync ( SD_VS_O ),
|
||||
.R_out ( osd_r_o ),
|
||||
.G_out ( osd_g_o ),
|
||||
.B_out ( osd_b_o )
|
||||
);
|
||||
|
||||
wire [5:0] cofi_r, cofi_g, cofi_b;
|
||||
wire cofi_hs, cofi_vs;
|
||||
|
||||
cofi #(6) cofi (
|
||||
.clk ( clk_sys ),
|
||||
.pix_ce ( pixel_ena ),
|
||||
.enable ( blend ),
|
||||
.hblank ( ~SD_HS_O ),
|
||||
.hs ( SD_HS_O ),
|
||||
.vs ( SD_VS_O ),
|
||||
.red ( osd_r_o ),
|
||||
.green ( osd_g_o ),
|
||||
.blue ( osd_b_o ),
|
||||
.hs_out ( cofi_hs ),
|
||||
.vs_out ( cofi_vs ),
|
||||
.red_out ( cofi_r ),
|
||||
.green_out( cofi_g ),
|
||||
.blue_out( cofi_b )
|
||||
);
|
||||
|
||||
wire hs, vs, cs;
|
||||
wire [5:0] r,g,b;
|
||||
|
||||
RGBtoYPbPr #(6) rgb2ypbpr
|
||||
(
|
||||
.clk ( clk_sys ),
|
||||
.ena ( ypbpr ),
|
||||
|
||||
.red_in ( cofi_r ),
|
||||
.green_in ( cofi_g ),
|
||||
.blue_in ( cofi_b ),
|
||||
.hs_in ( cofi_hs ),
|
||||
.vs_in ( cofi_vs ),
|
||||
.cs_in ( SYNC_AND ? (cofi_hs & cofi_vs) : ~(cofi_hs ^ cofi_vs) ),
|
||||
.red_out ( r ),
|
||||
.green_out ( g ),
|
||||
.blue_out ( b ),
|
||||
.hs_out ( hs ),
|
||||
.vs_out ( vs ),
|
||||
.cs_out ( cs )
|
||||
);
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
VGA_R <= r;
|
||||
VGA_G <= g;
|
||||
VGA_B <= b;
|
||||
// a minimig vga->scart cable expects a composite sync signal on the VGA_HS output.
|
||||
// and VCC on VGA_VS (to switch into rgb mode)
|
||||
VGA_HS <= ((~no_csync & scandoubler_disable) || ypbpr)? cs : hs;
|
||||
VGA_VS <= ((~no_csync & scandoubler_disable) || ypbpr)? 1'b1 : vs;
|
||||
end
|
||||
endmodule
|
216
rtl/mist-modules/osd.v
Normal file
216
rtl/mist-modules/osd.v
Normal file
@ -0,0 +1,216 @@
|
||||
// A simple OSD implementation. Can be hooked up between a cores
|
||||
// VGA output and the physical VGA pins
|
||||
|
||||
module osd (
|
||||
// OSDs pixel clock, should be synchronous to cores pixel clock to
|
||||
// avoid jitter.
|
||||
input clk_sys,
|
||||
input ce,
|
||||
|
||||
// SPI interface
|
||||
input SPI_SCK,
|
||||
input SPI_SS3,
|
||||
input SPI_DI,
|
||||
|
||||
input [1:0] rotate, //[0] - rotate [1] - left or right
|
||||
|
||||
// VGA signals coming from core
|
||||
input [5:0] R_in,
|
||||
input [5:0] G_in,
|
||||
input [5:0] B_in,
|
||||
input HSync,
|
||||
input VSync,
|
||||
|
||||
// VGA signals going to video connector
|
||||
output [5:0] R_out,
|
||||
output [5:0] G_out,
|
||||
output [5:0] B_out
|
||||
);
|
||||
|
||||
parameter OSD_X_OFFSET = 11'd0;
|
||||
parameter OSD_Y_OFFSET = 11'd0;
|
||||
parameter OSD_COLOR = 3'd0;
|
||||
parameter OSD_AUTO_CE = 1'b1;
|
||||
|
||||
localparam OSD_WIDTH = 11'd256;
|
||||
localparam OSD_HEIGHT = 11'd128;
|
||||
|
||||
localparam OSD_WIDTH_PADDED = OSD_WIDTH + (OSD_WIDTH >> 1); // 25% padding left and right
|
||||
|
||||
// *********************************************************************************
|
||||
// spi client
|
||||
// *********************************************************************************
|
||||
|
||||
// this core supports only the display related OSD commands
|
||||
// of the minimig
|
||||
reg osd_enable;
|
||||
(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself
|
||||
|
||||
// the OSD has its own SPI interface to the io controller
|
||||
always@(posedge SPI_SCK, posedge SPI_SS3) begin
|
||||
reg [4:0] cnt;
|
||||
reg [10:0] bcnt;
|
||||
reg [7:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
|
||||
if(SPI_SS3) begin
|
||||
cnt <= 0;
|
||||
bcnt <= 0;
|
||||
end else begin
|
||||
sbuf <= {sbuf[6:0], SPI_DI};
|
||||
|
||||
// 0:7 is command, rest payload
|
||||
if(cnt < 15) cnt <= cnt + 1'd1;
|
||||
else cnt <= 8;
|
||||
|
||||
if(cnt == 7) begin
|
||||
cmd <= {sbuf[6:0], SPI_DI};
|
||||
|
||||
// lower three command bits are line address
|
||||
bcnt <= {sbuf[1:0], SPI_DI, 8'h00};
|
||||
|
||||
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
|
||||
if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI;
|
||||
end
|
||||
|
||||
// command 0x20: OSDCMDWRITE
|
||||
if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin
|
||||
osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI};
|
||||
bcnt <= bcnt + 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// *********************************************************************************
|
||||
// video timing and sync polarity anaylsis
|
||||
// *********************************************************************************
|
||||
|
||||
// horizontal counter
|
||||
reg [10:0] h_cnt;
|
||||
reg [10:0] hs_low, hs_high;
|
||||
wire hs_pol = hs_high < hs_low;
|
||||
wire [10:0] dsp_width = hs_pol ? hs_low : hs_high;
|
||||
|
||||
// vertical counter
|
||||
reg [10:0] v_cnt;
|
||||
reg [10:0] vs_low, vs_high;
|
||||
wire vs_pol = vs_high < vs_low;
|
||||
wire [10:0] dsp_height = vs_pol ? vs_low : vs_high;
|
||||
|
||||
wire doublescan = (dsp_height>350);
|
||||
|
||||
reg auto_ce_pix;
|
||||
always @(posedge clk_sys) begin
|
||||
reg [15:0] cnt = 0;
|
||||
reg [2:0] pixsz;
|
||||
reg [2:0] pixcnt;
|
||||
reg hs;
|
||||
|
||||
cnt <= cnt + 1'd1;
|
||||
hs <= HSync;
|
||||
|
||||
pixcnt <= pixcnt + 1'd1;
|
||||
if(pixcnt == pixsz) pixcnt <= 0;
|
||||
auto_ce_pix <= !pixcnt;
|
||||
|
||||
if(hs && ~HSync) begin
|
||||
cnt <= 0;
|
||||
if(cnt <= OSD_WIDTH_PADDED * 2) pixsz <= 0;
|
||||
else if(cnt <= OSD_WIDTH_PADDED * 3) pixsz <= 1;
|
||||
else if(cnt <= OSD_WIDTH_PADDED * 4) pixsz <= 2;
|
||||
else if(cnt <= OSD_WIDTH_PADDED * 5) pixsz <= 3;
|
||||
else if(cnt <= OSD_WIDTH_PADDED * 6) pixsz <= 4;
|
||||
else pixsz <= 5;
|
||||
|
||||
pixcnt <= 0;
|
||||
auto_ce_pix <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
wire ce_pix = OSD_AUTO_CE ? auto_ce_pix : ce;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD;
|
||||
reg vsD;
|
||||
|
||||
if(ce_pix) begin
|
||||
// bring hsync into local clock domain
|
||||
hsD <= HSync;
|
||||
|
||||
// falling edge of HSync
|
||||
if(!HSync && hsD) begin
|
||||
h_cnt <= 0;
|
||||
hs_high <= h_cnt;
|
||||
end
|
||||
|
||||
// rising edge of HSync
|
||||
else if(HSync && !hsD) begin
|
||||
h_cnt <= 0;
|
||||
hs_low <= h_cnt;
|
||||
v_cnt <= v_cnt + 1'd1;
|
||||
end else begin
|
||||
h_cnt <= h_cnt + 1'd1;
|
||||
end
|
||||
|
||||
vsD <= VSync;
|
||||
|
||||
// falling edge of VSync
|
||||
if(!VSync && vsD) begin
|
||||
v_cnt <= 0;
|
||||
// if the difference is only one line, that might be interlaced picture
|
||||
if (vs_high != v_cnt + 1'd1) vs_high <= v_cnt;
|
||||
end
|
||||
|
||||
// rising edge of VSync
|
||||
else if(VSync && !vsD) begin
|
||||
v_cnt <= 0;
|
||||
// if the difference is only one line, that might be interlaced picture
|
||||
if (vs_low != v_cnt + 1'd1) vs_low <= v_cnt;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// area in which OSD is being displayed
|
||||
reg [10:0] h_osd_start;
|
||||
reg [10:0] h_osd_end;
|
||||
reg [10:0] v_osd_start;
|
||||
reg [10:0] v_osd_end;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
h_osd_start <= ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET;
|
||||
h_osd_end <= h_osd_start + OSD_WIDTH;
|
||||
v_osd_start <= ((dsp_height- (OSD_HEIGHT<<doublescan))>> 1) + OSD_Y_OFFSET;
|
||||
v_osd_end <= v_osd_start + (OSD_HEIGHT<<doublescan);
|
||||
end
|
||||
|
||||
wire [10:0] osd_hcnt = h_cnt - h_osd_start;
|
||||
wire [10:0] osd_vcnt = v_cnt - v_osd_start;
|
||||
wire [10:0] osd_hcnt_next = osd_hcnt + 2'd1; // one pixel offset for osd pixel
|
||||
wire [10:0] osd_hcnt_next2 = osd_hcnt + 2'd2; // two pixel offset for osd byte address register
|
||||
reg osd_de;
|
||||
|
||||
reg [10:0] osd_buffer_addr;
|
||||
wire [7:0] osd_byte = osd_buffer[osd_buffer_addr];
|
||||
reg osd_pixel;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
if(ce_pix) begin
|
||||
osd_buffer_addr <= rotate[0] ? {rotate[1] ? osd_hcnt_next2[7:5] : ~osd_hcnt_next2[7:5],
|
||||
rotate[1] ? (doublescan ? ~osd_vcnt[7:0] : ~{osd_vcnt[6:0], 1'b0}) :
|
||||
(doublescan ? osd_vcnt[7:0] : {osd_vcnt[6:0], 1'b0})} :
|
||||
{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt_next2[7:0]};
|
||||
|
||||
osd_pixel <= rotate[0] ? osd_byte[rotate[1] ? osd_hcnt_next[4:2] : ~osd_hcnt_next[4:2]] :
|
||||
osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]];
|
||||
|
||||
osd_de <= osd_enable &&
|
||||
(HSync != hs_pol) && ((h_cnt + 1'd1) >= h_osd_start) && ((h_cnt + 1'd1) < h_osd_end) &&
|
||||
(VSync != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end);
|
||||
end
|
||||
end
|
||||
|
||||
assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]};
|
||||
assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]};
|
||||
assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]};
|
||||
|
||||
endmodule
|
0
rtl/mist-modules/pll.qip
Normal file
0
rtl/mist-modules/pll.qip
Normal file
103
rtl/mist-modules/rgb2ypbpr.v
Normal file
103
rtl/mist-modules/rgb2ypbpr.v
Normal file
@ -0,0 +1,103 @@
|
||||
// Multiplier-based RGB -> YPbPr conversion
|
||||
|
||||
// Copyright 2020/2021 by Alastair M. Robinson
|
||||
|
||||
module RGBtoYPbPr
|
||||
(
|
||||
input clk,
|
||||
input ena,
|
||||
|
||||
input [WIDTH-1:0] red_in,
|
||||
input [WIDTH-1:0] green_in,
|
||||
input [WIDTH-1:0] blue_in,
|
||||
input hs_in,
|
||||
input vs_in,
|
||||
input cs_in,
|
||||
input pixel_in,
|
||||
|
||||
output [WIDTH-1:0] red_out,
|
||||
output [WIDTH-1:0] green_out,
|
||||
output [WIDTH-1:0] blue_out,
|
||||
output reg hs_out,
|
||||
output reg vs_out,
|
||||
output reg cs_out,
|
||||
output reg pixel_out
|
||||
);
|
||||
|
||||
parameter WIDTH = 8;
|
||||
|
||||
reg [8+WIDTH-1:0] r_y;
|
||||
reg [8+WIDTH-1:0] g_y;
|
||||
reg [8+WIDTH-1:0] b_y;
|
||||
|
||||
reg [8+WIDTH-1:0] r_b;
|
||||
reg [8+WIDTH-1:0] g_b;
|
||||
reg [8+WIDTH-1:0] b_b;
|
||||
|
||||
reg [8+WIDTH-1:0] r_r;
|
||||
reg [8+WIDTH-1:0] g_r;
|
||||
reg [8+WIDTH-1:0] b_r;
|
||||
|
||||
reg [8+WIDTH-1:0] y;
|
||||
reg [8+WIDTH-1:0] b;
|
||||
reg [8+WIDTH-1:0] r;
|
||||
|
||||
reg hs_d;
|
||||
reg vs_d;
|
||||
reg cs_d;
|
||||
reg pixel_d;
|
||||
|
||||
assign red_out = r[8+WIDTH-1:8];
|
||||
assign green_out = y[8+WIDTH-1:8];
|
||||
assign blue_out = b[8+WIDTH-1:8];
|
||||
|
||||
// Multiply in the first stage...
|
||||
always @(posedge clk) begin
|
||||
hs_d <= hs_in; // Register sync, pixel clock, etc
|
||||
vs_d <= vs_in; // so they're delayed the same amount as the incoming video
|
||||
cs_d <= cs_in;
|
||||
pixel_d <= pixel_in;
|
||||
|
||||
if(ena) begin
|
||||
// (Y = 0.299*R + 0.587*G + 0.114*B)
|
||||
r_y <= red_in * 8'd76;
|
||||
g_y <= green_in * 8'd150;
|
||||
b_y <= blue_in * 8'd29;
|
||||
|
||||
// (Pb = -0.169*R - 0.331*G + 0.500*B)
|
||||
r_b <= red_in * 8'd43;
|
||||
g_b <= green_in * 8'd84;
|
||||
b_b <= blue_in * 8'd128;
|
||||
|
||||
// (Pr = 0.500*R - 0.419*G - 0.081*B)
|
||||
r_r <= red_in * 8'd128;
|
||||
g_r <= green_in * 8'd107;
|
||||
b_r <= blue_in * 8'd20;
|
||||
end else begin
|
||||
r_r[8+WIDTH-1:8] <= red_in; // Passthrough
|
||||
g_y[8+WIDTH-1:8] <= green_in;
|
||||
b_b[8+WIDTH-1:8] <= blue_in;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// Second stage - adding
|
||||
|
||||
always @(posedge clk) begin
|
||||
hs_out <= hs_d;
|
||||
vs_out <= vs_d;
|
||||
cs_out <= cs_d;
|
||||
pixel_out <= pixel_d;
|
||||
|
||||
if(ena) begin
|
||||
y <= r_y + g_y + b_y;
|
||||
b <= 2'd2**(8+WIDTH-1) + b_b - r_b - g_b;
|
||||
r <= 2'd2**(8+WIDTH-1) + r_r - g_r - b_r;
|
||||
end else begin
|
||||
y <= g_y; // Passthrough
|
||||
b <= b_b;
|
||||
r <= r_r;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
229
rtl/mist-modules/scandoubler.v
Normal file
229
rtl/mist-modules/scandoubler.v
Normal file
@ -0,0 +1,229 @@
|
||||
//
|
||||
// scandoubler.v
|
||||
//
|
||||
// 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/>.
|
||||
|
||||
// TODO: Delay vsync one line
|
||||
|
||||
module scandoubler
|
||||
(
|
||||
// system interface
|
||||
input clk_sys,
|
||||
input bypass,
|
||||
input ce_divider,
|
||||
output pixel_ena,
|
||||
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
input [1:0] scanlines,
|
||||
|
||||
// shifter video interface
|
||||
input hs_in,
|
||||
input vs_in,
|
||||
input [COLOR_DEPTH-1:0] r_in,
|
||||
input [COLOR_DEPTH-1:0] g_in,
|
||||
input [COLOR_DEPTH-1:0] b_in,
|
||||
|
||||
// output interface
|
||||
output reg hs_out,
|
||||
output reg vs_out,
|
||||
output reg [5:0] r_out,
|
||||
output reg [5:0] g_out,
|
||||
output reg [5:0] b_out
|
||||
);
|
||||
|
||||
parameter HCNT_WIDTH = 9;
|
||||
parameter COLOR_DEPTH = 6;
|
||||
|
||||
// pixel clock divider
|
||||
reg [1:0] i_div;
|
||||
reg ce_x1, ce_x2;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg last_hs_in;
|
||||
last_hs_in <= hs_in;
|
||||
if(last_hs_in & !hs_in) begin
|
||||
i_div <= 2'b00;
|
||||
end else begin
|
||||
i_div <= i_div + 2'd1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(*) begin
|
||||
if (!ce_divider) begin
|
||||
ce_x1 = (i_div == 2'b01);
|
||||
ce_x2 = i_div[0];
|
||||
end else begin
|
||||
ce_x1 = i_div[0];
|
||||
ce_x2 = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
assign pixel_ena = bypass ? ce_x1 : ce_x2;
|
||||
|
||||
// --------------------- create output signals -----------------
|
||||
// latch everything once more to make it glitch free and apply scanline effect
|
||||
reg scanline;
|
||||
reg [5:0] r;
|
||||
reg [5:0] g;
|
||||
reg [5:0] b;
|
||||
|
||||
always @(*) begin
|
||||
if (COLOR_DEPTH == 6) begin
|
||||
b = sd_out[5:0];
|
||||
g = sd_out[11:6];
|
||||
r = sd_out[17:12];
|
||||
end else if (COLOR_DEPTH == 2) begin
|
||||
b = {3{sd_out[1:0]}};
|
||||
g = {3{sd_out[3:2]}};
|
||||
r = {3{sd_out[5:4]}};
|
||||
end else if (COLOR_DEPTH == 1) begin
|
||||
b = {6{sd_out[0]}};
|
||||
g = {6{sd_out[1]}};
|
||||
r = {6{sd_out[2]}};
|
||||
end else begin
|
||||
b = { sd_out[COLOR_DEPTH-1:0], sd_out[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] };
|
||||
g = { sd_out[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_out[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] };
|
||||
r = { sd_out[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_out[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] };
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
if(bypass) begin
|
||||
r_out <= r;
|
||||
g_out <= g;
|
||||
b_out <= b;
|
||||
hs_out <= hs_sd;
|
||||
vs_out <= vs_sd;
|
||||
end else if(ce_x2) begin
|
||||
hs_out <= hs_sd;
|
||||
vs_out <= vs_sd;
|
||||
|
||||
// reset scanlines at every new screen
|
||||
if(vs_out != vs_in) scanline <= 0;
|
||||
|
||||
// toggle scanlines at begin of every hsync
|
||||
if(hs_out && !hs_sd) scanline <= !scanline;
|
||||
|
||||
// if no scanlines or not a scanline
|
||||
if(!scanline || !scanlines) begin
|
||||
r_out <= r;
|
||||
g_out <= g;
|
||||
b_out <= b;
|
||||
end else begin
|
||||
case(scanlines)
|
||||
1: begin // reduce 25% = 1/2 + 1/4
|
||||
r_out <= {1'b0, r[5:1]} + {2'b00, r[5:2] };
|
||||
g_out <= {1'b0, g[5:1]} + {2'b00, g[5:2] };
|
||||
b_out <= {1'b0, b[5:1]} + {2'b00, b[5:2] };
|
||||
end
|
||||
|
||||
2: begin // reduce 50% = 1/2
|
||||
r_out <= {1'b0, r[5:1]};
|
||||
g_out <= {1'b0, g[5:1]};
|
||||
b_out <= {1'b0, b[5:1]};
|
||||
end
|
||||
|
||||
3: begin // reduce 75% = 1/4
|
||||
r_out <= {2'b00, r[5:2]};
|
||||
g_out <= {2'b00, g[5:2]};
|
||||
b_out <= {2'b00, b[5:2]};
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// scan doubler output register
|
||||
wire [COLOR_DEPTH*3-1:0] sd_out = bypass ? sd_bypass_out : sd_buffer_out;
|
||||
|
||||
// ==================================================================
|
||||
// ======================== the line buffers ========================
|
||||
// ==================================================================
|
||||
|
||||
// 2 lines of 2**HCNT_WIDTH pixels 3*COLOR_DEPTH bit RGB
|
||||
(* ramstyle = "no_rw_check" *) reg [COLOR_DEPTH*3-1:0] sd_buffer[2*2**HCNT_WIDTH];
|
||||
|
||||
// use alternating sd_buffers when storing/reading data
|
||||
reg line_toggle;
|
||||
|
||||
// total hsync time (in 16MHz cycles), hs_total reaches 1024
|
||||
reg [HCNT_WIDTH-1:0] hs_max;
|
||||
reg [HCNT_WIDTH-1:0] hs_rise;
|
||||
reg [HCNT_WIDTH-1:0] hcnt;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD, vsD;
|
||||
|
||||
if(ce_x1) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// falling edge of hsync indicates start of line
|
||||
if(hsD && !hs_in) begin
|
||||
hs_max <= hcnt;
|
||||
hcnt <= 0;
|
||||
end else begin
|
||||
hcnt <= hcnt + 1'd1;
|
||||
end
|
||||
|
||||
// save position of rising edge
|
||||
if(!hsD && hs_in) hs_rise <= hcnt;
|
||||
|
||||
vsD <= vs_in;
|
||||
if(vsD != vs_in) line_toggle <= 0;
|
||||
|
||||
// begin of incoming hsync
|
||||
if(hsD && !hs_in) line_toggle <= !line_toggle;
|
||||
|
||||
sd_buffer[{line_toggle, hcnt}] <= {r_in, g_in, b_in};
|
||||
end
|
||||
end
|
||||
|
||||
// ==================================================================
|
||||
// ==================== output timing generation ====================
|
||||
// ==================================================================
|
||||
|
||||
reg [COLOR_DEPTH*3-1:0] sd_buffer_out, sd_bypass_out;
|
||||
reg [HCNT_WIDTH-1:0] sd_hcnt;
|
||||
reg hs_sd, vs_sd;
|
||||
|
||||
// timing generation runs 32 MHz (twice the input signal analysis speed)
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD;
|
||||
|
||||
if(ce_x2) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// output counter synchronous to input and at twice the rate
|
||||
sd_hcnt <= sd_hcnt + 1'd1;
|
||||
if(hsD && !hs_in) sd_hcnt <= hs_max;
|
||||
if(sd_hcnt == hs_max) sd_hcnt <= 0;
|
||||
|
||||
// replicate horizontal sync at twice the speed
|
||||
if(sd_hcnt == hs_max) hs_sd <= 0;
|
||||
if(sd_hcnt == hs_rise) hs_sd <= 1;
|
||||
|
||||
// read data from line sd_buffer
|
||||
sd_buffer_out <= sd_buffer[{~line_toggle, sd_hcnt}];
|
||||
vs_sd <= vs_in;
|
||||
end
|
||||
if(bypass) begin
|
||||
sd_bypass_out <= {r_in, g_in, b_in};
|
||||
hs_sd <= hs_in;
|
||||
vs_sd <= vs_in;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
619
rtl/mist-modules/sd_card.v
Normal file
619
rtl/mist-modules/sd_card.v
Normal file
@ -0,0 +1,619 @@
|
||||
//
|
||||
// sd_card.v
|
||||
//
|
||||
// This file implelents a sd card for the MIST board since on the board
|
||||
// the SD card is connected to the ARM IO controller and the FPGA has no
|
||||
// direct connection to the SD card. This file provides a SD card like
|
||||
// interface to the IO controller easing porting of cores that expect
|
||||
// a direct interface to the SD card.
|
||||
//
|
||||
// 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 Lesser 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/>.
|
||||
//
|
||||
// http://elm-chan.org/docs/mmc/mmc_e.html
|
||||
|
||||
module sd_card (
|
||||
input clk_sys,
|
||||
// link to user_io for io controller
|
||||
output reg[31:0] sd_lba,
|
||||
output reg sd_rd,
|
||||
output reg sd_wr,
|
||||
input sd_ack,
|
||||
input sd_ack_conf,
|
||||
output sd_conf,
|
||||
output sd_sdhc,
|
||||
|
||||
input img_mounted,
|
||||
input [63:0] img_size,
|
||||
|
||||
output reg sd_busy = 0,
|
||||
// data coming in from io controller
|
||||
input [7:0] sd_buff_dout,
|
||||
input sd_buff_wr,
|
||||
|
||||
// data going out to io controller
|
||||
output [7:0] sd_buff_din,
|
||||
|
||||
input [8:0] sd_buff_addr,
|
||||
|
||||
// configuration input
|
||||
// in case of a VHD file, this will determine the SD Card type returned to the SPI master
|
||||
// in case of a pass-through, the firmware will display a warning if SDHC is not allowed,
|
||||
// but the card inserted is SDHC
|
||||
input allow_sdhc,
|
||||
|
||||
input sd_cs,
|
||||
input sd_sck,
|
||||
input sd_sdi,
|
||||
output reg sd_sdo
|
||||
);
|
||||
|
||||
wire [31:0] OCR = { 1'b1, sdhc, 6'h0, 9'h1f, 15'h0 }; // bit31 = finished powerup
|
||||
// bit30 = 1 -> high capaciry card (sdhc)
|
||||
// 15-23 supported voltage range
|
||||
wire [7:0] READ_DATA_TOKEN = 8'hfe;
|
||||
|
||||
// number of bytes to wait after a command before sending the reply
|
||||
localparam NCR=4;
|
||||
|
||||
localparam RD_STATE_IDLE = 3'd0;
|
||||
localparam RD_STATE_WAIT_BUSY = 3'd1;
|
||||
localparam RD_STATE_WAIT_IO = 3'd2;
|
||||
localparam RD_STATE_SEND_TOKEN = 3'd3;
|
||||
localparam RD_STATE_SEND_DATA = 3'd4;
|
||||
localparam RD_STATE_DELAY = 3'd5;
|
||||
reg [2:0] read_state = RD_STATE_IDLE;
|
||||
|
||||
localparam WR_STATE_IDLE = 3'd0;
|
||||
localparam WR_STATE_EXP_DTOKEN = 3'd1;
|
||||
localparam WR_STATE_RECV_DATA = 3'd2;
|
||||
localparam WR_STATE_RECV_CRC0 = 3'd3;
|
||||
localparam WR_STATE_RECV_CRC1 = 3'd4;
|
||||
localparam WR_STATE_SEND_DRESP = 3'd5;
|
||||
localparam WR_STATE_WRITE = 3'd6;
|
||||
localparam WR_STATE_BUSY = 3'd7;
|
||||
reg [2:0] write_state = WR_STATE_IDLE;
|
||||
|
||||
reg card_is_reset = 1'b0; // flag that card has received a reset command
|
||||
reg [6:0] sbuf;
|
||||
reg cmd55;
|
||||
reg terminate_cmd = 1'b0;
|
||||
reg [7:0] cmd = 8'h00;
|
||||
reg [2:0] bit_cnt = 3'd0; // counts bits 0-7 0-7 ...
|
||||
reg [3:0] byte_cnt= 4'd15; // counts bytes
|
||||
reg [4:0] delay_cnt;
|
||||
reg wr_first;
|
||||
|
||||
reg [39:0] args;
|
||||
|
||||
reg [7:0] reply;
|
||||
reg [7:0] reply0, reply1, reply2, reply3;
|
||||
reg [3:0] reply_len;
|
||||
|
||||
// ------------------------- SECTOR BUFFER -----------------------
|
||||
|
||||
// the buffer itself. Can hold two sectors
|
||||
reg [9:0] buffer_ptr;
|
||||
wire [7:0] buffer_dout;
|
||||
reg [7:0] buffer_din;
|
||||
reg buffer_write_strobe;
|
||||
reg sd_buff_sel;
|
||||
|
||||
sd_card_dpram #(8, 10) buffer_dpram
|
||||
(
|
||||
.clock_a (clk_sys),
|
||||
.address_a ({sd_buff_sel, sd_buff_addr}),
|
||||
.data_a (sd_buff_dout),
|
||||
.wren_a (sd_buff_wr & sd_ack & read_state != RD_STATE_IDLE),
|
||||
.q_a (sd_buff_din),
|
||||
|
||||
.clock_b (clk_sys),
|
||||
.address_b (buffer_ptr),
|
||||
.data_b (buffer_din),
|
||||
.wren_b (buffer_write_strobe),
|
||||
.q_b (buffer_dout)
|
||||
);
|
||||
|
||||
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
|
||||
|
||||
// ------------------------- CSD/CID BUFFER ----------------------
|
||||
reg [7:0] conf;
|
||||
assign sd_conf = sd_configuring;
|
||||
|
||||
reg sd_configuring = 1;
|
||||
reg [4:0] conf_buff_ptr;
|
||||
reg [7:0] conf_byte_orig;
|
||||
reg[255:0] csdcid;
|
||||
|
||||
reg vhd = 0;
|
||||
reg [40:0] vhd_size;
|
||||
|
||||
// conf[0]==1 -> io controller is using an sdhc card
|
||||
wire sd_has_sdhc = conf[0];
|
||||
assign sd_sdhc = (allow_sdhc & sd_has_sdhc) | vhd; // report to user_io
|
||||
wire sdhc = allow_sdhc & (sd_has_sdhc | vhd); // used internally
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg old_mounted;
|
||||
|
||||
if (sd_buff_wr & sd_ack_conf) begin
|
||||
if (sd_buff_addr == 32) begin
|
||||
conf <= sd_buff_dout;
|
||||
sd_configuring <= 0;
|
||||
end
|
||||
else csdcid[(31-sd_buff_addr) << 3 +:8] <= sd_buff_dout;
|
||||
end
|
||||
conf_byte_orig <= csdcid[(31-conf_buff_ptr) << 3 +:8];
|
||||
|
||||
old_mounted <= img_mounted;
|
||||
if (~old_mounted & img_mounted) begin
|
||||
vhd <= |img_size;
|
||||
vhd_size <= img_size[40:0];
|
||||
end
|
||||
end
|
||||
|
||||
// CSD V1.0 no. of blocks = c_size ** (c_size_mult + 2)
|
||||
wire [127:0] csd_sd = {
|
||||
8'h00, // CSD_STRUCTURE + reserved
|
||||
8'h2d, // TAAC
|
||||
8'd0, // NSAC
|
||||
8'h32, // TRAN_SPEED
|
||||
12'h5b5, // CCC
|
||||
4'h9, // READ_BL_LEN
|
||||
1'b1, 1'b0, 1'b0, 1'b0, // READ_BL_PARTIAL, WRITE_BLK_MISALIGN, READ_BLK_MISALIGN, DSR_IMP
|
||||
2'd0, vhd_size[29:18], // reserved + C_SIZE
|
||||
3'b111, // VDD_R_CURR_MIN
|
||||
3'b110, // VDD_R_CURR_MAX
|
||||
3'b111, // VDD_W_CURR_MIN
|
||||
3'b110, // VDD_W_CURR_MAX
|
||||
3'd7, // C_SIZE_MULT
|
||||
1'b1, // ERASE_BLK_EN
|
||||
7'd127, // SECTOR_SIZE
|
||||
7'd0, // WP_GRP_SIZE
|
||||
1'b0, // WP_GRP_ENABLE,
|
||||
2'b00, // reserved,
|
||||
3'd5, // R2W_FACTOR,
|
||||
4'h9, // WRITE_BL_LEN,
|
||||
1'b0, // WRITE_BL_PARTIAL,
|
||||
5'd0, // reserved,
|
||||
8'd0,
|
||||
7'h67, // CRC (wrong, but usually not checked)
|
||||
1'b1 };
|
||||
|
||||
// CSD V2.0 size = (c_size + 1) * 512K
|
||||
wire [127:0] csd_sdhc = {
|
||||
8'h40, // CSD_STRUCTURE + reserved
|
||||
8'h0e, // TAAC
|
||||
8'd0, // NSAC
|
||||
8'h32, // TRAN_SPEED
|
||||
12'h5b5, // CCC
|
||||
4'h9, // READ_BL_LEN
|
||||
1'b0, 1'b0, 1'b0, 1'b0, // READ_BL_PARTIAL, WRITE_BLK_MISALIGN, READ_BLK_MISALIGN, DSR_IMP
|
||||
6'd0, // reserved
|
||||
vhd_size[40:19] - 1'd1, // C_SIZE
|
||||
1'b0, // reserved
|
||||
1'b1, // ERASE_BLK_EN
|
||||
7'd127, // SECTOR_SIZE
|
||||
7'd0, // WP_GRP_SIZE
|
||||
1'b0, // WP_GRP_ENABLE,
|
||||
2'b00, // reserved,
|
||||
3'd2, // R2W_FACTOR,
|
||||
4'h9, // WRITE_BL_LEN,
|
||||
1'b0, // WRITE_BL_PARTIAL,
|
||||
5'd0, // reserved,
|
||||
8'd0,
|
||||
7'h78, // CRC (wrong, but usually not checked)
|
||||
1'b1 };
|
||||
|
||||
wire [7:0] conf_byte = (!conf_buff_ptr[4] | !vhd) ? conf_byte_orig : // CID or CSD if not VHD
|
||||
sdhc ? csd_sdhc[(15-conf_buff_ptr[3:0]) << 3 +:8] :
|
||||
csd_sd[(15-conf_buff_ptr[3:0]) << 3 +:8];
|
||||
|
||||
always@(posedge clk_sys) begin
|
||||
|
||||
reg old_sd_sck;
|
||||
reg [5:0] ack;
|
||||
|
||||
ack <= {ack[4:0], sd_ack};
|
||||
if(ack[5:4] == 'b01) { sd_rd, sd_wr } <= 2'b00;
|
||||
if(ack[5:4] == 'b10) sd_busy <= 0;
|
||||
|
||||
buffer_write_strobe <= 0;
|
||||
if (buffer_write_strobe) buffer_ptr <= buffer_ptr + 1'd1;
|
||||
|
||||
old_sd_sck <= sd_sck;
|
||||
|
||||
// advance transmitter state machine on falling sck edge, so data is valid on the
|
||||
// rising edge
|
||||
// ----------------- spi transmitter --------------------
|
||||
if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin
|
||||
|
||||
sd_sdo <= 1'b1; // default: send 1's (busy/wait)
|
||||
|
||||
if(byte_cnt == 5+NCR) begin
|
||||
sd_sdo <= reply[~bit_cnt];
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
// these three commands all have a reply_len of 0 and will thus
|
||||
// not send more than a single reply byte
|
||||
|
||||
// CMD9: SEND_CSD
|
||||
// CMD10: SEND_CID
|
||||
if((cmd == 8'h49)||(cmd == 8'h4a))
|
||||
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
|
||||
|
||||
// CMD17: READ_SINGLE_BLOCK
|
||||
// CMD18: READ_MULTIPLE_BLOCK
|
||||
if((cmd == 8'h51 || cmd == 8'h52) && !terminate_cmd)
|
||||
read_state <= RD_STATE_WAIT_BUSY; // start waiting for data from io controller
|
||||
|
||||
end
|
||||
end
|
||||
else if((reply_len > 0) && (byte_cnt == 5+NCR+1))
|
||||
sd_sdo <= reply0[~bit_cnt];
|
||||
else if((reply_len > 1) && (byte_cnt == 5+NCR+2))
|
||||
sd_sdo <= reply1[~bit_cnt];
|
||||
else if((reply_len > 2) && (byte_cnt == 5+NCR+3))
|
||||
sd_sdo <= reply2[~bit_cnt];
|
||||
else if((reply_len > 3) && (byte_cnt == 5+NCR+4))
|
||||
sd_sdo <= reply3[~bit_cnt];
|
||||
|
||||
// ---------- read state machine processing -------------
|
||||
|
||||
case(read_state)
|
||||
RD_STATE_IDLE: ;
|
||||
// don't do anything
|
||||
|
||||
// wait until the IO controller is free and issue a read
|
||||
RD_STATE_WAIT_BUSY:
|
||||
if (~sd_busy) begin
|
||||
sd_buff_sel <= 0;
|
||||
sd_lba <= sdhc?args[39:8]:{9'd0, args[39:17]};
|
||||
sd_rd <= 1; // trigger request to io controller
|
||||
sd_busy <= 1;
|
||||
read_state <= RD_STATE_WAIT_IO;
|
||||
end
|
||||
|
||||
// waiting for io controller to return data
|
||||
RD_STATE_WAIT_IO: begin
|
||||
buffer_ptr <= 0;
|
||||
if(~sd_busy) begin
|
||||
if (terminate_cmd) begin
|
||||
cmd <= 0;
|
||||
read_state <= RD_STATE_IDLE;
|
||||
end else if (bit_cnt == 7)
|
||||
read_state <= RD_STATE_SEND_TOKEN;
|
||||
end
|
||||
end
|
||||
|
||||
// send data token
|
||||
RD_STATE_SEND_TOKEN: begin
|
||||
if(~sd_busy) begin
|
||||
sd_sdo <= READ_DATA_TOKEN[~bit_cnt];
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
read_state <= RD_STATE_SEND_DATA; // next: send data
|
||||
conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// send data
|
||||
RD_STATE_SEND_DATA: begin
|
||||
if(cmd == 8'h51 || (cmd == 8'h52 && !terminate_cmd)) // CMD17: READ_SINGLE_BLOCK, CMD18: READ_MULTIPLE_BLOCK
|
||||
sd_sdo <= buffer_dout[~bit_cnt];
|
||||
else if(cmd == 8'h49 || cmd == 8'h4a) // CMD9: SEND_CSD, CMD10: SEND CID
|
||||
sd_sdo <= conf_byte[~bit_cnt];
|
||||
|
||||
if(bit_cnt == 7) begin
|
||||
|
||||
// sent 512 sector data bytes?
|
||||
if((cmd == 8'h51) && &buffer_ptr[8:0])
|
||||
read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state
|
||||
|
||||
if (cmd == 8'h52) begin
|
||||
if (terminate_cmd) begin
|
||||
read_state <= RD_STATE_IDLE;
|
||||
cmd <= 0;
|
||||
end else if (buffer_ptr[8:0] == 10) begin
|
||||
// prefetch the next sector into the other buffer
|
||||
sd_lba <= sd_lba + 1'd1;
|
||||
sd_rd <= 1;
|
||||
sd_busy <= 1;
|
||||
sd_buff_sel <= !sd_buff_sel;
|
||||
end else if (&buffer_ptr[8:0]) begin
|
||||
delay_cnt <= 20;
|
||||
read_state <= RD_STATE_DELAY;
|
||||
end
|
||||
end
|
||||
|
||||
// sent 16 cid/csd data bytes?
|
||||
if(((cmd == 8'h49)||(cmd == 8'h4a)) && conf_buff_ptr[3:0] == 4'h0f) // && (buffer_rptr == 16))
|
||||
read_state <= RD_STATE_IDLE; // return to idle state
|
||||
|
||||
buffer_ptr <= buffer_ptr + 1'd1;
|
||||
conf_buff_ptr<= conf_buff_ptr+ 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
RD_STATE_DELAY:
|
||||
if(bit_cnt == 7) begin
|
||||
if (delay_cnt == 0) begin
|
||||
read_state <= RD_STATE_SEND_TOKEN;
|
||||
end else begin
|
||||
delay_cnt <= delay_cnt - 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
|
||||
// ------------------ write support ----------------------
|
||||
// send write data response
|
||||
if(write_state == WR_STATE_SEND_DRESP)
|
||||
sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt];
|
||||
|
||||
// busy after write until the io controller sends ack
|
||||
if(write_state == WR_STATE_WRITE || write_state == WR_STATE_BUSY)
|
||||
sd_sdo <= 1'b0;
|
||||
end
|
||||
|
||||
// spi receiver
|
||||
// cs is active low
|
||||
if(sd_cs == 1) begin
|
||||
bit_cnt <= 3'd0;
|
||||
terminate_cmd <= 0;
|
||||
cmd <= 0;
|
||||
read_state <= RD_STATE_IDLE;
|
||||
reply_len <= 0;
|
||||
end else if (~old_sd_sck & sd_sck) begin
|
||||
bit_cnt <= bit_cnt + 3'd1;
|
||||
|
||||
// assemble byte
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], sd_sdi };
|
||||
else begin
|
||||
// finished reading one byte
|
||||
// byte counter runs against 15 byte boundary
|
||||
if(byte_cnt != 15)
|
||||
byte_cnt <= byte_cnt + 4'd1;
|
||||
|
||||
// byte_cnt > 6 -> complete command received
|
||||
// first byte of valid command is 01xxxxxx
|
||||
// don't accept new commands (except STOP TRANSMISSION) once a write or read command has been accepted
|
||||
if((byte_cnt > (reply_len == 0 ? 5 : (5+NCR+reply_len))) &&
|
||||
(write_state == WR_STATE_IDLE) &&
|
||||
(read_state == RD_STATE_IDLE || (read_state != RD_STATE_IDLE && { sbuf, sd_sdi} == 8'h4c)) &&
|
||||
sbuf[6:5] == 2'b01)
|
||||
begin
|
||||
byte_cnt <= 4'd0;
|
||||
terminate_cmd <= 0;
|
||||
if ({ sbuf, sd_sdi } == 8'h4c) begin
|
||||
terminate_cmd <= 1;
|
||||
end else
|
||||
cmd <= { sbuf, sd_sdi};
|
||||
end
|
||||
|
||||
// parse additional command bytes
|
||||
if(byte_cnt == 0) args[39:32] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 1) args[31:24] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 2) args[23:16] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 3) args[15:8] <= { sbuf, sd_sdi};
|
||||
if(byte_cnt == 4) args[7:0] <= { sbuf, sd_sdi};
|
||||
|
||||
// last byte received, evaluate
|
||||
if(byte_cnt == 5) begin
|
||||
|
||||
// default:
|
||||
reply <= 8'h04; // illegal command
|
||||
reply_len <= 4'd0; // no extra reply bytes
|
||||
cmd55 <= 0;
|
||||
|
||||
// CMD0: GO_IDLE_STATE
|
||||
if(cmd == 8'h40) begin
|
||||
card_is_reset <= 1'b1;
|
||||
reply <= 8'h01; // ok, busy
|
||||
end
|
||||
|
||||
// every other command is only accepted after a reset
|
||||
else if(card_is_reset) begin
|
||||
// CMD12: STOP_TRANSMISSION
|
||||
if (terminate_cmd)
|
||||
reply <= 8'h00; // ok
|
||||
else case(cmd)
|
||||
// CMD1: SEND_OP_COND
|
||||
8'h41: reply <= 8'h00; // ok, not busy
|
||||
|
||||
// CMD8: SEND_IF_COND (V2 only)
|
||||
8'h48: begin
|
||||
reply <= 8'h01; // ok, busy
|
||||
reply0 <= 8'h00;
|
||||
reply1 <= 8'h00;
|
||||
reply2 <= { 4'b0, args[19:16] };
|
||||
reply3 <= args[15:8];
|
||||
reply_len <= 4'd4;
|
||||
end
|
||||
|
||||
// CMD9: SEND_CSD
|
||||
8'h49: reply <= 8'h00; // ok
|
||||
|
||||
// CMD10: SEND_CID
|
||||
8'h4a: reply <= 8'h00; // ok
|
||||
|
||||
// CMD13: SEND_STATUS
|
||||
8'h4d: begin
|
||||
reply <= 8'h00; // ok
|
||||
reply0 <=8'h00;
|
||||
reply_len <= 4'd1;
|
||||
end
|
||||
|
||||
// CMD16: SET_BLOCKLEN
|
||||
8'h50:
|
||||
// we only support a block size of 512
|
||||
if(args[39:8] == 32'd512)
|
||||
reply <= 8'h00; // ok
|
||||
else
|
||||
reply <= 8'h40; // parmeter error
|
||||
|
||||
// CMD17: READ_SINGLE_BLOCK
|
||||
8'h51: reply <= 8'h00; // ok
|
||||
|
||||
// CMD18: READ_MULTIPLE_BLOCK
|
||||
8'h52: reply <= 8'h00; // ok
|
||||
|
||||
// CMD24: WRITE_BLOCK
|
||||
// CMD25: WRITE_MULTIPLE_BLOCKS
|
||||
8'h58, 8'h59: begin
|
||||
reply <= 8'h00; // ok
|
||||
buffer_ptr <= 0;
|
||||
wr_first <= 1;
|
||||
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
|
||||
end
|
||||
|
||||
// ACMD41: APP_SEND_OP_COND
|
||||
8'h69: if(cmd55) begin
|
||||
reply <= 8'h00; // ok, not busy
|
||||
end
|
||||
|
||||
// CMD55: APP_COND
|
||||
8'h77: begin
|
||||
reply <= 8'h01; // ok, busy
|
||||
cmd55 <= 1;
|
||||
end
|
||||
|
||||
// CMD58: READ_OCR
|
||||
8'h7a: begin
|
||||
reply <= 8'h00; // ok
|
||||
|
||||
reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card
|
||||
reply1 <= OCR[23:16];
|
||||
reply2 <= OCR[15:8];
|
||||
reply3 <= OCR[7:0];
|
||||
reply_len <= 4'd4;
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ---------- handle write -----------
|
||||
case(write_state)
|
||||
// don't do anything in idle state
|
||||
WR_STATE_IDLE: ;
|
||||
|
||||
// waiting for data token
|
||||
WR_STATE_EXP_DTOKEN:
|
||||
if (sd_cs) write_state <= WR_STATE_IDLE;
|
||||
else if (~old_sd_sck && sd_sck && bit_cnt == 7) begin
|
||||
if({ sbuf, sd_sdi} == 8'hfd && cmd == 8'h59)
|
||||
// stop multiple write (and wait until the last write finishes)
|
||||
write_state <= WR_STATE_BUSY;
|
||||
else
|
||||
if({ sbuf, sd_sdi} == ((cmd == 8'h59) ? 8'hfc : 8'hfe))
|
||||
write_state <= WR_STATE_RECV_DATA;
|
||||
end
|
||||
|
||||
// transfer 512 bytes
|
||||
WR_STATE_RECV_DATA:
|
||||
if (sd_cs) write_state <= WR_STATE_IDLE;
|
||||
else if (~old_sd_sck && sd_sck && bit_cnt == 7) begin
|
||||
// push one byte into local buffer
|
||||
buffer_write_strobe <= 1'b1;
|
||||
buffer_din <= { sbuf, sd_sdi };
|
||||
|
||||
// all bytes written?
|
||||
if(&buffer_ptr[8:0])
|
||||
write_state <= WR_STATE_RECV_CRC0;
|
||||
end
|
||||
|
||||
// transfer 1st crc byte
|
||||
WR_STATE_RECV_CRC0:
|
||||
if (sd_cs) write_state <= WR_STATE_IDLE;
|
||||
else if (~old_sd_sck && sd_sck && bit_cnt == 7) write_state <= WR_STATE_RECV_CRC1;
|
||||
|
||||
// transfer 2nd crc byte
|
||||
WR_STATE_RECV_CRC1:
|
||||
if (sd_cs) write_state <= WR_STATE_IDLE;
|
||||
else if (~old_sd_sck && sd_sck && bit_cnt == 7) write_state <= WR_STATE_SEND_DRESP;
|
||||
|
||||
// send data response
|
||||
WR_STATE_SEND_DRESP:
|
||||
if (sd_cs) write_state <= WR_STATE_IDLE;
|
||||
else if (~old_sd_sck && sd_sck && bit_cnt == 7) write_state <= WR_STATE_WRITE;
|
||||
|
||||
WR_STATE_WRITE:
|
||||
if (~sd_busy) begin
|
||||
if (wr_first) begin
|
||||
sd_buff_sel <= 0;
|
||||
sd_lba <= sdhc?args[39:8]:{9'd0, args[39:17]};
|
||||
wr_first <= 0;
|
||||
end else begin
|
||||
sd_buff_sel <= !sd_buff_sel;
|
||||
sd_lba <= sd_lba + 1'd1;
|
||||
end
|
||||
sd_wr <= 1; // trigger write request to io controller
|
||||
sd_busy <= 1;
|
||||
|
||||
if (sd_cs || cmd == 8'h58)
|
||||
write_state <= WR_STATE_BUSY;
|
||||
else
|
||||
write_state <= WR_STATE_EXP_DTOKEN; // multi-sector writes
|
||||
|
||||
end
|
||||
|
||||
WR_STATE_BUSY:
|
||||
if (~sd_busy) write_state <= WR_STATE_IDLE;
|
||||
|
||||
default: ;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module sd_card_dpram #(parameter DATAWIDTH=8, ADDRWIDTH=9)
|
||||
(
|
||||
input clock_a,
|
||||
input [ADDRWIDTH-1:0] address_a,
|
||||
input [DATAWIDTH-1:0] data_a,
|
||||
input wren_a,
|
||||
output reg [DATAWIDTH-1:0] q_a,
|
||||
|
||||
input clock_b,
|
||||
input [ADDRWIDTH-1:0] address_b,
|
||||
input [DATAWIDTH-1:0] data_b,
|
||||
input wren_b,
|
||||
output reg [DATAWIDTH-1:0] q_b
|
||||
);
|
||||
|
||||
reg [DATAWIDTH-1:0] ram[0:(1<<ADDRWIDTH)-1];
|
||||
|
||||
always @(posedge clock_a) begin
|
||||
q_a <= ram[address_a];
|
||||
if(wren_a) begin
|
||||
q_a <= data_a;
|
||||
ram[address_a] <= data_a;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clock_b) begin
|
||||
q_b <= ram[address_b];
|
||||
if(wren_b) begin
|
||||
q_b <= data_b;
|
||||
ram[address_b] <= data_b;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
748
rtl/mist-modules/user_io.v
Normal file
748
rtl/mist-modules/user_io.v
Normal file
@ -0,0 +1,748 @@
|
||||
//
|
||||
// user_io.v
|
||||
//
|
||||
// user_io for the MiST board
|
||||
// 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/>.
|
||||
//
|
||||
|
||||
// parameter STRLEN and the actual length of conf_str have to match
|
||||
|
||||
module user_io (
|
||||
input [(8*STRLEN)-1:0] conf_str,
|
||||
output [9:0] conf_addr, // RAM address for config string, if STRLEN=0
|
||||
input [7:0] conf_chr,
|
||||
|
||||
input clk_sys, // clock for system-related messages (kbd, joy, etc...)
|
||||
input clk_sd, // clock for SD-card related messages
|
||||
|
||||
input SPI_CLK,
|
||||
input SPI_SS_IO,
|
||||
output reg SPI_MISO,
|
||||
input SPI_MOSI,
|
||||
|
||||
output reg [31:0] joystick_0,
|
||||
output reg [31:0] joystick_1,
|
||||
output reg [31:0] joystick_2,
|
||||
output reg [31:0] joystick_3,
|
||||
output reg [31:0] joystick_4,
|
||||
output reg [31:0] joystick_analog_0,
|
||||
output reg [31:0] joystick_analog_1,
|
||||
output [1:0] buttons,
|
||||
output [1:0] switches,
|
||||
output scandoubler_disable,
|
||||
output ypbpr,
|
||||
output no_csync,
|
||||
output reg [63:0] status,
|
||||
output reg [6:0] core_mod, // core variant, sent before the config string is requested
|
||||
// RTC data from IO controller
|
||||
// sec, min, hour, date, month, year, day (BCD)
|
||||
output reg [63:0] rtc,
|
||||
|
||||
// connection to sd card emulation
|
||||
input [31:0] sd_lba,
|
||||
input [SD_IMAGES-1:0] sd_rd,
|
||||
input [SD_IMAGES-1:0] sd_wr,
|
||||
output reg sd_ack,
|
||||
output reg sd_ack_conf,
|
||||
input sd_conf,
|
||||
input sd_sdhc,
|
||||
output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe
|
||||
output reg sd_dout_strobe,
|
||||
input [7:0] sd_din,
|
||||
output reg sd_din_strobe,
|
||||
output reg [8:0] sd_buff_addr,
|
||||
|
||||
output reg [SD_IMAGES-1:0] img_mounted, // rising edge if a new image is mounted
|
||||
output reg [63:0] img_size, // size of image in bytes
|
||||
|
||||
// ps2 keyboard/mouse emulation
|
||||
output ps2_kbd_clk,
|
||||
output reg ps2_kbd_data,
|
||||
input ps2_kbd_clk_i,
|
||||
input ps2_kbd_data_i,
|
||||
output ps2_mouse_clk,
|
||||
output reg ps2_mouse_data,
|
||||
input ps2_mouse_clk_i,
|
||||
input ps2_mouse_data_i,
|
||||
|
||||
// keyboard data
|
||||
output reg key_pressed, // 1-make (pressed), 0-break (released)
|
||||
output reg key_extended, // extended code
|
||||
output reg [7:0] key_code, // key scan code
|
||||
output reg key_strobe, // key data valid
|
||||
|
||||
// mouse data
|
||||
output reg [8:0] mouse_x,
|
||||
output reg [8:0] mouse_y,
|
||||
output reg [3:0] mouse_z,
|
||||
output reg [7:0] mouse_flags, // YOvfl, XOvfl, dy8, dx8, 1, mbtn, rbtn, lbtn
|
||||
output reg mouse_strobe, // mouse data is valid on mouse_strobe
|
||||
output reg mouse_idx, // which mouse?
|
||||
|
||||
// serial com port
|
||||
input [7:0] serial_data,
|
||||
input serial_strobe
|
||||
);
|
||||
|
||||
parameter STRLEN=0; // config string length
|
||||
parameter PS2DIV=100; // master clock divider for psk2_kbd/mouse clk
|
||||
parameter ROM_DIRECT_UPLOAD=0; // direct upload used for file uploads from the ARM
|
||||
parameter SD_IMAGES=2; // number of block-access images (max. 4 supported in current firmware)
|
||||
parameter PS2BIDIR=0; // bi-directional PS2 interface
|
||||
parameter FEATURES=0; // requested features from the firmware
|
||||
|
||||
localparam W = $clog2(SD_IMAGES);
|
||||
|
||||
reg [6:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
|
||||
reg [9:0] byte_cnt; // counts bytes
|
||||
reg [7:0] but_sw;
|
||||
reg [2:0] stick_idx;
|
||||
|
||||
assign buttons = but_sw[1:0];
|
||||
assign switches = but_sw[3:2];
|
||||
assign scandoubler_disable = but_sw[4];
|
||||
assign ypbpr = but_sw[5];
|
||||
assign no_csync = but_sw[6];
|
||||
|
||||
assign conf_addr = byte_cnt;
|
||||
|
||||
// this variant of user_io is for 8 bit cores (type == a4) only
|
||||
// bit 4 indicates ROM direct upload capability
|
||||
wire [7:0] core_type = ROM_DIRECT_UPLOAD ? 8'hb4 : 8'ha4;
|
||||
|
||||
reg [W:0] drive_sel;
|
||||
always begin
|
||||
integer i;
|
||||
drive_sel = 0;
|
||||
for(i = 0; i < SD_IMAGES; i = i + 1) if(sd_rd[i] | sd_wr[i]) drive_sel = i[W:0];
|
||||
end
|
||||
|
||||
// command byte read by the io controller
|
||||
wire [7:0] sd_cmd = { 4'h6, sd_conf, sd_sdhc, sd_wr[drive_sel], sd_rd[drive_sel] };
|
||||
|
||||
wire spi_sck = SPI_CLK;
|
||||
|
||||
// ---------------- PS2 ---------------------
|
||||
// 16 byte fifos to store ps2 bytes
|
||||
localparam PS2_FIFO_BITS = 4;
|
||||
|
||||
reg ps2_clk;
|
||||
always @(posedge clk_sys) begin
|
||||
integer cnt;
|
||||
cnt <= cnt + 1'd1;
|
||||
if(cnt == PS2DIV) begin
|
||||
ps2_clk <= ~ps2_clk;
|
||||
cnt <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
// keyboard
|
||||
reg [7:0] ps2_kbd_fifo [(2**PS2_FIFO_BITS)-1:0];
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr;
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr;
|
||||
|
||||
// ps2 transmitter state machine
|
||||
reg [3:0] ps2_kbd_tx_state;
|
||||
reg [7:0] ps2_kbd_tx_byte;
|
||||
reg ps2_kbd_parity;
|
||||
|
||||
// ps2 receiver state machine
|
||||
reg [3:0] ps2_kbd_rx_state = 0;
|
||||
reg [1:0] ps2_kbd_rx_start = 0;
|
||||
reg [7:0] ps2_kbd_rx_byte = 0;
|
||||
reg ps2_kbd_rx_strobe = 0;
|
||||
|
||||
assign ps2_kbd_clk = ps2_clk || (ps2_kbd_tx_state == 0 && ps2_kbd_rx_state == 0);
|
||||
|
||||
// ps2 transmitter/receiver
|
||||
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
|
||||
// Sends a command to the IO controller if bidirectional mode is enabled.
|
||||
always@(posedge clk_sys) begin : ps2_kbd
|
||||
|
||||
reg ps2_clkD;
|
||||
reg ps2_clk_iD, ps2_dat_iD;
|
||||
reg ps2_kbd_r_inc;
|
||||
|
||||
// send data
|
||||
ps2_clkD <= ps2_clk;
|
||||
if (~ps2_clkD & ps2_clk) begin
|
||||
ps2_kbd_r_inc <= 1'b0;
|
||||
|
||||
if(ps2_kbd_r_inc)
|
||||
ps2_kbd_rptr <= ps2_kbd_rptr + 1'd1;
|
||||
|
||||
// transmitter is idle?
|
||||
if(ps2_kbd_tx_state == 0) begin
|
||||
ps2_kbd_data <= 1;
|
||||
// data in fifo present?
|
||||
if(ps2_kbd_wptr != ps2_kbd_rptr && (ps2_kbd_clk_i | !PS2BIDIR)) begin
|
||||
// load tx register from fifo
|
||||
ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr];
|
||||
ps2_kbd_r_inc <= 1'b1;
|
||||
|
||||
// reset parity
|
||||
ps2_kbd_parity <= 1'b1;
|
||||
|
||||
// start transmitter
|
||||
ps2_kbd_tx_state <= 4'd1;
|
||||
|
||||
// put start bit on data line
|
||||
ps2_kbd_data <= 1'b0; // start bit is 0
|
||||
end
|
||||
end else begin
|
||||
|
||||
// transmission of 8 data bits
|
||||
if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin
|
||||
ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits
|
||||
ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down
|
||||
if(ps2_kbd_tx_byte[0])
|
||||
ps2_kbd_parity <= !ps2_kbd_parity;
|
||||
end
|
||||
|
||||
// transmission of parity
|
||||
if(ps2_kbd_tx_state == 9)
|
||||
ps2_kbd_data <= ps2_kbd_parity;
|
||||
|
||||
// transmission of stop bit
|
||||
if(ps2_kbd_tx_state == 10)
|
||||
ps2_kbd_data <= 1'b1; // stop bit is 1
|
||||
|
||||
// advance state machine
|
||||
if(ps2_kbd_tx_state < 11)
|
||||
ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1;
|
||||
else
|
||||
ps2_kbd_tx_state <= 4'd0;
|
||||
end
|
||||
end
|
||||
|
||||
if (PS2BIDIR) begin
|
||||
ps2_clk_iD <= ps2_kbd_clk_i;
|
||||
ps2_dat_iD <= ps2_kbd_data_i;
|
||||
|
||||
// receive command
|
||||
case (ps2_kbd_rx_start)
|
||||
2'd0:
|
||||
// first: host pulls down the clock line
|
||||
if (ps2_clk_iD & ~ps2_kbd_clk_i) ps2_kbd_rx_start <= 1;
|
||||
2'd1:
|
||||
// second: host pulls down the data line, while releasing the clock
|
||||
if (ps2_dat_iD && !ps2_kbd_data_i) ps2_kbd_rx_start <= 2'd2;
|
||||
// if it releases the clock without pulling down the data line: goto 0
|
||||
else if (ps2_kbd_clk_i) ps2_kbd_rx_start <= 0;
|
||||
2'd2:
|
||||
if (ps2_clkD && ~ps2_clk) begin
|
||||
ps2_kbd_rx_state <= 4'd1;
|
||||
ps2_kbd_rx_start <= 0;
|
||||
end
|
||||
default: ;
|
||||
endcase
|
||||
|
||||
// host data is valid after the rising edge of the clock
|
||||
if(ps2_kbd_rx_state != 0 && ~ps2_clkD && ps2_clk) begin
|
||||
ps2_kbd_rx_state <= ps2_kbd_rx_state + 1'd1;
|
||||
if (ps2_kbd_rx_state == 9) ;// parity
|
||||
else if (ps2_kbd_rx_state == 10) begin
|
||||
ps2_kbd_data <= 0; // ack the received byte
|
||||
end else if (ps2_kbd_rx_state == 11) begin
|
||||
ps2_kbd_rx_state <= 0;
|
||||
ps2_kbd_rx_strobe <= ~ps2_kbd_rx_strobe;
|
||||
end else begin
|
||||
ps2_kbd_rx_byte <= {ps2_kbd_data_i, ps2_kbd_rx_byte[7:1]};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// mouse
|
||||
reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0];
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr;
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr;
|
||||
|
||||
// ps2 transmitter state machine
|
||||
reg [3:0] ps2_mouse_tx_state;
|
||||
reg [7:0] ps2_mouse_tx_byte;
|
||||
reg ps2_mouse_parity;
|
||||
|
||||
// ps2 receiver state machine
|
||||
reg [3:0] ps2_mouse_rx_state = 0;
|
||||
reg [1:0] ps2_mouse_rx_start = 0;
|
||||
reg [7:0] ps2_mouse_rx_byte = 0;
|
||||
reg ps2_mouse_rx_strobe = 0;
|
||||
|
||||
assign ps2_mouse_clk = ps2_clk || (ps2_mouse_tx_state == 0 && ps2_mouse_rx_state == 0);
|
||||
|
||||
// ps2 transmitter/receiver
|
||||
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
|
||||
// Sends a command to the IO controller if bidirectional mode is enabled.
|
||||
always@(posedge clk_sys) begin : ps2_mouse
|
||||
reg ps2_clkD;
|
||||
reg ps2_clk_iD, ps2_dat_iD;
|
||||
reg ps2_mouse_r_inc;
|
||||
|
||||
ps2_clkD <= ps2_clk;
|
||||
if (~ps2_clkD & ps2_clk) begin
|
||||
ps2_mouse_r_inc <= 1'b0;
|
||||
|
||||
if(ps2_mouse_r_inc)
|
||||
ps2_mouse_rptr <= ps2_mouse_rptr + 1'd1;
|
||||
|
||||
// transmitter is idle?
|
||||
if(ps2_mouse_tx_state == 0) begin
|
||||
ps2_mouse_data <= 1;
|
||||
// data in fifo present?
|
||||
if(ps2_mouse_wptr != ps2_mouse_rptr && (ps2_mouse_clk_i | !PS2BIDIR)) begin
|
||||
// load tx register from fifo
|
||||
ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr];
|
||||
ps2_mouse_r_inc <= 1'b1;
|
||||
|
||||
// reset parity
|
||||
ps2_mouse_parity <= 1'b1;
|
||||
|
||||
// start transmitter
|
||||
ps2_mouse_tx_state <= 4'd1;
|
||||
|
||||
// put start bit on data line
|
||||
ps2_mouse_data <= 1'b0; // start bit is 0
|
||||
end
|
||||
end else begin
|
||||
|
||||
// transmission of 8 data bits
|
||||
if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin
|
||||
ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits
|
||||
ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down
|
||||
if(ps2_mouse_tx_byte[0])
|
||||
ps2_mouse_parity <= !ps2_mouse_parity;
|
||||
end
|
||||
|
||||
// transmission of parity
|
||||
if(ps2_mouse_tx_state == 9)
|
||||
ps2_mouse_data <= ps2_mouse_parity;
|
||||
|
||||
// transmission of stop bit
|
||||
if(ps2_mouse_tx_state == 10)
|
||||
ps2_mouse_data <= 1'b1; // stop bit is 1
|
||||
|
||||
// advance state machine
|
||||
if(ps2_mouse_tx_state < 11)
|
||||
ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1;
|
||||
else
|
||||
ps2_mouse_tx_state <= 4'd0;
|
||||
end
|
||||
end
|
||||
|
||||
if (PS2BIDIR) begin
|
||||
|
||||
ps2_clk_iD <= ps2_mouse_clk_i;
|
||||
ps2_dat_iD <= ps2_mouse_data_i;
|
||||
|
||||
// receive command
|
||||
case (ps2_mouse_rx_start)
|
||||
2'd0:
|
||||
// first: host pulls down the clock line
|
||||
if (ps2_clk_iD & ~ps2_mouse_clk_i) ps2_mouse_rx_start <= 1;
|
||||
2'd1:
|
||||
// second: host pulls down the data line, while releasing the clock
|
||||
if (ps2_dat_iD && !ps2_mouse_data_i) ps2_mouse_rx_start <= 2'd2;
|
||||
// if it releases the clock without pulling down the data line: goto 0
|
||||
else if (ps2_mouse_clk_i) ps2_mouse_rx_start <= 0;
|
||||
2'd2:
|
||||
if (ps2_clkD && ~ps2_clk) begin
|
||||
ps2_mouse_rx_state <= 4'd1;
|
||||
ps2_mouse_rx_start <= 0;
|
||||
end
|
||||
default: ;
|
||||
endcase
|
||||
|
||||
// host data is valid after the rising edge of the clock
|
||||
if(ps2_mouse_rx_state != 0 && ~ps2_clkD && ps2_clk) begin
|
||||
ps2_mouse_rx_state <= ps2_mouse_rx_state + 1'd1;
|
||||
if (ps2_mouse_rx_state == 9) ;// parity
|
||||
else if (ps2_mouse_rx_state == 10) begin
|
||||
ps2_mouse_data <= 0; // ack the received byte
|
||||
end else if (ps2_mouse_rx_state == 11) begin
|
||||
ps2_mouse_rx_state <= 0;
|
||||
ps2_mouse_rx_strobe <= ~ps2_mouse_rx_strobe;
|
||||
end else begin
|
||||
ps2_mouse_rx_byte <= {ps2_mouse_data_i, ps2_mouse_rx_byte[7:1]};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// fifo to receive serial data from core to be forwarded to io controller
|
||||
|
||||
// 16 byte fifo to store serial bytes
|
||||
localparam SERIAL_OUT_FIFO_BITS = 6;
|
||||
reg [7:0] serial_out_fifo [(2**SERIAL_OUT_FIFO_BITS)-1:0];
|
||||
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_wptr;
|
||||
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_rptr;
|
||||
|
||||
wire serial_out_data_available = serial_out_wptr != serial_out_rptr;
|
||||
wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr] /* synthesis keep */;
|
||||
wire [7:0] serial_out_status = { 7'b1000000, serial_out_data_available};
|
||||
|
||||
// status[0] is reset signal from io controller and is thus used to flush
|
||||
// the fifo
|
||||
always @(posedge serial_strobe or posedge status[0]) begin : serial_out
|
||||
if(status[0] == 1) begin
|
||||
serial_out_wptr <= 0;
|
||||
end else begin
|
||||
serial_out_fifo[serial_out_wptr] <= serial_data;
|
||||
serial_out_wptr <= serial_out_wptr + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
always@(negedge spi_sck or posedge status[0]) begin : serial_in
|
||||
if(status[0] == 1) begin
|
||||
serial_out_rptr <= 0;
|
||||
end else begin
|
||||
if((byte_cnt != 0) && (cmd == 8'h1b)) begin
|
||||
// read last bit -> advance read pointer
|
||||
if((bit_cnt == 7) && !byte_cnt[0] && serial_out_data_available)
|
||||
serial_out_rptr <= serial_out_rptr + 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// SPI bit and byte counters
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_counter
|
||||
if(SPI_SS_IO == 1) begin
|
||||
bit_cnt <= 0;
|
||||
byte_cnt <= 0;
|
||||
end else begin
|
||||
if((bit_cnt == 7)&&(~&byte_cnt))
|
||||
byte_cnt <= byte_cnt + 8'd1;
|
||||
|
||||
bit_cnt <= bit_cnt + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
// SPI transmitter FPGA -> IO
|
||||
reg [7:0] spi_byte_out;
|
||||
|
||||
always@(negedge spi_sck or posedge SPI_SS_IO) begin : spi_byteout
|
||||
if(SPI_SS_IO == 1) begin
|
||||
SPI_MISO <= 1'bZ;
|
||||
end else begin
|
||||
SPI_MISO <= spi_byte_out[~bit_cnt];
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter
|
||||
reg [31:0] sd_lba_r;
|
||||
reg [W:0] drive_sel_r;
|
||||
reg ps2_kbd_rx_strobeD;
|
||||
reg ps2_mouse_rx_strobeD;
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_byte_out <= core_type;
|
||||
end else begin
|
||||
// read the command byte to choose the response
|
||||
if(bit_cnt == 7) begin
|
||||
if(!byte_cnt) cmd <= {sbuf, SPI_MOSI};
|
||||
|
||||
spi_byte_out <= 0;
|
||||
case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd})
|
||||
// PS2 keyboard command
|
||||
8'h0e: if (byte_cnt == 0) begin
|
||||
ps2_kbd_rx_strobeD <= ps2_kbd_rx_strobe;
|
||||
//echo the command code if there's a byte to send, indicating the core supports the command
|
||||
spi_byte_out <= (ps2_kbd_rx_strobe ^ ps2_kbd_rx_strobeD) ? 8'h0e : 8'h00;
|
||||
end else spi_byte_out <= ps2_kbd_rx_byte;
|
||||
|
||||
// PS2 mouse command
|
||||
8'h0f: if (byte_cnt == 0) begin
|
||||
ps2_mouse_rx_strobeD <= ps2_mouse_rx_strobe;
|
||||
//echo the command code if there's a byte to send, indicating the core supports the command
|
||||
spi_byte_out <= (ps2_mouse_rx_strobe ^ ps2_mouse_rx_strobeD) ? 8'h0f : 8'h00;
|
||||
end else spi_byte_out <= ps2_mouse_rx_byte;
|
||||
|
||||
// reading config string
|
||||
8'h14: if (STRLEN == 0) spi_byte_out <= conf_chr; else
|
||||
if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8];
|
||||
|
||||
// reading sd card status
|
||||
8'h16: if(byte_cnt == 0) begin
|
||||
spi_byte_out <= sd_cmd;
|
||||
sd_lba_r <= sd_lba;
|
||||
drive_sel_r <= drive_sel;
|
||||
end
|
||||
else if(byte_cnt == 1) spi_byte_out <= drive_sel_r;
|
||||
else if(byte_cnt < 6) spi_byte_out <= sd_lba_r[(5-byte_cnt)<<3 +:8];
|
||||
|
||||
// reading sd card write data
|
||||
8'h18: spi_byte_out <= sd_din;
|
||||
|
||||
8'h1b:
|
||||
// send alternating flag byte and data
|
||||
if(byte_cnt[0]) spi_byte_out <= serial_out_status;
|
||||
else spi_byte_out <= serial_out_byte;
|
||||
|
||||
// core features
|
||||
8'h80:
|
||||
if (byte_cnt == 0) spi_byte_out <= 8'h80;
|
||||
else spi_byte_out <= FEATURES[(4-byte_cnt)<<3 +:8];
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// SPI receiver IO -> FPGA
|
||||
|
||||
reg spi_receiver_strobe_r = 0;
|
||||
reg spi_transfer_end_r = 1;
|
||||
reg [7:0] spi_byte_in;
|
||||
|
||||
// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys
|
||||
always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_receiver
|
||||
|
||||
if(SPI_SS_IO == 1) begin
|
||||
spi_transfer_end_r <= 1;
|
||||
end else begin
|
||||
spi_transfer_end_r <= 0;
|
||||
|
||||
if(bit_cnt != 7)
|
||||
sbuf[6:0] <= { sbuf[5:0], SPI_MOSI };
|
||||
|
||||
// finished reading a byte, prepare to transfer to clk_sys
|
||||
if(bit_cnt == 7) begin
|
||||
spi_byte_in <= { sbuf, SPI_MOSI};
|
||||
spi_receiver_strobe_r <= ~spi_receiver_strobe_r;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Process bytes from SPI at the clk_sys domain
|
||||
always @(posedge clk_sys) begin : cmd_block
|
||||
|
||||
reg spi_receiver_strobe;
|
||||
reg spi_transfer_end;
|
||||
reg spi_receiver_strobeD;
|
||||
reg spi_transfer_endD;
|
||||
reg [7:0] acmd;
|
||||
reg [7:0] abyte_cnt; // counts bytes
|
||||
|
||||
reg [7:0] mouse_flags_r;
|
||||
reg [7:0] mouse_x_r;
|
||||
reg [7:0] mouse_y_r;
|
||||
|
||||
reg key_pressed_r;
|
||||
reg key_extended_r;
|
||||
|
||||
//synchronize between SPI and sys clock domains
|
||||
spi_receiver_strobeD <= spi_receiver_strobe_r;
|
||||
spi_receiver_strobe <= spi_receiver_strobeD;
|
||||
spi_transfer_endD <= spi_transfer_end_r;
|
||||
spi_transfer_end <= spi_transfer_endD;
|
||||
|
||||
key_strobe <= 0;
|
||||
mouse_strobe <= 0;
|
||||
|
||||
if (spi_transfer_end) begin
|
||||
abyte_cnt <= 8'd0;
|
||||
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
|
||||
|
||||
if(~&abyte_cnt)
|
||||
abyte_cnt <= abyte_cnt + 8'd1;
|
||||
|
||||
if(abyte_cnt == 0) begin
|
||||
acmd <= spi_byte_in;
|
||||
end else begin
|
||||
case(acmd)
|
||||
// buttons and switches
|
||||
8'h01: but_sw <= spi_byte_in;
|
||||
8'h60: if (abyte_cnt < 5) joystick_0[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h61: if (abyte_cnt < 5) joystick_1[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h62: if (abyte_cnt < 5) joystick_2[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
8'h70,8'h71: begin
|
||||
// store incoming ps2 mouse bytes
|
||||
if (abyte_cnt < 4) begin
|
||||
ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in;
|
||||
ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1;
|
||||
end
|
||||
|
||||
if (abyte_cnt == 1) mouse_flags_r <= spi_byte_in;
|
||||
else if (abyte_cnt == 2) mouse_x_r <= spi_byte_in;
|
||||
else if (abyte_cnt == 3) mouse_y_r <= spi_byte_in;
|
||||
else if (abyte_cnt == 4) begin
|
||||
// flags: YOvfl, XOvfl, dy8, dx8, 1, mbtn, rbtn, lbtn
|
||||
mouse_flags <= mouse_flags_r;
|
||||
mouse_x <= { mouse_flags_r[4], mouse_x_r };
|
||||
mouse_y <= { mouse_flags_r[5], mouse_y_r };
|
||||
mouse_z <= spi_byte_in[3:0];
|
||||
mouse_idx <= acmd[0];
|
||||
mouse_strobe <= 1;
|
||||
end
|
||||
end
|
||||
8'h05: begin
|
||||
// store incoming ps2 keyboard bytes
|
||||
ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in;
|
||||
ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1;
|
||||
if (abyte_cnt == 1) begin
|
||||
key_extended_r <= 0;
|
||||
key_pressed_r <= 1;
|
||||
end
|
||||
if (spi_byte_in == 8'he0) key_extended_r <= 1'b1;
|
||||
else if (spi_byte_in == 8'hf0) key_pressed_r <= 1'b0;
|
||||
else begin
|
||||
key_extended <= key_extended_r && abyte_cnt != 1;
|
||||
key_pressed <= key_pressed_r || abyte_cnt == 1;
|
||||
key_code <= spi_byte_in;
|
||||
key_strobe <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// joystick analog
|
||||
8'h1a: begin
|
||||
// first byte is joystick index
|
||||
if(abyte_cnt == 1)
|
||||
stick_idx <= spi_byte_in[2:0];
|
||||
else if(abyte_cnt == 2) begin
|
||||
// second byte is x axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[15:8] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[15:8] <= spi_byte_in;
|
||||
end else if(abyte_cnt == 3) begin
|
||||
// third byte is y axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[7:0] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[7:0] <= spi_byte_in;
|
||||
end else if(abyte_cnt == 4) begin
|
||||
// fourth byte is 2nd x axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[31:24] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[31:24] <= spi_byte_in;
|
||||
end else if(abyte_cnt == 5) begin
|
||||
// fifth byte is 2nd y axis
|
||||
if(stick_idx == 0)
|
||||
joystick_analog_0[23:16] <= spi_byte_in;
|
||||
else if(stick_idx == 1)
|
||||
joystick_analog_1[23:16] <= spi_byte_in;
|
||||
end
|
||||
end
|
||||
|
||||
8'h15: status <= spi_byte_in;
|
||||
|
||||
// status, 64bit version
|
||||
8'h1e: if(abyte_cnt<9) status[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
|
||||
// core variant
|
||||
8'h21: core_mod <= spi_byte_in[6:0];
|
||||
|
||||
// RTC
|
||||
8'h22: if(abyte_cnt<9) rtc[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// Process SD-card related bytes from SPI at the clk_sd domain
|
||||
always @(posedge clk_sd) begin : sd_block
|
||||
|
||||
reg spi_receiver_strobe;
|
||||
reg spi_transfer_end;
|
||||
reg spi_receiver_strobeD;
|
||||
reg spi_transfer_endD;
|
||||
reg [SD_IMAGES-1:0] sd_wrD;
|
||||
reg [7:0] acmd;
|
||||
reg [7:0] abyte_cnt; // counts bytes
|
||||
|
||||
//synchronize between SPI and sd clock domains
|
||||
spi_receiver_strobeD <= spi_receiver_strobe_r;
|
||||
spi_receiver_strobe <= spi_receiver_strobeD;
|
||||
spi_transfer_endD <= spi_transfer_end_r;
|
||||
spi_transfer_end <= spi_transfer_endD;
|
||||
|
||||
if(sd_dout_strobe) begin
|
||||
sd_dout_strobe<= 0;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
|
||||
sd_din_strobe<= 0;
|
||||
sd_wrD <= sd_wr;
|
||||
// fetch the first byte immediately after the write command seen
|
||||
if (|(~sd_wrD & sd_wr)) begin
|
||||
sd_buff_addr <= 0;
|
||||
sd_din_strobe <= 1;
|
||||
end
|
||||
|
||||
img_mounted <= 0;
|
||||
|
||||
if (spi_transfer_end) begin
|
||||
abyte_cnt <= 8'd0;
|
||||
sd_ack <= 1'b0;
|
||||
sd_ack_conf <= 1'b0;
|
||||
sd_buff_addr <= 0;
|
||||
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
|
||||
|
||||
if(~&abyte_cnt)
|
||||
abyte_cnt <= abyte_cnt + 8'd1;
|
||||
|
||||
if(abyte_cnt == 0) begin
|
||||
acmd <= spi_byte_in;
|
||||
|
||||
if(spi_byte_in == 8'h18) begin
|
||||
sd_din_strobe <= 1'b1;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
|
||||
if(spi_byte_in == 8'h19)
|
||||
sd_ack_conf <= 1'b1;
|
||||
if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18))
|
||||
sd_ack <= 1'b1;
|
||||
|
||||
end else begin
|
||||
case(acmd)
|
||||
|
||||
// send sector IO -> FPGA
|
||||
8'h17,
|
||||
// send SD config IO -> FPGA
|
||||
8'h19: begin
|
||||
// flag that download begins
|
||||
sd_dout_strobe <= 1'b1;
|
||||
sd_dout <= spi_byte_in;
|
||||
end
|
||||
|
||||
// send sector FPGA -> IO
|
||||
8'h18: begin
|
||||
if(~&sd_buff_addr) begin
|
||||
sd_din_strobe <= 1'b1;
|
||||
sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
8'h1c: img_mounted[spi_byte_in[W:0]] <= 1;
|
||||
|
||||
// send image info
|
||||
8'h1d: if(abyte_cnt<9) img_size[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
454
rtl/mist-modules_old/hq2x.sv
Normal file
454
rtl/mist-modules_old/hq2x.sv
Normal file
@ -0,0 +1,454 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2012-2013 Ludvig Strigeus
|
||||
// Copyright (c) 2017 Sorgelig
|
||||
//
|
||||
// This program is GPL Licensed. See COPYING for the full license.
|
||||
//
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// synopsys translate_off
|
||||
`timescale 1 ps / 1 ps
|
||||
// synopsys translate_on
|
||||
|
||||
`define BITS_TO_FIT(N) ( \
|
||||
N <= 2 ? 0 : \
|
||||
N <= 4 ? 1 : \
|
||||
N <= 8 ? 2 : \
|
||||
N <= 16 ? 3 : \
|
||||
N <= 32 ? 4 : \
|
||||
N <= 64 ? 5 : \
|
||||
N <= 128 ? 6 : \
|
||||
N <= 256 ? 7 : \
|
||||
N <= 512 ? 8 : \
|
||||
N <=1024 ? 9 : 10 )
|
||||
|
||||
module hq2x_in #(parameter LENGTH, parameter DWIDTH)
|
||||
(
|
||||
input clk,
|
||||
|
||||
input [AWIDTH:0] rdaddr,
|
||||
input rdbuf,
|
||||
output[DWIDTH:0] q,
|
||||
|
||||
input [AWIDTH:0] wraddr,
|
||||
input wrbuf,
|
||||
input [DWIDTH:0] data,
|
||||
input wren
|
||||
);
|
||||
|
||||
localparam AWIDTH = `BITS_TO_FIT(LENGTH);
|
||||
wire [DWIDTH:0] out[2];
|
||||
assign q = out[rdbuf];
|
||||
|
||||
hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]);
|
||||
hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]);
|
||||
endmodule
|
||||
|
||||
|
||||
module hq2x_out #(parameter LENGTH, parameter DWIDTH)
|
||||
(
|
||||
input clk,
|
||||
|
||||
input [AWIDTH:0] rdaddr,
|
||||
input [1:0] rdbuf,
|
||||
output[DWIDTH:0] q,
|
||||
|
||||
input [AWIDTH:0] wraddr,
|
||||
input [1:0] wrbuf,
|
||||
input [DWIDTH:0] data,
|
||||
input wren
|
||||
);
|
||||
|
||||
localparam AWIDTH = `BITS_TO_FIT(LENGTH*2);
|
||||
wire [DWIDTH:0] out[4];
|
||||
assign q = out[rdbuf];
|
||||
|
||||
hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]);
|
||||
hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]);
|
||||
hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf2(clk,data,rdaddr,wraddr,wren && (wrbuf == 2),out[2]);
|
||||
hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf3(clk,data,rdaddr,wraddr,wren && (wrbuf == 3),out[3]);
|
||||
endmodule
|
||||
|
||||
|
||||
module hq2x_buf #(parameter NUMWORDS, parameter AWIDTH, parameter DWIDTH)
|
||||
(
|
||||
input clock,
|
||||
input [DWIDTH:0] data,
|
||||
input [AWIDTH:0] rdaddress,
|
||||
input [AWIDTH:0] wraddress,
|
||||
input wren,
|
||||
output [DWIDTH:0] q
|
||||
);
|
||||
|
||||
altsyncram altsyncram_component (
|
||||
.address_a (wraddress),
|
||||
.clock0 (clock),
|
||||
.data_a (data),
|
||||
.wren_a (wren),
|
||||
.address_b (rdaddress),
|
||||
.q_b(q),
|
||||
.aclr0 (1'b0),
|
||||
.aclr1 (1'b0),
|
||||
.addressstall_a (1'b0),
|
||||
.addressstall_b (1'b0),
|
||||
.byteena_a (1'b1),
|
||||
.byteena_b (1'b1),
|
||||
.clock1 (1'b1),
|
||||
.clocken0 (1'b1),
|
||||
.clocken1 (1'b1),
|
||||
.clocken2 (1'b1),
|
||||
.clocken3 (1'b1),
|
||||
.data_b ({(DWIDTH+1){1'b1}}),
|
||||
.eccstatus (),
|
||||
.q_a (),
|
||||
.rden_a (1'b1),
|
||||
.rden_b (1'b1),
|
||||
.wren_b (1'b0));
|
||||
defparam
|
||||
altsyncram_component.address_aclr_b = "NONE",
|
||||
altsyncram_component.address_reg_b = "CLOCK0",
|
||||
altsyncram_component.clock_enable_input_a = "BYPASS",
|
||||
altsyncram_component.clock_enable_input_b = "BYPASS",
|
||||
altsyncram_component.clock_enable_output_b = "BYPASS",
|
||||
altsyncram_component.intended_device_family = "Cyclone III",
|
||||
altsyncram_component.lpm_type = "altsyncram",
|
||||
altsyncram_component.numwords_a = NUMWORDS,
|
||||
altsyncram_component.numwords_b = NUMWORDS,
|
||||
altsyncram_component.operation_mode = "DUAL_PORT",
|
||||
altsyncram_component.outdata_aclr_b = "NONE",
|
||||
altsyncram_component.outdata_reg_b = "UNREGISTERED",
|
||||
altsyncram_component.power_up_uninitialized = "FALSE",
|
||||
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
|
||||
altsyncram_component.widthad_a = AWIDTH+1,
|
||||
altsyncram_component.widthad_b = AWIDTH+1,
|
||||
altsyncram_component.width_a = DWIDTH+1,
|
||||
altsyncram_component.width_b = DWIDTH+1,
|
||||
altsyncram_component.width_byteena_a = 1;
|
||||
|
||||
endmodule
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module DiffCheck
|
||||
(
|
||||
input [17:0] rgb1,
|
||||
input [17:0] rgb2,
|
||||
output result
|
||||
);
|
||||
|
||||
wire [5:0] r = rgb1[5:1] - rgb2[5:1];
|
||||
wire [5:0] g = rgb1[11:7] - rgb2[11:7];
|
||||
wire [5:0] b = rgb1[17:13] - rgb2[17:13];
|
||||
wire [6:0] t = $signed(r) + $signed(b);
|
||||
wire [6:0] gx = {g[5], g};
|
||||
wire [7:0] y = $signed(t) + $signed(gx);
|
||||
wire [6:0] u = $signed(r) - $signed(b);
|
||||
wire [7:0] v = $signed({g, 1'b0}) - $signed(t);
|
||||
|
||||
// if y is inside (-24..24)
|
||||
wire y_inside = (y < 8'h18 || y >= 8'he8);
|
||||
|
||||
// if u is inside (-4, 4)
|
||||
wire u_inside = (u < 7'h4 || u >= 7'h7c);
|
||||
|
||||
// if v is inside (-6, 6)
|
||||
wire v_inside = (v < 8'h6 || v >= 8'hfA);
|
||||
assign result = !(y_inside && u_inside && v_inside);
|
||||
endmodule
|
||||
|
||||
module InnerBlend
|
||||
(
|
||||
input [8:0] Op,
|
||||
input [5:0] A,
|
||||
input [5:0] B,
|
||||
input [5:0] C,
|
||||
output [5:0] O
|
||||
);
|
||||
|
||||
function [8:0] mul6x3;
|
||||
input [5:0] op1;
|
||||
input [2:0] op2;
|
||||
begin
|
||||
mul6x3 = 9'd0;
|
||||
if(op2[0]) mul6x3 = mul6x3 + op1;
|
||||
if(op2[1]) mul6x3 = mul6x3 + {op1, 1'b0};
|
||||
if(op2[2]) mul6x3 = mul6x3 + {op1, 2'b00};
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire OpOnes = Op[4];
|
||||
wire [8:0] Amul = mul6x3(A, Op[7:5]);
|
||||
wire [8:0] Bmul = mul6x3(B, {Op[3:2], 1'b0});
|
||||
wire [8:0] Cmul = mul6x3(C, {Op[1:0], 1'b0});
|
||||
wire [8:0] At = Amul;
|
||||
wire [8:0] Bt = (OpOnes == 0) ? Bmul : {3'b0, B};
|
||||
wire [8:0] Ct = (OpOnes == 0) ? Cmul : {3'b0, C};
|
||||
wire [9:0] Res = {At, 1'b0} + Bt + Ct;
|
||||
assign O = Op[8] ? A : Res[9:4];
|
||||
endmodule
|
||||
|
||||
module Blend
|
||||
(
|
||||
input [5:0] rule,
|
||||
input disable_hq2x,
|
||||
input [17:0] E,
|
||||
input [17:0] A,
|
||||
input [17:0] B,
|
||||
input [17:0] D,
|
||||
input [17:0] F,
|
||||
input [17:0] H,
|
||||
output [17:0] Result
|
||||
);
|
||||
|
||||
reg [1:0] input_ctrl;
|
||||
reg [8:0] op;
|
||||
localparam BLEND0 = 9'b1_xxx_x_xx_xx; // 0: A
|
||||
localparam BLEND1 = 9'b0_110_0_10_00; // 1: (A * 12 + B * 4) >> 4
|
||||
localparam BLEND2 = 9'b0_100_0_10_10; // 2: (A * 8 + B * 4 + C * 4) >> 4
|
||||
localparam BLEND3 = 9'b0_101_0_10_01; // 3: (A * 10 + B * 4 + C * 2) >> 4
|
||||
localparam BLEND4 = 9'b0_110_0_01_01; // 4: (A * 12 + B * 2 + C * 2) >> 4
|
||||
localparam BLEND5 = 9'b0_010_0_11_11; // 5: (A * 4 + (B + C) * 6) >> 4
|
||||
localparam BLEND6 = 9'b0_111_1_xx_xx; // 6: (A * 14 + B + C) >> 4
|
||||
localparam AB = 2'b00;
|
||||
localparam AD = 2'b01;
|
||||
localparam DB = 2'b10;
|
||||
localparam BD = 2'b11;
|
||||
wire is_diff;
|
||||
DiffCheck diff_checker(rule[1] ? B : H, rule[0] ? D : F, is_diff);
|
||||
|
||||
always @* begin
|
||||
case({!is_diff, rule[5:2]})
|
||||
1,17: {op, input_ctrl} = {BLEND1, AB};
|
||||
2,18: {op, input_ctrl} = {BLEND1, DB};
|
||||
3,19: {op, input_ctrl} = {BLEND1, BD};
|
||||
4,20: {op, input_ctrl} = {BLEND2, DB};
|
||||
5,21: {op, input_ctrl} = {BLEND2, AB};
|
||||
6,22: {op, input_ctrl} = {BLEND2, AD};
|
||||
|
||||
8: {op, input_ctrl} = {BLEND0, 2'bxx};
|
||||
9: {op, input_ctrl} = {BLEND0, 2'bxx};
|
||||
10: {op, input_ctrl} = {BLEND0, 2'bxx};
|
||||
11: {op, input_ctrl} = {BLEND1, AB};
|
||||
12: {op, input_ctrl} = {BLEND1, AB};
|
||||
13: {op, input_ctrl} = {BLEND1, AB};
|
||||
14: {op, input_ctrl} = {BLEND1, DB};
|
||||
15: {op, input_ctrl} = {BLEND1, BD};
|
||||
|
||||
24: {op, input_ctrl} = {BLEND2, DB};
|
||||
25: {op, input_ctrl} = {BLEND5, DB};
|
||||
26: {op, input_ctrl} = {BLEND6, DB};
|
||||
27: {op, input_ctrl} = {BLEND2, DB};
|
||||
28: {op, input_ctrl} = {BLEND4, DB};
|
||||
29: {op, input_ctrl} = {BLEND5, DB};
|
||||
30: {op, input_ctrl} = {BLEND3, BD};
|
||||
31: {op, input_ctrl} = {BLEND3, DB};
|
||||
default: {op, input_ctrl} = 11'bx;
|
||||
endcase
|
||||
|
||||
// Setting op[8] effectively disables HQ2X because blend will always return E.
|
||||
if (disable_hq2x) op[8] = 1;
|
||||
end
|
||||
|
||||
// Generate inputs to the inner blender. Valid combinations.
|
||||
// 00: E A B
|
||||
// 01: E A D
|
||||
// 10: E D B
|
||||
// 11: E B D
|
||||
wire [17:0] Input1 = E;
|
||||
wire [17:0] Input2 = !input_ctrl[1] ? A :
|
||||
!input_ctrl[0] ? D : B;
|
||||
|
||||
wire [17:0] Input3 = !input_ctrl[0] ? B : D;
|
||||
InnerBlend inner_blend1(op, Input1[5:0], Input2[5:0], Input3[5:0], Result[5:0]);
|
||||
InnerBlend inner_blend2(op, Input1[11:6], Input2[11:6], Input3[11:6], Result[11:6]);
|
||||
InnerBlend inner_blend3(op, Input1[17:12], Input2[17:12], Input3[17:12], Result[17:12]);
|
||||
endmodule
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module Hq2x #(parameter LENGTH, parameter HALF_DEPTH)
|
||||
(
|
||||
input clk,
|
||||
input ce_x4,
|
||||
input [DWIDTH:0] inputpixel,
|
||||
input mono,
|
||||
input disable_hq2x,
|
||||
input reset_frame,
|
||||
input reset_line,
|
||||
input [1:0] read_y,
|
||||
input [AWIDTH+1:0] read_x,
|
||||
output [DWIDTH:0] outpixel
|
||||
);
|
||||
|
||||
|
||||
localparam AWIDTH = `BITS_TO_FIT(LENGTH);
|
||||
localparam DWIDTH = HALF_DEPTH ? 8 : 17;
|
||||
|
||||
wire [5:0] hqTable[256] = '{
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39,
|
||||
19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 35, 35, 23, 15, 7, 35,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43,
|
||||
19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 51, 35, 23, 15, 7, 43,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 35, 35, 23, 61, 51, 35,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 7, 35, 23, 61, 7, 43,
|
||||
19, 19, 26, 11, 19, 19, 26, 58, 23, 15, 51, 35, 23, 61, 7, 43,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 39, 23, 15, 7, 43,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 39,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 35,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 43,
|
||||
19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 7, 35, 23, 15, 7, 43
|
||||
};
|
||||
|
||||
reg [17:0] Prev0, Prev1, Prev2, Curr0, Curr1, Next0, Next1, Next2;
|
||||
reg [17:0] A, B, D, F, G, H;
|
||||
reg [7:0] pattern, nextpatt;
|
||||
reg [1:0] i;
|
||||
reg [7:0] y;
|
||||
|
||||
wire curbuf = y[0];
|
||||
reg prevbuf = 0;
|
||||
wire iobuf = !curbuf;
|
||||
|
||||
wire diff0, diff1;
|
||||
DiffCheck diffcheck0(Curr1, (i == 0) ? Prev0 : (i == 1) ? Curr0 : (i == 2) ? Prev2 : Next1, diff0);
|
||||
DiffCheck diffcheck1(Curr1, (i == 0) ? Prev1 : (i == 1) ? Next0 : (i == 2) ? Curr2 : Next2, diff1);
|
||||
|
||||
wire [7:0] new_pattern = {diff1, diff0, pattern[7:2]};
|
||||
|
||||
wire [17:0] X = (i == 0) ? A : (i == 1) ? Prev1 : (i == 2) ? Next1 : G;
|
||||
wire [17:0] blend_result;
|
||||
Blend blender(hqTable[nextpatt], disable_hq2x, Curr0, X, B, D, F, H, blend_result);
|
||||
|
||||
reg Curr2_addr1;
|
||||
reg [AWIDTH:0] Curr2_addr2;
|
||||
wire [17:0] Curr2 = HALF_DEPTH ? h2rgb(Curr2tmp) : Curr2tmp;
|
||||
wire [DWIDTH:0] Curr2tmp;
|
||||
|
||||
reg [AWIDTH:0] wrin_addr2;
|
||||
reg [DWIDTH:0] wrpix;
|
||||
reg wrin_en;
|
||||
|
||||
function [17:0] h2rgb;
|
||||
input [8:0] v;
|
||||
begin
|
||||
h2rgb = mono ? {v[5:3],v[2:0], v[5:3],v[2:0], v[5:3],v[2:0]} : {v[8:6],v[8:6],v[5:3],v[5:3],v[2:0],v[2:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [8:0] rgb2h;
|
||||
input [17:0] v;
|
||||
begin
|
||||
rgb2h = mono ? {3'b000, v[17:15], v[14:12]} : {v[17:15], v[11:9], v[5:3]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
hq2x_in #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_in
|
||||
(
|
||||
.clk(clk),
|
||||
|
||||
.rdaddr(Curr2_addr2),
|
||||
.rdbuf(Curr2_addr1),
|
||||
.q(Curr2tmp),
|
||||
|
||||
.wraddr(wrin_addr2),
|
||||
.wrbuf(iobuf),
|
||||
.data(wrpix),
|
||||
.wren(wrin_en)
|
||||
);
|
||||
|
||||
reg [1:0] wrout_addr1;
|
||||
reg [AWIDTH+1:0] wrout_addr2;
|
||||
reg wrout_en;
|
||||
reg [DWIDTH:0] wrdata;
|
||||
|
||||
hq2x_out #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_out
|
||||
(
|
||||
.clk(clk),
|
||||
|
||||
.rdaddr(read_x),
|
||||
.rdbuf(read_y),
|
||||
.q(outpixel),
|
||||
|
||||
.wraddr(wrout_addr2),
|
||||
.wrbuf(wrout_addr1),
|
||||
.data(wrdata),
|
||||
.wren(wrout_en)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
reg [AWIDTH:0] offs;
|
||||
reg old_reset_line;
|
||||
reg old_reset_frame;
|
||||
|
||||
wrout_en <= 0;
|
||||
wrin_en <= 0;
|
||||
|
||||
if(ce_x4) begin
|
||||
|
||||
pattern <= new_pattern;
|
||||
|
||||
if(~&offs) begin
|
||||
if (i == 0) begin
|
||||
Curr2_addr1 <= prevbuf;
|
||||
Curr2_addr2 <= offs;
|
||||
end
|
||||
if (i == 1) begin
|
||||
Prev2 <= Curr2;
|
||||
Curr2_addr1 <= curbuf;
|
||||
Curr2_addr2 <= offs;
|
||||
end
|
||||
if (i == 2) begin
|
||||
Next2 <= HALF_DEPTH ? h2rgb(inputpixel) : inputpixel;
|
||||
wrpix <= inputpixel;
|
||||
wrin_addr2 <= offs;
|
||||
wrin_en <= 1;
|
||||
end
|
||||
if (i == 3) begin
|
||||
offs <= offs + 1'd1;
|
||||
end
|
||||
|
||||
if(HALF_DEPTH) wrdata <= rgb2h(blend_result);
|
||||
else wrdata <= blend_result;
|
||||
|
||||
wrout_addr1 <= {curbuf, i[1]};
|
||||
wrout_addr2 <= {offs, i[1]^i[0]};
|
||||
wrout_en <= 1;
|
||||
end
|
||||
|
||||
if(i==3) begin
|
||||
nextpatt <= {new_pattern[7:6], new_pattern[3], new_pattern[5], new_pattern[2], new_pattern[4], new_pattern[1:0]};
|
||||
{A, G} <= {Prev0, Next0};
|
||||
{B, F, H, D} <= {Prev1, Curr2, Next1, Curr0};
|
||||
{Prev0, Prev1} <= {Prev1, Prev2};
|
||||
{Curr0, Curr1} <= {Curr1, Curr2};
|
||||
{Next0, Next1} <= {Next1, Next2};
|
||||
end else begin
|
||||
nextpatt <= {nextpatt[5], nextpatt[3], nextpatt[0], nextpatt[6], nextpatt[1], nextpatt[7], nextpatt[4], nextpatt[2]};
|
||||
{B, F, H, D} <= {F, H, D, B};
|
||||
end
|
||||
|
||||
i <= i + 1'b1;
|
||||
if(old_reset_line && ~reset_line) begin
|
||||
old_reset_frame <= reset_frame;
|
||||
offs <= 0;
|
||||
i <= 0;
|
||||
y <= y + 1'd1;
|
||||
prevbuf <= curbuf;
|
||||
if(old_reset_frame & ~reset_frame) begin
|
||||
y <= 0;
|
||||
prevbuf <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
old_reset_line <= reset_line;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule // Hq2x
|
491
rtl/mist-modules_old/mist_io.v
Normal file
491
rtl/mist-modules_old/mist_io.v
Normal file
@ -0,0 +1,491 @@
|
||||
//
|
||||
// mist_io.v
|
||||
//
|
||||
// mist_io for the MiST board
|
||||
// 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/>.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Use buffer to access SD card. It's time-critical part.
|
||||
// Made module synchroneous with 2 clock domains: clk_sys and SPI_SCK
|
||||
// (Sorgelig)
|
||||
//
|
||||
// for synchronous projects default value for PS2DIV is fine for any frequency of system clock.
|
||||
// clk_ps2 = clk_sys/(PS2DIV*2)
|
||||
//
|
||||
|
||||
module mist_io #(parameter STRLEN=0, parameter PS2DIV=100)
|
||||
(
|
||||
|
||||
// parameter STRLEN and the actual length of conf_str have to match
|
||||
input [(8*STRLEN)-1:0] conf_str,
|
||||
|
||||
// Global clock. It should be around 100MHz (higher is better).
|
||||
input clk_sys,
|
||||
|
||||
// Global SPI clock from ARM. 24MHz
|
||||
input SPI_SCK,
|
||||
|
||||
input CONF_DATA0,
|
||||
input SPI_SS2,
|
||||
output SPI_DO,
|
||||
input SPI_DI,
|
||||
|
||||
output reg [7:0] joystick_0,
|
||||
output reg [7:0] joystick_1,
|
||||
output reg [15:0] joystick_analog_0,
|
||||
output reg [15:0] joystick_analog_1,
|
||||
output [1:0] buttons,
|
||||
output [1:0] switches,
|
||||
output scandoubler_disable,
|
||||
output ypbpr,
|
||||
|
||||
output reg [31:0] status,
|
||||
|
||||
// SD config
|
||||
input sd_conf,
|
||||
input sd_sdhc,
|
||||
output img_mounted, // signaling that new image has been mounted
|
||||
output reg [31:0] img_size, // size of image in bytes
|
||||
|
||||
// SD block level access
|
||||
input [31:0] sd_lba,
|
||||
input sd_rd,
|
||||
input sd_wr,
|
||||
output reg sd_ack,
|
||||
output reg sd_ack_conf,
|
||||
|
||||
// SD byte level access. Signals for 2-PORT altsyncram.
|
||||
output reg [8:0] sd_buff_addr,
|
||||
output reg [7:0] sd_buff_dout,
|
||||
input [7:0] sd_buff_din,
|
||||
output reg sd_buff_wr,
|
||||
|
||||
// ps2 keyboard emulation
|
||||
output ps2_kbd_clk,
|
||||
output reg ps2_kbd_data,
|
||||
output ps2_mouse_clk,
|
||||
output reg ps2_mouse_data,
|
||||
input ps2_caps_led,
|
||||
|
||||
// ARM -> FPGA download
|
||||
output reg ioctl_download = 0, // signal indicating an active download
|
||||
output reg [7:0] ioctl_index, // menu index used to upload the file
|
||||
output ioctl_wr,
|
||||
output reg [24:0] ioctl_addr,
|
||||
output reg [7:0] ioctl_dout
|
||||
);
|
||||
|
||||
reg [7:0] b_data;
|
||||
reg [6:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
|
||||
reg [9:0] byte_cnt; // counts bytes
|
||||
reg [7:0] but_sw;
|
||||
reg [2:0] stick_idx;
|
||||
|
||||
reg mount_strobe = 0;
|
||||
assign img_mounted = mount_strobe;
|
||||
|
||||
assign buttons = but_sw[1:0];
|
||||
assign switches = but_sw[3:2];
|
||||
assign scandoubler_disable = but_sw[4];
|
||||
assign ypbpr = but_sw[5];
|
||||
|
||||
wire [7:0] spi_dout = { sbuf, SPI_DI};
|
||||
|
||||
// this variant of user_io is for 8 bit cores (type == a4) only
|
||||
wire [7:0] core_type = 8'ha4;
|
||||
|
||||
// command byte read by the io controller
|
||||
wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd };
|
||||
|
||||
reg spi_do;
|
||||
assign SPI_DO = CONF_DATA0 ? 1'bZ : spi_do;
|
||||
|
||||
wire [7:0] kbd_led = { 2'b01, 4'b0000, ps2_caps_led, 1'b1};
|
||||
|
||||
// drive MISO only when transmitting core id
|
||||
always@(negedge SPI_SCK) begin
|
||||
if(!CONF_DATA0) begin
|
||||
// first byte returned is always core type, further bytes are
|
||||
// command dependent
|
||||
if(byte_cnt == 0) begin
|
||||
spi_do <= core_type[~bit_cnt];
|
||||
|
||||
end else begin
|
||||
case(cmd)
|
||||
// reading config string
|
||||
8'h14: begin
|
||||
// returning a byte from string
|
||||
if(byte_cnt < STRLEN + 1) spi_do <= conf_str[{STRLEN - byte_cnt,~bit_cnt}];
|
||||
else spi_do <= 0;
|
||||
end
|
||||
|
||||
// reading sd card status
|
||||
8'h16: begin
|
||||
if(byte_cnt == 1) spi_do <= sd_cmd[~bit_cnt];
|
||||
else if((byte_cnt >= 2) && (byte_cnt < 6)) spi_do <= sd_lba[{5-byte_cnt, ~bit_cnt}];
|
||||
else spi_do <= 0;
|
||||
end
|
||||
|
||||
// reading sd card write data
|
||||
8'h18:
|
||||
spi_do <= b_data[~bit_cnt];
|
||||
|
||||
// reading keyboard LED status
|
||||
8'h1f:
|
||||
spi_do <= kbd_led[~bit_cnt];
|
||||
|
||||
default:
|
||||
spi_do <= 0;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg b_wr2,b_wr3;
|
||||
always @(negedge clk_sys) begin
|
||||
b_wr3 <= b_wr2;
|
||||
sd_buff_wr <= b_wr3;
|
||||
end
|
||||
|
||||
// SPI receiver
|
||||
always@(posedge SPI_SCK or posedge CONF_DATA0) begin
|
||||
|
||||
if(CONF_DATA0) begin
|
||||
b_wr2 <= 0;
|
||||
bit_cnt <= 0;
|
||||
byte_cnt <= 0;
|
||||
sd_ack <= 0;
|
||||
sd_ack_conf <= 0;
|
||||
end else begin
|
||||
b_wr2 <= 0;
|
||||
|
||||
sbuf <= spi_dout[6:0];
|
||||
bit_cnt <= bit_cnt + 1'd1;
|
||||
if(bit_cnt == 5) begin
|
||||
if (byte_cnt == 0) sd_buff_addr <= 0;
|
||||
if((byte_cnt != 0) & (sd_buff_addr != 511)) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
if((byte_cnt == 1) & ((cmd == 8'h17) | (cmd == 8'h19))) sd_buff_addr <= 0;
|
||||
end
|
||||
|
||||
// finished reading command byte
|
||||
if(bit_cnt == 7) begin
|
||||
if(~&byte_cnt) byte_cnt <= byte_cnt + 8'd1;
|
||||
if(byte_cnt == 0) begin
|
||||
cmd <= spi_dout;
|
||||
|
||||
if(spi_dout == 8'h19) begin
|
||||
sd_ack_conf <= 1;
|
||||
sd_buff_addr <= 0;
|
||||
end
|
||||
if((spi_dout == 8'h17) || (spi_dout == 8'h18)) begin
|
||||
sd_ack <= 1;
|
||||
sd_buff_addr <= 0;
|
||||
end
|
||||
if(spi_dout == 8'h18) b_data <= sd_buff_din;
|
||||
|
||||
mount_strobe <= 0;
|
||||
|
||||
end else begin
|
||||
|
||||
case(cmd)
|
||||
// buttons and switches
|
||||
8'h01: but_sw <= spi_dout;
|
||||
8'h02: joystick_0 <= spi_dout;
|
||||
8'h03: joystick_1 <= spi_dout;
|
||||
|
||||
// store incoming ps2 mouse bytes
|
||||
8'h04: begin
|
||||
ps2_mouse_fifo[ps2_mouse_wptr] <= spi_dout;
|
||||
ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1;
|
||||
end
|
||||
|
||||
// store incoming ps2 keyboard bytes
|
||||
8'h05: begin
|
||||
ps2_kbd_fifo[ps2_kbd_wptr] <= spi_dout;
|
||||
ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1;
|
||||
end
|
||||
|
||||
8'h15: status[7:0] <= spi_dout;
|
||||
|
||||
// send SD config IO -> FPGA
|
||||
// flag that download begins
|
||||
// sd card knows data is config if sd_dout_strobe is asserted
|
||||
// with sd_ack still being inactive (low)
|
||||
8'h19,
|
||||
// send sector IO -> FPGA
|
||||
// flag that download begins
|
||||
8'h17: begin
|
||||
sd_buff_dout <= spi_dout;
|
||||
b_wr2 <= 1;
|
||||
end
|
||||
|
||||
8'h18: b_data <= sd_buff_din;
|
||||
|
||||
// joystick analog
|
||||
8'h1a: begin
|
||||
// first byte is joystick index
|
||||
if(byte_cnt == 1) stick_idx <= spi_dout[2:0];
|
||||
else if(byte_cnt == 2) begin
|
||||
// second byte is x axis
|
||||
if(stick_idx == 0) joystick_analog_0[15:8] <= spi_dout;
|
||||
else if(stick_idx == 1) joystick_analog_1[15:8] <= spi_dout;
|
||||
end else if(byte_cnt == 3) begin
|
||||
// third byte is y axis
|
||||
if(stick_idx == 0) joystick_analog_0[7:0] <= spi_dout;
|
||||
else if(stick_idx == 1) joystick_analog_1[7:0] <= spi_dout;
|
||||
end
|
||||
end
|
||||
|
||||
// notify image selection
|
||||
8'h1c: mount_strobe <= 1;
|
||||
|
||||
// send image info
|
||||
8'h1d: if(byte_cnt<5) img_size[(byte_cnt-1)<<3 +:8] <= spi_dout;
|
||||
|
||||
// status, 32bit version
|
||||
8'h1e: if(byte_cnt<5) status[(byte_cnt-1)<<3 +:8] <= spi_dout;
|
||||
default: ;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
/////////////////////////////// PS2 ///////////////////////////////
|
||||
// 8 byte fifos to store ps2 bytes
|
||||
localparam PS2_FIFO_BITS = 3;
|
||||
|
||||
reg clk_ps2;
|
||||
always @(negedge clk_sys) begin
|
||||
integer cnt;
|
||||
cnt <= cnt + 1'd1;
|
||||
if(cnt == PS2DIV) begin
|
||||
clk_ps2 <= ~clk_ps2;
|
||||
cnt <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
// keyboard
|
||||
reg [7:0] ps2_kbd_fifo[1<<PS2_FIFO_BITS];
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr;
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr;
|
||||
|
||||
// ps2 transmitter state machine
|
||||
reg [3:0] ps2_kbd_tx_state;
|
||||
reg [7:0] ps2_kbd_tx_byte;
|
||||
reg ps2_kbd_parity;
|
||||
|
||||
assign ps2_kbd_clk = clk_ps2 || (ps2_kbd_tx_state == 0);
|
||||
|
||||
// ps2 transmitter
|
||||
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
|
||||
reg ps2_kbd_r_inc;
|
||||
always@(posedge clk_sys) begin
|
||||
reg old_clk;
|
||||
old_clk <= clk_ps2;
|
||||
if(~old_clk & clk_ps2) begin
|
||||
ps2_kbd_r_inc <= 0;
|
||||
|
||||
if(ps2_kbd_r_inc) ps2_kbd_rptr <= ps2_kbd_rptr + 1'd1;
|
||||
|
||||
// transmitter is idle?
|
||||
if(ps2_kbd_tx_state == 0) begin
|
||||
// data in fifo present?
|
||||
if(ps2_kbd_wptr != ps2_kbd_rptr) begin
|
||||
// load tx register from fifo
|
||||
ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr];
|
||||
ps2_kbd_r_inc <= 1;
|
||||
|
||||
// reset parity
|
||||
ps2_kbd_parity <= 1;
|
||||
|
||||
// start transmitter
|
||||
ps2_kbd_tx_state <= 1;
|
||||
|
||||
// put start bit on data line
|
||||
ps2_kbd_data <= 0; // start bit is 0
|
||||
end
|
||||
end else begin
|
||||
|
||||
// transmission of 8 data bits
|
||||
if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin
|
||||
ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits
|
||||
ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down
|
||||
if(ps2_kbd_tx_byte[0])
|
||||
ps2_kbd_parity <= !ps2_kbd_parity;
|
||||
end
|
||||
|
||||
// transmission of parity
|
||||
if(ps2_kbd_tx_state == 9) ps2_kbd_data <= ps2_kbd_parity;
|
||||
|
||||
// transmission of stop bit
|
||||
if(ps2_kbd_tx_state == 10) ps2_kbd_data <= 1; // stop bit is 1
|
||||
|
||||
// advance state machine
|
||||
if(ps2_kbd_tx_state < 11) ps2_kbd_tx_state <= ps2_kbd_tx_state + 1'd1;
|
||||
else ps2_kbd_tx_state <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// mouse
|
||||
reg [7:0] ps2_mouse_fifo[1<<PS2_FIFO_BITS];
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr;
|
||||
reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr;
|
||||
|
||||
// ps2 transmitter state machine
|
||||
reg [3:0] ps2_mouse_tx_state;
|
||||
reg [7:0] ps2_mouse_tx_byte;
|
||||
reg ps2_mouse_parity;
|
||||
|
||||
assign ps2_mouse_clk = clk_ps2 || (ps2_mouse_tx_state == 0);
|
||||
|
||||
// ps2 transmitter
|
||||
// Takes a byte from the FIFO and sends it in a ps2 compliant serial format.
|
||||
reg ps2_mouse_r_inc;
|
||||
always@(posedge clk_sys) begin
|
||||
reg old_clk;
|
||||
old_clk <= clk_ps2;
|
||||
if(~old_clk & clk_ps2) begin
|
||||
ps2_mouse_r_inc <= 0;
|
||||
|
||||
if(ps2_mouse_r_inc) ps2_mouse_rptr <= ps2_mouse_rptr + 1'd1;
|
||||
|
||||
// transmitter is idle?
|
||||
if(ps2_mouse_tx_state == 0) begin
|
||||
// data in fifo present?
|
||||
if(ps2_mouse_wptr != ps2_mouse_rptr) begin
|
||||
// load tx register from fifo
|
||||
ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr];
|
||||
ps2_mouse_r_inc <= 1;
|
||||
|
||||
// reset parity
|
||||
ps2_mouse_parity <= 1;
|
||||
|
||||
// start transmitter
|
||||
ps2_mouse_tx_state <= 1;
|
||||
|
||||
// put start bit on data line
|
||||
ps2_mouse_data <= 0; // start bit is 0
|
||||
end
|
||||
end else begin
|
||||
|
||||
// transmission of 8 data bits
|
||||
if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin
|
||||
ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits
|
||||
ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down
|
||||
if(ps2_mouse_tx_byte[0])
|
||||
ps2_mouse_parity <= !ps2_mouse_parity;
|
||||
end
|
||||
|
||||
// transmission of parity
|
||||
if(ps2_mouse_tx_state == 9) ps2_mouse_data <= ps2_mouse_parity;
|
||||
|
||||
// transmission of stop bit
|
||||
if(ps2_mouse_tx_state == 10) ps2_mouse_data <= 1; // stop bit is 1
|
||||
|
||||
// advance state machine
|
||||
if(ps2_mouse_tx_state < 11) ps2_mouse_tx_state <= ps2_mouse_tx_state + 1'd1;
|
||||
else ps2_mouse_tx_state <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
/////////////////////////////// DOWNLOADING ///////////////////////////////
|
||||
|
||||
reg [7:0] data_w;
|
||||
reg [24:0] addr_w;
|
||||
reg rclk = 0;
|
||||
|
||||
localparam UIO_FILE_TX = 8'h53;
|
||||
localparam UIO_FILE_TX_DAT = 8'h54;
|
||||
localparam UIO_FILE_INDEX = 8'h55;
|
||||
|
||||
// data_io has its own SPI interface to the io controller
|
||||
always@(posedge SPI_SCK, posedge SPI_SS2) begin
|
||||
reg [6:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
reg [4:0] cnt;
|
||||
reg [24:0] addr;
|
||||
|
||||
if(SPI_SS2) cnt <= 0;
|
||||
else begin
|
||||
rclk <= 0;
|
||||
|
||||
// don't shift in last bit. It is evaluated directly
|
||||
// when writing to ram
|
||||
if(cnt != 15) sbuf <= { sbuf[5:0], SPI_DI};
|
||||
|
||||
// increase target address after write
|
||||
if(rclk) addr <= addr + 1'd1;
|
||||
|
||||
// count 0-7 8-15 8-15 ...
|
||||
if(cnt < 15) cnt <= cnt + 1'd1;
|
||||
else cnt <= 8;
|
||||
|
||||
// finished command byte
|
||||
if(cnt == 7) cmd <= {sbuf, SPI_DI};
|
||||
|
||||
// prepare/end transmission
|
||||
if((cmd == UIO_FILE_TX) && (cnt == 15)) begin
|
||||
// prepare
|
||||
if(SPI_DI) begin
|
||||
addr <= 0;
|
||||
ioctl_download <= 1;
|
||||
end else begin
|
||||
addr_w <= addr;
|
||||
ioctl_download <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
// command 0x54: UIO_FILE_TX
|
||||
if((cmd == UIO_FILE_TX_DAT) && (cnt == 15)) begin
|
||||
addr_w <= addr;
|
||||
data_w <= {sbuf, SPI_DI};
|
||||
rclk <= 1;
|
||||
end
|
||||
|
||||
// expose file (menu) index
|
||||
if((cmd == UIO_FILE_INDEX) && (cnt == 15)) ioctl_index <= {sbuf, SPI_DI};
|
||||
end
|
||||
end
|
||||
|
||||
assign ioctl_wr = |ioctl_wrd;
|
||||
reg [1:0] ioctl_wrd;
|
||||
|
||||
always@(negedge clk_sys) begin
|
||||
reg rclkD, rclkD2;
|
||||
|
||||
rclkD <= rclk;
|
||||
rclkD2 <= rclkD;
|
||||
ioctl_wrd<= {ioctl_wrd[0],1'b0};
|
||||
|
||||
if(rclkD & ~rclkD2) begin
|
||||
ioctl_dout <= data_w;
|
||||
ioctl_addr <= addr_w;
|
||||
ioctl_wrd <= 2'b11;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
179
rtl/mist-modules_old/osd.v
Normal file
179
rtl/mist-modules_old/osd.v
Normal file
@ -0,0 +1,179 @@
|
||||
// A simple OSD implementation. Can be hooked up between a cores
|
||||
// VGA output and the physical VGA pins
|
||||
|
||||
module osd (
|
||||
// OSDs pixel clock, should be synchronous to cores pixel clock to
|
||||
// avoid jitter.
|
||||
input clk_sys,
|
||||
|
||||
// SPI interface
|
||||
input SPI_SCK,
|
||||
input SPI_SS3,
|
||||
input SPI_DI,
|
||||
|
||||
// VGA signals coming from core
|
||||
input [5:0] R_in,
|
||||
input [5:0] G_in,
|
||||
input [5:0] B_in,
|
||||
input HSync,
|
||||
input VSync,
|
||||
|
||||
// VGA signals going to video connector
|
||||
output [5:0] R_out,
|
||||
output [5:0] G_out,
|
||||
output [5:0] B_out
|
||||
);
|
||||
|
||||
parameter OSD_X_OFFSET = 10'd0;
|
||||
parameter OSD_Y_OFFSET = 10'd0;
|
||||
parameter OSD_COLOR = 3'd0;
|
||||
|
||||
localparam OSD_WIDTH = 10'd256;
|
||||
localparam OSD_HEIGHT = 10'd128;
|
||||
|
||||
// *********************************************************************************
|
||||
// spi client
|
||||
// *********************************************************************************
|
||||
|
||||
// this core supports only the display related OSD commands
|
||||
// of the minimig
|
||||
reg osd_enable;
|
||||
(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself
|
||||
|
||||
// the OSD has its own SPI interface to the io controller
|
||||
always@(posedge SPI_SCK, posedge SPI_SS3) begin
|
||||
reg [4:0] cnt;
|
||||
reg [10:0] bcnt;
|
||||
reg [7:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
|
||||
if(SPI_SS3) begin
|
||||
cnt <= 0;
|
||||
bcnt <= 0;
|
||||
end else begin
|
||||
sbuf <= {sbuf[6:0], SPI_DI};
|
||||
|
||||
// 0:7 is command, rest payload
|
||||
if(cnt < 15) cnt <= cnt + 1'd1;
|
||||
else cnt <= 8;
|
||||
|
||||
if(cnt == 7) begin
|
||||
cmd <= {sbuf[6:0], SPI_DI};
|
||||
|
||||
// lower three command bits are line address
|
||||
bcnt <= {sbuf[1:0], SPI_DI, 8'h00};
|
||||
|
||||
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
|
||||
if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI;
|
||||
end
|
||||
|
||||
// command 0x20: OSDCMDWRITE
|
||||
if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin
|
||||
osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI};
|
||||
bcnt <= bcnt + 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// *********************************************************************************
|
||||
// video timing and sync polarity anaylsis
|
||||
// *********************************************************************************
|
||||
|
||||
// horizontal counter
|
||||
reg [9:0] h_cnt;
|
||||
reg [9:0] hs_low, hs_high;
|
||||
wire hs_pol = hs_high < hs_low;
|
||||
wire [9:0] dsp_width = hs_pol ? hs_low : hs_high;
|
||||
|
||||
// vertical counter
|
||||
reg [9:0] v_cnt;
|
||||
reg [9:0] vs_low, vs_high;
|
||||
wire vs_pol = vs_high < vs_low;
|
||||
wire [9:0] dsp_height = vs_pol ? vs_low : vs_high;
|
||||
|
||||
wire doublescan = (dsp_height>350);
|
||||
|
||||
reg ce_pix;
|
||||
always @(negedge clk_sys) begin
|
||||
integer cnt = 0;
|
||||
integer pixsz, pixcnt;
|
||||
reg hs;
|
||||
|
||||
cnt <= cnt + 1;
|
||||
hs <= HSync;
|
||||
|
||||
pixcnt <= pixcnt + 1;
|
||||
if(pixcnt == pixsz) pixcnt <= 0;
|
||||
ce_pix <= !pixcnt;
|
||||
|
||||
if(hs && ~HSync) begin
|
||||
cnt <= 0;
|
||||
pixsz <= (cnt >> 9) - 1;
|
||||
pixcnt <= 0;
|
||||
ce_pix <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD, hsD2;
|
||||
reg vsD, vsD2;
|
||||
|
||||
if(ce_pix) begin
|
||||
// bring hsync into local clock domain
|
||||
hsD <= HSync;
|
||||
hsD2 <= hsD;
|
||||
|
||||
// falling edge of HSync
|
||||
if(!hsD && hsD2) begin
|
||||
h_cnt <= 0;
|
||||
hs_high <= h_cnt;
|
||||
end
|
||||
|
||||
// rising edge of HSync
|
||||
else if(hsD && !hsD2) begin
|
||||
h_cnt <= 0;
|
||||
hs_low <= h_cnt;
|
||||
v_cnt <= v_cnt + 1'd1;
|
||||
end else begin
|
||||
h_cnt <= h_cnt + 1'd1;
|
||||
end
|
||||
|
||||
vsD <= VSync;
|
||||
vsD2 <= vsD;
|
||||
|
||||
// falling edge of VSync
|
||||
if(!vsD && vsD2) begin
|
||||
v_cnt <= 0;
|
||||
vs_high <= v_cnt;
|
||||
end
|
||||
|
||||
// rising edge of VSync
|
||||
else if(vsD && !vsD2) begin
|
||||
v_cnt <= 0;
|
||||
vs_low <= v_cnt;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// area in which OSD is being displayed
|
||||
wire [9:0] h_osd_start = ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET;
|
||||
wire [9:0] h_osd_end = h_osd_start + OSD_WIDTH;
|
||||
wire [9:0] v_osd_start = ((dsp_height- (OSD_HEIGHT<<doublescan))>> 1) + OSD_Y_OFFSET;
|
||||
wire [9:0] v_osd_end = v_osd_start + (OSD_HEIGHT<<doublescan);
|
||||
wire [9:0] osd_hcnt = h_cnt - h_osd_start + 1'd1; // one pixel offset for osd_byte register
|
||||
wire [9:0] osd_vcnt = v_cnt - v_osd_start;
|
||||
|
||||
wire osd_de = osd_enable &&
|
||||
(HSync != hs_pol) && (h_cnt >= h_osd_start) && (h_cnt < h_osd_end) &&
|
||||
(VSync != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end);
|
||||
|
||||
reg [7:0] osd_byte;
|
||||
always @(posedge clk_sys) if(ce_pix) osd_byte <= osd_buffer[{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt[7:0]}];
|
||||
|
||||
wire osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]];
|
||||
|
||||
assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]};
|
||||
assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]};
|
||||
assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]};
|
||||
|
||||
endmodule
|
195
rtl/mist-modules_old/scandoubler.v
Normal file
195
rtl/mist-modules_old/scandoubler.v
Normal file
@ -0,0 +1,195 @@
|
||||
//
|
||||
// scandoubler.v
|
||||
//
|
||||
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
|
||||
// Copyright (c) 2017 Sorgelig
|
||||
//
|
||||
// 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/>.
|
||||
|
||||
// TODO: Delay vsync one line
|
||||
|
||||
module scandoubler #(parameter LENGTH, parameter HALF_DEPTH)
|
||||
(
|
||||
// system interface
|
||||
input clk_sys,
|
||||
input ce_pix,
|
||||
input ce_pix_actual,
|
||||
|
||||
input hq2x,
|
||||
|
||||
// shifter video interface
|
||||
input hs_in,
|
||||
input vs_in,
|
||||
input line_start,
|
||||
|
||||
input [DWIDTH:0] r_in,
|
||||
input [DWIDTH:0] g_in,
|
||||
input [DWIDTH:0] b_in,
|
||||
input mono,
|
||||
|
||||
// output interface
|
||||
output reg hs_out,
|
||||
output vs_out,
|
||||
output [DWIDTH:0] r_out,
|
||||
output [DWIDTH:0] g_out,
|
||||
output [DWIDTH:0] b_out
|
||||
);
|
||||
|
||||
|
||||
localparam DWIDTH = HALF_DEPTH ? 2 : 5;
|
||||
|
||||
assign vs_out = vs_in;
|
||||
|
||||
reg [2:0] phase;
|
||||
reg [2:0] ce_div;
|
||||
reg [7:0] pix_len = 0;
|
||||
wire [7:0] pl = pix_len + 1'b1;
|
||||
|
||||
reg ce_x1, ce_x4;
|
||||
reg req_line_reset;
|
||||
wire ls_in = hs_in | line_start;
|
||||
always @(negedge clk_sys) begin
|
||||
reg old_ce;
|
||||
reg [2:0] ce_cnt;
|
||||
|
||||
reg [7:0] pixsz2, pixsz4 = 0;
|
||||
|
||||
old_ce <= ce_pix;
|
||||
if(~&pix_len) pix_len <= pix_len + 1'd1;
|
||||
|
||||
ce_x4 <= 0;
|
||||
ce_x1 <= 0;
|
||||
|
||||
// use such odd comparison to place c_x4 evenly if master clock isn't multiple 4.
|
||||
if((pl == pixsz4) || (pl == pixsz2) || (pl == (pixsz2+pixsz4))) begin
|
||||
phase <= phase + 1'd1;
|
||||
ce_x4 <= 1;
|
||||
end
|
||||
|
||||
if(~old_ce & ce_pix) begin
|
||||
pixsz2 <= {1'b0, pl[7:1]};
|
||||
pixsz4 <= {2'b00, pl[7:2]};
|
||||
ce_x1 <= 1;
|
||||
ce_x4 <= 1;
|
||||
pix_len <= 0;
|
||||
phase <= phase + 1'd1;
|
||||
|
||||
ce_cnt <= ce_cnt + 1'd1;
|
||||
if(ce_pix_actual) begin
|
||||
phase <= 0;
|
||||
ce_div <= ce_cnt + 1'd1;
|
||||
ce_cnt <= 0;
|
||||
req_line_reset <= 0;
|
||||
end
|
||||
|
||||
if(ls_in) req_line_reset <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
reg ce_sd;
|
||||
always @(*) begin
|
||||
case(ce_div)
|
||||
2: ce_sd = !phase[0];
|
||||
4: ce_sd = !phase[1:0];
|
||||
default: ce_sd <= 1;
|
||||
endcase
|
||||
end
|
||||
|
||||
`define BITS_TO_FIT(N) ( \
|
||||
N <= 2 ? 0 : \
|
||||
N <= 4 ? 1 : \
|
||||
N <= 8 ? 2 : \
|
||||
N <= 16 ? 3 : \
|
||||
N <= 32 ? 4 : \
|
||||
N <= 64 ? 5 : \
|
||||
N <= 128 ? 6 : \
|
||||
N <= 256 ? 7 : \
|
||||
N <= 512 ? 8 : \
|
||||
N <=1024 ? 9 : 10 )
|
||||
|
||||
localparam AWIDTH = `BITS_TO_FIT(LENGTH);
|
||||
Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x
|
||||
(
|
||||
.clk(clk_sys),
|
||||
.ce_x4(ce_x4 & ce_sd),
|
||||
.inputpixel({b_in,g_in,r_in}),
|
||||
.mono(mono),
|
||||
.disable_hq2x(~hq2x),
|
||||
.reset_frame(vs_in),
|
||||
.reset_line(req_line_reset),
|
||||
.read_y(sd_line),
|
||||
.read_x(sd_h_actual),
|
||||
.outpixel({b_out,g_out,r_out})
|
||||
);
|
||||
|
||||
reg [10:0] sd_h_actual;
|
||||
always @(*) begin
|
||||
case(ce_div)
|
||||
2: sd_h_actual = sd_h[10:1];
|
||||
4: sd_h_actual = sd_h[10:2];
|
||||
default: sd_h_actual = sd_h;
|
||||
endcase
|
||||
end
|
||||
|
||||
reg [10:0] sd_h;
|
||||
reg [1:0] sd_line;
|
||||
always @(posedge clk_sys) begin
|
||||
|
||||
reg [11:0] hs_max,hs_rise,hs_ls;
|
||||
reg [10:0] hcnt;
|
||||
reg [11:0] sd_hcnt;
|
||||
|
||||
reg hs, hs2, vs, ls;
|
||||
|
||||
if(ce_x1) begin
|
||||
hs <= hs_in;
|
||||
ls <= ls_in;
|
||||
|
||||
if(ls && !ls_in) hs_ls <= {hcnt,1'b1};
|
||||
|
||||
// falling edge of hsync indicates start of line
|
||||
if(hs && !hs_in) begin
|
||||
hs_max <= {hcnt,1'b1};
|
||||
hcnt <= 0;
|
||||
if(ls && !ls_in) hs_ls <= {10'd0,1'b1};
|
||||
end else begin
|
||||
hcnt <= hcnt + 1'd1;
|
||||
end
|
||||
|
||||
// save position of rising edge
|
||||
if(!hs && hs_in) hs_rise <= {hcnt,1'b1};
|
||||
|
||||
vs <= vs_in;
|
||||
if(vs && ~vs_in) sd_line <= 0;
|
||||
end
|
||||
|
||||
if(ce_x4) begin
|
||||
hs2 <= hs_in;
|
||||
|
||||
// output counter synchronous to input and at twice the rate
|
||||
sd_hcnt <= sd_hcnt + 1'd1;
|
||||
sd_h <= sd_h + 1'd1;
|
||||
if(hs2 && !hs_in) sd_hcnt <= hs_max;
|
||||
if(sd_hcnt == hs_max) sd_hcnt <= 0;
|
||||
|
||||
// replicate horizontal sync at twice the speed
|
||||
if(sd_hcnt == hs_max) hs_out <= 0;
|
||||
if(sd_hcnt == hs_rise) hs_out <= 1;
|
||||
|
||||
if(sd_hcnt == hs_ls) sd_h <= 0;
|
||||
if(sd_hcnt == hs_ls) sd_line <= sd_line + 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
242
rtl/mist-modules_old/video_mixer.sv
Normal file
242
rtl/mist-modules_old/video_mixer.sv
Normal file
@ -0,0 +1,242 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2017 Sorgelig
|
||||
//
|
||||
// This program is GPL Licensed. See COPYING for the full license.
|
||||
//
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
//
|
||||
// LINE_LENGTH: Length of display line in pixels
|
||||
// Usually it's length from HSync to HSync.
|
||||
// May be less if line_start is used.
|
||||
//
|
||||
// HALF_DEPTH: If =1 then color dept is 3 bits per component
|
||||
// For half depth 6 bits monochrome is available with
|
||||
// mono signal enabled and color = {G, R}
|
||||
|
||||
module video_mixer
|
||||
#(
|
||||
parameter LINE_LENGTH = 768,
|
||||
parameter HALF_DEPTH = 0,
|
||||
|
||||
parameter OSD_COLOR = 3'd4,
|
||||
parameter OSD_X_OFFSET = 10'd0,
|
||||
parameter OSD_Y_OFFSET = 10'd0
|
||||
)
|
||||
(
|
||||
// master clock
|
||||
// it should be multiple by (ce_pix*4).
|
||||
input clk_sys,
|
||||
|
||||
// Pixel clock or clock_enable (both are accepted).
|
||||
input ce_pix,
|
||||
|
||||
// Some systems have multiple resolutions.
|
||||
// ce_pix_actual should match ce_pix where every second or fourth pulse is enabled,
|
||||
// thus half or qurter resolutions can be used without brake video sync while switching resolutions.
|
||||
// For fixed single resolution (or when video sync stability isn't required) ce_pix_actual = ce_pix.
|
||||
input ce_pix_actual,
|
||||
|
||||
// OSD SPI interface
|
||||
input SPI_SCK,
|
||||
input SPI_SS3,
|
||||
input SPI_DI,
|
||||
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
input [1:0] scanlines,
|
||||
|
||||
// 0 = HVSync 31KHz, 1 = CSync 15KHz
|
||||
input scandoubler_disable,
|
||||
|
||||
// High quality 2x scaling
|
||||
input hq2x,
|
||||
|
||||
// YPbPr always uses composite sync
|
||||
input ypbpr,
|
||||
|
||||
// 0 = 16-240 range. 1 = 0-255 range. (only for YPbPr color space)
|
||||
input ypbpr_full,
|
||||
|
||||
// color
|
||||
input [DWIDTH:0] R,
|
||||
input [DWIDTH:0] G,
|
||||
input [DWIDTH:0] B,
|
||||
|
||||
// Monochrome mode (for HALF_DEPTH only)
|
||||
input mono,
|
||||
|
||||
// interlace sync. Positive pulses.
|
||||
input HSync,
|
||||
input VSync,
|
||||
|
||||
// Falling of this signal means start of informative part of line.
|
||||
// It can be horizontal blank signal.
|
||||
// This signal can be used to reduce amount of required FPGA RAM for HQ2x scan doubler
|
||||
// If FPGA RAM is not an issue, then simply set it to 0 for whole line processing.
|
||||
// Keep in mind: due to algo first and last pixels of line should be black to avoid side artefacts.
|
||||
// Thus, if blank signal is used to reduce the line, make sure to feed at least one black (or paper) pixel
|
||||
// before first informative pixel.
|
||||
input line_start,
|
||||
|
||||
// MiST video output signals
|
||||
output [5:0] VGA_R,
|
||||
output [5:0] VGA_G,
|
||||
output [5:0] VGA_B,
|
||||
output VGA_VS,
|
||||
output VGA_HS
|
||||
);
|
||||
|
||||
localparam DWIDTH = HALF_DEPTH ? 2 : 5;
|
||||
|
||||
wire [DWIDTH:0] R_sd;
|
||||
wire [DWIDTH:0] G_sd;
|
||||
wire [DWIDTH:0] B_sd;
|
||||
wire hs_sd, vs_sd;
|
||||
|
||||
scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH)) scandoubler
|
||||
(
|
||||
.*,
|
||||
.hs_in(HSync),
|
||||
.vs_in(VSync),
|
||||
.r_in(R),
|
||||
.g_in(G),
|
||||
.b_in(B),
|
||||
|
||||
.hs_out(hs_sd),
|
||||
.vs_out(vs_sd),
|
||||
.r_out(R_sd),
|
||||
.g_out(G_sd),
|
||||
.b_out(B_sd)
|
||||
);
|
||||
|
||||
wire [DWIDTH:0] rt = (scandoubler_disable ? R : R_sd);
|
||||
wire [DWIDTH:0] gt = (scandoubler_disable ? G : G_sd);
|
||||
wire [DWIDTH:0] bt = (scandoubler_disable ? B : B_sd);
|
||||
|
||||
generate
|
||||
if(HALF_DEPTH) begin
|
||||
wire [5:0] r = mono ? {gt,rt} : {rt,rt};
|
||||
wire [5:0] g = mono ? {gt,rt} : {gt,gt};
|
||||
wire [5:0] b = mono ? {gt,rt} : {bt,bt};
|
||||
end else begin
|
||||
wire [5:0] r = rt;
|
||||
wire [5:0] g = gt;
|
||||
wire [5:0] b = bt;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
wire hs = (scandoubler_disable ? HSync : hs_sd);
|
||||
wire vs = (scandoubler_disable ? VSync : vs_sd);
|
||||
|
||||
reg scanline = 0;
|
||||
always @(posedge clk_sys) begin
|
||||
reg old_hs, old_vs;
|
||||
|
||||
old_hs <= hs;
|
||||
old_vs <= vs;
|
||||
|
||||
if(old_hs && ~hs) scanline <= ~scanline;
|
||||
if(old_vs && ~vs) scanline <= 0;
|
||||
end
|
||||
|
||||
wire [5:0] r_out, g_out, b_out;
|
||||
always @(*) begin
|
||||
case(scanlines & {scanline, scanline})
|
||||
1: begin // reduce 25% = 1/2 + 1/4
|
||||
r_out = {1'b0, r[5:1]} + {2'b00, r[5:2]};
|
||||
g_out = {1'b0, g[5:1]} + {2'b00, g[5:2]};
|
||||
b_out = {1'b0, b[5:1]} + {2'b00, b[5:2]};
|
||||
end
|
||||
|
||||
2: begin // reduce 50% = 1/2
|
||||
r_out = {1'b0, r[5:1]};
|
||||
g_out = {1'b0, g[5:1]};
|
||||
b_out = {1'b0, b[5:1]};
|
||||
end
|
||||
|
||||
3: begin // reduce 75% = 1/4
|
||||
r_out = {2'b00, r[5:2]};
|
||||
g_out = {2'b00, g[5:2]};
|
||||
b_out = {2'b00, b[5:2]};
|
||||
end
|
||||
|
||||
default: begin
|
||||
r_out = r;
|
||||
g_out = g;
|
||||
b_out = b;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
wire [5:0] red, green, blue;
|
||||
osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR) osd
|
||||
(
|
||||
.*,
|
||||
|
||||
.R_in(r_out),
|
||||
.G_in(g_out),
|
||||
.B_in(b_out),
|
||||
.HSync(hs),
|
||||
.VSync(vs),
|
||||
|
||||
.R_out(red),
|
||||
.G_out(green),
|
||||
.B_out(blue)
|
||||
);
|
||||
|
||||
wire [5:0] yuv_full[225] = '{
|
||||
6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1,
|
||||
6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4,
|
||||
6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6,
|
||||
6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8,
|
||||
6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11,
|
||||
6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13,
|
||||
6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15,
|
||||
6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17,
|
||||
6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20,
|
||||
6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22,
|
||||
6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24,
|
||||
6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27,
|
||||
6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29,
|
||||
6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31,
|
||||
6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33,
|
||||
6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36,
|
||||
6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38,
|
||||
6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40,
|
||||
6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42,
|
||||
6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45,
|
||||
6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47,
|
||||
6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49,
|
||||
6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52,
|
||||
6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54,
|
||||
6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56,
|
||||
6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58,
|
||||
6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61,
|
||||
6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63,
|
||||
6'd63
|
||||
};
|
||||
|
||||
// http://marsee101.blog19.fc2.com/blog-entry-2311.html
|
||||
// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B)
|
||||
// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B)
|
||||
// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B)
|
||||
|
||||
wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0});
|
||||
wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0});
|
||||
wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0});
|
||||
|
||||
wire [7:0] y = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8];
|
||||
wire [7:0] pb = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8];
|
||||
wire [7:0] pr = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8];
|
||||
|
||||
assign VGA_R = ypbpr ? (ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]) : red;
|
||||
assign VGA_G = ypbpr ? (ypbpr_full ? yuv_full[y -8'd16] : y[7:2]) : green;
|
||||
assign VGA_B = ypbpr ? (ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]) : blue;
|
||||
assign VGA_VS = (scandoubler_disable | ypbpr) ? 1'b1 : ~vs_sd;
|
||||
assign VGA_HS = scandoubler_disable ? ~(HSync ^ VSync) : ypbpr ? ~(hs_sd ^ vs_sd) : ~hs_sd;
|
||||
|
||||
endmodule
|
32
rtl/old/aholme_6502.v
Normal file
32
rtl/old/aholme_6502.v
Normal file
@ -0,0 +1,32 @@
|
||||
module aholme_6502(
|
||||
input clk,
|
||||
input enable,
|
||||
input reset,
|
||||
output [15:0] ab,
|
||||
input [7:0] dbi,
|
||||
output [7:0] dbo,
|
||||
output we,
|
||||
input irq,
|
||||
input nmi,
|
||||
input ready
|
||||
);
|
||||
|
||||
wire we_c;
|
||||
|
||||
chip_6502 aholme_cpu (
|
||||
.clk(clk),
|
||||
.phi(clk & enable),
|
||||
.res(~reset),
|
||||
.so(1'b0),
|
||||
.rdy(ready),
|
||||
.nmi(nmi_n),
|
||||
.irq(irq_n),
|
||||
.rw(we_c),
|
||||
.dbi(dbi),
|
||||
.dbo(dbo),
|
||||
.ab(ab)
|
||||
);
|
||||
|
||||
assign we = ~we_c;
|
||||
|
||||
endmodule
|
122
rtl/old/tm1638.v
Normal file
122
rtl/old/tm1638.v
Normal file
@ -0,0 +1,122 @@
|
||||
module tm1638(
|
||||
input clk,
|
||||
input clk_en,
|
||||
input rst,
|
||||
|
||||
input data_latch,
|
||||
inout [7:0] data,
|
||||
input rw,
|
||||
|
||||
output busy,
|
||||
|
||||
output sclk,
|
||||
input dio_in,
|
||||
output reg dio_out
|
||||
);
|
||||
|
||||
localparam CLK_DIV = 3; // seems happy at 12MHz with 3
|
||||
localparam CLK_DIV1 = CLK_DIV - 1;
|
||||
localparam [1:0]
|
||||
S_IDLE = 2'h0,
|
||||
S_WAIT = 2'h1,
|
||||
S_TRANSFER = 2'h2;
|
||||
|
||||
reg [1:0] cur_state, next_state;
|
||||
reg [CLK_DIV1:0] sclk_d, sclk_q;
|
||||
reg [7:0] data_d, data_q, data_out_d, data_out_q;
|
||||
reg dio_out_d;
|
||||
reg [2:0] ctr_d, ctr_q;
|
||||
|
||||
// output read data if we're reading
|
||||
assign data = rw ? 8'hZZ : data_out_q;
|
||||
|
||||
// we're busy if we're not idle
|
||||
assign busy = cur_state != S_IDLE;
|
||||
|
||||
// tick the clock if we're transfering data
|
||||
assign sclk = ~((~sclk_q[CLK_DIV1]) & (cur_state == S_TRANSFER));
|
||||
|
||||
always @(*)
|
||||
begin
|
||||
sclk_d = sclk_q;
|
||||
data_d = data_q;
|
||||
dio_out_d = dio_out;
|
||||
ctr_d = ctr_q;
|
||||
data_out_d = data_out_q;
|
||||
next_state = cur_state;
|
||||
|
||||
case(cur_state)
|
||||
S_IDLE: begin
|
||||
sclk_d = 0;
|
||||
if (data_latch) begin
|
||||
// if we're reading, set to zero, otherwise latch in
|
||||
// data to send
|
||||
data_d = rw ? data : 8'b0;
|
||||
next_state = S_WAIT;
|
||||
end
|
||||
end
|
||||
|
||||
S_WAIT: begin
|
||||
sclk_d = sclk_q + 1;
|
||||
// wait till we're halfway into clock pulse
|
||||
if (sclk_q == {1'b0, {CLK_DIV1{1'b1}}}) begin
|
||||
sclk_d = 0;
|
||||
next_state = S_TRANSFER;
|
||||
end
|
||||
end
|
||||
|
||||
S_TRANSFER: begin
|
||||
sclk_d = sclk_q + 1;
|
||||
if (sclk_q == 0) begin
|
||||
// start of clock pulse, output MSB
|
||||
dio_out_d = data_q[0];
|
||||
|
||||
end else if (sclk_q == {1'b0, {CLK_DIV1{1'b1}}}) begin
|
||||
// halfway through pulse, read from device
|
||||
data_d = {dio_in, data_q[7:1]};
|
||||
|
||||
end else if (&sclk_q) begin
|
||||
// end of pulse, tick the counter
|
||||
ctr_d = ctr_q + 1;
|
||||
|
||||
if (&ctr_q) begin
|
||||
// last bit sent, switch back to idle
|
||||
// and output any data recieved
|
||||
next_state = S_IDLE;
|
||||
data_out_d = data_q;
|
||||
|
||||
dio_out_d = 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
default:
|
||||
next_state = S_IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (clk_en)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
cur_state <= S_IDLE;
|
||||
sclk_q <= 0;
|
||||
ctr_q <= 0;
|
||||
dio_out <= 0;
|
||||
data_q <= 0;
|
||||
data_out_q <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
cur_state <= next_state;
|
||||
sclk_q <= sclk_d;
|
||||
ctr_q <= ctr_d;
|
||||
dio_out <= dio_out_d;
|
||||
data_q <= data_d;
|
||||
data_out_q <= data_out_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
4
rtl/pll.qip
Normal file
4
rtl/pll.qip
Normal file
@ -0,0 +1,4 @@
|
||||
set_global_assignment -name IP_TOOL_NAME "ALTPLL"
|
||||
set_global_assignment -name IP_TOOL_VERSION "13.1"
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"]
|
||||
set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"]
|
348
rtl/pll.v
Normal file
348
rtl/pll.v
Normal file
@ -0,0 +1,348 @@
|
||||
// megafunction wizard: %ALTPLL%
|
||||
// GENERATION: STANDARD
|
||||
// VERSION: WM1.0
|
||||
// MODULE: altpll
|
||||
|
||||
// ============================================================
|
||||
// File Name: pll.v
|
||||
// Megafunction Name(s):
|
||||
// altpll
|
||||
//
|
||||
// Simulation Library Files(s):
|
||||
// altera_mf
|
||||
// ============================================================
|
||||
// ************************************************************
|
||||
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
|
||||
//
|
||||
// 13.1.4 Build 182 03/12/2014 SJ Web Edition
|
||||
// ************************************************************
|
||||
|
||||
|
||||
//Copyright (C) 1991-2014 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.
|
||||
|
||||
|
||||
// synopsys translate_off
|
||||
`timescale 1 ps / 1 ps
|
||||
// synopsys translate_on
|
||||
module pll (
|
||||
areset,
|
||||
inclk0,
|
||||
c0,
|
||||
c1,
|
||||
locked);
|
||||
|
||||
input areset;
|
||||
input inclk0;
|
||||
output c0;
|
||||
output c1;
|
||||
output locked;
|
||||
`ifndef ALTERA_RESERVED_QIS
|
||||
// synopsys translate_off
|
||||
`endif
|
||||
tri0 areset;
|
||||
`ifndef ALTERA_RESERVED_QIS
|
||||
// synopsys translate_on
|
||||
`endif
|
||||
|
||||
wire [4:0] sub_wire0;
|
||||
wire sub_wire2;
|
||||
wire [0:0] sub_wire6 = 1'h0;
|
||||
wire [0:0] sub_wire3 = sub_wire0[0:0];
|
||||
wire [1:1] sub_wire1 = sub_wire0[1:1];
|
||||
wire c1 = sub_wire1;
|
||||
wire locked = sub_wire2;
|
||||
wire c0 = sub_wire3;
|
||||
wire sub_wire4 = inclk0;
|
||||
wire [1:0] sub_wire5 = {sub_wire6, sub_wire4};
|
||||
|
||||
altpll altpll_component (
|
||||
.areset (areset),
|
||||
.inclk (sub_wire5),
|
||||
.clk (sub_wire0),
|
||||
.locked (sub_wire2),
|
||||
.activeclock (),
|
||||
.clkbad (),
|
||||
.clkena ({6{1'b1}}),
|
||||
.clkloss (),
|
||||
.clkswitch (1'b0),
|
||||
.configupdate (1'b0),
|
||||
.enable0 (),
|
||||
.enable1 (),
|
||||
.extclk (),
|
||||
.extclkena ({4{1'b1}}),
|
||||
.fbin (1'b1),
|
||||
.fbmimicbidir (),
|
||||
.fbout (),
|
||||
.fref (),
|
||||
.icdrclk (),
|
||||
.pfdena (1'b1),
|
||||
.phasecounterselect ({4{1'b1}}),
|
||||
.phasedone (),
|
||||
.phasestep (1'b1),
|
||||
.phaseupdown (1'b1),
|
||||
.pllena (1'b1),
|
||||
.scanaclr (1'b0),
|
||||
.scanclk (1'b0),
|
||||
.scanclkena (1'b1),
|
||||
.scandata (1'b0),
|
||||
.scandataout (),
|
||||
.scandone (),
|
||||
.scanread (1'b0),
|
||||
.scanwrite (1'b0),
|
||||
.sclkout0 (),
|
||||
.sclkout1 (),
|
||||
.vcooverrange (),
|
||||
.vcounderrange ());
|
||||
defparam
|
||||
altpll_component.bandwidth_type = "AUTO",
|
||||
altpll_component.clk0_divide_by = 675000,
|
||||
altpll_component.clk0_duty_cycle = 50,
|
||||
altpll_component.clk0_multiply_by = 715909,
|
||||
altpll_component.clk0_phase_shift = "0",
|
||||
altpll_component.clk1_divide_by = 1350000,
|
||||
altpll_component.clk1_duty_cycle = 50,
|
||||
altpll_component.clk1_multiply_by = 715909,
|
||||
altpll_component.clk1_phase_shift = "0",
|
||||
altpll_component.compensate_clock = "CLK0",
|
||||
altpll_component.inclk0_input_frequency = 37037,
|
||||
altpll_component.intended_device_family = "Cyclone III",
|
||||
altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll",
|
||||
altpll_component.lpm_type = "altpll",
|
||||
altpll_component.operation_mode = "NORMAL",
|
||||
altpll_component.pll_type = "AUTO",
|
||||
altpll_component.port_activeclock = "PORT_UNUSED",
|
||||
altpll_component.port_areset = "PORT_USED",
|
||||
altpll_component.port_clkbad0 = "PORT_UNUSED",
|
||||
altpll_component.port_clkbad1 = "PORT_UNUSED",
|
||||
altpll_component.port_clkloss = "PORT_UNUSED",
|
||||
altpll_component.port_clkswitch = "PORT_UNUSED",
|
||||
altpll_component.port_configupdate = "PORT_UNUSED",
|
||||
altpll_component.port_fbin = "PORT_UNUSED",
|
||||
altpll_component.port_inclk0 = "PORT_USED",
|
||||
altpll_component.port_inclk1 = "PORT_UNUSED",
|
||||
altpll_component.port_locked = "PORT_USED",
|
||||
altpll_component.port_pfdena = "PORT_UNUSED",
|
||||
altpll_component.port_phasecounterselect = "PORT_UNUSED",
|
||||
altpll_component.port_phasedone = "PORT_UNUSED",
|
||||
altpll_component.port_phasestep = "PORT_UNUSED",
|
||||
altpll_component.port_phaseupdown = "PORT_UNUSED",
|
||||
altpll_component.port_pllena = "PORT_UNUSED",
|
||||
altpll_component.port_scanaclr = "PORT_UNUSED",
|
||||
altpll_component.port_scanclk = "PORT_UNUSED",
|
||||
altpll_component.port_scanclkena = "PORT_UNUSED",
|
||||
altpll_component.port_scandata = "PORT_UNUSED",
|
||||
altpll_component.port_scandataout = "PORT_UNUSED",
|
||||
altpll_component.port_scandone = "PORT_UNUSED",
|
||||
altpll_component.port_scanread = "PORT_UNUSED",
|
||||
altpll_component.port_scanwrite = "PORT_UNUSED",
|
||||
altpll_component.port_clk0 = "PORT_USED",
|
||||
altpll_component.port_clk1 = "PORT_USED",
|
||||
altpll_component.port_clk2 = "PORT_UNUSED",
|
||||
altpll_component.port_clk3 = "PORT_UNUSED",
|
||||
altpll_component.port_clk4 = "PORT_UNUSED",
|
||||
altpll_component.port_clk5 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena0 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena1 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena2 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena3 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena4 = "PORT_UNUSED",
|
||||
altpll_component.port_clkena5 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk0 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk1 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk2 = "PORT_UNUSED",
|
||||
altpll_component.port_extclk3 = "PORT_UNUSED",
|
||||
altpll_component.self_reset_on_loss_lock = "OFF",
|
||||
altpll_component.width_clock = 5;
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
// ============================================================
|
||||
// CNX file retrieval info
|
||||
// ============================================================
|
||||
// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000"
|
||||
// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1"
|
||||
// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz"
|
||||
// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low"
|
||||
// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1"
|
||||
// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0"
|
||||
// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0"
|
||||
// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0"
|
||||
// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0"
|
||||
// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8"
|
||||
// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "108"
|
||||
// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "27"
|
||||
// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
|
||||
// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000"
|
||||
// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "28.636360"
|
||||
// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "14.318180"
|
||||
// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0"
|
||||
// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0"
|
||||
// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1"
|
||||
// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0"
|
||||
// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575"
|
||||
// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1"
|
||||
// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000"
|
||||
// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz"
|
||||
// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000"
|
||||
// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1"
|
||||
// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1"
|
||||
// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz"
|
||||
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III"
|
||||
// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1"
|
||||
// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1"
|
||||
// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1"
|
||||
// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available"
|
||||
// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0"
|
||||
// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg"
|
||||
// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg"
|
||||
// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any"
|
||||
// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0"
|
||||
// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0"
|
||||
// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "25"
|
||||
// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "25"
|
||||
// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
|
||||
// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "28.63636000"
|
||||
// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "14.31818000"
|
||||
// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1"
|
||||
// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1"
|
||||
// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz"
|
||||
// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz"
|
||||
// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1"
|
||||
// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000"
|
||||
// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000"
|
||||
// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg"
|
||||
// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg"
|
||||
// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1"
|
||||
// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1"
|
||||
// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0"
|
||||
// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0"
|
||||
// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0"
|
||||
// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0"
|
||||
// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0"
|
||||
// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif"
|
||||
// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0"
|
||||
// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1"
|
||||
// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0"
|
||||
// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0"
|
||||
// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0"
|
||||
// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000"
|
||||
// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz"
|
||||
// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500"
|
||||
// Retrieval info: PRIVATE: SPREAD_USE STRING "0"
|
||||
// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0"
|
||||
// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1"
|
||||
// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1"
|
||||
// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1"
|
||||
// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1"
|
||||
// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
|
||||
// Retrieval info: PRIVATE: USE_CLK0 STRING "1"
|
||||
// Retrieval info: PRIVATE: USE_CLK1 STRING "1"
|
||||
// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0"
|
||||
// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0"
|
||||
// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0"
|
||||
// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0"
|
||||
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
|
||||
// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO"
|
||||
// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "675000"
|
||||
// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
|
||||
// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "715909"
|
||||
// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
|
||||
// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "1350000"
|
||||
// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50"
|
||||
// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "715909"
|
||||
// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0"
|
||||
// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0"
|
||||
// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037"
|
||||
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III"
|
||||
// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll"
|
||||
// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL"
|
||||
// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO"
|
||||
// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED"
|
||||
// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED"
|
||||
// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED"
|
||||
// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED"
|
||||
// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED"
|
||||
// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED"
|
||||
// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF"
|
||||
// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5"
|
||||
// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]"
|
||||
// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset"
|
||||
// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0"
|
||||
// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1"
|
||||
// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0"
|
||||
// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked"
|
||||
// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0
|
||||
// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0
|
||||
// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0
|
||||
// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0
|
||||
// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1
|
||||
// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE
|
||||
// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE
|
||||
// Retrieval info: LIB_FILE: altera_mf
|
||||
// Retrieval info: CBX_MODULE_PREFIX: ON
|
339
rtl/ps2keyboard.v
Normal file
339
rtl/ps2keyboard.v
Normal file
@ -0,0 +1,339 @@
|
||||
// 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 interface
|
||||
//
|
||||
// Author.....: Niels A. Moseley
|
||||
// Date.......: 28-1-2018
|
||||
//
|
||||
|
||||
module ps2keyboard (
|
||||
input clk14, // 25MHz clock
|
||||
input rst, // active high reset
|
||||
|
||||
// I/O interface to keyboard
|
||||
input key_clk, // clock input from keyboard / device
|
||||
input key_din, // data input from keyboard / device
|
||||
|
||||
// I/O interface to computer
|
||||
input cs, // chip select, active high
|
||||
input address, // =0 RX buffer, =1 RX status
|
||||
output reg [7:0] dout // 8-bit output bus.
|
||||
);
|
||||
|
||||
reg [3:0] rxcnt; // count how many bits have been shift into rxshiftbuf
|
||||
reg [10:0] rxshiftbuf; // 11 bit shift receive register
|
||||
reg rx_flag = 0; // this flag is 1 when
|
||||
// valid data is available in rxshiftbuf
|
||||
|
||||
reg [7:0] rx; // scancode receive buffer
|
||||
|
||||
// wire ps2_clkdb; // debounced PS/2 clock signal
|
||||
reg prev_ps2_clkdb; // previous clock state (in clk14 domain)
|
||||
|
||||
// keyboard translation signals
|
||||
reg [7:0] ascii; // ASCII code of received character
|
||||
reg ascii_rdy; // new ASCII character received
|
||||
reg shift; // state of the shift key
|
||||
reg [2:0] cur_state;
|
||||
reg [2:0] next_state;
|
||||
|
||||
// debounce ps2clk_debounce
|
||||
// (
|
||||
// .clk14(clk14),
|
||||
// .rst(rst),
|
||||
// .sig_in(key_clk),
|
||||
// .sig_out(ps2_clkdb)
|
||||
// );
|
||||
|
||||
always @(posedge clk14 or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
prev_ps2_clkdb <= 1'b0;
|
||||
rx_flag <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
rx_flag <= 1'b0; // reset the new data flag register
|
||||
|
||||
// check for negative edge of PS/2 clock
|
||||
// and sample the state of the PS/2 data line
|
||||
if ((prev_ps2_clkdb == 1'b1) && (key_clk == 1'b0))//(ps2_clkdb == 1'b0))
|
||||
begin
|
||||
rxshiftbuf <= {key_din, rxshiftbuf[10:1]};
|
||||
rxcnt <= rxcnt + 4'b1;
|
||||
if (rxcnt == 4'd10)
|
||||
begin
|
||||
// 10 bits have been shifted in
|
||||
// we should have a complete
|
||||
// scan code here, including
|
||||
// start, parity and stop bits.
|
||||
rxcnt <= 0;
|
||||
|
||||
// signal new data is present
|
||||
// note: this signal will only remain high for one
|
||||
// clock cycle!
|
||||
//
|
||||
// TODO: check parity here?
|
||||
rx_flag <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// update previous clock state
|
||||
prev_ps2_clkdb <= key_clk;//ps2_clkdb;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
//
|
||||
// IBM Keyboard code page translation
|
||||
// state machine for US keyboard layout
|
||||
//
|
||||
// http://www.computer-engineering.org/ps2keyboard/scancodes2.html
|
||||
//
|
||||
|
||||
localparam S_KEYNORMAL = 3'b000;
|
||||
localparam S_KEYF0 = 3'b001; // regular key release state
|
||||
localparam S_KEYE0 = 3'b010; // extended key state
|
||||
localparam S_KEYE0F0 = 3'b011; // extended release state
|
||||
|
||||
always @(posedge clk14 or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
rx <= 0;
|
||||
ascii_rdy <= 0;
|
||||
shift <= 0;
|
||||
cur_state <= S_KEYNORMAL;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// handle I/O from CPU
|
||||
if (cs == 1'b1)
|
||||
begin
|
||||
if (address == 1'b0)
|
||||
begin
|
||||
// RX buffer address
|
||||
dout <= {1'b1, ascii[6:0]};
|
||||
ascii_rdy <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// RX status register
|
||||
dout <= {ascii_rdy, 7'b0};
|
||||
end
|
||||
end
|
||||
|
||||
// keyboard translation state machine
|
||||
if (rx_flag == 1'b1)
|
||||
begin
|
||||
// latch data from the serial buffer into
|
||||
// the rx scancode buffer.
|
||||
rx <= rxshiftbuf[8:1];
|
||||
case(cur_state)
|
||||
S_KEYNORMAL:
|
||||
begin
|
||||
if (rx == 8'hF0)
|
||||
next_state = S_KEYF0;
|
||||
else if (rx == 8'hE0)
|
||||
next_state = S_KEYE0;
|
||||
else
|
||||
begin
|
||||
// check the debounce timer, if this is
|
||||
// not zero, a new key arrived too quickly
|
||||
// and we simply discard it. For better
|
||||
// debouncing, we should check if the key
|
||||
// is actually the same as the previous received/
|
||||
// key, but let's try this first to see if it works
|
||||
// ok...
|
||||
|
||||
//if (debounce_timer == 16'd0)
|
||||
//begin
|
||||
ascii_rdy <= 1'b1; // new key has arrived!
|
||||
//debounce_timer <= 16'hFFFF; // reset the debounce timer
|
||||
//end
|
||||
|
||||
// check for a SHIFT key
|
||||
if ((rx == 8'h59) || (rx == 8'h12))
|
||||
begin
|
||||
shift <= 1'b1;
|
||||
ascii_rdy <= 1'b0; // shift is not a key!
|
||||
end
|
||||
else begin
|
||||
if (!shift)
|
||||
case(rx)
|
||||
8'h1C: ascii <= "A";
|
||||
8'h32: ascii <= "B";
|
||||
8'h21: ascii <= "C";
|
||||
8'h23: ascii <= "D";
|
||||
8'h24: ascii <= "E";
|
||||
8'h2B: ascii <= "F";
|
||||
8'h34: ascii <= "G";
|
||||
8'h33: ascii <= "H";
|
||||
8'h43: ascii <= "I";
|
||||
8'h3B: ascii <= "J";
|
||||
8'h42: ascii <= "K";
|
||||
8'h4B: ascii <= "L";
|
||||
8'h3A: ascii <= "M";
|
||||
8'h31: ascii <= "N";
|
||||
8'h44: ascii <= "O";
|
||||
8'h4D: ascii <= "P";
|
||||
8'h15: ascii <= "Q";
|
||||
8'h2D: ascii <= "R";
|
||||
8'h1B: ascii <= "S";
|
||||
8'h2C: ascii <= "T";
|
||||
8'h3C: ascii <= "U";
|
||||
8'h2A: ascii <= "V";
|
||||
8'h1D: ascii <= "W";
|
||||
8'h22: ascii <= "X";
|
||||
8'h35: ascii <= "Y";
|
||||
8'h1A: ascii <= "Z";
|
||||
|
||||
8'h45: ascii <= "0";
|
||||
8'h16: ascii <= "1";
|
||||
8'h1E: ascii <= "2";
|
||||
8'h26: ascii <= "3";
|
||||
8'h25: ascii <= "4";
|
||||
8'h2E: ascii <= "5";
|
||||
8'h36: ascii <= "6";
|
||||
8'h3D: ascii <= "7";
|
||||
8'h3E: ascii <= "8";
|
||||
8'h46: ascii <= "9";
|
||||
|
||||
8'h4E: ascii <= "-";
|
||||
8'h55: ascii <= "=";
|
||||
8'h5D: ascii <= 8'h34; // backslash
|
||||
8'h66: ascii <= 8'd8; // backspace
|
||||
8'h29: ascii <= " ";
|
||||
|
||||
8'h5A: ascii <= 8'd13; // enter
|
||||
8'h54: ascii <= "[";
|
||||
8'h5B: ascii <= "]";
|
||||
8'h4C: ascii <= ";";
|
||||
8'h52: ascii <= "'";
|
||||
8'h41: ascii <= ",";
|
||||
8'h49: ascii <= ".";
|
||||
8'h4A: ascii <= "/";
|
||||
default:
|
||||
// unsupported key!
|
||||
begin
|
||||
ascii_rdy <= 1'b0; // shift is not a key!
|
||||
ascii <= " ";
|
||||
end
|
||||
endcase
|
||||
else
|
||||
// Here, we're in a shifted state
|
||||
case(rx)
|
||||
8'h1C: ascii <= "A";
|
||||
8'h32: ascii <= "B";
|
||||
8'h21: ascii <= "C";
|
||||
8'h23: ascii <= "D";
|
||||
8'h24: ascii <= "E";
|
||||
8'h2B: ascii <= "F";
|
||||
8'h34: ascii <= "G";
|
||||
8'h33: ascii <= "H";
|
||||
8'h43: ascii <= "I";
|
||||
8'h3B: ascii <= "J";
|
||||
8'h42: ascii <= "K";
|
||||
8'h4B: ascii <= "L";
|
||||
8'h3A: ascii <= "M";
|
||||
8'h31: ascii <= "N";
|
||||
8'h44: ascii <= "O";
|
||||
8'h4D: ascii <= "P";
|
||||
8'h15: ascii <= "Q";
|
||||
8'h2D: ascii <= "R";
|
||||
8'h1B: ascii <= "S";
|
||||
8'h2C: ascii <= "T";
|
||||
8'h3C: ascii <= "U";
|
||||
8'h2A: ascii <= "V";
|
||||
8'h1D: ascii <= "W";
|
||||
8'h22: ascii <= "X";
|
||||
8'h35: ascii <= "Y";
|
||||
8'h1A: ascii <= "Z";
|
||||
|
||||
8'h45: ascii <= ")";
|
||||
8'h16: ascii <= "!";
|
||||
8'h1E: ascii <= "@";
|
||||
8'h26: ascii <= "#";
|
||||
8'h25: ascii <= "$";
|
||||
8'h2E: ascii <= "%";
|
||||
8'h36: ascii <= "^";
|
||||
8'h3D: ascii <= "&";
|
||||
8'h3E: ascii <= "*";
|
||||
8'h46: ascii <= "(";
|
||||
|
||||
8'h4E: ascii <= "_";
|
||||
8'h55: ascii <= "+";
|
||||
8'h5D: ascii <= "|";
|
||||
8'h66: ascii <= 8'd8; // backspace
|
||||
8'h29: ascii <= " ";
|
||||
|
||||
8'h5A: ascii <= 8'd13; // enter
|
||||
8'h54: ascii <= "{";
|
||||
8'h5B: ascii <= "}";
|
||||
8'h4C: ascii <= ":";
|
||||
8'h52: ascii <= "\"";
|
||||
8'h41: ascii <= "<";
|
||||
8'h49: ascii <= ">";
|
||||
8'h4A: ascii <= "?";
|
||||
default:
|
||||
// unsupported key!
|
||||
begin
|
||||
ascii_rdy <= 1'b0; // shift is not a key!
|
||||
ascii <= " ";
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
S_KEYF0:
|
||||
// when we end up here, a 0xF0 byte was received
|
||||
// which usually means a key release event
|
||||
begin
|
||||
if ((rx == 8'h59) || (rx == 8'h12))
|
||||
shift <= 1'b0;
|
||||
next_state = S_KEYNORMAL;
|
||||
end
|
||||
S_KEYE0:
|
||||
begin
|
||||
if (rx == 8'hF0)
|
||||
next_state = S_KEYE0F0;
|
||||
else
|
||||
next_state = S_KEYNORMAL;
|
||||
end
|
||||
S_KEYE0F0:
|
||||
begin
|
||||
next_state = S_KEYNORMAL;
|
||||
end
|
||||
default:
|
||||
begin
|
||||
next_state = S_KEYNORMAL;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
else
|
||||
begin
|
||||
next_state = cur_state; // deliberate blocking assingment!
|
||||
end
|
||||
|
||||
cur_state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
55
rtl/pwr_reset.v
Normal file
55
rtl/pwr_reset.v
Normal 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 pwr_reset(
|
||||
input clk14, // 14Mhz master clock
|
||||
input rst_n, // active low synchronous reset
|
||||
input enable, // clock enable
|
||||
output rst // active high synchronous system reset
|
||||
);
|
||||
|
||||
reg hard_reset;
|
||||
reg [5:0] reset_cnt;
|
||||
wire pwr_up_flag = &reset_cnt;
|
||||
|
||||
always @(posedge clk14)
|
||||
begin
|
||||
if (rst_n == 1'b0)
|
||||
begin
|
||||
reset_cnt <= 6'b0;
|
||||
hard_reset <= 1'b0;
|
||||
end
|
||||
else if (enable)
|
||||
begin
|
||||
if (!pwr_up_flag)
|
||||
reset_cnt <= reset_cnt + 6'b1;
|
||||
|
||||
hard_reset <= pwr_up_flag;
|
||||
end
|
||||
end
|
||||
|
||||
assign rst = ~hard_reset;
|
||||
|
||||
endmodule
|
45
rtl/ram.v
Normal file
45
rtl/ram.v
Normal file
@ -0,0 +1,45 @@
|
||||
// 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: 8KB RAM for system
|
||||
//
|
||||
// Author.....: Alan Garfield
|
||||
// Niels A. Moseley
|
||||
// Date.......: 26-1-2018
|
||||
//
|
||||
|
||||
module ram (
|
||||
input clk, // clock signal
|
||||
input [12:0] address, // address bus
|
||||
input w_en, // active high write enable strobe
|
||||
input [7:0] din, // 8-bit data bus (input)
|
||||
output reg [7:0] dout // 8-bit data bus (output)
|
||||
);
|
||||
|
||||
reg [7:0] ram_data[0:8191];
|
||||
|
||||
initial
|
||||
$readmemh("roms/ram.hex", ram_data, 0, 8191);
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
dout <= ram_data[address];
|
||||
if (w_en) ram_data[address] <= din;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
39
rtl/rom_basic.v
Normal file
39
rtl/rom_basic.v
Normal file
@ -0,0 +1,39 @@
|
||||
// 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: Wrapper for Apple Integer Basic ROM
|
||||
//
|
||||
// Author.....: Alan Garfield
|
||||
// Niels A. Moseley
|
||||
// Date.......: 26-1-2018
|
||||
//
|
||||
|
||||
module rom_basic (
|
||||
input clk, // clock signal
|
||||
input [11:0] address, // address bus
|
||||
output reg [7:0] dout // 8-bit data bus (output)
|
||||
);
|
||||
|
||||
reg [7:0] rom_data[0:4095];
|
||||
|
||||
initial
|
||||
$readmemh("roms/basic.hex", rom_data, 0, 4095);
|
||||
|
||||
always @(posedge clk)
|
||||
dout <= rom_data[address];
|
||||
|
||||
endmodule
|
41
rtl/rom_wozmon.v
Normal file
41
rtl/rom_wozmon.v
Normal file
@ -0,0 +1,41 @@
|
||||
// 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: Wrapper for the Woz Mon ROM
|
||||
//
|
||||
// Author.....: Alan Garfield
|
||||
// Niels A. Moseley
|
||||
// Date.......: 26-1-2018
|
||||
//
|
||||
|
||||
module rom_wozmon (
|
||||
input clk, // clock signal
|
||||
input [7:0] address, // address bus
|
||||
output reg [7:0] dout // 8-bit data bus (output)
|
||||
);
|
||||
|
||||
reg [7:0] rom_data[0:255];
|
||||
|
||||
initial
|
||||
$readmemh("roms/wozmon.hex", rom_data, 0, 255);
|
||||
|
||||
always @(posedge clk)
|
||||
dout <= rom_data[address];
|
||||
|
||||
endmodule
|
||||
|
||||
|
4096
rtl/roms/basic.hex
Normal file
4096
rtl/roms/basic.hex
Normal file
File diff suppressed because it is too large
Load Diff
8192
rtl/roms/ram.hex
Normal file
8192
rtl/roms/ram.hex
Normal file
File diff suppressed because it is too large
Load Diff
703
rtl/roms/vga_font.bin
Normal file
703
rtl/roms/vga_font.bin
Normal file
@ -0,0 +1,703 @@
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01010100
|
||||
01011100
|
||||
01011000
|
||||
01000000
|
||||
00111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00101000
|
||||
01000100
|
||||
01000100
|
||||
01111100
|
||||
01000100
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111000
|
||||
01000100
|
||||
01000100
|
||||
01111000
|
||||
01000100
|
||||
01000100
|
||||
01111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
01000000
|
||||
01000000
|
||||
01111000
|
||||
01000000
|
||||
01000000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
01000000
|
||||
01000000
|
||||
01111000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111100
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
01001100
|
||||
01000100
|
||||
00111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01111100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000100
|
||||
00000100
|
||||
00000100
|
||||
00000100
|
||||
00000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01001000
|
||||
01010000
|
||||
01100000
|
||||
01010000
|
||||
01001000
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01101100
|
||||
01010100
|
||||
01010100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
01100100
|
||||
01010100
|
||||
01001100
|
||||
01000100
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111000
|
||||
01000100
|
||||
01000100
|
||||
01111000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01010100
|
||||
01001000
|
||||
00110100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111000
|
||||
01000100
|
||||
01000100
|
||||
01111000
|
||||
01010000
|
||||
01001000
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01000000
|
||||
00111000
|
||||
00000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
00101000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
01000100
|
||||
01010100
|
||||
01010100
|
||||
01101100
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
00101000
|
||||
00010000
|
||||
00101000
|
||||
01000100
|
||||
01000100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01000100
|
||||
01000100
|
||||
00101000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00000100
|
||||
00001000
|
||||
00010000
|
||||
00100000
|
||||
01000000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
01100000
|
||||
01100000
|
||||
01100000
|
||||
01100000
|
||||
01100000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
01000000
|
||||
00100000
|
||||
00010000
|
||||
00001000
|
||||
00000100
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00001100
|
||||
00001100
|
||||
00001100
|
||||
00001100
|
||||
00001100
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00101000
|
||||
01000100
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00000000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00101000
|
||||
00101000
|
||||
00101000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00101000
|
||||
00101000
|
||||
01111100
|
||||
00101000
|
||||
01111100
|
||||
00101000
|
||||
00101000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00111100
|
||||
01010000
|
||||
00111000
|
||||
00010100
|
||||
01111000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01100000
|
||||
01100100
|
||||
00001000
|
||||
00010000
|
||||
00100000
|
||||
01001100
|
||||
00001100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00100000
|
||||
01010000
|
||||
01010000
|
||||
00100000
|
||||
01010100
|
||||
01001000
|
||||
00110100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00100000
|
||||
01000000
|
||||
01000000
|
||||
01000000
|
||||
00100000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00001000
|
||||
00000100
|
||||
00000100
|
||||
00000100
|
||||
00001000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
01010100
|
||||
00111000
|
||||
00010000
|
||||
00111000
|
||||
01010100
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00010000
|
||||
01111100
|
||||
00010000
|
||||
00010000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00010000
|
||||
00100000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000100
|
||||
00001000
|
||||
00010000
|
||||
00100000
|
||||
01000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01001100
|
||||
01010100
|
||||
01100100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00110000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
00010000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
00000100
|
||||
00011000
|
||||
00100000
|
||||
01000000
|
||||
01111100
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00000100
|
||||
00001000
|
||||
00011000
|
||||
00000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00001000
|
||||
00011000
|
||||
00101000
|
||||
01001000
|
||||
01111100
|
||||
00001000
|
||||
00001000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
01000000
|
||||
01111000
|
||||
00000100
|
||||
00000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00011100
|
||||
00100000
|
||||
01000000
|
||||
01111000
|
||||
01000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00000100
|
||||
00001000
|
||||
00010000
|
||||
00100000
|
||||
00100000
|
||||
00100000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01000100
|
||||
00111000
|
||||
01000100
|
||||
01000100
|
||||
00111000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
01000100
|
||||
00111100
|
||||
00000100
|
||||
00001000
|
||||
01110000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00000000
|
||||
00010000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00010000
|
||||
00000000
|
||||
00010000
|
||||
00010000
|
||||
00100000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00001000
|
||||
00010000
|
||||
00100000
|
||||
01000000
|
||||
00100000
|
||||
00010000
|
||||
00001000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
01111100
|
||||
00000000
|
||||
01111100
|
||||
00000000
|
||||
00000000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00100000
|
||||
00010000
|
||||
00001000
|
||||
00000100
|
||||
00001000
|
||||
00010000
|
||||
00100000
|
||||
00000000
|
||||
|
||||
00000000
|
||||
00000000
|
||||
00111000
|
||||
01000100
|
||||
00001000
|
||||
00010000
|
||||
00010000
|
||||
00000000
|
||||
00010000
|
||||
00000000
|
640
rtl/roms/vga_font.hex
Normal file
640
rtl/roms/vga_font.hex
Normal file
@ -0,0 +1,640 @@
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
54
|
||||
5C
|
||||
58
|
||||
40
|
||||
3C
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
28
|
||||
44
|
||||
44
|
||||
7C
|
||||
44
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
78
|
||||
44
|
||||
44
|
||||
78
|
||||
44
|
||||
44
|
||||
78
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
40
|
||||
40
|
||||
40
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
78
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
78
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
40
|
||||
40
|
||||
78
|
||||
40
|
||||
40
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
40
|
||||
40
|
||||
78
|
||||
40
|
||||
40
|
||||
40
|
||||
00
|
||||
00
|
||||
00
|
||||
3C
|
||||
40
|
||||
40
|
||||
40
|
||||
4C
|
||||
44
|
||||
3C
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
44
|
||||
7C
|
||||
44
|
||||
44
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
04
|
||||
04
|
||||
04
|
||||
04
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
48
|
||||
50
|
||||
60
|
||||
50
|
||||
48
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
40
|
||||
40
|
||||
40
|
||||
40
|
||||
40
|
||||
40
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
6C
|
||||
54
|
||||
54
|
||||
44
|
||||
44
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
64
|
||||
54
|
||||
4C
|
||||
44
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
78
|
||||
44
|
||||
44
|
||||
78
|
||||
40
|
||||
40
|
||||
40
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
44
|
||||
44
|
||||
54
|
||||
48
|
||||
34
|
||||
00
|
||||
00
|
||||
00
|
||||
78
|
||||
44
|
||||
44
|
||||
78
|
||||
50
|
||||
48
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
40
|
||||
38
|
||||
04
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
44
|
||||
28
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
44
|
||||
54
|
||||
54
|
||||
6C
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
28
|
||||
10
|
||||
28
|
||||
44
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
44
|
||||
44
|
||||
28
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
04
|
||||
08
|
||||
10
|
||||
20
|
||||
40
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
60
|
||||
60
|
||||
60
|
||||
60
|
||||
60
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
40
|
||||
20
|
||||
10
|
||||
08
|
||||
04
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
0C
|
||||
0C
|
||||
0C
|
||||
0C
|
||||
0C
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
28
|
||||
44
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
28
|
||||
28
|
||||
28
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
28
|
||||
28
|
||||
7C
|
||||
28
|
||||
7C
|
||||
28
|
||||
28
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
3C
|
||||
50
|
||||
38
|
||||
14
|
||||
78
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
60
|
||||
64
|
||||
08
|
||||
10
|
||||
20
|
||||
4C
|
||||
0C
|
||||
00
|
||||
00
|
||||
00
|
||||
20
|
||||
50
|
||||
50
|
||||
20
|
||||
54
|
||||
48
|
||||
34
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
10
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
20
|
||||
40
|
||||
40
|
||||
40
|
||||
20
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
08
|
||||
04
|
||||
04
|
||||
04
|
||||
08
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
54
|
||||
38
|
||||
10
|
||||
38
|
||||
54
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
10
|
||||
7C
|
||||
10
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
10
|
||||
20
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
08
|
||||
10
|
||||
20
|
||||
40
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
4C
|
||||
54
|
||||
64
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
30
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
04
|
||||
18
|
||||
20
|
||||
40
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
04
|
||||
08
|
||||
18
|
||||
04
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
08
|
||||
18
|
||||
28
|
||||
48
|
||||
7C
|
||||
08
|
||||
08
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
40
|
||||
78
|
||||
04
|
||||
04
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
1C
|
||||
20
|
||||
40
|
||||
78
|
||||
44
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
04
|
||||
08
|
||||
10
|
||||
20
|
||||
20
|
||||
20
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
44
|
||||
38
|
||||
44
|
||||
44
|
||||
38
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
44
|
||||
3C
|
||||
04
|
||||
08
|
||||
70
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
10
|
||||
10
|
||||
20
|
||||
00
|
||||
00
|
||||
00
|
||||
08
|
||||
10
|
||||
20
|
||||
40
|
||||
20
|
||||
10
|
||||
08
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
7C
|
||||
00
|
||||
7C
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
20
|
||||
10
|
||||
08
|
||||
04
|
||||
08
|
||||
10
|
||||
20
|
||||
00
|
||||
00
|
||||
00
|
||||
38
|
||||
44
|
||||
08
|
||||
10
|
||||
10
|
||||
00
|
||||
10
|
||||
00
|
1024
rtl/roms/vga_font_bitreversed.hex
Normal file
1024
rtl/roms/vga_font_bitreversed.hex
Normal file
File diff suppressed because it is too large
Load Diff
2048
rtl/roms/vga_vram.bin
Normal file
2048
rtl/roms/vga_vram.bin
Normal file
File diff suppressed because it is too large
Load Diff
256
rtl/roms/wozmon.hex
Normal file
256
rtl/roms/wozmon.hex
Normal file
@ -0,0 +1,256 @@
|
||||
D8
|
||||
58
|
||||
A0
|
||||
7F
|
||||
8C
|
||||
12
|
||||
D0
|
||||
A9
|
||||
A7
|
||||
8D
|
||||
11
|
||||
D0
|
||||
8D
|
||||
13
|
||||
D0
|
||||
C9
|
||||
DF
|
||||
F0
|
||||
13
|
||||
C9
|
||||
9B
|
||||
F0
|
||||
03
|
||||
C8
|
||||
10
|
||||
0F
|
||||
A9
|
||||
DC
|
||||
20
|
||||
EF
|
||||
FF
|
||||
A9
|
||||
8D
|
||||
20
|
||||
EF
|
||||
FF
|
||||
A0
|
||||
01
|
||||
88
|
||||
30
|
||||
F6
|
||||
AD
|
||||
11
|
||||
D0
|
||||
10
|
||||
FB
|
||||
AD
|
||||
10
|
||||
D0
|
||||
99
|
||||
00
|
||||
02
|
||||
20
|
||||
EF
|
||||
FF
|
||||
C9
|
||||
8D
|
||||
D0
|
||||
D4
|
||||
A0
|
||||
FF
|
||||
A9
|
||||
00
|
||||
AA
|
||||
0A
|
||||
85
|
||||
2B
|
||||
C8
|
||||
B9
|
||||
00
|
||||
02
|
||||
C9
|
||||
8D
|
||||
F0
|
||||
D4
|
||||
C9
|
||||
AE
|
||||
90
|
||||
F4
|
||||
F0
|
||||
F0
|
||||
C9
|
||||
BA
|
||||
F0
|
||||
EB
|
||||
C9
|
||||
D2
|
||||
F0
|
||||
3B
|
||||
86
|
||||
28
|
||||
86
|
||||
29
|
||||
84
|
||||
2A
|
||||
B9
|
||||
00
|
||||
02
|
||||
49
|
||||
B0
|
||||
C9
|
||||
0A
|
||||
90
|
||||
06
|
||||
69
|
||||
88
|
||||
C9
|
||||
FA
|
||||
90
|
||||
11
|
||||
0A
|
||||
0A
|
||||
0A
|
||||
0A
|
||||
A2
|
||||
04
|
||||
0A
|
||||
26
|
||||
28
|
||||
26
|
||||
29
|
||||
CA
|
||||
D0
|
||||
F8
|
||||
C8
|
||||
D0
|
||||
E0
|
||||
C4
|
||||
2A
|
||||
F0
|
||||
97
|
||||
24
|
||||
2B
|
||||
50
|
||||
10
|
||||
A5
|
||||
28
|
||||
81
|
||||
26
|
||||
E6
|
||||
26
|
||||
D0
|
||||
B5
|
||||
E6
|
||||
27
|
||||
4C
|
||||
44
|
||||
FF
|
||||
6C
|
||||
24
|
||||
00
|
||||
30
|
||||
2B
|
||||
A2
|
||||
02
|
||||
B5
|
||||
27
|
||||
95
|
||||
25
|
||||
95
|
||||
23
|
||||
CA
|
||||
D0
|
||||
F7
|
||||
D0
|
||||
14
|
||||
A9
|
||||
8D
|
||||
20
|
||||
EF
|
||||
FF
|
||||
A5
|
||||
25
|
||||
20
|
||||
DC
|
||||
FF
|
||||
A5
|
||||
24
|
||||
20
|
||||
DC
|
||||
FF
|
||||
A9
|
||||
BA
|
||||
20
|
||||
EF
|
||||
FF
|
||||
A9
|
||||
A0
|
||||
20
|
||||
EF
|
||||
FF
|
||||
A1
|
||||
24
|
||||
20
|
||||
DC
|
||||
FF
|
||||
86
|
||||
2B
|
||||
A5
|
||||
24
|
||||
C5
|
||||
28
|
||||
A5
|
||||
25
|
||||
E5
|
||||
29
|
||||
B0
|
||||
C1
|
||||
E6
|
||||
24
|
||||
D0
|
||||
02
|
||||
E6
|
||||
25
|
||||
A5
|
||||
24
|
||||
29
|
||||
07
|
||||
10
|
||||
C8
|
||||
48
|
||||
4A
|
||||
4A
|
||||
4A
|
||||
4A
|
||||
20
|
||||
E5
|
||||
FF
|
||||
68
|
||||
29
|
||||
0F
|
||||
09
|
||||
B0
|
||||
C9
|
||||
BA
|
||||
90
|
||||
02
|
||||
69
|
||||
06
|
||||
2C
|
||||
12
|
||||
D0
|
||||
30
|
||||
FB
|
||||
8D
|
||||
12
|
||||
D0
|
||||
60
|
||||
00
|
||||
00
|
||||
00
|
||||
0F
|
||||
00
|
||||
FF
|
||||
00
|
||||
00
|
169
rtl/uart.v
Normal file
169
rtl/uart.v
Normal file
@ -0,0 +1,169 @@
|
||||
// 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 the basic UART from fpga4fun.com
|
||||
//
|
||||
// Author.....: Alan Garfield
|
||||
// Niels A. Moseley
|
||||
// Date.......: 26-1-2018
|
||||
//
|
||||
|
||||
module uart(
|
||||
input clk, // clock signal
|
||||
input enable, // clock enable strobe
|
||||
input rst, // active high reset signal
|
||||
input [1:0] address, // address bus
|
||||
input w_en, // active high write enable strobe
|
||||
input [7:0] din, // 8-bit data bus (input)
|
||||
output reg [7:0] dout, // 8-bit data bus (output)
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
parameter ClkFrequency = 25000000; // 25MHz
|
||||
parameter Baud = 115200;
|
||||
parameter Oversampling = 16;
|
||||
|
||||
reg uart_tx_stb, uart_tx_init;
|
||||
reg [7:0] uart_tx_byte;
|
||||
wire uart_tx_status;
|
||||
|
||||
async_transmitter #(ClkFrequency, Baud) my_tx (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.TxD_start(uart_tx_stb),
|
||||
.TxD_data(uart_tx_byte),
|
||||
.TxD(uart_tx),
|
||||
.TxD_busy(uart_tx_status)
|
||||
);
|
||||
|
||||
wire uart_rx_stb, rx_idle, rx_end;
|
||||
wire [7:0] rx_data;
|
||||
reg uart_rx_status, uart_rx_ack;
|
||||
reg [7:0] uart_rx_byte;
|
||||
|
||||
async_receiver #(ClkFrequency, Baud, Oversampling) my_rx(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.RxD(uart_rx),
|
||||
.RxD_data_ready(uart_rx_stb),
|
||||
.RxD_data(rx_data),
|
||||
.RxD_idle(rx_idle),
|
||||
.RxD_endofpacket(rx_end)
|
||||
);
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
uart_rx_status <= 'b0;
|
||||
uart_rx_byte <= 8'd0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// new byte from RX, check register is clear and CPU has seen
|
||||
// previous byte, otherwise we ignore the new data
|
||||
if (uart_rx_stb && ~uart_rx_status)
|
||||
begin
|
||||
uart_rx_status <= 'b1;
|
||||
uart_rx_byte <= rx_data;
|
||||
end
|
||||
|
||||
// clear the rx status flag on ack from CPU
|
||||
if (uart_rx_ack)
|
||||
uart_rx_status <= 'b0;
|
||||
end
|
||||
end
|
||||
|
||||
assign uart_cts = ~rx_idle || uart_rx_status;
|
||||
|
||||
localparam UART_RX = 2'b00;
|
||||
localparam UART_RXCR = 2'b01;
|
||||
localparam UART_TX = 2'b10;
|
||||
localparam UART_TXCR = 2'b11;
|
||||
|
||||
// Handle Register
|
||||
always @(posedge clk or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
dout <= 8'd0;
|
||||
|
||||
uart_tx_init <= 0; // flag to ignore the DDR setup from Wozmon PIA call
|
||||
uart_tx_stb <= 0;
|
||||
uart_tx_byte <= 8'd0;
|
||||
uart_rx_ack <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
uart_tx_stb <= 0;
|
||||
uart_rx_ack <= 0;
|
||||
|
||||
case (address)
|
||||
|
||||
UART_RX:
|
||||
begin
|
||||
// UART RX - 0xD010
|
||||
// Bit b7 of KBD is permanently tied to high
|
||||
dout <= {1'b1, uart_rx_byte[6:0]};
|
||||
if (~w_en && ~uart_rx_ack && uart_rx_status && enable)
|
||||
uart_rx_ack <= 1'b1;
|
||||
end
|
||||
|
||||
UART_RXCR:
|
||||
begin
|
||||
// UART RX CR - 0xD011
|
||||
dout <= {uart_rx_status, 7'b0};
|
||||
end
|
||||
|
||||
UART_TX:
|
||||
begin
|
||||
// UART TX - 0xD012
|
||||
dout <= {uart_tx_status, 7'd0};
|
||||
|
||||
if (w_en)
|
||||
begin
|
||||
// Apple 1 terminal only uses 7 bits, MSB indicates
|
||||
// terminal has ack'd RX
|
||||
//
|
||||
// uart_tx_init is a flag to stop the first character
|
||||
// sent to the UART from being sent. Wozmon initializes
|
||||
// the PIA which normally isn't sent to the terminal.
|
||||
// This causes the UART to ignore the very first byte sent.
|
||||
if (~uart_tx_status && uart_tx_init)
|
||||
begin
|
||||
uart_tx_byte <= {1'b0, din[6:0]};
|
||||
uart_tx_stb <= 1;
|
||||
end
|
||||
else if (~uart_tx_init)
|
||||
uart_tx_init <= 1 && enable;
|
||||
end
|
||||
end
|
||||
|
||||
UART_TXCR:
|
||||
begin
|
||||
// UART TX CR - 0xD013
|
||||
// Ignore the TX control register
|
||||
dout <= 8'b0;
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
endmodule
|
299
rtl/vga.v
Normal file
299
rtl/vga.v
Normal file
@ -0,0 +1,299 @@
|
||||
module vga (
|
||||
input clk14, // clock signal
|
||||
input enable, // clock enable strobe,
|
||||
input rst, // active high reset signal
|
||||
output vga_h_sync, // horizontal 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 address, // address bus
|
||||
input w_en, // active high write enable strobe
|
||||
input [7:0] din, // 8-bit data bus (input)
|
||||
input [1:0] mode, // 2-bit mode setting for pixel doubling
|
||||
input [2:0] fg_colour, // 3 bit background colour
|
||||
input [2:0] bg_colour, // 3 bit foreground colour
|
||||
input clr_screen // clear screen button
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Registers and Parameters
|
||||
|
||||
// video structure constants
|
||||
parameter h_pixels = 910; // horizontal pixels per line
|
||||
parameter v_lines = 262; // vertical lines per frame
|
||||
parameter h_pulse = 65; // hsync pulse length (was: 96)
|
||||
parameter v_pulse = 2; // vsync pulse length
|
||||
parameter hbp = 144+64; // end of horizontal back porch
|
||||
parameter hfp = 784+64; // beginning of horizontal front porch
|
||||
parameter vbp = 10+32; // end of vertical back porch
|
||||
parameter vfp = 202+32; // beginning of vertical front porch
|
||||
|
||||
// registers for storing the horizontal & vertical counters
|
||||
reg [9:0] h_cnt;
|
||||
reg [9:0] v_cnt;
|
||||
wire [3:0] h_dot;
|
||||
reg [4:0] v_dot;
|
||||
|
||||
// hardware cursor registers
|
||||
wire [10:0] cursor;
|
||||
reg [5:0] h_cursor;
|
||||
reg [4:0] v_cursor;
|
||||
|
||||
// vram indexing registers
|
||||
reg [5:0] vram_h_addr;
|
||||
reg [4:0] vram_v_addr;
|
||||
reg [4:0] vram_start_addr;
|
||||
reg [4:0] vram_end_addr;
|
||||
wire [4:0] vram_clr_addr;
|
||||
|
||||
// vram registers
|
||||
wire [10:0] vram_r_addr;
|
||||
reg [10:0] vram_w_addr;
|
||||
reg vram_w_en;
|
||||
reg [5:0] vram_din;
|
||||
wire [5:0] vram_dout;
|
||||
|
||||
// font rom registers
|
||||
wire [5:0] font_char;
|
||||
wire [3:0] font_pixel;
|
||||
wire [4:0] font_line;
|
||||
wire font_out;
|
||||
|
||||
// cpu control registers
|
||||
reg char_seen;
|
||||
|
||||
// active region strobes
|
||||
wire h_active;
|
||||
wire v_active;
|
||||
assign h_active = (h_cnt >= hbp && h_cnt < hfp);
|
||||
assign v_active = (v_cnt >= vbp && v_cnt < vfp);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// VGA Sync Generation
|
||||
//
|
||||
always @(posedge clk14 or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
h_cnt <= 10'd0;
|
||||
v_cnt <= 10'd0;
|
||||
v_dot <= 5'd0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (h_cnt < h_pixels)
|
||||
h_cnt <= h_cnt + 1;
|
||||
|
||||
else
|
||||
begin
|
||||
// reset horizontal counters
|
||||
h_cnt <= 0;
|
||||
|
||||
if (v_cnt < v_lines)
|
||||
begin
|
||||
v_cnt <= v_cnt + 1;
|
||||
|
||||
// count 20 rows, so 480px / 20 = 24 rows
|
||||
if (v_active)
|
||||
begin
|
||||
v_dot <= v_dot + 1; // +1
|
||||
|
||||
if (v_dot == 5'd7) // == d19
|
||||
v_dot <= 0;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
// reset vertical counters
|
||||
v_cnt <= 0;
|
||||
v_dot <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// count 16 pixels, so 640px / 16 = 40 characters
|
||||
assign h_dot = h_active ? h_cnt[3:0] : 4'd0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Character ROM
|
||||
|
||||
font_rom font_rom(
|
||||
.clk(clk14),
|
||||
.mode(mode),
|
||||
.character(font_char),
|
||||
.pixel(font_pixel),
|
||||
.line(font_line),
|
||||
.out(font_out)
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Video RAM
|
||||
|
||||
vram vram(
|
||||
.clk(clk14),
|
||||
.read_addr(vram_r_addr),
|
||||
.write_addr(vram_w_addr),
|
||||
.r_en(h_active),
|
||||
.w_en(vram_w_en),
|
||||
.din(vram_din),
|
||||
.dout(vram_dout)
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Video Signal Generation
|
||||
|
||||
always @(posedge clk14 or posedge rst) begin
|
||||
if (rst) begin
|
||||
vram_h_addr <= 'd0;
|
||||
vram_v_addr <= 'd0;
|
||||
end else begin
|
||||
// start the pipeline for reading vram and font details
|
||||
// 3 pixel clock cycles early
|
||||
if (h_dot == 4'hC)
|
||||
vram_h_addr <= vram_h_addr + 'd1;
|
||||
|
||||
// advance to next row when last display line is reached for row
|
||||
if (v_dot == 5'd7 && h_cnt == 10'd0) // == d19
|
||||
vram_v_addr <= vram_v_addr + 'd1;
|
||||
|
||||
// clear the address registers if we're not in visible area
|
||||
if (~h_active)
|
||||
vram_h_addr <= 'd0;
|
||||
if (~v_active)
|
||||
vram_v_addr <= vram_start_addr;
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Cursor blink
|
||||
|
||||
reg blink;
|
||||
reg [22:0] blink_div;
|
||||
always @(posedge clk14 or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
blink_div <= 0;
|
||||
else
|
||||
begin
|
||||
blink_div <= blink_div + 1;
|
||||
|
||||
if (blink_div == 23'd0)
|
||||
blink <= ~blink;
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Pipeline and VGA signals
|
||||
|
||||
// vram to font rom to display pipeline assignments
|
||||
assign cursor = {v_cursor, h_cursor};
|
||||
assign vram_r_addr = {vram_v_addr, vram_h_addr};
|
||||
|
||||
assign font_char = (vram_r_addr != cursor) ? vram_dout : (blink) ? 6'd0 : 6'd32;
|
||||
assign font_pixel = h_dot + 1; // offset by one to get pixel into right cycle,
|
||||
// font output one pixel clk behind
|
||||
assign font_line = v_dot * 2 + 4;
|
||||
|
||||
// vga signals out to monitor
|
||||
assign vga_red = (h_active & v_active) ? (font_out ? fg_colour[2] : bg_colour[2]) : 1'b0;
|
||||
assign vga_grn = (h_active & v_active) ? (font_out ? fg_colour[1] : bg_colour[1]) : 1'b0;
|
||||
assign vga_blu = (h_active & v_active) ? (font_out ? fg_colour[0] : bg_colour[0]) : 1'b0;
|
||||
|
||||
assign vga_h_sync = (h_cnt < h_pulse) ? 0 : 1;
|
||||
assign vga_v_sync = (v_cnt < v_pulse) ? 0 : 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CPU control and hardware cursor
|
||||
|
||||
assign vram_clr_addr = vram_end_addr + {3'd0, vram_v_addr[1:0]};
|
||||
|
||||
always @(posedge clk14 or posedge rst)
|
||||
begin
|
||||
if (rst)
|
||||
begin
|
||||
h_cursor <= 6'd0;
|
||||
v_cursor <= 5'd0;
|
||||
char_seen <= 'b0;
|
||||
vram_start_addr <= 5'd0;
|
||||
vram_end_addr <= 5'd24;
|
||||
end
|
||||
else
|
||||
begin
|
||||
vram_w_en <= 0;
|
||||
|
||||
if (clr_screen)
|
||||
begin
|
||||
// return to top of screen
|
||||
h_cursor <= 6'd0;
|
||||
v_cursor <= 5'd0;
|
||||
|
||||
vram_start_addr <= 5'd0;
|
||||
vram_end_addr <= 5'd24;
|
||||
|
||||
// clear the screen
|
||||
vram_w_addr <= {vram_v_addr, vram_h_addr};
|
||||
vram_din <= 6'd32;
|
||||
vram_w_en <= 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// cursor overflow handling
|
||||
if (h_cursor == 6'd40)
|
||||
begin
|
||||
h_cursor <= 6'd0;
|
||||
v_cursor <= v_cursor + 'd1;
|
||||
end
|
||||
|
||||
if (v_cursor == vram_end_addr)
|
||||
begin
|
||||
vram_start_addr <= vram_start_addr + 'd1;
|
||||
vram_end_addr <= vram_end_addr + 'd1;
|
||||
end
|
||||
|
||||
if (address == 1'b0) // address low == TX register
|
||||
begin
|
||||
if (enable & w_en & ~char_seen)
|
||||
begin
|
||||
// incoming character
|
||||
char_seen <= 1;
|
||||
|
||||
case(din)
|
||||
8'h0D,
|
||||
8'h8D: begin
|
||||
// handle carriage return
|
||||
h_cursor <= 0;
|
||||
v_cursor <= v_cursor + 'd1;
|
||||
end
|
||||
|
||||
8'h00,
|
||||
8'h0A,
|
||||
8'h9B,
|
||||
8'h7F: begin
|
||||
// ignore the escape key
|
||||
h_cursor <= 0;
|
||||
end
|
||||
|
||||
default: begin
|
||||
vram_w_addr <= cursor;
|
||||
vram_din <= {~din[6], din[4:0]};
|
||||
vram_w_en <= 1;
|
||||
h_cursor <= h_cursor + 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
else if(~enable & ~w_en)
|
||||
char_seen <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
vram_w_addr <= {vram_clr_addr, vram_h_addr};
|
||||
vram_din <= 6'd32;
|
||||
vram_w_en <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
46
rtl/vram.v
Normal file
46
rtl/vram.v
Normal file
@ -0,0 +1,46 @@
|
||||
// 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: Video RAM for system
|
||||
//
|
||||
// Author.....: Alan Garfield
|
||||
// Niels A. Moseley
|
||||
// Date.......: 26-1-2018
|
||||
//
|
||||
|
||||
module vram (
|
||||
input clk, // clock signal
|
||||
input [10:0] read_addr, // read address bus
|
||||
input [10:0] write_addr, // write address bus
|
||||
input r_en, // active high read enable strobe
|
||||
input w_en, // active high write enable strobe
|
||||
input [5:0] din, // 6-bit data bus (input)
|
||||
output reg [5:0] dout // 6-bit data bus (output)
|
||||
);
|
||||
|
||||
reg [5:0] ram_data[0:2047];
|
||||
|
||||
initial
|
||||
$readmemb("roms/vga_vram.bin", ram_data, 0, 2047);
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (r_en) dout <= ram_data[read_addr];
|
||||
if (w_en) ram_data[write_addr] <= din;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user